spree_cm_commissioner 2.0.0.pre.pre → 2.0.0

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 (259) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +3 -0
  3. data/.github/workflows/test_and_build_gem.yml +2 -16
  4. data/.gitignore +1 -2
  5. data/Gemfile.lock +1 -32
  6. data/Rakefile +4 -33
  7. data/app/assets/images/cm-hangmeas-checkout_image.svg +63 -0
  8. data/app/assets/images/cm-hangmeas-failed.svg +56 -0
  9. data/app/assets/images/cm-hangmeas-loader.svg +50 -0
  10. data/app/assets/images/cm-hangmeas-success.svg +51 -0
  11. data/app/assets/images/mailer/mail.png +0 -0
  12. data/app/assets/images/mailer/tenant_phone.png +0 -0
  13. data/app/assets/images/mailer/tenant_user.png +0 -0
  14. data/app/assets/javascripts/spree_cm_commissioner/backend.js +1 -0
  15. data/app/assets/javascripts/spree_cm_commissioner/tenant_payment_icon_fields.js +65 -0
  16. data/app/assets/stylesheets/spree_cm_commissioner/backend/calendar.scss +11 -8
  17. data/app/assets/stylesheets/spree_cm_commissioner/backend/commissioner_admin.css.scss +1 -0
  18. data/app/assets/stylesheets/spree_cm_commissioner/backend/tenant_payment_icon_fields.scss +60 -0
  19. data/app/controllers/concerns/spree_cm_commissioner/content_cachable.rb +2 -1
  20. data/app/controllers/concerns/spree_cm_commissioner/transit/taxon_bitwise.rb +44 -0
  21. data/app/controllers/spree/admin/event_blazer_queries_controller.rb +11 -4
  22. data/app/controllers/spree/admin/stock_managements_controller.rb +1 -63
  23. data/app/controllers/spree/admin/tenants_controller.rb +8 -0
  24. data/app/controllers/spree/admin/trip_blazer_queries_controller.rb +35 -0
  25. data/app/controllers/spree/api/v2/organizer/invite_crews_controller.rb +33 -0
  26. data/app/controllers/spree/api/v2/organizer/invite_guests_controller.rb +1 -1
  27. data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +31 -14
  28. data/app/controllers/spree/api/v2/storefront/dynamic_field_options_controller.rb +5 -1
  29. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +30 -4
  30. data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
  31. data/app/controllers/spree/api/v2/tenant/checkout_controller.rb +2 -0
  32. data/app/controllers/spree_cm_commissioner/admin/variants_controller_decorator.rb +1 -1
  33. data/app/controllers/spree_cm_commissioner/api/v2/storefront/checkout_controller_decorator.rb +11 -0
  34. data/app/controllers/spree_cm_commissioner/well_known_controller.rb +31 -17
  35. data/app/factory/spree_cm_commissioner/invite_guest_claimed_telegram_message_factory.rb +23 -81
  36. data/app/finders/spree_cm_commissioner/line_items/find_by_variant_decorator.rb +20 -0
  37. data/app/interactors/spree_cm_commissioner/apple_app_site_association_fetcher.rb +27 -0
  38. data/app/interactors/spree_cm_commissioner/asset_links_fetcher.rb +27 -0
  39. data/app/interactors/spree_cm_commissioner/create_ticket.rb +6 -5
  40. data/app/interactors/spree_cm_commissioner/crew_invite_link_handler.rb +48 -0
  41. data/app/interactors/spree_cm_commissioner/pin_code_sender.rb +0 -1
  42. data/app/interactors/spree_cm_commissioner/sms.rb +1 -1
  43. data/app/interactors/spree_cm_commissioner/telegram_chats_auto_finder.rb +144 -0
  44. data/app/interactors/spree_cm_commissioner/user_id_token_authenticator.rb +7 -3
  45. data/app/interactors/spree_cm_commissioner/user_id_token_checker.rb +11 -3
  46. data/app/interactors/spree_cm_commissioner/user_identity_checker.rb +12 -6
  47. data/app/interactors/spree_cm_commissioner/user_registration_with_id_token.rb +7 -1
  48. data/app/interactors/spree_cm_commissioner/vattanac_bank_initiator.rb +5 -1
  49. data/app/jobs/spree_cm_commissioner/application_job.rb +0 -20
  50. data/app/jobs/spree_cm_commissioner/application_unique_job.rb +0 -20
  51. data/app/jobs/spree_cm_commissioner/sms_pin_code_job.rb +1 -1
  52. data/app/mailers/spree/order_mailer_decorator.rb +18 -3
  53. data/app/models/concerns/spree_cm_commissioner/event_check_in_flowable.rb +30 -0
  54. data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +15 -9
  55. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +13 -1
  56. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -39
  57. data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +3 -1
  58. data/app/models/concerns/spree_cm_commissioner/product_type.rb +0 -10
  59. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -1
  60. data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +5 -0
  61. data/app/models/spree_cm_commissioner/blazer_queryable.rb +8 -0
  62. data/app/models/spree_cm_commissioner/branch.rb +12 -0
  63. data/app/models/spree_cm_commissioner/crew_invite_link.rb +4 -0
  64. data/app/models/spree_cm_commissioner/dynamic_field.rb +37 -3
  65. data/app/models/spree_cm_commissioner/dynamic_field_option.rb +7 -1
  66. data/app/models/spree_cm_commissioner/guest.rb +57 -19
  67. data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +61 -3
  68. data/app/models/spree_cm_commissioner/invite.rb +4 -6
  69. data/app/models/spree_cm_commissioner/invite_team.rb +3 -1
  70. data/app/models/spree_cm_commissioner/line_item_decorator.rb +78 -46
  71. data/app/models/spree_cm_commissioner/line_item_seat.rb +10 -0
  72. data/app/models/spree_cm_commissioner/notification_taxon.rb +1 -1
  73. data/app/models/spree_cm_commissioner/option_type_decorator.rb +11 -1
  74. data/app/models/spree_cm_commissioner/option_value_vehicle_type.rb +8 -0
  75. data/app/models/spree_cm_commissioner/order_decorator.rb +1 -30
  76. data/app/models/spree_cm_commissioner/pin_code.rb +3 -2
  77. data/app/models/spree_cm_commissioner/pin_code_telegram.rb +28 -0
  78. data/app/models/spree_cm_commissioner/place.rb +3 -1
  79. data/app/models/spree_cm_commissioner/product_decorator.rb +26 -10
  80. data/app/models/spree_cm_commissioner/promotion_category_decorator.rb +11 -0
  81. data/app/models/spree_cm_commissioner/service_calendar.rb +2 -0
  82. data/app/models/spree_cm_commissioner/state_decorator.rb +1 -0
  83. data/app/models/spree_cm_commissioner/stock/availability_checker.rb +25 -26
  84. data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +1 -2
  85. data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
  86. data/app/models/spree_cm_commissioner/stock_item_decorator.rb +0 -17
  87. data/app/models/spree_cm_commissioner/stop.rb +23 -0
  88. data/app/models/spree_cm_commissioner/taxon_decorator.rb +6 -2
  89. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +6 -0
  90. data/app/models/spree_cm_commissioner/telegram_chat.rb +6 -0
  91. data/app/models/spree_cm_commissioner/trip.rb +10 -12
  92. data/app/models/spree_cm_commissioner/trip_connection.rb +5 -5
  93. data/app/models/spree_cm_commissioner/trip_stop.rb +3 -2
  94. data/app/models/spree_cm_commissioner/user_identity_provider.rb +26 -4
  95. data/app/models/spree_cm_commissioner/user_taxon.rb +1 -0
  96. data/app/models/spree_cm_commissioner/variant_decorator.rb +47 -36
  97. data/app/models/spree_cm_commissioner/variant_options.rb +23 -0
  98. data/app/models/spree_cm_commissioner/vehicle.rb +14 -9
  99. data/app/models/spree_cm_commissioner/vehicle_seat.rb +11 -0
  100. data/app/models/spree_cm_commissioner/vehicle_type.rb +76 -0
  101. data/app/models/spree_cm_commissioner/vendor_decorator.rb +13 -7
  102. data/app/models/spree_cm_commissioner/vendor_place.rb +5 -6
  103. data/app/models/spree_cm_commissioner/vendor_stop.rb +2 -1
  104. data/app/overrides/spree/admin/taxons/_form/check_in_flows.html.erb.deface +18 -0
  105. data/app/overrides/spree/admin/variants/_form/kyc_field.html.erb.deface +2 -2
  106. data/app/queries/spree_cm_commissioner/guest_searcher_query.rb +45 -3
  107. data/app/queries/spree_cm_commissioner/trip_query.rb +26 -23
  108. data/app/queries/spree_cm_commissioner/trip_search_query.rb +76 -0
  109. data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +45 -0
  110. data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +55 -0
  111. data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +0 -3
  112. data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
  113. data/app/serializers/spree/v2/organizer/invite_crews_serializer.rb +11 -0
  114. data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +0 -2
  115. data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +0 -1
  116. data/app/serializers/spree/v2/tenant/user_serializer.rb +1 -0
  117. data/app/serializers/spree_cm_commissioner/v2/operator/dashboard_crew_event_serializer.rb +4 -1
  118. data/app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_option_serializer.rb +1 -3
  119. data/app/serializers/spree_cm_commissioner/v2/storefront/dynamic_field_serializer.rb +1 -3
  120. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_dynamic_field_serializer.rb +2 -1
  121. data/app/services/spree_cm_commissioner/organizer/export_guest_csv_service.rb +23 -15
  122. data/app/services/spree_cm_commissioner/user_authenticator.rb +1 -1
  123. data/app/services/spree_cm_commissioner/vehicle_option_value_creator.rb +11 -0
  124. data/app/views/blazer/queries/_content.html.erb +8 -0
  125. data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +2 -7
  126. data/app/views/spree/admin/stock_managements/index.html.erb +6 -55
  127. data/app/views/spree/admin/tenant_vendors/index.html.erb +9 -2
  128. data/app/views/spree/admin/tenants/_form.html.erb +118 -42
  129. data/app/views/spree/admin/tenants/edit.html.erb +2 -1
  130. data/app/views/spree/admin/tenants/index.html.erb +7 -1
  131. data/app/views/spree/admin/vendors/_form.html.erb +14 -0
  132. data/app/views/spree/order_mailer/confirm_email.html.erb +27 -16
  133. data/app/views/spree_cm_commissioner/layouts/order_mailer.html.erb +5 -1
  134. data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +41 -4
  135. data/app/views/spree_cm_commissioner/order_mailer/tenant/_customer_info.html.erb +42 -0
  136. data/app/views/spree_cm_commissioner/order_mailer/tenant/_footer.html.erb +25 -0
  137. data/app/views/spree_cm_commissioner/order_mailer/tenant/_greeting.html.erb +19 -0
  138. data/app/views/spree_cm_commissioner/order_mailer/tenant/_support_contact.html.erb +33 -0
  139. data/config/initializers/spree_permitted_attributes.rb +2 -5
  140. data/config/locales/en.yml +10 -1
  141. data/config/routes.rb +6 -22
  142. data/db/migrate/20240202080634_update_counter_cache_of_vehicle_type.rb +1 -3
  143. data/db/migrate/20250616084219_add_description_to_cm_vendor_place.rb +5 -0
  144. data/db/migrate/20250630103536_create_cm_telegram_chats.rb +13 -0
  145. data/db/migrate/20250701093203_add_configurations_to_cm_dynamic_field.rb +6 -0
  146. data/db/migrate/20250702091305_add_dynamic_field_option_to_guest_dynamic_field.rb +5 -0
  147. data/db/migrate/20250702091935_add_status_to_dynamic_field_option.rb +5 -0
  148. data/db/migrate/20250707032008_add_vendor_id_to_spree_category.rb +7 -0
  149. data/db/migrate/20250709073455_add_email_fields_to_spree_vendors.rb +6 -0
  150. data/db/migrate/20250711092937_add_position_to_cm_dynamic_fields.rb +11 -0
  151. data/db/migrate/20250711093045_add_position_to_cm_dynamic_field_options.rb +11 -0
  152. data/db/migrate/20250714121508_rename_cm_taxon_blazer_query_to_blazer_queryables.rb +7 -0
  153. data/db/migrate/20250714124323_make_cm_blazer_queryables_polymorphic.rb +19 -0
  154. data/db/migrate/20250715103333_remove_indexes_from_cm_user_identity_providers.rb +13 -0
  155. data/db/migrate/20250718071620_add_data_fill_stage_to_dynamic_fields.rb +5 -0
  156. data/docker-compose.yml +1 -1
  157. data/lib/cm_app_logger.rb +4 -11
  158. data/lib/generators/spree_cm_commissioner/install/install_generator.rb +11 -14
  159. data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_dashboard/spree_cm_commissioner → spree_cm_commissioner}/utilities.js +0 -4
  160. data/lib/spree_cm_commissioner/calendar_event.rb +1 -11
  161. data/lib/spree_cm_commissioner/test_helper/factories/branch_factory.rb +12 -0
  162. data/lib/spree_cm_commissioner/test_helper/factories/departure_time_option_type_factory.rb +8 -0
  163. data/lib/spree_cm_commissioner/test_helper/factories/duration_option_type_factory.rb +8 -0
  164. data/lib/spree_cm_commissioner/test_helper/factories/guest_factory.rb +0 -10
  165. data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_relatable_factory.rb +1 -1
  166. data/lib/spree_cm_commissioner/test_helper/factories/line_item_factory.rb +1 -1
  167. data/lib/spree_cm_commissioner/test_helper/factories/line_item_seat_factory.rb +7 -0
  168. data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +30 -6
  169. data/lib/spree_cm_commissioner/test_helper/factories/order_factory.rb +36 -0
  170. data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +34 -18
  171. data/lib/spree_cm_commissioner/test_helper/factories/stock_location_factory.rb +2 -2
  172. data/lib/spree_cm_commissioner/test_helper/factories/stop_factory.rb +14 -0
  173. data/lib/spree_cm_commissioner/test_helper/factories/transit_place_factory.rb +8 -0
  174. data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +3 -10
  175. data/lib/spree_cm_commissioner/test_helper/factories/user_identity_provider_factory.rb +1 -1
  176. data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +19 -41
  177. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_factory.rb +1 -1
  178. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_option_type_factory.rb +8 -0
  179. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_type_factory.rb +96 -0
  180. data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -1
  181. data/lib/spree_cm_commissioner/trip_seat_layout_result.rb +11 -0
  182. data/lib/spree_cm_commissioner/version.rb +1 -1
  183. data/lib/spree_cm_commissioner.rb +1 -35
  184. data/spree_cm_commissioner.gemspec +0 -7
  185. metadata +66 -135
  186. data/app/controllers/spree/admin/inventory_items_controller.rb +0 -83
  187. data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +0 -42
  188. data/app/finders/spree_cm_commissioner/accommodations/find.rb +0 -37
  189. data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +0 -32
  190. data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +0 -40
  191. data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +0 -25
  192. data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +0 -44
  193. data/app/interactors/spree_cm_commissioner/stock/inventory_items_adjuster.rb +0 -13
  194. data/app/interactors/spree_cm_commissioner/stock/inventory_items_generator.rb +0 -15
  195. data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +0 -75
  196. data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +0 -32
  197. data/app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb +0 -7
  198. data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +0 -7
  199. data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +0 -11
  200. data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +0 -11
  201. data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +0 -9
  202. data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +0 -44
  203. data/app/models/spree_cm_commissioner/block.rb +0 -23
  204. data/app/models/spree_cm_commissioner/inventory.rb +0 -11
  205. data/app/models/spree_cm_commissioner/inventory_item.rb +0 -69
  206. data/app/models/spree_cm_commissioner/price_decorator.rb +0 -9
  207. data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +0 -41
  208. data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +0 -126
  209. data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +0 -36
  210. data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +0 -25
  211. data/app/models/spree_cm_commissioner/reserved_block.rb +0 -30
  212. data/app/models/spree_cm_commissioner/seat_layout.rb +0 -20
  213. data/app/models/spree_cm_commissioner/seat_section.rb +0 -16
  214. data/app/models/spree_cm_commissioner/seats/blocks_canceler.rb +0 -30
  215. data/app/models/spree_cm_commissioner/seats/blocks_holder.rb +0 -53
  216. data/app/models/spree_cm_commissioner/seats/blocks_reserver.rb +0 -49
  217. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_on_hold_by_other_guest.rb +0 -4
  218. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_other_guest.rb +0 -4
  219. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_same_guest.rb +0 -4
  220. data/app/models/spree_cm_commissioner/seats/errors/unable_to_save_reserved_block_record.rb +0 -4
  221. data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +0 -44
  222. data/app/models/spree_cm_commissioner/taxon_blazer_query.rb +0 -8
  223. data/app/models/spree_cm_commissioner/variant_block.rb +0 -9
  224. data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +0 -19
  225. data/app/views/spree/admin/inventory_items/show.html.erb +0 -72
  226. data/app/views/spree/admin/stock_managements/calendar.html.erb +0 -56
  227. data/config/initializers/paper_trail.rb +0 -1
  228. data/db/migrate/20250304293518_create_cm_inventory_items.rb +0 -21
  229. data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +0 -5
  230. data/db/migrate/20250502025848_add_index_to_spree_products.rb +0 -5
  231. data/db/migrate/20250502030001_add_product_type_to_spree_variants.rb +0 -5
  232. data/db/migrate/20250502030002_add_product_type_to_spree_line_items.rb +0 -5
  233. data/db/migrate/20250603035256_add_inventory_item_to_spree_prices.rb +0 -7
  234. data/db/migrate/20250619073724_drop_table_cm_line_item_seats.rb +0 -5
  235. data/db/migrate/20250619073812_drop_table_cm_vehicle_seats.rb +0 -5
  236. data/db/migrate/20250619073844_drop_table_cm_vehicle_types.rb +0 -9
  237. data/db/migrate/20250619073957_drop_table_cm_option_value_vehicle_types.rb +0 -5
  238. data/db/migrate/20250619082354_remove_unnecessary_fields_from_cm_places.rb +0 -9
  239. data/db/migrate/20250619082736_remove_route_type_from_spree_products.rb +0 -5
  240. data/db/migrate/20250619083055_remove_unnecessary_fields_from_spree_taxons.rb +0 -5
  241. data/db/migrate/20250620083055_remove_variant_id_from_cm_trips.rb +0 -5
  242. data/db/migrate/20250620090000_update_cm_trip_connections_to_use_cm_trips.rb +0 -6
  243. data/db/migrate/20250620090001_create_cm_seat_layouts.rb +0 -17
  244. data/db/migrate/20250620090002_create_cm_seat_sections.rb +0 -18
  245. data/db/migrate/20250620090003_create_cm_blocks.rb +0 -18
  246. data/db/migrate/20250624091005_create_cm_reserved_blocks.rb +0 -29
  247. data/db/migrate/20250626083642_create_cm_variant_blocks.rb +0 -24
  248. data/db/migrate/20250627023314_add_block_id_to_cm_guests.rb +0 -13
  249. data/lib/spree_cm_commissioner/cached_inventory_item.rb +0 -23
  250. data/lib/spree_cm_commissioner/test_helper/factories/block_factory.rb +0 -9
  251. data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +0 -9
  252. data/lib/spree_cm_commissioner/test_helper/factories/reserved_block_factory.rb +0 -27
  253. data/lib/spree_cm_commissioner/test_helper/factories/seat_layout_factory.rb +0 -8
  254. data/lib/spree_cm_commissioner/test_helper/factories/seat_section_factory.rb +0 -8
  255. data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +0 -6
  256. data/lib/spree_cm_commissioner/test_helper/factories/variant_block_factory.rb +0 -7
  257. data/lib/tasks/create_default_non_permanent_inventory_items.rake +0 -16
  258. data/lib/tasks/ensure_correct_product_type.rake +0 -7
  259. data/lib/tasks/generate_inventory_items.rake +0 -7
