spree_cm_commissioner 2.0.1.pre.pre → 2.0.1.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.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_and_build_gem.yml +2 -16
  3. data/.gitignore +1 -2
  4. data/Gemfile.lock +1 -28
  5. data/Rakefile +4 -33
  6. data/app/assets/images/mailer/mail.png +0 -0
  7. data/app/assets/images/mailer/tenant_phone.png +0 -0
  8. data/app/assets/images/mailer/tenant_user.png +0 -0
  9. data/app/assets/stylesheets/spree_cm_commissioner/backend/calendar.scss +11 -8
  10. data/app/controllers/concerns/spree_cm_commissioner/transit/taxon_bitwise.rb +44 -0
  11. data/app/controllers/spree/admin/stock_managements_controller.rb +1 -63
  12. data/app/controllers/spree/api/v2/organizer/invite_guests_controller.rb +1 -1
  13. data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +31 -14
  14. data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
  15. data/app/factory/spree_cm_commissioner/invite_guest_claimed_telegram_message_factory.rb +22 -80
  16. data/app/finders/spree_cm_commissioner/line_items/find_by_variant_decorator.rb +20 -0
  17. data/app/interactors/spree_cm_commissioner/create_ticket.rb +6 -5
  18. data/app/interactors/spree_cm_commissioner/pin_code_sender.rb +0 -1
  19. data/app/interactors/spree_cm_commissioner/sms.rb +1 -1
  20. data/app/interactors/spree_cm_commissioner/user_id_token_authenticator.rb +7 -3
  21. data/app/interactors/spree_cm_commissioner/user_id_token_checker.rb +11 -3
  22. data/app/interactors/spree_cm_commissioner/user_identity_checker.rb +12 -6
  23. data/app/interactors/spree_cm_commissioner/user_registration_with_id_token.rb +7 -1
  24. data/app/jobs/spree_cm_commissioner/application_job.rb +0 -20
  25. data/app/jobs/spree_cm_commissioner/application_unique_job.rb +0 -20
  26. data/app/jobs/spree_cm_commissioner/sms_pin_code_job.rb +1 -1
  27. data/app/mailers/spree/order_mailer_decorator.rb +18 -3
  28. data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +15 -9
  29. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +12 -1
  30. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -39
  31. data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +3 -1
  32. data/app/models/concerns/spree_cm_commissioner/product_type.rb +0 -10
  33. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -1
  34. data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +1 -0
  35. data/app/models/spree_cm_commissioner/branch.rb +12 -0
  36. data/app/models/spree_cm_commissioner/guest.rb +0 -18
  37. data/app/models/spree_cm_commissioner/line_item_decorator.rb +78 -46
  38. data/app/models/spree_cm_commissioner/line_item_seat.rb +10 -0
  39. data/app/models/spree_cm_commissioner/notification_taxon.rb +1 -1
  40. data/app/models/spree_cm_commissioner/option_type_decorator.rb +11 -1
  41. data/app/models/spree_cm_commissioner/option_value_vehicle_type.rb +8 -0
  42. data/app/models/spree_cm_commissioner/order_decorator.rb +1 -30
  43. data/app/models/spree_cm_commissioner/place.rb +4 -1
  44. data/app/models/spree_cm_commissioner/product_decorator.rb +6 -10
  45. data/app/models/spree_cm_commissioner/service_calendar.rb +2 -0
  46. data/app/models/spree_cm_commissioner/state_decorator.rb +1 -0
  47. data/app/models/spree_cm_commissioner/stock/availability_checker.rb +25 -26
  48. data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +1 -2
  49. data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
  50. data/app/models/spree_cm_commissioner/stock_item_decorator.rb +0 -17
  51. data/app/models/spree_cm_commissioner/stop.rb +23 -0
  52. data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -0
  53. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +6 -0
  54. data/app/models/spree_cm_commissioner/trip.rb +10 -8
  55. data/app/models/spree_cm_commissioner/trip_connection.rb +5 -5
  56. data/app/models/spree_cm_commissioner/trip_stop.rb +25 -6
  57. data/app/models/spree_cm_commissioner/user_identity_provider.rb +26 -4
  58. data/app/models/spree_cm_commissioner/variant_decorator.rb +47 -37
  59. data/app/models/spree_cm_commissioner/variant_options.rb +23 -0
  60. data/app/models/spree_cm_commissioner/vehicle.rb +14 -9
  61. data/app/models/spree_cm_commissioner/vehicle_seat.rb +11 -0
  62. data/app/models/spree_cm_commissioner/vehicle_type.rb +76 -0
  63. data/app/models/spree_cm_commissioner/vendor_decorator.rb +17 -11
  64. data/app/models/spree_cm_commissioner/vendor_place.rb +3 -9
  65. data/app/models/spree_cm_commissioner/vendor_stop.rb +10 -0
  66. data/app/queries/spree_cm_commissioner/trip_query.rb +44 -70
  67. data/app/queries/spree_cm_commissioner/trip_search_query.rb +76 -0
  68. data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +45 -0
  69. data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +55 -0
  70. data/app/queries/spree_cm_commissioner/vendor_stop_place_query.rb +54 -0
  71. data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +0 -3
  72. data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
  73. data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +0 -2
  74. data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +0 -1
  75. data/app/serializers/spree/v2/tenant/user_serializer.rb +1 -0
  76. data/app/services/spree_cm_commissioner/user_authenticator.rb +1 -1
  77. data/app/services/spree_cm_commissioner/vehicle_option_value_creator.rb +11 -0
  78. data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +2 -7
  79. data/app/views/spree/admin/stock_managements/index.html.erb +6 -55
  80. data/app/views/spree/admin/tenants/_form.html.erb +9 -0
  81. data/app/views/spree/admin/vendors/_form.html.erb +14 -0
  82. data/app/views/spree/order_mailer/confirm_email.html.erb +27 -16
  83. data/app/views/spree_cm_commissioner/layouts/order_mailer.html.erb +5 -1
  84. data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +41 -4
  85. data/app/views/spree_cm_commissioner/order_mailer/tenant/_customer_info.html.erb +42 -0
  86. data/app/views/spree_cm_commissioner/order_mailer/tenant/_footer.html.erb +25 -0
  87. data/app/views/spree_cm_commissioner/order_mailer/tenant/_greeting.html.erb +19 -0
  88. data/app/views/spree_cm_commissioner/order_mailer/tenant/_support_contact.html.erb +33 -0
  89. data/config/initializers/spree_permitted_attributes.rb +0 -5
  90. data/config/routes.rb +2 -21
  91. data/db/migrate/20240202080634_update_counter_cache_of_vehicle_type.rb +1 -3
  92. data/db/migrate/20250709073455_add_email_fields_to_spree_vendors.rb +6 -0
  93. data/db/migrate/20250715103333_remove_indexes_from_cm_user_identity_providers.rb +13 -0
  94. data/docker-compose.yml +1 -1
  95. data/lib/cm_app_logger.rb +4 -11
  96. data/lib/generators/spree_cm_commissioner/install/install_generator.rb +11 -14
  97. data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_dashboard/spree_cm_commissioner → spree_cm_commissioner}/utilities.js +0 -4
  98. data/lib/spree_cm_commissioner/calendar_event.rb +1 -11
  99. data/lib/spree_cm_commissioner/test_helper/factories/branch_factory.rb +12 -0
  100. data/lib/spree_cm_commissioner/test_helper/factories/departure_time_option_type_factory.rb +8 -0
  101. data/lib/spree_cm_commissioner/test_helper/factories/duration_option_type_factory.rb +8 -0
  102. data/lib/spree_cm_commissioner/test_helper/factories/guest_factory.rb +0 -10
  103. data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_relatable_factory.rb +1 -1
  104. data/lib/spree_cm_commissioner/test_helper/factories/line_item_factory.rb +1 -1
  105. data/lib/spree_cm_commissioner/test_helper/factories/line_item_seat_factory.rb +7 -0
  106. data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +30 -6
  107. data/lib/spree_cm_commissioner/test_helper/factories/order_factory.rb +36 -0
  108. data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +34 -18
  109. data/lib/spree_cm_commissioner/test_helper/factories/stock_location_factory.rb +2 -2
  110. data/lib/spree_cm_commissioner/test_helper/factories/stop_factory.rb +14 -0
  111. data/lib/spree_cm_commissioner/test_helper/factories/transit_place_factory.rb +8 -0
  112. data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +3 -11
  113. data/lib/spree_cm_commissioner/test_helper/factories/user_identity_provider_factory.rb +1 -1
  114. data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +19 -41
  115. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_factory.rb +1 -1
  116. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_option_type_factory.rb +8 -0
  117. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_type_factory.rb +96 -0
  118. data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -6
  119. data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +1 -13
  120. data/lib/spree_cm_commissioner/trip_query_result.rb +0 -8
  121. data/lib/spree_cm_commissioner/trip_result.rb +3 -5
  122. data/lib/spree_cm_commissioner/trip_seat_layout_result.rb +11 -0
  123. data/lib/spree_cm_commissioner/version.rb +1 -1
  124. data/lib/spree_cm_commissioner.rb +1 -35
  125. data/spree_cm_commissioner.gemspec +0 -7
  126. metadata +35 -139
  127. data/app/controllers/spree/admin/inventory_items_controller.rb +0 -83
  128. data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +0 -42
  129. data/app/finders/spree_cm_commissioner/accommodations/find.rb +0 -37
  130. data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +0 -32
  131. data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +0 -40
  132. data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +0 -25
  133. data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +0 -44
  134. data/app/interactors/spree_cm_commissioner/stock/inventory_items_adjuster.rb +0 -13
  135. data/app/interactors/spree_cm_commissioner/stock/inventory_items_generator.rb +0 -15
  136. data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +0 -75
  137. data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +0 -32
  138. data/app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb +0 -7
  139. data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +0 -7
  140. data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +0 -11
  141. data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +0 -11
  142. data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +0 -9
  143. data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +0 -44
  144. data/app/models/spree_cm_commissioner/block.rb +0 -23
  145. data/app/models/spree_cm_commissioner/inventory.rb +0 -11
  146. data/app/models/spree_cm_commissioner/inventory_item.rb +0 -69
  147. data/app/models/spree_cm_commissioner/price_decorator.rb +0 -9
  148. data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +0 -41
  149. data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +0 -126
  150. data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +0 -36
  151. data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +0 -25
  152. data/app/models/spree_cm_commissioner/reserved_block.rb +0 -30
  153. data/app/models/spree_cm_commissioner/seat_layout.rb +0 -20
  154. data/app/models/spree_cm_commissioner/seat_section.rb +0 -16
  155. data/app/models/spree_cm_commissioner/seats/blocks_canceler.rb +0 -30
  156. data/app/models/spree_cm_commissioner/seats/blocks_holder.rb +0 -53
  157. data/app/models/spree_cm_commissioner/seats/blocks_reserver.rb +0 -49
  158. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_on_hold_by_other_guest.rb +0 -4
  159. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_other_guest.rb +0 -4
  160. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_same_guest.rb +0 -4
  161. data/app/models/spree_cm_commissioner/seats/errors/unable_to_save_reserved_block_record.rb +0 -4
  162. data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +0 -44
  163. data/app/models/spree_cm_commissioner/variant_block.rb +0 -9
  164. data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +0 -19
  165. data/app/views/spree/admin/inventory_items/show.html.erb +0 -72
  166. data/app/views/spree/admin/stock_managements/calendar.html.erb +0 -56
  167. data/config/initializers/paper_trail.rb +0 -1
  168. data/db/migrate/20250304293518_create_cm_inventory_items.rb +0 -21
  169. data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +0 -5
  170. data/db/migrate/20250502025848_add_index_to_spree_products.rb +0 -5
  171. data/db/migrate/20250502030001_add_product_type_to_spree_variants.rb +0 -5
  172. data/db/migrate/20250502030002_add_product_type_to_spree_line_items.rb +0 -5
  173. data/db/migrate/20250603035256_add_inventory_item_to_spree_prices.rb +0 -7
  174. data/db/migrate/20250619073724_drop_table_cm_line_item_seats.rb +0 -5
  175. data/db/migrate/20250619073812_drop_table_cm_vehicle_seats.rb +0 -5
  176. data/db/migrate/20250619073844_drop_table_cm_vehicle_types.rb +0 -9
  177. data/db/migrate/20250619073957_drop_table_cm_option_value_vehicle_types.rb +0 -5
  178. data/db/migrate/20250619082354_remove_unnecessary_fields_from_cm_places.rb +0 -9
  179. data/db/migrate/20250619082736_remove_route_type_from_spree_products.rb +0 -5
  180. data/db/migrate/20250619083055_remove_unnecessary_fields_from_spree_taxons.rb +0 -5
  181. data/db/migrate/20250620083055_remove_variant_id_from_cm_trips.rb +0 -5
  182. data/db/migrate/20250620090000_update_cm_trip_connections_to_use_cm_trips.rb +0 -6
  183. data/db/migrate/20250620090001_create_cm_seat_layouts.rb +0 -17
  184. data/db/migrate/20250620090002_create_cm_seat_sections.rb +0 -18
  185. data/db/migrate/20250620090003_create_cm_blocks.rb +0 -18
  186. data/db/migrate/20250624091005_create_cm_reserved_blocks.rb +0 -29
  187. data/db/migrate/20250626083642_create_cm_variant_blocks.rb +0 -24
  188. data/db/migrate/20250627023314_add_block_id_to_cm_guests.rb +0 -13
  189. data/db/migrate/20250716022821_add_location_reference_to_cm_vendor_places.rb +0 -5
  190. data/db/migrate/20250716031743_drop_table_cm_vendor_stops.rb +0 -5
  191. data/db/migrate/20250717023824_add_vendor_reference_to_cm_trips.rb +0 -5
  192. data/db/migrate/20250717041414_add_location_place_reference_to_cm_trip_stops.rb +0 -5
  193. data/db/migrate/20250717042539_rename_cm_trip_stops_stop_id_column_to_stop_place_id.rb +0 -7
  194. data/db/migrate/20250717042707_rename_cm_trips_origin_and_destination_to_origin_place_and_destination_place.rb +0 -11
  195. data/lib/spree_cm_commissioner/cached_inventory_item.rb +0 -23
  196. data/lib/spree_cm_commissioner/test_helper/factories/block_factory.rb +0 -15
  197. data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +0 -9
  198. data/lib/spree_cm_commissioner/test_helper/factories/reserved_block_factory.rb +0 -27
  199. data/lib/spree_cm_commissioner/test_helper/factories/seat_layout_factory.rb +0 -11
  200. data/lib/spree_cm_commissioner/test_helper/factories/seat_section_factory.rb +0 -16
  201. data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +0 -6
  202. data/lib/spree_cm_commissioner/test_helper/factories/trip_stop_factory.rb +0 -10
  203. data/lib/spree_cm_commissioner/test_helper/factories/variant_block_factory.rb +0 -7
  204. data/lib/tasks/create_default_non_permanent_inventory_items.rake +0 -16
  205. data/lib/tasks/ensure_correct_product_type.rake +0 -7
  206. data/lib/tasks/generate_inventory_items.rake +0 -7
