spree_cm_commissioner 2.5.0.pre.pre7 → 2.5.0.pre.pre9

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.bundle/config +3 -2
  3. data/.github/workflows/test_and_build_gem.yml +123 -57
  4. data/Gemfile.lock +1 -1
  5. data/Rakefile +55 -29
  6. data/app/controllers/spree/admin/base_controller_decorator.rb +3 -3
  7. data/app/controllers/spree/admin/base_import_orders_controller.rb +6 -1
  8. data/app/controllers/spree/admin/classifications_controller.rb +1 -1
  9. data/app/controllers/spree/admin/notification_sender_controller.rb +1 -1
  10. data/app/controllers/spree/api/v2/storefront/popular_route_places_controller.rb +7 -1
  11. data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +6 -6
  12. data/app/controllers/spree/api/v2/storefront/route_places_controller.rb +9 -9
  13. data/app/finders/spree_cm_commissioner/places/find_with_route.rb +10 -10
  14. data/app/finders/spree_cm_commissioner/routes/find_popular.rb +10 -14
  15. data/app/interactors/spree_cm_commissioner/create_event.rb +1 -1
  16. data/app/interactors/spree_cm_commissioner/customer_notification_cron_executor.rb +1 -1
  17. data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +3 -2
  18. data/app/jobs/spree_cm_commissioner/conversion_pre_calculator_job.rb +2 -2
  19. data/app/jobs/spree_cm_commissioner/customer_notification_sender_job.rb +3 -3
  20. data/app/jobs/spree_cm_commissioner/enqueue_cart/add_item_job.rb +7 -7
  21. data/app/jobs/spree_cm_commissioner/ensure_event_for_product_line_item_guests_job.rb +1 -1
  22. data/app/jobs/spree_cm_commissioner/event_line_items_date_syncer_job.rb +2 -2
  23. data/app/jobs/spree_cm_commissioner/export_csv_job.rb +2 -2
  24. data/app/jobs/spree_cm_commissioner/import_order_job.rb +5 -5
  25. data/app/jobs/spree_cm_commissioner/invalidate_cache_request_job.rb +2 -2
  26. data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +8 -2
  27. data/app/jobs/spree_cm_commissioner/option_type_variants_public_metadata_updater_job.rb +7 -3
  28. data/app/jobs/spree_cm_commissioner/option_value_variants_public_metadata_updater_job.rb +6 -2
  29. data/app/jobs/spree_cm_commissioner/order_complete_telegram_sender_job.rb +2 -2
  30. data/app/jobs/spree_cm_commissioner/product_event_id_to_children_syncer_job.rb +2 -2
  31. data/app/jobs/spree_cm_commissioner/reports_assigner_job.rb +2 -2
  32. data/app/jobs/spree_cm_commissioner/sms_pin_code_job.rb +1 -1
  33. data/app/jobs/spree_cm_commissioner/state_job.rb +2 -2
  34. data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +4 -1
  35. data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +2 -2
  36. data/app/jobs/spree_cm_commissioner/transit/route_fulfilled_order_count_incrementer_job.rb +2 -2
  37. data/app/jobs/spree_cm_commissioner/transit/route_order_count_incrementer_job.rb +2 -2
  38. data/app/jobs/spree_cm_commissioner/transit/route_previous_trip_count_decrementer_job.rb +2 -2
  39. data/app/jobs/spree_cm_commissioner/transit/route_trip_count_decrementer_job.rb +2 -2
  40. data/app/jobs/spree_cm_commissioner/transit/route_trip_count_incrementer_job.rb +2 -2
  41. data/app/jobs/spree_cm_commissioner/vendor_creation_telegram_alert_sender_job.rb +2 -2
  42. data/app/jobs/spree_cm_commissioner/vendor_job.rb +2 -2
  43. data/app/jobs/spree_cm_commissioner/waiting_room_session_firebase_logger_job.rb +1 -1
  44. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +1 -1
  45. data/app/models/concerns/spree_cm_commissioner/option_value_attr_type.rb +1 -1
  46. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +2 -2
  47. data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +3 -0
  48. data/app/models/spree_cm_commissioner/export.rb +1 -1
  49. data/app/models/spree_cm_commissioner/product_decorator.rb +1 -1
  50. data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +4 -1
  51. data/app/models/spree_cm_commissioner/stock_item_decorator.rb +4 -4
  52. data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -1
  53. data/app/models/spree_cm_commissioner/vendor_decorator.rb +2 -2
  54. data/app/request_schemas/spree_cm_commissioner/popular_route_places_request_schema.rb +12 -0
  55. data/app/request_schemas/spree_cm_commissioner/route_places_request_schema.rb +5 -0
  56. data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/inventory/unstock_inventory.rb +1 -1
  57. data/app/views/spree/admin/tenants/_form.html.erb +18 -0
  58. data/app/views/spree/admin/tenants/form/_footer.html.erb +31 -0
  59. data/app/views/spree/admin/tenants/form/_social.html.erb +31 -0
  60. data/app/views/spree/order_mailer/confirm_email.html.erb +1 -1
  61. data/app/views/spree_cm_commissioner/layouts/order_mailer.html.erb +1 -1
  62. data/app/views/spree_cm_commissioner/order_mailer/tenant/_footer.html.erb +13 -6
  63. data/app/views/spree_cm_commissioner/order_mailer/tenant/_support_contact.html.erb +23 -24
  64. data/bin/run_spec_group +101 -0
  65. data/db/migrate/20251209022924_add_contact_fields_to_cm_tenants.rb +9 -0
  66. data/lib/cm_app_logger.rb +28 -14
  67. data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -0
  68. data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +3 -2
  69. data/lib/spree_cm_commissioner/version.rb +1 -1
  70. metadata +7 -2
