spree_cm_commissioner 2.3.2.pre.pre2 → 2.3.2.pre.pre5
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/controllers/spree/api/v2/storefront/intercity_taxi/draft_orders_controller.rb +36 -36
- data/app/controllers/spree/api/v2/storefront/popular_route_places_controller.rb +63 -0
- data/app/controllers/spree/api/v2/storefront/route_places_controller.rb +68 -0
- data/app/controllers/spree/api/v2/tenant/intercity_taxi/draft_orders_controller.rb +37 -37
- data/app/controllers/spree/api/v2/tenant/trip_places_controller.rb +5 -11
- data/app/controllers/spree/api/v2/tenant/trip_search_controller.rb +1 -1
- data/app/controllers/spree/api/v2/tenant/trips_controller.rb +8 -8
- data/app/factory/spree_cm_commissioner/order_telegram_message_factory.rb +12 -0
- data/app/finders/spree_cm_commissioner/places/find_with_route.rb +43 -0
- data/app/finders/spree_cm_commissioner/routes/find_popular.rb +25 -0
- data/app/mailers/spree/order_mailer_decorator.rb +8 -6
- data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +34 -89
- data/app/models/concerns/spree_cm_commissioner/service_recommendations.rb +2 -2
- data/app/models/spree_cm_commissioner/adjustment_decorator.rb +1 -1
- data/app/models/spree_cm_commissioner/calculators/extra_drop_off_distance.rb +15 -0
- data/app/models/spree_cm_commissioner/calculators/extra_pick_up_distance.rb +15 -0
- data/app/models/spree_cm_commissioner/order_decorator.rb +1 -1
- data/app/models/spree_cm_commissioner/place.rb +7 -0
- data/app/models/spree_cm_commissioner/pricing_action.rb +27 -0
- data/app/models/spree_cm_commissioner/pricing_model.rb +18 -0
- data/app/models/spree_cm_commissioner/pricing_model_variant.rb +6 -0
- data/app/models/spree_cm_commissioner/pricing_rule.rb +15 -0
- data/app/models/spree_cm_commissioner/pricing_rule_group.rb +20 -0
- data/app/models/spree_cm_commissioner/pricing_rules/extra_drop_off_distance.rb +10 -0
- data/app/models/spree_cm_commissioner/pricing_rules/extra_pick_up_distance.rb +12 -0
- data/app/models/spree_cm_commissioner/pricing_rules/nationality.rb +35 -0
- data/app/models/spree_cm_commissioner/tenant.rb +4 -0
- data/app/models/spree_cm_commissioner/variant_decorator.rb +3 -0
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +1 -0
- data/app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_update_schema.rb +22 -3
- data/app/request_schemas/spree_cm_commissioner/route_places_request_schema.rb +12 -0
- data/app/serializers/spree/v2/storefront/place_serializer.rb +3 -2
- data/app/serializers/spree/v2/tenant/cart_serializer.rb +1 -0
- data/app/serializers/spree/v2/tenant/intercity_taxi_cart_serializer.rb +12 -0
- data/app/serializers/spree/v2/tenant/line_item_serializer.rb +1 -0
- data/app/serializers/spree/v2/tenant/trip_place_serializer.rb +8 -0
- data/app/serializers/spree/v2/tenant/trip_query_result_serializer.rb +8 -0
- data/app/serializers/spree/v2/tenant/trip_serializer.rb +8 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/intercity_taxi_line_item_serializer.rb +17 -18
- data/app/serializers/spree_cm_commissioner/v2/storefront/route_serializer.rb +12 -0
- data/app/services/spree_cm_commissioner/intercity_taxi_order/create.rb +11 -22
- data/app/services/spree_cm_commissioner/intercity_taxi_order/update.rb +32 -11
- data/app/services/spree_cm_commissioner/pricing_models/apply.rb +51 -0
- data/app/services/spree_cm_commissioner/pricing_rules/build_params.rb +53 -0
- data/app/services/spree_cm_commissioner/pricing_rules/build_template.rb +27 -0
- data/app/services/spree_cm_commissioner/pricing_rules/create.rb +10 -0
- data/app/services/spree_cm_commissioner/pricing_rules/update.rb +11 -0
- data/app/services/spree_cm_commissioner/vendor_places/base.rb +24 -0
- data/app/services/spree_cm_commissioner/vendor_places/bulk_create.rb +70 -0
- data/app/services/spree_cm_commissioner/vendor_places/create_with_google_map_data.rb +85 -0
- data/app/services/spree_cm_commissioner/vendor_places/update.rb +56 -0
- data/app/views/spree/order_mailer/confirm_email.html.erb +1 -1
- data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +14 -13
- data/app/views/spree_cm_commissioner/order_mailer/tenant/_greeting.html.erb +6 -4
- data/config/routes.rb +4 -10
- data/db/migrate/20250915075830_create_spree_cm_commissioner_pricing_models.rb +17 -0
- data/db/migrate/20250915080733_create_spree_cm_commissioner_pricing_model_variants.rb +14 -0
- data/db/migrate/20251003082144_create_spree_cm_commissioner_pricing_rule_groups.rb +16 -0
- data/db/migrate/20251003093408_create_spree_cm_commissioner_pricing_rule.rb +19 -0
- data/db/migrate/20251003093643_create_spree_cm_commissioner_pricing_action.rb +14 -0
- data/db/migrate/20251119093000_add_tenant_id_to_cm_vendor_places.rb +2 -1
- data/lib/spree_cm_commissioner/intercity_taxi/distance.rb +38 -0
- data/lib/spree_cm_commissioner/intercity_taxi/map_place.rb +31 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb +5 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_model_factory.rb +8 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_rule_factory.rb +17 -0
- data/lib/spree_cm_commissioner/test_helper/factories/pricing_rule_group_factory.rb +8 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +2 -0
- metadata +42 -2
|
@@ -1,30 +1,14 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
module IntercityTaxiOrder
|
|
3
3
|
class Create
|
|
4
|
-
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
|
-
def
|
|
7
|
-
|
|
8
|
-
trip_id: trip_id,
|
|
9
|
-
from_date: from_date,
|
|
10
|
-
to_date: to_date,
|
|
11
|
-
user: user,
|
|
12
|
-
quantity: quantity
|
|
13
|
-
).call
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def initialize(trip_id:, from_date:, to_date:, user:, quantity:)
|
|
17
|
-
@trip_id = trip_id
|
|
18
|
-
@from_date = from_date
|
|
19
|
-
@to_date = to_date
|
|
20
|
-
@user = user
|
|
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
|
-
|
|
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?
|
|
@@ -49,15 +33,20 @@ module SpreeCmCommissioner
|
|
|
49
33
|
|
|
50
34
|
order
|
|
51
35
|
end
|
|
36
|
+
|
|
37
|
+
success(order)
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
failure(nil, e.message)
|
|
52
40
|
end
|
|
53
41
|
|
|
54
42
|
private
|
|
55
43
|
|
|
56
|
-
def validate!
|
|
44
|
+
def validate!(trip_id:, from_date:, to_date:, quantity:)
|
|
57
45
|
raise ArgumentError, 'trip_id is required' if trip_id.blank?
|
|
58
46
|
raise ArgumentError, 'from_date is required' if from_date.blank?
|
|
59
47
|
raise ArgumentError, 'to_date is required' if to_date.blank?
|
|
60
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
|
|
61
50
|
end
|
|
62
51
|
|
|
63
52
|
def build_guests_for!(line_item, qty)
|
|
@@ -1,21 +1,42 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
module IntercityTaxiOrder
|
|
3
3
|
class Update
|
|
4
|
-
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
5
|
|
|
6
|
-
def
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
14
34
|
|
|
15
|
-
|
|
16
|
-
order.update!(order_params)
|
|
35
|
+
line_item.update!(remark: remark)
|
|
17
36
|
|
|
18
|
-
order
|
|
37
|
+
success(order.reload)
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
failure(nil, e.message)
|
|
19
40
|
end
|
|
20
41
|
end
|
|
21
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
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module PricingRules
|
|
3
|
+
class BuildTemplate
|
|
4
|
+
def self.call(pricing_model:, template_key:)
|
|
5
|
+
template = PRICING_RULE_GROUP_TEMPLATES[template_key.to_sym]
|
|
6
|
+
return unless template
|
|
7
|
+
|
|
8
|
+
group = pricing_model.pricing_rule_groups.build
|
|
9
|
+
|
|
10
|
+
template[:rules]&.each do |rule_data|
|
|
11
|
+
group.pricing_rules.where(type: rule_data[:type]).build(
|
|
12
|
+
type: rule_data[:type],
|
|
13
|
+
private_metadata: rule_data[:private_metadata] || {}
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
if template[:action]
|
|
18
|
+
calculator = template[:action][:calculator_type].constantize.new
|
|
19
|
+
BuildParams.set_preferences(calculator, template[:action][:preferences])
|
|
20
|
+
group.build_pricing_action(calculator: calculator)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
group
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module VendorPlaces
|
|
3
|
+
class Base
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
ALLOWED_PLACE_TYPES = %w[venue stop branch location].freeze
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def validate_place_type!(place_type)
|
|
11
|
+
return I18n.t('controller.vendor_places.place_type_required', default: 'Place type is required') if place_type.nil?
|
|
12
|
+
|
|
13
|
+
unless ALLOWED_PLACE_TYPES.include?(place_type.to_s)
|
|
14
|
+
return I18n.t(
|
|
15
|
+
'controller.vendor_places.invalid_place_type',
|
|
16
|
+
default: "Place type must be one of: #{ALLOWED_PLACE_TYPES.join(', ')}"
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Bulk creates vendor places of any valid type (e.g., :stop, :branch, :location) with validation and transaction support.
|
|
2
|
+
#
|
|
3
|
+
# Validates place_ids count and creates vendor places atomically.
|
|
4
|
+
# Rolls back all changes if any creation fails.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# result = SpreeCmCommissioner::VendorPlaces::BulkCreate.call(
|
|
8
|
+
# vendor: current_vendor,
|
|
9
|
+
# place_ids: [1, 2, 3],
|
|
10
|
+
# place_type: :location, # or :stop, :branch, etc.
|
|
11
|
+
# description: "Sample description",
|
|
12
|
+
# max_count: 10,
|
|
13
|
+
# location: parent_location # required for :stop and :branch
|
|
14
|
+
# )
|
|
15
|
+
#
|
|
16
|
+
# if result.success?
|
|
17
|
+
# created_vendor_places = result.value
|
|
18
|
+
# else
|
|
19
|
+
# error_message = result.error
|
|
20
|
+
|
|
21
|
+
module SpreeCmCommissioner
|
|
22
|
+
module VendorPlaces
|
|
23
|
+
class BulkCreate < Base
|
|
24
|
+
def call(vendor:, place_ids:, place_type:, description: nil, max_count: 10, location: nil) # rubocop:disable Metrics/ParameterLists
|
|
25
|
+
error_message = validate_inputs!(place_ids: place_ids, place_type: place_type, max_count: max_count, location: location)
|
|
26
|
+
return failure(nil, error_message) if error_message
|
|
27
|
+
|
|
28
|
+
created_vendor_places = []
|
|
29
|
+
|
|
30
|
+
ActiveRecord::Base.transaction do
|
|
31
|
+
place_ids.each do |place_id|
|
|
32
|
+
vendor_place = build_vendor_place(
|
|
33
|
+
vendor: vendor,
|
|
34
|
+
place_id: place_id,
|
|
35
|
+
place_type: place_type,
|
|
36
|
+
description: description,
|
|
37
|
+
location: location
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
vendor_place.save!
|
|
41
|
+
created_vendor_places << vendor_place
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
success(created_vendor_places)
|
|
46
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
47
|
+
failure(nil, e.record.errors.full_messages.to_sentence)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def validate_inputs!(place_ids:, place_type:, max_count:, location: nil)
|
|
53
|
+
validate_place_type!(place_type) ||
|
|
54
|
+
(place_ids.blank? && I18n.t('controller.vendor_places.place_ids_blank')) ||
|
|
55
|
+
(place_ids.size > max_count && I18n.t('controller.vendor_places.selection_limit', count: max_count)) ||
|
|
56
|
+
(requires_location?(place_type: place_type) && location.blank? && I18n.t('controller.vendor_places.location_required'))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def build_vendor_place(vendor:, place_id:, place_type:, description:, location: nil)
|
|
60
|
+
attrs = { vendor_id: vendor.id, place_type: place_type.to_sym, place_id: place_id, description: description }
|
|
61
|
+
attrs[:location_id] = location&.id if requires_location?(place_type: place_type)
|
|
62
|
+
SpreeCmCommissioner::VendorPlace.new(attrs)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def requires_location?(place_type:)
|
|
66
|
+
%i[stop branch].include?(place_type.to_sym)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Creates a vendor place from Google Map base64-encoded place data.
|
|
2
|
+
# Processes place data and creates both Place and VendorPlace records atomically.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# result = SpreeCmCommissioner::VendorPlaces::CreateWithGoogleMapData.call(
|
|
6
|
+
# vendor: current_vendor,
|
|
7
|
+
# place_type: 'stop',
|
|
8
|
+
# google_place_base_64_content: google_place_base_64_content,
|
|
9
|
+
# description: 'Main Warehouse',
|
|
10
|
+
# location: parent_vendor_location
|
|
11
|
+
# )
|
|
12
|
+
#
|
|
13
|
+
# if result.success?
|
|
14
|
+
# vendor_place = result.value
|
|
15
|
+
# else
|
|
16
|
+
# error_message = result.error
|
|
17
|
+
# end
|
|
18
|
+
|
|
19
|
+
module SpreeCmCommissioner
|
|
20
|
+
module VendorPlaces
|
|
21
|
+
class CreateWithGoogleMapData < Base
|
|
22
|
+
def call(vendor:, place_type:, google_place_base_64_content:, description: nil, location: nil)
|
|
23
|
+
error_message = validate_place_type!(place_type)
|
|
24
|
+
return failure(nil, error_message) if error_message.present?
|
|
25
|
+
|
|
26
|
+
# Only require location for stop and branch types
|
|
27
|
+
return failure(nil, I18n.t('controller.vendor_places.location_required')) if %w[stop branch].include?(place_type) && location.nil?
|
|
28
|
+
|
|
29
|
+
place = process_place(google_place_base_64_content: google_place_base_64_content)
|
|
30
|
+
return failure(nil, place) unless place.is_a?(SpreeCmCommissioner::Place)
|
|
31
|
+
|
|
32
|
+
vendor_place = create_vendor_place(vendor: vendor, place: place, place_type: place_type, description: description, location: location)
|
|
33
|
+
return failure(nil, vendor_place) if vendor_place.nil? || vendor_place.is_a?(String)
|
|
34
|
+
|
|
35
|
+
success(vendor_place)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def process_place(google_place_base_64_content:)
|
|
41
|
+
place = SpreeCmCommissioner::PlaceDecoder.process_place(google_place_base_64_content)
|
|
42
|
+
return I18n.t('controller.vendor_places.process_place_failed', default: 'Failed to process place') if place.nil? || !place.save
|
|
43
|
+
|
|
44
|
+
place
|
|
45
|
+
rescue StandardError => e
|
|
46
|
+
e.message
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def create_vendor_place(vendor:, place:, place_type:, description:, location:)
|
|
50
|
+
error_message = nil
|
|
51
|
+
result = ActiveRecord::Base.transaction do
|
|
52
|
+
vendor_place = build_vendor_place(vendor: vendor, place: place, type: place_type, description: description, location: location)
|
|
53
|
+
unless vendor_place.save
|
|
54
|
+
error_message = vendor_place.errors.full_messages.to_sentence
|
|
55
|
+
raise ActiveRecord::Rollback
|
|
56
|
+
end
|
|
57
|
+
vendor_place
|
|
58
|
+
end
|
|
59
|
+
error_message || result
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def build_vendor_place(vendor:, place:, type:, description: nil, location: nil)
|
|
63
|
+
case type
|
|
64
|
+
when 'stop'
|
|
65
|
+
vendor.stops.new(
|
|
66
|
+
place_id: place.id,
|
|
67
|
+
description: description,
|
|
68
|
+
location_id: location&.id
|
|
69
|
+
)
|
|
70
|
+
when 'branch'
|
|
71
|
+
vendor.branches.new(
|
|
72
|
+
place_id: place.id,
|
|
73
|
+
description: description,
|
|
74
|
+
location_id: location&.id
|
|
75
|
+
)
|
|
76
|
+
when 'location'
|
|
77
|
+
vendor.locations.new(
|
|
78
|
+
place_id: place.id,
|
|
79
|
+
description: description
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Updates all vendor places matching the same vendor, place_id, and location_id.
|
|
2
|
+
# Only updates description and location_id. Rolls back if any update fails.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# result = SpreeCmCommissioner::VendorPlaces::Update.call(
|
|
6
|
+
# vendor: current_vendor,
|
|
7
|
+
# vendor_place: existing_vendor_place,
|
|
8
|
+
# location_id: new_location_id,
|
|
9
|
+
# description: 'Updated description'
|
|
10
|
+
# )
|
|
11
|
+
#
|
|
12
|
+
# if result.success?
|
|
13
|
+
# updated_place = result.value
|
|
14
|
+
# else
|
|
15
|
+
# error_message = result.error
|
|
16
|
+
# end
|
|
17
|
+
module SpreeCmCommissioner
|
|
18
|
+
module VendorPlaces
|
|
19
|
+
class Update < Base
|
|
20
|
+
def call(vendor:, vendor_place:, description: nil, location_id: nil)
|
|
21
|
+
if vendor_place.blank?
|
|
22
|
+
return failure(
|
|
23
|
+
nil,
|
|
24
|
+
I18n.t('controller.vendor_places.vendor_place_not_found', default: 'Vendor place not found')
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
ActiveRecord::Base.transaction do
|
|
29
|
+
related_places = SpreeCmCommissioner::VendorPlace.where(
|
|
30
|
+
vendor_id: vendor.id,
|
|
31
|
+
place_id: vendor_place.place_id,
|
|
32
|
+
location_id: vendor_place.location_id
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
update_attrs = {}
|
|
36
|
+
update_attrs[:description] = description unless description.nil?
|
|
37
|
+
update_attrs[:location_id] = location_id unless location_id.nil?
|
|
38
|
+
|
|
39
|
+
related_places.each do |vp|
|
|
40
|
+
unless vp.update(update_attrs)
|
|
41
|
+
error_message = vp.errors.full_messages.to_sentence
|
|
42
|
+
raise ActiveRecord::Rollback, error_message
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
vendor_place.reload
|
|
48
|
+
success(vendor_place)
|
|
49
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
50
|
+
failure(nil, e.record.errors.full_messages.to_sentence)
|
|
51
|
+
rescue ActiveRecord::Rollback => e
|
|
52
|
+
failure(nil, e.message)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</div>
|
|
17
17
|
<% else %>
|
|
18
18
|
<div class="f-fallback">
|
|
19
|
-
<%= render 'spree_cm_commissioner/order_mailer/tenant/greeting', order: @order %>
|
|
19
|
+
<%= render 'spree_cm_commissioner/order_mailer/tenant/greeting', order: @order, logo: @logo, name: @name%>
|
|
20
20
|
<div class="content">
|
|
21
21
|
<%= render 'spree_cm_commissioner/order_mailer/order_total', order: @order %>
|
|
22
22
|
<%= render 'spree_cm_commissioner/order_mailer/your_booking', order: @order, show_booking_header: true %>
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
background-position: center;
|
|
75
75
|
background-repeat: no-repeat;
|
|
76
76
|
border-radius: 1.5625rem 1.5625rem 0 0;
|
|
77
|
-
|
|
77
|
+
<% if @brand_color.present? %>
|
|
78
|
+
background: <%= @brand_color %>;
|
|
79
|
+
<% end %>
|
|
78
80
|
}
|
|
79
81
|
#confirm-email #greeting-card-1 p,
|
|
80
82
|
#confirm-email #greeting-card-1 .header,
|
|
@@ -93,21 +95,20 @@
|
|
|
93
95
|
margin-bottom: 0.625rem;
|
|
94
96
|
}
|
|
95
97
|
#confirm-email .icon-hang-meas {
|
|
96
|
-
width:
|
|
97
|
-
|
|
98
|
-
border-radius: 50%;
|
|
99
|
-
background-color: #fff;
|
|
100
|
-
display: flex;
|
|
101
|
-
align-items: center;
|
|
102
|
-
justify-content: center;
|
|
103
|
-
overflow: hidden;
|
|
98
|
+
width: 50%;
|
|
99
|
+
text-align: right;
|
|
104
100
|
}
|
|
105
|
-
|
|
106
101
|
#confirm-email .icon-hang-meas img {
|
|
107
|
-
width:
|
|
108
|
-
height:
|
|
109
|
-
object-fit: cover;
|
|
102
|
+
width: 6.25rem;
|
|
103
|
+
height: 6.25rem;
|
|
110
104
|
border-radius: 50%;
|
|
105
|
+
background-color: #fff;
|
|
106
|
+
display: inline-block;
|
|
107
|
+
}
|
|
108
|
+
#confirm-email .header h1 {
|
|
109
|
+
margin: 0;
|
|
110
|
+
color: #fff;
|
|
111
|
+
width: 50%;
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
#confirm-email .header {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<div id="greeting-card-1">
|
|
2
2
|
<div>
|
|
3
3
|
<div class="header">
|
|
4
|
-
<h1
|
|
5
|
-
<% if
|
|
6
|
-
<
|
|
4
|
+
<h1><%= name %></h1>
|
|
5
|
+
<% if logo.present? %>
|
|
6
|
+
<div class="icon-hang-meas">
|
|
7
|
+
<img src="<%= logo %>" alt="<%= name %> Logo">
|
|
8
|
+
</div>
|
|
7
9
|
<% end %>
|
|
8
10
|
</div>
|
|
9
11
|
<div class="booking-confirm">
|
|
@@ -13,7 +15,7 @@
|
|
|
13
15
|
<%= I18n.t('mail.order_mailer.hello', full_name: user_full_name(order)) %>
|
|
14
16
|
</div>
|
|
15
17
|
<div class="description">
|
|
16
|
-
<%= I18n.t('mail.order_mailer.booking_event', order_number:
|
|
18
|
+
<%= I18n.t('mail.order_mailer.booking_event', order_number: order.number || 'NA') %>
|
|
17
19
|
</div>
|
|
18
20
|
</div>
|
|
19
21
|
</div>
|
data/config/routes.rb
CHANGED
|
@@ -555,11 +555,7 @@ Spree::Core::Engine.add_routes do
|
|
|
555
555
|
resources :trips, only: %i[show]
|
|
556
556
|
|
|
557
557
|
namespace :intercity_taxi do
|
|
558
|
-
|
|
559
|
-
collection do
|
|
560
|
-
patch :update
|
|
561
|
-
end
|
|
562
|
-
end
|
|
558
|
+
resource :draft_orders, only: %i[create update]
|
|
563
559
|
end
|
|
564
560
|
|
|
565
561
|
resource :reset_passwords, only: [:update]
|
|
@@ -587,6 +583,8 @@ Spree::Core::Engine.add_routes do
|
|
|
587
583
|
resources :trip_places
|
|
588
584
|
resources :trip_search, only: [:index]
|
|
589
585
|
resources :trips, only: %i[show]
|
|
586
|
+
resources :route_places, only: [:index]
|
|
587
|
+
resources :popular_route_places, only: [:index]
|
|
590
588
|
|
|
591
589
|
namespace :queue_cart do
|
|
592
590
|
resources :line_items, only: [:create]
|
|
@@ -701,11 +699,7 @@ Spree::Core::Engine.add_routes do
|
|
|
701
699
|
resources :draft_orders, only: %i[create]
|
|
702
700
|
end
|
|
703
701
|
namespace :intercity_taxi do
|
|
704
|
-
|
|
705
|
-
collection do
|
|
706
|
-
patch :update
|
|
707
|
-
end
|
|
708
|
-
end
|
|
702
|
+
resource :draft_orders, only: %i[create update]
|
|
709
703
|
end
|
|
710
704
|
end
|
|
711
705
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class CreateSpreeCmCommissionerPricingModels < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :cm_pricing_models, if_not_exists: true do |t|
|
|
4
|
+
t.string :name, null: false
|
|
5
|
+
t.text :description
|
|
6
|
+
t.integer :status, default: 0, null: false
|
|
7
|
+
t.integer :position, null: false, default: 0
|
|
8
|
+
|
|
9
|
+
t.references :vendor, null: false, foreign_key: { to_table: :spree_vendors }
|
|
10
|
+
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :cm_pricing_models, :position unless index_exists?(:cm_pricing_models, :position)
|
|
15
|
+
add_index :cm_pricing_models, :vendor_id unless index_exists?(:cm_pricing_models, :vendor_id)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateSpreeCmCommissionerPricingModelVariants < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :cm_pricing_model_variants, if_not_exists: true do |t|
|
|
4
|
+
t.references :pricing_model, null: false, foreign_key: { to_table: :cm_pricing_models }
|
|
5
|
+
t.references :variant, null: false, foreign_key: { to_table: :spree_variants }
|
|
6
|
+
t.references :product, null: true, foreign_key: { to_table: :spree_products }
|
|
7
|
+
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :cm_pricing_model_variants, [:pricing_model_id, :variant_id], name: 'idx_pm_variants_on_model_variant'
|
|
12
|
+
add_index :cm_pricing_model_variants, [:pricing_model_id, :product_id], name: 'idx_pm_variants_on_model_product'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CreateSpreeCmCommissionerPricingRuleGroups < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :cm_pricing_rule_groups, if_not_exists: true do |t|
|
|
4
|
+
t.references :pricing_model, null: false, foreign_key: { to_table: :cm_pricing_models }
|
|
5
|
+
t.string :name
|
|
6
|
+
t.integer :position, default: 0
|
|
7
|
+
t.integer :status, default: 0, null: false
|
|
8
|
+
t.jsonb :public_metadata
|
|
9
|
+
t.jsonb :private_metadata
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
add_index :cm_pricing_rule_groups, :pricing_model_id, name: 'idx_rule_groups_on_model'
|
|
14
|
+
add_index :cm_pricing_rule_groups, [:pricing_model_id, :position], name: 'idx_rule_groups_on_model_position'
|
|
15
|
+
end
|
|
16
|
+
end
|