effective_orders 6.27.2 → 6.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: acc426e93e1ea3adbe5196dbde6e2fba838633da8b7af235face31c2a49a006f
4
- data.tar.gz: 706cab97c78e46022a093625aca51d4cd6f4c742e0d56b05f4dd9fdf9e61f3ce
3
+ metadata.gz: 5d9af403d4a78ea5498469fb7c45b0dddad5ff8f72b6e752c059d473442e332d
4
+ data.tar.gz: 79cfedddb1851a9bb4c7c6b798dbc8cd14ad5a0e77aebe3ce5954d4b8ace116c
5
5
  SHA512:
6
- metadata.gz: fc4c197abee2f8735da26394903951a9f09e4296c462bb7c806786c23760ec6eff9c60106c32d2e1ca484f4b5b5b6ca07d246cdb8d37286b79609b0f31775f1b
7
- data.tar.gz: 527409a4eaabbbf8b5bf50fec7672cab51f0daa83fc6bbd68299701b1baf682aba589828e8e676fda351135cb3e5ec5829a6999d13662d0e2ff5525b3faa7383
6
+ metadata.gz: fddb18b9e210244dc6c009a4885f97610cf324a10cf9c154373e1bd95a13f61c995bbe262d9d0784fd17d32a3af7a8f237bac4950c599b2c3d6cbad2d168310f
7
+ data.tar.gz: 4a262a7709a4df828f604bf5f4f02cb9825bcf3a27b1713ea3b0006cc56339be48a23ab87e262b36d2d8b7ae261eb7c8ac2478b3f8fbe6980c27ba2555eb1ef9
@@ -20,14 +20,17 @@ function initializeHelcim() {
20
20
 
21
21
  function helcimPayIframeEvent(event) {
22
22
  if(event.data.eventName.startsWith('helcim-pay-js')) {
23
- window.removeEventListener('message', helcimPayIframeEvent, false);
24
23
 
25
24
  if(event.data.eventStatus == 'HIDE') {
25
+ window.removeEventListener('message', helcimPayIframeEvent, false);
26
+
26
27
  let button = $('.effective-helcim-checkout').find('#helcim-checkout-button').get(0);
27
28
  Rails.enableElement(button)
28
29
  }
29
30
 
30
31
  if(event.data.eventStatus == 'SUCCESS') {
32
+ window.removeEventListener('message', helcimPayIframeEvent, false);
33
+
31
34
  let payment = btoa(event.data.eventMessage);
32
35
 
33
36
  let $form = $('form[data-helcim-checkout]').first();
@@ -22,8 +22,14 @@ module Effective
22
22
  return order_not_processed(declined_url: helcim_params[:declined_url])
23
23
  end
24
24
 
25
- # Verify the payment
26
- payment = api.verify_payment(@order, payment_payload)
25
+ # Get the trusted payment Hash from Helcim
26
+ payment = api.get_payment(@order, payment_payload)
27
+
28
+ # If fee_saver? we assign any surcharge to the order
29
+ api.assign_order_charges!(@order, payment)
30
+
31
+ # Verify the payment. This will raise a 500 error if the payment is not valid
32
+ api.verify_payment!(@order, payment)
27
33
 
28
34
  # If it's purchased
29
35
  purchased = api.purchased?(payment)
@@ -51,7 +51,7 @@ module EffectiveOrdersHelper
51
51
  when :free
52
52
  'Checkout Free'
53
53
  when :helcim
54
- 'Pay by Credit Card'
54
+ EffectiveOrders.fee_saver? ? 'Pay by Credit Card or ACH Payment' : 'Pay by Credit Card'
55
55
  when :mark_as_paid
56
56
  'Admin: Mark as Paid'
57
57
  when :moneris
@@ -49,7 +49,7 @@ module Effective
49
49
  brandColor: (brand_color || '815AF0')
50
50
  },
51
51
  invoiceRequest: {
52
- invoiceNumber: '#' + order.to_param
52
+ invoiceNumber: '#' + order.transaction_id(short: true)
53
53
  },
54
54
  customerRequest: {
55
55
  contactName: order.billing_name,
@@ -110,6 +110,22 @@ module Effective
110
110
  end
111
111
 
112
112
  # Decode the base64 encoded JSON object that was given from the form into a Hash
113
+ # {"transactionId"=>"38142732",
114
+ # "dateCreated"=>"2025-08-15 10:10:32",
115
+ # "cardBatchId"=>"4656307",
116
+ # "status"=>"APPROVED",
117
+ # "type"=>"purchase",
118
+ # "amount"=>"10.97",
119
+ # "currency"=>"CAD",
120
+ # "avsResponse"=>"X",
121
+ # "cvvResponse"=>"",
122
+ # "approvalCode"=>"T5E3ST",
123
+ # "cardToken"=>"gv5J-lJAQNqVjZ_HkXyisQ",
124
+ # "cardNumber"=>"4242424242",
125
+ # "cardHolderName"=>"Test User",
126
+ # "customerCode"=>"CST1022",
127
+ # "invoiceNumber"=>"#30",
128
+ # "warning"=>""}
113
129
  def decode_payment_payload(payload)
114
130
  return if payload.blank?
115
131
 
@@ -127,11 +143,15 @@ module Effective
127
143
 
128
144
  def purchased?(payment)
129
145
  raise('expected a payment Hash') unless payment.kind_of?(Hash)
130
- (payment['status'] == 'APPROVED' && payment['type'] == 'purchase')
146
+
147
+ return true if (payment['status'] == 'APPROVED' && payment['type'] == 'purchase') # CC
148
+ return true if (payment['bankToken'].present? && payment['type'] == 'WITHDRAWAL') # ACH
149
+
150
+ false
131
151
  end
132
152
 
133
153
  # Considers the insecure payment_payload, requests the real transaction from Helcim and verifies it vs the order
134
- def verify_payment(order, payment_payload)
154
+ def get_payment(order, payment_payload)
135
155
  raise('expected a payment_payload Hash') unless payment_payload.kind_of?(Hash)
136
156
 
137
157
  transaction_id = payment_payload['transactionId']
@@ -145,8 +165,32 @@ module Effective
145
165
  raise('expected the payment and payment_payload to have the same transactionId')
146
166
  end
147
167
 
168
+ # Normalize the card info and scrub out the card number
169
+ payment = payment.merge(card_info(payment)).except('cardNumber')
170
+
171
+ payment
172
+ end
173
+
174
+ # Adds the order.surcharge if this is a fee saver order
175
+ def assign_order_charges!(order, payment)
176
+ raise('expected an order') unless order.kind_of?(Effective::Order)
177
+ raise('expected a payment Hash') unless payment.kind_of?(Hash)
178
+
179
+ return unless EffectiveOrders.fee_saver?
180
+
181
+ # Validate amounts if purchased
182
+ amount = payment['amount'].to_f
183
+ amountAuthorized = order.total_to_f
184
+
185
+ surcharge = ((amount - amountAuthorized) * 100.0).round(0)
186
+ raise('expected surcharge to be a positive number') if surcharge < 0
187
+
188
+ order.update!(surcharge: surcharge)
189
+ end
190
+
191
+ def verify_payment!(order, payment)
148
192
  # Validate order ids
149
- if payment['invoiceNumber'].to_s != '#' + order.to_param
193
+ unless payment['invoiceNumber'].to_s.start_with?('#' + order.to_param)
150
194
  raise("expected card-transaction invoiceNumber to be the same as the order to_param")
151
195
  end
152
196
 
@@ -155,9 +199,6 @@ module Effective
155
199
  raise("expected card-transaction amount #{amount} to be the same as the amountAuthorized #{amountAuthorized} but it was not")
156
200
  end
157
201
 
158
- # Normalize the card info and scrub out the card number
159
- payment = payment.merge(card_info(payment)).except('cardNumber')
160
-
161
202
  payment
162
203
  end
163
204
 
@@ -167,6 +208,8 @@ module Effective
167
208
  last4 = payment['cardNumber'].to_s.last(4)
168
209
  card = payment['cardType'].to_s.downcase
169
210
 
211
+ card = 'ACH' if card.blank? && payment['bankToken'].present?
212
+
170
213
  active_card = "**** **** **** #{last4} #{card}" if last4.present?
171
214
 
172
215
  { 'active_card' => active_card, 'card' => card }.compact
@@ -205,6 +205,13 @@ module Effective
205
205
  validates :delayed_payment_total, presence: true
206
206
  end
207
207
 
208
+ # helcim fee saver and our own surcharge cannot co-exist
209
+ validate do
210
+ if EffectiveOrders.fee_saver? && EffectiveOrders.surcharge?
211
+ errors.add(:base, "cannot use fee saver and surcharge at the same time")
212
+ end
213
+ end
214
+
208
215
  validate do
209
216
  if EffectiveOrders.organization_enabled?
210
217
  errors.add(:base, "must have a User or #{EffectiveOrders.organization_class_name || 'Organization'}") if user_id.blank? && organization_id.blank?
@@ -214,6 +221,8 @@ module Effective
214
221
  end
215
222
 
216
223
  # Price validations
224
+ validates :surcharge, numericality: { greater_than_or_equal_to: 0, allow_blank: true }, unless: -> { refund? }
225
+
217
226
  validates :subtotal, presence: true
218
227
  validates :total, presence: true, if: -> { EffectiveOrders.minimum_charge.to_i > 0 }
219
228
 
@@ -337,7 +346,7 @@ module Effective
337
346
  removed.each { |order_item| order_item.mark_for_destruction }
338
347
 
339
348
  # Make sure to reset stored aggregates
340
- assign_attributes(subtotal: nil, tax_rate: nil, tax: nil, amount_owing: nil, surcharge_percent: nil, surcharge: nil, total: nil)
349
+ assign_attributes(subtotal: nil, tax_rate: nil, tax: nil, amount_owing: nil, surcharge_percent: nil, surcharge: nil, surcharge_tax: nil, total: nil)
341
350
 
342
351
  removed.length == 1 ? removed.first : removed
343
352
  end
@@ -381,7 +390,7 @@ module Effective
381
390
  end.compact
382
391
 
383
392
  # Make sure to reset stored aggregates
384
- assign_attributes(subtotal: nil, tax_rate: nil, tax: nil, amount_owing: nil, surcharge_percent: nil, surcharge: nil, total: nil)
393
+ assign_attributes(subtotal: nil, tax_rate: nil, tax: nil, amount_owing: nil, surcharge_percent: nil, surcharge: nil, surcharge_tax: nil, total: nil)
385
394
 
386
395
  retval = cart_items.map do |item|
387
396
  order_items.build(
@@ -455,8 +464,12 @@ module Effective
455
464
  end
456
465
 
457
466
  # For moneris and moneris_checkout. Just a unique value. Must be 50 characters or fewer or will raise moneris error.
458
- def transaction_id
459
- [to_param, billing_name.to_s.parameterize.first(20).presence, Time.zone.now.to_i, rand(1000..9999)].compact.join('-')
467
+ def transaction_id(short: false)
468
+ if short
469
+ [to_param, Time.zone.now.to_i].compact.join('-')
470
+ else
471
+ [to_param, billing_name.to_s.parameterize.first(20).presence, Time.zone.now.to_i, rand(1000..9999)].compact.join('-')
472
+ end
460
473
  end
461
474
 
462
475
  def billing_first_name
@@ -979,10 +992,10 @@ module Effective
979
992
  end
980
993
 
981
994
  def get_surcharge_percent
982
- percent = EffectiveOrders.credit_card_surcharge_percent.to_f
983
- return nil unless percent > 0.0
995
+ return nil unless EffectiveOrders.surcharge?
996
+ return nil if purchased_without_credit_card?
984
997
 
985
- return 0.0 if purchased_without_credit_card?
998
+ percent = EffectiveOrders.credit_card_surcharge_percent.to_f
986
999
 
987
1000
  if (percent > 10.0 || percent < 0.5)
988
1001
  raise "expected EffectiveOrders.credit_card_surcharge to return a value between 10.0 (10%) and 0.5 (0.5%) or nil. Received #{percent}. Please return 2.5 for 2.5% surcharge."
@@ -992,21 +1005,25 @@ module Effective
992
1005
  end
993
1006
 
994
1007
  def get_surcharge
995
- return 0 unless surcharge_percent.present?
1008
+ return nil unless EffectiveOrders.surcharge?
1009
+ return nil unless surcharge_percent.present?
1010
+
996
1011
  ((subtotal + tax) * (surcharge_percent / 100.0)).round(0).to_i
997
1012
  end
998
1013
 
999
1014
  def get_surcharge_tax
1000
- return 0 unless tax_rate.present?
1001
- (surcharge * (tax_rate / 100.0)).round(0).to_i
1015
+ return nil unless EffectiveOrders.surcharge?
1016
+ return nil unless tax_rate.present?
1017
+
1018
+ (surcharge.to_i * (tax_rate / 100.0)).round(0).to_i
1002
1019
  end
1003
1020
 
1004
1021
  def get_total
1005
- subtotal + tax + surcharge + surcharge_tax
1022
+ subtotal + tax + surcharge.to_i + surcharge_tax.to_i
1006
1023
  end
1007
1024
 
1008
1025
  def get_total_with_surcharge
1009
- subtotal + tax + surcharge + surcharge_tax
1026
+ subtotal + tax + surcharge.to_i + surcharge_tax.to_i
1010
1027
  end
1011
1028
 
1012
1029
  def get_total_without_surcharge
@@ -1025,6 +1042,7 @@ module Effective
1025
1042
  when 'm', 'mc', 'master', 'mastercard' then 'MasterCard'
1026
1043
  when 'a', 'ax', 'american', 'americanexpress' then 'American Express'
1027
1044
  when 'd', 'discover' then 'Discover'
1045
+ when 'ach' then 'ACH Payment'
1028
1046
  else payment_card.to_s
1029
1047
  end
1030
1048
 
@@ -1119,10 +1137,15 @@ module Effective
1119
1137
  end
1120
1138
 
1121
1139
  def assign_order_charges
1140
+ # We are assigning credit card surcharges ourselves
1122
1141
  # We only apply surcharge for credit card orders. But we have to display and calculate for non purchased orders
1123
- self.surcharge_percent = get_surcharge_percent()
1124
- self.surcharge = get_surcharge()
1125
- self.surcharge_tax = get_surcharge_tax()
1142
+ if EffectiveOrders.surcharge?
1143
+ raise('surcharge is not supported with fee saver') if EffectiveOrders.fee_saver?
1144
+
1145
+ self.surcharge_percent = get_surcharge_percent()
1146
+ self.surcharge = get_surcharge()
1147
+ self.surcharge_tax = get_surcharge_tax()
1148
+ end
1126
1149
 
1127
1150
  # Subtotal + Tax + Surcharge + Surcharge Tax
1128
1151
  self.total = get_total()
@@ -32,7 +32,7 @@
32
32
 
33
33
  - elsif order.payment_provider == 'etransfer'
34
34
  %ul
35
- %li Please submit your etransfer payment within 30 days of the invoice date.
35
+ %li Please submit your e-transfer payment within 30 days of the invoice date.
36
36
  %li You have until payment is received or until <strong>#{order.delayed_payment_date.strftime("%A, %B %e, %Y")}</strong>, whichever is first, to make changes and cancellations.
37
37
  %li A receipt will be sent after payment has been received.
38
38
 
@@ -65,7 +65,7 @@
65
65
  %li A receipt will be sent after payment has been received.
66
66
  - elsif order.payment_provider == 'etransfer'
67
67
  %ul
68
- %li Please submit your etransfer within 30 days of the invoice date.
68
+ %li Please submit your e-transfer within 30 days of the invoice date.
69
69
  %li A receipt will be sent after payment has been received.
70
70
  - else
71
71
  - providers = EffectiveOrders.deferred_providers.to_sentence(last_word_connector: ', or', two_words_connector: ' or ')
@@ -23,6 +23,11 @@
23
23
  = render partial: '/effective/orders/refund/form', locals: provider_locals
24
24
 
25
25
  - else
26
+ - if EffectiveOrders.fee_saver?
27
+ .alert.alert-info.mb-4
28
+ All credit card transations are subject to a surcharge.
29
+ To avoid this fee you can pay by #{['ACH', ('cheque' if EffectiveOrders.cheque?), ('e-transfer' if EffectiveOrders.etransfer?)].compact.to_sentence(last_word_connector: ' or ')}.
30
+
26
31
  - if EffectiveOrders.pretend?
27
32
  = render partial: '/effective/orders/pretend/form', locals: provider_locals
28
33
 
@@ -36,6 +36,7 @@
36
36
  -# Nothing to do. We can't display Tax, Total or Credit Card Surcharge (which is taxed) yet.
37
37
 
38
38
  - elsif order.tax_rate.present? && order.surcharge_percent.to_f > 0.0
39
+ - # We're adding the surcharge. EffectiveOrders.surcharge? mode
39
40
  %tr
40
41
  %th.tax{colspan: 2} #{EffectiveOrders.tax_label} (#{rate_to_percentage(order.tax_rate)})
41
42
  %td.price.tax-price= price_to_currency(order.tax)
@@ -56,7 +57,26 @@
56
57
  %th.total{colspan: 2} Total amount charged to credit card
57
58
  %td.price.total-price= price_to_currency(order.total)
58
59
 
60
+ - elsif order.tax_rate.present? && !(order.surcharge_percent.to_f > 0.0) && order.surcharge.to_i > 0
61
+ - # The surcharge is being added by the payment processor. EffectiveOrders.fee_saver? mode
62
+ %tr
63
+ %th.tax{colspan: 2} #{EffectiveOrders.tax_label} (#{rate_to_percentage(order.tax_rate)})
64
+ %td.price.tax-price= price_to_currency(order.tax)
65
+
66
+ %tr.single-line
67
+ %th.amount-owing{colspan: 2} Total
68
+ %td.price.amount-owing-price= price_to_currency(order.amount_owing)
69
+
70
+ %tr
71
+ %th.surcharge{colspan: 2} Credit card surcharge
72
+ %td.price.surcharge-price= price_to_currency(order.surcharge)
73
+
74
+ %tr.double-line
75
+ %th.total{colspan: 2} Credit card sale
76
+ %td.price.total-price= price_to_currency(order.total)
77
+
59
78
  - elsif order.tax_rate.present? && !(order.surcharge_percent.to_f > 0.0)
79
+ - # No surcharges
60
80
  %tr
61
81
  %th.tax{colspan: 2} #{EffectiveOrders.tax_label} (#{rate_to_percentage(order.tax_rate)})
62
82
  %td.price.tax-price= price_to_currency(order.tax)
@@ -11,7 +11,7 @@
11
11
  %td
12
12
  %div= order.billing_name
13
13
 
14
- - if order.user.try(:membership).present?
14
+ - if order.user.try(:membership).try(:number).present?
15
15
  %div= "##{order.user.membership.number}"
16
16
 
17
17
  %div= mail_to(order.email)
@@ -17,6 +17,6 @@
17
17
  .alert.alert-info.mb-4
18
18
  This is the #{Rails.env.upcase} SERVER.
19
19
  %br
20
- Use credit card number 4242 4242 4242 4242 with any future expiry and cvv 123
20
+ Use credit card number 4242 4242 4242 4242 with any future Expiry date and CVV 123
21
21
 
22
22
  = render('effective/orders/helcim/element')
@@ -50,6 +50,5 @@ module EffectiveOrders
50
50
  end
51
51
  end
52
52
  end
53
-
54
53
  end
55
54
  end
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '6.27.2'.freeze
2
+ VERSION = '6.28.0'.freeze
3
3
  end
@@ -243,6 +243,10 @@ module EffectiveOrders
243
243
  credit_card_surcharge_percent.to_f > 0.0
244
244
  end
245
245
 
246
+ def self.fee_saver?
247
+ helcim? && helcim[:fee_saver] == true
248
+ end
249
+
246
250
  def self.mailer_class
247
251
  mailer&.constantize || Effective::OrdersMailer
248
252
  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.27.2
4
+ version: 6.28.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: 2025-08-12 00:00:00.000000000 Z
11
+ date: 2025-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails