spree_cm_commissioner 2.3.1 → 2.3.2.pre.pre4

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/controllers/spree/admin/product_completion_steps_controller.rb +17 -1
  4. data/app/controllers/spree/admin/tenants_controller.rb +1 -1
  5. data/app/controllers/spree/api/v2/storefront/intercity_taxi/draft_orders_controller.rb +52 -11
  6. data/app/controllers/spree/api/v2/storefront/popular_route_places_controller.rb +63 -0
  7. data/app/controllers/spree/api/v2/storefront/route_places_controller.rb +68 -0
  8. data/app/controllers/spree/api/v2/tenant/intercity_taxi/draft_orders_controller.rb +81 -0
  9. data/app/controllers/spree/api/v2/tenant/trip_places_controller.rb +42 -0
  10. data/app/controllers/spree/api/v2/tenant/trip_search_controller.rb +103 -0
  11. data/app/controllers/spree/api/v2/tenant/trips_controller.rb +32 -0
  12. data/app/factory/spree_cm_commissioner/order_telegram_message_factory.rb +12 -0
  13. data/app/finders/spree_cm_commissioner/places/find_with_route.rb +43 -0
  14. data/app/finders/spree_cm_commissioner/routes/find_popular.rb +25 -0
  15. data/app/interactors/spree_cm_commissioner/create_ticket.rb +2 -0
  16. data/app/interactors/spree_cm_commissioner/host_matcher.rb +1 -1
  17. data/app/interactors/spree_cm_commissioner/vendor_creation_telegram_alert_sender.rb +1 -1
  18. data/app/mailers/spree/order_mailer_decorator.rb +12 -11
  19. data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +34 -89
  20. data/app/models/concerns/spree_cm_commissioner/service_recommendations.rb +2 -2
  21. data/app/models/concerns/spree_cm_commissioner/store_preference.rb +1 -0
  22. data/app/models/spree_cm_commissioner/adjustment_decorator.rb +1 -1
  23. data/app/models/spree_cm_commissioner/calculators/extra_drop_off_distance.rb +15 -0
  24. data/app/models/spree_cm_commissioner/calculators/extra_pick_up_distance.rb +15 -0
  25. data/app/models/spree_cm_commissioner/place.rb +7 -0
  26. data/app/models/spree_cm_commissioner/pricing_action.rb +27 -0
  27. data/app/models/spree_cm_commissioner/pricing_model.rb +18 -0
  28. data/app/models/spree_cm_commissioner/pricing_model_variant.rb +6 -0
  29. data/app/models/spree_cm_commissioner/pricing_rule.rb +15 -0
  30. data/app/models/spree_cm_commissioner/pricing_rule_group.rb +20 -0
  31. data/app/models/spree_cm_commissioner/pricing_rules/extra_drop_off_distance.rb +10 -0
  32. data/app/models/spree_cm_commissioner/pricing_rules/extra_pick_up_distance.rb +12 -0
  33. data/app/models/spree_cm_commissioner/pricing_rules/nationality.rb +35 -0
  34. data/app/models/spree_cm_commissioner/product_completion_step.rb +4 -1
  35. data/app/models/spree_cm_commissioner/product_completion_step_banner.rb +12 -0
  36. data/app/models/spree_cm_commissioner/product_completion_steps/social_entry_url.rb +86 -19
  37. data/app/models/spree_cm_commissioner/tenant.rb +14 -1
  38. data/app/models/spree_cm_commissioner/variant_decorator.rb +3 -0
  39. data/app/models/spree_cm_commissioner/vendor_decorator.rb +1 -0
  40. data/app/models/spree_cm_commissioner/vendor_place.rb +10 -1
  41. data/app/overrides/spree/admin/stores/_form/store_preferences.html.erb.deface +9 -0
  42. data/app/queries/spree_cm_commissioner/trip_query.rb +23 -17
  43. data/app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_schema.rb +10 -0
  44. data/app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_update_schema.rb +29 -0
  45. data/app/request_schemas/spree_cm_commissioner/route_places_request_schema.rb +12 -0
  46. data/app/serializers/spree/v2/storefront/place_serializer.rb +3 -2
  47. data/app/serializers/spree/v2/tenant/cart_serializer.rb +1 -0
  48. data/app/serializers/spree/v2/tenant/intercity_taxi_cart_serializer.rb +12 -0
  49. data/app/serializers/spree/v2/tenant/line_item_serializer.rb +1 -0
  50. data/app/serializers/spree/v2/tenant/trip_place_serializer.rb +8 -0
  51. data/app/serializers/spree/v2/tenant/trip_query_result_serializer.rb +8 -0
  52. data/app/serializers/spree/v2/tenant/trip_serializer.rb +8 -0
  53. data/app/serializers/spree_cm_commissioner/v2/storefront/intercity_taxi_line_item_serializer.rb +17 -18
  54. data/app/serializers/spree_cm_commissioner/v2/storefront/route_serializer.rb +12 -0
  55. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_vehicle_serializer.rb +1 -1
  56. data/app/services/spree_cm_commissioner/intercity_taxi_order/create.rb +20 -23
  57. data/app/services/spree_cm_commissioner/intercity_taxi_order/update.rb +36 -72
  58. data/app/services/spree_cm_commissioner/pricing_models/apply.rb +51 -0
  59. data/app/services/spree_cm_commissioner/pricing_rules/build_params.rb +53 -0
  60. data/app/services/spree_cm_commissioner/pricing_rules/build_template.rb +27 -0
  61. data/app/services/spree_cm_commissioner/pricing_rules/create.rb +10 -0
  62. data/app/services/spree_cm_commissioner/pricing_rules/update.rb +11 -0
  63. data/app/services/spree_cm_commissioner/vendor_places/base.rb +24 -0
  64. data/app/services/spree_cm_commissioner/vendor_places/bulk_create.rb +70 -0
  65. data/app/services/spree_cm_commissioner/vendor_places/create_with_google_map_data.rb +85 -0
  66. data/app/services/spree_cm_commissioner/vendor_places/update.rb +56 -0
  67. data/app/views/shared/_asset_field.html.erb +13 -0
  68. data/app/views/spree/admin/product_completion_steps/_form.html.erb +28 -2
  69. data/app/views/spree/admin/product_completion_steps/_supported_fields.html.erb +33 -0
  70. data/app/views/spree/admin/tenants/_form.html.erb +1 -1
  71. data/app/views/spree/order_mailer/confirm_email.html.erb +1 -1
  72. data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +14 -13
  73. data/app/views/spree_cm_commissioner/order_mailer/tenant/_greeting.html.erb +6 -4
  74. data/config/initializers/spree_permitted_attributes.rb +1 -0
  75. data/config/locales/en.yml +4 -0
  76. data/config/locales/km.yml +65 -61
  77. data/config/routes.rb +15 -1
  78. data/db/migrate/20250915075830_create_spree_cm_commissioner_pricing_models.rb +17 -0
  79. data/db/migrate/20250915080733_create_spree_cm_commissioner_pricing_model_variants.rb +14 -0
  80. data/db/migrate/20251003082144_create_spree_cm_commissioner_pricing_rule_groups.rb +16 -0
  81. data/db/migrate/20251003093408_create_spree_cm_commissioner_pricing_rule.rb +19 -0
  82. data/db/migrate/20251003093643_create_spree_cm_commissioner_pricing_action.rb +14 -0
  83. data/db/migrate/20251119093000_add_tenant_id_to_cm_vendor_places.rb +8 -0
  84. data/lib/spree_cm_commissioner/intercity_taxi/distance.rb +38 -0
  85. data/lib/spree_cm_commissioner/intercity_taxi/map_place.rb +31 -0
  86. data/lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb +5 -0
  87. data/lib/spree_cm_commissioner/test_helper/factories/pricing_model_factory.rb +8 -0
  88. data/lib/spree_cm_commissioner/test_helper/factories/pricing_rule_factory.rb +17 -0
  89. data/lib/spree_cm_commissioner/test_helper/factories/pricing_rule_group_factory.rb +8 -0
  90. data/lib/spree_cm_commissioner/test_helper/factories/product_completion_step_banner_factory.rb +7 -0
  91. data/lib/spree_cm_commissioner/version.rb +1 -1
  92. data/lib/spree_cm_commissioner.rb +2 -0
  93. metadata +54 -4
