spree_cm_commissioner 2.0.3.pre.pre5 → 2.0.3.pre.pre.pre7

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 (215) 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 +4 -39
  5. data/Rakefile +4 -33
  6. data/app/assets/stylesheets/spree_cm_commissioner/backend/calendar.scss +11 -8
  7. data/app/controllers/concerns/spree_cm_commissioner/transit/taxon_bitwise.rb +44 -0
  8. data/app/controllers/spree/admin/stock_managements_controller.rb +1 -63
  9. data/app/controllers/spree/api/v2/operator/event_charts_controller.rb +2 -8
  10. data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +31 -14
  11. data/app/controllers/spree/api/v2/storefront/dynamic_fields_controller.rb +42 -0
  12. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +2 -0
  13. data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
  14. data/app/controllers/spree_cm_commissioner/admin/products_controller_decorator.rb +14 -0
  15. data/app/finders/spree_cm_commissioner/line_items/find_by_variant_decorator.rb +20 -0
  16. data/app/interactors/spree_cm_commissioner/create_vendor.rb +11 -1
  17. data/app/jobs/spree_cm_commissioner/application_job.rb +0 -20
  18. data/app/jobs/spree_cm_commissioner/application_unique_job.rb +0 -20
  19. data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +15 -18
  20. data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +15 -29
  21. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +12 -2
  22. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -39
  23. data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +3 -1
  24. data/app/models/concerns/spree_cm_commissioner/product_type.rb +0 -10
  25. data/app/models/concerns/spree_cm_commissioner/route_type.rb +1 -1
  26. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -1
  27. data/app/models/spree_cm_commissioner/address_decorator.rb +2 -22
  28. data/app/models/spree_cm_commissioner/branch.rb +12 -0
  29. data/app/models/spree_cm_commissioner/guest.rb +85 -71
  30. data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +37 -27
  31. data/app/models/spree_cm_commissioner/line_item_decorator.rb +78 -47
  32. data/app/models/spree_cm_commissioner/line_item_seat.rb +10 -0
  33. data/app/models/spree_cm_commissioner/notification_taxon.rb +1 -1
  34. data/app/models/spree_cm_commissioner/option_type_decorator.rb +11 -1
  35. data/app/models/spree_cm_commissioner/option_value_vehicle_type.rb +8 -0
  36. data/app/models/spree_cm_commissioner/order_decorator.rb +1 -31
  37. data/app/models/spree_cm_commissioner/place.rb +4 -1
  38. data/app/models/spree_cm_commissioner/product_decorator.rb +35 -10
  39. data/app/models/spree_cm_commissioner/service_calendar.rb +2 -0
  40. data/app/models/spree_cm_commissioner/state_decorator.rb +1 -0
  41. data/app/models/spree_cm_commissioner/stock/availability_checker.rb +25 -26
  42. data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +1 -2
  43. data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
  44. data/app/models/spree_cm_commissioner/stock_item_decorator.rb +0 -17
  45. data/app/models/spree_cm_commissioner/stop.rb +23 -0
  46. data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -0
  47. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +6 -0
  48. data/app/models/spree_cm_commissioner/trip.rb +10 -17
  49. data/app/models/spree_cm_commissioner/trip_connection.rb +5 -5
  50. data/app/models/spree_cm_commissioner/trip_stop.rb +21 -10
  51. data/app/models/spree_cm_commissioner/user_decorator.rb +1 -1
  52. data/app/models/spree_cm_commissioner/variant_decorator.rb +47 -37
  53. data/app/models/spree_cm_commissioner/variant_options.rb +23 -0
  54. data/app/models/spree_cm_commissioner/vehicle.rb +16 -11
  55. data/app/models/spree_cm_commissioner/vehicle_seat.rb +11 -0
  56. data/app/models/spree_cm_commissioner/vehicle_type.rb +76 -0
  57. data/app/models/spree_cm_commissioner/vendor_decorator.rb +14 -11
  58. data/app/models/spree_cm_commissioner/vendor_place.rb +3 -13
  59. data/app/models/spree_cm_commissioner/vendor_stop.rb +10 -0
  60. data/app/overrides/spree/admin/products/_form/industry_taxons.html.erb.deface +26 -0
  61. data/app/overrides/spree/admin/products/_form/taxons.html.erb.deface +26 -0
  62. data/app/queries/spree_cm_commissioner/trip_query.rb +131 -110
  63. data/app/queries/spree_cm_commissioner/trip_search_query.rb +76 -0
  64. data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +45 -0
  65. data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +55 -0
  66. data/app/queries/spree_cm_commissioner/vendor_stop_place_query.rb +54 -0
  67. data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +0 -3
  68. data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
  69. data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +0 -2
  70. data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +0 -1
  71. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +2 -0
  72. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +1 -3
  73. data/app/services/spree_cm_commissioner/vehicle_option_value_creator.rb +11 -0
  74. data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +2 -7
  75. data/app/views/spree/admin/stock_managements/index.html.erb +6 -55
  76. data/config/initializers/spree_permitted_attributes.rb +0 -5
  77. data/config/routes.rb +3 -24
  78. data/db/migrate/20240202080634_update_counter_cache_of_vehicle_type.rb +1 -3
  79. data/db/migrate/20250812015522_remove_unique_indexes_from_cm_user_identity_providers.rb +8 -0
  80. data/db/migrate/20250812121745_add_data_fill_stage_phase_to_cm_guests.rb +5 -0
  81. data/db/migrate/20250814073854_add_call_to_action_to_spree_products.rb +5 -0
  82. data/docker-compose.yml +1 -1
  83. data/lib/cm_app_logger.rb +4 -11
  84. data/lib/generators/spree_cm_commissioner/install/install_generator.rb +11 -14
  85. data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_dashboard/spree_cm_commissioner → spree_cm_commissioner}/utilities.js +0 -4
  86. data/lib/spree_cm_commissioner/calendar_event.rb +1 -11
  87. data/lib/spree_cm_commissioner/test_helper/factories/branch_factory.rb +12 -0
  88. data/lib/spree_cm_commissioner/test_helper/factories/departure_time_option_type_factory.rb +8 -0
  89. data/lib/spree_cm_commissioner/test_helper/factories/duration_option_type_factory.rb +8 -0
  90. data/lib/spree_cm_commissioner/test_helper/factories/guest_factory.rb +0 -10
  91. data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_relatable_factory.rb +1 -1
  92. data/lib/spree_cm_commissioner/test_helper/factories/line_item_factory.rb +1 -1
  93. data/lib/spree_cm_commissioner/test_helper/factories/line_item_seat_factory.rb +7 -0
  94. data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +30 -6
  95. data/lib/spree_cm_commissioner/test_helper/factories/order_factory.rb +36 -0
  96. data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +34 -18
  97. data/lib/spree_cm_commissioner/test_helper/factories/stock_location_factory.rb +2 -2
  98. data/lib/spree_cm_commissioner/test_helper/factories/stop_factory.rb +14 -0
  99. data/lib/spree_cm_commissioner/test_helper/factories/transit_place_factory.rb +8 -0
  100. data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +3 -11
  101. data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +19 -41
  102. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_factory.rb +1 -1
  103. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_option_type_factory.rb +8 -0
  104. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_type_factory.rb +96 -0
  105. data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -6
  106. data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +1 -13
  107. data/lib/spree_cm_commissioner/trip_query_result.rb +0 -16
  108. data/lib/spree_cm_commissioner/trip_result.rb +10 -12
  109. data/lib/spree_cm_commissioner/trip_seat_layout_result.rb +11 -0
  110. data/lib/spree_cm_commissioner/version.rb +1 -1
  111. data/lib/spree_cm_commissioner.rb +1 -37
  112. data/spree_cm_commissioner.gemspec +0 -7
  113. metadata +32 -161
  114. data/app/controllers/spree/admin/inventory_items_controller.rb +0 -83
  115. data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +0 -42
  116. data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +0 -60
  117. data/app/finders/spree_cm_commissioner/accommodations/find.rb +0 -37
  118. data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +0 -32
  119. data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +0 -40
  120. data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +0 -25
  121. data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +0 -44
  122. data/app/interactors/spree_cm_commissioner/stock/inventory_items_adjuster.rb +0 -13
  123. data/app/interactors/spree_cm_commissioner/stock/inventory_items_generator.rb +0 -15
  124. data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +0 -75
  125. data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +0 -32
  126. data/app/interactors/spree_cm_commissioner/taxi_trip_creator.rb +0 -66
  127. data/app/interactors/spree_cm_commissioner/transit/draft_order_creator.rb +0 -119
  128. data/app/interactors/spree_cm_commissioner/variant_block_updater.rb +0 -62
  129. data/app/interactors/spree_cm_commissioner/vehicle_updater.rb +0 -41
  130. data/app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb +0 -7
  131. data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +0 -7
  132. data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +0 -11
  133. data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +0 -11
  134. data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +0 -9
  135. data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +0 -89
  136. data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +0 -44
  137. data/app/models/concerns/spree_cm_commissioner/vehicle_type.rb +0 -11
  138. data/app/models/spree_cm_commissioner/block.rb +0 -43
  139. data/app/models/spree_cm_commissioner/inventory.rb +0 -11
  140. data/app/models/spree_cm_commissioner/inventory_item.rb +0 -69
  141. data/app/models/spree_cm_commissioner/price_decorator.rb +0 -9
  142. data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +0 -41
  143. data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +0 -126
  144. data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +0 -36
  145. data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +0 -25
  146. data/app/models/spree_cm_commissioner/reserved_block.rb +0 -30
  147. data/app/models/spree_cm_commissioner/saved_guest.rb +0 -13
  148. data/app/models/spree_cm_commissioner/seat_layout.rb +0 -20
  149. data/app/models/spree_cm_commissioner/seat_section.rb +0 -16
  150. data/app/models/spree_cm_commissioner/seats/blocks_canceler.rb +0 -30
  151. data/app/models/spree_cm_commissioner/seats/blocks_holder.rb +0 -53
  152. data/app/models/spree_cm_commissioner/seats/blocks_reserver.rb +0 -49
  153. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_on_hold_by_other_guest.rb +0 -4
  154. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_other_guest.rb +0 -4
  155. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_same_guest.rb +0 -4
  156. data/app/models/spree_cm_commissioner/seats/errors/unable_to_save_reserved_block_record.rb +0 -4
  157. data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +0 -44
  158. data/app/models/spree_cm_commissioner/variant_block.rb +0 -17
  159. data/app/request_schemas/spree_cm_commissioner/trip_search_request_schema.rb +0 -20
  160. data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +0 -19
  161. data/app/serializers/spree/v2/storefront/amenity_serializer.rb +0 -15
  162. data/app/serializers/spree/v2/storefront/trip_query_result_serializer.rb +0 -14
  163. data/app/serializers/spree/v2/storefront/trip_result_serializer.rb +0 -16
  164. data/app/serializers/spree/v2/storefront/trip_vehicle_serializer.rb +0 -11
  165. data/app/serializers/spree/v2/storefront/trip_vendor_serializer.rb +0 -13
  166. data/app/views/spree/admin/inventory_items/show.html.erb +0 -72
  167. data/app/views/spree/admin/stock_managements/calendar.html.erb +0 -56
  168. data/config/initializers/paper_trail.rb +0 -1
  169. data/db/migrate/20250122000000_move_route_type_from_vehicles_to_trips.rb +0 -7
  170. data/db/migrate/20250304293518_create_cm_inventory_items.rb +0 -21
  171. data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +0 -5
  172. data/db/migrate/20250502025848_add_index_to_spree_products.rb +0 -5
  173. data/db/migrate/20250502030001_add_product_type_to_spree_variants.rb +0 -5
  174. data/db/migrate/20250502030002_add_product_type_to_spree_line_items.rb +0 -5
  175. data/db/migrate/20250603035256_add_inventory_item_to_spree_prices.rb +0 -7
  176. data/db/migrate/20250619073724_drop_table_cm_line_item_seats.rb +0 -5
  177. data/db/migrate/20250619073812_drop_table_cm_vehicle_seats.rb +0 -5
  178. data/db/migrate/20250619073844_drop_table_cm_vehicle_types.rb +0 -9
  179. data/db/migrate/20250619073957_drop_table_cm_option_value_vehicle_types.rb +0 -5
  180. data/db/migrate/20250619082354_remove_unnecessary_fields_from_cm_places.rb +0 -9
  181. data/db/migrate/20250619082736_remove_route_type_from_spree_products.rb +0 -5
  182. data/db/migrate/20250619083055_remove_unnecessary_fields_from_spree_taxons.rb +0 -5
  183. data/db/migrate/20250620083055_remove_variant_id_from_cm_trips.rb +0 -5
  184. data/db/migrate/20250620090000_update_cm_trip_connections_to_use_cm_trips.rb +0 -6
  185. data/db/migrate/20250620090001_create_cm_seat_layouts.rb +0 -17
  186. data/db/migrate/20250620090002_create_cm_seat_sections.rb +0 -18
  187. data/db/migrate/20250620090003_create_cm_blocks.rb +0 -18
  188. data/db/migrate/20250624091005_create_cm_reserved_blocks.rb +0 -29
  189. data/db/migrate/20250626083642_create_cm_variant_blocks.rb +0 -24
  190. data/db/migrate/20250627023314_add_block_id_to_cm_guests.rb +0 -13
  191. data/db/migrate/20250716022821_add_location_reference_to_cm_vendor_places.rb +0 -5
  192. data/db/migrate/20250716031743_drop_table_cm_vendor_stops.rb +0 -5
  193. data/db/migrate/20250717023824_add_vendor_reference_to_cm_trips.rb +0 -5
  194. data/db/migrate/20250717041414_add_location_place_reference_to_cm_trip_stops.rb +0 -5
  195. data/db/migrate/20250717042539_rename_cm_trip_stops_stop_id_column_to_stop_place_id.rb +0 -7
  196. data/db/migrate/20250717042707_rename_cm_trips_origin_and_destination_to_origin_place_and_destination_place.rb +0 -11
  197. data/db/migrate/20250721080738_add_vehicle_type_to_cm_vehicles.rb +0 -7
  198. data/db/migrate/20250725092713_add_block_type_to_cm_blocks.rb +0 -5
  199. data/db/migrate/20250731062816_add_departure_time_and_arrival_time_to_trip_stop.rb +0 -6
  200. data/db/migrate/20250807033035_create_spree_cm_commissioner_saved_guests.rb +0 -23
  201. data/db/migrate/20250808054835_add_saved_guest_reference_to_cm_blocks.rb +0 -5
  202. data/lib/spree_cm_commissioner/cached_inventory_item.rb +0 -23
  203. data/lib/spree_cm_commissioner/test_helper/factories/block_factory.rb +0 -16
  204. data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +0 -9
  205. data/lib/spree_cm_commissioner/test_helper/factories/reserved_block_factory.rb +0 -27
  206. data/lib/spree_cm_commissioner/test_helper/factories/seat_layout_factory.rb +0 -11
  207. data/lib/spree_cm_commissioner/test_helper/factories/seat_section_factory.rb +0 -16
  208. data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +0 -6
  209. data/lib/spree_cm_commissioner/test_helper/factories/trip_stop_factory.rb +0 -13
  210. data/lib/spree_cm_commissioner/test_helper/factories/variant_block_factory.rb +0 -7
  211. data/lib/spree_cm_commissioner/transit/leg.rb +0 -23
  212. data/lib/spree_cm_commissioner/transit/seat_selection.rb +0 -19
  213. data/lib/tasks/create_default_non_permanent_inventory_items.rake +0 -16
  214. data/lib/tasks/ensure_correct_product_type.rake +0 -7
  215. data/lib/tasks/generate_inventory_items.rake +0 -7
