zip_money 1.2.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 (124) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +69 -0
  4. data/README.md +128 -0
  5. data/Rakefile +8 -0
  6. data/docs/Address.md +15 -0
  7. data/docs/Authority.md +9 -0
  8. data/docs/CaptureChargeRequest.md +8 -0
  9. data/docs/Charge.md +17 -0
  10. data/docs/ChargeCollection.md +8 -0
  11. data/docs/ChargeOrder.md +11 -0
  12. data/docs/ChargesApi.md +307 -0
  13. data/docs/Checkout.md +18 -0
  14. data/docs/CheckoutConfiguration.md +8 -0
  15. data/docs/CheckoutFeatures.md +8 -0
  16. data/docs/CheckoutFeaturesTokenisation.md +8 -0
  17. data/docs/CheckoutOrder.md +13 -0
  18. data/docs/CheckoutsApi.md +119 -0
  19. data/docs/CreateChargeRequest.md +14 -0
  20. data/docs/CreateCheckoutRequest.md +13 -0
  21. data/docs/CreateCheckoutRequestFeatures.md +8 -0
  22. data/docs/CreateCheckoutRequestFeaturesTokenisation.md +8 -0
  23. data/docs/CreateRefundRequest.md +11 -0
  24. data/docs/CreateTokenRequest.md +8 -0
  25. data/docs/Customer.md +15 -0
  26. data/docs/CustomersApi.md +96 -0
  27. data/docs/ErrorResponse.md +8 -0
  28. data/docs/ErrorResponseError.md +10 -0
  29. data/docs/ErrorResponseErrorDetails.md +9 -0
  30. data/docs/InlineResponse200.md +8 -0
  31. data/docs/Metadata.md +7 -0
  32. data/docs/OrderItem.md +16 -0
  33. data/docs/OrderShipping.md +10 -0
  34. data/docs/OrderShippingTracking.md +10 -0
  35. data/docs/Refund.md +13 -0
  36. data/docs/RefundsApi.md +181 -0
  37. data/docs/SettlementsApi.md +96 -0
  38. data/docs/Shopper.md +17 -0
  39. data/docs/ShopperStatistics.md +16 -0
  40. data/docs/Token.md +11 -0
  41. data/docs/TokensApi.md +66 -0
  42. data/lib/zip_money.rb +68 -0
  43. data/lib/zip_money/api/charges_api.rb +301 -0
  44. data/lib/zip_money/api/checkouts_api.rb +120 -0
  45. data/lib/zip_money/api/customers_api.rb +116 -0
  46. data/lib/zip_money/api/refunds_api.rb +181 -0
  47. data/lib/zip_money/api/settlements_api.rb +116 -0
  48. data/lib/zip_money/api/tokens_api.rb +70 -0
  49. data/lib/zip_money/api_client.rb +386 -0
  50. data/lib/zip_money/api_error.rb +31 -0
  51. data/lib/zip_money/configuration.rb +238 -0
  52. data/lib/zip_money/models/address.rb +413 -0
  53. data/lib/zip_money/models/authority.rb +235 -0
  54. data/lib/zip_money/models/capture_charge_request.rb +206 -0
  55. data/lib/zip_money/models/charge.rb +369 -0
  56. data/lib/zip_money/models/charge_collection.rb +188 -0
  57. data/lib/zip_money/models/charge_order.rb +250 -0
  58. data/lib/zip_money/models/checkout.rb +344 -0
  59. data/lib/zip_money/models/checkout_configuration.rb +187 -0
  60. data/lib/zip_money/models/checkout_features.rb +181 -0
  61. data/lib/zip_money/models/checkout_features_tokenisation.rb +184 -0
  62. data/lib/zip_money/models/checkout_order.rb +299 -0
  63. data/lib/zip_money/models/create_charge_request.rb +289 -0
  64. data/lib/zip_money/models/create_checkout_request.rb +272 -0
  65. data/lib/zip_money/models/create_checkout_request_features.rb +181 -0
  66. data/lib/zip_money/models/create_checkout_request_features_tokenisation.rb +189 -0
  67. data/lib/zip_money/models/create_refund_request.rb +246 -0
  68. data/lib/zip_money/models/create_token_request.rb +186 -0
  69. data/lib/zip_money/models/customer.rb +310 -0
  70. data/lib/zip_money/models/error_response.rb +181 -0
  71. data/lib/zip_money/models/error_response_error.rb +211 -0
  72. data/lib/zip_money/models/error_response_error_details.rb +190 -0
  73. data/lib/zip_money/models/inline_response_200.rb +188 -0
  74. data/lib/zip_money/models/metadata.rb +172 -0
  75. data/lib/zip_money/models/order_item.rb +333 -0
  76. data/lib/zip_money/models/order_shipping.rb +200 -0
  77. data/lib/zip_money/models/order_shipping_tracking.rb +247 -0
  78. data/lib/zip_money/models/refund.rb +252 -0
  79. data/lib/zip_money/models/shopper.rb +339 -0
  80. data/lib/zip_money/models/shopper_statistics.rb +295 -0
  81. data/lib/zip_money/models/token.rb +228 -0
  82. data/lib/zip_money/version.rb +8 -0
  83. data/spec/api/charges_api_spec.rb +114 -0
  84. data/spec/api/checkouts_api_spec.rb +54 -0
  85. data/spec/api/customers_api_spec.rb +51 -0
  86. data/spec/api/refunds_api_spec.rb +67 -0
  87. data/spec/api/settlements_api_spec.rb +51 -0
  88. data/spec/api/tokens_api_spec.rb +41 -0
  89. data/spec/api_client_spec.rb +219 -0
  90. data/spec/configuration_spec.rb +50 -0
  91. data/spec/models/address_spec.rb +77 -0
  92. data/spec/models/authority_spec.rb +45 -0
  93. data/spec/models/capture_charge_request_spec.rb +35 -0
  94. data/spec/models/charge_collection_spec.rb +35 -0
  95. data/spec/models/charge_order_spec.rb +53 -0
  96. data/spec/models/charge_spec.rb +93 -0
  97. data/spec/models/checkout_configuration_spec.rb +35 -0
  98. data/spec/models/checkout_features_spec.rb +35 -0
  99. data/spec/models/checkout_features_tokenisation_spec.rb +35 -0
  100. data/spec/models/checkout_order_spec.rb +65 -0
  101. data/spec/models/checkout_spec.rb +103 -0
  102. data/spec/models/create_charge_request_spec.rb +75 -0
  103. data/spec/models/create_checkout_request_features_spec.rb +35 -0
  104. data/spec/models/create_checkout_request_features_tokenisation_spec.rb +35 -0
  105. data/spec/models/create_checkout_request_spec.rb +69 -0
  106. data/spec/models/create_refund_request_spec.rb +53 -0
  107. data/spec/models/create_token_request_spec.rb +35 -0
  108. data/spec/models/customer_spec.rb +81 -0
  109. data/spec/models/error_response_error_details_spec.rb +41 -0
  110. data/spec/models/error_response_error_spec.rb +47 -0
  111. data/spec/models/error_response_spec.rb +35 -0
  112. data/spec/models/inline_response_200_spec.rb +35 -0
  113. data/spec/models/metadata_spec.rb +29 -0
  114. data/spec/models/order_item_spec.rb +87 -0
  115. data/spec/models/order_shipping_spec.rb +47 -0
  116. data/spec/models/order_shipping_tracking_spec.rb +47 -0
  117. data/spec/models/refund_spec.rb +65 -0
  118. data/spec/models/shopper_spec.rb +92 -0
  119. data/spec/models/shopper_statistics_spec.rb +86 -0
  120. data/spec/models/token_spec.rb +52 -0
  121. data/spec/payload_helper.rb +96 -0
  122. data/spec/spec_helper.rb +104 -0
  123. data/zip_money.gemspec +38 -0
  124. metadata +380 -0