@@ -1,24 +1,31 @@
1
1
  <div class="email-footer_inner">
2
- <div class="mb-24"><%= store.description%></div>
3
- <div class="mb-24 f-14"><%= store.address%></div>
2
+ <div class="mb-24"><%= tenant&.description %></div>
3
+ <div class="mb-24 f-14"><%= tenant&.address %></div>
4
4
  <h2 class="mb-24">Connect with us</h2>
5
5
  <table class="mb-24 social_icons">
6
6
  <tbody>
7
7
  <tr>
8
- <% if store.facebook? %>
8
+ <% if tenant&.preferred_facebook.present? %>
9
9
  <td class="social_icon">
10
- <%= link_to store.facebook, target: :_blank do %>
10
+ <%= link_to tenant.preferred_facebook, target: :_blank do %>
11
11
  <%= image_tag "mailer/facebook.png", class: "mail-icon"%>
12
12
  <% end %>
13
13
  </td>
14
14
  <% end %>
15
- <% if store.instagram?%>
15
+ <% if tenant&.preferred_instagram.present? %>
16
16
  <td class="social_icon">
17
- <%= link_to store.instagram, target: :_blank do %>
17
+ <%= link_to tenant.preferred_instagram, target: :_blank do %>
18
18
  <%= image_tag "mailer/instagram.png", class: "mail-icon"%>
19
19
  <% end %>
20
20
  </td>
21
21
  <% end %>
22
+ <% if tenant&.preferred_twitter.present? %>
23
+ <td class="social_icon">
24
+ <%= link_to tenant.preferred_twitter, target: :_blank do %>
25
+ <%= image_tag "mailer/twitter.png", class: "mail-icon"%>
26
+ <% end %>
27
+ </td>
28
+ <% end %>
22
29
  </tr>
23
30
  </tbody>
24
31
  </table>
@@ -1,33 +1,32 @@
1
1
  <div class="content-cell">
2
- <div class="container">
3
- <h2><%= I18n.t('mail.order_mailer.bookmeplus_support')%></h2>
4
- <div class="flex two-columns">
5
- <div class="two-columns-item">
6
- <div class="flex two-columns-item_detail">
7
- <div class="two-columns_icon"><%= image_tag "mailer/tenant_phone.png", class: "mail-icon"%></div>
8
- <div class="two-columns_text-container">
9
- <p class="two-columns_title">Contact</p>
10
- <% if @order.store.contact_phone.present? %>
11
- <p class="two-columns_description">
12
- <%= link_to @order.store.contact_phone, "tel:#{@order.store.contact_phone}" %>
13
- </p>
14
- <% end %>
2
+ <div class="container">
3
+ <h2><%= name %> Support</h2>
4
+ <div class="flex two-columns">
5
+ <div class="two-columns-item">
6
+ <div class="flex two-columns-item_detail">
7
+ <div class="two-columns_icon"><%= image_tag "mailer/tenant_phone.png", class: "mail-icon"%></div>
8
+ <div class="two-columns_text-container">
9
+ <p class="two-columns_title">Contact</p>
10
+ <% if order&.tenant&.contact_phone&.present? %>
11
+ <p class="two-columns_description">
12
+ <%= link_to order.tenant.contact_phone, "tel:#{order.tenant.contact_phone}" %>
13
+ </p>
14
+ <% end %>
15
+ </div>
15
16
  </div>
