spree_cm_commissioner 2.8.7.pre.pre1 → 2.8.7.pre.pre2

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: 423377b68ab98a03dc1b8c6cf94df82ed330255cd5b5249e6fbd3efd97507e96
4
- data.tar.gz: ced4f7bb4506a6d0652a305cba71c57b117328a5e3b7a55a7cdeb3755aa4d057
3
+ metadata.gz: 5f8d7b76d756c273ceb72a1549b5ecd5b0226957d7e126c534eb6a0823658a13
4
+ data.tar.gz: d191fab60ac9d96c42677d0190a2a0f5546e98febe9c7fd72587874c0310a62c
5
5
  SHA512:
6
- metadata.gz: 41d86b9d82bbc702c8a04bff0b474c1daebbfed2cf0b0bb8b50fa8ee56358930e0cd98899d936f394ca005e62f93c92bfe8fc6cd8cbdf6d90e6db885c5a14d8e
7
- data.tar.gz: ba9caa729146ca74e0ac1155f48ca54fa7baec727ffbf6d6ce591c872cf97688baa5b9efc7dcc1ef3e9b288ba1ea506c1d8b74b79e6e1a0cc236421fcdbdb004
6
+ metadata.gz: 4b75b6d9677233ba25b3bce1f7c36629b63304486e1c90e05d89cbb38c6b4d5a065709b9fcb85ddfb50cc95f2d3c2965f02c86127fbf84d0373277f52420bba8
7
+ data.tar.gz: 5241b014525d37014ba84baae757d9738de28bca55b71542d68745a710c58593138f66ba3f4e11653da6bf2e48df76f17b2938f389756eba6fdc486e713d6d7e
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.8.7.pre.pre1)
37
+ spree_cm_commissioner (2.8.7.pre.pre2)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -9,6 +9,7 @@ module Spree
9
9
  q['s'] ||= 'created_at desc'
10
10
  q['created_at_gt'] = parse_time_or_nil(q['created_at_gt'], :beginning_of_day) if q['created_at_gt'].present?
11
11
  q['created_at_lt'] = parse_time_or_nil(q['created_at_lt'], :end_of_day) if q['created_at_lt'].present?
12
+ normalize_enum_filters!(q)
12
13
 
13
14
  @search = scope.ransack(q)
14
15
  result_scope = @search.result(distinct: true)
@@ -18,7 +19,11 @@ module Spree
18
19
  .page(params[:page])
19
20
  .per(params[:per_page] || Spree::Backend::Config[:admin_orders_per_page])
20
21
 
21
- @status_counts = result_scope.reorder(nil).group(:status).count
22
+ # Status tab counts must reflect every other filter but NOT the status filter, so
23
+ # each tab shows how many holds it would return (otherwise selecting one status
24
+ # zeroes out all the other tabs).
25
+ @status_counts = scope.ransack(q.except('status_eq')).result(distinct: true)
26
+ .reorder(nil).group(:status).count
22
27
  end
23
28
 
24
29
  def release
@@ -44,6 +49,20 @@ module Spree
44
49
 
45
50
  private
46
51
 
52
+ # `status` and `release_reason` are integer-backed enums. Ransack casts a string
53
+ # value for an integer column with String#to_i, so "payment_locked" becomes 0
54
+ # (== :pending) and every label silently filters to the wrong status. Translate
55
+ # enum labels to their stored integer before searching.
56
+ def normalize_enum_filters!(query)
57
+ {
58
+ 'status_eq' => SpreeCmCommissioner::InventoryHold.statuses,
59
+ 'release_reason_eq' => SpreeCmCommissioner::InventoryHold.release_reasons
60
+ }.each do |key, mapping|
61
+ value = query[key]
62
+ query[key] = mapping[value.to_s] if value.present? && mapping.key?(value.to_s)
63
+ end
64
+ end
65
+
47
66
  def back_params
48
67
  raw_params = params[:back_params].presence || params
49
68
  ActionController::Parameters.new(raw_params).permit(:page, :per_page, q: {})
@@ -30,13 +30,18 @@ module Spree
30
30
  private
31
31
 
32
32
  def collection
33
+ # WARNING: Do NOT remove .order(id: :desc).
34
+ # Mobile relies on this ordering for paginated order_histories.
35
+ # Removing it will cause mobile to paginate by oldest records first (last 10 oldest),
36
+ # breaking the "most recent orders" display on the order history screen.
37
+ # It related to user cancel or complete order flow, which relies on the most recent orders being returned first.
33
38
  if spree_current_user.present?
