spree_cm_commissioner 2.5.1.pre.pre2 → 2.5.1.pre.pre3

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/controllers/spree/api/chatrace/guests_controller.rb +37 -20
  4. data/app/controllers/spree/api/v2/operator/check_in_bulks_controller.rb +9 -0
  5. data/app/controllers/spree/api/v2/storefront/account/qr_data_controller.rb +30 -0
  6. data/app/controllers/spree/api/v2/storefront/popular_route_places_controller.rb +1 -1
  7. data/app/controllers/spree/api/v2/storefront/transit/draft_orders_controller.rb +4 -4
  8. data/app/controllers/spree/transit/trips_controller.rb +3 -3
  9. data/app/finders/spree_cm_commissioner/places/find_with_route.rb +12 -12
  10. data/app/finders/spree_cm_commissioner/routes/find_popular.rb +35 -20
  11. data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +4 -11
  12. data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +1 -10
  13. data/app/{services/spree_cm_commissioner/transit_order/create.rb → interactors/spree_cm_commissioner/transit/draft_order_creator.rb} +16 -13
  14. data/app/interactors/spree_cm_commissioner/trip_clone_creator.rb +3 -4
  15. data/app/interactors/spree_cm_commissioner/trip_stops_creator.rb +2 -2
  16. data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +2 -2
  17. data/app/jobs/spree_cm_commissioner/transit/route_fulfilled_order_count_incrementer_job.rb +10 -0
  18. data/app/jobs/spree_cm_commissioner/transit/route_order_count_incrementer_job.rb +10 -0
  19. data/app/jobs/spree_cm_commissioner/transit/route_previous_trip_count_decrementer_job.rb +13 -0
  20. data/app/jobs/spree_cm_commissioner/transit/route_trip_count_decrementer_job.rb +10 -0
  21. data/app/jobs/spree_cm_commissioner/transit/route_trip_count_incrementer_job.rb +10 -0
  22. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +16 -11
  23. data/app/models/concerns/spree_cm_commissioner/route_order_countable.rb +2 -2
  24. data/app/models/concerns/spree_cm_commissioner/route_trip_count_callbacks.rb +48 -0
  25. data/app/models/concerns/spree_cm_commissioner/user_identity.rb +0 -6
  26. data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +4 -0
  27. data/app/models/spree_cm_commissioner/guest.rb +4 -4
  28. data/app/models/spree_cm_commissioner/place.rb +8 -5
  29. data/app/models/spree_cm_commissioner/product_decorator.rb +0 -1
  30. data/app/models/spree_cm_commissioner/route.rb +5 -46
  31. data/app/models/spree_cm_commissioner/trip.rb +33 -8
  32. data/app/models/spree_cm_commissioner/trip_connection.rb +36 -0
  33. data/app/models/spree_cm_commissioner/trip_stop.rb +2 -16
  34. data/app/models/spree_cm_commissioner/user_decorator.rb +30 -18
  35. data/app/models/spree_cm_commissioner/vendor_decorator.rb +1 -3
  36. data/app/models/spree_cm_commissioner/vendor_route.rb +9 -0
  37. data/app/queries/spree_cm_commissioner/guest_searcher_query.rb +25 -2
  38. data/app/queries/spree_cm_commissioner/trip_query.rb +2 -2
  39. data/app/serializers/spree/v2/storefront/user_serializer_decorator.rb +2 -1
  40. data/app/serializers/spree_cm_commissioner/v2/operator/guest_serializer.rb +1 -0
  41. data/app/serializers/spree_cm_commissioner/v2/operator/line_item_serializer.rb +2 -2
  42. data/app/serializers/spree_cm_commissioner/v2/operator/{line_item_order_serializer.rb → order_serializer.rb} +1 -2
  43. data/app/serializers/spree_cm_commissioner/v2/operator/user_serializer.rb +11 -0
  44. data/app/serializers/spree_cm_commissioner/v2/operator/variant_serializer.rb +9 -0
  45. data/app/serializers/spree_cm_commissioner/v2/storefront/route_serializer.rb +1 -3
  46. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_stop_serializer.rb +1 -1
  47. data/app/services/spree_cm_commissioner/{route_metrics/update_route_metrics.rb → routes/base_update_order_metrics.rb} +16 -11
  48. data/app/services/spree_cm_commissioner/routes/decrement_previous_trip_count.rb +30 -0
  49. data/app/services/spree_cm_commissioner/routes/decrement_trip_count.rb +33 -0
  50. data/app/services/spree_cm_commissioner/{route_metrics/increase_fulfilled_order_count.rb → routes/increment_fulfilled_order_count.rb} +3 -3
  51. data/app/services/spree_cm_commissioner/{route_metrics/increase_order_count.rb → routes/increment_order_count.rb} +3 -3
  52. data/app/services/spree_cm_commissioner/routes/increment_trip_count.rb +33 -0
  53. data/app/services/spree_cm_commissioner/seeds/user_usernames.rb +86 -0
  54. data/app/services/spree_cm_commissioner/users/qr_data/extract_login.rb +18 -0
  55. data/app/services/spree_cm_commissioner/users/qr_data/generate.rb +14 -0
  56. data/app/services/spree_cm_commissioner/users/qr_data/invalidate.rb +19 -0
  57. data/app/services/spree_cm_commissioner/users/qr_data/verify.rb +33 -0
  58. data/app/services/spree_cm_commissioner/users/username/generate.rb +68 -0
  59. data/app/views/spree/transit/trip_stops/index.html.erb +2 -4
  60. data/app/views/spree_cm_commissioner/guest_mailer/send_ticket_to_guest.html.erb +1 -0
  61. data/config/initializers/spree_permitted_attributes.rb +1 -11
  62. data/config/routes.rb +2 -6
  63. data/db/migrate/20260126110528_seed_user_initial_usernames.rb +5 -0
  64. data/lib/spree_cm_commissioner/test_helper/factories/route_factory.rb +6 -7
  65. data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +6 -0
  66. data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +1 -4
  67. data/lib/spree_cm_commissioner/test_helper/factories/trip_stop_factory.rb +1 -3
  68. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_type_factory.rb +1 -1
  69. data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -2
  70. data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +0 -22
  71. data/lib/spree_cm_commissioner/version.rb +1 -1
  72. data/lib/spree_cm_commissioner.rb +0 -4
  73. metadata +29 -38
  74. data/app/controllers/spree/api/v2/tenant/popular_route_places_controller.rb +0 -60
  75. data/app/controllers/spree/api/v2/tenant/routes_controller.rb +0 -50
  76. data/app/controllers/spree/api/v2/tenant/transit/draft_orders_controller.rb +0 -46
  77. data/app/finders/spree_cm_commissioner/route_metrics/find_popular.rb +0 -44
  78. data/app/finders/spree_cm_commissioner/routes/find.rb +0 -94
  79. data/app/jobs/spree_cm_commissioner/route_metrics/decrease_trip_count_job.rb +0 -10
  80. data/app/jobs/spree_cm_commissioner/route_metrics/increase_fulfilled_order_count_job.rb +0 -10
  81. data/app/jobs/spree_cm_commissioner/route_metrics/increase_order_count_job.rb +0 -10
  82. data/app/jobs/spree_cm_commissioner/route_metrics/increase_trip_count_job.rb +0 -10
  83. data/app/models/spree_cm_commissioner/route_metric.rb +0 -21
  84. data/app/models/spree_cm_commissioner/route_photo.rb +0 -12
  85. data/app/serializers/spree/v2/tenant/transit_cart_serializer.rb +0 -11
  86. data/app/serializers/spree_cm_commissioner/v2/storefront/transit_line_item_serializer.rb +0 -17
  87. data/app/services/spree_cm_commissioner/route_metrics/decrease_trip_count.rb +0 -31
  88. data/app/services/spree_cm_commissioner/route_metrics/increase_trip_count.rb +0 -31
  89. data/app/services/spree_cm_commissioner/routes/create.rb +0 -51
  90. data/app/services/spree_cm_commissioner/routes/update.rb +0 -25
  91. data/app/services/spree_cm_commissioner/trips/create_single_leg.rb +0 -123
  92. data/app/services/spree_cm_commissioner/trips/service_calendars/create_or_update.rb +0 -54
  93. data/app/services/spree_cm_commissioner/trips/update_single_leg.rb +0 -88
  94. data/app/services/spree_cm_commissioner/trips/variants/create.rb +0 -103
  95. data/db/migrate/20251224033103_migrate_cm_routes_to_cm_route_metrics.rb +0 -17
  96. data/db/migrate/20251224033910_migrate_cm_vendor_routes_to_cm_routes.rb +0 -30
  97. data/db/migrate/20260105072450_migrate_cm_trip_stops_to_support_trip_connection.rb +0 -12
  98. data/db/migrate/20260108101406_add_allow_booking_to_cm_trips.rb +0 -5
  99. data/lib/spree_cm_commissioner/test_helper/factories/route_metric_factory.rb +0 -12
  100. data/lib/spree_cm_commissioner/test_helper/factories/route_photo_factory.rb +0 -5
  101. data/lib/spree_cm_commissioner/transit/route_stop.rb +0 -61
  102. data/lib/spree_cm_commissioner/transit/route_stop_collection.rb +0 -175
  103. data/lib/spree_cm_commissioner/transit/trip_form.rb +0 -81
  104. data/lib/spree_cm_commissioner/transit/trip_stop_form.rb +0 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20effeac142fface8df473f26f1a62707092ee81066953512b51f0a021657fa0