@@ -42,7 +42,7 @@ module SpreeCmCommissioner
42
42
  end
43
43
 
44
44
  def sms_options
45
- opts = { from: context.from, to: context.to, body: context.body }
45
+ opts = { to: context.to, body: context.body }
46
46
  opts[:to] = sanitize(opts[:to]) if opts[:to].present?
47
47
  opts[:from] = from_number
48
48
  opts
@@ -1,6 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  class UserIdTokenAuthenticator < BaseInteractor
3
- # :id_token
3
+ # :id_token, :tenant_id (optional)
4
4
  def call
5
5
  context.user = if checker.user.nil?
6
6
  register_user
@@ -14,7 +14,11 @@ module SpreeCmCommissioner
14
14
  end
15
15
 
16
16
  def register_user
17
- register_context = SpreeCmCommissioner::UserRegistrationWithIdToken.call(id_token: context.id_token)
17
+ register_context = SpreeCmCommissioner::UserRegistrationWithIdToken.call(
18
+ id_token: context.id_token,
19
+ tenant_id: context.tenant_id
20
+ )
21
+
18
22
  register_context.user
19
23
  end
20
24
 
@@ -27,7 +31,7 @@ module SpreeCmCommissioner
27
31
  end
28
32
 
29
33
  def checker
30
- @checker ||= SpreeCmCommissioner::UserIdTokenChecker.call(id_token: context.id_token)
34
+ @checker ||= SpreeCmCommissioner::UserIdTokenChecker.call(id_token: context.id_token, tenant_id: context.tenant_id)
31
35
  @checker
