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 |