4
- data.tar.gz: 82ffb806998821e0432c86aaabbe664b87d076453419926c392935e55b11d517
3
+ metadata.gz: 2ee953cf63ab26a979ddaa919500a3f7da95e812f8dc20557cb54411047821b6
4
+ data.tar.gz: bb72deade157e1dde753706bc7a9ad4dbfd329ebb0fc7290074983bdc3d17eca
5
5
  SHA512:
6
- metadata.gz: 944769159e8f13b6be0cfb8fda0929fb2ef5c19716c882aa7cfa0a16847820e19657e52cc50f831995c85a24299cb73f6d346a82f08483f702461f20f81199ea
7
- data.tar.gz: fd28f9f3960e2bd0967e42d91f0434165f383fedf3c0e330fd812cce1a2ccea2921e1f07e380bbf8bd426a2e18adb5732974322b2083f2578b160cb57bd480f1
6
+ metadata.gz: e4db3651d96a7e492cc13d3755ba0ec2f8474f49cbe5918e1af02855dba9d74786feacf7215806f3fb744919a710378ff25551829319ec96740d1d42f3d19d02
7
+ data.tar.gz: 5f28bd001f3cc004058ccbdb253dd9b7614aa6ecdef0673da30ba03492abd900dfe3c48b2af18cfccd2c8f228c9753e0c9c3c51f896be6e13b5d6e23cc478c54
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.5.1.pre.pre2)
37
+ spree_cm_commissioner (2.5.1.pre.pre3)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -27,32 +27,52 @@ module Spree
27
27
  end
