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 +4 -4
- data/Gemfile.lock +1 -1
- data/app/models/concerns/spree_cm_commissioner/order_holdable.rb +6 -0
- data/app/models/spree_cm_commissioner/inventory_hold.rb +1 -1
- data/app/services/spree_cm_commissioner/cart/add_guest.rb +8 -0
- data/app/services/spree_cm_commissioner/cart/add_item_decorator.rb +22 -0
- data/app/services/spree_cm_commissioner/cart/create_guest.rb +19 -0
- data/app/services/spree_cm_commissioner/cart/empty_decorator.rb +23 -0
- data/app/services/spree_cm_commissioner/cart/remove_guest.rb +20 -0
- data/app/services/spree_cm_commissioner/cart/remove_item_decorator.rb +17 -0
- data/app/services/spree_cm_commissioner/cart/remove_line_item_decorator.rb +17 -0
- data/app/services/spree_cm_commissioner/cart/set_quantity_decorator.rb +17 -0
- data/app/services/spree_cm_commissioner/inventory_holds/release.rb +3 -1
- data/config/locales/en.yml +3 -3
- data/config/locales/km.yml +3 -3
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d17bf5be351fe1e468d5772155df5cb6dad36710f3211444d7c6277c3019992
|
|
4
|
+
data.tar.gz: 73090f05ce40a930e5041040d531d5b4823e3aa7fb95c57b1b710613d75dc13b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5329436173e30eb89975c67d5fda96b8217c19507414a2631ad4cbb808b59be492f47ba18239114f4325851df932df657e10dd71b5551140d1c3f52e277ae867
|
|
7
|
+
data.tar.gz: 6db4e5c326dcc47fd5956b2253d793db7f3a0c86cd3b08eae34d4e629396c2c62347ccf2ecc9a01329e724f40232b1eca1296098b5779e233e91096596a39cdf
|
data/Gemfile.lock
CHANGED
|
@@ -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
|
-
|
|
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
|
data/config/locales/en.yml
CHANGED
|
@@ -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
|
|
730
|
-
ip_rate_limit: "Too many reservation attempts from your
|
|
731
|
-
hold_cooldown: "
|
|
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}"
|
data/config/locales/km.yml
CHANGED
|
@@ -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}"
|
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.
|
|
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
|