@@ -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
@@ -18,32 +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
- return [] unless permanent_stock?
27
-
28
- # For transit products (e.g., bus, train), only return the departure day,
29
- # as the booking represents a single trip rather than a duration.
30
- return [from_date.to_date] if transit?
31
26
 
32
- # For products with a stay or usage period (e.g., hotel, car rental, activities),
33
- # return the full date range from start to end, inclusive.
34
- return (from_date.to_date..to_date.to_date).to_a if service? || accommodation?
35
-
36
- []
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
37
30
  end
38
31
 
39
- def checkin_date
40
- from_date&.to_datetime
41
- end
32
+ def date_range_including_checkout
33
+ return [] unless date_present?
42
34
 
43
- def checkout_date
44
- return to_date ? to_date.to_datetime + 1.day : nil if accommodation?
35
+ (from_date.to_date..to_date.to_date).to_a
36
+ end
45
37
 
46
- to_date&.to_datetime
38
+ def date_range
39
+ if accommodation?
40
+ date_range_excluding_checkout
41
+ else
42
+ date_range_including_checkout
43
+ end
47
44
  end
48
45
 
49
46
  private
@@ -1,21 +1,13 @@
1
- # Number of guests are depend on the variant, but user is allowed to input custom number of guests
2
- # which will be stored in public_metadata.
3
- #
4
- # metadata {
5
- # 'number_of_adults': 2,
6
- # 'number_of_kids': 1,
7
- # }
8
1
  module SpreeCmCommissioner