28
28
  end
29
29
 
30
+ def serialize_resource(guest)
31
+ guest_auto_payload(guest)
32
+ .merge(default_payload(guest))
33
+ .merge(dynamic_field_key_value(guest))
34
+ end
35
+
36
+ private
37
+
38
+ # In API Response eg: "field_17": "chhunlin", "field_18": "on",......
30
39
  def dynamic_field_key_value(guest)
31
40
  guest.guest_dynamic_fields
32
41
  .includes(:dynamic_field)
33
42
  .to_h do |gdf|
34
- key = gdf.dynamic_field.label
35
- .parameterize
36
- .underscore
43
+ label = "field_#{gdf.dynamic_field.id}"
37
44
 
38
- [key, gdf.value]
45
+ value = gdf.value.strip
46
+
47
+ [label, value]
39
48
  end
40
49
  end
41
50
 
42
- def serialize_resource(guest)
51
+ EXCLUDED_GUEST_COLUMNS = %w[
52
+ id created_at updated_at occupation_id event_id nationality_id
53
+ preferences upload_later social_contact_platform user_id
54
+ bib_number bib_prefix bib_index public_metadata private_metadata
55
+ seat_number intel_phone_number block_id saved_guest_id
56
+ data_fill_stage_phase
57
+ ].freeze
58
+
59
+ def guest_base_columns
60
+ SpreeCmCommissioner::Guest.column_names - EXCLUDED_GUEST_COLUMNS
61
+ end
62
+
63
+ def guest_auto_payload(guest)
64
+ guest_base_columns.index_with do |column|
65
+ guest.public_send(column)
66
+ end
67
+ end
68
+
69
+ def default_payload(guest) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
43
70
  order = guest.line_item.order
44
71
 
