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
@@ -1,42 +0,0 @@
1
- module SpreeCmCommissioner
2
- module RedisStock
3
- class LineItemsCachedInventoryItemsBuilder
4
- attr_reader :line_item_ids
5
-
6
- def initialize(line_item_ids:)
7
- @line_item_ids = line_item_ids
8
- end
9
-
10
- # return list of inventory items group by :line_item_id:
11
- # {
12
- # 1: [ CachedInventoryItem(...), CachedInventoryItem(...) ],
13
- # 2: [ CachedInventoryItem(...), CachedInventoryItem(...) ],
14
- # }
15
- def call
16
- cached_inventory_items.group_by do |cached_inventory_item|
17
- line_item = line_items.find { |item| item.variant_id == cached_inventory_item.variant_id }
18
- line_item.id
19
- end
20
- end
21
-
22
- def cached_inventory_items
23
- @cached_inventory_items ||= SpreeCmCommissioner::RedisStock::CachedInventoryItemsBuilder.new(inventory_items)
24
- .call
25
- end
26
-
27
- def inventory_items
28
- @inventory_items ||= line_items.flat_map do |line_item|
29
- # TODO: N+1, we could fix but have a product_type in line item
30
- # then include inventory_items in line item directly #2581
31
- scope = line_item.inventory_items
32
- scope = scope.where(inventory_date: line_item.date_range) if line_item.permanent_stock?
33
- scope
34
- end
35
- end
36
-
37
- def line_items
38
- @line_items ||= Spree::LineItem.where(id: line_item_ids).includes(variant: %i[product])
39
- end
40
- end
41
- end
42
- end
@@ -1,27 +0,0 @@
1
- module SpreeCmCommissioner
2
- module RedisStock
3
- class VariantCachedInventoryItemsBuilder
4
- attr_reader :variant_id, :from_date, :to_date
5
-
6
- def initialize(variant_id:, from_date: nil, to_date: nil)
7
- @variant_id = variant_id
8
- @from_date = from_date
9
- @to_date = to_date
10
- end
11
-
12
- # output: [ CachedInventoryItem(...), CachedInventoryItem(...) ]
13
- def call
14
- ::SpreeCmCommissioner::RedisStock::CachedInventoryItemsBuilder.new(inventory_items).call
15
- end
16
-
17
- def inventory_items
18
- variant = Spree::Variant.find(variant_id)
19
-
20
- inventory_items = variant.inventory_items
21
- inventory_items.where(inventory_date: from_date..to_date) if variant.permanent_stock?
22
-
23
- inventory_items
24
- end
25
- end
26
- end
27
- end
@@ -1,44 +0,0 @@
1
- # On top of SpreeCmCommissioner::Stock::AvailabilityChecker, this class does the same thing but in bulk check with redis.
2
- # Which mean, it check basic condition with db first, once pass, it check with redis.
3
- module SpreeCmCommissioner
4
- module Stock
5
- class OrderAvailabilityChecker
6
- attr_reader :order
7
-
8
- def initialize(order)
9
- @order = order
10
- end
11
-
12
- def can_supply_all?
13
- insufficient_stock_lines.empty?
14
- end
15
-
16
- def insufficient_stock_lines
17
- cached_inventory_items_group_by_line_item_id.map do |line_item_id, cached_inventory_items|
18
- line_item = order.line_items.find { |item| item.id == line_item_id }
19
- line_item unless sufficient_stock_for?(line_item, cached_inventory_items)
20
- end.compact
21
- end
22
-
23
- # {
24
- # 1: [ {inventory_key: "inventory:1", active: true, quantity_available: 5, inventory_item_id: 1, variant_id: 1}],
25
- # 2: [ {inventory_key: "inventory:2", active: true, quantity_available: 5, inventory_item_id: 2, variant_id: 2}],
26
- # }
27
- def cached_inventory_items_group_by_line_item_id
28
- @cached_inventory_items_group_by_line_item_id ||=
29
- ::SpreeCmCommissioner::RedisStock::LineItemsCachedInventoryItemsBuilder.new(
30
- line_item_ids: order.line_items.pluck(:id)
31
- ).call
32
- end
33
-
34
- def sufficient_stock_for?(line_item, cached_inventory_items)
35
- return false unless line_item.variant.available?
36
- return true unless line_item.variant.should_track_inventory?
37
- return true if line_item.variant.backorderable?
38
- return true if line_item.variant.need_confirmation?
39
-
40
- cached_inventory_items.all? { |item| item.active? && item.quantity_available >= line_item.quantity }
41
- end
42
- end
43
- end
44
- end
@@ -1,34 +0,0 @@
1
- module SpreeCmCommissioner
2
- module StockMovementDecorator
3
- def self.prepended(base)
4
- base.after_create :adjust_inventory_items, if: -> { stock_item.should_track_inventory? }
5
- end
6
-
7
- def adjust_inventory_items
8
- if !variant.permanent_stock? && !variant.default_inventory_item_exist?
9
- variant.create_default_non_permanent_inventory_item!
10
- else
11
- adjust_existing_inventory_items!
12
- end
13
- end
14
-
15
- private
16
-
17
- def should_create_default_non_permanent_inventory_item?
18
- return false if variant.permanent_stock?
19
- return false if variant.inventory_items.exists?(inventory_date: nil)
20
-
21
- true
22
- end
23
-
24
- def adjust_existing_inventory_items!
25
- variant.inventory_items.active.find_each(batch_size: 100) do |inventory_item|
26
- inventory_item.adjust_quantity!(quantity)
27
- end
28
- end
29
- end
30
- end
31
-
32
- unless Spree::StockMovement.included_modules.include?(SpreeCmCommissioner::StockMovementDecorator)
33
- Spree::StockMovement.prepend(SpreeCmCommissioner::StockMovementDecorator)
34
- end
@@ -1,19 +0,0 @@
1
- module SpreeCmCommissioner
2
- class VariantRequestSchema < ApplicationRequestSchema
3
- params do
4
- required(:from_date).value(:date)
5
- required(:to_date).value(:date)
6
- required(:number_of_adults).value(:integer)
7
- required(:number_of_kids).value(:integer)
8
- end
9
-
10
- rule(:from_date, :to_date) do
11
- from_date = values[:from_date]
12
- to_date = values[:to_date]
13
-
14
- key.failure(:must_be_in_future) if from_date < Time.zone.today
15
- key.failure(:must_be_later_than_start_date) if from_date > to_date
16
- key.failure(:stay_is_too_long) if (to_date - from_date).to_i > ENV.fetch('ACCOMMODATION_MAX_STAY_DAYS', 10).to_i
17
- end
18
- end
19
- end
@@ -1,17 +0,0 @@
1
- <div>
2
- <% events.each do |event| %>
3
- <div>
4
- <h6><%= event.options[:inventory_item].variant.options_text %></h6>
5
- <ul class="list-group mt-1">
6
- <li class="list-group-item d-flex justify-content-between align-items-center">
7
- Max capacity
8
- <span class="badge badge-primary badge-pill"><%= event.options[:inventory_item].max_capacity %></span>
9
- </li>
10
- <li class="list-group-item d-flex justify-content-between align-items-center">
11
- Quantity available
12
- <span class="badge badge-primary badge-pill"><%= event.options[:inventory_item].quantity_available %></span>
13
- </li>
14
- </ul>
15
- </div>
16
- <% end %>
17
- </div>
@@ -1,32 +0,0 @@
1
- <%= turbo_frame_tag "calendar" do %>
2
- <%= form_with url: admin_product_stock_managements_path, method: :get, class: "mt-4" do %>
3
- <%= select_year(params[:year]&.to_i || @year, { start_year: 2025, end_year: @year + 3 }, { name: "year", onchange: "this.form.submit()" }) %>
4
- <% end %>
5
-
6
- <div class="c-annual-calendar-container mt-2">
7
- <div class="c-annual-calendar">
8
- <% (1..12).each do |month| %>
9
- <%= month_calendar(start_date: Date.new(@year, month, 1), attribute: :from_date, end_attribute: :to_date, events: @events) do |date, events| %>
10
- <div class="c-annual-day"
11
- data-date="<%= date.strftime '%Y-%m-%d' %>"
12
- type="button"
13
- tabindex="0"
14
- data-toggle="popover"
15
- data-trigger="hover"
16
- data-placement="right"
17
- data-html="true"
18
- data-content="<%= raw render_escape_html partial: "events_popover", locals: { events: events } if events.any? %>">
19
- <%= date.day %>
20
- <ul class="p-0 m-0 list-unstyled">
21
- <% events.each do |event| %>
22
- <li class="badge badge-warning">
23
- <%= event.options[:inventory_item].quantity_available %>
24
- </li>
25
- <% end %>
26
- </ul>
27
- </div>
28
- <% end %>
29
- <% end %>
30
- </div>
31
- </div>
32
- <% end %>
@@ -1,21 +0,0 @@
1
- class CreateCmInventoryItems < ActiveRecord::Migration[7.0]
2
- def up
3
- create_table :cm_inventory_items, if_not_exists: true do |t|
4
- t.integer :variant_id
5
- t.date :inventory_date
6
- t.integer :max_capacity, default: 0, null: false
7
- t.integer :quantity_available, default: 0, null: false
8
- t.integer :product_type, default: 0, null: false
9
-
10
- t.timestamps
11
- end
12
-
13
- add_index :cm_inventory_items, :variant_id, if_not_exists: true
14
- add_index :cm_inventory_items, :inventory_date, if_not_exists: true
15
- add_index :cm_inventory_items, [:variant_id, :inventory_date], unique: true, if_not_exists: true
16
- end
17
-
18
- def down
19
- drop_table :cm_inventory_items
20
- end
21
- end
@@ -1,5 +0,0 @@
1
- class AddLockVersionToCmInventoryItems < ActiveRecord::Migration[7.0]
2
- def change
3
- add_column :cm_inventory_items, :lock_version, :integer, default: 0, null: false
4
- end
5
- end
@@ -1,23 +0,0 @@
1
- module SpreeCmCommissioner
2
- class CachedInventoryItem
3
- attr_reader :inventory_key, :active, :quantity_available, :inventory_item_id, :variant_id
4
-
5
- def initialize(inventory_key:, active:, quantity_available:, inventory_item_id:, variant_id:)
6
- @inventory_key = inventory_key
7
- @active = active
8
- @quantity_available = quantity_available
9
- @inventory_item_id = inventory_item_id
10
- @variant_id = variant_id
11
- end
12
-
13
- def active?
14
- active
15
- end
16
-
17
- def to_h
18
- instance_variables.each_with_object({}) do |var, hash|
19
- hash[var.to_s.delete('@').to_sym] = instance_variable_get(var)
20
- end
21
- end
22
- end
23
- end
@@ -1,9 +0,0 @@
1
- FactoryBot.define do
2
- factory :cm_inventory_item, class: SpreeCmCommissioner::InventoryItem do
3
- variant { create(:variant) }
4
- max_capacity { 10 }
5
- quantity_available { 10 }
6
- product_type { 'accommodation' }
7
- inventory_date { Date.today }
8
- end
9
- end
@@ -1,16 +0,0 @@
1
- # recommend to be used in schedule.yml & manually access in /sidekiq/cron
2
- namespace :spree_cm_commissioner do
3
- desc 'Create default inventory items for non-permanent stock products'
4
- task create_default_non_permanent_inventory_items: :environment do
5
- Spree::Variant.active.with_non_permanent_stock.find_each do |variant|
6
- total_purchases = variant.complete_line_items.sum(:quantity).to_i || 0
7
- max_capacity = variant.total_on_hand || 0
8
- quantity_available = [max_capacity - total_purchases, 0].max
9
-
10
- variant.create_default_non_permanent_inventory_item!(
11
- max_capacity: max_capacity,
12
- quantity_available: quantity_available
13
- )
14
- end
15
- end
16
- end
@@ -1,7 +0,0 @@
1
- # recommend to be used in schedule.yml & schedule run it everyday
2
- namespace :spree_cm_commissioner do
3
- desc 'Generate inventory items for permanent_stock variants.'
4
- task generate_inventory_items: :environment do
5
- SpreeCmCommissioner::Stock::PermanentInventoryItemsGeneratorJob.perform_now
6
- end
7
- end