spree_cm_commissioner 2.8.11 → 2.8.12

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: 9db31429085eb3f3365a250a214b1025f0f0ab0252f2519581755240ff83cf1a
4
- data.tar.gz: a99971540c37e2cb085b29c3bae51087dbcbab5141cd6b08ae1611fa5c5bb1bb
3
+ metadata.gz: 4d17bf5be351fe1e468d5772155df5cb6dad36710f3211444d7c6277c3019992
4
+ data.tar.gz: 73090f05ce40a930e5041040d531d5b4823e3aa7fb95c57b1b710613d75dc13b
5
5
  SHA512:
6
- metadata.gz: 75b2c0ba0b20eac7fa49f22e6ead3253b06b8cbc61831b87d98c8e6010401c2c24f42a74b6e0441ed67da2aef02f4ae32700679651576a0ba167678056b45cf7
7
- data.tar.gz: 0d7e16f4f6bd9aa8124f958b9c8b3ab4ed93783bc9b1b3167bc7b95bc592590a5b0aad4852fe17abe4013b9f8563a677be70218c74102c604c4f10f8a551ee9b
6
+ metadata.gz: 5329436173e30eb89975c67d5fda96b8217c19507414a2631ad4cbb808b59be492f47ba18239114f4325851df932df657e10dd71b5551140d1c3f52e277ae867
7
+ data.tar.gz: 6db4e5c326dcc47fd5956b2253d793db7f3a0c86cd3b08eae34d4e629396c2c62347ccf2ecc9a01329e724f40232b1eca1296098b5779e233e91096596a39cdf
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.8.11)
37
+ spree_cm_commissioner (2.8.12)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -62,6 +62,12 @@ module SpreeCmCommissioner
62
62
  SpreeCmCommissioner::OrderHolds::Release.call!(order: self, reason: reason)
63
63
  end
64
64
 
65
+ # Non-raising variant. OrderHolds::Release rescues internally and returns a failure
66
+ # result, so callers can guard on `.success?` instead of handling exceptions.
67
+ def release_order_holds(reason: :user_canceled)
68
+ SpreeCmCommissioner::OrderHolds::Release.call(order: self, reason: reason)
69
+ end
70
+
65
71
  # Converts all holds to reserved/complete state on order completion.
66
72
  # Raises on failure so the surrounding transaction rolls back.
67
73
  def reserve_order_holds!
@@ -9,7 +9,7 @@ module SpreeCmCommissioner
9
9
  belongs_to :user, class_name: 'Spree::User', optional: true
10
10
 
11
11
  enum status: { pending: 0, active: 1, payment_locked: 2, converted: 3, released: 4 }
12
- enum release_reason: { user_canceled: 0, hold_expired: 1, payment_timeout: 2 }
12
+ enum release_reason: { user_canceled: 0, hold_expired: 1, payment_timeout: 2, cart_changed: 3 }
13
13
 
14
14
  validates :expires_at, presence: true
15
15
  validates :held_at, presence: true
@@ -4,6 +4,14 @@ module SpreeCmCommissioner
4
4
  prepend Spree::ServiceModule::Base
5
5
 
6
6
  def call(order:, line_item:)
7
+ # Release holds BEFORE mutating, using the quantities the hold was placed against
8
+ # (Release reads live line items). Only release when this guest will actually bump
9
+ # the quantity. Guard on success and abort if it fails.
10
+ if should_increase_quantity?(line_item)
11
+ release = order.release_order_holds(reason: :cart_changed)
12
+ return release unless release.success?
13
+ end
14
+
7
15
  # Lock the line item (SELECT ... FOR UPDATE) so concurrent guest add/remove
8
16
  # on the same line item are serialized. with_lock reloads the record inside
9
17
  # the lock, so quantity/guests reflect the latest committed state before we
