activemerchant 1.26.0 → 1.27.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.
- data/CHANGELOG +17 -0
- data/CONTRIBUTORS +20 -0
- data/README.md +5 -0
- data/lib/active_merchant/billing/base.rb +2 -2
- data/lib/active_merchant/billing/gateway.rb +6 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +0 -3
- data/lib/active_merchant/billing/gateways/balanced.rb +462 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +3 -3
- data/lib/active_merchant/billing/gateways/beanstream.rb +1 -1
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -2
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +1 -1
- data/lib/active_merchant/billing/gateways/braintree.rb +2 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -1
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +2 -4
- data/lib/active_merchant/billing/gateways/card_stream.rb +2 -2
- data/lib/active_merchant/billing/gateways/certo_direct.rb +2 -3
- data/lib/active_merchant/billing/gateways/cyber_source.rb +3 -3
- data/lib/active_merchant/billing/gateways/data_cash.rb +3 -3
- data/lib/active_merchant/billing/gateways/efsnet.rb +3 -3
- data/lib/active_merchant/billing/gateways/epay.rb +3 -3
- data/lib/active_merchant/billing/gateways/eway.rb +8 -7
- data/lib/active_merchant/billing/gateways/eway_managed.rb +3 -3
- data/lib/active_merchant/billing/gateways/exact.rb +2 -2
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +4 -4
- data/lib/active_merchant/billing/gateways/federated_canada.rb +2 -2
- data/lib/active_merchant/billing/gateways/first_pay.rb +3 -3
- data/lib/active_merchant/billing/gateways/garanti.rb +2 -2
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +3 -1
- data/lib/active_merchant/billing/gateways/inspire.rb +2 -2
- data/lib/active_merchant/billing/gateways/instapay.rb +2 -2
- data/lib/active_merchant/billing/gateways/iridium.rb +4 -5
- data/lib/active_merchant/billing/gateways/itransact.rb +2 -2
- data/lib/active_merchant/billing/gateways/jetpay.rb +3 -3
- data/lib/active_merchant/billing/gateways/linkpoint.rb +3 -6
- data/lib/active_merchant/billing/gateways/litle.rb +50 -34
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +3 -3
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +2 -2
- data/lib/active_merchant/billing/gateways/migs.rb +8 -4
- data/lib/active_merchant/billing/gateways/modern_payments.rb +2 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +4 -4
- data/lib/active_merchant/billing/gateways/moneris.rb +3 -3
- data/lib/active_merchant/billing/gateways/moneris_us.rb +3 -3
- data/lib/active_merchant/billing/gateways/nab_transact.rb +8 -6
- data/lib/active_merchant/billing/gateways/net_registry.rb +2 -2
- data/lib/active_merchant/billing/gateways/netaxept.rb +4 -4
- data/lib/active_merchant/billing/gateways/netbilling.rb +2 -2
- data/lib/active_merchant/billing/gateways/ogone.rb +10 -5
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +3 -3
- data/lib/active_merchant/billing/gateways/orbital.rb +4 -4
- data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +2 -2
- data/lib/active_merchant/billing/gateways/pay_secure.rb +2 -2
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +7 -5
- data/lib/active_merchant/billing/gateways/payflow.rb +39 -37
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +4 -3
- data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +98 -85
- data/lib/active_merchant/billing/gateways/paystation.rb +2 -2
- data/lib/active_merchant/billing/gateways/payway.rb +3 -2
- data/lib/active_merchant/billing/gateways/plugnpay.rb +63 -66
- data/lib/active_merchant/billing/gateways/psigate.rb +3 -3
- data/lib/active_merchant/billing/gateways/psl_card.rb +3 -3
- data/lib/active_merchant/billing/gateways/quantum.rb +2 -2
- data/lib/active_merchant/billing/gateways/quickpay.rb +2 -2
- data/lib/active_merchant/billing/gateways/realex.rb +7 -7
- data/lib/active_merchant/billing/gateways/sage.rb +2 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +1 -1
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +2 -3
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +1 -1
- data/lib/active_merchant/billing/gateways/sage_pay.rb +8 -6
- data/lib/active_merchant/billing/gateways/sallie_mae.rb +2 -2
- data/lib/active_merchant/billing/gateways/secure_net.rb +4 -4
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +9 -6
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +2 -2
- data/lib/active_merchant/billing/gateways/skip_jack.rb +3 -3
- data/lib/active_merchant/billing/gateways/smart_ps.rb +3 -1
- data/lib/active_merchant/billing/gateways/stripe.rb +2 -2
- data/lib/active_merchant/billing/gateways/trans_first.rb +2 -2
- data/lib/active_merchant/billing/gateways/transax.rb +1 -3
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +3 -3
- data/lib/active_merchant/billing/gateways/usa_epay.rb +2 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +3 -2
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -6
- data/lib/active_merchant/billing/gateways/verifi.rb +2 -2
- data/lib/active_merchant/billing/gateways/wirecard.rb +4 -4
- data/lib/active_merchant/billing/gateways/worldpay.rb +37 -18
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +6 -5
- data/lib/active_merchant/billing/integrations/first_data.rb +38 -0
- data/lib/active_merchant/billing/integrations/first_data/helper.rb +63 -0
- data/lib/active_merchant/billing/integrations/first_data/notification.rb +56 -0
- data/lib/active_merchant/billing/integrations/helper.rb +4 -0
- data/lib/active_merchant/billing/integrations/maksuturva.rb +86 -0
- data/lib/active_merchant/billing/integrations/maksuturva/helper.rb +119 -0
- data/lib/active_merchant/billing/integrations/maksuturva/notification.rb +48 -0
- data/lib/active_merchant/billing/integrations/paxum.rb +44 -0
- data/lib/active_merchant/billing/integrations/paxum/common.rb +24 -0
- data/lib/active_merchant/billing/integrations/paxum/helper.rb +42 -0
- data/lib/active_merchant/billing/integrations/paxum/notification.rb +33 -0
- data/lib/active_merchant/billing/integrations/pxpay.rb +31 -0
- data/lib/active_merchant/billing/integrations/pxpay/helper.rb +110 -0
- data/lib/active_merchant/billing/integrations/pxpay/notification.rb +157 -0
- data/lib/active_merchant/billing/integrations/pxpay/return.rb +25 -0
- data/lib/active_merchant/billing/integrations/web_pay.rb +45 -0
- data/lib/active_merchant/billing/integrations/web_pay/common.rb +50 -0
- data/lib/active_merchant/billing/integrations/web_pay/helper.rb +68 -0
- data/lib/active_merchant/billing/integrations/web_pay/notification.rb +51 -0
- data/lib/active_merchant/version.rb +1 -1
- data/lib/support/gateway_support.rb +9 -2
- data/lib/support/ssl_verify.rb +93 -0
- metadata +45 -71
- data.tar.gz.sig +0 -3
- metadata.gz.sig +0 -0
data/CHANGELOG
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
|
2
2
|
|
|
3
|
+
== Version 1.27.0 (August 10, 2012)
|
|
4
|
+
|
|
5
|
+
* Add First Data integration [courtland]
|
|
6
|
+
* Add WebPay integration [nashby]
|
|
7
|
+
* Add Suomen Maksuturva integration [akonan]
|
|
8
|
+
* Payway gateway: Fix card storage [BenZhang]
|
|
9
|
+
* Payflow Pro gateway: Add MaxFailPayments support [gregwinn]
|
|
10
|
+
* Add Paxum integration [Mehonoshin]
|
|
11
|
+
* Add Balanced gateway [mjallday]
|
|
12
|
+
* Plug'n Pay gateway: Add tests for partial capture [csaunders]
|
|
13
|
+
* Braintree Blue gateway: Add credit card details to responses [dougbradbury]
|
|
14
|
+
* PayPal gateway: Support for 'Full' refund type [kurenn]
|
|
15
|
+
* Worldpay: fix refund [jduff/omh]
|
|
16
|
+
* Add PxPay offsite integration [boourns]
|
|
17
|
+
* Wirecard: always capture 'authorization' transaction [ntalbott]
|
|
18
|
+
* Add rake task to verify ssl certs [boourns]
|
|
19
|
+
|
|
3
20
|
== Version 1.26.0 (July 6, 2012)
|
|
4
21
|
|
|
5
22
|
* Orbital gateway: fix broken requests by ensuring the order of XML elements matches their DTD [Soleone]
|
data/CONTRIBUTORS
CHANGED
|
@@ -325,3 +325,23 @@ PayGateXML gateway (July 2012)
|
|
|
325
325
|
PayWay gateway (July 2012)
|
|
326
326
|
|
|
327
327
|
* Ben Zhang (BenZhang)
|
|
328
|
+
|
|
329
|
+
First Data integration (July 2012)
|
|
330
|
+
|
|
331
|
+
* Nick Rogers (courtland)
|
|
332
|
+
|
|
333
|
+
WebPay integration (July 2012)
|
|
334
|
+
|
|
335
|
+
* Vasiliy Ermolovich (nashby)
|
|
336
|
+
|
|
337
|
+
Suomen Maksuturva integration (July 2012)
|
|
338
|
+
|
|
339
|
+
* Antti Akonniemi (akonan)
|
|
340
|
+
|
|
341
|
+
Paxum integration (July 2012)
|
|
342
|
+
|
|
343
|
+
* Stanislav Mekhonoshin (Mehonoshin)
|
|
344
|
+
|
|
345
|
+
Balanced gateway (July 2012)
|
|
346
|
+
|
|
347
|
+
* Marshall Jones (mjallday)
|
data/README.md
CHANGED
|
@@ -86,6 +86,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
|
86
86
|
|
|
87
87
|
* [Authorize.Net](http://www.authorize.net/) - US
|
|
88
88
|
* [Authorize.Net CIM](http://www.authorize.net/) - US
|
|
89
|
+
* [Balanced](https://www.balancedpayments.com/) - US
|
|
89
90
|
* [Barclays ePDQ](http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/) - UK
|
|
90
91
|
* [Beanstream.com](http://www.beanstream.com/) - CA
|
|
91
92
|
* [BluePay](http://www.bluepay.com/) - US
|
|
@@ -174,14 +175,18 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
|
174
175
|
* [Dotpay](http://dotpay.pl)
|
|
175
176
|
* [Dwolla](https://www.dwolla.com/default.aspx)
|
|
176
177
|
* [ePay](http://www.epay.dk/epay-payment-solutions/)
|
|
178
|
+
* [First Data](https://firstdata.zendesk.com/entries/407522-first-data-global-gateway-e4sm-payment-pages-integration-manual)
|
|
177
179
|
* [HiTRUST](http://www.hitrust.com.hk/)
|
|
178
180
|
* [Moneybookers](http://www.moneybookers.com)
|
|
179
181
|
* [Nochex](http://www.nochex.com)
|
|
182
|
+
* [Paxum](https://www.paxum.com/)
|
|
180
183
|
* [PayPal Website Payments Standard](https://www.paypal.com/cgi-bin/webscr?cmd#_wp-standard-overview-outside)
|
|
181
184
|
* [Robokassa](http://robokassa.ru/)
|
|
182
185
|
* [SagePay Form](http://www.sagepay.com/products_services/sage_pay_go/integration/form)
|
|
186
|
+
* [Suomen Maksuturva](https://www.maksuturva.fi/services/vendor_services/integration_guidelines.html)
|
|
183
187
|
* [Valitor](http://www.valitor.is/) - IS
|
|
184
188
|
* [Verkkomaksut](http://www.verkkomaksut.fi) - FI
|
|
189
|
+
* [WebPay](http://webpay.by/)
|
|
185
190
|
* [WorldPay](http://www.worldpay.com)
|
|
186
191
|
|
|
187
192
|
## Contributing
|
|
@@ -37,8 +37,8 @@ module ActiveMerchant #:nodoc:
|
|
|
37
37
|
# Return the matching integration module
|
|
38
38
|
# You can then get the notification from the module
|
|
39
39
|
# * <tt>bogus</tt>: Bogus - Does nothing (for testing)
|
|
40
|
-
# * <tt>chronopay</tt>: Chronopay
|
|
41
|
-
# * <tt>paypal</tt>:
|
|
40
|
+
# * <tt>chronopay</tt>: Chronopay
|
|
41
|
+
# * <tt>paypal</tt>: Paypal
|
|
42
42
|
#
|
|
43
43
|
# chronopay = ActiveMerchant::Billing::Base.integration('chronopay')
|
|
44
44
|
# notification = chronopay.notification(raw_post)
|
|
@@ -93,6 +93,12 @@ module ActiveMerchant #:nodoc:
|
|
|
93
93
|
class_attribute :homepage_url
|
|
94
94
|
class_attribute :display_name
|
|
95
95
|
|
|
96
|
+
class_attribute :test_url, :live_url
|
|
97
|
+
|
|
98
|
+
class_attribute :abstract_class
|
|
99
|
+
|
|
100
|
+
self.abstract_class = false
|
|
101
|
+
|
|
96
102
|
# The application making the calls to the gateway
|
|
97
103
|
# Useful for things like the PayPal build notation (BN) id fields
|
|
98
104
|
superclass_delegating_accessor :application_id
|
|
@@ -26,7 +26,7 @@ module ActiveMerchant #:nodoc:
|
|
|
26
26
|
class AuthorizeNetGateway < Gateway
|
|
27
27
|
API_VERSION = '3.1'
|
|
28
28
|
|
|
29
|
-
class_attribute :
|
|
29
|
+
class_attribute :arb_test_url, :arb_live_url
|
|
30
30
|
|
|
31
31
|
self.test_url = "https://test.authorize.net/gateway/transact.dll"
|
|
32
32
|
self.live_url = "https://secure.authorize.net/gateway/transact.dll"
|
|
@@ -27,9 +27,6 @@ module ActiveMerchant #:nodoc:
|
|
|
27
27
|
# 4. Type in the answer to the secret question configured on setup
|
|
28
28
|
# 5. Click Submit
|
|
29
29
|
class AuthorizeNetCimGateway < Gateway
|
|
30
|
-
|
|
31
|
-
class_attribute :test_url, :live_url
|
|
32
|
-
|
|
33
30
|
self.test_url = 'https://apitest.authorize.net/xml/v1/request.api'
|
|
34
31
|
self.live_url = 'https://api.authorize.net/xml/v1/request.api'
|
|
35
32
|
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module ActiveMerchant #:nodoc:
|
|
4
|
+
module Billing #:nodoc:
|
|
5
|
+
|
|
6
|
+
# For more information on Balanced visit https://www.balancedpayments.com
|
|
7
|
+
# or visit #balanced on irc.freenode.net
|
|
8
|
+
#
|
|
9
|
+
# Instantiate a instance of BalancedGateway by passing through your
|
|
10
|
+
# Balanced API key secret.
|
|
11
|
+
#
|
|
12
|
+
# ==== To obtain an API key of your own
|
|
13
|
+
#
|
|
14
|
+
# 1. Visit https://www.balancedpayments.com
|
|
15
|
+
# 2. Click "Get started"
|
|
16
|
+
# 3. The next screen will give you a test API key of your own
|
|
17
|
+
# 4. When you're ready to generate a production API key click the "Go
|
|
18
|
+
# live" button on the Balanced dashboard and fill in your marketplace
|
|
19
|
+
# details.
|
|
20
|
+
#
|
|
21
|
+
# ==== Overview
|
|
22
|
+
#
|
|
23
|
+
# Balanced provides a RESTful API, all entities within Balanced are
|
|
24
|
+
# represented by their respective URIs, these are returned in the
|
|
25
|
+
# `authorization` parameter of the Active Merchant Response object.
|
|
26
|
+
#
|
|
27
|
+
# All Response objects will contain a hash property called `params` which
|
|
28
|
+
# holds the raw JSON dictionary returned by Balanced. You can find
|
|
29
|
+
# properties about the operation performed and the object that represents
|
|
30
|
+
# it within this hash.
|
|
31
|
+
#
|
|
32
|
+
# All operations within Balanced are tied to an account, as such, when you
|
|
33
|
+
# perform an `authorization` or a `capture` with a new credit card you
|
|
34
|
+
# must ensure you also pass the `:email` property within the `options`
|
|
35
|
+
# parameter.
|
|
36
|
+
#
|
|
37
|
+
# For more details about Balanced's API visit:
|
|
38
|
+
# https://www.balancedpayments.com/docs
|
|
39
|
+
#
|
|
40
|
+
# ==== Terminology & Transaction Flow
|
|
41
|
+
#
|
|
42
|
+
# * An `authorization` operation will return a Hold URI. An `authorization`
|
|
43
|
+
# within Balanced is valid until the `expires_at` property. You can see the
|
|
44
|
+
# exact date of the expiry on the Response object by inspecting the
|
|
45
|
+
# property `response.params['expires_at']`. The resulting Hold may be
|
|
46
|
+
# `capture`d or `void`ed at any time before the `expires_at` date for
|
|
47
|
+
# any amount up to the full amount of the original `authorization`.
|
|
48
|
+
# * A `capture` operation will return a Debit URI. You must pass the URI of
|
|
49
|
+
# the previously performed `authorization`
|
|
50
|
+
# * A `purchase` will create a Hold and Debit in a single operation and
|
|
51
|
+
# return the URI of the resulting Debit.
|
|
52
|
+
# * A `void` operation must be performed on an existing `authorization`
|
|
53
|
+
# and will result in releasing the funds reserved by the
|
|
54
|
+
# `authorization`.
|
|
55
|
+
# * The `refund` operation must be performed on a previously captured
|
|
56
|
+
# Debit URI. You may refund any fraction of the original amount of the
|
|
57
|
+
# debit up to the original total.
|
|
58
|
+
#
|
|
59
|
+
class BalancedGateway < Gateway
|
|
60
|
+
VERSION = '1.0.0'
|
|
61
|
+
|
|
62
|
+
TEST_URL = LIVE_URL = 'https://api.balancedpayments.com'
|
|
63
|
+
|
|
64
|
+
# The countries the gateway supports merchants from as 2 digit ISO
|
|
65
|
+
# country codes
|
|
66
|
+
self.supported_countries = ['US']
|
|
67
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
|
68
|
+
self.homepage_url = 'https://www.balancedpayments.com/'
|
|
69
|
+
self.display_name = 'Balanced'
|
|
70
|
+
self.money_format = :cents
|
|
71
|
+
|
|
72
|
+
class Error < StandardError
|
|
73
|
+
attr_reader :response
|
|
74
|
+
|
|
75
|
+
def initialize(response, msg=nil)
|
|
76
|
+
@response = response
|
|
77
|
+
super(msg || response['description'])
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class CardDeclined < Error
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Creates a new BalancedGateway
|
|
85
|
+
#
|
|
86
|
+
# The gateway requires that a valid api_key be passed in the +options+
|
|
87
|
+
# hash.
|
|
88
|
+
#
|
|
89
|
+
# ==== Options
|
|
90
|
+
#
|
|
91
|
+
# * <tt>:login</tt> -- The Balanced API Secret (REQUIRED)
|
|
92
|
+
def initialize(options = {})
|
|
93
|
+
requires!(options, :login)
|
|
94
|
+
@options = options
|
|
95
|
+
initialize_marketplace(options[:marketplace] || load_marketplace)
|
|
96
|
+
super
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Performs an authorization (Hold in Balanced nonclementure), which
|
|
100
|
+
# reserves the funds on the customer's credit card, but does not charge
|
|
101
|
+
# the card. An authorization is valid until the `expires_at` field in
|
|
102
|
+
# the params Hash passes. See `response.params['expires_at']`. The exact
|
|
103
|
+
# amount of time until an authorization expires depends on the card
|
|
104
|
+
# issuer.
|
|
105
|
+
#
|
|
106
|
+
# If you pass a previously tokenized `credit_card` URI the only other
|
|
107
|
+
# parameter required is `money`. If you pass `credit_card` as a hash of
|
|
108
|
+
# credit card information you must also pass `options` with a `:email`
|
|
109
|
+
# entry.
|
|
110
|
+
#
|
|
111
|
+
# ==== Parameters
|
|
112
|
+
#
|
|
113
|
+
# * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
|
|
114
|
+
# * <tt>credit_card</tt> -- A hash of credit card details for this
|
|
115
|
+
# transaction or the URI of a card previously stored in Balanced.
|
|
116
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
|
117
|
+
#
|
|
118
|
+
# ==== Options
|
|
119
|
+
#
|
|
120
|
+
# If you are passing a new credit card you must pass one of these two
|
|
121
|
+
# parameters
|
|
122
|
+
#
|
|
123
|
+
# * <tt>email</tt> -- the email address of user associated with this
|
|
124
|
+
# purchase.
|
|
125
|
+
# * <tt>account_uri</tt> -- `account_uri` is the URI of an existing
|
|
126
|
+
# Balanced account.
|
|
127
|
+
def authorize(money, credit_card, options = {})
|
|
128
|
+
if credit_card.respond_to?(:number)
|
|
129
|
+
requires!(options, :email) unless options[:account_uri]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
post = {}
|
|
133
|
+
post[:amount] = money
|
|
134
|
+
post[:description] = options[:description]
|
|
135
|
+
|
|
136
|
+
create_or_find_account(post, options)
|
|
137
|
+
add_credit_card(post, credit_card, options)
|
|
138
|
+
add_address(credit_card, options)
|
|
139
|
+
|
|
140
|
+
create_transaction(:post, @holds_uri, post)
|
|
141
|
+
rescue Error => ex
|
|
142
|
+
failed_response(ex.response)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Perform a purchase, which is an authorization and capture in a single
|
|
146
|
+
# operation.
|
|
147
|
+
#
|
|
148
|
+
# ==== Parameters
|
|
149
|
+
#
|
|
150
|
+
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
|
151
|
+
# * <tt>credit_card</tt> -- A hash of credit card details for this
|
|
152
|
+
# transaction or the URI of a card previously stored in Balanced.
|
|
153
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
|
154
|
+
#
|
|
155
|
+
# ==== Options
|
|
156
|
+
#
|
|
157
|
+
# If you are passing a new credit card you must pass one of these two
|
|
158
|
+
# parameters
|
|
159
|
+
#
|
|
160
|
+
# * <tt>email</tt> -- the email address of user associated with this
|
|
161
|
+
# purchase.
|
|
162
|
+
# * <tt>account_uri</tt> -- `account_uri` is the URI of an existing
|
|
163
|
+
# Balanced account.
|
|
164
|
+
def purchase(money, credit_card, options = {})
|
|
165
|
+
if credit_card.respond_to?('number')
|
|
166
|
+
requires!(options, :email) unless options[:account_uri]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
post = {}
|
|
170
|
+
post[:amount] = money
|
|
171
|
+
post[:description] = options[:description]
|
|
172
|
+
|
|
173
|
+
create_or_find_account(post, options)
|
|
174
|
+
add_credit_card(post, credit_card, options)
|
|
175
|
+
add_address(credit_card, options)
|
|
176
|
+
|
|
177
|
+
create_transaction(:post, @debits_uri, post)
|
|
178
|
+
rescue Error => ex
|
|
179
|
+
failed_response(ex.response)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Captures the funds from an authorized transaction (Hold).
|
|
183
|
+
#
|
|
184
|
+
# ==== Parameters
|
|
185
|
+
#
|
|
186
|
+
# * <tt>money</tt> -- The amount to be captured as an Integer value in
|
|
187
|
+
# cents. If omitted the full amount of the original authorization
|
|
188
|
+
# transaction will be captured.
|
|
189
|
+
# * <tt>authorization</tt> -- The uri of an authorization returned from
|
|
190
|
+
# an authorize request.
|
|
191
|
+
#
|
|
192
|
+
# ==== Options
|
|
193
|
+
#
|
|
194
|
+
# * <tt>description</tt> -- A string that will be displayed on the
|
|
195
|
+
# Balanced dashboard
|
|
196
|
+
def capture(money, authorization, options = {})
|
|
197
|
+
post = {}
|
|
198
|
+
post[:hold_uri] = authorization
|
|
199
|
+
post[:amount] = money if money
|
|
200
|
+
post[:description] = options[:description] if options[:description]
|
|
201
|
+
|
|
202
|
+
create_transaction(:post, @debits_uri, post)
|
|
203
|
+
rescue Error => ex
|
|
204
|
+
failed_response(ex.response)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Void a previous authorization (Hold)
|
|
208
|
+
#
|
|
209
|
+
# ==== Parameters
|
|
210
|
+
#
|
|
211
|
+
# * <tt>authorization</tt> -- The uri of the authorization returned from
|
|
212
|
+
# an `authorize` request.
|
|
213
|
+
def void(authorization)
|
|
214
|
+
post = {}
|
|
215
|
+
post[:is_void] = true
|
|
216
|
+
|
|
217
|
+
create_transaction(:put, authorization, post)
|
|
218
|
+
rescue Error => ex
|
|
219
|
+
failed_response(ex.response)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Refund a transaction.
|
|
223
|
+
#
|
|
224
|
+
# Returns the money debited from a card to the card from the
|
|
225
|
+
# marketplace's escrow balance.
|
|
226
|
+
#
|
|
227
|
+
# ==== Parameters
|
|
228
|
+
#
|
|
229
|
+
# * <tt>debit_uri</tt> -- The uri of the original transaction against
|
|
230
|
+
# which the refund is being issued.
|
|
231
|
+
# * <tt>options</tt> -- A hash of parameters.
|
|
232
|
+
#
|
|
233
|
+
# ==== Options
|
|
234
|
+
#
|
|
235
|
+
# * <tt>`:amount`<tt> -- specify an amount if you want to perform a
|
|
236
|
+
# partial refund. This value will default to the total amount of the
|
|
237
|
+
# debit that has not been refunded so far.
|
|
238
|
+
def refund(debit_uri, options = {})
|
|
239
|
+
requires!(debit_uri)
|
|
240
|
+
post = {}
|
|
241
|
+
post[:debit_uri] = debit_uri
|
|
242
|
+
post[:amount] = options[:amount] if options[:amount]
|
|
243
|
+
post[:description] = options[:description]
|
|
244
|
+
create_transaction(:post, @refunds_uri, post)
|
|
245
|
+
rescue Error => ex
|
|
246
|
+
failed_response(ex.response)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Stores a card and email address
|
|
250
|
+
#
|
|
251
|
+
# ==== Parameters
|
|
252
|
+
#
|
|
253
|
+
# * <tt>credit_card</tt> --
|
|
254
|
+
def store(credit_card, options = {})
|
|
255
|
+
requires!(options, :email)
|
|
256
|
+
post = {}
|
|
257
|
+
account_uri = create_or_find_account(post, options)
|
|
258
|
+
if credit_card.respond_to? :number
|
|
259
|
+
add_credit_card(post, credit_card, options)
|
|
260
|
+
else
|
|
261
|
+
associate_card_to_account(account_uri, credit_card)
|
|
262
|
+
credit_card
|
|
263
|
+
end
|
|
264
|
+
rescue Error => ex
|
|
265
|
+
failed_response(ex.response)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
private
|
|
269
|
+
|
|
270
|
+
# Load URIs for this marketplace by inspecting the marketplace object
|
|
271
|
+
# returned from the uri. http://en.wikipedia.org/wiki/HATEOAS
|
|
272
|
+
def load_marketplace
|
|
273
|
+
response = http_request(:get, '/v1/marketplaces')
|
|
274
|
+
if error?(response)
|
|
275
|
+
raise Error.new(response, 'Invalid login credentials supplied')
|
|
276
|
+
end
|
|
277
|
+
response['items'][0]
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def initialize_marketplace(marketplace)
|
|
281
|
+
@marketplace_uri = marketplace['uri']
|
|
282
|
+
@holds_uri = marketplace['holds_uri']
|
|
283
|
+
@debits_uri = marketplace['debits_uri']
|
|
284
|
+
@cards_uri = marketplace['cards_uri']
|
|
285
|
+
@accounts_uri = marketplace['accounts_uri']
|
|
286
|
+
@refunds_uri = marketplace['refunds_uri']
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def create_or_find_account(post, options)
|
|
290
|
+
account_uri = nil
|
|
291
|
+
|
|
292
|
+
if options.has_key? :account_uri
|
|
293
|
+
account_uri = options[:account_uri]
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
if account_uri == nil
|
|
297
|
+
post[:email_address] = options[:email]
|
|
298
|
+
|
|
299
|
+
# create an account
|
|
300
|
+
response = http_request(:post, @accounts_uri, post)
|
|
301
|
+
|
|
302
|
+
if response.has_key? 'uri'
|
|
303
|
+
account_uri = response['uri']
|
|
304
|
+
elsif error?(response)
|
|
305
|
+
# lookup account from Balanced, account_uri should be in the
|
|
306
|
+
# exception in a dictionary called extras
|
|
307
|
+
account_uri = response['extras']['account_uri']
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
post[:account_uri] = account_uri
|
|
312
|
+
|
|
313
|
+
account_uri
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def add_address(credit_card, options)
|
|
317
|
+
return unless credit_card.kind_of?(Hash)
|
|
318
|
+
if address = options[:billing_address] || options[:address]
|
|
319
|
+
credit_card[:street_address] = address[:address1] if address[:address1]
|
|
320
|
+
credit_card[:street_address] += ' ' + address[:address2] if address[:address2]
|
|
321
|
+
credit_card[:postal_code] = address[:zip] if address[:zip]
|
|
322
|
+
credit_card[:country] = address[:country] if address[:country]
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def add_credit_card(post, credit_card, options)
|
|
327
|
+
if credit_card.respond_to? :number
|
|
328
|
+
card = {}
|
|
329
|
+
card[:card_number] = credit_card.number
|
|
330
|
+
card[:expiration_month] = credit_card.month
|
|
331
|
+
card[:expiration_year] = credit_card.year
|
|
332
|
+
card[:security_code] = credit_card.verification_value if credit_card.verification_value?
|
|
333
|
+
card[:name] = credit_card.name if credit_card.name
|
|
334
|
+
|
|
335
|
+
add_address(card, options)
|
|
336
|
+
|
|
337
|
+
response = http_request(:post, @cards_uri, card)
|
|
338
|
+
if error?(response)
|
|
339
|
+
raise CardDeclined, response
|
|
340
|
+
end
|
|
341
|
+
card_uri = response['uri']
|
|
342
|
+
|
|
343
|
+
associate_card_to_account(post[:account_uri], card_uri)
|
|
344
|
+
|
|
345
|
+
post[:card_uri] = card_uri
|
|
346
|
+
elsif credit_card.kind_of?(String)
|
|
347
|
+
post[:card_uri] = credit_card
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
post[:card_uri]
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def associate_card_to_account(account_uri, card_uri)
|
|
354
|
+
http_request(:put, account_uri, :card_uri => card_uri)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def http_request(method, url, parameters={}, meta={})
|
|
358
|
+
begin
|
|
359
|
+
if method == :get
|
|
360
|
+
raw_response = ssl_get(LIVE_URL + url, headers(meta))
|
|
361
|
+
else
|
|
362
|
+
raw_response = ssl_request(method,
|
|
363
|
+
LIVE_URL + url,
|
|
364
|
+
post_data(parameters),
|
|
365
|
+
headers(meta))
|
|
366
|
+
end
|
|
367
|
+
parse(raw_response)
|
|
368
|
+
rescue ResponseError => e
|
|
369
|
+
raw_response = e.response.body
|
|
370
|
+
response_error(raw_response)
|
|
371
|
+
rescue JSON::ParserError
|
|
372
|
+
json_error(raw_response)
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def create_transaction(method, url, parameters, meta={})
|
|
377
|
+
response = http_request(method, url, parameters, meta)
|
|
378
|
+
success = !error?(response)
|
|
379
|
+
|
|
380
|
+
Response.new(success,
|
|
381
|
+
(success ? "Transaction approved" : response["description"]),
|
|
382
|
+
response,
|
|
383
|
+
:test => (@marketplace_uri.index("TEST") ? true : false),
|
|
384
|
+
:authorization => response["uri"]
|
|
385
|
+
)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def failed_response(response)
|
|
389
|
+
is_test = false
|
|
390
|
+
if @marketplace_uri
|
|
391
|
+
is_test = (@marketplace_uri.index("TEST") ? true : false)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
Response.new(false,
|
|
395
|
+
response["description"],
|
|
396
|
+
response,
|
|
397
|
+
:test => is_test
|
|
398
|
+
)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def parse(body)
|
|
402
|
+
JSON.parse(body)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def response_error(raw_response)
|
|
406
|
+
begin
|
|
407
|
+
parse(raw_response)
|
|
408
|
+
rescue JSON::ParserError
|
|
409
|
+
json_error(raw_response)
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def json_error(raw_response)
|
|
414
|
+
msg = 'Invalid response received from the Balanced API. Please contact support@balancedpayments.com if you continue to receive this message.'
|
|
415
|
+
msg += " (The raw response returned by the API was #{raw_response.inspect})"
|
|
416
|
+
{
|
|
417
|
+
"error" => {
|
|
418
|
+
"message" => msg
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def error?(response)
|
|
424
|
+
response.key?('status_code')
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def post_data(params)
|
|
428
|
+
return nil unless params
|
|
429
|
+
|
|
430
|
+
params.map do |key, value|
|
|
431
|
+
next if value.blank?
|
|
432
|
+
if value.is_a?(Hash)
|
|
433
|
+
h = {}
|
|
434
|
+
value.each do |k, v|
|
|
435
|
+
h["#{key}[#{k}]"] = v unless v.blank?
|
|
436
|
+
end
|
|
437
|
+
post_data(h)
|
|
438
|
+
else
|
|
439
|
+
"#{key}=#{CGI.escape(value.to_s)}"
|
|
440
|
+
end
|
|
441
|
+
end.compact.join("&")
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def headers(meta={})
|
|
445
|
+
@@ua ||= JSON.dump({
|
|
446
|
+
:bindings_version => ActiveMerchant::VERSION,
|
|
447
|
+
:lang => 'ruby',
|
|
448
|
+
:lang_version => "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})",
|
|
449
|
+
:lib_version => BalancedGateway::VERSION,
|
|
450
|
+
:platform => RUBY_PLATFORM,
|
|
451
|
+
:publisher => 'active_merchant'
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
{
|
|
455
|
+
"Authorization" => "Basic " + Base64.encode64(@options[:login].to_s + ":").strip,
|
|
456
|
+
"User-Agent" => "Balanced/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
|
|
457
|
+
"X-Balanced-User-Agent" => @@ua,
|
|
458
|
+
}
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
end
|