spree_cm_commissioner 2.0.3.pre.pre5 → 2.0.3.pre.pre8

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/controllers/spree/admin/locations_controller.rb +62 -0
  4. data/app/controllers/spree/api/v2/operator/event_charts_controller.rb +2 -8
  5. data/app/controllers/spree/api/v2/platform/places_controller.rb +4 -1
  6. data/app/controllers/spree/api/v2/storefront/dynamic_fields_controller.rb +42 -0
  7. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +2 -0
  8. data/app/controllers/spree/api/v2/storefront/trip_places_controller.rb +29 -0
  9. data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +3 -1
  10. data/app/controllers/spree/api/v2/storefront/trips_controller.rb +24 -0
  11. data/app/controllers/spree_cm_commissioner/admin/products_controller_decorator.rb +14 -0
  12. data/app/interactors/spree_cm_commissioner/billing_address_creator.rb +33 -0
  13. data/app/interactors/spree_cm_commissioner/create_vendor.rb +11 -1
  14. data/app/interactors/spree_cm_commissioner/google_places_fetcher.rb +1 -0
  15. data/app/interactors/spree_cm_commissioner/intercity_taxi_order_creator.rb +106 -0
  16. data/app/interactors/spree_cm_commissioner/transit/draft_order_creator.rb +17 -4
  17. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -1
  18. data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +1 -0
  19. data/app/models/spree_cm_commissioner/address_decorator.rb +17 -3
  20. data/app/models/spree_cm_commissioner/guest.rb +105 -56
  21. data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +37 -27
  22. data/app/models/spree_cm_commissioner/order/address_book_decorator.rb +30 -12
  23. data/app/models/spree_cm_commissioner/order_decorator.rb +8 -1
  24. data/app/models/spree_cm_commissioner/place.rb +2 -0
  25. data/app/models/spree_cm_commissioner/product_decorator.rb +29 -0
  26. data/app/models/spree_cm_commissioner/saved_guest.rb +2 -0
  27. data/app/models/spree_cm_commissioner/taxon_decorator.rb +7 -0
  28. data/app/models/spree_cm_commissioner/trip.rb +4 -2
  29. data/app/models/spree_cm_commissioner/user_decorator.rb +1 -1
  30. data/app/models/spree_cm_commissioner/variant_options.rb +4 -0
  31. data/app/models/spree_cm_commissioner/vehicle.rb +2 -0
  32. data/app/models/spree_cm_commissioner/vendor_decorator.rb +3 -0
  33. data/app/overrides/spree/admin/products/_form/industry_taxons.html.erb.deface +26 -0
  34. data/app/overrides/spree/admin/products/_form/taxons.html.erb.deface +26 -0
  35. data/app/overrides/spree/admin/shared/sub_menu/_configuration/locations_tab.html.erb.deface +5 -0
  36. data/app/queries/spree_cm_commissioner/trip_query.rb +18 -18
  37. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +2 -0
  38. data/app/serializers/{spree → spree_cm_commissioner}/v2/storefront/amenity_serializer.rb +2 -2
  39. data/app/serializers/spree_cm_commissioner/v2/storefront/block_serializer.rb +9 -0
  40. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +1 -3
  41. data/app/serializers/spree_cm_commissioner/v2/storefront/seat_layout_serializer.rb +12 -0
  42. data/app/serializers/spree_cm_commissioner/v2/storefront/seat_section_serializer.rb +11 -0
  43. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_place_serializer.rb +10 -0
  44. data/app/serializers/{spree → spree_cm_commissioner}/v2/storefront/trip_query_result_serializer.rb +2 -2
  45. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_result_serializer.rb +17 -0
  46. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_serializer.rb +17 -0
  47. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_stop_serializer.rb +9 -0
  48. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_variant_serializer.rb +12 -0
  49. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_vehicle_serializer.rb +16 -0
  50. data/app/serializers/{spree → spree_cm_commissioner}/v2/storefront/trip_vendor_serializer.rb +4 -1
  51. data/app/serializers/spree_cm_commissioner/v2/storefront/variant_block_serializer.rb +9 -0
  52. data/app/views/shared/_map.html.erb +5 -4
  53. data/app/views/spree/admin/locations/_form.html.erb +133 -0
  54. data/app/views/spree/admin/locations/edit.html.erb +11 -0
  55. data/app/views/spree/admin/locations/index.html.erb +67 -0
  56. data/app/views/spree/admin/locations/new.html.erb +11 -0
  57. data/config/locales/en.yml +2 -0
  58. data/config/routes.rb +4 -0
  59. data/db/migrate/20250812015522_remove_unique_indexes_from_cm_user_identity_providers.rb +8 -0
  60. data/db/migrate/20250812121745_add_data_fill_stage_phase_to_cm_guests.rb +5 -0
  61. data/db/migrate/20250814073854_add_call_to_action_to_spree_products.rb +5 -0
  62. data/lib/spree_cm_commissioner/transit/leg.rb +14 -0
  63. data/lib/spree_cm_commissioner/transit/seat_selection.rb +9 -1
  64. data/lib/spree_cm_commissioner/trip_query_result.rb +34 -0
  65. data/lib/spree_cm_commissioner/trip_result.rb +8 -1
  66. data/lib/spree_cm_commissioner/version.rb +1 -1
  67. metadata +31 -7
  68. data/app/serializers/spree/v2/storefront/trip_result_serializer.rb +0 -16
  69. data/app/serializers/spree/v2/storefront/trip_vehicle_serializer.rb +0 -11