34
- spree_current_user.orders.not_archived
39
+ spree_current_user.orders.not_archived.order(id: :desc)
35
40
  else
36
41
  order_tokens = Array(params[:order_tokens])
37
42
  return Spree::Order.none if order_tokens.empty?
38
43
 
39
- Spree::Order.not_archived.without_user.where(token: order_tokens)
44
+ Spree::Order.not_archived.without_user.where(token: order_tokens).order(id: :desc)
40
45
  end
41
46
  end
42
47
 
@@ -37,13 +37,18 @@ module Spree
37
37
  end
38
38
 
39
39
  def collection
40
+ # WARNING: Do NOT remove .order(id: :desc).
41
+ # Mobile relies on this ordering for paginated order_histories.
42
+ # Removing it will cause mobile to paginate by oldest records first (last 10 oldest),
43
+ # breaking the "most recent orders" display on the order history screen.
44
+ # It related to user cancel or complete order flow, which relies on the most recent orders being returned first.
40
45
  if spree_current_user.present?
41
- spree_current_user.orders.not_archived
46
+ spree_current_user.orders.not_archived.order(id: :desc)
42
47
  else
43
48
  order_tokens = Array(params[:order_tokens])
44
49
  return Spree::Order.none if order_tokens.empty?
45
50
 
46
- Spree::Order.not_archived.without_user.where(token: order_tokens)
51
+ Spree::Order.not_archived.without_user.where(token: order_tokens).order(id: :desc)
47
52
  end
48
53
  end
49
54
 
@@ -33,6 +33,7 @@ module Spree
33
33
  @brand_color = @order.tenant.preferred_brand_primary_color
34
34
  end
35
35
  @product_type = @order.products.first&.product_type || 'accommodation'
36
+ @is_email = true
36
37
 
37
38
  subject = build_subject(resend)
38
39
 
@@ -86,6 +87,7 @@ module Spree
86
87
 
87
88
  @current_store = @order.store
88
89
  @product_type = @line_item.product_type
90
+ @is_email = true
89
91
 
90
92
  subject = "#{@current_store&.name} Booking Confirmation ##{@order.number}"
91
93
 
@@ -1,7 +1,7 @@
1
1
  # Make sure to put this concern below other concern or methods that generating additional order info like guests, seat number, etc.
2
2
  # This will ensure that when each notification is sent with neccessary data.
3
3
  module SpreeCmCommissioner
4
- module OrderStateMachine
4
+ module OrderStateMachine # rubocop:disable Metrics/ModuleLength
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do # rubocop:disable Metrics/BlockLength
@@ -273,7 +273,18 @@ module SpreeCmCommissioner
273
273
 
274
274
  def send_order_request_telegram_confirmation_alert_to_vendor; end
275
275
 
276
+ # Telegram order alerts are sent unless EVERY purchased product opts out.
277
+ # Default is true (see product_decorator), so existing orders are unaffected.
278
+ # Checked at enqueue time so disabled products create no telegram jobs at all.
279
+ def telegram_alert_enabled?
280
+ return @telegram_alert_enabled if defined?(@telegram_alert_enabled)
281
+
282
+ @telegram_alert_enabled = line_items.any?(&:enable_telegram_alert?)
283
+ end
284
+
276
285
  def send_order_complete_telegram_alert_to_vendors
286
+ return unless telegram_alert_enabled?
287
+
277
288
  vendor_list.each do |vendor|
278
289
  title = '🎫 --- [NEW ORDER FROM BOOKME+] ---'
279
290
  chat_id = vendor.preferred_telegram_chat_id
@@ -289,6 +300,8 @@ module SpreeCmCommissioner
289
300
  end
290
301
 
291
302
  def notify_order_complete_telegram_notification_to_user
303
+ return unless telegram_alert_enabled?
304
+
292
305
  SpreeCmCommissioner::OrderCompleteTelegramSenderJob.perform_later(order_id: id) if user_id.present?
293
306
  end
294
307
 
@@ -305,6 +318,8 @@ module SpreeCmCommissioner
305
318
  end
306
319
 
307
320
  def send_order_requested_telegram_alert_to_store
321
+ return unless telegram_alert_enabled?
322
+
308
323
  title = '🔔 --- [NEW REQUESTED BY USER] ---'
309
324
  chat_id = store.preferred_telegram_order_request_alert_chat_id
310
325
  factory = OrderTelegramMessageFactory.new(title: title, order: self)
@@ -312,6 +327,8 @@ module SpreeCmCommissioner
312
327
  end