@@ -0,0 +1,27 @@
1
+ module SpreeCmCommissioner
2
+ class AppleAppSiteAssociationFetcher < BaseInteractor
3
+ delegate :store, :tenant, :refreshed, to: :context
4
+
5
+ def call
6
+ key = cache_key
7
+
8
+ CmAppLogger.log(label: 'LOOKING_UP_CACHE', data: { cache_key: key })
9
+
10
+ Rails.cache.delete(key) if refreshed
11
+
12
+ context.contents = Rails.cache.fetch(key) do
13
+ CmAppLogger.log(label: 'CACHE_MISS', data: { cache_key: key })
14
+ resource.preferred_apple_app_site_association
15
+ end
16
+ end
17
+
18
+ def cache_key
19
+ updated_at = tenant&.updated_at || store&.updated_at
20
+ "well_known:apple-app-site-association:#{resource.class.name}:#{resource.id}:#{updated_at}"
21
+ end
22
+
23
+ def resource
24
+ tenant || store
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module SpreeCmCommissioner
2
+ class AssetLinksFetcher < BaseInteractor
3
+ delegate :store, :tenant, :refreshed, to: :context
4
+
5
+ def call
6
+ key = cache_key
7
+
8
+ CmAppLogger.log(label: 'LOOKING_UP_CACHE', data: { cache_key: key })
9
+
10
+ Rails.cache.delete(key) if refreshed
11
+
12
+ context.contents = Rails.cache.fetch(key) do
13
+ CmAppLogger.log(label: 'CACHE_MISS', data: { cache_key: key })
14
+ resource.preferred_assetlinks
15
+ end
16
+ end
17
+
18
+ def cache_key
19
+ updated_at = tenant&.updated_at || store&.updated_at
20
+ "well_known:assetlinks.json:#{resource.class.name}:#{resource.id}:#{updated_at}"
21
+ end
22
+
23
+ def resource
24
+ tenant || store
25
+ end
26
+ end
27
+ end
@@ -9,7 +9,8 @@ module SpreeCmCommissioner
9
9
  set_option_value
