spree_cm_commissioner 1.10.0.pre.pre1 → 1.10.0

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_and_build_gem.yml +0 -2
  3. data/.gitignore +1 -2
  4. data/Gemfile.lock +1 -22
  5. data/app/controllers/spree/admin/stock_managements_controller.rb +1 -17
  6. data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +31 -14
  7. data/app/interactors/spree_cm_commissioner/vattanac_bank_initiator.rb +6 -25
  8. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +3 -2
  9. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -26
  10. data/app/models/concerns/spree_cm_commissioner/product_type.rb +0 -10
  11. data/app/models/spree_cm_commissioner/line_item_decorator.rb +0 -1
  12. data/app/models/spree_cm_commissioner/order_decorator.rb +0 -15
  13. data/app/models/spree_cm_commissioner/product_decorator.rb +0 -1
  14. data/app/models/spree_cm_commissioner/stock/availability_checker.rb +25 -27
  15. data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +1 -2
  16. data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
  17. data/app/models/spree_cm_commissioner/trip_connection.rb +1 -0
  18. data/app/models/spree_cm_commissioner/trip_stop.rb +2 -2
  19. data/app/models/spree_cm_commissioner/variant_decorator.rb +20 -24
  20. data/app/models/spree_cm_commissioner/variant_options.rb +0 -14
  21. data/app/queries/spree_cm_commissioner/trip_query.rb +11 -11
  22. data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +45 -0
  23. data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +55 -0
  24. data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +0 -3
  25. data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
  26. data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +0 -2
  27. data/app/services/spree_cm_commissioner/aes_encryption_service.rb +4 -6
  28. data/app/views/spree/admin/stock_managements/index.html.erb +5 -31
  29. data/config/routes.rb +2 -11
  30. data/docker-compose.yml +1 -1
  31. data/lib/generators/spree_cm_commissioner/install/install_generator.rb +2 -2
  32. data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_dashboard/spree_cm_commissioner → spree_cm_commissioner}/utilities.js +0 -4
  33. data/lib/spree_cm_commissioner/calendar_event.rb +1 -11
  34. data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +6 -28
  35. data/lib/spree_cm_commissioner/version.rb +1 -1
  36. data/lib/spree_cm_commissioner.rb +0 -34
  37. data/spree_cm_commissioner.gemspec +0 -5
  38. metadata +7 -71
  39. data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +0 -42
  40. data/app/finders/spree_cm_commissioner/accommodations/find.rb +0 -40
  41. data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +0 -35
  42. data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +0 -25
  43. data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +0 -71
  44. data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +0 -7
  45. data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +0 -9
  46. data/app/models/spree_cm_commissioner/inventory.rb +0 -11
  47. data/app/models/spree_cm_commissioner/inventory_item.rb +0 -37
  48. data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +0 -40
  49. data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +0 -114
  50. data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +0 -42
  51. data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +0 -27
  52. data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +0 -44
  53. data/app/models/spree_cm_commissioner/stock_movement_decorator.rb +0 -34
  54. data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +0 -19
  55. data/app/views/spree/admin/stock_managements/_events_popover.html.erb +0 -17
  56. data/app/views/spree/admin/stock_managements/calendar.html.erb +0 -32
  57. data/db/migrate/20250304293518_create_cm_inventory_items.rb +0 -21
  58. data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +0 -5
  59. data/lib/spree_cm_commissioner/cached_inventory_item.rb +0 -23
  60. data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +0 -9
  61. data/lib/tasks/create_default_non_permanent_inventory_items.rake +0 -16
  62. data/lib/tasks/generate_inventory_items.rake +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e91babac12da4e1fc7e8083b3cb07936fd5a7b7af45217ef38b2a47fc3bed9ca
4
- data.tar.gz: b5831b6964e0ea47ac4a6c7c2355330c9ed8386c160ec482ab8201100321a0cf
3
+ metadata.gz: 634d4cd6a4373be586e59598dab82c2440eb292abe53abeeb1161e6bfca85da2
4
+ data.tar.gz: 3e0e4f5293ce46f30d227269baf174b7b8b3a32ac269a30b733f3e7ea1065aca
5
5
  SHA512:
6
- metadata.gz: 8f229d110a73433c448dece4554dfc99f60e0b9208e5260282b7b48c2f2869a9431700b8f418ba0ed0f00a6369924acf370506dc22234d678c157a4984b6d49d
7
- data.tar.gz: b0913cc8c5bfc42042bd78bc23a3e13050b7cd39e9cbf315ae6f0f99dad38ce3984c1f042d34b95d29688c51ce9c9f67b38c450a857063659f395c297233bb3f
6
+ metadata.gz: 7830251cadb15def91fb9d7bc6c6c68dacb3af529d941f6c1d17364f3dd621c2e3539bf24d7d870d0b82e88f2309d78ab895de19219144192dd8924f1a1943b1
7
+ data.tar.gz: 64bbba3e3a8227f1788748ac27ee108d8f3ad93d89829336f53817556eb6a7e67fd4c43263ce6aa57e087df046139db1c9a665f57411634e1648d8dbd55b9f33
@@ -133,14 +133,12 @@ jobs:
133
133
  bundle install --jobs 4 --retry 3
134
134
 
135
135
  - name: Quality
136
- if: github.event_name == 'pull_request'
137
136
  env:
138
137
  DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
139
138
  run: |
140
139
  bundle exec rubocop
141
140
 
142
141
  - name: Security
143
- if: github.event_name == 'pull_request'
144
142
  env:
145
143
  DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
146
144
  run: |
data/.gitignore CHANGED
@@ -28,5 +28,4 @@ node_modules
28
28
  # VScode
29
29
  .vscode
30
30
  !.vscode/.settings.json
31
- .env
32
- vendor/bundle/
31
+ .env
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (1.10.0.pre.pre1)
37
+ spree_cm_commissioner (1.10.0)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -42,7 +42,6 @@ PATH
42
42
  aws-sdk-s3
43
43
  blazer (~> 3.0.4)
44
44
  byebug
45
- connection_pool
46
45
  counter_culture (~> 3.2)
47
46
  dry-validation (~> 1.10)
48
47
  elasticsearch (~> 8.5)
@@ -58,8 +57,6 @@ PATH
58
57
  phonelib
59
58
  premailer-rails
60
59
  rails (~> 7.0.4)
61
- redis
62
- redis-rails
63
60
  rqrcode (~> 2.0)
64
61
  searchkick (~> 5.1)
65
62
  simple_calendar (~> 2.4)
@@ -620,8 +617,6 @@ GEM
620
617
  activesupport (>= 2.3.14)
621
618
  racc (1.7.1)
622
619
  rack (2.2.8)
623
- rack-session (1.0.2)
624
- rack (< 3)
625
620
  rack-test (2.1.0)
626
621
  rack (>= 1.3)
627
622
  rails (7.0.8)
@@ -665,24 +660,8 @@ GEM
665
660
  rbtree (0.4.6)
666
661
  redis (5.0.7)
667
662
  redis-client (>= 0.9.0)
668
- redis-actionpack (5.5.0)
669
- actionpack (>= 5)
670
- redis-rack (>= 2.1.0, < 4)
671
- redis-store (>= 1.1.0, < 2)
672
- redis-activesupport (5.3.0)
673
- activesupport (>= 3, < 8)
674
- redis-store (>= 1.3, < 2)
675
663
  redis-client (0.17.0)
676
664
  connection_pool
677
- redis-rack (3.0.0)
678
- rack-session (>= 0.2.0)
679
- redis-store (>= 1.2, < 2)
680
- redis-rails (5.0.2)
681
- redis-actionpack (>= 5.0, < 6)
682
- redis-activesupport (>= 5.0, < 6)
683
- redis-store (>= 1.2, < 2)
684
- redis-store (1.11.0)
685
- redis (>= 4, < 6)
686
665
  regexp_parser (2.8.2)
687
666
  representable (3.2.0)
688
667
  declarative (< 0.1.0)
@@ -12,25 +12,9 @@ module Spree
12
12
  def index
13
13
  @variants = @product.variants.includes(:images, stock_items: :stock_location, option_values: :option_type)
14
14
  @variants = [@product.master] if @variants.empty?
15
- @stock_locations = (@variants.flat_map(&:stock_locations) + @product.vendor.stock_locations).uniq
16
-
17
- load_inventories unless @product.permanent_stock?
18
- end
19
-
20
- def calendar
21
- @year = params[:year].present? ? params[:year].to_i : Time.zone.today.year
22
15
 
23
- from_date = Date.new(@year, 1, 1).beginning_of_year
24
- to_date = Date.new(@year, 1, 1).end_of_year
25
-
26
- @inventory_items = @product.inventory_items.includes(:variant).where(inventory_date: from_date..to_date).to_a
27
- @events = SpreeCmCommissioner::CalendarEvent.from_inventory_items(@inventory_items)
28
- end
29
-
30
- private
16
+ @stock_locations = (@variants.flat_map(&:stock_locations) + @product.vendor.stock_locations).uniq
31
17
 
32
- def load_inventories
33
- @inventory_items = @product.inventory_items.group_by { |item| item.variant.id }
34
18
  @reserved_stocks = Spree::LineItem
35
19
  .complete
36
20
  .where(variant_id: @variants.pluck(:id))
@@ -5,38 +5,55 @@ module Spree
5
5
  class AccommodationsController < ::Spree::Api::V2::ResourceController
6
6
  private
7
7
 
8
- # override
9
8
  def collection
10
- @collection ||= SpreeCmCommissioner::Accommodations::Find.new(
11
- from_date: params[:from_date]&.to_date,
12
- to_date: params[:to_date]&.to_date,
13
- state_id: params[:state_id],
14
- number_of_adults: params[:number_of_adults].to_i,
15
- number_of_kids: params[:number_of_kids].to_i
16
- ).execute
9
+ @collection ||= collection_finder.call(params: params).value
10
+ end
11
+
12
+ def paginated_collection
13
+ return @paginated_collection if defined?(@paginated_collection)
14
+
15
+ @paginated_collection = super
16
+ @paginated_collection = apply_service_availability(@paginated_collection)
17
17
  end
18
18
 
19
- # override
20
19
  def resource
21
- @resource ||= collection.find(params[:id])
20
+ resource = resource_finder.call(params: params).value
21
+ raise ActiveRecord::RecordNotFound if resource.nil?
22
+
23
+ apply_service_availability(resource)
24
+ end
25
+
26
+ def apply_service_availability(resource)
27
+ SpreeCmCommissioner::ApplyServiceAvailability.call(calendarable: resource,
28
+ from_date: params[:from_date].to_date,
29
+ to_date: params[:to_date].to_date
30
+ ).value
22
31
  end
23
32
 
24
- # override
25
33
  def allowed_sort_attributes
26
34
  super << :min_price << :max_price
27
35
  end
28
36
 
29
- # override
37
+ def model_class
38
+ Spree::Vendor
39
+ end
40
+
30
41
  def resource_serializer
31
42
  Spree::V2::Storefront::AccommodationSerializer
32
43
  end
33
44
 
34
- # override
35
45
  def collection_serializer
36
46
  Spree::V2::Storefront::AccommodationSerializer
37
47
  end
38
48
 
39
- # override
49
+ def collection_finder
50
+ SpreeCmCommissioner::AccommodationSearchDetail
51
+ end
52
+
53
+ def resource_finder
54
+ SpreeCmCommissioner::AccommodationSearchDetail
55
+ end
56
+
40
57
  def required_schema
41
58
  SpreeCmCommissioner::AccommodationRequestSchema
42
59
  end
@@ -25,8 +25,10 @@ module SpreeCmCommissioner
25
25
  end
26
26
 
27
27
  def verify_signature
28
+ public_key = ENV['VATTANAC_PUBLIC_KEY'].presence || Rails.application.credentials.vattanac.public_key
29
+
28
30
  rsa_service = SpreeCmCommissioner::RsaService.new(
29
- public_key: vattanac_public_key
31
+ public_key: public_key
30
32
  )
31
33
 
32
34
  return if rsa_service.verify(context.encrypted_data, context.signature)
@@ -35,6 +37,8 @@ module SpreeCmCommissioner
35
37
  end
36
38
 
37
39
  def decrypt_payload
40
+ aes_key = ENV['VATTANAC_AES_SECRET_KEY'].presence || Rails.application.credentials.vattanac.aes_secret_key
41
+
38
42
  context.fail!(message: 'Invalid AES key length', status: :unprocessable_entity) unless aes_key
39
43
 
40
44
  begin
@@ -95,41 +99,18 @@ module SpreeCmCommissioner
95
99
 
96
100
  def construct_data
97
101
  user = context.user
98
-
99
- raw_data = {
102
+ context.data = {
100
103
  sessionId: session_id,
101
104
  name: user.full_name,
102
105
  phone: user.phone_number,
103
106
  email: user.email,
104
107
  webUrl: "#{Spree::Store.default.formatted_url}/vattanac_bank_web_app?session_id=#{session_id}"
105
108
  }
106
-
107
- json_data = raw_data.to_json
108
-
109
- encrypted_data = SpreeCmCommissioner::AesEncryptionService.encrypt(json_data, aes_key)
110
-
111
- rsa_service = SpreeCmCommissioner::RsaService.new(private_key: bookmeplus_private_key)
112
-
113
- signed_data = rsa_service.sign(encrypted_data)
114
-
115
- context.data = signed_data
116
109
  end
117
110
 
118
111
  def session_id
119
112
  payload = { user_id: context.user.id }
120
113
  SpreeCmCommissioner::UserSessionJwtToken.encode(payload, context.user.reload.secure_token)
121
114
  end
122
-
123
- def aes_key
124
- ENV['VATTANAC_AES_SECRET_KEY'].presence || Rails.application.credentials.vattanac.aes_secret_key
125
- end
126
-
127
- def bookmeplus_private_key
128
- ENV['BOOKMEPLUS_PRIVATE_KEY'].presence || Rails.application.credentials.bookmeplus.private_key
129
- end
130
-
131
- def vattanac_public_key
132
- ENV['VATTANAC_PUBLIC_KEY'].presence || Rails.application.credentials.vattanac.public_key
133
- end
134
115
  end
135
116
  end
@@ -20,6 +20,7 @@ module SpreeCmCommissioner
20
20
  vehicle_id
21
21
  origin
22
22
  destination
23
+ place_id
23
24
  ].freeze
24
25
 
25
26
  RESERVED_OPTIONS = {
@@ -47,8 +48,8 @@ module SpreeCmCommissioner
47
48
  'bib-display-prefix' => 'boolean',
48
49
  'bib-pre-generation-on-create' => 'boolean',
49
50
  'seat-number-positions' => 'array',
50
- 'origin' => 'origin',
51
- 'destination' => 'destination',
51
+ 'origin' => 'place_id',
52
+ 'destination' => 'place_id',
52
53
  'departure-time' => 'time',
53
54
  'vehicle' => 'vehicle_id',
54
55
  'allow-seat-selection' => 'boolean'
@@ -13,13 +13,10 @@ module SpreeCmCommissioner
13
13
  state_machine.after_transition to: :complete, do: :notify_order_complete_telegram_notification_to_user, unless: :subscription?
14
14
  state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_vendors, unless: :need_confirmation?
15
15
  state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_store, unless: :need_confirmation?
16
- state_machine.around_transition to: :complete, do: :handle_unstock_in_redis
17
16
 
18
17
  state_machine.after_transition to: :resumed, do: :precalculate_conversion
19
- state_machine.around_transition to: :resumed, do: :handle_unstock_in_redis
20
18
 
21
19
  state_machine.after_transition to: :canceled, do: :precalculate_conversion
22
- state_machine.after_transition to: :canceled, do: :restock_inventory_in_redis!
23
20
 
24
21
  scope :accepted, -> { where(request_state: 'accepted') }
25
22
 
@@ -69,29 +66,6 @@ module SpreeCmCommissioner
69
66
  end
70
67
  end
71
68
 
72
- def handle_unstock_in_redis
73
- ActiveRecord::Base.transaction do
74
- yield # Equal to block.call
75
-
76
- # After the transition is complete, the following code will execute first before proceeding to other `after_transition` callbacks.
77
- # This ensures that if `unstock_inventory_in_redis!` fails, the state will be rolled back,
78
- # and neither the `finalize!` method nor any notifications will be triggered.
79
- # The payment will be reversed in vPago gem, and `Spree::Checkout::Complete` will be called, which checks `order.reload.complete?`.
80
- # This is critical because if the order state is complete, the payment will be marked as paid.
81
- CmAppLogger.log(label: 'order_state_machine_before_unstock', data: { order_id: id, state: state })
82
- unstock_inventory_in_redis!
83
- # We rollback only order state, and we keep payment state as it is.
84
- # We implement payment in vPago gem, and it will be reversed in the gem.
85
- # Some bank has api for refund, but some don't have the api to refund yet. So we keep the payment state as it is and refund manually.
86
- CmAppLogger.log(label: 'order_state_machine_after_unstock', data: { order_id: id, state: state })
87
- end
88
- rescue StandardError => e
89
- CmAppLogger.log(label: 'order_state_machine',
90
- data: { order_id: id, error: e.message, type: e.class.name, backtrace: e.backtrace.first(5).join("\n") }
91
- )
92
- raise e
93
- end
94
-
95
69
  def generate_bib_number
96
70
  line_items.find_each(&:generate_remaining_guests)
97
71
 
@@ -6,20 +6,10 @@ module SpreeCmCommissioner
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  PRODUCT_TYPES = %i[accommodation service ecommerce transit].freeze
9
- PERMANENT_STOCK_PRODUCT_TYPES = %w[accommodation service transit].freeze
10
- PRE_INVENTORY_DAYS = { 'transit' => 90, 'accommodation' => 365, 'service' => 30 }.freeze
11
9
 
12
10
  included do
13
11
  enum product_type: PRODUCT_TYPES if table_exists? && column_names.include?('product_type')
14
12
  enum primary_product_type: PRODUCT_TYPES if table_exists? && column_names.include?('primary_product_type')
15
13
  end
16
-
17
- def permanent_stock?
18
- PERMANENT_STOCK_PRODUCT_TYPES.include?(product_type)
19
- end
20
-
21
- def pre_inventory_days
22
- PRE_INVENTORY_DAYS[product_type]
23
- end
24
14
  end
25
15
  end
@@ -9,7 +9,6 @@ module SpreeCmCommissioner
9
9
  base.has_one :google_wallet, class_name: 'SpreeCmCommissioner::GoogleWallet', through: :product
10
10
 
11
11
  base.has_many :option_types, through: :product
12
- base.has_many :inventory_items, through: :variant
13
12
  base.has_many :taxons, class_name: 'Spree::Taxon', through: :product
14
13
  base.has_many :guests, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
15
14
  base.has_many :pending_guests, pending_guests_query, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
@@ -58,13 +58,6 @@ module SpreeCmCommissioner
58
58
  end
59
59
  end
60
60
 
61
- # override
62
- # spree use this method to check stock availability & consider whether :order can continue to next state.
63
- def insufficient_stock_lines
64
- checker = SpreeCmCommissioner::Stock::OrderAvailabilityChecker.new(self)
65
- checker.insufficient_stock_lines
66
- end
67
-
68
61
  def ticket_seller_user?
69
62
  return false if user.nil?
70
63
 
@@ -201,14 +194,6 @@ module SpreeCmCommissioner
201
194
 
202
195
  private
203
196
 
204
- def unstock_inventory_in_redis!
205
- SpreeCmCommissioner::RedisStock::InventoryUpdater.new(line_item_ids).unstock!
206
- end
207
-
208
- def restock_inventory_in_redis!
209
- SpreeCmCommissioner::RedisStock::InventoryUpdater.new(line_item_ids).restock!
210
- end
211
-
212
197
  # override :spree_api
213
198
  def webhook_payload_body
214
199
  resource_serializer.new(
@@ -33,7 +33,6 @@ module SpreeCmCommissioner
33
33
  base.has_one :google_wallet, class_name: 'SpreeCmCommissioner::GoogleWallet', dependent: :destroy
34
34
 
35
35
  base.has_many :complete_line_items, through: :classifications, source: :line_items
36
- base.has_many :inventory_items, through: :variants
37
36
 
38
37
  base.has_many :product_places, class_name: 'SpreeCmCommissioner::ProductPlace', dependent: :destroy
39
38
  base.has_many :places, through: :product_places
@@ -1,49 +1,47 @@
1
1
  module SpreeCmCommissioner
2
2
  module Stock
3
3
  class AvailabilityChecker
4
- attr_reader :variant, :options, :error_message
4
+ attr_reader :variant, :error_message
5
5
 
6
- def initialize(variant, options = {})
6
+ def initialize(variant)
7
7
  @variant = variant
8
- @options = options
9
8
  @error_message = nil
10
9
  end
11
10
 
12
- def can_supply?(quantity = 1)
11
+ def can_supply?(quantity = 1, options = {})
13
12
  return false unless variant.available?
14
13
  return true unless variant.should_track_inventory?
15
14
  return true if variant.backorderable?
16
15
  return true if variant.need_confirmation?
17
16
 
18
- variant_available?(quantity)
19
- end
20
-
21
- def variant_available?(quantity = 1)
22
- return false if cached_inventory_items.empty?
23
-
24
- cached_inventory_items.all? do |cached_inventory_item|
25
- cached_inventory_item.active? && cached_inventory_item.quantity_available >= quantity
26
- end
27
- end
28
-
29
- def cached_inventory_items
30
- return @cached_inventory_items if defined?(@cached_inventory_items)
17
+ # when delivery required, shipment will dynamically add / remove unit from stock item.
18
+ # so we can directly check can_supply with stock items directly.
19
+ return variant.stock_items.sum(:count_on_hand) >= quantity if variant.delivery_required?
31
20
 
32
21
  if variant.permanent_stock?
33
- return [] if options[:from_date].blank? || options[:to_date].blank?
34
-
35
- @cached_inventory_items = builder_klass.new(
36
- variant_id: variant.id,
37
- from_date: options[:from_date].to_date,
38
- to_date: options[:to_date].to_date
39
- ).call
22
+ permanent_stock_variant_available?(quantity, options)
40
23
  else
41
- @cached_inventory_items = builder_klass.new(variant_id: variant.id).call
24
+ variant_available?(quantity, options)
42
25
  end
43
26
  end
44
27
 
45
- def builder_klass
46
- ::SpreeCmCommissioner::RedisStock::VariantCachedInventoryItemsBuilder
28
+ def variant_available?(quantity = 1, options = {})
29
+ query = SpreeCmCommissioner::VariantAvailability::NonPermanentStockQuery.new(
30
+ variant: variant,
31
+ except_line_item_id: options[:except_line_item_id]
32
+ )
33
+ result = query.available?(quantity)
34
+ @error_message = query.error_message unless result
35
+ result
36
+ end
37
+
38
+ def permanent_stock_variant_available?(quantity = 1, options = {})
39
+ SpreeCmCommissioner::VariantAvailability::PermanentStockQuery.new(
40
+ variant: variant,
41
+ from_date: options[:from_date].to_date,
42
+ to_date: options[:to_date].to_date,
43
+ except_line_item_id: options[:except_line_item_id]
44
+ ).available?(quantity)
47
45
  end
48
46
  end
49
47
  end
@@ -3,8 +3,7 @@ module SpreeCmCommissioner
3
3
  module AvailabilityValidatorDecorator
4
4
  # override
5
5
  def item_available?(line_item, quantity)
6
- SpreeCmCommissioner::Stock::LineItemAvailabilityChecker.new(line_item)
7
- .can_supply?(quantity)
6
+ SpreeCmCommissioner::Stock::LineItemAvailabilityChecker.new(line_item).can_supply?(quantity)
8
7
  end
9
8
  end
10
9
  end
@@ -8,14 +8,14 @@ module SpreeCmCommissioner
8
8
  end
9
9
 
10
10
  def can_supply?(quantity)
11
- ::SpreeCmCommissioner::Stock::AvailabilityChecker.new(line_item.variant, options)
12
- .can_supply?(quantity)
11
+ AvailabilityChecker.new(line_item.variant).can_supply?(quantity, options)
13
12
  end
14
13
 
15
14
  def options
16
15
  {
17
16
  from_date: line_item.from_date,
18
- to_date: line_item.to_date
17
+ to_date: line_item.to_date,
18
+ except_line_item_id: line_item.id
19
19
  }
20
20
  end
21
21
  end
@@ -5,6 +5,7 @@ module SpreeCmCommissioner
5
5
 
6
6
  validate :both_trip_cannot_be_the_same
7
7
  before_validation :calculate_connection_time_minutes
8
+ validates :from_trip_id, uniqueness: { scope: :to_trip_id }
8
9
 
9
10
  private
10
11
 
@@ -13,11 +13,11 @@ module SpreeCmCommissioner
13
13
  validates :stop_id, uniqueness: { scope: :trip_id }
14
14
 
15
15
  def set_stop_name
16
- self.stop_name = stop.name
16
+ self.stop_name = stop.name if stop.present?
17
17
  end
18
18
 
19
19
  def create_vendor_stop
20
- vendor.vendor_stops.where(stop_id: stop_id, stop_type: stop_type).first_or_create
20
+ vendor.vendor_stops.where(stop_id: stop_id, stop_type: stop_type).first_or_create if trip.present?
21
21
  end
22
22
 
23
23
  private
@@ -1,7 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  module VariantDecorator
3
3
  def self.prepended(base)
4
- base.include SpreeCmCommissioner::ProductType
5
4
  base.include SpreeCmCommissioner::ProductDelegation
6
5
  base.include SpreeCmCommissioner::VariantOptionsConcern
7
6
 
@@ -22,16 +21,14 @@ module SpreeCmCommissioner
22
21
  base.has_many :variant_guest_card_class, class_name: 'SpreeCmCommissioner::VariantGuestCardClass'
23
22
  base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variant_guest_card_class
24
23
 
25
- base.has_many :inventory_items, class_name: 'SpreeCmCommissioner::InventoryItem'
26
-
27
24
  base.scope :subscribable, -> { active.joins(:product).where(product: { subscribable: true, status: :active }) }
28
- base.scope :with_permanent_stock, -> { joins(:product).where(product: { product_type: base::PERMANENT_STOCK_PRODUCT_TYPES }) }
29
- base.scope :with_non_permanent_stock, -> { joins(:product).where.not(product: { product_type: base::PERMANENT_STOCK_PRODUCT_TYPES }) }
30
-
31
25
  base.has_one :trip,
32
26
  class_name: 'SpreeCmCommissioner::Trip'
27
+ base.has_many :trip_stops, class_name: 'SpreeCmCommissioner::TripStop', dependent: :destroy, foreign_key: :trip_id
33
28
  base.accepts_nested_attributes_for :option_values
29
+ base.has_many :trip_stops, class_name: 'SpreeCmCommissioner::TripStop', foreign_key: :trip_id, dependent: :destroy
34
30
  base.after_commit :sync_trip, if: -> { product.product_type == 'transit' }
31
+ base.accepts_nested_attributes_for :trip_stops, allow_destroy: true
35
32
  end
36
33
 
37
34
  def delivery_required?
@@ -47,24 +44,12 @@ module SpreeCmCommissioner
47
44
  super || product.discontinued?
48
45
  end
49
46
 
50
- def event
51
- taxons.event.first
52
- end
53
-
54
- def default_inventory_item_exist?
55
- inventory_items.exists?(inventory_date: nil)
47
+ def permanent_stock?
48
+ accommodation?
56
49
  end
57
50
 
58
- def create_default_non_permanent_inventory_item!(quantity_available: nil, max_capacity: nil)
59
- return if product_type.blank? # handle in case product not exist for variant.
60
- return unless should_track_inventory?
61
- return if default_inventory_item_exist?
62
-
63
- inventory_items.create!(
64
- product_type: product_type,
65
- quantity_available: [0, quantity_available || total_on_hand].max,
66
- max_capacity: [0, max_capacity || total_on_hand].max
67
- )
51
+ def event
52
+ taxons.event.first
68
53
  end
69
54
 
70
55
  # override
@@ -87,12 +72,23 @@ module SpreeCmCommissioner
87
72
  end
88
73
 
89
74
  # override
90
- def in_stock?(options = {})
91
- SpreeCmCommissioner::Stock::AvailabilityChecker.new(self, options).can_supply?
75
+ def in_stock?
76
+ available_quantity.positive?
92
77
  end
93
78
 
94
79
  private
95
80
 
81
+ def total_purchases
82
+ Spree::LineItem.complete.where(variant_id: id).sum(:quantity).to_i
83
+ end
84
+
85
+ def available_quantity
86
+ stock_count = stock_items.sum(&:count_on_hand)
87
+ return stock_count if delivery_required?
88
+
89
+ stock_count - total_purchases
90
+ end
91
+
96
92
  def update_vendor_price
97
93
  return unless vendor.present? && product&.product_type == vendor&.primary_product_type
98
94
 
@@ -166,19 +166,5 @@ module SpreeCmCommissioner
166
166
  Time.zone.parse(time) if time.present?
167
167
  end
168
168
  end
169
-
170
- def arrival_time
171
- @arrival_time ||= departure_time + total_duration_in_minutes.minutes
172
- end
173
-
174
- def total_duration_in_minutes
175
- total_duration_in_minutes = 0
176
-
177
- total_duration_in_minutes += duration_in_hours * 60 if duration_in_hours.present?
178
- total_duration_in_minutes += duration_in_minutes if duration_in_minutes.present?
179
- total_duration_in_minutes += duration_in_seconds / 60 if duration_in_seconds.present?
180
-
181
- total_duration_in_minutes
182
- end
183
169
  end
184
170
  end