@@ -0,0 +1,181 @@
1
+ #Merchant API
2
+ #ZipMoney Merchant API Initial build
3
+ #zipMoney Merchant API version: 2017-03-01
4
+
5
+
6
+ require "uri"
7
+
8
+ module ZipMoney
9
+ class RefundsApi
10
+ attr_accessor :api_client
11
+
12
+ def initialize(api_client = ApiClient.default)
13
+ @api_client = api_client
14
+ end
15
+
16
+ # Create a refund
17
+ # Creates a refund for a previously authorised or captured charge. See #model:xWJer4QQyRumRi9LD for more information. This endpoint will return 201 or otherwise 402 if unable to perform the refund. | Error code | Description | |------------------------------------|--------------------------------------------------------------------------------------------------| | amount_invalid | The refund amount is greater than the remaining captured total | | invalid_state | 1. The charge is already fully refunded |
18
+ # @param [Hash] opts the optional parameters
19
+ # @option opts [CreateRefundRequest] :body
20
+ # @option opts [String] :idempotency_key The unique idempotency key.
21
+ # @return [Refund]
22
+ def refunds_create(opts = {})
23
+ data, _status_code, _headers = refunds_create_with_http_info(opts)
24
+ return data
25
+ end
26
+
27
+ # Create a refund
28
+ # Creates a refund for a previously authorised or captured charge. See #model:xWJer4QQyRumRi9LD for more information. This endpoint will return 201 or otherwise 402 if unable to perform the refund. | Error code | Description | |------------------------------------|--------------------------------------------------------------------------------------------------| | amount_invalid | The refund amount is greater than the remaining captured total | | invalid_state | 1. The charge is already fully refunded |
29
+ # @param [Hash] opts the optional parameters
30
+ # @option opts [CreateRefundRequest] :body
31
+ # @option opts [String] :idempotency_key The unique idempotency key.
32
+ # @return [Array<(Refund, Fixnum, Hash)>] Refund data, response status code and response headers
33
+ def refunds_create_with_http_info(opts = {})
34
+ if @api_client.config.debugging
35
+ @api_client.config.logger.debug "Calling API: RefundsApi.refunds_create ..."
36
+ end
37
+ # resource path
38
+ local_var_path = "/refunds".sub('{format}','json')
39
+
40
+ # query parameters
41
+ query_params = {}
42
+
43
+ # header parameters
44
+ header_params = {}
45
+ # HTTP header 'Accept' (if needed)
46
+ header_params['Accept'] = @api_client.select_header_accept(['application/javascript'])
47
+ # HTTP header 'Content-Type'
48
+ header_params['Content-Type'] = @api_client.select_header_content_type(['application/json'])
49
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
50
+
51
+ # form parameters
52
+ form_params = {}
53
+
54
+ # http body (model)
55
+ post_body = @api_client.object_to_http_body(opts[:'body'])
56
+ auth_names = ['Authorization']
57
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path,
58
+ :header_params => header_params,
59
+ :query_params => query_params,
60
+ :form_params => form_params,
61
+ :body => post_body,
62
+ :auth_names => auth_names,
63
+ :return_type => 'Refund')
64
+ if @api_client.config.debugging
65
+ @api_client.config.logger.debug "API called: RefundsApi#refunds_create\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
66
+ end
67
+ return data, status_code, headers
68
+ end
69
+
70
+ # List refunds
71
+ # List all refunds
72
+ # @param [Hash] opts the optional parameters
73
+ # @option opts [String] :charge_id
74
+ # @option opts [Integer] :skip Number of items to skip when paging (default to 0)
75
+ # @option opts [Integer] :limit Number of items to retrieve when paging (default to 100)
76
+ # @return [Array<InlineResponse200>]
77
+ def refunds_list(opts = {})
78
+ data, _status_code, _headers = refunds_list_with_http_info(opts)
79
+ return data
80
+ end
81
+
82
+ # List refunds
83
+ # List all refunds
84
+ # @param [Hash] opts the optional parameters
85
+ # @option opts [String] :charge_id
86
+ # @option opts [Integer] :skip Number of items to skip when paging
87
+ # @option opts [Integer] :limit Number of items to retrieve when paging
88
+ # @return [Array<(Array<InlineResponse200>, Fixnum, Hash)>] Array<InlineResponse200> data, response status code and response headers
89
+ def refunds_list_with_http_info(opts = {})
90
+ if @api_client.config.debugging
91
+ @api_client.config.logger.debug "Calling API: RefundsApi.refunds_list ..."
92
+ end
93
+ # resource path
94
+ local_var_path = "/refunds".sub('{format}','json')
95
+
96
+ # query parameters
97
+ query_params = {}
98
+ query_params[:'chargeId'] = opts[:'charge_id'] if !opts[:'charge_id'].nil?
99
+ query_params[:'skip'] = opts[:'skip'] if !opts[:'skip'].nil?
100
+ query_params[:'limit'] = opts[:'limit'] if !opts[:'limit'].nil?
101
+
102
+ # header parameters
103
+ header_params = {}
104
+ # HTTP header 'Accept' (if needed)
105
+ header_params['Accept'] = @api_client.select_header_accept(['application/javascript'])
106
+ # HTTP header 'Content-Type'
107
+ header_params['Content-Type'] = @api_client.select_header_content_type(['application/javascript'])
108
+
109
+ # form parameters
110
+ form_params = {}
111
+
112
+ # http body (model)
113
+ post_body = nil
114
+ auth_names = ['Authorization']
115
+ data, status_code, headers = @api_client.call_api(:GET, local_var_path,
116
+ :header_params => header_params,
117
+ :query_params => query_params,
118
+ :form_params => form_params,
119
+ :body => post_body,
120
+ :auth_names => auth_names,
121
+ :return_type => 'Array<InlineResponse200>')
122
+ if @api_client.config.debugging
123
+ @api_client.config.logger.debug "API called: RefundsApi#refunds_list\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
124
+ end
125
+ return data, status_code, headers
126
+ end
127
+
128
+ # Retrieve a refund
129
+ # Retrieves details of a specific refund
130
+ # @param id The id of the refund
131
+ # @param [Hash] opts the optional parameters
132
+ # @return [Refund]
133
+ def refunds_retrieve(id, opts = {})
134
+ data, _status_code, _headers = refunds_retrieve_with_http_info(id, opts)
135
+ return data
136
+ end
137
+
138
+ # Retrieve a refund
139
+ # Retrieves details of a specific refund
140
+ # @param id The id of the refund
141
+ # @param [Hash] opts the optional parameters
142
+ # @return [Array<(Refund, Fixnum, Hash)>] Refund data, response status code and response headers
143
+ def refunds_retrieve_with_http_info(id, opts = {})
144
+ if @api_client.config.debugging
145
+ @api_client.config.logger.debug "Calling API: RefundsApi.refunds_retrieve ..."
146
+ end
147
+ # verify the required parameter 'id' is set
148
+ fail ArgumentError, "Missing the required parameter 'id' when calling RefundsApi.refunds_retrieve" if id.nil?
149
+ # resource path
150
+ local_var_path = "/refunds/{id}".sub('{format}','json').sub('{' + 'id' + '}', id.to_s)
151
+
152
+ # query parameters
153
+ query_params = {}
154
+
155
+ # header parameters
156
+ header_params = {}
157
+ # HTTP header 'Accept' (if needed)
158
+ header_params['Accept'] = @api_client.select_header_accept(['application/javascript'])
159
+ # HTTP header 'Content-Type'
160
+ header_params['Content-Type'] = @api_client.select_header_content_type(['application/javascript'])
161
+
162
+ # form parameters
163
+ form_params = {}
164
+
165
+ # http body (model)
166
+ post_body = nil
167
+ auth_names = ['Authorization']
168
+ data, status_code, headers = @api_client.call_api(:GET, local_var_path,
169
+ :header_params => header_params,
170
+ :query_params => query_params,
171
+ :form_params => form_params,
172
+ :body => post_body,
173
+ :auth_names => auth_names,
174
+ :return_type => 'Refund')
175
+ if @api_client.config.debugging
176
+ @api_client.config.logger.debug "API called: RefundsApi#refunds_retrieve\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
177
+ end
178
+ return data, status_code, headers
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,116 @@
1
+ #Merchant API
2
+ #ZipMoney Merchant API Initial build
3
+ #zipMoney Merchant API version: 2017-03-01
4
+
5
+
6
+ require "uri"
7
+
8
+ module ZipMoney
9
+ class SettlementsApi
10
+ attr_accessor :api_client
11
+
12
+ def initialize(api_client = ApiClient.default)
13
+ @api_client = api_client
14
+ end
15
+
16
+ # Retrieve a settlement
17
+ # Retrieves the full transactional details of a settlement.
18
+ # @param id The settlement id
19
+ # @param [Hash] opts the optional parameters
20
+ # @return [nil]
21
+ def settlements_get(id, opts = {})
22
+ settlements_get_with_http_info(id, opts)
23
+ return nil
24
+ end
25
+
26
+ # Retrieve a settlement
27
+ # Retrieves the full transactional details of a settlement.
28
+ # @param id The settlement id
29
+ # @param [Hash] opts the optional parameters
30
+ # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers
31
+ def settlements_get_with_http_info(id, opts = {})
32
+ if @api_client.config.debugging
33
+ @api_client.config.logger.debug "Calling API: SettlementsApi.settlements_get ..."
34
+ end
35
+ # verify the required parameter 'id' is set
36
+ fail ArgumentError, "Missing the required parameter 'id' when calling SettlementsApi.settlements_get" if id.nil?
37
+ # resource path
38
+ local_var_path = "/settlements/{id}".sub('{format}','json').sub('{' + 'id' + '}', id.to_s)
39
+
40
+ # query parameters
41
+ query_params = {}
42
+
43
+ # header parameters
44
+ header_params = {}
45
+ # HTTP header 'Accept' (if needed)
46
+ header_params['Accept'] = @api_client.select_header_accept(['application/javascript'])
47
+ # HTTP header 'Content-Type'
48
+ header_params['Content-Type'] = @api_client.select_header_content_type(['application/javascript'])
49
+
50
+ # form parameters
51
+ form_params = {}
52
+
53
+ # http body (model)
54
+ post_body = nil
55
+ auth_names = []
56
+ data, status_code, headers = @api_client.call_api(:GET, local_var_path,
57
+ :header_params => header_params,
58
+ :query_params => query_params,
59
+ :form_params => form_params,
60
+ :body => post_body,
61
+ :auth_names => auth_names)
62
+ if @api_client.config.debugging
63
+ @api_client.config.logger.debug "API called: SettlementsApi#settlements_get\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
64
+ end
65
+ return data, status_code, headers
66
+ end
67
+
68
+ # List settlements
69
+ # This endpoint will allow a merchant to view the settlements which have occured. To view detailed transaction information for a specific settlement you can use the Retrieve a settlement endpoint.
70
+ # @param [Hash] opts the optional parameters
71
+ # @return [nil]
72
+ def settlements_list(opts = {})
73
+ settlements_list_with_http_info(opts)
74
+ return nil
75
+ end
76
+
77
+ # List settlements
78
+ # This endpoint will allow a merchant to view the settlements which have occured. To view detailed transaction information for a specific settlement you can use the Retrieve a settlement endpoint.
79
+ # @param [Hash] opts the optional parameters
80
+ # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers
81
+ def settlements_list_with_http_info(opts = {})
82
+ if @api_client.config.debugging
83
+ @api_client.config.logger.debug "Calling API: SettlementsApi.settlements_list ..."
84
+ end
85
+ # resource path
86
+ local_var_path = "/settlements".sub('{format}','json')
87
+
88
+ # query parameters
89
+ query_params = {}
90
+
91
+ # header parameters
92
+ header_params = {}
93
+ # HTTP header 'Accept' (if needed)
94
+ header_params['Accept'] = @api_client.select_header_accept(['application/javascript'])
95
+ # HTTP header 'Content-Type'
96
+ header_params['Content-Type'] = @api_client.select_header_content_type(['application/javascript'])
97
+
98
+ # form parameters
99
+ form_params = {}
100
+
101
+ # http body (model)
102
+ post_body = nil
103
+ auth_names = []
104
+ data, status_code, headers = @api_client.call_api(:GET, local_var_path,
105
+ :header_params => header_params,
106
+ :query_params => query_params,
107
+ :form_params => form_params,
108
+ :body => post_body,
109
+ :auth_names => auth_names)
110
+ if @api_client.config.debugging
111
+ @api_client.config.logger.debug "API called: SettlementsApi#settlements_list\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
112
+ end
113
+ return data, status_code, headers
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,70 @@
1
+ #Merchant API
2
+ #ZipMoney Merchant API Initial build
3
+ #zipMoney Merchant API version: 2017-03-01
4
+
5
+
6
+ require "uri"
7
+
8
+ module ZipMoney
9
+ class TokensApi
10
+ attr_accessor :api_client
11
+
12
+ def initialize(api_client = ApiClient.default)
13
+ @api_client = api_client
14
+ end
15
+
16
+ # Create token
17
+ # Tokenises a zip account allowing a charge to be performed at a later date without direct customer involvement. In order to create a token you will first need to request customer approval by implementing one of the online checkout flows. The checkout id will then be provided as the authority when tokenising. | Error code | Description | |------------------------------------|--------------------------------------------------------------------------------------------------| | account_inoperative | The account is in arrears or closed and cannot be charged | | account_locked | The account is locked |
18
+ # @param [Hash] opts the optional parameters
19
+ # @option opts [CreateTokenRequest] :body
20
+ # @option opts [String] :idempotency_key The unique idempotency key.
21
+ # @return [Token]
22
+ def tokens_create(opts = {})
23
+ data, _status_code, _headers = tokens_create_with_http_info(opts)
24
+ return data
25
+ end
26
+
27
+ # Create token
28
+ # Tokenises a zip account allowing a charge to be performed at a later date without direct customer involvement. In order to create a token you will first need to request customer approval by implementing one of the online checkout flows. The checkout id will then be provided as the authority when tokenising. | Error code | Description | |------------------------------------|--------------------------------------------------------------------------------------------------| | account_inoperative | The account is in arrears or closed and cannot be charged | | account_locked | The account is locked |
29
+ # @param [Hash] opts the optional parameters
30
+ # @option opts [CreateTokenRequest] :body
31
+ # @option opts [String] :idempotency_key The unique idempotency key.
32
+ # @return [Array<(Token, Fixnum, Hash)>] Token data, response status code and response headers
33
+ def tokens_create_with_http_info(opts = {})
34
+ if @api_client.config.debugging
35
+ @api_client.config.logger.debug "Calling API: TokensApi.tokens_create ..."
36
+ end
37
+ # resource path
38
+ local_var_path = "/tokens".sub('{format}','json')
39
+
40
+ # query parameters
41
+ query_params = {}
42
+
43
+ # header parameters
44
+ header_params = {}
45
+ # HTTP header 'Accept' (if needed)
46
+ header_params['Accept'] = @api_client.select_header_accept(['application/javascript'])
47
+ # HTTP header 'Content-Type'
48
+ header_params['Content-Type'] = @api_client.select_header_content_type(['application/json'])
49
+ header_params[:'Idempotency-Key'] = opts[:'idempotency_key'] if !opts[:'idempotency_key'].nil?
50
+
51
+ # form parameters
52
+ form_params = {}
53
+
54
+ # http body (model)
55
+ post_body = @api_client.object_to_http_body(opts[:'body'])
56
+ auth_names = ['Authorization']
57
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path,
58
+ :header_params => header_params,
59
+ :query_params => query_params,
60
+ :form_params => form_params,
61
+ :body => post_body,
62
+ :auth_names => auth_names,
63
+ :return_type => 'Token')
64
+ if @api_client.config.debugging
65
+ @api_client.config.logger.debug "API called: TokensApi#tokens_create\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
66
+ end
67
+ return data, status_code, headers
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,386 @@
1
+ #Merchant API
2
+ #ZipMoney Merchant API Initial build
3
+ #zipMoney Merchant API version: 2017-03-01
4
+
5
+
6
+ require 'date'
7
+ require 'json'
8
+ require 'logger'
9
+ require 'tempfile'
10
+ require 'typhoeus'
11
+ require 'uri'
12
+
13
+ module ZipMoney
14
+ class ApiClient
15
+ # The Configuration object holding settings to be used in the API client.
16
+ attr_accessor :config
17
+
18
+ # Defines the headers to be used in HTTP requests of all API calls by default.
19
+ #
20
+ # @return [Hash]
21
+ attr_accessor :default_headers
22
+
23
+ # Initializes the ApiClient
24
+ # @option config [Configuration] Configuration for initializing the object, default to Configuration.default
25
+ def initialize(config = Configuration.default)
26
+ @config = config
27
+
28
+ @user_agent = @config.user_agent
29
+ if @config.platform
30
+ @user_agent = @config.platform + "/" + @config.user_agent
31
+ end
32
+
33
+ @default_headers = {
34
+ 'Content-Type' => "application/json",
35
+ 'User-Agent' => @user_agent,
36
+ 'Zip-Version' => @config.api_version
37
+ }
38
+ end
39
+
40
+ def self.default
41
+ @@default ||= ApiClient.new
42
+ end
43
+
44
+ # Call an API with given options.
45
+ #
46
+ # @return [Array<(Object, Fixnum, Hash)>] an array of 3 elements:
47
+ # the data deserialized from response body (could be nil), response status code and response headers.
48
+ def call_api(http_method, path, opts = {})
49
+ request = build_request(http_method, path, opts)
50
+ count = 0
51
+ @response = nil
52
+
53
+ loop do
54
+ # Retry after specified retry interval
55
+ sleep(@config.retry_interval) if count > 0 && @config.retry_interval > 0
56
+ @config.logger.debug "Running the request. Count #{count+1}" if @config.debugging
57
+ @response = request.run
58
+ count = count + 1
59
+ break if (( count >= @config.num_retries && @response.code == 0 && @response.return_message == "Couldn't connect to server") || @response.code > 0 || opts[:header_params][:'Idempotency-Key'].nil?)
60
+ end
61
+
62
+ if @config.debugging
63
+ @config.logger.debug "HTTP response body ~BEGIN~\n#{@response.body}\n~END~\n"
64
+ end
65
+
66
+ unless @response.success?
67
+ if @response.timed_out?
68
+ fail ApiError.new('Connection timed out')
69
+ elsif @response.code == 0
70
+ # Errors from libcurl will be made visible here
71
+ fail ApiError.new(:code => 0,
72
+ :message => @response.return_message)
73
+ else
74
+ fail ApiError.new(:code => @response.code,
75
+ :response_headers => @response.headers,
76
+ :response_body => @response.body),
77
+ @response.status_message
78
+ end
79
+ end
80
+
81
+ if opts[:return_type]
82
+ data = deserialize(@response, opts[:return_type])
83
+ else
84
+ data = nil
85
+ end
86
+ return data, @response.code, @response.headers
87
+ end
88
+
89
+ # Builds the HTTP request
90
+ #
91
+ # @param [String] http_method HTTP method/verb (e.g. POST)
92
+ # @param [String] path URL path (e.g. /account/new)
93
+ # @option opts [Hash] :header_params Header parameters
94
+ # @option opts [Hash] :query_params Query parameters
95
+ # @option opts [Hash] :form_params Query parameters
96
+ # @option opts [Object] :body HTTP body (JSON/XML)
97
+ # @return [Typhoeus::Request] A Typhoeus Request
98
+ def build_request(http_method, path, opts = {})
99
+ url = build_request_url(path)
100
+ http_method = http_method.to_sym.downcase
101
+
102
+ header_params = @default_headers.merge(opts[:header_params] || {})
103
+ query_params = opts[:query_params] || {}
104
+ form_params = opts[:form_params] || {}
105
+
106
+ update_params_for_auth! header_params, query_params, opts[:auth_names]
107
+
108
+ # set ssl_verifyhosts option based on @config.verify_ssl_host (true/false)
109
+ _verify_ssl_host = @config.verify_ssl_host ? 2 : 0
110
+
111
+ req_opts = {
112
+ :method => http_method,
113
+ :headers => header_params,
114
+ :params => query_params,
115
+ :params_encoding => @config.params_encoding,
116
+ :timeout => @config.timeout,
117
+ :ssl_verifypeer => @config.verify_ssl,
118
+ :ssl_verifyhost => _verify_ssl_host,
119
+ :sslcert => @config.cert_file,
120
+ :sslkey => @config.key_file,
121
+ :verbose => @config.debugging
122
+ }
123
+
124
+ # set custom cert, if provided
125
+ req_opts[:cainfo] = @config.ssl_ca_cert if @config.ssl_ca_cert
126
+
127
+ if [:post, :patch, :put, :delete].include?(http_method)
128
+ req_body = build_request_body(header_params, form_params, opts[:body])
129
+ req_opts.update :body => req_body
130
+ if @config.debugging
131
+ @config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"
132
+ end
133
+ end
134
+
135
+ Typhoeus::Request.new(url, req_opts)
136
+ end
137
+
138
+ # Check if the given MIME is a JSON MIME.
139
+ # JSON MIME examples:
140
+ # application/json
141
+ # application/json; charset=UTF8
142
+ # APPLICATION/JSON
143
+ # */*
144
+ # @param [String] mime MIME
145
+ # @return [Boolean] True if the MIME is application/json
146
+ def json_mime?(mime)
147
+ (mime == "*/*") || !(mime =~ /\Aapplication\/json(;.*)?\z/i).nil?
148
+ end
149
+
150
+ # Deserialize the response to the given return type.
151
+ #
152
+ # @param [Response] response HTTP response
153
+ # @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]"
154
+ def deserialize(response, return_type)
155
+ body = response.body
156
+ return nil if body.nil? || body.empty?
157
+
158
+ # return response body directly for String return type
159
+ return body if return_type == 'String'
160
+
161
+ # handle file downloading - save response body into a tmp file and return the File instance
162
+ return download_file(response) if return_type == 'File'
163
+
164
+ # ensuring a default content type
165
+ content_type = response.headers['Content-Type'] || 'application/json'
166
+
167
+ fail "Content-Type is not supported: #{content_type}" unless json_mime?(content_type)
168
+
169
+ begin
170
+ data = JSON.parse("[#{body}]", :symbolize_names => true)[0]
171
+ rescue JSON::ParserError => e
172
+ if %w(String Date DateTime).include?(return_type)
173
+ data = body
174
+ else
175
+ raise e
176
+ end
177
+ end
178
+
179
+ convert_to_type data, return_type
180
+ end
181
+
182
+ # Convert data to the given return type.
183
+ # @param [Object] data Data to be converted
184
+ # @param [String] return_type Return type
185
+ # @return [Mixed] Data in a particular type
186
+ def convert_to_type(data, return_type)
187
+ return nil if data.nil?
188
+ case return_type
189
+ when 'String'
190
+ data.to_s
191
+ when 'Integer'
192
+ data.to_i
193
+ when 'Float'
194
+ data.to_f
195
+ when 'BOOLEAN'
196
+ data == true
197
+ when 'DateTime'
198
+ # parse date time (expecting ISO 8601 format)
199
+ DateTime.parse data
200
+ when 'Date'
201
+ # parse date time (expecting ISO 8601 format)
202
+ Date.parse data
203
+ when 'Object'
204
+ # generic object (usually a Hash), return directly
205
+ data
206
+ when /\AArray<(.+)>\z/
207
+ # e.g. Array<Pet>
208
+ sub_type = $1
209
+ data.map {|item| convert_to_type(item, sub_type) }
210
+ when /\AHash\<String, (.+)\>\z/
211
+ # e.g. Hash<String, Integer>
212
+ sub_type = $1
213
+ {}.tap do |hash|
214
+ data.each {|k, v| hash[k] = convert_to_type(v, sub_type) }
215
+ end
216
+ else
217
+ # models, e.g. Pet
218
+ ZipMoney.const_get(return_type).new.tap do |model|
219
+ model.build_from_hash data
220
+ end
221
+ end
222
+ end
223
+
224
+ # Save response body into a file in (the defined) temporary folder, using the filename
225
+ # from the "Content-Disposition" header if provided, otherwise a random filename.
226
+ #
227
+ # @see Configuration#temp_folder_path
228
+ # @return [Tempfile] the file downloaded
229
+ def download_file(response)
230
+ content_disposition = response.headers['Content-Disposition']
231
+ if content_disposition and content_disposition =~ /filename=/i
232
+ filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
233
+ prefix = sanitize_filename(filename)
234
+ else
235
+ prefix = 'download-'
236
+ end
237
+ prefix = prefix + '-' unless prefix.end_with?('-')
238
+
239
+ tempfile = nil
240
+ encoding = response.body.encoding
241
+ Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding) do |file|
242
+ file.write(response.body)
243
+ tempfile = file
244
+ end
245
+ @config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
246
+ "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
247
+ "will be deleted automatically with GC. It's also recommended to delete the temp file "\
248
+ "explicitly with `tempfile.delete`"
249
+ tempfile
250
+ end
251
+
252
+ # Sanitize filename by removing path.
253
+ # e.g. ../../sun.gif becomes sun.gif
254
+ #
255
+ # @param [String] filename the filename to be sanitized
256
+ # @return [String] the sanitized filename
257
+ def sanitize_filename(filename)
258
+ filename.gsub(/.*[\/\\]/, '')
259
+ end
260
+
261
+ def build_request_url(path)
262
+ # Add leading and trailing slashes to path
263
+ path = "/#{path}".gsub(/\/+/, '/')
264
+ URI.encode(@config.base_url + path)
265
+ end
266
+
267
+ # Builds the HTTP request body
268
+ #
269
+ # @param [Hash] header_params Header parameters
270
+ # @param [Hash] form_params Query parameters
271
+ # @param [Object] body HTTP body (JSON/XML)
272
+ # @return [String] HTTP body data in the form of string
273
+ def build_request_body(header_params, form_params, body)
274
+ # http form
275
+ if header_params['Content-Type'] == 'application/x-www-form-urlencoded' ||
276
+ header_params['Content-Type'] == 'multipart/form-data'
277
+ data = {}
278
+ form_params.each do |key, value|
279
+ case value
280
+ when File, Array, nil
281
+ # let typhoeus handle File, Array and nil parameters
282
+ data[key] = value
283
+ else
284
+ data[key] = value.to_s
285
+ end
286
+ end
287
+ elsif body
288
+ data = body.is_a?(String) ? body : body.to_json
289
+ else
290
+ data = nil
291
+ end
292
+ data
293
+ end
294
+
295
+ # Update hearder and query params based on authentication settings.
296
+ #
297
+ # @param [Hash] header_params Header parameters
298
+ # @param [Hash] query_params Query parameters
299
+ # @param [String] auth_names Authentication scheme name
300
+ def update_params_for_auth!(header_params, query_params, auth_names)
301
+ Array(auth_names).each do |auth_name|
302
+ auth_setting = @config.auth_settings[auth_name]
303
+ next unless auth_setting
304
+ case auth_setting[:in]
305
+ when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
306
+ when 'query' then query_params[auth_setting[:key]] = auth_setting[:value]
307
+ else fail ArgumentError, 'Authentication token must be in `query` of `header`'
308
+ end
309
+ end
310
+ end
311
+
312
+ # Sets user agent in HTTP header
313
+ #
314
+ # @param [String] user_agent User agent (e.g. merchantapi/ruby/1.0.0)
315
+ def user_agent=(user_agent)
316
+ @user_agent = user_agent
317
+ @default_headers['User-Agent'] = @user_agent
318
+ end
319
+
320
+ # Return Accept header based on an array of accepts provided.
321
+ # @param [Array] accepts array for Accept
322
+ # @return [String] the Accept header (e.g. application/json)
323
+ def select_header_accept(accepts)
324
+ return nil if accepts.nil? || accepts.empty?
325
+ # use JSON when present, otherwise use all of the provided
326
+ json_accept = accepts.find { |s| json_mime?(s) }
327
+ return json_accept || accepts.join(',')
328
+ end
329
+
330
+ # Return Content-Type header based on an array of content types provided.
331
+ # @param [Array] content_types array for Content-Type
332
+ # @return [String] the Content-Type header (e.g. application/json)
333
+ def select_header_content_type(content_types)
334
+ # use application/json by default
335
+ return 'application/json' if content_types.nil? || content_types.empty?
336
+ # use JSON when present, otherwise use the first one
337
+ json_content_type = content_types.find { |s| json_mime?(s) }
338
+ return json_content_type || content_types.first
339
+ end
340
+
341
+ # Convert object (array, hash, object, etc) to JSON string.
342
+ # @param [Object] model object to be converted into JSON string
343
+ # @return [String] JSON string representation of the object
344
+ def object_to_http_body(model)
345
+ return model if model.nil? || model.is_a?(String)
346
+ local_body = nil
347
+ if model.is_a?(Array)
348
+ local_body = model.map{|m| object_to_hash(m) }
349
+ else
350
+ local_body = object_to_hash(model)
351
+ end
352
+ local_body.to_json
353
+ end
354
+
355
+ # Convert object(non-array) to hash.
356
+ # @param [Object] obj object to be converted into JSON string
357
+ # @return [String] JSON string representation of the object
358
+ def object_to_hash(obj)
359
+ if obj.respond_to?(:to_hash)
360
+ obj.to_hash
361
+ else
362
+ obj
363
+ end
364
+ end
365
+
366
+ # Build parameter value according to the given collection format.
367
+ # @param [String] collection_format one of :csv, :ssv, :tsv, :pipes and :multi
368
+ def build_collection_param(param, collection_format)
369
+ case collection_format
370
+ when :csv
371
+ param.join(',')
372
+ when :ssv
373
+ param.join(' ')
374
+ when :tsv
375
+ param.join("\t")
376
+ when :pipes
377
+ param.join('|')
378
+ when :multi
379
+ # return the array directly as typhoeus will handle it as expected
380
+ param
381
+ else
382
+ fail "unknown collection format: #{collection_format.inspect}"
383
+ end
384
+ end
385
+ end
386
+ end