10
10
  create_variant
11
11
  create_stock_item
12
- upload_image
12
+ upload_image_to(@ticket.master)
13
+ upload_image_to(@variant)
13
14
  create_place
14
15
  end
15
16
  end
@@ -77,13 +78,13 @@ module SpreeCmCommissioner
77
78
  context.fail!(message: @stock_item.errors.full_messages.join(', '))
78
79
  end
79
80
 
80
- def upload_image
81
+ def upload_image_to(target)
81
82
  return if context.params[:ticket_image].blank?
82
83
 
83
- @image = @ticket.master.images.new(attachment: context.params[:ticket_image])
84
- return if @image.save
84
+ image = target.images.new(attachment: context.params[:ticket_image])
85
+ return if image.save
85
86
 
86
- context.fail!(message: @image.errors.full_messages.join(', '))
87
+ context.fail!(message: image.errors.full_messages.join(', '))
87
88
  end
88
89
 
89
90
  def create_place
@@ -0,0 +1,48 @@
1
+ module SpreeCmCommissioner
2
+ class CrewInviteLinkHandler < BaseInteractor
3
+ delegate :params, to: :context
4
+
5
+ def call
6
+ validate_data
7
+ assign_role_to_user
8
+ create_user_event
9
+ end
10
+
11
+ private
12
+
13
+ def validate_data
14
+ if invite.nil?
15
+ context.fail!(message: I18n.t('invite.url_not_found'))
16
+ else
17
+ context.invite = invite
18
+ end
19
+ end
20
+
21
+ def assign_role_to_user
22
+ return if user.operator?
23
+
24
+ role = Spree::Role.find_by(name: 'operator')
25
+ role_user = Spree::RoleUser.new(user_id: user.id, role_id: role.id)
26
+ role_user.save
27
+ end
28
+
29
+ def create_user_event
30
+ @user_event = SpreeCmCommissioner::UserEvent.new(
31
+ taxon_id: invite.taxon_id,
32
+ user_id: user.id
33
+ )
34
+
35
+ return if @user_event.save
36
+
37
+ context.fail!(message: I18n.t('invite.already_invited'))
38
+ end
39
+
40
+ def invite
41
+ @invite ||= SpreeCmCommissioner::Invite.find_by(token: params[:id])
42
+ end
43
+
44
+ def user
45
+ @user ||= Spree::User.find(params[:user_id])
46
+ end
47
+ end
48
+ end
@@ -18,7 +18,6 @@ module SpreeCmCommissioner
18
18
 
