gmo 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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