spree_cm_commissioner 2.3.1 → 2.3.2.pre.pre2

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 (39) 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 +44 -3
  6. data/app/controllers/spree/api/v2/tenant/intercity_taxi/draft_orders_controller.rb +81 -0
  7. data/app/controllers/spree/api/v2/tenant/trip_places_controller.rb +48 -0
  8. data/app/controllers/spree/api/v2/tenant/trip_search_controller.rb +103 -0
  9. data/app/controllers/spree/api/v2/tenant/trips_controller.rb +32 -0
  10. data/app/interactors/spree_cm_commissioner/create_ticket.rb +2 -0
  11. data/app/interactors/spree_cm_commissioner/host_matcher.rb +1 -1
  12. data/app/interactors/spree_cm_commissioner/vendor_creation_telegram_alert_sender.rb +1 -1
  13. data/app/mailers/spree/order_mailer_decorator.rb +8 -9
  14. data/app/models/concerns/spree_cm_commissioner/service_recommendations.rb +2 -2
  15. data/app/models/concerns/spree_cm_commissioner/store_preference.rb +1 -0
  16. data/app/models/spree_cm_commissioner/product_completion_step.rb +4 -1
  17. data/app/models/spree_cm_commissioner/product_completion_step_banner.rb +12 -0
  18. data/app/models/spree_cm_commissioner/product_completion_steps/social_entry_url.rb +86 -19
  19. data/app/models/spree_cm_commissioner/tenant.rb +10 -1
  20. data/app/models/spree_cm_commissioner/vendor_place.rb +10 -1
  21. data/app/overrides/spree/admin/stores/_form/store_preferences.html.erb.deface +9 -0
  22. data/app/queries/spree_cm_commissioner/trip_query.rb +23 -17
  23. data/app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_schema.rb +10 -0
  24. data/app/request_schemas/spree_cm_commissioner/intercity_taxi_draft_order_update_schema.rb +10 -0
  25. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_vehicle_serializer.rb +1 -1
  26. data/app/services/spree_cm_commissioner/intercity_taxi_order/create.rb +14 -6
  27. data/app/services/spree_cm_commissioner/intercity_taxi_order/update.rb +6 -63
  28. data/app/views/shared/_asset_field.html.erb +13 -0
  29. data/app/views/spree/admin/product_completion_steps/_form.html.erb +28 -2
  30. data/app/views/spree/admin/product_completion_steps/_supported_fields.html.erb +33 -0
  31. data/app/views/spree/admin/tenants/_form.html.erb +1 -1
  32. data/config/initializers/spree_permitted_attributes.rb +1 -0
  33. data/config/locales/en.yml +4 -0
  34. data/config/locales/km.yml +65 -61
  35. data/config/routes.rb +21 -1
  36. data/db/migrate/20251119093000_add_tenant_id_to_cm_vendor_places.rb +7 -0
  37. data/lib/spree_cm_commissioner/test_helper/factories/product_completion_step_banner_factory.rb +7 -0
  38. data/lib/spree_cm_commissioner/version.rb +1 -1
  39. metadata +14 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87608fab14f473c498987cb8ecf0793926b031a1368d9a1d03f05fc3bf03e819
4
- data.tar.gz: 9472eaf172e1346757684e9c2b69cec671053927d1a99739f13d0eea1fcb17ce
3
+ metadata.gz: 4090589caa9f83b8b2020e1ed20383647e2671b87692bcecf57f2f455bee7a58
4
+ data.tar.gz: 8cd128d3b2764b6ba6b309c8e0c9b71108b7057ccdd4e03fe92ec4e9d8702d9a
5
5
  SHA512:
