spree_cm_commissioner 2.7.1.pre.pre4 → 2.7.1.pre.pre6

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -4
  3. data/Gemfile.lock +1 -1
  4. data/app/controllers/spree/api/v2/storefront/pricing_previews_controller.rb +39 -0
  5. data/app/controllers/spree/api/v2/tenant/base_controller.rb +0 -4
  6. data/app/controllers/spree/api/v2/tenant/pricing_previews_controller.rb +39 -0
  7. data/app/factory/spree_cm_commissioner/order_telegram_message_factory.rb +88 -0
  8. data/app/finders/spree_cm_commissioner/accommodations/find.rb +6 -5
  9. data/app/helpers/spree_cm_commissioner/admin/homepage_segment_helper.rb +0 -2
  10. data/app/models/concerns/spree_cm_commissioner/homepage_section_bitwise.rb +1 -2
  11. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +1 -2
  12. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -10
  13. data/app/models/concerns/spree_cm_commissioner/product_type.rb +1 -1
  14. data/app/models/spree_cm_commissioner/pricing_action.rb +2 -2
  15. data/app/models/spree_cm_commissioner/pricing_actions/create_guest_adjustments.rb +34 -42
  16. data/app/models/spree_cm_commissioner/pricing_actions/create_line_item_adjustments.rb +17 -10
  17. data/app/models/spree_cm_commissioner/pricing_actions/create_route_adjustments.rb +38 -39
  18. data/app/models/spree_cm_commissioner/pricing_model.rb +13 -15
  19. data/app/models/spree_cm_commissioner/pricing_rule.rb +1 -1
  20. data/app/models/spree_cm_commissioner/pricing_rules/age_group.rb +9 -12
  21. data/app/models/spree_cm_commissioner/pricing_rules/extra_drop_off_distance.rb +2 -2
  22. data/app/models/spree_cm_commissioner/pricing_rules/extra_pick_up_distance.rb +2 -2
  23. data/app/models/spree_cm_commissioner/pricing_rules/nationality.rb +18 -19
  24. data/app/models/spree_cm_commissioner/pricing_rules/nationality_group.rb +7 -16
  25. data/app/models/spree_cm_commissioner/product_decorator.rb +0 -2
  26. data/app/models/spree_cm_commissioner/taxon_decorator.rb +0 -2
  27. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +1 -10
  28. data/app/models/spree_cm_commissioner/tenant.rb +0 -9
  29. data/app/models/spree_cm_commissioner/user_decorator.rb +0 -3
  30. data/app/models/spree_cm_commissioner/variant_options.rb +0 -4
  31. data/app/models/spree_cm_commissioner/vendor_decorator.rb +0 -4
  32. data/app/serializers/spree/v2/tenant/pricing_preview_serializer.rb +15 -0
  33. data/app/serializers/spree_cm_commissioner/v2/storefront/pricing_preview_serializer.rb +15 -0
  34. data/app/services/spree_cm_commissioner/checkout/update_decorator.rb +1 -1
  35. data/app/services/spree_cm_commissioner/pricing_models/activate.rb +41 -0
  36. data/app/services/spree_cm_commissioner/pricing_models/preview.rb +93 -0
  37. data/config/initializers/spree_permitted_attributes.rb +0 -3
  38. data/config/locales/en.yml +0 -8
  39. data/config/locales/km.yml +0 -2
  40. data/config/routes.rb +4 -17
  41. data/db/migrate/20260506090000_remove_default_from_cm_guests_nationality_group.rb +6 -0
  42. data/docs/tenant/test.com.md +88 -0
  43. data/lib/spree_cm_commissioner/pricing_models/guest_context.rb +81 -0
  44. data/lib/spree_cm_commissioner/pricing_models/line_item_context.rb +63 -0
  45. data/lib/spree_cm_commissioner/pricing_models/order_context.rb +61 -0
  46. data/lib/spree_cm_commissioner/pricing_models/preview_adjustment.rb +30 -0
  47. data/lib/spree_cm_commissioner/pricing_models/pricing_preview.rb +15 -0
  48. data/lib/spree_cm_commissioner/test_helper/factories/pricing_action_factory.rb +4 -0
  49. data/lib/spree_cm_commissioner/version.rb +1 -1
  50. data/lib/spree_cm_commissioner.rb +6 -7
  51. metadata +15 -81
  52. data/app/controllers/spree/api/v2/tenant/free_vote_claims_controller.rb +0 -37
  53. data/app/controllers/spree/api/v2/tenant/show_contestants_controller.rb +0 -50
  54. data/app/controllers/spree/api/v2/tenant/show_people_controller.rb +0 -49
  55. data/app/controllers/spree/api/v2/tenant/show_person_assignments_controller.rb +0 -36
  56. data/app/controllers/spree/api/v2/tenant/shows_controller.rb +0 -34
  57. data/app/controllers/spree/api/v2/tenant/votes_controller.rb +0 -94
  58. data/app/controllers/spree/api/v2/tenant/voting_contestants_controller.rb +0 -40
  59. data/app/controllers/spree/api/v2/tenant/voting_credit_transactions_controller.rb +0 -41
  60. data/app/controllers/spree/api/v2/tenant/voting_credits_controller.rb +0 -31
  61. data/app/jobs/spree_cm_commissioner/vote_fraud_event_job.rb +0 -9
  62. data/app/jobs/spree_cm_commissioner/voting_credit_allocation_job.rb +0 -10
  63. data/app/jobs/spree_cm_commissioner/voting_credit_de_allocation_job.rb +0 -10
  64. data/app/models/spree_cm_commissioner/maintenance_tasks/voting_session.rb +0 -19
  65. data/app/models/spree_cm_commissioner/pricing_model_handler/order.rb +0 -78
  66. data/app/models/spree_cm_commissioner/show.rb +0 -152
  67. data/app/models/spree_cm_commissioner/show_contestant.rb +0 -29
  68. data/app/models/spree_cm_commissioner/show_contestant_image.rb +0 -11
  69. data/app/models/spree_cm_commissioner/show_episode.rb +0 -98
  70. data/app/models/spree_cm_commissioner/show_person.rb +0 -15
  71. data/app/models/spree_cm_commissioner/show_person_assignment.rb +0 -20
  72. data/app/models/spree_cm_commissioner/show_person_image.rb +0 -11
  73. data/app/models/spree_cm_commissioner/vote.rb +0 -16
  74. data/app/models/spree_cm_commissioner/vote_fraud_event.rb +0 -19
  75. data/app/models/spree_cm_commissioner/voting_contestant.rb +0 -33
  76. data/app/models/spree_cm_commissioner/voting_credit.rb +0 -72
  77. data/app/models/spree_cm_commissioner/voting_credit_transaction.rb +0 -55
  78. data/app/models/spree_cm_commissioner/voting_session.rb +0 -153
  79. data/app/serializers/spree/v2/tenant/show_contestant_serializer.rb +0 -19
  80. data/app/serializers/spree/v2/tenant/show_episode_serializer.rb +0 -17
  81. data/app/serializers/spree/v2/tenant/show_person_assignment_serializer.rb +0 -15
  82. data/app/serializers/spree/v2/tenant/show_person_serializer.rb +0 -13
  83. data/app/serializers/spree/v2/tenant/show_serializer.rb +0 -26
  84. data/app/serializers/spree/v2/tenant/vote_serializer.rb +0 -14
  85. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +0 -17
  86. data/app/serializers/spree/v2/tenant/voting_credit_serializer.rb +0 -10
  87. data/app/serializers/spree/v2/tenant/voting_credit_transaction_serializer.rb +0 -14
  88. data/app/serializers/spree/v2/tenant/voting_session_serializer.rb +0 -14
  89. data/app/services/spree_cm_commissioner/fraud_check.rb +0 -275
  90. data/app/services/spree_cm_commissioner/vote_counters/audit_counters.rb +0 -35
  91. data/app/services/spree_cm_commissioner/vote_counters/base.rb +0 -31
  92. data/app/services/spree_cm_commissioner/vote_counters/increment.rb +0 -34
  93. data/app/services/spree_cm_commissioner/vote_counters/per_contestant_counter.rb +0 -25
  94. data/app/services/spree_cm_commissioner/vote_counters/rebuild_from_db.rb +0 -41
  95. data/app/services/spree_cm_commissioner/vote_credit_deductor.rb +0 -68
  96. data/app/services/spree_cm_commissioner/vote_package/create.rb +0 -155
  97. data/app/services/spree_cm_commissioner/vote_processor.rb +0 -133
  98. data/app/services/spree_cm_commissioner/voting_contestants/advancer.rb +0 -334
  99. data/app/services/spree_cm_commissioner/voting_contestants/assigner.rb +0 -32
  100. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +0 -96
  101. data/app/services/spree_cm_commissioner/voting_credits/allocate.rb +0 -77
  102. data/app/services/spree_cm_commissioner/voting_credits/claim_free_votes.rb +0 -119
  103. data/app/services/spree_cm_commissioner/voting_credits/credit_calculator.rb +0 -35
  104. data/app/services/spree_cm_commissioner/voting_credits/de_allocate.rb +0 -87
  105. data/db/migrate/20260309230148_create_cm_show_people.rb +0 -14
  106. data/db/migrate/20260309230149_create_cm_show_people_assignments.rb +0 -16
  107. data/db/migrate/20260310082711_create_cm_show_contestants.rb +0 -28
  108. data/db/migrate/20260310082720_create_cm_voting_sessions.rb +0 -21
  109. data/db/migrate/20260310082721_create_cm_voting_contestants.rb +0 -23
  110. data/db/migrate/20260310082734_add_voting_fields_to_spree_taxons.rb +0 -9
  111. data/db/migrate/20260310082735_add_type_to_spree_products.rb +0 -6
  112. data/db/migrate/20260310082749_create_cm_voting_credits.rb +0 -27
  113. data/db/migrate/20260326080200_create_cm_voting_credit_transactions.rb +0 -27
  114. data/db/migrate/20260330160000_create_cm_votes.rb +0 -25
  115. data/db/migrate/20260401072500_add_advanced_from_to_cm_voting_contestants.rb +0 -7
  116. data/db/migrate/20260402000001_add_voting_credit_scope_to_spree_taxons.rb +0 -6
  117. data/db/migrate/20260402000002_rename_scopeable_to_votable_in_cm_voting_credits.rb +0 -12
  118. data/db/migrate/20260403070000_add_name_to_cm_voting_sessions.rb +0 -5
  119. data/db/migrate/20260406000001_add_vendor_id_to_voting_tables.rb +0 -6
  120. data/db/migrate/20260406000001_rename_votes_remaining_to_amount_in_cm_voting_credits.rb +0 -11
  121. data/db/migrate/20260408085255_add_show_id_and_vendor_id_to_cm_voting_sessions.rb +0 -9
  122. data/db/migrate/20260420000001_rename_type_to_credit_type_in_cm_voting_credits.rb +0 -25
  123. data/db/migrate/20260422000001_create_cm_vote_fraud_events.rb +0 -23
  124. data/docs/sql/jsonb_query_guide.md +0 -57
  125. data/lib/spree_cm_commissioner/test_helper/factories/show_episode_factory.rb +0 -12
  126. data/lib/spree_cm_commissioner/test_helper/factories/show_factory.rb +0 -93
  127. data/lib/spree_cm_commissioner/test_helper/factories/vote_credit_factory.rb +0 -37
  128. data/lib/spree_cm_commissioner/test_helper/factories/vote_factory.rb +0 -28
  129. data/lib/spree_cm_commissioner/test_helper/factories/voting_credit_transaction_factory.rb +0 -11
  130. data/lib/spree_cm_commissioner/test_helper/factories/voting_session_factory.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 944d89b890c859cb1cee685f691f32bfb1f10afe8d5626b1fbf826209a9c3a9a
4
- data.tar.gz: 1fa1276dcdbb1a9a5d0d3fcb1e54e6f6188c517e19a684a3245e95ac500b3695
3
+ metadata.gz: f88085ac9f274a24587f64dca172c3219d84b76e02385419388bc84196bdbc2e
4
+ data.tar.gz: 3865b929388b20b69d3a641bbdf2695ae79055e5636c5fed7033bc297b511ff5
5
5
  SHA512:
6
- metadata.gz: 3263d20a3572a6b195466b3970cf853837c0ba4413d67f967400a4207e8ec68cfdd2268245a0d901f9cdccbae5948623887f47a1deb5093f51cee469b0cbffa0
7
- data.tar.gz: fa7d5472e9205a55ea3fd9e4f9057f508e4fdc7b6c5db1db8d4d1127f73c72b91979591230c31ea79947f0fe9f6db46b03b6edd5645778fae96926f520945a86
6
+ metadata.gz: ec9862ee95fb74dc2031f22534084dbbfe01c7fd5351a248014f5a8011a97fd990d0145b1536d697877face277480bdc837fa126e64b73a41039a55268072182
7
+ data.tar.gz: 4b84c53d6a14a05702b5eaa78a76b1eb6f80471f15b4cc95bee9fef3772f00abe49f40c9c9d0cd78ec7761d5aa012c1d4546931a121e7e8ae2e264e7788e5bb2
data/.gitignore CHANGED
@@ -34,7 +34,3 @@ vendor/bundle/
34
34
  # Cursor
