Class: ActiveMerchant::Billing::SquareGateway
- Inherits:
-
Gateway
- Object
- Gateway
- ActiveMerchant::Billing::SquareGateway
- Defined in:
- lib/active_merchant/billing/gateways/square.rb
Constant Summary collapse
- STANDARD_ERROR_CODE_MAPPING =
Map to Square’s error codes: docs.connect.squareup.com/api/connect/v2/#handlingerrors
{ 'INVALID_CARD' => STANDARD_ERROR_CODE[:invalid_number], 'INVALID_EXPIRATION' => STANDARD_ERROR_CODE[:invalid_expiry_date], 'INVALID_EXPIRATION_DATE' => STANDARD_ERROR_CODE[:invalid_expiry_date], 'INVALID_EXPIRATION_YEAR' => STANDARD_ERROR_CODE[:invalid_expiry_date], # Something invalid in the card, e.g. verify declined when linking card to customer. 'INVALID_CARD_DATA' => STANDARD_ERROR_CODE[:processing_error], 'CARD_EXPIRED' => STANDARD_ERROR_CODE[:expired_card], 'VERIFY_CVV_FAILURE' => STANDARD_ERROR_CODE[:incorrect_cvc], 'VERIFY_AVS_FAILURE' => STANDARD_ERROR_CODE[:incorrect_zip], 'CARD_DECLINED' => STANDARD_ERROR_CODE[:card_declined], 'UNAUTHORIZED' => STANDARD_ERROR_CODE[:config_error] }
Instance Method Summary collapse
-
#authorize(money, card_nonce, options = {}) ⇒ Object
Authorize for Square uses the Charge with delay_capture = true option.
-
#capture(ignored_money, txn_id, ignored_options = {}) ⇒ Object
Capture is only used if you did an Authorize, (creating a delayed capture).
-
#create_customer(options) ⇒ Object
See also store().
-
#initialize(options = {}) ⇒ SquareGateway
constructor
The ‘login` key is the client_id (also known as application id) in the dev portal.
-
#purchase(money, card_nonce, options = {}) ⇒ Object
To create a charge on a card using a card nonce: purchase(money, card_nonce, { …create transaction options… }).
-
#refund(money, txn_id, options = {}) ⇒ Object
Refund refunds a previously Charged transaction.
- #scrub(transcript) ⇒ Object
-
#store(card_nonce, options = {}) ⇒ Object
Required in options hash one of: a) :customer_id from the Square CreateCustomer endpoint of customer to link to.
-
#supports_scrubbing? ⇒ Boolean
Scrubbing removes the access token from the header and the card_nonce.
-
#unstore(card_id, options = {}, deprecated_options = {}) ⇒ Object
docs.connect.squareup.com/api/connect/v2/#endpoint-deletecustomercard Required options[:id] and ‘card_id’ params.
- #update(customer_id, card_id, options = {}) ⇒ Object
- #update_customer(customer_id, options = {}) ⇒ Object
-
#verify(card_nonce, options = {}) ⇒ Object
Do an Authorize (Charge with delayed capture) and then Void.
-
#void(txn_id, options = {}) ⇒ Object
Void cancels a delayed capture (not-yet-captured) transaction.
Constructor Details
#initialize(options = {}) ⇒ SquareGateway
The ‘login` key is the client_id (also known as application id)
in the dev portal. Get it after you create a new app:
https://connect.squareup.com/apps/
The ‘password` is the access token (personal or OAuth) The `location_id` must be fetched initially
https://docs.connect.squareup.com/articles/processing-payment-rest/
The ‘test` indicates if these credentials are for sandbox or
production (money moving) access
42 43 44 45 46 47 48 49 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 42 def initialize(={}) requires!(, :login, :password, :location_id) @client_id = [:login].strip @bearer_token = [:password].strip @location_id = [:location_id].strip super end |
Instance Method Details
#authorize(money, card_nonce, options = {}) ⇒ Object
Authorize for Square uses the Charge with delay_capture = true option. docs.connect.squareup.com/api/connect/v2/#endpoint-charge Same as with ‘purchase`, pass nil for `card_nonce` if using a customer’s stored card on file.
See purchase for more details for calling this.
124 125 126 127 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 124 def (money, card_nonce, ={}) [:delay_capture] = true purchase(money, card_nonce, ) end |
#capture(ignored_money, txn_id, ignored_options = {}) ⇒ Object
Capture is only used if you did an Authorize, (creating a delayed capture). docs.connect.squareup.com/api/connect/v2/#endpoint-capturetransaction Both ‘money` and `options` are unused. Only a full capture is supported.
132 133 134 135 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 132 def capture(ignored_money, txn_id, ={}) raise ArgumentError('txn_id required') if txn_id.nil? commit(:post, "locations/#{CGI.escape(@location_id)}/transactions/#{CGI.escape(txn_id)}/capture") end |
#create_customer(options) ⇒ Object
See also store(). Options hash takes the keys as defined here: docs.connect.squareup.com/api/connect/v2/#endpoint-createcustomer
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 220 def create_customer() required_one_of = [:email, :email_address, :family_name, :given_name, :company_name, :phone_number] if required_one_of.none?{|k| .key?(k)} raise ArgumentError.new("one of these options keys required:" + " #{required_one_of} but none included.") end MultiResponse.run do |r| post = .slice(*required_one_of - [:email] + [:phone_number, :reference_id, :note, :nickname]) post[:email_address] = [:email] if [:email] post[:note] = [:description] if [:description] add_address(post, , :address) r.process{ commit(:post, 'customers', post) } end end |
#purchase(money, card_nonce, options = {}) ⇒ Object
To create a charge on a card using a card nonce:
purchase(money, card_nonce, { ...create transaction options... })
To create a customer and save a card (via card_nonce) to the customer:
purchase(money, card_nonce, {customer: {...params hash same as in store() method...}, ...})
Note for US and CA, you must have {customer: {billing_address: {zip: 12345}}} which passes AVS to store a card.
Note this always creates a new customer, so it may make a duplicate
customer if this card was associated to another customer previously.
To use a customer’s card on file:
purchase(money, nil, {customer: {id: 'customer-id', card_id: 'card-id'}})
Note this does not update any fields on the customer.
To use a customer, and link a new card to the customer:
purchase(money, card_nonce, {customer: {id: 'customer-id', billing_address: {zip: 12345}})
Note the zip is required to store the new nonce, and it must pass AVS. Note this does not update any other fields on the customer.
As this may make multiple requests, it returns a MultiResponse.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 70 def purchase(money, card_nonce, ={}) raise ArgumentError('money required') if money.nil? if card_nonce.nil? requires!(, :customer) requires!([:customer], :card_id, :id) end if card_nonce && [:customer] && [:customer][:card_id] raise ArgumentError('Cannot call with both card_nonce and' + ' options[:customer][:card_id], choose one.') end post = .slice(:buyer_email_address, :delay_capture, :note, :reference_id) add_idempotency_key(post, ) add_amount(post, money, ) add_address(post, ) post[:reference_id] = [:order_id] if [:order_id] post[:note] = [:description] if [:description] MultiResponse.run do |r| if [:customer] && card_nonce # Since customer was passed in, create customer (if needed) and # store card (always in here). [:customer][:customer_id] = [:customer][:id] if [:customer][:id] # To make store() happy. r.process { store(card_nonce, [:customer]) } # If we just created a customer. if [:customer][:id].nil? [:customer][:id] = r.responses.first.params['customer']['id'] end # We always stored a card, so grab it. [:customer][:card_id] = r.responses.last.params['card']['id'] # Empty the card_nonce, since we now have the card on file. card_nonce = nil # Invariant: we have a customer and a linked card, and our options # hash is correct. end add_payment(post, card_nonce, ) r.process { commit(:post, "locations/#{@location_id}/transactions", post) } end end |
#refund(money, txn_id, options = {}) ⇒ Object
Refund refunds a previously Charged transaction. docs.connect.squareup.com/api/connect/v2/#endpoint-createrefund Options require: ‘tender_id`, and permit `idempotency_key`, `reason`.
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 140 def refund(money, txn_id, ={}) raise ArgumentError('txn_id required') if txn_id.nil? raise ArgumentError('money required') if money.nil? requires!(, :tender_id) post = .slice(:tender_id, :reason) add_idempotency_key(post, ) add_amount(post, money, ) commit(:post, "locations/#{CGI.escape(@location_id)}/transactions/#{CGI.escape(txn_id)}/refund", post) end |
#scrub(transcript) ⇒ Object
246 247 248 249 250 251 252 253 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 246 def scrub(transcript) transcript. gsub(%r((Authorization: Bearer )[^\r\n]+), '\1[FILTERED]'). # Extra [\\]* for test. We do an extra escape in the regex of [\\]* # b/c the remote_square_test.rb seems to double escape the # backslashes before the quote. This ensures tests pass. gsub(%r((\"card_nonce[\\]*\":[\\]*")[^"]+), '\1[FILTERED]') end |
#store(card_nonce, options = {}) ⇒ Object
Required in options hash one of: a) :customer_id from the Square CreateCustomer endpoint of customer to link to.
Required in the US and CA: options[:billing_address][:zip] (AVS must pass to link)
https://docs.connect.squareup.com/api/connect/v2/#endpoint-createcustomercard
b) :email, :family_name, :given_name, :company_name, :phone_number to create a new customer.
Optional: :cardholder_name, :address (to store on customer) Return values (e.g. the card id) are available on the response.params[‘id’]
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 177 def store(card_nonce, = {}) raise ArgumentError('card_nonce required') if card_nonce.nil? raise ArgumentError.new('card_nonce nil but is a required field.') if card_nonce.nil? MultiResponse.run do |r| if !([:customer_id]) r.process { create_customer() } [:customer_id] = r.responses.last.params['customer']['id'] end post = .slice(:cardholder_name, :billing_address) if post[:billing_address].present? post[:billing_address][:postal_code] = post[:billing_address].delete(:zip) end post[:card_nonce] = card_nonce r.process { commit(:post, "customers/#{CGI.escape([:customer_id])}/cards", post) } end end |
#supports_scrubbing? ⇒ Boolean
Scrubbing removes the access token from the header and the card_nonce. Square does not let the merchant ever see PCI data. All payment card data is directly handled on Square’s servers via iframes as described here: docs.connect.squareup.com/articles/adding-payment-form/
242 243 244 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 242 def supports_scrubbing? true end |
#unstore(card_id, options = {}, deprecated_options = {}) ⇒ Object
docs.connect.squareup.com/api/connect/v2/#endpoint-deletecustomercard Required options[:id] and ‘card_id’ params.
210 211 212 213 214 215 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 210 def unstore(card_id, = {}, = {}) raise ArgumentError.new('card_id nil but is a required field.') if card_id.nil? requires!(, :customer) requires!([:customer], :id) commit(:delete, "customers/#{CGI.escape([:customer][:id])}/cards/#{CGI.escape(card_id)}", nil) end |
#update(customer_id, card_id, options = {}) ⇒ Object
195 196 197 198 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 195 def update(customer_id, card_id, = {}) raise Exception.new('Square API does not currently support updating' + ' a given card_id, instead create a new one and delete the old one.') end |
#update_customer(customer_id, options = {}) ⇒ Object
201 202 203 204 205 206 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 201 def update_customer(customer_id, = {}) raise ArgumentError.new('customer_id nil but is a required field.') if customer_id.nil? [:email_address] = [:email] if [:email] [:note] = [:description] if [:description] commit(:put, "customers/#{CGI.escape(customer_id)}", ) end |
#verify(card_nonce, options = {}) ⇒ Object
Do an Authorize (Charge with delayed capture) and then Void. Storing a card with a customer will do a verify, however a direct verification only endpoint is not exposed today (Oct ‘16).
161 162 163 164 165 166 167 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 161 def verify(card_nonce, ={}) raise ArgumentError('card_nonce required') if card_nonce.nil? MultiResponse.run(:use_first_response) do |r| r.process { (100, card_nonce, ) } r.process(:ignore_result) { void(r., ) } end end |
#void(txn_id, options = {}) ⇒ Object
Void cancels a delayed capture (not-yet-captured) transaction. docs.connect.squareup.com/api/connect/v2/#endpoint-voidtransaction
153 154 155 156 |
# File 'lib/active_merchant/billing/gateways/square.rb', line 153 def void(txn_id, ={}) raise ArgumentError('txn_id required') if txn_id.nil? commit(:post, "locations/#{CGI.escape(@location_id)}/transactions/#{CGI.escape(txn_id)}/void") end |