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
@@ -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,10 @@
1
+ module SpreeCmCommissioner
2
+ module PricingRules
3
+ class Create
4
+ def self.call(pricing_model:, params:)
5
+ attrs = BuildParams.permitted_group_params(params)
6
+ pricing_model.pricing_rule_groups.create(attrs)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeCmCommissioner
2
+ module PricingRules
3
+ class Update
4
+ def self.call(pricing_rule_group:, params:)
5
+ attrs = BuildParams.permitted_group_params(params)
6
+ pricing_rule_group.update(attrs)
7
+ pricing_rule_group
8
+ end
9
+ end
10
+ end
11
+ 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
@@ -3,6 +3,8 @@
3
3
  <%# :asset %>
4
4
  <%# :remove_url, optional %>
5
5
  <%# :classes, optional %>
6
+ <%# :aspect_ratio, optional %>
7
+ <%# :size_info, optional %>
6
8
  <%# :form %>
7
9
  <%# :required, optional, default: false %>
8
10
 
@@ -16,6 +18,17 @@
16
18
  class: 'rounded border mb-4 mw-100',
17
19
  style: 'max-height: 100px') if asset.present? && asset.attachment.present? %>
18
20
 
21
+ <% if defined?(aspect_ratio) || defined?(size_info) %>
22
+ <small class="mb-2 form-text text-muted d-block">
23
+ <% if defined?(aspect_ratio) && aspect_ratio.present? %>
24
+ <strong>Aspect Ratio:</strong> <%= aspect_ratio %><br>
25
+ <% end %>
26
+ <% if defined?(size_info) && size_info.present? %>
27
+ <strong>Recommended Size:</strong> <%= size_info %>
28
+ <% end %>
29
+ </small>
30
+ <% end %>
31
+
19
32
  <div data-hook="file" class="form-group">
20
33
  <%= form.label field, label || Spree.t(field) %>
21
34
  <%= form.file_field field, required: required %>
@@ -1,7 +1,7 @@
1
1
  <div data-hook="admin_product_completion_step_form_fields">
2
2
  <div data-hook="product_completion_step" class="row">
3
3
  <div class="col-12 col-md-6">
4
- <div class="card mb-3">
4
+ <div class="mb-3 card">
5
5
  <div class="card-header">
6
6
  <h5 class="mb-0"><%= Spree.t(:settings) %></h5>
7
7
  </div>
@@ -32,7 +32,7 @@
32
32
  </div>
33
33
 
34
34
  <div class="col-12 col-md-6">
35
- <div class="card mb-3">
35
+ <div class="mb-3 card">
36
36
  <div class="card-header">
37
37
  <h5 class="mb-0"><%= Spree.t(:completion_settings) %></h5>
38
38
  </div>
@@ -49,6 +49,32 @@
49
49
  </div>
50
50
  </div>
51
51
  </div>
52
+
53
+ <div class="mb-3 card">
54
+ <div class="card-header">
55
+ <h5 class="mb-0"><%= Spree.t(:banner) %></h5>
56
+ </div>
57
+ <div class="card-body">
58
+ <%= render 'shared/asset_field',
59
+ field: :banner,
60
+ label: Spree.t(:banner),
61
+ asset: @object.banner,
62
+ remove_url: (@object.banner.present? ? remove_banner_admin_product_product_completion_step_url(@object.product, @object) : nil),
63
+ form: f,
64
+ size_info: 'Min: 480x270, Max: 960x540',
65
+ aspect_ratio: '16x9',
66
+ classes: ['col-md-12']
67
+ %>
68
+ </div>
69
+ </div>
52
70
  </div>
53
71
  </div>
72
+
73
+ <% if @object.is_a?(SpreeCmCommissioner::ProductCompletionSteps::SocialEntryUrl) %>
74
+ <div class="row mt-3">
75
+ <div class="col-12">
76
+ <%= render 'supported_fields' %>
77
+ </div>
78
+ </div>
79
+ <% end %>
54
80
  </div>
