mizuho_bank 0.1.1 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.rdoc +11 -1
  2. data/VERSION +1 -1
  3. data/lib/mizuho_bank.rb +154 -6
  4. metadata +2 -2
data/README.rdoc CHANGED
@@ -6,7 +6,6 @@
6
6
  == 使い方 (こんな感じで)
7
7
 
8
8
  # encoding: utf-8
9
- Encoding.default_external = Encoding.default_internal = "UTF-8"
10
9
  require 'mizuho_bank'
11
10
  require 'pit'
12
11
 
@@ -31,6 +30,17 @@
31
30
  p bank.info.main_account.money
32
31
  }
33
32
 
33
+ == 用例集
34
+ 1. 口座残高取得したいとき
35
+ bank.info.main_account.money
36
+
37
+ 2. 最近の取引履歴を配列で取得したいとき
38
+ bank.info.main_account.cache_flows
39
+
40
+ 3. 口座番号とか種別しりたいとき
41
+ bank.info.main_account.number
42
+ bank.info.main_account.type
43
+
34
44
  == 既知の問題
35
45
  まだ画像認証に対応してない。画像認証は秘密の質問に失敗しまくってるとやらなきゃいけなくなる
36
46
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.1.3
data/lib/mizuho_bank.rb CHANGED
@@ -4,6 +4,8 @@ require 'kconv'
4
4
  require 'logger'
5
5
  require 'retry-handler'
6
6
  require 'moji'
7
+ require 'chronic'
8
+ require 'open-uri'
7
9
 
8
10
  # utility class
9
11
  class String
@@ -12,12 +14,6 @@ class String
12
14
  end
13
15
  end
14
16
 
15
- class Time
16
- def self.mizuho_time_parse(string)
17
- p string
18
- end
19
- end
20
-
21
17
  class Integer
22
18
  def humanize
23
19
  case
@@ -42,12 +38,39 @@ class MizuhoBank
42
38
  @logger = Logger.new(nil)
43
39
  @logger = logger unless logger.nil?
44
40
 
41
+ unless MizuhoBank.is_available?
42
+ raise "MizuhoBank is not available"
43
+ end
44
+
45
45
  if login(keiyaku_no, password, aikotoba_dict)
46
46
  block.call(self) if block_given?
47
47
  end
48
48
  self
49
49
  end
50
50
 
51
+ def self.new_with_pit(logger = nil, &block)
52
+ pit = Pit.get("MizuhoBank",
53
+ :require => {
54
+ "keiyaku_no" => "keiyaku_no",
55
+ "password" => "password",
56
+ "aikotoba1_question" => "aikotoba1_question",
57
+ "aikotoba2_question" => "aikotoba2_question",
58
+ "aikotoba3_question" => "aikotoba3_question",
59
+ "aikotoba1_answer" => "aikotoba1_answer",
60
+ "aikotoba2_answer" => "aikotoba2_answer",
61
+ "aikotoba3_answer" => "aikotoba3_answer",
62
+ })
63
+
64
+ aikotoba_dict = {
65
+ pit['aikotoba1_question'] => pit['aikotoba1_answer'],
66
+ pit['aikotoba2_question'] => pit['aikotoba2_answer'],
67
+ pit['aikotoba3_question'] => pit['aikotoba3_answer']
68
+ }
69
+ self.new(pit['keiyaku_no'].to_s, pit['password'].to_s, aikotoba_dict, logger){ |bank|
70
+ block.call(bank)
71
+ }
72
+ end
73
+
51
74
  def login(keiyaku_no, password, aikotoba_dict={})
52
75
  @login_result = false
53
76
  Proc.new do
@@ -72,6 +95,8 @@ class MizuhoBank
72
95
  auth_password(password)
73
96
  when :logout_fail_info
74
97
  raise "Logout fail info page!!"
98
+ when :not_available_page
99
+ raise "not available page"
75
100
  when :unknown
76
101
  @logger.info "unknown page reached: #{@agent.page.title}"
77
102
  @login_result = true
@@ -88,6 +113,123 @@ class MizuhoBank
88
113
  @login_result
89
114
  end
90
115
 
