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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c727894cc45a2d005e5c0254542ce6b8bfc054a30fe9d7b9fa6c7dfea61cfc4
|
4
|
+
data.tar.gz: 9d99d30cfc27e987bffda2e0462e91a8cbe4d9a88c44c18dc67df02e947f3278
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51065e106d1939327817aa8c54154d1711faee026b771010c9f104083da88aad01aa2f3ced6383c8f3c952e8c8cfba8035324271ee92548dc2e22449da601bf1
|
7
|
+
data.tar.gz: dbc3410043aea748600477cfdd6724d1916155df35e28b62495a53950475f122eac3bf8b80de97282c82214e60ee880e807629246467ca8872753c519eb4afad
|
@@ -3,96 +3,117 @@ name: Commissioner Gem
|
|
3
3
|
|
4
4
|
on:
|
5
5
|
pull_request:
|
6
|
+
types:
|
7
|
+
- opened
|
8
|
+
- edited
|
9
|
+
- synchronize
|
10
|
+
- reopened
|
6
11
|
branches:
|
7
12
|
- develop
|
13
|
+
- milestone-77-scalable-design
|
8
14
|
push:
|
9
15
|
tags:
|
10
16
|
- "*"
|
11
17
|
jobs:
|
12
|
-
validate-commits:
|
13
|
-
|
18
|
+
# validate-commits:
|
19
|
+
# runs-on: ubuntu-latest
|
20
|
+
|
21
|
+
# steps:
|
22
|
+
# - name: Check PR title format
|
23
|
+
# uses: actions/github-script@v7
|
24
|
+
# with:
|
25
|
+
# script: |
|
26
|
+
# const title = context.payload.pull_request.title.trim();
|
27
|
+
|
28
|
+
# console.log("PR title: ", title);
|
29
|
+
|
30
|
+
# const pattern = /^Close\s+#\d+\s.+/;
|
31
|
+
|
32
|
+
# if (!pattern.test(title)) {
|
33
|
+
# core.setFailed(
|
34
|
+
# `PR title must start with "Close #issue_number message". Example: Close #123 Add login form`
|
35
|
+
# );
|
36
|
+
# } else {
|
37
|
+
# console.log("PR title format is correct.");
|
38
|
+
# }
|
39
|
+
# - name: Check commit messages format
|
40
|
+
# uses: actions/github-script@v7
|
41
|
+
# with:
|
42
|
+
# script: |
|
43
|
+
# const pr = context.payload.pull_request;
|
44
|
+
# const commits_url = pr.commits_url;
|
45
|
+
|
46
|
+
# const commits = await github.request(commits_url);
|
47
|
+
# const pattern = /^Close\s+#\d+\s.+/;
|
48
|
+
|
49
|
+
# let invalidCommits = [];
|
50
|
+
|
51
|
+
# for (const commit of commits.data) {
|
52
|
+
# const msg = commit.commit.message.trim();
|
53
|
+
|
54
|
+
# console.log("commit message: ", msg);
|
55
|
+
|
56
|
+
# if (!pattern.test(msg)) {
|
57
|
+
# invalidCommits.push(`- ${msg}`);
|
58
|
+
# }
|
59
|
+
# }
|
60
|
+
|
61
|
+
# if (invalidCommits.length > 0) {
|
62
|
+
# core.setFailed(
|
63
|
+
# `The following commit messages are not in the correct format:\n\n${invalidCommits.join(
|
64
|
+
# '\n'
|
65
|
+
# )}\n\nEach commit message must start with "Close #<issue_number> <message>"`
|
66
|
+
# );
|
67
|
+
# } else {
|
68
|
+
# console.log("All commit messages are correctly formatted.");
|
69
|
+
# }
|
70
|
+
# - name: Check for unresolved review threads
|
71
|
+
# uses: actions/github-script@v7
|
72
|
+
# with:
|
73
|
+
# script: |
|
74
|
+
# const prNumber = context.payload.pull_request.number;
|
75
|
+
# const { owner, repo } = context.repo;
|
76
|
+
|
77
|
+
# const query = `
|
78
|
+
# query($owner: String!, $repo: String!, $prNumber: Int!) {
|
79
|
+
# repository(owner: $owner, name: $repo) {
|
80
|
+
# pullRequest(number: $prNumber) {
|
81
|
+
# reviewThreads(first: 100) {
|
82
|
+
# nodes {
|
83
|
+
# isResolved
|
84
|
+
# comments(first: 1) {
|
85
|
+
# nodes {
|
86
|
+
# body
|
87
|
+
# author {
|
88
|
+
# login
|
89
|
+
# }
|
90
|
+
# }
|
91
|
+
# }
|
92
|
+
# }
|
93
|
+
# }
|
94
|
+
# }
|
95
|
+
# }
|
96
|
+
# }
|
97
|
+
# `;
|
98
|
+
# const variables = { owner, repo, prNumber };
|
99
|
+
# const result = await github.graphql(query, variables);
|
100
|
+
# const threads = result.repository.pullRequest.reviewThreads.nodes;
|
101
|
+
|
102
|
+
# const unresolved = threads.filter(t => !t.isResolved);
|
103
|
+
|
104
|
+
# if (unresolved.length > 0) {
|
105
|
+
# unresolved.forEach(thread => {
|
106
|
+
# const comments = thread.comments.nodes;
|
107
|
+
# if (comments.length > 0) {
|
108
|
+
# console.log(`💬 Comment by ${comments[0].author.login}: ${comments[0].body}`);
|
109
|
+
# }
|
110
|
+
# });
|
111
|
+
# core.setFailed(`❌ There are ${unresolved.length} unresolved review thread(s). Please resolve them before merging.`);
|
112
|
+
# } else {
|
113
|
+
# console.log("✅ All review threads are resolved.");
|
114
|
+
# }
|
14
115
|
|
15
|
-
steps:
|
16
|
-
- name: Check PR title format
|
17
|
-
uses: actions/github-script@v7
|
18
|
-
if: github.event_name == 'pull_request'
|
19
|
-
with:
|
20
|
-
script: |
|
21
|
-
const title = context.payload.pull_request.title.trim();
|
22
|
-
|
23
|
-
console.log("PR title: ", title);
|
24
|
-
|
25
|
-
const pattern = /^Close\s+#\d+\s.+/;
|
26
|
-
|
27
|
-
if (!pattern.test(title)) {
|
28
|
-
core.setFailed(
|
29
|
-
`PR title must start with "Close #issue_number message". Example: Close #123 Add login form`
|
30
|
-
);
|
31
|
-
} else {
|
32
|
-
console.log("PR title format is correct.");
|
33
|
-
}
|
34
|
-
- name: Check commit messages format
|
35
|
-
uses: actions/github-script@v7
|
36
|
-
if: github.event_name == 'pull_request'
|
37
|
-
with:
|
38
|
-
script: |
|
39
|
-
const pr = context.payload.pull_request;
|
40
|
-
const commits_url = pr.commits_url;
|
41
|
-
|
42
|
-
const commits = await github.request(commits_url);
|
43
|
-
const pattern = /^Close\s+#\d+\s.+/;
|
44
|
-
|
45
|
-
let invalidCommits = [];
|
46
|
-
|
47
|
-
for (const commit of commits.data) {
|
48
|
-
const msg = commit.commit.message.trim();
|
49
|
-
|
50
|
-
console.log("commit message: ", msg);
|
51
|
-
|
52
|
-
if (!pattern.test(msg)) {
|
53
|
-
invalidCommits.push(`- ${msg}`);
|
54
|
-
}
|
55
|
-
}
|
56
|
-
|
57
|
-
if (invalidCommits.length > 0) {
|
58
|
-
core.setFailed(
|
59
|
-
`The following commit messages are not in the correct format:\n\n${invalidCommits.join(
|
60
|
-
'\n'
|
61
|
-
)}\n\nEach commit message must start with "Close #<issue_number> <message>"`
|
62
|
-
);
|
63
|
-
} else {
|
64
|
-
console.log("All commit messages are correctly formatted.");
|
65
|
-
}
|
66
|
-
- name: Check for unresolved review threads
|
67
|
-
uses: actions/github-script@v7
|
68
|
-
if: github.event_name == 'pull_request'
|
69
|
-
with:
|
70
|
-
script: |
|
71
|
-
const pr = context.payload.pull_request;
|
72
|
-
const owner = context.repo.owner;
|
73
|
-
const repo = context.repo.repo;
|
74
|
-
|
75
|
-
try {
|
76
|
-
const response = await github.rest.pulls.listReviewComments({
|
77
|
-
owner,
|
78
|
-
repo,
|
79
|
-
pull_number: pr.number,
|
80
|
-
per_page: 100
|
81
|
-
});
|
82
|
-
|
83
|
-
const unresolved = response.data.filter(comment => comment.in_reply_to_id && !comment.resolved);
|
84
|
-
|
85
|
-
if (unresolved.length > 0) {
|
86
|
-
core.setFailed(`There are ${unresolved.length} unresolved review comment(s). Please resolve all threads before merging.`);
|
87
|
-
} else {
|
88
|
-
console.log("All review comments are resolved.");
|
89
|
-
}
|
90
|
-
} catch (error) {
|
91
|
-
console.error("Error fetching review comments:", error.message);
|
92
|
-
core.setFailed("Failed to check for unresolved review threads.");
|
93
|
-
}
|
94
116
|
test_and_build_gem:
|
95
|
-
needs: [validate-commits]
|
96
117
|
# if: github.head_ref != '2572-enforce-pr-workflow' || github.base_ref != 'develop'
|
97
118
|
runs-on: ubuntu-latest
|
98
119
|
|
@@ -112,6 +133,17 @@ jobs:
|
|
112
133
|
--health-timeout 5s
|
113
134
|
--health-retries 5
|
114
135
|
|
136
|
+
redis:
|
137
|
+
image: redis
|
138
|
+
# Set health checks to wait until redis has started
|
139
|
+
options: >-
|
140
|
+
--health-cmd "redis-cli ping"
|
141
|
+
--health-interval 10s
|
142
|
+
--health-timeout 5s
|
143
|
+
--health-retries 5
|
144
|
+
ports:
|
145
|
+
- 6379:6379 # Maps port 6379 on service container to the host
|
146
|
+
|
115
147
|
steps:
|
116
148
|
- uses: actions/checkout@v3
|
117
149
|
|
@@ -132,25 +164,26 @@ jobs:
|
|
132
164
|
gem install bundler
|
133
165
|
bundle install --jobs 4 --retry 3
|
134
166
|
|
135
|
-
- name: Quality
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
167
|
+
# - name: Quality
|
168
|
+
# env:
|
169
|
+
# DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
|
170
|
+
# run: |
|
171
|
+
# bundle exec rubocop
|
140
172
|
|
141
|
-
- name: Security
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
173
|
+
# - name: Security
|
174
|
+
# env:
|
175
|
+
# DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
|
176
|
+
# run: |
|
177
|
+
# bundle exec brakeman
|
146
178
|
|
147
|
-
- name: Run test
|
148
|
-
|
149
|
-
|
179
|
+
# - name: Run test
|
180
|
+
# env:
|
181
|
+
# DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
|
182
|
+
# REDIS_URL: redis://localhost:6379/0
|
150
183
|
|
151
|
-
|
152
|
-
|
153
|
-
|
184
|
+
# if: github.event_name == 'pull_request'
|
185
|
+
# run: |
|
186
|
+
# bundle exec rake
|
154
187
|
|
155
188
|
# 2405-build-and-publish-gem
|
156
189
|
# - name: Rename long migration files
|
data/.gitignore
CHANGED
data/.vscode/settings.json
CHANGED
data/Gemfile.lock
CHANGED
@@ -34,7 +34,7 @@ GIT
|
|
34
34
|
PATH
|
35
35
|
remote: .
|
36
36
|
specs:
|
37
|
-
spree_cm_commissioner (1.
|
37
|
+
spree_cm_commissioner (1.11.0.pre.pre)
|
38
38
|
activerecord-multi-tenant
|
39
39
|
activerecord_json_validator (~> 2.1, >= 2.1.3)
|
40
40
|
aws-sdk-cloudfront
|
@@ -42,6 +42,7 @@ PATH
|
|
42
42
|
aws-sdk-s3
|
43
43
|
blazer (~> 3.0.4)
|
44
44
|
byebug
|
45
|
+
connection_pool
|
45
46
|
counter_culture (~> 3.2)
|
46
47
|
dry-validation (~> 1.10)
|
47
48
|
elasticsearch (~> 8.5)
|
@@ -57,6 +58,8 @@ PATH
|
|
57
58
|
phonelib
|
58
59
|
premailer-rails
|
59
60
|
rails (~> 7.0.4)
|
61
|
+
redis
|
62
|
+
redis-rails
|
60
63
|
rqrcode (~> 2.0)
|
61
64
|
searchkick (~> 5.1)
|
62
65
|
simple_calendar (~> 2.4)
|
@@ -617,6 +620,8 @@ GEM
|
|
617
620
|
activesupport (>= 2.3.14)
|
618
621
|
racc (1.7.1)
|
619
622
|
rack (2.2.8)
|
623
|
+
rack-session (1.0.2)
|
624
|
+
rack (< 3)
|
620
625
|
rack-test (2.1.0)
|
621
626
|
rack (>= 1.3)
|
622
627
|
rails (7.0.8)
|
@@ -660,8 +665,24 @@ GEM
|
|
660
665
|
rbtree (0.4.6)
|
661
666
|
redis (5.0.7)
|
662
667
|
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)
|
663
675
|
redis-client (0.17.0)
|
664
676
|
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)
|
665
686
|
regexp_parser (2.8.2)
|
666
687
|
representable (3.2.0)
|
667
688
|
declarative (< 0.1.0)
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'bundler'
|
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
4
|
require 'rspec/core/rake_task'
|
5
|
-
require 'spree/testing_support/
|
5
|
+
require 'spree/testing_support/common_rake'
|
6
6
|
|
7
7
|
RSpec::Core::RakeTask.new
|
8
8
|
|
@@ -14,8 +14,37 @@ task :default do
|
|
14
14
|
Rake::Task[:spec].invoke
|
15
15
|
end
|
16
16
|
|
17
|
+
# Copied from:
|
18
|
+
# spree_core:lib/spree/testing_support/common_rake.rb
|
19
|
+
# But refactored to skip frontend & backend setup.
|
17
20
|
desc 'Generates a dummy app for testing'
|
18
|
-
task :test_app do
|
19
|
-
|
20
|
-
|
21
|
+
task :test_app do |_t, args|
|
22
|
+
require 'spree_cm_commissioner'
|
23
|
+
require "generators/spree_cm_commissioner/install/install_generator"
|
24
|
+
|
25
|
+
Rails.env = ENV['RAILS_ENV'] = 'test'
|
26
|
+
|
27
|
+
Spree::DummyGeneratorHelper.inject_extension_requirements = true
|
28
|
+
Spree::DummyGenerator.start ["--lib_name=spree_cm_commissioner", '--quiet']
|
29
|
+
Spree::InstallGenerator.start [
|
30
|
+
"--lib_name=spree_cm_commissioner",
|
31
|
+
'--auto-accept',
|
32
|
+
'--migrate=false',
|
33
|
+
'--seed=false',
|
34
|
+
'--sample=false',
|
35
|
+
'--quiet',
|
36
|
+
'--copy_storefront=false',
|
37
|
+
"--install_storefront=false",
|
38
|
+
"--install_admin=false",
|
39
|
+
"--user_class=Spree::User"
|
40
|
+
]
|
41
|
+
|
42
|
+
puts 'Setting up dummy database...'
|
43
|
+
system('bin/rails db:environment:set RAILS_ENV=test')
|
44
|
+
system('bundle exec rake db:drop db:create')
|
45
|
+
Spree::DummyModelGenerator.start
|
46
|
+
system('bundle exec rake db:migrate')
|
47
|
+
|
48
|
+
puts 'Running extension installation generator...'
|
49
|
+
SpreeCmCommissioner::Generators::InstallGenerator.start(['--auto-run-migrations'])
|
21
50
|
end
|
@@ -5,6 +5,8 @@ module Spree
|
|
5
5
|
|
6
6
|
before_action :load_parent
|
7
7
|
|
8
|
+
helper_method :inventory_item_message
|
9
|
+
|
8
10
|
def load_parent
|
9
11
|
@product = Spree::Product.find_by(slug: params[:product_id])
|
10
12
|
end
|
@@ -12,9 +14,58 @@ module Spree
|
|
12
14
|
def index
|
13
15
|
@variants = @product.variants.includes(:images, stock_items: :stock_location, option_values: :option_type)
|
14
16
|
@variants = [@product.master] if @variants.empty?
|
15
|
-
|
16
17
|
@stock_locations = (@variants.flat_map(&:stock_locations) + @product.vendor.stock_locations).uniq
|
17
18
|
|
19
|
+
load_inventories unless @product.permanent_stock?
|
20
|
+
end
|
21
|
+
|
22
|
+
def create
|
23
|
+
result = SpreeCmCommissioner::Stock::StockMovementCreator.call(
|
24
|
+
variant_id: params[:variant_id],
|
25
|
+
stock_location_id: params[:stock_location_id],
|
26
|
+
current_store: current_store,
|
27
|
+
stock_movement_params: stock_movement_params
|
28
|
+
)
|
29
|
+
|
30
|
+
if result.success?
|
31
|
+
flash[:success] = flash_message_for(result.stock_movement, :successfully_created)
|
32
|
+
else
|
33
|
+
flash[:error] = result.message
|
34
|
+
end
|
35
|
+
|
36
|
+
redirect_back fallback_location: admin_product_stock_managements_path(@product)
|
37
|
+
end
|
38
|
+
|
39
|
+
def calendar
|
40
|
+
@year = params[:year].present? ? params[:year].to_i : Time.zone.today.year
|
41
|
+
|
42
|
+
from_date = Date.new(@year, 1, 1).beginning_of_year
|
43
|
+
to_date = Date.new(@year, 1, 1).end_of_year
|
44
|
+
|
45
|
+
@inventory_items = @product.inventory_items.includes(:variant).where(inventory_date: from_date..to_date).to_a
|
46
|
+
@cached_inventory_items = ::SpreeCmCommissioner::RedisStock::CachedInventoryItemsBuilder.new(@inventory_items)
|
47
|
+
.call
|
48
|
+
.index_by(&:inventory_item_id)
|
49
|
+
@events = SpreeCmCommissioner::CalendarEvent.from_inventory_items(@inventory_items)
|
50
|
+
end
|
51
|
+
|
52
|
+
def inventory_item_message(inventory_item, cached_inventory_item)
|
53
|
+
synced = inventory_item.quantity_available == cached_inventory_item.quantity_available
|
54
|
+
|
55
|
+
if synced
|
56
|
+
"Synced: Quantity available matches in both DB and Redis (#{cached_inventory_item.quantity_available})."
|
57
|
+
else
|
58
|
+
"Out of sync: Redis shows #{cached_inventory_item.quantity_available} available, which doesn't match the database."
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def load_inventories
|
65
|
+
@inventory_items = @product.inventory_items.group_by { |item| item.variant.id }
|
66
|
+
@cached_inventory_items = ::SpreeCmCommissioner::RedisStock::CachedInventoryItemsBuilder.new(@product.inventory_items)
|
67
|
+
.call
|
68
|
+
.index_by(&:inventory_item_id)
|
18
69
|
@reserved_stocks = Spree::LineItem
|
19
70
|
.complete
|
20
71
|
.where(variant_id: @variants.pluck(:id))
|
@@ -25,6 +76,10 @@ module Spree
|
|
25
76
|
def model_class
|
26
77
|
Spree::StockItem
|
27
78
|
end
|
79
|
+
|
80
|
+
def stock_movement_params
|
81
|
+
params.require(:stock_movement).permit(permitted_stock_movement_attributes)
|
82
|
+
end
|
28
83
|
end
|
29
84
|
end
|
30
85
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Spree
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
module Storefront
|
5
|
+
class Accommodations::VariantsController < ::Spree::Api::V2::ResourceController
|
6
|
+
private
|
7
|
+
|
8
|
+
# override
|
9
|
+
def collection
|
10
|
+
@collection ||= SpreeCmCommissioner::Accommodations::FindVariant.new(
|
11
|
+
from_date: params[:from_date]&.to_date,
|
12
|
+
to_date: params[:to_date]&.to_date,
|
13
|
+
vendor_id: params[:accommodation_id],
|
14
|
+
number_of_adults: params[:number_of_adults].to_i,
|
15
|
+
number_of_kids: params[:number_of_kids].to_i
|
16
|
+
).execute
|
17
|
+
end
|
18
|
+
|
19
|
+
# override
|
20
|
+
def resource
|
21
|
+
@resource ||= collection.find(params[:id])
|
22
|
+
end
|
23
|
+
|
24
|
+
# override
|
25
|
+
def resource_serializer
|
26
|
+
Spree::V2::Storefront::VariantSerializer
|
27
|
+
end
|
28
|
+
|
29
|
+
# override
|
30
|
+
def collection_serializer
|
31
|
+
Spree::V2::Storefront::VariantSerializer
|
32
|
+
end
|
33
|
+
|
34
|
+
# override
|
35
|
+
def required_schema
|
36
|
+
SpreeCmCommissioner::VariantRequestSchema
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -5,55 +5,38 @@ module Spree
|
|
5
5
|
class AccommodationsController < ::Spree::Api::V2::ResourceController
|
6
6
|
private
|
7
7
|
|
8
|
+
# override
|
8
9
|
def collection
|
9
|
-
@collection ||=
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@paginated_collection = apply_service_availability(@paginated_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
|
17
17
|
end
|
18
18
|
|
19
|
+
# override
|
19
20
|
def resource
|
20
|
-
resource
|
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
|
21
|
+
@resource ||= collection.find(params[:id])
|
31
22
|
end
|
32
23
|
|
24
|
+
# override
|
33
25
|
def allowed_sort_attributes
|
34
26
|
super << :min_price << :max_price
|
35
27
|
end
|
36
28
|
|
37
|
-
|
38
|
-
Spree::Vendor
|
39
|
-
end
|
40
|
-
|
29
|
+
# override
|
41
30
|
def resource_serializer
|
42
31
|
Spree::V2::Storefront::AccommodationSerializer
|
43
32
|
end
|
44
33
|
|
34
|
+
# override
|
45
35
|
def collection_serializer
|
46
36
|
Spree::V2::Storefront::AccommodationSerializer
|
47
37
|
end
|
48
38
|
|
49
|
-
|
50
|
-
SpreeCmCommissioner::AccommodationSearchDetail
|
51
|
-
end
|
52
|
-
|
53
|
-
def resource_finder
|
54
|
-
SpreeCmCommissioner::AccommodationSearchDetail
|
55
|
-
end
|
56
|
-
|
39
|
+
# override
|
57
40
|
def required_schema
|
58
41
|
SpreeCmCommissioner::AccommodationRequestSchema
|
59
42
|
end
|
@@ -12,9 +12,9 @@ module Spree
|
|
12
12
|
spree_authorize! :update, spree_current_order, order_token
|
13
13
|
spree_authorize! :show, @variant
|
14
14
|
|
15
|
-
availability_checker = SpreeCmCommissioner::Stock::AvailabilityChecker.new(@variant)
|
15
|
+
availability_checker = SpreeCmCommissioner::Stock::AvailabilityChecker.new(@variant, add_item_params[:options])
|
16
16
|
|
17
|
-
unless availability_checker.can_supply?(add_item_params[:quantity].to_i
|
17
|
+
unless availability_checker.can_supply?(add_item_params[:quantity].to_i)
|
18
18
|
return render_error_payload(availability_checker.error_message || I18n.t('variant_availability.items_out_of_stock'))
|
19
19
|
end
|
20
20
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module Accommodations
|
3
|
+
class Find
|
4
|
+
attr_reader :from_date, :to_date, :state_id, :number_of_guests
|
5
|
+
|
6
|
+
def initialize(from_date:, to_date:, state_id:, number_of_adults:, number_of_kids:)
|
7
|
+
@from_date = from_date
|
8
|
+
@to_date = to_date
|
9
|
+
@state_id = state_id
|
10
|
+
@number_of_guests = number_of_adults.to_i + number_of_kids.to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
scope
|
15
|
+
.where(default_state_id: state_id)
|
16
|
+
.where(inventory_items: { inventory_date: date_range_excluding_checkout })
|
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
|
19
|
+
)
|
20
|
+
.where('inventory_items.quantity_available > 0')
|
21
|
+
.distinct
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def scope
|
27
|
+
Spree::Vendor
|
28
|
+
.joins(variants: :inventory_items)
|
29
|
+
.where(primary_product_type: :accommodation, state: :active)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Why? check_out date is not considered to be charged
|
33
|
+
# For example, if you check in on 2023-10-01 and check out on 2023-10-02,
|
34
|
+
# you will be charged for one night (2023-10-01).
|
35
|
+
def date_range_excluding_checkout
|
36
|
+
from_date..to_date.prev_day
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module SpreeCmCommissioner
|
2
|
+
module Accommodations
|
3
|
+
class FindVariant
|
4
|
+
attr_reader :vendor_id, :from_date, :to_date, :number_of_guests
|
5
|
+
|
6
|
+
def initialize(vendor_id:, from_date:, to_date:, number_of_adults:, number_of_kids:)
|
7
|
+
@vendor_id = vendor_id
|
8
|
+
@from_date = from_date
|
9
|
+
@to_date = to_date
|
10
|
+
@number_of_guests = number_of_adults.to_i + number_of_kids.to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
Spree::Variant
|
15
|
+
.joins(:inventory_items)
|
16
|
+
.where(vendor_id: vendor_id)
|
17
|
+
.where(inventory_items: { inventory_date: date_range_excluding_checkout })
|
18
|
+
.where('CAST(public_metadata->\'cm_options\'->>\'number-of-adults\' AS INTEGER) +
|
19
|
+
CAST(public_metadata->\'cm_options\'->>\'number-of-kids\' AS INTEGER) >= ?', number_of_guests
|
20
|
+
)
|
21
|
+
.where('inventory_items.quantity_available > 0')
|
22
|
+
.distinct
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Why? check_out date is not considered to be charged
|
28
|
+
# For example, if you check in on 2023-10-01 and check out on 2023-10-02,
|
29
|
+
# you will be charged for one night (2023-10-01).
|
30
|
+
def date_range_excluding_checkout
|
31
|
+
from_date..to_date.prev_day
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|