9
2
  module LineItemGuestsConcern
10
3
  extend ActiveSupport::Concern
11
4
 
12
5
  included do
13
- validate :validate_total_adults, if: -> { valid_integer_metadata?('number_of_adults') }
14
- validate :validate_total_kids, if: -> { valid_integer_metadata?('number_of_kids') }
6
+ validate :validate_total_adults, if: -> { public_metadata[:number_of_adults].present? }
7
+ validate :validate_total_kids, if: -> { public_metadata[:number_of_kids].present? }
15
8
  end
16
9
 
17
- def number_of_adults = public_metadata['number_of_adults']&.to_i || (variant.number_of_adults * quantity)
18
- def number_of_kids = public_metadata['number_of_kids']&.to_i || (variant.number_of_kids * quantity)
10
+ def remaining_total_guests = [number_of_guests - guests.size, 0].max
19
11
  def number_of_guests = number_of_adults + number_of_kids
20
12
 
21
13
  def allowed_extra_adults = variant.allowed_extra_adults * quantity
@@ -24,7 +16,8 @@ module SpreeCmCommissioner
24
16
  def allowed_total_adults = (variant.number_of_adults * quantity) + allowed_extra_adults
25
17
  def allowed_total_kids = (variant.number_of_kids * quantity) + allowed_extra_kids