313
328
 
314
329
  def send_order_accepted_telegram_alert_to_store
330
+ return unless telegram_alert_enabled?
331
+
315
332
  title = '✅ --- [ORDER ACCEPTED BY VENDOR] ---'
316
333
  chat_id = store.preferred_telegram_order_request_alert_chat_id
317
334
  factory = OrderTelegramMessageFactory.new(title: title, order: self)
@@ -319,6 +336,8 @@ module SpreeCmCommissioner
319
336
  end
320
337
 
321
338
  def send_order_rejected_telegram_alert_to_store
339
+ return unless telegram_alert_enabled?
340
+
322
341
  title = '❌ --- [ORDER REJECTED BY VENDOR] ---'
323
342
  chat_id = store.preferred_telegram_order_request_alert_chat_id
324
343
  factory = OrderTelegramMessageFactory.new(title: title, order: self)
@@ -327,6 +346,7 @@ module SpreeCmCommissioner
327
346
 
328
347
  def run_order_complete_alerts
329
348
  return unless ENV['ORDER_INTEGRITY_TELEGRAM_ALERT_ENABLED'] == 'yes'
349
+ return unless telegram_alert_enabled?
330
350
 
331
351
  # Allow async payment processors time to settle before checking for alerts
332
352
  SpreeCmCommissioner::TelegramAlerts::OrderIntegrityCheckJob
@@ -335,6 +355,8 @@ module SpreeCmCommissioner
335
355
  end
336
356
 
337
357
  def send_order_complete_telegram_alert_to_store
358
+ return unless telegram_alert_enabled?
359
+
338
360
  title = '🎫 --- [NEW ORDER] ---'
339
361
  chat_id = store.preferred_telegram_order_alert_chat_id
340
362
  factory = OrderTelegramMessageFactory.new(title: title, order: self)
@@ -11,6 +11,8 @@ module SpreeCmCommissioner
11
11
  :allow_self_check_in?,
12
12
  :required_self_check_in_location,
13
13
  :required_self_check_in_location?,
14
+ :enable_telegram_alert,
15
+ :enable_telegram_alert?,
14
16
  to: :product
15
17
  end
16
18
  end
@@ -132,6 +132,7 @@ module SpreeCmCommissioner
132
132
 
133
133
  base.store_public_metadata :open_dated_validity_days, :integer, default: 90
134
134
  base.store_public_metadata :enable_inventory_hold, :boolean, default: false
135
+ base.store_public_metadata :enable_telegram_alert, :boolean, default: true
135
136
 
136
137
  base.store_private_metadata :advertise_weight, :integer, default: 1
137
138
  base.store_private_metadata :video_url, :string
@@ -0,0 +1,8 @@
1
+ <!-- insert_after ".date-range-filter" -->
2
+
3
+ <div class="col-12 col-lg-4">
4
+ <div class="form-group">
5
+ <%= label_tag :q_payments_number_cont, 'Payment Number' %>
6
+ <%= f.text_field :payments_number_cont, class: 'form-control' %>
7
+ </div>
8
+ </div>
@@ -0,0 +1,14 @@
1
+ <!-- insert_after "[data-hook='admin_product_form_promotionable']" -->
2
+
3
+ <div>
4
+ <%= f.field_container :enable_telegram_alert do %>
5
+ <%= f.label :enable_telegram_alert do %>
6
+ <%= f.check_box :enable_telegram_alert %>
7
+ <%= Spree.t(:enable_telegram_alert) %>
8
+ <% end %>
9
+ <small class="form-text text-muted">
10
+ When enabled, Telegram order alerts are sent for this product. Turn off for
11
+ high-volume products to avoid flooding Telegram with order notifications.
12
+ </small>
13
+ <% end %>
14
+ </div>
@@ -13,9 +13,23 @@ module SpreeCmCommissioner
13
13
  create_blank_guest(line_item)
14
14
  increase_quantity(line_item) if should_increase_quantity?(line_item)
15
15
  recalculate_cart(order, line_item)
16
-
17
- success(order: order, line_item: line_item)
18
16
  end