32
36
  end
33
37
  end
@@ -1,6 +1,9 @@
1
1
  module SpreeCmCommissioner
2
2
  class UserIdTokenChecker < BaseInteractor
3
- # :id_token
3
+ # expects:
4
+ # context.id_token
5
+ # context.tenant_id (optional)
6
+
4
7
  def call
5
8
  firebase_id_token_context = SpreeCmCommissioner::FirebaseIdTokenProvider.call(id_token: context.id_token)
6
9
 
@@ -11,9 +14,14 @@ module SpreeCmCommissioner
11
14
  end
12
15
  end
13
16
 
14
- # :identity_type, :sub
17
+ # :identity_type, :sub, :tenant_id
15
18
  def validate_user_by_provider(provider)
16
- identity_checker = SpreeCmCommissioner::UserIdentityChecker.call(provider)
19
+ identity_checker = SpreeCmCommissioner::UserIdentityChecker.call(
20
+ identity_type: provider[:identity_type],
21
+ sub: provider[:sub],
22
+ tenant_id: context.tenant_id
23
+ )
24
+
17
25
  if identity_checker.success?
18
26
  context.user = identity_checker.user
19
27
  else
@@ -1,6 +1,10 @@
1
1
  module SpreeCmCommissioner
2
2
  class UserIdentityChecker < BaseInteractor
