gmo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +8 -0
  2. data/Gemfile +22 -0
  3. data/README.ja.md +54 -0
  4. data/README.md +54 -0
  5. data/Rakefile +15 -0
  6. data/autotest/discover.rb +1 -0
  7. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_alter_tran_change_order_auth_to_sale.yml +90 -0
  8. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_alter_tran_gets_data_about_order.yml +90 -0
  9. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_alter_tran_got_error_if_missing_options.yml +32 -0
  10. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_change_tran_gets_data_about_order.yml +90 -0
  11. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_change_tran_got_error_if_missing_options.yml +32 -0
  12. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_entry_tran_gets_data_about_a_transaction.yml +32 -0
  13. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_entry_tran_got_error_if_missing_options.yml +32 -0
  14. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_exec_tran_gets_data_about_a_transaction.yml +32 -0
  15. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_exec_tran_got_error_if_missing_options.yml +32 -0
  16. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_search_trade_gets_data_about_order.yml +32 -0
  17. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_search_trade_got_error_if_missing_options.yml +32 -0
  18. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_search_trade_multi_gets_data_about_order.yml +34 -0
  19. data/fixtures/vcr_cassettes/GMO_Payment_ShopAPI/_search_trade_multi_got_error_if_missing_options.yml +34 -0
  20. data/fixtures/vcr_cassettes/GMO_Payment_ShopAndSiteAPI/_trade_card_got_error_if_missing_options.yml +32 -0
  21. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_delete_card_gets_data_about_a_card.yml +34 -0
  22. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_delete_member_gets_data_about_a_member.yml +34 -0
  23. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_save_card_gets_data_about_a_card.yml +34 -0
  24. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_save_member_gets_data_about_a_transaction.yml +32 -0
  25. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_save_member_got_error_if_missing_options.yml +32 -0
  26. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_search_card_gets_data_about_a_card.yml +65 -0
  27. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_search_member_gets_data_about_a_member.yml +65 -0
  28. data/fixtures/vcr_cassettes/GMO_Payment_SiteAPI/_update_member_gets_data_about_a_transaction.yml +32 -0
  29. data/gmo.gemspec +30 -0
  30. data/lib/gmo.rb +99 -0
  31. data/lib/gmo/errors.rb +51 -0
  32. data/lib/gmo/http_services.rb +77 -0
  33. data/lib/gmo/shop_and_site_api.rb +56 -0
  34. data/lib/gmo/shop_api.rb +218 -0
  35. data/lib/gmo/site_api.rb +146 -0
  36. data/lib/gmo/version.rb +3 -0
  37. data/spec/gmo/api_spec.rb +32 -0
  38. data/spec/gmo/error_spec.rb +25 -0
  39. data/spec/gmo/http_service_spec.rb +23 -0
  40. data/spec/gmo/shop_and_site_api_spec.rb +45 -0
  41. data/spec/gmo/shop_api_spec.rb +261 -0
  42. data/spec/gmo/site_api_spec.rb +140 -0
  43. data/spec/spec_helper.rb +21 -0
  44. data/spec/support/config.example.yml +4 -0
  45. data/spec/support/config.yml +4 -0
  46. data/spec/support/config_loader.rb +2 -0
  47. data/spec/support/factory.rb +8 -0
  48. data/spec/support/vcr.rb +21 -0
  49. data/travis.yml +11 -0
  50. metadata +202 -0