116
+ def self.is_available?(time = Time.now)
117
+ get_jikangai_ranges(time).each{ |range|
118
+ if range.cover? time
119
+ return false
120
+ end
121
+ }
122
+ return true
123
+ end
124
+
125
+ class RepeatDate
126
+ attr_accessor :wday
127
+ attr_accessor :hour
128
+ attr_accessor :minute
129
+
130
+ def to_s
131
+ if @wday.nil?
132
+ "%02d:%02d" % [@hour, @minute]
133
+ else
134
+ "%s %02d:%02d" % [wday, @hour, @minute]
135
+ end
136
+ end
137
+ end
138
+
139
+ class RepeatDateRange
140
+ attr_accessor :start
141
+ attr_accessor :end
142
+
143
+ def initialize
144
+ @start = RepeatDate.new
145
+ @end = RepeatDate.new
146
+ end
147
+
148
+ def cover? (time, context = Time.now)
149
+ s = start_time(context)
150
+ e = end_time(s)
151
+ (s .. e).cover? (time)
152
+ end
153
+
154
+ def include? (*args)
155
+ cover? *args
156
+ end
157
+
158
+ def start_time(context = Time.now)
159
+ Chronic.parse(translate_in_this_month(@start.to_s, context), :now => context)
160
+ end
161
+
162
+ def end_time(context = Time.now)
163
+ Chronic.parse(translate_in_this_month(@end.to_s, context), :now => context)
164
+ end
165
+
166
+ def translate_in_this_month(text, context=Time.now)
167
+ if text.match(/(.*?)(.+) (.+) in this month(.*)/)
168
+ month = context.strftime("%B")
169
+ previous = Regexp.last_match(1)
170
+ n = Regexp.last_match(2)
171
+ wday = Regexp.last_match(3)
172
+ last = Regexp.last_match(4)
173
+
174
+ time = Chronic.parse("#{n} #{wday} in #{month}")
175
+ time.strftime("#{previous} %Y/%m/%d #{last}")
176
+ else
177
+ text
178
+ end
179
+ end
180
+
181
+ def to_s(context = Time.now)
182
+ s = start_time(context)
183
+ e = end_time(s)
184
+ "#{s} - #{e}"
185
+ end
186
+ end
187
+
188
+ def self.get_jikangai_ranges(context = Time.now)
189
+ url = "http://www.mizuhobank.co.jp/direct/jikangai.html"
190
+ body = open(url).read.toutf8
191
+ doc = Nokogiri(body)
192
+ unless body.include? "以下の時間帯は、インターネットバンキングをご利用いただけません。"
193
+ raise "page format error"
194
+ end
195
+
196
+ dates = doc.search("#contents > div.section > div.inner > table :first-child > th > ul.normal > li > strong").map(&:text)
197
+
198
+ ranges = []
199
+ if dates.first =~ /土曜日(\d+)時(\d+)分~翌日曜日(\d+)時(\d+)分/
200
+ range = RepeatDateRange.new
201
+ range.start.wday = "last saturday"
202
+ range.start.hour = Regexp.last_match(1).to_i
203
+ range.start.minute = Regexp.last_match(2).to_i
204
+ range.end.wday = "next sunday"
205
+ range.end.hour = Regexp.last_match(3).to_i
206
+ range.end.minute = Regexp.last_match(4).to_i
207
+ ranges << range
208
+ end
209
+
210
+ if dates.second =~ /第1・第4土曜日(\d+)時(\d+)分~(\d+)時(\d+)分/
211
+ range = RepeatDateRange.new
212
+ range.start.wday = "1st saturday in this month"
213
+ range.start.hour = Regexp.last_match(1).to_i
214
+ range.start.minute = Regexp.last_match(2).to_i
215
+ range.end.wday = nil
216
+ range.end.hour = Regexp.last_match(3).to_i
217
+ range.end.minute = Regexp.last_match(4).to_i
218
+ ranges << range
219
+
220
+ range = RepeatDateRange.new
221
+ range.start.wday = "4th saturday in this month"
222
+ range.start.hour = Regexp.last_match(1).to_i
223
+ range.start.minute = Regexp.last_match(2).to_i
224
+ range.end.wday = nil
225
+ range.end.hour = Regexp.last_match(3).to_i
226
+ range.end.minute = Regexp.last_match(4).to_i
227
+ ranges << range
228
+ end
229
+
230
+ ranges
231
+ end
232
+
91
233
  private
92
234
  # 契約者番号の認証ページ処理
93
235
  def is_auth_keiyaku_no_page?
@@ -137,6 +279,10 @@ class MizuhoBank
137
279
  @agent.page.body.toutf8.include? "ログインできませんでした。前回の操作で正しくログアウトされていない可能性があります。"
138
280
  end
139
281
 
282
+ def is_not_available_page?
283
+ @agent.page.body.toutf8.include? "以下の時間帯は、インターネットバンキングをご利用いただけません"
284
+ end
285
+
140
286
  def auth_password(password)
141
287
  @agent.page.form_with(:name => 'FORM1'){ |f|
142
288
  f.field_with(:name => 'Anshu1No').value = password.tosjis
@@ -157,6 +303,8 @@ class MizuhoBank
157
303
  return :auth_password
158
304
  elsif is_auth_keiyaku_no_page?
159
305
  return :auth_keiyaku_no
306
+ elsif is_not_available_page?
307
+ return :not_available
160
308
  else
161
309
  return :unknown
162
310
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 1
9
- version: 0.1.1
8
+ - 4
9
+ version: 0.1.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - kimoto