3
- # :identity_type, :sub
3
+ # expects:
4
+ # context.identity_type
5
+ # context.sub
6
+ # context.tenant_id (optional)
7
+
4
8
  def call
5
9
  load_user
6
10
 
@@ -11,12 +15,14 @@ module SpreeCmCommissioner
11
15
  end
12
16
 
13
17
  def load_user
14
- user_identity_provider = UserIdentityProvider.where(
15
- identity_type: context.identity_type,
16
- sub: context.sub
17
- ).first
18
+ return if context.sub.blank? || context.identity_type.blank?
19
+
20
+ user_identity_provider = UserIdentityProvider.joins(:user)
21
+ .where(identity_type: context.identity_type, sub: context.sub)
22
+ .where(spree_users: { tenant_id: context.tenant_id })
23
+ .first
18
24
 
19
- context.user = (user_identity_provider.user if user_identity_provider.present?)
25
+ context.user = user_identity_provider&.user
20
26
  end
21
27
  end
22
28
  end
@@ -15,7 +15,13 @@ module SpreeCmCommissioner
15
15
  end
16
16
 
17
17
  def register_user!(name, email)
18
- user = Spree.user_class.new(password: SecureRandom.base64(16), email: email, **name_attributes(name))
18
+ user = Spree.user_class.new(
19
+ password: SecureRandom.base64(16),
20
+ email: email,
21
+ tenant_id: context.tenant_id,
22
+ **name_attributes(name)
23
+ )
24
+
19
25
  if user.save(validate: false)
20
26
  context.user = user
21
27
  else
@@ -1,25 +1,5 @@
1
1
  module SpreeCmCommissioner
2
2
  class ApplicationJob < ::ApplicationJob
3
3
  queue_as :default
4
-
5
- around_perform :log_exceptions
6
-
7
- private
8
-
9
- def log_exceptions
10
- yield
11
- rescue StandardError => e
12
- CmAppLogger.log(
13
- label: "#{self.class.name} failed",
14
- data: {
15
- error_class: e.class.name,
16
- error_message: e.message,
17
- arguments: arguments.inspect,
18
- backtrace: e.backtrace&.first(5)&.join("\n")
19
- }
20
- )
21
-
22
- raise # Re-raise the exception to let Sidekiq handle retries or failure
23
- end
24
4
  end
25
5
  end
@@ -2,25 +2,5 @@
2
2
  module SpreeCmCommissioner
3
3
  class ApplicationUniqueJob < ::ApplicationUniqueJob
4
4
  queue_as :default
5
-
6
- around_perform :log_exceptions
7
-
8
- private
9
-
10
- def log_exceptions
11
- yield
12
- rescue StandardError => e
13
- CmAppLogger.log(
14
- label: "#{self.class.name} failed",
15
- data: {
16
- error_class: e.class.name,
17
- error_message: e.message,
18
- arguments: arguments.inspect,
19
- backtrace: e.backtrace&.first(5)&.join("\n")
20
- }
21
- )
22
-
23
- raise # Re-raise the exception to let Sidekiq handle retries or failure
24
- end
25
5
  end