26
18
 
27
- def remaining_total_guests = [number_of_guests - guests.size, 0].max
19
+ def number_of_adults = public_metadata[:number_of_adults] || (variant.number_of_adults * quantity)
20
+ def number_of_kids = public_metadata[:number_of_kids] || (variant.number_of_kids * quantity)
28
21
 
29
22
  def generate_remaining_guests
30
23
  return if remaining_total_guests.zero?
@@ -35,17 +28,15 @@ module SpreeCmCommissioner
35
28
  end
36
29
 
37
30
  def extra_adults
38
- return 0 unless valid_integer_metadata?('number_of_adults')
39
31
  return 0 unless extra_adults?
40
32
 
41
- public_metadata['number_of_adults'].to_i - (variant.number_of_adults * quantity)
33
+ public_metadata[:number_of_adults] - (variant.number_of_adults * quantity)
42
34
  end
43
35
 
44
36
  def extra_kids
45
- return 0 unless valid_integer_metadata?('number_of_kids')
46
37
  return 0 unless extra_kids?
47
38
 
48
- public_metadata['number_of_kids'].to_i - (variant.number_of_kids * quantity)
39
+ public_metadata[:number_of_kids] - (variant.number_of_kids * quantity)
49
40
  end
50
41
 
51
42
  def guest_options
