Compare commits

...

424 Commits

Author SHA1 Message Date
dependabot[bot]
820ca10556 Bump bigdecimal from 3.3.1 to 4.1.0
Bumps [bigdecimal](https://github.com/ruby/bigdecimal) from 3.3.1 to 4.1.0.
- [Release notes](https://github.com/ruby/bigdecimal/releases)
- [Changelog](https://github.com/ruby/bigdecimal/blob/master/CHANGES.md)
- [Commits](https://github.com/ruby/bigdecimal/compare/v3.3.1...v4.1.0)

---
updated-dependencies:
- dependency-name: bigdecimal
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-07 09:57:07 +00:00
Maikel Linke
e10efe425a Update checksums 2026-04-07 13:25:49 +10:00
David Cook
12c36bf83e Merge pull request #14127 from mkllnk/bundler-checksums
Add checksums to Gemfile.lock to guard against gem replacement
2026-04-07 12:03:13 +10:00
Gaetan Craig-Riou
0f10ffbb66 Merge pull request #14131 from openfoodfoundation/dependabot/npm_and_yarn/lodash-4.18.1
Bump lodash from 4.17.23 to 4.18.1
2026-04-07 11:58:48 +10:00
Gaetan Craig-Riou
366c457474 Merge pull request #14133 from openfoodfoundation/dependabot/npm_and_yarn/mini-css-extract-plugin-2.10.2
Bump mini-css-extract-plugin from 2.10.1 to 2.10.2
2026-04-07 11:00:10 +10:00
Gaetan Craig-Riou
af8ea31c76 Merge pull request #14130 from openfoodfoundation/dependabot/bundler/flipper-1.4.1
Bump flipper from 1.4.0 to 1.4.1
2026-04-07 10:55:34 +10:00
Ahmed Ejaz
d1608a0288 Update all locales with the latest Transifex translations 2026-04-04 21:46:56 +05:00
Ahmed Ejaz
e4e7ef395b Merge pull request #14113 from gbathree/13817-fix-guest-order-cancellation
Fix guest order cancellation redirecting to home page
2026-04-04 21:42:44 +05:00
Ahmed Ejaz
ec24740c3b Merge pull request #14085 from dacook/admin-product-actions-fixes
[Admin Products] Action menu fixes
2026-04-04 21:42:12 +05:00
dependabot[bot]
4e0f5225b4 Bump mini-css-extract-plugin from 2.10.1 to 2.10.2
Bumps [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin) from 2.10.1 to 2.10.2.
- [Release notes](https://github.com/webpack/mini-css-extract-plugin/releases)
- [Changelog](https://github.com/webpack/mini-css-extract-plugin/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/mini-css-extract-plugin/compare/v2.10.1...v2.10.2)

---
updated-dependencies:
- dependency-name: mini-css-extract-plugin
  dependency-version: 2.10.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-03 09:32:58 +00:00
Gaetan Craig-Riou
783ac990bc Merge pull request #14132 from openfoodfoundation/dependabot/bundler/rack-2.2.23
Bump rack from 2.2.22 to 2.2.23
2026-04-03 09:33:02 +11:00
dependabot[bot]
a4cc2f17dc Bump rack from 2.2.22 to 2.2.23
Bumps [rack](https://github.com/rack/rack) from 2.2.22 to 2.2.23.
- [Release notes](https://github.com/rack/rack/releases)
- [Changelog](https://github.com/rack/rack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rack/rack/compare/v2.2.22...v2.2.23)

---
updated-dependencies:
- dependency-name: rack
  dependency-version: 2.2.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-02 20:02:57 +00:00
Rachel Arnould
c19241ddd9 Merge pull request #14118 from dacook/linked-variants-14088
Prevent creating a linked variant from a linked variant
2026-04-02 17:44:34 +02:00
dependabot[bot]
92423106ef Bump lodash from 4.17.23 to 4.18.1
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-02 03:25:10 +00:00
dependabot[bot]
6b876a0051 Bump flipper from 1.4.0 to 1.4.1
Bumps [flipper](https://github.com/flippercloud/flipper) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/flippercloud/flipper/releases)
- [Changelog](https://github.com/flippercloud/flipper/blob/main/Changelog.md)
- [Commits](https://github.com/flippercloud/flipper/compare/v1.4.0...v1.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-02 01:00:16 +00:00
Maikel
eee9f61c38 Merge pull request #14129 from openfoodfoundation/dependabot/bundler/aws-sdk-s3-1.217.0
Bump aws-sdk-s3 from 1.215.0 to 1.217.0
2026-04-02 11:50:42 +11:00
Maikel
7f711d746f Merge pull request #14126 from dacook/dependabot-cooldown
Dependabot cooldown
2026-04-02 11:49:55 +11:00
dependabot[bot]
732234f1c0 Bump aws-sdk-s3 from 1.215.0 to 1.217.0
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.215.0 to 1.217.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-version: 1.217.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 11:11:34 +00:00
Maikel
450fe4ada1 Merge pull request #14119 from mkllnk/replace-whenever
Replace whenever with sidekiq scheduler
2026-04-01 15:37:33 +11:00
Maikel Linke
bcecbf9a0f Require rake dependency to run it within jobs 2026-04-01 15:18:49 +11:00
David Cook
15abea51ab Avoid unnecessary extra page visit
The second spec example below has to load the page after creating a record, so it's not helpful to load it here.
2026-04-01 14:48:18 +11:00
David Cook
cacb62f58c Style fix 2026-04-01 14:11:19 +11:00
David Cook
6048fcb053 Define function as member arrow function
This way it behaves as an instance method, and we don't have to pass in the object.
2026-04-01 14:11:19 +11:00
David Cook
6013b6be70 Remove transform at end of animation
During transform, any overflow on the element is clipped/hidden. This caused all dropdown menus to be clipped and unusable. Now, once the animation is complete, the overflow is visible, and menus are usable.

Mistral Vibe AI was used to find this solution. I tried to find a CSS solution last week but failed, then started to consider using JS to remove the class, but decided against it once I realised that the product clone JS was already doing that, and it didn't seem to solve the clipping issue.
So I asked Mistral Vibe and it suggested adding 'forwards' (before it had spent energy on evaluating the existing style rules). As you can see 'forwards' was already there, but removing it helped. So Mistral was wrong, but at least pointed me in the right direction, yay!
2026-04-01 14:11:19 +11:00
David Cook
22a1528ac7 Show unit in tooltip
Variants may have the same name, or no display_name at all. This helper method provides a more comprehensive way of describing the variant.
2026-04-01 14:11:19 +11:00
David Cook
ca3c0c98bf Don't group reviewdog output
Grouping is a nice feature, but it wasn't helpful here. If there's an error in rubocop for example, the rubocop section will be collapsed, and because we didn't close the group, the haml group was always open. So it wasn't clear where the error was.

Better to just show all the output, which isn't very long, so you can see where the problem is straight away.

Even better would be to add support for GitHub Actions annotations. I thought we used to have that turned on, not sure why it's not working now.
2026-04-01 14:11:19 +11:00
David Cook
19006d6c17 Close action menu when making a selection
But don't hide it immediately, because the user can't see if they made a selection, or accidentally closed it. Instead, fade slowly so that you can see the selected option momentarily (like system menus). This gives enough feedback while we wait for the selected action to perform.

I did attempt a blink on the item background colour, like my favourite OS does which is really helpful. But couldn't get the CSS to work.
2026-04-01 14:11:19 +11:00
David Cook
da69e2c383 Widen action menus slightly when needed 2026-04-01 14:11:19 +11:00
Maikel Linke
2fbfe590d7 Add checksums to Gemfile.lock to guard against gem replacement
Result of:

```
bundle lock --add-checksums
```

Recommendation from:

- https://www.fastruby.io/blog/hidden-dangers-in-your-gemfile.html
2026-04-01 13:51:06 +11:00
Maikel
2e6e4b665f Merge pull request #14122 from openfoodfoundation/dependabot/bundler/view_component-4.5.0
Bump view_component from 4.1.1 to 4.5.0
2026-04-01 10:31:41 +11:00
David Cook
e255bcc082 Formatting
Compacted and adjusted comments to make it a bit easier to read.
2026-04-01 10:31:34 +11:00
David Cook
51b4dc64cc Add cooldown for turbo_power
Ensure it's treated the same as other gems and packages.
2026-04-01 10:17:40 +11:00
Maikel
77b6bc15e7 Merge pull request #14121 from openfoodfoundation/dependabot/bundler/devise-i18n-1.16.0
Bump devise-i18n from 1.15.0 to 1.16.0
2026-04-01 10:11:37 +11:00
Ahmed Ejaz
9b145da898 Merge pull request #14040 from chahmedejaz/task/13797-improve-performance-of-products-page
Fix Admin Bulk Products screen performance issue
2026-04-01 00:37:40 +05:00
dependabot[bot]
00d600911d Bump view_component from 4.1.1 to 4.5.0
Bumps [view_component](https://github.com/viewcomponent/view_component) from 4.1.1 to 4.5.0.
- [Release notes](https://github.com/viewcomponent/view_component/releases)
- [Changelog](https://github.com/ViewComponent/view_component/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/viewcomponent/view_component/compare/v4.1.1...v4.5.0)

---
updated-dependencies:
- dependency-name: view_component
  dependency-version: 4.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-31 09:55:00 +00:00
dependabot[bot]
10d6dd73f2 Bump devise-i18n from 1.15.0 to 1.16.0
Bumps [devise-i18n](https://github.com/devise-i18n/devise-i18n) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/devise-i18n/devise-i18n/releases)
- [Changelog](https://github.com/devise-i18n/devise-i18n/blob/main/CHANGELOG.md)
- [Commits](https://github.com/devise-i18n/devise-i18n/compare/v1.15.0...v1.16.0)

---
updated-dependencies:
- dependency-name: devise-i18n
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-31 09:41:05 +00:00
Maikel Linke
c74624cd57 Remove unused gem whenever 2026-03-31 14:58:57 +11:00
Maikel Linke
60edcada2c Remove whenever config 2026-03-31 14:56:41 +11:00
Maikel Linke
b61f6ab444 Schedule all jobs with Sidekiq 2026-03-31 14:53:26 +11:00
David Cook
ccc38367f3 Prevent creating a linked variant from a linked variant
It's just too confusing.
2026-03-31 14:34:17 +11:00
Maikel Linke
80a12db191 Move database clean from cron to Sidekiq scheduler
After moving the remaining tasks from schedule.rb to sidekiq.yml, we can
remove whenever and won't rely on cron any more. That will simplify the
setup and migration to a new server.
2026-03-31 12:34:47 +11:00
Maikel
5beed6f028 Merge pull request #14117 from openfoodfoundation/dependabot/bundler/whenever-1.1.2
Bump whenever from 1.1.0 to 1.1.2
2026-03-31 10:27:56 +11:00
Ahmed Ejaz
0a65322594 rename ajax_search_spec 2026-03-31 04:05:06 +05:00
Ahmed Ejaz
b7f154d289 revert back the bin/setup 2026-03-31 03:49:35 +05:00
Maikel
edb8a03436 Merge pull request #14116 from openfoodfoundation/dependabot/bundler/active_storage_validations-3.0.4
Bump active_storage_validations from 3.0.3 to 3.0.4
2026-03-31 09:35:28 +11:00
Ahmed Ejaz
3ee338fa8d Add ajax search controller 2026-03-31 01:54:02 +05:00
dependabot[bot]
e3da27ca12 Bump whenever from 1.1.0 to 1.1.2
Bumps [whenever](https://github.com/javan/whenever) from 1.1.0 to 1.1.2.
- [Release notes](https://github.com/javan/whenever/releases)
- [Changelog](https://github.com/javan/whenever/blob/main/CHANGELOG.md)
- [Commits](https://github.com/javan/whenever/compare/v1.1.0...v1.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 10:17:45 +00:00
dependabot[bot]
4c8e6d8260 Bump active_storage_validations from 3.0.3 to 3.0.4
Bumps [active_storage_validations](https://github.com/igorkasyanchuk/active_storage_validations) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/igorkasyanchuk/active_storage_validations/releases)
- [Changelog](https://github.com/igorkasyanchuk/active_storage_validations/blob/master/CHANGES.md)
- [Commits](https://github.com/igorkasyanchuk/active_storage_validations/compare/3.0.03...3.0.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 10:16:06 +00:00
Maikel
de28083007 Merge pull request #14112 from openfoodfoundation/dependabot/bundler/bootsnap-1.23.0
Bump bootsnap from 1.22.0 to 1.23.0
2026-03-30 11:59:05 +11:00
Greg Austic
cc608adddc Address review feedback: use referer in specs, remove demo screenshots
- Set HTTP_REFERER in cancel action specs so they test the redirect to
  the actual order page (not the cancel path, which was the implicit
  referer in controller specs)
- Keep response.body match pattern (consistent with checkout_controller_spec
  for CableReady redirects — redirect_to matcher does not work here since
  the cancel action uses cable_car.redirect_to, not a Rails redirect)
- Remove doc/demo screenshots; images to be added to PR description instead

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 19:03:47 -04:00
Gaetan Craig-Riou
01bfd72387 Merge pull request #14115 from openfoodfoundation/dependabot/npm_and_yarn/trix-2.1.18
Bump trix from 2.1.17 to 2.1.18
2026-03-30 09:57:33 +11:00
Gaetan Craig-Riou
69d9c52a53 Merge pull request #14111 from openfoodfoundation/dependabot/bundler/pg-1.6.3
Bump pg from 1.6.2 to 1.6.3
2026-03-30 09:44:59 +11:00
dependabot[bot]
5371361a74 Bump trix from 2.1.17 to 2.1.18
Bumps [trix](https://github.com/basecamp/trix) from 2.1.17 to 2.1.18.
- [Release notes](https://github.com/basecamp/trix/releases)
- [Commits](https://github.com/basecamp/trix/compare/v2.1.17...v2.1.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-29 18:49:52 +00:00
Greg Austic
a6f5f2c10d Add demo screenshots for guest order cancellation fix
Before/after screenshots showing the fix works end-to-end:
- step1: guest order confirmed, Cancel Order button visible
- step2: same page after cancellation, order shows Cancelled

These can be removed after the PR is reviewed and merged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 09:44:12 -04:00
Greg Austic
c72976b1e2 Fix guest order cancellation redirecting to home page
When a guest places an order and tries to cancel it from the order
confirmation page, the cancellation silently failed and redirected
to the home page. The guest was left unsure whether the order was
cancelled, and the hub received no cancellation notification.

Root cause: two missing pieces for guest (token-based) authorization:

1. The `:cancel` ability in Ability#add_shopping_abilities only checked
   `order.user == user`, ignoring the guest token. The `:read` and
   `:update` abilities already support `order.token && token == order.token`
   as a fallback — `:cancel` now does the same.

2. The `cancel` action called `authorize! :cancel, @order` without
   passing `session[:access_token]`, so even with the corrected ability
   the token was never evaluated.

Fixes #13817

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 09:05:47 -04:00
dependabot[bot]
b7c628dc2a Bump bootsnap from 1.22.0 to 1.23.0
Bumps [bootsnap](https://github.com/rails/bootsnap) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/rails/bootsnap/releases)
- [Changelog](https://github.com/rails/bootsnap/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rails/bootsnap/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: bootsnap
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-27 09:34:18 +00:00
dependabot[bot]
5bef61aa2e Bump pg from 1.6.2 to 1.6.3
Bumps [pg](https://github.com/ged/ruby-pg) from 1.6.2 to 1.6.3.
- [Changelog](https://github.com/ged/ruby-pg/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ged/ruby-pg/compare/v1.6.2...v1.6.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-27 09:33:08 +00:00
Maikel
79c346acb1 Merge pull request #14109 from openfoodfoundation/dependabot/npm_and_yarn/node-forge-1.4.0
Bump node-forge from 1.3.3 to 1.4.0
2026-03-27 13:56:43 +11:00
Gaetan Craig-Riou
e87159426e Update all locales with the latest Transifex translations 2026-03-27 13:49:26 +11:00
dependabot[bot]
ca10ae2f5c Bump node-forge from 1.3.3 to 1.4.0
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.3 to 1.4.0.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.3...v1.4.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-27 00:12:35 +00:00
Maikel
423e8a2cff Merge pull request #14104 from openfoodfoundation/dependabot/npm_and_yarn/picomatch-2.3.2
Bump picomatch from 2.3.1 to 2.3.2
2026-03-27 10:29:10 +11:00
dependabot[bot]
191df4ecf7 Bump picomatch from 2.3.1 to 2.3.2
Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-26 23:17:51 +00:00
Maikel
c274c19e96 Merge pull request #14106 from mkllnk/taler-fix
Fix specs after taler gem update
2026-03-27 10:15:59 +11:00
Maikel
0e7e09bcfe Merge pull request #14103 from openfoodfoundation/dependabot/bundler/webmock-3.26.2
Bump webmock from 3.26.1 to 3.26.2
2026-03-27 10:06:00 +11:00
Maikel
96c2dff744 Merge pull request #14102 from openfoodfoundation/dependabot/bundler/undercover-0.8.4
Bump undercover from 0.8.3 to 0.8.4
2026-03-27 10:05:23 +11:00
Gaetan Craig-Riou
01cff7a618 Merge pull request #14060 from mvanhorn/add-order-id-to-webhook
Add order number to Payment webhook payload
2026-03-27 09:29:10 +11:00
Maikel Linke
ecca47f96d Fix specs after taler gem update 2026-03-26 13:28:16 +11:00
Ahmed Ejaz
4a66984ec4 Merge pull request #14084 from chahmedejaz/bugfix/14081-delete-user
Fix authorization for removing enterprise managers for non-admins
2026-03-26 05:10:36 +05:00
Ahmed Ejaz
ac716150eb Merge pull request #14091 from chahmedejaz/bugfix/14015-products-search-timeout-on-subscriptions
Fix Products search timing out when creating a new subscription
2026-03-25 20:49:45 +05:00
Ahmed Ejaz
2fe28d1707 Merge pull request #14101 from mkllnk/taler-currency
Use real currency for Taler payments unless using demo backend
2026-03-25 20:44:44 +05:00
Rachel Arnould
dcf3ab74b8 Merge pull request #13962 from mkllnk/taler-credit
Credit customers via Taler
2026-03-25 15:24:06 +01:00
dependabot[bot]
ef56df09a1 Bump webmock from 3.26.1 to 3.26.2
Bumps [webmock](https://github.com/bblimke/webmock) from 3.26.1 to 3.26.2.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.26.1...v3.26.2)

---
updated-dependencies:
- dependency-name: webmock
  dependency-version: 3.26.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-25 09:38:33 +00:00
dependabot[bot]
3d116d0027 Bump undercover from 0.8.3 to 0.8.4
Bumps [undercover](https://github.com/grodowski/undercover) from 0.8.3 to 0.8.4.
- [Release notes](https://github.com/grodowski/undercover/releases)
- [Changelog](https://github.com/grodowski/undercover/blob/master/CHANGELOG.md)
- [Commits](https://github.com/grodowski/undercover/compare/v0.8.3...v0.8.4)

---
updated-dependencies:
- dependency-name: undercover
  dependency-version: 0.8.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-25 09:37:16 +00:00
Maikel Linke
fe0c6a4deb Use real currency for Taler payments unless using demo backend. 2026-03-25 15:09:43 +11:00
Gaetan Craig-Riou
1e6de5e251 Merge pull request #14096 from openfoodfoundation/dependabot/npm_and_yarn/babel/preset-env-7.29.2
Bump @babel/preset-env from 7.29.0 to 7.29.2
2026-03-25 11:08:44 +11:00
Gaetan Craig-Riou
af2299c666 Merge pull request #14098 from openfoodfoundation/dependabot/bundler/bugsnag-6.29.0
Bump bugsnag from 6.28.0 to 6.29.0
2026-03-25 11:08:25 +11:00
Gaetan Craig-Riou
b37111f007 Merge pull request #14097 from openfoodfoundation/dependabot/bundler/puffing-billy-4.0.4
Bump puffing-billy from 4.0.2 to 4.0.4
2026-03-25 10:52:26 +11:00
Gaetan Craig-Riou
043a8a84f3 Merge pull request #14095 from openfoodfoundation/dependabot/npm_and_yarn/babel/runtime-7.29.2
Bump @babel/runtime from 7.28.6 to 7.29.2
2026-03-25 10:48:50 +11:00
Ahmed Ejaz
8ba0ab6b5a Update specs according to new remote search function on products page 2026-03-25 02:01:36 +05:00
Ahmed Ejaz
044f6131da fix aria_label translations 2026-03-25 01:30:06 +05:00
Ahmed Ejaz
062fcd317c Add searchable dropdowns for producers, categories, and tax categories in products_v3 2026-03-25 01:30:06 +05:00
dependabot[bot]
a2fad2cab3 Bump bugsnag from 6.28.0 to 6.29.0
Bumps [bugsnag](https://github.com/bugsnag/bugsnag-ruby) from 6.28.0 to 6.29.0.
- [Release notes](https://github.com/bugsnag/bugsnag-ruby/releases)
- [Changelog](https://github.com/bugsnag/bugsnag-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bugsnag/bugsnag-ruby/compare/v6.28.0...v6.29.0)

---
updated-dependencies:
- dependency-name: bugsnag
  dependency-version: 6.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-24 09:34:24 +00:00
dependabot[bot]
5ab1ce751b Bump puffing-billy from 4.0.2 to 4.0.4
Bumps [puffing-billy](https://github.com/oesmith/puffing-billy) from 4.0.2 to 4.0.4.
- [Release notes](https://github.com/oesmith/puffing-billy/releases)
- [Changelog](https://github.com/oesmith/puffing-billy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/oesmith/puffing-billy/commits)

---
updated-dependencies:
- dependency-name: puffing-billy
  dependency-version: 4.0.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-24 09:32:08 +00:00
dependabot[bot]
1a2b5ffc3a Bump @babel/preset-env from 7.29.0 to 7.29.2
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.29.0 to 7.29.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.2/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-version: 7.29.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-24 09:31:58 +00:00
dependabot[bot]
080c4f7cb5 Bump @babel/runtime from 7.28.6 to 7.29.2
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.28.6 to 7.29.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.2/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-version: 7.29.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-24 09:31:42 +00:00
Maikel
9d389e22d3 Merge pull request #14087 from openfoodfoundation/dependabot/bundler/haml-7.2.0
Bump haml from 6.3.0 to 7.2.0
2026-03-24 11:34:28 +11:00
Ahmed Ejaz
fc123b38b4 Add comment for outgroing exchange variants 2026-03-24 03:46:17 +05:00
Gaetan Craig-Riou
6c4ae1d2c1 Fix spec 2026-03-24 09:40:28 +11:00
Gaetan Craig-Riou
eff1ed4a5e Upgrade haml-lint 2026-03-24 09:40:28 +11:00
dependabot[bot]
7ea2b126f2 Bump haml from 6.3.0 to 7.2.0
Bumps [haml](https://github.com/haml/haml) from 6.3.0 to 7.2.0.
- [Release notes](https://github.com/haml/haml/releases)
- [Changelog](https://github.com/haml/haml/blob/main/CHANGELOG.md)
- [Commits](https://github.com/haml/haml/compare/v6.3.0...v7.2.0)

---
updated-dependencies:
- dependency-name: haml
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-24 09:40:28 +11:00
Gaetan Craig-Riou
bfca6248ae Merge pull request #14086 from openfoodfoundation/dependabot/bundler/private_address_check-0.6.0
Bump private_address_check from 0.5.0 to 0.6.0
2026-03-24 08:45:55 +11:00
Ahmed Ejaz
1ff665a33a Refactor permitted producer IDs and outgoing exchange variant IDs queries for improved performance 2026-03-24 02:24:40 +05:00
dependabot[bot]
8250029eb7 Bump private_address_check from 0.5.0 to 0.6.0
Bumps [private_address_check](https://github.com/jtdowney/private_address_check) from 0.5.0 to 0.6.0.
- [Commits](https://github.com/jtdowney/private_address_check/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: private_address_check
  dependency-version: 0.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 10:02:55 +00:00
David Cook
5e92fa9a17 Merge pull request #14078 from rioug/fix-flacky-order-cylcle-spec
[Spec] Fix flaky order cycle spec
2026-03-23 12:24:05 +11:00
Maikel
d23ad9c8ad Merge pull request #14079 from openfoodfoundation/dependabot/bundler/i18n-tasks-1.1.2
Bump i18n-tasks from 1.0.15 to 1.1.2
2026-03-23 11:27:59 +11:00
David Cook
d80249da2d Merge pull request #14064 from openfoodfoundation/dependabot/bundler/taler-0.3.0
Bump taler from 0.2.0 to 0.3.0
2026-03-23 10:52:08 +11:00
Gaetan Craig-Riou
d6c69fdc2c Fix code typo
Co-authored-by: Maikel <maikel@email.org.au>
2026-03-23 10:48:27 +11:00
Ahmed Ejaz
715a8f421a 14081: fix permission issue for deleting manager 2026-03-21 03:38:38 +05:00
Rachel Arnould
06d6db5a07 Merge pull request #14075 from gbathree/13688-fix-button-font-consistency
Fix: unify font-family across all .button elements
2026-03-20 11:03:51 +01:00
Rachel Arnould
3f81883bc7 Merge pull request #14061 from mvanhorn/fix/enterprise-user-inline-error-style
Fix inline error style in Add Manager dialog
2026-03-20 11:03:32 +01:00
Rachel Arnould
27be0f6fd1 Merge pull request #13912 from dacook/sourced-variant1-13887
Create linked variants
2026-03-20 10:59:46 +01:00
dependabot[bot]
8880f83d09 Bump i18n-tasks from 1.0.15 to 1.1.2
Bumps [i18n-tasks](https://github.com/glebm/i18n-tasks) from 1.0.15 to 1.1.2.
- [Release notes](https://github.com/glebm/i18n-tasks/releases)
- [Changelog](https://github.com/glebm/i18n-tasks/blob/main/CHANGES.md)
- [Commits](https://github.com/glebm/i18n-tasks/compare/v1.0.15...v1.1.2)

---
updated-dependencies:
- dependency-name: i18n-tasks
  dependency-version: 1.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-20 09:33:07 +00:00
Maikel Linke
23a4ca5933 Add additional Taler token requests to specs 2026-03-20 15:52:41 +11:00
Gaetan Craig-Riou
4dc44c6156 Fix code syntax 2026-03-20 15:49:41 +11:00
Gaetan Craig-Riou
8defb2f4c8 Improve EnterpriseFee loading
Request is only send if there isn't another currently running, and also
ensure that filtered enterprise fees are loaded only when not other
request is running.
2026-03-20 14:38:49 +11:00
dependabot[bot]
067349f742 Bump taler from 0.2.0 to 0.3.0
Bumps [taler](https://github.com/openfoodfoundation/taler-ruby) from 0.2.0 to 0.3.0.
- [Changelog](https://github.com/openfoodfoundation/taler-ruby/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openfoodfoundation/taler-ruby/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: taler
  dependency-version: 0.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-20 01:24:38 +00:00
Maikel Linke
74fd019863 Update all locales with the latest Transifex translations 2026-03-20 12:23:59 +11:00
Maikel
1207bb5f8f Merge pull request #14023 from mkllnk/api-v0-redirect
Remove compatibility redirect for APIv0
2026-03-20 12:21:26 +11:00
Maikel
d25eea660e Merge pull request #14054 from mkllnk/devise
Bump devise from 4.9.4 to 5.0.3
2026-03-20 12:18:48 +11:00
Maikel
fdfb155682 Merge pull request #14077 from openfoodfoundation/dependabot/npm_and_yarn/flatted-3.4.2
Bump flatted from 3.3.3 to 3.4.2
2026-03-20 12:17:30 +11:00
Matt Van Horn
aa3fa59a32 fix(spec): include order number in webhook_service_spec expected data
The webhook_payload now includes :number in the order slice, but
webhook_service_spec still expected the order hash without it. Since
hash_including only matches at the top level, the nested order hash
comparison was strict and failed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:05:49 -07:00
Maikel Linke
66d6627c89 Spec recently changed code path 2026-03-20 11:51:50 +11:00
Maikel Linke
c5d38d684b Remove repeated navigation to speed up spec 2026-03-20 11:51:50 +11:00
Maikel Linke
c2907b839a Remove ineffective sorting spec
The spec was not really testing the order of users appearing on the
page. It's also a UX detail only visible to super admins which is not
important to test. So I'm not investing time to fix it.
2026-03-20 11:51:50 +11:00
Maikel Linke
ee653bb825 Remove redundant spec description
Admin users are the only one who can manage users.
2026-03-20 11:51:50 +11:00
Maikel Linke
75616e69e7 Bump devise from 4.9.4 to 5.0.3 2026-03-20 11:51:47 +11:00
Maikel Linke
b4b3e21cf6 Replace deprecated option bypass
- https://github.com/heartcombo/devise/pull/5803
2026-03-20 11:32:49 +11:00
Maikel Linke
ce90ec0f5b Ignore unused authentication_token column 2026-03-20 11:32:49 +11:00
Maikel Linke
2998432744 Remove use of devise token_authenticable
Our production servers don't show any use of this feature. The
associated column is nil for all users.

The gem has not been updated in seven years and it's blocking an
important upgrade of devise.
2026-03-20 11:32:48 +11:00
Maikel
c5aaecf76a Merge pull request #13961 from mkllnk/taler-checkout-stock-error
Taler checkout stock error
2026-03-20 11:29:58 +11:00
Gaetan Craig-Riou
2e64f54740 Merge pull request #14076 from openfoodfoundation/dependabot/bundler/bcrypt-3.1.22
Bump bcrypt from 3.1.20 to 3.1.22
2026-03-20 10:24:54 +11:00
Gaetan Craig-Riou
c7de67a14f Merge pull request #14074 from openfoodfoundation/dependabot/bundler/json-2.19.2
Bump json from 2.19.1 to 2.19.2
2026-03-20 10:05:19 +11:00
dependabot[bot]
545e69835d Bump flatted from 3.3.3 to 3.4.2
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-19 22:57:24 +00:00
Gaetan Craig-Riou
e3a757bd2d Merge pull request #14070 from openfoodfoundation/dependabot/bundler/loofah-2.25.1
Bump loofah from 2.25.0 to 2.25.1
2026-03-20 09:55:44 +11:00
dependabot[bot]
8223d1ce52 Bump bcrypt from 3.1.20 to 3.1.22
Bumps [bcrypt](https://github.com/bcrypt-ruby/bcrypt-ruby) from 3.1.20 to 3.1.22.
- [Release notes](https://github.com/bcrypt-ruby/bcrypt-ruby/releases)
- [Changelog](https://github.com/bcrypt-ruby/bcrypt-ruby/blob/master/CHANGELOG)
- [Commits](https://github.com/bcrypt-ruby/bcrypt-ruby/compare/v3.1.20...v3.1.22)

---
updated-dependencies:
- dependency-name: bcrypt
  dependency-version: 3.1.22
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-19 18:48:18 +00:00
Greg Austic
032953e7d6 Fix: unify font-family across all .button elements
<button> elements don't inherit font-family from parent by default
in all browsers, causing a visible font mismatch between the
link-based buttons (Back To Store, Back To Website, Cancel Order)
and the button-tag-based Save Changes button on the order
confirmation page.

Add `font-family: inherit` to the base `.button, button` rule so
all button elements use the inherited page font (Roboto). Remove the
now-redundant `font-family: $body-font` from the `.primary` rule.

Fixes #13688

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 10:22:59 -04:00
dependabot[bot]
167846138f Bump json from 2.19.1 to 2.19.2
Bumps [json](https://github.com/ruby/json) from 2.19.1 to 2.19.2.
- [Release notes](https://github.com/ruby/json/releases)
- [Changelog](https://github.com/ruby/json/blob/master/CHANGES.md)
- [Commits](https://github.com/ruby/json/compare/v2.19.1...v2.19.2)

---
updated-dependencies:
- dependency-name: json
  dependency-version: 2.19.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-19 13:02:05 +00:00
Matt Van Horn
1878a39188 Fix inline error style in Add Manager dialog to match product list
Add .field class to the email row in the user invitation modal so
the .formError styles (icon, color, font-size) defined in forms.scss
apply consistently with the product list inline errors.

Fixes #13993
2026-03-18 21:46:21 -07:00
Maikel
243e70427d Merge pull request #14065 from openfoodfoundation/dependabot/bundler/debug-1.11.1
Bump debug from 1.11.0 to 1.11.1
2026-03-19 13:54:54 +11:00
Maikel
0ae3c8d668 Merge pull request #14063 from openfoodfoundation/dependabot/npm_and_yarn/mini-css-extract-plugin-2.10.1
Bump mini-css-extract-plugin from 2.10.0 to 2.10.1
2026-03-19 13:54:17 +11:00
Maikel
c8f46e52d3 Merge pull request #14062 from openfoodfoundation/dependabot/npm_and_yarn/sass-embedded-1.98.0
Bump sass-embedded from 1.97.3 to 1.98.0
2026-03-19 13:53:40 +11:00
dependabot[bot]
131a916d99 Bump loofah from 2.25.0 to 2.25.1
Bumps [loofah](https://github.com/flavorjones/loofah) from 2.25.0 to 2.25.1.
- [Release notes](https://github.com/flavorjones/loofah/releases)
- [Changelog](https://github.com/flavorjones/loofah/blob/main/CHANGELOG.md)
- [Commits](https://github.com/flavorjones/loofah/compare/v2.25.0...v2.25.1)

---
updated-dependencies:
- dependency-name: loofah
  dependency-version: 2.25.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-18 21:07:53 +00:00
dependabot[bot]
9dd9e08694 Bump debug from 1.11.0 to 1.11.1
Bumps [debug](https://github.com/ruby/debug) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/ruby/debug/releases)
- [Commits](https://github.com/ruby/debug/compare/v1.11.0...v1.11.1)

---
updated-dependencies:
- dependency-name: debug
  dependency-version: 1.11.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-18 09:34:28 +00:00
dependabot[bot]
e7180e956f Bump mini-css-extract-plugin from 2.10.0 to 2.10.1
Bumps [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin) from 2.10.0 to 2.10.1.
- [Release notes](https://github.com/webpack/mini-css-extract-plugin/releases)
- [Changelog](https://github.com/webpack/mini-css-extract-plugin/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/mini-css-extract-plugin/compare/v2.10.0...v2.10.1)

---
updated-dependencies:
- dependency-name: mini-css-extract-plugin
  dependency-version: 2.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-18 09:33:00 +00:00
dependabot[bot]
7f312caa25 Bump sass-embedded from 1.97.3 to 1.98.0
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.97.3 to 1.98.0.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.97.3...1.98.0)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-version: 1.98.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-18 09:32:55 +00:00
Matt Van Horn
544f62dbc5 feat(payments): add order number to webhook payload
Include the order number in the webhook payload so consumers can
identify which order a payment notification belongs to.

Fixes #13858
2026-03-18 00:12:23 -07:00
Maikel Linke
8f0d4d23a7 Restore Stripe spec stubs as todo list 2026-03-18 14:54:44 +11:00
Maikel Linke
d56b4b4109 Make locale spec more accurate 2026-03-18 14:49:35 +11:00
Maikel Linke
7a01409f5c Save time by avoiding page visit 2026-03-18 14:49:34 +11:00
Maikel Linke
5c634c269b Remove unused helpers from spec 2026-03-18 14:49:34 +11:00
Maikel Linke
bf22484add Add default locale to fallbacks
The comment about falling back to the default locale came from the first
commit, when the config was just `fallbacks = true`. The fallback logic
is a lot more sophisticated now and we can supply the country's default
locale as first fallback and our source locale `en` as last resort. It
should contain everything.

In the future, we may want to support maps like Canadian French can fall
back to original French. I18n supports this but providing the config per
isntance may be a bit tricky.
2026-03-18 14:49:34 +11:00
Maikel Linke
1696dd2de6 DRY language fallback config 2026-03-18 14:49:34 +11:00
Maikel Linke
63988fff4f Configure test locales like other envs
The locale config is set in application.rb from environment variables
already. We don't need to repeat that logic in test.rb. And because it
was outdated, the language switcher was actually broken in the test
environment. We did have an English selector for the fallback `en` even
though we were already displaying English as en_TST. And after
switchting to Spanish, we could switch back because en_TST was not in
the available locales.

I now fixed the test with the right assumption and the config to solve
the problem.
2026-03-18 14:49:15 +11:00
David Cook
8e6f1c4e99 Show display name 2026-03-18 14:30:27 +11:00
David Cook
2004934399 Register only necessary elements
This should be more efficient.

Best viewed with whitespace ignored.
2026-03-18 14:30:23 +11:00
David Cook
827ba1990d Ensure changes are tracked on newly added variant
I considered a few ways to do this. Cloned products are done with MutationObserver but it doesn't quite sit right with me. A dedicated controller for newly added rows would provide a good general solution. But do we want yet another controller? I'm not sure. This works and is pretty simple (although it requires a quick loop over _every_ form element.. let's see if we can avoid that.)
2026-03-18 14:03:11 +11:00
Maikel Linke
d56790b71e Remove unneeded context blocks
Best viewed ignoring whitespace.
2026-03-18 13:23:54 +11:00
Maikel Linke
c2f725b20c Remove redundant language setup
We tested earlier already that we have the needed languages available.
2026-03-18 13:21:27 +11:00
Maikel Linke
b939d41bf5 Remove useless negative spec
Any change in markup would invalidate the test.

It is unlikely to ever fail and then it would not be a big problem.
2026-03-18 13:18:15 +11:00
Maikel Linke
91c4ba03cd Remove more expensive specs 2026-03-18 13:15:35 +11:00
Maikel Linke
3f29cdab3c Combine specs and add detail 2026-03-18 13:14:57 +11:00
Maikel Linke
60a4d36408 Remove expensive without really new coverage 2026-03-18 13:08:24 +11:00
Maikel Linke
9513c07c2f Remove ineffective test
It would pass even if locales were broken.
2026-03-18 13:05:23 +11:00
Maikel Linke
4b5fd2495f Restore multilingual spec 2026-03-18 13:03:48 +11:00
David Cook
939ae20081 Merge pull request #14053 from chahmedejaz/fix/wkhtmltopdf-binary-install-issue
Fix wkhtmltopdf-binary installation error
2026-03-18 12:44:10 +11:00
David Cook
78e9524767 Add comment 2026-03-18 12:41:28 +11:00
Maikel
3f5b7aaea9 Merge pull request #14051 from openfoodfoundation/dependabot/bundler/mini_portile2-2.8.9
Bump mini_portile2 from 2.8.6 to 2.8.9
2026-03-18 12:20:40 +11:00
Maikel
00ab4379c9 Merge pull request #14050 from openfoodfoundation/dependabot/bundler/aws-sdk-s3-1.215.0
Bump aws-sdk-s3 from 1.213.0 to 1.215.0
2026-03-18 12:19:39 +11:00
Maikel
9dec68032c Merge pull request #14049 from openfoodfoundation/dependabot/npm_and_yarn/jest-30.3.0
Bump jest from 30.2.0 to 30.3.0
2026-03-18 12:18:52 +11:00
Maikel
e449ae95d5 Merge pull request #14052 from dacook/linter-ubuntu-version
Use same ubuntu version for linters to share bundler cache
2026-03-18 12:17:27 +11:00
Ahmed Ejaz
d0af6ddcc1 Fix wkhtmltopdf-binary installation by specifying the original source in Gemfile 2026-03-18 06:07:59 +05:00
dependabot[bot]
a17d3f34d9 Bump jest from 30.2.0 to 30.3.0
Bumps [jest](https://github.com/jestjs/jest/tree/HEAD/packages/jest) from 30.2.0 to 30.3.0.
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.3.0/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-version: 30.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-18 00:49:46 +00:00
David Cook
6c5d49ae33 Merge pull request #14048 from openfoodfoundation/dependabot/npm_and_yarn/jest-environment-jsdom-30.3.0
Bump jest-environment-jsdom from 30.2.0 to 30.3.0
2026-03-18 11:48:31 +11:00
David Cook
7d4389de4a Use same ubuntu version for linters to share bundler cache 2026-03-18 11:26:56 +11:00
David Cook
93c9181c3f Merge pull request #14021 from mkllnk/money
Remove dead code from Spree::Money
2026-03-18 10:50:54 +11:00
David Cook
7473a2f0bd Merge pull request #14020 from mkllnk/flaky-invite-spec
Expect UI change before emails
2026-03-18 10:49:03 +11:00
dependabot[bot]
af8544a4fa Bump mini_portile2 from 2.8.6 to 2.8.9
Bumps [mini_portile2](https://github.com/flavorjones/mini_portile) from 2.8.6 to 2.8.9.
- [Release notes](https://github.com/flavorjones/mini_portile/releases)
- [Changelog](https://github.com/flavorjones/mini_portile/blob/main/CHANGELOG.md)
- [Commits](https://github.com/flavorjones/mini_portile/compare/v2.8.6...v2.8.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-17 09:39:55 +00:00
dependabot[bot]
be156e5621 Bump aws-sdk-s3 from 1.213.0 to 1.215.0
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.213.0 to 1.215.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-version: 1.215.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-17 09:34:41 +00:00
dependabot[bot]
ec8fcecbd6 Bump jest-environment-jsdom from 30.2.0 to 30.3.0
Bumps [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom) from 30.2.0 to 30.3.0.
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.3.0/packages/jest-environment-jsdom)

---
updated-dependencies:
- dependency-name: jest-environment-jsdom
  dependency-version: 30.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-17 09:32:53 +00:00
Maikel
35ae3a424a Merge pull request #14046 from openfoodfoundation/RachL-patch-1
Update release task template
2026-03-17 10:34:58 +11:00
Maikel
c2c83898a2 Merge pull request #14045 from openfoodfoundation/dependabot/bundler/knapsack_pro-9.2.3
Bump knapsack_pro from 9.2.2 to 9.2.3
2026-03-17 10:33:27 +11:00
Maikel
2879f77aa1 Merge pull request #14044 from openfoodfoundation/dependabot/bundler/json-2.19.1
Bump json from 2.18.1 to 2.19.1
2026-03-17 10:32:57 +11:00
Rachel Arnould
68032657c3 Update release task template
Add a reminder + change the last step
2026-03-16 12:10:17 +01:00
dependabot[bot]
be4037d05a Bump knapsack_pro from 9.2.2 to 9.2.3
Bumps [knapsack_pro](https://github.com/KnapsackPro/knapsack_pro-ruby) from 9.2.2 to 9.2.3.
- [Changelog](https://github.com/KnapsackPro/knapsack_pro-ruby/blob/main/CHANGELOG.md)
- [Commits](https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v9.2.2...v9.2.3)

---
updated-dependencies:
- dependency-name: knapsack_pro
  dependency-version: 9.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 10:05:34 +00:00
dependabot[bot]
9661e8a53e Bump json from 2.18.1 to 2.19.1
Bumps [json](https://github.com/ruby/json) from 2.18.1 to 2.19.1.
- [Release notes](https://github.com/ruby/json/releases)
- [Changelog](https://github.com/ruby/json/blob/master/CHANGES.md)
- [Commits](https://github.com/ruby/json/compare/v2.18.1...v2.19.1)

---
updated-dependencies:
- dependency-name: json
  dependency-version: 2.19.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 10:03:56 +00:00
Maikel Linke
9961578fc1 Don't offer to void a refund 2026-03-16 12:56:38 +11:00
Maikel Linke
53c2ef53d5 Call #credit with right arguments 2026-03-16 12:56:22 +11:00
David Cook
5e93c27277 Merge pull request #14041 from openfoodfoundation/dependabot/bundler/puma-7.2.0
Bump puma from 6.5.0 to 7.2.0
2026-03-16 09:57:17 +11:00
Ahmed Ejaz
2a67b616e8 Update all locales with the latest Transifex translations 2026-03-14 17:26:41 +05:00
Ahmed Ejaz
1708901b01 Merge pull request #13975 from AwsAqh/fix/session-cookie-domain-13974
Fix shared login sessions between staging and production
2026-03-14 17:22:28 +05:00
David Cook
247f144773 Remove string interpolation 2026-03-14 17:07:30 +05:00
AwsAqh
d09e288887 Update session_store.rb 2026-03-14 17:07:30 +05:00
AwsAqh
c8e4911a2d Update session_store.rb 2026-03-14 17:07:30 +05:00
AwsAqh
4cc2390e6d Fix session cookie domain isolation 2026-03-14 17:07:30 +05:00
Rachel Arnould
7fe4717077 Merge pull request #13985 from openfoodfoundation/dependabot/bundler/valid_email2-7.0.15
Bump valid_email2 from 5.2.3 to 7.0.15
2026-03-13 12:31:53 +01:00
dependabot[bot]
fcb3b67efb Bump puma from 6.5.0 to 7.2.0
Bumps [puma](https://github.com/puma/puma) from 6.5.0 to 7.2.0.
- [Release notes](https://github.com/puma/puma/releases)
- [Changelog](https://github.com/puma/puma/blob/main/History.md)
- [Commits](https://github.com/puma/puma/compare/v6.5.0...v7.2.0)

---
updated-dependencies:
- dependency-name: puma
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-13 09:33:46 +00:00
Gaetan Craig-Riou
50c0c3f0b6 Merge pull request #14025 from openfoodfoundation/dependabot/npm_and_yarn/webpack-5.105.4
Bump webpack from 5.105.3 to 5.105.4
2026-03-13 11:07:34 +11:00
Maikel
6d65607e3b Merge pull request #14022 from rioug/14014-manual-credit-customer-authorization
[Payment with Credit] Fix manual crediting customer
2026-03-13 09:33:03 +11:00
Maikel
43134223ca Merge pull request #14039 from openfoodfoundation/dependabot/npm_and_yarn/trix-2.1.17
Bump trix from 2.1.16 to 2.1.17
2026-03-13 09:30:32 +11:00
dependabot[bot]
8510a3c70d Bump trix from 2.1.16 to 2.1.17
Bumps [trix](https://github.com/basecamp/trix) from 2.1.16 to 2.1.17.
- [Release notes](https://github.com/basecamp/trix/releases)
- [Commits](https://github.com/basecamp/trix/compare/v2.1.16...v2.1.17)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-12 17:36:40 +00:00
dependabot[bot]
80ffcb9074 Bump webpack from 5.105.3 to 5.105.4
Bumps [webpack](https://github.com/webpack/webpack) from 5.105.3 to 5.105.4.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.105.3...v5.105.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-12 01:44:14 +00:00
Maikel
cdd6c0f66c Merge pull request #14026 from openfoodfoundation/dependabot/bundler/aws-sdk-s3-1.213.0
Bump aws-sdk-s3 from 1.208.0 to 1.213.0
2026-03-12 12:44:11 +11:00
Maikel
ebc7dc9bcf Merge pull request #14024 from openfoodfoundation/dependabot/npm_and_yarn/terser-webpack-plugin-5.3.17
Bump terser-webpack-plugin from 5.3.16 to 5.3.17
2026-03-12 12:42:08 +11:00
dependabot[bot]
98c3b0eac4 Bump aws-sdk-s3 from 1.208.0 to 1.213.0
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.208.0 to 1.213.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-version: 1.213.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-11 09:33:29 +00:00
dependabot[bot]
5e46c35f68 Bump terser-webpack-plugin from 5.3.16 to 5.3.17
Bumps [terser-webpack-plugin](https://github.com/webpack/terser-webpack-plugin) from 5.3.16 to 5.3.17.
- [Release notes](https://github.com/webpack/terser-webpack-plugin/releases)
- [Changelog](https://github.com/webpack/terser-webpack-plugin/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/terser-webpack-plugin/compare/v5.3.16...v5.3.17)

---
updated-dependencies:
- dependency-name: terser-webpack-plugin
  dependency-version: 5.3.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-11 09:32:58 +00:00
Maikel Linke
0629153362 Complete code coverage on Taler error handling 2026-03-11 16:05:54 +11:00
Gaetan Craig-Riou
4946ffc329 Add specs for CustomerAccountTransaction ability 2026-03-11 15:45:33 +11:00
Gaetan Craig-Riou
c134bbf49b Add missing ability for credit customer
Fix the specs to use a non super admin user, so it should catch missing
ability in the future.
2026-03-11 15:34:27 +11:00
Maikel Linke
5e871fc71e Expect UI change before emails
Fixing a flaky spec.
2026-03-11 15:30:39 +11:00
Maikel Linke
35e03ea3c7 Check stock before completing order after Taler payment 2026-03-11 15:12:21 +11:00
Maikel Linke
ee7ed56f44 Remove unused method Spree::Money#format 2026-03-11 14:56:28 +11:00
Maikel Linke
4140209820 Remove unused delegator to Money#cents 2026-03-11 14:56:28 +11:00
Maikel Linke
1bb4fdf294 Remove compatibility redirect for APIv0 2026-03-11 14:52:11 +11:00
Maikel Linke
9ca1a9e33f Allow orders to be paid before checkout
Taler puts the payment completion into the hands of the user. So we
can't strictly finalise the payment and order together.

And in the bigger picture, it should be okay if a payment goes through
but we have to abort checkout due to stock issues. Then we want to be
able to check out again, using the existing complete payment. Any
refunds can be handled later by the shop owner.
2026-03-11 14:46:06 +11:00
Maikel Linke
62af416696 Avoid useless page visit causing spec flakiness 2026-03-11 14:41:40 +11:00
Maikel Linke
bcf39acebc Remove confusing if-branch in shared examples 2026-03-11 14:41:40 +11:00
Maikel Linke
82186118a7 Remove long inactive specs
Several years ago, some checkout features got rewritten and some specs
became invalid. They had been set to pending to keep the option of
rewriting them one day. Some were re-written. But I'm deleting the
remainder.

If we haven't "needed" these specs for several years then I question
their use. System specs are expensive and should only cover the most
common scenarios or the ones we know could go wrong (after a bug
report). We can always write new specs if needed. Otherwise they are
just adding to maintenance cost.
2026-03-11 14:41:40 +11:00
Maikel Linke
7619062ad2 Revert "Move payment action logic to payment"
This reverts commit fdd22bc097.

And it adds the now needed `can_credit?` method to Taler.
It's just a duplicate.
2026-03-11 11:32:08 +11:00
David Cook
18fb1cfa74 Rename variant 'owner' to 'hub'
As discussed by team, and using same nomenclature as VariantOverride.
2026-03-11 11:09:13 +11:00
David Cook
e9ce2df5a9 Rename 'source variant' to linked variant (in most places)
There are two types of linked variant associations: source and target, so we need to keep the name there.
But when cloning a variant and retaining a link as source,  we will prefer the general term 'linked variant'. Hopefully this name works well.
2026-03-11 11:09:13 +11:00
David Cook
c165ade4ba Avoid unnecessary save
Actually, the variant factory is still adding an extra save. We should refactor Variant to avoid that.. but the afternoon slump has got me.
2026-03-11 11:09:12 +11:00
David Cook
7e8b3694be Move class instance variable to helper 2026-03-11 11:09:12 +11:00
David Cook
6ee715419a ORder by ID to ensure deterministic results 2026-03-11 11:09:12 +11:00
David Cook
7da6adfe4f Use reference command
For uniformity

Co-authored-by: Maikel <maikel@email.org.au>
2026-03-11 11:09:12 +11:00
David Cook
05c31db46a Remove touch
I think I was just following convention from existing relationships. Perhaps you could argue that a variant is affected by the links added/removed.. but we never look at updated_at so really there's no point at all.
2026-03-11 11:09:12 +11:00
David Cook
666e872ac8 Revert uninentional schema change
I guess my local db is slightly out of sync.
2026-03-11 11:09:12 +11:00
David Cook
de6eb9e281 Avoid useless updated_at column
These records won't be updatable, but it might still be worth tracking when they were created.
2026-03-11 11:09:12 +11:00
David Cook
299ada1220 Refactor: move variant duplication to model
I tried to avoid it but rubocop made me move it. I think maybe it will need to go into a concern or service class later, but hopefully it's ok here for now.
2026-03-11 11:09:12 +11:00
David Cook
5757f086ec Set owner enterprise when creating source variant 2026-03-11 11:09:12 +11:00
David Cook
8955ffe126 AddOwnerToSpreeVariants [migration]
Should existing variants be migrated to have an owner (copied from supplier)? No, because you can change supplier. This concept needs work.
2026-03-11 11:09:09 +11:00
David Cook
b26152cf0e Only show option when you have permission
Preload the allow list once in the controller. This controller was initially set up to avoid instance variables, and pass variables explicitly to the template. That's a good principle, but in practice we have a growing list of variables passed down the chain to multiple partials which is getting cumbersome. I think instance variables have their place after all.
2026-03-11 11:08:50 +11:00
David Cook
78db179ff3 haml-lint:disable ViewLength
TIL we have linting on haml.

I couldn't think of a better way to handle this but would be glad to receive feedback.
2026-03-11 11:08:50 +11:00
David Cook
5fc6d25a69 Display presence of variant link in UI
It's quite ugly. But we will be iterating on this later.
2026-03-11 11:08:50 +11:00
David Cook
b877540f5f Create sourced variant link on clone 2026-03-11 11:08:50 +11:00
copilot-swe-agent[bot]
04c0adf960 Fix source_variants and target_variants associations in Variant model
Co-authored-by: dacook <4188088+dacook@users.noreply.github.com>

Thanks co-pilot for sending me in the right direction.
Would this be neater as a has_and_belongs_to_many? Maybe but I will try to keep moving.
2026-03-11 11:08:50 +11:00
David Cook
1c89e9979e CreateVariantLinks [migration]
Tried using the rails generator, but as usual it was a waste of time becuase it doesn't handle unusual cases.

I found more good guidance from that stackoverflow post:
> why are you worrying about your indexes? Build your app!

Something's not right in the model, see next commit.
2026-03-11 11:08:47 +11:00
David Cook
eba2fbcc30 Create source variants 2026-03-11 11:07:08 +11:00
David Cook
940aa57daf Set up permissions for creating source variants 2026-03-11 11:07:08 +11:00
David Cook
766bedb773 Label this feature as 'beta'
The permission is effectively the feature toggle. Users can choose to use it, but shouldn't expect it all to work perfectly yet.
When it's considered full featured, we just need to update the translation. Hm... I hope that's not too painful.🤞
2026-03-11 11:07:08 +11:00
David Cook
6fe2357ca0 Add enterprise permission create_sourced_variants 2026-03-11 11:07:08 +11:00
David Cook
bd01b5f113 Add 'create sourced variant' option in variant actions menu
For now, we will only be able to create sourced variant from variants that are visible to us (variants that we manage)

    In a later commit I will hide the option if you can't use it
2026-03-11 11:07:08 +11:00
David Cook
e565243ce4 Remove unnecessary before action
Each context has different setup and needs to load the page after setup.
2026-03-11 11:07:08 +11:00
David Cook
0f3b299544 Clean up spec
There's no "COPY OF" product in the spec setup, so we don't need to check that it's not there. (unless maybe we added that to the product factory, but it seems unlikely).

Also we can use helper method.
2026-03-11 11:07:08 +11:00
David Cook
1332051a6e Move specs to relevant file
These tests are about browsing products, not performing actions.

Well, ok there's one about updating, which should probably go in the update file. But hey this is better than before.
And admittedly the "Actions" file covers three different things, not just the actions menu. shrug.
2026-03-11 11:07:07 +11:00
Maikel Linke
fb2dfed6bf Pass amount to payment mailer
We now include the refunded amount in the email to the customer. When
voiding a payment, it's the full amount of the payment. When giving back
credit then it's only the money that has been paid too much.
2026-03-11 10:58:30 +11:00
Maikel Linke
cf53ac1990 Add credit action to Taler 2026-03-11 10:58:30 +11:00
Maikel Linke
fdd22bc097 Move payment action logic to payment
At closer inspection, almost all logic around which payment actions to
display involves only the state of the payment. So I moved the logic
there.

We now have one list of all possible actions supported by the UX. Then
payment methods can declare a list of supported actions. If that's
conditional, they can implement the conditions themselves. The payment
model itself then still filters the actions based on its state.
2026-03-11 10:58:30 +11:00
Maikel Linke
956c4a27c2 Remove unnecessary guard clause
Previously, payment actions that were listed without an associated
`can_?` method were interpreted as supported. All payment methods are
implementing all `can_?` methods for listed actions though. And I think
that new payment methods should explicitely implement all `can_?`
methods instead of relying on this hidden logic.
2026-03-11 10:58:30 +11:00
Maikel Linke
2b32f6b909 Make payment method source of truth of supported actions 2026-03-11 10:58:30 +11:00
Maikel Linke
303b91af5e Move list of payment actions from card to gateway
We currently ask the credit card first which payment actions like "void"
it supports. But all the logic is not card specifc. It depends on the
payment method which actions it supports.

And instead of having two different classes potentially being the source
of truth for actions, I prefer leaving that responsibility with exactly
one class, the payment method.

I'll move the `can_?` methods next.
2026-03-11 10:58:30 +11:00
Maikel Linke
ce96b58800 Remove useless setting of payment amount
It gets overridden later anyway.
2026-03-11 10:58:25 +11:00
Gaetan Craig-Riou
dff9d7ede6 Merge pull request #14009 from openfoodfoundation/dependabot/npm_and_yarn/postcss-8.5.8
Bump postcss from 8.5.6 to 8.5.8
2026-03-11 10:32:14 +11:00
Gaetan Craig-Riou
210303de90 Merge pull request #14011 from openfoodfoundation/dependabot/bundler/flipper-ui-1.4.0
Bump flipper-ui from 1.3.6 to 1.4.0
2026-03-11 10:30:56 +11:00
Gaetan Craig-Riou
7a0eee121d Merge pull request #14010 from openfoodfoundation/dependabot/npm_and_yarn/floating-ui/dom-1.7.6
Bump @floating-ui/dom from 1.7.5 to 1.7.6
2026-03-11 10:24:43 +11:00
Gaetan Craig-Riou
9816332601 Update all locales with the latest Transifex translations 2026-03-10 22:15:29 +11:00
Gaetan Craig-Riou
4810b02233 Merge pull request #13702 from marincarroll/improve-accessibility-of-admin-pagination
Improve accessibility of admin pagination
2026-03-10 22:12:57 +11:00
Gaetan Craig-Riou
f8716f8005 Merge pull request #13963 from rioug/13855-payment-with-credit
Payment with credit
2026-03-10 22:11:40 +11:00
dependabot[bot]
8064154a86 Bump flipper-ui from 1.3.6 to 1.4.0
Bumps [flipper-ui](https://github.com/flippercloud/flipper) from 1.3.6 to 1.4.0.
- [Release notes](https://github.com/flippercloud/flipper/releases)
- [Changelog](https://github.com/flippercloud/flipper/blob/main/Changelog.md)
- [Commits](https://github.com/flippercloud/flipper/compare/v1.3.6...v1.4.0)

---
updated-dependencies:
- dependency-name: flipper-ui
  dependency-version: 1.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 09:34:57 +00:00
dependabot[bot]
c3051ea351 Bump @floating-ui/dom from 1.7.5 to 1.7.6
Bumps [@floating-ui/dom](https://github.com/floating-ui/floating-ui/tree/HEAD/packages/dom) from 1.7.5 to 1.7.6.
- [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.7.6/packages/dom)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 09:33:40 +00:00
dependabot[bot]
c850feeab8 Bump postcss from 8.5.6 to 8.5.8
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 09:33:21 +00:00
Gaetan Craig-Riou
5cf213f22a Fix failing spec 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
251a1acffc Clean up enterprise controller 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
d5dec05ab1 Remove payment method ApiCustomerCredit 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
7790259c27 Add transaction origin for internal credit payments 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
6a99d2a3c8 Add transaction origin in descriptiopn 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
e7a2b7ea48 Remove payment method from customer account transaction 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
bd0dcd99f3 Fix failing spec
I wrongly fixed it due to my local database having rogue data
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
bc23423521 Remove the link between enterprise and internal payment method
Enterprise have access to the internal payment method by default.
The access is handled at the application level so we don't have to
manage database links.
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
a4ca56c7a5 Refactored internal payment method
We now check on known payment method type, instead of using the internal
collumn.
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
9f7655852d Provide helper method to get internal payment method 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
ec106a8f83 Add new payment method ApiCustomerCredit
It was previously modelled by a "Check" payment method
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
2e7237197a Refactor customer credit payment method
Set fixed name and description
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
25c579c478 Per review, small code fixes 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
66b820869c Add missing reference to spree_payments 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
ffc819ea76 Linting migration 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
ed3f928783 Fix diplaying customer transactions when no transaction 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
63a9601812 Add scroll bar to modal component
When content is too big, the bottom is displayed off screen
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
3b068b7125 Add created_by to customer account transactions
It allows tracking of who credited the customer via :
- customer account transaction API
- order payment screen
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
597c0590ed Add the ability to show ID on backoffice customer screen
The customer ID is needed for the customer account transaction api
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
b9b91620ef Make sure to link credit payment method on create and update 2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
c67d47a773 Check if internal payment can be voided
Add extra security, we don't want to void a credit payment that is not
completed, otherwise we would be refunding credit that was not used.
A credit payment should not be in a non completed state, but you never
know.
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
85e0da8aeb Improve concurrency spec
Add checks to see if breakpoint is actually reach and if we have a race
condition.
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
34c91613f7 Customer account transaction, simplify balance calculation
Lock the customer to ensure the balance calculation is correct. Much
simpler than locking the first transaction.
2026-03-10 16:07:43 +11:00
Gaetan Craig-Riou
219e3ca9c8 Fix typo 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
628810eb33 Fix spec to work with the internal payment method 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
d95aac333b Add internal to payment method
It's used to hide the payment method used for paying with credit. These
payment method are for internal use only.
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
3e2e7f1799 Add button to credit customer when order is credit owed state
It will add a negative payment, matching the amount credited in the
customer_account_transaction
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
ee13a3abaf Add Orders::CustomerCreditService.refund
It will be used to credit the customer any fund from an order in
credit_owed state
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
d5bd8fa086 Add ability to "void" a customer credit payment
Voiding the payment will refund the credit used to the customer.
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
5e4cd4d51d Remove unused helper 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
c0823d24c2 Fix deprecation warning 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
41e4fd79a3 Move logic to apply customer credit to it's on service
It's now called as a before transition callback when the order move to
payment. We need to apply the credit at this point to account for
order fees, ie: shippment fees.
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
a60afd10e4 Display credit used on the order confirmation page 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
b42b10fcd1 Use the order outstanding balance to create payment
When a customer credit is applied to an order, the balance due is the
order outstanding balance and not the order total.
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
c8dbf4c6f0 Add error handling around payment with credit
For now we log error but don't report it to the user, so they can
proceed through the checkout.
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
f5a3093e41 Automatically use credit at checkout when available
This only cover the ideal scenario, error handling will be added later
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
5a376c9106 Add customer_credit scope 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
152fd15bd0 Use display_name and display_description for payment method 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
5bdb6e6d69 Clean up spec 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
cb6b1f2dd0 Link producer enterprise to credit payment method 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
130401263a Add CreditPaymentMethod::Linker
It links the given enterprise to credit related payment method. It
will create the methods if missing.
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
29a8a6641c Add ability to use payment with credit
Currently it works like any other payment method you can select on
checkout. It will eventually be added automatically to the order, when a
customer has credit available.
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
7ab33d86f1 Add Customer credit payment method migration 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
28241756aa Add Customer Credit payment method
It doesn't do anything yet
2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
fec5516fce Backoffice customer, Add pop up to list customer payments 2026-03-10 16:07:42 +11:00
Gaetan Craig-Riou
6aa4bf7a33 Add available credit on the admin customer page 2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
c58a65a52b Add a tab to list customer payment on the account page 2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
e21fadd124 Add CustomerAccountTransactions::DataLoaderService
It's used to load customer transactions related to a user and a specific
enterprise
2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
1b468522e6 Add concurrency spec
Make sure two transactions cannot be processed at the same time
2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
be7be9bbc6 Add api endpoing to create customer transactions
Plus specs and documentation
2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
6915836a14 Add balance to customer account transaction
It stores the running balance for the customer account, so we don't have
to calulate it on the fly.
2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
e10fd0b020 Add api payment method
It will be used to credit customer via the customer account transaction
API
2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
45786780a8 Code formating 2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
7d400e9860 Add CustomerAccountTransaction model
It's used to store payment against a customer, to model customer credit
2026-03-10 16:07:41 +11:00
Gaetan Craig-Riou
b50f299381 Merge pull request #14008 from rioug/14004-link-correct-customer-to-order
14004 link correct customer to order
2026-03-10 16:04:45 +11:00
Gaetan Craig-Riou
d706b3a6c2 Per review, remove customer when no existing customer 2026-03-10 15:20:56 +11:00
Gaetan Craig-Riou
153b94f18e Merge pull request #14006 from openfoodfoundation/dependabot/bundler/turbo-rails-2.0.23
Bump turbo-rails from 2.0.20 to 2.0.23
2026-03-10 14:55:27 +11:00
Gaetan Craig-Riou
71daccb49a Merge pull request #14005 from openfoodfoundation/dependabot/npm_and_yarn/webpack-5.105.3
Bump webpack from 5.105.2 to 5.105.3
2026-03-10 14:53:47 +11:00
Gaetan Craig-Riou
bca5ee226d Add spec to test the correct customer is linked 2026-03-10 14:16:01 +11:00
Gaetan Craig-Riou
fe00d1f813 reset_other! now reset the customer when present 2026-03-10 14:16:01 +11:00
Gaetan Craig-Riou
57a69f7fa3 Improve spec for reset_other!
Covers resetting the user
2026-03-10 14:15:54 +11:00
dependabot[bot]
f4d972fc5e Bump turbo-rails from 2.0.20 to 2.0.23
Bumps [turbo-rails](https://github.com/hotwired/turbo-rails) from 2.0.20 to 2.0.23.
- [Release notes](https://github.com/hotwired/turbo-rails/releases)
- [Commits](https://github.com/hotwired/turbo-rails/compare/v2.0.20...v2.0.23)

---
updated-dependencies:
- dependency-name: turbo-rails
  dependency-version: 2.0.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 09:33:08 +00:00
dependabot[bot]
6db3b44e92 Bump webpack from 5.105.2 to 5.105.3
Bumps [webpack](https://github.com/webpack/webpack) from 5.105.2 to 5.105.3.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.105.2...v5.105.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 09:32:45 +00:00
Maikel
f7f7a5738a Merge pull request #13895 from cillian/remove-angular-from-enterprise-settings-users
Remove Angular from Enterprise > Settings > Users section
2026-03-06 14:05:13 +11:00
Gaetan Craig-Riou
da912f21b3 Merge pull request #14003 from openfoodfoundation/dependabot/npm_and_yarn/dompurify-3.3.2
Bump dompurify from 3.3.1 to 3.3.2
2026-03-06 11:29:51 +11:00
dependabot[bot]
e2146eb1a3 Bump dompurify from 3.3.1 to 3.3.2
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.1 to 3.3.2.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.3.1...3.3.2)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-05 23:10:00 +00:00
Gaetan Craig-Riou
8e19bfca3c Merge pull request #13991 from openfoodfoundation/dependabot/npm_and_yarn/immutable-5.1.5
Bump immutable from 5.1.4 to 5.1.5
2026-03-06 09:59:29 +11:00
Gaetan Craig-Riou
255836b4d2 Merge pull request #13990 from openfoodfoundation/dependabot/npm_and_yarn/svgo-4.0.1
Bump svgo from 4.0.0 to 4.0.1
2026-03-06 09:54:52 +11:00
Gaetan Craig-Riou
fcd7b457e6 Merge pull request #13989 from openfoodfoundation/dependabot/bundler/vcr-6.4.0
Bump vcr from 6.3.1 to 6.4.0
2026-03-06 09:53:05 +11:00
Gaetan Craig-Riou
eb1daf425a Merge pull request #13988 from openfoodfoundation/dependabot/npm_and_yarn/hotkeys-js-4.0.2
Bump hotkeys-js from 4.0.1 to 4.0.2
2026-03-06 09:51:44 +11:00
Gaetan Craig-Riou
06bc6c276a Merge pull request #13987 from mkllnk/spring-watch
Add gem for spring to listen to filesystem changes efficiently
2026-03-06 09:50:32 +11:00
Gaetan Craig-Riou
6854a53bd1 Merge pull request #13785 from pacodelaluna/repair-rounding-issue-on-totals-in-reports
Repair rounding issue on totals in reports
2026-03-06 09:34:39 +11:00
Rachel Arnould
57186a74a8 Merge pull request #13958 from arunguleria/13864-remove-variants-dead-features
13864-Remove dead feature to re-arrange variants
2026-03-05 12:44:05 +01:00
dependabot[bot]
3575952d4b Bump immutable from 5.1.4 to 5.1.5
Bumps [immutable](https://github.com/immutable-js/immutable-js) from 5.1.4 to 5.1.5.
- [Release notes](https://github.com/immutable-js/immutable-js/releases)
- [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/immutable-js/immutable-js/compare/v5.1.4...v5.1.5)

---
updated-dependencies:
- dependency-name: immutable
  dependency-version: 5.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 23:24:58 +00:00
dependabot[bot]
11203da5ca Bump svgo from 4.0.0 to 4.0.1
Bumps [svgo](https://github.com/svg/svgo) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/svg/svgo/releases)
- [Commits](https://github.com/svg/svgo/compare/v4.0.0...v4.0.1)

---
updated-dependencies:
- dependency-name: svgo
  dependency-version: 4.0.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 23:08:16 +00:00
dependabot[bot]
86091a5a79 Bump vcr from 6.3.1 to 6.4.0
Bumps [vcr](https://github.com/vcr/vcr) from 6.3.1 to 6.4.0.
- [Release notes](https://github.com/vcr/vcr/releases)
- [Changelog](https://github.com/vcr/vcr/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vcr/vcr/compare/v6.3.1...v6.4.0)

---
updated-dependencies:
- dependency-name: vcr
  dependency-version: 6.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 09:35:06 +00:00
dependabot[bot]
f4328f1d18 Bump hotkeys-js from 4.0.1 to 4.0.2
Bumps [hotkeys-js](https://github.com/jaywcjlove/hotkeys-js) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/jaywcjlove/hotkeys-js/releases)
- [Commits](https://github.com/jaywcjlove/hotkeys-js/compare/v4.0.1...v4.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 09:34:51 +00:00
Marin @Home
2334a695a8 adds back CSS hiding disabled prev/next for similar pagination components 2026-03-04 14:43:43 +11:00
Marin @Home
c9418c52e4 linting 2026-03-04 14:43:43 +11:00
Marin @Home
ce1e38f97b Fixes 'orders' test failure 2026-03-04 14:43:43 +11:00
Marin @Home
e16595eacb Adds empty href; prev/next button labels 2026-03-04 14:43:43 +11:00
Marin @Home
510fd4867b Removes disabled/hidden prev/next buttons 2026-03-04 14:43:43 +11:00
Marin @Home
53d6886f20 <ul> should only wrap pagelist 2026-03-04 14:43:43 +11:00
Marin @Home
dad9014a60 Adds ARIA labels to page button/links 2026-03-04 14:43:43 +11:00
Marin @Home
abe9032910 Adds rel "next" and "prev" to pagination 2026-03-04 14:43:43 +11:00
Marin @Home
272cf9ae87 Adds ARIA current "page" attribute 2026-03-04 14:43:43 +11:00
Marin @Home
1d5bc14f2f Adds ARIA label to pagination with English translation 2026-03-04 14:43:43 +11:00
Marin @Home
0332049551 Updates CSS after pagination markup change 2026-03-04 14:43:43 +11:00
Marin @Home
0ffd4dcc35 Pagination should use ul > li pattern 2026-03-04 14:43:42 +11:00
Marin @Home
e899d1b7fd Button element should be <a> 2026-03-04 14:43:42 +11:00
Marin @Home
ed331dc104 Pagination wrapper should be <nav> 2026-03-04 14:43:42 +11:00
Maikel Linke
1bec028a09 Add gem for spring to listen to filesystem changes efficiently
I found that each spring process was using around 3% CPU in the
background just scanning for file changes. By default, spring polls the
file system every 0.2 seconds.

With the added gem, I can't see any CPU use of spring in the background.
2026-03-04 14:43:18 +11:00
David Cook
59547ba9e4 Merge pull request #13964 from mkllnk/flaky-spec
Stabilise actions_spec
2026-03-04 13:06:08 +11:00
Maikel
9fb8bb15e8 Merge pull request #13951 from zilton7/fix/spree-credit-card-brand-deprecation
Fix Spree::CreditCard#brand= deprecation for Rails 7.2 compatibility
2026-03-04 11:01:10 +11:00
Maikel
8aa89c0bf7 Merge pull request #13669 from pacodelaluna/repair-proxy-order-to-support-order-cycle-without-closing-time
Repair ProxyOrder to support order cycle without closing time
2026-03-04 10:59:21 +11:00
Cillian O'Ruanaidh
447d80c960 Fix spec due to switch to email type field 2026-03-04 10:28:40 +11:00
Cillian O'Ruanaidh
67853bb976 Use guard 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
d57274fc4c Manager invitation email is only for new users 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
f063e2e8c6 Change to email field 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
d3eb887664 Align button 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
efae11e2af Change assertion for flakey test failure 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
1554459eb9 Display a JS alert if /admin/search/known_users returns an error 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
50265780cf Call AdminTooltipComponent directly and remove unnecessary partial 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
7433f6d183 Rename :save to save! on UserInvitation because it possibly could raise an exception 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
f1071575cd Remove Angular from Enterprise > Settings > Users section 2026-03-04 10:28:36 +11:00
Maikel
7a4beb8b22 Merge pull request #13982 from openfoodfoundation/dependabot/npm_and_yarn/tom-select-2.5.2
Bump tom-select from 2.5.1 to 2.5.2
2026-03-04 09:49:28 +11:00
Maikel
9a48ee16cc Merge pull request #13983 from openfoodfoundation/dependabot/npm_and_yarn/hotkeys-js-4.0.1
Bump hotkeys-js from 4.0.0 to 4.0.1
2026-03-04 09:48:23 +11:00
Maikel
50c0e8af7d Merge pull request #13984 from openfoodfoundation/dependabot/bundler/pdf-reader-2.15.1
Bump pdf-reader from 2.15.0 to 2.15.1
2026-03-04 09:47:35 +11:00
David Cook
1cf2928f9f Merge pull request #13979 from openfoodfoundation/RachL-patch-1
Update release issue template
2026-03-04 09:10:24 +11:00
François Turbelin
6cacde837d Remove duplicated test 2026-03-03 14:27:20 +01:00
dependabot[bot]
a3aebe5363 Bump valid_email2 from 5.2.3 to 7.0.15
Bumps [valid_email2](https://github.com/micke/valid_email2) from 5.2.3 to 7.0.15.
- [Release notes](https://github.com/micke/valid_email2/releases)
- [Changelog](https://github.com/micke/valid_email2/blob/main/CHANGELOG.md)
- [Commits](https://github.com/micke/valid_email2/compare/v5.2.3...v7.0.15)

---
updated-dependencies:
- dependency-name: valid_email2
  dependency-version: 7.0.15
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:43:46 +00:00
dependabot[bot]
1d2d661675 Bump pdf-reader from 2.15.0 to 2.15.1
Bumps [pdf-reader](https://github.com/yob/pdf-reader) from 2.15.0 to 2.15.1.
- [Changelog](https://github.com/yob/pdf-reader/blob/main/CHANGELOG)
- [Commits](https://github.com/yob/pdf-reader/compare/v2.15.0...v2.15.1)

---
updated-dependencies:
- dependency-name: pdf-reader
  dependency-version: 2.15.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:33:47 +00:00
dependabot[bot]
5029c03205 Bump hotkeys-js from 4.0.0 to 4.0.1
Bumps [hotkeys-js](https://github.com/jaywcjlove/hotkeys-js) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/jaywcjlove/hotkeys-js/releases)
- [Commits](https://github.com/jaywcjlove/hotkeys-js/compare/v4.0.0...v4.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:33:32 +00:00
dependabot[bot]
2b648f3f3c Bump tom-select from 2.5.1 to 2.5.2
Bumps [tom-select](https://github.com/orchidjs/tom-select) from 2.5.1 to 2.5.2.
- [Release notes](https://github.com/orchidjs/tom-select/releases)
- [Commits](https://github.com/orchidjs/tom-select/compare/v2.5.1...2.5.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:33:16 +00:00
David Cook
b2e847b551 Merge pull request #13957 from openfoodfoundation/dependabot/bundler/i18n-1.14.8
Bump i18n from 1.14.7 to 1.14.8
2026-03-03 17:16:58 +11:00
Maikel Linke
4873fd3275 Remove non-task item 2026-03-03 16:16:57 +11:00
Maikel Linke
e0ad4363a9 Fix formatting 2026-03-03 16:12:47 +11:00
David Cook
46de21ea2b Restore required expectation
It is the whole purpose of the spec.
2026-03-03 11:06:10 +11:00
Gaetan Craig-Riou
efdbf25f86 Merge pull request #13248 from drummer83/email_whitelabel
White labelling all customer facing emails
2026-03-03 09:40:47 +11:00
François Turbelin
a069e4247f Remove helper method to use direct logic 2026-03-02 22:43:18 +01:00
François Turbelin
7010cda9f7 Tidy up the tests 2026-03-02 22:07:45 +01:00
Konrad
498ed5a3ec Resolve conflicts 2026-03-02 22:05:29 +01:00
Rachel Arnould
c7d4c6f3c4 Merge pull request #13835 from prikeshsavla/13569-remove-v3-admin-styles
Refactor admin CSS: Promote v3 to canonical admin styles
2026-03-02 12:29:33 +01:00
Rachel Arnould
70b2a6d999 Update release template
Currently testers are using google docs to store release tests. This is maybe overkill.

I've documented the steps here and the proposal is for testers to document their test in the release issue.
2026-03-02 12:22:11 +01:00
dependabot[bot]
36e3e16ba0 Bump i18n from 1.14.7 to 1.14.8
Bumps [i18n](https://github.com/ruby-i18n/i18n) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/ruby-i18n/i18n/releases)
- [Changelog](https://github.com/ruby-i18n/i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ruby-i18n/i18n/compare/v1.14.7...v1.14.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 02:36:18 +00:00
Gaetan Craig-Riou
0f047e2c25 Merge pull request #13977 from openfoodfoundation/dependabot/npm_and_yarn/minimatch-3.1.5
Bump minimatch from 3.1.2 to 3.1.5
2026-03-02 12:00:02 +11:00
dependabot[bot]
ef7bd083ed Bump minimatch from 3.1.2 to 3.1.5
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-28 03:02:06 +00:00
Rachel Arnould
c13785f2e3 Merge pull request #13943 from pavelk-lab/replace-brand-story-angular-with-details
Replace Angular expand/collapse with native HTML <details>/<summary> for brand story
2026-02-27 15:37:00 +01:00
François Turbelin
28dde86960 Repair ProxyOrder to support order cycle without closing time 2026-02-27 14:36:20 +01:00
François Turbelin
08691f81a1 Adjust logic and specs 2026-02-27 14:09:44 +01:00
Gaetan Craig-Riou
0c0304b1c1 Merge pull request #13976 from openfoodfoundation/revert-13973-fix-rubocop-violations
Revert "Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations"
2026-02-27 10:06:29 +11:00
David-OFN-CA
7922bf7b65 Revert "Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations" 2026-02-26 17:04:21 -05:00
David-OFN-CA
2d46676bb4 Merge pull request #13973 from David-OFN-CA/fix-rubocop-violations
Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations
2026-02-26 16:01:15 -05:00
David Thomas
2808a41f0d Safely autocorrect Rails/RedirectBackOrTo
Inspecting 1721 files
........................................W...................................................................W................W..W.......W................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

Offenses:

app/controllers/admin/order_cycles_controller.rb:212:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back(fallback_location: root_path)
        ^^^^^^^^^^^^^
app/controllers/locales_controller.rb:6:5: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
    redirect_back fallback_location: main_app.root_url
    ^^^^^^^^^^^^^
app/controllers/spree/admin/invoices_controller.rb:31:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back(fallback_location: spree.admin_dashboard_path)
        ^^^^^^^^^^^^^
app/controllers/spree/admin/orders_controller.rb:83:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back fallback_location: spree.admin_dashboard_path
        ^^^^^^^^^^^^^
app/controllers/spree/admin/orders_controller.rb:91:25: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
          format.html { redirect_back(fallback_location: spree.admin_dashboard_path) }
                        ^^^^^^^^^^^^^
app/controllers/spree/admin/return_authorizations_controller.rb:13:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back fallback_location: spree.admin_dashboard_path
        ^^^^^^^^^^^^^

1721 files inspected, 6 offenses detected, 6 offenses corrected
2026-02-26 15:35:55 -05:00
David Thomas
18869979db Safely autocorrect Rails/Presence
Inspecting 1721 files
...................................C.................................................................................................................................................................................................................................................................................................................................................C...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

Offenses:

app/controllers/admin/enterprises_controller.rb:180:7: C: [Corrected] Rails/Presence: Use @object.custom_tab.presence&.destroy instead of @object.custom_tab.destroy if @object.custom_tab.present?.
      @object.custom_tab.destroy if @object.custom_tab.present?
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/controllers/admin/enterprises_controller.rb:243:9: C: [Corrected] Rails/Presence: Use (enterprises.presence&.includes(supplied_products: [:variants, :image])) instead of if enterprises.present? ... end.
        if enterprises.present? ...
        ^^^^^^^^^^^^^^^^^^^^^^^
app/controllers/admin/enterprises_controller.rb:243:9: C: [Corrected] Style/RedundantParentheses: Don't use parentheses around a method call.
        (enterprises.presence&.includes(supplied_products: [:variants, :image]))
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/spree/product.rb:298:7: C: [Corrected] Rails/Presence: Use (first_variant.supplier.presence&.touch) instead of first_variant.supplier.touch if first_variant.supplier.present?.
      first_variant.supplier.touch if first_variant.supplier.present?
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/spree/product.rb:298:7: C: [Corrected] Style/RedundantParentheses: Don't use parentheses around a method call.
      (first_variant.supplier.presence&.touch)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1721 files inspected, 5 offenses detected, 5 offenses corrected
2026-02-26 15:34:45 -05:00
David Thomas
708dbb2270 Regenerate Rubocop's TODO file 2026-02-26 15:33:37 -05:00
François Turbelin
de52e21ee9 Remove floating point overkill for prices sum 2026-02-26 18:04:02 +01:00
Zil Norvilis
9488e9b459 feat: display credit card brand instead of card type in the saved cards list. 2026-02-26 15:52:45 +02:00
Zil Norvilis
503429960a Reverse credit_card_serializer changes 2026-02-26 15:10:21 +02:00
Rachel Arnould
83ec97e720 Merge pull request #13944 from pavelk-lab/fix/rails-7-serialize-deprecation
Fix Rails 7.2 serialize deprecation warnings
2026-02-26 11:29:27 +01:00
Maikel Linke
fd178ee80b Use unique categories to avoid flakiness 2026-02-26 11:42:46 +11:00
Maikel Linke
e4db20f86e Remove unncessary expectation
This assertion was confusing me. It was quite complex and the only thing
it was asserting was the placeholder via a CSS selector. I don't think
it's worth keeping.
2026-02-26 11:37:30 +11:00
Zil Norvilis
58520a0c4c test: Add specs for the stripe_card_options helper method, verifying card formatting and month padding. 2026-02-25 19:49:10 +02:00
Zil Norvilis
0bc4b1c885 refactor: Standardize credit card type attribute to cc_type across the application, removing the brand alias and related methods. 2026-02-25 19:35:53 +02:00
Arun Guleria
b7a1754879 13864 - remove unnecessary routes for update positions 2026-02-25 16:29:20 +05:30
Maikel Linke
560348722c Revert "Test current flakiness of spec"
This reverts commit 7b715bf6c7.
2026-02-25 15:18:39 +11:00
Maikel Linke
6d17cf50fb Test impact of longer wait time on flakiness 2026-02-25 15:08:50 +11:00
Maikel Linke
7b715bf6c7 Test current flakiness of spec 2026-02-25 15:07:52 +11:00
Arun Guleria
ab811b2c83 13864-Remove dead feature to re-arrange variants 2026-02-24 18:16:34 +05:30
Pavel
85c903cb7f Remove fixed serialize deprecation from allowed warnings
The "Passing the class as positional argument" warning was suppressed
while serialize calls were being updated to use the keyword argument
form. Now that the fix is applied, the suppression is no longer needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 23:30:48 +00:00
Zil Norvilis
2cfd386ad7 test: add spec for Spree::CreditCard#brand= setter to verify card type reformatting 2026-02-22 22:28:40 +02:00
Zil Norvilis
ce94b394b2 feat: Add brand= setter to Spree::CreditCard for cc_type assignment. 2026-02-22 22:01:54 +02:00
Pavel
98775bfdb8 Pass type as keyword argument in migration serialize call
Same fix as applied to Invoice and ReportRenderingOptions models in
the parent PR: Rails 7.2 requires the type class to be passed as a
keyword argument to serialize.

  serialize :options, Hash, coder: YAML
  ->
  serialize :options, type: Hash, coder: YAML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 23:23:12 +00:00
pavelk-lab
47ef21deb3 Merge branch 'master' into fix/rails-7-serialize-deprecation 2026-02-21 23:19:58 +00:00
Pavel
e98244fe63 Fix Rails 7.2 serialize deprecation warnings
Pass type as keyword argument in serialize calls, as required from Rails 7.2 onwards.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 21:55:13 +00:00
Pavel
b348536d12 Clean up dead code after Angular brand story removal
- Delete HomeCtrl controller file (nothing references it anymore)
- Remove misplaced .text-vbig class from <details> (was on the old <a> toggle; summary has no visible text)
- Remove redundant cursor: pointer on #brand-story-text (<summary> already sets it)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 21:39:32 +00:00
Pavel
b528bb47a0 Replace Angular expand/collapse with native HTML details/summary for brand story
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-19 21:23:09 +00:00
Prikesh Savla
5a9aa87831 Rename admin-style-v3 to admin-style and remove the admin_legacy styles folder that has no references 2026-01-25 21:15:40 +05:30
Prikesh Savla
8cfab08f9e Refactor admin CSS: Promote v3 to canonical admin styles
The Admin V3 styles are now the primary styles for the application. This change promotes the `admin_v3` directory to `admin` and archives the old styles.

Changes:
- Renamed `app/webpacker/css/admin_v3` to `app/webpacker/css/admin`.
- Renamed the previous `app/webpacker/css/admin` to `app/webpacker/css/admin_legacy`.
- Moved all files referenced by V3 styles from the legacy directory to the new `admin` directory.
- Updated imports in `all.scss` to distinct local files instead of relative paths.
- Cleaned up `admin_legacy` by removing files that are duplicates (by name or content) of the new admin styles.
- Updated `admin-style-v3` pack to point to the new location.
2026-01-25 21:05:38 +05:30
Konrad
e814fdd447 Remove test for active white labeling in test email as proposed by David 2025-12-29 12:36:50 +01:00
David Cook
4d6231105f Assign attribute directly instead of mocking
It's better to set a variable the same way the real code would

Co-authored-by: Maikel <maikel@email.org.au>
2025-12-29 12:18:55 +01:00
Konrad
3a75c3446e Update backorder mailer specs to check that these hub facing emails remain unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
29a76fd721 Update report mailer specs to check that this enterprise facing email remains unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
593bd89095 Update test mailer specs to check that this super admin facing email remains unaffected by white labelling (there are no user or customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
0079ed219b Update producer mailer specs to check that this producer facing email remains unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
5957d99812 Update enterprise mailer specs to check that enterprise facing emails remain unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
89453ec758 Update subscription mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples

Made the check for link to order page more general, because on my system a double quote was expected but a single quote was generated
2025-12-29 12:18:55 +01:00
Konrad
0de4f2f596 Update payment mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
183cbecef6 Update shipment mailer specs to check that customer facing emails are white labelled (there are no shop facing emails here)
Make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
ab6a49e568 Update order mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples

Including the invoice email was too tricky for me for now, sorry
2025-12-29 12:18:55 +01:00
Konrad
52ddb29dc7 Update user mailer specs to check that white labelling does not affect these emails
Move tests to separate file for reuse in other emails

Pass on :mail symbol and obtain the mail-object using public_send() to call it with different names
2025-12-29 12:18:54 +01:00
drummer83
5ce7905a33 White labelling ALL customer facing emails
White labelling added for Order: cancellation email, Order: invoice email, Shipment: shipped email, Subscriptions: authorize payment email, Subscriptions: placement email, Subscriptions: empty order email, Subscriptions: failed payment email

White labelling existed already for Order: confirmation email, Subscriptions: order confirmation email
2025-12-29 12:18:54 +01:00
François Turbelin
8748bd76e2 Introduce a prices_sum helper to factorize the calculation on reports 2025-12-18 18:00:23 +01:00
François Turbelin
30f702ea96 Repair rounding issue on totals in reports 2025-12-04 16:14:04 +01:00
359 changed files with 7787 additions and 4580 deletions

6
.env
View File

@@ -21,12 +21,6 @@ CHECKOUT_ZONE="Australia"
# Find currency codes at http://en.wikipedia.org/wiki/ISO_4217.
CURRENCY="AUD"
# The whenever gem can set the `MAILTO` variable for our cron jobs.
# You can define an email address to notify if any job outputs something.
# But you need a working mail server setup so that the message is delivered.
# See: config/schedule.rb
# SCHEDULE_NOTIFICATIONS="admin@example.com"
# Mail settings
MAIL_HOST="example.com"
MAIL_DOMAIN="example.com"

View File

@@ -13,6 +13,9 @@ CAPYBARA_MAX_WAIT_TIME="10"
# successful fallback to `en`.
LOCALE="en_TST"
# For multilingual - ENV doesn't have array so pass it as string with commas
AVAILABLE_LOCALES="en_TST,es,pt"
OFN_REDIS_JOBS_URL="redis://localhost:6379/2"
SECRET_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

View File

@@ -27,7 +27,13 @@ assignees: ''
- [ ] Move this issue to Test Ready.
- [ ] Notify `@testers` in [#testing].
- [ ] Test build: [Deploy to Staging] with release tag.
- [ ] Notify a deployer to deploy it
- [ ] Map is displayed correctly. Address changes are reflected in the map.
- [ ] Stripe with no authentication card: `4242424242424242` as shopper and as Admin. Order confirmation displays order as "Paid".
- [ ] Stripe with Authentication required card: `4000002760003184` as shopper and as Admin. As admin, check authorization through customer account `/account#/transactions` and email.
- [ ] Pay with Paypal.
- [ ] Order on mobile.
- [ ] Explore a bit the platform to see if there is nothing unusual (15 min. max)
- [ ] Comment on the issue: if it's all good, move to ready to go. If there are issues, don't forget to mention your Desktop/Browser version and number and ping @ reviewers so someone available can have a look
## 3. Deployment at beginning of week
@@ -57,4 +63,4 @@ The full process is described at https://github.com/openfoodfoundation/openfoodn
[Create issue]: https://github.com/openfoodfoundation/openfoodnetwork/issues/new?assignees=&labels=&projects=&template=release.md&title=Release
[#delivery-circle]: https://openfoodnetwork.slack.com/archives/C01T75H6G0Z
[Transifex Client]: https://developers.transifex.com/docs/cli
[minor or major breaking changes]: https://github.com/openfoodfoundation/openfoodnetwork/pulls?q=label%3A%22breaking+change%22%2C%22major+breaking+change%22
[minor or major breaking changes]: https://github.com/openfoodfoundation/openfoodnetwork/pulls?q=label%3A%22breaking+change%22%2C%22major+breaking+change%22

View File

@@ -9,32 +9,30 @@ multi-ecosystem-groups:
turbo_power:
schedule:
interval: "daily"
cooldown:
default-days: 7
updates:
# turbo_power: ensure gem and package are updated together
- package-ecosystem: "bundler"
directory: "/"
patterns: ["turbo_power"]
multi-ecosystem-group: "turbo_power"
# Only specific requirements are specified in Gemfile, so don't touch it.
versioning-strategy: lockfile-only
- package-ecosystem: "npm"
directory: "/"
patterns: ["turbo_power"]
multi-ecosystem-group: "turbo_power"
# Only specific requirements are specified in package.json, so don't touch it.
versioning-strategy: lockfile-only
# All others
- package-ecosystem: "bundler"
directory: "/"
schedule:
interval: "daily"
cooldown:
default-days: 7
# Only specific requirements are specified in Gemfile, so don't touch it.
# Only specific requirements are specified in Gemfile, so don't let Dependabot touch it.
versioning-strategy: lockfile-only
- package-ecosystem: "npm"
@@ -43,6 +41,5 @@ updates:
interval: "daily"
cooldown:
default-days: 7
# Only specific requirements are specified in package.json, so don't touch it.
# Only specific requirements are specified in package.json, so don't let Dependabot touch it.
versioning-strategy: lockfile-only

View File

@@ -5,7 +5,7 @@ permissions:
jobs:
lint:
name: reviewdog
runs-on: ubuntu-latest
runs-on: ubuntu-22.04 # same as build.yml so it can share bundler cache
steps:
- uses: actions/checkout@v3

View File

@@ -63,7 +63,6 @@ gem "taler"
gem 'devise'
gem 'devise-encryptable'
gem 'devise-i18n'
gem 'devise-token_authenticatable'
gem 'jwt', '~> 2.3'
gem 'oauth2', '~> 1.4.7' # Used for Stripe Connect
@@ -113,14 +112,12 @@ gem "turbo-rails"
gem 'combine_pdf'
gem 'wicked_pdf', github: "openfoodfoundation/wicked_pdf", branch: "master"
gem 'wkhtmltopdf-binary'
gem 'wkhtmltopdf-binary', source: 'https://rubygems.org' # due to https://github.com/gem-coop/gem.coop/issues/36
gem 'immigrant'
gem 'roo' # read spreadsheets
gem 'spreadsheet_architect' # write spreadsheets
gem 'whenever', require: false
gem 'coffee-rails', '~> 5.0.0'
gem 'angular_rails_csrf'
@@ -203,6 +200,7 @@ group :development do
gem 'spring'
gem 'spring-commands-rspec'
gem 'spring-commands-rubocop'
gem 'spring-watcher-listen'
gem 'web-console'
gem 'rack-mini-profiler', '< 3.0.0'

View File

@@ -112,7 +112,7 @@ GEM
rails-html-sanitizer (~> 1.6)
active_model_serializers (0.8.4)
activemodel (>= 3.0)
active_storage_validations (3.0.3)
active_storage_validations (3.0.4)
activejob (>= 6.1.4)
activemodel (>= 6.1.4)
activestorage (>= 6.1.4)
@@ -167,10 +167,10 @@ GEM
zeitwerk (>= 2.4, < 3.0)
acts_as_list (1.0.4)
activerecord (>= 4.2)
addressable (2.8.8)
addressable (2.8.9)
public_suffix (>= 2.0.2, < 8.0)
aes_key_wrap (1.1.0)
afm (0.2.2)
afm (1.0.0)
angular-rails-templates (1.4.0)
railties (>= 5.0, < 8.2)
sprockets (>= 3.0, < 5)
@@ -185,8 +185,8 @@ GEM
ast (2.4.3)
attr_required (1.0.2)
aws-eventstream (1.4.0)
aws-partitions (1.1196.0)
aws-sdk-core (3.240.0)
aws-partitions (1.1233.0)
aws-sdk-core (3.244.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
@@ -194,25 +194,25 @@ GEM
bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.118.0)
aws-sdk-core (~> 3, >= 3.239.1)
aws-sdk-kms (1.123.0)
aws-sdk-core (~> 3, >= 3.244.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.208.0)
aws-sdk-core (~> 3, >= 3.234.0)
aws-sdk-s3 (1.217.0)
aws-sdk-core (~> 3, >= 3.244.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.3.0)
bcp47_spec (0.2.1)
bcrypt (3.1.20)
bcrypt (3.1.22)
benchmark (0.5.0)
bigdecimal (3.3.1)
bigdecimal (4.1.0)
bindata (2.5.1)
bindex (0.8.1)
bootsnap (1.22.0)
bootsnap (1.23.0)
msgpack (~> 1.2)
bugsnag (6.28.0)
bugsnag (6.29.0)
concurrent-ruby (~> 1.0)
builder (3.3.0)
bullet (8.1.0)
@@ -245,7 +245,6 @@ GEM
cgi (0.5.1)
childprocess (5.0.0)
choice (0.2.0)
chronic (0.10.2)
coderay (1.1.3)
coffee-rails (5.0.0)
coffee-script (>= 2.2.0)
@@ -279,22 +278,20 @@ GEM
datafoodconsortium-connector (1.2.0)
virtual_assembly-semantizer (~> 1.0, >= 1.0.5)
date (3.5.1)
debug (1.11.0)
debug (1.11.1)
irb (~> 1.10)
reline (>= 0.3.8)
devise (4.9.4)
devise (5.0.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
railties (>= 7.0)
responders
warden (~> 1.2.3)
devise-encryptable (0.2.0)
devise (>= 2.1.0)
devise-i18n (1.15.0)
devise (>= 4.9.0)
devise-i18n (1.16.0)
devise (>= 5.0.0)
rails-i18n
devise-token_authenticatable (1.1.0)
devise (>= 4.0.0, < 5.0.0)
diff-lcs (1.6.2)
digest (3.2.1)
docile (1.4.1)
@@ -313,7 +310,7 @@ GEM
eventmachine (>= 1.0.0.beta.1)
email_validator (2.2.4)
activemodel
erb (6.0.1)
erb (6.0.2)
erubi (1.13.1)
et-orbi (1.4.0)
tzinfo
@@ -342,14 +339,14 @@ GEM
websocket-driver (~> 0.7)
ffaker (2.25.0)
ffi (1.17.3)
flipper (1.3.6)
flipper (1.4.1)
concurrent-ruby (< 2)
flipper-active_record (1.3.6)
flipper-active_record (1.4.0)
activerecord (>= 4.2, < 9)
flipper (~> 1.3.6)
flipper-ui (1.3.6)
flipper (~> 1.4.0)
flipper-ui (1.4.0)
erubi (>= 1.0.0, < 2.0.0)
flipper (~> 1.3.6)
flipper (~> 1.4.0)
rack (>= 1.4, < 4)
rack-protection (>= 1.5.3, < 5.0.0)
rack-session (>= 1.0.2, < 3.0.0)
@@ -387,11 +384,11 @@ GEM
good_migrations (0.3.1)
activerecord (>= 3.1)
railties (>= 3.1)
haml (6.3.0)
haml (7.2.0)
temple (>= 0.8.2)
thor
tilt
haml_lint (0.68.0)
haml_lint (0.72.0)
haml (>= 5.0)
parallel (~> 1.10)
rainbow
@@ -404,18 +401,19 @@ GEM
highline (3.1.2)
reline
htmlentities (4.4.2)
http_parser.rb (0.8.0)
i18n (1.14.7)
http_parser.rb (0.8.1)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
i18n-js (3.9.2)
i18n (>= 0.6.6)
i18n-tasks (1.0.15)
i18n-tasks (1.1.2)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
erubi
highline (>= 2.0.0)
highline (>= 3.0.0)
i18n
parser (>= 3.2.2.1)
prism
rails-i18n
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.8, >= 1.8.1)
@@ -443,7 +441,7 @@ GEM
thor (>= 0.14, < 2.0)
jquery-ui-rails (4.2.1)
railties (>= 3.2.16)
json (2.18.1)
json (2.19.2)
json-canonicalization (1.0.0)
json-jwt (1.17.0)
activesupport (>= 4.2)
@@ -469,7 +467,8 @@ GEM
activesupport (>= 4.2)
jwt (2.10.2)
base64
knapsack_pro (9.2.2)
knapsack_pro (9.2.3)
logger
rake
language_server-protocol (3.17.0.5)
launchy (3.0.0)
@@ -484,7 +483,7 @@ GEM
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.7.0)
loofah (2.25.0)
loofah (2.25.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.9.0)
@@ -506,20 +505,21 @@ GEM
mini_magick (5.3.1)
logger
mini_mime (1.1.5)
mini_portile2 (2.8.6)
minitest (6.0.1)
mini_portile2 (2.8.9)
minitest (6.0.2)
drb (~> 2.0)
prism (~> 1.5)
monetize (1.13.0)
money (~> 6.12)
money (6.16.0)
i18n (>= 0.6.4, <= 2)
msgpack (1.8.0)
multi_json (1.17.0)
multi_json (1.19.1)
multi_xml (0.6.0)
mutex_m (0.3.0)
net-http (0.9.1)
uri (>= 0.11.1)
net-imap (0.5.12)
net-imap (0.6.3)
date
net-protocol
net-pop (0.1.2)
@@ -530,7 +530,7 @@ GEM
net-protocol
newrelic_rpm (9.24.0)
nio4r (2.7.5)
nokogiri (1.19.1)
nokogiri (1.19.2)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri-html5-inference (0.3.0)
@@ -584,18 +584,18 @@ GEM
xml-simple
paypal-sdk-merchant (1.117.2)
paypal-sdk-core (~> 0.3.0)
pdf-reader (2.15.0)
pdf-reader (2.15.1)
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
afm (>= 0.2.1, < 2)
hashery (~> 2.0)
ruby-rc4
ttfunk
pg (1.6.2)
pg (1.6.3)
pp (0.6.3)
prettyprint
prettyprint (0.2.0)
prism (1.9.0)
private_address_check (0.5.0)
private_address_check (0.6.0)
pry (0.16.0)
coderay (~> 1.1)
method_source (~> 1.0)
@@ -603,23 +603,24 @@ GEM
psych (5.3.1)
date
stringio
public_suffix (7.0.2)
puffing-billy (4.0.2)
public_suffix (7.0.5)
puffing-billy (4.0.4)
addressable (~> 2.5)
cgi
em-http-request (~> 1.1, >= 1.1.0)
em-synchrony
eventmachine (~> 1.2)
eventmachine_httpserver
http_parser.rb (~> 0.8.0)
multi_json
puma (6.5.0)
puma (7.2.0)
nio4r (~> 2.0)
query_count (1.1.1)
activerecord (>= 4.2)
railties (>= 4.2)
raabro (1.4.0)
racc (1.8.1)
rack (2.2.22)
rack (2.2.23)
rack-mini-profiler (2.3.4)
rack (>= 1.2.0)
rack-oauth2 (2.3.0)
@@ -670,8 +671,8 @@ GEM
activesupport (>= 4.2)
choice (~> 0.2.0)
ruby-graphviz (~> 1.2)
rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
rails-html-sanitizer (1.7.0)
loofah (~> 2.25)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
rails-i18n (7.0.10)
i18n (>= 0.7, < 2)
@@ -695,19 +696,13 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
rdf (3.3.4)
rdf (3.3.1)
bcp47_spec (~> 0.2)
bigdecimal (~> 3.1, >= 3.1.5)
link_header (~> 0.0, >= 0.0.8)
logger (~> 1.5)
ostruct (~> 0.6)
readline (~> 0.0)
rdoc (7.2.0)
erb
psych (>= 4.0.0)
tsort
readline (0.0.4)
reline
redcarpet (3.6.1)
redis (5.4.1)
redis-client (>= 0.22.0)
@@ -857,6 +852,9 @@ GEM
spring (>= 0.9.1)
spring-commands-rubocop (0.4.0)
spring (>= 1.0)
spring-watcher-listen (2.1.0)
listen (>= 2.7, < 4.0)
spring (>= 4)
sprockets (3.7.5)
base64
concurrent-ruby (~> 1.0)
@@ -893,25 +891,24 @@ GEM
faraday (~> 2.0)
faraday-follow_redirects
sysexits (1.2.0)
taler (0.2.0)
taler (0.3.0)
temple (0.10.4)
terminal-table (4.0.0)
unicode-display_width (>= 1.1.1, < 4)
thor (1.5.0)
thread-local (1.1.0)
tilt (2.7.0)
timeout (0.6.0)
timeout (0.6.1)
tsort (0.2.0)
ttfunk (1.8.0)
bigdecimal (~> 3.1)
turbo-rails (2.0.20)
ttfunk (1.7.0)
turbo-rails (2.0.23)
actionpack (>= 7.1.0)
railties (>= 7.1.0)
turbo_power (0.7.0)
turbo-rails (>= 1.3.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
undercover (0.8.3)
undercover (0.8.4)
base64
bigdecimal
imagen (>= 0.2.0)
@@ -924,19 +921,18 @@ GEM
unicode-emoji (4.2.0)
uniform_notifier (1.18.0)
uri (1.1.1)
valid_email2 (5.2.3)
activemodel (>= 3.2)
valid_email2 (7.0.15)
activemodel (>= 6.0)
mail (~> 2.5)
validate_url (1.0.15)
activemodel (>= 3.0.0)
public_suffix
validates_lengths_from_database (0.8.0)
activerecord (>= 4)
vcr (6.3.1)
base64
view_component (4.1.1)
actionview (>= 7.1.0, < 8.2)
activesupport (>= 7.1.0, < 8.2)
vcr (6.4.0)
view_component (4.5.0)
actionview (>= 7.1.0)
activesupport (>= 7.1.0)
concurrent-ruby (~> 1)
view_component_reflex (3.1.14.pre9)
rails (>= 5.2, < 8.0)
@@ -955,7 +951,7 @@ GEM
activesupport
faraday (~> 2.0)
faraday-follow_redirects
webmock (3.26.1)
webmock (3.26.2)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
@@ -964,13 +960,15 @@ GEM
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
whenever (1.1.0)
chronic (>= 0.6.3)
wkhtmltopdf-binary (0.12.6.10)
xml-simple (1.1.8)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.7.4)
zeitwerk (2.7.5)
GEM
remote: https://rubygems.org/
specs:
wkhtmltopdf-binary (0.12.6.10)
PLATFORMS
ruby
@@ -1010,7 +1008,6 @@ DEPENDENCIES
devise
devise-encryptable
devise-i18n
devise-token_authenticatable
dfc_provider!
digest
dotenv
@@ -1101,6 +1098,7 @@ DEPENDENCIES
spring
spring-commands-rspec
spring-commands-rubocop
spring-watcher-listen
sprockets (~> 3.7)
state_machines-activerecord
stimulus_reflex
@@ -1119,9 +1117,353 @@ DEPENDENCIES
web!
web-console
webmock
whenever
wicked_pdf!
wkhtmltopdf-binary
wkhtmltopdf-binary!
CHECKSUMS
Ascii85 (2.0.1) sha256=15cb5d941808543cbb9e7e6aea3c8ec3877f154c3461e8b3673e97f7ecedbe5a
actioncable (7.1.6) sha256=ad428d5f0a810452160820ae3cf3d9d68d8f59e7c76de3bd1f1de2a5ad03c3da
actionmailbox (7.1.6) sha256=ded958ad8ec147a5f14555833541f07063af188777b09b50cfeeaa623bc2f731
actionmailer (7.1.6) sha256=b07f6420ec66bd299a9da5a35c075849fbd5504e82793301b0c275fa4211d273
actionpack (7.1.6) sha256=3fa42da36fdcfc3690a711ed35ac5d527b87d3d676f8d111238aa399151203eb
actionpack-action_caching (1.2.2) sha256=2da245520de40dda6b9bed2151dfed1e68644cf22ca23239966d62d834faaaaf
actiontext (7.1.6) sha256=79d657422dd67cc8cb46866a7bec9d89ec8699f7fa5647c0eab3472dc0297e66
actionview (7.1.6) sha256=11147d81f90465ae062b2a77805c6f8f446e044e309c51bd9449bdbd43edf566
active_model_serializers (0.8.4) sha256=7350e3d3b6a5946bbec033241d908013cc85ff4d584230e6aa074225547c754c
active_storage_validations (3.0.4) sha256=134ba51d5166cd419311fe1510d7eb64af6996e7041d8d56c26a2f151abb6522
activejob (7.1.6) sha256=0dd9cd051d494608349dd9223a3e61c3933250db77e35ab6617c26c1d52dccbb
activemerchant (1.137.0) sha256=fdf5e33f5c94d1981bd632d72e282c0a5afaf06bac6df3f933c08a95e98bd5ce
activemodel (7.1.6) sha256=f72f510018a560b5969e3ffc88214441ff09eed60b310feba678a597b2a2e721
activerecord (7.1.6) sha256=1aa298cd7fc97ed8639ebb05a46bd17243a1218d89945bdc2bac1e61e673f079
activerecord-import (2.2.0) sha256=f8ca99b196e50775723d1f1d192c379f656378dc9f5628240992a0d78807fa4b
activerecord-postgresql-adapter (0.0.1) sha256=b42b23d8e94f32b32e9a5f5cb4789735140393e928546b328d48683b6b68aef1
activerecord-session_store (2.2.0) sha256=65918054573683bf4f87af89e765e1fece14c9d71cfac1f11abe4687c96e2743
activestorage (7.1.6) sha256=2f1acb8e6592ba783d9cbc3da93ac4477d441dffc5d533ceccbbfab39f4bf398
activesupport (7.1.6) sha256=7f12140a813b1c4922a322663e547129aef1840fc512fa262378f6d7e7fd3a7c
acts-as-taggable-on (13.0.0) sha256=dca776c6ddebc458d175b57554ad692488e283f27047117e01ed871f1cba6135
acts_as_list (1.0.4) sha256=5516558f4058b369191e3cb9af0428d1c75f8e98f886b218b3ad10960a14e28a
addressable (2.8.9) sha256=cc154fcbe689711808a43601dee7b980238ce54368d23e127421753e46895485
aes_key_wrap (1.1.0) sha256=b935f4756b37375895db45669e79dfcdc0f7901e12d4e08974d5540c8e0776a5
afm (1.0.0) sha256=5bd4d6f6241e7014ef090985ec6f4c3e9745f6de0828ddd58bc1efdd138f4545
angular-rails-templates (1.4.0) sha256=1eaf00a796eaeca9574acdc1adc3c4f005d004c3d938003520fa19853236398d
angular_rails_csrf (7.0.2) sha256=b9672752efa7ec1089c864e3bd130b44bd7711471380f3dc179b03d368d31e7f
angularjs-file-upload-rails (2.4.1) sha256=6de1d8a70b0b6ccd5656786bc42d2e949d70d1c126dc6c02d30addc6175a401f
angularjs-rails (1.8.0) sha256=fde5805a84dd760e7af29ceb528391adf7e9ed63f24857b43954a0f7b3847405
arel-helpers (2.17.0) sha256=0af23b8d32c3ef670eda04e6e371ab177ed684f0edaa06aeed57f822bc0acf6d
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
attr_required (1.0.2) sha256=f0ebfc56b35e874f4d0ae799066dbc1f81efefe2364ca3803dc9ea6a4de6cb99
aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b
aws-partitions (1.1233.0) sha256=928d3486082db11659397eb4c957f41e33fac8848bf87eb42fd921bbb96213c2
aws-sdk-core (3.244.0) sha256=3e458c078b0c5bdee95bc370c3a483374b3224cf730c1f9f0faf849a5d9a18ea
aws-sdk-kms (1.123.0) sha256=d405f37e82f8fa32045ca8980be266c0b45b37aaf2012afe0254321a1e811f20
aws-sdk-s3 (1.217.0) sha256=6ea709272c666888b14e9c62345abd9a6a967759ae13667c28f01fde6823c24b
aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
bcp47_spec (0.2.1) sha256=3fd62edf96c126bd9624e4319ac74082a966081859d1ee0ef3c3041640a37810
bcrypt (3.1.22) sha256=1f0072e88c2d705d94aff7f2c5cb02eb3f1ec4b8368671e19112527489f29032
benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
bigdecimal (4.1.0) sha256=6dc07767aa3dc456ccd48e7ae70a07b474e9afd7c5bc576f80bd6da5c8dd6cae
bindata (2.5.1) sha256=53186a1ec2da943d4cb413583d680644eb810aacbf8902497aac8f191fad9e58
bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e
bootsnap (1.23.0) sha256=c1254f458d58558b58be0f8eb8f6eec2821456785b7cdd1e16248e2020d3f214
bugsnag (6.29.0) sha256=35ebdcfa2e12f1147ed353dbb7bdfa97e93d363afde2fcd7d27c3b5410d9a9e7
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
bullet (8.1.0) sha256=604b7e2636ec2137dcab3ba61a56248c39a0004a0c9405d58bad0686d23b98ff
cable_ready (5.0.6) sha256=de1c94beab04b15a47c8794507a0b5d0ce9c0f25edb1b60a7542adc5413ea894
cancancan (1.15.0) sha256=05f540c62143fde51f7ceaba8584f8dc0e34c93e43ab7a6c1a832b4553216b16
capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef
capybara-shadowdom (0.3.0) sha256=956b57c90c91c48fd45797d806cbbb40b353ad247e8fb68c125c9d579529bfa5
catalog (0.0.1)
caxlsx (4.0.0) sha256=a93a1c23a076caed4ddc4e944d66d57439b817c58e44f95df92e4db982524cc9
cgi (0.5.1) sha256=e93fcafc69b8a934fe1e6146121fa35430efa8b4a4047c4893764067036f18e9
childprocess (5.0.0) sha256=0746b7ab1d6c68156e64a3767631d7124121516192c0492929a7f0af7310d835
choice (0.2.0) sha256=a19617f7dfd4921b38a85d0616446620de685a113ec6d1ecc85bdb67bf38c974
coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
coffee-rails (5.0.0) sha256=5daaa1ba51fd4907c98a333b6a9e7c1a99b1fff57fcef999b6c62d813cb91a9c
coffee-script (2.4.1) sha256=82fe281e11b93c8117b98c5ea8063e71741870f1c4fbb27177d7d6333dd38765
coffee-script-source (1.12.2) sha256=e12b16fd8927fbbf8b87cb2e9a85a6cf457c6881cc7ff8b1af15b31f70da07a4
combine_pdf (1.0.31) sha256=f0aaa687dba78d1f9b1d57622db6bdaff018480313b9dae05145ed8ca830f0bd
concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
connection_pool (2.5.5) sha256=e54ff92855753df1fd7c59fa04a398833355f27dd14c074f8c83a05f72a716ad
cookiejar (0.3.4) sha256=11b16acfc4baf7a0f463c21a6212005e04e25f5554d4d9f24d97f3492dfda0df
crack (1.0.1) sha256=ff4a10390cd31d66440b7524eb1841874db86201d5b70032028553130b6d4c7e
crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
css_parser (1.21.1) sha256=6cfd3ffc0a97333b39d2b1b49c95397b05e0e3b684d68f77ec471ba4ec2ef7c7
csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f
cuprite (0.17) sha256=b140d5dc70d08b97ad54bcf45cd95d0bd430e291e9dffe76fff851fddd57c12b
database_cleaner (2.1.0) sha256=1dcba26e3b1576da692fc6bac10136a4744da5bcc293d248aae19640c65d89cd
database_cleaner-active_record (2.2.2) sha256=88296b9f3088c31f7c0d4fcec10f68e4b71c96698043916de59b04debec10388
database_cleaner-core (2.0.1) sha256=8646574c32162e59ed7b5258a97a208d3c44551b854e510994f24683865d846c
datafoodconsortium-connector (1.2.0) sha256=00d5f559d6e3955708dcbe8912ef0899eae03929ac4826772c82f6fea0316ee8
date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
db2fog (0.9.2)
debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6
devise (5.0.3) sha256=c4c065051cdc4ace11547b2b7f5c3c4c97d0f1269250f5fe90f614ff78f29546
devise-encryptable (0.2.0) sha256=9860caed9484030c438cfaf05831355c16c6a9612dcd1e12e84805850f7d09b6
devise-i18n (1.16.0) sha256=a33306f90f317cfe92753a000064e3ba9dec3cab2d5d01ef40d30f4b6e24e753
dfc_provider (0.0.1)
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
digest (3.2.1) sha256=ab3312b4e272d7d5dc41c564c86a25861a1f34ac5153374199a0b74861395947
docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
dotenv (3.2.0) sha256=e375b83121ea7ca4ce20f214740076129ab8514cd81378161f11c03853fe619d
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
em-http-request (1.1.7) sha256=16fbc72b2a6e20c804c564ac5d12e98668c6fcef8c3b1dd2387dff505f2efdab
em-socksify (0.3.3) sha256=7d8d08a7a8acc1263173433a6b5540edd80a8a36e35a066b650c929a3a3974ed
em-synchrony (1.0.6) sha256=6e7470a684d9bbc00d61d552911b65711540bd89e95c157156f5aacdd6f306ca
email_validator (2.2.4) sha256=5ab238095bec7aef9389f230e9e0c64c5081cdf91f19d6c5cecee0a93af20604
erb (6.0.2) sha256=9fe6264d44f79422c87490a1558479bd0e7dad4dd0e317656e67ea3077b5242b
erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
et-orbi (1.4.0) sha256=6c7e3c90779821f9e3b324c5e96fda9767f72995d6ae435b96678a4f3e2de8bc
eventmachine (1.2.7) sha256=994016e42aa041477ba9cff45cbe50de2047f25dd418eba003e84f0d16560972
eventmachine_httpserver (0.2.1) sha256=5db5e8a23754204d43592e5fcc2160457c57c870babe6307c4e61fc95019b809
excon (0.81.0) sha256=e7c78b2114c42e06024fb9812fc5a6b9a984ed973f585c09c67f5ae6e7b6e5a5
execjs (2.7.0) sha256=e1fae0c5c831934c47d92363b4ea66ef2951350ab91b5d8d3174342b9c2ee5fb
factory_bot (6.2.0) sha256=d181902cdda531cf6cef036001b3a700a7b5e04bac63976864530120b2ac7d13
factory_bot_rails (6.2.0) sha256=278b969666b078e76e1c972c501da9b1fac15e5b0ff328cc7ce400366164d0a1
faraday (2.14.1) sha256=a43cceedc1e39d188f4d2cdd360a8aaa6a11da0c407052e426ba8d3fb42ef61c
faraday-follow_redirects (0.4.0) sha256=d3fa1118ab1350e24035a272b4cff64948643bb7182846db89acaf87abadd5d9
faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c
ferrum (0.17.1) sha256=51d591120fc593e5a13b5d9d6474389f5145bb92a91e36eab147b5d096c8cbe7
ffaker (2.25.0) sha256=e485c5adf8195aac55662875b7f515469bca46d77b60d0e7d08db6861bcbec40
ffi (1.17.3) sha256=0e9f39f7bb3934f77ad6feab49662be77e87eedcdeb2a3f5c0234c2938563d4c
flipper (1.4.1) sha256=05843240fb3093c7037549e34b046b636c765120f22e0a6268212daf44166e4d
flipper-active_record (1.4.0) sha256=a42531d81e399a2272df19fad4420ad60db2514b143a7b470431832ff50d4d8f
flipper-ui (1.4.0) sha256=1d773344249778b3f6f6874f4a0ea3e6bc997957da01e8e5ba813af666ff8fd1
fog-aws (2.0.1) sha256=e3c5fa9cbff08115f5c0bee527f7f0c171604f4980d7ffee33f863b8df5a5303
fog-core (1.45.0) sha256=e3c225fc8f5e7886e790afbc2cf7f459affb91df02d4af7b4ff28f2ee04c8408
fog-json (1.2.0) sha256=dd4f5ab362dbc72b687240bba9d2dd841d5dfe888a285797533f85c03ea548fe
fog-xml (0.1.3) sha256=5604c42649ebb0d8a31bd973aa000c2dd0127f1c1c4c174b69266a2e78e37410
foreman (0.90.0) sha256=ff675e2d47b607ac58714a6d4ac3e1ee8f06f41d8db084531c31961e2c3f117c
formatador (0.2.5) sha256=80821869ddacb79e72870ff4bb1531efacd278c04f2df26bc6b4529ee13582bd
fugit (1.12.1) sha256=5898f478ede9b415f0804e42b8f3fd53f814bd85eebffceebdbc34e1107aaf68
fuubar (2.5.1) sha256=b272a7804b282661c7fab583a3764f92543cb482c365ae39c685cd218fdd4880
geocoder (1.8.6) sha256=e0ca1554b499f466de9b003f7dff70f89a5888761c2ca68ed9f86b6e5e24e74c
globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11
gmaps4rails (2.1.2) sha256=09c3bf095ca8e97d1d6f3b5c9e4dd905d445b0399c5ecfd5cc53e0fafce87c2b
good_migrations (0.3.1) sha256=3f8267c00caa29689823cb8d53cbfb62cd5b0310fe6b088f5ce589243f6f797f
haml (7.2.0) sha256=87fd2b71f7feab1724337b090a7d767f5ab2d42f08c974f3ead673f18cfcd55a
haml_lint (0.72.0) sha256=23acb3f5db1602eb99bccec8009372465321702e1229017cca53272957bfc9c8
hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
hashery (2.1.2) sha256=d239cc2310401903f6b79d458c2bbef5bf74c46f3f974ae9c1061fb74a404862
hashie (5.1.0) sha256=c266471896f323c446ea8207f8ffac985d2718df0a0ba98651a3057096ca3870
highline (3.1.2) sha256=67cbd34d19f6ef11a7ee1d82ffab5d36dfd5b3be861f450fc1716c7125f4bb4a
htmlentities (4.4.2) sha256=bbafbdf69f2eca9262be4efef7e43e6a1de54c95eb600f26984f71d2fe96c5c3
http_parser.rb (0.8.1) sha256=9ae8df145b39aa5398b2f90090d651c67bd8e2ebfe4507c966579f641e11097a
i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
i18n-js (3.9.2) sha256=34c20bf3183afea475a372382ad6258be073dca5354a4bdab19b01adea3b798e
i18n-tasks (1.1.2) sha256=4dcfba49e52a623f30661cb316cb80d84fbba5cb8c6d88ef5e02545fffa3637a
image_processing (1.14.0) sha256=754cc169c9c262980889bec6bfd325ed1dafad34f85242b5a07b60af004742fb
imagen (0.2.0) sha256=369fe912078877dba92615ebfc6f35a7d833e31f24f47bdd3ad5371a4139e24b
immigrant (0.3.6) sha256=9c154dec2a2cbce62b32967a8b33e1eed58fed6432be3601f67cb88820024e96
invisible_captcha (2.3.0) sha256=309ee5a5e891ecfb732c85b12f1aa9252a648df6f2761b3b41205e824e30ff15
io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
ipaddress (0.8.3) sha256=85640c4f9194c26937afc8c78e3074a8e7c97d5d1210358d1440f01034d006f5
irb (1.17.0) sha256=168c4ddb93d8a361a045c41d92b2952c7a118fa73f23fe14e55609eb7a863aae
jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1
jquery-rails (4.4.0) sha256=b1048e5bf181b94dcac82d28a4696cd79c6200167a024a07f57607ab28aa7036
jquery-ui-rails (4.2.1) sha256=5b349e7066150b16d7a784183f040c083d51af3357937b8564aa0cc8b1cd59bd
json (2.19.2) sha256=e7e1bd318b2c37c4ceee2444841c86539bc462e81f40d134cf97826cb14e83cf
json-canonicalization (1.0.0) sha256=d4848a8cca7534455c6721f2d9fc9e5e9adca49486864a898810024f67d59446
json-jwt (1.17.0) sha256=6ff99026b4c54281a9431179f76ceb81faa14772d710ef6169785199caadc4cc
json-ld (3.3.2) sha256=b9531893bf5bdc01db428e96953845a23adb1097125ce918ae0f97c4a6e1ab27
json-schema (4.1.1) sha256=89a8399745a710c2c7be3ff9564f67a0ae982c82f7590a95ab9cebe374fa2d49
json_spec (1.1.5) sha256=7a77b97a92c787e2aa3fbc4a1239afc3342c781151dc98cfb81461b3b7cad10f
jsonapi-serializer (2.2.0) sha256=f8141ac6f0c1e17e8513df68f8341afe2d7bffc285841d7090bc07f07efb0029
jwt (2.10.2) sha256=31e1ee46f7359883d5e622446969fe9c118c3da87a0b1dca765ce269c3a0c4f4
knapsack_pro (9.2.3) sha256=354b402cb08709b98f9ffa32d69e989f3bdd829a6c989649d60a9a0256421eed
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
launchy (3.0.0) sha256=4abcdab659689550ceca6ec0630cd9efd9940b51dc14cb4ebceee8f7aedc791b
letter_opener (1.10.0) sha256=2ff33f2e3b5c3c26d1959be54b395c086ca6d44826e8bf41a14ff96fdf1bdbb2
link_header (0.0.8) sha256=15c65ce43b29f739b30d05e5f25c22c23797e89cf6f905dbb595fb4c70cb55f9
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
listen (3.10.0) sha256=c6e182db62143aeccc2e1960033bebe7445309c7272061979bb098d03760c9d2
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
loofah (2.25.1) sha256=d436c73dbd0c1147b16c4a41db097942d217303e1f7728704b37e4df9f6d2e04
mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941
marcel (1.1.0) sha256=fdcfcfa33cc52e93c4308d40e4090a5d4ea279e160a7f6af988260fa970e0bee
matrix (0.4.3) sha256=a0d5ab7ddcc1973ff690ab361b67f359acbb16958d1dc072b8b956a286564c5b
method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
mime-types (3.7.0) sha256=dcebf61c246f08e15a4de34e386ebe8233791e868564a470c3fe77c00eed5e56
mime-types-data (3.2025.0924) sha256=f276bca15e59f35767cbcf2bc10e023e9200b30bd6a572c1daf7f4cc24994728
mimemagic (0.4.3) sha256=08ac2d41e2d7cd967b00843dea8c189f91939e3f47732204944908f1ab7ecc9f
mini_magick (5.3.1) sha256=29395dfd76badcabb6403ee5aff6f681e867074f8f28ce08d78661e9e4a351c4
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289
minitest (6.0.2) sha256=db6e57956f6ecc6134683b4c87467d6dd792323c7f0eea7b93f66bd284adbc3d
monetize (1.13.0) sha256=0c1f8ae28aa21bbf1a6d014138d9bb0a5ce756c1a99b8b7f7d409c258b01d3b3
money (6.16.0) sha256=cf476f5f19188e247ec20f6509cff64dc35d395ee018bad799b1a9ea8bd4754a
msgpack (1.8.0) sha256=e64ce0212000d016809f5048b48eb3a65ffb169db22238fb4b72472fecb2d732
multi_json (1.19.1) sha256=7aefeff8f2c854bf739931a238e4aea64592845e0c0395c8a7d2eea7fdd631b7
multi_xml (0.6.0) sha256=d24393cf958adb226db884b976b007914a89c53ad88718e25679d7008823ad52
mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
net-imap (0.6.3) sha256=9bab75f876596d09ee7bf911a291da478e0cd6badc54dfb82874855ccc82f2ad
net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
newrelic_rpm (9.24.0) sha256=70fb09fe684d97f161d27e430ab4baeab6c84dc73d07402130c653fe808eadb6
nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
nokogiri (1.19.2) sha256=38fdd8b59db3d5ea9e7dfb14702e882b9bf819198d5bf976f17ebce12c481756
nokogiri-html5-inference (0.3.0) sha256=04f078ad36843da11973773dbdd034672eb397373b0766ab11679e4a7b86c01e
oauth2 (1.4.11) sha256=6739fcc8872bc94f476b0cae3e8bd78a56d8364b1b79b0757794c25e152d5c10
observer (0.1.2) sha256=d8a3107131ba661138d748e7be3dbafc0d82e732fffba9fccb3d7829880950ac
omniauth (2.1.4) sha256=42a05b0496f0d22e1dd85d42aaf602f064e36bb47a6826a27ab55e5ba608763c
omniauth-rails_csrf_protection (2.0.1) sha256=c6e3204d7e3925bb537cb52d50fdfc9f05293f1a9d87c5d4ab4ca3a39ba8c32d
omniauth_openid_connect (0.8.0) sha256=1f2f3890386e2a742221cee0d2e903b78d874e6fab9ea3bfa31c1462f4793d25
openid_connect (2.3.1) sha256=5d808380cff80d78e3d3d54cfaebe2d6461d835c674faa29e2314a402c1b2182
order_management (0.0.1)
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
ostruct (0.6.1) sha256=09a3fb7ecc1fa4039f25418cc05ae9c82bd520472c5c6a6f515f03e4988cb817
package_json (0.2.0) sha256=92c022dc2999a9e57e835f1ec1a84c9a6c2be08e0fd68886c6f86d94101b6b4d
pagy (9.4.0) sha256=db3f2e043f684155f18f78be62a81e8d033e39b9f97b1e1a8d12ad38d7bce738
paper_trail (17.0.0) sha256=1c2842061d3874ca7015908e821e2aa14f9b982af2acb2a7974713bf79021c85
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
paranoia (2.6.4) sha256=9d88a6589b2418eaa136ec491e5995f4f31061d7301acec14f4f0f1827b86250
parser (3.3.10.2) sha256=6f60c84aa4bdcedb6d1a2434b738fe8a8136807b6adc8f7f53b97da9bc4e9357
paypal-sdk-core (0.3.4) sha256=142cf0a5f375344acb812da47ec4906b07eb7b3a4121cb45da561bdbeff4587e
paypal-sdk-merchant (1.117.2) sha256=c78d424ab767aa7c65d023521e2d0cc80a01ef700c0e548a6b7d147d2cc40f6d
pdf-reader (2.15.1) sha256=18c6a986a84a3117fa49f4279fc2de51f5d2399b71833df5d2bccd595c7068ce
pg (1.6.3) sha256=1388d0563e13d2758c1089e35e973a3249e955c659592d10e5b77c468f628a99
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
private_address_check (0.6.0) sha256=94ac6edefb857f7e2288695498b463aac342fb9701dad326f6555375b0c8dbef
pry (0.16.0) sha256=d76c69065698ed1f85e717bd33d7942c38a50868f6b0673c636192b3d1b6054e
psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
puffing-billy (4.0.4) sha256=87015b0c41e0722b2171a0c5aa8130fd3f58aa1c016a1dc6dc569b2028aa846f
puma (7.2.0) sha256=bf8ef4ab514a4e6d4554cb4326b2004eba5036ae05cf765cfe51aba9706a72a8
query_count (1.1.1) sha256=97204a71ae22d7bda9165ebb85f7e967ef86b3b07d5c966b42e5b22d6a41b181
raabro (1.4.0) sha256=d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
rack (2.2.23) sha256=a8fe9d7e07064770b8ec123663fded8a59ef7e2b6db5cda7173d45a5718ab69c
rack-mini-profiler (2.3.4) sha256=2c43bb1d0091c23e3efba054de5ebfb9c40a238f37f2d24dd4df7cf70d0bee3c
rack-oauth2 (2.3.0) sha256=43e02cf73f13886a0a06499603caeec58aeba6eae1fefc4977c9678b7652c632
rack-protection (3.2.0) sha256=3c74ba7fc59066453d61af9bcba5b6fe7a9b3dab6f445418d3b391d5ea8efbff
rack-proxy (0.7.7) sha256=446a4b57001022145d5c3ba73b775f66a2260eaf7420c6907483141900395c8a
rack-rewrite (1.5.1) sha256=682079619b15e4a8084377ce12887b2d14cdafff6b23120db3dca4ddc2e13456
rack-session (1.0.2) sha256=a02115e5420b4de036839b9811e3f7967d73446a554b42aa45106af335851d76
rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
rack-timeout (0.7.0) sha256=757337e9793cca999bb73a61fe2a7d4280aa9eefbaf787ce3b98d860749c87d9
rackup (1.0.1) sha256=ba86604a28989fe1043bff20d819b360944ca08156406812dca6742b24b3c249
rails (7.1.6) sha256=9a0a335e510de3daad7542cd791af3d8ff710c644e1da17ed12e96d2f28a7470
rails-controller-testing (1.0.5) sha256=741448db59366073e86fc965ba403f881c636b79a2c39a48d0486f2607182e94
rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
rails-erd (1.7.2) sha256=0b17d0fba25d319d8da8af7a3e5e2149d02d6187cc7351e8be43423f07c48bcd
rails-html-sanitizer (1.7.0) sha256=28b145cceaf9cc214a9874feaa183c3acba036c9592b19886e0e45efc62b1e89
rails-i18n (7.0.10) sha256=efae16e0ac28c0f42e98555c8db1327d69ab02058c8b535e0933cb106dd931ca
railties (7.1.6) sha256=2a10e97f2eaca66d11f0fef4b1f4d826e6ee28d4cf01ff16624420dd45e7de1c
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
ransack (4.1.1) sha256=01db200ede29be9f147a2c433eb0005b36df24bc7f8b624a6eeea62d50788901
rb-fsevent (0.11.2) sha256=43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe
rb-inotify (0.11.1) sha256=a0a700441239b0ff18eb65e3866236cd78613d6b9f78fea1f9ac47a85e47be6e
rdf (3.3.1) sha256=dda6a2c95198915fc63d66ee270e35d4a76d431720747a2cf97ecd92062fa150
rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
redcarpet (3.6.1) sha256=d444910e6aa55480c6bcdc0cdb057626e8a32c054c29e793fa642ba2f155f445
redis (5.4.1) sha256=b5e675b57ad22b15c9bcc765d5ac26f60b675408af916d31527af9bd5a81faae
redis-client (0.26.4) sha256=3ad70beff5da2653e02dfeae996e7d8d7147a558da12b16b2282ad345e4c7120
regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
request_store (1.7.0) sha256=e1b75d5346a315f452242a68c937ef8e48b215b9453a77a6c0acdca2934c88cb
responders (3.2.0) sha256=89c2d6ac0ae16f6458a11524cae4a8efdceba1a3baea164d28ee9046bd3df55a
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
roadie (5.2.1) sha256=e4a4f61ce792bd91b228b6844b4bad6b160cdc1b8df86c81a8b983082a5001d6
roadie-rails (3.4.0) sha256=f7b02bd3b74051eaa51ebb636049c4c9fc54cf2a68234eafc5a5fb78ad1f9aa9
rodf (1.2.0) sha256=0c10b48c57033473f7bfca8d825e04296b13642cfaacca470121bbd28d1e2991
roo (2.10.1) sha256=cbb43bc955f9c110e74b721c835fb9bd3515b63af88ec709ac87fbf30f8be70e
rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
rspec-core (3.13.5) sha256=ab3f682897c6131c67f9a17cfee5022a597f283aebe654d329a565f9937a4fa3
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
rspec-mocks (3.13.5) sha256=e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81
rspec-rails (7.1.1) sha256=e15dccabed211e2fd92f21330c819adcbeb1591c1d66c580d8f2d8288557e331
rspec-retry (0.6.2) sha256=6101ba23a38809811ae3484acde4ab481c54d846ac66d5037ccb40131a60d858
rspec-sql (0.0.3) sha256=132a5e1ca722b3b0d5f7ad5ae6e644fdb4a1e0a4cf7ce020a5fd89ddc37766b4
rspec-support (3.13.6) sha256=2e8de3702427eab064c9352fe74488cc12a1bfae887ad8b91cba480ec9f8afb2
rswag (2.17.0) sha256=aba267bd205f0f4f8db53277182897f125890338731971641add050f7911414c
rswag-api (2.17.0) sha256=728b336b65168ab8ab6024b0e5d267b485c22ccdeb9dfbfb6ec3bac423545a13
rswag-specs (2.17.0) sha256=a3b2bdf6df89f8741fe4a4ee47ceb1e77dc13e1c96bbe07352117d6e61afa9e3
rswag-ui (2.17.0) sha256=5f707b9b5e8171ddf9f519f6e401e79e419bd1d07387508603e76124f2443212
rubocop (1.84.2) sha256=5692cea54168f3dc8cb79a6fe95c5424b7ea893c707ad7a4307b0585e88dbf5f
rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd
rubocop-capybara (2.22.1) sha256=ced88caef23efea53f46e098ff352f8fc1068c649606ca75cb74650970f51c0c
rubocop-factory_bot (2.28.0) sha256=4b17fc02124444173317e131759d195b0d762844a71a29fe8139c1105d92f0cb
rubocop-rails (2.34.3) sha256=10d37989024865ecda8199f311f3faca990143fbac967de943f88aca11eb9ad2
rubocop-rspec (3.9.0) sha256=8fa70a3619408237d789aeecfb9beef40576acc855173e60939d63332fdb55e2
rubocop-rspec_rails (2.32.0) sha256=4a0d641c72f6ebb957534f539d9d0a62c47abd8ce0d0aeee1ef4701e892a9100
ruby-graphviz (1.2.5) sha256=1c2bb44e3f6da9e2b829f5e7fd8d75a521485fb6b4d1fc66ff0f93f906121504
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
ruby-rc4 (0.1.5) sha256=00cc40a39d20b53f5459e7ea006a92cf584e9bc275e2a6f7aa1515510e896c03
ruby-vips (2.2.5) sha256=f3c547a172c36ba26b8614c809f5823bc6199623ec6204ec7c3bce29037f7758
rubyzip (2.4.1) sha256=8577c88edc1fde8935eb91064c5cb1aef9ad5494b940cf19c775ee833e075615
rufus-scheduler (3.9.2) sha256=55fa9e4db0ff69d7f38c804f17baba0c9bce5cba39984ae3c5cf6c039d1323b9
rugged (1.9.0) sha256=7faaa912c5888d6e348d20fa31209b6409f1574346b1b80e309dbc7e8d63efac
sanitize (7.0.0) sha256=269d1b9d7326e69307723af5643ec032ff86ad616e72a3b36d301ac75a273984
sd_notify (0.1.1) sha256=cbc7ac6caa7cedd26b30a72b5eeb6f36050dc0752df263452ea24fb5a4ad3131
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
select2-rails (3.4.9)
semantic_range (3.1.0) sha256=9fc01ee40f2e5f81042e95d421837f688177dd603753b5eab41ff9bba50a34a1
shakapacker (8.4.0) sha256=df234ed4a9173407adc288df0d7f156c485ada9214b23d8f0e2c734f11c1aca8
shoulda-matchers (7.0.1) sha256=b4bfd8744c10e0a36c8ac1a687f921ee7e25ed529e50488d61b79a8688749c77
sidekiq (7.3.10) sha256=781eb4f65ef36042534ad73d72f211283afb7fee82eec786ada4ed1972ef8e3c
sidekiq-scheduler (6.0.1) sha256=e1fc04e851a3e2d9896bc6ab00f03d790fef8923bb56915e5b141804bca34062
simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
spreadsheet_architect (5.1.0) sha256=5000ae41a0a40270b9334da02cd9f5a6ca6aec1e867348eaa2263913860d9159
spring (4.4.2) sha256=22f61bacd8dc8595cedcdc738de46d7fc18be4d7a770986760344c924f485ce7
spring-commands-rspec (1.0.4) sha256=6202e54fa4767452e3641461a83347645af478bf45dddcca9737b43af0dd1a2c
spring-commands-rubocop (0.4.0) sha256=3e677a2c8a27ae8a986f04bfb69e66d5d55b017541e8be93bf0dc48a7f5690c1
spring-watcher-listen (2.1.0) sha256=e958bcd956d1026eb95d16b2ef0e241d1ca35a754628bd45040e3d9954a61949
sprockets (3.7.5) sha256=72c20f256548f8a37fe7db41d96be86c3262fddaf4ebe9d69ec8317394fed383
sprockets-rails (3.5.2) sha256=a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e
state_machines (0.100.4) sha256=dd4e555ebb061569dd8fe18a5f39b51d10be6306b89a0c315a9697671d752565
state_machines-activemodel (0.31.0) sha256=82465856736fa6e3ddd76b8dba9e17c82d0823027ec1fbc18432f47817be4500
state_machines-activerecord (0.31.0) sha256=c8cc334ba4ea202a2feaaa42aaa43d360e5e111c1aff1e2fa156fe232ca31181
stimulus_reflex (3.5.5) sha256=cf08eddccc75c4b8f61446da73972b8bd9304f173f4881f500202d5c3f70e3c9
stimulus_reflex_testing (0.3.1)
stringex (2.8.6) sha256=c7b382d2b2a47a1e1646f256df201c48d487d6296fbb289d76802f67f5e929c4
stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
stripe (15.5.0) sha256=e61cac450194df863697039559e314bad41c1b0e10c627039c28019349a570d0
swd (2.0.3) sha256=4cdbe2a4246c19f093fce22e967ec3ebdd4657d37673672e621bf0c7eb770655
sysexits (1.2.0) sha256=598241c4ae57baa403c125182dfdcc0d1ac4c0fb606dd47fbed57e4aaf795662
taler (0.3.0) sha256=905da226ad420eda7ebe0e57b91086efac51a0f11205aaab671168534e02a559
temple (0.10.4) sha256=b7a1e94b6f09038ab0b6e4fe0126996055da2c38bec53a8a336f075748fff72c
terminal-table (4.0.0) sha256=f504793203f8251b2ea7c7068333053f0beeea26093ec9962e62ea79f94301d2
thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
thread-local (1.1.0) sha256=2fb568d31f0ef278063f45a3923c5ed62ee5c33da8134103bc7d2ecdb87bd2e7
tilt (2.7.0) sha256=0d5b9ba69f6a36490c64b0eee9f6e9aad517e20dcc848800a06eb116f08c6ab3
timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
ttfunk (1.7.0) sha256=2370ba484b1891c70bdcafd3448cfd82a32dd794802d81d720a64c15d3ef2a96
turbo-rails (2.0.23) sha256=ee0d90733aafff056cf51ff11e803d65e43cae258cc55f6492020ec1f9f9315f
turbo_power (0.7.0) sha256=ad95d147e0fa761d0023ad9ca00528c7b7ddf6bba8ca2e23755d5b21b290d967
tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
undercover (0.8.4) sha256=99a6df93a6bb2c8d06e701df5fdb3be9411f50eae3f9f9e1d67672176258d09c
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
uniform_notifier (1.18.0) sha256=4787785556f66f6418486da0f1d78b3239aaff98e2e7938fb05e2062b0ffce9d
uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
valid_email2 (7.0.15) sha256=f3fe1c4b87b9a405bb2e8de060b736cce168e476e4c72725c5d05e11321ff4a1
validate_url (1.0.15) sha256=72fe164c0713d63a9970bd6700bea948babbfbdcec392f2342b6704042f57451
validates_lengths_from_database (0.8.0) sha256=a4cfbbd49673da331c4f098ade90893dde531cae7ca37da41b8f79e15bc0538b
vcr (6.4.0) sha256=077ac92cc16efc5904eb90492a18153b5e6ca5398046d8a249a7c96a9ea24ae6
view_component (4.5.0) sha256=0d951360d830752da4d1daa5f6cb643f17c30f295fb779fd4de90a051537d9c1
view_component_reflex (3.1.14.pre9) sha256=d1f9e61fdeb2f949fe292aba263b4c05a81e531b0ce2cd58297ad55353bbbaa7
virtual_assembly-semantizer (1.1.1) sha256=a8ce46cd525ce7875a07da7f513c7045cb9c2ee6c32980f7245ffd0d718ba94f
warden (1.2.9) sha256=46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0
web (0.0.1)
web-console (4.2.1) sha256=e7bcf37a10ea2b4ec4281649d1cee461b32232d0a447e82c786e6841fd22fe20
webfinger (2.1.3) sha256=567a52bde77fb38ca6b67e55db755f988766ec4651c1d24916a65aa70540695c
webmock (3.26.2) sha256=774556f2ea6371846cca68c01769b2eac0d134492d21f6d0ab5dd643965a4c90
webrick (1.9.2) sha256=beb4a15fc474defed24a3bda4ffd88a490d517c9e4e6118c3edce59e45864131
websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
wicked_pdf (2.8.1)
wkhtmltopdf-binary (0.12.6.10) sha256=863060a4559253d20f9a73c76106bd972a443aec9fdd5013b45e1d1a9a44f352
xml-simple (1.1.8) sha256=3b53afc963c0b952892dcfc0d30de24bda2cef3c861b37e8c286c6c5e0ab97ba
xpath (3.2.0) sha256=6dfda79d91bb3b949b947ecc5919f042ef2f399b904013eb3ef6d20dd3a4082e
zeitwerk (2.7.5) sha256=d8da92128c09ea6ec62c949011b00ed4a20242b255293dd66bf41545398f73dd
RUBY VERSION
ruby 3.4.8p72

View File

@@ -4,16 +4,12 @@ angular.module("admin.enterprises")
$scope.Enterprises = Enterprises
$scope.navClear = NavigationCheck.clear
$scope.menu = SideMenu
$scope.newManager = { id: null, email: (t('add_manager')) }
$scope.StatusMessage = StatusMessage
$scope.RequestMonitor = RequestMonitor
$scope.$watch 'enterprise_form.$dirty', (newValue) ->
StatusMessage.display 'notice', t('admin.unsaved_changes') if newValue
$scope.$watch 'newManager', (newValue) ->
$scope.addManager($scope.newManager) if newValue
$scope.setFormDirty = ->
$scope.$apply ->
$scope.enterprise_form.$setDirty()
@@ -35,26 +31,6 @@ angular.module("admin.enterprises")
# Register the NavigationCheck callback
NavigationCheck.register(enterpriseNavCallback)
$scope.removeManager = (manager) ->
if manager.id?
if manager.id == $scope.Enterprise.owner.id or manager.id == parseInt($scope.receivesNotifications)
return
for i, user of $scope.Enterprise.users when user.id == manager.id
$scope.Enterprise.users.splice i, 1
$scope.enterprise_form?.$setDirty()
$scope.addManager = (manager) ->
if manager.id? and angular.isNumber(manager.id) and manager.email?
manager =
id: manager.id
email: manager.email
confirmed: manager.confirmed
if (user for user in $scope.Enterprise.users when user.id == manager.id).length == 0
$scope.Enterprise.users.unshift(manager)
$scope.enterprise_form?.$setDirty()
else
alert ("#{manager.email}" + " " + t("is_already_manager"))
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
return unless confirm($scope.translation(warning_message_key))

View File

@@ -3,7 +3,15 @@ angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($
$scope.view = 'incoming'
# NB: weirdly at this next line $scope.order_cycle.id comes out undefined so we use $scope.order_cycle_id instead
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: $scope.order_cycle_id, per_item: true)
$scope.enterprise_fees = null
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: $scope.order_cycle_id, per_item: true) unless EnterpriseFee.loading
# We want to make sure to load the filtered EnterpriseFee when any previous request is finished
# otherwise the enterprise_fees migh get overriden by non filtered ones.
$scope.$watch(( -> EnterpriseFee.loading), (isLoading) =>
$scope.enterprise_fees ||= EnterpriseFee.index(order_cycle_id: $scope.order_cycle_id, per_item: true) unless isLoading
)
$scope.exchangeTotalVariants = (exchange) ->
return unless $scope.enterprises? && $scope.enterprises[exchange.enterprise_id]?

View File

@@ -14,10 +14,14 @@ angular.module('admin.orderCycles').factory('EnterpriseFee', ($resource) ->
EnterpriseFee: EnterpriseFee
enterprise_fees: {}
loaded: false
loading: false
index: (params={}) ->
return if @loading == true
@loading = true
EnterpriseFee.index params, (data) =>
@enterprise_fees = data
@loading = false
@loaded = true
forEnterprise: (enterprise_id) ->

View File

@@ -6,6 +6,7 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
'manage_products'
'edit_profile'
'create_variant_overrides'
'create_linked_variants'
]
constructor: ->
@@ -30,3 +31,4 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
when "manage_products" then t('js.services.manage_products')
when "edit_profile" then t('js.services.edit_profile')
when "create_variant_overrides" then t('js.services.add_products_to_inventory')
when "create_linked_variants" then t('js.services.create_linked_variants')

View File

@@ -1,5 +0,0 @@
angular.module('Darkswarm').controller "HomeCtrl", ($scope) ->
$scope.brandStoryExpanded = false
$scope.toggleBrandStory = ->
$scope.brandStoryExpanded = !$scope.brandStoryExpanded

View File

@@ -9,6 +9,11 @@
padding: 1.2rem;
}
&.big {
max-height: 50em;
overflow: auto;
}
h1,
h2,
h3,

View File

@@ -19,7 +19,9 @@
background-color: white;
box-shadow: $box-shadow;
border-radius: 3px;
width: max-content;
min-width: 80px;
max-width: 110px;
display: none;
z-index: 100;
@@ -27,6 +29,15 @@
display: block;
}
// Fade out so user can see which option was selected
&.selected {
transition:
opacity 0.2s linear,
visibility 0.2s linear;
opacity: 0;
visibility: hidden;
}
& > a {
display: block;
padding: 5px 10px;

View File

@@ -6,6 +6,9 @@ export default class extends Controller {
connect() {
super.connect();
window.addEventListener("click", this.#hideIfClickedOutside);
// Close menu when making a selection
this.contentTarget.addEventListener("click", this.#selected);
}
disconnect() {
@@ -13,17 +16,22 @@ export default class extends Controller {
}
toggle() {
this.contentTarget.classList.toggle("show");
this.#toggleShow();
}
#selected = () => {
this.contentTarget.classList.add("selected");
};
#hideIfClickedOutside = (event) => {
if (this.element.contains(event.target)) {
return;
}
this.#hide();
this.#toggleShow(false);
};
#hide() {
this.contentTarget.classList.remove("show");
#toggleShow(force = undefined) {
this.contentTarget.classList.toggle("show", force);
this.contentTarget.classList.remove("selected");
}
}

View File

@@ -0,0 +1,56 @@
# frozen_string_literal: true
module Admin
class AjaxSearchController < Spree::Admin::BaseController
def producers
query = OpenFoodNetwork::Permissions.new(spree_current_user)
.managed_product_enterprises.is_primary_producer.by_name
render json: build_search_response(query)
end
def categories
query = Spree::Taxon.all
render json: build_search_response(query)
end
def tax_categories
query = Spree::TaxCategory.all
render json: build_search_response(query)
end
private
def build_search_response(query)
page = (params[:page] || 1).to_i
per_page = 30
filtered_query = apply_search_filter(query)
total_count = filtered_query.size
items = paginated_items(filtered_query, page, per_page)
results = format_results(items)
{ results: results, pagination: { more: (page * per_page) < total_count } }
end
def apply_search_filter(query)
search_term = params[:q]
return query if search_term.blank?
escaped_search_term = ActiveRecord::Base.sanitize_sql_like(search_term)
pattern = "%#{escaped_search_term}%"
query.where('name ILIKE ?', pattern)
end
def paginated_items(query, page, per_page)
query.order(:name).offset((page - 1) * per_page).limit(per_page).pluck(:name, :id)
end
def format_results(items)
items.map { |label, value| { value:, label: } }
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module Admin
class CustomerAccountTransactionController < Admin::ResourceController
def index
@available_credit = @collection.first&.balance || 0.00
respond_with do |format|
format.turbo_stream {
render :index
}
end
end
# We are using an old version of CanCanCan so I could not get `accessible_by` to work properly,
# so we are doing our own authorization before calling 'accessible_by'
def collection
allowed_customers = OpenFoodNetwork::Permissions.new(spree_current_user)
.managed_enterprises.joins(:customers).select("customers.id").map(&:id)
raise CanCan::AccessDenied unless allowed_customers.include?(params[:customer_id].to_i)
CustomerAccountTransaction.accessible_by(current_ability, action)
.where(customer_id: params[:customer_id]).order(id: :desc)
end
end
end

View File

@@ -67,7 +67,6 @@ module Admin
def update
tag_rules_attributes = params[object_name].delete :tag_rules_attributes
update_tag_rules(tag_rules_attributes) if tag_rules_attributes.present?
update_enterprise_notifications
update_vouchers
delete_custom_tab if params[:custom_tab] == 'false'
@@ -163,9 +162,11 @@ module Admin
end
def destroy
if @object.destroy
@object.transaction do
@object.destroy!
flash.now[:success] = flash_message_for(@object, :successfully_removed)
else
rescue StandardError
Rails.logger.error @object.errors.full_messages.to_sentence
flash.now[:error] = @object.errors.full_messages.to_sentence
end
@@ -177,7 +178,7 @@ module Admin
protected
def delete_custom_tab
@object.custom_tab.destroy if @object.custom_tab.present?
@object.custom_tab.presence&.destroy
enterprise_params.delete(:custom_tab_attributes)
end
@@ -240,9 +241,7 @@ module Admin
enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, @order_cycle)
.visible_enterprises
if enterprises.present?
enterprises.includes(supplied_products: [:variants, :image])
end
enterprises.presence&.includes(supplied_products: [:variants, :image])
when :index
if spree_current_user.admin?
OpenFoodNetwork::Permissions.new(spree_current_user).
@@ -314,14 +313,6 @@ module Admin
end
end
def update_enterprise_notifications
user_id = params[:receives_notifications].to_i
return unless user_id.positive? && @enterprise.user_ids.include?(user_id)
@enterprise.update_contact(user_id)
end
def update_vouchers
params_voucher_ids = params[:enterprise][:voucher_ids].to_a.map(&:to_i)
voucher_ids = @enterprise.vouchers.map(&:id)

View File

@@ -107,6 +107,33 @@ module Admin
end
end
# Clone a variant, retaining a link to the "source"
def create_linked_variant
linked_variant = Spree::Variant.find(params[:variant_id])
product_index = params[:product_index]
authorize! :create_linked_variant, linked_variant
status = :ok
begin
variant = linked_variant.create_linked_variant(spree_current_user)
flash.now[:success] = t('.success')
variant_index = "-#{variant.id}"
rescue ActiveRecord::RecordInvalid
flash.now[:error] = variant.errors.full_messages.to_sentence
status = :unprocessable_entity
variant_index = "-1" # Create a unique-enough index
end
respond_with do |format|
format.turbo_stream {
locals = { linked_variant:, variant:, product_index:, variant_index:,
producer_options:, category_options: categories, tax_category_options: }
render :create_linked_variant, status:, locals:
}
end
end
def index_url(params)
"/admin/products?#{params.to_query}" # todo: fix routing so this can be automaticly generated
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
module Admin
class UserInvitationsController < ResourceController
before_action :load_enterprise
def new; end
def create
@user_invitation.attributes = permitted_resource_params
if @user_invitation.save!
flash[:success] = I18n.t(:user_invited, email: @user_invitation.email)
else
render :new
end
end
private
def load_enterprise
@enterprise = OpenFoodNetwork::Permissions
.new(spree_current_user)
.editable_enterprises
.find_by(permalink: params[:enterprise_id])
end
def permitted_resource_params
params.require(:user_invitation).permit(:email).merge(enterprise: @enterprise)
end
end
end

View File

@@ -0,0 +1,34 @@
# frozen_string_literal: true
module Api
module V1
class CustomerAccountTransactionController < Api::V1::BaseController
def create
authorize! :create, CustomerAccountTransaction
default_params = {
currency: CurrentConfig.get(:currency), created_by: current_api_user
}
parameters = default_params.merge(customer_account_transaction_params).merge(description: )
transaction = CustomerAccountTransaction.new(parameters)
if transaction.save
render json: Api::V1::CustomerAccountTransactionSerializer.new(transaction),
status: :created
else
invalid_resource! transaction
end
end
private
def customer_account_transaction_params
params.require(:customer_account_transaction).permit(:customer_id, :amount, :description)
end
def description
I18n.t(".api_customer_credit", description: params[:description])
end
end
end
end

View File

@@ -31,6 +31,11 @@ class CheckoutController < BaseController
check_step
end
if payment_step? || summary_step?
credit_payment_method = @order.distributor.payment_methods.customer_credit
@paid_with_credit = @order.payments.find_by(payment_method: credit_payment_method)&.amount
end
return if available_shipping_methods.any?
flash[:error] = I18n.t('checkout.errors.no_shipping_methods_available')
@@ -121,7 +126,9 @@ class CheckoutController < BaseController
shipping_method_updated = @order.shipping_method&.id != params[:shipping_method_id].to_i
@order.select_shipping_method(params[:shipping_method_id])
@order.update(order_params)
# We need to update voucher to take into account:
# * when moving away from "details" step : potential change in shipping method fees
# * when moving away from "payment" step : payment fees

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
module ManagerInvitations
extend ActiveSupport::Concern
def create_new_manager(email, enterprise)
password = SecureRandom.base58(64)
new_user = Spree::User.create(email:, unconfirmed_email: email, password:)
new_user.reset_password_token = Devise.friendly_token
# Same time as used in Devise's lib/devise/models/recoverable.rb.
new_user.reset_password_sent_at = Time.now.utc
if new_user.save
enterprise.users << new_user
EnterpriseMailer.manager_invitation(enterprise, new_user).deliver_later
end
new_user
end
end

View File

@@ -2,15 +2,36 @@
module PaymentGateways
class TalerController < BaseController
include OrderStockCheck
include OrderCompletion
class StockError < StandardError
end
# The Taler merchant backend has taken the payment.
# Now we just need to confirm that and update our local database
# before finalising the order.
def confirm
payment = Spree::Payment.find(params[:payment_id])
# Process payment early because it's probably paid already.
# We want to capture that before any validations raise errors.
unless payment.process!
return redirect_to order_failed_route(step: "payment")
end
@order = payment.order
process_payment_completion!
OrderLocker.lock_order_and_variants(@order) do
raise StockError unless sufficient_stock?
process_payment_completion!
end
rescue Spree::Core::GatewayError => e
flash[:notice] = e.message
redirect_to order_failed_route(step: "payment")
rescue StockError
flash[:notice] = t("checkout.payment_cancelled_due_to_stock")
redirect_to main_app.checkout_step_path(step: "details")
end
end
end

View File

@@ -15,6 +15,7 @@ module Spree
Spree::Gateway::StripeSCA
Spree::PaymentMethod::Check
Spree::PaymentMethod::Taler
Spree::PaymentMethod::CustomerCredit
}.freeze
def create

View File

@@ -5,7 +5,7 @@ module Spree
class PaymentsController < Spree::Admin::BaseController
before_action :load_order, except: [:show]
before_action :load_payment, only: [:fire, :show]
before_action :load_data
before_action :load_data, except: [:credit_customer]
before_action :can_transition_to_payment
# We ensure that items are in stock before all screens if the order is in the Payment state.
# This way, we don't allow someone to enter credit card details for an order only to be told
@@ -52,7 +52,7 @@ module Spree
# (we can't use respond_override because Spree no longer uses respond_with)
def fire
event = params[:e]
return unless event && @payment.payment_source
return unless event
# capture_and_complete_order will complete the order, so we want to try to redeem VINE
# voucher first and exit if it fails
@@ -92,6 +92,18 @@ module Spree
end
end
def credit_customer
response = ::Orders::CustomerCreditService.new(@order).refund
if response.success?
flash[:success] = Spree.t(:customer_credit_successful, scope: "admin.payments")
else
flash[:error] = response.message
end
redirect_to admin_order_payments_path(@order)
end
private
def load_payment_source
@@ -185,7 +197,7 @@ module Spree
end
def allowed_events
%w{capture void_transaction credit refund resend_authorization_email
%w{capture void_transaction credit refund internal_void resend_authorization_email
capture_and_complete_order}
end

View File

@@ -102,7 +102,7 @@ module Spree
def sign_in_if_change_own_password
return unless spree_current_user == @user && @user.password.present?
sign_in(@user, event: :authentication, bypass: true)
bypass_sign_in(@user)
end
def new_email_unconfirmed?

View File

@@ -29,7 +29,13 @@ module Spree
hide_ofn_navigation(@order.distributor)
end
def show; end
def show
credit_payment_method = @order.distributor.payment_methods.customer_credit
credit_payment = @order.payments.find_by(payment_method: credit_payment_method)
@paid_with_credit = credit_payment&.amount
@payment_total = @order.payment_total - @paid_with_credit.to_f
end
def empty
if @order = current_order
@@ -101,7 +107,7 @@ module Spree
def cancel
@order = Spree::Order.find_by!(number: params[:id])
authorize! :cancel, @order
authorize! :cancel, @order, session[:access_token]
if Orders::CustomerCancellationService.new(@order).call
flash[:success] = I18n.t(:orders_your_order_has_been_cancelled)

View File

@@ -0,0 +1,50 @@
# frozen_string_literal: true
class UserInvitation
include ActiveModel::Model
include ActiveModel::Attributes
include ActiveModel::Validations::Callbacks
attribute :enterprise
attribute :email
before_validation :normalize_email
validates :email, presence: true, 'valid_email_2/email': { mx: true }
validates :enterprise, presence: true
validate :not_existing_enterprise_user
def save!
return unless valid?
user = find_or_create_user!
enterprise.users << user
return unless user.previously_new_record?
EnterpriseMailer.manager_invitation(enterprise, user).deliver_later
end
private
def find_or_create_user!
Spree::User.find_or_create_by!(email: email) do |user|
user.email = email
user.password = SecureRandom.base58(64)
user.unconfirmed_email = email
user.reset_password_token = Devise.friendly_token
# Same time as used in Devise's lib/devise/models/recoverable.rb.
user.reset_password_sent_at = Time.now.utc
end
end
def normalize_email
self.email = email.strip if email.present?
end
def not_existing_enterprise_user
return unless email.present? && enterprise.users.where(email: email).exists?
errors.add(:email, :is_already_manager)
end
end

View File

@@ -47,5 +47,20 @@ module Admin
def variant_tag_enabled?(user)
feature?(:variant_tag, user) || feature?(:variant_tag, *user.enterprises)
end
def allowed_source_producers
@allowed_source_producers ||= OpenFoodNetwork::Permissions.new(spree_current_user)
.enterprises_granting_linked_variants
end
# Query only name of the model to avoid loading the whole record
def selected_option(id, model)
return [] unless id
name = model.where(id: id).pick(:name)
return [] unless name
[[name, id]]
end
end
end

View File

@@ -83,31 +83,6 @@ module CheckoutHelper
Spree::Money.new order.total - order.total_tax, currency: order.currency
end
def validated_input(name, path, args = {})
attributes = {
:required => true,
:type => :text,
:name => path,
:id => path,
"ng-model" => path,
"ng-class" => "{error: !fieldValid('#{path}')}"
}.merge args
render "shared/validated_input", name:, path:, attributes:
end
def validated_select(name, path, options, args = {})
attributes = {
:required => true,
:id => path,
"ng-model" => path,
"ng-class" => "{error: !fieldValid('#{path}')}"
}.merge args
render "shared/validated_select", name:, path:, options:,
attributes:
end
def payment_method_price(method, order)
price = method.compute_amount(order)
if price == 0
@@ -139,7 +114,7 @@ module CheckoutHelper
def stripe_card_options(cards)
cards.map do |cc|
[
"#{cc.brand} #{cc.last_digits} #{I18n.t(:card_expiry_abbreviation)}:" \
"#{cc.cc_type} #{cc.last_digits} #{I18n.t(:card_expiry_abbreviation)}:" \
"#{cc.month.to_s.rjust(2, '0')}/#{cc.year}", cc.id
]
end

View File

@@ -17,7 +17,7 @@ module ReportsHelper
next unless payment_method
[payment_method.name, payment_method.id]
[payment_method.display_name, payment_method.id]
end.compact.uniq
end

View File

@@ -11,7 +11,7 @@ module Spree
end
def payment_method_name(payment)
payment_method(payment)&.name
payment_method(payment)&.display_name
end
end
end

15
app/jobs/rake_job.rb Normal file
View File

@@ -0,0 +1,15 @@
# frozen_string_literal: true
require "rake"
# Executes a rake task
class RakeJob < ApplicationJob
def perform(task_string)
Rails.application.load_tasks if Rake::Task.tasks.empty?
Rake.application.invoke_task(task_string)
ensure
name, _args = Rake.application.parse_task_string(task_string)
Rake::Task[name].reenable
end
end

View File

@@ -0,0 +1,30 @@
# frozen_string_literal: true
class CustomerAccountTransactionSchema < JsonApiSchema
def self.object_name
"customer_account_transaction"
end
def self.attributes
{
id: { type: :integer, example: 1 },
customer_id: { type: :integer, example: 10 },
amount: { type: :decimal, example: 10.50 },
currency: { type: :string, example: "AUD" },
description: { type: :string, nullable: true, example: "Payment processed by POS" },
balance: { type: :decimal, example: 10.50 },
}
end
def self.required_attributes
[:customer_id, :amount]
end
def self.writable_attributes
attributes.except(:id, :balance, :currency)
end
def self.relationships
[:customer]
end
end

View File

@@ -6,6 +6,7 @@ class PaymentMailer < ApplicationMailer
def authorize_payment(payment)
@payment = payment
@order = @payment.order
@hide_ofn_navigation = @payment.order.distributor.hide_ofn_navigation
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject: default_i18n_subject(distributor: @order.distributor.name),
@@ -21,10 +22,10 @@ class PaymentMailer < ApplicationMailer
end
end
def refund_available(payment, taler_order_status_url)
def refund_available(amount, payment, taler_order_status_url)
@order = payment.order
@shop = @order.distributor.name
@amount = payment.display_amount
@amount = amount
@taler_order_status_url = taler_order_status_url
I18n.with_locale valid_locale(@order.user) do

View File

@@ -11,6 +11,7 @@ module Spree
def cancel_email(order_or_order_id, resend = false)
@order = find_order(order_or_order_id)
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject: mail_subject(t('spree.order_mailer.cancel_email.subject'), resend),
@@ -51,6 +52,7 @@ module Spree
def invoice_email(order_or_order_id, options = {})
@order = find_order(order_or_order_id)
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
current_user = if options[:current_user_id].present?
find_user(options[:current_user_id])
end

View File

@@ -4,6 +4,7 @@ module Spree
class ShipmentMailer < ApplicationMailer
def shipped_email(shipment, delivery:)
@shipment = shipment.respond_to?(:id) ? shipment : Spree::Shipment.find(shipment)
@hide_ofn_navigation = @shipment.order.distributor.hide_ofn_navigation
@delivery = delivery
@order = @shipment.order
subject = base_subject

View File

@@ -19,6 +19,7 @@ class SubscriptionMailer < ApplicationMailer
@type = 'empty'
@changes = changes
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end
@@ -26,11 +27,13 @@ class SubscriptionMailer < ApplicationMailer
@type = 'placement'
@changes = changes
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end
def failed_payment_email(order)
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end

View File

@@ -19,6 +19,7 @@ class Customer < ApplicationRecord
belongs_to :enterprise
belongs_to :user, class_name: "Spree::User", optional: true
has_many :orders, class_name: "Spree::Order", dependent: :nullify
has_many :customer_account_transactions, dependent: :restrict_with_error
before_validation :downcase_email
before_validation :empty_code
before_create :associate_user

View File

@@ -0,0 +1,38 @@
# frozen_string_literal: true
require "spree/localized_number"
class CustomerAccountTransaction < ApplicationRecord
extend Spree::LocalizedNumber
localize_number :amount
belongs_to :customer
belongs_to :payment, class_name: "Spree::Payment", optional: true
belongs_to :created_by, class_name: "Spree::User", optional: true
validates :amount, presence: true
validates :currency, presence: true
before_create :update_balance
private
def readonly?
!new_record?
end
def update_balance
# Locking the customer to prevent two transactions from behing created at the same time
# resulting in a potentially wrong balance calculation.
customer.with_lock(requires_new: true) do
last_transaction = CustomerAccountTransaction.where(customer: customer).last
self.balance = if last_transaction.present?
last_transaction.balance + amount
else
amount
end
end
end
end

View File

@@ -294,7 +294,13 @@ class Enterprise < ApplicationRecord
contact || owner
end
def update_contact(user_id)
def contact_id
contact&.id
end
def contact_id=(user_id)
return unless user_id.to_i.positive? && users.confirmed.exists?(user_id.to_i)
enterprise_roles.update_all(["receives_notifications=(user_id=?)", user_id])
end
@@ -576,7 +582,7 @@ class Enterprise < ApplicationRecord
end
def set_default_contact
update_contact owner_id
self.contact_id = owner_id
end
def relate_to_owners_enterprises

View File

@@ -4,7 +4,7 @@ class Invoice < ApplicationRecord
self.belongs_to_required_by_default = false
belongs_to :order, class_name: 'Spree::Order'
serialize :data, Hash, coder: YAML
serialize :data, type: Hash, coder: YAML
before_validation :serialize_order
after_create :cancel_previous_invoices
default_scope { order(created_at: :desc) }

View File

@@ -18,7 +18,7 @@ class Invoice
end
def payment_method_name
payment_method&.name
payment_method&.display_name
end
end
end

View File

@@ -3,7 +3,7 @@
class Invoice
class DataPresenter
class PaymentMethod < Invoice::DataPresenter::Base
attributes :id, :name, :description
attributes :id, :display_name, :display_description
invoice_generation_attributes :id
end
end

View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true
class OrderBalance
delegate :negative?, :positive?, :zero?, :abs, :to_s, :to_f, :to_d, :<, :>, to: :amount
delegate :negative?, :positive?, :zero?, :abs, :to_s, :to_f, :to_d, :<, :>, :<=, :>=, to: :amount
def initialize(order)
@order = order

View File

@@ -76,6 +76,7 @@ class ProxyOrder < ApplicationRecord
def cart?
order&.state == 'complete' &&
order_cycle.orders_close_at.present? &&
order_cycle.orders_close_at > Time.zone.now
end

View File

@@ -4,5 +4,5 @@ class ReportRenderingOptions < ApplicationRecord
self.belongs_to_required_by_default = false
belongs_to :user, class_name: "Spree::User"
serialize :options, Hash, coder: YAML
serialize :options, type: Hash, coder: YAML
end

View File

@@ -61,6 +61,7 @@ module Spree
add_manage_line_items_abilities user
end
add_relationship_management_abilities user if can_manage_relationships? user
add_customer_account_transaction_abilities user if can_manage_enterprises? user
end
# New users have no enterprises.
@@ -112,7 +113,11 @@ module Spree
item.order.changes_allowed?
end
can [:cancel, :bulk_cancel], Spree::Order do |order|
can :cancel, Spree::Order do |order, token|
order.user == user || (order.token && token == order.token)
end
can :bulk_cancel, Spree::Order do |order|
order.user == user
end
@@ -191,17 +196,21 @@ module Spree
user.enterprises.include? stripe_account.enterprise
end
can [:admin, :create], :manager_invitation
can [:admin, :create], UserInvitation
can [:admin, :index, :destroy], :oidc_setting
can [:admin, :create], Voucher
can [:admin, :destroy], EnterpriseRole do |enterprise_role|
enterprise_role.enterprise.owner_id == user.id
end
end
def add_product_management_abilities(user)
# Enterprise User can only access products that they are a supplier for
can [:create], Spree::Product
# An enterperprise user can change a product if they are supplier of at least
# An enterprise user can change a product if they are supplier of at least
# one of the product's associated variants
can [:admin, :read, :index, :update,
:seo, :group_buy_options,
@@ -213,7 +222,24 @@ module Spree
)
end
can [:admin, :index, :bulk_update, :destroy, :destroy_variant, :clone], :products_v3
# An enterprise user can clone if they have been granted permission to the source variant.
# Technically I'd call this permission clone_linked_variant, but it would be less confusing to
# use the same name as everywhere else.
can [:create_linked_variant], Spree::Variant do |variant|
OpenFoodNetwork::Permissions.new(user).
enterprises_granting_linked_variants.include? variant.supplier
end
can [
:admin,
:index,
:bulk_update,
:destroy,
:destroy_variant,
:clone,
:create_linked_variant
], :products_v3
can [:admin, :producers, :categories, :tax_categories], :ajax_search
can [:create], Spree::Variant
can [:admin, :index, :read, :edit,
@@ -314,7 +340,8 @@ module Spree
can [:create], Spree::Order
can [:read, :update], Spree::Order do |order|
# Spree::Admin::PaymentController need to load the order to credit_customer
can [:read, :update, :credit_customer], Spree::Order do |order|
# We allow editing orders with a nil distributor as this state occurs
# during the order creation process from the admin backend
order.distributor.nil? ||
@@ -366,7 +393,7 @@ module Spree
can_edit_as_producer(shipment.order, user)
end
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Payment
can [:admin, :index, :read, :create, :edit, :update, :fire, :credit_customer], Spree::Payment
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Adjustment
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::ReturnAuthorization
can [:destroy], Spree::Adjustment do |adjustment|
@@ -457,5 +484,9 @@ module Spree
user.enterprises.include?(enterprise_relationship.child)
end
end
def add_customer_account_transaction_abilities(_user)
can [:admin, :create, :index], CustomerAccountTransaction
end
end
end

View File

@@ -25,9 +25,6 @@ module Spree
scope :with_payment_profile, -> { where.not(gateway_customer_profile_id: nil) }
# needed for some of the ActiveMerchant gateways (eg. SagePay)
alias_attribute :brand, :cc_type
def expiry=(expiry)
self[:month], self[:year] = expiry.split(" / ")
self[:year] = "20#{self[:year]}"
@@ -66,35 +63,6 @@ module Spree
"XXXX-XXXX-XXXX-#{last_digits}"
end
def actions
%w{capture_and_complete_order void credit resend_authorization_email}
end
def can_resend_authorization_email?(payment)
payment.requires_authorization?
end
# Indicates whether its possible to capture the payment
def can_capture_and_complete_order?(payment)
return false if payment.requires_authorization?
payment.pending? || payment.checkout?
end
# Indicates whether its possible to void the payment.
def can_void?(payment)
!payment.void?
end
# Indicates whether its possible to credit the payment. Note that most gateways require that the
# payment be settled first which generally happens within 12-24 hours of the transaction.
def can_credit?(payment)
return false unless payment.completed?
return false unless payment.order.payment_state == 'credit_owed'
payment.credit_allowed.positive?
end
# Allows us to use a gateway_payment_profile_id to store Stripe Tokens
def has_payment_profile?
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?

View File

@@ -13,6 +13,35 @@ module Spree
preference :server, :string, default: 'live'
preference :test_mode, :boolean, default: false
def actions
%w{capture_and_complete_order void credit resend_authorization_email}
end
# Indicates whether its possible to capture the payment
def can_capture_and_complete_order?(payment)
return false if payment.requires_authorization?
payment.pending? || payment.checkout?
end
# Indicates whether its possible to void the payment.
def can_void?(payment)
!payment.void?
end
# Indicates whether its possible to credit the payment. Note that most gateways require that the
# payment be settled first which generally happens within 12-24 hours of the transaction.
def can_credit?(payment)
return false unless payment.completed?
return false unless payment.order.payment_state == 'credit_owed'
payment.credit_allowed.positive?
end
def can_resend_authorization_email?(payment)
payment.requires_authorization?
end
def payment_source_class
CreditCard
end
@@ -52,9 +81,9 @@ module Spree
def supports?(source)
return true unless provider_class.respond_to? :supports?
return false unless source.brand
return false unless source.cc_type
provider_class.supports?(source.brand)
provider_class.supports?(source.cc_type)
end
end
end

View File

@@ -674,8 +674,6 @@ module Spree
end
def process_each_payment
raise Core::GatewayError, Spree.t(:no_pending_payments) if pending_payments.empty?
pending_payments.each do |payment|
if payment.amount.zero? && zero_priced_order?
payment.update_columns(state: "completed", captured_at: Time.zone.now)
@@ -730,5 +728,9 @@ module Spree
adjustment.update_adjustment!(force: true)
update_totals_and_states
end
def apply_customer_credit
Orders::CustomerCreditService.new(self).apply
end
end
end

View File

@@ -78,6 +78,8 @@ module Spree
before_transition to: :delivery, do: :create_proposed_shipments
before_transition to: :delivery, do: :ensure_available_shipping_rates
before_transition to: :payment, do: :apply_customer_credit
before_transition to: :confirmation, do: :validate_payment_method!
after_transition to: :payment do |order|

View File

@@ -18,7 +18,7 @@ module Spree
belongs_to :order, class_name: 'Spree::Order'
belongs_to :source, polymorphic: true
belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
belongs_to :payment_method, class_name: "Spree::PaymentMethod", inverse_of: :payments
has_many :offsets, -> { where("source_type = 'Spree::Payment' AND amount < 0").completed },
class_name: "Spree::Payment", foreign_key: :source_id,
@@ -115,12 +115,20 @@ module Spree
Alert.raise(
e,
metadata: {
event_tye: "ofn.payment_transition", payment_id: payment.id, event: transition.to
event_type: "ofn.payment_transition", payment_id: payment.id, event: transition.to
}
)
end
end
# Allows by passing the default scope on Spree::PaymentMethod. It's needed to link payment
# to internal payment method.
# Using ->{ unscoped } on the association doesn't work presumably because the default scope
# is not a simple `where`.
def payment_method
Spree::PaymentMethod.unscoped { super }
end
def money
Spree::Money.new(amount, currency:)
end
@@ -144,11 +152,10 @@ module Spree
end
def actions
return [] unless payment_source.respond_to?(:actions)
return [] unless payment_method.respond_to?(:actions)
payment_source.actions.select do |action|
!payment_source.respond_to?("can_#{action}?") ||
payment_source.__send__("can_#{action}?", self)
payment_method.actions.select do |action|
payment_method.__send__("can_#{action}?", self)
end
end
@@ -158,11 +165,6 @@ module Spree
PaymentMailer.authorize_payment(self).deliver_later
end
def payment_source
res = source.is_a?(Payment) ? source.source : source
res || payment_method
end
def ensure_correct_adjustment
revoke_adjustment_eligibility if ['failed', 'invalid', 'void'].include?(state)
return if adjustment.try(:finalized?)

View File

@@ -4,6 +4,8 @@ module Spree
class Payment < ApplicationRecord
module Processing
def process!
return internal_purchase! if payment_method.internal?
return unless validate!
purchase!
@@ -20,6 +22,17 @@ module Spree
end
end
def internal_purchase!
started_processing!
options = { customer_id: order.customer_id, payment_id: id, order_number: order.number }
response = payment_method.purchase(
(amount * 100).round,
nil,
options
)
handle_response(response, :complete, :failure)
end
def authorize!(return_url = nil)
started_processing!
gateway_action(source, :authorize, :pend, return_url:)
@@ -131,6 +144,27 @@ module Spree
end
end
def internal_void!
return true if void?
# We should only void complete payment, otherwise we will be refunding credit that was
# not used in the first place.
return gateway_error(Spree.t(:internal_payment_not_voidable)) if state != "completed"
options = { customer_id: order.customer_id, payment_id: id, order_number: order.number }
response = payment_method.void(
(amount * 100).round,
nil,
options
)
record_response(response)
if response.success?
void
else
gateway_error(response)
end
end
def partial_credit(amount)
return if amount > credit_allowed
@@ -248,6 +282,7 @@ module Spree
end
logger.error(Spree.t(:gateway_error))
logger.error(" #{error.to_yaml}")
# TODO why is this not captured ?
raise Core::GatewayError, text
end

View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Spree
class PaymentMethod < ApplicationRecord
class PaymentMethod < ApplicationRecord # rubocop:disable Metrics/ClassLength
include CalculatedAdjustments
include PaymentMethodDistributors
@@ -11,9 +11,11 @@ module Spree
acts_as_paranoid
DISPLAY = [:both, :back_end].freeze
default_scope -> { where(deleted_at: nil) }
INTERNAL = Spree::PaymentMethod::CustomerCredit.to_s
default_scope -> { where(deleted_at: nil).where.not(type: INTERNAL) }
has_many :credit_cards, class_name: "Spree::CreditCard", dependent: :destroy
has_many :payments, class_name: "Spree::Payment", dependent: :restrict_with_error
validates :name, presence: true
validate :distributor_validation
@@ -52,6 +54,12 @@ module Spree
.where(environment: [Rails.env, "", nil])
}
# These method is used to get the internal payment method. It is accessible to all
# enterprise, but the accessibility is managed by the code, as opposed to using the database.
def self.customer_credit
unscoped.find_by(type: "Spree::PaymentMethod::CustomerCredit", deleted_at: nil)
end
def configured?
!stripe? || stripe_configured?
end
@@ -109,9 +117,23 @@ module Spree
distributors.include?(distributor)
end
def display_name
try_translating(name)
end
def display_description
try_translating(description)
end
def internal?
type == INTERNAL
end
private
def distributor_validation
return true if internal?
validates_with DistributorsValidator
end
@@ -126,5 +148,11 @@ module Spree
preferred_enterprise_id > 0 &&
stripe_account_id.present?
end
def try_translating(value)
return value if value.blank?
I18n.t(value, default: value)
end
end
end

View File

@@ -0,0 +1,110 @@
# frozen_string_literal: true
module Spree
class PaymentMethod
class CustomerCredit < Spree::PaymentMethod
# Name and description are translatable string, to allow instances to customise them
def name
"credit_payment_method.name"
end
def description
"credit_payment_method.description"
end
def actions
%w{internal_void}
end
# We should only void complete payment, otherwise we will be refunding credit that was
# not used in the first place.
def can_internal_void?(payment)
payment.state == "completed"
end
# Main method called by Spree::Payment::Processing during checkout
# - amount is in cents
# - options: {
# customer_id:, payment_id:, order_number:
# }
def purchase(amount, _source, options)
calculated_amount = amount / 100.00
customer = Customer.find_by(id: options[:customer_id])
return error_response("customer_not_found") if customer.nil?
return error_response("missing_payment") if options[:payment_id].nil?
available_credit = customer.customer_account_transactions.last&.balance
return error_response("no_credit_available") if available_credit.nil?
return error_response("not_enough_credit_available") if calculated_amount > available_credit
customer.with_lock do
description = I18n.t(
"order_payment_description",
scope: "credit_payment_method",
order_number: options[:order_number]
)
customer.customer_account_transactions.create(
amount: -calculated_amount,
currency:,
payment_id: options[:payment_id],
description:
)
end
message = I18n.t("success", scope: "credit_payment_method")
ActiveMerchant::Billing::Response.new(true, message)
end
# Main method called by Spree::Payment::Processing for void
# - amount is in cents
# - options: {
# customer_id:, payment_id:, order_number:, user_id: (optional)
# }
def void(amount, _source, options)
calculated_amount = amount / 100.00
customer = Customer.find_by(id: options[:customer_id])
return error_response("customer_not_found") if customer.nil?
return error_response("missing_payment") if options[:payment_id].nil?
customer.with_lock do
description = I18n.t(
"order_void_description",
scope: "credit_payment_method",
order_number: options[:order_number]
)
customer.customer_account_transactions.create(
amount: calculated_amount,
currency:,
payment_id: options[:payment_id],
description:,
created_by_id: options[:user_id]
)
end
message = I18n.t("void_success", scope: "credit_payment_method")
ActiveMerchant::Billing::Response.new(true, message)
end
def method_type
"check" # empty view
end
def source_required?
false
end
private
def error_response(translation_key)
message = I18n.t(translation_key, scope: "credit_payment_method.errors")
ActiveMerchant::Billing::Response.new(false, message)
end
def currency
CurrentConfig.get(:currency)
end
end
end
end

View File

@@ -18,15 +18,27 @@ module Spree
# - backend_url: https://backend.demo.taler.net/instances/sandbox
# - api_key: sandbox
class Taler < PaymentMethod
# Demo backend instances will use the KUDOS currency.
DEMO_PREFIX = "https://backend.demo.taler.net/instances"
preference :backend_url, :string
preference :api_key, :password
def actions
%w{void}
%w[credit void]
end
def can_void?(payment)
payment.state == "completed"
# The source can be another payment. Then this is an offset payment
# like a credit record. We can't void a refund.
payment.source == self && payment.state == "completed"
end
def can_credit?(payment)
return false unless payment.completed?
return false unless payment.order.payment_state == 'credit_owed'
payment.credit_allowed.positive?
end
# Name of the view to display during checkout
@@ -68,6 +80,23 @@ module Spree
ActiveMerchant::Billing::Response.new(success, message)
end
def credit(money, response_code, gateway_options)
amount = money / 100 # called with cents
payment = gateway_options[:payment]
taler_order = taler_order(id: response_code)
status = taler_order.fetch("order_status")
raise "Unsupported action" if status != "paid"
taler_amount = "KUDOS:#{amount}"
taler_order.refund(refund: taler_amount, reason: "credit")
spree_money = Spree::Money.new(amount, currency: payment.currency).to_s
PaymentMailer.refund_available(spree_money, payment, taler_order.status_url).deliver_later
ActiveMerchant::Billing::Response.new(true, "Refund initiated")
end
def void(response_code, gateway_options)
payment = gateway_options[:payment]
taler_order = taler_order(id: response_code)
@@ -82,7 +111,8 @@ module Spree
amount = taler_order.fetch("contract_terms")["amount"]
taler_order.refund(refund: amount, reason: "void")
PaymentMailer.refund_available(payment, taler_order.status_url).deliver_later
spree_money = payment.money.to_s
PaymentMailer.refund_available(spree_money, payment, taler_order.status_url).deliver_later
ActiveMerchant::Billing::Response.new(true, "Refund initiated")
end
@@ -96,7 +126,7 @@ module Spree
def create_taler_order(payment)
# We are ignoring currency for now so that we can test with the
# current demo backend only working with the KUDOS currency.
taler_amount = "KUDOS:#{payment.amount}"
taler_amount = "#{currency(payment)}:#{payment.amount}"
urls = Rails.application.routes.url_helpers
fulfillment_url = urls.payment_gateways_confirm_taler_url(payment_id: payment.id)
taler_order.create(
@@ -113,6 +143,12 @@ module Spree
id:,
)
end
def currency(payment)
return "KUDOS" if preferred_backend_url.starts_with?(DEMO_PREFIX)
payment.order.currency
end
end
end
end

View File

@@ -5,10 +5,11 @@ module Spree
include SetUnusedAddressFields
self.belongs_to_required_by_default = false
self.ignored_columns += [:authentication_token]
searchable_attributes :email
devise :database_authenticatable, :token_authenticatable, :registerable, :recoverable,
devise :database_authenticatable, :registerable, :recoverable,
:rememberable, :trackable, :validatable, :omniauthable,
:encryptable, :confirmable,
encryptor: 'authlogic_sha512', reconfirmable: true,
@@ -23,6 +24,7 @@ module Spree
before_destroy :check_completed_orders
scope :admin, -> { where(admin: true) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
has_many :enterprise_roles, dependent: :destroy
has_many :enterprises, through: :enterprise_roles

View File

@@ -40,6 +40,7 @@ module Spree
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory', optional: false
belongs_to :primary_taxon, class_name: 'Spree::Taxon', touch: true, optional: false
belongs_to :supplier, class_name: 'Enterprise', optional: false, touch: true
belongs_to :hub, class_name: 'Enterprise', optional: true
delegate :name, :name=, :description, :description=, :meta_keywords, to: :product
@@ -72,6 +73,15 @@ module Spree
has_many :semantic_links, as: :subject, dependent: :delete_all
has_many :supplier_properties, through: :supplier, source: :properties
# Linked variants: I may have one or many sources.
has_many :variant_links_as_target, class_name: 'VariantLink', foreign_key: :target_variant_id,
dependent: :delete_all, inverse_of: :target_variant
has_many :source_variants, through: :variant_links_as_target, source: :source_variant
# I may also have one more many targets.
has_many :variant_links_as_source, class_name: 'VariantLink', foreign_key: :source_variant_id,
dependent: :delete_all, inverse_of: :source_variant
has_many :target_variants, through: :variant_links_as_source, source: :target_variant
localize_number :price, :weight
validates_lengths_from_database
@@ -263,6 +273,24 @@ module Spree
@on_hand_desired = ActiveModel::Type::Integer.new.cast(val)
end
# Clone this variant, retaining a 'source' link to it
def create_linked_variant(user)
# Hub owner is my enterprise which has permission to create variant sourced from that supplier
hub_id = EnterpriseRelationship.permitted_by(supplier).permitting(user.enterprises)
.with_permission(:create_linked_variants)
.pick(:child_id)
dup.tap do |variant|
variant.price = price
variant.source_variants = [self]
variant.stock_items << Spree::StockItem.new(variant:)
variant.hub_id = hub_id
variant.on_demand = on_demand
variant.on_hand = on_hand
variant.save!
end
end
private
def check_currency

View File

@@ -0,0 +1,6 @@
# frozen_string_literal: true
class VariantLink < ApplicationRecord
belongs_to :source_variant, class_name: 'Spree::Variant'
belongs_to :target_variant, class_name: 'Spree::Variant'
end

View File

@@ -12,7 +12,8 @@ class CustomersWithBalanceQuery
joins(left_join_complete_orders).
group("customers.id").
select("customers.*").
select("#{outstanding_balance_sum} AS balance_value")
select("#{outstanding_balance_sum} AS balance_value").
select("#{available_credit} AS credit_value")
end
private
@@ -34,4 +35,21 @@ class CustomersWithBalanceQuery
def outstanding_balance_sum
"SUM(#{OutstandingBalanceQuery.new.statement})::float"
end
def available_credit
<<~SQL.squish
CASE WHEN EXISTS (#{available_credit_subquery}) THEN (#{available_credit_subquery})#{' '}
ELSE 0.00 END
SQL
end
def available_credit_subquery
<<~SQL.squish
SELECT balance
FROM customer_account_transactions
WHERE customer_account_transactions.customer_id = customers.id
ORDER BY id desc
LIMIT 1
SQL
end
end

View File

@@ -1,40 +0,0 @@
# frozen_string_literal: true
class InviteManagerReflex < ApplicationReflex
include ManagerInvitations
def invite
email = params[:email]
enterprise = Enterprise.find(params[:enterprise_id])
authorize! :edit, enterprise
existing_user = Spree::User.find_by(email:)
locals = { error: nil, success: nil, email:, enterprise: }
if existing_user
locals[:error] = I18n.t('admin.enterprises.invite_manager.user_already_exists')
return_morph(locals)
return
end
new_user = create_new_manager(email, enterprise)
if new_user.errors.empty?
locals[:success] = true
else
locals[:error] = new_user.errors.full_messages.to_sentence
end
return_morph(locals)
end
private
def return_morph(locals)
morph "#add_manager_modal",
render(partial: "admin/enterprises/form/add_new_unregistered_manager", locals:)
end
end

View File

@@ -7,9 +7,9 @@ module Api
# columns to instance methods. This way, the `balance_value` alias on that class ends up being
# `object.balance_value` here.
class CustomerWithBalanceSerializer < CustomerSerializer
attributes :balance, :balance_status
attributes :balance, :balance_status, :available_credit, :available_credit_url
delegate :balance_value, to: :object
delegate :balance_value, :credit_value, to: :object
def balance
Spree::Money.new(balance_value, currency: CurrentConfig.get(:currency)).to_s
@@ -24,6 +24,14 @@ module Api
""
end
end
def available_credit
Spree::Money.new(object.credit_value).to_s
end
def available_credit_url
admin_customer_customer_account_transaction_index_path(object.id)
end
end
end
end

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
module Api
module V1
class CustomerAccountTransactionSerializer < Api::V1::BaseSerializer
attributes :id, :customer_id, :amount, :currency, :description, :balance
end
end
end

View File

@@ -2,6 +2,6 @@
class Invoice
class PaymentMethodSerializer < ActiveModel::Serializer
attributes :id, :name, :description
attributes :id, :display_name, :display_description
end
end

View File

@@ -14,7 +14,6 @@ module Checkout
apply_strong_parameters
set_pickup_address
set_address_details
set_payment_amount
set_existing_card
@order_params
@@ -58,12 +57,6 @@ module Checkout
end
end
def set_payment_amount
return unless @order_params[:payments_attributes]
@order_params[:payments_attributes].first[:amount] = order.total
end
def set_existing_card
return unless existing_card_selected?

View File

@@ -28,6 +28,8 @@ module Checkout
def validate_payment
return true if params.dig(:order, :payments_attributes, 0, :payment_method_id).present?
return true if order.zero_priced_order?
# No payment required, it's usually due to the order being paid by customer credit
return true if order.outstanding_balance <= 0.00
order.errors.add :payment_method, I18n.t('checkout.errors.select_a_payment_method')
end

View File

@@ -0,0 +1,28 @@
# frozen_string_literal: false
module CustomerAccountTransactions
class DataLoaderService
attr_reader :user, :enterprise
def initialize(user:, enterprise:)
@user = user
@enterprise = enterprise
end
def customer_account_transactions
return [] if user.customers.empty?
enterprise_customer = user.customers.find_by(enterprise: )
return [] if enterprise_customer.nil?
enterprise_customer.customer_account_transactions.order(id: :desc)
end
def available_credit
return 0 if customer_account_transactions.empty?
# We are ordered by newest, so the lastest transaction is the first one
customer_account_transactions.first.balance
end
end
end

View File

@@ -19,8 +19,9 @@ module Orders
end
def reset_other!(current_user, current_customer)
reset_user_and_customer(current_user)
reset_user(current_user)
reset_order_cycle(current_customer)
order.customer = current_customer
order.save!
end
@@ -28,7 +29,7 @@ module Orders
attr_reader :order, :distributor, :current_user
def reset_user_and_customer(current_user)
def reset_user(current_user)
return unless current_user
order.associate_user!(current_user) if order.user.blank? || order.email.blank?

View File

@@ -0,0 +1,115 @@
# frozen_string_literal: true
module Orders
class CustomerCreditService
def initialize(order)
@order = order
end
def apply
add_payment_with_credit if credit_available?
end
def refund(user: nil) # rubocop:disable Metrics/AbcSize
if order.payment_state != "credit_owed"
return Response.new(
success: false, message: I18n.t(:no_credit_owed, scope: translation_scope)
)
end
if credit_payment_method.nil?
error_message = I18n.t(:credit_payment_method_missing, scope: translation_scope)
log_error(error_message)
return Response.new(success: false, message: error_message)
end
amount = order.new_outstanding_balance
order.customer.with_lock do
payment = order.payments.create!( payment_method: credit_payment_method, amount: amount,
state: "completed", skip_source_validation: true)
options = { customer_id: order.customer_id, payment_id: payment.id,
order_number: order.number, user_id: user&.id }
response = credit_payment_method.void((-1 * amount * 100).round, nil, options)
raise response.message if response.failure?
Response.new(success: true, message: I18n.t(:refund_sucessful, scope: translation_scope))
end
rescue StandardError => e
# Even though the transaction rolled back, the order still have a payment in memory,
# so we reload the payments so the payment doesn't get saved later on
order.payments.reload
log_error(e)
Response.new(success: false, message: e.to_s)
end
private
attr_reader :order
def add_payment_with_credit
if credit_payment_method.nil?
error_message = I18n.t(:credit_payment_method_missing, scope: translation_scope)
log_error(error_message)
return
end
return if order.payments.where(payment_method: credit_payment_method).exists?
# we are already in a transaction because the order is locked, so we force creating a new one
# to make sure the rollback works as expected :
# https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions
ActiveRecord::Base.transaction(requires_new: true) do
amount = [available_credit, order.total].min
payment = order.payments.create!(payment_method: credit_payment_method, amount:)
payment.internal_purchase!
end
rescue StandardError => e
# Even though the transaction rolled back, the order still have a payment in memory,
# so we reload the payments so the payment doesn't get saved later on
order.payments.reload
log_error(e)
end
def credit_available?
return false if order.customer.nil?
available_credit > 0
end
def available_credit
@available_credit ||= order.customer.customer_account_transactions.last&.balance || 0.00
end
def credit_payment_method
Spree::PaymentMethod.customer_credit
end
def log_error(error)
Rails.logger.error("Orders::CustomerCreditService: #{error}")
Alert.raise(error)
end
def translation_scope
"orders.customer_credit_service"
end
class Response
attr_reader :message
def initialize(success:, message:)
@success = success
@message = message
end
def success?
@success
end
def failure?
!success?
end
end
end
end

View File

@@ -13,7 +13,7 @@ module Payments
payment: @payment.slice(:updated_at, :amount, :state),
enterprise: @enterprise.slice(:abn, :acn, :name)
.merge(address: @enterprise.address.slice(:address1, :address2, :city, :zipcode)),
order: @order.slice(:total, :currency).merge(line_items: line_items)
order: @order.slice(:number, :total, :currency).merge(line_items: line_items)
}.with_indifferent_access
end
@@ -31,6 +31,7 @@ module Payments
def self.test_order
order = Spree::Order.new(
number: "R555555555",
total: 0.00,
currency: "AUD",
)

View File

@@ -40,7 +40,7 @@ module PermittedAttributes
:hide_ofn_navigation, :white_label_logo, :white_label_logo_link,
:hide_groups_tab, :external_billing_id,
:enable_producers_to_edit_orders,
:remove_logo, :remove_promo_image, :remove_white_label_logo
:remove_logo, :remove_promo_image, :remove_white_label_logo, :contact_id
]
end
end

View File

@@ -0,0 +1,31 @@
= turbo_stream.update "customer-account-transactions-modal-container" do
= render ModalComponent.new(id: "customer-account-transactions-modal", instant: true, modal_class: "big") do
%h3
= t(".available_credit", available_credit: Spree::Money.new(@available_credit))
%table.index
%thead
%tr
%th.transaction-date
= t(".transaction_date")
%th.description
= t(".description")
%th.created-by
= t(".created_by")
%th.amount
= t(".amount")
%th.running-balance
= t(".running_balance")
%tbody
- @collection.each do |transaction|
%tr.transaction
%td.transaction-date
= transaction.updated_at.strftime("%Y-%m-%d")
%td.description
= transaction.description
%td.created-by
= transaction.created_by&.email
%td.amount
= Spree::Money.new(transaction.amount)
%td.running-balance
= Spree::Money.new(transaction.balance)

View File

@@ -48,6 +48,7 @@
%input.red{ type: "button", value: t(:save_changes), "ng-click": "submitAll(customers_form)", "ng-disabled": "!hasUnsavedChanges()" }
%table.index#customers{ 'ng-show' => '!RequestMonitor.loading && filteredCustomers.length > 0' }
%col.id{ width: "5%", 'ng-show' => 'columns.id.visible' }
%col.email{ width: "20%", 'ng-show' => 'columns.email.visible' }
%col.first_name{ width: "20%", 'ng-show' => 'columns.first_name.visible' }
%col.last_name{ width: "20%", 'ng-show' => 'columns.last_name.visible' }
@@ -61,6 +62,7 @@
%tr{ "ng-controller": "ColumnsCtrl" }
-# %th.bulk
-# %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" }
%th.id{ 'ng-show' => 'columns.id.visible' }=t('admin.customers.index.id')
%th.email{ 'ng-show' => 'columns.email.visible' }
%a{ :href => '', 'ng-click' => "sorting.toggle('email')" }=t('admin.email')
%th.first_name{ 'ng-show' => 'columns.first_name.visible' }
@@ -73,10 +75,13 @@
%th.bill_address{ 'ng-show' => 'columns.bill_address.visible' }=t('admin.customers.index.bill_address')
%th.ship_address{ 'ng-show' => 'columns.ship_address.visible' }=t('admin.customers.index.ship_address')
%th.balance{ 'ng-show' => 'columns.balance.visible' }=t('admin.customers.index.balance')
%th.credit{ 'ng-show' => 'columns.credit.visible' }=t('admin.customers.index.credit')
%tbody
%tr.customer{ 'ng-repeat' => "customer in filteredCustomers = ( customers | filter:quickSearch | orderBy: sorting.predicate:sorting.reverse ) | limitTo:customerLimit track by customer.id", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "c_{{customer.id}}" }
-# %td.bulk
-# %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'customer.checked' }
%td.id{ 'ng-show' => 'columns.id.visible'}
%span{ 'ng-bind' => '::customer.id' }
%td.email{ 'ng-show' => 'columns.email.visible'}
%span{ 'ng-bind' => '::customer.email' }
%span.guest-label{ 'ng-show' => 'customer.user_id == null' }= t('.guest_label')
@@ -98,9 +103,14 @@
%td.balance.align-center{ 'ng-show' => 'columns.balance.visible'}
%span.state.white-space-nowrap{ 'ng-class' => 'customer.balance_status', 'ng-bind' => 'displayBalanceStatus(customer)' }
%span{ 'ng-bind' => '::customer.balance' }
%td.balance.align-center{ 'ng-show' => 'columns.credit.visible', "data-turbo": true}
%a{ "ng-href": "{{customer.available_credit_url}}", "data-turbo-stream": "" }
%span{ 'ng-bind' => '::customer.available_credit' }
%td.actions
%a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" }
.text-center{ "ng-show": "filteredCustomers.length > customerLimit" }
%input{ type: 'button', value: t(:show_more), "ng-click": 'customerLimit = customerLimit + 20' }
%input{ type: 'button', value: t(:show_all_with_more, num: '{{ filteredCustomers.length - customerLimit }}'), "ng-click": 'customerLimit = filteredCustomers.length' }
#customer-account-transactions-modal-container

View File

@@ -1,21 +0,0 @@
%form#add_manager_modal{ 'data-reflex': 'submit->InviteManager#invite', 'data-reflex-serialize-form': true }
.margin-bottom-30.text-center
.text-big
= t('js.admin.modals.invite_title')
- if success
%p.alert-box.ok= t('user_invited', email: email)
- if error
%p.alert-box.error= error
= text_field_tag :email, nil, class: 'fullwidth margin-bottom-20'
= hidden_field_tag :enterprise_id, @enterprise&.id || enterprise.id
.modal-actions
- if success
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->help-modal#close" }
- else
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->help-modal#close" }
= submit_tag "#{t('js.admin.modals.invite')}"

View File

@@ -11,7 +11,7 @@
%tbody
- @payment_methods.each do |payment_method|
%tr
%td= payment_method.name
%td= payment_method.display_name
%td= f.check_box :payment_method_ids, { multiple: true }, payment_method.id, nil
%td= link_to t(:edit), edit_admin_payment_method_path(payment_method)
%br

View File

@@ -1,75 +1,54 @@
- owner_email = @enterprise&.owner&.email || ""
- full_permissions = (spree_current_user.admin? || spree_current_user == @enterprise&.owner)
.row
.three.columns.alpha
=f.label :owner_id, t('.owner')
- if full_permissions
%span.required *
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.owner_tip')}
.eight.columns.omega
- if full_permissions
= f.hidden_field :owner_id, class: "select2 fullwidth", 'user-select' => 'Enterprise.owner', 'ng-model' => 'Enterprise.owner'
- else
= owner_email
= t '.description'
.row
.three.columns.alpha
=f.label :user_ids, t('.notifications')
- if full_permissions
%span.required *
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.contact_tip')}
.eight.columns.omega
- if full_permissions
%select.select2.fullwidth{ id: 'receives_notifications_dropdown', name: 'receives_notifications', "ng-model": 'receivesNotifications', "ng-init": "receivesNotifications = '#{@enterprise.contact.id}'" }
%option{ value: '{{user.id}}', "ng-repeat": 'user in Enterprise.users', "ng-selected": "user.id == #{@enterprise.contact.id}", "ng-hide": '!user.confirmed' }
{{user.email}}
- else
= @enterprise.contact.email
- if full_permissions && @enterprise.users.count > 0
- enterprise_role_ids_by_user_id = @enterprise.enterprise_roles.pluck(:user_id, :id).to_h
.row
.three.columns.alpha
=f.label :user_ids, t('.managers')
- if full_permissions
%span.required *
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.managers_tip')}
.eight.columns.omega
- if full_permissions
%table.managers
%tr
%table.managers
%thead
%tr
%th= t('.manager')
%th.center
= t('.owner')
= render AdminTooltipComponent.new(text: t('.owner_tip'), link_text: %[<i class="fa fa-question-circle"></i>].html_safe, link: nil)
%th.center
= t('.contact')
= render AdminTooltipComponent.new(text: t('.contact_tip'), link_text: %[<i class="fa fa-question-circle"></i>].html_safe, link: nil)
%tbody
- @enterprise.users.each do |user|
- contact = user.id == @enterprise.contact&.id
- owner = user.id == @enterprise.owner&.id
%tr{ id: "manager-#{user.id}" }
%td
- # Ignore this input in the submit
= hidden_field_tag :ignored, nil, class: "select2 fullwidth", 'user-select' => 'newManager', 'ng-model' => 'newManager'
= user.email
- if user.confirmed?
%i.confirmation.confirmed.fa.fa-check-circle{ "ofn-with-tip": t('.email_confirmed') }
- else
%i.confirmation.unconfirmed.fa.fa-exclamation-triangle{ "ofn-with-tip": t('.email_not_confirmed') }
%td.center
- if user.confirmed?
= f.label :owner_id, t(".set_as_owner", email: user.email), class: "sr-only", value: user.id
= f.radio_button :owner_id, user.id
%td.center
- if user.confirmed?
= f.label :owner_id, t(".set_as_contact", email: user.email), class: "sr-only", value: user.id
= f.radio_button :contact_id, user.id
%td.actions
%tr.animate-repeat{ id: "manager-{{manager.id}}", "ng-repeat": 'manager in Enterprise.users' }
%td
= hidden_field_tag "enterprise[user_ids][]", nil, multiple: true, 'ng-value' => 'manager.id'
{{ manager.email }}
%i.confirmation.confirmed.fa.fa-check-circle{ "ofn-with-tip": t('.email_confirmed'), "ng-show": 'manager.confirmed' }
%i.confirmation.unconfirmed.fa.fa-exclamation-triangle{ "ofn-with-tip": t('.email_not_confirmed'), "ng-show": '!manager.confirmed' }
%i.role.contact.fa.fa-envelope-o{ "ofn-with-tip": t('.contact'), "ng-show": 'manager.id == receivesNotifications' }
%i.role.owner.fa.fa-star{ "ofn-with-tip": t('.owner'), "ng-show": 'manager.id == Enterprise.owner.id' }
%td.actions
%a{ class: "icon-trash no-text", "ng-click": 'removeManager(manager)', "ng-class": "{disabled: manager.id == Enterprise.owner.id || manager.id == receivesNotifications}" }
- if !owner && !contact
= link_to_delete user, no_text: true, url: admin_enterprise_role_path(id: enterprise_role_ids_by_user_id[user.id])
- else
%a{ class: "icon-trash no-text disabled" }
- else
- @enterprise.users.each do |manager|
= manager.email
%br
%a.button{ href: "#{new_admin_enterprise_user_invitation_path(@enterprise)}", data: { turbo_stream: true, turbo: true } }
%i.icon-plus
= t('.invite_manager')
%br
- if full_permissions
%form
.row
.three.columns.alpha
%label
= t('.invite_manager')
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.invite_manager_tip')}
.eight.columns.omega
.row
%a.button{ "data-controller": "help-modal-link", "data-action": "click->help-modal-link#open", "data-help-modal-link-target-value": "invite-manager-modal" }
= t('.add_unregistered_user')
-# add to admin footer to avoid nesting invitation form inside enterprise form
- content_for :admin_footer do
= render HelpModalComponent.new(id: "invite-manager-modal", close_button: false) do
= render partial: 'admin/enterprises/form/add_new_unregistered_manager', locals: { error: nil, success: nil }
- else
- @enterprise.users.each do |manager|
= manager.email
%br

View File

@@ -68,11 +68,11 @@
@order_cycle.distributor_payment_methods.include?(distributor_payment_method),
id: "order_cycle_selected_distributor_payment_method_ids_#{distributor_payment_method.id}",
data: ({ "checked-target" => "checkbox" } if distributor_payment_method.payment_method.frontend?)
= distributor_payment_method.payment_method.name
= distributor_payment_method.payment_method.display_name
- distributor.payment_methods.inactive_or_backend.each do |payment_method|
%label.disabled
= check_box_tag nil, nil, false, disabled: true
= payment_method.name
= payment_method.display_name
= "(#{t('.back_end')})"
- if distributor.payment_methods.available.none?
%p

View File

@@ -9,14 +9,22 @@
- if producer_options.many?
.producers
= label_tag :producer_id, t('.producers.label')
= select_tag :producer_id, options_for_select(producer_options, producer_id),
include_blank: t('.all_producers'), class: "fullwidth",
data: { "controller": "tom-select", 'tom-select-placeholder-value': t('.search_for_producers')}
= render(SearchableDropdownComponent.new(name: :producer_id,
aria_label: t('.producers.label'),
options: selected_option(producer_id, Enterprise),
selected_option: producer_id,
remote_url: admin_ajax_search_producers_url,
include_blank: t('.all_producers'),
placeholder_value: t('.search_for_producers')))
.categories
= label_tag :category_id, t('.categories.label')
= select_tag :category_id, options_for_select(category_options, category_id),
include_blank: t('.all_categories'), class: "fullwidth",
data: { "controller": "tom-select", 'tom-select-placeholder-value': t('.search_for_categories')}
= render(SearchableDropdownComponent.new(name: :category_id,
aria_label: t('.categories.label'),
options: selected_option(category_id, Spree::Taxon),
selected_option: category_id,
remote_url: admin_ajax_search_categories_url,
include_blank: t('.all_categories'),
placeholder_value: t('.search_for_categories')))
-if variant_tag_enabled?(spree_current_user)
.tags
= label_tag :tags_name_in, t('.tags.label')

View File

@@ -11,9 +11,10 @@
-# Filter out variant a user has not permission to update, but keep variant with no supplier
- next if variant.supplier.present? && !allowed_producers.include?(variant.supplier)
= form.fields_for("products][#{product_index}][variants_attributes", variant, index: variant_index) do |variant_form|
%tr.condensed{ id: dom_id(variant), 'data-controller': "variant", 'class': "nested-form-wrapper", 'data-new-record': variant.new_record? ? "true" : false }
= render partial: 'variant_row', locals: { variant:, f: variant_form, category_options:, tax_category_options:, producer_options: }
= render partial: 'variant_row', locals: { variant:, f: variant_form, product_index:, category_options:, tax_category_options:, producer_options: }
= form.fields_for("products][#{product_index}][variants_attributes][NEW_RECORD", prepare_new_variant(product, producer_options)) do |new_variant_form|
%template{ 'data-nested-form-target': "template" }

View File

@@ -1,7 +1,10 @@
-# locals: (variant:, f:, category_options:, tax_category_options:, producer_options:)
-# haml-lint:disable ViewLength (This file is big, but doesn't make sense to split up at this point)
-# locals: (variant:, f:, product_index: nil, category_options:, tax_category_options:, producer_options:)
- method_on_demand, method_on_hand = variant.new_record? ? [:on_demand_desired, :on_hand_desired ]: [:on_demand, :on_hand]
%td.col-image
-# empty
- variant.source_variants.each do |source_variant|
= content_tag(:span, "🔗", title: t('admin.products_page.variant_row.sourced_from', source_name: source_variant.full_name, source_id: source_variant.id, hub_name: variant.hub&.name))
%td.col-name.field.naked_inputs
= f.hidden_field :id
= f.text_field :display_name, 'aria-label': t('admin.products_page.columns.name'), placeholder: variant.product.name
@@ -56,27 +59,28 @@
= render(SearchableDropdownComponent.new(form: f,
name: :supplier_id,
aria_label: t('.producer_field_name'),
options: producer_options,
options: variant.supplier_id ? [[variant.supplier.name, variant.supplier_id]] : [],
selected_option: variant.supplier_id,
include_blank: t('admin.products_v3.filters.select_producer'),
remote_url: admin_ajax_search_producers_url,
placeholder_value: t('admin.products_v3.filters.select_producer')))
= error_message_on variant, :supplier
%td.col-category.field.naked_inputs
= render(SearchableDropdownComponent.new(form: f,
name: :primary_taxon_id,
options: category_options,
options: variant.primary_taxon_id ? [[variant.primary_taxon.name, variant.primary_taxon_id]] : [],
selected_option: variant.primary_taxon_id,
aria_label: t('.category_field_name'),
include_blank: t('admin.products_v3.filters.select_category'),
remote_url: admin_ajax_search_categories_url,
placeholder_value: t('admin.products_v3.filters.select_category')))
= error_message_on variant, :primary_taxon
%td.col-tax_category.field.naked_inputs
= render(SearchableDropdownComponent.new(form: f,
name: :tax_category_id,
options: tax_category_options,
options: variant.tax_category_id ? [[variant.tax_category.name, variant.tax_category_id]] : [],
selected_option: variant.tax_category_id,
include_blank: t('.none_tax_category'),
aria_label: t('.tax_category_field_name'),
include_blank: t('.none_tax_category'),
remote_url: admin_ajax_search_tax_categories_url,
placeholder_value: t('.search_for_tax_categories')))
= error_message_on variant, :tax_category
- if variant_tag_enabled?(spree_current_user)
@@ -88,6 +92,10 @@
= render(VerticalEllipsisMenuComponent.new) do
- if variant.persisted?
= link_to t('admin.products_page.actions.edit'), edit_admin_product_variant_path(variant.product, variant)
- if variant.source_variants.empty? && allowed_source_producers.include?(variant.supplier)
= link_to t('admin.products_page.actions.create_linked_variant'), admin_create_linked_variant_path(variant_id: variant.id, product_index:), 'data-turbo-method': :post
- if variant.product.variants.size > 1
%a{ "data-controller": "modal-link", "data-action": "click->modal-link#setModalDataSetOnConfirm click->modal-link#open",
"data-modal-link-target-value": "variant-delete-modal", "class": "delete",

View File

@@ -0,0 +1,16 @@
-# locals: (variant:, linked_variant:, product_index:, variant_index:, producer_options:, category_options:, tax_category_options:)
-# Pre-render the form, because you can't do it inside turbo stream block
- variant_row = nil
- fields_for("products][#{product_index}][variants_attributes", variant, index: variant_index) do |f|
- variant_row = render(partial: 'variant_row', formats: :html,
locals: { f:,
variant:,
producer_options:,
category_options:,
tax_category_options:})
= turbo_stream.after dom_id(linked_variant) do
%tr.condensed{ id: dom_id(variant), 'data-controller': "variant", 'class': "nested-form-wrapper slide-in",'data-variant-bulk-form-outlet': "#products-form"}
= variant_row
= turbo_stream.append "flashes" do
= render(partial: 'admin/shared/flashes', locals: { flashes: flash })

View File

@@ -1,24 +1,24 @@
- link = pagy_anchor(pagy)
.pagination{ "data-controller": "search" }
%nav.pagination{ "aria-label": t('.navigation'), "data-controller": "search" }
- if pagy.prev
%button.page.prev{ data: { action: 'click->search#changePage', page: pagy.prev } }
%a.page.prev{ href: "#", rel: "prev", "aria-label": t('.previous'), data: { action: 'click->search#changePage', page: pagy.prev } }
%i.icon-chevron-left{ data: { action: 'click->search#changePage', page: pagy.prev } }
- else
%button.page.disabled{disabled: "disabled"}!= pagy_t('pagy.prev')
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
- if item.is_a?(Integer) # page link
%button.page{ data: { action: 'click->search#changePage', page: item } }= item
%ul.pagelist
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
- if item.is_a?(Integer) # page link
%li
%a.page{ href: "#", "aria-label": t('.page', number: item), data: { action: 'click->search#changePage', page: item } }= item
- elsif item.is_a?(String) # current page
%button.page.current.active= item
- elsif item.is_a?(String) # current page
%li
%a.page.current.active{ href: "#", "aria-label": t('.page', number: item), "aria-current": "page" }= item
- elsif item == :gap # page gap
%span.page.gap.pagination-ellipsis!= pagy_t('pagy.gap')
- elsif item == :gap # page gap
%li
%span.page.gap.pagination-ellipsis!= pagy_t('pagy.gap')
- if pagy.next
%button.page.next{ data: { action: 'click->search#changePage', page: pagy.next } }
%a.page.next{ href: "#", rel: "next", "aria-label": t('.next'), data: { action: 'click->search#changePage', page: pagy.next } }
%i.icon-chevron-right{ data: { action: 'click->search#changePage', page: pagy.next } }
- else
%button.page.disabled.pagination-next{disabled: "disabled"}!= pagy_t('pagy.next')

View File

@@ -0,0 +1,5 @@
= turbo_stream.update "remote_modal", ""
= turbo_stream.update "users_panel" do
= render partial: "admin/enterprises/form/users", locals: { f: ActionView::Helpers::FormBuilder.new(:enterprise, @enterprise, self, {}) }
= turbo_stream.append "flashes" do
= render partial: 'admin/shared/flashes', locals: { flashes: flash }

View File

@@ -0,0 +1,17 @@
= turbo_stream.update "remote_modal" do
= render ModalComponent.new id: "#modal_new_user_invitation", instant: true, close_button: false, modal_class: :fit do
= form_with model: @user_invitation, url: admin_enterprise_user_invitations_path(@enterprise), html: { name: "user_invitation", data: { turbo: true } } do |f|
%h2= t ".invite_new_user"
%p= t ".description"
%fieldset.no-border-top.no-border-bottom
.row.field
= f.label :email, t(:email)
= f.email_field :email, placeholder: t('.eg_email_address'), data: { controller: "select-user" }, inputmode: "email", autocomplete: "off"
= f.error_message_on :email
.modal-actions.justify-end.filter-actions
%input{ class: "secondary relaxed", type: 'button', value: t('.back'), "data-action": "click->modal#close" }
%button.button.primary.relaxed.icon-envelope{ type: "submit" }
= t(".invite")

View File

@@ -8,10 +8,17 @@
.checkout-title
= t("checkout.step2.payment_method.title")
- if @order.zero_priced_order?
- if @order.zero_priced_order? || @order.outstanding_balance.zero?
%h3= t(:no_payment_required)
= hidden_field_tag "order[payments_attributes][][amount]", 0
- if @order.zero_priced_order?
= hidden_field_tag "order[payments_attributes][][amount]", 0
- if @paid_with_credit
= t(:credit_used, amount: Spree::Money.new(@paid_with_credit))
- else
- if @paid_with_credit
= t(:credit_used, amount: Spree::Money.new(@paid_with_credit))
- selected_payment_method = @order.payments&.with_state(:checkout)&.first&.payment_method_id
- selected_payment_method ||= available_payment_methods[0].id if available_payment_methods.length == 1
- available_payment_methods.each do |payment_method|
@@ -23,13 +30,13 @@
"data-action": "paymentmethod#selectPaymentMethod",
"data-paymentmethod-id": "#{payment_method.id}",
"data-paymentmethod-target": "input"
= f.label :payment_method_id, "#{payment_method.name}", for: "payment_method_#{payment_method.id}"
= f.label :payment_method_id, "#{payment_method.display_name}", for: "payment_method_#{payment_method.id}"
%em.fees=payment_or_shipping_price(payment_method, @order)
.paymentmethod-container{"data-paymentmethod-id": "#{payment_method.id}", style: "display: #{payment_method.id == selected_payment_method ? "block" : "none"}"}
- if payment_method.description && !payment_method.description.empty?
.paymentmethod-description.panel
= simple_format(html_escape(payment_method.description))
= simple_format(html_escape(payment_method.display_description))
.paymentmethod-form
= render partial: "checkout/payment/#{payment_method.method_type}", locals: { payment_method: payment_method, f: f }

View File

@@ -30,7 +30,7 @@
- payment_method = last_payment_method(@order)
%div
- if payment_method
= payment_method.name
= payment_method.display_name
%em.fees
= payment_or_shipping_price(payment_method, @order)
- elsif @order.zero_priced_order?
@@ -41,7 +41,7 @@
.summary-subtitle
= t("checkout.step3.payment_method.instructions")
%div
= payment_method&.description
= payment_method&.display_description
.checkout-substep
@@ -56,7 +56,8 @@
.summary-right{ "data-controller": "sticky", "data-sticky-target": "container" }
.summary-right-line.total
.summary-right-line-label= t :order_total_price
.summary-right-line-value#order_total= @order.display_total.to_html
.summary-right-line-value#order_total= @order.display_outstanding_balance.to_html
.summary-right-line
.summary-right-line-label= t :order_produce
@@ -78,6 +79,11 @@
.summary-right-line-label= t :order_includes_tax
.summary-right-line-value#tax-row= display_checkout_tax_total(@order)
- if @paid_with_credit.present?
.summary-right-line
.summary-right-line-label= t :customer_credit
.summary-right-line-value#customer-credit= Spree::Money.new(-1 * @paid_with_credit).to_html
.checkout-submit
- if any_terms_required?(@order.distributor)
= render partial: "terms_and_conditions", locals: { f: f }

View File

@@ -6,21 +6,21 @@
%p
= t :brandstory_intro
#brand-story-text.hide-show.slideable
%p
= t :brandstory_part1
%p
= t :brandstory_part2
%p
= t :brandstory_part3
%p
= t :brandstory_part4
%p
%strong
= t :brandstory_part5_strong
%p
= t :brandstory_part6
%a.text-vbig{"slide-toggle" => "#brand-story-text", "ng-click" => "toggleBrandStory()"}
%i.ofn-i_005-caret-down{"ng-hide" => "brandStoryExpanded"}
%i.ofn-i_006-caret-up{ "ng-show" => "brandStoryExpanded"}
%details#brand-story-text
%summary
%i.ofn-i_005-caret-down
%i.ofn-i_006-caret-up
.brand-story-content
%p
= t :brandstory_part1
%p
= t :brandstory_part2
%p
= t :brandstory_part3
%p
= t :brandstory_part4
%p
%strong
= t :brandstory_part5_strong
%p
= t :brandstory_part6

View File

@@ -5,7 +5,7 @@
- content_for :page_alert do
= render "shared/menu/alert"
%div{"ng-controller" => "HomeCtrl"}
%div
= render "home/tagline"
#panes

View File

@@ -1,6 +0,0 @@
%label{for: path}= name
%input.medium.input-text{attributes}
%small.error.medium.input-text{"ng-show" => "!fieldValid('#{path}')"}
= "{{ fieldErrors('#{path}') }}"

View File

@@ -1,6 +0,0 @@
%label{for: path}= name
= select_tag path, options_for_select(options), attributes
%small.error.medium.input-text{"ng-show" => "!fieldValid('#{path}')"}
= "{{ fieldErrors('#{path}') }}"

View File

@@ -17,4 +17,4 @@
%p.callout{style: "margin-top: 40px"}
%strong
= t :email_payment_description
%p{style: "margin: 5px"}= @order.last_payment_method.description
%p{style: "margin: 5px"}= @order.last_payment_method.display_description

View File

@@ -4,7 +4,7 @@
- content_for :page_title do
= t('.editing_payment_method')
%i.icon-arrow-right
= @payment_method.name
= @payment_method.display_name
- content_for :page_actions do
%li
= button_link_to t('.new'), spree.new_admin_payment_method_path, icon: 'icon-plus'

View File

@@ -32,7 +32,7 @@
%tbody
- @payment_methods.each do |method|
%tr{class: "#{cycle('odd', 'even')}", id: "#{spree_dom_id method}"}
%td.align-center= method.name
%td.align-center= method.display_name
%td.align-center
- method.distributors.each do |distributor|
= distributor.name

View File

@@ -14,7 +14,7 @@
%li
%label
= radio_button_tag 'payment[payment_method_id]', method.id, method == @payment_method, { class: "payment_methods_radios", "ng-model" => 'form_data.payment_method' }
= t(method.name, scope: :payment_methods, default: method.name)
= method.display_name
.payment-method-settings
- @payment_methods.each do |method|
.payment-methods{id: "payment_method_#{method.id}"}

View File

@@ -2,6 +2,10 @@
= render partial: 'spree/admin/shared/order_tabs', locals: { current: 'Payments' }
- content_for :page_actions do
- if @order.payment_state == "credit_owed"
%li#credit_customer_section
= button_link_to t(:credit_customer), admin_order_payments_credit_customer_url(@order), data: { method: :post }
- if @order.outstanding_balance?
%li#new_payment_section
= button_link_to t(:new_payment), new_admin_order_payment_url(@order), icon: 'icon-plus'

View File

@@ -14,7 +14,7 @@
= " - OFN #{t(:administration)}"
%link{:href => "https://fonts.googleapis.com/css?family=Open+Sans:400italic,600italic,400,600&subset=latin,cyrillic,greek,vietnamese", :rel => "stylesheet", :type => "text/css"}
= stylesheet_pack_tag 'admin-style-v3', media: "screen, print"
= stylesheet_pack_tag 'admin-style', media: "screen, print"
= render "layouts/bugsnag_js"
- if content_for? :minimal_js

View File

@@ -4,25 +4,21 @@
#new_variant
%table.index.sortable{"data-sortable-link" => update_positions_admin_product_variants_path(@product)}
%table.index
%colgroup
%col{style: "width: 5%"}/
%col{style: "width: 25%"}/
%col{style: "width: 20%"}/
%col{style: "width: 20%"}/
%col{style: "width: 15%"}/
%col{style: "width: 15%"}/
%col{style: "width: 25%"}/
%col{style: "width: 25%"}/
%col{style: "width: 25%"}/
%thead
%tr
%th{colspan: "2"}= t('.options')
%th= t('.price')
%th= t('.sku')
%th= t('.options')
%th{ style: 'text-align: center;' }= t('.price')
%th{ style: 'text-align: center;' }= t('.sku')
%th.actions
%tbody
- @variants.each do |variant|
%tr{id: spree_dom_id(variant), class: cycle('odd', 'even'), style: "#{"color:red;" if variant.deleted? }" }
%td.no-border
%span.handle
%td= variant.full_name
%td.align-center= variant.display_price.to_html
%td.align-center= variant.sku

View File

@@ -60,10 +60,12 @@
= yield :sidebar
= render "admin/terms_of_service_banner" if tos_need_accepting?
%script
= raw "Spree.api_key = \"#{spree_current_user.try(:spree_api_key).to_s}\";"
= render "layouts/matomo_tag"
= yield :admin_footer
#remote_modal

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