26
6
  end
@@ -1,6 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  class SmsPinCodeJob < SpreeCmCommissioner::SmsJob
3
- # options = { from: xxx, to: xxxx, body: xxxx }
3
+ # options = { to: xxxx, body: xxxx }
4
4
  def perform(options)
5
5
  SpreeCmCommissioner::Sms.call(options)
6
6
  end
@@ -1,6 +1,5 @@
1
1
  module Spree
2
2
  module OrderMailerDecorator
3
- # overrided
4
3
  def cancel_email(order, resend: false)
5
4
  @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
6
5
  return false if @order.email.blank?
@@ -12,18 +11,34 @@ module Spree
12
11
  @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
13
12
  return false if @order.email.blank?
14
13
 
14
+ @tenant = @order.tenant
15
+ if @tenant.present?
16
+ @brand_color = @tenant.preferences[:brand_primary_color]
17
+ @vendor_logo_url = @tenant.active_vendor&.logo&.original_url
18
+ end
19
+
15
20
  @current_store = @order.store
16
21
  @product_type = @order.products.first&.product_type || 'accommodation'
17
22
 
18
- subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
23
+ subject = resend ? "[#{Spree.t(:resend).upcase}] " : ''
19
24
  subject += "#{@current_store&.name} Booking Confirmation ##{@order.number}"
20
25
 
21
- mail(to: @order.email, from: from_address, subject: subject, store_url: @current_store.url) do |format|
26
+ mail(to: @order.email, from: from_email_address, subject: subject, store_url: @current_store.url) do |format|
22
27
  format.html { render layout: 'spree_cm_commissioner/layouts/order_mailer' }
23
28
  format.text
24
29
  end
25
30
  end
26
31
 
32
+ private
33
+
34
+ def from_email_address
35
+ if @order.tenant.nil?
36
+ from_address
37
+ else
38
+ @order.tenant.active_vendor&.from_email
39
+ end
40
+ end
41
+
27
42
  def ticket_email(guest, email)
28
43
  @guest = guest
29
44
  @event = @guest.event
@@ -18,23 +18,29 @@ module SpreeCmCommissioner
18
18
  def date_unit
19
19
  return nil unless permanent_stock?
20
20
 
21
- date_range.size
21
+ date_range_excluding_checkout.size if accommodation?
22
22
  end
23
23
 
24
- def date_range
24
+ def date_range_excluding_checkout
25
25
  return [] unless date_present?
26
26
 
27
- (from_date.to_date..to_date.to_date).to_a
27
+ date_range = (from_date.to_date..to_date.to_date).to_a
28
+ date_range.pop if date_range.size > 1
29
+ date_range
28
30
  end
29
31
 
30
- def checkin_date
31
- from_date&.to_date
32
- end
32
+ def date_range_including_checkout
33
+ return [] unless date_present?
33
34
 
34
- def checkout_date
35
- return to_date ? to_date.to_date - 1.day : nil if accommodation?
35
+ (from_date.to_date..to_date.to_date).to_a
36
+ end
36
37
 
37
- to_date&.to_date
38
+ def date_range
39
+ if accommodation?
40
+ date_range_excluding_checkout
41
+ else
42
+ date_range_including_checkout
43
+ end
38
44
  end
39
45
 
40
46
  private
@@ -14,6 +14,13 @@ module SpreeCmCommissioner
14
14
  state_selection
15
15
  payment_option
16
16
  delivery_option
17
+ amenity
18
+ departure_time
19
+ duration
20
+ vehicle_id
21
+ origin
22
+ destination
23
+ place_id
17
24
  ].freeze
18
25
 
19
26
  RESERVED_OPTIONS = {
@@ -41,7 +48,11 @@ module SpreeCmCommissioner
41
48
  'bib-display-prefix' => 'boolean',
42
49
  'bib-pre-generation-on-create' => 'boolean',
43
50
  'seat-number-positions' => 'array',
44
- 'seat-type' => 'string'
51
+ 'origin' => 'place_id',
52
+ 'destination' => 'place_id',
53
+ 'departure-time' => 'time',
54
+ 'vehicle' => 'vehicle_id',
55
+ 'allow-seat-selection' => 'boolean'
45
56
  }.freeze
46
57
 
47
58
  included do
@@ -5,8 +5,6 @@ module SpreeCmCommissioner
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- state_machine.before_transition to: :payment, do: :hold_blocks!
9
-
10
8
  state_machine.before_transition to: :complete, do: :request, if: :need_confirmation?
11
9
  state_machine.before_transition to: :complete, do: :generate_bib_number
12
10
 
@@ -16,14 +14,10 @@ module SpreeCmCommissioner
16
14
  state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_vendors, unless: :need_confirmation?
17
15
  state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_store, unless: :need_confirmation?
18
16
 
19
- state_machine.around_transition to: :complete, do: :unstock_inventory!
20
-
21
17
  state_machine.after_transition to: :complete, do: :send_transaction_email_to_user, if: :user_has_email?
22
18
  state_machine.after_transition to: :resumed, do: :precalculate_conversion
23
- state_machine.around_transition to: :resumed, do: :unstock_inventory!
24
19
 
25
20
  state_machine.after_transition to: :canceled, do: :precalculate_conversion
26
- state_machine.after_transition to: :canceled, do: :restock_inventory!
27
21
 