16
17
  </div>
17
- </div>
18
- <div class="vertical-separater"></div>
19
- <div class="two-columns-item">
20
- <div class="flex two-columns-item_detail">
21
- <div class="two-columns_icon"><%= image_tag "mailer/mail.png", class: "mail-icon"%></div>
22
- <div class="two-columns_text-container">
23
- <p class="two-columns_title">Email</p>
18
+ <div class="vertical-separater"></div>
19
+ <div class="two-columns-item">
20
+ <div class="flex two-columns-item_detail">
21
+ <div class="two-columns_icon"><%= image_tag "mailer/mail.png", class: "mail-icon"%></div>
22
+ <div class="two-columns_text-container">
23
+ <p class="two-columns_title">Email</p>
24
24
  <p class="two-columns_description">
25
- <%= @vendor&.support_email.present? ? link_to(@vendor.support_email, "mailto:#{@vendor.support_email}") : "N/A" %>
26
- </p>
27
-
25
+ <%= order&.tenant&.customer_support_email.present? ? link_to(order.tenant.customer_support_email, "mailto:#{order.tenant.customer_support_email}") : "N/A" %>
26
+ </p>
27
+ </div>
28
28
  </div>
29
29
  </div>
30
30
  </div>
31
31
  </div>
32
32
  </div>
33
- </div>
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ============================================================================
4
+ # Spec Group Runner - Parallel Test Execution
5
+ # ============================================================================
6
+ #
7
+ # PURPOSE:
8
+ # Split all spec files into N equal groups and run a specific group.
9
+ # Used for parallel test execution in CI (GitHub Actions) and locally.
10
+ #
11
+ # HOW IT WORKS:
12
+ # 1. Finds all *_spec.rb files in spec/ directory
13
+ # 2. Sorts them alphabetically for consistent ordering
14
+ # 3. Divides them into N equal groups (e.g., 10 groups)
15
+ # 4. Runs RSpec on the files in the specified group
16
+ #
17
+ # USAGE:
18
+ # bin/run_spec_group <group_number> <total_groups>
19
+ #
20
+ # EXAMPLES:
21
+ # bin/run_spec_group 1 10 # Run group 1 out of 10 (files 1-15 if 150 total)
22
+ # bin/run_spec_group 5 10 # Run group 5 out of 10 (files 61-75 if 150 total)
23
+ # bin/run_spec_group 1 3 # Run first third of all specs
24
+ #
25
+ # CI USAGE (GitHub Actions):
26
+ # - Matrix strategy runs 10-12 parallel jobs (groups 1-12)
27
+ # - Each job runs ~1/10th or ~1/12th of total specs
28
+ # - Total test time = slowest group time (not sum of all)
29
+ # - Example: 150 specs × 2s each = 300s sequential
30
+ # 150 specs ÷ 10 groups = 15 specs × 2s = 30s parallel
31
+ # 150 specs ÷ 12 groups = 13 specs × 2s = 26s parallel
32
+ #
33
+ # LOCAL USAGE:
34
+ # - Run specific group to debug failing tests
35
+ # - Run multiple groups in parallel terminals
36
+ # - Faster iteration than running all specs
37
+ #
38
+ # OUTPUT:
39
+ # - Shows total spec count
40
+ # - Shows files per group
41
+ # - Lists all files in current group
42
+ # - Runs RSpec with those files
43
+ #
44
+ # WHERE USED:
45
+ # - .github/workflows/test_and_build_gem.yml (test job, matrix strategy)
46
+ # - Can be run locally for debugging
47
+ #
48
+ # ============================================================================
49
+
50
+ group_num = ARGV[0]&.to_i
51
+ total_groups = ARGV[1]&.to_i
52
+
53
+ unless group_num && group_num > 0 && group_num <= total_groups
54
+ puts "Usage: bin/run_spec_group <group_number> [total_groups]"
55
+ puts "Example: bin/run_spec_group 1 10"
56
+ puts " Runs group 1 out of 10 total groups"
57
+ exit 1
58
+ end
59
+
60
+ spec_dir = File.expand_path('../spec', __dir__)
61
+
62
+ # Find all spec files and sort for consistent ordering
63
+ all_spec_files = Dir.glob("#{spec_dir}/**/*_spec.rb").sort
64
+
65
+ if all_spec_files.empty?
66
+ puts "❌ No spec files found in #{spec_dir}"
67
+ exit 1
68
+ end
69
+
70
+ # Calculate files per group
71
+ files_per_group = (all_spec_files.length.to_f / total_groups).ceil
72
+
73
+ # Get the files for this specific group
74
+ start_idx = (group_num - 1) * files_per_group
75
+ end_idx = [start_idx + files_per_group - 1, all_spec_files.length - 1].min
76
+
77
+ if start_idx >= all_spec_files.length
78
+ puts "⚠️ Group #{group_num} has no spec files (total: #{all_spec_files.length} files across #{total_groups} groups)"
79
+ exit 0
80
+ end
81
+
82
+ group_files = all_spec_files[start_idx..end_idx]
83
+
84
+ puts "=" * 80
85
+ puts "Running Group #{group_num}/#{total_groups}"
86
+ puts "Total spec files: #{all_spec_files.length}"
87
+ puts "Files per group: ~#{files_per_group}"
88
+ puts "This group: #{group_files.length} files (#{start_idx + 1}-#{end_idx + 1})"
89
+ puts "=" * 80
90
+ puts
91
+ puts "📋 Files in this group:"
92
+ group_files.each_with_index do |file, idx|
93
+ relative_path = file.sub("#{spec_dir}/", '')
94
+ puts " #{start_idx + idx + 1}. #{relative_path}"
95
+ end
96
+ puts
97
+ puts "=" * 80
98
+ puts
99
+
100
+ # Run rspec with the specific files
101
+ exec("bundle", "exec", "rspec", *group_files)
@@ -0,0 +1,9 @@
1
+ class AddContactFieldsToCmTenants < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :cm_tenants, :customer_support_email, :string, if_not_exists: true
4
+ add_column :cm_tenants, :address, :text, if_not_exists: true
5
+ add_column :cm_tenants, :contact_phone, :string, if_not_exists: true
6
+ add_index :cm_tenants, :customer_support_email, if_not_exists: true
7
+ add_index :cm_tenants, :contact_phone, if_not_exists: true
8
+ end
9
+ end
data/lib/cm_app_logger.rb CHANGED
@@ -10,7 +10,7 @@ module CmAppLogger
10
10
  # Capture the block's return value and return it to preserve existing behavior for callers expecting that value.