19
19
  def send_sms
20
20
  options = {
21
- from: sender_name(context.tenant),
22
21
  to: context.pin_code.contact,
23
22
  body: I18n.t('pincode_sender.sms.body', code: context.pin_code.code, readable_type: context.pin_code.readable_type)
24
23
  }
@@ -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
@@ -0,0 +1,144 @@
1
+ module SpreeCmCommissioner
2
+ class TelegramChatsAutoFinder < BaseInteractor
3
+ delegate :contact, :pin_code, to: :context
4
+
5
+ def call
6
+ context.chats = []
7
+ context.verified_chat_ids = []
8
+
9
+ updates = fetch_updates
10
+
11
+ if updates['result'].any?
12
+ updates['result'].sort_by { |u| u['update_id'] }.reverse.each do |update|
13
+ handle_message_update(update) if update['message']
14
+ handle_channel_post_update(update) if update['channel_post']
15
+ handle_chat_member_update(update) if update['my_chat_member']
16
+ end
17
+ end
18
+ context.fail!(message: 'No pin codes verified') if context.verified_chat_ids.empty?
19
+ end
20
+
21
+ private
22
+
23
+ def handle_chat_member_update(update)
24
+ chat = update.dig('my_chat_member', 'chat')
25
+ return unless chat
26
+
27
+ chat_data = {
28
+ id: chat['id'],
29
+ title: chat['title'] || 'Unnamed Chat',
30
+ type: chat['type']
31
+ }
32
+
33
+ return if context.chats.any? { |c| c[:id] == chat_data[:id] }
34
+
35
+ db_chat = SpreeCmCommissioner::TelegramChat.find_or_initialize_by(chat_id: chat_data[:id])
36
+ is_new_chat = db_chat.new_record?
37
+ db_chat.update(chat_title: chat_data[:title], chat_type: chat_data[:type])
38
+ context.chats << chat_data
39
+ message = "👋Hello! This is Bookme+ bot.\n\nPlease enter the 6-digit PIN code displayed in your portal."
40
+ send_message(chat_data[:id], message) if is_new_chat
41
+ end
42
+
43
+ def handle_channel_post_update(update)
44
+ message = update['channel_post']
45
+ process_pin_code_message(message)
46
+ end
47
+
48
+ def handle_message_update(update)
49
+ message = update['message']
50
+ process_pin_code_message(message)
51
+ end
52
+
53
+ def process_pin_code_message(message)
54
+ chat_id = message.dig('chat', 'id')
55
+ text = message['text']&.strip
56
+
57
+ return unless valid_pin_code?(text, chat_id)
58
+
59
+ pin_code_record = find_pin_code_record
60
+ return unless pin_code_record
61
+
62
+ vendor = find_vendor
63
+ return unless vendor
64
+
65
+ chat = update_telegram_chat(message, chat_id)
66
+ return unless chat
67
+
68
+ handle_successful_verification(chat, vendor, pin_code_record)
69
+ end
70
+
71
+ def valid_pin_code?(text, chat_id)
72
+ text && chat_id && text == pin_code
73
+ end
74
+
75
+ def find_pin_code_record
76
+ pin_code_record = SpreeCmCommissioner::PinCodeTelegram.find_by(code: pin_code, contact: contact)
77
+ unless pin_code_record
78
+ context.fail!(message: "Pin code #{pin_code} not found for contact #{contact}")
79
+ return nil
80
+ end
81
+ pin_code_record
82
+ end
83
+
84
+ def find_vendor
85
+ vendor = Spree::Vendor.find_by(id: contact)
86
+ unless vendor
87
+ context.fail!(message: "Vendor not found for contact #{contact}")
88
+ return nil
89
+ end
90
+ vendor
91
+ end
92
+
93
+ def update_telegram_chat(message, chat_id)
94
+ chat = SpreeCmCommissioner::TelegramChat.find_or_initialize_by(chat_id: chat_id)
95
+ unless chat.update(
96
+ chat_title: message.dig('chat', 'title') || 'Unnamed Chat',
97
+ chat_type: message.dig('chat', 'type')
98
+ )
99
+ context.fail!(message: "Failed to update chat: #{chat.errors.full_messages.join(', ')}")
100
+ return nil
101
+ end
102
+
103
+ context.chats << { id: chat.chat_id, title: chat.chat_title, type: chat.chat_type }
104
+ chat
105
+ end
106
+
107
+ def handle_successful_verification(chat, vendor, pin_code_record)
108
+ return if chat.vendor && chat.vendor != vendor
109
+
110
+ update_vendor_preferences(vendor, chat)
111
+ chat.update(active: true, vendor: vendor)
112
+ expire_pin_code(pin_code_record)
113
+ send_success_message(chat.chat_id, vendor.name)
114
+ context.verified_chat_ids << chat.chat_id
115
+ end
116
+
117
+ def update_vendor_preferences(vendor, chat)
118
+ vendor.update(
119
+ preferred_telegram_chat_id: chat.chat_id,
120
+ preferred_telegram_chat_name: chat.chat_title,
121
+ preferred_telegram_chat_type: chat.chat_type
122
+ )
123
+ end
124
+
125
+ def expire_pin_code(pin_code_record)
126
+ pin_code_record.expire
127
+ pin_code_record.save
128
+ end
129
+
130
+ def send_success_message(chat_id, vendor_name)
131
+ message = "✅ PIN code verified successfully! This chat is now connected to <b>#{vendor_name}</b>.\n\n" \
132
+ 'All completed orders will be sent to this chat.'
133
+ send_message(chat_id, message)
134
+ end
135
+
136
+ def fetch_updates
137
+ ::Telegram.bot.get_updates
138
+ end
139
+
140
+ def send_message(chat_id, text)
141
+ ::Telegram.bot.send_message(chat_id: chat_id, text: text, parse_mode: 'HTML')
142
+ end
143
+ end
144
+ end
@@ -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
@@ -93,6 +93,10 @@ module SpreeCmCommissioner
93
93
  context.fail!(message: "User creation failed: #{context.user.errors.full_messages.join(', ')}")
