Class: Effective::DeluxeApi
- Inherits:
-
Object
- Object
- Effective::DeluxeApi
- Defined in:
- app/models/effective/deluxe_api.rb
Constant Summary collapse
- SCRUB =
/[^\w\d#,\s]/
Instance Attribute Summary collapse
-
#access_token ⇒ Object
Returns the value of attribute access_token.
-
#client_id ⇒ Object
Returns the value of attribute client_id.
-
#client_secret ⇒ Object
Returns the value of attribute client_secret.
-
#currency ⇒ Object
Returns the value of attribute currency.
-
#environment ⇒ Object
All required.
-
#purchase_response ⇒ Object
Returns the value of attribute purchase_response.
Instance Method Summary collapse
-
#card_info(payment_intent) ⇒ Object
Takes a payment_intent and returns the card info we can store.
-
#create_payment(order, payment_intent) ⇒ Object
Create Payment.
-
#decode_payment_intent_payload(payload) ⇒ Object
Decode the base64 encoded JSON object into a Hash.
-
#generate_payment_intent(card: nil, expiry: nil, cvv: nil, encode: false) ⇒ Object
This is only used for testing.
- #health_check ⇒ Object
- #healthy? ⇒ Boolean
-
#initialize(environment: nil, client_id: nil, client_secret: nil, access_token: nil, currency: nil) ⇒ DeluxeApi
constructor
A new instance of DeluxeApi.
-
#payment ⇒ Object
The response from last create payment request.
-
#purchase!(order, payment_intent) ⇒ Object
After we store a payment intent we can call purchase! immediately or wait till later.
-
#purchase_delayed_orders!(orders) ⇒ Object
Called by rake task.
- #purchase_free!(order) ⇒ Object
- #webhook_subscribe(params) ⇒ Object
- #webhook_test(params) ⇒ Object
- #webhook_unsubscribe(params) ⇒ Object
Constructor Details
#initialize(environment: nil, client_id: nil, client_secret: nil, access_token: nil, currency: nil) ⇒ DeluxeApi
Returns a new instance of DeluxeApi.
18 19 20 21 22 23 24 |
# File 'app/models/effective/deluxe_api.rb', line 18 def initialize(environment: nil, client_id: nil, client_secret: nil, access_token: nil, currency: nil) self.environment = environment || EffectiveOrders.deluxe.fetch(:environment) self.client_id = client_id || EffectiveOrders.deluxe.fetch(:client_id) self.client_secret = client_secret || EffectiveOrders.deluxe.fetch(:client_secret) self.access_token = access_token || EffectiveOrders.deluxe.fetch(:access_token) self.currency = currency || EffectiveOrders.deluxe.fetch(:currency) end |
Instance Attribute Details
#access_token ⇒ Object
Returns the value of attribute access_token.
13 14 15 |
# File 'app/models/effective/deluxe_api.rb', line 13 def access_token @access_token end |
#client_id ⇒ Object
Returns the value of attribute client_id.
11 12 13 |
# File 'app/models/effective/deluxe_api.rb', line 11 def client_id @client_id end |
#client_secret ⇒ Object
Returns the value of attribute client_secret.
12 13 14 |
# File 'app/models/effective/deluxe_api.rb', line 12 def client_secret @client_secret end |
#currency ⇒ Object
Returns the value of attribute currency.
14 15 16 |
# File 'app/models/effective/deluxe_api.rb', line 14 def currency @currency end |
#environment ⇒ Object
All required
10 11 12 |
# File 'app/models/effective/deluxe_api.rb', line 10 def environment @environment end |
#purchase_response ⇒ Object
Returns the value of attribute purchase_response.
16 17 18 |
# File 'app/models/effective/deluxe_api.rb', line 16 def purchase_response @purchase_response end |
Instance Method Details
#card_info(payment_intent) ⇒ Object
Takes a payment_intent and returns the card info we can store
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'app/models/effective/deluxe_api.rb', line 53 def card_info(payment_intent) token = extract_token(payment_intent) # Return the authorization params merged with the card info last4 = token['maskedPan'].to_s.last(4) card = token['cardType'].to_s.downcase date = token['expDate'] cvv = token['cvv'] active_card = "**** **** **** #{last4} #{card} #{date}" if last4.present? { 'active_card' => active_card, 'card' => card, 'expDate' => date, 'cvv' => cvv }.compact end |
#create_payment(order, payment_intent) ⇒ Object
Create Payment
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'app/models/effective/deluxe_api.rb', line 101 def create_payment(order, payment_intent) response = post('/payments', params: create_payment_params(order, payment_intent)) # Sanity check response raise('expected responseCode') unless response.kind_of?(Hash) && response['responseCode'].present? # Sanity check response approved vs authorized valid = [0].include?(response['responseCode']) # We might be approved for an amount less than the order total. Not sure what to do here if valid && (amountApproved = response['amountApproved']) != (amountAuthorized = order.total_to_f) raise("expected complete payment amountApproved #{amountApproved} to be the same as the amountAuthorized #{amountAuthorized} but it was not") end # Generate the card info we can store card = card_info(payment_intent) # Return the response merged with the card info response.reverse_merge(card) end |
#decode_payment_intent_payload(payload) ⇒ Object
Decode the base64 encoded JSON object into a Hash
41 42 43 44 45 46 47 48 49 50 |
# File 'app/models/effective/deluxe_api.rb', line 41 def decode_payment_intent_payload(payload) raise('expected a string') unless payload.kind_of?(String) payment_intent = (JSON.parse(Base64.decode64(payload)) rescue nil) raise('expected payment_intent to be a Hash') unless payment_intent.kind_of?(Hash) raise('expected a token payment') unless payment_intent['type'] == 'Token' payment_intent end |
#generate_payment_intent(card: nil, expiry: nil, cvv: nil, encode: false) ⇒ Object
This is only used for testing
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'app/models/effective/deluxe_api.rb', line 183 def generate_payment_intent(card: nil, expiry: nil, cvv: nil, encode: false) card ||= '5555 5555 5555 4444' expiry ||= "12/#{Time.zone.now.year - 1998}" cvv ||= '123' card_info = { expiry: expiry, cvv: cvv } params = { paymentMethod: { card: { card: card.gsub(" ", '') }.merge(card_info) } } response = post('/paymentmethods/token', params: params) # Like the delayed_purchase form gives us retval = { type: "Token", status: "success", data: { expDate: card_info[:expiry], cardType: 'Visa', token: response.fetch('token') } } encode ? Base64.encode64(retval.to_json) : retval end |
#health_check ⇒ Object
26 27 28 |
# File 'app/models/effective/deluxe_api.rb', line 26 def health_check get('/') end |
#healthy? ⇒ Boolean
30 31 32 33 34 35 36 37 38 |
# File 'app/models/effective/deluxe_api.rb', line 30 def healthy? response = health_check() return false unless response.kind_of?(Hash) return false unless response['appName'].present? return false unless response['environment'].present? true end |
#payment ⇒ Object
The response from last create payment request
123 124 125 126 |
# File 'app/models/effective/deluxe_api.rb', line 123 def payment raise('expected purchase response to be present') unless purchase_response.kind_of?(Hash) purchase_response end |
#purchase!(order, payment_intent) ⇒ Object
After we store a payment intent we can call purchase! immediately or wait till later. This calls the /payments Create Payment endpoint Returns true when purchased. Returns false when declined. The response is stored in api.payment() after this is run
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'app/models/effective/deluxe_api.rb', line 71 def purchase!(order, payment_intent) payment_intent = decode_payment_intent_payload(payment_intent) if payment_intent.kind_of?(String) raise('expected payment_intent to be a Hash') unless payment_intent.kind_of?(Hash) raise('expected a token payment') unless payment_intent['type'] == 'Token' # Start a purchase. Which is an Authorization and a Completion self.purchase_response = nil payment = create_payment(order, payment_intent) self.purchase_response = payment # Validate valid = [0].include?(payment['responseCode']) return false unless valid # Valid purchase. This is authorized and completed. true end |
#purchase_delayed_orders!(orders) ⇒ Object
Called by rake task
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'app/models/effective/deluxe_api.rb', line 129 def purchase_delayed_orders!(orders) now = Time.zone.now Array(orders).each do |order| puts "Trying order #{order.id}" begin raise('expected a delayed order') unless order.delayed? raise('expected a deferred order') unless order.deferred? raise('expected delayed payment intent') unless order.delayed_payment_intent.present? raise('expected a delayed_ready_to_purchase? order') unless order.delayed_ready_to_purchase? order.update_columns(delayed_payment_purchase_ran_at: now, delayed_payment_purchase_result: nil) purchased = if order.total.to_i > 0 purchase!(order, order.delayed_payment_intent) elsif order.free? purchase_free!(order) else raise("Unexpected order amount: #{order.total}") end provider = (order.free? ? 'free' : order.payment_provider) payment = self.payment() card = payment["card"] || payment[:card] if purchased order.assign_attributes(delayed_payment_purchase_result: "success") order.purchase!(payment: payment, provider: provider, card: card, email: true, skip_buyer_validations: true) puts "Successfully purchased order #{order.id}" else order.assign_attributes(delayed_payment_purchase_result: "failed with message: #{Array(payment['responseMessage']).to_sentence.presence || 'none'}") order.decline!(payment: payment, provider: provider, card: card, email: true) puts "Failed to purchase order #{order.id} #{order.delayed_payment_purchase_result}" end rescue => e order.update_columns(delayed_payment_purchase_ran_at: now, delayed_payment_purchase_result: "error: #{e.}") EffectiveLogger.error(e., associated: order) if defined?(EffectiveLogger) ExceptionNotifier.notify_exception(e, data: { order_id: order.id }) if defined?(ExceptionNotifier) puts "Error purchasing #{order.id}: #{e.}" raise(e) if Rails.env.development? || Rails.env.test? end end true end |
#purchase_free!(order) ⇒ Object
89 90 91 92 93 94 95 96 97 98 |
# File 'app/models/effective/deluxe_api.rb', line 89 def purchase_free!(order) raise('expected a free order') unless order.free? self.purchase_response = nil payment = { card: "none", details: "free order. no payment required."} self.purchase_response = payment # Free is always valid true end |
#webhook_subscribe(params) ⇒ Object
203 204 205 |
# File 'app/models/effective/deluxe_api.rb', line 203 def webhook_subscribe(params) post('/events/subscribe', params: params) end |
#webhook_test(params) ⇒ Object
211 212 213 |
# File 'app/models/effective/deluxe_api.rb', line 211 def webhook_test(params) post('/events/test', params: params) end |
#webhook_unsubscribe(params) ⇒ Object
207 208 209 |
# File 'app/models/effective/deluxe_api.rb', line 207 def webhook_unsubscribe(params) post('/events/unsubscribe', params: params) end |