45
- base_payload = {
46
- token: guest.token,
47
- first_name: guest.first_name,
48
- last_name: guest.last_name,
49
- dob: guest.dob,
50
- gender: guest.gender,
51
- age: guest.age,
72
+ {
73
+ guest_nationality: guest.nationality&.name,
74
+ guest_id_card_type: guest.id_card&.card_type,
52
75
  occupation: guest.occupation&.name || guest.other_occupation,
53
- entry_type: guest.entry_type,
54
- organization: guest.other_organization,
55
- expectation: guest.expectation,
56
76
  telegram_user_id: guest.preferred_telegram_user_id,
57
77
  telegram_user_verified_at: guest.preferred_telegram_user_verified_at,
58
78
  order_number: order.number,
@@ -63,13 +83,10 @@ module Spree
63
83
  checked_in_at: guest.earliest_check_in&.created_at,
64
84
  qr_data: guest.qr_data,
65
85
  order_qr_data: order.qr_data,
66
- country_code: guest.country_code,
67
- line_item_id: guest.line_item_id,
68
86
  order_token: order.token,
69
- bib: guest.formatted_bib_number
87
+ bib: guest.formatted_bib_number,
88
+ line_item_option_text: guest.line_item&.options_text
70
89
  }
71
-
72
- base_payload.merge(dynamic_field_key_value(guest))
73
90
  end
74
91
  end
75
92
  end
@@ -8,6 +8,15 @@ module Spree
8
8
  def create
9
9
  spree_authorize! :create, model_class
10
10
 
11
+ # Optional QR data from a scanned user QR code.
12
+ # - If provided, the system will validate the QR data before check-in.
13
+ # - If omitted, check-in proceeds normally (e.g. manual search by operator).
14
+ # This is only for validating scanned QR codes; operators can always check in guests without it.
15
+ if params[:scanned_user_qr_data].present?
16
+ result = SpreeCmCommissioner::Users::QrData::Verify.call(qr_data: params[:scanned_user_qr_data])
17
+ return render_error_payload(result.error) if result.failure?
18
+ end
19
+
11
20
  check_ins = []
12
21
 
13
22
  if params[:check_ins].present?
@@ -0,0 +1,30 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ module Account
6
+ class QrDataController < ::Spree::Api::V2::ResourceController
7
+ before_action :require_spree_current_user
8
+
9
+ # override
10
+ # invalidate existing QR data and return new QR data with user info.
11
+ def update
12
+ result = SpreeCmCommissioner::Users::QrData::Invalidate.call(user: spree_current_user)
13
+
14
+ if result.success?
15
+ render_serialized_payload { serialize_resource(result.value) }
16
+ else
17
+ render_error_payload(result.error)
18
+ end
19
+ end
20
+
21
+ # override
22
+ def resource_serializer
23
+ Spree::V2::Storefront::UserSerializer
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -31,7 +31,7 @@ module Spree
31
31
 
32
32
  # override
33
33
  def collection_finder
34
- SpreeCmCommissioner::RouteMetrics::FindPopular
34
+ SpreeCmCommissioner::Routes::FindPopular
35
35
  end
36
36
 
37
37
  # override
@@ -15,7 +15,7 @@ module Spree
15
15
  @outbound_legs = params[:outbound_legs].is_a?(Array) && params[:outbound_legs].any? ? build_legs(:outbound, params[:outbound_legs]) : []
16
16
  @inbound_legs = params[:inbound_legs].is_a?(Array) && params[:inbound_legs].any? ? build_legs(:inbound, params[:inbound_legs]) : []
17
17
 
18
- result = SpreeCmCommissioner::TransitOrder::Create.call(
18
+ context = SpreeCmCommissioner::Transit::DraftOrderCreator.call(
19
19
  outbound_date: params[:outbound_date]&.to_date,
20
20
  inbound_date: params[:inbound_date]&.to_date,
21
21
  outbound_legs: @outbound_legs,
@@ -23,10 +23,10 @@ module Spree
23
23
  user: spree_current_user
24
24
  )
25
25
 
26
- if result.success?
27
- render_serialized_payload { serialize_resource(result.value[:order]) }
26
+ if context.success?
27
+ render_serialized_payload { serialize_resource(context.order) }
28
28
  else
29
- render_error_payload(result.error)
29
+ render_error_payload(context.message)
30
30
  end
31
31
  end
32
32
 
@@ -48,13 +48,13 @@ module Spree
48
48
  boarding_points_attributes = (cm_params.delete('boarding_points') || []).compact_blank
49
49
  .map do |point_id|
50
50
  trip_stop = trip_stops.delete(point_id.to_i)
51
- { stop_id: point_id, allow_boarding: true, id: trip_stop.try(:id) }
51
+ { stop_id: point_id, stop_type: 'boarding', id: trip_stop.try(:id) }
52
52
  end
53
53
 
54
54
  drop_off_points_attributes = (cm_params.delete('drop_off_points') || []).compact_blank
55
55
  .map do |point_id|
56
56
  trip_stop = trip_stops.delete(point_id.to_i)
57
- { stop_id: point_id, allow_drop_off: true, id: trip_stop.try(:id) }
57
+ { stop_id: point_id, stop_type: 'drop_off', id: trip_stop.try(:id) }
58
58
  end
59
59
 
60
60
  trip_stops.each_value do |trip_stop|
@@ -74,7 +74,7 @@ module Spree
74
74
  :origin_id, :destination_id, :vehicle_id, :hours, :minutes, :seconds,
75
75
  'departure_time(1i)', 'departure_time(2i)', 'departure_time(3i)',
76
76
  'departure_time(4i)', 'departure_time(5i)', :product_id,
77
- trip_stops_attributes: %i[stop_id allow_boarding allow_drop_off _destroy id]
77
+ trip_stops_attributes: %i[stop_id stop_type _destroy id]
78
78
  )
79
79
  end
80
80
 
@@ -1,20 +1,20 @@
1
- # Finds places connected via route metrics with optional filtering.
1
+ # Finds places connected via routes with optional filtering.
2
2
  #
3
3
  # @param place_type [String] Required. 'origin' or 'destination'
4
4
  # @param place_id [Integer] Optional. Filter by connected place ID
5
5
  # @param query [String] Optional. Filter by place name (case-insensitive)
6
- # @param route_type [Symbol, String] Optional. Filter by route type from route metrics (e.g., :ferry, :bus)
6
+ # @param route_type [Symbol, String] Optional. Filter by route type from associated trips (e.g., :ferry, :bus)
7
7
  #
8
8
  # @return [ActiveRecord::Relation<SpreeCmCommissioner::Place>]
9
9
  #
10
10
  # Modes:
11
11
  # - place_id only: returns connected places (origins TO or destinations FROM given place)
12
12
  # - query only: filters by name
13
- # - route_type only: filters by route type on route metrics
13
+ # - route_type only: filters by trip route types on those routes
14
14
  # - combinations: connected places filtered by name and/or route type
15
- # - neither: all origins/destinations in route metrics
15
+ # - neither: all origins/destinations in routes
16
16
  #
17
- # @example Origins with ferry route metrics to place 123
17
+ # @example Origins with ferry trips to place 123
18
18
  # FindWithRoute.new(place_type: 'origin', place_id: 123, route_type: :ferry).execute
19
19
  #
20
20
  # @example Destinations filtered by query and route type
@@ -46,14 +46,14 @@ module SpreeCmCommissioner
46
46
  def scope
47
47
  return SpreeCmCommissioner::Place.none unless valid_place_type?
48
48
 
49
- base_scope = origin? ? SpreeCmCommissioner::Place.with_route_metrics_as_origin : SpreeCmCommissioner::Place.with_route_metrics_as_destination
49
+ base_scope = origin? ? SpreeCmCommissioner::Place.with_routes_as_origin : SpreeCmCommissioner::Place.with_routes_as_destination
50
50
 
51
51
  return base_scope if place_id.blank?
52
52
 
53
53
  if origin?
54
- base_scope.where(route_metrics_as_origin: { destination_place_id: place_id })
54
+ base_scope.where(routes_as_origin: { destination_place_id: place_id })
55
55
  else
56
- base_scope.where(route_metrics_as_destination: { origin_place_id: place_id })
56
+ base_scope.where(routes_as_destination: { origin_place_id: place_id })
57
57
  end
58
58
  end
59
59
 
@@ -62,10 +62,10 @@ module SpreeCmCommissioner
62
62
  end
63
63
 
64
64
  def apply_route_type_filter(result)
65
- # Use the association name as the table alias in the WHERE clause
66
- # This works whether the association is already joined or not
67
- association_name = origin? ? :route_metrics_as_origin : :route_metrics_as_destination
68
- result.where(association_name => { route_type: route_type.to_sym })
65
+ trips_association = origin? ? :trips_as_origin : :trips_as_destination
66
+ result.joins(trips_association)
67
+ .where(cm_trips: { route_type: route_type.to_sym })
68
+ .distinct
69
69
  end
70
70
 
71
71
  def origin?
@@ -1,31 +1,46 @@
1
- # Finder to get popular route metrics scoped to a vendor or tenant.
2
- # Orders by fulfilled_order_count DESC, then order_count DESC.
3
- # Usage:
4
- # finder = SpreeCmCommissioner::Routes::FindPopular.new(vendor: vendor, route_type: :bus, limit: 10)
5
- # finder.execute
1
+ # Finds routes ordered by popularity based on order metrics.
2
+ #
3
+ # Routes are sorted by:
4
+ # 1. fulfilled_order_count (completed orders) - DESC
5
+ # 2. order_count (total orders including incomplete) - DESC
6
+ #
7
+ # @param route_type [Symbol, String] Optional. Filter by route type from associated trips (e.g., :ferry, :bus)
8
+ #
9
+ # @return [ActiveRecord::Relation<SpreeCmCommissioner::Route>] Routes with origin and destination places loaded,
10
+ # ordered from most to least popular
11
+ #
12
+ # @example Get all popular routes
13
+ # finder = SpreeCmCommissioner::Routes::FindPopular.new
14
+ # finder.execute # => Returns all routes sorted by fulfillment and order counts
15
+ #
16
+ # @example Get popular ferry routes
17
+ # finder = SpreeCmCommissioner::Routes::FindPopular.new
18
+ # finder.execute(route_type: :ferry) # => Returns ferry routes sorted by popularity
19
+ #
20
+ # @example Get popular bus routes
21
+ # finder = SpreeCmCommissioner::Routes::FindPopular.new
22
+ # finder.execute(route_type: :bus) # => Returns bus routes sorted by popularity
6
23
 
7
24
  module SpreeCmCommissioner
8
25
  module Routes
9
26
  class FindPopular
10
- def initialize(vendor: nil, tenant: nil, route_type: nil, limit: 20)
11
- @vendor = vendor
12
- @tenant = tenant
13
- @route_type = route_type
14
- @limit = limit.to_i
15
- end
16
-
17
- def execute
18
- scope = SpreeCmCommissioner::Route.includes(:origin_place, :destination_place, :route_photos)
19
- scope = scope.where(vendor_id: vendor.id) if vendor.present?
20
- scope = scope.where(tenant_id: tenant.id) if tenant.present?
21
- scope = scope.where(route_type: route_type.to_sym) if route_type.present?
22
- scope.order(fulfilled_order_count: :desc, order_count: :desc)
23
- .limit(limit)
27
+ def execute(route_type: nil, query: nil)
28
+ scope(route_type: route_type, query: query)
24
29
  end
25
30
 
26
31
  private
27
32
 
28
- attr_reader :vendor, :tenant, :route_type, :limit
33
+ def scope(route_type:, query:)
34
+ includes_associations = %i[origin_place destination_place]
35
+ includes_associations << :trips if route_type.present?
36
+ result = SpreeCmCommissioner::Route.includes(*includes_associations)
37
+
38
+ result = result.joins(:trips).where(cm_trips: { route_type: route_type.to_sym }) if route_type.present?
39
+
40
+ result = result.where('cm_routes.route_name ILIKE ?', "%#{query}%") if query.present?
41
+
42
+ result.distinct.order(fulfilled_order_count: :desc, order_count: :desc)
43
+ end
29
44
  end
30
45
  end
31
46
  end
@@ -33,18 +33,11 @@ module SpreeCmCommissioner
33
33
  end
34
34
  end
35
35
 
36
- # Returns dates for which inventory should be generated, based on calendar or default period.
37
36
  def inventory_dates_for(variant)
38
- calendar = variant.product&.service_calendar
37
+ start_date = Time.zone.tomorrow
38
+ end_date = Time.zone.today + pre_inventory_days_for(variant)
39
39
 
40
- if calendar.present?
41
- calendar.start_date.upto(calendar.end_date).select { |date| calendar.service_available?(date) }
42
- else
43
- start_date = Time.zone.tomorrow
44
- end_date = Time.zone.today + pre_inventory_days_for(variant)
45
-
46
- start_date.upto(end_date).to_a
47
- end
40
+ (start_date..end_date)
48
41
  end
49
42
 
50
43
  def inventory_exist?(variant, inventory_date)
@@ -75,7 +68,7 @@ module SpreeCmCommissioner
75
68
  def variants
76
69
  scope = Spree::Variant.active.with_permanent_stock.where(is_master: false)
77
70
  scope = scope.where(id: variant_ids) if variant_ids.present?
78
- scope.includes(product: :service_calendar)
71
+ scope
79
72
  end
80
73
  end
81
74
  end
@@ -8,8 +8,7 @@ module SpreeCmCommissioner
8
8
 
9
9
  return context.fail!(message: Spree.t(:doesnt_track_inventory)) unless variant.track_inventory?
10
10
 
11
- stock_location = resolve_stock_location(variant, stock_location_id)
12
-
11
+ stock_location = Spree::StockLocation.find(stock_location_id)
13
12
  stock_movement = stock_location.stock_movements.build(stock_movement_params)
14
13
  stock_movement.stock_item = stock_location.set_up_stock_item(variant)
15
14
 
@@ -23,14 +22,6 @@ module SpreeCmCommissioner
23
22
 
24
23
  private
25
24
 
26
- def resolve_stock_location(variant, stock_location_id = nil)
27
- if stock_location_id.present?
28
- Spree::StockLocation.find(stock_location_id)
29
- else
30
- variant.vendor.stock_locations.first || variant.vendor.send(:create_stock_location)
31
- end
32
- end
33
-
34
25
  def adjust_inventory_items_async(variant_id, quantity)
35
26
  args = { variant_id: variant_id, quantity: quantity }
36
27
  CmAppLogger.log(label: "#{self.class.name}#adjust_inventory_items_async", data: args) do
@@ -1,4 +1,4 @@
1
- # SpreeCmCommissioner::TransitOrder::Create creates a new order for a entire journey, including outbound and (if present) inbound directions.
1
+ # DraftOrderCreator creates a new order for a entire journey, including outbound and (if present) inbound directions.
2
2
  #
3
3
  # Attributes:
4
4
  # - outbound_date: [Date] The date of outbound transit
@@ -12,22 +12,25 @@
12
12
  #
13
13
  # Note: inbound_legs and inbound_date are optional; the order may represent a one-way (outbound only) journey.
14
14
  module SpreeCmCommissioner
15
- module TransitOrder
16
- class Create
17
- prepend ::Spree::ServiceModule::Base
15
+ module Transit
16
+ class DraftOrderCreator < BaseInteractor
17
+ delegate :outbound_date,
18
+ :inbound_date,
19
+ :outbound_legs,
20
+ :inbound_legs,
21
+ :user, to: :context
18
22
 
19
- def call(outbound_date:, inbound_date:, outbound_legs:, inbound_legs: [], user: nil)
20
- return failure(nil, 'Outbound legs are missing') if outbound_legs.blank?
23
+ def call
24
+ return context.fail!(message: 'Outbound legs are missing') if outbound_legs.blank?
21
25
 
22
26
  begin
23
- order = create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
24
- success(order: order)
27
+ context.order = create_order!
25
28
  rescue StandardError => e
26
- failure(nil, e.message)
29
+ context.fail!(message: e.message)
27
30
  end
28
31
  end
29
32
 
30
- def create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
33
+ def create_order!
31
34
  order = Spree::Order.new(state: 'cart', use_billing: true, user: user)
32
35
 
33
36
  outbound_line_items = build_line_items_for_legs!(order: order, legs: outbound_legs, initial_date: outbound_date)
@@ -109,10 +112,10 @@ module SpreeCmCommissioner
109
112
 
110
113
  def insert_saved_guests_per_line_items_leg(line_items)
111
114
  line_items.flat_map(&:guests).each_with_index do |guest, index|
112
- @saved_guests ||= []
113
- @saved_guests << SpreeCmCommissioner::SavedGuest.new if @saved_guests[index].blank?
115
+ context.saved_guests ||= []
116
+ context.saved_guests << SpreeCmCommissioner::SavedGuest.new if context.saved_guests[index].blank?
114
117
 
115
- guest.saved_guest = @saved_guests[index]
118
+ guest.saved_guest = context.saved_guests[index]
116
119
  end
117
120
 
118
121
  line_items
@@ -91,10 +91,9 @@ module SpreeCmCommissioner
91
91
  stop_params = params.dig(:trip_stops_attributes, index.to_s)
92
92
  return unless stop_params
93
93
 
94
- cloned_stop.departure_time = parse_time(stop_params[:departure_time])
95
- cloned_stop.arrival_time = parse_time(stop_params[:arrival_time])
96
- cloned_stop.allow_boarding = stop_params[:allow_boarding] if stop_params.key?(:allow_boarding)
97
- cloned_stop.allow_drop_off = stop_params[:allow_drop_off] if stop_params.key?(:allow_drop_off)
94
+ cloned_stop.departure_time = parse_time(stop_params[:departure_time])
95
+ cloned_stop.arrival_time = parse_time(stop_params[:arrival_time])
96
+ cloned_stop.stop_type = stop_params[:stop_type].presence
98
97
  cloned_stop.location_place_id = stop_params[:location_place_id].presence
99
98
  end
100
99
 
@@ -26,7 +26,7 @@ module SpreeCmCommissioner
26
26
  trip: trip,
27
27
  stop_place: origin_place,
28
28
  location_place: origin_place,
29
- allow_boarding: true
29
+ stop_type: :boarding
30
30
  }