@@ -0,0 +1,33 @@
1
+ <div class="mb-3 card">
2
+ <div class="card-header">
3
+ <h5 class="mb-0">Supported Placeholder Fields</h5>
4
+ </div>
5
+ <div class="card-body">
6
+ <p class="text-muted mb-3">Use these placeholders in your entry point link template:</p>
7
+
8
+ <% if @object.is_a?(SpreeCmCommissioner::ProductCompletionSteps::SocialEntryUrl) && @object.supported_fields.present? %>
9
+ <% @object.supported_fields.each do |category, fields| %>
10
+ <div class="mb-3">
11
+ <h6 class="fw-bold text-capitalize">
12
+ <%= category.to_s.humanize %>
13
+ <span class="badge bg-secondary"><%= fields.count %></span>
14
+ </h6>
15
+ <div class="field-list">
16
+ <% fields.each do |field| %>
17
+ <div class="field-item d-inline-block me-2 mb-2">
18
+ <code class="bg-light p-2 rounded">
19
+ {<%= category %><%= category == :guests ? '[index]' : '' %>.<%=field %>}
20
+ </code>
21
+ </div>
22
+ <% end %>
23
+ </div>
24
+ </div>
25
+ <% end %>
26
+
27
+ <div class="alert alert-info mt-3">
28
+ <strong>Example:</strong><br>
29
+ <code>https://example.com?order={order.number}&name={bill_address.first_name}&guest={guests[0].first_name}</code>
30
+ </div>
31
+ <% end %>
32
+ </div>
33
+ </div>
@@ -36,7 +36,7 @@
36
36
  <div class="col-12">
37
37
  <%= f.field_container :host do %>
38
38
  <%= f.label :host, raw(Spree.t(:host) + required_span_tag) %>
39
- <%= f.text_field :host, required: true, class: 'form-control', placeholder: 'host' %>
39
+ <%= f.text_field :host, required: true, class: 'form-control', placeholder: 'example.com' %>
40
40
  <% if f.object.errors[:host].any? %>
41
41
  <div class="error text-danger"><%= f.object.errors[:host].join(', ') %></div>
42
42
  <% 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
- background: <%= @brand_color %>;
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: 6.25rem;
97
- height: 6.25rem;
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: 100%;
108
- height: 100%;
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><%=@order.tenant.name %></h1>
5
- <% if @vendor_logo_url.present? %>
6
- <img src="<%= @vendor_logo_url %>" alt="Vendor Logo" class="icon-hang-meas">
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: @order.number || 'NA') %>
18
+ <%= I18n.t('mail.order_mailer.booking_event', order_number: order.number || 'NA') %>
17
19
  </div>
18
20
  </div>
19
21
  </div>
@@ -48,6 +48,7 @@ module Spree
48
48
  :preferred_sms_sender_id,
49
49
  :preferred_telegram_order_alert_chat_id,
50
50
  :preferred_telegram_order_request_alert_chat_id,
51
+ :preferred_telegram_new_vendor_alert_chat_id,
51
52
  :preferred_assetlinks,
52
53
  :preferred_apple_app_site_association,
53
54
  { default_notification_image_attributes: {} },
@@ -509,6 +509,10 @@ en:
509
509
  attributes:
510
510
  place_id:
511
511
  taken: "has already existed with this place type"
512
+ spree_cm_commissioner/tenant:
513
+ attributes:
514
+ host:
515
+ format: "must not include protocol (http:// or https://)"
512
516
 
513
517
  mail:
514
518
  order_mailer:
@@ -370,6 +370,10 @@ km:
370
370
  attributes:
371
371
  exception_rules:
372
372
  invalid_json: "Format មិនត្រឹមត្រូវ"
373
+ spree_cm_commissioner/tenant:
374
+ attributes:
375
+ host:
376
+ format: "មិនអនុញ្ញាតឱ្យបញ្ចូលឈ្មោះដែលភ្ជាប់ជាមួយ (http:// ឬ https://)"
373
377
 