6
- metadata.gz: b3da7fbad39575ce43d6b39e088c24ec878095d88a6652e4dd07d87ae0b474403ef368dba1233e0a2d3a2084a03c45d1932c20eee21ee6a65f99e0cb8e4d1e1d
7
- data.tar.gz: 92f4f8a8a446c765568b23b8a1183f7f2f83a499a608a59a34ab315314bf4ea256fbb8264da0da2e80ad0dab527a9fed4c8498a9c77342e186f61386dfad735b
6
+ metadata.gz: 692a3b8079e7f44d84556a826f8519ece6226334b28f78b194829f908f005902a4aaa34f18683aecbb161450197f3c808a82d84545fcc868975306ae45b396a5
7
+ data.tar.gz: e5e0191151979f1476f7ba43fe46ce13dd346c9d44d729d18da9fcff587004c21c7f028bc814356fa2c08a3a32dc867e3bd155ccc0f7659761ab7a9a6201b9b9
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.3.1)
37
+ spree_cm_commissioner (2.3.2.pre.pre2)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -4,6 +4,7 @@ module Spree
4
4
  belongs_to 'spree/product', find_by: :slug
5
5
 
6
6
  before_action :load_step_types, if: :member_action?
7
+ before_action :build_assets, only: %i[create update]
7
8
 
8
9
  def load_step_types