@@ -0,0 +1,22 @@
1
+ module SpreeCmCommissioner
2
+ module Cart
3
+ module AddItemDecorator
4
+ # Release the order's holds BEFORE mutating the cart, so the hold is reversed using
5
+ # the quantities it was actually placed against (Release reads live line items, it
6
+ # stores no snapshot). Releasing after the change would restock the wrong amounts.
7
+ # A fresh hold is re-acquired when the order transitions toward checkout.
8
+ # Guard on success: if the release fails, abort and surface the error — the cart
9
+ # stays untouched.
10
+ def call(order:, **)
11
+ release = order.release_order_holds(reason: :cart_changed)
12
+ return release unless release.success?
13
+
14
+ super
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ unless Spree::Cart::AddItem.included_modules.include?(SpreeCmCommissioner::Cart::AddItemDecorator)
21
+ Spree::Cart::AddItem.prepend(SpreeCmCommissioner::Cart::AddItemDecorator)
22
+ end
@@ -11,6 +11,14 @@ module SpreeCmCommissioner
11
11
  def call(line_item:, options: {})
12
12
  guest = line_item.guests.new(options)
13
13
 
14
+ # Release holds BEFORE mutating, using the quantities the hold was placed against
15
+ # (Release reads live line items). Only release when this guest will actually bump
16
+ # the quantity. Guard on success and abort if it fails.
17
+ if will_change_quantity?(line_item)
18
+ release = line_item.order.release_order_holds(reason: :cart_changed)
19
+ return release unless release.success?
20
+ end
21
+
14
22
  line_item.with_lock do
15
23
  next unless guest.save
16
24
 
@@ -45,6 +53,17 @@ module SpreeCmCommissioner
45
53
  true
46
54
  end
47
55
 
56
+ # True only when the guest about to be created will push the guest count past the
57
+ # current capacity (number_of_guests = variant.number_of_guests * quantity), i.e. the
58
+ # quantity will actually be bumped. One guest needs at most one extra unit, so a single
59
+ # `+1` comparison is enough. Used to gate the hold release so it fires only on a real
60
+ # quantity change, mirroring Cart::AddGuest#should_increase_quantity?.
61
+ def will_change_quantity?(line_item)
62
+ return false unless need_to_bump_quantity?(line_item)
63
+
64
+ (line_item.guests.count + 1) > line_item.number_of_guests
65
+ end
66
+
48
67
  def bump_quantity_to_cover_guests(line_item)
49
68
  guest_count = line_item.guests.count
50
69
  original_quantity = line_item.quantity
@@ -0,0 +1,23 @@
1
+ module SpreeCmCommissioner
2
+ module Cart
3
+ module EmptyDecorator
4
+ # Emptying the cart removes all line items, so any inventory/seat holds must be
5
+ # released first — reversed against the quantities the hold was placed against
6
+ # (Release reads live line items). Skip completed orders (Cart::Empty refuses them
7
+ # anyway, and their holds are already converted, not active). Guard on success and
8
+ # abort if the release fails.
9
+ def call(order:)
10
+ if order.present? && !order.completed?
11
+ release = order.release_order_holds(reason: :cart_changed)
12
+ return release unless release.success?
13
+ end
14
+
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ unless Spree::Cart::Empty.included_modules.include?(SpreeCmCommissioner::Cart::EmptyDecorator)
22
+ Spree::Cart::Empty.prepend(SpreeCmCommissioner::Cart::EmptyDecorator)
23
+ end
@@ -4,6 +4,16 @@ module SpreeCmCommissioner
4
4
  prepend ::Spree::ServiceModule::Base
5
5
 
6
6
  def call(order:, line_item:, guest_id: nil)
7
+ # Release holds BEFORE mutating, using the quantities the hold was placed against
8
+ # (Release reads live line items). Only release when the quantity will actually
9
+ # decrease. The gate projects the pending guest removal (we evaluate before it
10
+ # happens), unlike should_decrease_quantity? which assumes the guest is already
11
+ # gone. Guard on success and abort if it fails.
12
+ if will_decrease_quantity?(order, line_item, guest_id)
13
+ release = order.release_order_holds(reason: :cart_changed)
14
+ return release unless release.success?
15
+ end
16
+
7
17
  # Lock the line item (SELECT ... FOR UPDATE) so concurrent guest add/remove
8
18
  # on the same line item are serialized. with_lock reloads the record inside