35
35
  .cursor
36
36
  dump.rdb
37
- # Added by code-review-graph
38
- .code-review-graph/
39
- .cursorrules
40
- .claude
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.7.1.pre.pre4)
37
+ spree_cm_commissioner (2.7.1.pre.pre6)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -0,0 +1,39 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ class PricingPreviewsController < ::Spree::Api::V2::BaseController
6
+ # GET /api/v2/tenant/pricing_previews
7
+ def index
8
+ permitted_preview_params = params.permit(SpreeCmCommissioner::PricingModels::OrderContext::PREVIEW_PERMITTED_PARAMS)
9
+ order_context = SpreeCmCommissioner::PricingModels::OrderContext.load!(permitted_preview_params[:order_context])
10
+ pricing_models_updated_at = SpreeCmCommissioner::PricingModel.joins(:vendor)
11
+ .where(spree_vendors: { tenant_id: nil })
12
+ .maximum(:updated_at)
13
+ cache_key = 'pricing:preview:v2:' \
14
+ "#{Digest::SHA256.hexdigest(permitted_preview_params.to_json)}:" \
15
+ "#{pricing_models_updated_at.to_i}"
16
+
17
+ result = Rails.cache.fetch(cache_key, expires_in: 60.seconds) do
18
+ SpreeCmCommissioner::PricingModels::Preview.call(order_context: order_context)
19
+ end
20
+
21
+ if result.success?
22
+ render_serialized_payload { serialize_resource(result.value[:pricing_preview]) }
23
+ else
24
+ render_error_payload(result.error, 422)
25
+ end
26
+ rescue ArgumentError => e
27
+ render_error_payload(e.message, 422)
28
+ end
29
+
30
+ private
31
+
32
+ def resource_serializer
33
+ SpreeCmCommissioner::V2::Storefront::PricingPreviewSerializer
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -16,10 +16,6 @@ module Spree
16
16
  set_current_tenant(@tenant)
