effective_orders 6.12.3 → 6.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f5fbabf9c4012193962576f7ef67838e17e382740ad3860ab9c9f527ce86787
4
- data.tar.gz: 71f6af17259b5b62ee66b2fd993bb085dc8411ad8040c21fa0a3bc639381c655
3
+ metadata.gz: 5523fdde5cab838b117069bf24a20a0bc0509265ebbccc033447eb2d5faa9f95
4
+ data.tar.gz: 4c4040b7ba4845fb531005e97cd18096d3fb915be1c8a041d1fbbdff649d811e
5
5
  SHA512:
6
- metadata.gz: 60eff8ba4e046b46575a23c98daf14b0ba07cf548041826590ac49c3bf193cde6632437baeae38bfe011f37a3cae0e7d3d5d444aeeb0340a0990d1c93a88ce2b
7
- data.tar.gz: 9b91126b76b01d50fefc86b31d1a163dfe8164c523f69a2c3a523a827c632faaf0b0b5e13e0174b01450078dd32754a76157b5c4338b39b16b47a10ca1d25c59
6
+ metadata.gz: 36f22450eeeb3ffbd0755f9f840ae4be8ffd39d7a6ba9095005ee51044781d05a616f929adfe58b7a42678b42c85135c82dfdb572767ca527b6bd35a357e02d7
7
+ data.tar.gz: 927f6c0dcd4f715010fd073e056357a875222cc026b84159db6616c1ba2d36815017fab998f648969d39dba3950f53b7f5543a7f5319ad5fa835c6e9b8213d54
@@ -104,6 +104,7 @@ module Admin
104
104
  col :delayed_payment, visible: false
105
105
  col :delayed_payment_date
106
106
  col :delayed_payment_intent, visible: false
107
+ col :delayed_payment_total, as: :price, visible: false
107
108
  col :delayed_payment_purchase_ran_at, visible: false
108
109
  col :delayed_payment_purchase_result, visible: false
109
110
  end
@@ -45,7 +45,7 @@ module EffectiveOrdersHelper
45
45
  when :deluxe
46
46
  'Pay Now'
47
47
  when :deluxe_delayed
48
- 'Save now and charge me later'
48
+ 'Save card and charge me later'
49
49
  when :etransfer
50
50
  'Pay by E-transfer'
51
51
  when :free
@@ -110,6 +110,15 @@ module ActsAsPurchasable
110
110
  self[:tax_exempt] || false
111
111
  end
112
112
 
113
+ def purchased_or_deferred?
114
+ purchased_order_id.present? || orders.any? { |order| order.purchased? || order.deferred? }
115
+ end
116
+
117
+ def purchased_or_deferred_at
118
+ order = orders.find { |order| order.purchased? } || orders.find { |order| order.deferred? }
119
+ order&.purchased_at || order&.deferred_at
120
+ end
121
+
113
122
  def purchased?
114
123
  purchased_order_id.present?
115
124
  end
@@ -39,8 +39,19 @@ module ActsAsPurchasableParent
39
39
  end
40
40
 
41
41
  included do
42
- has_many :orders, -> { order(:id) }, as: :parent, class_name: 'Effective::Order', dependent: :nullify
42
+ has_many :orders, -> { order(:id) }, as: :parent, class_name: 'Effective::Order'
43
+
43
44
  accepts_nested_attributes_for :orders
45
+
46
+ before_destroy do
47
+ orders.each do |order|
48
+ raise('unable to destroy a purchasable_parent with purchased orders') if order.purchased?
49
+ order.voided? ? order.save! : order.void!
50
+ end
51
+
52
+ true
53
+ end
54
+
44
55
  end
45
56
 
46
57
  end
@@ -65,7 +65,7 @@ module Effective
65
65
  end
66
66
 
67
67
  # After we store a payment intent we can call purchase! immediately or wait till later.
68
- # This calls Authorize Payment and Complete Payment
68
+ # This calls the /payments Create Payment endpoint
69
69
  # Returns true when purchased. Returns false when declined.
70
70
  # The response is stored in api.payment() after this is run
71
71
  def purchase!(order, payment_intent)
@@ -75,18 +75,10 @@ module Effective
75
75
 