9
19
  # the lock, so quantity/guests reflect the latest committed state before we
@@ -44,6 +54,16 @@ module SpreeCmCommissioner
44
54
  total_guests(line_item) <= required_guests_for_previous_unit(line_item)
45
55
  end
46
56
 
57
+ # Same decision as should_decrease_quantity? but evaluated BEFORE the guest is
58
+ # removed, so we subtract the guest about to be destroyed from the current count.
59
+ # Used only to gate the pre-mutation hold release.
60
+ def will_decrease_quantity?(order, line_item, guest_id)
61
+ return false if order.completed?
62
+
63
+ projected_guests = total_guests(line_item) - (guest_id.present? ? 1 : 0)
64
+ projected_guests <= required_guests_for_previous_unit(line_item)
65
+ end
66
+
47
67
  def total_guests(line_item)
48
68
  line_item.guests.size
49
69
  end
@@ -0,0 +1,17 @@
1
+ module SpreeCmCommissioner
2
+ module Cart
3
+ module RemoveItemDecorator
4
+ # See AddItemDecorator: release holds (guarded) before mutating the cart.
5
+ def call(order:, **)
6
+ release = order.release_order_holds(reason: :cart_changed)
7
+ return release unless release.success?
8
+
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ unless Spree::Cart::RemoveItem.included_modules.include?(SpreeCmCommissioner::Cart::RemoveItemDecorator)
16
+ Spree::Cart::RemoveItem.prepend(SpreeCmCommissioner::Cart::RemoveItemDecorator)
17
+ end
@@ -0,0 +1,17 @@
1
+ module SpreeCmCommissioner
2
+ module Cart
3
+ module RemoveLineItemDecorator
4
+ # See AddItemDecorator: release holds (guarded) before mutating the cart.
5
+ def call(order:, **)
6
+ release = order.release_order_holds(reason: :cart_changed)
7
+ return release unless release.success?
8
+
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ unless Spree::Cart::RemoveLineItem.included_modules.include?(SpreeCmCommissioner::Cart::RemoveLineItemDecorator)
16
+ Spree::Cart::RemoveLineItem.prepend(SpreeCmCommissioner::Cart::RemoveLineItemDecorator)
17
+ end
@@ -0,0 +1,17 @@
1
+ module SpreeCmCommissioner
2
+ module Cart
3
+ module SetQuantityDecorator
4
+ # See AddItemDecorator: release holds (guarded) before mutating the cart.
5
+ def call(order:, **)
6
+ release = order.release_order_holds(reason: :cart_changed)
7
+ return release unless release.success?
8
+
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ unless Spree::Cart::SetQuantity.included_modules.include?(SpreeCmCommissioner::Cart::SetQuantityDecorator)
16
+ Spree::Cart::SetQuantity.prepend(SpreeCmCommissioner::Cart::SetQuantityDecorator)
17
+ end
@@ -31,7 +31,9 @@ module SpreeCmCommissioner
31
31
  # Notify AFTER the transaction commits (deliver_later must not be enqueued inside an open
32
32
  # transaction), and only when THIS invocation performed the release — the `next` guards above
33
33
  # commit without releasing, so this keeps notifications idempotent across stale/concurrent jobs.
34
- notify_release(hold) if released
34
+ # Only scheduled (cron/job) releases may notify. Cart-driven releases never set
35
+ # scheduled_release, so customers editing their cart don't get a "released" push.
36
+ notify_release(hold) if released && scheduled_release
35
37
 
36
38
  success(hold)
37
39
  rescue ActiveRecord::StaleObjectError
@@ -726,9 +726,9 @@ en:
726
726
  db_save_error: "We encountered an issue saving your reservation. Please try again."
727
727
  redis_error: "We encountered an issue processing your reservation. Please try again."
728
728
  validate_limits:
729
- exceeded_active_holds: "You have too many pending reservations. Please complete or cancel a reservation before trying another."
730
- ip_rate_limit: "Too many reservation attempts from your location. Please wait and try again."
731
- hold_cooldown: "Please wait before retrying. Your previous reservation may still be processing."
729
+ exceeded_active_holds: "You've reached the limit of reservations you can hold at once. Please complete or cancel one before reserving more."
730
+ ip_rate_limit: "Too many reservation attempts from your network in a short time. Please wait a while and try again."
731
+ hold_cooldown: "Your previous reservation just expired. Please wait a couple of minutes before reserving again."
732
732
 
733
733
  account_link:
734
734
  failure: "Failed to link your %{identity_type} account: %{reason}"
@@ -526,9 +526,9 @@ km:
526
526
  db_save_error: "មានបញ្ហាក្នុងការរក្សាទុកការកក់របស់អ្នក។ សូមព្យាយាមម្តងទៀត។"
527
527
  redis_error: "មានបញ្ហាក្នុងការដំណើរការការកក់របស់អ្នក។ សូមព្យាយាមម្តងទៀត។"
528
528
  validate_limits:
529
- exceeded_active_holds: "អ្នកមានការកក់ដែលរង់ចាំច្រើនពេក។ សូមបញ្ចប់ ឬលុបការកក់មួយមុនពេលព្យាយាមវិញ។"
530
- ip_rate_limit: "មានការព្យាយាមកក់ច្រើនពេកពីទីតាំងរបស់អ្នក។ សូមរង់ចាំ ហើយព្យាយាមម្តងទៀត។"
531
- hold_cooldown: "សូមរង់ចាំមុនពេលព្យាយាមម្តងទៀត។ ការកក់របស់អ្នកមុនប្រហែលជាកំពុងដំណើរការ។"
529
+ exceeded_active_holds: "អ្នកកក់ដល់ចំនួនកំណត់អតិបរមាក្នុងពេលតែមួយហើយ។ សូមបញ្ចប់ ឬលុបការកក់មួយ មុនពេលកក់បន្ថែម។"
530
+ ip_rate_limit: "មានការព្យាយាមកក់ច្រើនពេកពីបណ្តាញរបស់អ្នកក្នុងរយៈពេលខ្លី។ សូមរង់ចាំបន្តិច រួចព្យាយាមម្តងទៀត។"
531
+ hold_cooldown: "ការកក់មុនរបស់អ្នកទើបតែផុតកំណត់។ សូមរង់ចាំពីរបីនាទី មុនពេលកក់ម្តងទៀត។"
532
532
 
533
533
  account_link:
534
534
  failure: "បរាជ័យក្នុងការភ្ជាប់គណនី %{identity_type}: %{reason}"
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.8.11'.freeze
2
+ VERSION = '2.8.12'.freeze
3
3
 
4
4
  module_function
5
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_cm_commissioner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.11
4
+ version: 2.8.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
@@ -2100,10 +2100,15 @@ files:
2100
2100
  - app/services/spree_cm_commissioner/assign_product_to_section/update.rb
2101
2101
  - app/services/spree_cm_commissioner/calculate_distance.rb
2102
2102
  - app/services/spree_cm_commissioner/cart/add_guest.rb
2103
+ - app/services/spree_cm_commissioner/cart/add_item_decorator.rb
2103
2104
  - app/services/spree_cm_commissioner/cart/create_guest.rb
2104
2105
  - app/services/spree_cm_commissioner/cart/destroy_decorator.rb
2106
+ - app/services/spree_cm_commissioner/cart/empty_decorator.rb
2105
2107
  - app/services/spree_cm_commissioner/cart/recalculate_decorator.rb
2106
2108
  - app/services/spree_cm_commissioner/cart/remove_guest.rb
2109
+ - app/services/spree_cm_commissioner/cart/remove_item_decorator.rb
2110
+ - app/services/spree_cm_commissioner/cart/remove_line_item_decorator.rb
2111
+ - app/services/spree_cm_commissioner/cart/set_quantity_decorator.rb
2107
2112
  - app/services/spree_cm_commissioner/check_ins/create_bulk.rb
2108
2113
  - app/services/spree_cm_commissioner/check_ins/destroy_bulk.rb
2109
2114
  - app/services/spree_cm_commissioner/checkout/advance_decorator.rb