Compare commits

...

384 Commits

Author SHA1 Message Date
filipefurtad0
c08f925ff8 Update all locales with the latest Transifex translations 2025-01-30 22:03:47 -06:00
Filipe
54fad01a91 Merge pull request #13104 from mkllnk/test-seeds
Remove unused preference default_country_id
2025-01-30 21:59:46 -06:00
Filipe
32c4b4557b Merge pull request #13086 from rioug/fix-tax-rate-refund
Remove tax rate refund code path
2025-01-30 21:54:30 -06:00
Filipe
e2161660b3 Merge pull request #13090 from mkllnk/replace-spree-roles
Replace spree roles
2025-01-30 21:30:56 -06:00
Maikel
139dba6637 Merge pull request #13108 from dacook/reduce-rack-timeout-logs
Log rack-timeout ready and completed messages in DEBUG mode
2025-01-31 10:49:41 +11:00
David Cook
a0833af780 Log rack-timeout ready and completed messages in DEBUG mode
Instead of default INFO, because it pollutes the logs unnecessarily.

Error messages will still be logged the same as before.
2025-01-30 10:20:58 +11:00
Maikel
0797614769 Merge pull request #13106 from openfoodfoundation/dependabot/npm_and_yarn/tom-select-2.4.2
chore(deps): bump tom-select from 2.4.1 to 2.4.2
2025-01-30 08:51:23 +11:00
dependabot[bot]
c84881252c chore(deps): bump tom-select from 2.4.1 to 2.4.2
Bumps [tom-select](https://github.com/orchidjs/tom-select) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/orchidjs/tom-select/releases)
- [Commits](https://github.com/orchidjs/tom-select/compare/v2.4.1...v2.4.2)

---
updated-dependencies:
- dependency-name: tom-select
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-29 09:19:24 +00:00
Gaetan Craig-Riou
1ee2f4d18e Merge pull request #13103 from mkllnk/gmaps-region-code
Simplify default country code lookup
2025-01-29 09:54:43 +11:00
Maikel Linke
6885184bcc Remove unused preference default_country_id 2025-01-28 16:31:45 +11:00
Maikel Linke
1a393592b4 Reduce database writes seeding zones 2025-01-28 15:47:32 +11:00
Maikel
f8e55f1eb3 Merge pull request #13098 from cillian/osm-marker-positioning
Specify OpenStreetMap marker size and tip position so they are positioned correctly at all zoom levels
2025-01-28 13:40:18 +11:00
Maikel Linke
e1f62148c9 Remove now unnecessary country seeding for assets 2025-01-28 13:26:42 +11:00
Maikel Linke
ea6efa9164 Simplify default country code lookup
The code was using the code from the environment variables to load a
reocrd from the database to then return the initial code again.

The only use of `DefaultCountry.code` is currently in the geocoder JS
compilation. Now it doesn't need the database anymore.
2025-01-28 13:22:26 +11:00
Maikel
4b6c3fe1d0 Merge pull request #13099 from rioug/compile-test-asset-path
Specify test assets output path
2025-01-28 10:58:41 +11:00
Gaetan Craig-Riou
3bf01602d9 Specify test assets output path
Test assets need to be compiled to a specific path for system test
to work. It was mistakenly remove here :
https://github.com/openfoodfoundation/openfoodnetwork/pull/13096/files#diff-46b7721b943217c3670f6818a10c2661ec1f9f72dfea66469fd9f026dc74c36a
2025-01-27 14:14:54 +11:00
Gaetan Craig-Riou
fa4785bc85 Merge pull request #13096 from mkllnk/assets
Compile assets on demand in test local environment
2025-01-27 13:00:10 +11:00
Gaetan Craig-Riou
6fb86dd4ac Merge pull request #13093 from mkllnk/dfc-token-error
Handle wrong OIDC tokens gracefully
2025-01-27 12:56:23 +11:00
Gaetan Craig-Riou
c4d74ac10d Apply Rubocop linting 2025-01-27 11:03:54 +11:00
Gaetan Craig-Riou
6ef73acfcd Fix seeding file for Spree::Zones 2025-01-27 11:03:48 +11:00
David Cook
ffad3f249b Update comment
See: https://github.com/openfoodfoundation/openfoodnetwork/blob/master/spec/system/admin/adjustments_spec.rb
2025-01-27 11:02:50 +11:00
Gaetan Craig-Riou
be78c2ac41 Fix system admin adjustment spec 2025-01-27 11:02:50 +11:00
Gaetan Craig-Riou
900b751559 Revert change from d58aa2b14f44fa15b67a18cf3457eccaaca5a56c
Turns out there seem to be a legitimate use for this code, see
spec/system/admin/adjustments_spec.rb ie, adding a manual discount to an
order using an adjustment.
2025-01-27 11:02:50 +11:00
Gaetan Craig-Riou
cd7e92c6ca Fix various spec 2025-01-27 11:02:41 +11:00
Gaetan Craig-Riou
6b7373e4cf Clean up spec syntax 2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
6e8eb443c1 Consolidate .adjust specs 2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
42df158669 Fix TaxRate#compute_amount
Remove the code path that can create a tax refund, it is unlikely to
happen with the configuration our instances are using. Instead return 0
do that no adjustment gets created
2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
5e42a9be55 Fix TaxRate spec to work with the zone changes 2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
d4a060c6a2 Fix Zone system spec 2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
f7998f6570 Fix zone new form to allow adding state or country 2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
a953e3dde3 Fix Spree::Zone spec and factory 2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
75c0752340 Sree::Zone, require at least one member
Add validations and specs
2025-01-27 11:01:07 +11:00
Gaetan Craig-Riou
bcb4525cdd Clean up spec, use describe instead of context
Although `describe` and `context` are functionally equivalent, they
don't convey the same message
2025-01-27 11:01:07 +11:00
Cillian O'Ruanaidh
ff7c1e6d1f Specify OpenStreetMap marker size and tip position so they are positioned correctly at all zoom levels 2025-01-25 12:55:48 +00:00
Konrad
01036e6321 Merge pull request #13087 from mkllnk/stock-location
Remove class Spree::StockLocation
2025-01-25 12:41:37 +01:00
Maikel Linke
95625c16b2 Comment on seeds 2025-01-24 16:55:19 +11:00
Maikel Linke
690d137971 Combine rake tasks for efficiency 2025-01-24 16:54:56 +11:00
David Cook
09fe6d7542 Merge pull request #13091 from mkllnk/flaky-ship
Fix flaky spec of order shipment
2025-01-24 15:02:19 +11:00
David Cook
f6bd1c49ee Apply suggestions from code review 2025-01-24 14:52:54 +11:00
David Cook
bb040812aa Refactor spec 2025-01-24 14:49:18 +11:00
David Cook
e38d305ca1 Merge pull request #13089 from mkllnk/haml-up-remove
Remove unneeded HAML upgrade script
2025-01-24 14:23:56 +11:00
David Cook
46c92db415 Merge pull request #13088 from mkllnk/controller-helpers
Remove unused helper module
2025-01-24 14:22:46 +11:00
filipefurtad0
3e4d689903 Update all locales with the latest Transifex translations 2025-01-23 19:51:48 -06:00
Filipe
adf1c63c11 Merge pull request #13072 from rioug/update-action-cable-config
Update ActionCable config
2025-01-23 19:24:44 -06:00
Maikel Linke
f21f8f38da Compile assets on demand in test environment
We still do it in CI to prevent flaky specs. Otherwise, when a spec
needs to compile assets, it may time out.
2025-01-24 12:10:09 +11:00
Filipe
5d360730c7 Merge pull request #13023 from rioug/12907-fix-checkout-shipping-fee
[Checkout] Shipping fees update, remove order callback
2025-01-23 18:50:31 -06:00
Maikel Linke
8636d3fc00 Handle wrong OIDC tokens gracefully
If you copy and paste only part of a token then a general DecodeError is
raised. It's the parent class for all other related errors like for
expired signatures.

Now we just fail authentication instead of raising a server error.
2025-01-24 09:01:04 +11:00
Maikel Linke
7b8b7b6bbc Satisfy Rubocop on new migrations 2025-01-23 08:39:40 +11:00
Maikel
2d77b54685 Merge pull request #13092 from openfoodfoundation/dependabot/npm_and_yarn/leaflet-geosearch-4.1.0
chore(deps): bump leaflet-geosearch from 4.0.0 to 4.1.0
2025-01-23 08:38:09 +11:00
Konrad
0b8807146e Merge pull request #13058 from mkllnk/currency-config
Remove unused app config options
2025-01-22 11:27:12 +01:00
dependabot[bot]
486af8f58b chore(deps): bump leaflet-geosearch from 4.0.0 to 4.1.0
Bumps [leaflet-geosearch](https://github.com/smeijer/leaflet-geosearch) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/smeijer/leaflet-geosearch/releases)
- [Commits](https://github.com/smeijer/leaflet-geosearch/compare/v4.0.0...v4.1.0)

---
updated-dependencies:
- dependency-name: leaflet-geosearch
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-22 09:57:36 +00:00
Maikel
c258bee44d Merge pull request #13065 from mkllnk/dfc-amend-nothing
Admin updates can trigger new backorders until the order cycle is closed
2025-01-22 16:32:23 +11:00
Maikel Linke
c975a2c8c4 Fix flaky spec of order shipment
I found that a delay in the reflex handling the request could fail the
spec. Added a sleep in the reflex to reproduce the fail. The I added
expectations for the page content to wait until the page was updated and
that fixed the specs.
2025-01-22 15:34:09 +11:00
Maikel Linke
ea9a5c8dd5 Remove class Spree::Role 2025-01-22 14:59:49 +11:00
Maikel Linke
d49cea5e3d Use admin flag instead of user role 2025-01-22 14:59:49 +11:00
Maikel Linke
920002e084 Copy admin attribute to users 2025-01-22 14:05:50 +11:00
Maikel Linke
698d1daa57 Add admin attribute to users 2025-01-22 14:05:23 +11:00
Maikel Linke
f8f6c80aa9 Remove unused helper module
SimpleCov says that it's not used. So let's see about that. If any
included helpers are used, we can bring them back individually.
2025-01-22 13:51:35 +11:00
Maikel Linke
a2459a3742 Remove class Spree::StockLocation
The database table is still there and can stay for a while until we are
confident that nothing is broken in production.
2025-01-22 12:09:17 +11:00
Maikel Linke
64608beaa8 Remove DefaultStockLocation created in setup 2025-01-22 12:01:57 +11:00
Maikel Linke
187a78b78d Remove stock location from add-variant JS 2025-01-22 11:58:15 +11:00
Maikel Linke
70ebe7b964 Remove stock location from specs 2025-01-22 11:52:25 +11:00
Maikel Linke
33ed0998a9 Removing old references to stock location 2025-01-22 11:34:54 +11:00
Maikel Linke
f098327808 Remove now useless wrapper method 2025-01-22 11:31:27 +11:00
Maikel Linke
c27aa00bed Make old migration independent of app code 2025-01-22 11:25:58 +11:00
Maikel Linke
8e15d571e7 Remove StockLocation from Packer 2025-01-22 11:20:05 +11:00
Maikel Linke
d5ff1f5c71 Remove StockItem#stock_location 2025-01-22 11:20:05 +11:00
Maikel Linke
87d20877ad Remove Shipment#stock_location 2025-01-22 11:20:05 +11:00
Maikel Linke
33c6f3b94f Remove StockLocation#stock_item 2025-01-22 11:20:05 +11:00
Maikel Linke
aa9daed66e Remove unused StockLocation#stock_items
And the reverse association.
2025-01-22 11:20:05 +11:00
Maikel Linke
6dfa184a15 Remove unused StockLocation#stock_movements 2025-01-22 11:20:05 +11:00
Maikel Linke
34fdcface2 Remove unused StockLocation#stock_item_or_create 2025-01-22 11:20:04 +11:00
Maikel Linke
450576a938 Remove unused StockLocation#count_on_hand 2025-01-22 11:20:04 +11:00
Maikel Linke
1650ccd55a Remove unused StockLocation#backorderable? 2025-01-22 11:20:04 +11:00
Maikel Linke
531c068347 Remove StockLocation#fill_status, now on Variant 2025-01-22 11:20:04 +11:00
Maikel Linke
a4b92f289c Move fill_status spec to prepare removal from StockLocation 2025-01-22 11:20:04 +11:00
Maikel Linke
68a0f8df1f Remove detour via StockLocation updating stock 2025-01-22 11:20:04 +11:00
Maikel Linke
248110cfb3 Make stock location association optional
Prepare for removal
2025-01-22 11:20:04 +11:00
Gaetan Craig-Riou
31c717349f Merge pull request #13085 from mkllnk/ci-runs
Reduce parallel CI runs from 45 to 27
2025-01-22 09:38:49 +11:00
Maikel Linke
cf35e48d14 Remove unused app config options
This has been defined in ENV for a while
2025-01-21 20:11:05 +01:00
Maikel Linke
917e0ff01a Remove unnecessary storage of currency 2025-01-21 20:11:05 +01:00
Maikel Linke
ed926e9e26 Remove unnecessary storage of checkout zone 2025-01-21 20:11:05 +01:00
David Cook
51300eecd9 Merge pull request #13079 from mkllnk/dfc-price
Publish price as in new DFC standard
2025-01-21 16:42:19 +11:00
Maikel Linke
ca12e35537 Reduce parallel CI runs from 45 to 27
This should shave off 18 minutes of overhead time for 18 fewer worker
runs in total. It also means that forks with only 20 parallel worker
should complete quicker.
2025-01-21 16:20:21 +11:00
Maikel
a1df61c612 Merge pull request #13076 from mkllnk/police-migrations
Police migrations
2025-01-21 11:36:34 +11:00
Maikel Linke
fcc31fffcd Fix user seeding 2025-01-21 11:21:08 +11:00
Maikel Linke
971d5bea44 Police new migrations 2025-01-21 11:19:58 +11:00
Maikel Linke
8c68179069 Style default user creation 2025-01-21 11:19:57 +11:00
Maikel Linke
042cc238c8 Modernise db default scripts 2025-01-21 11:17:31 +11:00
Maikel Linke
25a90a44f9 Modernise seeds file 2025-01-21 11:17:29 +11:00
Maikel Linke
8383441f79 List ignored files more explicitely 2025-01-21 11:12:59 +11:00
Maikel
229ee7028c Merge pull request #13064 from mkllnk/negative-stock
Don't show stock for on-demand inventory items
2025-01-21 11:05:50 +11:00
Gaetan Craig-Riou
fcd366cc06 Fix spec
Payment needs to be linked to the order, in order for the payment
callback to update `order.payment_total`
2025-01-21 10:52:32 +11:00
Gaetan Craig-Riou
0ca164a354 Fix spec
Use a completed payment, instead of trying to complete a payment
2025-01-21 10:51:08 +11:00
Gaetan Craig-Riou
d7ae91c23e Per review, specify the actual expected value 2025-01-20 16:21:19 +11:00
Gaetan Craig-Riou
17e7f7d26d Small linting fix 2025-01-20 16:16:00 +11:00
Gaetan Craig-Riou
c71ae35685 Fix payment_total calculation
For payment that complete during the checkout (Paypal, Stripe) the
amount was recorded twice against `order.payment_total`. This is because
the `payment_total` gets updated in an afer_save Payment callback when a
payment is completed, and then once more when we process payment in
`Spree::Order#process_each_payment`.
This is an existing  issue on master, but it was hidden by the
`update_shipping_fees!` callback, it trigerred an update of the order's
total, which then updated `order.payment_total` with the correct value.
Now that we removed the callback, the bug showed up.

Note, I updated the stripe specs for consistency even though they are
currently disabled.
2025-01-20 16:07:32 +11:00
Gaetan Craig-Riou
1cf5dac979 Merge pull request #13077 from mkllnk/simplecov
Fix artifact download for Simplecov collation
2025-01-20 09:41:38 +11:00
filipefurtad0
d0a3d4996e Update all locales with the latest Transifex translations 2025-01-17 16:53:56 -06:00
Filipe
a472f3e4f5 Merge pull request #13068 from vishaldeepak/variant-with-tax
New variants should inherit tax category in UI
2025-01-17 10:57:22 -06:00
Filipe
ace3bfa2a5 Merge pull request #13061 from kernal053/add-voucher-label-to-edit-cart-page
Add 'Voucher:' before voucher code on edit cart page
2025-01-16 22:51:57 -06:00
Maikel Linke
06d9d96f54 Fix error on removed product from catalog 2025-01-17 12:21:28 +11:00
Filipe
3c1dd10219 Merge pull request #13047 from mkllnk/spree-roles
Clarify that our only user role is "admin" and simplify code
2025-01-16 18:06:49 -06:00
Filipe
5726eeffaa Merge pull request #13038 from chahmedejaz/task/13032-plural-variant-unit-names
Add plural form for flower farming variant unit names
2025-01-16 17:51:07 -06:00
Maikel Linke
84648690a6 Publish price as in new DFC standard 2025-01-16 09:45:26 +11:00
Gaetan Craig-Riou
1afa7fe5c0 Per review, small improvment 2025-01-15 15:44:24 -06:00
Gaetan Craig-Riou
a8d1d0c591 Update spec to properly update line items on an order
User Order::Contents#update_item to update line item on an order, it
ensures the order is properly updated
2025-01-15 15:44:24 -06:00
Gaetan Craig-Riou
9e7e40a5a8 Update spec to properly test shipping fee update 2025-01-15 15:44:24 -06:00
Gaetan Craig-Riou
f9bd720341 Add spec for #update_shipping_fees!
And update related specs
2025-01-15 15:44:24 -06:00
Gaetan Craig-Riou
20df5c23e8 Remove before save callback to update shipping fees
It should be handled in the controller, it's currently handled in
`Spree::OrderContents#remove`. As long as we don't manually remove line
item from an order we should be good.
Currently it gets trigerred each time the order is saved, which seems to
happen mutiple time when we finalize an order. It's a bit useless to
recalculated the fees over and over
Context, it was added here : 217eda8362
2025-01-15 15:44:24 -06:00
Maikel Linke
c9eed4f5b8 Trigger new backorder only when user checks out
When an admin creates an order, then AmendBackorderJob is called which
can also trigger a new backorder if needed.

This means that we are not creating backorders via subscriptions any
more. It has never been requested and we can bring that back if needed.
2025-01-15 15:52:57 +11:00
Maikel Linke
18ec97992d Remove unneeded HAML upgrade script
We updated a long time ago and I now copied those scripts to a Gist to
share with others:

* https://gist.github.com/mkllnk/bab2d474d686a2e3b88914129aee63e1
2025-01-15 12:55:13 +11:00
Maikel Linke
6b76fbc817 Fix artifact download for Simplecov collation
v4 of the artifact actions works differently to v3.
2025-01-15 12:44:34 +11:00
Gaetan Craig-Riou
a3e939e0ac Add OFN_REDIS_CABLE_URL env variable
It lets us specify a redis url to be used with ActionCable
2025-01-15 10:59:29 +11:00
Maikel
eace31f1fc Merge pull request #13074 from rioug/sync-prod-databse-schema
Sync prod database schema
2025-01-15 08:23:40 +11:00
Gaetan Craig-Riou
600195a726 Allow null for customers.created_manually
Some production database don't allow null for customers.created_maually,
we want to allow it to bring the database inline with schema.rb
2025-01-14 12:10:22 +11:00
Gaetan Craig-Riou
e2e12ccb52 Remove spree_variants default value and constraint
Some of the production database have default value for `weight` and
`unit_value` has well as check constraint. We want to remove them to
bring the database schema inline with schema.rb
2025-01-14 12:09:40 +11:00
Rachel Arnould
92c45084dc Merge pull request #12980 from pacodelaluna/add-external-billing-id-on-enterprises
Add external billing id on enterprises
2025-01-13 17:03:40 +01:00
David Cook
244e0524c7 Re-instate check for external_billing_id 2025-01-13 16:54:17 +01:00
François Turbelin
96c7c828c1 Fix specs 2025-01-13 16:54:17 +01:00
François Turbelin
9c153c6083 Improve specs 2025-01-13 16:54:17 +01:00
François Turbelin
e946b50515 Isolate into an Admin Only section 2025-01-13 16:54:17 +01:00
François Turbelin
3ef5b41282 Remove Admin Only tab logic 2025-01-13 16:54:17 +01:00
François Turbelin
a007fdaab8 Revert "Put back permalink fields on primary details panel"
This reverts commit d90ca538fb5b02e942842f1f9c1f44232f44027d.
2025-01-13 16:54:17 +01:00
François Turbelin
983e3e717b Revert "Fix spec"
This reverts commit b40e8a1ff9072721c468a7c012e1e4a9d47e3957.
2025-01-13 16:54:17 +01:00
François Turbelin
1e3f86625f Revert "Add spinner"
This reverts commit 16506c44fa8aee0a588c01a253b78b023a8f3a39.
2025-01-13 16:54:17 +01:00
François Turbelin
9cd3bbf46f Revert "Use params value only if present"
This reverts commit 5cd50b1c1ff66398f470d51fdafacf26663a2730.
2025-01-13 16:54:17 +01:00
François Turbelin
f9f5d0eb51 Revert "Do explicit save in specs when switching tabs"
This reverts commit 3230159dceeb1485b0c6ec2422ea282b39431e0c.
2025-01-13 16:54:17 +01:00
François Turbelin
0b0b6a04e1 Do explicit save in specs when switching tabs 2025-01-13 16:54:17 +01:00
François Turbelin
0f77d1bad5 Use params value only if present 2025-01-13 16:54:17 +01:00
François Turbelin
cd38e02cac Add spinner 2025-01-13 16:54:17 +01:00
François Turbelin
d6faa23fc2 Fix spec 2025-01-13 16:54:17 +01:00
François Turbelin
9dc364979a Put back permalink fields on primary details panel 2025-01-13 16:54:17 +01:00
François Turbelin
3c7c02da2f Repair specs 2025-01-13 16:54:17 +01:00
François Turbelin
657df9eb8f Repair field placeholder translation 2025-01-13 16:54:17 +01:00
François Turbelin
6ae3c8b102 Add external_billing_id field on revenues_by_hub report 2025-01-13 16:54:17 +01:00
François Turbelin
e37881837b Add unit tests for admin entreprises changes 2025-01-13 16:54:17 +01:00
François Turbelin
57c237c72d Move admin_only tab upper 2025-01-13 16:54:17 +01:00
François Turbelin
6030d7e05b Handle the async action for entreprises sells field changes 2025-01-13 16:54:17 +01:00
François Turbelin
30dfae7e18 Deal with translations 2025-01-13 16:54:17 +01:00
François Turbelin
14334b02bf Add new field on enterprise admin form 2025-01-13 16:54:17 +01:00
François Turbelin
772f1f8fde Add external_billing_id field on enterprises table 2025-01-13 16:54:17 +01:00
Gaetan Craig-Riou
a5c199d397 Set action cable to use the unused redis instance 2025-01-13 15:05:56 +11:00
Vishal Deepak
1586c8ef28 New varaints should inherit tax category in UI 2025-01-10 13:30:18 +05:30
Maikel
e2bc86faa9 Merge pull request #12491 from openfoodfoundation/dependabot/bundler/rubocop-rails-2.25.0
chore(deps-dev): bump rubocop-rails from 2.24.1 to 2.28.0
2025-01-10 13:03:25 +11:00
David Cook
7f2266ef40 Merge pull request #13066 from mkllnk/fix-flaky-order-spec
Fix flaky admin order spec
2025-01-10 12:26:46 +11:00
Maikel Linke
b8c5b24c17 Fix flaky admin order spec
We were trying to assert values in the database withou waiting for he
update to finish. First expecting the changed values on the screen
ensures that Capybara waits for the action to finish. Then we can check
the database.
2025-01-10 09:54:50 +11:00
Maikel Linke
f8788d358e UNSAFE style Rails/RootPathnameMethods 2025-01-10 09:14:34 +11:00
Maikel Linke
c1198c8e1f UNSAFE Style Rails/CompactBlank 2025-01-10 09:14:34 +11:00
Maikel Linke
6cf1a0500d Bump rubocop-rails from 2.25.0 to 2.28.0 2025-01-10 09:14:04 +11:00
David Cook
314126a937 Update all locales with the latest Transifex translations 2025-01-10 09:08:52 +11:00
Maikel Linke
f9d436b1c9 Simplify subscription query
The artificial limit of 100 years was just set because the old SQL query
wouldn't deal with `null` well. Comparing with null always is always
false and returns nothing.

But Rails is now clever enough to interpret `begins_at..nil` as open
end query. This shouldn't have any practical impact as there's unlikely
to be an order cycle closing in more than 100 years. And if there was,
it would be confusing that it's not treated like other order cycles
ending in 80 years.
2025-01-10 08:57:20 +11:00
Maikel Linke
49ec9a3136 Style Rails/WhereRange 2025-01-10 08:43:58 +11:00
dependabot[bot]
2937595a33 chore(deps-dev): bump rubocop-rails from 2.24.1 to 2.25.0
Bumps [rubocop-rails](https://github.com/rubocop/rubocop-rails) from 2.24.1 to 2.25.0.
- [Release notes](https://github.com/rubocop/rubocop-rails/releases)
- [Changelog](https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop/rubocop-rails/compare/v2.24.1...v2.25.0)

---
updated-dependencies:
- dependency-name: rubocop-rails
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-10 08:34:00 +11:00
Maikel Linke
dc7b6245fd Allow creating backorders before order cycle opens
Admins may want to pre-process some orders manually for going public.
And it's good to reserve stock for these.

At some point in the future, the supplier may have an order cycle with
its own times but the current FDC implementation allows orders at any
time.
2025-01-09 13:32:43 +11:00
Maikel Linke
884206b4ed Place new backorder when there's none to amend 2025-01-09 13:28:09 +11:00
Maikel Linke
2297b650f8 Skip amending backorder if there's none 2025-01-09 12:10:07 +11:00
Maikel Linke
a3ec3e74ae Hide stock level of on-demand inventory items
We changed to tracking stock of on-demand items to be able to place
backorders. This is mostly hidden in the app but was still visible on
the inventory page. Now we are hiding that here, too.
2025-01-09 10:06:04 +11:00
Maikel Linke
0805501445 Format spec data with less indent 2025-01-09 10:06:04 +11:00
Maikel
edf236778e Merge pull request #13063 from openfoodfoundation/dependabot/npm_and_yarn/floating-ui/dom-1.6.13
Bump @floating-ui/dom from 1.6.12 to 1.6.13
2025-01-09 08:54:47 +11:00
dependabot[bot]
bf98603fcf Bump @floating-ui/dom from 1.6.12 to 1.6.13
Bumps [@floating-ui/dom](https://github.com/floating-ui/floating-ui/tree/HEAD/packages/dom) from 1.6.12 to 1.6.13.
- [Release notes](https://github.com/floating-ui/floating-ui/releases)
- [Changelog](https://github.com/floating-ui/floating-ui/blob/master/packages/dom/CHANGELOG.md)
- [Commits](https://github.com/floating-ui/floating-ui/commits/@floating-ui/dom@1.6.13/packages/dom)

---
updated-dependencies:
- dependency-name: "@floating-ui/dom"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-08 09:29:52 +00:00
Maikel
5f486bd611 Merge pull request #13036 from chahmedejaz/bugfix/13024-dfc-catalog-syncs-for-blank-cart
Fix DFC catalog syncs for blank cart
2025-01-08 12:53:19 +11:00
Maikel
1df3a6bb66 Merge pull request #13049 from mkllnk/dfc-wholesale-stock
Calculate stock from DFC wholesale variants
2025-01-08 12:32:44 +11:00
Konrad
8e0c0392d9 Merge pull request #12991 from murjax/remove-sku-11973
Remove product SKU from product pages and report
2025-01-07 21:14:39 +01:00
Konrad
428eb465c0 Merge pull request #13009 from MrBowmanXD/dev
Added the :selected option with the default tax category #12989
2025-01-07 20:04:28 +01:00
Rachel Arnould
1147976069 Merge pull request #13011 from drummer83/ConnApps
Make Connected Apps links available in Transifex
2025-01-07 15:31:46 +01:00
kernal053
45a4b33920 Ensure existing format 'Voucher: Code' on edit cart page. Handle rubocop warning 2025-01-07 09:17:24 +05:30
Maikel Linke
0bd6fe6709 Fix setting stock from wholesale offer 2025-01-07 11:03:36 +11:00
Maikel Linke
21195c5750 Calculate stock from wholesale products 2025-01-07 11:03:36 +11:00
Maikel Linke
faad7fa95c Move wholesale calculation for re-use 2025-01-07 11:03:36 +11:00
Maikel Linke
ddaeff7c53 Use DfcCatalog in offer broker 2025-01-07 11:03:34 +11:00
Maikel Linke
ef08ae49fe DRY DFC catalog logic for re-use 2025-01-07 10:49:37 +11:00
Konrad
7e3baabd23 Merge pull request #12983 from saunmanoj888/12957-hide-search-filter-for-no-products
Back Office Product List - Hide search field and filters when there are no products in list
2025-01-07 00:16:59 +01:00
David Cook
a89d65cfc7 Merge pull request #13057 from mkllnk/remove-local-storage
Remove local storage
2025-01-06 11:45:27 +11:00
Gaetan Craig-Riou
ab57618e59 Merge pull request #13044 from mkllnk/dfc-store-order-links-only
Remove old, replaced backorder lookup
2025-01-06 10:11:34 +11:00
Konrad
cdcc6871fd Merge pull request #12979 from cillian/remove-unused-angular-directives-2024-11
Remove unused renderSvg, ofnDisableScroll, integer, ofnScrollTo angular directives
2025-01-04 15:50:38 +01:00
kernal053
98adefbd67 Add 'Voucher:' before voucher code on edit cart page. Add spec correspondigly 2025-01-04 14:26:02 +05:30
Cillian O'Ruanaidh
ce38c1a3d5 Remove unused :ofn-scroll-to angular directive 2025-01-03 14:31:21 +01:00
Cillian O'Ruanaidh
6923349de6 Remove unused :integer angular directive 2025-01-03 14:31:21 +01:00
Cillian O'Ruanaidh
1fb987f0bd Remove unused :disable-scroll angular directive 2025-01-03 14:31:21 +01:00
Cillian O'Ruanaidh
0b389b8ff4 Remove unused :render-svg angular directive 2025-01-03 14:31:21 +01:00
Konrad
35fa4155e4 Merge pull request #12998 from kernal053/add-voucher-to-order-confirmation-emails
Add 'Voucher:' before voucher code on order confirmation emails
2025-01-03 14:01:45 +01:00
Maikel
1b03ee1a02 Merge pull request #13040 from openfoodfoundation/dependabot/npm_and_yarn/stimulus_reflex-3.5.3
Bump stimulus_reflex from 3.5.1 to 3.5.3
2025-01-03 15:29:20 +11:00
kernal053
bad32e226e Fix label for other adjustments and add spec correspodingly 2025-01-02 16:29:48 +01:00
kernal053
65f7980246 remove locale files changes except en.yml inorder to avoid conflict with Transifex 2025-01-02 16:29:48 +01:00
kernal053
65abda2a38 add voucher label & correspoding code with translation for order confirmation mailer 2025-01-02 16:29:48 +01:00
kernal053
f99f2c81ac Add 'Voucher:' before voucher code on order confirmation emails 2025-01-02 16:29:48 +01:00
David Cook
bc53e4301c Bump cable_ready package 2025-01-02 16:32:18 +11:00
David Cook
807782cc2a Bump cable_ready gem 2025-01-02 16:29:03 +11:00
David Cook
6adc6321f5 Bump stimulus_reflex gem 2025-01-02 16:28:37 +11:00
Maikel Linke
558d4debdb Remove unused AngularJS local storage 2025-01-02 15:40:13 +11:00
Maikel Linke
8f761fc438 Remove unused localStorageService clearing 2025-01-02 15:23:43 +11:00
Maikel Linke
be98544537 Remove unused AngularJS service KeyValueMapStore 2025-01-02 15:19:55 +11:00
David Cook
7f3b1c0d7a Merge pull request #13029 from mkllnk/flaky-order-cycle-spec
Add timepicker helper with added expectation to reduce flakiness
2025-01-02 13:45:28 +11:00
dependabot[bot]
d71b282fda Bump stimulus_reflex from 3.5.1 to 3.5.3
Bumps [stimulus_reflex](https://github.com/stimulusreflex/stimulus_reflex) from 3.5.1 to 3.5.3.
- [Release notes](https://github.com/stimulusreflex/stimulus_reflex/releases)
- [Changelog](https://github.com/stimulusreflex/stimulus_reflex/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stimulusreflex/stimulus_reflex/compare/v3.5.1...v3.5.3)

---
updated-dependencies:
- dependency-name: stimulus_reflex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-02 02:29:54 +00:00
Maikel
f5856d54da Merge pull request #13053 from openfoodfoundation/dependabot/npm_and_yarn/js-big-decimal-2.2.0
Bump js-big-decimal from 2.1.0 to 2.2.0
2025-01-02 13:28:48 +11:00
Maikel
386970adb0 Merge pull request #13050 from openfoodfoundation/dependabot/npm_and_yarn/trix-2.1.12
Bump trix from 2.1.11 to 2.1.12
2025-01-02 13:27:56 +11:00
David Cook
deee451b88 Merge pull request #12867 from dacook/turbo-error-messages
Alert user when error requesting a report
2025-01-02 11:28:10 +11:00
dependabot[bot]
77864fc149 Bump js-big-decimal from 2.1.0 to 2.2.0
Bumps [js-big-decimal](https://github.com/royNiladri/js-big-decimal) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/royNiladri/js-big-decimal/releases)
- [Commits](https://github.com/royNiladri/js-big-decimal/compare/v2.1.0...v2.2.0)

---
updated-dependencies:
- dependency-name: js-big-decimal
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-30 09:51:47 +00:00
Filipe
5fdd0e5d42 Merge pull request #12954 from rioug/fix-shipment-not-updated
Ensure shipment gets updated when an order is updated
2024-12-26 15:56:12 -06:00
dependabot[bot]
38ed025d88 Bump trix from 2.1.11 to 2.1.12
Bumps [trix](https://github.com/basecamp/trix) from 2.1.11 to 2.1.12.
- [Release notes](https://github.com/basecamp/trix/releases)
- [Commits](https://github.com/basecamp/trix/compare/v2.1.11...v2.1.12)

---
updated-dependencies:
- dependency-name: trix
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-23 09:48:27 +00:00
Maikel
b8aa970040 Merge pull request #13048 from openfoodfoundation/dependabot/npm_and_yarn/trix-2.1.11
Bump trix from 2.1.10 to 2.1.11
2024-12-20 15:40:08 +11:00
Filipe
e2e2285f81 Merge pull request #13027 from chahmedejaz/bugfix/13026-reset-variant-unit-name
Changing a variant unit scale from items to weight/volume does not remove variant unit name
2024-12-19 18:27:39 -06:00
Maikel Linke
c1f8d3035a Sleep after selecting time for stability 2024-12-20 11:15:49 +11:00
Maikel Linke
f74492190d Select time like the user does
It makes it easier to understand. It didn't improve stability.
2024-12-20 11:15:49 +11:00
Maikel Linke
874c464088 Tidy one spec example 2024-12-20 11:15:49 +11:00
dependabot[bot]
5a69acb742 Bump trix from 2.1.10 to 2.1.11
Bumps [trix](https://github.com/basecamp/trix) from 2.1.10 to 2.1.11.
- [Release notes](https://github.com/basecamp/trix/releases)
- [Commits](https://github.com/basecamp/trix/compare/v2.1.10...v2.1.11)

---
updated-dependencies:
- dependency-name: trix
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-19 09:17:56 +00:00
Maikel Linke
72376da98f Assess stability without retry 2024-12-19 16:29:33 +11:00
Maikel Linke
a30f764a22 Add timepicker helper with added expectation 2024-12-19 16:29:33 +11:00
Maikel Linke
5db8cb452e Leverage Rails' caching when checking for admin
The privileges of a user should never change within a request
life cycle. The `spree_roles` association is very small, between 0 and 2
items are quickly searched in memory without the need of additional
database queries.

From memory, I've seen a lot of spree_roles queries in log files per
request. This should reduce it to one.
2024-12-19 10:12:31 +11:00
Maikel Linke
54f83b45c8 Replace has_spree_role? with simpler admin?
We have only one role, so let's get rid of the unneeded method.

Now we are in a better place to get rid of Spree::Role and replace it
with a simple boolean.
2024-12-19 09:19:01 +11:00
Maikel Linke
a7140d1f60 Use only admin role, on demand
We are now creating the role on demand which removes the need for
seeding it as well.
2024-12-19 09:02:04 +11:00
Maikel Linke
a529d95fc5 Remove unused user role from seeding
We only ever check for the admin role.
2024-12-19 08:54:39 +11:00
Maikel Linke
fa82f80ab9 Use plain static value for spree_roles 2024-12-19 08:50:10 +11:00
Maikel Linke
a7dfa36883 Typo: we sync catalogs, not categories 2024-12-18 13:01:23 +11:00
Maikel Linke
60b62d41d6 Remove old, replaced backorder lookup 2024-12-17 13:48:03 +11:00
Maikel
0f706a9929 Merge pull request #13034 from mkllnk/rbenv-install
Install rbenv automatically if missing
2024-12-17 12:47:22 +11:00
Maikel
b9483ce63d Update script/rbenv-install.sh
Co-authored-by: David Cook <david@redcliffs.net>
2024-12-17 11:51:47 +11:00
David Cook
a3a79686db Don't catch other 4xx errors 2024-12-17 11:16:56 +11:00
David Cook
0616827419 Catch errors and alert the user
I'm not sure why, but Turbo was swallowing the unauthorized error, so I thought we should alert the user to help with debugging.
Same with network error, it gave no feedback before.

I think this is testable in theory, but I haven't invested the time on it.
2024-12-17 10:37:28 +11:00
Ahmed Ejaz
71ee7d5390 13032: add pularal variant names for flower farms 2024-12-17 00:16:20 +05:00
David Cook
e689844a0f Merge pull request #13033 from mkllnk/dfc-pricing
DFC Orders: Calculate wholesale price for imported retail variants
2024-12-16 15:37:30 +11:00
David Cook
5c08446515 Merge pull request #13039 from rioug/fix-es-unit-scale
Use the correct spanish translation for Unit Scale
2024-12-16 12:27:21 +11:00
Gaetan Craig-Riou
ad7ba3e680 Use the correct spanish translation for Unit Scale 2024-12-16 11:25:23 +11:00
Gaetan Craig-Riou
e54a1afe52 Merge pull request #13035 from openfoodfoundation/dependabot/npm_and_yarn/hotkeys-js-3.13.9
Bump hotkeys-js from 3.13.7 to 3.13.9
2024-12-16 10:49:43 +11:00
filipefurtad0
7d0bcfa06a Update all locales with the latest Transifex translations 2024-12-13 10:53:25 -06:00
Filipe
9bfac66412 Merge pull request #13012 from chahmedejaz/task/13007-customer-code-in-order-cycle-email
Add customer code to notify producer emails when enabled
2024-12-13 10:50:02 -06:00
dependabot[bot]
e26a1d4d3d Bump hotkeys-js from 3.13.7 to 3.13.9
Bumps [hotkeys-js](https://github.com/jaywcjlove/hotkeys-js) from 3.13.7 to 3.13.9.
- [Release notes](https://github.com/jaywcjlove/hotkeys-js/releases)
- [Commits](https://github.com/jaywcjlove/hotkeys-js/compare/v3.13.7...v3.13.9)

---
updated-dependencies:
- dependency-name: hotkeys-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 09:51:55 +00:00
Maikel Linke
8d1d0c27c9 Install rbenv automatically if missing
This small script addition will allow us to remove the rbenv
installation from our Ansible provisioning scripts.
2024-12-12 17:15:53 +11:00
Maikel Linke
13e008e91e Calculate wholesale price for imported retail variants 2024-12-12 16:08:45 +11:00
Maikel Linke
e47a57fa3c DRY with offer broker we'll need anyway 2024-12-12 15:48:42 +11:00
Maikel Linke
d5c3e94b24 OfferBroker needs only catalog URL, no other URLs 2024-12-12 15:45:42 +11:00
Maikel Linke
9b965f657c Use OIDC account factory 2024-12-12 15:22:35 +11:00
Maikel
58c39166e1 Merge pull request #13000 from mkllnk/dfc-amend-order
Amend DFC backorder completely
2024-12-12 12:47:13 +11:00
Ahmed Ejaz
b6eca58798 13024: fix dfc catalog sync for blank cart 2024-12-12 04:28:15 +05:00
Maikel Linke
bf41658d32 Fix nil error when amending backorder 2024-12-11 12:40:46 +11:00
Maikel Linke
88837b55b9 Amend backorder also when resuming order 2024-12-11 12:40:46 +11:00
Maikel Linke
9c0a15f431 Amend backorders on admin update orders 2024-12-11 12:40:46 +11:00
Maikel Linke
fcbaefb2c8 Update each backorder only once in bulk cancel 2024-12-11 12:40:46 +11:00
Maikel Linke
9ca1b48d2e Move backorder amendment out of order callback
Triggering it for each order is inefficient when we cancel them in bulk.
The callback doesn't allow us to optimise this.
2024-12-11 12:40:46 +11:00
Maikel Linke
e76d6ad3df Spec current order cancellation amending backorder
The cancellation happens async in Javascript. Therefore we need to wait
for and outcome on the page to know that the action finished. The
expectation needs to be around that whole block.

We actually want only one job enqueued if the same backorder is
affected. Time to fix that.
2024-12-11 12:40:46 +11:00
Maikel Linke
e1febc6e00 Simplify page actions 2024-12-11 12:40:46 +11:00
Maikel Linke
7d27f46d68 Simplify negated expectation 2024-12-11 12:40:46 +11:00
Maikel Linke
7d7253cf0e Re-use BackorderUpdater to complete backorder 2024-12-11 12:40:46 +11:00
Maikel Linke
4fa4eb1b4e Move backorder update code to re-usable class 2024-12-11 12:40:46 +11:00
Maikel Linke
d16cd8c84e Amend backorder completely
Update every single order line to reflect local orders and stock levels.

New cases supported:

* Add lines for orders created by an admin.
* Create backorder line after increase of local line item quantity.
* Adjust local stock after variant has been removed from order cycle.
2024-12-11 12:40:46 +11:00
Gaetan Craig-Riou
9870abfb1c Merge pull request #13025 from openfoodfoundation/dependabot/npm_and_yarn/trix-2.1.10
Bump trix from 2.1.9 to 2.1.10
2024-12-11 10:08:00 +11:00
Gaetan Craig-Riou
8e46c0f897 Apply changes from https://github.com/openfoodfoundation/openfoodnetwork/pull/13016 2024-12-11 10:04:57 +11:00
Ahmed Ejaz
3e031ab735 13026: reset variant unit name if unit is not items 2024-12-11 03:14:11 +05:00
dependabot[bot]
141000f0df Bump trix from 2.1.9 to 2.1.10
Bumps [trix](https://github.com/basecamp/trix) from 2.1.9 to 2.1.10.
- [Release notes](https://github.com/basecamp/trix/releases)
- [Commits](https://github.com/basecamp/trix/commits)

---
updated-dependencies:
- dependency-name: trix
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 21:47:00 +00:00
Maikel
7302c2d161 Merge pull request #12990 from openfoodfoundation/dependabot/npm_and_yarn/tom-select-2.4.1
Bump tom-select from 2.3.1 to 2.4.1
2024-12-11 08:45:16 +11:00
Maikel Linke
4be4c7622b Clean up Haml 2024-12-10 15:32:09 +11:00
Ahmed Ejaz
604a47bd96 13007: add specs for text mail 2024-12-10 05:49:35 +05:00
Ahmed Ejaz
241a6d8128 13007: fix specs 2024-12-10 05:34:33 +05:00
Ahmed Ejaz
bb70d21a35 13007: add specs 2024-12-10 05:34:32 +05:00
Ahmed Ejaz
626a269cf8 13007: only show business name when all customers have one 2024-12-10 05:34:32 +05:00
Ahmed Ejaz
302336ab02 13007: add business name in order cycle report email 2024-12-10 05:34:27 +05:00
filipefurtad0
ee2a6bf2e6 Update all locales with the latest Transifex translations 2024-12-09 16:46:51 -06:00
Filipe
7ca5927411 Merge pull request #12996 from chahmedejaz/bugfix/12993-fix-order-cycle-report-text-version
Order cycle mail reports to producers display different data in html and txt versions
2024-12-09 16:32:46 -06:00
dependabot[bot]
2926a9662c Bump tom-select from 2.3.1 to 2.4.1
Bumps [tom-select](https://github.com/orchidjs/tom-select) from 2.3.1 to 2.4.1.
- [Release notes](https://github.com/orchidjs/tom-select/releases)
- [Commits](https://github.com/orchidjs/tom-select/compare/v2.3.1...v2.4.1)

---
updated-dependencies:
- dependency-name: tom-select
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 22:27:56 +00:00
David Cook
118ed915dc Merge pull request #13020 from openfoodfoundation/dependabot/npm_and_yarn/trix-2.1.9
Bump trix from 2.1.8 to 2.1.9
2024-12-10 09:23:28 +11:00
Filipe
6e40e4da60 Merge pull request #13018 from chahmedejaz/task/13008-add-tax-category-in-all-products-report
Add 'tax category' to the All Products report
2024-12-09 16:21:01 -06:00
dependabot[bot]
693bef1e7a Bump trix from 2.1.8 to 2.1.9
Bumps [trix](https://github.com/basecamp/trix) from 2.1.8 to 2.1.9.
- [Release notes](https://github.com/basecamp/trix/releases)
- [Commits](https://github.com/basecamp/trix/commits)

---
updated-dependencies:
- dependency-name: trix
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 20:41:14 +00:00
Manuel Gonçalves
0d4904d9e4 Small change in spec file 2024-12-09 09:07:22 +00:00
Manuel Gonçalves
5def2b53e5 Added a spec file in order to test the tax categories helper 2024-12-08 10:52:14 +00:00
Ahmed Ejaz
42940f4729 12993: add total tax incl. 2024-12-08 01:05:21 +05:00
Ahmed Ejaz
f2da3bb11c 12993: html sanitize city and zip 2024-12-08 01:05:02 +05:00
Ahmed Ejaz
f8003b00db 12993: translate tax incl and qty 2024-12-08 01:03:38 +05:00
Filipe
521b72a6c9 Merge pull request #13004 from chahmedejaz/bugfix/12982-unable-to-close-confirmation-modals
[Orders Page] Fix Confirmation modals do not auto-close
2024-12-07 10:33:56 -06:00
Filipe
aa4552aac4 Merge pull request #13001 from chahmedejaz/bugfix/12973-product-import-never-completes
Bulk product import stalling at 66% when missing info
2024-12-05 16:34:43 -06:00
Ahmed Ejaz
93a3130851 12973: add specs 2024-12-05 16:18:21 -06:00
Ahmed Ejaz
f3a30f94db 12973: fix error rendering on UI
- The caught errors do not get rendered to the UI because of incorrect rendering methods
2024-12-05 16:18:21 -06:00
Ahmed Ejaz
16cae2dbcc 12973: fix error raised in variant creation
- if the sheet doesn't have the units present, then the variant is not saved due to model validation
- After that, while assigning on_hand value, error is raised that the variant is not created first
- Now this commit makes sure that the variant is created before implementing above logic
2024-12-05 16:18:21 -06:00
Gaetan Craig-Riou
cedf040b47 Per review, test on create and update 2024-12-04 22:15:56 +11:00
Gaetan Craig-Riou
4a6e4d4c6d Ensure shipment is updated when using update_or_create
`Spree::OrderContents#update_or_create` is used to update the cart when
on the /shop page. If you start an order and proceed to the "Order
summary" step, and then decide to update your order by using the shop
link next to the cart, such update wouldn't update the shipment.
This result in the order page in the backoffice displaying the wrong data,
and more importantly, in the stock not being updated.
So now we ensure shipment will be updated, which result in the checkout
flow being restarted, thus making sure the shipment is updated.
2024-12-04 16:30:45 +11:00
Maikel
4c71ea3866 Merge pull request #12994 from mkllnk/dfc-update-voc
Add new DFC vocabulary for order states
2024-12-04 12:57:03 +11:00
Gaetan Craig-Riou
bc970927a5 Merge pull request #13017 from openfoodfoundation/dependabot/npm_and_yarn/jasmine-core-5.5.0
Bump jasmine-core from 5.4.0 to 5.5.0
2024-12-04 09:49:37 +11:00
Ahmed Ejaz
c331d57cdb 13008: add tax category in all products report 2024-12-04 03:36:42 +05:00
dependabot[bot]
5845fee663 Bump jasmine-core from 5.4.0 to 5.5.0
Bumps [jasmine-core](https://github.com/jasmine/jasmine) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/jasmine/jasmine/releases)
- [Changelog](https://github.com/jasmine/jasmine/blob/main/RELEASE.md)
- [Commits](https://github.com/jasmine/jasmine/compare/v5.4.0...v5.5.0)

---
updated-dependencies:
- dependency-name: jasmine-core
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-03 09:38:47 +00:00
Manuel Gonçalves
3199118bae Removed the :selected attribute when the tax category is not required (like original version) 2024-12-03 08:54:35 +00:00
Maikel
de938f6f10 Merge pull request #12949 from rioug/12859-use-VINE-voucher
[City OFN Voucher] A shopper can use a VINE voucher
2024-12-03 14:04:44 +11:00
Maikel
697f430156 Merge pull request #12992 from mkllnk/errors
Add simpler Alert.raise interface to notify Bugsnag
2024-12-03 13:29:11 +11:00
Maikel Linke
c41c15b895 Fix missed Alert call with order object 2024-12-03 13:02:08 +11:00
Manuel Gonçalves
980f86ce89 Fixed the lint errors 2024-12-02 21:22:12 +00:00
Ahmed Ejaz
af200ab4a0 12993: fix lint issues 2024-12-02 18:40:18 +05:00
Ahmed Ejaz
4c6c1eedb1 12993: use html safe strings wherever required 2024-12-02 18:23:24 +05:00
Ahmed Ejaz
bbdee7c0f3 12993: add included tax in text report 2024-12-02 18:04:18 +05:00
Ahmed Ejaz
11959515b8 12993: update the condition to display details 2024-12-02 18:04:17 +05:00
David Cook
cb781536b6 Merge pull request #12905 from macanudo527/docker/use_alpine_image
Add Alpine Image for Docker
2024-12-02 09:57:51 +11:00
drummer83
53d2166579 Make Connected Apps links available in Transifex 2024-12-01 23:55:26 +01:00
Manuel Gonçalves
d95bb7736a Fixed the logic and moved the code to a helper file 2024-12-01 20:43:31 +00:00
Manuel Gonçalves
7d5bb4a6fa Added the :selected option with the default tax category 2024-12-01 15:13:49 +00:00
Maikel Linke
5719d0682d Remove duplicate lines, dev leftovers 2024-11-29 16:16:43 +11:00
Maikel Linke
c4c95d472e Use defined DFC orders states 2024-11-29 16:16:42 +11:00
Maikel Linke
3e7f61c4d1 Add new DFC vocabulary
So that we can use order states programmatically.
2024-11-29 16:16:42 +11:00
Maikel
db76cd1659 Merge pull request #13005 from mkllnk/map-spec
Remove failing map spec
2024-11-29 14:10:57 +11:00
Maikel Linke
e791184468 Remove failing map spec
I couldn't fix it easily. But I also think that the testing approach had
low value here.

It raised:

```
Failures:

  1) Map map can load does not show alert
     Failure/Error:
       assert_raises(Capybara::ModalNotFound) do
         accept_alert { visit '/map' }
       end

     Minitest::Assertion:
       Capybara::ModalNotFound expected but nothing was raised.

     [Screenshot Image]: /home/runner/work/openfoodnetwork/openfoodnetwork/tmp/capybara/screenshots/failures_r_spec_example_groups_map_map_can_load_does_not_show_alert_64.png

     # ./spec/system/consumer/map_spec.rb:11:in `block (3 levels) in <top (required)>'
     # ./spec/system/support/cuprite_setup.rb:39:in `block (2 levels) in <top (required)>'
     # ./spec/base_spec_helper.rb:153:in `block (3 levels) in <main>'
     # ./spec/base_spec_helper.rb:153:in `block (2 levels) in <main>'
```
2024-11-29 13:46:01 +11:00
filipefurtad0
23287573f4 Update all locales with the latest Transifex translations 2024-11-28 20:21:43 -06:00
Maikel
925ac2ea6a Merge pull request #12862 from dacook/anonymise-customer-names
Anonymise customer first and last names
2024-11-29 09:17:19 +11:00
Filipe
355c9686e3 Merge pull request #12963 from murjax/map-network-check-8230
Show alert if map cannot load
2024-11-28 12:26:22 -06:00
Filipe
58d174fad9 Merge pull request #12969 from chahmedejaz/task/12919-remove-empty-option-from-unit-scale-dropdown
[Products] Empty option on unit scale dropdown
2024-11-28 09:31:42 -06:00
Filipe
d90c4f6aed Merge pull request #12995 from chahmedejaz/bugfix/12968-product-import-update
Impossible to update product sold by weight with product import
2024-11-28 08:38:58 -06:00
Gaetan Craig-Riou
f5b9ca361c Use the voucher adjustment amount for redeeming 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
16d6e1f935 Remove unused error translation 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
1e6fbadd8b Fix Vine::VoucherRedeemerService to handle exceptions 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
d102652c03 Fix Vine::VoucherValidatorService to handle exceptions 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
1b50217242 Re worked the Vine::ApiService to raise exception on error
Log Client and Server error, and re raise exception for the caller
to handle
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
73819a4638 Fix unique validator for vouche code
Paranoia doesn't support unique validation including deleted records:
  https://github.com/rubysherpas/paranoia/pull/333
We use a custom validator, ScopedUniquenessValidator to avoid the issue
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
9ab2a3ae3d Per review, fix a some minor issues 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
d413a142c9 Update various voucher related file to use the new Vouchers::Vine 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
48ad7ed8a0 Add voucher used by multiple enterprise and recycle code scenario
Plus optimise code with `find_or_initialize_by` as suggested in review
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
a2c4c44eea Move Vine voucher to Vouchers::Vine
A Vine voucher is really a specific type of FlatRate voucher but because
a Vine voucher can be used by mutiple enterprise, it can be considered
different enough to warrant it's own class.
It still share a lot of the behaviour of a FlatRate voucher, so to avoid
duplication, all the shared functionality have been moved to a
Vouchers::FlatRatable concern.
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
e7ece294cc Better error for VineVoucherValidatorService
Co-authored-by: David Cook <david@redcliffs.net>
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
d7313ffec9 Per review, improve Vine::VoucherValidatorService
plus specs
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
b42cba8c37 Add vine_voucher factory 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
7726c7d129 Per review, rename not_vine scope to local
- use IS DISTINCT FROM instead of two conditions
- added spec for scope
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
d4d995851f Display voucher section if connected to VINE 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
12cf62c2ff Refactor, add OrderManagement::Order::Updater#update_voucher
Move the logic to update a voucher and associated order to
`OrderManagement`
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
0569b30e0d Refactor Vine related services
Move them under Vine module to keep the code nicely organised
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
9f3da1af4f Reddeem VINE voucher when firing "capture_and_complete_order"o
'Spree::Payment#capture_and_complete!' will try to complete the order,
so we want to redeem any VINE voucher associated with the order first.
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
afb336d789 Add spec for fire event "capture_and_complete_order" 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
92c4cb9b7f Redeem VINE voucher when creating a new payment
Creating a new payment will try to complete the order, so we want to
redeem any VINE voucher associated with the order first
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
724d5a2ca0 Add spec for creating a payment from admin page 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
6251814152 Hide VINE voucher from admin voucher page 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
cf13dc2ff6 Add system spec when completing order with VINE voucher 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
4906c19c8e Checkout Summary, remove shared example 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
129ccc33f8 CheckoutController, add VINE voucher redemption 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
9399c7e129 Add VineVoucherRedeemerService
It handles redeeming a voucher
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
c17eddd69b Add Voucher#vine?
And small refactor
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
b30096317c VineApiService, add voucher_redemptions
It is used to redeem a voucher
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
c89b4fb86b Add system spec fot adding VINE voucher to order 2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
3a367ceb6e Handle adding a VINE voucher to an order
Plus specs
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
f9fb7bf399 Add VineVoucherValidatorService and spec
It handles validating and creating vine voucher
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
0f9b933117 Add extra column to Voucher
They are used to store additional informations for VINE vouchers
2024-11-28 13:35:01 +01:00
Gaetan Craig-Riou
7cbe77668a VineApiService, add voucher_validation
It is used to validate a voucher using the given short code
2024-11-28 13:35:01 +01:00
Rachel Arnould
479eacc956 Merge pull request #12964 from chahmedejaz/task/12890-add-data-to-dfc-affiliate-sales-endpoint
Add cities and countries to DFC affiliate sales data endpoint
2024-11-28 10:46:20 +01:00
Neal Chambers
e7213dba68 Revise README 2024-11-28 08:39:51 +09:00
Neal Chambers
078e191d26 Sync Docker Container to the Host 2024-11-28 08:39:51 +09:00
Neal Chambers
b554eda7c7 Add Windows Docker Commands to README 2024-11-28 08:39:51 +09:00
Neal Chambers
477447ad92 Rewrite Powershell Scripts for Alternative Dockerfile 2024-11-28 08:39:51 +09:00
Neal Chambers
039399ee37 Simplify Docker Build 2024-11-28 08:39:51 +09:00
Neal Chambers
d36438037a Revise Docker README 2024-11-28 08:39:51 +09:00
Neal Chambers
5b58f7b20e Add Dockerfile back in 2024-11-28 08:39:51 +09:00
Neal Chambers
02e2214caa Revert "Remove bundle exec from docker commands"
This reverts commit 2d193a689406cf826e241314acd661fd87a6ae37.
2024-11-28 08:39:51 +09:00
Neal Chambers
0ec8d13641 Optimize Dockerfile 2024-11-28 08:39:51 +09:00
Neal Chambers
151fc7bf85 Revise docker scripts to use optional dockfiles 2024-11-28 08:39:51 +09:00
Neal Chambers
15c920c911 Refactor Alpine Dockerfile 2024-11-28 08:39:51 +09:00
Neal Chambers
b4aaa0fae1 Add Helpful Docker Commands 2024-11-28 08:39:51 +09:00
Neal Chambers
efe0a2a701 Add Redis Test URL for Spree Preferences 2024-11-28 08:39:51 +09:00
Neal Chambers
3f905cce16 Remove bundle exec from docker commands 2024-11-28 08:39:51 +09:00
Neal Chambers
5c5213e872 Use Alpine Image for Docker 2024-11-28 08:39:51 +09:00
David Cook
3a7aed154c Merge pull request #13003 from chahmedejaz/bugfix/13002-orders-pagination
[Orders Page] - Fix Pagination not working
2024-11-28 09:28:30 +11:00
Ahmed Ejaz
60ace5d3ff 12982: add hu locale config for flatpickr 2024-11-28 03:18:34 +05:00
Ahmed Ejaz
1dec3debe1 12982: update close guard condition
- Execute the close method only when the current context modal is opened
2024-11-28 03:12:11 +05:00
Ahmed Ejaz
711f37bce1 13002: fix the search-controller error
- productForm is not accessible on the orders page
- putting the check to do the scrollIntoView only if the productForm is available
2024-11-27 17:49:21 +05:00
Filipe
a493d70f5c Merge pull request #12950 from macanudo527/unlock_bigdecimal
Fix rounding issues by upgrading decimal maths library
2024-11-25 19:18:19 -06:00
Ahmed Ejaz
c0887b1806 12890: remove city from response 2024-11-25 19:29:31 +05:00
Ahmed Ejaz
3d09ac01cc 12968: fix existing specs
- As per the new changes, unit_type change will create a new product rather than give errors.
- on bulk-update screen as well, two products can have same name with different unit_type
2024-11-25 17:29:27 +05:00
Ahmed Ejaz
3a3d729dcb 12968: fix product import update 2024-11-25 16:36:13 +05:00
Ahmed Ejaz
283706114e 12968: update condition to match variant with unit scale 2024-11-25 16:36:13 +05:00
Ahmed Ejaz
7ca544540b 12890: fix product names 2024-11-24 15:24:39 +05:00
Maikel Linke
b1b4b10417 Update API docs 2024-11-22 12:40:54 +05:00
Ahmed Ejaz
3b83200a14 12890: fix specs 2024-11-22 12:40:54 +05:00
Ahmed Ejaz
7cd8311dcb 12890: add cities and countries data 2024-11-22 12:40:54 +05:00
saunmanoj888
87d7f73ba9 Hide search filters when no product is present 2024-11-22 00:15:08 +05:30
Maikel Linke
14e7c57102 Deactivate some specs on CI
Somehow Bugsnag doesn't report in CI environment and I have no idea how
to circumvent that. And I don't want to spend more time on this.
2024-11-21 16:17:27 +11:00
Maikel Linke
9f859f420d Remove unnecessary error creation 2024-11-21 15:58:56 +11:00
Maikel Linke
af33fc357e Use shorter Alert syntax
I still think that some of these objects won't be visible in Bugsnag but
I don't want to test any more on cases that were broken before and may
not be relevant now.
2024-11-21 15:58:56 +11:00
Maikel Linke
6a8cc410d2 Replace broken order data
Bugsnag expects a string as value, not an ActiveRecord object. The
result was just "filtered" data, not showing any of the order's
attributes.

Since wanting to share the order data seems a common pattern, I added a
convenience method for it.
2024-11-21 15:58:55 +11:00
Maikel Linke
61e7c1db07 Replace obsolete ErrorLogger 2024-11-21 15:58:55 +11:00
Maikel Linke
0d8df5d2a8 Replace Bugsnag calls with Alert.raise 2024-11-21 15:58:55 +11:00
Maikel Linke
73a1698aad Add live test for Bugsnag
Needs human to review Bugsnag account.
2024-11-21 15:28:19 +11:00
Maikel Linke
97d41c230e Add simpler Bugsnag wrapper 2024-11-21 15:28:19 +11:00
Maikel Linke
1b4efd2164 Revert "Notify bugsnag on 404 errors"
This reverts commit 2eec3d625a.

We started tracking 404 errors out of interest without an actual problem
to solve. Now we face rate-limiting in our Bugsnag account. And we
didn't use these 404 reports in the two years this code was active. We
don't even act on all 500 errors. So while our resources are so
constrained, let's keep our focus on the severe errors and user reports
and ignore the rest. 404 errors are mostly generated by vulnerability
scanners.
2024-11-21 15:28:19 +11:00
Maikel Linke
1e13005fb5 Enable Bugsnag testing in any Rails env with ENV var 2024-11-21 15:28:19 +11:00
Ryan Murphy
bab7756017 Remove product SKU from product pages and report 2024-11-20 19:12:29 -05:00
Neal Chambers
7a5074cc90 Refactor option_value_value_unit_scaled for correct unit value scaling and update sales tax report spec for clarity 2024-11-13 16:28:18 +09:00
Neal Chambers
41ffe848ed Update BigDecimal to Latest Version 2024-11-13 16:28:18 +09:00
Neal Chambers
0797314360 Fix inaccuracies introduced with truncation 2024-11-13 16:28:18 +09:00
Neal Chambers
3302f0e78d Improve Precision of Spec for New Version of BigDecimal 2024-11-13 16:28:18 +09:00
Ahmed Ejaz
bafb881c46 12919: add unit scale prompt 2024-11-10 14:57:45 +05:00
Ryan Murphy
32ab821839 8230 - Map spec update 2024-11-06 08:43:37 -05:00
Ryan Murphy
008d764c34 Show alert if map cannot load 2024-11-05 18:37:17 -05:00
David Cook
9c51615b03 Anonymise customer first and last names
These were added a couple of years ago in https://github.com/openfoodfoundation/openfoodnetwork/pull/8763
But I guess we never noticed the names weren't getting anonymised.

The old 'name' field is still in the DB. It was kept for compatibility during migraiton but never cleaned up. I've added the tech debt task to the welcome new devs board now: https://github.com/openfoodfoundation/openfoodnetwork/issues/8835
2024-09-16 11:42:58 +10:00
396 changed files with 7446 additions and 4330 deletions

View File

@@ -16,6 +16,7 @@ SECRET_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
OFN_REDIS_URL="redis://localhost:6379/1"
OFN_REDIS_JOBS_URL="redis://localhost:6379/2"
OFN_REDIS_CABLE_URL="redis://localhost:6379/0"
SITE_URL="0.0.0.0:3000"

View File

@@ -38,10 +38,10 @@ jobs:
# [n] - where the n is a number of parallel jobs you want to run your tests on.
# Use a higher number if you have slow tests to split them between more parallel jobs.
# Remember to update the value of the `ci_node_index` below to (0..n-1).
ci_node_total: [8]
ci_node_total: [4]
# Indexes for parallel jobs (starting from zero).
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7]
ci_node_index: [0, 1, 2, 3]
steps:
- uses: actions/checkout@v3
@@ -66,7 +66,7 @@ jobs:
- name: Set up database
run: |
bin/rake db:create db:schema:load
bin/rails db:create db:schema:load
- name: Run tests
env:
@@ -84,7 +84,7 @@ jobs:
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/controllers/**/*_spec.rb}"
run: |
git show --no-patch # the commit being tested (which is often a merge due to actions/checkout@v3)
bin/rake knapsack_pro:rspec
bin/rails assets:precompile knapsack_pro:rspec
- name: Save SimpleCov file
uses: actions/upload-artifact@v4
@@ -116,10 +116,10 @@ jobs:
# [n] - where the n is a number of parallel jobs you want to run your tests on.
# Use a higher number if you have slow tests to split them between more parallel jobs.
# Remember to update the value of the `ci_node_index` below to (0..n-1).
ci_node_total: [4]
ci_node_total: [2]
# Indexes for parallel jobs (starting from zero).
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
ci_node_index: [0, 1, 2, 3]
ci_node_index: [0, 1]
steps:
- uses: actions/checkout@v3
@@ -135,7 +135,7 @@ jobs:
- name: Set up database
run: |
bin/rake db:create db:schema:load
bin/rails db:create db:schema:load
- name: Run tests
env:
@@ -184,10 +184,10 @@ jobs:
# [n] - where the n is a number of parallel jobs you want to run your tests on.
# Use a higher number if you have slow tests to split them between more parallel jobs.
# Remember to update the value of the `ci_node_index` below to (0..n-1).
ci_node_total: [14]
ci_node_total: [10]
# Indexes for parallel jobs (starting from zero).
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
steps:
- uses: actions/checkout@v3
@@ -211,7 +211,7 @@ jobs:
- name: Set up database
run: |
bin/rake db:create db:schema:load
bin/rails db:create db:schema:load
- name: Run tests
@@ -230,7 +230,7 @@ jobs:
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/system/admin/**/*_spec.rb}"
run: |
bin/rake knapsack_pro:queue:rspec
bin/rails assets:precompile knapsack_pro:queue:rspec
- name: Save SimpleCov file
uses: actions/upload-artifact@v4
@@ -271,10 +271,10 @@ jobs:
# [n] - where the n is a number of parallel jobs you want to run your tests on.
# Use a higher number if you have slow tests to split them between more parallel jobs.
# Remember to update the value of the `ci_node_index` below to (0..n-1).
ci_node_total: [12]
ci_node_total: [6]
# Indexes for parallel jobs (starting from zero).
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
ci_node_index: [0, 1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
@@ -298,7 +298,7 @@ jobs:
- name: Set up database
run: |
bin/rake db:create db:schema:load
bin/rails db:create db:schema:load
- name: Run tests
@@ -317,7 +317,7 @@ jobs:
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/system/consumer/**/*_spec.rb}"
run: |
bin/rake knapsack_pro:queue:rspec
bin/rails assets:precompile knapsack_pro:queue:rspec
- name: Save SimpleCov file
uses: actions/upload-artifact@v4
@@ -386,7 +386,7 @@ jobs:
- name: Set up database
run: |
bin/rake db:create db:schema:load
bin/rails db:create db:schema:load
- name: Run tests
@@ -405,7 +405,7 @@ jobs:
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/lib/**/*_spec.rb,spec/migrations/**/*_spec.rb,spec/serializers/**/*_spec.rb,engines/**/*_spec.rb}"
run: |
bin/rake knapsack_pro:rspec
bin/rails assets:precompile knapsack_pro:rspec
- name: Save SimpleCov file
uses: actions/upload-artifact@v4
@@ -437,10 +437,10 @@ jobs:
# [n] - where the n is a number of parallel jobs you want to run your tests on.
# Use a higher number if you have slow tests to split them between more parallel jobs.
# Remember to update the value of the `ci_node_index` below to (0..n-1).
ci_node_total: [5]
ci_node_total: [3]
# Indexes for parallel jobs (starting from zero).
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
ci_node_index: [0, 1, 2, 3, 4]
ci_node_index: [0, 1, 2]
steps:
- uses: actions/checkout@v3
@@ -465,7 +465,7 @@ jobs:
- name: Set up database
run: |
bin/rake db:create db:schema:load
bin/rails db:create db:schema:load
- name: Run tests
env:
@@ -482,7 +482,7 @@ jobs:
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
KNAPSACK_PRO_TEST_FILE_EXCLUDE_PATTERN: "{engines/**/*_spec.rb,spec/models/**/*_spec.rb,spec/controllers/**/*_spec.rb,spec/serializers/**/*_spec.rb,spec/lib/**/*_spec.rb,spec/migrations/**/*_spec.rb,spec/system/**/*_spec.rb}"
run: |
bin/rake knapsack_pro:rspec
bin/rails assets:precompile knapsack_pro:rspec
- name: Save SimpleCov file
uses: actions/upload-artifact@v4
@@ -553,7 +553,6 @@ jobs:
with:
pattern: simplecov-chunk-*
path: tmp/simplecov
merge-multiple: true
- name: collate results from each of the workers
run: bundle exec rake 'simplecov:collate_results[tmp/simplecov]'

View File

@@ -3,10 +3,14 @@
# These are the rules we agreed upon and we work towards.
AllCops:
NewCops: enable
MigratedSchemaVersion: "20250111000000"
Exclude:
- bin/**/*
- db/**/*
- config/**/*
- db/bad_migrations/*
- db/migrate/201*
- db/migrate/202[0-4]*
- db/schema.rb
- script/**/*
- vendor/**/*
- node_modules/**/*

View File

@@ -34,12 +34,6 @@ Lint/EmptyClass:
Exclude:
- 'spec/lib/reports/report_loader_spec.rb'
# Offense count: 1
# Configuration parameters: AllowComments.
Lint/EmptyFile:
Exclude:
- 'spec/lib/open_food_network/enterprise_injection_data_spec.rb'
# Offense count: 2
Lint/FloatComparison:
Exclude:
@@ -92,7 +86,6 @@ Metrics/AbcSize:
- 'app/controllers/admin/enterprises_controller.rb'
- 'app/controllers/payment_gateways/paypal_controller.rb'
- 'app/controllers/spree/admin/payments_controller.rb'
- 'app/controllers/spree/admin/taxons_controller.rb'
- 'app/controllers/spree/admin/variants_controller.rb'
- 'app/controllers/spree/orders_controller.rb'
- 'app/helpers/spree/admin/navigation_helper.rb'
@@ -127,7 +120,7 @@ Metrics/BlockNesting:
Exclude:
- 'app/models/spree/payment/processing.rb'
# Offense count: 46
# Offense count: 47
# Configuration parameters: CountComments, Max, CountAsOne.
Metrics/ClassLength:
Exclude:
@@ -137,6 +130,7 @@ Metrics/ClassLength:
- 'app/controllers/admin/resource_controller.rb'
- 'app/controllers/admin/subscriptions_controller.rb'
- 'app/controllers/application_controller.rb'
- 'app/controllers/checkout_controller.rb'
- 'app/controllers/payment_gateways/paypal_controller.rb'
- 'app/controllers/spree/admin/orders_controller.rb'
- 'app/controllers/spree/admin/payment_methods_controller.rb'
@@ -183,7 +177,7 @@ Metrics/ClassLength:
Metrics/CyclomaticComplexity:
Exclude:
- 'app/controllers/admin/enterprises_controller.rb'
- 'app/controllers/spree/admin/taxons_controller.rb'
- 'app/controllers/spree/admin/payments_controller.rb'
- 'app/controllers/spree/orders_controller.rb'
- 'app/helpers/checkout_helper.rb'
- 'app/helpers/order_cycles_helper.rb'
@@ -208,13 +202,12 @@ Metrics/CyclomaticComplexity:
- 'lib/spree/localized_number.rb'
- 'spec/models/product_importer_spec.rb'
# Offense count: 24
# Offense count: 23
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength:
Exclude:
- 'app/controllers/admin/enterprises_controller.rb'
- 'app/controllers/payment_gateways/paypal_controller.rb'
- 'app/controllers/spree/admin/taxons_controller.rb'
- 'app/controllers/spree/orders_controller.rb'
- 'app/helpers/spree/admin/navigation_helper.rb'
- 'app/models/spree/ability.rb'
@@ -293,19 +286,17 @@ Metrics/ParameterLists:
- 'spec/support/controller_requests_helper.rb'
- 'spec/system/admin/reports_spec.rb'
# Offense count: 4
# Offense count: 3
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
Metrics/PerceivedComplexity:
Exclude:
- 'app/controllers/spree/admin/taxons_controller.rb'
- 'app/models/enterprise_relationship.rb'
- 'app/models/spree/ability.rb'
- 'app/models/spree/order/checkout.rb'
# Offense count: 8
# Offense count: 7
Naming/AccessorMethodName:
Exclude:
- 'app/controllers/spree/admin/taxonomies_controller.rb'
- 'app/mailers/producer_mailer.rb'
- 'app/models/spree/order.rb'
- 'app/services/checkout/post_checkout_actions.rb'
@@ -348,12 +339,11 @@ Naming/VariableNumber:
- 'app/models/preference_sections/main_links_section.rb'
- 'lib/spree/core/controller_helpers/common.rb'
- 'spec/controllers/spree/admin/search_controller_spec.rb'
- 'spec/factories/stock_location_factory.rb'
- 'spec/models/spree/stock_item_spec.rb'
- 'spec/models/spree/tax_rate_spec.rb'
- 'spec/requests/api/orders_spec.rb'
# Offense count: 142
# Offense count: 143
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: ResponseMethods.
# ResponseMethods: response, last_response
@@ -557,7 +547,7 @@ RSpecRails/InferredSpecType:
- 'spec/requests/voucher_adjustments_spec.rb'
- 'spec/routing/stripe_spec.rb'
# Offense count: 22
# Offense count: 21
# Configuration parameters: IgnoreScopes, Include.
# Include: app/models/**/*.rb
Rails/InverseOf:
@@ -572,7 +562,6 @@ Rails/InverseOf:
- 'app/models/spree/price.rb'
- 'app/models/spree/product.rb'
- 'app/models/spree/stock_item.rb'
- 'app/models/spree/taxonomy.rb'
- 'app/models/spree/variant.rb'
- 'app/models/subscription_line_item.rb'
@@ -720,7 +709,7 @@ Style/GlobalStdStream:
- 'lib/tasks/subscriptions/debug.rake'
- 'lib/tasks/subscriptions/test.rake'
# Offense count: 12
# Offense count: 10
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowSplatArgument.
Style/HashConversion:
@@ -728,9 +717,7 @@ Style/HashConversion:
- 'app/controllers/admin/column_preferences_controller.rb'
- 'app/controllers/admin/variant_overrides_controller.rb'
- 'app/controllers/spree/admin/products_controller.rb'
- 'app/models/order_cycle.rb'
- 'app/models/product_import/product_importer.rb'
- 'app/models/spree/shipping_method.rb'
- 'app/serializers/api/admin/exchange_serializer.rb'
- 'app/services/variants_stock_levels.rb'
- 'spec/controllers/admin/inventory_items_controller_spec.rb'

View File

@@ -89,4 +89,4 @@ RUN ./script/install-bundler
RUN yarn install
# Run bundler install in parallel with the amount of available CPUs
RUN bundle install --jobs="$(nproc)"
RUN bundle install --jobs="$(nproc)"

View File

@@ -86,7 +86,7 @@ gem "active_model_serializers", "0.8.4"
gem 'activerecord-session_store'
gem 'acts-as-taggable-on'
gem 'angularjs-file-upload-rails', '~> 2.4.1'
gem 'bigdecimal', '3.0.2'
gem 'bigdecimal'
gem 'bootsnap', require: false
gem 'geocoder'
gem 'gmaps4rails'

View File

@@ -180,7 +180,7 @@ GEM
base64 (0.2.0)
bcp47_spec (0.2.1)
bcrypt (3.1.20)
bigdecimal (3.0.2)
bigdecimal (3.1.8)
bindata (2.5.0)
bindex (0.8.1)
bootsnap (1.18.3)
@@ -191,7 +191,7 @@ GEM
bullet (7.1.6)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
cable_ready (5.0.5)
cable_ready (5.0.6)
actionpack (>= 5.2)
actionview (>= 5.2)
activesupport (>= 5.2)
@@ -683,10 +683,10 @@ GEM
rubocop (~> 1.41)
rubocop-factory_bot (2.25.1)
rubocop (~> 1.41)
rubocop-rails (2.24.1)
rubocop-rails (2.28.0)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop (>= 1.52.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (2.29.2)
rubocop (~> 1.40)
@@ -755,16 +755,16 @@ GEM
state_machines-activerecord (0.9.0)
activerecord (>= 6.0)
state_machines-activemodel (>= 0.9.0)
stimulus_reflex (3.5.1)
actioncable (>= 5.2, < 8)
actionpack (>= 5.2, < 8)
actionview (>= 5.2, < 8)
activesupport (>= 5.2, < 8)
stimulus_reflex (3.5.3)
actioncable (>= 5.2)
actionpack (>= 5.2)
actionview (>= 5.2)
activesupport (>= 5.2)
cable_ready (~> 5.0)
nokogiri (~> 1.0)
nokogiri-html5-inference (~> 0.3)
rack (>= 2, < 4)
railties (>= 5.2, < 8)
railties (>= 5.2)
redis (>= 4.0, < 6.0)
stringex (2.8.6)
stringio (3.1.0)
@@ -865,7 +865,7 @@ DEPENDENCIES
angularjs-rails (= 1.8.0)
arel-helpers (~> 2.12)
aws-sdk-s3
bigdecimal (= 3.0.2)
bigdecimal
bootsnap
bugsnag
bullet

32
alpine.Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
FROM ruby:3.1.4-alpine3.19 AS base
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
TZ=Europe/London \
RAILS_ROOT=/usr/src/app
RUN apk --no-cache upgrade && \
apk add --no-cache tzdata postgresql-client imagemagick imagemagick-jpeg && \
apk add --no-cache --virtual wkhtmltopdf
WORKDIR $RAILS_ROOT
# Development dependencies
FROM base AS development-base
RUN apk add --no-cache --virtual .build-deps \
build-base postgresql-dev git nodejs yarn && \
apk add --no-cache --virtual .dev-utils \
bash curl less vim chromium-chromedriver zlib-dev openssl-dev \
readline-dev yaml-dev sqlite-dev libxml2-dev libxslt-dev libffi-dev vips-dev && \
curl -o /usr/local/bin/wait-for-it https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && \
chmod +x /usr/local/bin/wait-for-it
# Install yarn dependencies separately for caching
FROM development-base AS yarn-dependencies
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# Install Ruby gems
FROM development-base
COPY . $RAILS_ROOT
COPY Gemfile Gemfile.lock ./
RUN bundle install --jobs "$(nproc)"
COPY --from=yarn-dependencies $RAILS_ROOT/node_modules ./node_modules

View File

@@ -67,8 +67,5 @@
// foundation
//= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js
// LocalStorage
//= require ../shared/angular-local-storage.js
// requires the rest of the JS code in this folder
//= require_tree .

View File

@@ -307,9 +307,6 @@ filterSubmitProducts = (productsToFilter) ->
variantHasUpdatableProperty = result.hasUpdatableProperty
filteredVariants.push filteredVariant if variantHasUpdatableProperty
if product.hasOwnProperty("sku")
filteredProduct.sku = product.sku
hasUpdatableProperty = true
if product.hasOwnProperty("name")
filteredProduct.name = product.name
hasUpdatableProperty = true

View File

@@ -1,29 +0,0 @@
angular.module("admin.indexUtils").factory 'KeyValueMapStore', (localStorageService)->
new class KeyValueMapStore
localStorageKey: ''
storableKeys: []
constructor: ->
localStorageService.setStorageType("sessionStorage")
getStoredKeyValueMap: ->
localStorageService.get(@localStorageKey) || {}
setStoredValues: (source) ->
keyValueMap = {}
for key in @storableKeys
keyValueMap[key] = source[key]
localStorageService.set(@localStorageKey, keyValueMap)
restoreValues: (target) ->
storedKeyValueMap = @getStoredKeyValueMap()
return false if _.isEmpty(storedKeyValueMap)
for k,v of storedKeyValueMap
target[k] = v
return true
clearKeyValueMap: () ->
localStorageService.remove(@localStorageKey)

View File

@@ -187,18 +187,17 @@ addVariantFromStockLocation = function() {
$('#stock_details').hide();
var variant_id = $('input.variant_autocomplete').val();
var stock_location_id = $(this).data('stock-location-id');
var quantity = $("input.quantity[data-stock-location-id='" + stock_location_id + "']").val();
var quantity = $("input.quantity").val();
var shipment = _.find(shipments, function(shipment){
return shipment.stock_location_id == stock_location_id && (shipment.state == 'ready' || shipment.state == 'pending');
return shipment.state == 'ready' || shipment.state == 'pending';
});
if(shipment==undefined){
$.ajax({
type: "POST",
url: Spree.url(Spree.routes.orders_api + "/" + order_number + "/shipments.json"),
data: { variant_id: variant_id, quantity: quantity, stock_location_id: stock_location_id }
data: { variant_id: variant_id, quantity: quantity }
}).done(function( msg ) {
window.location.reload();
}).error(function( msg ) {

View File

@@ -17,7 +17,6 @@
#= require angular-google-maps.min.js
#= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js
#= require ../shared/ng-infinite-scroll.min.js
#= require ../shared/angular-local-storage.js
#= require ../shared/angular-slideables.js
#= require ../shared/shared
#= require_tree ../shared/directives

View File

@@ -1,7 +1,6 @@
angular.module("Darkswarm", [
'ngResource',
'mm.foundation',
'LocalStorageModule',
'infinite-scroll',
'angular-flash.service',
'templates',

View File

@@ -1,10 +0,0 @@
angular.module('Darkswarm').directive "ofnDisableScroll", ()->
# Stops scrolling from incrementing or decrementing input value
# Useful for number inputs
restrict: 'A'
link: (scope, element, attrs)->
element.bind 'focus', ->
element.bind 'mousewheel', (e)->
e.preventDefault()
element.bind 'blur', ->
element.unbind 'mousewheel'

View File

@@ -1,5 +0,0 @@
angular.module('Darkswarm').directive "integer", ->
restrict: 'A'
link: (scope, elem, attr) ->
elem.bind 'input', ->
elem.val Math.round(elem.val())

View File

@@ -20,10 +20,13 @@ angular.module('Darkswarm').directive 'mapSearch', ($timeout, Search) ->
$timeout =>
map = ctrl.getMap()
searchBox = scope.createSearchBox map
scope.bindSearchResponse map, searchBox
scope.biasResults map, searchBox
scope.performUrlSearch map
if !map
alert(t('gmap_load_failure'))
else
searchBox = scope.createSearchBox map
scope.bindSearchResponse map, searchBox
scope.biasResults map, searchBox
scope.performUrlSearch map
scope.createSearchBox = (map) ->
map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input

View File

@@ -13,6 +13,8 @@ angular.module('Darkswarm').directive 'ofnOpenStreetMap', ($window, MapCentreCal
buildMarker = (enterprise, latlng, title) ->
icon = L.icon
iconAnchor: [14, 33]
iconSize: [28, 33]
iconUrl: enterprise.icon
marker = L.marker latlng,
draggable: true,

View File

@@ -1,14 +0,0 @@
angular.module('Darkswarm').directive "renderSvg", ()->
# Magical directive that'll render SVGs from URLs
# If only there were a neater way of doing this
restrict: 'E'
priority: 99
template: "<svg-wrapper></svg-wrapper>"
# Fetch SVG via ajax, inject into page using DOM
link: (scope, elem, attr)->
if /.svg/.test attr.path # Only do this if we've got an svg
$.ajax
url: attr.path
success: (html)->
elem.html($(html).find("svg"))

View File

@@ -1,9 +0,0 @@
angular.module('Darkswarm').directive "ofnScrollTo", ($location, $anchorScroll)->
# Onclick sets $location.hash to attrs.ofnScrollTo
# Then triggers anchorScroll
restrict: 'A'
link: (scope, element, attrs)->
element.bind 'click', (ev)->
ev.stopPropagation()
$location.hash attrs.ofnScrollTo
$anchorScroll()

View File

@@ -1,4 +1,4 @@
angular.module('Darkswarm').factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService, Messages) ->
angular.module('Darkswarm').factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, Messages) ->
# Handles syncing of current cart/order state to server
new class Cart
dirty: false
@@ -113,7 +113,6 @@ angular.module('Darkswarm').factory 'Cart', (CurrentOrder, Variants, $timeout, $
clear: ->
@line_items = []
localStorageService.clearAll() # One day this will have to be moar GRANULAR
isOnlyItemInOrder: (id) =>
deletedItem = @line_items_finalised.find((item) -> item.id == id)

View File

@@ -1,546 +0,0 @@
/**
* An Angular module that gives you access to the browsers local storage
* @version v0.5.0 - 2016-08-29
* @link https://github.com/grevory/angular-local-storage
* @author grevory <greg@gregpike.ca>
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
(function (window, angular) {
var isDefined = angular.isDefined,
isUndefined = angular.isUndefined,
isNumber = angular.isNumber,
isObject = angular.isObject,
isArray = angular.isArray,
extend = angular.extend,
toJson = angular.toJson;
angular
.module('LocalStorageModule', [])
.provider('localStorageService', function() {
// You should set a prefix to avoid overwriting any local storage variables from the rest of your app
// e.g. localStorageServiceProvider.setPrefix('yourAppName');
// With provider you can use config as this:
// myApp.config(function (localStorageServiceProvider) {
// localStorageServiceProvider.prefix = 'yourAppName';
// });
this.prefix = 'ls';
// You could change web storage type localstorage or sessionStorage
this.storageType = 'localStorage';
// Cookie options (usually in case of fallback)
// expiry = Number of days before cookies expire // 0 = Does not expire
// path = The web path the cookie represents
// secure = Wether the cookies should be secure (i.e only sent on HTTPS requests)
this.cookie = {
expiry: 30,
path: '/',
secure: false
};
// Decides wether we should default to cookies if localstorage is not supported.
this.defaultToCookie = true;
// Send signals for each of the following actions?
this.notify = {
setItem: true,
removeItem: false
};
// Setter for the prefix
this.setPrefix = function(prefix) {
this.prefix = prefix;
return this;
};
// Setter for the storageType
this.setStorageType = function(storageType) {
this.storageType = storageType;
return this;
};
// Setter for defaultToCookie value, default is true.
this.setDefaultToCookie = function (shouldDefault) {
this.defaultToCookie = !!shouldDefault; // Double-not to make sure it's a bool value.
return this;
};
// Setter for cookie config
this.setStorageCookie = function(exp, path, secure) {
this.cookie.expiry = exp;
this.cookie.path = path;
this.cookie.secure = secure;
return this;
};
// Setter for cookie domain
this.setStorageCookieDomain = function(domain) {
this.cookie.domain = domain;
return this;
};
// Setter for notification config
// itemSet & itemRemove should be booleans
this.setNotify = function(itemSet, itemRemove) {
this.notify = {
setItem: itemSet,
removeItem: itemRemove
};
return this;
};
this.$get = ['$rootScope', '$window', '$document', '$parse','$timeout', function($rootScope, $window, $document, $parse, $timeout) {
var self = this;
var prefix = self.prefix;
var cookie = self.cookie;
var notify = self.notify;
var storageType = self.storageType;
var webStorage;
// When Angular's $document is not available
if (!$document) {
$document = document;
} else if ($document[0]) {
$document = $document[0];
}
// If there is a prefix set in the config lets use that with an appended period for readability
if (prefix.substr(-1) !== '.') {
prefix = !!prefix ? prefix + '.' : '';
}
var deriveQualifiedKey = function(key) {
return prefix + key;
};
// Removes prefix from the key.
var underiveQualifiedKey = function (key) {
return key.replace(new RegExp('^' + prefix, 'g'), '');
};
// Check if the key is within our prefix namespace.
var isKeyPrefixOurs = function (key) {
return key.indexOf(prefix) === 0;
};
// Checks the browser to see if local storage is supported
var checkSupport = function () {
try {
var supported = (storageType in $window && $window[storageType] !== null);
// When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
// is available, but trying to call .setItem throws an exception.
//
// "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
// that exceeded the quota."
var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
if (supported) {
webStorage = $window[storageType];
webStorage.setItem(key, '');
webStorage.removeItem(key);
}
return supported;
} catch (e) {
// Only change storageType to cookies if defaulting is enabled.
if (self.defaultToCookie)
storageType = 'cookie';
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return false;
}
};
var browserSupportsLocalStorage = checkSupport();
// Directly adds a value to local storage
// If local storage is not available in the browser use cookies
// Example use: localStorageService.add('library','angular');
var addToLocalStorage = function (key, value, type) {
setStorageType(type);
// Let's convert undefined values to null to get the value consistent
if (isUndefined(value)) {
value = null;
} else {
value = toJson(value);
}
// If this browser does not support local storage use cookies
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
if (notify.setItem) {
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
}
return addToCookies(key, value);
}
try {
if (webStorage) {
webStorage.setItem(deriveQualifiedKey(key), value);
}
if (notify.setItem) {
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
}
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return addToCookies(key, value);
}
return true;
};
// Directly get a value from local storage
// Example use: localStorageService.get('library'); // returns 'angular'
var getFromLocalStorage = function (key, type) {
setStorageType(type);
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
return getFromCookies(key);
}
var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
// angular.toJson will convert null to 'null', so a proper conversion is needed
// FIXME not a perfect solution, since a valid 'null' string can't be stored
if (!item || item === 'null') {
return null;
}
try {
return JSON.parse(item);
} catch (e) {
return item;
}
};
// Remove an item from local storage
// Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
//
// This is var-arg removal, check the last argument to see if it is a storageType
// and set type accordingly before removing.
//
var removeFromLocalStorage = function () {
// can't pop on arguments, so we do this
var consumed = 0;
if (arguments.length >= 1 &&
(arguments[arguments.length - 1] === 'localStorage' ||
arguments[arguments.length - 1] === 'sessionStorage')) {
consumed = 1;
setStorageType(arguments[arguments.length - 1]);
}
var i, key;
for (i = 0; i < arguments.length - consumed; i++) {
key = arguments[i];
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
if (notify.removeItem) {
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
}
removeFromCookies(key);
}
else {
try {
webStorage.removeItem(deriveQualifiedKey(key));
if (notify.removeItem) {
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {
key: key,
storageType: self.storageType
});
}
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
removeFromCookies(key);
}
}
}
};
// Return array of keys for local storage
// Example use: var keys = localStorageService.keys()
var getKeysForLocalStorage = function (type) {
setStorageType(type);
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
return [];
}
var prefixLength = prefix.length;
var keys = [];
for (var key in webStorage) {
// Only return keys that are for this app
if (key.substr(0, prefixLength) === prefix) {
try {
keys.push(key.substr(prefixLength));
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
return [];
}
}
}
return keys;
};
// Remove all data for this app from local storage
// Also optionally takes a regular expression string and removes the matching key-value pairs
// Example use: localStorageService.clearAll();
// Should be used mostly for development purposes
var clearAllFromLocalStorage = function (regularExpression, type) {
setStorageType(type);
// Setting both regular expressions independently
// Empty strings result in catchall RegExp
var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp();
var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp();
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
return clearAllFromCookies();
}
if (!browserSupportsLocalStorage && !self.defaultToCookie)
return false;
var prefixLength = prefix.length;
for (var key in webStorage) {
// Only remove items that are for this app and match the regular expression
if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) {
try {
removeFromLocalStorage(key.substr(prefixLength));
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return clearAllFromCookies();
}
}
}
return true;
};
// Checks the browser to see if cookies are supported
var browserSupportsCookies = (function() {
try {
return $window.navigator.cookieEnabled ||
("cookie" in $document && ($document.cookie.length > 0 ||
($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return false;
}
}());
// Directly adds a value to cookies
// Typically used as a fallback if local storage is not available in the browser
// Example use: localStorageService.cookie.add('library','angular');
var addToCookies = function (key, value, daysToExpiry, secure) {
if (isUndefined(value)) {
return false;
} else if(isArray(value) || isObject(value)) {
value = toJson(value);
}
if (!browserSupportsCookies) {
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
return false;
}
try {
var expiry = '',
expiryDate = new Date(),
cookieDomain = '';
if (value === null) {
// Mark that the cookie has expired one day ago
expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
expiry = "; expires=" + expiryDate.toGMTString();
value = '';
} else if (isNumber(daysToExpiry) && daysToExpiry !== 0) {
expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000));
expiry = "; expires=" + expiryDate.toGMTString();
} else if (cookie.expiry !== 0) {
expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
expiry = "; expires=" + expiryDate.toGMTString();
}
if (!!key) {
var cookiePath = "; path=" + cookie.path;
if (cookie.domain) {
cookieDomain = "; domain=" + cookie.domain;
}
/* Providing the secure parameter always takes precedence over config
* (allows developer to mix and match secure + non-secure) */
if (typeof secure === 'boolean') {
if (secure === true) {
/* We've explicitly specified secure,
* add the secure attribute to the cookie (after domain) */
cookieDomain += "; secure";
}
// else - secure has been supplied but isn't true - so don't set secure flag, regardless of what config says
}
else if (cookie.secure === true) {
// secure parameter wasn't specified, get default from config
cookieDomain += "; secure";
}
$document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
}
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return false;
}
return true;
};
// Directly get a value from a cookie
// Example use: localStorageService.cookie.get('library'); // returns 'angular'
var getFromCookies = function (key) {
if (!browserSupportsCookies) {
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
return false;
}
var cookies = $document.cookie && $document.cookie.split(';') || [];
for(var i=0; i < cookies.length; i++) {
var thisCookie = cookies[i];
while (thisCookie.charAt(0) === ' ') {
thisCookie = thisCookie.substring(1,thisCookie.length);
}
if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length));
try {
return JSON.parse(storedValues);
} catch(e) {
return storedValues;
}
}
}
return null;
};
var removeFromCookies = function (key) {
addToCookies(key,null);
};
var clearAllFromCookies = function () {
var thisCookie = null;
var prefixLength = prefix.length;
var cookies = $document.cookie.split(';');
for(var i = 0; i < cookies.length; i++) {
thisCookie = cookies[i];
while (thisCookie.charAt(0) === ' ') {
thisCookie = thisCookie.substring(1, thisCookie.length);
}
var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
removeFromCookies(key);
}
};
var getStorageType = function() {
return storageType;
};
var setStorageType = function(type) {
if (type && storageType !== type) {
storageType = type;
browserSupportsLocalStorage = checkSupport();
}
return browserSupportsLocalStorage;
};
// Add a listener on scope variable to save its changes to local storage
// Return a function which when called cancels binding
var bindToScope = function(scope, key, def, lsKey, type) {
lsKey = lsKey || key;
var value = getFromLocalStorage(lsKey, type);
if (value === null && isDefined(def)) {
value = def;
} else if (isObject(value) && isObject(def)) {
value = extend(value, def);
}
$parse(key).assign(scope, value);
return scope.$watch(key, function(newVal) {
addToLocalStorage(lsKey, newVal, type);
}, isObject(scope[key]));
};
// Add listener to local storage, for update callbacks.
if (browserSupportsLocalStorage) {
if ($window.addEventListener) {
$window.addEventListener("storage", handleStorageChangeCallback, false);
$rootScope.$on('$destroy', function() {
$window.removeEventListener("storage", handleStorageChangeCallback);
});
} else if($window.attachEvent){
// attachEvent and detachEvent are proprietary to IE v6-10
$window.attachEvent("onstorage", handleStorageChangeCallback);
$rootScope.$on('$destroy', function() {
$window.detachEvent("onstorage", handleStorageChangeCallback);
});
}
}
// Callback handler for storage changed.
function handleStorageChangeCallback(e) {
if (!e) { e = $window.event; }
if (notify.setItem) {
if (isKeyPrefixOurs(e.key)) {
var key = underiveQualifiedKey(e.key);
// Use timeout, to avoid using $rootScope.$apply.
$timeout(function () {
$rootScope.$broadcast('LocalStorageModule.notification.changed', { key: key, newvalue: e.newValue, storageType: self.storageType });
});
}
}
}
// Return localStorageService.length
// ignore keys that not owned
var lengthOfLocalStorage = function(type) {
setStorageType(type);
var count = 0;
var storage = $window[storageType];
for(var i = 0; i < storage.length; i++) {
if(storage.key(i).indexOf(prefix) === 0 ) {
count++;
}
}
return count;
};
return {
isSupported: browserSupportsLocalStorage,
getStorageType: getStorageType,
setStorageType: setStorageType,
set: addToLocalStorage,
add: addToLocalStorage, //DEPRECATED
get: getFromLocalStorage,
keys: getKeysForLocalStorage,
remove: removeFromLocalStorage,
clearAll: clearAllFromLocalStorage,
bind: bindToScope,
deriveKey: deriveQualifiedKey,
underiveKey: underiveQualifiedKey,
length: lengthOfLocalStorage,
defaultToCookie: this.defaultToCookie,
cookie: {
isSupported: browserSupportsCookies,
set: addToCookies,
add: addToCookies, //DEPRECATED
get: getFromCookies,
remove: removeFromCookies,
clearAll: clearAllFromCookies
}
};
}];
});
})(window, window.angular);

View File

@@ -1,5 +1,4 @@
window.OFNShared = angular.module("OFNShared", [
"mm.foundation",
"LocalStorageModule"
]).config ($httpProvider) ->
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"

View File

@@ -44,9 +44,9 @@ module Admin
create_connected_app
jwt_service = VineJwtService.new(secret: connected_app_params[:vine_secret])
vine_api = VineApiService.new(api_key: connected_app_params[:vine_api_key],
jwt_generator: jwt_service)
jwt_service = Vine::JwtService.new(secret: connected_app_params[:vine_secret])
vine_api = Vine::ApiService.new(api_key: connected_app_params[:vine_api_key],
jwt_generator: jwt_service)
if !@app.connect(api_key: connected_app_params[:vine_api_key],
secret: connected_app_params[:vine_secret], vine_api:)
@@ -77,7 +77,7 @@ module Admin
def log_and_notify_exception(exception)
Rails.logger.error exception.inspect
Bugsnag.notify(exception)
Alert.raise(exception)
end
def vine_params_empty?

View File

@@ -19,15 +19,12 @@ module Admin
.find(params.require(:enterprise_id))
catalog_url = params.require(:catalog_url)
json_catalog = fetch_catalog(catalog_url)
graph = DfcIo.import(json_catalog)
catalog = DfcCatalog.load(spree_current_user, catalog_url)
catalog.apply_wholesale_values!
# * First step: import all products for given enterprise.
# * Second step: render table and let user decide which ones to import.
imported = graph.map do |subject|
next unless subject.is_a? DataFoodConsortium::Connector::SuppliedProduct
imported = catalog.products.map do |subject|
existing_variant = enterprise.supplied_variants.linked_to(subject.semanticId)
if existing_variant
@@ -44,11 +41,5 @@ module Admin
flash[:error] = e.message
redirect_to admin_product_import_path
end
private
def fetch_catalog(url)
DfcRequest.new(spree_current_user).call(url)
end
end
end

View File

@@ -30,13 +30,13 @@ module Admin
def validate_data
return unless process_data('validate')
render json: @importer.import_results, response: 200
render json: @importer.import_results
end
def save_data
return unless process_data('save')
render json: @importer.save_results, response: 200
render json: @importer.save_results
end
def reset_absent_products
@@ -76,7 +76,7 @@ module Admin
begin
@importer.public_send("#{method}_entries")
rescue StandardError => e
render json: e.message, response: 500
render plain: e.message, status: :internal_server_error
return false
end

View File

@@ -144,7 +144,7 @@ module Admin
def product_scope
user = spree_current_user
scope = if user.has_spree_role?("admin") || user.enterprises.present?
scope = if user.admin? || user.enterprises.present?
Spree::Product
else
Spree::Product.active

View File

@@ -71,6 +71,12 @@ module Admin
def load_collection
collection_hash = Hash[variant_overrides_params.each_with_index.map { |vo, i| [i, vo] }]
# Reset count_on_hand when switching to producer settings:
collection_hash.each_value do |vo|
vo["count_on_hand"] = nil if vo.fetch("on_demand", :unchanged).nil?
end
@vo_set = Sets::VariantOverrideSet.new(@variant_overrides,
collection_attributes: collection_hash)
end

View File

@@ -66,7 +66,7 @@ module Api
end
def error_during_processing(exception)
Bugsnag.notify(exception)
Alert.raise(exception)
render(json: { exception: exception.message },
status: :unprocessable_entity) && return

View File

@@ -14,7 +14,7 @@ module Api
def create
variant = scoped_variant(params[:variant_id])
quantity = params[:quantity].to_i
@shipment = get_or_create_shipment(params[:stock_location_id])
@shipment = @order.shipment || @order.shipments.create
@order.contents.add(variant, quantity, @shipment)
@@ -24,6 +24,7 @@ module Api
Orders::WorkflowService.new(@order).advance_to_payment if @order.line_items.any?
@order.recreate_all_fees!
AmendBackorderJob.perform_later(@order) if @order.completed?
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
end
@@ -73,6 +74,7 @@ module Api
@order.contents.add(variant, quantity, @shipment)
@order.recreate_all_fees!
AmendBackorderJob.perform_later(@order) if @order.completed?
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
end
@@ -86,6 +88,7 @@ module Api
@shipment.reload if @shipment.persisted?
@order.recreate_all_fees!
AmendBackorderJob.perform_later(@order) if @order.completed?
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
end
@@ -113,10 +116,6 @@ module Api
variant
end
def get_or_create_shipment(stock_location_id)
@order.shipment || @order.shipments.create(stock_location_id:)
end
def shipment_params
return {} unless params.has_key? :shipment

View File

@@ -55,14 +55,14 @@ module Api
def scope
if @product
variants = if current_api_user.has_spree_role?("admin") || params[:show_deleted]
variants = if current_api_user.admin? || params[:show_deleted]
@product.variants.with_deleted
else
@product.variants
end
else
variants = Spree::Variant.where(nil)
if current_api_user.has_spree_role?("admin")
if current_api_user.admin?
unless params[:show_deleted]
variants = Spree::Variant.active
end

View File

@@ -52,7 +52,7 @@ module Api
end
def error_during_processing(exception)
Bugsnag.notify(exception)
Alert.raise(exception)
if Rails.env.development? || Rails.env.test?
render status: :unprocessable_entity,

View File

@@ -11,7 +11,7 @@ class CartController < BaseController
order.cap_quantity_at_stock!
order.recreate_all_fees!
StockSyncJob.sync_linked_catalogs(order)
StockSyncJob.sync_linked_catalogs_later(order)
render json: { error: false, stock_levels: stock_levels(order) }, status: :ok
else

View File

@@ -78,8 +78,21 @@ class CheckoutController < BaseController
return true if redirect_to_payment_gateway
# Redeem VINE voucher
vine_voucher_redeemer = Vine::VoucherRedeemerService.new(order: @order)
unless vine_voucher_redeemer.redeem
# rubocop:disable Rails/DeprecatedActiveModelErrorsMethods
flash[:error] = if vine_voucher_redeemer.errors.keys.include?(:redeeming_failed)
vine_voucher_redeemer.errors[:redeeming_failed]
else
I18n.t('checkout.errors.voucher_redeeming_error')
end
return false
# rubocop:enable Rails/DeprecatedActiveModelErrorsMethods
end
@order.process_payments!
@order.confirm!
BackorderJob.check_stock(@order)
order_completion_reset @order
end

View File

@@ -50,9 +50,7 @@ module OrderCompletion
end
def order_invalid!
Bugsnag.notify("Notice: invalid order loaded during checkout") do |payload|
payload.add_metadata :order, :order, @order
end
Alert.raise_with_record("Notice: invalid order loaded during checkout", @order)
flash[:error] = t('checkout.order_not_loaded')
redirect_to main_app.shop_path
@@ -92,9 +90,7 @@ module OrderCompletion
end
def notify_failure(error = RuntimeError.new(order_processing_error))
Bugsnag.notify(error) do |payload|
payload.add_metadata :order, @order
end
Alert.raise_with_record(error, @order)
flash[:error] = order_processing_error if flash.blank?
end

View File

@@ -20,9 +20,7 @@ module OrderStockCheck
def check_order_cycle_expiry
return unless current_order_cycle&.closed?
Bugsnag.notify("Notice: order cycle closed during checkout completion") do |payload|
payload.add_metadata :order, :order, current_order
end
Alert.raise_with_record("Notice: order cycle closed during checkout completion", current_order)
current_order.empty!
current_order.set_order_cycle! nil

View File

@@ -4,11 +4,6 @@ class ErrorsController < ApplicationController
layout "errors"
def not_found
Bugsnag.notify("404") do |event|
event.severity = "info"
event.add_metadata(:request, :env, request.env)
end
render status: :not_found, formats: :html
end

View File

@@ -70,6 +70,7 @@ module Spree
@order.restock_items = params.fetch(:restock_items, "true") == "true"
if @order.public_send(event.to_s)
AmendBackorderJob.perform_later(@order) if @order.completed?
flash[:success] = Spree.t(:order_updated)
else
flash[:error] = Spree.t(:cannot_perform_operation)

View File

@@ -24,9 +24,12 @@ module Spree
end
def create
# Try to redeem VINE voucher first as we don't want to create a payment and complete
# the order if it fails
return redirect_to spree.admin_order_payments_path(@order) unless redeem_vine_voucher
@payment = @order.payments.build(object_params)
load_payment_source
begin
unless @payment.save
redirect_to spree.admin_order_payments_path(@order)
@@ -51,6 +54,10 @@ module Spree
event = params[:e]
return unless event && @payment.payment_source
# capture_and_complete_order will complete the order, so we want to try to redeem VINE
# voucher first and exit if it fails
return if event == "capture_and_complete_order" && !redeem_vine_voucher
# Because we have a transition method also called void, we do this to avoid conflicts.
event = "void_transaction" if event == "void"
if allowed_events.include?(event) && @payment.public_send("#{event}!")
@@ -60,7 +67,7 @@ module Spree
end
rescue StandardError => e
logger.error e.message
Bugsnag.notify(e)
Alert.raise(e)
flash[:error] = e.message
ensure
redirect_to request.referer
@@ -182,6 +189,22 @@ module Spree
%w{capture void_transaction credit refund resend_authorization_email
capture_and_complete_order}
end
def redeem_vine_voucher
vine_voucher_redeemer = Vine::VoucherRedeemerService.new(order: @order)
if vine_voucher_redeemer.redeem == false
# rubocop:disable Rails/DeprecatedActiveModelErrorsMethods
flash[:error] = if vine_voucher_redeemer.errors.keys.include?(:redeeming_failed)
vine_voucher_redeemer.errors[:redeeming_failed]
else
I18n.t('checkout.errors.voucher_redeeming_error')
end
# rubocop:enable Rails/DeprecatedActiveModelErrorsMethods
return false
end
true
end
end
end
end

View File

@@ -11,6 +11,7 @@ module Spree
include OrderCyclesHelper
include EnterprisesHelper
helper ::Admin::ProductsHelper
helper Spree::Admin::TaxCategoriesHelper
before_action :load_data
before_action :load_producers, only: [:index, :new]
@@ -213,7 +214,7 @@ module Spree
end
def notify_bugsnag(error, product, variant)
Bugsnag.notify(error) do |report|
Alert.raise(error) do |report|
report.add_metadata(:product,
{ product: product.attributes, variant: variant.attributes })
report.add_metadata(:product, :product_error, product.errors.first) unless product.valid?

View File

@@ -11,8 +11,6 @@ module Spree
# http://spreecommerce.com/blog/2010/11/02/json-hijacking-vulnerability/
before_action :check_json_authenticity, only: :index
before_action :load_roles, only: [:edit, :new, :update, :create,
:generate_api_key, :clear_api_key]
def index
respond_with(@collection) do |format|
@@ -22,17 +20,9 @@ module Spree
end
def create
if params[:user]
roles = params[:user].delete("spree_role_ids")
end
@user = Spree::User.new(user_params)
if @user.save
if roles
@user.spree_roles = roles.compact_blank.collect{ |r| Spree::Role.find(r) }
end
flash[:success] = Spree.t(:created_successfully)
redirect_to edit_admin_user_path(@user)
else
@@ -41,15 +31,7 @@ module Spree
end
def update
if params[:user]
roles = params[:user].delete("spree_role_ids")
end
if @user.update(user_params)
if roles
@user.spree_roles = roles.compact_blank.collect{ |r| Spree::Role.find(r) }
end
flash[:success] = update_message
redirect_to edit_admin_user_path(@user)
else
@@ -123,10 +105,6 @@ module Spree
sign_in(@user, event: :authentication, bypass: true)
end
def load_roles
@roles = Spree::Role.where(nil)
end
def new_email_unconfirmed?
params[:user][:email] != @user.email
end
@@ -137,7 +115,7 @@ module Spree
def user_params
::PermittedAttributes::User.new(params).call(
%i[enterprise_limit show_api_key_view]
%i[admin enterprise_limit show_api_key_view]
)
end
end

View File

@@ -2,7 +2,6 @@
module Spree
class ApiKeysController < ::BaseController
include Spree::Core::ControllerHelpers
include I18nHelper
prepend_before_action :load_object

View File

@@ -70,14 +70,15 @@ module Spree
@order.recreate_all_fees! # Enterprise fees on line items and on the order itself
# Re apply the voucher
VoucherAdjustmentsService.new(@order).update
@order.update_totals_and_states
OrderManagement::Order::Updater.new(@order).update_voucher
if @order.complete?
@order.update_payment_fees!
@order.create_tax_charge!
end
AmendBackorderJob.perform_later(@order) if @order.completed?
respond_with(@order) do |format|
format.html do
if params.key?(:checkout)

View File

@@ -2,7 +2,6 @@
module Spree
class UsersController < ::BaseController
include Spree::Core::ControllerHelpers
include I18nHelper
include CablecarResponses

View File

@@ -1,6 +1,5 @@
# frozen_string_literal: true
require 'open_food_network/error_logger'
require "spree/core/controller_helpers/auth"
require "spree/core/controller_helpers/common"
require "spree/core/controller_helpers/order"
@@ -37,7 +36,7 @@ class UserRegistrationsController < Devise::RegistrationsController
end
end
rescue StandardError => e
OpenFoodNetwork::ErrorLogger.notify(e)
Alert.raise(e)
render_error(message: I18n.t('unknown_error', scope: I18N_SCOPE))
end

View File

@@ -4,7 +4,16 @@ class VoucherAdjustmentsController < BaseController
before_action :set_order
def create
if add_voucher
if voucher_params[:voucher_code].blank?
@order.errors.add(:voucher_code, I18n.t('checkout.errors.voucher_not_found'))
return render_error
end
voucher = load_voucher
return render_error unless valid_voucher?(voucher)
if add_voucher_to_order(voucher)
update_payment_section
elsif @order.errors.present?
render_error
@@ -30,19 +39,28 @@ class VoucherAdjustmentsController < BaseController
@order = current_order
end
def add_voucher
if voucher_params[:voucher_code].blank?
@order.errors.add(:voucher_code, I18n.t('checkout.errors.voucher_not_found'))
return false
end
voucher = Voucher.find_by(code: voucher_params[:voucher_code], enterprise: @order.distributor)
def valid_voucher?(voucher)
return false if @order.errors.present?
if voucher.nil?
@order.errors.add(:voucher_code, I18n.t('checkout.errors.voucher_not_found'))
return false
end
if !voucher.valid?
@order.errors.add(
:voucher_code,
I18n.t(
'checkout.errors.create_voucher_error', error: voucher.errors.full_messages.to_sentence
)
)
return false
end
true
end
def add_voucher_to_order(voucher)
adjustment = voucher.create_adjustment(voucher.code, @order)
unless adjustment.persisted?
@@ -51,14 +69,38 @@ class VoucherAdjustmentsController < BaseController
return false
end
# calculate_voucher_adjustment
clear_payments
VoucherAdjustmentsService.new(@order).update
@order.update_totals_and_states
OrderManagement::Order::Updater.new(@order).update_voucher
true
end
def load_voucher
voucher = Voucher.find_by(code: voucher_params[:voucher_code],
enterprise: @order.distributor)
return voucher unless voucher.nil? || voucher.is_a?(Vouchers::Vine)
vine_voucher
end
def vine_voucher
vine_voucher_validator = Vine::VoucherValidatorService.new(
voucher_code: voucher_params[:voucher_code], enterprise: @order.distributor
)
voucher = vine_voucher_validator.validate
return nil if vine_voucher_validator.errors[:not_found_voucher].present?
if vine_voucher_validator.errors.present?
@order.errors.add(:voucher_code, I18n.t('checkout.errors.add_voucher_error'))
return nil
end
voucher
end
def update_payment_section
render cable_ready: cable_car.replace(
selector: "#checkout-payment-methods",

View File

@@ -14,6 +14,7 @@ module Admin
# e.g producer_options = [['producer name', id]]
product.variants.build do |new_variant|
new_variant.supplier_id = producer_options.first.second if producer_options.one?
new_variant.tax_category_id = product.variants.first.tax_category_id
end
end

View File

@@ -6,7 +6,7 @@ module SharedHelper
end
def admin_user?
spree_current_user&.has_spree_role? 'admin'
spree_current_user&.admin?
end
def current_shop_products_path

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
module Spree
module Admin
module TaxCategoriesHelper
def tax_category_dropdown_options(require_tax_category)
if require_tax_category
{
include_blank: false,
selected: Spree::TaxCategory.find_by(is_default: true)&.id
}
else
{
include_blank: t(:none),
}
end
end
end
end
end

View File

@@ -3,7 +3,7 @@
module Spree
module BaseHelper
def available_countries
checkout_zone = Zone.find_by(name: Spree::Config[:checkout_zone])
checkout_zone = Zone.find_by(name: ENV.fetch("CHECKOUT_ZONE", nil))
countries = if checkout_zone && checkout_zone.kind == 'country'
checkout_zone.countries

View File

@@ -1,98 +1,38 @@
# frozen_string_literal: true
# When orders are cancelled, we need to amend
# When orders are created, adjusted or cancelled, we need to amend
# an existing backorder as well.
# We're not dealing with line item changes just yet.
class AmendBackorderJob < ApplicationJob
sidekiq_options retry: 0
def self.schedule_bulk_update_for(orders)
# We can have one backorder per order cycle and distributor.
groups = orders.group_by { |order| [order.order_cycle, order.distributor] }
groups.each_value do |orders_with_same_backorder|
# We need to trigger only one update per backorder.
perform_later(orders_with_same_backorder.first)
end
end
def perform(order)
OrderLocker.lock_order_and_variants(order) do
amend_backorder(order)
end
end
# The following is a mix of the BackorderJob and the CompleteBackorderJob.
# TODO: Move the common code into a re-usable service class.
def amend_backorder(order)
order_cycle = order.order_cycle
distributor = order.distributor
user = distributor.owner
items = backorderable_items(order)
backorder = BackorderUpdater.new.amend_backorder(order)
return if items.empty?
if backorder
user = order.distributor.owner
urls = nil # Not needed to send order. The backorder id is the URL.
FdcBackorderer.new(user, urls).send_order(backorder)
elsif !order.order_cycle.closed?
# We are assuming that all variants are linked to the same wholesale
# shop and its catalog:
reference_link = items[0].variant.semantic_links[0].semantic_id
urls = FdcUrlBuilder.new(reference_link)
orderer = FdcBackorderer.new(user, urls)
backorder = orderer.find_open_order(order)
variants = order_cycle.variants_distributed_by(distributor)
adjust_quantities(order_cycle, user, backorder, urls, variants)
FdcBackorderer.new(user, urls).send_order(backorder)
end
# Check if we have enough stock to reduce the backorder.
#
# Our local stock can increase when users cancel their orders.
# But stock levels could also have been adjusted manually. So we review all
# quantities before finalising the order.
def adjust_quantities(order_cycle, user, order, urls, variants)
broker = FdcOfferBroker.new(user, urls)
order.lines.each do |line|
line.quantity = line.quantity.to_i
wholesale_product_id = line.offer.offeredItem.semanticId
transformation = broker.wholesale_to_retail(wholesale_product_id)
linked_variant = variants.linked_to(transformation.retail_product_id)
# Assumption: If a transformation is present then we only sell the retail
# variant. If that can't be found, it was deleted and we'll ignore that
# for now.
next if linked_variant.nil?
# Find all line items for this order cycle
# Update quantity accordingly
if linked_variant.on_demand
release_superfluous_stock(line, linked_variant, transformation)
else
aggregate_final_quantities(order_cycle, line, linked_variant, transformation)
end
# We don't have an order to amend but the order cycle is or will open.
# We can assume that this job was triggered by an admin creating a new
# order or adding backorderable items to an order.
BackorderJob.new.place_backorder(order)
end
# Clean up empty lines:
order.lines.reject! { |line| line.quantity.zero? }
end
# We look at all linked variants.
def backorderable_items(order)
order.line_items.select do |item|
# TODO: scope variants to hub.
# We are only supporting producer stock at the moment.
item.variant.semantic_links.present?
end
end
def release_superfluous_stock(line, linked_variant, transformation)
# Note that a division of integers dismisses the remainder, like `floor`:
wholesale_items_contained_in_stock = linked_variant.on_hand / transformation.factor
# But maybe we didn't actually order that much:
deductable_quantity = [line.quantity, wholesale_items_contained_in_stock].min
line.quantity -= deductable_quantity
retail_stock_changes = deductable_quantity * transformation.factor
linked_variant.on_hand -= retail_stock_changes
end
def aggregate_final_quantities(order_cycle, line, variant, transformation)
orders = order_cycle.orders.invoiceable
quantity = Spree::LineItem.where(order: orders, variant:).sum(:quantity)
wholesale_quantity = (quantity.to_f / transformation.factor).ceil
line.quantity = wholesale_quantity
end
end

View File

@@ -19,9 +19,7 @@ class BackorderJob < ApplicationJob
rescue StandardError => e
# Errors here shouldn't affect the checkout. So let's report them
# separately:
Bugsnag.notify(e) do |payload|
payload.add_metadata(:order, :order, order)
end
Alert.raise_with_record(e, order)
end
def perform(order)
@@ -119,7 +117,8 @@ class BackorderJob < ApplicationJob
end
def load_broker(user, urls)
FdcOfferBroker.new(user, urls)
catalog = DfcCatalog.load(user, urls.catalog_url)
FdcOfferBroker.new(catalog)
end
def place_order(user, order, orderer, backorder)

View File

@@ -24,8 +24,7 @@ class CompleteBackorderJob < ApplicationJob
urls = FdcUrlBuilder.new(order.lines[0].offer.offeredItem.semanticId)
variants = order_cycle.variants_distributed_by(distributor)
adjust_quantities(order_cycle, user, order, urls, variants)
BackorderUpdater.new.update(order, user, distributor, order_cycle)
FdcBackorderer.new(user, urls).complete_order(order)
@@ -36,55 +35,4 @@ class CompleteBackorderJob < ApplicationJob
raise
end
# Check if we have enough stock to reduce the backorder.
#
# Our local stock can increase when users cancel their orders.
# But stock levels could also have been adjusted manually. So we review all
# quantities before finalising the order.
def adjust_quantities(order_cycle, user, order, urls, variants)
broker = FdcOfferBroker.new(user, urls)
order.lines.each do |line|
line.quantity = line.quantity.to_i
wholesale_product_id = line.offer.offeredItem.semanticId
transformation = broker.wholesale_to_retail(wholesale_product_id)
linked_variant = variants.linked_to(transformation.retail_product_id)
# Assumption: If a transformation is present then we only sell the retail
# variant. If that can't be found, it was deleted and we'll ignore that
# for now.
next if linked_variant.nil?
# Find all line items for this order cycle
# Update quantity accordingly
if linked_variant.on_demand
release_superfluous_stock(line, linked_variant, transformation)
else
aggregate_final_quantities(order_cycle, line, linked_variant, transformation)
end
end
# Clean up empty lines:
order.lines.reject! { |line| line.quantity.zero? }
end
def release_superfluous_stock(line, linked_variant, transformation)
# Note that a division of integers dismisses the remainder, like `floor`:
wholesale_items_contained_in_stock = linked_variant.on_hand / transformation.factor
# But maybe we didn't actually order that much:
deductable_quantity = [line.quantity, wholesale_items_contained_in_stock].min
line.quantity -= deductable_quantity
retail_stock_changes = deductable_quantity * transformation.factor
linked_variant.on_hand -= retail_stock_changes
end
def aggregate_final_quantities(order_cycle, line, variant, transformation)
orders = order_cycle.orders.invoiceable
quantity = Spree::LineItem.where(order: orders, variant:).sum(:quantity)
wholesale_quantity = (quantity.to_f / transformation.factor).ceil
line.quantity = wholesale_quantity
end
end

View File

@@ -22,11 +22,7 @@ class ReportJob < ApplicationJob
broadcast_result(channel, format, blob) if channel
rescue StandardError => e
Bugsnag.notify(e) do |payload|
payload.add_metadata :report, {
report_class:, user:, params:, format:
}
end
Alert.raise(e, { report: { report_class:, user:, params:, format: } })
broadcast_error(channel)
end

View File

@@ -8,30 +8,12 @@ class StockSyncJob < ApplicationJob
# product. These variants are rare though and we check first before we
# enqueue a new job. That should save some time loading the order with
# all the stock data to make this decision.
def self.sync_linked_catalogs(order)
user = order.distributor.owner
catalog_ids(order).each do |catalog_id|
perform_later(user, catalog_id)
end
rescue StandardError => e
# Errors here shouldn't affect the shopping. So let's report them
# separately:
Bugsnag.notify(e) do |payload|
payload.add_metadata(:order, :order, order)
end
def self.sync_linked_catalogs_later(order)
sync_catalogs_by_perform_method(order, :perform_later)
end
def self.sync_linked_catalogs_now(order)
user = order.distributor.owner
catalog_ids(order).each do |catalog_id|
perform_now(user, catalog_id)
end
rescue StandardError => e
# Errors here shouldn't affect the shopping. So let's report them
# separately:
Bugsnag.notify(e) do |payload|
payload.add_metadata(:order, :order, order)
end
sync_catalogs_by_perform_method(order, :perform_now)
end
def self.catalog_ids(order)
@@ -44,7 +26,10 @@ class StockSyncJob < ApplicationJob
end
def perform(user, catalog_id)
products = load_products(user, catalog_id)
catalog = DfcCatalog.load(user, catalog_id)
catalog.apply_wholesale_values!
products = catalog.products
products_by_id = products.index_by(&:semanticId)
product_ids = products_by_id.keys
variants = linked_variants(user.enterprises, product_ids)
@@ -62,18 +47,23 @@ class StockSyncJob < ApplicationJob
end
end
def load_products(user, catalog_id)
json_catalog = DfcRequest.new(user).call(catalog_id)
graph = DfcIo.import(json_catalog)
graph.select do |subject|
subject.is_a? DataFoodConsortium::Connector::SuppliedProduct
end
end
def linked_variants(enterprises, product_ids)
Spree::Variant.where(supplier: enterprises)
.includes(:semantic_links).references(:semantic_links)
.where(semantic_links: { semantic_id: product_ids })
end
def self.sync_catalogs_by_perform_method(order, perform_method)
distributor = order.distributor
return unless distributor
user = distributor.owner
catalog_ids(order).each do |catalog_id|
public_send(perform_method, user, catalog_id)
end
rescue StandardError => e
# Errors here shouldn't affect the shopping. So let's report them
# separately:
Alert.raise_with_record(e, order)
end
end

View File

@@ -55,9 +55,7 @@ class SubscriptionConfirmJob < ApplicationJob
if order.errors.any?
send_failed_payment_email(order)
else
Bugsnag.notify(e) do |payload|
payload.add_metadata :order, :order, order
end
Alert.raise_with_record(e, order)
send_failed_payment_email(order, e.message)
end
end
@@ -108,8 +106,6 @@ class SubscriptionConfirmJob < ApplicationJob
record_and_log_error(:failed_payment, order, error_message)
SubscriptionMailer.failed_payment_email(order).deliver_now
rescue StandardError => e
Bugsnag.notify(e) do |payload|
payload.add_metadata :subscription_data, { order:, error_message: }
end
Alert.raise(e, { subscription_data: { order:, error_message: } })
end
end

View File

@@ -79,14 +79,19 @@ class ProducerMailer < ApplicationMailer
def set_customer_data(line_items)
return unless @coordinator.show_customer_names_to_suppliers?
@display_business_name = false
line_items.map do |line_item|
customer_code = line_item.order.customer&.code
@display_business_name = true if customer_code.present?
{
sku: line_item.variant.sku,
supplier_name: line_item.variant.supplier.name,
product_and_full_name: line_item.product_and_full_name,
quantity: line_item.quantity,
first_name: line_item.order.billing_address.first_name,
last_name: line_item.order.billing_address.last_name
last_name: line_item.order.billing_address.last_name,
business_name: customer_code,
}
end.sort_by { |line_item| [line_item[:last_name].downcase, line_item[:first_name].downcase] }
end

View File

@@ -28,7 +28,7 @@ module Calculator
# In theory it should never be called any more after this has been deployed.
# If the message below doesn't show up in Bugsnag, we can safely delete this method and all
# the related methods below it.
Bugsnag.notify("Calculator::DefaultTax was called with legacy tax calculations")
Alert.raise("Calculator::DefaultTax was called with legacy tax calculations")
calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor,
order.order_cycle)

View File

@@ -78,11 +78,6 @@ module VariantStock
on_demand || total_on_hand >= quantity
end
# Moving Spree::StockLocation.fill_status to the variant enables us
# to override this behaviour for variant overrides
# We can have this responsibility here in the variant because there is
# only one stock item per variant
#
# Here we depend only on variant.total_on_hand and variant.on_demand.
# This way, variant_overrides only need to override variant.total_on_hand and variant.on_demand.
def fill_status(quantity)
@@ -107,13 +102,15 @@ module VariantStock
raise_error_if_no_stock_item_available
# Creates a stock movement: it updates stock_item.count_on_hand and fills backorders
#
# This is the original Spree::StockLocation#move,
# except that we raise an error if the stock item is missing,
# because, unlike Spree, we should always have exactly one stock item per variant.
stock_item.stock_movements.create!(quantity:, originator:)
end
# There shouldn't be any other stock items, because we should
# have only one stock location.
def stock_item
stock_items.first
end
private
# Persists the single stock item associated to this variant. As defined in
@@ -139,10 +136,4 @@ module VariantStock
def overwrite_stock_levels(new_level)
stock_item.adjust_count_on_hand(new_level.to_i - stock_item.count_on_hand)
end
# There shouldn't be any other stock items, because we should
# have only one stock location.
def stock_item
stock_items.first
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
require "active_support/concern"
module Vouchers
module FlatRatable
extend ActiveSupport::Concern
included do
validates :amount,
presence: true,
numericality: { greater_than: 0 }
end
def display_value
Spree::Money.new(amount)
end
# We limit adjustment to the maximum amount needed to cover the order, ie if the voucher
# covers more than the order.total we only need to create an adjustment covering the order.total
def compute_amount(order)
-amount.clamp(0, order.pre_discount_total)
end
def rate(order)
amount = compute_amount(order)
amount / order.pre_discount_total
end
end
end

View File

@@ -218,7 +218,7 @@ class Enterprise < ApplicationRecord
}
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
joins(:enterprise_roles).where(enterprise_roles: { user_id: user.id })
@@ -481,7 +481,7 @@ class Enterprise < ApplicationRecord
image_variant_url_for(image.variant(name))
rescue StandardError => e
Bugsnag.notify "Enterprise ##{id} #{image.try(:name)} error: #{e.message}"
Alert.raise "Enterprise ##{id} #{image.try(:name)} error: #{e.message}"
Rails.logger.error(e.message)
nil

View File

@@ -28,7 +28,7 @@ class EnterpriseFee < ApplicationRecord
scope :for_enterprises, lambda { |enterprises| where(enterprise_id: enterprises) }
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
where(enterprise_id: user.enterprises.select(&:id))

View File

@@ -38,7 +38,7 @@ class EnterpriseGroup < ApplicationRecord
scope :by_position, -> { order('position ASC') }
scope :on_front_page, -> { where(on_front_page: true) }
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
where(owner_id: user.id)

View File

@@ -75,7 +75,7 @@ class Exchange < ApplicationRecord
}
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
joins("LEFT JOIN enterprises senders ON senders.id = exchanges.sender_id").

View File

@@ -32,6 +32,6 @@ class Invoice < ApplicationRecord
end
def previous_invoice
order.invoices.where("id < ?", id).first
order.invoices.where(id: ...id).first
end
end

View File

@@ -53,7 +53,7 @@ class OrderCycle < ApplicationRecord
Time.zone.now,
Time.zone.now)
}
scope :active_or_complete, lambda { where('order_cycles.orders_open_at <= ?', Time.zone.now) }
scope :active_or_complete, lambda { where(order_cycles: { orders_open_at: ..Time.zone.now }) }
scope :inactive, lambda {
where('order_cycles.orders_open_at > ? OR order_cycles.orders_close_at < ?',
Time.zone.now,
@@ -64,8 +64,8 @@ class OrderCycle < ApplicationRecord
where('order_cycles.orders_close_at > ? OR order_cycles.orders_close_at IS NULL', Time.zone.now)
}
scope :closed, lambda {
where('order_cycles.orders_close_at < ?',
Time.zone.now).order("order_cycles.orders_close_at DESC")
where(order_cycles: { orders_close_at: ...Time.zone.now })
.order("order_cycles.orders_close_at DESC")
}
scope :unprocessed, -> { where(processed_at: nil) }
scope :undated, -> { where('order_cycles.orders_open_at IS NULL OR orders_close_at IS NULL') }
@@ -84,7 +84,7 @@ class OrderCycle < ApplicationRecord
}
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
where(coordinator_id: user.enterprises.to_a)
@@ -93,7 +93,7 @@ class OrderCycle < ApplicationRecord
# Return order cycles that user coordinates, sends to or receives from
scope :visible_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
with_exchanging_enterprises_outer.

View File

@@ -79,10 +79,9 @@ module ProductImport
if entry.attributes['on_hand'].present?
new_variant.on_hand = entry.attributes['on_hand']
end
check_on_hand_nil(entry, new_variant)
end
check_on_hand_nil(entry, new_variant)
if new_variant.valid?
entry.product_object = new_variant
entry.validates_as = 'new_variant' unless entry.errors?
@@ -161,7 +160,7 @@ module ProductImport
end
def unit_fields_validation(entry)
unit_types = ['g', 'oz', 'lb', 'kg', 't', 'ml', 'l', 'kl', '']
unit_types = ['mg', 'g', 'kg', 'oz', 'lb', 't', 'ml', 'cl', 'dl', 'l', 'kl', 'gal', '']
if entry.units.blank?
mark_as_invalid(entry, attribute: 'units',
@@ -297,7 +296,7 @@ module ProductImport
unscaled_units = entry.unscaled_units.to_f || 0
entry.unit_value = unscaled_units * unit_scale unless unit_scale.nil?
if entry.match_inventory_variant?(existing_variant)
if entry.match_variant?(existing_variant)
variant_override = create_inventory_item(entry, existing_variant)
return validate_inventory_item(entry, variant_override)
end

View File

@@ -85,10 +85,6 @@ module ProductImport
end
def match_variant?(variant)
match_display_name?(variant) && variant.unit_value.to_d == unscaled_units.to_d
end
def match_inventory_variant?(variant)
match_display_name?(variant) && variant.unit_value.to_d == unit_value.to_d
end

View File

@@ -32,14 +32,18 @@ module ProductImport
def unit_scales
{
'mg' => { scale: 0.001, unit: 'weight' },
'g' => { scale: 1, unit: 'weight' },
'kg' => { scale: 1000, unit: 'weight' },
'oz' => { scale: 28.35, unit: 'weight' },
'lb' => { scale: 453.6, unit: 'weight' },
't' => { scale: 1_000_000, unit: 'weight' },
'ml' => { scale: 0.001, unit: 'volume' },
'cl' => { scale: 0.01, unit: 'volume' },
'dl' => { scale: 0.1, unit: 'volume' },
'l' => { scale: 1, unit: 'volume' },
'kl' => { scale: 1000, unit: 'volume' }
'kl' => { scale: 1000, unit: 'volume' },
'gal' => { scale: 4.54609, unit: 'volume' },
}
end

View File

@@ -18,7 +18,7 @@ module Spree
user ||= Spree::User.new
if user.respond_to?(:has_spree_role?) && user.has_spree_role?('admin')
if user.try(:admin?)
can :manage, :all
else
can [:index, :read], Country

View File

@@ -126,7 +126,7 @@ module Spree
end
def address_and_city
[address1, address2, city].select(&:present?).join(' ')
[address1, address2, city].compact_blank.join(' ')
end
private
@@ -176,7 +176,7 @@ module Spree
end
def render_address(parts)
parts.select(&:present?).join(', ')
parts.compact_blank.join(', ')
end
end
end

View File

@@ -33,14 +33,10 @@ module Spree
preference :allow_backorder_shipping, :boolean, default: false
preference :allow_checkout_on_gateway_error, :boolean, default: false
preference :allow_guest_checkout, :boolean, default: true
# Replace with the name of a zone if you would like to limit the countries
preference :checkout_zone, :string, default: nil
preference :currency, :string, default: "USD"
preference :currency_decimal_mark, :string, default: "."
preference :currency_symbol_position, :string, default: "before"
preference :currency_thousands_separator, :string, default: ","
preference :display_currency, :boolean, default: false
preference :default_country_id, :integer
preference :default_meta_description, :string, default: 'OFN demo site'
preference :default_meta_keywords, :string, default: 'ofn, demo'
preference :default_seo_title, :string, default: ''

View File

@@ -34,7 +34,7 @@ module Spree
image_variant_url_for(variant(size))
rescue StandardError => e
Bugsnag.notify "Product ##{viewable_id} Image ##{id} error: #{e.message}"
Alert.raise "Product ##{viewable_id} Image ##{id} error: #{e.message}"
Rails.logger.error(e.message)
self.class.default_image_url(size)

View File

@@ -35,18 +35,6 @@ module Spree
end
end
# This was refactored from a simpler query because the previous implementation
# lead to issues once users tried to modify the objects returned. That's due
# to ActiveRecord `joins(shipment: :stock_location)` only return readonly
# objects
#
# Returns an array of backordered inventory units as per a given stock item
def self.backordered_for_stock_item(stock_item)
backordered_per_variant(stock_item).select do |unit|
unit.shipment.stock_location == stock_item.stock_location
end
end
def self.finalize_units!(inventory_units)
inventory_units.map do |iu|
iu.update_columns(
@@ -57,8 +45,7 @@ module Spree
end
def find_stock_item
Spree::StockItem.find_by(stock_location_id: shipment.stock_location_id,
variant_id:)
Spree::StockItem.find_by(variant_id:)
end
private

View File

@@ -55,7 +55,7 @@ module Spree
# -- Scopes
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
# Find line items that are from orders distributed by the user or supplied by the user

View File

@@ -106,7 +106,6 @@ module Spree
before_validation :clone_billing_address, if: :use_billing?
before_validation :ensure_customer
before_save :update_shipping_fees!, if: :complete?
before_save :update_payment_fees!, if: :complete?
before_create :link_by_email
@@ -125,7 +124,7 @@ module Spree
}
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
# Find orders that are distributed by the user or have products supplied by the user
@@ -140,7 +139,7 @@ module Spree
}
scope :distributed_by_user, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
where(spree_orders: { distributor_id: user.enterprises.select(&:id) })
@@ -392,8 +391,6 @@ module Spree
deliver_order_confirmation_email
BackorderJob.check_stock(self)
state_changes.create(
previous_state: 'cart',
next_state: 'complete',
@@ -535,7 +532,7 @@ module Spree
# because an outdated shipping fee is not as bad as a lost payment.
# And the shipping fee is already up-to-date when this error occurs.
# https://github.com/openfoodfoundation/openfoodnetwork/issues/3924
Bugsnag.notify(e) do |report|
Alert.raise(e) do |report|
report.add_metadata(:order, attributes)
report.add_metadata(:shipment, shipment.attributes)
report.add_metadata(:shipment_in_db, Spree::Shipment.find_by(id: shipment.id).attributes)
@@ -674,10 +671,6 @@ module Spree
break if payment_total >= total
yield payment
if payment.completed?
self.payment_total += payment.amount
end
end
end

View File

@@ -142,8 +142,6 @@ module Spree
OrderMailer.cancel_email(id).deliver_later if send_cancellation_email
update(payment_state: updater.update_payment_state)
AmendBackorderJob.perform_later(self)
end
def after_resume

View File

@@ -38,6 +38,7 @@ module Spree
line_item.price = variant.price
order.line_items << line_item
end
update_shipment
order.reload
line_item

View File

@@ -12,8 +12,8 @@ module Spree
# have inventory assigned via +order.create_proposed_shipment+) or when
# shipment is explicitly passed
#
# In case shipment is passed the stock location should only unstock or
# restock items if the order is completed. That is so because stock items
# In case shipment is passed stock should only be adjusted
# if the order is completed. That is so because stock items
# are always unstocked when the order is completed through +shipment.finalize+
def verify(line_item, shipment = nil)
if order.completed? || shipment.present?
@@ -60,27 +60,24 @@ module Spree
# Returns either one of the shipment:
#
# first unshipped that already includes this variant
# first unshipped that's leaving from a stock_location that stocks this variant
def determine_target_shipment(variant)
target_shipment = order.shipments.detect do |shipment|
(shipment.ready? || shipment.pending?) && shipment.contains?(variant)
end
target_shipment || order.shipments.detect do |shipment|
(shipment.ready? || shipment.pending?) &&
variant.stock_location_ids.include?(shipment.stock_location_id)
shipment.ready? || shipment.pending?
end
end
def add_to_shipment(shipment, variant, quantity)
on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
on_hand, back_order = variant.fill_status(quantity)
on_hand.times { shipment.set_up_inventory('on_hand', variant, order) }
back_order.times { shipment.set_up_inventory('backordered', variant, order) }
# adding to this shipment, and removing from stock_location
if order.completed?
shipment.stock_location.unstock(variant, quantity, shipment)
variant.move(-quantity, shipment)
end
quantity
@@ -103,9 +100,8 @@ module Spree
end
shipment.destroy if shipment.inventory_units.reload.count == 0
# removing this from shipment, and adding to stock_location
if order.completed? && restock_item
shipment.stock_location.restock variant, removed_quantity, shipment
variant.move(removed_quantity, shipment)
end
removed_quantity

View File

@@ -168,7 +168,7 @@ module Spree
scope :by_name, -> { order('spree_products.name') }
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
in_supplier(user.enterprises)

View File

@@ -1,8 +0,0 @@
# frozen_string_literal: true
module Spree
class Role < ApplicationRecord
has_and_belongs_to_many :users, join_table: 'spree_roles_users',
class_name: "Spree::User"
end
end

View File

@@ -5,10 +5,10 @@ require 'ostruct'
module Spree
class Shipment < ApplicationRecord
self.belongs_to_required_by_default = false
self.ignored_columns += [:stock_location_id]
belongs_to :order, class_name: 'Spree::Order'
belongs_to :address, class_name: 'Spree::Address'
belongs_to :stock_location, class_name: 'Spree::StockLocation'
has_many :shipping_rates, dependent: :delete_all
has_many :shipping_methods, through: :shipping_rates
@@ -257,7 +257,7 @@ module Spree
end
def to_package
package = OrderManagement::Stock::Package.new(stock_location, order)
package = OrderManagement::Stock::Package.new(order)
grouped_inventory_units = inventory_units.includes(:variant).group_by do |iu|
[iu.variant, iu.state_name]
end
@@ -313,11 +313,11 @@ module Spree
end
def manifest_unstock(item)
stock_location.unstock item.variant, item.quantity, self
item.variant.move(-1 * item.quantity, self)
end
def manifest_restock(item)
stock_location.restock item.variant, item.quantity, self
item.variant.move(item.quantity, self)
end
def generate_shipment_number

View File

@@ -37,7 +37,7 @@ module Spree
after_save :touch_distributors
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
if user.admin?
where(nil)
else
joins(:distributors).

View File

@@ -2,20 +2,21 @@
module Spree
class StockItem < ApplicationRecord
self.ignored_columns += [:stock_location_id]
acts_as_paranoid
belongs_to :stock_location, class_name: 'Spree::StockLocation', inverse_of: :stock_items
belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
has_many :stock_movements, dependent: :destroy
validates :variant_id, uniqueness: { scope: [:stock_location_id, :deleted_at] }
validates :variant_id, uniqueness: { scope: [:deleted_at] }
validates :count_on_hand, numericality: { greater_than_or_equal_to: 0, unless: :backorderable? }
delegate :weight, to: :variant
delegate :name, to: :variant, prefix: true
def backordered_inventory_units
Spree::InventoryUnit.backordered_for_stock_item(self)
Spree::InventoryUnit.backordered_per_variant(self)
end
def adjust_count_on_hand(value)

View File

@@ -1,57 +0,0 @@
# frozen_string_literal: true
module Spree
class StockLocation < ApplicationRecord
self.belongs_to_required_by_default = false
self.ignored_columns += [:backorderable_default, :active]
has_many :stock_items, dependent: :delete_all, inverse_of: :stock_location
has_many :stock_movements, through: :stock_items
belongs_to :state, class_name: 'Spree::State'
belongs_to :country, class_name: 'Spree::Country'
validates :name, presence: true
after_create :create_stock_items
# Wrapper for creating a new stock item respecting the backorderable config
def stock_item(variant)
stock_items.where(variant_id: variant).order(:id).first
end
def stock_item_or_create(variant)
stock_item(variant) || stock_items.create(variant:)
end
def count_on_hand(variant)
stock_item(variant).try(:count_on_hand)
end
def backorderable?(variant)
stock_item(variant).try(:backorderable?)
end
def restock(variant, quantity, originator = nil)
move(variant, quantity, originator)
end
def unstock(variant, quantity, originator = nil)
move(variant, -quantity, originator)
end
def move(variant, quantity, originator = nil)
variant.move(quantity, originator)
end
def fill_status(variant, quantity)
variant.fill_status(quantity)
end
private
def create_stock_items
Variant.find_each { |variant| stock_items.create!(variant:) }
end
end
end

View File

@@ -105,16 +105,7 @@ module Spree
if default_zone_or_zone_match?(item.order)
calculator.compute(item)
else
# Tax refund should not be possible with the way our production server are configured
Bugsnag.notify(
"Notice: Tax refund should not be possible, please check the default zone and " \
"the tax rate zone configuration"
) do |payload|
payload.add_metadata :order_tax_zone, item.order.tax_zone
payload.add_metadata :tax_rate_zone, zone
payload.add_metadata :default_zone, Zone.default_tax
end
# In this case, it's a refund.
# In this case, it's a refund (for instance offering a manual discount via an adjustment)
calculator.compute(item) * - 1
end
else

View File

@@ -18,17 +18,11 @@ module Spree
belongs_to :ship_address, class_name: 'Spree::Address'
belongs_to :bill_address, class_name: 'Spree::Address'
has_and_belongs_to_many :spree_roles,
join_table: 'spree_roles_users',
class_name: "Spree::Role"
before_validation :set_login
after_create :associate_customers, :associate_orders
before_destroy :check_completed_orders
roles_table_name = Role.table_name
scope :admin, lambda { includes(:spree_roles).where("#{roles_table_name}.name" => "admin") }
scope :admin, -> { where(admin: true) }
has_many :enterprise_roles, dependent: :destroy
has_many :enterprises, through: :enterprise_roles
@@ -60,16 +54,6 @@ module Spree
User.admin.count > 0
end
# Whether a user has a role or not.
def has_spree_role?(role_in_question)
spree_roles.where(name: role_in_question.to_s).any?
end
# Checks whether the specified user is a superadmin, with full control of the instance
def admin?
has_spree_role?('admin')
end
# Send devise-based user emails asyncronously via ActiveJob
# See: https://github.com/heartcombo/devise/tree/v3.5.10#activejob-integration
def send_devise_notification(notification, *args)

View File

@@ -39,7 +39,6 @@ module Spree
has_many :line_items, inverse_of: :variant, dependent: nil
has_many :stock_items, dependent: :destroy, inverse_of: :variant
has_many :stock_locations, through: :stock_items
has_many :images, -> { order(:position) }, as: :viewable,
dependent: :destroy,
class_name: "Spree::Image"
@@ -268,9 +267,7 @@ module Spree
def create_stock_items
return unless stock_items.empty?
StockLocation.find_each do |stock_location|
stock_items.create!(stock_location:)
end
stock_items.create!
end
def update_weight_from_unit_value
@@ -293,7 +290,7 @@ module Spree
end
def ensure_unit_value
Bugsnag.notify("Trying to set unit_value to NaN") if unit_value&.nan?
Alert.raise("Trying to set unit_value to NaN") if unit_value&.nan?
return unless (variant_unit == "items" && unit_value.nil?) || unit_value&.nan?
self.unit_value = 1.0

View File

@@ -7,6 +7,8 @@ module Spree
has_and_belongs_to_many :shipping_methods, join_table: 'spree_shipping_methods_zones'
validates :name, presence: true, uniqueness: true
validates :zone_members, presence: true
after_save :remove_defunct_members
after_save :remove_previous_default

View File

@@ -15,7 +15,7 @@ class StripeAccount < ApplicationRecord
destroy && Stripe::OAuth.deauthorize(stripe_user_id:)
rescue Stripe::OAuth::OAuthError => e
Bugsnag.notify(
Alert.raise(
e,
stripe_account: stripe_user_id,
enterprise_id:

View File

@@ -48,8 +48,8 @@ class VariantOverride < ApplicationRecord
def move_stock!(quantity)
unless stock_overridden?
Bugsnag.notify RuntimeError.new "Attempting to move stock of a VariantOverride " \
"without a count_on_hand specified."
Alert.raise "Attempting to move stock of a VariantOverride " \
"without a count_on_hand specified."
return
end
@@ -73,8 +73,8 @@ class VariantOverride < ApplicationRecord
self.attributes = { on_demand: false, count_on_hand: default_stock }
save
else
Bugsnag.notify RuntimeError.new "Attempting to reset stock level for a variant " \
"with no default stock level."
Alert.raise "Attempting to reset stock level for a variant " \
"with no default stock level."
end
end
self

View File

@@ -14,7 +14,7 @@ class Voucher < ApplicationRecord
class_name: 'Spree::Adjustment',
dependent: nil
validates :code, presence: true, uniqueness: { scope: :enterprise_id }
validates :code, presence: true
TYPES = ["Vouchers::FlatRate", "Vouchers::PercentageRate"].freeze

View File

@@ -2,24 +2,8 @@
module Vouchers
class FlatRate < Voucher
validates :amount,
presence: true,
numericality: { greater_than: 0 }
include FlatRatable
def display_value
Spree::Money.new(amount)
end
# We limit adjustment to the maximum amount needed to cover the order, ie if the voucher
# covers more than the order.total we only need to create an adjustment covering the order.total
def compute_amount(order)
-amount.clamp(0, order.pre_discount_total)
end
def rate(order)
amount = compute_amount(order)
amount / order.pre_discount_total
end
validates_with ScopedUniquenessValidator
end
end

View File

@@ -5,6 +5,7 @@ module Vouchers
validates :amount,
presence: true,
numericality: { greater_than: 0, less_than_or_equal_to: 100 }
validates_with ScopedUniquenessValidator
def display_value
ActionController::Base.helpers.number_to_percentage(amount, precision: 2)

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: false
module Vouchers
class Vine < Voucher
include FlatRatable
# a VINE voucher :
# - can potentially be associated with mutiple enterprise
# - code ( "short code" in VINE ) can be recycled, but they shouldn't be linked to the same
# voucher_id
validates :code, uniqueness: { scope: [:enterprise_id, :external_voucher_id] }
end
end

View File

@@ -46,7 +46,7 @@ class ProductScopeQuery
end
def product_scope
if @user.has_spree_role?("admin") || @user.enterprises.present?
if @user.admin? || @user.enterprises.present?
scope = Spree::Product
if @params[:show_deleted]
scope = scope.with_deleted
@@ -61,7 +61,7 @@ class ProductScopeQuery
def product_query_includes
[
image: { attachment_attachment: :blob },
variants: [:default_price, :stock_locations, :stock_items, :variant_overrides]
variants: [:default_price, :stock_items, :variant_overrides]
]
end

View File

@@ -15,7 +15,7 @@ module Api
:terms_and_conditions_file_name, :terms_and_conditions_updated_at,
:preferred_invoice_order_by_supplier, :preferred_product_low_stock_display,
:visible, :hide_ofn_navigation, :white_label_logo,
:white_label_logo_link
:white_label_logo_link, :external_billing_id
has_one :owner, serializer: Api::Admin::UserSerializer
has_many :users, serializer: Api::Admin::UserSerializer

View File

@@ -11,7 +11,6 @@ module Api
object.variants,
each_serializer: Api::Admin::VariantSerializer,
image: thumb_url,
stock_location: Spree::StockLocation.first
)
end

View File

@@ -6,6 +6,12 @@ module Api
attributes :id, :hub_id, :variant_id, :sku, :price, :count_on_hand, :on_demand,
:default_stock, :resettable, :tag_list, :tags, :import_date
def count_on_hand
return if object.on_demand
object.count_on_hand
end
def tag_list
object.tag_list.join(",")
end

View File

@@ -6,7 +6,7 @@ module Api
attributes :id, :name, :producer_name, :image, :sku, :import_date, :tax_category_id,
:options_text, :unit_value, :unit_description, :unit_to_display,
:display_as, :display_name, :name_to_display, :variant_overrides_count,
:price, :on_demand, :on_hand, :in_stock, :stock_location_id, :stock_location_name,
:price, :on_demand, :on_hand, :in_stock,
:variant_unit, :variant_unit_scale, :variant_unit_name, :variant_unit_with_scale
has_one :primary_taxon, key: :category_id, embed: :id
@@ -44,18 +44,6 @@ module Api
object.in_stock?
end
def stock_location_id
return if object.stock_items.empty?
options[:stock_location]&.id || object.stock_items.first.stock_location.id
end
def stock_location_name
return if object.stock_items.empty?
options[:stock_location]&.name || object.stock_items.first.stock_location.name
end
def variant_overrides_count
object.variant_overrides.count
end

Some files were not shown because too many files have changed in this diff Show More