mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-04 02:31:33 +00:00
Compare commits
31 Commits
v4.4.7
...
v4.4.0-mas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd889133cb | ||
|
|
4ac3dda398 | ||
|
|
9d5d269f1f | ||
|
|
f4405775f6 | ||
|
|
3a38361857 | ||
|
|
68b59ab7a6 | ||
|
|
a56541216e | ||
|
|
05d9646f3e | ||
|
|
b1de64bf3e | ||
|
|
e976cc6d95 | ||
|
|
9a89b22364 | ||
|
|
1b304e2aa4 | ||
|
|
48cdca59fd | ||
|
|
9095abfed2 | ||
|
|
aa9fd682d8 | ||
|
|
5b73ccb213 | ||
|
|
dda3cfa58d | ||
|
|
9da649a296 | ||
|
|
2e53b9a0c6 | ||
|
|
527e305e2f | ||
|
|
89b59f97ee | ||
|
|
26d3cffba3 | ||
|
|
86703bb545 | ||
|
|
8e99f496ff | ||
|
|
2f2506e698 | ||
|
|
7ef9c2f56a | ||
|
|
ee4402f751 | ||
|
|
79a2d1228d | ||
|
|
da3202460c | ||
|
|
75ccc5c72f | ||
|
|
aca72e6071 |
6
.env
6
.env
@@ -61,9 +61,3 @@ SMTP_PASSWORD="f00d"
|
||||
# STRIPE_INSTANCE_PUBLISHABLE_KEY="pk_test_xxxx" # This can be a test key or a live key
|
||||
# STRIPE_CLIENT_ID="ca_xxxx" # This can be a development ID or a production ID
|
||||
# STRIPE_ENDPOINT_SECRET="whsec_xxxx"
|
||||
|
||||
# New relic settings
|
||||
# see: https://one.eu.newrelic.com/admin-portal/, Administration > API keys to get the license key
|
||||
# NEW_RELIC_AGENT_ENABLED=true
|
||||
# NEW_RELIC_APP_NAME="Open Food Network"
|
||||
# NEW_RELIC_LICENSE_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/release.md
vendored
8
.github/ISSUE_TEMPLATE/release.md
vendored
@@ -7,21 +7,21 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## 1. Preparation on Thursday
|
||||
## Preparation on Thursday
|
||||
|
||||
- [ ] Merge pull requests in the [Ready To Go] column
|
||||
- [ ] Include translations: `tx pull --force`
|
||||
- [ ] [Draft new release]. Look at previous [releases] for inspiration.
|
||||
- [ ] Notify [#instance-managers] of user-facing changes.
|
||||
|
||||
## 2. Testing
|
||||
## Testing
|
||||
|
||||
- [ ] [Find build] of the release commit and copy it below.
|
||||
- [ ] Move this issue to Test Ready.
|
||||
- [ ] Notify `@testers` in [#testing].
|
||||
- [ ] Test build: <!-- paste build link here, e.g. https://semaphore...builds/1234 -->
|
||||
|
||||
## 3. Finish on Tuesday
|
||||
## Finish on Tuesday
|
||||
|
||||
- [ ] Publish and notify [#global-community] (this is automatically posted with a plugin)
|
||||
- [ ] Deploy the new release to all managed instances.
|
||||
@@ -40,7 +40,7 @@ The full process is described at https://github.com/openfoodfoundation/openfoodn
|
||||
|
||||
[Ready To Go]: #zenhub
|
||||
[Transifex pull request]: https://github.com/openfoodfoundation/openfoodnetwork/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+head%3Atransifex
|
||||
[Draft new release]: https://github.com/openfoodfoundation/openfoodnetwork/releases/new?tag=v&title=v+Code+Name&body=Congrats%0A%0ADescription%0A%0A%23%23+User+facing+changes+:eyes:%0A%0A%0A%23%23%23+Experimental+features+for+testing+:sunglasses:%0A%0A%0A%23%23+Technical+changes+:wrench:%0A%0A
|
||||
[Draft new release]: https://github.com/openfoodfoundation/openfoodnetwork/releases/new?tag=v&title=v+Code+Name&body=Congrats%0A%0ADescription%0A%0A%23%23+User+facing+changes+:eyes:%0A%0A%0A%0A%23%23+Technical+changes+:wrench:%0A%0A
|
||||
[releases]: https://github.com/openfoodfoundation/openfoodnetwork/releases
|
||||
[#instance-managers]: https://app.slack.com/client/T02G54U79/CG7NJ966B
|
||||
[#testing]: https://openfoodnetwork.slack.com/app_redirect?channel=C02TZ6X00
|
||||
|
||||
25
.github/workflows/stage.yml
vendored
25
.github/workflows/stage.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: "Deploy to Staging"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -14,27 +14,23 @@ on:
|
||||
- staging.openfoodnetwork.org.au
|
||||
- staging.coopcircuits.fr
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy_pr:
|
||||
if: contains(fromJSON('["pr-staged-uk", "pr-staged-au", "pr-staged-fr"]'), github.event.label.name)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Check user has write access"
|
||||
uses: "lannonbr/repo-permission-check-action@2.0.2"
|
||||
with:
|
||||
permission: "write"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Configure deployment key
|
||||
if: success()
|
||||
run: |
|
||||
install -m 600 -D /dev/null ~/.ssh/id_rsa
|
||||
echo "${{ secrets.DEPLOYMENT_KEY }}" > ~/.ssh/id_rsa
|
||||
echo "${{ secrets.DEPLOYMENT_HOSTS }}" > ~/.ssh/known_hosts
|
||||
|
||||
- name: Deploy to Staging
|
||||
if: success()
|
||||
env:
|
||||
LABEL: ${{ github.event.label.name }}
|
||||
run: |
|
||||
ssh ofn-deploy@${{ github.event.label.description }} -o LogLevel=ERROR "pull-request-${{ github.event.pull_request.number }} ."
|
||||
|
||||
@@ -42,21 +38,12 @@ jobs:
|
||||
if: ${{ inputs.server }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Check user has write access"
|
||||
uses: "lannonbr/repo-permission-check-action@2.0.2"
|
||||
with:
|
||||
permission: "write"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Configure deployment key
|
||||
if: success()
|
||||
run: |
|
||||
install -m 600 -D /dev/null ~/.ssh/id_rsa
|
||||
echo "${{ secrets.DEPLOYMENT_KEY }}" > ~/.ssh/id_rsa
|
||||
echo "${{ secrets.DEPLOYMENT_HOSTS }}" > ~/.ssh/known_hosts
|
||||
|
||||
- name: Deploy to Staging
|
||||
if: success()
|
||||
run: |
|
||||
ssh ofn-deploy@${{ inputs.server }} -o LogLevel=ERROR "$GITHUB_REF_NAME $GITHUB_SHA"
|
||||
|
||||
@@ -13,8 +13,7 @@ postcss.config.js
|
||||
|
||||
# SCSS
|
||||
# Enabled: most of admin
|
||||
/app/webpacker/css/admin/globals/mixins.scss
|
||||
/app/webpacker/css/admin/globals/variables.scss
|
||||
/app/webpacker/css/admin/globals/
|
||||
/app/webpacker/css/admin/shared/
|
||||
/app/webpacker/css/admin_v3/globals/variables.scss
|
||||
/app/webpacker/css/darkswarm/
|
||||
|
||||
@@ -25,7 +25,6 @@ Metrics/BlockLength:
|
||||
AllowedMethods: [
|
||||
"class_eval",
|
||||
"collection",
|
||||
"configure",
|
||||
"context",
|
||||
"delete",
|
||||
"describe",
|
||||
@@ -45,9 +44,6 @@ Metrics/BlockLength:
|
||||
"xdescribe",
|
||||
]
|
||||
|
||||
Metrics/ParameterLists:
|
||||
CountKeywordArgs: false
|
||||
|
||||
Rails/ApplicationRecord:
|
||||
Exclude:
|
||||
# Migrations should not contain application code:
|
||||
@@ -93,8 +89,6 @@ Naming/VariableNumber:
|
||||
AllowedIdentifiers:
|
||||
- street_address_1
|
||||
- street_address_2
|
||||
AllowedPatterns:
|
||||
- _v[\d]+
|
||||
|
||||
Bundler/DuplicatedGem:
|
||||
Enabled: false
|
||||
|
||||
1015
.rubocop_todo.yml
1015
.rubocop_todo.yml
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
3.1.4
|
||||
3.0.3
|
||||
|
||||
12
Gemfile
12
Gemfile
@@ -1,10 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
ruby "3.0.3"
|
||||
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
|
||||
|
||||
ruby File.read('.ruby-version').chomp
|
||||
|
||||
gem 'dotenv-rails', require: 'dotenv/rails-now' # Load ENV vars before other gems
|
||||
|
||||
gem 'rails'
|
||||
@@ -103,8 +102,8 @@ gem 'redis', '>= 4.0', require: ['redis', 'redis/connection/hiredis']
|
||||
gem 'sidekiq'
|
||||
gem 'sidekiq-scheduler'
|
||||
|
||||
gem "cable_ready", "5.0.1"
|
||||
gem "stimulus_reflex", "3.5.0.rc3"
|
||||
gem "cable_ready", "5.0.0.rc2"
|
||||
gem "stimulus_reflex", "3.5.0.rc2"
|
||||
|
||||
gem 'combine_pdf'
|
||||
gem 'wicked_pdf'
|
||||
@@ -116,6 +115,8 @@ gem 'spreadsheet_architect' # write spreadsheets
|
||||
|
||||
gem 'whenever', require: false
|
||||
|
||||
gem 'test-unit', '~> 3.5'
|
||||
|
||||
gem 'coffee-rails', '~> 5.0.0'
|
||||
|
||||
gem 'angular_rails_csrf'
|
||||
@@ -138,9 +139,8 @@ gem 'mini_portile2', '~> 2.8'
|
||||
gem "faraday"
|
||||
gem "private_address_check"
|
||||
|
||||
gem 'newrelic_rpm'
|
||||
|
||||
group :production, :staging do
|
||||
gem 'ddtrace'
|
||||
gem 'sd_notify' # For better Systemd process management. Used by Puma.
|
||||
end
|
||||
|
||||
|
||||
244
Gemfile.lock
244
Gemfile.lock
@@ -26,6 +26,9 @@ PATH
|
||||
remote: engines/dfc_provider
|
||||
specs:
|
||||
dfc_provider (0.0.1)
|
||||
active_model_serializers (~> 0.8.4)
|
||||
jwt (~> 2.2)
|
||||
rspec (~> 3.9)
|
||||
|
||||
PATH
|
||||
remote: engines/order_management
|
||||
@@ -41,49 +44,49 @@ GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
Ascii85 (1.1.0)
|
||||
actioncable (7.0.6)
|
||||
actionpack (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
actioncable (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (7.0.6)
|
||||
actionpack (= 7.0.6)
|
||||
activejob (= 7.0.6)
|
||||
activerecord (= 7.0.6)
|
||||
activestorage (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
actionmailbox (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activestorage (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.0.6)
|
||||
actionpack (= 7.0.6)
|
||||
actionview (= 7.0.6)
|
||||
activejob (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
actionmailer (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
actionview (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (7.0.6)
|
||||
actionview (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
actionpack (7.0.5)
|
||||
actionview (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
rack (~> 2.0, >= 2.2.4)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionpack-action_caching (1.2.2)
|
||||
actionpack (>= 4.0.0)
|
||||
actiontext (7.0.6)
|
||||
actionpack (= 7.0.6)
|
||||
activerecord (= 7.0.6)
|
||||
activestorage (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
actiontext (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activestorage (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
actionview (7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
@@ -95,19 +98,19 @@ GEM
|
||||
activemodel (>= 5.2.0)
|
||||
activestorage (>= 5.2.0)
|
||||
activesupport (>= 5.2.0)
|
||||
activejob (7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
activejob (7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
globalid (>= 0.3.6)
|
||||
activemerchant (1.123.0)
|
||||
activesupport (>= 4.2)
|
||||
builder (>= 2.1.2, < 4.0.0)
|
||||
i18n (>= 0.6.9)
|
||||
nokogiri (~> 1.4)
|
||||
activemodel (7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
activerecord (7.0.6)
|
||||
activemodel (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
activemodel (7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
activerecord (7.0.5)
|
||||
activemodel (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
activerecord-import (1.4.1)
|
||||
activerecord (>= 4.2)
|
||||
activerecord-postgresql-adapter (0.0.1)
|
||||
@@ -118,14 +121,14 @@ GEM
|
||||
multi_json (~> 1.11, >= 1.11.2)
|
||||
rack (>= 2.0.8, < 3)
|
||||
railties (>= 5.2.4.1)
|
||||
activestorage (7.0.6)
|
||||
actionpack (= 7.0.6)
|
||||
activejob (= 7.0.6)
|
||||
activerecord (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
activestorage (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (7.0.6)
|
||||
activesupport (7.0.5)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@@ -154,35 +157,34 @@ GEM
|
||||
awesome_nested_set (3.5.0)
|
||||
activerecord (>= 4.0.0, < 7.1)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.792.0)
|
||||
aws-sdk-core (3.179.0)
|
||||
aws-partitions (1.779.0)
|
||||
aws-sdk-core (3.174.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.71.0)
|
||||
aws-sdk-core (~> 3, >= 3.177.0)
|
||||
aws-sdk-kms (1.66.0)
|
||||
aws-sdk-core (~> 3, >= 3.174.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.132.0)
|
||||
aws-sdk-core (~> 3, >= 3.179.0)
|
||||
aws-sdk-s3 (1.124.0)
|
||||
aws-sdk-core (~> 3, >= 3.174.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.6)
|
||||
aws-sigv4 (1.6.0)
|
||||
aws-sigv4 (~> 1.4)
|
||||
aws-sigv4 (1.5.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
base64 (0.1.1)
|
||||
bcrypt (3.1.18)
|
||||
bigdecimal (3.0.2)
|
||||
bindata (2.4.15)
|
||||
bindex (0.8.1)
|
||||
bootsnap (1.16.0)
|
||||
msgpack (~> 1.2)
|
||||
bugsnag (6.26.0)
|
||||
bugsnag (6.25.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
builder (3.2.4)
|
||||
bullet (7.0.7)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
cable_ready (5.0.1)
|
||||
cable_ready (5.0.0.rc2)
|
||||
actionpack (>= 5.2)
|
||||
actionview (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
@@ -232,9 +234,15 @@ GEM
|
||||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
database_cleaner-core (2.0.1)
|
||||
datafoodconsortium-connector (1.0.0.pre.alpha.8)
|
||||
virtual_assembly-semantizer (~> 1.0, >= 1.0.5)
|
||||
datafoodconsortium-connector (1.0.0.pre.alpha.6)
|
||||
virtual_assembly-semantizer (~> 1.0, >= 1.0.4)
|
||||
date (3.3.3)
|
||||
ddtrace (1.12.1)
|
||||
debase-ruby_core_source (= 3.2.1)
|
||||
libdatadog (~> 2.0.0.1.0)
|
||||
libddwaf (~> 1.9.0.0.0)
|
||||
msgpack
|
||||
debase-ruby_core_source (3.2.1)
|
||||
debug (1.8.0)
|
||||
irb (>= 1.5.0)
|
||||
reline (>= 0.3.1)
|
||||
@@ -268,7 +276,7 @@ GEM
|
||||
factory_bot_rails (6.2.0)
|
||||
factory_bot (~> 6.2.0)
|
||||
railties (>= 5.0.0)
|
||||
faraday (2.7.10)
|
||||
faraday (2.7.6)
|
||||
faraday-net_http (>= 2.0, < 3.1)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-follow_redirects (0.3.0)
|
||||
@@ -315,7 +323,7 @@ GEM
|
||||
fuubar (2.5.1)
|
||||
rspec-core (~> 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
geocoder (1.8.2)
|
||||
geocoder (1.8.1)
|
||||
globalid (1.1.0)
|
||||
activesupport (>= 5.0)
|
||||
gmaps4rails (2.1.2)
|
||||
@@ -353,20 +361,20 @@ GEM
|
||||
jquery-ui-rails (4.2.1)
|
||||
railties (>= 3.2.16)
|
||||
json (2.6.3)
|
||||
json-canonicalization (0.3.2)
|
||||
json-canonicalization (0.3.1)
|
||||
json-jwt (1.16.3)
|
||||
activesupport (>= 4.2)
|
||||
aes_key_wrap
|
||||
bindata
|
||||
faraday (~> 2.0)
|
||||
faraday-follow_redirects
|
||||
json-ld (3.2.5)
|
||||
json-ld (3.2.3)
|
||||
htmlentities (~> 4.3)
|
||||
json-canonicalization (~> 0.3, >= 0.3.2)
|
||||
json-canonicalization (~> 0.3)
|
||||
link_header (~> 0.0, >= 0.0.8)
|
||||
multi_json (~> 1.15)
|
||||
rack (>= 2.2, < 4)
|
||||
rdf (~> 3.2, >= 3.2.10)
|
||||
rack (~> 2.2)
|
||||
rdf (~> 3.2, >= 3.2.9)
|
||||
json-schema (3.0.0)
|
||||
addressable (>= 2.8)
|
||||
json_spec (1.1.5)
|
||||
@@ -375,13 +383,15 @@ GEM
|
||||
jsonapi-serializer (2.2.0)
|
||||
activesupport (>= 4.2)
|
||||
jwt (2.7.1)
|
||||
knapsack_pro (5.3.5)
|
||||
knapsack_pro (5.1.0)
|
||||
rake
|
||||
language_server-protocol (3.17.0.3)
|
||||
launchy (2.5.0)
|
||||
addressable (~> 2.7)
|
||||
letter_opener (1.8.1)
|
||||
launchy (>= 2.2, < 3)
|
||||
libdatadog (2.0.0.1.0)
|
||||
libddwaf (1.9.0.0.1)
|
||||
ffi (~> 1.0)
|
||||
link_header (0.0.8)
|
||||
listen (3.8.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
@@ -397,16 +407,16 @@ GEM
|
||||
marcel (1.0.2)
|
||||
matrix (0.4.2)
|
||||
method_source (1.0.0)
|
||||
mime-types (3.5.0)
|
||||
mime-types (3.4.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2023.0218.1)
|
||||
mime-types-data (3.2021.0225)
|
||||
mimemagic (0.4.3)
|
||||
nokogiri (~> 1)
|
||||
rake
|
||||
mini_magick (4.11.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.4)
|
||||
minitest (5.18.1)
|
||||
mini_portile2 (2.8.2)
|
||||
minitest (5.18.0)
|
||||
monetize (1.12.0)
|
||||
money (~> 6.12)
|
||||
money (6.16.0)
|
||||
@@ -414,7 +424,7 @@ GEM
|
||||
msgpack (1.7.1)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
net-imap (0.3.6)
|
||||
net-imap (0.3.4)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
@@ -423,9 +433,8 @@ GEM
|
||||
timeout
|
||||
net-smtp (0.3.3)
|
||||
net-protocol
|
||||
newrelic_rpm (9.3.1)
|
||||
nio4r (2.5.9)
|
||||
nokogiri (1.15.3)
|
||||
nokogiri (1.15.2)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
oauth2 (1.4.11)
|
||||
@@ -479,18 +488,19 @@ GEM
|
||||
ruby-rc4
|
||||
ttfunk
|
||||
pg (1.2.3)
|
||||
power_assert (2.0.3)
|
||||
private_address_check (0.5.0)
|
||||
pry (0.13.1)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
public_suffix (5.0.3)
|
||||
public_suffix (5.0.1)
|
||||
puma (6.3.0)
|
||||
nio4r (~> 2.0)
|
||||
query_count (1.1.1)
|
||||
activerecord (>= 4.2)
|
||||
railties (>= 4.2)
|
||||
raabro (1.4.0)
|
||||
racc (1.7.1)
|
||||
racc (1.7.0)
|
||||
rack (2.2.7)
|
||||
rack-mini-profiler (2.3.4)
|
||||
rack (>= 1.2.0)
|
||||
@@ -508,27 +518,26 @@ GEM
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rack-timeout (0.6.3)
|
||||
rails (7.0.6)
|
||||
actioncable (= 7.0.6)
|
||||
actionmailbox (= 7.0.6)
|
||||
actionmailer (= 7.0.6)
|
||||
actionpack (= 7.0.6)
|
||||
actiontext (= 7.0.6)
|
||||
actionview (= 7.0.6)
|
||||
activejob (= 7.0.6)
|
||||
activemodel (= 7.0.6)
|
||||
activerecord (= 7.0.6)
|
||||
activestorage (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
rails (7.0.5)
|
||||
actioncable (= 7.0.5)
|
||||
actionmailbox (= 7.0.5)
|
||||
actionmailer (= 7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
actiontext (= 7.0.5)
|
||||
actionview (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activemodel (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activestorage (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.0.6)
|
||||
railties (= 7.0.5)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
activesupport (>= 5.0.1.rc1)
|
||||
rails-dom-testing (2.1.1)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-erd (1.7.2)
|
||||
activerecord (>= 4.2)
|
||||
@@ -542,9 +551,9 @@ GEM
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
rails_safe_tasks (1.0.0)
|
||||
railties (7.0.6)
|
||||
actionpack (= 7.0.6)
|
||||
activesupport (= 7.0.6)
|
||||
railties (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
@@ -558,7 +567,7 @@ GEM
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rdf (3.2.11)
|
||||
rdf (3.2.9)
|
||||
link_header (~> 0.0, >= 0.0.8)
|
||||
redcarpet (3.6.0)
|
||||
redis (4.8.1)
|
||||
@@ -572,7 +581,7 @@ GEM
|
||||
responders (3.1.0)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rexml (3.2.6)
|
||||
rexml (3.2.5)
|
||||
roadie (5.0.1)
|
||||
css_parser (~> 1.4)
|
||||
nokogiri (~> 1.8)
|
||||
@@ -607,32 +616,30 @@ GEM
|
||||
rspec-support (~> 3.12)
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.12.1)
|
||||
rswag-api (2.10.1)
|
||||
rspec-support (3.12.0)
|
||||
rswag-api (2.9.0)
|
||||
railties (>= 3.1, < 7.1)
|
||||
rswag-specs (2.10.1)
|
||||
rswag-specs (2.9.0)
|
||||
activesupport (>= 3.1, < 7.1)
|
||||
json-schema (>= 2.2, < 4.0)
|
||||
railties (>= 3.1, < 7.1)
|
||||
rspec-core (>= 2.14)
|
||||
rswag-ui (2.10.1)
|
||||
rswag-ui (2.9.0)
|
||||
actionpack (>= 3.1, < 7.1)
|
||||
railties (>= 3.1, < 7.1)
|
||||
rubocop (1.56.0)
|
||||
base64 (~> 0.1.1)
|
||||
rubocop (1.52.1)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.2.2.3)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml (>= 3.2.5, < 4.0)
|
||||
rubocop-ast (>= 1.28.1, < 2.0)
|
||||
rubocop-ast (>= 1.28.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.29.0)
|
||||
parser (>= 3.2.1.0)
|
||||
rubocop-rails (2.20.2)
|
||||
rubocop-rails (2.19.1)
|
||||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
@@ -646,7 +653,7 @@ GEM
|
||||
rubyzip (2.3.2)
|
||||
rufus-scheduler (3.8.2)
|
||||
fugit (~> 1.1, >= 1.1.6)
|
||||
sanitize (6.0.2)
|
||||
sanitize (6.0.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
sass (3.4.25)
|
||||
@@ -688,35 +695,37 @@ GEM
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
sprockets (>= 3.0.0)
|
||||
state_machines (0.6.0)
|
||||
state_machines-activemodel (0.9.0)
|
||||
activemodel (>= 6.0)
|
||||
state_machines (>= 0.6.0)
|
||||
state_machines-activerecord (0.9.0)
|
||||
activerecord (>= 6.0)
|
||||
state_machines-activemodel (>= 0.9.0)
|
||||
stimulus_reflex (3.5.0.rc3)
|
||||
state_machines (0.5.0)
|
||||
state_machines-activemodel (0.8.0)
|
||||
activemodel (>= 5.1)
|
||||
state_machines (>= 0.5.0)
|
||||
state_machines-activerecord (0.8.0)
|
||||
activerecord (>= 5.1)
|
||||
state_machines-activemodel (>= 0.8.0)
|
||||
stimulus_reflex (3.5.0.rc2)
|
||||
actioncable (>= 5.2, < 8)
|
||||
actionpack (>= 5.2, < 8)
|
||||
actionview (>= 5.2, < 8)
|
||||
activesupport (>= 5.2, < 8)
|
||||
cable_ready (~> 5.0)
|
||||
cable_ready (>= 5.0.0.rc2)
|
||||
nokogiri (~> 1.0)
|
||||
rack (>= 2, < 4)
|
||||
railties (>= 5.2, < 8)
|
||||
redis (>= 4.0, < 6.0)
|
||||
stringex (2.8.6)
|
||||
stripe (8.6.0)
|
||||
stripe (8.5.0)
|
||||
swd (1.3.0)
|
||||
activesupport (>= 3)
|
||||
attr_required (>= 0.0.5)
|
||||
httpclient (>= 2.4)
|
||||
temple (0.8.2)
|
||||
test-unit (3.6.0)
|
||||
power_assert
|
||||
thor (1.2.2)
|
||||
thread-local (1.1.0)
|
||||
tilt (2.1.0)
|
||||
timecop (0.9.6)
|
||||
timeout (0.4.0)
|
||||
timeout (0.3.2)
|
||||
ttfunk (1.7.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
@@ -731,8 +740,8 @@ GEM
|
||||
validate_url (1.0.15)
|
||||
activemodel (>= 3.0.0)
|
||||
public_suffix
|
||||
vcr (6.2.0)
|
||||
view_component (3.5.0)
|
||||
vcr (6.1.0)
|
||||
view_component (3.2.0)
|
||||
activesupport (>= 5.2.0, < 8.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
method_source (~> 1.0)
|
||||
@@ -740,7 +749,7 @@ GEM
|
||||
rails (>= 5.2, < 8.0)
|
||||
stimulus_reflex (>= 3.5.0.pre2)
|
||||
view_component (>= 2.28.0)
|
||||
virtual_assembly-semantizer (1.0.5)
|
||||
virtual_assembly-semantizer (1.0.4)
|
||||
json-ld (~> 3.2, >= 3.2.3)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
@@ -799,7 +808,7 @@ DEPENDENCIES
|
||||
bootsnap
|
||||
bugsnag
|
||||
bullet
|
||||
cable_ready (= 5.0.1)
|
||||
cable_ready (= 5.0.0.rc2)
|
||||
cancancan (~> 1.15.0)
|
||||
capybara
|
||||
catalog!
|
||||
@@ -809,6 +818,7 @@ DEPENDENCIES
|
||||
database_cleaner
|
||||
datafoodconsortium-connector
|
||||
db2fog!
|
||||
ddtrace
|
||||
debug (>= 1.0.0)
|
||||
debugger-linecache
|
||||
devise
|
||||
@@ -850,7 +860,6 @@ DEPENDENCIES
|
||||
mimemagic (> 0.3.5)
|
||||
mini_portile2 (~> 2.8)
|
||||
monetize (~> 1.11)
|
||||
newrelic_rpm
|
||||
oauth2 (~> 1.4.7)
|
||||
omniauth-rails_csrf_protection
|
||||
omniauth_openid_connect
|
||||
@@ -898,9 +907,10 @@ DEPENDENCIES
|
||||
spring
|
||||
spring-commands-rspec
|
||||
state_machines-activerecord
|
||||
stimulus_reflex (= 3.5.0.rc3)
|
||||
stimulus_reflex (= 3.5.0.rc2)
|
||||
stringex (~> 2.8.5)
|
||||
stripe
|
||||
test-unit (~> 3.5)
|
||||
timecop
|
||||
valid_email2
|
||||
vcr
|
||||
@@ -915,7 +925,7 @@ DEPENDENCIES
|
||||
wkhtmltopdf-binary
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.1.4p223
|
||||
ruby 3.0.3p157
|
||||
|
||||
BUNDLED WITH
|
||||
2.4.3
|
||||
|
||||
1
Rakefile
1
Rakefile
@@ -7,3 +7,4 @@
|
||||
require_relative 'config/application'
|
||||
|
||||
Openfoodnetwork::Application.load_tasks
|
||||
|
||||
|
||||
@@ -68,6 +68,25 @@
|
||||
//= require textAngular.min.js
|
||||
//= require i18n/translations
|
||||
//= require darkswarm/i18n.translate.js
|
||||
//= require moment/min/moment.min.js
|
||||
//= require moment/locale/ar.js
|
||||
//= require moment/locale/ca.js
|
||||
//= require moment/locale/de.js
|
||||
//= require moment/locale/en-gb.js
|
||||
//= require moment/locale/es.js
|
||||
//= require moment/locale/fil.js
|
||||
//= require moment/locale/fr.js
|
||||
//= require moment/locale/it.js
|
||||
//= require moment/locale/nb.js
|
||||
//= require moment/locale/nl-be.js
|
||||
//= require moment/locale/pt-br.js
|
||||
//= require moment/locale/pt.js
|
||||
//= require moment/locale/ru.js
|
||||
//= require moment/locale/sv.js
|
||||
//= require moment/locale/tr.js
|
||||
//= require moment/locale/pl.js
|
||||
|
||||
//= require js-big-decimal/dist/web/js-big-decimal.min.js
|
||||
|
||||
// foundation
|
||||
//= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js
|
||||
|
||||
@@ -113,7 +113,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
(DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
|
||||
|
||||
editProductUrl = (product, variant) ->
|
||||
"/admin/products/" + product.id + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
"/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
|
||||
$scope.editWarn = (product, variant) ->
|
||||
if confirm_unsaved_changes()
|
||||
@@ -135,7 +135,6 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
display_name: null
|
||||
on_hand: null
|
||||
price: null
|
||||
tax_category_id: null
|
||||
DisplayProperties.setShowVariants product.id, true
|
||||
|
||||
|
||||
@@ -163,7 +162,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
if confirm(t("are_you_sure"))
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/v0/products/" + product.id + "/variants/" + variant.id
|
||||
url: "/api/v0/products/" + product.permalink_live + "/variants/" + variant.id
|
||||
).then (response) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
@@ -347,9 +346,15 @@ filterSubmitProducts = (productsToFilter) ->
|
||||
if product.hasOwnProperty("category_id")
|
||||
filteredProduct.primary_taxon_id = product.category_id
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("tax_category_id")
|
||||
filteredProduct.tax_category_id = product.tax_category_id
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("inherits_properties")
|
||||
filteredProduct.inherits_properties = product.inherits_properties
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("available_on")
|
||||
filteredProduct.available_on = product.available_on
|
||||
hasUpdatableProperty = true
|
||||
if filteredMaster?
|
||||
filteredProduct.master_attributes = filteredMaster
|
||||
hasUpdatableProperty = true
|
||||
@@ -387,9 +392,6 @@ filterSubmitVariant = (variant) ->
|
||||
if variant.hasOwnProperty("display_name")
|
||||
filteredVariant.display_name = variant.display_name
|
||||
hasUpdatableProperty = true
|
||||
if variant.hasOwnProperty("tax_category_id")
|
||||
filteredVariant.tax_category_id = variant.tax_category_id
|
||||
hasUpdatableProperty = true
|
||||
if variant.hasOwnProperty("display_as")
|
||||
filteredVariant.display_as = variant.display_as
|
||||
hasUpdatableProperty = true
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
angular.module("admin.dropdown").directive "linksDropdown", ($window)->
|
||||
restrict: "C"
|
||||
scope:
|
||||
links: "="
|
||||
templateUrl: "admin/links_dropdown.html"
|
||||
@@ -11,5 +11,24 @@
|
||||
|
||||
//= require i18n/translations
|
||||
//= require darkswarm/i18n.translate.js
|
||||
//= require moment/min/moment.min.js
|
||||
//= require moment/locale/ar.js
|
||||
//= require moment/locale/ca.js
|
||||
//= require moment/locale/de.js
|
||||
//= require moment/locale/en-gb.js
|
||||
//= require moment/locale/es.js
|
||||
//= require moment/locale/fil.js
|
||||
//= require moment/locale/fr.js
|
||||
//= require moment/locale/it.js
|
||||
//= require moment/locale/nb.js
|
||||
//= require moment/locale/nl-be.js
|
||||
//= require moment/locale/pt-br.js
|
||||
//= require moment/locale/pt.js
|
||||
//= require moment/locale/ru.js
|
||||
//= require moment/locale/sv.js
|
||||
//= require moment/locale/tr.js
|
||||
//= require moment/locale/pl.js
|
||||
|
||||
window.angular = { module: function(noop){ return { value: function(){} } } }
|
||||
//= require js-big-decimal/dist/web/js-big-decimal.min.js
|
||||
|
||||
window.angular = { module: function(noop){ return { value: function(){} } } }
|
||||
@@ -29,6 +29,24 @@
|
||||
#
|
||||
#= require angular-flash.min.js
|
||||
#
|
||||
#= require moment/min/moment.min.js
|
||||
#= require moment/locale/ar.js
|
||||
#= require moment/locale/ca.js
|
||||
#= require moment/locale/de.js
|
||||
#= require moment/locale/en-gb.js
|
||||
#= require moment/locale/es.js
|
||||
#= require moment/locale/fil.js
|
||||
#= require moment/locale/fr.js
|
||||
#= require moment/locale/it.js
|
||||
#= require moment/locale/nb.js
|
||||
#= require moment/locale/nl-be.js
|
||||
#= require moment/locale/pt-br.js
|
||||
#= require moment/locale/pt.js
|
||||
#= require moment/locale/ru.js
|
||||
#= require moment/locale/sv.js
|
||||
#= require moment/locale/tr.js
|
||||
#= require moment/locale/pl.js
|
||||
#
|
||||
#= require modernizr
|
||||
#
|
||||
#= require foundation-sites/js/foundation.js
|
||||
|
||||
@@ -9,9 +9,10 @@ angular.module('Darkswarm').controller "RegistrationFormCtrl", ($scope, Registra
|
||||
$scope.create = (form) ->
|
||||
if ($scope.valid(form))
|
||||
$scope.disableButton()
|
||||
EnterpriseRegistrationService.create($scope.enableButton).then(() ->
|
||||
EnterpriseRegistrationService.create().then(() ->
|
||||
$scope.enableButton()
|
||||
)
|
||||
end
|
||||
|
||||
$scope.update = (nextStep, form) ->
|
||||
EnterpriseRegistrationService.update(nextStep) if $scope.valid(form)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
.ofn-drop-down
|
||||
%span
|
||||
%i.icon-check
|
||||
{{ 'admin.actions' | t }}
|
||||
%i{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
|
||||
%div.menu{ 'ng-show' => "expanded" }
|
||||
%div{ 'ng-repeat' => "link in links" }
|
||||
%a.menu_item{ 'ng-if': "link.method", href: '{{link.url}}', target: "{{link.target || '_self'}}", data: { method: "{{ link.method }}", "ujs-navigate": "false", confirm: "{{link.confirm}}" } }
|
||||
%span
|
||||
%i{ ng: { class: "link.icon" } }
|
||||
%span {{ link.name }}
|
||||
%a.menu_item{ 'ng-if': "link.confirm && !link.method", href: '{{link.url}}', target: "{{link.target || '_self'}}", "data-confirm": "{{link.confirm}}" }
|
||||
%span
|
||||
%i{ ng: { class: "link.icon" } }
|
||||
%span {{ link.name }}
|
||||
%a.menu_item{ 'ng-if': "!link.confirm && !link.method", href: '{{link.url}}', target: "{{link.target || '_self'}}" }
|
||||
%span
|
||||
%i{ ng: { class: "link.icon" } }
|
||||
%span {{ link.name }}
|
||||
@@ -1,13 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ScopedChannel < ApplicationCable::Channel
|
||||
class << self
|
||||
def for_id(id)
|
||||
"ScopedChannel:#{id}"
|
||||
end
|
||||
end
|
||||
|
||||
def subscribed
|
||||
stream_from "ScopedChannel:#{params[:id]}"
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ConfirmModalComponent < ModalComponent
|
||||
def initialize(id:, confirm_actions: nil, reflex: nil, controller: nil, message: nil,
|
||||
confirm_reflexes: nil)
|
||||
def initialize(id:, confirm_actions: nil, reflex: nil, controller: nil, message: nil, confirm_reflexes: nil)
|
||||
super(id: id, close_button: true)
|
||||
@confirm_actions = confirm_actions
|
||||
@reflex = reflex
|
||||
|
||||
@@ -16,7 +16,7 @@ nav {
|
||||
|
||||
&.inactive {
|
||||
cursor: default;
|
||||
color: $dark-grey;
|
||||
color: $disabled-dark;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ nav {
|
||||
}
|
||||
|
||||
.pagination-gap {
|
||||
color: $dark-grey;
|
||||
color: $disabled-dark;
|
||||
}
|
||||
|
||||
.pagination-page {
|
||||
|
||||
@@ -20,7 +20,7 @@ class ProductComponent < ViewComponentReflex::Component
|
||||
@product.id
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
||||
def column_value(column)
|
||||
case column
|
||||
when 'name'
|
||||
@@ -40,14 +40,16 @@ class ProductComponent < ViewComponentReflex::Component
|
||||
when 'on_demand'
|
||||
@product.on_demand
|
||||
when 'tax_category'
|
||||
@product.variant.tax_category.name
|
||||
@product.tax_category.name
|
||||
when 'inherits_properties'
|
||||
@product.inherits_properties
|
||||
when 'available_on'
|
||||
format_date(@product.available_on)
|
||||
when 'import_date'
|
||||
format_date(@product.import_date)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ class ProductsTableComponent < ViewComponentReflex::Component
|
||||
label: I18n.t("admin.products_page.columns_selector.inherits_properties"),
|
||||
value: "inherits_properties"
|
||||
},
|
||||
{ label: I18n.t("admin.products_page.columns_selector.available_on"), value: "available_on" },
|
||||
{ label: I18n.t("admin.products_page.columns_selector.import_date"), value: "import_date" }
|
||||
].sort do |a, b|
|
||||
a[:label] <=> b[:label]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.search-input {
|
||||
border: 1px solid $light-grey;
|
||||
border: 1px solid $disabled-light;
|
||||
height: 3em;
|
||||
display: flex;
|
||||
line-height: 3em;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
position: relative;
|
||||
|
||||
.selector-main {
|
||||
border: 1px solid $light-grey;
|
||||
border: 1px solid $disabled-light;
|
||||
height: 3em;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
@@ -30,7 +30,7 @@
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 5px solid $light-grey;
|
||||
border-top: 5px solid $disabled-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@
|
||||
z-index: 1;
|
||||
background-color: white;
|
||||
margin-top: -1px;
|
||||
border: 1px solid $light-grey;
|
||||
border: 1px solid $disabled-light;
|
||||
|
||||
.selector-items {
|
||||
overflow-y: auto;
|
||||
@@ -51,7 +51,7 @@
|
||||
.selector-item {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
border-bottom: 1px solid $light-grey;
|
||||
border-bottom: 1px solid $disabled-light;
|
||||
position: relative;
|
||||
height: 3em;
|
||||
line-height: 3em;
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
|
||||
.selector-wrapper {
|
||||
.super-selector-search {
|
||||
border-bottom: 1px solid $light-grey;
|
||||
border-bottom: 1px solid $disabled-light;
|
||||
padding: 10px 5px;
|
||||
|
||||
input {
|
||||
border: 1px solid $light-grey;
|
||||
border: 1px solid $disabled-light;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
|
||||
@@ -12,7 +12,7 @@ module Admin
|
||||
@line_items = order_permissions.
|
||||
editable_line_items.where(order_id: orders).
|
||||
includes(:variant).
|
||||
ransack(params[:q]).result.order(:id)
|
||||
ransack(params[:q]).result
|
||||
|
||||
@pagy, @line_items = pagy(@line_items) if pagination_required?
|
||||
|
||||
@@ -34,8 +34,7 @@ module Admin
|
||||
# and https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE
|
||||
order.with_lock do
|
||||
if order.contents.update_item(@line_item, line_item_params)
|
||||
# No Content, does not trigger ng resource auto-update
|
||||
render body: nil, status: :no_content
|
||||
render body: nil, status: :no_content # No Content, does not trigger ng resource auto-update
|
||||
else
|
||||
render json: { errors: @line_item.errors }, status: :precondition_failed
|
||||
end
|
||||
|
||||
@@ -36,10 +36,8 @@ module Admin
|
||||
end
|
||||
|
||||
def create
|
||||
@customer = Customer.find_or_initialize_by(customer_params.slice(:email, :enterprise_id))
|
||||
|
||||
@customer = Customer.new(customer_params)
|
||||
if user_can_create_customer?
|
||||
@customer.created_manually = true
|
||||
if @customer.save
|
||||
tag_rule_mapping = TagRule.mapping_for(Enterprise.where(id: @customer.enterprise))
|
||||
render_as_json @customer, tag_rule_mapping: tag_rule_mapping
|
||||
@@ -85,7 +83,7 @@ module Admin
|
||||
def customers
|
||||
return @customers if @customers.present?
|
||||
|
||||
@customers = Customer.visible.managed_by(spree_current_user)
|
||||
@customers = Customer.managed_by(spree_current_user)
|
||||
return @customers if params[:enterprise_id].blank?
|
||||
|
||||
@customers = @customers.where(enterprise_id: params[:enterprise_id])
|
||||
|
||||
@@ -6,6 +6,8 @@ module Admin
|
||||
class EnterpriseFeesController < Admin::ResourceController
|
||||
before_action :load_enterprise_fee_set, only: :index
|
||||
before_action :load_data
|
||||
before_action :check_enterprise_fee_input, only: [:bulk_update]
|
||||
before_action :check_calculators_compatibility_with_taxes, only: [:bulk_update]
|
||||
|
||||
def index
|
||||
@include_calculators = params[:include_calculators].present?
|
||||
@@ -34,8 +36,7 @@ module Admin
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
# Forms has strong parameters, so we don't need to validate them in controller
|
||||
@enterprise_fee_set = EnterpriseFeesBulkUpdate.new(params)
|
||||
@enterprise_fee_set = Sets::EnterpriseFeeSet.new(enterprise_fee_bulk_params)
|
||||
|
||||
if @enterprise_fee_set.save
|
||||
redirect_to redirect_path, notice: I18n.t(:enterprise_fees_update_notice)
|
||||
@@ -61,7 +62,9 @@ module Admin
|
||||
when :for_order_cycle
|
||||
order_cycle = OrderCycle.find_by(id: params[:order_cycle_id]) if params[:order_cycle_id]
|
||||
coordinator = Enterprise.find_by(id: params[:coordinator_id]) if params[:coordinator_id]
|
||||
order_cycle ||= OrderCycle.new(coordinator: coordinator) if coordinator.present?
|
||||
if order_cycle.nil? && coordinator.present?
|
||||
order_cycle = OrderCycle.new(coordinator: coordinator)
|
||||
end
|
||||
enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user,
|
||||
order_cycle).visible_enterprises
|
||||
EnterpriseFee.for_enterprises(enterprises).order('enterprise_id', 'fee_type', 'name')
|
||||
@@ -88,5 +91,47 @@ module Admin
|
||||
|
||||
main_app.admin_enterprise_fees_path
|
||||
end
|
||||
|
||||
def enterprise_fee_bulk_params
|
||||
params.require(:sets_enterprise_fee_set).permit(
|
||||
collection_attributes: [
|
||||
:id, :enterprise_id, :fee_type, :name, :tax_category_id,
|
||||
:inherits_tax_category, :calculator_type,
|
||||
{ calculator_attributes: PermittedAttributes::Calculator.attributes }
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check_enterprise_fee_input
|
||||
enterprise_fee_bulk_params['collection_attributes'].each do |_, fee_row|
|
||||
enterprise_fees = fee_row['calculator_attributes']&.slice(
|
||||
:preferred_flat_percent, :preferred_amount,
|
||||
:preferred_first_item, :preferred_additional_item,
|
||||
:preferred_minimal_amount, :preferred_normal_amount,
|
||||
:preferred_discount_amount, :preferred_per_unit
|
||||
)
|
||||
|
||||
next unless enterprise_fees
|
||||
|
||||
enterprise_fees.each do |_, enterprise_amount|
|
||||
unless enterprise_amount.nil? || Float(enterprise_amount, exception: false)
|
||||
flash[:error] = I18n.t(:calculator_preferred_value_error)
|
||||
return redirect_to redirect_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_calculators_compatibility_with_taxes
|
||||
enterprise_fee_bulk_params['collection_attributes'].each do |_, enterprise_fee|
|
||||
next unless enterprise_fee['inherits_tax_category'] == "true"
|
||||
next unless EnterpriseFee::PER_ORDER_CALCULATORS.include?(enterprise_fee['calculator_type'])
|
||||
|
||||
flash[:error] = I18n.t(
|
||||
'activerecord.errors.models.enterprise_fee.inherit_tax_requires_per_item_calculator'
|
||||
)
|
||||
return redirect_to redirect_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,8 +16,7 @@ module Admin
|
||||
@enterprise_relationship = EnterpriseRelationship.new enterprise_relationship_params
|
||||
|
||||
if @enterprise_relationship.save
|
||||
render plain: Api::Admin::EnterpriseRelationshipSerializer
|
||||
.new(@enterprise_relationship).to_json
|
||||
render plain: Api::Admin::EnterpriseRelationshipSerializer.new(@enterprise_relationship).to_json
|
||||
else
|
||||
render status: :bad_request,
|
||||
json: { errors: @enterprise_relationship.errors.full_messages.join(', ') }
|
||||
|
||||
@@ -92,7 +92,7 @@ module Admin
|
||||
return render :welcome, layout: "spree/layouts/bare_admin"
|
||||
end
|
||||
|
||||
attributes = { sells: register_params[:sells], visible: "only_through_links" }
|
||||
attributes = { sells: register_params[:sells], visible: true }
|
||||
|
||||
if @enterprise.update(attributes)
|
||||
flash[:success] = I18n.t(:enterprise_register_success_notice, enterprise: @enterprise.name)
|
||||
@@ -121,12 +121,8 @@ module Admin
|
||||
def for_order_cycle
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render(
|
||||
json: @collection,
|
||||
each_serializer: Api::Admin::ForOrderCycle::EnterpriseSerializer,
|
||||
order_cycle: @order_cycle,
|
||||
spree_current_user: spree_current_user
|
||||
)
|
||||
render json: @collection,
|
||||
each_serializer: Api::Admin::ForOrderCycle::EnterpriseSerializer, order_cycle: @order_cycle, spree_current_user: spree_current_user
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -182,7 +178,9 @@ module Admin
|
||||
when :for_order_cycle
|
||||
@order_cycle = OrderCycle.find_by(id: params[:order_cycle_id]) if params[:order_cycle_id]
|
||||
coordinator = Enterprise.find_by(id: params[:coordinator_id]) if params[:coordinator_id]
|
||||
@order_cycle ||= OrderCycle.new(coordinator: coordinator) if coordinator.present?
|
||||
if @order_cycle.nil? && coordinator.present?
|
||||
@order_cycle = OrderCycle.new(coordinator: coordinator)
|
||||
end
|
||||
|
||||
enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, @order_cycle)
|
||||
.visible_enterprises
|
||||
|
||||
@@ -37,14 +37,8 @@ module Admin
|
||||
end
|
||||
|
||||
def reset_absent_products
|
||||
@importer = ProductImport::ProductImporter.new(
|
||||
File.new(file_path),
|
||||
spree_current_user,
|
||||
import_into: params[:import_into],
|
||||
enterprises_to_reset: params[:enterprises_to_reset],
|
||||
updated_ids: params[:updated_ids],
|
||||
settings: params[:settings]
|
||||
)
|
||||
@importer = ProductImport::ProductImporter.new(File.new(file_path),
|
||||
spree_current_user, import_into: params[:import_into], enterprises_to_reset: params[:enterprises_to_reset], updated_ids: params[:updated_ids], settings: params[:settings])
|
||||
|
||||
if params.key?(:enterprises_to_reset) && params.key?(:updated_ids)
|
||||
@importer.reset_absent(params[:updated_ids])
|
||||
@@ -62,13 +56,8 @@ module Admin
|
||||
end
|
||||
|
||||
def process_data(method)
|
||||
@importer = ProductImport::ProductImporter.new(
|
||||
File.new(file_path),
|
||||
spree_current_user,
|
||||
start: params[:start],
|
||||
end: params[:end],
|
||||
settings: params[:settings]
|
||||
)
|
||||
@importer = ProductImport::ProductImporter.new(File.new(file_path),
|
||||
spree_current_user, start: params[:start], end: params[:end], settings: params[:settings])
|
||||
|
||||
begin
|
||||
@importer.public_send("#{method}_entries")
|
||||
@@ -139,8 +128,7 @@ module Admin
|
||||
end
|
||||
|
||||
def raise_invalid_file_path
|
||||
redirect_to '/admin/product_import',
|
||||
notice: I18n.t(:product_import_no_data_in_spreadsheet_notice)
|
||||
redirect_to '/admin/product_import', notice: I18n.t(:product_import_no_data_in_spreadsheet_notice)
|
||||
raise 'Invalid File Path'
|
||||
end
|
||||
TEMP_FILE_PATH_REGEX = %r{^/tmp/product_import[A-Za-z0-9-]*/import\.csv$}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class ProductsV3Controller < Spree::Admin::BaseController
|
||||
def index; end
|
||||
end
|
||||
end
|
||||
@@ -22,29 +22,24 @@ module Admin
|
||||
def show
|
||||
@report = report_class.new(spree_current_user, params, render: render_data?)
|
||||
|
||||
@background_reports = OpenFoodNetwork::FeatureToggle
|
||||
.enabled?(:background_reports, spree_current_user)
|
||||
|
||||
if @background_reports && request.post?
|
||||
return background(report_format)
|
||||
end
|
||||
|
||||
if params[:report_format].present?
|
||||
export_report
|
||||
else
|
||||
show_report
|
||||
end
|
||||
rescue Timeout::Error
|
||||
render_timeout_error
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def export_report
|
||||
send_data @report.render_as(report_format), filename: report_filename
|
||||
send_data render_report_as(report_format), filename: report_filename
|
||||
end
|
||||
|
||||
def show_report
|
||||
assign_view_data
|
||||
@table = @report.render_as(:html) if render_data?
|
||||
@table = render_report_as(:html) if render_data?
|
||||
render "show"
|
||||
end
|
||||
|
||||
@@ -55,39 +50,51 @@ module Admin
|
||||
@report_title = report_title
|
||||
@rendering_options = rendering_options
|
||||
@data = Reporting::FrontendData.new(spree_current_user)
|
||||
|
||||
variant_id_in = params[:variant_id_in]&.compact_blank
|
||||
load_selected_variant if variant_id_in.present?
|
||||
end
|
||||
|
||||
# Orders and Fulfillment Reports include a per product filter, load any selected product
|
||||
def load_selected_variant
|
||||
variant = Spree::Variant.find(params[:variant_id_in][0])
|
||||
@variant_serialized = Api::Admin::VariantSerializer.new(variant)
|
||||
end
|
||||
|
||||
def render_data?
|
||||
request.post?
|
||||
end
|
||||
|
||||
def background(format)
|
||||
cable_ready[ScopedChannel.for_id(params[:uuid])]
|
||||
.inner_html(
|
||||
selector: "#report-table",
|
||||
html: render_to_string(partial: "admin/reports/loading")
|
||||
).scroll_into_view(
|
||||
selector: "#report-table",
|
||||
block: "start"
|
||||
).broadcast
|
||||
def render_report_as(format)
|
||||
if OpenFoodNetwork::FeatureToggle.enabled?(:background_reports, spree_current_user)
|
||||
@blob = ReportBlob.create_for_upload_later!(report_filename)
|
||||
ReportJob.perform_later(
|
||||
report_class, spree_current_user, params, format, @blob
|
||||
)
|
||||
Timeout.timeout(max_wait_time) do
|
||||
sleep 1 until @blob.content_stored?
|
||||
end
|
||||
|
||||
blob = ReportBlob.create_for_upload_later!(report_filename)
|
||||
# This result has been rendered by Rails in safe mode already.
|
||||
@blob.result.html_safe # rubocop:disable Rails/OutputSafety
|
||||
else
|
||||
@report.render_as(format)
|
||||
end
|
||||
end
|
||||
|
||||
ReportJob.perform_later(
|
||||
report_class: report_class, user: spree_current_user, params: params,
|
||||
format: format, blob: blob, channel: ScopedChannel.for_id(params[:uuid]),
|
||||
)
|
||||
def render_timeout_error
|
||||
assign_view_data
|
||||
if @blob
|
||||
@error = ".report_taking_longer_html"
|
||||
@error_url = @blob.expiring_service_url
|
||||
else
|
||||
@error = ".report_taking_longer"
|
||||
@error_url = ""
|
||||
end
|
||||
render "show"
|
||||
end
|
||||
|
||||
head :no_content
|
||||
def max_wait_time
|
||||
# This value is used by rack-timeout and nginx, usually 30 seconds in
|
||||
# staging and production:
|
||||
server_timeout = ENV.fetch("RACK_TIMEOUT_SERVICE_TIMEOUT", "15").to_f
|
||||
|
||||
# Zero disables the timeout:
|
||||
return 0 if server_timeout.zero?
|
||||
|
||||
# We want to time out earlier than nginx:
|
||||
server_timeout - 2.seconds
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,10 +24,9 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
def update
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to location_after_save }
|
||||
format.js { render layout: false }
|
||||
@@ -37,9 +36,10 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
def create
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to location_after_save }
|
||||
format.js { render layout: false }
|
||||
|
||||
@@ -18,8 +18,7 @@ module Admin
|
||||
if view_context.subscriptions_setup_complete?(@shops)
|
||||
@order_cycles = OrderCycle.joins(:schedules).managed_by(spree_current_user)
|
||||
.includes([:distributors, :cached_incoming_exchanges])
|
||||
@payment_methods = Spree::PaymentMethod.managed_by(spree_current_user)
|
||||
.includes(:taggings)
|
||||
@payment_methods = Spree::PaymentMethod.managed_by(spree_current_user).includes(:taggings)
|
||||
@payment_method_tags = payment_method_tags_by_id
|
||||
@shipping_methods = Spree::ShippingMethod.managed_by(spree_current_user)
|
||||
else
|
||||
@@ -101,8 +100,7 @@ module Admin
|
||||
end
|
||||
|
||||
def load_shops
|
||||
@shops = Enterprise.managed_by(spree_current_user)
|
||||
.is_distributor.where(enable_subscriptions: true)
|
||||
@shops = Enterprise.managed_by(spree_current_user).is_distributor.where(enable_subscriptions: true)
|
||||
end
|
||||
|
||||
def load_form_data
|
||||
@@ -141,9 +139,7 @@ module Admin
|
||||
@open_orders_to_keep = @subscription.proxy_orders.placed_and_open.pluck(:id)
|
||||
return if @open_orders_to_keep.empty? || params[:open_orders] == 'keep'
|
||||
|
||||
render json: {
|
||||
errors: { open_orders: t('admin.subscriptions.confirm_cancel_open_orders_msg') }
|
||||
},
|
||||
render json: { errors: { open_orders: t('admin.subscriptions.confirm_cancel_open_orders_msg') } },
|
||||
status: :conflict
|
||||
end
|
||||
|
||||
@@ -151,9 +147,7 @@ module Admin
|
||||
return if params[:canceled_orders] == 'notified'
|
||||
return if @subscription.proxy_orders.active.canceled.empty?
|
||||
|
||||
render json: {
|
||||
errors: { canceled_orders: t('admin.subscriptions.resume_canceled_orders_msg') }
|
||||
},
|
||||
render json: { errors: { canceled_orders: t('admin.subscriptions.resume_canceled_orders_msg') } },
|
||||
status: :conflict
|
||||
end
|
||||
|
||||
|
||||
@@ -9,11 +9,14 @@ module Admin
|
||||
end
|
||||
|
||||
def create
|
||||
@voucher = Voucher.create(permitted_resource_params.merge(enterprise: @enterprise))
|
||||
voucher_params = permitted_resource_params.merge(enterprise: @enterprise)
|
||||
@voucher = Voucher.create(voucher_params)
|
||||
|
||||
if @voucher.save
|
||||
flash[:success] = flash_message_for(@voucher, :successfully_created)
|
||||
redirect_to edit_admin_enterprise_path(@enterprise, anchor: :vouchers_panel)
|
||||
redirect_to(
|
||||
"#{edit_admin_enterprise_path(@enterprise)}#vouchers_panel",
|
||||
flash: { success: flash_message_for(@voucher, :successfully_created) }
|
||||
)
|
||||
else
|
||||
flash[:error] = @voucher.errors.full_messages.to_sentence
|
||||
render :new
|
||||
|
||||
@@ -6,7 +6,7 @@ module Api
|
||||
skip_authorization_check only: :index
|
||||
|
||||
def index
|
||||
@customers = current_api_user.customers.visible
|
||||
@customers = current_api_user.customers
|
||||
render json: @customers, each_serializer: CustomerSerializer
|
||||
end
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ module Api
|
||||
end
|
||||
|
||||
def override_visible
|
||||
enterprise_params[:visible] = "only_through_links"
|
||||
enterprise_params[:visible] = false
|
||||
end
|
||||
|
||||
def enterprise_params
|
||||
|
||||
@@ -5,6 +5,11 @@ module Api
|
||||
class OrdersController < Api::V0::BaseController
|
||||
include PaginationData
|
||||
|
||||
def show
|
||||
authorize! :read, order
|
||||
render json: order, serializer: Api::OrderDetailedSerializer, current_order: order
|
||||
end
|
||||
|
||||
def index
|
||||
authorize! :admin, Spree::Order
|
||||
|
||||
@@ -21,11 +26,6 @@ module Api
|
||||
}
|
||||
end
|
||||
|
||||
def show
|
||||
authorize! :read, order
|
||||
render json: order, serializer: Api::OrderDetailedSerializer, current_order: order
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :admin, order
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ module Api
|
||||
respond_to :json
|
||||
DEFAULT_PER_PAGE = 15
|
||||
|
||||
before_action :set_default_available_on, only: :create
|
||||
|
||||
skip_authorization_check only: [:show, :bulk_products, :overridable]
|
||||
|
||||
def show
|
||||
@@ -21,10 +23,15 @@ module Api
|
||||
authorize! :create, Spree::Product
|
||||
@product = Spree::Product.new(product_params)
|
||||
|
||||
if @product.save
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: :created
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
begin
|
||||
if @product.save
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: :created
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
@product.permalink = nil
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,6 +96,8 @@ module Api
|
||||
private
|
||||
|
||||
def find_product(id)
|
||||
product_scope.find_by!(permalink: id.to_s)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
product_scope.find(id)
|
||||
end
|
||||
|
||||
@@ -143,6 +152,10 @@ module Api
|
||||
@product_params ||=
|
||||
params.permit(product: PermittedAttributes::Product.attributes)[:product].to_h
|
||||
end
|
||||
|
||||
def set_default_available_on
|
||||
product_params[:available_on] ||= Time.zone.now
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,7 +50,7 @@ module Api
|
||||
private
|
||||
|
||||
def product
|
||||
@product ||= Spree::Product.find(params[:product_id]) if params[:product_id]
|
||||
@product ||= Spree::Product.find_by(permalink: params[:product_id]) if params[:product_id]
|
||||
end
|
||||
|
||||
def scope
|
||||
|
||||
@@ -69,14 +69,14 @@ module Api
|
||||
end
|
||||
|
||||
def missing_parameter(error)
|
||||
message = I18n.t('api.missing_parameter', param: error.param)
|
||||
message = I18n.t(:missing_parameter, param: error.param, scope: :api)
|
||||
|
||||
render status: :unprocessable_entity,
|
||||
json: json_api_error(message)
|
||||
end
|
||||
|
||||
def unpermitted_parameters(error)
|
||||
message = I18n.t('api.unpermitted_parameters', params: error.params.join(", "))
|
||||
message = I18n.t(:unpermitted_parameters, params: error.params.join(", "), scope: :api)
|
||||
|
||||
render status: :unprocessable_entity,
|
||||
json: json_api_error(message)
|
||||
|
||||
@@ -29,8 +29,7 @@ module Api
|
||||
|
||||
def create
|
||||
authorize! :update, Enterprise.find(customer_params[:enterprise_id])
|
||||
customer = Customer.find_or_initialize_by(customer_params.slice(:email, :enterprise_id))
|
||||
customer.assign_attributes(customer_params)
|
||||
customer = Customer.new(customer_params)
|
||||
|
||||
if customer.save
|
||||
render json: Api::V1::CustomerSerializer.new(customer), status: :created
|
||||
@@ -81,7 +80,7 @@ module Api
|
||||
end
|
||||
|
||||
def visible_customers
|
||||
Customer.visible.managed_by(current_api_user)
|
||||
Customer.managed_by(current_api_user)
|
||||
end
|
||||
|
||||
def customer_params
|
||||
@@ -97,7 +96,6 @@ module Api
|
||||
]
|
||||
).to_h
|
||||
|
||||
attributes.merge!(created_manually: true)
|
||||
attributes.merge!(tag_list: params[:tags]) if params.key?(:tags)
|
||||
|
||||
transform_address!(attributes, :billing_address, :bill_address)
|
||||
|
||||
@@ -14,7 +14,7 @@ module CheckoutCallbacks
|
||||
prepend_before_action :require_order_cycle
|
||||
prepend_before_action :require_distributor_chosen
|
||||
|
||||
before_action :load_order, :associate_user, :load_saved_addresses
|
||||
before_action :load_order, :associate_user, :load_saved_addresses, :load_saved_credit_cards
|
||||
before_action :load_shipping_methods, if: -> { params[:step] == "details" }
|
||||
|
||||
before_action :ensure_order_not_completed
|
||||
@@ -30,6 +30,8 @@ module CheckoutCallbacks
|
||||
@order.manual_shipping_selection = true
|
||||
@order.checkout_processing = true
|
||||
|
||||
@voucher_adjustment = @order.voucher_adjustments.first
|
||||
|
||||
redirect_to(main_app.shop_path) && return if redirect_to_shop?
|
||||
redirect_to_cart_path && return unless valid_order_line_items?
|
||||
end
|
||||
@@ -41,6 +43,11 @@ module CheckoutCallbacks
|
||||
@order.ship_address ||= finder.ship_address
|
||||
end
|
||||
|
||||
def load_saved_credit_cards
|
||||
@saved_credit_cards = spree_current_user&.credit_cards&.with_payment_profile.to_a
|
||||
@selected_card = nil
|
||||
end
|
||||
|
||||
def load_shipping_methods
|
||||
@shipping_methods = available_shipping_methods.sort { |a, b| a.name.casecmp(b.name) }
|
||||
end
|
||||
|
||||
@@ -41,8 +41,8 @@ module OrderCompletion
|
||||
main_app.order_path(@order, order_token: @order.token)
|
||||
end
|
||||
|
||||
def order_failed_route(step: 'details')
|
||||
main_app.checkout_step_path(step:)
|
||||
def order_failed_route
|
||||
main_app.checkout_path
|
||||
end
|
||||
|
||||
def order_invalid_for_checkout?
|
||||
@@ -60,8 +60,8 @@ module OrderCompletion
|
||||
|
||||
def process_payment_completion!
|
||||
unless @order.process_payments!
|
||||
payment_failed
|
||||
return redirect_to order_failed_route(step: 'payment')
|
||||
processing_failed
|
||||
return redirect_to order_failed_route
|
||||
end
|
||||
|
||||
if OrderWorkflow.new(@order).next && @order.complete?
|
||||
@@ -82,20 +82,12 @@ module OrderCompletion
|
||||
order_completion_reset(@order)
|
||||
end
|
||||
|
||||
def payment_failed
|
||||
notify_failure
|
||||
end
|
||||
|
||||
def processing_failed
|
||||
notify_failure
|
||||
Checkout::PostCheckoutActions.new(@order).failure
|
||||
end
|
||||
|
||||
def notify_failure(error = RuntimeError.new(order_processing_error))
|
||||
def processing_failed(error = RuntimeError.new(order_processing_error))
|
||||
Bugsnag.notify(error) do |payload|
|
||||
payload.add_metadata :order, @order
|
||||
end
|
||||
flash[:error] = order_processing_error if flash.blank?
|
||||
Checkout::PostCheckoutActions.new(@order).failure
|
||||
end
|
||||
|
||||
def order_processing_error
|
||||
|
||||
@@ -27,11 +27,8 @@ module PaymentGateways
|
||||
redirect_to provider.express_checkout_url(pp_response, useraction: 'commit')
|
||||
else
|
||||
flash[:error] =
|
||||
Spree.t(
|
||||
'flash.generic_error',
|
||||
scope: 'paypal',
|
||||
reasons: pp_response.errors.map(&:long_message).join(" "),
|
||||
)
|
||||
Spree.t('flash.generic_error', scope: 'paypal',
|
||||
reasons: pp_response.errors.map(&:long_message).join(" "))
|
||||
redirect_to main_app.checkout_step_path(:payment)
|
||||
end
|
||||
rescue SocketError
|
||||
|
||||
@@ -24,13 +24,14 @@ class SplitCheckoutController < ::BaseController
|
||||
def edit
|
||||
redirect_to_step_based_on_order unless params[:step]
|
||||
check_step if params[:step]
|
||||
recalculate_tax if params[:step] == "summary"
|
||||
|
||||
return if available_shipping_methods.any?
|
||||
|
||||
flash[:error] = I18n.t('split_checkout.errors.no_shipping_methods_available')
|
||||
flash_error_when_no_shipping_method_available if available_shipping_methods.none?
|
||||
end
|
||||
|
||||
def update
|
||||
return process_voucher if params[:apply_voucher].present?
|
||||
|
||||
if confirm_order || update_order
|
||||
return if performed?
|
||||
|
||||
@@ -60,6 +61,27 @@ class SplitCheckoutController < ::BaseController
|
||||
replace("#flashes", partial("shared/flashes", locals: { flashes: flash }))
|
||||
end
|
||||
|
||||
def render_voucher_section_or_redirect
|
||||
respond_to do |format|
|
||||
format.cable_ready { render_voucher_section }
|
||||
format.html { redirect_to checkout_step_path(:payment) }
|
||||
end
|
||||
end
|
||||
|
||||
# Using the power of cable_car we replace only the #voucher_section instead of reloading the page
|
||||
def render_voucher_section
|
||||
render(
|
||||
status: :ok,
|
||||
cable_ready: cable_car.replace(
|
||||
"#voucher-section",
|
||||
partial(
|
||||
"split_checkout/voucher_section",
|
||||
locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def order_error_messages
|
||||
# Remove ship_address.* errors if no shipping method is not selected
|
||||
remove_ship_address_errors if no_ship_address_needed?
|
||||
@@ -104,6 +126,10 @@ class SplitCheckoutController < ::BaseController
|
||||
end
|
||||
end
|
||||
|
||||
def flash_error_when_no_shipping_method_available
|
||||
flash[:error] = I18n.t('split_checkout.errors.no_shipping_methods_available')
|
||||
end
|
||||
|
||||
def check_payments_adjustments
|
||||
@order.payments.each(&:ensure_correct_adjustment)
|
||||
end
|
||||
@@ -176,6 +202,39 @@ class SplitCheckoutController < ::BaseController
|
||||
selected_shipping_method.first.require_ship_address == false
|
||||
end
|
||||
|
||||
def process_voucher
|
||||
if add_voucher
|
||||
render_voucher_section_or_redirect
|
||||
elsif @order.errors.present?
|
||||
render_error
|
||||
end
|
||||
end
|
||||
|
||||
def add_voucher
|
||||
if params.dig(:order, :voucher_code).blank?
|
||||
@order.errors.add(:voucher, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
# Fetch Voucher
|
||||
voucher = Voucher.find_by(code: params[:order][:voucher_code], enterprise: @order.distributor)
|
||||
|
||||
if voucher.nil?
|
||||
@order.errors.add(:voucher, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
adjustment = voucher.create_adjustment(voucher.code, @order)
|
||||
|
||||
if !adjustment.valid?
|
||||
@order.errors.add(:voucher, I18n.t('split_checkout.errors.add_voucher_error'))
|
||||
adjustment.errors.each { |error| @order.errors.import(error) }
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def summary_step?
|
||||
params[:step] == "summary"
|
||||
end
|
||||
@@ -203,7 +262,6 @@ class SplitCheckoutController < ::BaseController
|
||||
|
||||
def validate_payment!
|
||||
return true if params.dig(:order, :payments_attributes, 0, :payment_method_id).present?
|
||||
return true if @order.zero_priced_order?
|
||||
|
||||
@order.errors.add :payment_method, I18n.t('split_checkout.errors.select_a_payment_method')
|
||||
end
|
||||
@@ -250,4 +308,18 @@ class SplitCheckoutController < ::BaseController
|
||||
redirect_to checkout_step_path(:payment) if params[:step] == "summary"
|
||||
end
|
||||
end
|
||||
|
||||
def recalculate_tax
|
||||
@order.create_tax_charge!
|
||||
@order.update_order!
|
||||
|
||||
apply_voucher if @order.voucher_adjustments.present?
|
||||
end
|
||||
|
||||
def apply_voucher
|
||||
VoucherAdjustmentsService.calculate(@order)
|
||||
|
||||
# update order to take into account the voucher we applied
|
||||
@order.update_order!
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@ module Spree
|
||||
|
||||
def model_class
|
||||
const_name = controller_name.classify
|
||||
return "Spree::#{const_name}".constantize if Object.const_defined?("Spree::#{const_name}")
|
||||
return "Spree::#{const_name}".constantize if Spree.const_defined?(const_name)
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ module Spree
|
||||
# This will make resource controller redirect correctly after deleting product images.
|
||||
# This can be removed after upgrading to Spree 2.1.
|
||||
# See here https://github.com/spree/spree/commit/334a011d2b8e16355e4ae77ae07cd93f7cbc8fd1
|
||||
belongs_to 'spree/product'
|
||||
belongs_to 'spree/product', find_by: :permalink
|
||||
|
||||
before_action :load_data
|
||||
|
||||
@@ -20,10 +20,6 @@ module Spree
|
||||
render layout: !request.xhr?
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def create
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
set_viewable
|
||||
@@ -38,6 +34,10 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
set_viewable
|
||||
@@ -80,7 +80,7 @@ module Spree
|
||||
end
|
||||
|
||||
def load_data
|
||||
@product = Product.find(params[:product_id])
|
||||
@product = Product.find_by(permalink: params[:product_id])
|
||||
end
|
||||
|
||||
def set_viewable
|
||||
|
||||
@@ -4,10 +4,13 @@ module Spree
|
||||
module Admin
|
||||
class InvoicesController < Spree::Admin::BaseController
|
||||
respond_to :json
|
||||
authorize_resource class: false
|
||||
|
||||
def index
|
||||
@order = Spree::Order.find_by(number: params[:order_id])
|
||||
authorize! :invoice, @order
|
||||
def create
|
||||
invoice_service = BulkInvoiceService.new
|
||||
invoice_service.start_pdf_job(params[:order_ids])
|
||||
|
||||
render json: invoice_service.id, status: :ok
|
||||
end
|
||||
|
||||
def show
|
||||
@@ -17,23 +20,6 @@ module Spree
|
||||
send_file(invoice_pdf, type: 'application/pdf', disposition: :inline)
|
||||
end
|
||||
|
||||
def create
|
||||
Spree::Order.where(id: params[:order_ids]).find_each do |order|
|
||||
authorize! :invoice, order
|
||||
end
|
||||
invoice_service = BulkInvoiceService.new
|
||||
invoice_service.start_pdf_job(params[:order_ids])
|
||||
|
||||
render json: invoice_service.id, status: :ok
|
||||
end
|
||||
|
||||
def generate
|
||||
@order = Order.find_by(number: params[:order_id])
|
||||
authorize! :invoice, @order
|
||||
OrderInvoiceGenerator.new(@order).generate_or_update_latest_invoice
|
||||
redirect_back(fallback_location: spree.admin_dashboard_path)
|
||||
end
|
||||
|
||||
def poll
|
||||
invoice_id = params[:invoice_id]
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ module Spree
|
||||
end
|
||||
|
||||
refresh_shipment_rates
|
||||
recalculate_taxes
|
||||
OrderWorkflow.new(@order).advance_to_payment
|
||||
|
||||
flash[:success] = Spree.t('customer_details_updated')
|
||||
@@ -51,6 +52,15 @@ module Spree
|
||||
@order.shipments.map(&:refresh_rates)
|
||||
end
|
||||
|
||||
def recalculate_taxes
|
||||
# If the order's address has been changed, the tax zone could be different,
|
||||
# which means a different set of tax rates might be applicable.
|
||||
@order.create_tax_charge!
|
||||
Spree::TaxRate.adjust(@order, @order.adjustments.admin)
|
||||
|
||||
@order.update_totals_and_states
|
||||
end
|
||||
|
||||
def order_params
|
||||
params.require(:order).permit(
|
||||
:email,
|
||||
|
||||
@@ -99,10 +99,6 @@ module Spree
|
||||
end
|
||||
|
||||
def print
|
||||
if OpenFoodNetwork::FeatureToggle.enabled?(:invoices)
|
||||
@order = @order.invoices.find(params[:invoice_id]).presenter
|
||||
end
|
||||
|
||||
render_with_wicked_pdf InvoiceRenderer.new.args(@order)
|
||||
end
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class ProductPropertiesController < ::Admin::ResourceController
|
||||
belongs_to 'spree/product'
|
||||
belongs_to 'spree/product', find_by: :permalink
|
||||
before_action :find_properties
|
||||
before_action :setup_property, only: [:index]
|
||||
|
||||
|
||||
@@ -16,24 +16,10 @@ module Spree
|
||||
before_action :load_spree_api_key, only: [:index, :variant_overrides]
|
||||
before_action :strip_new_properties, only: [:create, :update]
|
||||
|
||||
def index
|
||||
@current_user = spree_current_user
|
||||
@show_latest_import = params[:latest_import] || false
|
||||
end
|
||||
|
||||
def show
|
||||
session[:return_to] ||= request.referer
|
||||
redirect_to( action: :edit )
|
||||
end
|
||||
|
||||
def new
|
||||
@object.shipping_category = DefaultShippingCategory.find_or_create
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def create
|
||||
delete_stock_params_and_set_after do
|
||||
@object.attributes = permitted_resource_params
|
||||
@@ -49,6 +35,20 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
session[:return_to] ||= request.referer
|
||||
redirect_to( action: :edit )
|
||||
end
|
||||
|
||||
def index
|
||||
@current_user = spree_current_user
|
||||
@show_latest_import = params[:latest_import] || false
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
@@ -103,7 +103,7 @@ module Spree
|
||||
protected
|
||||
|
||||
def find_resource
|
||||
Product.find(params[:id])
|
||||
Product.find_by!(permalink: params[:id])
|
||||
end
|
||||
|
||||
def location_after_save
|
||||
|
||||
@@ -5,12 +5,6 @@ module Spree
|
||||
class TaxonsController < Spree::Admin::BaseController
|
||||
respond_to :html, :json, :js
|
||||
|
||||
def edit
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.find(params[:id])
|
||||
@permalink_part = @taxon.permalink.split("/").last
|
||||
end
|
||||
|
||||
def create
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.build(params[:taxon])
|
||||
@@ -32,6 +26,12 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.find(params[:id])
|
||||
@permalink_part = @taxon.permalink.split("/").last
|
||||
end
|
||||
|
||||
def update
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.find(params[:id])
|
||||
|
||||
@@ -5,19 +5,30 @@ require 'open_food_network/scope_variants_for_search'
|
||||
module Spree
|
||||
module Admin
|
||||
class VariantsController < ::Admin::ResourceController
|
||||
belongs_to 'spree/product'
|
||||
|
||||
before_action :load_data, only: [:new, :edit]
|
||||
belongs_to 'spree/product', find_by: :permalink
|
||||
|
||||
def index
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def new
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def edit
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
redirect_to spree.admin_product_variants_url(params[:product_id], @url_filters)
|
||||
else
|
||||
redirect_to spree.edit_admin_product_variant_url(params[:product_id],
|
||||
@object,
|
||||
@url_filters)
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
@@ -42,19 +53,6 @@ module Spree
|
||||
@object.on_hand = on_hand.to_i if on_hand.present?
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
redirect_to spree.admin_product_variants_url(params[:product_id], @url_filters)
|
||||
else
|
||||
redirect_to spree.edit_admin_product_variant_url(params[:product_id],
|
||||
@object,
|
||||
@url_filters)
|
||||
end
|
||||
end
|
||||
|
||||
def search
|
||||
scoper = OpenFoodNetwork::ScopeVariantsForSearch.new(variant_search_params)
|
||||
@variants = scoper.search
|
||||
@@ -109,12 +107,6 @@ module Spree
|
||||
:include_out_of_stock
|
||||
).to_h.with_indifferent_access
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_data
|
||||
@tax_categories = TaxCategory.order(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -69,10 +69,6 @@ module Spree
|
||||
if @order.contents.update_cart(order_params)
|
||||
@order.recreate_all_fees! # Enterprise fees on line items and on the order itself
|
||||
|
||||
# Re apply the voucher
|
||||
VoucherAdjustmentsService.new(@order).update
|
||||
@order.update_totals_and_states
|
||||
|
||||
if @order.complete?
|
||||
@order.update_payment_fees!
|
||||
@order.create_tax_charge!
|
||||
|
||||
@@ -33,8 +33,8 @@ module Spree
|
||||
render status: :ok, cable_ready: cable_car.
|
||||
inner_html(
|
||||
"#login-feedback",
|
||||
partial("layouts/alert",
|
||||
locals: { type: "alert", message: t('devise.failure.already_registered') })
|
||||
partial("layouts/alert",
|
||||
locals: { type: "alert", message: t('devise.failure.already_registered') })
|
||||
).
|
||||
dispatch_event(name: "login:modal:open")
|
||||
else
|
||||
@@ -48,11 +48,9 @@ module Spree
|
||||
if @user.save
|
||||
render cable_ready: cable_car.inner_html(
|
||||
"#signup-feedback",
|
||||
partial("layouts/alert",
|
||||
locals: {
|
||||
type: "success",
|
||||
message: t('devise.user_registrations.spree_user.signed_up_but_unconfirmed')
|
||||
})
|
||||
partial("layouts/alert",
|
||||
locals: { type: "success",
|
||||
message: t('devise.user_registrations.spree_user.signed_up_but_unconfirmed') })
|
||||
)
|
||||
else
|
||||
render status: :unprocessable_entity, cable_ready: cable_car.morph(
|
||||
|
||||
@@ -5,13 +5,6 @@ class UserConfirmationsController < DeviseController
|
||||
include Spree::Core::ControllerHelpers::Auth
|
||||
include CablecarResponses
|
||||
|
||||
# GET /resource/confirmation?confirmation_token=abcdef
|
||||
def show
|
||||
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
|
||||
|
||||
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource) }
|
||||
end
|
||||
|
||||
# GET /resource/confirmation/new
|
||||
def new
|
||||
build_resource({})
|
||||
@@ -31,8 +24,8 @@ class UserConfirmationsController < DeviseController
|
||||
else
|
||||
render cable_ready: cable_car.inner_html(
|
||||
"##{params[:tab] || 'forgot'}-feedback",
|
||||
partial("layouts/alert",
|
||||
locals: { type: "success", message: t("devise.confirmations.send_instructions") })
|
||||
partial("layouts/alert",
|
||||
locals: { type: "success", message: t("devise.confirmations.send_instructions") })
|
||||
)
|
||||
return
|
||||
end
|
||||
@@ -40,6 +33,13 @@ class UserConfirmationsController < DeviseController
|
||||
respond_with_navigational(resource){ redirect_to login_path }
|
||||
end
|
||||
|
||||
# GET /resource/confirmation?confirmation_token=abcdef
|
||||
def show
|
||||
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
|
||||
|
||||
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource) }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_return_url
|
||||
|
||||
@@ -1,91 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class VoucherAdjustmentsController < BaseController
|
||||
before_action :set_order
|
||||
|
||||
def create
|
||||
if add_voucher
|
||||
update_payment_section
|
||||
elsif @order.errors.present?
|
||||
render_error
|
||||
end
|
||||
end
|
||||
include CablecarResponses
|
||||
|
||||
def destroy
|
||||
# An order can have more than one adjustment linked to one voucher
|
||||
adjustment = @order.voucher_adjustments.find_by(id: params[:id])
|
||||
if adjustment.present?
|
||||
@order.voucher_adjustments.where(originator_id: adjustment.originator_id)&.destroy_all
|
||||
@order = current_order
|
||||
|
||||
@order.voucher_adjustments.find_by(id: params[:id])&.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.cable_ready { render_voucher_section }
|
||||
format.html { redirect_to checkout_step_path(:payment) }
|
||||
end
|
||||
|
||||
# Update order to make sure we display the appropriate payment method
|
||||
@order.update_totals_and_states
|
||||
|
||||
update_payment_section
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_order
|
||||
@order = current_order
|
||||
end
|
||||
|
||||
def add_voucher
|
||||
if voucher_params[:voucher_code].blank?
|
||||
@order.errors.add(:voucher_code, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
voucher = Voucher.find_by(code: voucher_params[:voucher_code], enterprise: @order.distributor)
|
||||
|
||||
if voucher.nil?
|
||||
@order.errors.add(:voucher_code, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
adjustment = voucher.create_adjustment(voucher.code, @order)
|
||||
|
||||
unless adjustment.persisted?
|
||||
@order.errors.add(:voucher_code, I18n.t('split_checkout.errors.add_voucher_error'))
|
||||
adjustment.errors.each { |error| @order.errors.import(error) }
|
||||
return false
|
||||
end
|
||||
|
||||
clear_payments
|
||||
|
||||
VoucherAdjustmentsService.new(@order).update
|
||||
@order.update_totals_and_states
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def update_payment_section
|
||||
render cable_ready: cable_car.replace(
|
||||
selector: "#checkout-payment-methods",
|
||||
html: render_to_string(partial: "split_checkout/payment", locals: { step: "payment" })
|
||||
)
|
||||
end
|
||||
|
||||
def render_error
|
||||
flash.now[:error] = @order.errors.full_messages.to_sentence
|
||||
|
||||
render status: :unprocessable_entity, cable_ready: cable_car.
|
||||
replace("#flashes", partial("shared/flashes", locals: { flashes: flash })).
|
||||
replace(
|
||||
# Using the power of cable_car we replace only the #voucher_section instead of reloading the page
|
||||
def render_voucher_section
|
||||
render(
|
||||
status: :ok,
|
||||
cable_ready: cable_car.replace(
|
||||
"#voucher-section",
|
||||
partial(
|
||||
"split_checkout/voucher_section",
|
||||
locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def voucher_params
|
||||
params.require(:order).permit(:voucher_code)
|
||||
end
|
||||
|
||||
# Clear payments and payment fees, to not affect voucher adjustment calculation
|
||||
def clear_payments
|
||||
@order.payments.incomplete.destroy_all
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class EnterpriseFeesBulkUpdate
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_reader :errors
|
||||
|
||||
validate :check_enterprise_fee_input
|
||||
validate :check_calculators_compatibility_with_taxes
|
||||
|
||||
def initialize(params)
|
||||
@errors = ActiveModel::Errors.new self
|
||||
@params = params
|
||||
end
|
||||
|
||||
def save
|
||||
return false unless valid?
|
||||
|
||||
@enterprise_fee_set = Sets::EnterpriseFeeSet.new(enterprise_fee_bulk_params)
|
||||
unless @enterprise_fee_set.save
|
||||
@enterprise_fee_set.errors.each do |error|
|
||||
@errors.add(error.attribute, error.type)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_enterprise_fee_input
|
||||
enterprise_fee_bulk_params['collection_attributes'].each do |_, fee_row|
|
||||
enterprise_fees = fee_row['calculator_attributes']&.slice(
|
||||
:preferred_flat_percent, :preferred_amount,
|
||||
:preferred_first_item, :preferred_additional_item,
|
||||
:preferred_minimal_amount, :preferred_normal_amount,
|
||||
:preferred_discount_amount, :preferred_per_unit
|
||||
)
|
||||
|
||||
next unless enterprise_fees
|
||||
|
||||
enterprise_fees.each do |_, enterprise_amount|
|
||||
unless enterprise_amount.nil? || Float(enterprise_amount, exception: false)
|
||||
@errors.add(:base, I18n.t(:calculator_preferred_value_error))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_calculators_compatibility_with_taxes
|
||||
enterprise_fee_bulk_params['collection_attributes'].each do |_, enterprise_fee|
|
||||
next unless enterprise_fee['inherits_tax_category'] == "true"
|
||||
next unless EnterpriseFee::PER_ORDER_CALCULATORS.include?(enterprise_fee['calculator_type'])
|
||||
|
||||
@errors.add(
|
||||
:base,
|
||||
I18n.t(
|
||||
'activerecord.errors.models.enterprise_fee.inherit_tax_requires_per_item_calculator'
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def enterprise_fee_bulk_params
|
||||
@params.require(:sets_enterprise_fee_set).permit(
|
||||
collection_attributes: [
|
||||
:id, :enterprise_id, :fee_type, :name, :tax_category_id,
|
||||
:inherits_tax_category, :calculator_type,
|
||||
{ calculator_attributes: PermittedAttributes::Calculator.attributes }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -42,7 +42,7 @@ module Admin
|
||||
{ name: 'shipping_methods', icon_class: "icon-truck", show: show_shipping_methods },
|
||||
{ name: 'payment_methods', icon_class: "icon-money", show: show_payment_methods },
|
||||
{ name: 'enterprise_fees', icon_class: "icon-tasks", show: show_enterprise_fees },
|
||||
{ name: 'vouchers', icon_class: "icon-ticket", show: is_shop },
|
||||
{ name: 'vouchers', icon_class: "icon-ticket", show: true },
|
||||
{ name: 'enterprise_permissions', icon_class: "icon-plug", show: true,
|
||||
href: admin_enterprise_relationships_path },
|
||||
{ name: 'inventory_settings', icon_class: "icon-list-ol", show: is_shop },
|
||||
|
||||
@@ -7,8 +7,7 @@ module AngularFormHelper
|
||||
container.map do |element|
|
||||
html_attributes = option_html_attributes(element)
|
||||
text, value = option_text_and_value(element).map(&:to_s)
|
||||
%(<option value="#{ERB::Util.html_escape(value)}"\
|
||||
#{html_attributes}>#{ERB::Util.html_escape(text)}</option>)
|
||||
%(<option value="#{ERB::Util.html_escape(value)}"#{html_attributes}>#{ERB::Util.html_escape(text)}</option>)
|
||||
end.join("\n").html_safe
|
||||
end
|
||||
|
||||
|
||||
@@ -38,15 +38,15 @@ module ApplicationHelper
|
||||
end.join("\n").html_safe
|
||||
end
|
||||
|
||||
def ng_form_for(name, *args, &)
|
||||
def ng_form_for(name, *args, &block)
|
||||
options = args.extract_options!
|
||||
|
||||
form_for(name, *(args << options.merge(builder: AngularFormBuilder)), &)
|
||||
form_for(name, *(args << options.merge(builder: AngularFormBuilder)), &block)
|
||||
end
|
||||
|
||||
# Pass URL helper calls on to spree where applicable so that we don't need to use
|
||||
# spree.foo_path in any view rendered from non-spree-namespaced controllers.
|
||||
def method_missing(method, *args, &)
|
||||
def method_missing(method, *args, &block)
|
||||
if method.to_s.end_with?('_path', '_url') && spree.respond_to?(method)
|
||||
spree.public_send(method, *args)
|
||||
else
|
||||
|
||||
@@ -120,8 +120,6 @@ module CheckoutHelper
|
||||
end
|
||||
|
||||
def payment_or_shipping_price(method, order)
|
||||
return unless method
|
||||
|
||||
price = method.compute_amount(order)
|
||||
if price.zero?
|
||||
t('checkout_method_free')
|
||||
@@ -141,7 +139,7 @@ module CheckoutHelper
|
||||
def stripe_card_options(cards)
|
||||
cards.map do |cc|
|
||||
[
|
||||
"#{cc.brand} #{cc.last_digits} #{I18n.t(:card_expiry_abbreviation)}:" \
|
||||
"#{cc.brand} #{cc.last_digits} #{I18n.t(:card_expiry_abbreviation)}:"\
|
||||
"#{cc.month.to_s.rjust(2, '0')}/#{cc.year}", cc.id
|
||||
]
|
||||
end
|
||||
|
||||
@@ -77,8 +77,7 @@ module EnterprisesHelper
|
||||
end
|
||||
|
||||
def subscriptions_enabled?
|
||||
spree_current_user.admin? ||
|
||||
spree_current_user.enterprises.where(enable_subscriptions: true).any?
|
||||
spree_current_user.admin? || spree_current_user.enterprises.where(enable_subscriptions: true).any?
|
||||
end
|
||||
|
||||
def enterprise_url_selector(enterprise)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module LinkHelper
|
||||
def link_to_service(baseurl, name, html_options = {}, &)
|
||||
def link_to_service(baseurl, name, html_options = {}, &block)
|
||||
return if name.blank?
|
||||
|
||||
html_options = html_options.merge target: '_blank'
|
||||
link_to(ext_url(baseurl, name), html_options, &)
|
||||
link_to ext_url(baseurl, name), html_options, &block
|
||||
end
|
||||
|
||||
def ext_url(prefix, url)
|
||||
|
||||
@@ -36,13 +36,6 @@ module OrderCyclesHelper
|
||||
shipping_and_payment_methods: true
|
||||
end
|
||||
|
||||
def distributors_with_editable_shipping_and_payment_methods(order_cycle)
|
||||
return order_cycle.distributors if Enterprise
|
||||
.managed_by(spree_current_user).exists?(order_cycle.coordinator.id)
|
||||
|
||||
order_cycle.distributors.managed_by(spree_current_user)
|
||||
end
|
||||
|
||||
def order_cycle_status_class(order_cycle)
|
||||
if order_cycle.undated?
|
||||
'undated'
|
||||
|
||||
@@ -8,14 +8,4 @@ module OrderHelper
|
||||
def outstanding_balance_label(order)
|
||||
order.outstanding_balance.label
|
||||
end
|
||||
|
||||
def show_generate_invoice_button?(order)
|
||||
comparator = order_comparator(order)
|
||||
comparator.can_generate_new_invoice? ||
|
||||
comparator.can_update_latest_invoice?
|
||||
end
|
||||
|
||||
def order_comparator(order)
|
||||
OrderInvoiceComparator.new(order)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,28 +32,7 @@ module ReportsHelper
|
||||
end
|
||||
end
|
||||
|
||||
def fee_name_options(orders)
|
||||
EnterpriseFee.where(id: enterprise_fee_ids(orders))
|
||||
.pluck(:name, :id)
|
||||
end
|
||||
|
||||
def fee_owner_options(orders)
|
||||
Enterprise.where(id: enterprise_fee_owner_ids(orders))
|
||||
.pluck(:name, :id)
|
||||
end
|
||||
|
||||
def currency_symbol
|
||||
Spree::Money.currency_symbol
|
||||
end
|
||||
|
||||
def enterprise_fee_owner_ids(orders)
|
||||
EnterpriseFee.where(id: enterprise_fee_ids(orders))
|
||||
.pluck(:enterprise_id)
|
||||
end
|
||||
|
||||
def enterprise_fee_ids(orders)
|
||||
Spree::Adjustment.enterprise_fee
|
||||
.where(order_id: orders.map(&:id))
|
||||
.pluck(:originator_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
module Spree
|
||||
module Admin
|
||||
module BaseHelper
|
||||
def field_container(model, method, options = {}, &)
|
||||
def field_container(model, method, options = {}, &block)
|
||||
css_classes = options[:class].to_a
|
||||
css_classes << 'field'
|
||||
if error_message_on(model, method).present?
|
||||
css_classes << 'withError'
|
||||
end
|
||||
content_tag(:div,
|
||||
capture(&),
|
||||
capture(&block),
|
||||
class: css_classes.join(' '),
|
||||
id: "#{model}_#{method}_field")
|
||||
end
|
||||
|
||||
@@ -31,7 +31,6 @@ module Spree
|
||||
end
|
||||
|
||||
def invoice_links
|
||||
return [] if OpenFoodNetwork::FeatureToggle.enabled?(:invoices)
|
||||
return [] unless Spree::Config[:enable_invoices?]
|
||||
|
||||
[send_invoice_link, print_invoice_link]
|
||||
|
||||
@@ -18,8 +18,9 @@ module Spree
|
||||
def changeable_orders
|
||||
# Only returns open order for the current user + shop + oc combo
|
||||
return @changeable_orders unless @changeable_orders.nil?
|
||||
return @changeable_orders = [] unless spree_current_user &&
|
||||
current_distributor && current_order_cycle
|
||||
unless spree_current_user && current_distributor && current_order_cycle
|
||||
return @changeable_orders = []
|
||||
end
|
||||
return @changeable_orders = [] unless current_distributor.allow_order_changes?
|
||||
|
||||
@changeable_orders = Spree::Order.complete.where(
|
||||
|
||||
@@ -5,13 +5,11 @@ module Spree
|
||||
def payment_method(payment)
|
||||
# hack to allow us to retrieve the name of a "deleted" payment method
|
||||
id = payment.payment_method_id
|
||||
return if id.nil?
|
||||
|
||||
Spree::PaymentMethod.find_with_destroyed(id)
|
||||
end
|
||||
|
||||
def payment_method_name(payment)
|
||||
payment_method(payment)&.name
|
||||
payment_method(payment).name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,11 +7,4 @@ class ApplicationJob < ActiveJob::Base
|
||||
|
||||
# Most jobs are safe to ignore if the underlying records are no longer available
|
||||
# discard_on ActiveJob::DeserializationError
|
||||
|
||||
private
|
||||
|
||||
def enable_active_storage_urls
|
||||
ActiveStorage::Current.url_options ||=
|
||||
Rails.application.config.action_controller.default_url_options
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,9 +5,13 @@ class BulkInvoiceJob < ApplicationJob
|
||||
delegate :render, to: ActionController::Base
|
||||
|
||||
def perform(order_ids, filepath, options = {})
|
||||
orders = sorted_orders(order_ids)
|
||||
orders.filter!(&:invoiceable?) if OpenFoodNetwork::FeatureToggle.enabled?(:invoices)
|
||||
orders.each(&method(:generate_invoice))
|
||||
pdf = CombinePDF.new
|
||||
|
||||
sorted_orders(order_ids).each do |order|
|
||||
invoice = renderer.render_to_string(order)
|
||||
|
||||
pdf << CombinePDF.parse(invoice)
|
||||
end
|
||||
|
||||
ensure_directory_exists filepath
|
||||
|
||||
@@ -28,17 +32,6 @@ class BulkInvoiceJob < ApplicationJob
|
||||
@renderer ||= InvoiceRenderer.new
|
||||
end
|
||||
|
||||
def generate_invoice(order)
|
||||
renderer_data = if OpenFoodNetwork::FeatureToggle.enabled?(:invoices)
|
||||
OrderInvoiceGenerator.new(order).generate_or_update_latest_invoice
|
||||
order.invoices.first.presenter
|
||||
else
|
||||
order
|
||||
end
|
||||
invoice = renderer.render_to_string(renderer_data)
|
||||
pdf << CombinePDF.parse(invoice)
|
||||
end
|
||||
|
||||
def broadcast(filepath, channel)
|
||||
file_id = filepath.split("/").last.split(".").first
|
||||
|
||||
@@ -54,8 +47,4 @@ class BulkInvoiceJob < ApplicationJob
|
||||
def ensure_directory_exists(filepath)
|
||||
FileUtils.mkdir_p(File.dirname(filepath))
|
||||
end
|
||||
|
||||
def pdf
|
||||
@pdf ||= CombinePDF.new
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,14 +2,9 @@
|
||||
|
||||
# Renders a report and stores it in a given blob.
|
||||
class ReportJob < ApplicationJob
|
||||
include CableReady::Broadcaster
|
||||
delegate :render, to: ActionController::Base
|
||||
|
||||
before_perform :enable_active_storage_urls
|
||||
|
||||
NOTIFICATION_TIME = 5.seconds
|
||||
|
||||
def perform(report_class:, user:, params:, format:, blob:, channel: nil)
|
||||
def perform(report_class, user, params, format, blob)
|
||||
start_time = Time.zone.now
|
||||
|
||||
report = report_class.new(user, params, render: true)
|
||||
@@ -19,8 +14,6 @@ class ReportJob < ApplicationJob
|
||||
execution_time = Time.zone.now - start_time
|
||||
|
||||
email_result(user, blob) if execution_time > NOTIFICATION_TIME
|
||||
|
||||
broadcast_result(channel, format, blob) if channel
|
||||
end
|
||||
|
||||
def email_result(user, blob)
|
||||
@@ -29,17 +22,4 @@ class ReportJob < ApplicationJob
|
||||
blob: blob,
|
||||
).report_ready.deliver_later
|
||||
end
|
||||
|
||||
def broadcast_result(channel, format, blob)
|
||||
cable_ready[channel].inner_html(
|
||||
selector: "#report-table",
|
||||
html: actioncable_content(format, blob)
|
||||
).broadcast
|
||||
end
|
||||
|
||||
def actioncable_content(format, blob)
|
||||
return blob.result if format.to_sym == :html
|
||||
|
||||
render(partial: "admin/reports/download", locals: { file_url: blob.expiring_service_url })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -41,9 +41,7 @@ class SubscriptionConfirmJob < ApplicationJob
|
||||
|
||||
def recently_closed_order_cycles
|
||||
OrderCycle.closed.where(
|
||||
'order_cycles.orders_close_at BETWEEN (?) AND (?) ' \
|
||||
'OR order_cycles.updated_at BETWEEN (?) AND (?)',
|
||||
1.hour.ago, Time.zone.now, 1.hour.ago, Time.zone.now
|
||||
'order_cycles.orders_close_at BETWEEN (?) AND (?) OR order_cycles.updated_at BETWEEN (?) AND (?)', 1.hour.ago, Time.zone.now, 1.hour.ago, Time.zone.now
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -48,14 +48,7 @@ module Spree
|
||||
|
||||
def invoice_email(order_or_order_id)
|
||||
@order = find_order(order_or_order_id)
|
||||
renderer_data = if OpenFoodNetwork::FeatureToggle.enabled?(:invoices)
|
||||
OrderInvoiceGenerator.new(@order).generate_or_update_latest_invoice
|
||||
@order.invoices.first.presenter
|
||||
else
|
||||
@order
|
||||
end
|
||||
|
||||
pdf = InvoiceRenderer.new.render_to_string(renderer_data)
|
||||
pdf = InvoiceRenderer.new.render_to_string(@order)
|
||||
|
||||
attach_file("invoice-#{@order.number}.pdf", pdf)
|
||||
I18n.with_locale valid_locale(@order.user) do
|
||||
|
||||
@@ -13,7 +13,7 @@ module Spree
|
||||
@edit_password_reset_url = spree.
|
||||
edit_spree_user_password_url(reset_password_token: token)
|
||||
subject = "#{Spree::Config[:site_name]} " \
|
||||
"#{I18n.t('spree.user_mailer.reset_password_instructions.subject')}"
|
||||
"#{I18n.t('spree.user_mailer.reset_password_instructions.subject')}"
|
||||
|
||||
I18n.with_locale valid_locale(user) do
|
||||
mail(to: user.email, subject: subject)
|
||||
|
||||
@@ -38,16 +38,14 @@ class SubscriptionMailer < ApplicationMailer
|
||||
@shop = Enterprise.find(summary.shop_id)
|
||||
@summary = summary
|
||||
mail(to: @shop.contact.email,
|
||||
subject: "#{Spree::Config[:site_name]} " \
|
||||
"#{t('subscription_mailer.placement_summary_email.subject')}")
|
||||
subject: "#{Spree::Config[:site_name]} #{t('subscription_mailer.placement_summary_email.subject')}")
|
||||
end
|
||||
|
||||
def confirmation_summary_email(summary)
|
||||
@shop = Enterprise.find(summary.shop_id)
|
||||
@summary = summary
|
||||
mail(to: @shop.contact.email,
|
||||
subject: "#{Spree::Config[:site_name]} " \
|
||||
"#{t('subscription_mailer.confirmation_summary_email.subject')}")
|
||||
subject: "#{Spree::Config[:site_name]} #{t('subscription_mailer.confirmation_summary_email.subject')}")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -15,16 +15,6 @@ class ApplicationRecord < ActiveRecord::Base
|
||||
ENV["S3_BUCKET"].present? ? :amazon_public : :local
|
||||
end
|
||||
|
||||
# We might have a development environment without S3 but with a database
|
||||
# dump pointing to S3 images. Accessing the service fails then.
|
||||
def image_variant_url_for(variant)
|
||||
if ENV["S3_BUCKET"].present? && variant.service.public?
|
||||
variant.processed.url
|
||||
else
|
||||
url_for(variant)
|
||||
end
|
||||
end
|
||||
|
||||
def url_for(*args)
|
||||
Rails.application.routes.url_helpers.url_for(*args)
|
||||
end
|
||||
|
||||
@@ -45,7 +45,7 @@ module Calculator
|
||||
|
||||
def line_items_total(order)
|
||||
matched_line_items = order.line_items.select do |line_item|
|
||||
line_item.variant.tax_category == rate.tax_category
|
||||
line_item.product.tax_category == rate.tax_category
|
||||
end
|
||||
|
||||
matched_line_items.sum(&:total)
|
||||
@@ -70,7 +70,7 @@ module Calculator
|
||||
def applicable_rate?(applicator, line_item)
|
||||
fee = applicator.enterprise_fee
|
||||
(!fee.inherits_tax_category && fee.tax_category == rate.tax_category) ||
|
||||
(fee.inherits_tax_category && line_item.variant.tax_category == rate.tax_category)
|
||||
(fee.inherits_tax_category && line_item.product.tax_category == rate.tax_category)
|
||||
end
|
||||
|
||||
# Finds relevant fees for whole order,
|
||||
|
||||
@@ -35,7 +35,7 @@ module Calculator
|
||||
private
|
||||
|
||||
def compute_for(count)
|
||||
(count * preferred_additional_item.to_f) + preferred_first_item.to_f
|
||||
count * preferred_additional_item.to_f + preferred_first_item.to_f
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ require 'active_support/concern'
|
||||
|
||||
# This module is an adapter for OFN to work with Spree 2 code.
|
||||
#
|
||||
# Although Spree 2 supports multiple shipments per order, in OFN we have only 1 shipment per order.
|
||||
# Although Spree 2 supports multiple shipments per order, in OFN we have only one shipment per order.
|
||||
# A shipment is associated to a shipping_method through a selected shipping_rate.
|
||||
# See https://github.com/openfoodfoundation/openfoodnetwork/wiki/Spree-Upgrade:-Migration-to-multiple-shipments
|
||||
# for details.
|
||||
@@ -30,8 +30,7 @@ module OrderShipment
|
||||
shipments.first.shipping_method
|
||||
end
|
||||
|
||||
# Finds the shipment's shipping_rate for the given shipping_method_id
|
||||
# and selects that shipping_rate.
|
||||
# Finds the shipment's shipping_rate for the given shipping_method_id and selects that shipping_rate.
|
||||
# If the selection is successful, it persists it in the database by saving the shipment.
|
||||
# If it fails, it does not clear the current shipping_method selection.
|
||||
#
|
||||
|
||||
@@ -6,8 +6,7 @@ module ProductStock
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def on_demand
|
||||
raise 'Cannot determine product on_demand value of product with multiple variants' if
|
||||
variants.size > 1
|
||||
raise 'Cannot determine product on_demand value of product with multiple variants' if variants.size > 1
|
||||
|
||||
variants.first.on_demand
|
||||
end
|
||||
|
||||
@@ -42,8 +42,7 @@ module VariantStock
|
||||
# Checks whether this variant is produced on demand.
|
||||
def on_demand
|
||||
# A variant that has not been saved yet or has been soft-deleted doesn't have a stock item
|
||||
# This provides a default value for variant.on_demand
|
||||
# using Spree::StockLocation.backorderable_default
|
||||
# This provides a default value for variant.on_demand using Spree::StockLocation.backorderable_default
|
||||
return Spree::StockLocation.first.backorderable_default if new_record? || deleted?
|
||||
|
||||
# This can be removed unless we have seen this error in Bugsnag recently
|
||||
@@ -77,10 +76,8 @@ module VariantStock
|
||||
end
|
||||
end
|
||||
|
||||
# Moving Spree::Stock::Quantifier.can_supply? to the variant enables us
|
||||
# to override this behaviour for variant overrides
|
||||
# We can have this responsibility here in the variant because there is
|
||||
# only one stock item per variant
|
||||
# Moving Spree::Stock::Quantifier.can_supply? to the variant enables us to override this behaviour for variant overrides
|
||||
# We can have this responsibility here in the variant because there is only one stock item per variant
|
||||
#
|
||||
# Here we depend only on variant.total_on_hand and variant.on_demand.
|
||||
# This way, variant_overrides only need to override variant.total_on_hand and variant.on_demand.
|
||||
@@ -88,10 +85,8 @@ module VariantStock
|
||||
on_demand || total_on_hand >= quantity
|
||||
end
|
||||
|
||||
# Moving Spree::StockLocation.fill_status to the variant enables us
|
||||
# to override this behaviour for variant overrides
|
||||
# We can have this responsibility here in the variant because there is
|
||||
# only one stock item per variant
|
||||
# Moving Spree::StockLocation.fill_status to the variant enables us to override this behaviour for variant overrides
|
||||
# We can have this responsibility here in the variant because there is only one stock item per variant
|
||||
#
|
||||
# Here we depend only on variant.total_on_hand and variant.on_demand.
|
||||
# This way, variant_overrides only need to override variant.total_on_hand and variant.on_demand.
|
||||
@@ -107,8 +102,7 @@ module VariantStock
|
||||
[on_hand, backordered]
|
||||
end
|
||||
|
||||
# We can have this responsibility here in the variant because there is
|
||||
# only one stock item per variant
|
||||
# We can have this responsibility here in the variant because there is only one stock item per variant
|
||||
#
|
||||
# This enables us to override this behaviour for variant overrides
|
||||
def move(quantity, originator = nil)
|
||||
@@ -144,8 +138,7 @@ module VariantStock
|
||||
|
||||
# Overwrites stock_item.count_on_hand
|
||||
#
|
||||
# Calling stock_item.adjust_count_on_hand will bypass filling backorders
|
||||
# and creating stock movements
|
||||
# Calling stock_item.adjust_count_on_hand will bypass filling backorders and creating stock movements
|
||||
# If that was required we could call self.move
|
||||
def overwrite_stock_levels(new_level)
|
||||
stock_item.adjust_count_on_hand(new_level.to_i - stock_item.count_on_hand)
|
||||
|
||||
@@ -19,9 +19,6 @@ class Customer < ApplicationRecord
|
||||
belongs_to :enterprise
|
||||
belongs_to :user, class_name: "Spree::User", optional: true
|
||||
has_many :orders, class_name: "Spree::Order"
|
||||
before_validation :downcase_email
|
||||
before_validation :empty_code
|
||||
before_create :associate_user
|
||||
before_destroy :update_orders_and_delete_canceled_subscriptions
|
||||
|
||||
belongs_to :bill_address, class_name: "Spree::Address", optional: true
|
||||
@@ -32,19 +29,17 @@ class Customer < ApplicationRecord
|
||||
alias_attribute :shipping_address, :ship_address
|
||||
accepts_nested_attributes_for :ship_address
|
||||
|
||||
before_validation :downcase_email
|
||||
before_validation :empty_code
|
||||
|
||||
validates :code, uniqueness: { scope: :enterprise_id, allow_nil: true }
|
||||
validates :email, presence: true, 'valid_email_2/email': true,
|
||||
uniqueness: {
|
||||
scope: :enterprise_id,
|
||||
message: I18n.t('validation_msg_is_associated_with_an_exising_customer')
|
||||
}
|
||||
uniqueness: { scope: :enterprise_id, message: I18n.t('validation_msg_is_associated_with_an_exising_customer') }
|
||||
|
||||
scope :of, ->(enterprise) { where(enterprise_id: enterprise) }
|
||||
scope :managed_by, ->(user) {
|
||||
user&.persisted? ? where(user: user).or(of(Enterprise.managed_by(user))) : none
|
||||
}
|
||||
scope :created_manually, -> { where(created_manually: true) }
|
||||
scope :visible, -> { where(id: Spree::Order.complete.select(:customer_id)).or(created_manually) }
|
||||
scope :managed_by, ->(user) { user&.persisted? ? where(user: user).or(of(Enterprise.managed_by(user))) : none }
|
||||
|
||||
before_create :associate_user
|
||||
|
||||
attr_accessor :gateway_recurring_payment_client_secret, :gateway_shop_id
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ class Enterprise < ApplicationRecord
|
||||
belongs_to :owner, class_name: 'Spree::User',
|
||||
inverse_of: :owned_enterprises
|
||||
has_many :distributor_payment_methods,
|
||||
inverse_of: :distributor, foreign_key: :distributor_id
|
||||
inverse_of: :distributor, foreign_key: :distributor_id
|
||||
has_many :distributor_shipping_methods,
|
||||
inverse_of: :distributor, foreign_key: :distributor_id
|
||||
inverse_of: :distributor, foreign_key: :distributor_id
|
||||
has_many :payment_methods, through: :distributor_payment_methods
|
||||
has_many :shipping_methods, through: :distributor_shipping_methods
|
||||
has_many :customers
|
||||
@@ -91,7 +91,7 @@ class Enterprise < ApplicationRecord
|
||||
end
|
||||
has_one_attached :white_label_logo, service: image_service do |attachment|
|
||||
attachment.variant :default, resize_to_fill: [217, 44]
|
||||
attachment.variant :mobile, resize_to_fill: [128, 26]
|
||||
attachment.variant :mobile, resize_to_fill: [75, 26]
|
||||
end
|
||||
|
||||
validates :logo,
|
||||
@@ -114,23 +114,24 @@ class Enterprise < ApplicationRecord
|
||||
validate :shopfront_taxons
|
||||
validate :shopfront_producers
|
||||
validate :enforce_ownership_limit, if: lambda { owner_id_changed? && !owner_id.nil? }
|
||||
validates :instagram,
|
||||
format: {
|
||||
with: VALID_INSTAGRAM_REGEX,
|
||||
message: Spree.t('errors.messages.invalid_instagram_url')
|
||||
}, allow_blank: true
|
||||
validates :instagram,
|
||||
format: {
|
||||
with: VALID_INSTAGRAM_REGEX,
|
||||
message: Spree.t('errors.messages.invalid_instagram_url')
|
||||
}, allow_blank: true
|
||||
validate :validate_white_label_logo_link
|
||||
|
||||
before_validation :initialize_permalink, if: lambda { permalink.nil? }
|
||||
before_validation :set_unused_address_fields
|
||||
after_validation :ensure_owner_is_manager, if: lambda { owner_id_changed? && !owner_id.nil? }
|
||||
|
||||
after_touch :touch_distributors
|
||||
after_create :set_default_contact
|
||||
after_create :relate_to_owners_enterprises
|
||||
after_rollback :restore_permalink
|
||||
after_touch :touch_distributors
|
||||
after_create_commit :send_welcome_email
|
||||
|
||||
after_rollback :restore_permalink
|
||||
|
||||
scope :by_name, -> { order('name') }
|
||||
scope :visible, -> { where(visible: "public") }
|
||||
scope :not_hidden, -> { where.not(visible: "hidden") }
|
||||
@@ -358,7 +359,7 @@ class Enterprise < ApplicationRecord
|
||||
def category
|
||||
# Make this crazy logic human readable so we can argue about it sanely.
|
||||
cat = is_primary_producer ? "producer_" : "non_producer_"
|
||||
cat << ("sells_" + sells)
|
||||
cat << "sells_" + sells
|
||||
|
||||
# Map backend cases to front end cases.
|
||||
case cat
|
||||
@@ -458,10 +459,10 @@ class Enterprise < ApplicationRecord
|
||||
|
||||
def image_url_for(image, name)
|
||||
return unless image.variable?
|
||||
return image.variant(name).processed.url if image.attachment.service.name == :amazon_public
|
||||
|
||||
image_variant_url_for(image.variant(name))
|
||||
rescue ActiveStorage::Error, MiniMagick::Error, ActionView::Template::Error => e
|
||||
Bugsnag.notify "Enterprise ##{id} #{image.try(:name)} error: #{e.message}"
|
||||
url_for(image.variant(name))
|
||||
rescue ActiveStorage::Error => e
|
||||
Rails.logger.error(e.message)
|
||||
|
||||
nil
|
||||
@@ -492,7 +493,7 @@ class Enterprise < ApplicationRecord
|
||||
end
|
||||
|
||||
def correct_whatsapp_url(phone_number)
|
||||
phone_number && ("https://wa.me/" + phone_number.tr('+ ', ''))
|
||||
phone_number && "https://wa.me/" + phone_number.tr('+ ', '')
|
||||
end
|
||||
|
||||
def correct_instagram_url(url)
|
||||
@@ -504,10 +505,7 @@ class Enterprise < ApplicationRecord
|
||||
end
|
||||
|
||||
def set_unused_address_fields
|
||||
if address.present?
|
||||
address.firstname = address.lastname = address.phone =
|
||||
address.company = 'unused'
|
||||
end
|
||||
address.firstname = address.lastname = address.phone = address.company = 'unused' if address.present?
|
||||
business_address.first_name = business_address.last_name = 'unused' if business_address.present?
|
||||
end
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ class EnterpriseGroup < ApplicationRecord
|
||||
validates :address, presence: true, associated: true
|
||||
before_validation :set_undefined_address_fields
|
||||
before_validation :set_unused_address_fields
|
||||
before_validation :sanitize_permalink
|
||||
after_save :unset_undefined_address_fields
|
||||
after_find :unset_undefined_address_fields
|
||||
after_save :unset_undefined_address_fields
|
||||
|
||||
validates :name, presence: true
|
||||
validates :description, presence: true
|
||||
|
||||
before_validation :sanitize_permalink
|
||||
validates :permalink, uniqueness: true, presence: true
|
||||
|
||||
delegate :phone, :address1, :address2, :city, :zipcode, :state, :country, to: :address
|
||||
|
||||
@@ -11,9 +11,9 @@ class EnterpriseRelationship < ApplicationRecord
|
||||
message: I18n.t('validation_msg_relationship_already_established')
|
||||
}
|
||||
|
||||
after_save :update_permissions_of_child_variant_overrides
|
||||
before_destroy :revoke_all_child_variant_overrides
|
||||
before_destroy :destroy_related_exchanges
|
||||
after_save :update_permissions_of_child_variant_overrides
|
||||
|
||||
scope :with_enterprises, -> {
|
||||
joins("
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Invoice < ApplicationRecord
|
||||
belongs_to :order, class_name: 'Spree::Order'
|
||||
serialize :data, Hash
|
||||
before_validation :serialize_order
|
||||
after_create :cancel_previous_invoices
|
||||
default_scope { order(created_at: :desc) }
|
||||
|
||||
def presenter
|
||||
@presenter ||= Invoice::DataPresenter.new(self)
|
||||
end
|
||||
|
||||
def serialize_order
|
||||
return data unless data.empty?
|
||||
|
||||
self.data = Invoice::OrderSerializer.new(order).serializable_hash
|
||||
end
|
||||
|
||||
def cancel_previous_invoices
|
||||
order.invoices.where.not(id:).update_all(cancelled: true)
|
||||
end
|
||||
end
|
||||
@@ -1,134 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
attr_reader :invoice
|
||||
|
||||
delegate :data, to: :invoice
|
||||
delegate :number, :date, to: :invoice, prefix: true
|
||||
|
||||
FINALIZED_NON_SUCCESSFUL_STATES = %w(canceled returned).freeze
|
||||
|
||||
extend Invoice::DataPresenterAttributes
|
||||
|
||||
attributes :additional_tax_total, :currency, :included_tax_total, :payment_total,
|
||||
:shipping_method_id, :state, :total, :number, :note, :special_instructions,
|
||||
:completed_at
|
||||
|
||||
attributes_with_presenter :bill_address, :customer, :distributor, :ship_address,
|
||||
:shipping_method, :order_cycle
|
||||
|
||||
array_attribute :sorted_line_items, class_name: 'LineItem'
|
||||
array_attribute :all_eligible_adjustments, class_name: 'Adjustment'
|
||||
array_attribute :payments, class_name: 'Payment'
|
||||
|
||||
# if any of the following attributes is updated, a new invoice should be generated
|
||||
invoice_generation_attributes :additional_tax_total, :all_eligible_adjustments, :bill_address,
|
||||
:included_tax_total, :payments, :payment_total, :ship_address,
|
||||
:shipping_method_id, :sorted_line_items, :total
|
||||
|
||||
# if any of the following attributes is updated, the latest invoice should be updated
|
||||
invoice_update_attributes :note, :special_instructions, :state,
|
||||
:all_eligible_adjustments, :payments
|
||||
|
||||
def initialize(invoice)
|
||||
@invoice = invoice
|
||||
end
|
||||
|
||||
def has_taxes_included
|
||||
included_tax_total > 0
|
||||
end
|
||||
|
||||
def total_tax
|
||||
additional_tax_total + included_tax_total
|
||||
end
|
||||
|
||||
def order_completed_at
|
||||
return nil if data[:completed_at].blank?
|
||||
|
||||
Time.zone.parse(data[:completed_at])
|
||||
end
|
||||
|
||||
def checkout_adjustments(exclude: [], reject_zero_amount: true)
|
||||
adjustments = all_eligible_adjustments
|
||||
|
||||
adjustments.reject! { |a| a.originator_type == 'Spree::TaxRate' }
|
||||
|
||||
if exclude.include? :line_item
|
||||
adjustments.reject! { |a|
|
||||
a.adjustable_type == 'Spree::LineItem'
|
||||
}
|
||||
end
|
||||
|
||||
if reject_zero_amount
|
||||
adjustments.reject! { |a| a.amount == 0 }
|
||||
end
|
||||
|
||||
adjustments
|
||||
end
|
||||
|
||||
def display_checkout_taxes_hash
|
||||
totals = OrderTaxAdjustmentsFetcher.new(nil).totals(all_tax_adjustments)
|
||||
|
||||
totals.map do |tax_rate, tax_amount|
|
||||
{
|
||||
amount: Spree::Money.new(tax_amount, currency: order.currency),
|
||||
percentage: number_to_percentage(tax_rate.amount * 100, precision: 1),
|
||||
rate_amount: tax_rate.amount,
|
||||
}
|
||||
end.sort_by { |tax| tax[:rate_amount] }
|
||||
end
|
||||
|
||||
def display_date
|
||||
I18n.l(invoice_date.to_date, format: :long)
|
||||
end
|
||||
|
||||
def all_tax_adjustments
|
||||
all_eligible_adjustments.select { |a| a.originator_type == 'Spree::TaxRate' }
|
||||
end
|
||||
|
||||
def paid?
|
||||
data[:payment_state] == 'paid' || data[:payment_state] == 'credit_owed'
|
||||
end
|
||||
|
||||
def outstanding_balance?
|
||||
!new_outstanding_balance.zero?
|
||||
end
|
||||
|
||||
def new_outstanding_balance
|
||||
if state.in?(FINALIZED_NON_SUCCESSFUL_STATES)
|
||||
-payment_total
|
||||
else
|
||||
total - payment_total
|
||||
end
|
||||
end
|
||||
|
||||
def outstanding_balance_label
|
||||
new_outstanding_balance.negative? ? I18n.t(:credit_owed) : I18n.t(:balance_due)
|
||||
end
|
||||
|
||||
def last_payment
|
||||
payments.max_by(&:created_at)
|
||||
end
|
||||
|
||||
def last_payment_method
|
||||
last_payment&.payment_method
|
||||
end
|
||||
|
||||
def display_outstanding_balance
|
||||
Spree::Money.new(new_outstanding_balance, currency: currency)
|
||||
end
|
||||
|
||||
def display_checkout_tax_total
|
||||
Spree::Money.new(total_tax, currency: currency)
|
||||
end
|
||||
|
||||
def display_checkout_total_less_tax
|
||||
Spree::Money.new(total - total_tax, currency: currency)
|
||||
end
|
||||
|
||||
def display_total
|
||||
Spree::Money.new(total, currency: currency)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,38 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
class Address < Invoice::DataPresenter::Base
|
||||
attributes :firstname, :lastname, :address1, :address2, :city, :zipcode, :company, :phone
|
||||
attributes_with_presenter :state
|
||||
invoice_generation_attributes :firstname, :lastname, :address1, :address2, :city, :zipcode,
|
||||
:company, :phone
|
||||
|
||||
def full_name
|
||||
"#{firstname} #{lastname}".strip
|
||||
end
|
||||
|
||||
def address_part1
|
||||
render_address([address1, address2])
|
||||
end
|
||||
|
||||
def address_part2
|
||||
render_address([city, zipcode, state&.name])
|
||||
end
|
||||
|
||||
def full_address
|
||||
render_address([address1, address2, city, zipcode, state&.name])
|
||||
end
|
||||
|
||||
def blank?
|
||||
@data.nil?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_address(address_parts)
|
||||
address_parts.compact_blank.join(', ')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,28 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
class Adjustment < Invoice::DataPresenter::Base
|
||||
attributes :additional_tax_total, :adjustable_type, :amount, :currency, :included_tax_total,
|
||||
:label, :originator_type
|
||||
invoice_generation_attributes :additional_tax_total, :adjustable_type, :amount,
|
||||
:included_tax_total
|
||||
invoice_update_attributes :label
|
||||
|
||||
def display_amount
|
||||
Spree::Money.new(amount, currency: currency)
|
||||
end
|
||||
|
||||
def display_taxes(display_zero: false)
|
||||
if included_tax_total.positive?
|
||||
amount = Spree::Money.new(included_tax_total, currency: currency)
|
||||
I18n.t(:tax_amount_included, amount: amount)
|
||||
elsif additional_tax_total.positive?
|
||||
Spree::Money.new(additional_tax_total, currency: currency)
|
||||
elsif display_zero
|
||||
Spree::Money.new(0.00, currency: currency)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,14 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
class Base
|
||||
attr_reader :data
|
||||
|
||||
def initialize(data)
|
||||
@data = data
|
||||
end
|
||||
extend Invoice::DataPresenterAttributes
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
class BillAddress < Invoice::DataPresenter::Address
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
class BusinessAddress < Invoice::DataPresenter::Address
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,9 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
class Contact < Invoice::DataPresenter::Base
|
||||
attributes :name, :email
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,9 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
class Invoice
|
||||
class DataPresenter
|
||||
class Customer < Invoice::DataPresenter::Base
|
||||
attributes :code, :email
|
||||
end
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user