9
10
  @step_types = [
@@ -14,10 +15,13 @@ module Spree
14
15
 
15
16
  # override
16
17
  def permitted_resource_params
18
+ return @permitted_resource_params if defined?(@permitted_resource_params)
19
+
17
20
  key = ActiveModel::Naming.param_key(@object)
18
21
  permit_keys = params.require(key).keys
19
22
 
20
- params.require(key).permit(permit_keys)
23
+ @permitted_resource_params = params.require(key).permit(permit_keys)
24
+ @permitted_resource_params
21
25
  end
22
26
 
23
27
  # @overrided
@@ -54,6 +58,18 @@ module Spree
54
58
  def location_after_save
55
59
  edit_object_url(@object)
56
60
  end
61
+
62
+ def remove_banner
63
+ @object.banner&.destroy
64
+ flash[:success] = Spree.t(:successfully_removed)
65
+ redirect_to edit_object_url(@object)
66
+ end
67
+
68
+ private
69
+
70
+ def build_assets
71
+ @object.build_banner(attachment: permitted_resource_params.delete(:banner)) if permitted_resource_params[:banner].present?
72
+ end
57
73
  end
58
74
  end
59
75
  end
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class TenantsController < Spree::Admin::ResourceController
4
- before_action :load_vector_icons, only: %i[new edit]
4
+ before_action :load_vector_icons, only: %i[new edit create update]
5
5
 
6
6
  # override
7
7
  def collection
@@ -4,12 +4,16 @@ module Spree
4
4
  module Storefront
5
5
  module IntercityTaxi
6
6
  class DraftOrdersController < ::Spree::Api::V2::ResourceController
7
+ include Spree::Api::V2::Storefront::OrderConcern
8
+ include SpreeCmCommissioner::OrderConcern
9
+
10
+ before_action :ensure_order, only: :update
7
11
  def create
8
12
  order = SpreeCmCommissioner::IntercityTaxiOrder::Create.call(
9
13
  trip_id: params[:trip_id],
10
14
  from_date: params[:from_date],
11
15
  to_date: params[:to_date],
12
- user_id: params[:user_id],
16
+ user: spree_current_user,
13
17
  quantity: params[:quantity]
14
18
  )
15
19
 
@@ -20,8 +24,8 @@ module Spree
20
24
 
21
25
  def update
22
26
  order = SpreeCmCommissioner::IntercityTaxiOrder::Update.call(
23
- order_number: params[:id],
24
- params: params
27
+ order: spree_current_order,
28
+ order_params: intercity_taxi_update_order_params
25
29
  )
26
30
 
27
31
  render_serialized_payload { serialize_resource(order) }
@@ -29,6 +33,43 @@ module Spree
29
33
  render_error_payload(e.message)
30
34
  end
31
35
 
36
+ private
37
+
38
+ def intercity_taxi_update_order_params
39
+ params.require(:order).permit(
40
+ line_items_attributes: %i[
41
+ id
42
+ pickup_place_name
43
+ drop_off_place_name
44
+ from_date
45
+ pickup_lat
46
+ pickup_lng
47
+ pickup_oob_confirmed
48
+ drop_off_lat
49
+ drop_off_lng
50
+ drop_off_oob_confirmed
51
+ distance_km
52
+ ordered_points
53
+ base_km
54
+ detour_pickup_km
55
+ detour_dropoff_km
56
+ extra_pickup_km
57
+ extra_dropoff_km
58
+ estimated_time_minutes
59
+ remark
60
+ passenger_count
61
+ ]
62
+ )
63
+ end
64
+
65
+ def required_schema
66
+ if action_name == 'create'
67
+ SpreeCmCommissioner::IntercityTaxiDraftOrderSchema
68
+ else
69
+ SpreeCmCommissioner::IntercityTaxiDraftOrderUpdateSchema
70
+ end
71
+ end
72
+
32
73
  def resource_serializer
33
74
  SpreeCmCommissioner::V2::Storefront::IntercityTaxiCartSerializer
34
75
  end
@@ -0,0 +1,81 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ module IntercityTaxi
6
+ class DraftOrdersController < BaseController
7
+ include Spree::Api::V2::Storefront::OrderConcern
8
+ include SpreeCmCommissioner::OrderConcern
9
+
10
+ before_action :ensure_order, only: :update
11
+ def create
12
+ order = SpreeCmCommissioner::IntercityTaxiOrder::Create.call(
13
+ trip_id: params[:trip_id],
14
+ from_date: params[:from_date],
15
+ to_date: params[:to_date],
16
+ quantity: params[:quantity],
17
+ user: spree_current_user
18
+ )
19
+
20
+ render_serialized_payload { serialize_resource(order) }
21
+ rescue StandardError => e
22
+ render_error_payload(e.message)
23
+ end
24
+
25
+ def update
26
+ order = SpreeCmCommissioner::IntercityTaxiOrder::Update.call(
27
+ order: spree_current_order,
28
+ order_params: intercity_taxi_update_order_params
29
+ )
30
+
31
+ render_serialized_payload { serialize_resource(order) }
32
+ rescue StandardError => e
33
+ render_error_payload(e.message)
34
+ end
35
+
36
+ private
37
+
38
+ def intercity_taxi_update_order_params
39
+ params.require(:order).permit(
40
+ line_items_attributes: %i[
41
+ id
42
+ pickup_place_name
43
+ drop_off_place_name
44
+ from_date
45
+ pickup_lat
46
+ pickup_lng
47
+ pickup_oob_confirmed
48
+ drop_off_lat
49
+ drop_off_lng
50
+ drop_off_oob_confirmed
51
+ distance_km
52
+ ordered_points
53
+ base_km
54
+ detour_pickup_km
55
+ detour_dropoff_km
56
+ extra_pickup_km
57
+ extra_dropoff_km
58
+ estimated_time_minutes
59
+ remark
60
+ passenger_count
61
+ ]
62
+ )
63
+ end
64
+
65
+ def required_schema
66
+ if action_name == 'create'
67
+ SpreeCmCommissioner::IntercityTaxiDraftOrderSchema
68
+ else
69
+ SpreeCmCommissioner::IntercityTaxiDraftOrderUpdateSchema
70
+ end
71
+ end
72
+
73
+ def resource_serializer
74
+ SpreeCmCommissioner::V2::Storefront::IntercityTaxiCartSerializer
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,48 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class TripPlacesController < BaseController
6
+ def index
7
+ render_serialized_payload do
8
+ serialize_collection(paginated_collection)
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def paginated_collection
15
+ collection.page(params[:page]).per(params[:per_page])
16
+ end
17
+
18
+ def collection
19
+ @collection ||= begin
20
+ base_scope = scope
21
+
22
+ if params[:q].present?
23
+ @search = base_scope.ransack(params[:q])
24
+ @search.result
25
+ else
26
+ base_scope
27
+ end
28
+ end
29
+ end
30
+
31
+ def scope
32
+ model_class.joins(:location_vendor_places)
33
+ .where(location_vendor_places: { tenant_id: @tenant.id })
34
+ .distinct
35
+ end
36
+
37
+ def model_class
38
+ SpreeCmCommissioner::Place
39
+ end
40
+
41
+ def collection_serializer
42
+ SpreeCmCommissioner::V2::Storefront::TripPlaceSerializer
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,103 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class TripSearchController < BaseController
6
+ CACHE_EXPIRES_IN = 5.minutes
7
+
8
+ def index
9
+ render_serialized_payload do
10
+ Rails.cache.fetch(collection_cache_key, collection_cache_opts) do
11
+ trips = SpreeCmCommissioner::TripQuery.new(
12
+ origin_id: params[:origin_id],
13
+ destination_id: params[:destination_id],
14
+ date: params[:date],
15
+ route_type: params[:route_type],
16
+ number_of_guests: params[:number_of_guests],
17
+ tenant_id: @tenant.id,
18
+ params: params
19
+ ).call
20
+
21
+ serialize_collection(trips)
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # override from ContentCacheable
29
+ def max_age
30
+ CACHE_EXPIRES_IN.to_i
31
+ end
32
+
33
+ # override
34
+ def collection_cache_key
35
+ cache_key_parts = [
36
+ 'trip_search',
37
+ @tenant.id,
38
+ params[:origin_id],
39
+ params[:destination_id],
40
+ params[:date],
41
+ params[:route_type],
42
+ params[:number_of_guests],
43
+ resource_includes&.sort&.join(','),
44
+ sparse_fields&.sort&.join(','),
45
+ serializer_params.to_json,
46
+ params[:page]&.to_s&.strip,
47
+ params[:per_page]&.to_s&.strip
48
+ ].compact.join('-')
49
+
50
+ Digest::MD5.hexdigest(cache_key_parts)
51
+ end
52
+
53
+ # override
54
+ def collection_cache_opts
55
+ {
56
+ namespace: Spree::Api::Config[:api_v2_collection_cache_namespace],
57
+ expires_in: CACHE_EXPIRES_IN
58
+ }
59
+ end
60
+
61
+ # override
62
+ def default_resource_includes
63
+ [
64
+ 'trips.vendor',
65
+ 'trips.vendor.logo',
66
+ 'trips.vehicle',
67
+ 'trips.vehicle.vehicle_photos',
68
+ 'trips.amenities'
69
+ ]
70
+ end
71
+
72
+ def serialize_collection(collection)
73
+ serialized_data = SpreeCmCommissioner::V2::Storefront::TripQueryResultSerializer.new(
74
+ collection,
75
+ include: default_resource_includes,
76
+ params: serializer_params
77
+ ).serializable_hash
78
+ serialized_data[:meta] = {
79
+ count: collection.size,
80
+ total_count: collection.respond_to?(:total_count) ? collection.total_count : collection.size,
81
+ current_page: collection.respond_to?(:current_page) ? collection.current_page : 1,
82
+ per_page: collection.respond_to?(:limit_value) ? collection.limit_value : collection.size,
83
+ pages: collection.respond_to?(:total_pages) ? collection.total_pages : 1,
84
+ next_page: collection.respond_to?(:next_page) ? collection.next_page : nil,
85
+ prev_page: collection.respond_to?(:prev_page) ? collection.prev_page : nil
86
+ }
87
+ serialized_data
88
+ end
89
+
90
+ # override
91
+ def serializer_params
92
+ params.permit(:include).to_hash
93
+ end
94
+
95
+ # override
96
+ def required_schema
97
+ SpreeCmCommissioner::TripSearchRequestSchema
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,32 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class TripsController < BaseController
6
+ def show
7
+ resource = scope.find(params[:id])
8
+
9
+ render_serialized_payload do
10
+ serialize_resource(resource)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def scope
17
+ model_class.joins(:vendor)
18
+ .where(spree_vendors: { tenant_id: @tenant.id })
19
+ end
20
+
21
+ def model_class
22
+ SpreeCmCommissioner::Trip
23
+ end
24
+
25
+ def resource_serializer
26
+ SpreeCmCommissioner::V2::Storefront::TripSerializer
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -48,6 +48,8 @@ module SpreeCmCommissioner
48
48
  name: 'ticket-type',
49
49
  presentation: 'Ticket Type'
50
50
  )
