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 +4 -4
- data/app/datatables/admin/effective_orders_datatable.rb +1 -0
- data/app/helpers/effective_orders_helper.rb +1 -1
- data/app/models/concerns/acts_as_purchasable.rb +9 -0
- data/app/models/concerns/acts_as_purchasable_parent.rb +12 -1
- data/app/models/effective/deluxe_api.rb +39 -71
- data/app/models/effective/order.rb +27 -5
- data/app/views/effective/orders/_order_deferred.html.haml +1 -1
- data/app/views/effective/orders/delayed/_form.html.haml +13 -7
- data/app/views/effective/orders/delayed/_form_purchase.html.haml +1 -1
- data/db/migrate/101_create_effective_orders.rb +1 -0
- data/lib/effective_orders/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5523fdde5cab838b117069bf24a20a0bc0509265ebbccc033447eb2d5faa9f95
|
4
|
+
data.tar.gz: 4c4040b7ba4845fb531005e97cd18096d3fb915be1c8a041d1fbbdff649d811e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
@@ -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'
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
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')}
|
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.
|
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
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
25
|
-
|
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.
|
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
|
|
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.
|
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-
|
11
|
+
date: 2024-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|