spree_cm_commissioner 2.3.0.pre.pre15 → 2.3.0.pre.pre17
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/README.md +33 -0
- data/app/controllers/blazer/base_controller_decorator.rb +20 -1
- data/app/controllers/spree/api/v2/storefront/intercity_taxi/draft_orders_controller.rb +40 -0
- data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +47 -9
- data/app/controllers/spree_cm_commissioner/admin/variants_controller_decorator.rb +1 -1
- data/app/factory/spree_cm_commissioner/vendor_telegram_message_factory.rb +65 -0
- data/app/helpers/spree/base_helper_decorator.rb +2 -19
- data/app/interactors/spree_cm_commissioner/vendor_creation_telegram_alert_sender.rb +28 -0
- data/app/jobs/spree_cm_commissioner/transit/route_fulfilled_order_count_incrementer_job.rb +1 -1
- data/app/jobs/spree_cm_commissioner/transit/route_order_count_incrementer_job.rb +1 -1
- data/app/jobs/spree_cm_commissioner/transit/route_previous_trip_count_decrementer_job.rb +1 -1
- data/app/jobs/spree_cm_commissioner/transit/route_trip_count_decrementer_job.rb +1 -1
- data/app/jobs/spree_cm_commissioner/transit/route_trip_count_incrementer_job.rb +1 -1
- data/app/jobs/spree_cm_commissioner/vendor_creation_telegram_alert_sender_job.rb +10 -0
- data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +51 -0
- data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +7 -0
- data/app/models/concerns/spree_cm_commissioner/option_value_attr_type.rb +25 -0
- data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +18 -1
- data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +2 -2
- data/app/models/concerns/spree_cm_commissioner/route_order_countable.rb +3 -14
- data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +18 -4
- data/app/models/spree_cm_commissioner/block.rb +19 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/variant_decorator.rb +0 -5
- data/app/models/spree_cm_commissioner/variant_options.rb +8 -0
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +6 -0
- data/app/overrides/spree/admin/variants/_form/add_permanent_stock.html.erb.deface +2 -1
- data/app/serializers/spree_cm_commissioner/v2/storefront/intercity_taxi_cart_serializer.rb +12 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/intercity_taxi_line_item_serializer.rb +31 -0
- data/app/serializers/spree_cm_commissioner/v2/storefront/trip_result_serializer.rb +11 -0
- data/app/services/spree_cm_commissioner/checkout/advance_decorator.rb +8 -4
- data/app/services/spree_cm_commissioner/intercity_taxi_order/create.rb +67 -0
- data/app/services/spree_cm_commissioner/intercity_taxi_order/update.rb +79 -0
- data/app/services/spree_cm_commissioner/{transit/base_route_order_metrics_updater.rb → routes/base_update_order_metrics.rb} +2 -2
- data/app/services/spree_cm_commissioner/{transit/route_previous_trip_count_decrementer_service.rb → routes/decrement_previous_trip_count.rb} +3 -3
- data/app/services/spree_cm_commissioner/{transit/route_trip_count_decrementer_service.rb → routes/decrement_trip_count.rb} +2 -2
- data/app/services/spree_cm_commissioner/{transit/route_fulfilled_order_count_incrementer_service.rb → routes/increment_fulfilled_order_count.rb} +3 -3
- data/app/services/spree_cm_commissioner/{transit/route_order_count_incrementer_service.rb → routes/increment_order_count.rb} +3 -3
- data/app/services/spree_cm_commissioner/{transit/route_trip_count_incrementer_service.rb → routes/increment_trip_count.rb} +2 -2
- data/app/services/spree_cm_commissioner/trips/search.rb +65 -0
- data/app/views/blazer/queries/embed/_content.html.erb +51 -2
- data/app/views/spree/admin/option_types/_color_field.html.erb +21 -0
- data/app/views/spree/admin/option_types/_option_value_fields.html.erb +2 -0
- data/app/views/spree/admin/variants/_color_field.html.erb +28 -0
- data/app/views/spree/admin/variants/_date_field.html.erb +11 -1
- data/app/views/spree/admin/variants/_default_field.html.erb +7 -3
- data/app/views/spree/admin/variants/_option_values.html.erb +5 -1
- data/app/views/spree/admin/variants/_time_field.html.erb +7 -1
- data/app/views/spree/order_mailer/_adjustment.html.erb +7 -0
- data/app/views/spree_cm_commissioner/event_transactional_mailer/_event_banner.html.erb +9 -3
- data/config/locales/km.yml +64 -0
- data/config/routes.rb +4 -1
- data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +18 -0
- data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +30 -0
- data/lib/spree_cm_commissioner/trip_result.rb +15 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- metadata +20 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76d6f1a36e751b1723a6a6f7d6ba016dcf6df4c24d4e66322fadd7cb6d99f133
|
|
4
|
+
data.tar.gz: 5ee3fb8b1c36b92b04b349218a72db179b9e5afffe18342b73c6bafea2375600
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d402702c7778ddf7a44be7b6370fb943c7e091ee1d9cc5214ac4ffa97fde73a2347f072692661a815daf85fd1a18441d44b79c2e4246fce686b5f9822554a5b5
|
|
7
|
+
data.tar.gz: 3adbb3c9b40e612c65be67ae0853047bd5f1b1c82ac5daf7e91dc494a1f16d51f005eca9dbc48adf83467d3edb25e466114d9716abec8d43b0e7edff1b0753f2
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -32,6 +32,39 @@ If your server was running, restart it so that it can find the assets properly.
|
|
|
32
32
|
|
|
33
33
|
Update the semantic version number in `lib/spree_cm_commissioner/version.rb`, then create and push a new tag to GitHub. When the tag is pushed, the GitHub Actions workflow will automatically build the gem and publish it to RubyGems.
|
|
34
34
|
|
|
35
|
+
Here's a cleaner and more polished version of your section:
|
|
36
|
+
|
|
37
|
+
## PostgreSQL Configuration
|
|
38
|
+
|
|
39
|
+
By default, this Rails engine uses your current system login to connect to the PostgreSQL database. To allow passwordless connections, you need to configure PostgreSQL to trust local connections by editing `pg_hba.conf`:
|
|
40
|
+
|
|
41
|
+
```conf
|
|
42
|
+
# pg_hba.conf
|
|
43
|
+
local all all trust
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
With this `trust` configuration, PostgreSQL expects a role that matches your current system username.
|
|
47
|
+
|
|
48
|
+
To check your system username:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
whoami # e.g., superdev
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then create a matching PostgreSQL role:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
createuser -U postgres -s superdev
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or simply run the following to create a role matching your current system user:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
createuser -U postgres -s $(whoami)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
> 💡 We recommend using [Postgres.app](https://postgresapp.com) for local development. It supports multiple PostgreSQL versions and provides a developer-friendly setup out of the box.
|
|
67
|
+
|
|
35
68
|
## Config
|
|
36
69
|
|
|
37
70
|
### Rake tasks
|
|
@@ -12,11 +12,30 @@ module Blazer
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def restrict_organizer_access
|
|
15
|
-
return
|
|
15
|
+
return if spree_current_user.admin?
|
|
16
|
+
|
|
17
|
+
return unless spree_current_user.organizer? || vendor_permissions?
|
|
16
18
|
return if controller_name == 'queries' && %w[show run].include?(action_name)
|
|
17
19
|
|
|
18
20
|
raise ActionController::RoutingError, 'Unauthorized'
|
|
19
21
|
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def current_vendor
|
|
26
|
+
@current_vendor ||= vendors&.find_by(id: session[:vendor_id]) || vendors&.first
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def vendors
|
|
30
|
+
@vendors ||= spree_current_user&.vendors
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def vendor_permissions?
|
|
34
|
+
return false unless current_vendor
|
|
35
|
+
|
|
36
|
+
permissions = spree_current_user.permissions_for_vendor(current_vendor.id)
|
|
37
|
+
permissions.exists?(entry: 'shared_console/reports', action: 'view_reports')
|
|
38
|
+
end
|
|
20
39
|
end
|
|
21
40
|
end
|
|
22
41
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V2
|
|
4
|
+
module Storefront
|
|
5
|
+
module IntercityTaxi
|
|
6
|
+
class DraftOrdersController < ::Spree::Api::V2::ResourceController
|
|
7
|
+
def create
|
|
8
|
+
order = SpreeCmCommissioner::IntercityTaxiOrder::Create.call(
|
|
9
|
+
trip_id: params[:trip_id],
|
|
10
|
+
from_date: params[:from_date],
|
|
11
|
+
to_date: params[:to_date],
|
|
12
|
+
user_id: params[:user_id],
|
|
13
|
+
quantity: params[:quantity]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
render_serialized_payload { serialize_resource(order) }
|
|
17
|
+
rescue StandardError => e
|
|
18
|
+
render_error_payload(e.message)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def update
|
|
22
|
+
order = SpreeCmCommissioner::IntercityTaxiOrder::Update.call(
|
|
23
|
+
order_number: params[:id],
|
|
24
|
+
params: params
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
render_serialized_payload { serialize_resource(order) }
|
|
28
|
+
rescue StandardError => e
|
|
29
|
+
render_error_payload(e.message)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def resource_serializer
|
|
33
|
+
SpreeCmCommissioner::V2::Storefront::IntercityTaxiCartSerializer
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -3,21 +3,59 @@ module Spree
|
|
|
3
3
|
module V2
|
|
4
4
|
module Storefront
|
|
5
5
|
class TripSearchController < ::Spree::Api::V2::ResourceController
|
|
6
|
+
CACHE_EXPIRES_IN = 5.minutes
|
|
7
|
+
|
|
6
8
|
def index
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
+
vendor_id: params[:vendor_id],
|
|
16
|
+
number_of_guests: params[:number_of_guests],
|
|
17
|
+
params: params
|
|
18
|
+
).call
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
serialize_collection(trips)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
17
23
|
end
|
|
18
24
|
|
|
19
25
|
private
|
|
20
26
|
|
|
27
|
+
# override from ContentCacheable
|
|
28
|
+
def max_age
|
|
29
|
+
CACHE_EXPIRES_IN.to_i
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# override
|
|
33
|
+
def collection_cache_key
|
|
34
|
+
cache_key_parts = [
|
|
35
|
+
'trip_search',
|
|
36
|
+
params[:origin_id],
|
|
37
|
+
params[:destination_id],
|
|
38
|
+
params[:date],
|
|
39
|
+
params[:vendor_id],
|
|
40
|
+
params[:number_of_guests],
|
|
41
|
+
resource_includes&.sort&.join(','),
|
|
42
|
+
sparse_fields&.sort&.join(','),
|
|
43
|
+
serializer_params.to_json,
|
|
44
|
+
params[:page]&.to_s&.strip,
|
|
45
|
+
params[:per_page]&.to_s&.strip
|
|
46
|
+
].compact.join('-')
|
|
47
|
+
|
|
48
|
+
Digest::MD5.hexdigest(cache_key_parts)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# override
|
|
52
|
+
def collection_cache_opts
|
|
53
|
+
{
|
|
54
|
+
namespace: Spree::Api::Config[:api_v2_collection_cache_namespace],
|
|
55
|
+
expires_in: CACHE_EXPIRES_IN
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
21
59
|
# override
|
|
22
60
|
def default_resource_includes
|
|
23
61
|
[
|
|
@@ -17,7 +17,7 @@ module SpreeCmCommissioner
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
# construct option values base on name & create new option value when not exist.
|
|
20
|
-
# then set to variant.
|
|
20
|
+
# then set to variant. Empty values will remove the option value from variant.
|
|
21
21
|
def build_option_values
|
|
22
22
|
option_values = permitted_resource_params.delete(:option_values_attributes).to_h.values
|
|
23
23
|
return if option_values.blank?
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# 📋 ---[New Vendor]---
|
|
2
|
+
#
|
|
3
|
+
# 📝 Name: {{vendor.name}}
|
|
4
|
+
#
|
|
5
|
+
# ✉️ Email: <code>{{vendor.notification_email || vendor.support_email}}</code>
|
|
6
|
+
# 📱 Phone Number: {{vendor.phone_number}}
|
|
7
|
+
#
|
|
8
|
+
# 👤 Created by: {{first_user.name || 'Admin'}}
|
|
9
|
+
# 🗓️ Created at: {{vendor.created_at}}
|
|
10
|
+
#
|
|
11
|
+
# 🔗 URL: {{vendor.organizer_url}}
|
|
12
|
+
module SpreeCmCommissioner
|
|
13
|
+
class VendorTelegramMessageFactory < TelegramMessageFactory
|
|
14
|
+
attr_reader :vendor
|
|
15
|
+
|
|
16
|
+
def initialize(vendor:)
|
|
17
|
+
@vendor = vendor
|
|
18
|
+
|
|
19
|
+
title = '✨ New Vendor ✨'
|
|
20
|
+
|
|
21
|
+
super(title: title)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def body
|
|
25
|
+
[
|
|
26
|
+
"📝 Name: #{vendor.name}",
|
|
27
|
+
'',
|
|
28
|
+
email_line,
|
|
29
|
+
phone_line,
|
|
30
|
+
'',
|
|
31
|
+
creator_line,
|
|
32
|
+
created_at_line,
|
|
33
|
+
'',
|
|
34
|
+
url_line
|
|
35
|
+
].compact.join("\n")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def email_line
|
|
41
|
+
return unless vendor.notification_email.present? || vendor.support_email.present?
|
|
42
|
+
|
|
43
|
+
"✉️ Email: #{inline_code(vendor.notification_email || vendor.support_email)}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def phone_line
|
|
47
|
+
return if vendor.contact_us.blank?
|
|
48
|
+
|
|
49
|
+
"📱 Phone Number: #{vendor.contact_us}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def creator_line
|
|
53
|
+
creator_email = vendor.users.first&.email
|
|
54
|
+
"👤 Created by: #{creator_email}" if creator_email.present?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def created_at_line
|
|
58
|
+
"🗓️ Created at: #{pretty_date(vendor.created_at)}" if vendor.created_at.present?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def url_line
|
|
62
|
+
"🔗 URL: #{vendor.organizer_url}" if vendor.organizer_url.present?
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -20,25 +20,8 @@ module Spree
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def custom_product_line_item_url(line_item
|
|
24
|
-
|
|
25
|
-
options.merge!(locale: locale_param)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
localize = if options[:locale].present?
|
|
29
|
-
"/#{options[:locale]}"
|
|
30
|
-
else
|
|
31
|
-
''
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
line_item = Spree::LineItem.find(line_item.id)
|
|
35
|
-
payload = { order_number: line_item.order.number, line_item_id: line_item.id }
|
|
36
|
-
|
|
37
|
-
jwt_token = SpreeCmCommissioner::LineItemJwtToken.encode(payload, line_item.order.token)
|
|
38
|
-
|
|
39
|
-
return if line_item.number.blank? && jwt_token.blank?
|
|
40
|
-
|
|
41
|
-
"#{current_store.formatted_url + localize}/a/#{line_item.qr_data}"
|
|
23
|
+
def custom_product_line_item_url(line_item)
|
|
24
|
+
main_app.url_for("/a/#{line_item.qr_data}")
|
|
42
25
|
end
|
|
43
26
|
end
|
|
44
27
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class VendorCreationTelegramAlertSender < BaseInteractor
|
|
3
|
+
delegate :vendor, to: :context
|
|
4
|
+
|
|
5
|
+
def call
|
|
6
|
+
return if admin_chat_id.blank?
|
|
7
|
+
|
|
8
|
+
send_alert
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def send_alert
|
|
12
|
+
TelegramNotificationSender.call(
|
|
13
|
+
chat_id: admin_chat_id,
|
|
14
|
+
message: alert_message,
|
|
15
|
+
parse_mode: 'HTML'
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def alert_message
|
|
20
|
+
factory = SpreeCmCommissioner::VendorTelegramMessageFactory.new(vendor: vendor)
|
|
21
|
+
factory.message
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def admin_chat_id
|
|
25
|
+
ENV.fetch('EXCEPTION_NOTIFIER_TELEGRAM_CHANNEL_ID', nil)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -3,7 +3,7 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class RouteFulfilledOrderCountIncrementerJob < ApplicationUniqueJob
|
|
4
4
|
def perform(order_id:)
|
|
5
5
|
order = Spree::Order.find(order_id)
|
|
6
|
-
SpreeCmCommissioner::
|
|
6
|
+
SpreeCmCommissioner::Routes::IncrementFulfilledOrderCount.call(order: order)
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -3,7 +3,7 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class RouteOrderCountIncrementerJob < ApplicationUniqueJob
|
|
4
4
|
def perform(order_id:)
|
|
5
5
|
order = Spree::Order.find(order_id)
|
|
6
|
-
SpreeCmCommissioner::
|
|
6
|
+
SpreeCmCommissioner::Routes::IncrementOrderCount.call(order: order)
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -6,7 +6,7 @@ module SpreeCmCommissioner
|
|
|
6
6
|
queue_as :default
|
|
7
7
|
|
|
8
8
|
def perform(previous_route_id:)
|
|
9
|
-
SpreeCmCommissioner::
|
|
9
|
+
SpreeCmCommissioner::Routes::DecrementPreviousTripCount.call(previous_route_id: previous_route_id)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -3,7 +3,7 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class RouteTripCountDecrementerJob < ApplicationUniqueJob
|
|
4
4
|
def perform(trip_id:)
|
|
5
5
|
trip = SpreeCmCommissioner::Trip.find(trip_id)
|
|
6
|
-
SpreeCmCommissioner::
|
|
6
|
+
SpreeCmCommissioner::Routes::DecrementTripCount.call(trip: trip)
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -3,7 +3,7 @@ module SpreeCmCommissioner
|
|
|
3
3
|
class RouteTripCountIncrementerJob < ApplicationUniqueJob
|
|
4
4
|
def perform(trip_id:)
|
|
5
5
|
trip = SpreeCmCommissioner::Trip.find(trip_id)
|
|
6
|
-
SpreeCmCommissioner::
|
|
6
|
+
SpreeCmCommissioner::Routes::IncrementTripCount.call(trip: trip)
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
class VendorCreationTelegramAlertSenderJob < ApplicationUniqueJob
|
|
3
|
+
queue_as :telegram_bot
|
|
4
|
+
|
|
5
|
+
def perform(vendor_id)
|
|
6
|
+
vendor = Spree::Vendor.find(vendor_id)
|
|
7
|
+
SpreeCmCommissioner::VendorCreationTelegramAlertSender.call(vendor: vendor)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -63,11 +63,22 @@ module SpreeCmCommissioner
|
|
|
63
63
|
|
|
64
64
|
def pickup_place_name = public_metadata['pickup_place_name']
|
|
65
65
|
def drop_off_place_name = public_metadata['drop_off_place_name']
|
|
66
|
+
|
|
66
67
|
def pickup_lat = public_metadata['pickup_lat']&.to_f
|
|
67
68
|
def pickup_lng = public_metadata['pickup_lng']&.to_f
|
|
68
69
|
def drop_off_lat = public_metadata['drop_off_lat']&.to_f
|
|
69
70
|
def drop_off_lng = public_metadata['drop_off_lng']&.to_f
|
|
70
71
|
def passenger_count = public_metadata['passenger_count']&.to_i
|
|
72
|
+
def distance_km = public_metadata['distance_km']&.to_f
|
|
73
|
+
def ordered_points = public_metadata['ordered_points']
|
|
74
|
+
def base_km = public_metadata['base_km']&.to_f
|
|
75
|
+
def detour_pickup_km = public_metadata['detour_pickup_km']&.to_f
|
|
76
|
+
def detour_dropoff_km = public_metadata['detour_dropoff_km']&.to_f
|
|
77
|
+
def extra_pickup_km = public_metadata['extra_pickup_km']&.to_f
|
|
78
|
+
def extra_dropoff_km = public_metadata['extra_dropoff_km']&.to_f
|
|
79
|
+
def extra_pickup_charge_usd = public_metadata['extra_pickup_charge_usd']&.to_f
|
|
80
|
+
def extra_dropoff_charge_usd = public_metadata['extra_dropoff_charge_usd']&.to_f
|
|
81
|
+
def estimated_time_minutes = public_metadata['estimated_time_minutes']&.to_i
|
|
71
82
|
def pickup_oob_confirmed = private_metadata['pickup_oob_confirmed']
|
|
72
83
|
def drop_off_oob_confirmed = private_metadata['drop_off_oob_confirmed']
|
|
73
84
|
|
|
@@ -123,6 +134,46 @@ module SpreeCmCommissioner
|
|
|
123
134
|
set_public_metadata_value('passenger_count', value)
|
|
124
135
|
end
|
|
125
136
|
|
|
137
|
+
def distance_km=(value)
|
|
138
|
+
set_public_metadata_value('distance_km', value)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def ordered_points=(value)
|
|
142
|
+
set_public_metadata_value('ordered_points', value)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def base_km=(value)
|
|
146
|
+
set_public_metadata_value('base_km', value)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def detour_pickup_km=(value)
|
|
150
|
+
set_public_metadata_value('detour_pickup_km', value)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def detour_dropoff_km=(value)
|
|
154
|
+
set_public_metadata_value('detour_dropoff_km', value)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def extra_pickup_km=(value)
|
|
158
|
+
set_public_metadata_value('extra_pickup_km', value)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def extra_dropoff_km=(value)
|
|
162
|
+
set_public_metadata_value('extra_dropoff_km', value)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def extra_pickup_charge_usd=(value)
|
|
166
|
+
set_public_metadata_value('extra_pickup_charge_usd', value)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def extra_dropoff_charge_usd=(value)
|
|
170
|
+
set_public_metadata_value('extra_dropoff_charge_usd', value)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def estimated_time_minutes=(value)
|
|
174
|
+
set_public_metadata_value('estimated_time_minutes', value)
|
|
175
|
+
end
|
|
176
|
+
|
|
126
177
|
private
|
|
127
178
|
|
|
128
179
|
def set_public_metadata_value(key, value)
|
|
@@ -10,6 +10,7 @@ module SpreeCmCommissioner
|
|
|
10
10
|
array
|
|
11
11
|
date
|
|
12
12
|
time
|
|
13
|
+
color
|
|
13
14
|
coordinate
|
|
14
15
|
state_selection
|
|
15
16
|
payment_option
|
|
@@ -41,6 +42,8 @@ module SpreeCmCommissioner
|
|
|
41
42
|
'bib-display-prefix' => 'boolean',
|
|
42
43
|
'bib-pre-generation-on-create' => 'boolean',
|
|
43
44
|
'seat-number-positions' => 'array',
|
|
45
|
+
'color' => 'color',
|
|
46
|
+
'ticket-type' => 'string',
|
|
44
47
|
'seat-type' => 'string',
|
|
45
48
|
'intercity-taxi' => 'string'
|
|
46
49
|
}.freeze
|
|
@@ -71,6 +74,10 @@ module SpreeCmCommissioner
|
|
|
71
74
|
name.in?(RESERVED_OPTIONS.keys)
|
|
72
75
|
end
|
|
73
76
|
|
|
77
|
+
def ticket_type?
|
|
78
|
+
name == 'ticket-type'
|
|
79
|
+
end
|
|
80
|
+
|
|
74
81
|
def set_reverved_options_attributes
|
|
75
82
|
self.attr_type = RESERVED_OPTIONS[name]
|
|
76
83
|
self.kind = :variant
|
|
@@ -13,6 +13,8 @@ module SpreeCmCommissioner
|
|
|
13
13
|
|
|
14
14
|
before_validation :construct_time, if: :attr_type_time?
|
|
15
15
|
before_validation :construct_date, if: :attr_type_date?
|
|
16
|
+
before_validation :construct_color, if: :attr_type_color?
|
|
17
|
+
before_validation :construct_ticket_type, if: :ticket_type?
|
|
16
18
|
before_validation :normalize_items, if: :attr_type_array?
|
|
17
19
|
|
|
18
20
|
after_save :update_variants_metadata, if: :saved_change_to_name?
|
|
@@ -27,6 +29,10 @@ module SpreeCmCommissioner
|
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
|
|
32
|
+
def ticket_type?
|
|
33
|
+
option_type.present? && option_type&.ticket_type?
|
|
34
|
+
end
|
|
35
|
+
|
|
30
36
|
def items
|
|
31
37
|
return nil unless attr_type_array?
|
|
32
38
|
return nil if name.nil?
|
|
@@ -92,6 +98,13 @@ module SpreeCmCommissioner
|
|
|
92
98
|
self.name = name.split(',').map(&:strip).join(',')
|
|
93
99
|
end
|
|
94
100
|
|
|
101
|
+
# Ticket types are case-sensitive: "STANDARD" and "Standard" are distinct ticket types.
|
|
102
|
+
# Only strip whitespace; preserve the exact case entered by the user.
|
|
103
|
+
def construct_ticket_type
|
|
104
|
+
self.name = name&.strip&.presence
|
|
105
|
+
self.presentation = name&.strip&.presence
|
|
106
|
+
end
|
|
107
|
+
|
|
95
108
|
def construct_time
|
|
96
109
|
hour, minute = extract_time_from_time_select
|
|
97
110
|
hour, minute = extract_time_from_default_format if hour.nil? || minute.nil?
|
|
@@ -141,5 +154,17 @@ module SpreeCmCommissioner
|
|
|
141
154
|
self.name = nil if parse_date(name).blank?
|
|
142
155
|
self.presentation = name if parse_date(presentation) != parse_date(name)
|
|
143
156
|
end
|
|
157
|
+
|
|
158
|
+
def construct_color
|
|
159
|
+
self.name = parse_hex_color(name)
|
|
160
|
+
self.presentation = name if parse_hex_color(presentation) != parse_hex_color(name)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def parse_hex_color(value)
|
|
164
|
+
return nil if value.nil?
|
|
165
|
+
return nil unless value.match?(/^#[0-9A-Fa-f]{6}$/)
|
|
166
|
+
|
|
167
|
+
value.upcase
|
|
168
|
+
end
|
|
144
169
|
end
|
|
145
170
|
end
|
|
@@ -23,13 +23,26 @@ module SpreeCmCommissioner
|
|
|
23
23
|
# Makes sure seat blocks are held if not held yet or if the hold has expired.
|
|
24
24
|
# Called before moving to payment state to ensure seats are held properly,
|
|
25
25
|
# even if hold was started from :address state or an old hold expired.
|
|
26
|
-
def ensure_blocks_held
|
|
26
|
+
def ensure_blocks_held
|
|
27
27
|
return unless should_manage_blocks?
|
|
28
28
|
return if hold_expires_at.present? && hold_expires_at > Time.zone.now
|
|
29
29
|
|
|
30
|
+
hold_blocks
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def hold_blocks
|
|
30
34
|
hold_blocks!
|
|
35
|
+
rescue SpreeCmCommissioner::Seats::BlocksAreReservedByOtherGuestError,
|
|
36
|
+
SpreeCmCommissioner::Seats::BlocksAreOnHoldByOtherGuestError,
|
|
37
|
+
SpreeCmCommissioner::Seats::BlocksAreReservedBySameGuestError,
|
|
38
|
+
SpreeCmCommissioner::Seats::UnableToSaveReservedBlockRecordError => e
|
|
39
|
+
errors.add(:seats, e.message)
|
|
40
|
+
false
|
|
31
41
|
end
|
|
32
42
|
|
|
43
|
+
# Hold blocks for the order. Called during checkout (user-initiated).
|
|
44
|
+
# Catches seat errors and adds them to order.errors to prevent state transition.
|
|
45
|
+
# Returns false if error occurs, true otherwise.
|
|
33
46
|
def hold_blocks!
|
|
34
47
|
return unless should_manage_blocks?
|
|
35
48
|
|
|
@@ -46,6 +59,8 @@ module SpreeCmCommissioner
|
|
|
46
59
|
end
|
|
47
60
|
end
|
|
48
61
|
|
|
62
|
+
# Cancel blocks for the order. Called from system (order cancellation/archive).
|
|
63
|
+
# Raises errors to alert the system if something goes wrong.
|
|
49
64
|
def cancel_blocks!
|
|
50
65
|
return unless should_manage_blocks?
|
|
51
66
|
|
|
@@ -55,6 +70,8 @@ module SpreeCmCommissioner
|
|
|
55
70
|
end
|
|
56
71
|
end
|
|
57
72
|
|
|
73
|
+
# Reserve blocks for the order. Called from system (order completion).
|
|
74
|
+
# Raises errors to alert the system if something goes wrong.
|
|
58
75
|
def reserve_blocks!
|
|
59
76
|
return unless should_manage_blocks?
|
|
60
77
|
|
|
@@ -5,8 +5,8 @@ module SpreeCmCommissioner
|
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
|
-
state_machine.before_transition to: :address, do: :hold_blocks
|
|
9
|
-
state_machine.before_transition to: :payment, do: :ensure_blocks_held
|
|
8
|
+
state_machine.before_transition to: :address, do: :hold_blocks
|
|
9
|
+
state_machine.before_transition to: :payment, do: :ensure_blocks_held
|
|
10
10
|
|
|
11
11
|
state_machine.before_transition to: :complete, do: :request, if: :need_confirmation?
|
|
12
12
|
state_machine.before_transition to: :complete, do: :generate_bib_number
|
|
@@ -1,30 +1,19 @@
|
|
|
1
1
|
module SpreeCmCommissioner
|
|
2
2
|
module RouteOrderCountable
|
|
3
|
-
def
|
|
3
|
+
def has_trip_ids? # rubocop:disable Naming/PredicateName
|
|
4
4
|
preload_trip_ids.any?
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def increment_route_fulfilled_order_count
|
|
8
|
-
return unless
|
|
8
|
+
return unless has_trip_ids?
|
|
9
9
|
|
|
10
10
|
SpreeCmCommissioner::Transit::RouteFulfilledOrderCountIncrementerJob.perform_later(order_id: id)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def increment_route_order_count
|
|
14
|
-
return unless
|
|
14
|
+
return unless has_trip_ids?
|
|
15
15
|
|
|
16
16
|
SpreeCmCommissioner::Transit::RouteOrderCountIncrementerJob.perform_later(order_id: id)
|
|
17
17
|
end
|
|
18
|
-
|
|
19
|
-
# Calling `.trip_ids` directly can cause many slow database queries (N+1 problem)
|
|
20
|
-
# every time `.should_update_trip_ids?` or `.preload_trip_ids` runs.
|
|
21
|
-
# To avoid this, we store a precomputed list of trip IDs in `private_metadata`.
|
|
22
|
-
def preload_trip_ids=(preload_trip_ids = [])
|
|
23
|
-
self.private_metadata = (private_metadata || {}).merge('preload_trip_ids' => preload_trip_ids)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def preload_trip_ids
|
|
27
|
-
private_metadata&.fetch('preload_trip_ids', []) || []
|
|
28
|
-
end
|
|
29
18
|
end
|
|
30
19
|
end
|