@@ -0,0 +1,32 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://pt01.mul-pay.jp/payment/SaveMember.idPass
6
+ body:
7
+ encoding: UTF-8
8
+ string: MemberID=null&MemberName=null&SiteID=tsite1&SitePass=1
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Date:
20
+ - Sat, 16 Feb 2013 04:56:31 GMT
21
+ Connection:
22
+ - close
23
+ Content-Type:
24
+ - text/plain;charset=Windows-31J
25
+ Transfer-Encoding:
26
+ - chunked
27
+ body:
28
+ encoding: US-ASCII
29
+ string: MemberID=null
30
+ http_version:
31
+ recorded_at: Sat, 16 Feb 2013 04:56:31 GMT
32
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,65 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://pt01.mul-pay.jp/payment/SaveCard.idPass
6
+ body:
7
+ encoding: UTF-8
8
+ string: MemberID=101&CardNo=4111111111111111&Expire=1405&SiteID=<SITE_ID>&SitePass=<SITE_PASS>
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - '*/*'
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Date:
22
+ - Sat, 16 Feb 2013 07:09:34 GMT
23
+ Connection:
24
+ - close
25
+ Content-Type:
26
+ - text/plain;charset=Windows-31J
27
+ Transfer-Encoding:
28
+ - chunked
29
+ body:
30
+ encoding: UTF-8
31
+ string: CardSeq=0&CardNo=*************111&Forward=2a99662
32
+ http_version:
33
+ recorded_at: Sat, 16 Feb 2013 07:09:34 GMT
34
+ - request:
35
+ method: post
36
+ uri: https://pt01.mul-pay.jp/payment/SearchCard.idPass
37
+ body:
38
+ encoding: UTF-8
39
+ string: MemberID=101&CardSeq=0&SeqMode=0&SiteID=<SITE_ID>&SitePass=<SITE_PASS>
40
+ headers:
41
+ Accept-Encoding:
42
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
43
+ Accept:
44
+ - '*/*'
45
+ User-Agent:
46
+ - Ruby
47
+ response:
48
+ status:
49
+ code: 200
50
+ message: OK
51
+ headers:
52
+ Date:
53
+ - Sat, 16 Feb 2013 07:09:34 GMT
54
+ Connection:
55
+ - close
56
+ Content-Type:
57
+ - text/plain;charset=Windows-31J
58
+ Transfer-Encoding:
59
+ - chunked
60
+ body:
61
+ encoding: UTF-8
62
+ string: CardSeq=0&DefaultFlag=0&CardName=&CardNo=*************111&Expire=1405&HolderName=&DeleteFlag=0
63
+ http_version:
64
+ recorded_at: Sat, 16 Feb 2013 07:09:34 GMT
65
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,65 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://pt01.mul-pay.jp/payment/SaveMember.idPass
6
+ body:
7
+ encoding: UTF-8
8
+ string: MemberID=101&MemberName=John+Smith&SiteID=<SITE_ID>&SitePass=<SITE_PASS>
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - '*/*'
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Date:
22
+ - Sat, 16 Feb 2013 06:55:41 GMT
23
+ Connection:
24
+ - close
25
+ Content-Type:
26
+ - text/plain;charset=Windows-31J
27
+ Transfer-Encoding:
28
+ - chunked
29
+ body:
30
+ encoding: UTF-8
31
+ string: MemberID=101
32
+ http_version:
33
+ recorded_at: Sat, 16 Feb 2013 06:55:41 GMT
34
+ - request:
35
+ method: post
36
+ uri: https://pt01.mul-pay.jp/payment/SearchMember.idPass
37
+ body:
38
+ encoding: UTF-8
39
+ string: MemberID=101&SiteID=<SITE_ID>&SitePass=<SITE_PASS>
40
+ headers:
41
+ Accept-Encoding:
42
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
43
+ Accept:
44
+ - '*/*'
45
+ User-Agent:
46
+ - Ruby
47
+ response:
48
+ status:
49
+ code: 200
50
+ message: OK
51
+ headers:
52
+ Date:
53
+ - Sat, 16 Feb 2013 06:55:42 GMT
54
+ Connection:
55
+ - close
56
+ Content-Type:
57
+ - text/plain;charset=Windows-31J
58
+ Transfer-Encoding:
59
+ - chunked
60
+ body:
61
+ encoding: UTF-8
62
+ string: MemberID=101&MemberName=John Smith&DeleteFlag=0
63
+ http_version:
64
+ recorded_at: Sat, 16 Feb 2013 06:55:41 GMT
65
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,32 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://pt01.mul-pay.jp/payment/UpdateMember.idPass
6
+ body:
7
+ encoding: UTF-8
8
+ string: MemberID=100&MemberName=John+Smith2&SiteID=<SITE_ID>&SitePass=<SITE_PASS>
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Date:
20
+ - Sat, 16 Feb 2013 05:29:21 GMT
21
+ Connection:
22
+ - close
23
+ Content-Type:
24
+ - text/plain;charset=Windows-31J
25
+ Transfer-Encoding:
26
+ - chunked
27
+ body:
28
+ encoding: US-ASCII
29
+ string: MemberID=100
30
+ http_version:
31
+ recorded_at: Sat, 16 Feb 2013 05:29:21 GMT
32
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gmo/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "gmo"
8
+ gem.description = %q{Ruby client library for the GMO Payment Platform.}
9
+ gem.summary = %q{GMO Payment API client: Ruby client library for the GMO Payment Platform.}
10
+ gem.homepage = ""
11
+ gem.version = GMO::VERSION
12
+
13
+ gem.authors = ["Tatsuo Kaniwa"]
14
+ gem.email = ["tatsuo@kaniwa.biz"]
15
+
16
+ gem.require_paths = ["lib"]
17
+ gem.files = `git ls-files`.split("\n")
18
+ gem.test_files = `git ls-files -- {spec}/*`.split("\n")
19
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+
21
+ gem.extra_rdoc_files = ["README.md"]
22
+ gem.rdoc_options = ["--line-numbers", "--inline-source", "--title", "GMO"]
23
+
24
+ gem.add_runtime_dependency "rack"
25
+ gem.add_runtime_dependency "multi_json"
26
+ gem.add_development_dependency "rspec"
27
+ gem.add_development_dependency "rake"
28
+ gem.add_development_dependency "vcr"
29
+ gem.add_development_dependency "webmock"
30
+ end
@@ -0,0 +1,99 @@
1
+ require 'cgi'
2
+ require 'rack/utils'
3
+ require 'multi_json'
4
+
5
+ require 'gmo/errors'
6
+ require 'gmo/http_services'
7
+ require 'gmo/shop_api'
8
+ require 'gmo/site_api'
9
+ require 'gmo/shop_and_site_api'
10
+ require "gmo/version"
11
+
12
+ # Ruby client library for the GMO Payment Platform.
13
+ # Copyright 2013 Tatsuo Kaniwa
14
+ # tatsuo[at]kaniwa.biz
15
+
16
+ module GMO
17
+
18
+ module Payment
19
+
20
+ DEV_SERVER = "pt01.mul-pay.jp"
21
+ # TODO: Set production server
22
+ PRO_SERVER = "pt01.mul-pay.jp"
23
+
24
+ class API
25
+
26
+ def initialize(options = {})
27
+ @development = options[:development] || true
28
+ end
29
+ attr_reader :development
30
+
31
+ def api(path, args = {}, verb = "post", options = {}, &error_checking_block)
32
+ # Setup args for make_request
33
+ path = "/payment/#{path}" unless path =~ /^\//
34
+ options.merge!({ "development" => @development })
35
+ # Make request via the provided service
36
+ result = GMO.make_request path, args, verb, options
37
+ # Check for any 500 server errors before parsing the body
38
+ if result.status >= 500
39
+ error_detail = {
40
+ :http_status => result.status.to_i,
41
+ :body => result.body,
42
+ }
43
+ raise GMO::Payment::ServerError.new(result.body, error_detail)
44
+ end
45
+ # Parse the body as Query string
46
+ body = response = Rack::Utils.parse_nested_query result.body.to_s
47
+ # Check for errors if provided a error_checking_block
48
+ yield(body) if error_checking_block
49
+ # Return result
50
+ if options[:http_component]
51
+ result.send options[:http_component]
52
+ else
53
+ body
54
+ end
55
+ end
56
+
57
+ # gmo.get_request("EntryTran.idPass", {:foo => "bar"})
58
+ # GET /EntryTran.idPass with params foo=bar
59
+ def get_request(name, args = {}, options = {})
60
+ api_call(name, args, "get", options)
61
+ end
62
+ alias :get! :get_request
63
+
64
+ # gmo.post_request("EntryTran.idPass", {:foo => "bar"})
65
+ # POST /EntryTran.idPass with params foo=bar
66
+ def post_request(name, args = {}, options = {})
67
+ api_call(name, args, "post", options)
68
+ end
69
+ alias :post! :post_request
70
+
71
+ private
72
+
73
+ def api_call(*args)
74
+ raise "Called abstract method: api_call"
75
+ end
76
+
77
+ end
78
+
79
+ class ShopAPI < API
80
+ include ShopAPIMethods
81
+ end
82
+
83
+ class SiteAPI < API
84
+ include SiteAPIMethods
85
+ end
86
+
87
+ class ShopAndSiteAPI < API
88
+ include ShopAndSiteAPIMethods
89
+ end
90
+
91
+ end
92
+
93
+ # Set up the http service GMO methods used to make requests
94
+ def self.http_service=(service)
95
+ self.send :include, service
96
+ end
97
+
98
+ GMO.http_service = NetHTTPService
99
+ end
@@ -0,0 +1,51 @@
1
+ # begin
2
+ # # do something...
3
+ # rescue GMO::Payment::APIError => e
4
+ # puts e.response_body
5
+ # # => ErrCode=hoge&ErrInfo=hoge
6
+ # puts e.error_info
7
+ # # {"ErrCode"=>"hoge", "ErrInfo"=>"hoge"}
8
+ # end
9
+
10
+ module GMO
11
+
12
+ class GMOError < StandardError; end
13
+
14
+ module Payment
15
+ class Error < ::GMO::GMOError
16
+ attr_accessor :error_info, :response_body
17
+
18
+ def initialize(response_body = "", error_info = nil)
19
+ if response_body && response_body.is_a?(String)
20
+ self.response_body = response_body.strip
21
+ else
22
+ self.response_body = ''
23
+ end
24
+ if error_info.nil?
25
+ begin
26
+ error_info = Rack::Utils.parse_nested_query(response_body.to_s)
27
+ rescue
28
+ error_info ||= {}
29
+ end
30
+ end
31
+ self.error_info = error_info
32
+ message = self.response_body
33
+ super(message)
34
+ end
35
+ end
36
+
37
+ class ServerError < Error
38
+ end
39
+
40
+ class APIError < Error
41
+ def initialize(error_info = {})
42
+ self.error_info = error_info
43
+ self.response_body = "ErrCode=#{error_info["ErrCode"]}&ErrInfo=#{error_info["ErrInfo"]}"
44
+ message = self.response_body
45
+ super(message)
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,77 @@
1
+ module GMO
2
+ class Response
3
+
4
+ attr_reader :status, :body, :headers
5
+ def initialize(status, body, headers)
6
+ @status = status
7
+ @body = body
8
+ @headers = headers
9
+ end
10
+
11
+ end
12
+
13
+ module HTTPService
14
+
15
+ def self.included(base)
16
+ base.class_eval do
17
+ def self.server(options = {})
18
+ options[:development] ? Payment::DEV_SERVER : Payment::PRO_SERVER
19
+ end
20
+ end# end class_eval
21
+ end
22
+ end
23
+
24
+ module NetHTTPService
25
+ def self.included(base)
26
+ base.class_eval do
27
+ require "net/http" unless defined?(Net::HTTP)
28
+ require "net/https"
29
+
30
+ include GMO::HTTPService
31
+
32
+ def self.make_request(path, args, verb, options = {})
33
+ args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
34
+
35
+ http = create_http(server(options), options)
36
+ http.use_ssl = true
37
+
38
+ result = http.start do |http|
39
+ response, body = if verb == "post"
40
+ http.post(path, encode_params(args))
41
+ else
42
+ http.get("#{path}?#{encode_params(args)}")
43
+ end
44
+ GMO::Response.new(response.code.to_i, response.body, response)
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ def self.encode_params(param_hash)
51
+ ((param_hash || {}).collect do |key_and_value|
52
+ key_and_value[1] = MultiJson.dump(key_and_value[1]) if key_and_value[1].class != String
53
+ "#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
54
+ end).join("&")
55
+ end
56
+
57
+ def self.create_http(server, options)
58
+ if options[:proxy]
59
+ proxy = URI.parse(options[:proxy])
60
+ http = Net::HTTP.new \
61
+ server, 443,
62
+ proxy.host, proxy.port,
63
+ proxy.user, proxy.password
64
+ else
65
+ http = Net::HTTP.new server, 443
66
+ end
67
+ if options[:timeout]
68
+ http.open_timeout = options[:timeout]
69
+ http.read_timeout = options[:timeout]
70
+ end
71
+ http
72
+ end
73
+
74
+ end
75
+ end
76
+ end
77
+ end