76
76
  # Start a purchase. Which is an Authorization and a Completion
77
77
  self.purchase_response = nil
78
-
79
- # Process Authorization
80
- authorization = authorize_payment(order, payment_intent)
81
- self.purchase_response = authorization
82
-
83
- valid = [0].include?(authorization['responseCode'])
84
- return false unless valid
85
-
86
- ## Complete Payment
87
- payment = complete_payment(order, authorization)
78
+ payment = create_payment(order, payment_intent)
88
79
  self.purchase_response = payment
89
80
 
81
+ # Validate
90
82
  valid = [0].include?(payment['responseCode'])
91
83
  return false unless valid
92
84
 
@@ -94,11 +86,35 @@ module Effective
94
86
  true
95
87
  end
96
88
 
89
+ # Create Payment
90
+ def create_payment(order, payment_intent)
91
+ response = post('/payments', params: create_payment_params(order, payment_intent))
92
+
93
+ # Sanity check response
94
+ raise('expected responseCode') unless response.kind_of?(Hash) && response['responseCode'].present?
95
+
96
+ # Sanity check response approved vs authorized
97
+ valid = [0].include?(response['responseCode'])
98
+
99
+ # We might be approved for an amount less than the order total. Not sure what to do here
100
+ if valid && (amountApproved = response['amountApproved']) != (amountAuthorized = order.total_to_f)
101
+ raise("expected complete payment amountApproved #{amountApproved} to be the same as the amountAuthorized #{amountAuthorized} but it was not")
102
+ end
103
+
104
+ # Generate the card info we can store
105
+ card = card_info(payment_intent)
106
+
107
+ # Return the response merged with the card info
108
+ response.reverse_merge(card)
109
+ end
110
+
111
+ # The response from last create payment request
97
112
  def payment
98
113
  raise('expected purchase response to be present') unless purchase_response.kind_of?(Hash)
99
114
  purchase_response
100
115
  end
101
116
 
117
+ # Called by rake task
102
118
  def purchase_delayed_orders!(orders)
103
119
  now = Time.zone.now
104
120
 
@@ -144,51 +160,7 @@ module Effective
144
160
 
145
161
  protected
146
162
 
147
- # Authorize Payment
148
- def authorize_payment(order, payment_intent)
149
- response = post('/payments/authorize', params: authorize_payment_params(order, payment_intent))
150
-
151
- # Sanity check response
152
- raise('expected responseCode') unless response.kind_of?(Hash) && response['responseCode'].present?
153
-
154
- # Sanity check response approved vs authorized
155
- valid = [0].include?(response['responseCode'])
156
-
157
- # We might be approved for an amount less than the order total. Not sure what to do here
158
- if valid && (amountApproved = response['amountApproved']) != (amountAuthorized = order.total_to_f)
159
- raise("expected authorize payment amountApproved #{amountApproved} to be the same as the amountAuthorized #{amountAuthorized} but it was not")
160
- end
161
-
162
- # Generate the card info we can store
163
- card = card_info(payment_intent)
164
-
165
- # Return the authorization params merged with the card info
166
- response.reverse_merge(card)
167
- end
168
-
169
- # Complete Payment
170
- def complete_payment(order, authorization)
171
- response = post('/payments/complete', params: complete_payment_params(order, authorization))
172
-
173
- # Sanity check response
174
- raise('expected responseCode') unless response.kind_of?(Hash) && response['responseCode'].present?
175
-
176
- # Sanity check response approved vs authorized
177
- valid = [0].include?(response['responseCode'])
178
-
179
- # We might be approved for an amount less than the order total. Not sure what to do here
180
- if valid && (amountApproved = response['amountApproved']) != (amountAuthorized = order.total_to_f)
181
- raise("expected complete payment amountApproved #{amountApproved} to be the same as the amountAuthorized #{amountAuthorized} but it was not")
182
- end
183
-
184
- # The authorization information
185
- authorization = { 'paymentId' => authorization } if authorization.kind_of?(String)
186
-
187
- # Return the complete params merged with the authorization params
188
- response.reverse_merge(authorization)
189
- end
190
-
191
- def authorize_payment_params(order, payment_intent)
163
+ def create_payment_params(order, payment_intent)
192
164
  raise('expected an Effective::Order') unless order.kind_of?(Effective::Order)