@@ -12,7 +12,10 @@ module SpreeCmCommissioner
12
12
  through: :vendors,
13
13
  source: :payment_methods
14
14
 
15
- validates :host, uniqueness: true, presence: true
15
+ validates :host, presence: true, uniqueness: true,
16
+ format: { without: %r{\Ahttps?://},
17
+ message: :format
18
+ }
16
19
 
17
20
  enum state: { enabled: 0, disabled: 1 }
18
21
 
@@ -22,6 +25,16 @@ module SpreeCmCommissioner
22
25
  vendors.where(state: :active).first
23
26
  end
24
27
 
28
+ def url
29
+ host
30
+ end
31
+
32
+ def formatted_url
33
+ return if host.blank?
34
+
35
+ Rails.env.development? || Rails.env.test? ? "http://#{host}" : "https://#{host}"
36
+ end
37
+
25
38
  private
26
39
 
27
40
  def generate_slug
@@ -30,6 +30,9 @@ module SpreeCmCommissioner
30
30
 
31
31
  base.has_many :inventory_items, class_name: 'SpreeCmCommissioner::InventoryItem'
32
32
 
33
+ base.has_many :pricing_model_variants, class_name: 'SpreeCmCommissioner::PricingModelVariant', dependent: :destroy
34
+ base.has_many :pricing_models, through: :pricing_model_variants, class_name: 'SpreeCmCommissioner::PricingModel'
35
+
33
36
  base.scope :subscribable, -> { active.joins(:product).where(product: { subscribable: true, status: :active }) }
34
37
  base.scope :with_permanent_stock, -> { where(product_type: base::PERMANENT_STOCK_PRODUCT_TYPES) }
35
38
  base.scope :with_non_permanent_stock, -> { where.not(product_type: base::PERMANENT_STOCK_PRODUCT_TYPES) }
@@ -91,6 +91,7 @@ module SpreeCmCommissioner
91
91
  base.has_many :trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop'
92
92
  base.has_many :boarding_trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop', source: :boarding_trip_stops
93
93
  base.has_many :drop_off_trip_stops, through: :trips, class_name: 'SpreeCmCommissioner::TripStop', source: :drop_off_trip_stops
94
+ base.has_many :pricing_models, class_name: 'SpreeCmCommissioner::PricingModel', foreign_key: :vendor_id, dependent: :destroy
94
95
 
95
96
  base.validates :account_name, :account_number, presence: true, if: lambda {
96
97
  payment_qrcode.present? && Spree::Store.default.code.include?('billing')
@@ -1,8 +1,9 @@
1
1
  module SpreeCmCommissioner
2
2
  class VendorPlace < Base
3
- enum place_type: { location: 0, branch: 1, stop: 2 }
3
+ enum place_type: { venue: 0, branch: 1, stop: 2, location: 3 }
4
4
  acts_as_list scope: :vendor
5
5
 
6
+ belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant', optional: true
6
7
  belongs_to :vendor, class_name: 'Spree::Vendor', optional: false
7
8
  belongs_to :place, class_name: 'SpreeCmCommissioner::Place', optional: false
8
9
  belongs_to :location, class_name: 'SpreeCmCommissioner::VendorPlace', optional: true
@@ -16,6 +17,8 @@ module SpreeCmCommissioner
16
17
 
17
18
  accepts_nested_attributes_for :place, allow_destroy: true
18
19
 
20
+ before_save :set_tenant_id
21
+
19
22
  # include place when using these delegate to avoid N+1
20
23
  def display_name
21
24
  place&.name
@@ -28,5 +31,11 @@ module SpreeCmCommissioner
28
31
  def selected
29
32
  vendor.selected_place_references.include?(place&.reference)
30
33
  end
34
+
35
+ private
36
+
37
+ def set_tenant_id
38
+ self.tenant_id = vendor&.tenant_id
39
+ end
31
40
  end
32
41
  end
@@ -37,6 +37,15 @@
37
37
  <% end %>
38
38
  </div>
39
39
 
40
+ <!-- Telegram New Vendor Alert Chat ID -->
41
+ <div class="col-6">
42
+ <%= f.field_container :preferred_telegram_new_vendor_alert_chat_id do %>
43
+ <%= f.label :preferred_telegram_new_vendor_alert_chat_id, Spree.t(:telegram_new_vendor_alert_chat_id) %>
44
+ <%= f.text_field :preferred_telegram_new_vendor_alert_chat_id, class: 'form-control' %>
45
+ <%= f.error_message_on :preferred_telegram_new_vendor_alert_chat_id %>
46
+ <% end %>
47
+ </div>
48
+
40
49
  <!-- Assetlinks -->
41
50
  <div class="col-12">
42
51
  <%= f.field_container :preferred_assetlinks do %>
@@ -1,12 +1,13 @@
1
1
  module SpreeCmCommissioner
2
2
  class TripQuery
3
- attr_reader :origin_id, :destination_id, :date, :vendor_id, :number_of_guests, :route_type, :params
3
+ attr_reader :origin_id, :destination_id, :date, :vendor_id, :tenant_id, :number_of_guests, :route_type, :params
4
4
 
5
- def initialize(origin_id:, destination_id:, date:, route_type: nil, vendor_id: nil, number_of_guests: nil, params: {}) # rubocop:disable Metrics/ParameterLists
5
+ def initialize(origin_id:, destination_id:, date:, route_type: nil, vendor_id: nil, tenant_id: nil, number_of_guests: nil, params: {}) # rubocop:disable Metrics/ParameterLists
6
6
  @origin_id = origin_id
7
7
  @destination_id = destination_id
8
8
  @date = date.to_date == Time.zone.now.to_date ? Time.zone.now : Time.zone.parse(date.to_s)
9
9
  @vendor_id = vendor_id
10
+ @tenant_id = tenant_id
10
11
  @number_of_guests = number_of_guests || 1
11
12
  @route_type = route_type
12
13
  @params = params
@@ -36,8 +37,9 @@ module SpreeCmCommissioner
36
37
 
37
38
  def direct_trips
38
39
  result = trip_scope
39
- result = result.where({ vendor_id: vendor_id }.compact)
40
+ result = result.where({ vendor_id: vendor_id }.compact) if vendor_id.present?
40
41
  result = result.where(route_type: route_type) if route_type.present?
42
+ result = result.where(spree_vendors: { tenant_id: tenant_id }) if tenant_id.present?
41
43
  paginate(result)
42
44
  end
43
45
 
@@ -56,20 +58,24 @@ module SpreeCmCommissioner
56
58
  private
57
59
 
58
60
  def trip_scope
59
- SpreeCmCommissioner::Trip
60
- .select(<<~SQL.squish)
61
- cm_trips.*,
62
- boarding.departure_time AS boarding_departure_time,
63
- boarding.stop_place_id AS boarding_stop_id, boarding.stop_name AS boarding_stop_name,
64
- drop_off.stop_name AS drop_off_stop_name, drop_off.stop_place_id AS drop_off_stop_id,
65
- drop_off.arrival_time AS drop_off_arrival_time,
66
- COALESCE(iv.quantity_available, 0) AS quantity_available,
67
- COALESCE(iv.max_capacity, 0) AS max_capacity,
68
- origin_places.name AS origin_place_name, dest_places.name AS destination_place_name,
69
- prices.amount AS amount, prices.compare_at_amount AS compare_at_amount,
70
- prices.currency AS currency
71
- SQL
72
- .includes(vendor: :logo, vehicle: :option_values)
61
+ scope = SpreeCmCommissioner::Trip
62
+ .select(<<~SQL.squish)
63
+ cm_trips.*,
64
+ boarding.departure_time AS boarding_departure_time,
65
+ boarding.stop_place_id AS boarding_stop_id, boarding.stop_name AS boarding_stop_name,
66
+ drop_off.stop_name AS drop_off_stop_name, drop_off.stop_place_id AS drop_off_stop_id,
67
+ drop_off.arrival_time AS drop_off_arrival_time,
68
+ COALESCE(iv.quantity_available, 0) AS quantity_available,
69
+ COALESCE(iv.max_capacity, 0) AS max_capacity,
70
+ origin_places.name AS origin_place_name, dest_places.name AS destination_place_name,
71
+ prices.amount AS amount, prices.compare_at_amount AS compare_at_amount,
72
+ prices.currency AS currency
73
+ SQL
74
+ .includes(vendor: :logo, vehicle: :option_values)
75
+
76
+ scope = scope.joins(:vendor) if tenant_id.present?
77
+
78
+ scope
73
79
  .joins(<<~SQL.squish)
74
80
  INNER JOIN cm_trip_stops AS boarding ON boarding.trip_id = cm_trips.id AND boarding.stop_type = 0
75
81
  INNER JOIN cm_trip_stops AS drop_off ON drop_off.trip_id = cm_trips.id AND drop_off.stop_type = 1
@@ -0,0 +1,10 @@
1
+ module SpreeCmCommissioner
2
+ class IntercityTaxiDraftOrderSchema < ApplicationRequestSchema
3
+ params do
4
+ required(:trip_id).value(:integer)
5
+ required(:from_date).value(:date)
6
+ required(:to_date).value(:date)
7
+ required(:quantity).value(:integer)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ module SpreeCmCommissioner
2
+ class IntercityTaxiDraftOrderUpdateSchema < ApplicationRequestSchema
3
+ params do
4
+ optional(:remark).filled(:string)
5
+ optional(:pickup_map_place_attributes).hash do
6
+ optional(:place_name).filled(:string)
7
+ optional(:lat).filled(:string)
8
+ optional(:lng).filled(:string)
9
+ optional(:oob_confirmed).filled(:bool)
10
+ end
11
+ optional(:dropoff_map_place_attributes).hash do
12
+ optional(:place_name).filled(:string)
13
+ optional(:lat).filled(:string)
14
+ optional(:lng).filled(:string)
15
+ optional(:oob_confirmed).filled(:bool)
16
+ end
17
+ optional(:distance_attributes).hash do
18
+ optional(:distance_km).filled(:float)
19
+ optional(:ordered_points).filled(:array)
20
+ optional(:estimated_time_minutes).filled(:integer)
21
+ optional(:base_km).filled(:float)
22
+ optional(:detour_pickup_km).filled(:float)
23
+ optional(:detour_dropoff_km).filled(:float)
24
+ optional(:extra_pickup_km).filled(:float)
25
+ optional(:extra_dropoff_km).filled(:float)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ module SpreeCmCommissioner
2
+ class RoutePlacesRequestSchema < ApplicationRequestSchema
3
+ params do
4
+ required(:place_type).filled(:string)
5
+ required(:query).filled(:string)
6
+ end
7
+
8
+ rule(:place_type) do
9
+ key.failure('Invalid place_type. Use origin or destination') unless %w[origin destination].include?(value)
10
+ end
11
+ end
12
+ end
@@ -4,8 +4,9 @@ module Spree
4
4
  class PlaceSerializer < BaseSerializer
5
5
  set_type :place
6
6
 
7
- has_many :vendors
8
- has_many :nearby_places, serializer: :nearby_place
7
+ # Included by default, pass false to exclude
8
+ has_many :vendors, if: proc { |_, params| params.nil? || params[:include_vendors] != false }
9
+ has_many :nearby_places, serializer: :nearby_place, if: proc { |_, params| params.nil? || params[:include_nearby_places] != false }
9
10
 
10
11
  attributes :reference, :name, :vicinity, :lat, :lon, :icon, :url, :rating,
11
12
  :formatted_phone_number, :formatted_address, :address_components, :types
@@ -20,6 +20,7 @@ module Spree
20
20
  has_many :promotions, object_method_name: :valid_promotions, id_method_name: :valid_promotion_ids,
21
21
  serializer: Spree::V2::Storefront::PromotionSerializer
22
22
 
23
+ has_many :saved_guests, serializer: SpreeCmCommissioner::V2::Storefront::SavedGuestSerializer
23
24
  has_many :variants, serializer: Spree::V2::Tenant::VariantSerializer
24
25
  has_many :products, serializer: Spree::V2::Tenant::ProductSerializer
25
26
  has_many :line_items, serializer: Spree::V2::Tenant::LineItemSerializer
@@ -0,0 +1,12 @@
1
+ module Spree
2
+ module V2
3
+ module Tenant
4
+ class IntercityTaxiCartSerializer < CartSerializer
5
+ has_many :line_items,
6
+ serializer: SpreeCmCommissioner::V2::Storefront::IntercityTaxiLineItemSerializer
7
+
8
+ cache_options store: nil
9
+ end
10
+ end
11
+ end
12
+ end
@@ -20,6 +20,7 @@ module Spree
20
20
 
21
21
  has_one :vendor, serializer: Spree::V2::Tenant::VendorSerializer
22
22
  has_one :product, serializer: Spree::V2::Storefront::ProductSerializer
23
+ has_many :saved_guests, serializer: SpreeCmCommissioner::V2::Storefront::SavedGuestSerializer
23
24
 
24
25
  belongs_to :variant, serializer: Spree::V2::Tenant::VariantSerializer
25
26
  belongs_to :order, serializer: Spree::V2::Tenant::OrderSerializer
@@ -0,0 +1,8 @@
1
+ module Spree
2
+ module V2
3
+ module Tenant
4
+ class TripPlaceSerializer < SpreeCmCommissioner::V2::Storefront::TripPlaceSerializer
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Spree
2
+ module V2
3
+ module Tenant
4
+ class TripQueryResultSerializer < SpreeCmCommissioner::V2::Storefront::TripQueryResultSerializer
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Spree
2
+ module V2
3
+ module Tenant
4
+ class TripSerializer < SpreeCmCommissioner::V2::Storefront::TripSerializer
5
+ end
6
+ end
7
+ end
8
+ end
@@ -2,29 +2,28 @@ module SpreeCmCommissioner
2
2
  module V2
3
3
  module Storefront
4
4
  class IntercityTaxiLineItemSerializer < BaseSerializer
5
- attributes :pickup_place_name,
6
- :drop_off_place_name,
7
- :pickup_lat,
8
- :pickup_lng,
9
- :drop_off_lat,
10
- :drop_off_lng,
11
- :passenger_count,
12
- :distance_km,
13
- :ordered_points,
14
- :base_km,
15
- :detour_pickup_km,
16
- :detour_dropoff_km,
17
- :extra_pickup_km,
18
- :extra_dropoff_km,
19
- :extra_pickup_charge_usd,
20
- :extra_dropoff_charge_usd,
21
- :estimated_time_minutes,
5
+ # Nested-only API shape
6
+ attributes :pickup_map_place,
7
+ :dropoff_map_place,
8
+ :distance,
22
9
  :from_date,
23
10
  :to_date,
24
- :direction,
11
+ :remark,
25
12
  :trip_id
26
13
 
27
14
  cache_options store: nil
15
+
16
+ def pickup_map_place
17
+ object.pickup_map_place&.to_h
18
+ end
19
+
20
+ def dropoff_map_place
21
+ object.dropoff_map_place&.to_h
22
+ end
23
+
24
+ def distance
25
+ object.distance&.to_h
26
+ end
28
27
  end
29
28
  end
30
29
  end
@@ -0,0 +1,12 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class RouteSerializer < BaseSerializer
5
+ attributes :route_name
6
+
7
+ has_one :origin_place, serializer: ::Spree::V2::Storefront::PlaceSerializer
8
+ has_one :destination_place, serializer: ::Spree::V2::Storefront::PlaceSerializer
9
+ end
10
+ end
11
+ end
12
+ end
@@ -4,7 +4,7 @@ module SpreeCmCommissioner
4
4
  class TripVehicleSerializer < BaseSerializer
5
5
  set_type :vehicle
6
6
 
7
- attributes :id, :code, :vehicle_type
7
+ attributes :id, :code, :vehicle_type, :number_of_seats
8
8
 
9
9
  has_many :vehicle_photos, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
10
10
  has_many :amenities, serializer: ::SpreeCmCommissioner::V2::Storefront::AmenitySerializer
@@ -1,35 +1,19 @@
1
1
  module SpreeCmCommissioner
2
2
  module IntercityTaxiOrder
3
3
  class Create
4
- attr_reader :trip_id, :from_date, :to_date, :user_id, :quantity
4
+ prepend ::Spree::ServiceModule::Base
5
5
 
6
- def self.call(trip_id:, from_date:, to_date:, user_id: nil, quantity: 1)
7
- new(
8
- trip_id: trip_id,
9
- from_date: from_date,
10
- to_date: to_date,
11
- user_id: user_id,
12
- quantity: quantity
13
- ).call
14
- end
15
-
16
- def initialize(trip_id:, from_date:, to_date:, user_id:, quantity:)
17
- @trip_id = trip_id
18
- @from_date = from_date
19
- @to_date = to_date
20
- @user_id = user_id
21
- @quantity = quantity.to_i <= 0 ? 1 : quantity.to_i
22
- end
6
+ def call(trip_id:, from_date:, to_date:, user: nil, quantity: 1)
7
+ validate!(trip_id: trip_id, from_date: from_date, to_date: to_date, quantity: quantity)
23
8
 
24
- def call
25
- validate!
9
+ quantity = quantity.to_i
26
10
 
27
- ActiveRecord::Base.transaction do
11
+ order = ActiveRecord::Base.transaction do
28
12
  trip = SpreeCmCommissioner::Trip.find(trip_id)
29
13
  variant = trip.product.variants.first
30
14
  raise ArgumentError, 'No variant found for trip' if variant.blank?
31
15
 
32
- order = Spree::Order.new(state: 'cart', use_billing: true, user_id: user_id)
16
+ order = Spree::Order.new(state: 'cart', use_billing: true, user: user)
33
17
 
34
18
  line_item = order.line_items.new(
35
19
  variant_id: variant.id,
@@ -42,26 +26,39 @@ module SpreeCmCommissioner
42
26
  )
43
27
 
44
28
  build_guests_for!(line_item, quantity)
29
+ assign_saved_guests_to_line_item(line_item)
45
30
 
46
31
  order.save!
47
32
  order.update_with_updater!
48
33
 
49
34
  order
50
35
  end
36
+
37
+ success(order)
38
+ rescue StandardError => e
39
+ failure(nil, e.message)
51
40
  end
52
41
 
53
42
  private
54
43
 
55
- def validate!
44
+ def validate!(trip_id:, from_date:, to_date:, quantity:)
56
45
  raise ArgumentError, 'trip_id is required' if trip_id.blank?
57
46
  raise ArgumentError, 'from_date is required' if from_date.blank?
58
47
  raise ArgumentError, 'to_date is required' if to_date.blank?
59
48
  raise ArgumentError, 'to_date must be after from_date' if from_date.present? && to_date.present? && to_date < from_date
49
+ raise ArgumentError, 'quantity must be 1' if quantity.to_i != 1
60
50
  end
61
51
 
62
52
  def build_guests_for!(line_item, qty)
63
53
  Array.new(qty) { line_item.guests.new }
64
54
  end
55
+
56
+ def assign_saved_guests_to_line_item(line_item)
57
+ line_item.guests.each do |guest|
58
+ saved_guest = SpreeCmCommissioner::SavedGuest.new
59
+ guest.saved_guest = saved_guest
60
+ end
61
+ end
65
62
  end
66
63
  end
67
64
  end
@@ -1,78 +1,42 @@
1
1
  module SpreeCmCommissioner
2
2
  module IntercityTaxiOrder
3
3
  class Update
4
- attr_reader :order_number, :params
5
-
6
- def self.call(order_number:, params:)
7
- new(order_number: order_number, params: params).call
8
- end
9
-
10
- def initialize(order_number:, params:)
11
- @order_number = order_number
12
- @params = ensure_parameters(params)
13
- end
14
-
15
- def call
16
- order = Spree::Order.find_by!(number: order_number)
17
- order.update!(order_params)
18
-
19
- create_billing_address_if_missing(order)
20
-
21
- order
22
- end
23
-
24
- private
25
-
26
- def ensure_parameters(params)
27
- return params if params.is_a?(::ActionController::Parameters)
28
-
29
- ::ActionController::Parameters.new(params)
30
- end
31
-
32
- def create_billing_address_if_missing(order)
33
- return if order.bill_address.present?
34
-
35
- SpreeCmCommissioner::BillingAddressCreator.call(order: order)
36
- end
37
-
38
- def order_params
39
- params.require(:order).permit(
40
- :intel_phone_number,
41
- :email,
42
- line_items_attributes: [
43
- :id,
44
- :pickup_place_name,
45
- :drop_off_place_name,
46
- :from_date,
47
- :pickup_lat,
48
- :pickup_lng,
49
- :pickup_oob_confirmed,
50
- :drop_off_lat,
51
- :drop_off_lng,
52
- :drop_off_oob_confirmed,
53
- :distance_km,
54
- :ordered_points,
55
- :base_km,
56
- :detour_pickup_km,
57
- :detour_dropoff_km,
58
- :extra_pickup_km,
59
- :extra_dropoff_km,
60
- :extra_pickup_charge_usd,
61
- :extra_dropoff_charge_usd,
62
- :estimated_time_minutes,
63
- :remark,
64
- :passenger_count,
65
- { guests_attributes: %i[
66
- id
67
- first_name
68
- last_name
69
- gender
70
- nationality_id
71
- age
72
- ]
73
- }
74
- ]
75
- )
4
+ prepend ::Spree::ServiceModule::Base
5
+
6
+ def call(
7
+ order:,
8
+ remark: nil,
9
+ pickup_map_place_attributes: nil,
10
+ dropoff_map_place_attributes: nil,
11
+ distance_attributes: nil
12
+ )
13
+ line_item = order.line_items.first
14
+
15
+ raise ArgumentError, 'Order has no line items' if line_item.blank?
16
+
17
+ if pickup_map_place_attributes.present?
18
+ line_item.pickup_map_place = SpreeCmCommissioner::IntercityTaxi::MapPlace.new(
19
+ pickup_map_place_attributes
20
+ )
21
+ end
22
+
23
+ if dropoff_map_place_attributes.present?
24
+ line_item.dropoff_map_place = SpreeCmCommissioner::IntercityTaxi::MapPlace.new(
25
+ dropoff_map_place_attributes
26
+ )
27
+ end
28
+
29
+ if distance_attributes.present?
30
+ line_item.distance = SpreeCmCommissioner::IntercityTaxi::Distance.new(
31
+ distance_attributes
32
+ )
33
+ end
34
+
35
+ line_item.update!(remark: remark)
36
+
37
+ success(order.reload)
38
+ rescue StandardError => e
39
+ failure(nil, e.message)
76
40
  end
77
41
  end
78
42
  end
@@ -0,0 +1,51 @@
1
+ module SpreeCmCommissioner
2
+ module PricingModels
3
+ class Apply
4
+ def initialize(line_item_id:, pricing_model_id:)
5
+ @line_item_id = line_item_id
6
+ @pricing_model_id = pricing_model_id
7
+ end
8
+
9
+ def call
10
+ pricing_model.pricing_rule_groups.each do |group|
11
+ apply_group(group, line_item)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :line_item_id, :pricing_model_id
18
+
19
+ def line_item
20
+ @line_item ||= Spree::LineItem.find(line_item_id)
21
+ end
22
+
23
+ def pricing_model
24
+ @pricing_model ||= SpreeCmCommissioner::PricingModel.find(pricing_model_id)
25
+ end
26
+
27
+ def apply_group(group, line_item)
28
+ eligible_rules = group.pricing_rules.select { |r| r.eligible?(line_item) }
29
+
30
+ return if eligible_rules.empty?
31
+
32
+ if group_eligible?(group, eligible_rules)
33
+ group.pricing_action&.perform(line_item)
34
+ else
35
+ Rails.logger.info("Group #{group.id} not eligible for line_item #{line_item.id}")
36
+ end
37
+ end
38
+
39
+ def group_eligible?(group, eligible_rules)
40
+ case group.match_type
41
+ when 'all'
42
+ eligible_rules.size == group.pricing_rules.size
43
+ when 'any'
44
+ eligible_rules.any?
45
+ else
46
+ false
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,53 @@
1
+ module SpreeCmCommissioner
2
+ module PricingRules
3
+ module BuildParams
4
+ module_function
5
+
6
+ def permitted_group_params(params)
7
+ group_params = params[:spree_cm_commissioner_pricing_rule_group] || params
8
+
9
+ {
10
+ name: group_params[:name],
11
+ status: group_params[:status],
12
+ template_key: group_params[:template_key],
13
+ match_type: group_params[:match_type],
14
+ pricing_rules_attributes: build_rules_attributes(params[:pricing_rules]),
15
+ pricing_action_attributes: build_action_attributes(params[:pricing_action])
16
+ }
17
+ end
18
+
19
+ def build_rules_attributes(rules_array)
20
+ return [] unless rules_array
21
+
22
+ rules_array.map do |r|
23
+ {
24
+ id: r[:id],
25
+ type: r[:type],
26
+ private_metadata: r[:private_metadata],
27
+ _destroy: r[:_destroy]
28
+ }
29
+ end
30
+ end
31
+
32
+ def build_action_attributes(action_data)
33
+ return nil unless action_data&.dig(:calculator)
34
+
35
+ calc_data = action_data[:calculator]
36
+ calculator = calc_data[:type].safe_constantize&.new
37
+ set_preferences(calculator, calc_data[:preferences]) if calculator
38
+
39
+ { id: action_data[:id], calculator: calculator }
40
+ end
41
+
42
+ def set_preferences(calculator, preferences)
43
+ return unless preferences && calculator
44
+
45
+ prefs = preferences.respond_to?(:to_unsafe_h) ? preferences.to_unsafe_h : preferences
46
+ prefs.each do |key, value|
47
+ setter = "preferred_#{key}="
48
+ calculator.public_send(setter, value) if calculator.respond_to?(setter)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end