31
31
 
32
32
  attributes[:departure_time] = departure_time
@@ -42,7 +42,7 @@ module SpreeCmCommissioner
42
42
  trip: trip,
43
43
  stop_place: destination_place,
44
44
  location_place: destination_place,
45
- allow_drop_off: true
45
+ stop_type: :drop_off
46
46
  }
47
47
 
48
48
  attributes[:arrival_time] = departure_time + duration_seconds.seconds
@@ -1,8 +1,8 @@
1
1
  module SpreeCmCommissioner
2
2
  module Stock
3
3
  class PermanentInventoryItemsGeneratorJob < ApplicationUniqueJob
4
- def perform(options = {})
5
- SpreeCmCommissioner::Stock::PermanentInventoryItemsGenerator.call(options)
4
+ def perform
5
+ SpreeCmCommissioner::Stock::PermanentInventoryItemsGenerator.call
6
6
  end
7
7
  end
8
8
  end
@@ -0,0 +1,10 @@
1
+ module SpreeCmCommissioner
2
+ module Transit
3
+ class RouteFulfilledOrderCountIncrementerJob < ApplicationUniqueJob
4
+ def perform(options = {})
5
+ order = Spree::Order.find(options[:order_id])
6
+ SpreeCmCommissioner::Routes::IncrementFulfilledOrderCount.call(order: order)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module SpreeCmCommissioner
2
+ module Transit
3
+ class RouteOrderCountIncrementerJob < ApplicationUniqueJob
4
+ def perform(options = {})
5
+ order = Spree::Order.find(options[:order_id])
6
+ SpreeCmCommissioner::Routes::IncrementOrderCount.call(order: order)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ # Perform the previous-route decrement outside the Trip transaction.
2
+
3
+ module SpreeCmCommissioner
4
+ module Transit
5
+ class RoutePreviousTripCountDecrementerJob < ApplicationUniqueJob
6
+ queue_as :default
7
+
8
+ def perform(options = {})
9
+ SpreeCmCommissioner::Routes::DecrementPreviousTripCount.call(previous_route_id: options[:previous_route_id])
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module SpreeCmCommissioner
2
+ module Transit
3
+ class RouteTripCountDecrementerJob < ApplicationUniqueJob
4
+ def perform(options = {})
5
+ trip = SpreeCmCommissioner::Trip.find(options[:trip_id])
6
+ SpreeCmCommissioner::Routes::DecrementTripCount.call(trip: trip)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module SpreeCmCommissioner
2
+ module Transit
3
+ class RouteTripCountIncrementerJob < ApplicationUniqueJob
4
+ def perform(options = {})
5
+ trip = SpreeCmCommissioner::Trip.find(options[:trip_id])
6
+ SpreeCmCommissioner::Routes::IncrementTripCount.call(trip: trip)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -9,7 +9,7 @@ module SpreeCmCommissioner
9
9
  state_machine.before_transition to: :payment, do: :ensure_blocks_held