28
22
  scope :accepted, -> { where(request_state: 'accepted') }
29
23
 
@@ -73,39 +67,6 @@ module SpreeCmCommissioner
73
67
  end
74
68
  end
75
69
 
76
- def unstock_inventory!
77
- ActiveRecord::Base.transaction do
78
- yield # Equal to block.call
79
-
80
- # After the transition is complete, the following code will execute first before proceeding to other `after_transition` callbacks.
81
- # This ensures that if `reserve_blocks!` or `unstock_inventory_in_redis!` fails, the state will be rolled back,
82
- # and neither the `finalize!` method nor any notifications will be triggered.
83
- # The payment will be reversed in vPago gem, and `Spree::Checkout::Complete` will be called, which checks `order.reload.complete?`.
84
- # This is critical because if the order state is complete, the payment will be marked as paid.
85
-
86
- reserve_blocks!
87
- unstock_inventory_in_redis!
88
-
89
- # We rollback only order state, and we keep payment state as it is.
90
- # We implement payment in vPago gem, and it will be reversed in the gem.
91
- # Some bank has api for refund, but some don't have the api to refund yet. So we keep the payment state as it is and refund manually.
92
- end
93
- rescue StandardError => e
94
- CmAppLogger.log(
95
- label: 'SpreeCmCommissioner::OrderStateMachine#reserve_inventory failed',
96
- data: { order_id: id, error: e.message, type: e.class.name, backtrace: e.backtrace&.first(5)&.join("\n") }
97
- )
98
-
99
- raise e
100
- end
101
-
102
- def restock_inventory!
103
- ActiveRecord::Base.transaction do
104
- cancel_blocks!
105
- restock_inventory_in_redis!
106
- end
107
- end
108
-
109
70
  def generate_bib_number
110
71
  line_items.find_each(&:generate_remaining_guests)
111
72
 
@@ -3,10 +3,12 @@ module SpreeCmCommissioner
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- delegate :subscribable?,
6
+ delegate :product_type,
7
+ :subscribable?,
7
8
  :allowed_upload_later?,
8
9
  :need_confirmation?, :need_confirmation,
9
10
  :allow_anonymous_booking,
11
+ :accommodation?, :service?, :ecommerce?,
10
12
  :allow_self_check_in,
11
13
  :allow_self_check_in?,
12
14
  :required_self_check_in_location,
@@ -6,20 +6,10 @@ module SpreeCmCommissioner
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  PRODUCT_TYPES = %i[accommodation service ecommerce transit].freeze
9
- PERMANENT_STOCK_PRODUCT_TYPES = %w[accommodation service transit].freeze
10
- PRE_INVENTORY_DAYS = { 'transit' => 90, 'accommodation' => 365, 'service' => 30 }.freeze
11
9
 
12
10
  included do
13
11
  enum product_type: PRODUCT_TYPES if table_exists? && column_names.include?('product_type')
14
12
  enum primary_product_type: PRODUCT_TYPES if table_exists? && column_names.include?('primary_product_type')
15
13
  end
16
-
17
- def permanent_stock?
18
- PERMANENT_STOCK_PRODUCT_TYPES.include?(product_type)
19
- end
20
-
21
- def pre_inventory_days
22
- PRE_INVENTORY_DAYS[product_type]
23
- end
24
14
  end
25
15
  end
@@ -3,7 +3,7 @@ module SpreeCmCommissioner
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- enum kind: { category: 0, cms: 1, event: 2, occupation: 3, nationality: 4, organization: 5 }
6
+ enum kind: { category: 0, cms: 1, event: 2, occupation: 3, nationality: 4, organization: 5, transit: 6 }
7
7
  end
8
8
  end
9
9
  end
@@ -9,6 +9,7 @@ module SpreeCmCommissioner
9
9
  preference :payment_failed_image, :string, default: ''
10
10
  preference :payment_success_image, :string, default: ''
11
11
  preference :payment_loader, :string, default: ''
12
+ preference :brand_primary_color, :string, default: ''
12
13
  end
13
14
  end
14
15
  end
@@ -0,0 +1,12 @@
1
+ require_dependency 'spree_cm_commissioner'
2
+
3
+ module SpreeCmCommissioner
4
+ class Branch < SpreeCmCommissioner::Place
5
+ belongs_to :state, class_name: 'Spree::State', optional: true
6
+ belongs_to :vendor, class_name: 'Spree::Vendor'
7
+
8
+ def validate_reference?
9
+ false
10
+ end
11
+ end
12
+ end
@@ -24,16 +24,10 @@ module SpreeCmCommissioner
24
24
  scope :none_bib, -> { where(bib_prefix: [nil, '']) }
25
25
 
26
26
  belongs_to :line_item, class_name: 'Spree::LineItem'
27
-
28
27
  has_one :variant, class_name: 'Spree::Variant', through: :line_item
29
-
30
28
  belongs_to :user, class_name: 'Spree::User'
31
29
  belongs_to :occupation, class_name: 'Spree::Taxon'
32
30
  belongs_to :nationality, class_name: 'Spree::Taxon'
33
- belongs_to :block, class_name: 'SpreeCmCommissioner::Block', optional: true
34
-
35
- has_one :reserved_block, class_name: 'SpreeCmCommissioner::ReservedBlock'
36
-
37
31
  scope :checked_ins, -> { joins(:check_in) }