374
378
  mail:
375
379
  order_mailer:
@@ -469,64 +473,64 @@ km:
469
473
 
470
474
  blazer:
471
475
  columns:
472
- 'No.': "លេខរៀង"
473
- 'Reservation No.': "លេខកក់"
474
- 'Direction': "ទិសដៅ"
475
- 'Vehicle type': "ប្រភេទយានយន្ត"
476
- 'Seller': "អ្នកលក់"
477
- 'Paid to': "បង់ទៅ"
478
- 'Branch': "សាខា"
479
- 'Gateway': "ច្រកទ្វារ"
480
- 'Departure': "ចេញដំណើរ"
481
- 'Issued': "ចេញឲ្យ"
482
- 'Paid': "បានបង់"
483
- '# of seats': "ចំនួនកៅអី"
484
- 'Source': "ប្រភព"
485
- 'Status': "ស្ថានភាព"
486
- 'Fare': "តម្លៃឈ្នួល"
487
- 'Discount': "ការបញ្ចុះតម្លៃ"
488
- 'Commission': "កម្រៃជើងសារ"
489
- 'Amount': "ចំនួនទឹកប្រាក់"
490
- 'Metric': "រង្វាស់"
491
- 'Value': "តម្លៃ"
492
- 'Group': "ក្រុម"
493
- 'Orders': "ការបញ្ជាទិញ"
494
- 'Passengers': "អ្នកដំណើរ"
495
- 'Total fare': "តម្លៃឈ្នួលសរុប"
496
- 'Total discount': "ការបញ្ចុះតម្លៃសរុប"
497
- 'Total commission': "កម្រៃជើងសារសរុប"
498
- 'Total amount': "ចំនួនទឹកប្រាក់សរុប"
499
- 'Trip ID': "លេខសម្គាល់ជើងដំណើរ"
500
- 'Route': "ផ្លូវ"
501
- 'Origin': "ទីតាំងដើម"
502
- 'Destination': "ទីតាំងគោលដៅ"
503
- 'Departure Time': "ម៉ោងចេញដំណើរ"
504
- 'Vehicle': "យានយន្ត"
505
- 'Total Seats': "ចំនួនកៅអីសរុប"
506
- 'Bookings': "ការកក់"
507
- 'Seats Sold': "កៅអីលក់បាន"
508
- 'Occupancy %': "ភាគរយនៃការកាន់កាប់"
509
- 'Total Revenue': "ចំណូលសរុប"
510
- 'Avg Ticket Price': "តម្លៃសំបុត្រជាមធ្យម"
511
- 'Date': "កាលបរិច្ឆេទ"
512
- 'Time': "ម៉ោង"
513
- 'From': "ពី"
514
- 'To': "ទៅ"
515
- 'Capacity': "ចំណុះ"
516
- 'Available': "ទំនេរ"
517
- 'Filled %': "ភាគរយនៃការបំពេញ"
518
- 'Vehicle Code': "លេខកូដយានយន្ត"
519
- 'Plate': "ស្លាកលេខ"
520
- 'Type': "ប្រភេទ"
521
- 'Total Trips': "ចំនួនជើងដំណើរ​សរុប"
522
- 'Trips with Bookings': "ជើងដំណើរ​មានការកក់"
523
- 'Total Bookings': "ចំនួនការកក់​សរុប"
524
- 'Total Passengers': "ចំនួនអ្នកដំណើរ​សរុប"
525
- 'Avg Occupancy %': "ភាគរយនៃការកាន់កាប់​ជាមធ្យម"
526
- 'Lead Time': "រយៈពេលនៃការរង់ចាំ"
527
- 'Revenue': "ចំណូល"
528
- 'Avg Days in Advance': "ចំនួនថ្ងៃជាមធ្យមមុន"
529
- 'Current Period': "រយៈពេលបច្ចុប្បន្ន"
530
- 'Previous Period': "រយៈពេលមុន"
531
- 'Change': "បំលាស់ប្តូរ"
532
- 'Change %': "ភាគរយនៃបំលាស់ប្តូរ"
476
+ "No.": "លេខរៀង"
477
+ "Reservation No.": "លេខកក់"
478
+ "Direction": "ទិសដៅ"
479
+ "Vehicle type": "ប្រភេទយានយន្ត"
480
+ "Seller": "អ្នកលក់"
481
+ "Paid to": "បង់ទៅ"
482
+ "Branch": "សាខា"
483
+ "Gateway": "ច្រកទ្វារ"
484
+ "Departure": "ចេញដំណើរ"
485
+ "Issued": "ចេញឲ្យ"
486
+ "Paid": "បានបង់"
487
+ "# of seats": "ចំនួនកៅអី"
488
+ "Source": "ប្រភព"
489
+ "Status": "ស្ថានភាព"
490
+ "Fare": "តម្លៃឈ្នួល"
491
+ "Discount": "ការបញ្ចុះតម្លៃ"
492
+ "Commission": "កម្រៃជើងសារ"
493
+ "Amount": "ចំនួនទឹកប្រាក់"
494
+ "Metric": "រង្វាស់"
495
+ "Value": "តម្លៃ"
496
+ "Group": "ក្រុម"
497
+ "Orders": "ការបញ្ជាទិញ"
498
+ "Passengers": "អ្នកដំណើរ"
499
+ "Total fare": "តម្លៃឈ្នួលសរុប"
500
+ "Total discount": "ការបញ្ចុះតម្លៃសរុប"
501
+ "Total commission": "កម្រៃជើងសារសរុប"
502
+ "Total amount": "ចំនួនទឹកប្រាក់សរុប"
503
+ "Trip ID": "លេខសម្គាល់ជើងដំណើរ"
504
+ "Route": "ផ្លូវ"
505
+ "Origin": "ទីតាំងដើម"
506
+ "Destination": "ទីតាំងគោលដៅ"
507
+ "Departure Time": "ម៉ោងចេញដំណើរ"
508
+ "Vehicle": "យានយន្ត"
509
+ "Total Seats": "ចំនួនកៅអីសរុប"
510
+ "Bookings": "ការកក់"
511
+ "Seats Sold": "កៅអីលក់បាន"
512
+ "Occupancy %": "ភាគរយនៃការកាន់កាប់"
513
+ "Total Revenue": "ចំណូលសរុប"
514
+ "Avg Ticket Price": "តម្លៃសំបុត្រជាមធ្យម"
515
+ "Date": "កាលបរិច្ឆេទ"
516
+ "Time": "ម៉ោង"
517
+ "From": "ពី"
518
+ "To": "ទៅ"
519
+ "Capacity": "ចំណុះ"
520
+ "Available": "ទំនេរ"
521
+ "Filled %": "ភាគរយនៃការបំពេញ"
522
+ "Vehicle Code": "លេខកូដយានយន្ត"
523
+ "Plate": "ស្លាកលេខ"
524
+ "Type": "ប្រភេទ"
525
+ "Total Trips": "ចំនួនជើងដំណើរ​សរុប"
526
+ "Trips with Bookings": "ជើងដំណើរ​មានការកក់"
527
+ "Total Bookings": "ចំនួនការកក់​សរុប"
528
+ "Total Passengers": "ចំនួនអ្នកដំណើរ​សរុប"
529
+ "Avg Occupancy %": "ភាគរយនៃការកាន់កាប់​ជាមធ្យម"
530
+ "Lead Time": "រយៈពេលនៃការរង់ចាំ"
531
+ "Revenue": "ចំណូល"
532
+ "Avg Days in Advance": "ចំនួនថ្ងៃជាមធ្យមមុន"
533
+ "Current Period": "រយៈពេលបច្ចុប្បន្ន"
534
+ "Previous Period": "រយៈពេលមុន"
535
+ "Change": "បំលាស់ប្តូរ"
536
+ "Change %": "ភាគរយនៃបំលាស់ប្តូរ"