51
+ # auto assign the option type to the ticket
52
+ @ticket.option_types << @option_type unless @ticket.option_types.include?(@option_type)
51
53
 
52
54
  @option_value = Spree::OptionValue.find_or_create_by!(
53
55
  name: @ticket.name,
@@ -22,7 +22,7 @@ module SpreeCmCommissioner
22
22
  end
23
23
 
24
24
  def find_tenant(normalized_host)
25
- SpreeCmCommissioner::Tenant.find_by(host: "https://#{normalized_host}")
25
+ SpreeCmCommissioner::Tenant.find_by(host: normalized_host)
26
26
  end
27
27
  end
28
28
  end
@@ -22,7 +22,7 @@ module SpreeCmCommissioner
22
22
  end
23
23
 
24
24
  def admin_chat_id
25
- ENV.fetch('EXCEPTION_NOTIFIER_TELEGRAM_CHANNEL_ID', nil)
25
+ Spree::Store.default&.preferred_telegram_new_vendor_alert_chat_id
26
26
  end
27
27
  end
28
28
  end
@@ -37,22 +37,21 @@ module Spree
37
37
 
38
38
  def setup_tenant_and_store
39
39
  @tenant = @order.tenant
40
- if @tenant.present?
41
- @brand_color = @tenant.preferences[:brand_primary_color]
42
- @vendor_logo_url = @tenant.active_vendor&.logo&.original_url
43
- @current_store = @tenant
44
- else
45
- @current_store = @order.store
46
- end
40
+ @current_store = @order.store
41
+ return if @tenant.blank?
42
+
43
+ @brand_color = @tenant.preferences[:brand_primary_color]
44
+ @vendor_logo_url = @tenant.active_vendor&.logo&.original_url
47
45
  end
48
46
 
49
47
  def build_subject(resend)
50
48
  prefix = resend ? "[#{Spree.t(:resend).upcase}] " : ''
51
- "#{prefix}#{@current_store&.name} Booking Confirmation ##{@order.number}"
49
+ store_name = @tenant.present? ? @tenant.name : @current_store&.name
50
+ "#{prefix}#{store_name} Booking Confirmation ##{@order.number}"
52
51
  end
53
52
 
54
53
  def store_url
55
- @tenant.present? ? @current_store.host : @current_store.url
54
+ @tenant.present? ? @tenant.url : @current_store.url
56
55
  end
57
56
 
58
57
  def ticket_email(guest, email)
@@ -50,9 +50,9 @@ module SpreeCmCommissioner
50
50
  private
51
51
 
52
52
  def tenant_link_or_default(tenant, default_link)
53
- return default_link unless tenant.respond_to?(:host)
53
+ return default_link unless tenant.respond_to?(:url)
54
54
 
55
- site = tenant.host.to_s.strip
55
+ site = tenant.url.to_s.strip
56
56
  site.presence || default_link
57
57
  rescue StandardError
58
58
  default_link
@@ -6,6 +6,7 @@ module SpreeCmCommissioner
6
6
  preference :sms_sender_id, :string
7
7
  preference :telegram_order_alert_chat_id, :string
8
8
  preference :telegram_order_request_alert_chat_id, :string
9
+ preference :telegram_new_vendor_alert_chat_id, :string
9
10
  preference :assetlinks, :string, default: ''
10
11
  preference :apple_app_site_association, :string, default: ''
11
12
  end
@@ -4,6 +4,8 @@ module SpreeCmCommissioner
4
4
 
5
5
  belongs_to :product, class_name: '::Spree::Product', optional: false
6
6
 
7
+ has_one :banner, as: :viewable, dependent: :destroy, class_name: 'SpreeCmCommissioner::ProductCompletionStepBanner'
8
+
7
9
  # When a completion step is changed, regenerate completion steps for all line items
8
10
  # of the product so they reflect the latest step configuration.
9
11
  after_destroy :regenerate_line_items_completion_steps
@@ -28,7 +30,8 @@ module SpreeCmCommissioner
28
30
  action_label: action_label,
29
31
  action_url: action_url_for(line_item),
30
32
  completed_at: existing_data&.dig('completed_at'),
31
- completed: completed?(line_item)
33
+ completed: completed?(line_item),
34
+ banner_url: banner.present? ? banner.original_url : nil
32
35
  }
33
36
  end
34
37
 
@@ -0,0 +1,12 @@
1
+ module SpreeCmCommissioner
2
+ class ProductCompletionStepBanner < Asset
3
+ # 16x9 aspect ratio
4
+ def asset_styles
5
+ {
6
+ mini: '160x90>',
7
+ small: '480x270>',
8
+ medium: '960x540>'
9
+ }
10
+ end
11
+ end
12
+ end