38
32
  scope :no_show, -> { left_outer_joins(:check_in).where(cm_check_ins: { id: nil }) }
39
33
 
@@ -54,10 +48,6 @@ module SpreeCmCommissioner
54
48
 
55
49
  before_create :generate_bib, if: -> { line_item.reload && variant.bib_pre_generation_on_create? }
56
50
 
57
- after_create :preload_order_block_ids, if: -> { block_id.present? }
58
- after_update :preload_order_block_ids, if: :saved_change_to_block_id?
59
- after_destroy :preload_order_block_ids
60
-
61
51
  validates :seat_number, uniqueness: { scope: :event_id }, allow_nil: true, if: -> { event_id.present? }
62
52
  validates :bib_index, uniqueness: true, allow_nil: true
63
53
 
@@ -237,14 +227,6 @@ module SpreeCmCommissioner
237
227
  filled_bib_number
238
228
  end
239
229
  end
240
-
241
- def preload_order_block_ids
242
- return if line_item.blank?
243
- return if line_item.order.blank?
244
-
245
- block_ids = line_item.order.blocks.pluck(:id)
246
- line_item.order.update(preload_block_ids: block_ids)
247
- end
248
230
  end
249
231
  end
250
232
  # rubocop:enable Metrics/ClassLength
@@ -1,6 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  module LineItemDecorator
3
- def self.prepended(base) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
3
+ def self.prepended(base) # rubocop:disable Metrics/MethodLength
4
4
  include_modules(base)
5
5
 
6
6
  base.belongs_to :accepter, class_name: 'Spree::User', optional: true
@@ -10,32 +10,31 @@ module SpreeCmCommissioner
10
10
  base.has_one :google_wallet, class_name: 'SpreeCmCommissioner::GoogleWallet', through: :product
11
11
 
12
12
  base.has_many :option_types, through: :product
13
-
14
- base.has_many :inventory_items, lambda { |line_item|
15
- where(inventory_date: nil).or(where(inventory_date: line_item.date_range))
16
- }, through: :variant
17
-
18
13
  base.has_many :taxons, class_name: 'Spree::Taxon', through: :product
19
14
  base.has_many :guests, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
20
- base.has_many :guests_with_blocks, -> { where.not(block_id: nil) }, class_name: 'SpreeCmCommissioner::Guest'
21
- base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
22
15
  base.has_many :pending_guests, pending_guests_query, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
23
16
  base.has_many :product_completion_steps, class_name: 'SpreeCmCommissioner::ProductCompletionStep', through: :product
17
+ base.has_many :line_item_seats, class_name: 'SpreeCmCommissioner::LineItemSeat', dependent: :destroy
24
18
 
25
19
  base.before_save :update_vendor_id
20
+ base.before_save :update_quantity, if: :transit?
21
+
22
+ base.validate :validate_seats_reservation, if: :transit?
26
23
 
27
24
  base.before_create :add_due_date, if: :subscription?
28
- base.before_save -> { self.product_type = variant.product_type }, if: -> { product_type.nil? }
29
25
 
30
26
  base.validate :ensure_not_exceed_max_quantity_per_order, if: -> { variant&.max_quantity_per_order.present? }
31
27
 
32
28
  base.whitelisted_ransackable_associations |= %w[guests order]
33
29
  base.whitelisted_ransackable_attributes |= %w[number to_date from_date vendor_id]
34
30
 
35
- base.delegate :delivery_required?, :high_demand,
31
+ base.delegate :delivery_required?, :permanent_stock?, :high_demand, :transit?,
36
32
  to: :variant
33
+ base.delegate :discontinue_on, :product_type, :accommodation?, :service?, :ecommerce?, :need_confirmation,
34
+ to: :product
37
35
 
38
36
  base.accepts_nested_attributes_for :guests, allow_destroy: true
37
+ base.accepts_nested_attributes_for :line_item_seats, allow_destroy: true
39
38
 
40
39
  def base.json_api_columns
41
40
  json_api_columns = column_names.reject { |c| c.match(/_id$|id|preferences|(.*)password|(.*)token|(.*)api_key/) }
@@ -43,10 +42,6 @@ module SpreeCmCommissioner
43
42
  json_api_columns << :vendor_id
44
43
  end
45
44
 
46
- def discontinue_on
47
- variant.discontinue_on || product.discontinue_on
48
- end
49
-
50
45
  def base.search_by_qr_data!(data)
51
46
  matches = data.match(/(R\d+)-([A-Za-z0-9_\-]+)-(L\d+)/)&.captures
52
47
 
@@ -65,7 +60,6 @@ module SpreeCmCommissioner
65
60
  base.include SpreeCmCommissioner::LineItemDurationable
66
61
  base.include SpreeCmCommissioner::LineItemsFilterScope
67
62
  base.include SpreeCmCommissioner::LineItemGuestsConcern
68
- base.include SpreeCmCommissioner::ProductType
69
63
  base.include SpreeCmCommissioner::ProductDelegation
70
64
  base.include SpreeCmCommissioner::KycBitwise
71
65
  end
@@ -81,39 +75,24 @@ module SpreeCmCommissioner
81
75
  }
82
76
  end
83
77
 