@@ -1,14 +1,16 @@
1
1
  module SpreeCmCommissioner
2
2
  class TripQuery
3
- attr_reader :origin_id, :destination_id, :date
3
+ attr_reader :origin_id, :destination_id, :date, :vendor_id, :number_of_guests, :params
4
4
 
5
- def initialize(origin_id:, destination_id:, date:, params: {})
5
+ def initialize(origin_id:, destination_id:, date:, vendor_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
+ @vendor_id = vendor_id
10
+ @number_of_guests = number_of_guests || 1
9
11
  @params = params
10
12
  @page = (params[:page] || 1).to_i
11
- @per_page = (params[:per_page] || 25).to_i
13
+ @per_page = params[:per_page]
12
14
  end
13
15
 
14
16
  def call
@@ -17,15 +19,16 @@ module SpreeCmCommissioner
17
19
  paginated_relation = direct_trips
18
20
  return Kaminari.paginate_array([]) if paginated_relation.empty?
19
21
 
20
- results_array = paginated_relation.map do |trip|
22
+ unique_trips = paginated_relation.uniq(&:id)
23
+ results_array = unique_trips.map do |trip|
21
24
  result = build_trip_result(trip)
22
25
  SpreeCmCommissioner::TripQueryResult.new([result])
23
26
  end
24
27
 
25
28
  Kaminari.paginate_array(
26
29
  results_array,
27
- total_count: paginated_relation.total_count,
28
- limit: @per_page,
30
+ total_count: unique_trips.size,
31
+ limit: unique_trips.size,
29
32
  offset: paginated_relation.offset_value
30
33
  )
31
34
  end
@@ -51,17 +54,17 @@ module SpreeCmCommissioner
51
54
  INNER JOIN cm_trip_stops AS drop_off ON drop_off.trip_id = cm_trips.id AND drop_off.stop_type = 1
52
55
  INNER JOIN cm_places AS origin_places ON origin_places.id = cm_trips.origin_place_id
53
56
  INNER JOIN cm_places AS dest_places ON dest_places.id = cm_trips.destination_place_id
54
- INNER JOIN spree_products ON spree_products.id = cm_trips.product_id
55
- INNER JOIN spree_variants AS master ON master.product_id = spree_products.id AND master.is_master = true
57
+ INNER JOIN spree_variants AS master ON master.product_id = cm_trips.product_id AND master.is_master = true
56
58
  INNER JOIN spree_prices AS prices ON prices.variant_id = master.id AND prices.deleted_at IS NULL
57
59
  SQL
58
- .where('(boarding.location_place_id = ? OR boarding.stop_place_id = ?)
59
- AND (drop_off.location_place_id = ? OR drop_off.stop_place_id = ?)', origin_id, origin_id, destination_id, destination_id
60
+ .where('(boarding.location_place_id = ? OR boarding.stop_place_id = ? OR cm_trips.origin_place_id = ?)
61
+ AND (drop_off.location_place_id = ? OR drop_off.stop_place_id = ? OR cm_trips.destination_place_id = ?)',
62
+ origin_id, origin_id, origin_id, destination_id, destination_id, destination_id
60
63
  )
61
- .joins("LEFT JOIN (#{@inventory_sql.to_sql}) iv ON cm_trips.product_id = iv.product_id")
64
+ .joins("INNER JOIN (#{@inventory_sql.to_sql}) iv ON cm_trips.product_id = iv.product_id")
62
65
 
63
- result = result.where(vendor_id: @params[:vendor_id]) if @params[:vendor_id].present?
64
- result.page(@page).per(@per_page)
66
+ result = result.where(vendor_id: vendor_id) if vendor_id.present?
67
+ @per_page.to_i.positive? ? result.page(@page).per(@per_page) : result.page(@page)
65
68
  end
66
69
 
67
70
  def product_inventory_totals
@@ -72,16 +75,12 @@ module SpreeCmCommissioner
72
75
  SUM(cm_inventory_items.quantity_available) AS quantity_available'
73
76
  )
74
77
  .joins(variants: :inventory_items)
75
- .where(cm_inventory_items: { inventory_date: date.to_date })
78
+ .where('cm_inventory_items.inventory_date = ? AND cm_inventory_items.quantity_available >= ?', @date.to_date, @number_of_guests)
76
79
  .group('spree_products.id')
77
80
  end
78
81
 
79
82
  private
80
83
 
81
- def cached_inventory_sql
82
- @inventory_sql ||= product_inventory_totals
83
- end
84
-
85
84
  def build_trip_result(trip)
86
85
  vehicle = trip&.vehicle
87
86
  vendor = trip&.vendor
@@ -90,6 +89,7 @@ module SpreeCmCommissioner
90
89
  departure_time: trip&.departure_time,
91
90
  duration: trip&.duration,
92
91
  allow_seat_selection: trip&.allow_seat_selection,
92
+ route_type: trip&.route_type,
93
93
  origin_place: {
94
94
  id: trip&.origin_place_id,
95
95
  name: trip&.origin_place_name
@@ -44,6 +44,8 @@ module Spree
44
44
  end
45
45
 
46
46
  base.cache_options store: nil
47
+
48
+ base.attribute :action_button, &:action_button
47
49
  end
48
50
  end
49
51
  end
@@ -1,11 +1,11 @@
1
- module Spree
1
+ module SpreeCmCommissioner
2
2
  module V2
3
3
  module Storefront
4
4
  class AmenitySerializer < BaseSerializer
5
5
  set_type :amenity
6
6
  attributes :name, :presentation
7
7
  attribute :display_icon do |option_value|
8
- ActionController::Base.helpers.image_url(option_value.display_icon)
8
+ ::ActionController::Base.helpers.image_url(option_value.display_icon)
9
9
  rescue StandardError
10
10
  nil
11
11
  end
@@ -0,0 +1,9 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class BlockSerializer < BaseSerializer
5
+ attributes :label, :width, :height, :x, :y, :rotation, :block_type
6
+ end
7
+ end
8
+ end
9
+ end
@@ -7,7 +7,7 @@ module SpreeCmCommissioner
7
7
  attributes :first_name, :last_name, :dob, :gender, :kyc_fields, :other_occupation, :created_at, :updated_at,
8
8
  :qr_data, :social_contact_platform, :social_contact, :available_social_contact_platforms,
9
9
  :age, :emergency_contact, :other_organization, :expectation, :upload_later, :address, :formatted_bib_number, :phone_number,
10
- :token, :country_code, :contact
10
+ :token, :country_code, :contact, :data_fill_stage_phase
11
11
 
12
12
  # temporary, once app release after cm-app v1.9.1, we no longer need this.
13
13
  attribute :seat_number do |object|
@@ -22,8 +22,6 @@ module SpreeCmCommissioner
22
22
  belongs_to :nationality, serializer: Spree::V2::Storefront::TaxonSerializer
23
23
  belongs_to :line_item, serializer: Spree::V2::Storefront::LineItemSerializer
24
24
 
25
- has_many :guest_dynamic_fields, serializer: SpreeCmCommissioner::V2::Storefront::GuestDynamicFieldSerializer
26
-
27
25
  has_one :id_card, serializer: Spree::V2::Storefront::IdCardSerializer
28
26
  has_one :check_in
29
27
 
@@ -0,0 +1,12 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class SeatLayoutSerializer < BaseSerializer
5
+ attributes :name, :status, :width, :height
6
+
7
+ has_many :seat_sections, serializer: SpreeCmCommissioner::V2::Storefront::SeatSectionSerializer
8
+ has_many :top_level_blocks, serializer: SpreeCmCommissioner::V2::Storefront::BlockSerializer
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class SeatSectionSerializer < BaseSerializer
5
+ attributes :name, :width, :height, :x, :y, :rotation, :shape_path
6
+
7
+ has_many :blocks, serializer: SpreeCmCommissioner::V2::Storefront::BlockSerializer
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class TripPlaceSerializer < BaseSerializer
5
+ attributes :reference, :name, :vicinity, :lat, :lon, :icon, :url, :rating,
6
+ :formatted_phone_number, :formatted_address, :address_components, :types
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,4 +1,4 @@
1
- module Spree
1
+ module SpreeCmCommissioner
2
2
  module V2
3
3
  module Storefront
4
4
  class TripQueryResultSerializer < BaseSerializer
@@ -7,7 +7,7 @@ module Spree
7
7
  attributes :quantity_available, :max_capacity
8
8
 
9
9
  attribute :direct, &:direct?
10
- has_many :trips, serializer: Spree::V2::Storefront::TripResultSerializer
10
+ has_many :trips, serializer: ::SpreeCmCommissioner::V2::Storefront::TripResultSerializer
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,17 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class TripResultSerializer < BaseSerializer
5
+ set_type :trip_result
6
+
7
+ attributes :origin_place, :destination_place, :boarding, :drop_off, :price, :compare_at_amount, :currency, :quantity_available, :max_capacity,
8
+ :allow_seat_selection, :departure_time, :route_type
9
+ attribute :duration_in_hms, &:duration_in_hms
10
+ attribute :arrival_time, &:arrival_time
11
+ belongs_to :vendor, serializer: ::SpreeCmCommissioner::V2::Storefront::TripVendorSerializer
12
+ belongs_to :vehicle, serializer: ::SpreeCmCommissioner::V2::Storefront::TripVehicleSerializer
13
+ has_many :amenities, serializer: ::SpreeCmCommissioner::V2::Storefront::AmenitySerializer
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class TripSerializer < BaseSerializer
5
+ attributes :departure_time, :arrival_time, :duration_in_hms, :origin_place, :destination_place, :route_type
6
+
7
+ has_one :vehicle, serializer: ::SpreeCmCommissioner::V2::Storefront::TripVehicleSerializer
8
+
9
+ has_many :boarding_trip_stops, serializer: ::SpreeCmCommissioner::V2::Storefront::TripStopSerializer
10
+ has_many :drop_off_trip_stops, serializer: ::SpreeCmCommissioner::V2::Storefront::TripStopSerializer
11
+ has_many :variants, serializer: ::SpreeCmCommissioner::V2::Storefront::TripVariantSerializer
12
+
13
+ belongs_to :vendor, serializer: ::SpreeCmCommissioner::V2::Storefront::TripVendorSerializer
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class TripStopSerializer < BaseSerializer
5
+ attributes :id, :stop_place, :arrival_time, :departure_time
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class TripVariantSerializer < BaseSerializer
5
+ attributes :price, :display_price, :compare_at_price, :display_compare_at_price,
6
+ :number_of_guests, :seat_type
7
+
8
+ has_many :variant_blocks, serializer: ::SpreeCmCommissioner::V2::Storefront::VariantBlockSerializer
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class TripVehicleSerializer < BaseSerializer
5
+ set_type :vehicle
6
+
7
+ attributes :id, :code, :vehicle_type
8
+
9
+ has_many :vehicle_photos, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
10
+ has_many :amenities, serializer: ::SpreeCmCommissioner::V2::Storefront::AmenitySerializer
11
+
12
+ has_one :seat_layout, serializer: SpreeCmCommissioner::V2::Storefront::SeatLayoutSerializer
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,4 +1,4 @@
1
- module Spree
1
+ module SpreeCmCommissioner
2
2
  module V2
3
3
  module Storefront
4
4
  class TripVendorSerializer < BaseSerializer
@@ -7,6 +7,9 @@ module Spree
7
7
  attributes :name, :star_rating
8
8
 
9
9
  has_one :logo, serializer: ::SpreeCmCommissioner::V2::Storefront::AssetSerializer
10
+
11
+ has_many :vendor_kind_option_types, serializer: ::Spree::V2::Storefront::OptionTypeSerializer
12
+ has_many :vendor_kind_option_values, serializer: ::Spree::V2::Storefront::OptionValueSerializer
10
13
  end
11
14
  end
12
15
  end
@@ -0,0 +1,9 @@
1
+ module SpreeCmCommissioner
2
+ module V2
3
+ module Storefront
4
+ class VariantBlockSerializer < BaseSerializer
5
+ attributes :variant_id, :block_id
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,14 +1,15 @@
1
- <div class="border rounded mb-4"><div id="map" class="rounded" style="height: 200px;"></div></div>
1
+ <% map_height ||= 200 %>
2
2
 
3
+ <div class="border rounded mb-4">
4
+ <div id="map" class="rounded" style="height: <%= map_height %>px;"></div>
5
+ </div>
3
6
  <% @default_latlon = ENV.fetch("DEFAULT_LATLON") %>
4
7
  <% @default_lat = @default_latlon.split(",")[0] %>
5
8
  <% @default_lon = @default_latlon.split(",")[1] %>
6
-
7
9
  <%= content_tag :div, class: 'map-selector', data: {
8
- lat: lat || @default_lat,
10
+ lat: lat || @default_lat,
9
11
  lon: lon || @default_lon
10
12
  } do %><% end %>
11
-
12
13
  <%# MAP scripts %>
13
14
  <% @map_key = ENV.fetch("GOOGLE_MAP_KEY") %>
14
15
  <% @map_src = "https://maps.googleapis.com/maps/api/js?key=#{@map_key}&callback=initMap&v=weekly" %>
@@ -0,0 +1,133 @@
1
+ <div class="row g-4" data-controller="place">
2
+ <div class="col-md-6">
3
+ <div class="form-group">
4
+ <%= f.field_container :base_64_content do %>
5
+ <%= f.label :base_64_content, Spree.t(:place) %>
6
+ <% if can? :modify, SpreeCmCommissioner::Place %>
7
+ <% selected_name = f.object.name.presence || f.object.formatted_address || "Search Place" %>
8
+ <%= f.select :base_64_content, [], { include_hidden: true },
9
+ class: 'select2autocomplete',
10
+ data: {
11
+ autocomplete_url_value: 'places_api_v2',
12
+ autocomplete_return_attr_value: :name,
13
+ autocomplete_custom_return_id_value: :base_64_content
14
+ } do %>
15
+ <option selected><%= selected_name %></option>
16
+ <% end %>
17
+ <% end %>
18
+ <% end %>
19
+ </div>
20
+
21
+ <%= render 'shared/map', lat: f.object.lat, lon: f.object.lon, map_height: 270 %>
22
+ </div>
23
+
24
+ <div class="col-md-6">
25
+ <div class="card shadow-sm border-0">
26
+ <div class="card-header bg-light fw-semibold">
27
+ <i class="bi bi-geo-alt-fill me-2"></i><%= Spree.t(:location_details) %>
28
+ </div>
29
+
30
+ <div class="card-body">
31
+ <div class="mb-3">
32
+ <%= f.label :name, raw(Spree.t(:name) + required_span_tag) %>
33
+ <%= f.text_field :name,
34
+ class: "form-control",
35
+ placeholder: "Enter your name",
36
+ required: :required,
37
+ data: { target: "place.name" } %>
38
+ <%= error_message_on(f.object, :name) %>
39
+ </div>
40
+
41
+ <div class="row">
42
+ <div class="col-md-6 mb-3">
43
+ <%= f.label :lat, Spree.t(:lat), class: "form-label" %>
44
+ <%= f.text_field :lat,
45
+ class: "form-control",
46
+ placeholder: "e.g., 11.5621",
47
+ data: { target: "place.lat" } %>
48
+ <%= error_message_on(f.object, :lat) %>
49
+ </div>
50
+
51
+ <div class="col-md-6 mb-3">
52
+ <%= f.label :lon, Spree.t(:lon), class: "form-label" %>
53
+ <%= f.text_field :lon,
54
+ class: "form-control",
55
+ placeholder: "e.g., 104.9143",
56
+ data: { target: "place.lon" } %>
57
+ <%= error_message_on(f.object, :lon) %>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="mb-3">
62
+ <%= f.label :formatted_address, Spree.t(:address), class: "form-label" %>
63
+ <%= f.text_field :formatted_address,
64
+ class: "form-control",
65
+ placeholder: "Enter your address",
66
+ data: { target: "place.address" } %>
67
+ <%= error_message_on(f.object, :formatted_address) %>
68
+ </div>
69
+
70
+ <%= f.hidden_field :reference, value: f.object.reference, data: { target: "place.reference" } %>
71
+ <%= f.hidden_field :types, value: f.object.types, data: { target: "place.types" } %>
72
+ <%= f.hidden_field :vicinity, value: f.object.vicinity, data: { target: "place.vicinity" } %>
73
+ <%= f.hidden_field :icon, value: f.object.icon, data: { target: "place.icon" } %>
74
+ <%= f.hidden_field :rating, value: f.object.rating, data: { target: "place.rating" } %>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </div>
79
+
80
+ <script>
81
+ let map, marker;
82
+
83
+ function initMap() {
84
+ const mapElement = document.getElementById("map");
85
+ if (!mapElement) return;
86
+
87
+ const container = document.querySelector(".map-selector");
88
+ const defaultLat = parseFloat(container?.dataset.lat) || 11.5621;
89
+ const defaultLon = parseFloat(container?.dataset.lon) || 104.8885;
90
+
91
+ const center = { lat: defaultLat, lng: defaultLon };
92
+
93
+ map = new google.maps.Map(mapElement, { center, zoom: 18 });
94
+ marker = new google.maps.Marker({ position: center, map });
95
+ }
96
+
97
+ document.addEventListener("spree:load", () => {
98
+ const select = document.querySelector(".select2autocomplete");
99
+ if (!select) return;
100
+
101
+ $(select).on("select2:select", (e) => {
102
+ const base64Content = e.params.data.id;
103
+ if (!base64Content) return;
104
+
105
+ try {
106
+ const placeData = JSON.parse(atob(base64Content));
107
+
108
+ const setValue = (selector, value) => {
109
+ const el = document.querySelector(selector);
110
+ if (el) el.value = value ?? "";
111
+ };
112
+
113
+ setValue('[data-target="place.name"]', placeData.name);
114
+ setValue('[data-target="place.lat"]', placeData.lat);
115
+ setValue('[data-target="place.lon"]', placeData.lon);
116
+ setValue('[data-target="place.address"]', placeData.formatted_address);
117
+ setValue('[data-target="place.reference"]', placeData.reference);
118
+ setValue('[data-target="place.types"]', placeData.types?.[0] || "");
119
+ setValue('[data-target="place.vicinity"]', placeData.vicinity);
120
+ setValue('[data-target="place.icon"]', placeData.icon);
121
+ setValue('[data-target="place.rating"]', placeData.rating);
122
+
123
+ if (placeData.lat && placeData.lon && map && marker) {
124
+ const newLatLng = new google.maps.LatLng(+placeData.lat, +placeData.lon);
125
+ map.setCenter(newLatLng);
126
+ marker.setPosition(newLatLng);
127
+ }
128
+ } catch (err) {
129
+ console.error("Error decoding or parsing place data:", err);
130
+ }
131
+ });
132
+ });
133
+ </script>
@@ -0,0 +1,11 @@
1
+ <% content_for :page_title do %>
2
+ <%= page_header_back_button spree.admin_locations_path %>
3
+ <%= @object.name %>
4
+ <% end %>
5
+
6
+ <%= form_with model: @object, url: { action: 'update' }, html: { multipart: true } do |f| %>
7
+ <fieldset>
8
+ <%= render partial: 'form', locals: { f: f } %>
9
+ <%= render partial: 'spree/admin/shared/edit_resource_links' %>
10
+ </fieldset>
11
+ <% end %>
@@ -0,0 +1,67 @@
1
+ <% content_for :page_title do %>
2
+ <%= Spree.t(:locations) %>
3
+ <% end %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <% if can?(:create, SpreeCmCommissioner::Place) %>
7
+ <%= button_link_to Spree.t(:new_location),
8
+ new_object_url,
9
+ class: "btn-success",
10
+ icon: "add.svg",
11
+ id: "admin_new_location" %>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <% content_for :table_filter do %>
16
+ <div data-hook="admin_locations_index_search">
17
+ <%= search_form_for [:admin, @search], url: spree.admin_locations_path do |f| %>
18
+ <div class="row">
19
+ <div class="col-md-6">
20
+ <div class="form-group">
21
+ <%= label_tag :q_name_cont, Spree.t(:name) %>
22
+ <%= f.text_field :name_cont, tabindex: 1, class: "form-control js-quick-search-target" %>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ <div data-hook="admin_locations_index_search_buttons" class="form-actions">
27
+ <%= button Spree.t(:filter_results), 'search' %>
28
+ </div>
29
+ <% end %>
30
+ </div>
31
+ <% end %>
32
+
33
+ <div class="table-responsive border rounded bg-white mb-3" >
34
+ <table class="table" id="listing_locations" data-hook>
35
+ <thead class="text-muted">
36
+ <tr data-hook="location_header">
37
+ <th><%= sort_link @search, :name, Spree.t(:name), {}, { title: 'name' } %></th>
38
+ <th><%= Spree.t(:address) %></th>
39
+ <th><%= Spree.t(:latitude) %></th>
40
+ <th><%= Spree.t(:longitude) %></th>
41
+ <th><%= sort_link @search, :created_at, Spree.t(:created_at), {}, { title: 'created_at' } %></th>
42
+ <th><%= sort_link @search, :updated_at, Spree.t(:updated_at), {}, { title: 'updated_at' } %></th>
43
+ <th scope="col" data-hook="admin_locations_actions" class="actions"></th>
44
+ </tr>
45
+ </thead>
46
+ <tbody>
47
+ <% @locations.each do |location| %>
48
+ <tr id="<%= spree_dom_id(location) %>" data-hook="location_row">
49
+ <td><%= link_to location.name, spree.edit_admin_location_path(location) %></td>
50
+ <td><%= location.formatted_address.presence || location.vicinity %></td>
51
+ <td><%= location.lat %></td>
52
+ <td><%= location.lon %></td>
53
+ <td><%= location.created_at %></td>
54
+ <td><%= location.updated_at %></td>
55
+ <td data-hook="admin_locations_index_row_actions">
56
+ <span class="d-flex justify-content-end ">
57
+ <%= link_to_edit(location, url: edit_admin_location_url(location), no_text: true, class: 'edit') if can?(:edit, location) %>
58
+ <%= link_to_delete(location, url: admin_location_url(location), no_text: true) if can?(:delete, location) %>
59
+ </span>
60
+ </td>
61
+ </tr>
62
+ <% end %>
63
+ </tbody>
64
+ </table>
65
+ </div>
66
+
67
+ <%= paginate @locations, theme: 'admin-twitter-bootstrap-4' %>
@@ -0,0 +1,11 @@
1
+ <% content_for :page_title do %>
2
+ <%= page_header_back_button spree.admin_locations_path %>
3
+ <%= Spree.t(:new_location) %>
4
+ <% end %>
5
+
6
+ <%= form_with model: @object, url: { action: 'create' }, html: { multipart: true } do |f| %>
7
+ <fieldset>
8
+ <%= render partial: 'form', locals: { f: f } %>
9
+ <%= render partial: 'spree/admin/shared/new_resource_links' %>
10
+ </fieldset>
11
+ <% end %>
@@ -117,6 +117,8 @@ en:
117
117
  empty_info: "No <b>Photos</b> found."
118
118
  nearby_place:
119
119
  empty_info: "No <b>Nearby places</b> found."
120
+ location:
121
+ already_exist: "Location already exist"
120
122
 
121
123
  product_place:
122
124
  empty_info: "No <b>Places</b> found."
data/config/routes.rb CHANGED
@@ -284,6 +284,8 @@ Spree::Core::Engine.add_routes do
284
284
  end
285
285
  end
286
286
 
287
+ resources :locations
288
+
287
289
  resources :tenants do
288
290
  resources :vendors, controller: :tenant_vendors
289
291
  end
@@ -555,6 +557,7 @@ Spree::Core::Engine.add_routes do
555
557
 
556
558
  resources :trip_places
557
559
  resources :trip_search, only: [:index]
560
+ resources :trips, only: %i[show]
558
561
 
559
562
  namespace :queue_cart do
560
563
  resources :line_items, only: [:create]
@@ -644,6 +647,7 @@ Spree::Core::Engine.add_routes do
644
647
  resources :id_cards
645
648
  end
646
649
  resources :dynamic_field_options
650
+ resources :dynamic_fields
647
651
  resources :user_guests do
648
652
  resources :id_cards
649
653
  end
@@ -0,0 +1,8 @@
1
+ class RemoveUniqueIndexesFromCmUserIdentityProviders < ActiveRecord::Migration[7.0]
2
+ def change
3
+ if index_exists?(:cm_user_identity_providers, [:identity_type, :sub], name: "index_cm_user_identity_providers_on_identity_type_and_sub")
4
+ remove_index :cm_user_identity_providers,
5
+ name: "index_cm_user_identity_providers_on_identity_type_and_sub"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class AddDataFillStagePhaseToCmGuests < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :cm_guests, :data_fill_stage_phase, :string, default: 'pre_registration', null: false, if_not_exists: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddCallToActionToSpreeProducts < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :spree_products, :call_to_action, :integer, null: true, if_not_exists: true
4
+ end
5
+ end
@@ -19,5 +19,19 @@ module SpreeCmCommissioner::Transit
19
19
  seat_selections: (hash[:seat_selections] || []).map { |seat_selection| SeatSelection.from_hash(seat_selection) }
20
20
  )
21
21
  end
22
+
23
+ def quantity
24
+ @seat_selections.sum(&:quantity).to_i
25
+ end
26
+
27
+ def to_h
28
+ {
29
+ direction: @direction,
30
+ trip_id: @trip_id,
31
+ boarding_trip_stop_id: @boarding_trip_stop_id,
32
+ drop_off_trip_stop_id: @drop_off_trip_stop_id,
33
+ seat_selections: @seat_selections.map(&:to_h)
34
+ }
35
+ end
22
36
  end
23
37
  end
@@ -4,7 +4,7 @@ module SpreeCmCommissioner::Transit
4
4
 
5
5
  def initialize(options = {})
6
6
  @variant_id = options[:variant_id]
7
- @quantity = options[:quantity]
7
+ @quantity = options[:quantity]&.to_i
8
8
  @block_ids = options[:block_ids] || []
9
9
  end
10
10
 
@@ -15,5 +15,13 @@ module SpreeCmCommissioner::Transit
15
15
  block_ids: hash[:block_ids] || [] # empty when no seat selection.
16
16
  )
17
17
  end
18
+
19
+ def to_h
20
+ {
21
+ variant_id: @variant_id,
22
+ quantity: @quantity,
23
+ block_ids: @block_ids
24
+ }
25
+ end
18
26
  end
19
27
  end