17
17
  end
18
18
 
19
- def current_vendor
20
- @current_vendor ||= @tenant.active_vendor
21
- end
22
-
23
19
  def render_serialized_payload(status = 200)
24
20
  render json: yield, status: status, content_type: content_type
25
21
  end
@@ -0,0 +1,39 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Tenant
5
+ class PricingPreviewsController < BaseController
6
+ # GET /api/v2/tenant/pricing_previews
7
+ def index
8
+ permitted_preview_params = params.permit(SpreeCmCommissioner::PricingModels::OrderContext::PREVIEW_PERMITTED_PARAMS)
9
+ order_context = SpreeCmCommissioner::PricingModels::OrderContext.load!(permitted_preview_params[:order_context])
10
+ pricing_models_updated_at = SpreeCmCommissioner::PricingModel.joins(:vendor)
11
+ .where(spree_vendors: { tenant_id: current_tenant.id })
12
+ .maximum(:updated_at)
13
+ cache_key = 'pricing:preview:v2:' \
14
+ "#{Digest::SHA256.hexdigest(permitted_preview_params.to_json)}:" \
15
+ "#{pricing_models_updated_at.to_i}"
16
+
17
+ result = Rails.cache.fetch(cache_key, expires_in: 60.seconds) do
18
+ SpreeCmCommissioner::PricingModels::Preview.call(order_context: order_context)
19
+ end
20
+
21
+ if result.success?
22
+ render_serialized_payload { serialize_resource(result.value[:pricing_preview]) }
23
+ else
24
+ render_error_payload(result.error, 422)
25
+ end
26
+ rescue ArgumentError => e
27
+ render_error_payload(e.message, 422)
28
+ end
29
+
30
+ private
31
+
32
+ def resource_serializer
33
+ Spree::V2::Tenant::PricingPreviewSerializer
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -48,6 +48,8 @@ module SpreeCmCommissioner
48
48
  end
49
49
 
50
50
  def line_item_content(line_item)
51
+ return intercity_taxi_line_item_content(line_item) if intercity_taxi?(line_item)
52
+
51
53
  text = []
52
54
 
53
55
  text << bold(line_item.product.name.to_s)
@@ -82,6 +84,8 @@ module SpreeCmCommissioner
82
84
  text << "Email: #{inline_code(order.email)}" if order.email.present?
83
85
  text << "Delivery Address: #{formatted_shipping_address.presence || 'N/A'}" if order.delivery_required?
84
86
 
87
+ append_intercity_taxi_footer(text) if intercity_taxi_order?
88
+
85
89
  if show_details_link && order.guests.any?
86
90
  text << ''
87
91
  text << 'View Tickets:'
@@ -125,5 +129,89 @@ module SpreeCmCommissioner
125
129
 
126
130
  formatted_rows
127
131
  end
