spree-paypal_platform 5.1.4 → 5.1.5

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: 10754110031d42b6574e51b4eef1c1cb1adcc5a0d09b7c203d8620eae06acae8
4
- data.tar.gz: e7d3ea6129314c8cf7d2083370a8997bdd09aa655cfd826d96145378a60865ae
3
+ metadata.gz: 4de54a54a0c7dd935c012bf20c72711b0bf78959b2556acebfacc3c0eb14e930
4
+ data.tar.gz: 94c506e594ce38d454fdff782d1dad610582b81e59e658d1bce232b29cf7344c
5
5
  SHA512:
6
- metadata.gz: 0e97ad651a97eba76344f666a171ad211583608a8ce307ca80fd507f5452e6a07ca2e81f04af9f4fce14594a5c507d1e95facce00eb0d334d7ea34c5b499ba2c
7
- data.tar.gz: 001c8dec98b5eed5f48c20cc398b453daeaca65829b81d49bb7aa40cc33b3b6ab06beeadf2c77b6ab2dd71612216f9f877dde3d8ed3723edec956fd3d5b4a2d9
6
+ metadata.gz: abdce2d88ae3c2fb939cb6ce006bf1b6a654fadf98436df56ff3771c7f79b55c66e28fea31934bdc20310877b2f875c4e19fe0be873b4d15b1a05cfeee45af7c
7
+ data.tar.gz: 8c4d81e0b0f6e8d80da95c7febc3c6acaefda891d4dce1c5722ea0a9a0700da8f9beaeccb2dbe046ce0fd320b4dac0bccffa6a555cbd2e1356d719ce3d7077dc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.5
4
+
5
+ - Gift cards and store credit: the PayPal order is created for the amount
6
+ due (`total_minus_store_credits`), not the full order total. Before, PayPal
7
+ charged the full total while Spree recorded the gift card as paying part
8
+ of it, so the customer paid twice for that part. A partial charge is sent
9
+ as a plain amount, without the breakdown and items that sum to the full
10
+ total.
11
+ - Completing a session refuses to capture when the PayPal order amount no
12
+ longer matches the amount due (e.g. a gift card was applied, or the cart
13
+ changed, after the PayPal order was created). The session fails and the
14
+ storefront creates a new one.
15
+
3
16
  ## 5.1.4
4
17
 
5
18
  - `enable_card_fields` preference (checkbox, default on).
@@ -42,7 +42,7 @@ module Spree
42
42
  return nil if total.zero?
43
43
 
44
44
  protect_from_error do
45
- order_presenter = OrderPresenter.new(order)
45
+ order_presenter = OrderPresenter.new(order, amount: total)
46
46
  paypal_response = client.orders.create_order(order_presenter.to_json)
47
47
 
48
48
  session_data = paypal_response.data.as_json
@@ -101,6 +101,7 @@ module Spree
101
101
  if fetched.data.status == 'COMPLETED'
102
102
  fetched
103
103
  else
104
+ ensure_amount_matches!(payment_session, fetched)
104
105
  client.orders.capture_order(lookup)
105
106
  end
106
107
 
@@ -166,6 +167,26 @@ module Spree
166
167
 
167
168
  private
168
169
 
170
+ ##
171
+ # Refuses to capture a PayPal order whose amount no longer matches what
172
+ # is due — e.g. a gift card was applied, or the cart changed, after the
173
+ # PayPal order was created. Capturing would take the stale amount; the
174
+ # storefront recreates the session instead.
175
+ #
176
+ # @raise [Spree::Core::GatewayError]
177
+ #
178
+ def ensure_amount_matches!(payment_session, fetched)
179
+ value = fetched.data.as_json.dig('purchase_units', 0, 'amount', 'value')
180
+ return if value.blank?
181
+
182
+ due = payment_session.order.total_minus_store_credits
183
+ return if value.to_d == due.to_d
184
+
185
+ payment_session.fail if payment_session.can_fail?
186
+ raise Spree::Core::GatewayError,
187
+ "PayPal order amount #{value} does not match the amount due #{due}"
188
+ end
189
+
169
190
  def extract_order_id_from_webhook(event_type, resource)
170
191
  case event_type
171
192
  when /\ACHECKOUT\.ORDER\./
@@ -18,9 +18,13 @@ module Spree
18
18
 
19
19
  ##
20
20
  # @param order [Spree::Order]
21
+ # @param amount [Numeric, NilClass] what PayPal should charge; defaults to
22
+ # the order total. Less than the total when a gift card or store credit
23
+ # pays part of the order.
21
24
  #
22
- def initialize(order)
25
+ def initialize(order, amount: nil)
23
26
  @order = order
27
+ @amount = amount
24
28
  end
25
29
 
26
30
  attr_reader :order
@@ -41,15 +45,29 @@ module Spree
41
45
  private
42
46
 
43
47
  def purchase_unit
44
- args = {
45
- amount: amount_with_breakdown,
46
- items: items
47
- }
48
+ # A gift card or store credit pays part of the order, so the breakdown
49
+ # and items (which always sum to the full order total) can't describe
50
+ # what PayPal charges. PayPal accepts an amount on its own.
51
+ args =
52
+ if partial_charge?
53
+ { amount: PaypalServerSdk::AmountWithBreakdown.new(currency_code: order.currency.upcase,
54
+ value: charge_amount.to_s) }
55
+ else
56
+ { amount: amount_with_breakdown, items: items }
57
+ end
48
58
  args[:shipping] = shipping_details if shipping_details
49
59
 
50
60
  PaypalServerSdk::PurchaseUnitRequest.new(**args)
51
61
  end
52
62
 
63
+ def charge_amount
64
+ @amount.presence || order.total
65
+ end
66
+
67
+ def partial_charge?
68
+ charge_amount.to_d != order.total.to_d
69
+ end
70
+
53
71
  # NOTE: the breakdown only sends additional (non-included) tax — sending
54
72
  # the full tax_total double-counts VAT on tax-inclusive markets and
55
73
  # trips AMOUNT_MISMATCH. Do not change to order.tax_total.
@@ -3,6 +3,6 @@
3
3
  module Spree
4
4
  module PaypalPlatform
5
5
  # Major version tracks Spree's major version: 5.x supports Spree 5.x.
6
- VERSION = '5.1.4'
6
+ VERSION = '5.1.5'
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree-paypal_platform
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.4
4
+ version: 5.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aypex
@@ -169,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
169
  - !ruby/object:Gem::Version
170
170
  version: '0'
171
171
  requirements: []
172
- rubygems_version: 4.0.16
172
+ rubygems_version: 4.0.20
173
173
  specification_version: 4
174
174
  summary: PayPal Checkout for Spree, including Apple Pay and Card Fields
175
175
  test_files: []