84
- # override to calculate price per date for permanent stock
85
- def update_price_from_modifier(currency, opts)
86
- self.currency = currency
87
-
88
- # these fields can be null during this process below.
89
- # it is needed for permanent_stock?, date_range to work.
90
- self.product_type = variant.product_type
91
- self.from_date = opts.delete(:from_date)&.to_date
92
- self.to_date = opts.delete(:to_date)&.to_date
93
-
94
- base_price = variant.price_in(currency)
95
-
96
- self.price = if permanent_stock?
97
- date_range.map do |date|
98
- selected_price = variant.price_for_date(date: date, currency: currency) || base_price
99
- (selected_price.amount || 0) + variant.price_modifier_amount_in(currency, opts.merge(date: date))
100
- end.sum
101
- else
102
- (base_price.amount || 0) + variant.price_modifier_amount_in(currency, opts)
103
- end
78
+ def reservation?
79
+ date_present? && !subscription?
104
80
  end
105
81
 
106
- # override to calculate price per date for permanent stock
107
- def update_price
108
- base_price = variant.price_in(order.currency)
109
- self.price = if permanent_stock?
110
- date_range.map do |date|
111
- selected_price = variant.price_for_date(date: date, currency: order.currency) || base_price
112
- selected_price.amount || 0
113
- end.sum
114
- else
115
- base_price.amount || 0
116
- end
82
+ # date_unit could be number of nights, or days or hours depending on usecases
83
+ # For example:
84
+ # - accomodation uses number of nights.
85
+ # - appointment uses number of hours, etc.
86
+ #
87
+ # override
88
+ def amount
89
+ base_price = price * quantity
90
+
91
+ if permanent_stock? && date_unit.present?
92
+ base_price * date_unit
93
+ else
94
+ base_price
95
+ end
117
96
  end
118
97
 
119
98
  def allowed_self_check_in?
@@ -200,6 +179,8 @@ module SpreeCmCommissioner
200
179
 
201
180
  # override
202
181
  def sufficient_stock?
182
+ return transit_sufficient_stock? if variant.product.product_type == 'transit'
183
+
203
184
  SpreeCmCommissioner::Stock::LineItemAvailabilityChecker.new(self).can_supply?(quantity)
204
185
  end
205
186
 
@@ -218,6 +199,18 @@ module SpreeCmCommissioner
218
199
  errors.add(:quantity, 'exceeded_max_quantity_per_order') if quantity > variant.max_quantity_per_order
219
200
  end
220
201
 
202
+ def transit_sufficient_stock?
203
+ return selected_seats_available? if reservation_trip.allow_seat_selection
204
+
205
+ seat_quantity_available?(reservation_trip)
206
+ end
207
+
208
+ def update_quantity
209
+ return if line_item_seats.blank?
210
+
211
+ self.quantity = line_item_seats.size
212
+ end
213
+
221
214
  def update_vendor_id
222
215
  self.vendor_id = variant.vendor_id
223
216
  end
@@ -240,6 +233,45 @@ module SpreeCmCommissioner
240
233
 
241
234
  from_date + variant.month.month + day.days
242
235
  end
236
+
237
+ def validate_seats_reservation
238
+ if reservation_trip.allow_seat_selection && !selected_seats_available?
239
+ errors.add(:base, :some_seats_are_booked, message: 'Some seats are already booked')
240
+ elsif !reservation_trip.allow_seat_selection && !seat_quantity_available?(reservation_trip)
241
+ errors.add(:quantity, :exceeded_available_quantity, message: 'exceeded available quantity')
242
+ end
243
+ end
244
+
245
+ def selected_seats_available?
246
+ selected_seat_ids = line_item_seats.map(&:seat_id)
247
+ !selected_seat_ids_occupied?(selected_seat_ids)
248
+ end
249
+
250
+ def seat_quantity_available?(trip)
251
+ booked_quantity = Spree::LineItem.joins(:order)
252
+ .where(variant_id: variant_id, date: date, spree_orders: { state: 'complete' })
253
+ .where.not(spree_line_items: { id: id })
254
+ .sum(:quantity)
255
+ remaining_quantity = trip.vehicle.number_of_seats - booked_quantity
256
+ remaining_quantity >= quantity
257
+ end
258
+
259
+ def reservation_trip
260
+ return @trip if defined? @trip
261
+
262
+ route = Spree::Variant.find_by(id: variant_id).product
263
+ @trip = route.trip
264
+ end
265
+
266
+ def selected_seat_ids_occupied?(selected_seat_ids)
267
+ # check to see if there are any selected_ids exist in the line_item_seats and belongs to completed order
268
+ SpreeCmCommissioner::LineItemSeat.joins(line_item: :order)
269
+ .where(seat_id: selected_seat_ids, date: date, variant_id: variant_id, spree_orders: { state: 'complete',
270
+ canceled_at: nil
271
+ }
272
+ )
273
+ .present?
274
+ end
243
275
  end
244
276
  end
245
277
 
@@ -0,0 +1,10 @@
1
+ require_dependency 'spree_cm_commissioner'
2
+ module SpreeCmCommissioner
3
+ class LineItemSeat < SpreeCmCommissioner::Base
4
+ belongs_to :line_item, class_name: 'Spree::LineItem'
5
+ belongs_to :seat, class_name: 'SpreeCmCommissioner::VehicleSeat'
6
+ belongs_to :variant, class_name: 'Spree::Variant'
7
+
8
+ validates :date, presence: true
9
+ end
10
+ end