@@ -64,30 +55,25 @@ module SpreeCmCommissioner
64
55
  end
65
56
 
66
57
  def extra_adults?
67
- return false unless valid_integer_metadata?('number_of_adults')
68
-
69
- public_metadata['number_of_adults'].to_i > variant.number_of_adults * quantity
58
+ public_metadata[:number_of_adults].present? && public_metadata[:number_of_adults] > variant.number_of_adults * quantity
70
59
  end
71
60
 
72
61
  def extra_kids?
73
- return false unless valid_integer_metadata?('number_of_kids')
74
-
75
- public_metadata['number_of_kids'].to_i > variant.number_of_kids * quantity
62
+ public_metadata[:number_of_kids].present? && public_metadata[:number_of_kids] > variant.number_of_kids * quantity
76
63
  end
77
64
 
78
65
  private
79
66
 
80
- def valid_integer_metadata?(key)
81
- value = public_metadata[key.to_s]
82
- value.present? && value.to_s.match?(/\A-?\d+\z/)
83
- end
84
-
85
67
  def validate_total_adults
86
- errors.add(:quantity, 'exceed_total_adults') if public_metadata['number_of_adults'].to_i > allowed_total_adults
68
+ return if public_metadata[:number_of_adults] <= allowed_total_adults
69
+
70
+ errors.add(:quantity, 'exceed_total_adults')
87
71
  end