94
94
  end
95
95
 
96
+ def disable_services
97
+ 'bus,ferry'
98
+ end
99
+
96
100
  def construct_data
97
101
  user = context.user
98
102
 
@@ -101,7 +105,7 @@ module SpreeCmCommissioner
101
105
  name: user.full_name,
102
106
  phone: user.phone_number,
103
107
  email: user.email,
104
- webUrl: "#{Spree::Store.default.formatted_url}/vattanac_bank_web_app?session_id=#{session_id}"
108
+ webUrl: "#{Spree::Store.default.formatted_url}/vattanac_bank_web_app?session_id=#{session_id}&ds=#{CGI.escape(disable_services)}"
105
109
  }
106
110
 
107
111
  json_data = raw_data.to_json
@@ -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
@@ -0,0 +1,30 @@
1
+ module SpreeCmCommissioner
2
+ module EventCheckInFlowable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ preference :group_check_in_enabled, :boolean, default: true
7
+ preference :individual_check_in_enabled, :boolean, default: true
8
+
9
+ before_validation :validate_at_least_one_check_in_flow_presence
10
+ end
11
+
12
+ def check_in_flows
13
+ flows = []
14
+ flows << 'group' if group_check_in_enabled?
15
+ flows << 'individual' if individual_check_in_enabled?
16
+ flows
17
+ end
18
+
19
+ def group_check_in_enabled? = preferred_group_check_in_enabled
20
+ def individual_check_in_enabled? = preferred_individual_check_in_enabled
21
+
22
+ private
23
+
24
+ def validate_at_least_one_check_in_flow_presence
25
+ return if check_in_flows.any?
26
+
27
+ errors.add(:check_in_flows, 'must have at least one flow selected')
28
+ end
29
+ end
30
+ end
@@ -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 = {
@@ -40,7 +47,12 @@ module SpreeCmCommissioner
40
47
  'bib-zerofill' => 'integer',
41
48
  'bib-display-prefix' => 'boolean',
42
49
  'bib-pre-generation-on-create' => 'boolean',
43
- 'seat-number-positions' => 'array'
50
+ 'seat-number-positions' => 'array',
51
+ 'origin' => 'place_id',
52
+ 'destination' => 'place_id',
53
+ 'departure-time' => 'time',
54
+ 'vehicle' => 'vehicle_id',
55
+ 'allow-seat-selection' => 'boolean'
44
56
  }.freeze
45
57
 
46
58
  included do