132
+
133
+ private
134
+
135
+ def intercity_taxi?(line_item)
136
+ trip_for(line_item)&.intercity_taxi?
137
+ end
138
+
139
+ def intercity_taxi_order?
140
+ selected_line_items.any? { |li| intercity_taxi?(li) }
141
+ end
142
+
143
+ def trip_for(line_item)
144
+ return nil unless line_item.respond_to?(:trip_id) && line_item.trip_id.present?
145
+
146
+ @trip_cache ||= {}
147
+ @trip_cache[line_item.trip_id] ||= SpreeCmCommissioner::Trip.find_by(id: line_item.trip_id)
148
+ end
149
+
150
+ def intercity_taxi_line_item_content(line_item)
151
+ text = []
152
+ route_text = taxi_route_text(line_item)
153
+ departure_text = taxi_departure_text(line_item)
154
+ text << bold('🚗 Trip Details')
155
+ text << "Route: #{route_text}" if route_text.present?
156
+ text << "Passengers: #{line_item.passenger_count || line_item.quantity}"
157
+ text << "Departure: #{departure_text}" if departure_text.present?
158
+
159
+ text.compact.join("\n")
160
+ end
161
+
162
+ def taxi_route_text(line_item)
163
+ trip = trip_for(line_item)
164
+ return line_item.product.name if trip.blank?
165
+
166
+ origin = trip.origin_place&.name
167
+ destination = trip.destination_place&.name
168
+ vehicle = trip.vehicle_type&.name
169
+
170
+ parts = [origin, destination].compact_blank.join(' → ')
171
+ vehicle.present? ? "#{parts} (#{vehicle})" : parts
172
+ end
173
+
174
+ def taxi_departure_text(line_item)
175
+ return nil unless line_item.date_present?
176
+
177
+ line_item.from_date.strftime('%b %d, %Y · %H:%M')
178
+ end
179
+
180
+ def nationality_text
181
+ values = order.saved_guests.map { |sg| sg.nationality&.name.presence || sg.nationality_group&.humanize }.compact.uniq
182
+ return nil if values.empty?
183
+
184
+ values.join(', ')
185
+ end
186
+
187
+ def append_intercity_taxi_footer(text)
188
+ text << "Nationality: #{nationality_text}" if nationality_text.present?
189
+
190
+ pickup = selected_line_items.filter_map(&:pickup_map_place).first
191
+ dropoff = selected_line_items.filter_map(&:dropoff_map_place).first
192
+
193
+ append_map_place(text, '📍 Pick-up Location', pickup) if pickup
194
+ append_map_place(text, '📍 Drop-off Location', dropoff) if dropoff
195
+
196
+ remark = selected_line_items.filter_map { |li| li.remark.presence }.first
197
+ return if remark.blank?
198
+
199
+ text << ''
200
+ text << bold('🗒️ Notes to Driver')
201
+ text << ERB::Util.html_escape(remark)
202
+ end
203
+
204
+ def append_map_place(text, title, map_place)
205
+ text << ''
206
+ text << bold(title)
207
+ text << "Address: #{ERB::Util.html_escape(map_place.place_name)}" if map_place.place_name.present?
208
+ text << "Google Maps: #{ERB::Util.html_escape(google_maps_link(map_place))}" if google_maps_link(map_place).present?
209
+ end
210
+
211
+ def google_maps_link(map_place)
212
+ return nil if map_place.lat.blank? || map_place.lng.blank?
213
+
214
+ "https://www.google.com/maps/search/?api=1&query=#{map_place.lat},#{map_place.lng}"
215
+ end
128
216
  end
129
217
  end
@@ -13,11 +13,11 @@ module SpreeCmCommissioner
13
13
  def execute
14
14
  scope
15
15
  .where(default_state_id: state_id)