10
10
 
11
11
  state_machine.before_transition to: :complete, do: :request, if: :need_confirmation?
12
- state_machine.before_transition to: :complete, do: :generate_bib_number
12
+ state_machine.before_transition to: :complete, do: :finalize_guests_and_bibs
13
13
  state_machine.before_transition to: :complete, do: :generate_completion_steps!, if: :product_completion_steps_exist?
14
14
 
15
15
  state_machine.after_transition to: :complete, do: :precalculate_conversion
@@ -168,21 +168,26 @@ module SpreeCmCommissioner
168
168
  end
169
169
  end
170
170
 
171
- def generate_bib_number
172
- line_items.find_each(&:generate_remaining_guests)
173
-
174
- line_items.with_bib_prefix.each do |line_item|
175
- line_item.guests.none_bib.each do |guest|
176
- guest.generate_bib
177
- next if guest.save
171
+ def finalize_guests_and_bibs
172
+ ActiveRecord::Base.transaction do
173
+ line_items.each do |line_item|
174
+ line_item.generate_remaining_guests
178
175
 
179
- guest.errors.each do |msg|
180
- errors.add(:guests, msg)
176
+ line_item.guests.each do |guest|
177
+ guest.user = user if user.present?
178
+ guest.generate_bib_if_needed
179
+ guest.save!
181
180
  end
182
181
  end
183
182
  end
184
183
 
185
- errors.empty?
184
+ true
185
+ rescue ActiveRecord::RecordInvalid => e
186
+ e.record.errors.each do |msg|
187
+ errors.add(:guests, msg)
188
+ end
189
+
190
+ false
186
191
  end
187
192
 
188
193
  def rejected_by(user)
@@ -7,13 +7,13 @@ module SpreeCmCommissioner
7
7
  def increment_route_fulfilled_order_count
8
8
  return unless has_trip_ids?
9
9
 
10
- SpreeCmCommissioner::RouteMetrics::IncreaseFulfilledOrderCountJob.perform_later(order_id: id)
10
+ SpreeCmCommissioner::Transit::RouteFulfilledOrderCountIncrementerJob.perform_later(order_id: id)
11
11
  end
12
12
 
13
13
  def increment_route_order_count
14
14
  return unless has_trip_ids?
15
15
 
16
- SpreeCmCommissioner::RouteMetrics::IncreaseOrderCountJob.perform_later(order_id: id)
16
+ SpreeCmCommissioner::Transit::RouteOrderCountIncrementerJob.perform_later(order_id: id)
17
17
  end
18
18
  end
19
19
  end