88
72
 
89
73
  def validate_total_kids
90
- errors.add(:quantity, 'exceed_total_kids') if public_metadata['number_of_kids'].to_i > allowed_total_kids
74
+ return if public_metadata[:number_of_kids] <= allowed_total_kids
75
+
76
+ errors.add(:quantity, 'exceed_total_kids')
91
77
  end
92
78
  end
93
79
  end
@@ -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,8 +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',
45
- 'intercity-taxi' => 'string'
51
+ 'origin' => 'place_id',
52
+ 'destination' => 'place_id',
53
+ 'departure-time' => 'time',
54
+ 'vehicle' => 'vehicle_id',
55
+ 'allow-seat-selection' => 'boolean'
46
56
  }.freeze
47
57
 
48
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
@@ -2,7 +2,7 @@ module SpreeCmCommissioner
2
2
  module RouteType
3
3
  extend ActiveSupport::Concern
4
4
 
5
- ROUTE_TYPES = %i[bus intercity_taxi airport_shuttle rails ferry].freeze
5
+ ROUTE_TYPES = %i[automobile subway rails ferry].freeze
6
6
 
7
7
  included do
8
8
  enum route_type: ROUTE_TYPES if table_exists? && column_names.include?('route_type')
@@ -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, industry: 7 }
7
7
  end
8
8
  end
9
9
  end
@@ -1,30 +1,10 @@
1
1
  module SpreeCmCommissioner
2
2
  module AddressDecorator
3
3
  def self.prepended(base)
4
+ # Field is not mandatory
4
5
  base.enum gender: { :not_selected => 0, :male => 1, :female => 2, :other => 3 }
5
-
6
- base.validates :address1, presence: true, if: :require_address1?
7
- base.validates :city, presence: true, if: :require_city?
8
- base.validates :country, presence: true, if: :require_country?
9
- end
10
-
11
- def require_address1?
12
- false
13
- end
14
-
15
- def require_city?
16
- false
17
- end
18
-
19
- def require_country?
20
- false
21
6
  end
22
7
  end
23
8
  end
24
9
 
25
- unless Spree::Address.included_modules.include?(SpreeCmCommissioner::AddressDecorator)
26
- # remove validators for the specified attributes
27
- %i[address1 city country].each { |attr| Spree::Address._validators.delete(attr) }
28
-
29
- Spree::Address.prepend(SpreeCmCommissioner::AddressDecorator)
30
- end
10
+ Spree::Address.prepend(SpreeCmCommissioner::AddressDecorator) unless Spree::Address.included_modules.include?(SpreeCmCommissioner::AddressDecorator)
@@ -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,17 +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
- belongs_to :saved_guest, class_name: 'SpreeCmCommissioner::SavedGuest', optional: true
35
-
36
- has_one :reserved_block, class_name: 'SpreeCmCommissioner::ReservedBlock'
37
-
38
31
  scope :checked_ins, -> { joins(:check_in) }
39
32
  scope :no_show, -> { left_outer_joins(:check_in).where(cm_check_ins: { id: nil }) }
40
33
 
@@ -55,15 +48,9 @@ module SpreeCmCommissioner
55
48
 
56
49
  before_create :generate_bib, if: -> { line_item.reload && variant.bib_pre_generation_on_create? }
57
50
 
58
- after_create :preload_order_block_ids, if: -> { block_id.present? }
59
- after_update :preload_order_block_ids, if: :saved_change_to_block_id?
60
- after_destroy :preload_order_block_ids
61
-
62
51
  validates :seat_number, uniqueness: { scope: :event_id }, allow_nil: true, if: -> { event_id.present? }
63
52
  validates :bib_index, uniqueness: true, allow_nil: true
64
53
 
65
- validate :validate_block, if: :should_validate_block?
66
-
67
54
  self.whitelisted_ransackable_associations = %w[id_card event line_item]
68
55
  self.whitelisted_ransackable_attributes = %w[first_name last_name phone_number gender contact occupation_id card_type created_at check_in_status]
69
56
 
@@ -226,97 +213,124 @@ module SpreeCmCommissioner
226
213
  save!