17
+
18
+ success(order: order, line_item: line_item)
19
+ rescue ActiveRecord::RecordInvalid => e
20
+ # Convert ONLY the out-of-stock failure into a failure result. The stock validator
21
+ # tags its error with the type :selected_quantity_not_available (see
22
+ # Spree::Stock::AvailabilityValidator), so we match on that type rather than on any
23
+ # RecordInvalid. The raise rolls back the lock transaction (so the blank guest is
24
+ # not persisted); returning it as a failure lets the caller render the overridden
25
+ # availability message instead of a 500.
26
+ #
27
+ # Anything else a different line item validation, or an invalid order/shipment
28
+ # raised by recalculate_cart is re-raised so genuine backend errors are not
29
+ # masked behind an empty quantity error.
30
+ raise unless e.record == line_item && e.record.errors.of_kind?(:quantity, :selected_quantity_not_available)
31
+
32
+ failure(e.record)
19
33
  end
20
34
 
21
35
  private
@@ -61,15 +61,18 @@
61
61
  <% end %>
62
62
  </td>
63
63
  </tr>
64
- <tr>
65
- <td></td>
66
- <td align="left" style="padding-top:6px;">
67
- <%= link_to(
68
- raw('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: inline-block; vertical-align: middle; margin-right: 8px;"><rect width="5" height="5" x="3" y="3" rx="1"/><rect width="5" height="5" x="16" y="3" rx="1"/><rect width="5" height="5" x="3" y="16" rx="1"/><path d="M21 16h-3a2 2 0 0 0-2 2v3"/><path d="M21 21v.01"/><path d="M12 7v3a2 2 0 0 1-2 2H7"/><path d="M3 12h.01"/><path d="M12 3h.01"/><path d="M12 16v.01"/><path d="M16 12h1"/><path d="M21 12v.01"/><path d="M12 21v-1"/></svg> View Your Digital Ticket'),
69
- custom_product_line_item_url(line_item), class: "btn-primary", target: :_blank
70
- ) %>
71
- </td>
72
- </tr>
64
+ <%# In the email only, hide the ticket link for app-only products. %>
65
+ <% unless @is_email && line_item&.product&.purchasable_on_app? %>
66
+ <tr>
67
+ <td></td>
68
+ <td align="left" style="padding-top:6px;">
69
+ <%= link_to(
70
+ raw('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: inline-block; vertical-align: middle; margin-right: 8px;"><rect width="5" height="5" x="3" y="3" rx="1"/><rect width="5" height="5" x="16" y="3" rx="1"/><rect width="5" height="5" x="3" y="16" rx="1"/><path d="M21 16h-3a2 2 0 0 0-2 2v3"/><path d="M21 21v.01"/><path d="M12 7v3a2 2 0 0 1-2 2H7"/><path d="M3 12h.01"/><path d="M12 3h.01"/><path d="M12 16v.01"/><path d="M16 12h1"/><path d="M21 12v.01"/><path d="M12 21v-1"/></svg> View Your Digital Ticket'),
71
+ custom_product_line_item_url(line_item), class: "btn-primary", target: :_blank
72
+ ) %>
73
+ </td>
74
+ </tr>
75
+ <% end %>
73
76
  </table>
74
77
  </td>
75
78
  </tr>
@@ -6,6 +6,9 @@ module Spree
6
6
  @@vendor_attributes << :logo
7
7
  @@vendor_attributes << :service_origin_id
8
8
 
9
+ # store_accessor key (public_metadata), not a DB column, so it must be permitted explicitly
10
+ @@product_attributes << :enable_telegram_alert unless @@product_attributes.include?(:enable_telegram_alert)
11
+
9
12
  # Permitted all guest attributes for now as permitting only some guest attributes is not working by design
10
13
  # of spree add_item service, if we want to only permit some guest attributes,
11
14
  # we need to override most part of add_item service.
@@ -220,6 +220,7 @@ en:
220
220
  reversion_error: "Cannot eliminate here yet. This contestant appears in a later session."
221
221
  is_open_dated: "Is Open Dated Trip?"
222
222
  description: "Description"
223
+ enable_telegram_alert: Enable Telegram Alert
223
224
  registered_by:
224
225
  system_registered: "System Registered"
225
226
  self_registered: "Self Registered"
@@ -417,6 +418,9 @@ en:
417
418
  zero: "Rooms are not available on %{date}"
418
419
  one: "Only 1 room available on %{date}"
419
420
  other: "Only %{count} rooms available on %{date}"
421
+ # Overrides Spree core's "selected of %{item} is not available." Must stay under
422
+ # `spree:` -- Spree::Stock::AvailabilityValidator looks it up as Spree.t(:selected_quantity_not_available).
423
+ selected_quantity_not_available: "Not enough %{item} are available for the quantity you selected. Please try again."
420
424
  auto_apply: "Auto apply"
421
425
  auto_apply_info: "Path & code will be removed"
422
426
  transit:
@@ -740,7 +744,7 @@ en:
740
744
  inventory_hold:
741
745
  acquire:
742
746
  success: "Item reserved for %{minutes} minutes"
743
- insufficient_stock: "Sorry, this item is no longer available."
747
+ insufficient_stock: "Some items in your cart are currently held by another customer or no longer available. Please update your cart or try again shortly."
744
748
  limit_exceeded: "You have too many pending reservations. Please complete or cancel a reservation before trying another."
745
749
  system_error: "We encountered an issue reserving this item. Please try again."
746
750
  lock_timeout: "Another reservation is in progress for this order. Please wait and try again."
@@ -359,6 +359,7 @@ km:
359
359
  unknown: "មិនស្គាល់"
360
360
  upsupported_payment: "មិនស្គាល់ការបង់ប្រាក់"
361
361
  selected_item_not_available_on_date: "Selected item not available on %{date}"
362
+ selected_quantity_not_available: "%{item} នៅសល់តិចជាងការអ្នកស្នើសុំរបស់អ្នក ឬអស់ពីស្តុក សូមព្យាយាមម្ដងទៀត។"
362
363
  auto_apply: "ដាក់ប្រើដោយស្វ័យប្រវត្តិ"
363
364
  auto_apply_info: "Path & code will be removed"
364
365
  device_tokens: "Device Tokens"
@@ -538,7 +539,7 @@ km:
538
539
  inventory_hold:
539
540
  acquire:
540
541
  success: "ទំនិញត្រូវបានកក់រយៈពេល %{minutes} នាទី"
541
- insufficient_stock: "សុំទោស! ទំនិញមិនមានស្តុកគ្រប់គ្រាន់សម្រាប់ការកក់របស់អ្នកទេ។"
542
+ insufficient_stock: "ទំនិញមួយចំនួននៅក្នុងកន្ត្រករបស់អ្នកកំពុងត្រូវបានកក់ដោយអតិថិជនផ្សេងទៀត ឬលែងមានស្តុក។ សូមកែប្រែកន្ត្រករបស់អ្នក ឬព្យាយាមម្តងទៀតក្នុងពេលបន្តិចទៀត។"
542
543
  limit_exceeded: "អ្នកមានការកក់ដែលរង់ចាំច្រើនពេក។ សូមបញ្ចប់ ឬលុបការកក់មួយមុនពេលព្យាយាមវិញ។"
543
544
  system_error: "មានបញ្ហាក្នុងការកក់ទំនិញនេះ។ សូមព្យាយាមម្តងទៀត។"
544
545
  lock_timeout: "កំពុងកក់សម្រាប់ការបញ្ជាទិញនេះ។ សូមរង់ចាំ ហើយព្យាយាមម្តងទៀត។"
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.8.7.pre.pre1'.freeze
2
+ VERSION = '2.8.7.pre.pre2'.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.7.pre.pre1
4
+ version: 2.8.7.pre.pre2
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
@@ -1779,6 +1779,7 @@ files:
1779
1779
  - app/overrides/spree/admin/orders/_search/intel_phone_number_search_field.html.erb.deface
1780
1780
  - app/overrides/spree/admin/orders/_search/line_item_number_search_field.html.erb.deface
1781
1781
  - app/overrides/spree/admin/orders/_search/payment_method_search_field.html.erb.deface
1782
+ - app/overrides/spree/admin/orders/_search/payment_number_search_field.html.erb.deface
1782
1783
  - app/overrides/spree/admin/orders/_search/vendor_search_field.html.erb.deface
1783
1784
  - app/overrides/spree/admin/orders/customer_details/_form/phone_number_field.html.erb.deface
1784
1785
  - app/overrides/spree/admin/payment_methods/_form/display_on_field.html.erb.deface
@@ -1791,6 +1792,7 @@ files:
1791
1792
  - app/overrides/spree/admin/products/_form/available_on.html.erb.deface
1792
1793
  - app/overrides/spree/admin/products/_form/discontinue_on.html.erb.deface
1793
1794
  - app/overrides/spree/admin/products/_form/enable_inventory_hold.html.erb.deface
1795
+ - app/overrides/spree/admin/products/_form/enable_telegram_alert.html.erb.deface
1794
1796
  - app/overrides/spree/admin/products/_form/industry_taxons.html.erb.deface
1795
1797
  - app/overrides/spree/admin/products/_form/need_confirmation_checkbox.html.erb.deface
1796
1798
  - app/overrides/spree/admin/products/_form/option_types.html.erb.deface