activemerchant 1.63.0 → 1.64.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG +26 -0
- data/README.md +1 -1
- data/lib/active_merchant/billing/gateway.rb +5 -1
- data/lib/active_merchant/billing/gateways/authorize_net.rb +13 -12
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +6 -3
- data/lib/active_merchant/billing/gateways/card_stream.rb +72 -1
- data/lib/active_merchant/billing/gateways/credorax.rb +78 -1
- data/lib/active_merchant/billing/gateways/digitzs.rb +292 -0
- data/lib/active_merchant/billing/gateways/global_collect.rb +2 -2
- data/lib/active_merchant/billing/gateways/kushki.rb +217 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +2 -2
- data/lib/active_merchant/billing/gateways/omise.rb +9 -5
- data/lib/active_merchant/billing/gateways/paymill.rb +18 -10
- data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -1
- data/lib/active_merchant/billing/gateways/sage.rb +5 -3
- data/lib/active_merchant/billing/gateways/stripe.rb +1 -1
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -3
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +114 -9
- data/lib/active_merchant/billing/gateways/wepay.rb +1 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1974da9f685774b95695ff91430141a164281f64
|
4
|
+
data.tar.gz: 5a547f1ff49dcf3d3ef6089d92636f0c92ac47f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2beea9543a20c61f6549a94d71a6c6d73962cdc0ca21548d378a4ffbf26ade9df8b0cb0d7cb14b7f1355d4999625e9cae82fe3a87572070a18fcbcb81168f83b
|
7
|
+
data.tar.gz: 1624eb5f2942edcff808a3ac70fb693c0c7f617c229e384d279f2e8b517558243bd2943a808198b59f378d7f8752cb2807d84717a3b72fa9119caf2e809656a0
|
data/CHANGELOG
CHANGED
@@ -2,6 +2,32 @@
|
|
2
2
|
|
3
3
|
== HEAD
|
4
4
|
|
5
|
+
== Version 1.64.0 (March 6, 2017)
|
6
|
+
* Authorize.net: Allow settings to be passed for CIM purchases [fwilkins] #2300
|
7
|
+
* Authorize.net: Use new `unsupported_feature` standard error code [jasonwebster] #2322
|
8
|
+
* Base Gateway: Add new `unsupported_feature` standard error code [jasonwebster] #2322
|
9
|
+
* Braintree Blue: Pass cardholder_name with card [curiousepic] #2324
|
10
|
+
* Braintree: Add Android Pay meta data fields [jknipp] #2347
|
11
|
+
* CardStream: Add additional of currencies [shasum] #2337
|
12
|
+
* Credorax: Return failure response reason [shasum] #2341
|
13
|
+
* Digitzs: Add gateway [davidsantoso]
|
14
|
+
* Digitzs: Remove merchant_id from gateway credentials [davidsantoso]
|
15
|
+
* GlobalCollect: Pass options to Refund [curiousepic] #2330
|
16
|
+
* Kushki: Add new gateway [shasum] #2326
|
17
|
+
* Kushki: Remove body from void call [shasum] #2348
|
18
|
+
* Linkpoint: Raise ArgumentError when trying to instantiate without `:pem` [jasonwebster] #2329
|
19
|
+
* Omise: Enable Japan, JPY and JCB support [zdk] #2284
|
20
|
+
* PayU LATAM: Count pending refunds as succeeded [curiousepic] #2336
|
21
|
+
* PayU LATAM: Let Refund take amount value [curiousepic] #2334
|
22
|
+
* Paymill: Send new required fields on tokenization requests [tschelabaumann] #2279
|
23
|
+
* Revert "Authorize.net: Allow settings to be passed for CIM purchases" [curiousepic] #2339
|
24
|
+
* Sage: Default billing state when outside US [shasum] #2340
|
25
|
+
* Stripe: Remove idempotency key from verify [shasum] #2335
|
26
|
+
* TransFirst Transaction Express: Don't send order_id with refunds [curiousepic] #2350
|
27
|
+
* TransFirst Transaction Express: Fix improper AVS and CVV response code mapping [shasum] #2342
|
28
|
+
* WePay: Update API version [shasum] #2349
|
29
|
+
* USA ePay Advanced: Add quick_update_customer action [joshreeves] #2229
|
30
|
+
|
5
31
|
== Version 1.63.0 (February 2, 2017)
|
6
32
|
* Authorize.net: Add #unstore support [jimryan] #2293
|
7
33
|
* AuthorizeNet: Fix line items quirk [shasum]
|
data/README.md
CHANGED
@@ -162,7 +162,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis
|
|
162
162
|
* [NETPAY Gateway](http://www.netpay.com.mx) - MX
|
163
163
|
* [NMI](http://nmi.com/) - US
|
164
164
|
* [Ogone](http://www.ogone.com/) - BE, DE, FR, NL, AT, CH
|
165
|
-
* [Omise](https://www.omise.co/) - TH
|
165
|
+
* [Omise](https://www.omise.co/) - TH, JP
|
166
166
|
* [Openpay](Openpay) - MX
|
167
167
|
* [Optimal Payments](http://www.optimalpayments.com/) - CA, US, GB
|
168
168
|
* [Orbital Paymentech](http://chasepaymentech.com/) - US, CA
|
@@ -77,6 +77,9 @@ module ActiveMerchant #:nodoc:
|
|
77
77
|
# :call_issuer - Transaction requires voice authentication, call issuer
|
78
78
|
# :pickup_card - Issuer requests that you pickup the card from merchant
|
79
79
|
# :test_mode_live_card - Card was declined. Request was in test mode, but used a non test card.
|
80
|
+
# :unsupported_feature - Transaction failed due to gateway or merchant
|
81
|
+
# configuration not supporting a feature used, such
|
82
|
+
# as network tokenization.
|
80
83
|
|
81
84
|
STANDARD_ERROR_CODE = {
|
82
85
|
:incorrect_number => 'incorrect_number',
|
@@ -93,7 +96,8 @@ module ActiveMerchant #:nodoc:
|
|
93
96
|
:call_issuer => 'call_issuer',
|
94
97
|
:pickup_card => 'pick_up_card',
|
95
98
|
:config_error => 'config_error',
|
96
|
-
:test_mode_live_card => 'test_mode_live_card'
|
99
|
+
:test_mode_live_card => 'test_mode_live_card',
|
100
|
+
:unsupported_feature => 'unsupported_feature',
|
97
101
|
}
|
98
102
|
|
99
103
|
cattr_reader :implementations
|
@@ -36,24 +36,25 @@ module ActiveMerchant
|
|
36
36
|
}
|
37
37
|
|
38
38
|
STANDARD_ERROR_CODE_MAPPING = {
|
39
|
-
'36' => STANDARD_ERROR_CODE[:incorrect_number],
|
40
|
-
'237' => STANDARD_ERROR_CODE[:invalid_number],
|
41
|
-
'2315' => STANDARD_ERROR_CODE[:invalid_number],
|
42
|
-
'37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
43
|
-
'2316' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
44
|
-
'378' => STANDARD_ERROR_CODE[:invalid_cvc],
|
45
|
-
'38' => STANDARD_ERROR_CODE[:expired_card],
|
46
|
-
'2317' => STANDARD_ERROR_CODE[:expired_card],
|
47
|
-
'244' => STANDARD_ERROR_CODE[:incorrect_cvc],
|
48
|
-
'227' => STANDARD_ERROR_CODE[:incorrect_address],
|
49
39
|
'2127' => STANDARD_ERROR_CODE[:incorrect_address],
|
50
40
|
'22' => STANDARD_ERROR_CODE[:card_declined],
|
41
|
+
'227' => STANDARD_ERROR_CODE[:incorrect_address],
|
51
42
|
'23' => STANDARD_ERROR_CODE[:card_declined],
|
52
|
-
'
|
43
|
+
'2315' => STANDARD_ERROR_CODE[:invalid_number],
|
44
|
+
'2316' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
45
|
+
'2317' => STANDARD_ERROR_CODE[:expired_card],
|
53
46
|
'235' => STANDARD_ERROR_CODE[:processing_error],
|
47
|
+
'237' => STANDARD_ERROR_CODE[:invalid_number],
|
54
48
|
'24' => STANDARD_ERROR_CODE[:pickup_card],
|
49
|
+
'244' => STANDARD_ERROR_CODE[:incorrect_cvc],
|
55
50
|
'300' => STANDARD_ERROR_CODE[:config_error],
|
56
|
-
'
|
51
|
+
'3153' => STANDARD_ERROR_CODE[:processing_error],
|
52
|
+
'3155' => STANDARD_ERROR_CODE[:unsupported_feature],
|
53
|
+
'36' => STANDARD_ERROR_CODE[:incorrect_number],
|
54
|
+
'37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
55
|
+
'378' => STANDARD_ERROR_CODE[:invalid_cvc],
|
56
|
+
'38' => STANDARD_ERROR_CODE[:expired_card],
|
57
|
+
'384' => STANDARD_ERROR_CODE[:config_error],
|
57
58
|
}
|
58
59
|
|
59
60
|
MARKET_TYPE = {
|
@@ -573,7 +573,7 @@ module ActiveMerchant #:nodoc:
|
|
573
573
|
:number => credit_card_or_vault_id.number,
|
574
574
|
:expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, "0"),
|
575
575
|
:expiration_year => credit_card_or_vault_id.year.to_s,
|
576
|
-
:cardholder_name =>
|
576
|
+
:cardholder_name => credit_card_or_vault_id.name,
|
577
577
|
:cryptogram => credit_card_or_vault_id.payment_cryptogram
|
578
578
|
}
|
579
579
|
elsif credit_card_or_vault_id.source == :android_pay
|
@@ -582,7 +582,9 @@ module ActiveMerchant #:nodoc:
|
|
582
582
|
:cryptogram => credit_card_or_vault_id.payment_cryptogram,
|
583
583
|
:expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, "0"),
|
584
584
|
:expiration_year => credit_card_or_vault_id.year.to_s,
|
585
|
-
:google_transaction_id => credit_card_or_vault_id.transaction_id
|
585
|
+
:google_transaction_id => credit_card_or_vault_id.transaction_id,
|
586
|
+
:source_card_type => credit_card_or_vault_id.brand,
|
587
|
+
:source_card_last_four => credit_card_or_vault_id.last_digits
|
586
588
|
}
|
587
589
|
end
|
588
590
|
else
|
@@ -590,7 +592,8 @@ module ActiveMerchant #:nodoc:
|
|
590
592
|
:number => credit_card_or_vault_id.number,
|
591
593
|
:cvv => credit_card_or_vault_id.verification_value,
|
592
594
|
:expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, "0"),
|
593
|
-
:expiration_year => credit_card_or_vault_id.year.to_s
|
595
|
+
:expiration_year => credit_card_or_vault_id.year.to_s,
|
596
|
+
:cardholder_name => credit_card_or_vault_id.name
|
594
597
|
}
|
595
598
|
end
|
596
599
|
end
|
@@ -14,24 +14,95 @@ module ActiveMerchant #:nodoc:
|
|
14
14
|
|
15
15
|
CURRENCY_CODES = {
|
16
16
|
"AED" => "784",
|
17
|
+
"ALL" => "008",
|
18
|
+
"AMD" => "051",
|
19
|
+
"ANG" => "532",
|
20
|
+
"ARS" => "032",
|
17
21
|
"AUD" => "036",
|
22
|
+
"AWG" => "533",
|
23
|
+
"BAM" => "977",
|
24
|
+
"BBD" => "052",
|
25
|
+
"BGN" => "975",
|
26
|
+
"BMD" => "060",
|
27
|
+
"BOB" => "068",
|
18
28
|
"BRL" => "986",
|
29
|
+
"BSD" => "044",
|
30
|
+
"BWP" => "072",
|
31
|
+
"BZD" => "084",
|
19
32
|
"CAD" => "124",
|
20
33
|
"CHF" => "756",
|
34
|
+
"CLP" => "152",
|
35
|
+
"CNY" => "156",
|
36
|
+
"COP" => "170",
|
37
|
+
"CRC" => "188",
|
21
38
|
"CZK" => "203",
|
22
39
|
"DKK" => "208",
|
40
|
+
"DOP" => "214",
|
41
|
+
"EGP" => "818",
|
23
42
|
"EUR" => "978",
|
24
43
|
"GBP" => "826",
|
44
|
+
"GEL" => "981",
|
45
|
+
"GIP" => "292",
|
46
|
+
"GTQ" => "320",
|
47
|
+
"GYD" => "328",
|
25
48
|
"HKD" => "344",
|
26
|
-
"
|
49
|
+
"HNL" => "340",
|
50
|
+
"HRK" => "191",
|
51
|
+
"HUF" => "348",
|
52
|
+
"ISK" => "352",
|
53
|
+
"IDR" => "360",
|
54
|
+
"ILS" => "376",
|
55
|
+
"INR" => "356",
|
27
56
|
"JPY" => "392",
|
57
|
+
"JMD" => "388",
|
58
|
+
"KES" => "404",
|
59
|
+
"KRW" => "410",
|
60
|
+
"KYD" => "136",
|
61
|
+
"LBP" => "422",
|
62
|
+
"LKR" => "144",
|
63
|
+
"MAD" => "504",
|
64
|
+
"MVR" => "462",
|
65
|
+
"MWK" => "454",
|
28
66
|
"MXN" => "484",
|
67
|
+
"MYR" => "458",
|
68
|
+
"NAD" => "516",
|
69
|
+
"NGN" => "566",
|
70
|
+
"NIO" => "558",
|
29
71
|
"NOK" => "578",
|
72
|
+
"NPR" => "524",
|
30
73
|
"NZD" => "554",
|
74
|
+
"PAB" => "590",
|
31
75
|
"PEN" => "604",
|
76
|
+
"PGK" => "598",
|
77
|
+
"PHP" => "608",
|
78
|
+
"PKR" => "586",
|
79
|
+
"PLN" => "985",
|
80
|
+
"PYG" => "600",
|
81
|
+
"QAR" => "634",
|
82
|
+
"RON" => "946",
|
83
|
+
"RSD" => "941",
|
84
|
+
"RUB" => "643",
|
85
|
+
"RWF" => "646",
|
86
|
+
"SAR" => "682",
|
32
87
|
"SEK" => "752",
|
33
88
|
"SGD" => "702",
|
89
|
+
"SRD" => "968",
|
90
|
+
"THB" => "764",
|
91
|
+
"TND" => "788",
|
92
|
+
"TRY" => "949",
|
93
|
+
"TTD" => "780",
|
94
|
+
"TWD" => "901",
|
95
|
+
"TZS" => "834",
|
96
|
+
"UAH" => "980",
|
97
|
+
"UGX" => "800",
|
34
98
|
"USD" => "840",
|
99
|
+
"UYU" => "858",
|
100
|
+
"VND" => "704",
|
101
|
+
"WST" => "882",
|
102
|
+
"XAF" => "950",
|
103
|
+
"XCD" => "951",
|
104
|
+
"XOF" => "952",
|
105
|
+
"ZAR" => "710"
|
35
106
|
}
|
36
107
|
|
37
108
|
CVV_CODE = {
|
@@ -20,6 +20,83 @@ module ActiveMerchant #:nodoc:
|
|
20
20
|
self.money_format = :cents
|
21
21
|
self.supported_cardtypes = [:visa, :master, :maestro]
|
22
22
|
|
23
|
+
RESPONSE_MESSAGES = {
|
24
|
+
"00" => "Approved or completed successfully",
|
25
|
+
"01" => "Refer to card issuer",
|
26
|
+
"02" => "Refer to card issuer special condition",
|
27
|
+
"03" => "Invalid merchant",
|
28
|
+
"04" => "Pick up card",
|
29
|
+
"05" => "Do not Honour",
|
30
|
+
"06" => "Invalid Transaction for Terminal",
|
31
|
+
"07" => "Pick up card special condition",
|
32
|
+
"08" => "Time-Out",
|
33
|
+
"09" => "No Original",
|
34
|
+
"10" => "Approved for partial amount",
|
35
|
+
"11" => "Partial Approval",
|
36
|
+
"12" => "Invalid transaction card / issuer / acquirer",
|
37
|
+
"13" => "Invalid amount",
|
38
|
+
"14" => "Invalid card number",
|
39
|
+
"17" => "Invalid Capture date (terminal business date)",
|
40
|
+
"19" => "System Error; Re-enter transaction",
|
41
|
+
"20" => "No From Account",
|
42
|
+
"21" => "No To Account",
|
43
|
+
"22" => "No Checking Account",
|
44
|
+
"23" => "No Saving Account",
|
45
|
+
"24" => "No Credit Account",
|
46
|
+
"30" => "Format error",
|
47
|
+
"34" => "Implausible card data",
|
48
|
+
"39" => "Transaction Not Allowed",
|
49
|
+
"41" => "Lost Card, Pickup",
|
50
|
+
"42" => "Special Pickup",
|
51
|
+
"43" => "Hot Card, Pickup (if possible)",
|
52
|
+
"44" => "Pickup Card",
|
53
|
+
"51" => "Not sufficient funds",
|
54
|
+
"52" => "No checking Account",
|
55
|
+
"53" => "No savings account",
|
56
|
+
"54" => "Expired card",
|
57
|
+
"55" => "Pin incorrect",
|
58
|
+
"57" => "Transaction not allowed for cardholder",
|
59
|
+
"58" => "Transaction not allowed for merchant",
|
60
|
+
"59" => "Suspected Fraud",
|
61
|
+
"61" => "Exceeds withdrawal amount limit",
|
62
|
+
"62" => "Restricted card",
|
63
|
+
"63" => "MAC Key Error",
|
64
|
+
"65" => "Activity count limit exceeded",
|
65
|
+
"66" => "Exceeds Acquirer Limit",
|
66
|
+
"67" => "Retain Card; no reason specified",
|
67
|
+
"68" => "Response received too late",
|
68
|
+
"75" => "Pin tries exceeded",
|
69
|
+
"76" => "Invalid Account",
|
70
|
+
"77" => "Issuer Does Not Participate In The Service",
|
71
|
+
"78" => "Function Not Available",
|
72
|
+
"79" => "Key Validation Error",
|
73
|
+
"80" => "Approval for Purchase Amount Only",
|
74
|
+
"81" => "Unable to Verify PIN",
|
75
|
+
"82" => "Time out at issuer system",
|
76
|
+
"83" => "Not declined (Valid for all zero amount transactions)",
|
77
|
+
"84" => "Invalid Life Cycle of transaction",
|
78
|
+
"85" => "Not declined",
|
79
|
+
"86" => "Cannot verify pin",
|
80
|
+
"87" => "Purchase amount only, no cashback allowed",
|
81
|
+
"88" => "MAC sync Error",
|
82
|
+
"89" => "Security Violation",
|
83
|
+
"91" => "Issuer not available",
|
84
|
+
"92" => "Unable to route at acquirer Module",
|
85
|
+
"93" => "Transaction cannot be completed",
|
86
|
+
"94" => "Duplicate transaction",
|
87
|
+
"95" => "Contact Acquirer",
|
88
|
+
"96" => "System malfunction",
|
89
|
+
"97" => "No Funds Transfer",
|
90
|
+
"98" => "Duplicate Reversal",
|
91
|
+
"99" => "Duplicate Transaction",
|
92
|
+
"N3" => "Cash Service Not Available",
|
93
|
+
"N4" => "Cash Back Request Exceeds Issuer Limit",
|
94
|
+
"N7" => "N7 (visa), Decline CVV2 failure",
|
95
|
+
"R0" => "Stop Payment Order",
|
96
|
+
"R1" => "Revocation of Authorisation Order",
|
97
|
+
"R3" => "Revocation of all Authorisations Order"
|
98
|
+
}
|
99
|
+
|
23
100
|
def initialize(options={})
|
24
101
|
requires!(options, :merchant_id, :cipher_key)
|
25
102
|
super
|
@@ -225,7 +302,7 @@ module ActiveMerchant #:nodoc:
|
|
225
302
|
if success_from(response)
|
226
303
|
"Succeeded"
|
227
304
|
else
|
228
|
-
response["Z3"] || "Unable to read error message"
|
305
|
+
RESPONSE_MESSAGES[response["Z6"]] || response["Z3"] || "Unable to read error message"
|
229
306
|
end
|
230
307
|
end
|
231
308
|
end
|
@@ -0,0 +1,292 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class DigitzsGateway < Gateway
|
4
|
+
include Empty
|
5
|
+
|
6
|
+
self.test_url = 'https://beta.digitzsapi.com/sandbox'
|
7
|
+
self.live_url = 'https://beta.digitzsapi.com/v3'
|
8
|
+
|
9
|
+
self.supported_countries = ['US']
|
10
|
+
self.default_currency = 'USD'
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
12
|
+
self.money_format = :cents
|
13
|
+
|
14
|
+
self.homepage_url = 'https://digitzs.com'
|
15
|
+
self.display_name = 'Digitzs'
|
16
|
+
|
17
|
+
def initialize(options={})
|
18
|
+
requires!(options, :app_key, :api_key)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def purchase(money, payment, options={})
|
23
|
+
MultiResponse.run do |r|
|
24
|
+
r.process { commit("auth/token", app_token_request(options)) }
|
25
|
+
r.process { commit('payments', purchase_request(money, payment, options), options.merge({ app_token: app_token_from(r) })) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def refund(money, authorization, options={})
|
30
|
+
MultiResponse.run do |r|
|
31
|
+
r.process { commit("auth/token", app_token_request(options)) }
|
32
|
+
r.process { commit('payments', refund_request(money, authorization, options), options.merge({ app_token: app_token_from(r) })) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def store(payment, options = {})
|
37
|
+
MultiResponse.run do |r|
|
38
|
+
r.process { commit("auth/token", app_token_request(options)) }
|
39
|
+
options.merge!({ app_token: app_token_from(r) })
|
40
|
+
|
41
|
+
if options[:customer_id].present?
|
42
|
+
customer_id = check_customer_exists(options)
|
43
|
+
|
44
|
+
if customer_id
|
45
|
+
r.process { add_credit_card_to_customer(payment, options) }
|
46
|
+
else
|
47
|
+
r.process { add_customer_with_credit_card(payment, options) }
|
48
|
+
end
|
49
|
+
else
|
50
|
+
r.process { add_customer_with_credit_card(payment, options) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def supports_scrubbing?
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def scrub(transcript)
|
60
|
+
transcript.
|
61
|
+
gsub(%r((Authorization: Bearer ).+), '\1[FILTERED]').
|
62
|
+
gsub(%r((X-Api-Key: )\w+), '\1[FILTERED]').
|
63
|
+
gsub(%r((\"id\\\":\\\").+), '\1[FILTERED]').
|
64
|
+
gsub(%r((\"appKey\\\":\\\").+), '\1[FILTERED]').
|
65
|
+
gsub(%r((\"appToken\\\":\\\").+), '\1[FILTERED]').
|
66
|
+
gsub(%r((\"code\\\":\\\")\d+), '\1[FILTERED]').
|
67
|
+
gsub(%r((\"number\\\":\\\")\d+), '\1[FILTERED]')
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def new_post
|
73
|
+
{
|
74
|
+
data: {
|
75
|
+
attributes: {}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_split(post, options)
|
81
|
+
return unless options[:payment_type] == "card_split" || options[:payment_type] == "token_split"
|
82
|
+
|
83
|
+
post[:data][:attributes][:split] = {
|
84
|
+
merchantId: options[:split_merchant_id],
|
85
|
+
amount: amount(options[:split_amount])
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_payment(post, payment, options)
|
90
|
+
if payment.is_a? String
|
91
|
+
customer_id, token = split_authorization(payment)
|
92
|
+
post[:data][:attributes][:token] = {
|
93
|
+
customerId: customer_id,
|
94
|
+
tokenId: token
|
95
|
+
}
|
96
|
+
else
|
97
|
+
post[:data][:attributes][:card] = {
|
98
|
+
type: payment.brand,
|
99
|
+
holder: payment.name,
|
100
|
+
number: payment.number,
|
101
|
+
expiry: expdate(payment),
|
102
|
+
code: payment.verification_value
|
103
|
+
}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_transaction(post, money, options)
|
108
|
+
post[:data][:attributes][:transaction] = {
|
109
|
+
amount: amount(money),
|
110
|
+
currency: (options[:currency] || currency(money)),
|
111
|
+
invoice: options[:order_id] || generate_unique_id
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def add_address(post, options)
|
116
|
+
if address = options[:billing_address] || options[:address]
|
117
|
+
post[:data][:attributes][:billingAddress] = {
|
118
|
+
line1: address[:address1] || "",
|
119
|
+
line2: address[:address2] || "",
|
120
|
+
city: address[:city] || "",
|
121
|
+
state: address[:state] || "",
|
122
|
+
zip: address[:zip] || "",
|
123
|
+
country: address["country"] || "USA"
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def app_token_request(options)
|
129
|
+
post = new_post
|
130
|
+
post[:data][:type] = "auth"
|
131
|
+
post[:data][:attributes] = { appKey: @options[:app_key] }
|
132
|
+
|
133
|
+
post
|
134
|
+
end
|
135
|
+
|
136
|
+
def purchase_request(money, payment, options)
|
137
|
+
post = new_post
|
138
|
+
post[:data][:type] = "payments"
|
139
|
+
post[:data][:attributes][:merchantId] = options[:merchant_id]
|
140
|
+
post[:data][:attributes][:paymentType] = determine_payment_type(payment, options)
|
141
|
+
add_split(post, options)
|
142
|
+
add_payment(post, payment, options)
|
143
|
+
add_transaction(post, money, options)
|
144
|
+
add_address(post, options)
|
145
|
+
|
146
|
+
post
|
147
|
+
end
|
148
|
+
|
149
|
+
def refund_request(money, authorization, options)
|
150
|
+
post = new_post
|
151
|
+
post[:data][:type] = "payments"
|
152
|
+
post[:data][:attributes][:merchantId] = options[:merchant_id]
|
153
|
+
post[:data][:attributes][:paymentType] = "cardRefund"
|
154
|
+
post[:data][:attributes][:originalTransaction] = {id: authorization}
|
155
|
+
add_transaction(post, money, options)
|
156
|
+
|
157
|
+
post
|
158
|
+
end
|
159
|
+
|
160
|
+
def create_customer_request(payment, options)
|
161
|
+
post = new_post
|
162
|
+
post[:data][:type] = "customers"
|
163
|
+
post[:data][:attributes] = {
|
164
|
+
merchantId: options[:merchant_id],
|
165
|
+
name: payment.name,
|
166
|
+
externalId: "#{SecureRandom.hex(16)}"
|
167
|
+
}
|
168
|
+
|
169
|
+
post
|
170
|
+
end
|
171
|
+
|
172
|
+
def create_token_request(payment, options)
|
173
|
+
post = new_post
|
174
|
+
post[:data][:type] = "tokens"
|
175
|
+
post[:data][:attributes] = {
|
176
|
+
tokenType: "card",
|
177
|
+
customerId: options[:customer_id],
|
178
|
+
label: "Credit Card",
|
179
|
+
}
|
180
|
+
add_payment(post, payment, options)
|
181
|
+
add_address(post, options)
|
182
|
+
|
183
|
+
post
|
184
|
+
end
|
185
|
+
|
186
|
+
def check_customer_exists(options = {})
|
187
|
+
url = (test? ? test_url : live_url)
|
188
|
+
response = parse(ssl_get(url + "/customers/#{options[:customer_id]}", headers(options)))
|
189
|
+
|
190
|
+
return response.try(:[], "data").try(:[], "customerId") if success_from(response)
|
191
|
+
return nil
|
192
|
+
end
|
193
|
+
|
194
|
+
def add_credit_card_to_customer(payment, options = {})
|
195
|
+
commit('tokens', create_token_request(payment, options), options)
|
196
|
+
end
|
197
|
+
|
198
|
+
def add_customer_with_credit_card(payment, options = {})
|
199
|
+
customer_response = commit('customers', create_customer_request(payment, options), options)
|
200
|
+
options.merge!({customer_id: customer_response.authorization})
|
201
|
+
commit('tokens', create_token_request(payment, options), options)
|
202
|
+
end
|
203
|
+
|
204
|
+
def parse(body)
|
205
|
+
JSON.parse(body)
|
206
|
+
end
|
207
|
+
|
208
|
+
def commit(action, parameters, options={})
|
209
|
+
url = (test? ? test_url : live_url)
|
210
|
+
response = parse(ssl_post(url + "/#{action}", parameters.to_json, headers(options)))
|
211
|
+
|
212
|
+
Response.new(
|
213
|
+
success_from(response),
|
214
|
+
message_from(response),
|
215
|
+
response,
|
216
|
+
authorization: authorization_from(response),
|
217
|
+
avs_result: AVSResult.new(code: avs_result_from(response)),
|
218
|
+
cvv_result: CVVResult.new(cvv_result_from(response)),
|
219
|
+
test: test?,
|
220
|
+
error_code: error_code_from(response)
|
221
|
+
)
|
222
|
+
end
|
223
|
+
|
224
|
+
def success_from(response)
|
225
|
+
response["errors"].nil? && response["message"].nil?
|
226
|
+
end
|
227
|
+
|
228
|
+
def message_from(response)
|
229
|
+
return response["message"] if response["message"]
|
230
|
+
return "Success" if success_from(response)
|
231
|
+
response["errors"].map {|error_hash| error_hash["detail"] }.join(", ")
|
232
|
+
end
|
233
|
+
|
234
|
+
def authorization_from(response)
|
235
|
+
if customer_id = response.try(:[], "data").try(:[], "attributes").try(:[], "customerId")
|
236
|
+
"#{customer_id}|#{response.try(:[], "data").try(:[], "id")}"
|
237
|
+
else
|
238
|
+
response.try(:[], "data").try(:[], "id")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def avs_result_from(response)
|
243
|
+
response.try(:[], "data").try(:[], "attributes").try(:[], "transaction").try(:[], "avsResult")
|
244
|
+
end
|
245
|
+
|
246
|
+
def cvv_result_from(response)
|
247
|
+
response.try(:[], "data").try(:[], "attributes").try(:[], "transaction").try(:[], "codeResult")
|
248
|
+
end
|
249
|
+
|
250
|
+
def app_token_from(response)
|
251
|
+
response.params.try(:[], "data").try(:[], "attributes").try(:[], "appToken")
|
252
|
+
end
|
253
|
+
|
254
|
+
def headers(options)
|
255
|
+
headers = {
|
256
|
+
'Content-Type' => 'application/json',
|
257
|
+
'x-api-key' => @options[:api_key]
|
258
|
+
}
|
259
|
+
|
260
|
+
headers.merge!({"Authorization" => "Bearer #{options[:app_token]}"}) if options[:app_token]
|
261
|
+
headers
|
262
|
+
end
|
263
|
+
|
264
|
+
def error_code_from(response)
|
265
|
+
unless success_from(response)
|
266
|
+
response["errors"].nil? ? response["message"] : response["errors"].map {|error_hash| error_hash["code"] }.join(", ")
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def split_authorization(authorization)
|
271
|
+
customer_id, token = authorization.split("|")
|
272
|
+
[customer_id, token]
|
273
|
+
end
|
274
|
+
|
275
|
+
def determine_payment_type(payment, options)
|
276
|
+
return "cardSplit" if options[:payment_type] == "card_split"
|
277
|
+
return "tokenSplit" if options[:payment_type] == "token_split"
|
278
|
+
return "token" if payment.is_a? String
|
279
|
+
"card"
|
280
|
+
end
|
281
|
+
|
282
|
+
def handle_response(response)
|
283
|
+
case response.code.to_i
|
284
|
+
when 200..499
|
285
|
+
response.body
|
286
|
+
else
|
287
|
+
raise ResponseError.new(response)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|