227
214
  end
228
215
 
229
- def missing_dynamic_fields_for_stage(stage)
230
- required_fields = line_item.product.dynamic_fields.where(data_fill_stage: stage)
231
- filled_ids = guest_dynamic_fields.map(&:dynamic_field_id)
216
+ # bib_number: 345, bib_prefix: 5KM, bib_zerofill: 5 => return 5KM00345
217
+ # bib_number: 345, bib_prefix: 5KM, bib_zerofill: 2 => return 5KM345
218
+ def formatted_bib_number
219
+ return nil if bib_prefix.blank?
220
+ return nil if bib_number.blank?
232
221
 
233
- required_fields.reject { |field| filled_ids.include?(field.id) }
222
+ filled_bib_number = bib_number.to_s.rjust(line_item.variant.bib_zerofill.to_i, '0')
223
+
224
+ if bib_display_prefix?
225
+ "#{bib_prefix}#{filled_bib_number}"
226
+ else
227
+ filled_bib_number
228
+ end
234
229
  end
235
230
 
236
231
  def all_required_dynamic_fields_completed?(stage)
237
232
  missing_dynamic_fields_for_stage(stage).blank?
238
233
  end
239
234
 
240
- def validate_dynamic_fields_for_phase(phase)
241
- required_fields = line_item.product.dynamic_fields.where(data_fill_stage: phase)
242
- filled_ids = guest_dynamic_fields.map(&:dynamic_field_id)
235
+ state_machine :data_fill_stage_phase, initial: 'pre_registration' do
236
+ state 'pre_registration', value: 'pre_registration'
237
+ state 'post_registration', value: 'post_registration'
238
+ state 'during_check_in', value: 'during_check_in'
239
+ state 'completed', value: 'completed'
240
+
241
+ event :complete_pre_registration do
242
+ transition 'pre_registration' => 'post_registration',
243
+ if: -> (guest) { guest.pre_registration_completed? && guest.post_registration_fields? }
244
+ transition 'pre_registration' => 'during_check_in',
245
+ if: -> (guest) { guest.pre_registration_completed? && !guest.post_registration_fields? && guest.during_check_in_fields? }
246
+ transition 'pre_registration' => 'completed',
247
+ if: -> (guest) { guest.pre_registration_completed? && !guest.post_registration_fields? && !guest.during_check_in_fields? }
248
+ end
249
+
250
+ event :complete_post_registration do
251
+ transition 'post_registration' => 'during_check_in',
252
+ if: -> (guest) { guest.post_registration_completed? && guest.during_check_in_fields? }
253
+ transition 'post_registration' => 'completed',
254
+ if: -> (guest) { guest.post_registration_completed? && !guest.during_check_in_fields? }
255
+ end
256
+
257
+ event :complete_check_in do
258
+ transition 'during_check_in' => 'completed',
259
+ if: -> (guest) { guest.check_in_completed? }
260
+ end
261
+ end
243
262
 
244
- required_fields.each do |field|
245
- errors.add(:base, "#{field.label} is required for #{phase} phase") unless filled_ids.include?(field.id)
263
+ def save_and_move_to_next_stage(_transition = nil)
264
+ # Trigger state machine transitions based on completion status
265
+ case data_fill_stage_phase
266
+ when 'pre_registration'
267
+ complete_pre_registration! if pre_registration_completed?
268
+ when 'post_registration'
269
+ complete_post_registration! if post_registration_completed?
270
+ when 'during_check_in'
271
+ complete_check_in! if check_in_completed?
246
272
  end
247
273
  end
248
274
 
275
+ def completed_phases
276
+ phases = []
277
+ phases << 'pre_registration' if pre_registration_completed?
278
+ phases << 'post_registration' if post_registration_completed?
279
+ phases << 'during_check_in' if check_in_completed?
280
+ phases
281
+ end
282
+
249
283
  def pre_registration_completed?
250
- return true unless line_item.product.dynamic_fields.pre_registration.any?
284
+ return true unless line_item&.product&.dynamic_fields&.pre_registration&.any?
251
285
 
252
- pre_registration_fields_completed?
286
+ required_fields = line_item.product.dynamic_fields.pre_registration.pluck(:id)
287
+ filled_fields = guest_dynamic_fields.where(dynamic_field_id: required_fields).pluck(:dynamic_field_id)
288
+ (required_fields - filled_fields).empty?
253
289
  end
254
290
 
255
291
  def post_registration_completed?
256
- return true unless line_item.product.dynamic_fields.post_registration.any?
292
+ return true unless line_item&.product&.dynamic_fields&.post_registration&.any?
257
293
 
258
- post_registration_fields_completed?
294
+ required_fields = line_item.product.dynamic_fields.post_registration.pluck(:id)
295
+ filled_fields = guest_dynamic_fields.where(dynamic_field_id: required_fields).pluck(:dynamic_field_id)
296
+ (required_fields - filled_fields).empty?
259
297
  end
260
298
 
261
299
  def check_in_completed?
262
- return true unless line_item.product.dynamic_fields.during_check_in.any?
263
-
264
- check_in_fields_completed?
265
- end
300
+ return true unless line_item&.product&.dynamic_fields&.during_check_in&.any?
266
301
 
267
- def current_collection_phase
268
- if check_in.present?
269
- :during_check_in
270
- elsif line_item.order.completed?
271
- :post_registration
272
- else
273
- :pre_registration
274
- end
302
+ required_fields = line_item.product.dynamic_fields.during_check_in.pluck(:id)
303
+ filled_fields = guest_dynamic_fields.where(dynamic_field_id: required_fields).pluck(:dynamic_field_id)
304
+ (required_fields - filled_fields).empty?
275
305
  end
276
306
 
277
- def phase_completion_status
278
- {
279
- pre_registration: pre_registration_completed?,
280
- post_registration: post_registration_completed?,
281
- during_check_in: check_in_completed?
282
- }
307
+ def pre_registration_fields?
308
+ line_item&.product&.dynamic_fields&.pre_registration&.any?
283
309
  end
284
310
 
285
- # bib_number: 345, bib_prefix: 5KM, bib_zerofill: 5 => return 5KM00345
286
- # bib_number: 345, bib_prefix: 5KM, bib_zerofill: 2 => return 5KM345
287
- def formatted_bib_number
288
- return nil if bib_prefix.blank?
289
- return nil if bib_number.blank?
290
-
291
- filled_bib_number = bib_number.to_s.rjust(line_item.variant.bib_zerofill.to_i, '0')
292
-
293
- if bib_display_prefix?
294
- "#{bib_prefix}#{filled_bib_number}"
295
- else
296
- filled_bib_number
297
- end
311
+ def post_registration_fields?
312
+ line_item&.product&.dynamic_fields&.post_registration&.any?
298
313
  end
299
314
 
300
- # validate only if block_id is present AND (new record OR block_id is changing)
301
- # goal: don't bother re-validating when block_id stays the same
302
- def should_validate_block?
303
- block_id.present? && (new_record? || will_save_change_to_block_id?)
315
+ def during_check_in_fields?
316
+ line_item&.product&.dynamic_fields&.during_check_in&.any?
304
317
  end
305
318
 
306
- def validate_block
307
- return if block_id.blank?
308
- return if line_item.blank? || line_item.variant.blank?
309
- return if line_item.variant.variant_blocks.exists?(block_id: block_id)
319
+ private
310
320
 
311
- errors.add(:block, "does not exist in variant #{line_item.variant_id}")
321
+ def product_dynamic_fields
322
+ @product_dynamic_fields ||= line_item.product.dynamic_fields
312
323
  end
313
324
 
314
- def preload_order_block_ids
315
- return if line_item.blank?
316
- return if line_item.order.blank?
325
+ def missing_dynamic_fields_for_stage(stage)
326
+ return [] if line_item.blank? || line_item.product.blank?
327
+
328
+ # Cache product dynamic fields to avoid multiple queries
329
+ @product_dynamic_fields ||= line_item.product.dynamic_fields
330
+ required_fields = @product_dynamic_fields.where(data_fill_stage: stage)
331
+ filled_ids = guest_dynamic_fields&.pluck(:dynamic_field_id) || []
317
332
 
318
- block_ids = line_item.order.blocks.pluck(:id)
319
- line_item.order.update(preload_block_ids: block_ids)
333
+ required_fields.reject { |field| filled_ids.include?(field.id) }
320
334
  end
321
335
  end
322
336
  end