spree_cm_commissioner 1.9.2 → 1.10.0.pre.pre

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_and_build_gem.yml +86 -0
  3. data/.gitignore +2 -1
  4. data/Gemfile.lock +22 -1
  5. data/app/controllers/spree/admin/events_controller.rb +47 -0
  6. data/app/controllers/spree/admin/prototypes_controller_decorator.rb +20 -0
  7. data/app/controllers/spree/admin/stock_managements_controller.rb +17 -1
  8. data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +42 -0
  9. data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +14 -31
  10. data/app/finders/spree_cm_commissioner/accommodations/find.rb +40 -0
  11. data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +35 -0
  12. data/app/interactors/spree_cm_commissioner/create_event.rb +65 -0
  13. data/app/interactors/spree_cm_commissioner/firebase_email_fetcher.rb +30 -4
  14. data/app/interactors/spree_cm_commissioner/firebase_email_fetcher_cron_executor.rb +23 -0
  15. data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +25 -0
  16. data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +71 -0
  17. data/app/interactors/spree_cm_commissioner/vattanac_bank_initiator.rb +25 -6
  18. data/app/jobs/spree_cm_commissioner/firebase_email_fetcher_job.rb +9 -0
  19. data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +7 -0
  20. data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +9 -0
  21. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +26 -0
  22. data/app/models/concerns/spree_cm_commissioner/product_type.rb +10 -0
  23. data/app/models/spree_cm_commissioner/inventory.rb +11 -0
  24. data/app/models/spree_cm_commissioner/inventory_item.rb +37 -0
  25. data/app/models/spree_cm_commissioner/invite_user_taxon.rb +1 -0
  26. data/app/models/spree_cm_commissioner/line_item_decorator.rb +1 -0
  27. data/app/models/spree_cm_commissioner/order_decorator.rb +15 -0
  28. data/app/models/spree_cm_commissioner/product_decorator.rb +10 -0
  29. data/app/models/spree_cm_commissioner/prototype_decorator.rb +9 -0
  30. data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +40 -0
  31. data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +114 -0
  32. data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +42 -0
  33. data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +27 -0
  34. data/app/models/spree_cm_commissioner/stock/availability_checker.rb +27 -25
  35. data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +2 -1
  36. data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
  37. data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +44 -0
  38. data/app/models/spree_cm_commissioner/stock_movement_decorator.rb +34 -0
  39. data/app/models/spree_cm_commissioner/taxon_decorator.rb +2 -1
  40. data/app/models/spree_cm_commissioner/user_decorator.rb +5 -1
  41. data/app/models/spree_cm_commissioner/variant_decorator.rb +24 -17
  42. data/app/overrides/spree/admin/prototypes/_form/description.html.erb.deface +6 -0
  43. data/app/overrides/spree/admin/prototypes/_form/icon.html.erb.deface +8 -0
  44. data/app/overrides/spree/admin/prototypes/_form/product_type.html.erb.deface +2 -2
  45. data/app/overrides/spree/admin/shared/sub_menu/_product/events_tab.html.erb.deface +3 -0
  46. data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +3 -0
  47. data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
  48. data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +19 -0
  49. data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +2 -0
  50. data/app/serializers/spree/v2/tenant/payment_method_serializer.rb +12 -0
  51. data/app/serializers/spree/v2/tenant/user_serializer.rb +1 -1
  52. data/app/views/spree/admin/events/_search_form.html.erb +61 -0
  53. data/app/views/spree/admin/events/_tab.html.erb +25 -0
  54. data/app/views/spree/admin/events/_table.html.erb +27 -0
  55. data/app/views/spree/admin/events/index.html.erb +15 -0
  56. data/app/views/spree/admin/stock_managements/_events_popover.html.erb +17 -0
  57. data/app/views/spree/admin/stock_managements/calendar.html.erb +32 -0
  58. data/app/views/spree/admin/stock_managements/index.html.erb +31 -5
  59. data/app/views/spree_cm_commissioner/crew_invite_mailer/_mailer_stylesheets.html.erb +2 -2
  60. data/app/views/spree_cm_commissioner/crew_invite_mailer/send_crew_invite_email.html.erb +1 -1
  61. data/config/initializers/user_manager_decorator.rb +26 -0
  62. data/config/routes.rb +12 -2
  63. data/db/migrate/20250304293518_create_cm_inventory_items.rb +21 -0
  64. data/db/migrate/20250425084929_add_description_to_spree_prototypes.rb +5 -0
  65. data/db/migrate/20250425085938_add_preferences_to_spree_prototypes.rb +5 -0
  66. data/db/migrate/20250428025645_add_slug_to_spree_prototypes.rb +6 -0
  67. data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +5 -0
  68. data/docker-compose.yml +1 -1
  69. data/lib/generators/spree_cm_commissioner/install/install_generator.rb +2 -2
  70. data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_cm_commissioner → spree_dashboard/spree_cm_commissioner}/utilities.js +4 -0
  71. data/lib/spree_cm_commissioner/cached_inventory_item.rb +23 -0
  72. data/lib/spree_cm_commissioner/calendar_event.rb +11 -1
  73. data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +9 -0
  74. data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +28 -6
  75. data/lib/spree_cm_commissioner/version.rb +1 -1
  76. data/lib/spree_cm_commissioner.rb +34 -0
  77. data/lib/tasks/create_default_non_permanent_inventory_items.rake +16 -0
  78. data/lib/tasks/fetch_email.rake +7 -0
  79. data/lib/tasks/generate_inventory_items.rake +7 -0
  80. data/spree_cm_commissioner.gemspec +5 -0
  81. metadata +88 -7
  82. data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +0 -45
  83. data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +0 -55
@@ -23,8 +23,8 @@
23
23
  line-height: 1.4;
24
24
  margin-top: 10px;
25
25
  margin-bottom: 15px;
26
- padding-left: 8px;
27
- padding-right: 8px;
26
+ padding-left: 5px;
27
+ padding-right: 5px;
28
28
 
29
29
  }
30
30
 
@@ -13,7 +13,7 @@
13
13
  </div>
14
14
  <div class="bar-thin"></div>
15
15
  <div class="heading-2">
16
- <%= @invite_user_event.invite.inviter.full_name.presence || @invite_user_event.invite.inviter.email %> invites you to join the <br>
16
+ <%= @invite_user_event.inviter.full_name.presence || @invite_user_event.inviter.email %> invites you to join the <br>
17
17
  <span class="title-bold">Check-in Crew</span> for the event <br>
18
18
  <%= @invite_user_event.invite.taxon.name %>
19
19
  </div>
@@ -0,0 +1,26 @@
1
+ require 'firebase-admin-sdk'
2
+
3
+ module Firebase
4
+ module Admin
5
+ module Auth
6
+ module UserManagerDecorator
7
+ def get_user_by_sub(query)
8
+ sub = query[:sub]
9
+ return if sub.blank?
10
+
11
+ payload = {
12
+ federatedUserId: {
13
+ providerId: 'google.com',
14
+ rawId: sub
15
+ }
16
+ }
17
+ response = @client.post(with_path('accounts:lookup'), payload).body
18
+ users = response['users'] if response
19
+ UserRecord.new(users[0]) if users.is_a?(Array) && users.any?
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ Firebase::Admin::Auth::UserManager.prepend(Firebase::Admin::Auth::UserManagerDecorator)
data/config/routes.rb CHANGED
@@ -16,6 +16,7 @@ Spree::Core::Engine.add_routes do
16
16
  end
17
17
  end
18
18
 
19
+ resources :events
19
20
  resources :promotions do
20
21
  resources :custom_dates_rules, controller: :promotion_custom_dates_rules, only: %i[edit update] do
21
22
  member do
@@ -137,7 +138,11 @@ Spree::Core::Engine.add_routes do
137
138
  end
138
139
  end
139
140
 
140
- resources :stock_managements
141
+ resources :stock_managements do
142
+ collection do
143
+ get :calendar
144
+ end
145
+ end
141
146
 
142
147
  resources :product_completion_steps do
143
148
  collection do
@@ -518,6 +523,8 @@ Spree::Core::Engine.add_routes do
518
523
  end
519
524
 
520
525
  namespace :storefront do
526
+ resources :inventory_item
527
+
521
528
  resources :waiting_room_sessions, only: :create
522
529
  resources :vattanac_banks, only: %i[create]
523
530
  resource :cart, controller: :cart, only: %i[show create destroy] do
@@ -543,7 +550,10 @@ Spree::Core::Engine.add_routes do
543
550
  resource :cart_guests, only: %i[create destroy]
544
551
  resources :cart_payment_method_groups, only: %i[index]
545
552
 
546
- resources :accommodations, only: %i[index show]
553
+ resources :accommodations, only: %i[index show] do
554
+ resources :variants, only: %i[index show], module: :accommodations
555
+ end
556
+
547
557
  resources :line_items, only: %i[index show]
548
558
  resources :account_checker
549
559
  resource :account_recovers, only: [:update]
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,5 @@
1
+ class AddDescriptionToSpreePrototypes < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :spree_prototypes, :description, :text, if_not_exists: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddPreferencesToSpreePrototypes < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :spree_prototypes, :preferences, :text, if_not_exists: true
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class AddSlugToSpreePrototypes < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :spree_prototypes, :slug, :string, if_not_exists: true
4
+ add_index :spree_prototypes, :slug, unique: true, if_not_exists: true
5
+ end
6
+ end
@@ -0,0 +1,5 @@
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
data/docker-compose.yml CHANGED
@@ -20,7 +20,7 @@ services:
20
20
 
21
21
  volumes:
22
22
  - .:/gem
23
- - /gem/vendor/bundle
23
+ - ./vendor/bundle:/gem/vendor/bundle
24
24
 
25
25
  # depends_on:
26
26
  # - db
@@ -40,8 +40,8 @@ module SpreeCmCommissioner
40
40
  after: %r{//= require spree/backend}, verbose: true
41
41
 
42
42
  # For NPM support
43
- template 'app/javascript/spree_cm_commissioner/utilities.js'
44
- inject_into_file 'app/javascript/spree-dashboard.js', "\nimport \"./spree_cm_commissioner/utilities.js\"",
43
+ template 'app/javascript/spree_dashboard/spree_cm_commissioner/utilities.js'
44
+ inject_into_file 'app/javascript/spree_dashboard/spree-dashboard.js', "\nimport \"./spree_cm_commissioner/utilities.js\"",
45
45
  after: %r{import "@spree/dashboard"}, verbose: true
46
46
  end
47
47
 
@@ -6,3 +6,7 @@ const $ = jquery;
6
6
  document.addEventListener("spree:load", function () {
7
7
  $('[data-toggle="popover"]').popover();
8
8
  });
9
+
10
+ document.documentElement.addEventListener("turbo:frame-load", (event) => {
11
+ $('[data-toggle="popover"]').popover();
12
+ });
@@ -0,0 +1,23 @@
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
@@ -2,7 +2,7 @@ module SpreeCmCommissioner
2
2
  class CalendarEvent
3
3
  attr_reader :from_date, :to_date, :title, :options
4
4
 
5
- def initialize(from_date:, to_date:, title:, options:)
5
+ def initialize(from_date:, to_date:, title: nil, options: nil)
6
6
  @from_date = from_date
7
7
  @to_date = to_date
8
8
  @title = title
@@ -23,5 +23,15 @@ module SpreeCmCommissioner
23
23
  )
24
24
  end
25
25
  end
26
+
27
+ def self.from_inventory_items(inventory_items)
28
+ inventory_items.map do |item|
29
+ CalendarEvent.new(
30
+ from_date: item.inventory_date,
31
+ to_date: item.inventory_date,
32
+ options: { inventory_item: item }
33
+ )
34
+ end
35
+ end
26
36
  end
27
37
  end
@@ -0,0 +1,9 @@
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,19 +1,40 @@
1
1
  FactoryBot.define do
2
2
  factory :cm_base_variant, parent: :base_variant do
3
+ is_master { false }
4
+
3
5
  transient do
4
6
  total_inventory { 10 }
7
+ backorderable { false }
5
8
  end
6
9
 
7
10
  after :create do |variant, evaluator|
8
11
  variant.stock_items.first.adjust_count_on_hand(evaluator.total_inventory)
12
+ variant.stock_items.update_all(backorderable: evaluator.backorderable)
9
13
  end
10
14
  end
11
15
 
12
- factory :cm_variant, parent: :variant do
13
- product do
14
- stock_locations = [create(:stock_location)]
15
- product = create(:product, vendor: create(:active_vendor, stock_locations: stock_locations))
16
- product
16
+ factory :cm_variant, parent: :cm_base_variant do
17
+ product { create(:product) }
18
+
19
+ transient do
20
+ number_of_adults { nil }
21
+ number_of_kids { nil }
22
+ end
23
+
24
+ after(:create) do |variant, evaluator|
25
+ if evaluator.number_of_adults.present?
26
+ number_of_adults = create(:cm_option_type, :number_of_adults)
27
+ variant.product.option_types << number_of_adults
28
+ variant.option_values << create(:cm_option_value, presentation: evaluator.number_of_adults, name: evaluator.number_of_adults, option_type: number_of_adults)
29
+ end
30
+
31
+ if evaluator.number_of_kids.present?
32
+ number_of_kids = create(:cm_option_type, :number_of_kids)
33
+ variant.product.option_types << number_of_kids
34
+ variant.option_values << create(:cm_option_value, presentation: evaluator.number_of_kids, name: evaluator.number_of_kids, option_type: number_of_kids)
35
+ end
36
+
37
+ variant.save!
17
38
  end
18
39
  end
19
40
 
@@ -24,12 +45,13 @@ FactoryBot.define do
24
45
  duration { "1" }
25
46
  route { }
26
47
  end
48
+
27
49
  before(:create) do |trip, evaluator|
28
50
  trip.product = evaluator.route
29
51
 
30
52
  trip.option_values = [evaluator.departure_time, evaluator.duration]
31
-
32
53
  end
54
+
33
55
  after(:create) do |trip, evaluator|
34
56
  trip.stock_items = [create(:stock_item, variant: trip, stock_location: evaluator.product.vendor.stock_locations.first)]
35
57
  trip.stock_items.first.adjust_count_on_hand(10)
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '1.9.2'.freeze
2
+ VERSION = '1.10.0-pre'.freeze
3
3
 
4
4
  module_function
5
5
 
@@ -19,6 +19,7 @@ require 'spree_cm_commissioner/user_session_jwt_token'
19
19
  require 'spree_cm_commissioner/trip_result'
20
20
  require 'spree_cm_commissioner/trip_query_result'
21
21
  require 'spree_cm_commissioner/trip_seat_layout_result'
22
+ require 'spree_cm_commissioner/cached_inventory_item'
22
23
 
23
24
  require 'activerecord_multi_tenant'
24
25
  require 'google/cloud/recaptcha_enterprise'
@@ -44,3 +45,36 @@ require 'cm_app_logger'
44
45
  require 'counter_culture'
45
46
 
46
47
  require 'byebug' if Rails.env.development? || Rails.env.test?
48
+
49
+ module SpreeCmCommissioner
50
+ class << self
51
+ # Allows overriding the default Redis connection pool with a custom one
52
+ attr_writer :redis_pool
53
+
54
+ def redis_pool
55
+ @redis_pool ||= default_redis_pool
56
+ end
57
+
58
+ # Resets the Redis pool, useful for testing or reinitialization
59
+ def reset_redis_pool
60
+ @redis_pool = nil
61
+ end
62
+
63
+ private
64
+
65
+ def default_redis_pool
66
+ pool_size = ENV.fetch('REDIS_POOL_SIZE', '5').to_i
67
+ timeout = ENV.fetch('REDIS_TIMEOUT', '5').to_i
68
+ redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/12')
69
+
70
+ ConnectionPool.new(size: pool_size, timeout: timeout) do
71
+ Redis.new(url: redis_url, timeout: timeout)
72
+ end
73
+ end
74
+ end
75
+
76
+ # Provides a configuration block for customizing SpreeCmCommissioner settings
77
+ def self.configure
78
+ yield self
79
+ end
80
+ end
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,7 @@
1
+ # recommend to be used in schedule.yml & manually access in /sidekiq/cron
2
+ namespace :spree_cm_commissioner do
3
+ desc 'Fetch email from firebase'
4
+ task fetch_email: :environment do
5
+ SpreeCmCommissioner::FirebaseEmailFetcherJob.perform_now
6
+ end
7
+ end
@@ -0,0 +1,7 @@
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
@@ -54,6 +54,11 @@ Gem::Specification.new do |s|
54
54
  s.add_dependency "rqrcode", "~> 2.0"
55
55
  s.add_dependency "premailer-rails"
56
56
  s.add_dependency 'counter_culture', '~> 3.2'
57
+ # Redis
58
+ s.add_dependency 'redis'
59
+ s.add_dependency 'redis-rails'
60
+ s.add_dependency 'connection_pool'
61
+
57
62
  s.add_development_dependency 'pg'
58
63
  s.add_development_dependency 'spree_dev_tools'
59
64
  s.add_dependency 'blazer', '~> 3.0.4'