16
- .where(inventory_items: { inventory_date: stay_dates })
17
- .where('CAST(spree_variants.public_metadata->\'cm_options\'->>\'number-of-adults\' AS INTEGER) +
18
- CAST(spree_variants.public_metadata->\'cm_options\'->>\'number-of-kids\' AS INTEGER) >= ?', number_of_guests
16
+ .where('spree_variants.track_inventory = FALSE OR cm_inventory_items.inventory_date BETWEEN ? AND ?', from_date, to_date)
17
+ .where('spree_variants.track_inventory = FALSE OR cm_inventory_items.quantity_available > 0')
18
+ .where('COALESCE(CAST(spree_variants.public_metadata->\'cm_options\'->>\'number-of-adults\' AS INTEGER), 0) +
19
+ COALESCE(CAST(spree_variants.public_metadata->\'cm_options\'->>\'number-of-kids\' AS INTEGER), 0) >= ?', number_of_guests
19
20
  )
20
- .where('inventory_items.quantity_available > 0')
21
21
  .distinct
22
22
  end
23
23
 
@@ -25,7 +25,8 @@ module SpreeCmCommissioner
25
25
 
26
26
  def scope
27
27
  Spree::Vendor
28
- .joins(variants: :inventory_items)
28
+ .joins(products: :variants)
29
+ .joins('LEFT OUTER JOIN cm_inventory_items ON cm_inventory_items.variant_id = spree_variants.id')
29
30
  .where(primary_product_type: :accommodation, state: :active)
30
31
  end
31
32
 
@@ -15,8 +15,6 @@ module SpreeCmCommissioner
15
15
  'badge badge-success text-uppercase'
16
16
  when :football
17
17
  'badge badge-dark text-uppercase'
18
- when :show
19
- 'badge badge-danger text-uppercase'
20
18
  else
21
19
  'badge'
22
20
  end
@@ -8,8 +8,7 @@ module SpreeCmCommissioner
8
8
  tour: 0b00100,
9
9
  accommodation: 0b01000,
10
10
  things_to_do: 0b10000,
11
- football: 0b100000,
12
- show: 0b1000000
11
+ football: 0b100000
13
12
  }.freeze
14
13
 
15
14
  BIT_SEGMENT.each do |segment, bit_value|
@@ -45,8 +45,7 @@ module SpreeCmCommissioner
45
45
  'color' => 'color',
46
46
  'ticket-type' => 'string',
47
47
  'seat-type' => 'string',
48
- 'intercity-taxi' => 'string',
49
- 'vote-package' => 'integer'
48
+ 'intercity-taxi' => 'string'
50
49
  }.freeze
51
50
 
52
51
  included do
@@ -26,10 +26,8 @@ module SpreeCmCommissioner
26
26
 
27
27
  state_machine.after_transition to: :canceled, do: :precalculate_conversion
28
28
  state_machine.after_transition to: :canceled, do: :restock_inventory!
29
- state_machine.after_transition to: :canceled, do: :de_allocate_resources
30
29
 
31
30
  state_machine.after_transition to: :complete, do: :increment_route_fulfilled_order_count
32
- state_machine.after_transition to: :complete, do: :allocate_resources
33
31
 
34
32
  scope :accepted, -> { where(request_state: 'accepted') }
35
33
 
@@ -330,13 +328,5 @@ module SpreeCmCommissioner
330
328
  factory = OrderTelegramMessageFactory.new(title: title, order: self)
331
329
  TelegramNotificationSenderJob.perform_later(chat_id: chat_id, message: factory.message, parse_mode: factory.parse_mode)
332
330
  end
333
-
334
- def allocate_resources
335
- SpreeCmCommissioner::VotingCreditAllocationJob.perform_later(order_id: id)
336
- end
337
-
338
- def de_allocate_resources
339
- SpreeCmCommissioner::VotingCreditDeAllocationJob.perform_later(order_id: id)
340
- end
341
331
  end
342
332
  end
@@ -5,7 +5,7 @@ module SpreeCmCommissioner
5
5
  module ProductType
6
6
  extend ActiveSupport::Concern
7
7
 
8
- PRODUCT_TYPES = %i[accommodation service ecommerce transit show_episode vote_package].freeze
8
+ PRODUCT_TYPES = %i[accommodation service ecommerce transit].freeze
9
9
  PERMANENT_STOCK_PRODUCT_TYPES = %w[accommodation service transit].freeze
10
10
  PRE_INVENTORY_DAYS = { 'transit' => 90, 'accommodation' => 365, 'service' => 30 }.freeze
11
11
 
@@ -9,8 +9,8 @@ module SpreeCmCommissioner
9
9
 
10
10
  delegate :pricing_rules, to: :pricing_rule_group
11
11
 
12
- def perform(_options = {})
13
- raise NotImplementedError, "#{self.class}#perform must be implemented"
12
+ def preview(_options = {})
13
+ raise NotImplementedError, "#{self.class}#preview must be implemented"
14
14
  end
15
15
 
16
16
  def compute_amount(adjustable)
@@ -1,68 +1,60 @@
1
1
  module SpreeCmCommissioner
2
2
  module PricingActions
3
3
  class CreateGuestAdjustments < SpreeCmCommissioner::PricingAction
4
- def perform(options = {})
5
- line_items = extract_line_items(options)
4
+ def preview(options = {})
5
+ line_item_contexts = Array(options[:line_item_contexts])
6
6
 
7
- return if pricing_rule_group.pricing_rules.blank?
8
- return if line_items.blank?
7
+ return [] if pricing_rule_group.pricing_rules.blank?
8
+ return [] if line_item_contexts.blank?
9
9
 
10
- line_items.each do |line_item|
11
- perform_for_line_item(line_item)
10
+ line_item_contexts.filter_map do |line_item_context|
11
+ preview_for_line_item_context(line_item_context)
12
12
  end
13
13
  end
14
14
 
15
15
  private
16
16
 
17
- def extract_line_items(options)
18
- return [options] if options.respond_to?(:guests)
17
+ def preview_for_line_item_context(line_item_context)
18
+ return nil if line_item_context.guest_contexts.blank?
19
19
 
20
- Array(options[:line_items])
20
+ eligible_guest_contexts = find_eligible_guest_contexts(line_item_context)
21
+ return nil if eligible_guest_contexts.empty?
22
+
23
+ total = eligible_guest_contexts.sum do |guest_context|
24
+ compute_guest_amount(line_item_context, guest_context)
25
+ end
26
+
27
+ return nil if total.zero?
28
+
29
+ PricingModels::PreviewAdjustment.new(
30
+ label: label,
31
+ amount: total,
32
+ action_type: 'create_guest_adjustments',
33
+ pricing_action: self,
34
+ adjustable_type: 'Spree::LineItem',
35
+ adjustable_id: line_item_context.id,
36
+ line_item_id: line_item_context.id,
37
+ guest_ids: eligible_guest_contexts.map(&:id).compact
38
+ )
21
39
  end
22
40
 
23
- def find_eligible_guests(line_item)
24
- line_item.guests.select do |guest|
25
- guest_eligible_for_all_rules?(guest)
41
+ def find_eligible_guest_contexts(line_item_context)
42
+ line_item_context.guest_contexts.select do |guest_context|
43
+ guest_context_eligible_for_all_rules?(guest_context, line_item_context)
26
44
  end
27
45
  end
28
46
 
29
- def guest_eligible_for_all_rules?(guest)
47
+ def guest_context_eligible_for_all_rules?(guest_context, line_item_context)
30
48
  pricing_rule_group.pricing_rules.all? do |rule|
31
- rule.respond_to?(:guest_eligible?) && rule.guest_eligible?(guest)
49
+ rule.respond_to?(:guest_eligible?) && rule.guest_eligible?(guest_context, line_item_context)
32
50
  end
33
51
  end
34
52
 
35
- def compute_guest_amount(line_item, _guest)
53
+ def compute_guest_amount(line_item_context, _guest_context)
36
54
  per_guest_item = Struct.new(:amount, :currency, :quantity)
37
- .new(line_item.amount_per_guest, line_item.currency, 1)
55
+ .new(line_item_context.price, line_item_context.currency, 1)
38
56
  calculator&.compute(per_guest_item) || 0
39
57
  end
40
-
41
- def create_adjustment(line_item, amount)
42
- line_item.adjustments.create!(
43
- amount: amount,
44
- source: self,
45
- adjustable: line_item,
46
- order: line_item.order,
47
- label: pricing_rule_group.pricing_model.name,
48
- mandatory: true
49
- )
50
- end
51
-
52
- def perform_for_line_item(line_item)
53
- return if line_item.guests.blank?
54
-
55
- eligible_guests = find_eligible_guests(line_item)
56
- return if eligible_guests.empty?
57
-
58
- total_amount = eligible_guests.sum do |guest|
59
- compute_guest_amount(line_item, guest)
60
- end
61
-
62
- return if total_amount.zero?
63
-
64
- create_adjustment(line_item, total_amount)
65
- end
66
58
  end
67
59
  end
68
60
  end
@@ -1,19 +1,26 @@
1
1
  module SpreeCmCommissioner
2
2
  module PricingActions
3
3
  class CreateLineItemAdjustments < SpreeCmCommissioner::PricingAction
4
- def perform(options = {})
5
- order = options[:order]
6
- line_items = options[:line_items] || []
4
+ def preview(options = {})
5
+ line_item_contexts = Array(options[:line_item_contexts])
7
6
 
8
- return if line_items.blank?
7
+ return [] if line_item_contexts.blank?
9
8
 
10
- line_items.each do |line_item|
11
- create_unique_adjustment(order, line_item)
12
- end
13
- end
9
+ line_item_contexts.filter_map do |line_item_context|
10
+ amount = compute_amount(line_item_context)
11
+ next nil if amount.zero?
14
12
 
15
- def compute_amount(line_item)
16
- compute(line_item)
13
+ PricingModels::PreviewAdjustment.new(
14
+ label: label,
15
+ amount: amount,
16
+ action_type: 'create_line_item_adjustments',
17
+ pricing_action: self,
18
+ adjustable_type: 'Spree::LineItem',
19
+ adjustable_id: line_item_context.id,
20
+ line_item_id: line_item_context.id,
21
+ guest_ids: []
22
+ )
23
+ end
17
24
  end
18
25
  end
19
26
  end
@@ -1,69 +1,68 @@
1
1
  module SpreeCmCommissioner
2
2
  module PricingActions
3
3
  class CreateRouteAdjustments < SpreeCmCommissioner::PricingAction
4
- def perform(options = {})
5
- order = options[:order]
6
- line_items = options[:line_items] || []
4
+ def preview(options = {})
5
+ order_context = options[:order_context]
6
+ line_item_contexts = Array(options[:line_item_contexts])
7
7
 
8
- return if pricing_rules.blank?
9
- return if line_items.blank?
8
+ return [] if pricing_rules.blank?
9
+ return [] if line_item_contexts.blank?
10
10
 
11
- eligible_guests = collect_unique_eligible_guests(line_items)
12
- return if eligible_guests.empty?
11
+ eligible_guest_contexts = collect_unique_eligible_guest_contexts(line_item_contexts)
12
+ return [] if eligible_guest_contexts.empty?
13
13
 
14
- total_amount = compute_total_amount(order, eligible_guests)
15
- return if total_amount.zero?
14
+ total_amount = compute_total_amount(line_item_contexts, eligible_guest_contexts)
15
+ return [] if total_amount.zero?
16
16
 
17
- create_route_adjustment(order, total_amount)
17
+ [
18
+ PricingModels::PreviewAdjustment.new(
19
+ label: label,
20
+ amount: total_amount,
21
+ action_type: 'create_route_adjustments',
22
+ pricing_action: self,
23
+ adjustable_type: 'Spree::Order',
24
+ adjustable_id: order_context.id,
25
+ line_item_id: nil,
26
+ guest_ids: eligible_guest_contexts.map(&:id).compact
27
+ )
28
+ ]
18
29
  end
19
30
 
20
31
  private
21
32
 
22
- def collect_unique_eligible_guests(line_items)
33
+ def collect_unique_eligible_guest_contexts(line_item_contexts)
23
34
  seen = {}
24
35
 
25
- line_items.each_with_object([]) do |line_item, result|
26
- line_item.guests.select { |guest| guest_eligible?(guest) }.each_with_index do |guest, index|
27
- key = guest.saved_guest_id.present? ? [guest.saved_guest_id, index] : guest.id
36
+ line_item_contexts.each_with_object([]) do |line_item_context, result|
37
+ line_item_context.guest_contexts.select { |gc| guest_context_eligible?(gc, line_item_context) }.each_with_index do |guest_context, index|
38
+ key = guest_context.saved_guest_id.present? ? [guest_context.saved_guest_id, index] : guest_context.id
28
39
  next if seen[key]
29
40
 
30
41
  seen[key] = true
31
- result << guest
42
+ result << guest_context
32
43
  end
33
44
  end
34
45
  end
35
46
 
36
- def guest_eligible?(guest)
47
+ def guest_context_eligible?(guest_context, line_item_context)
37
48
  pricing_rules.all? do |rule|
38
- !rule.respond_to?(:guest_eligible?) || rule.guest_eligible?(guest)
49
+ !rule.respond_to?(:guest_eligible?) || rule.guest_eligible?(guest_context, line_item_context)
39
50
  end
40
51
  end
41
52
 
42
- def compute_total_amount(order, guests)
43
- guests.sum { |guest| compute_per_guest_amount(order, guest) }
44
- end
45
-
46
- def compute_per_guest_amount(order, guest)
47
- item = build_per_guest_item(order, guest)
48
- compute_amount(item)
53
+ def compute_total_amount(line_item_contexts, eligible_guest_contexts)
54
+ eligible_guest_contexts.sum do |guest_context|
55
+ line_item_context = line_item_contexts.find { |l| l.id == guest_context.line_item_id }
56
+ compute_per_guest_amount(line_item_context, guest_context)
57
+ end
49
58
  end
50
59
 
51
- def build_per_guest_item(order, guest)
52
- Struct.new(:amount, :currency, :quantity).new(
53
- guest.line_item.amount_per_guest,
54
- order_currency(order),
55
- 1
56
- )
57
- end
60
+ def compute_per_guest_amount(line_item_context, _guest_context)
61
+ return 0 if line_item_context.nil?
58
62
 
59
- def create_route_adjustment(order, amount)
60
- adjustments.create!(
61
- adjustable: order,
62
- amount: amount,
63
- order: order,
64
- label: label,
65
- mandatory: true
66
- )
63
+ item = Struct.new(:amount, :currency, :quantity)
64
+ .new(line_item_context.price, line_item_context.currency, 1)
65
+ compute_amount(item)
67
66
  end
68
67
  end
69
68
  end
@@ -17,30 +17,28 @@ module SpreeCmCommissioner
17
17
 
18
18
  enum status: { draft: 0, active: 1, archived: 2 }
19
19
 
20
- # Activates pricing model for an order (similar to Spree::Promotion#activate)
21
- def activate(order:, line_items:)
22
- pricing_rule_groups.select(&:active?).each do |group|
23
- activate_group(group, order, line_items)
20
+ def preview(order_context:, line_item_contexts:)
21
+ eligible_groups(line_item_contexts).flat_map do |group|
22
+ group.pricing_action&.preview(
23
+ order_context: order_context,
24
+ line_item_contexts: line_item_contexts
25
+ ) || []
24
26
  end
25
27
  end
26
28
 
27
29
  private
28
30
 
29
- def activate_group(group, order, line_items)
30
- eligible_rules = group.pricing_rules.select { |r| any_line_item_eligible?(r, line_items) }
31
+ def eligible_groups(line_item_contexts)
32
+ pricing_rule_groups.select(&:active?).select do |group|
33
+ eligible_rules = group.pricing_rules.select { |r| any_line_item_context_eligible?(r, line_item_contexts) }
34
+ next false if eligible_rules.empty?
31
35
 
32
- return if eligible_rules.empty?
33
-
34
- if group_eligible?(group, eligible_rules)
35
-
36
- group.pricing_action&.perform(order: order, line_items: line_items)
37
- else
38
- Rails.logger.info("PricingRuleGroup #{group.id} not eligible for order #{order.id}")
36
+ group_eligible?(group, eligible_rules)
39
37
  end
40
38
  end
41
39
 
42
- def any_line_item_eligible?(rule, line_items)
43
- line_items.any? { |li| rule.eligible?(li) }
40
+ def any_line_item_context_eligible?(rule, line_item_contexts)
41
+ line_item_contexts.any? { |line_item_context| rule.eligible?(line_item_context) }
44
42
  end
45
43
 
46
44
  def group_eligible?(group, eligible_rules)
@@ -8,7 +8,7 @@ module SpreeCmCommissioner
8
8
  raise 'eligible? should be implemented in a sub-class of SpreeCmCommissioner::PricingRule'
9
9
  end
10
10
 
11
- def guest_eligible?(_guest)
11
+ def guest_eligible?(_guest_context, _line_item_context)
12
12
  raise 'guest_eligible? should be implemented in a sub-class of SpreeCmCommissioner::PricingRule'
13
13
  end
14
14