193
165
 
194
166
  token = extract_token(payment_intent)
@@ -232,28 +204,24 @@ module Effective
232
204
  ({ name: 'organization_id', value: order.organization_id.to_s } if order.organization_id.present?)
233
205
  ].compact
234
206
 
235
- # Params passed into Authorize Payment
236
- {
207
+ orderData = {
208
+ autoGenerateOrderId: true,
209
+ orderID: order.to_param,
210
+ orderIdIsUnique: true
211
+ }
212
+
213
+ # Params passed into Create Payment
214
+ params = {
215
+ paymentType: "Sale",
237
216
  amount: amount,
238
217
  paymentMethod: paymentMethod,
239
218
  shippingAddress: shippingAddress,
240
219
  customData: customData,
220
+ merchantCategory: "E-Commerce",
221
+ orderData: orderData
241
222
  }.compact
242
223
  end
243
224
 
244
- def complete_payment_params(order, payment_intent)
245
- raise('expected an Effective::Order') unless order.kind_of?(Effective::Order)
246
-
247
- payment_id = extract_payment_id(payment_intent)
248
- amount = { amount: order.total_to_f, currency: currency }
249
-
250
- # Params passed into Complete Payment
251
- {
252
- paymentId: payment_id,
253
- amount: amount
254
- }
255
- end
256
-
257
225
  def get(endpoint, params: nil)
258
226
  query = ('?' + params.compact.map { |k, v| "$#{k}=#{v}" }.join('&')) if params.present?
259
227
 
@@ -100,10 +100,11 @@ module Effective
100
100
  delayed_payment :boolean
101
101
  delayed_payment_date :date
102
102
 
103
- # When the order goes to checkout we require the delayed_payment_intent
104
- # This stores the user's card information in a secure way
103
+ # When the order goes to checkout we require the delayed_payment_intent and total
104
+ # This stores the user's card information
105
105
  # This is required for the order to become deferred?
106
106
  delayed_payment_intent :text
107
+ delayed_payment_total :integer # Only for reference, not really used. This is the order total we showed them when they last save card info'd
107
108
 
108
109
  # Set by the rake task that runs 1/day and processes any delayed orders before or on that day
109
110
  delayed_payment_purchase_ran_at :datetime
@@ -192,7 +193,11 @@ module Effective
192
193
  # Delayed Payment Validations
193
194
  validates :delayed_payment_date, presence: true, if: -> { delayed_payment? }
194
195
  validates :delayed_payment_date, absence: true, unless: -> { delayed_payment? }
195
- validates :delayed_payment_intent, presence: { message: 'please provide your card information' }, if: -> { delayed? && deferred? }
196
+
197
+ with_options(if: -> { delayed? && deferred? }) do
198
+ validates :delayed_payment_intent, presence: { message: 'please provide your card information' }
199
+ validates :delayed_payment_total, presence: true
200
+ end
196
201
 
197
202
  validate do
198
203
  if EffectiveOrders.organization_enabled?
@@ -548,13 +553,20 @@ module Effective
548
553
  return false unless delayed?
549
554
  return false unless deferred?
550
555
  return false unless delayed_payment_intent.present?
551
- return false if delayed_payment_date_future?
556
+ return false if delayed_payment_date_upcoming?
552
557
  return false if delayed_payment_purchase_ran_at.present? # We ran before and probably failed
553
558
 
554
559
  true
555
560
  end
556
561
 
557
- def delayed_payment_date_future?
562
+ def delayed_payment_info
563
+ return unless delayed? && deferred?
564
+ return unless delayed_payment_date_upcoming?
565
+
566
+ "Your #{delayed_payment_method} will be charged on #{delayed_payment_date.strftime('%F')} for the full amount of $#{'%0.2f' % total_to_f}"
567
+ end
568
+
569
+ def delayed_payment_date_upcoming?
558
570
  return false unless delayed?
559
571
  delayed_payment_date > Time.zone.now.to_date
560
572
  end
@@ -737,6 +749,7 @@ module Effective
737
749
 
738
750
  assign_attributes(
739
751
  delayed_payment_intent: payment_intent,
752
+ delayed_payment_total: total(),
740
753
 
741
754
  payment: payment_to_h(payment),
742
755
  payment_card: (card.presence || 'none')
@@ -832,6 +845,15 @@ module Effective
832
845
  unvoided!(skip_buyer_validations: true)
833
846
  end
834
847
 
848
+ def deluxe_delayed_purchase!
849
+ raise('expected a delayed order') unless delayed?
850
+ raise('expected a deferred order') unless deferred?
851
+ raise('expected delayed payment intent') unless delayed_payment_intent.present?
852
+ raise('expected a deluxe_delayed payment provider') unless payment_provider == 'deluxe_delayed'
853
+
854
+ Effective::DeluxeApi.new().purchase_delayed_orders!(self)
855
+ end
856
+
835
857
  # These are all the emails we send all notifications to
836
858
  def emails
837
859
  ([purchased_by.try(:email)] + [email] + [user.try(:email)] + Array(organization.try(:billing_emails))).map(&:presence).compact.uniq
@@ -8,6 +8,6 @@
8
8
  %tr
9
9
  %td
10
10
  - if order.delayed?
11
- Your #{order.delayed_payment_method} will be charged on #{order.delayed_payment_date.strftime('%F')} for the full amount
11
+ Your #{order.delayed_payment_method} will be charged on #{order.delayed_payment_date.strftime('%F')}
12
12
  - else
13
13
  Waiting for payment by #{order.payment_provider}
@@ -8,18 +8,24 @@
8
8
 
9
9
  The payment date for this order
10
10
 
11
- - if order.delayed_payment_date_future?
11
+ - if order.delayed_payment_date_upcoming?
12
12
  is in #{distance} from now on #{order.delayed_payment_date.strftime('%F')}
13
13
  - elsif order.delayed_payment_date_today?
14
14
  was today
15
15
  - else
16
16
  was #{distance} ago on #{order.delayed_payment_date.strftime('%F')}
17
+
18
+ - provider_locals = { order: order, deferred_url: deferred_url, declined_url: declined_url }
17
19
 
18
- %p
19
- Instead of charging your card right away, the following action will securely save a token
20
- representing your card information. The full amount will be charged on the payment date.
20
+ - if order.deferred? && order.delayed?
21
+ %p Your existing #{order.delayed_payment_method} will be charged on the payment date.
21
22
 
22
- - provider_locals = { order: order, deferred_url: deferred_url, declined_url: declined_url }
23
+ = collapse('Change my card info') do
24
+ - EffectiveOrders.delayed_providers.each do |provider|
25
+ = render partial: "/effective/orders/#{provider}/form", locals: provider_locals
26
+ - else
27
+ %p
28
+ Please enter your card information so it can be charged on the payment date.
23
29
 
24
- - EffectiveOrders.delayed_providers.each do |provider|
25
- = render partial: "/effective/orders/#{provider}/form", locals: provider_locals
30
+ - EffectiveOrders.delayed_providers.each do |provider|
31
+ = render partial: "/effective/orders/#{provider}/form", locals: provider_locals
@@ -13,7 +13,7 @@
13
13
 
14
14
  The payment date for this order
15
15
 
16
- - if order.delayed_payment_date_future?
16
+ - if order.delayed_payment_date_upcoming?
17
17
  is in #{distance} from now on #{order.delayed_payment_date.strftime('%F')}
18
18
  - elsif order.delayed_payment_date_today?
19
19
  was today
@@ -43,6 +43,7 @@ class CreateEffectiveOrders < ActiveRecord::Migration[6.0]
43
43
  t.boolean :delayed_payment, default: false
44
44
  t.date :delayed_payment_date
45
45
  t.text :delayed_payment_intent
46
+ t.integer :delayed_payment_total
46
47
  t.datetime :delayed_payment_purchase_ran_at
47
48
  t.text :delayed_payment_purchase_result
48
49
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '6.12.3'.freeze
2
+ VERSION = '6.13.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_orders
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.12.3
4
+ version: 6.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-31 00:00:00.000000000 Z
11
+ date: 2024-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails