spree_cm_commissioner 1.10.0 → 1.11.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.
- checksums.yaml +4 -4
- data/.github/workflows/test_and_build_gem.yml +131 -98
- data/.gitignore +2 -1
- data/.vscode/settings.json +1 -1
- data/Gemfile.lock +22 -1
- data/Rakefile +33 -4
- data/app/controllers/spree/admin/stock_managements_controller.rb +56 -1
- data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +42 -0
- data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +14 -31
- data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
- data/app/finders/spree_cm_commissioner/accommodations/find.rb +40 -0
- data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +35 -0
- data/app/interactors/spree_cm_commissioner/create_event.rb +23 -0
- data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +40 -0
- data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +25 -0
- data/app/interactors/spree_cm_commissioner/stock/inventory_items_adjuster.rb +13 -0
- data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +75 -0
- data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +24 -0
- data/app/interactors/spree_cm_commissioner/vattanac_bank_initiator.rb +27 -8
- data/app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb +7 -0
- data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +7 -0
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +11 -0
- data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +9 -0
- data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +26 -0
- data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +1 -3
- data/app/models/concerns/spree_cm_commissioner/product_type.rb +10 -0
- data/app/models/spree_cm_commissioner/inventory.rb +11 -0
- data/app/models/spree_cm_commissioner/inventory_item.rb +55 -0
- data/app/models/spree_cm_commissioner/line_item_decorator.rb +16 -5
- data/app/models/spree_cm_commissioner/order_decorator.rb +15 -0
- data/app/models/spree_cm_commissioner/place.rb +11 -2
- data/app/models/spree_cm_commissioner/product_decorator.rb +9 -2
- data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +40 -0
- data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +126 -0
- data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +36 -0
- data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +27 -0
- data/app/models/spree_cm_commissioner/stock/availability_checker.rb +27 -25
- data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +2 -1
- data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
- data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +44 -0
- data/app/models/spree_cm_commissioner/stock_item_decorator.rb +18 -0
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +11 -0
- data/app/models/spree_cm_commissioner/taxon_option_type.rb +8 -0
- data/app/models/spree_cm_commissioner/taxon_option_value.rb +8 -0
- data/app/models/spree_cm_commissioner/trip.rb +0 -11
- data/app/models/spree_cm_commissioner/trip_stop.rb +11 -4
- data/app/models/spree_cm_commissioner/variant_decorator.rb +39 -27
- data/app/models/spree_cm_commissioner/vendor_stop.rb +2 -1
- data/app/queries/spree_cm_commissioner/vendor_stop_place_query.rb +54 -0
- data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +3 -0
- data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
- data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +19 -0
- data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +2 -0
- data/app/serializers/spree/v2/tenant/guest_serializer.rb +1 -0
- data/app/services/spree_cm_commissioner/aes_encryption_service.rb +6 -4
- data/app/services/spree_cm_commissioner/organizer/export_guest_csv_service.rb +2 -0
- data/app/views/spree/admin/stock_managements/_events_popover.html.erb +23 -0
- data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +3 -1
- data/app/views/spree/admin/stock_managements/calendar.html.erb +35 -0
- data/app/views/spree/admin/stock_managements/index.html.erb +40 -5
- data/config/initializers/spree_permitted_attributes.rb +5 -0
- data/config/routes.rb +11 -2
- data/db/migrate/20250304293518_create_cm_inventory_items.rb +21 -0
- data/db/migrate/20250418072528_add_nested_set_columns_to_places.rb +10 -0
- data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +5 -0
- data/db/migrate/20250430091742_create_cm_taxon_option_types.rb +9 -0
- data/db/migrate/20250430092928_create_cm_taxon_option_values.rb +9 -0
- data/db/migrate/20250502025848_add_index_to_spree_products.rb +5 -0
- data/db/migrate/20250502030001_add_product_type_to_spree_variants.rb +5 -0
- data/db/migrate/20250502030002_add_product_type_to_spree_line_items.rb +5 -0
- data/db/migrate/20250506092929_add_trip_count_to_cm_vendor_stops.rb +5 -0
- data/docker-compose.yml +1 -1
- data/lib/generators/spree_cm_commissioner/install/install_generator.rb +11 -3
- data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_cm_commissioner → spree_dashboard/spree_cm_commissioner}/utilities.js +4 -0
- data/lib/spree_cm_commissioner/cached_inventory_item.rb +23 -0
- data/lib/spree_cm_commissioner/calendar_event.rb +11 -1
- data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_relatable_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +9 -0
- data/lib/spree_cm_commissioner/test_helper/factories/line_item_factory.rb +1 -1
- data/lib/spree_cm_commissioner/test_helper/factories/place_factory.rb +11 -1
- data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +18 -5
- data/lib/spree_cm_commissioner/test_helper/factories/stock_location_factory.rb +2 -2
- data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +39 -6
- data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -1
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +34 -0
- data/lib/tasks/create_default_non_permanent_inventory_items.rake +16 -0
- data/lib/tasks/ensure_correct_product_type.rake +7 -0
- data/lib/tasks/generate_inventory_items.rake +7 -0
- data/lib/tasks/migrate_and_rebuild_place_hierarchy.rake +9 -0
- data/lib/tasks/update_orphan_root_places.rake +7 -0
- data/spree_cm_commissioner.gemspec +5 -0
- metadata +88 -7
- data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +0 -45
- data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +0 -55
@@ -0,0 +1,54 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
class VendorStopPlaceQuery
|
3
|
+
attr_reader :query, :vendor_id, :stop_type, :reference_stop_id
|
4
|
+
|
5
|
+
def initialize(query:, vendor_id:, stop_type: :boarding, reference_stop_id: nil)
|
6
|
+
@query = query.to_s.strip
|
7
|
+
@vendor_id = vendor_id
|
8
|
+
@stop_type = stop_type
|
9
|
+
@reference_stop_id = reference_stop_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
results = vendor_stops
|
14
|
+
return [] if results.empty?
|
15
|
+
|
16
|
+
places = results.includes(:stop).map(&:stop).compact.uniq
|
17
|
+
|
18
|
+
format_places(places)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def vendor_stops
|
24
|
+
scope = base_scope
|
25
|
+
return scope if query.blank?
|
26
|
+
|
27
|
+
scope = scope.where.not(stop_id: reference_stop_id) if reference_stop_id.present?
|
28
|
+
scope.where('cm_places.name ILIKE ?', "%#{query}%")
|
29
|
+
end
|
30
|
+
|
31
|
+
def base_scope
|
32
|
+
SpreeCmCommissioner::VendorStop
|
33
|
+
.joins(:stop)
|
34
|
+
.where(vendor_id: vendor_id)
|
35
|
+
.where(stop_type: stop_type)
|
36
|
+
.order(trip_count: :desc)
|
37
|
+
.where.not(trip_count: 0)
|
38
|
+
end
|
39
|
+
|
40
|
+
def format_places(places)
|
41
|
+
places
|
42
|
+
.sort_by { |p| [-p.depth, -p.lft] }
|
43
|
+
.filter_map do |place|
|
44
|
+
next if place.depth.zero?
|
45
|
+
|
46
|
+
{
|
47
|
+
id: place.id,
|
48
|
+
parent_id: place.parent_id,
|
49
|
+
name: place.self_and_ancestors.map(&:name).reverse.join(', ')
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -3,6 +3,9 @@ module SpreeCmCommissioner
|
|
3
3
|
params do
|
4
4
|
required(:from_date).value(:date)
|
5
5
|
required(:to_date).value(:date)
|
6
|
+
required(:state_id).value(:integer)
|
7
|
+
required(:number_of_adults).value(:integer)
|
8
|
+
required(:number_of_kids).value(:integer)
|
6
9
|
end
|
7
10
|
|
8
11
|
rule(:from_date, :to_date) do
|
@@ -0,0 +1,19 @@
|
|
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
|
@@ -9,10 +9,12 @@ module Spree
|
|
9
9
|
|
10
10
|
attributes :total_inventory, :service_availabilities
|
11
11
|
|
12
|
+
# Deprecated
|
12
13
|
attribute :total_booking do |vendor|
|
13
14
|
vendor.respond_to?(:total_booking) ? vendor.total_booking : 0
|
14
15
|
end
|
15
16
|
|
17
|
+
# Deprecated
|
16
18
|
attribute :remaining do |vendor|
|
17
19
|
vendor.respond_to?(:remaining) ? vendor.remaining : vendor.total_inventory
|
18
20
|
end
|
@@ -13,6 +13,7 @@ module Spree
|
|
13
13
|
|
14
14
|
belongs_to :occupation, serializer: Spree::V2::Tenant::TaxonSerializer
|
15
15
|
belongs_to :nationality, serializer: Spree::V2::Tenant::TaxonSerializer
|
16
|
+
has_one :id_card, serializer: Spree::V2::Tenant::IdCardSerializer
|
16
17
|
|
17
18
|
# allowed_checkout updates frequently
|
18
19
|
cache_options store: nil
|
@@ -8,12 +8,13 @@ module SpreeCmCommissioner
|
|
8
8
|
IV_LENGTH = 12
|
9
9
|
TAG_LENGTH = 16
|
10
10
|
|
11
|
-
def self.encrypt(plaintext,
|
11
|
+
def self.encrypt(plaintext, base64_key)
|
12
|
+
key = Base64.decode64(base64_key)
|
12
13
|
validate_key!(key)
|
13
14
|
|
14
15
|
cipher = OpenSSL::Cipher.new(ALGORITHM)
|
15
16
|
cipher.encrypt
|
16
|
-
cipher.key = key
|
17
|
+
cipher.key = key[0, KEY_LENGTH]
|
17
18
|
iv = cipher.random_iv
|
18
19
|
cipher.iv = iv
|
19
20
|
|
@@ -24,7 +25,8 @@ module SpreeCmCommissioner
|
|
24
25
|
Base64.strict_encode64(combined)
|
25
26
|
end
|
26
27
|
|
27
|
-
def self.decrypt(encrypted_text,
|
28
|
+
def self.decrypt(encrypted_text, base64_key)
|
29
|
+
key = Base64.decode64(base64_key)
|
28
30
|
validate_key!(key)
|
29
31
|
|
30
32
|
combined = Base64.decode64(encrypted_text)
|
@@ -34,7 +36,7 @@ module SpreeCmCommissioner
|
|
34
36
|
|
35
37
|
cipher = OpenSSL::Cipher.new(ALGORITHM)
|
36
38
|
cipher.decrypt
|
37
|
-
cipher.key = key
|
39
|
+
cipher.key = key[0, KEY_LENGTH]
|
38
40
|
cipher.iv = iv
|
39
41
|
cipher.auth_tag = tag
|
40
42
|
|
@@ -48,6 +48,8 @@ module SpreeCmCommissioner
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def fetch_option_value(guest, option_type_name)
|
51
|
+
return guest.formatted_bib_number if option_type_name == 'bib-prefix'
|
52
|
+
|
51
53
|
guest.line_item&.variant&.find_option_value_name_for(option_type_name: option_type_name)
|
52
54
|
end
|
53
55
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<div>
|
2
|
+
<% events.each do |event| %>
|
3
|
+
<% inventory_item = event.options[:inventory_item] %>
|
4
|
+
|
5
|
+
<div class="mb-3">
|
6
|
+
<h6><%= inventory_item.variant.options_text %></h6>
|
7
|
+
<ul class="list-group mt-1 mb-1">
|
8
|
+
<li class="list-group-item d-flex justify-content-between align-items-center">
|
9
|
+
Max capacity
|
10
|
+
<span class="badge badge-primary badge-pill"><%= inventory_item.max_capacity %></span>
|
11
|
+
</li>
|
12
|
+
<li class="list-group-item d-flex justify-content-between align-items-center">
|
13
|
+
Quantity available in DB
|
14
|
+
<span class="badge badge-primary badge-pill"><%= inventory_item.quantity_available %></span>
|
15
|
+
</li>
|
16
|
+
</ul>
|
17
|
+
|
18
|
+
<small class="text-muted">
|
19
|
+
<%= inventory_item_message(inventory_item, @cached_inventory_items[inventory_item.id]) %>
|
20
|
+
</small>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
@@ -17,9 +17,11 @@
|
|
17
17
|
</td>
|
18
18
|
<td class="text-center d-flex flex-column align-items-center justify-content-center">
|
19
19
|
<div style="width: 90px;">
|
20
|
-
<%= form_tag
|
20
|
+
<%= form_tag admin_product_stock_managements_path(product_id: params[:product_id], variant_id: variant.id, stock_location_id: stock_location.id), method: :post do %>
|
21
21
|
<div class="input-group input-group-sm">
|
22
22
|
<%= number_field_tag 'stock_movement[quantity]', 0, class: 'form-control text-center p-0' %>
|
23
|
+
<%= hidden_field_tag 'stock_movement[originator_id]', spree_current_user.id %>
|
24
|
+
<%= hidden_field_tag 'stock_movement[originator_type]', spree_current_user.class.name %>
|
23
25
|
<div class="input-group-append">
|
24
26
|
<%= button_tag(class: 'btn btn-outline-success pl-2 pr-1') do %>
|
25
27
|
<%= svg_icon(name: 'arrow-left-right.svg', classes: "icon", width: 14, height: 14) %>
|
@@ -0,0 +1,35 @@
|
|
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
|
+
<% inventory_item = event.options[:inventory_item] %>
|
23
|
+
<% synced = inventory_item.quantity_available == @cached_inventory_items[inventory_item.id].quantity_available %>
|
24
|
+
|
25
|
+
<li class="badge <%= synced ? "badge-warning" : "badge-danger" %>">
|
26
|
+
<%= inventory_item.quantity_available %>
|
27
|
+
</li>
|
28
|
+
<% end %>
|
29
|
+
</ul>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
<% end %>
|
@@ -19,10 +19,7 @@
|
|
19
19
|
<% @variants.each do |variant| %>
|
20
20
|
<tr id="<%= spree_dom_id variant %>" data-hook="admin_product_stock_management_index_rows">
|
21
21
|
<td class="image text-center">
|
22
|
-
|
23
|
-
<div class="mt-4">
|
24
|
-
Reserved Stock: <%= @reserved_stocks[variant.id] || 0 %></strong>
|
25
|
-
</div>
|
22
|
+
<%= small_image(variant) %>
|
26
23
|
</td>
|
27
24
|
<td>
|
28
25
|
<%= variant.sku_and_options_text %>
|
@@ -35,14 +32,46 @@
|
|
35
32
|
<% end %>
|
36
33
|
</div>
|
37
34
|
<% end if can?(:update, @product) && can?(:update, variant) %>
|
35
|
+
|
36
|
+
<% if defined?(@reserved_stocks) %>
|
37
|
+
<div>
|
38
|
+
<span type="button" data-toggle="popover" data-trigger="hover" data-placement="right" data-content="This product stock will renew every day">
|
39
|
+
<%= svg_icon name: "cart-check.svg", width: '14', height: '14' %>
|
40
|
+
</span>
|
41
|
+
<%= label_tag "reserved_stock#{variant.id}", "Reserved Stock: #{@reserved_stocks[variant.id] || 0}", class: "m-0" %>
|
42
|
+
</div>
|
43
|
+
<% end %>
|
44
|
+
|
38
45
|
<% if variant.permanent_stock? %>
|
39
46
|
<div>
|
40
47
|
<span type="button" data-toggle="popover" data-trigger="hover" data-placement="right" data-content="This product stock will renew every day">
|
41
48
|
<%= svg_icon name: "info-circle-fill.svg", width: '14', height: '14' %>
|
42
49
|
</span>
|
43
|
-
<%= label_tag "permanent_stock_#{ variant.id }", Spree.t(:permanent_stock) %>
|
50
|
+
<%= label_tag "permanent_stock_#{ variant.id }", Spree.t(:permanent_stock), class: "m-0" %>
|
44
51
|
</div>
|
45
52
|
<% end %>
|
53
|
+
|
54
|
+
<% if defined?(@inventory_items) %>
|
55
|
+
<% @inventory_items[variant.id]&.each do |inventory_item| %>
|
56
|
+
<div>
|
57
|
+
<%= svg_icon name: "handbag.svg", width: '14', height: '14' %>
|
58
|
+
<%= label_tag "max_capacity_#{ inventory_item.id }", "Max capacity: #{inventory_item.max_capacity}", class: "m-0" %>
|
59
|
+
</div>
|
60
|
+
<div>
|
61
|
+
<%= svg_icon name: "approve.svg", width: '14', height: '14' %>
|
62
|
+
<%= label_tag "quantity_available_#{ inventory_item.id }", "Quantity available: #{inventory_item.quantity_available}", class: "m-0" %>
|
63
|
+
|
64
|
+
<% synced = inventory_item.quantity_available == @cached_inventory_items[inventory_item.id].quantity_available %>
|
65
|
+
<span type="button" data-toggle="popover" data-trigger="hover" data-placement="right" data-content="<%= inventory_item_message(inventory_item, @cached_inventory_items[inventory_item.id]) %>">
|
66
|
+
<% if synced %>
|
67
|
+
<%= svg_icon name: "cloud-check.svg", width: '14', height: '14', classes: 'text-success' %>
|
68
|
+
<% else %>
|
69
|
+
<%= svg_icon name: "cloud-slash.svg", width: '14', height: '14', classes: 'text-danger' %>
|
70
|
+
<% end %>
|
71
|
+
</span>
|
72
|
+
</div>
|
73
|
+
<% end %>
|
74
|
+
<% end %>
|
46
75
|
</td>
|
47
76
|
|
48
77
|
<td colspan="3" class="stock_location_info">
|
@@ -53,3 +82,9 @@
|
|
53
82
|
</tbody>
|
54
83
|
</table>
|
55
84
|
</div>
|
85
|
+
|
86
|
+
<%= turbo_frame_tag "calendar", src: calendar_admin_product_stock_managements_path(year: params[:year]) do %>
|
87
|
+
<div class="spinner-border mt-2" role="status">
|
88
|
+
<span class="sr-only">Loading...</span>
|
89
|
+
</div>
|
90
|
+
<% end if @product.permanent_stock? %>
|
data/config/routes.rb
CHANGED
@@ -138,7 +138,11 @@ Spree::Core::Engine.add_routes do
|
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
|
-
resources :stock_managements
|
141
|
+
resources :stock_managements do
|
142
|
+
collection do
|
143
|
+
get :calendar
|
144
|
+
end
|
145
|
+
end
|
142
146
|
|
143
147
|
resources :product_completion_steps do
|
144
148
|
collection do
|
@@ -519,6 +523,8 @@ Spree::Core::Engine.add_routes do
|
|
519
523
|
end
|
520
524
|
|
521
525
|
namespace :storefront do
|
526
|
+
resources :inventory_item
|
527
|
+
|
522
528
|
resources :waiting_room_sessions, only: :create
|
523
529
|
resources :vattanac_banks, only: %i[create]
|
524
530
|
resource :cart, controller: :cart, only: %i[show create destroy] do
|
@@ -544,7 +550,10 @@ Spree::Core::Engine.add_routes do
|
|
544
550
|
resource :cart_guests, only: %i[create destroy]
|
545
551
|
resources :cart_payment_method_groups, only: %i[index]
|
546
552
|
|
547
|
-
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
|
+
|
548
557
|
resources :line_items, only: %i[index show]
|
549
558
|
resources :account_checker
|
550
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,10 @@
|
|
1
|
+
class AddNestedSetColumnsToPlaces < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
add_column :cm_places, :parent_id, :integer if !column_exists?(:cm_places, :parent_id)
|
4
|
+
add_column :cm_places, :lft, :integer if !column_exists?(:cm_places, :lft)
|
5
|
+
add_column :cm_places, :rgt, :integer if !column_exists?(:cm_places, :rgt)
|
6
|
+
|
7
|
+
add_column :cm_places, :depth, :integer if !column_exists?(:cm_places, :depth)
|
8
|
+
add_column :cm_places, :children_count, :integer if !column_exists?(:cm_places, :children_count)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class CreateCmTaxonOptionTypes < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :cm_taxon_option_types do |t|
|
4
|
+
t.references :taxon, null: false, if_not_exists: true
|
5
|
+
t.references :option_type, null: false, if_not_exists: true
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class CreateCmTaxonOptionValues < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :cm_taxon_option_values do |t|
|
4
|
+
t.references :taxon, null: false, if_not_exists: true
|
5
|
+
t.references :option_value, null: false, if_not_exists: true
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
data/docker-compose.yml
CHANGED
@@ -40,9 +40,17 @@ module SpreeCmCommissioner
|
|
40
40
|
after: %r{//= require spree/backend}, verbose: true
|
41
41
|
|
42
42
|
# For NPM support
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
if File.exist?(File.join(destination_root, 'app/javascript/spree_dashboard'))
|
44
|
+
template 'app/javascript/spree_dashboard/spree_cm_commissioner/utilities.js'
|
45
|
+
inject_into_file 'app/javascript/spree_dashboard/spree-dashboard.js', "\nimport \"./spree_cm_commissioner/utilities.js\"",
|
46
|
+
after: %r{import "@spree/dashboard"}, verbose: true
|
47
|
+
else
|
48
|
+
Logger.new($stdout).debug <<~MSG
|
49
|
+
SpreeCmCommissioner: JavaScript files for the dashboard are missing.
|
50
|
+
Please move your JavaScript files to the appropriate location in
|
51
|
+
app/javascript/spree_dashboard.
|
52
|
+
MSG
|
53
|
+
end
|
46
54
|
end
|
47
55
|
|
48
56
|
def install_telegram_web_bot
|
@@ -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
|
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
|
@@ -10,5 +10,15 @@ FactoryBot.define do
|
|
10
10
|
address_components { FFaker::Address.street_address }
|
11
11
|
lat { FFaker::Geolocation.lat }
|
12
12
|
lon { FFaker::Geolocation.lng }
|
13
|
+
trait :with_parent do
|
14
|
+
association :parent, factory: :cm_place
|
15
|
+
end
|
16
|
+
transient do
|
17
|
+
children_count { 0 }
|
18
|
+
end
|
19
|
+
|
20
|
+
after(:create) do |place, evaluator|
|
21
|
+
create_list(:cm_place, evaluator.children_count, parent: place)
|
22
|
+
end
|
13
23
|
end
|
14
|
-
end
|
24
|
+
end
|
@@ -1,6 +1,19 @@
|
|
1
1
|
FactoryBot.define do
|
2
|
-
factory :
|
2
|
+
factory :cm_product_in_stock, parent: :product_in_stock do
|
3
|
+
product_type { :ecommerce }
|
4
|
+
end
|
5
|
+
|
6
|
+
factory :cm_product_with_option_types, parent: :product_with_option_types do
|
7
|
+
product_type { :ecommerce }
|
8
|
+
end
|
9
|
+
|
10
|
+
factory :cm_base_product, parent: :base_product do
|
11
|
+
product_type { :ecommerce }
|
12
|
+
end
|
13
|
+
|
14
|
+
factory :cm_product, parent: :product do
|
3
15
|
vendor { Spree::Vendor.first || create(:cm_vendor) }
|
16
|
+
product_type { :ecommerce }
|
4
17
|
|
5
18
|
before(:create) do |product|
|
6
19
|
create(:stock_location) unless Spree::StockLocation.any?
|
@@ -85,7 +98,7 @@ FactoryBot.define do
|
|
85
98
|
option_value2 = create(:cm_option_value, presentation: "#{evaluator.due_date} Days", name: evaluator.due_date.to_s, option_type: product.option_types[1])
|
86
99
|
option_value3 = create(:cm_option_value, presentation: "#{evaluator.payment_option}", name: evaluator.payment_option.to_s, option_type: product.option_types[2])
|
87
100
|
|
88
|
-
variant = create(:
|
101
|
+
variant = create(:cm_variant, price: product.price, product: product)
|
89
102
|
variant.option_values = [option_value1, option_value2, option_value3]
|
90
103
|
variant.save!
|
91
104
|
|
@@ -103,7 +116,7 @@ FactoryBot.define do
|
|
103
116
|
end
|
104
117
|
|
105
118
|
after(:create) do |product, evaluator|
|
106
|
-
variant = create(:
|
119
|
+
variant = create(:cm_variant, price: product.price, product: product)
|
107
120
|
variant.save!
|
108
121
|
|
109
122
|
variant.stock_items.first.adjust_count_on_hand(evaluator.total_inventory)
|
@@ -136,12 +149,12 @@ FactoryBot.define do
|
|
136
149
|
create(:cm_option_value, presentation: 'Yes', name: '1', option_type: product.option_types.find_by(name: 'bib-pre-generation-on-create'))
|
137
150
|
end
|
138
151
|
|
139
|
-
variant1 = create(:
|
152
|
+
variant1 = create(:cm_variant, price: product.price, product: product)
|
140
153
|
variant1.option_values = [option_value1]
|
141
154
|
variant1.option_values << bib_pre_generation_option_value if evaluator.bib_pre_generation_on_create
|
142
155
|
variant1.save!
|
143
156
|
|
144
|
-
variant2 = create(:
|
157
|
+
variant2 = create(:cm_variant, price: product.price, product: product)
|
145
158
|
variant2.option_values = [option_value2]
|
146
159
|
variant2.option_values << bib_pre_generation_option_value if evaluator.bib_pre_generation_on_create
|
147
160
|
variant2.save!
|
@@ -24,8 +24,8 @@ FactoryBot.define do
|
|
24
24
|
# variant will add itself to all stock_locations in an after_create
|
25
25
|
# creating a product will automatically create a master variant
|
26
26
|
store = Spree::Store.first || create(:store)
|
27
|
-
product_1 = create(:
|
28
|
-
product_2 = create(:
|
27
|
+
product_1 = create(:cm_product, stores: [store])
|
28
|
+
product_2 = create(:cm_product, stores: [store])
|
29
29
|
|
30
30
|
stock_location.stock_items.where(variant_id: product_1.master.id).first.adjust_count_on_hand(10)
|
31
31
|
stock_location.stock_items.where(variant_id: product_2.master.id).first.adjust_count_on_hand(20)
|