11
11
  block_result = yield
12
12
 
13
- message[:start_time] = start_time
13
+ message[:start_time] = start_time.iso8601(3)
14
14
  message[:duration_ms] = (Time.current - start_time) * 1000
15
15
  message[:result] = safe_serialize(block_result)
16
16
  Rails.logger.info(message.to_json)
@@ -26,20 +26,34 @@ module CmAppLogger
26
26
  Rails.logger.error(message.to_json)
27
27
  end
28
28
 
29
- def self.safe_serialize(obj)
30
- case obj
31
- when Hash
32
- obj.transform_values { |v| safe_serialize(v) }
33
- when Array
34
- obj.map { |item| safe_serialize(item) }
35
- when NilClass, TrueClass, FalseClass, Numeric, String, Symbol
36
- obj
37
- when ActiveJob::Base
38
- # Don't serialize the entire job object - just its class and ID
39
- { job_class: obj.class.name, job_id: obj.job_id }
29
+ # Safely serializes objects for JSON logging.
30
+ #
31
+ # @param obj [Object] The object to serialize
32
+ # @param depth [Integer] Internal parameter tracking recursion depth (max: 50)
33
+ # @return [Object] A JSON-safe representation of the input object
34
+ def self.safe_serialize(obj, depth: 0) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
35
+ return '[Max Depth Exceeded]' if depth > 50
36
+
37
+ if obj.is_a?(Hash)
38
+ obj.each_with_object({}) do |(k, v), memo|
39
+ memo[safe_serialize(k, depth: depth + 1)] = safe_serialize(v, depth: depth + 1)
40
+ end
41
+ elsif obj.is_a?(Array)
42
+ obj.map { |item| safe_serialize(item, depth: depth + 1) }
43
+ elsif obj.is_a?(Date)
44
+ obj.iso8601
45
+ elsif obj.is_a?(Time) || obj.is_a?(DateTime) || obj.is_a?(ActiveSupport::TimeWithZone)
46
+ obj.iso8601(3)
47
+ elsif obj.is_a?(ActiveJob::Base)
48
+ {
49
+ job_class: obj.class.name,
50
+ job_id: obj.job_id,
51
+ arguments: safe_serialize(obj.arguments, depth: depth + 1)
52
+ }
53
+ elsif obj.respond_to?(:id)
54
+ { class: obj.class.name, id: obj.id }
40
55
  else
41
- # For other objects, try to_s as fallback
42
- obj.respond_to?(:id) ? { class: obj.class.name, id: obj.id } : obj.to_s
56
+ obj.to_s
43
57
  end
44
58
  end
45
59
  end
@@ -5,6 +5,7 @@ FactoryBot.define do
5
5
  end
6
6
 
7
7
  factory :cm_vendor, parent: :vendor do
8
+ sequence(:name) { |n| "#{FFaker::Company.name} #{n}#{Kernel.rand(9999)}" }
8
9
  state { :active }
9
10
  default_state_id { Spree::State.first&.id }
10
11
  primary_product_type { :ecommerce }
@@ -1,6 +1,6 @@
1
1
  FactoryBot.define do
2
2
  factory :cm_location_vendor_place, class: SpreeCmCommissioner::VendorPlace do
3
- association :vendor, factory: :vendor
3
+ association :vendor, factory: :cm_vendor
4
4
  association :place, factory: :cm_place
5
5
 
6
6
  distance { FFaker::Number.decimal }
@@ -10,7 +10,7 @@ FactoryBot.define do
10
10
  end
11
11
 
12
12
  factory :cm_vendor_place, class: SpreeCmCommissioner::VendorPlace do
13
- association :vendor, factory: :vendor
13
+ association :vendor, factory: :cm_vendor
14
14
  association :place, factory: :cm_place
15
15
  association :location, factory: :cm_location_vendor_place
16
16
 
@@ -28,6 +28,7 @@ FactoryBot.define do
28
28
 
29
29
  trait :location do
30
30
  place_type { :location }
31
+ location { nil }
31
32
  end
32
33
  end
33
34
  end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.5.0-pre7'.freeze
2
+ VERSION = '2.5.0.pre.pre9'.freeze
3
3
 
4
4
  module_function
5
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_cm_commissioner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0.pre.pre7
4
+ version: 2.5.0.pre.pre9
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-16 00:00:00.000000000 Z
11
+ date: 2025-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -1791,6 +1791,7 @@ files:
1791
1791
  - app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_schema.rb
1792
1792
  - app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_update_schema.rb
1793
1793
  - app/request_schemas/spree_cm_commissioner/inventory_item_schema.rb
1794
+ - app/request_schemas/spree_cm_commissioner/popular_route_places_request_schema.rb
1794
1795
  - app/request_schemas/spree_cm_commissioner/profile_image_request_schema.rb
1795
1796
  - app/request_schemas/spree_cm_commissioner/route_places_request_schema.rb
1796
1797
  - app/request_schemas/spree_cm_commissioner/seat_layout_schema.rb
@@ -2244,6 +2245,8 @@ files:
2244
2245
  - app/views/spree/admin/tenants/_form.html.erb
2245
2246
  - app/views/spree/admin/tenants/_tabs.html.erb
2246
2247
  - app/views/spree/admin/tenants/edit.html.erb
2248
+ - app/views/spree/admin/tenants/form/_footer.html.erb
2249
+ - app/views/spree/admin/tenants/form/_social.html.erb
2247
2250
  - app/views/spree/admin/tenants/index.html.erb
2248
2251
  - app/views/spree/admin/tenants/new.html.erb
2249
2252
  - app/views/spree/admin/user_events/_events.html.erb
@@ -2527,6 +2530,7 @@ files:
2527
2530
  - app/views/spree_cm_commissioner/team_invite_mailer/_mailer_stylesheets.html.erb
2528
2531
  - app/views/spree_cm_commissioner/team_invite_mailer/send_team_invite_email.html.erb
2529
2532
  - bin/rails
2533
+ - bin/run_spec_group
2530
2534
  - config/brakeman.yml
2531
2535
  - config/initializers/assets.rb
2532
2536
  - config/initializers/doorkeeper.rb
@@ -2946,6 +2950,7 @@ files:
2946
2950
  - db/migrate/20251017101605_create_cm_integration_mappings.rb
2947
2951
  - db/migrate/20251113081853_add_index_to_spree_orders_updated_at.rb
2948
2952
  - db/migrate/20251119093000_add_tenant_id_to_cm_vendor_places.rb
2953
+ - db/migrate/20251209022924_add_contact_fields_to_cm_tenants.rb
2949
2954
  - docker-compose.yml
2950
2955
  - docs/api/scoped-access-token-endpoints.md
2951
2956
  - docs/option_types/attr_types.md