mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-05 02:41:33 +00:00
Compare commits
194 Commits
6b78f8b855
...
v5.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b559e2f83 | ||
|
|
a94ccd4493 | ||
|
|
fc6ed9ab4b | ||
|
|
2219513c93 | ||
|
|
fb713d8721 | ||
|
|
90761e0766 | ||
|
|
6fb4048bfd | ||
|
|
c3def926f1 | ||
|
|
d6cde5c793 | ||
|
|
756e876f61 | ||
|
|
2a3b076170 | ||
|
|
7e4886ad67 | ||
|
|
9297dbfa63 | ||
|
|
7bfe51d067 | ||
|
|
6ad49cc080 | ||
|
|
2a7e8816c0 | ||
|
|
988f903164 | ||
|
|
108e313e48 | ||
|
|
e502aad7c9 | ||
|
|
9af57e1fc4 | ||
|
|
a0c23825b8 | ||
|
|
4e5238d1bb | ||
|
|
26b8f62325 | ||
|
|
ee087f9eff | ||
|
|
3152362b9d | ||
|
|
601c921b4b | ||
|
|
39fbf01e98 | ||
|
|
69586ae5ae | ||
|
|
c87eb05c0e | ||
|
|
a1f363c53b | ||
|
|
76c6362db0 | ||
|
|
5c3308de36 | ||
|
|
a82b2c2799 | ||
|
|
4895010fe0 | ||
|
|
962097f237 | ||
|
|
941707a0df | ||
|
|
85439b4b54 | ||
|
|
35724bec81 | ||
|
|
6cbc6fbca3 | ||
|
|
b0b03cbb5f | ||
|
|
f7e119d06f | ||
|
|
52ee5929cf | ||
|
|
1e58882217 | ||
|
|
ca23f12451 | ||
|
|
cce37aa915 | ||
|
|
f808fe9685 | ||
|
|
dd5db396b4 | ||
|
|
e121a799ed | ||
|
|
5dfef4a3ae | ||
|
|
8236603f76 | ||
|
|
315d52961a | ||
|
|
dcb6f4676d | ||
|
|
3455ceb722 | ||
|
|
7361b2da0b | ||
|
|
3ebacbc31a | ||
|
|
c0bcf177e7 | ||
|
|
8dfede11c6 | ||
|
|
bac123f223 | ||
|
|
fdc775ae6d | ||
|
|
26b39d6626 | ||
|
|
8953e8481d | ||
|
|
1ce76a3166 | ||
|
|
1c703905fe | ||
|
|
feed223ab4 | ||
|
|
90f962a886 | ||
|
|
82f6484031 | ||
|
|
282fb44da4 | ||
|
|
82f40d2e93 | ||
|
|
cae1655ec3 | ||
|
|
e8e48f7c64 | ||
|
|
26702e6f0d | ||
|
|
8cd9e94148 | ||
|
|
a934b60f67 | ||
|
|
7fc9a6bf93 | ||
|
|
781bf940f6 | ||
|
|
92382ca473 | ||
|
|
76a3e913df | ||
|
|
23ab6bb489 | ||
|
|
fd3c1c1343 | ||
|
|
368da19993 | ||
|
|
419f4490d6 | ||
|
|
39245d55e2 | ||
|
|
fe8200b7e8 | ||
|
|
c799f15067 | ||
|
|
54f1047dcb | ||
|
|
c1e599deef | ||
|
|
f3c60148c1 | ||
|
|
2e08c9c44e | ||
|
|
93f2af7e7d | ||
|
|
cb7a4b67ce | ||
|
|
41a8d06326 | ||
|
|
a957df1205 | ||
|
|
a1bdfa0a20 | ||
|
|
1adf94093e | ||
|
|
476daf0d30 | ||
|
|
18ef5cc69a | ||
|
|
a69528c432 | ||
|
|
9dfecde6a7 | ||
|
|
c73f28b434 | ||
|
|
0cd9fa91a8 | ||
|
|
252943e9de | ||
|
|
cab4b2fb28 | ||
|
|
80bd6defcb | ||
|
|
bd367cb154 | ||
|
|
d0f48687e2 | ||
|
|
25063d2c4d | ||
|
|
bad04b70a9 | ||
|
|
5479572a08 | ||
|
|
79a9dbcf68 | ||
|
|
61c7c26822 | ||
|
|
969dcae8d0 | ||
|
|
ce5a95ff4f | ||
|
|
0d5330d388 | ||
|
|
3676acf244 | ||
|
|
caf6b087c1 | ||
|
|
24d6c1e386 | ||
|
|
a120e390d0 | ||
|
|
98a2bf5d47 | ||
|
|
bb0c1e7a0f | ||
|
|
55a15b914c | ||
|
|
8ce14a55c8 | ||
|
|
d1f47f6956 | ||
|
|
2d50dace20 | ||
|
|
bbbbe71bc4 | ||
|
|
b3dc76b8cf | ||
|
|
ad4b26e86d | ||
|
|
c2a7a89381 | ||
|
|
68e3623861 | ||
|
|
577aa55f98 | ||
|
|
b8e62b3d84 | ||
|
|
dbb8e07b9a | ||
|
|
19550ed4fe | ||
|
|
4d0c710e3b | ||
|
|
fccde70690 | ||
|
|
b8de75b1ef | ||
|
|
06bfd07fec | ||
|
|
e98cf78b4c | ||
|
|
13229cc0c1 | ||
|
|
0f59333cd9 | ||
|
|
ad4ce14486 | ||
|
|
3173c79e8f | ||
|
|
ca14d557c1 | ||
|
|
59a3a5bd92 | ||
|
|
a226088f5c | ||
|
|
e91fab5702 | ||
|
|
e09853af0c | ||
|
|
c65fcc1072 | ||
|
|
3bb68ec07e | ||
|
|
2c97638aa1 | ||
|
|
ceee9671d9 | ||
|
|
6b494be7ff | ||
|
|
a6855e6bc1 | ||
|
|
7ca43eb4a1 | ||
|
|
74b5ac559f | ||
|
|
07c236497c | ||
|
|
caf2ff9bb4 | ||
|
|
1b2a17d7e4 | ||
|
|
ce46115139 | ||
|
|
9fd2ff7620 | ||
|
|
98a25c1c7f | ||
|
|
12b86a35af | ||
|
|
e1f4210aa8 | ||
|
|
584b976dff | ||
|
|
4073238654 | ||
|
|
d7505bcef4 | ||
|
|
f6a7225c47 | ||
|
|
377f33b64f | ||
|
|
73b27f14ab | ||
|
|
0b497fbb77 | ||
|
|
5e4df41ec8 | ||
|
|
72085be896 | ||
|
|
e0bc8f9cdc | ||
|
|
efcb442a80 | ||
|
|
a38023475c | ||
|
|
4a6ba29b99 | ||
|
|
7f961d90c2 | ||
|
|
0ac4021729 | ||
|
|
ac662de789 | ||
|
|
23c57cb354 | ||
|
|
d6ef56af6e | ||
|
|
059e36318e | ||
|
|
7a72121b1b | ||
|
|
c01cca33c7 | ||
|
|
631306cfb3 | ||
|
|
f4d59305d7 | ||
|
|
c526e72539 | ||
|
|
e217a6fca8 | ||
|
|
6aa7ef3c21 | ||
|
|
bf0e5c0d44 | ||
|
|
6bd2f5af8d | ||
|
|
7bf54088a6 | ||
|
|
4792040240 | ||
|
|
dc631026d4 | ||
|
|
c05532c166 |
@@ -1,2 +0,0 @@
|
||||
defaults
|
||||
IE 11
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -8,4 +8,3 @@
|
||||
# Same thing for following files, but they don't have an sh extension
|
||||
pre-commit eol=lf
|
||||
webpack-dev-server eol=lf
|
||||
install-bundler eol=lf
|
||||
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,4 +1,4 @@
|
||||
#### What? Why?
|
||||
## What? Why?
|
||||
|
||||
- Closes # <!-- Insert issue number here. -->
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
|
||||
|
||||
#### What should we test?
|
||||
## What should we test?
|
||||
<!-- List which features should be tested and how.
|
||||
This can be similar to the Steps to Reproduce in the issue.
|
||||
Also think of other parts of the app which could be affected
|
||||
@@ -16,7 +16,7 @@
|
||||
- Visit ... page.
|
||||
-
|
||||
|
||||
#### Release notes
|
||||
## Release notes
|
||||
|
||||
<!-- Please select one for your PR and delete the other. -->
|
||||
|
||||
@@ -33,12 +33,12 @@ Changelog Category (reviewers may add a label for the release notes):
|
||||
The title of the pull request will be included in the release notes.
|
||||
|
||||
|
||||
#### Dependencies
|
||||
## Dependencies
|
||||
<!-- Does this PR depend on another one?
|
||||
Add the link or remove this section. -->
|
||||
|
||||
|
||||
|
||||
#### Documentation updates
|
||||
## Documentation updates
|
||||
<!-- Are there any wiki pages that need updating after merging this PR?
|
||||
List them here or remove this section. -->
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.2.9
|
||||
3.4.8
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ruby:3.2.9-alpine3.19 AS base
|
||||
FROM ruby:3.4.8-alpine3.19 AS base
|
||||
ENV LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8 \
|
||||
TZ=Europe/London \
|
||||
@@ -31,4 +31,4 @@ FROM development-base
|
||||
COPY . $RAILS_ROOT
|
||||
COPY Gemfile Gemfile.lock ./
|
||||
RUN bundle install --jobs "$(nproc)"
|
||||
COPY --from=yarn-dependencies $RAILS_ROOT/node_modules ./node_modules
|
||||
COPY --from=yarn-dependencies $RAILS_ROOT/node_modules ./node_modules
|
||||
|
||||
@@ -83,11 +83,8 @@ RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.z
|
||||
# Copy code and install app dependencies
|
||||
COPY . /usr/src/app/
|
||||
|
||||
# Install Bundler
|
||||
RUN ./script/install-bundler
|
||||
|
||||
# Install front-end dependencies
|
||||
RUN yarn install
|
||||
|
||||
# Run bundler install in parallel with the amount of available CPUs
|
||||
RUN bundle install --jobs="$(nproc)"
|
||||
RUN bundle install --jobs="$(nproc)"
|
||||
|
||||
8
Gemfile
8
Gemfile
@@ -18,7 +18,7 @@ gem 'activemerchant'
|
||||
gem 'angular-rails-templates'
|
||||
gem 'ransack', '~> 4.1.0'
|
||||
gem 'responders'
|
||||
gem 'webpacker', '~> 5'
|
||||
gem 'shakapacker', '7.2.3'
|
||||
|
||||
# Indirect dependency but we access it directly in JS specs.
|
||||
# It turns out to be hard to upgrade but please do if you can.
|
||||
@@ -49,7 +49,7 @@ gem 'acts_as_list', '1.0.4'
|
||||
gem 'cancancan', '~> 1.15.0'
|
||||
gem 'digest'
|
||||
gem 'ffaker'
|
||||
gem 'highline', '2.0.3' # Necessary for the install generator
|
||||
gem 'highline'
|
||||
gem 'json'
|
||||
gem 'monetize', '~> 1.11'
|
||||
gem 'paranoia', '~> 2.4'
|
||||
@@ -57,7 +57,7 @@ gem 'state_machines-activerecord'
|
||||
gem 'stringex', '~> 2.8.5', require: false
|
||||
|
||||
gem 'paypal-sdk-merchant', '1.117.2'
|
||||
gem 'stripe', '~> 13'
|
||||
gem 'stripe', '~> 15'
|
||||
|
||||
gem 'devise'
|
||||
gem 'devise-encryptable'
|
||||
@@ -126,6 +126,8 @@ gem 'angular_rails_csrf'
|
||||
|
||||
gem 'jquery-rails', '4.4.0'
|
||||
gem 'jquery-ui-rails', '~> 4.2'
|
||||
# TODO move away from sass-rails, master branch will get rid of dependency, so we can move to
|
||||
# https://github.com/sass/embedded-host-node
|
||||
gem "select2-rails", github: "openfoodfoundation/select2-rails", branch: "v349_with_thor_v1"
|
||||
|
||||
gem 'good_migrations'
|
||||
|
||||
73
Gemfile.lock
73
Gemfile.lock
@@ -104,11 +104,12 @@ GEM
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
active_model_serializers (0.8.4)
|
||||
activemodel (>= 3.0)
|
||||
active_storage_validations (1.1.4)
|
||||
activejob (>= 5.2.0)
|
||||
activemodel (>= 5.2.0)
|
||||
activestorage (>= 5.2.0)
|
||||
activesupport (>= 5.2.0)
|
||||
active_storage_validations (3.0.2)
|
||||
activejob (>= 6.1.4)
|
||||
activemodel (>= 6.1.4)
|
||||
activestorage (>= 6.1.4)
|
||||
activesupport (>= 6.1.4)
|
||||
marcel (>= 1.0.3)
|
||||
activejob (7.1.6)
|
||||
activesupport (= 7.1.6)
|
||||
globalid (>= 0.3.6)
|
||||
@@ -158,8 +159,8 @@ GEM
|
||||
zeitwerk (>= 2.4, < 3.0)
|
||||
acts_as_list (1.0.4)
|
||||
activerecord (>= 4.2)
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
addressable (2.8.8)
|
||||
public_suffix (>= 2.0.2, < 8.0)
|
||||
aes_key_wrap (1.1.0)
|
||||
afm (0.2.2)
|
||||
angular-rails-templates (1.4.0)
|
||||
@@ -176,8 +177,8 @@ GEM
|
||||
ast (2.4.3)
|
||||
attr_required (1.0.2)
|
||||
aws-eventstream (1.4.0)
|
||||
aws-partitions (1.1191.0)
|
||||
aws-sdk-core (3.239.2)
|
||||
aws-partitions (1.1196.0)
|
||||
aws-sdk-core (3.240.0)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
@@ -188,7 +189,7 @@ GEM
|
||||
aws-sdk-kms (1.118.0)
|
||||
aws-sdk-core (~> 3, >= 3.239.1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.206.0)
|
||||
aws-sdk-s3 (1.208.0)
|
||||
aws-sdk-core (~> 3, >= 3.234.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
@@ -251,7 +252,7 @@ GEM
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.5)
|
||||
cookiejar (0.3.4)
|
||||
crack (1.0.0)
|
||||
crack (1.0.1)
|
||||
bigdecimal
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
@@ -289,7 +290,7 @@ GEM
|
||||
diff-lcs (1.6.2)
|
||||
digest (3.2.1)
|
||||
docile (1.4.1)
|
||||
dotenv (3.1.8)
|
||||
dotenv (3.2.0)
|
||||
drb (2.2.3)
|
||||
em-http-request (1.1.7)
|
||||
addressable (>= 2.3.4)
|
||||
@@ -379,7 +380,7 @@ GEM
|
||||
temple (>= 0.8.2)
|
||||
thor
|
||||
tilt
|
||||
haml_lint (0.67.0)
|
||||
haml_lint (0.68.0)
|
||||
haml (>= 5.0)
|
||||
parallel (~> 1.10)
|
||||
rainbow
|
||||
@@ -388,7 +389,8 @@ GEM
|
||||
hashdiff (1.2.1)
|
||||
hashery (2.1.2)
|
||||
hashie (5.0.0)
|
||||
highline (2.0.3)
|
||||
highline (3.1.2)
|
||||
reline
|
||||
htmlentities (4.4.2)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.14.7)
|
||||
@@ -511,7 +513,7 @@ GEM
|
||||
timeout
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
newrelic_rpm (9.23.0)
|
||||
newrelic_rpm (9.24.0)
|
||||
nio4r (2.7.5)
|
||||
nokogiri (1.18.10)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
@@ -551,6 +553,7 @@ GEM
|
||||
webfinger (~> 2.0)
|
||||
orm_adapter (0.5.0)
|
||||
ostruct (0.6.1)
|
||||
package_json (0.2.0)
|
||||
pagy (9.4.0)
|
||||
paper_trail (17.0.0)
|
||||
activerecord (>= 7.1)
|
||||
@@ -576,7 +579,7 @@ GEM
|
||||
pp (0.6.3)
|
||||
prettyprint
|
||||
prettyprint (0.2.0)
|
||||
prism (1.6.0)
|
||||
prism (1.7.0)
|
||||
private_address_check (0.5.0)
|
||||
pry (0.15.2)
|
||||
coderay (~> 1.1)
|
||||
@@ -584,7 +587,7 @@ GEM
|
||||
psych (5.2.6)
|
||||
date
|
||||
stringio
|
||||
public_suffix (6.0.2)
|
||||
public_suffix (7.0.0)
|
||||
puffing-billy (4.0.2)
|
||||
addressable (~> 2.5)
|
||||
em-http-request (~> 1.1, >= 1.1.0)
|
||||
@@ -613,7 +616,7 @@ GEM
|
||||
rack-protection (3.2.0)
|
||||
base64 (>= 0.1.0)
|
||||
rack (~> 2.2, >= 2.2.4)
|
||||
rack-proxy (0.7.6)
|
||||
rack-proxy (0.7.7)
|
||||
rack
|
||||
rack-rewrite (1.5.1)
|
||||
rack-session (1.0.2)
|
||||
@@ -812,7 +815,13 @@ GEM
|
||||
tilt (>= 1.1, < 3)
|
||||
sd_notify (0.1.1)
|
||||
securerandom (0.4.1)
|
||||
semantic_range (3.0.0)
|
||||
semantic_range (3.1.0)
|
||||
shakapacker (7.2.3)
|
||||
activesupport (>= 5.2)
|
||||
package_json
|
||||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 5.2)
|
||||
semantic_range (>= 2.3.0)
|
||||
shoulda-matchers (7.0.1)
|
||||
activesupport (>= 7.1)
|
||||
sidekiq (7.2.4)
|
||||
@@ -868,14 +877,14 @@ GEM
|
||||
redis (>= 4.0, < 6.0)
|
||||
stringex (2.8.6)
|
||||
stringio (3.1.8)
|
||||
stripe (13.5.1)
|
||||
stripe (15.5.0)
|
||||
swd (2.0.3)
|
||||
activesupport (>= 3)
|
||||
attr_required (>= 0.0.5)
|
||||
faraday (~> 2.0)
|
||||
faraday-follow_redirects
|
||||
sysexits (1.2.0)
|
||||
temple (0.8.2)
|
||||
temple (0.10.4)
|
||||
terminal-table (4.0.0)
|
||||
unicode-display_width (>= 1.1.1, < 4)
|
||||
thor (1.4.0)
|
||||
@@ -902,7 +911,7 @@ GEM
|
||||
simplecov_json_formatter
|
||||
unicode-display_width (3.2.0)
|
||||
unicode-emoji (~> 4.1)
|
||||
unicode-emoji (4.1.0)
|
||||
unicode-emoji (4.2.0)
|
||||
uniform_notifier (1.17.0)
|
||||
uri (1.1.1)
|
||||
valid_email2 (5.2.3)
|
||||
@@ -913,7 +922,8 @@ GEM
|
||||
public_suffix
|
||||
validates_lengths_from_database (0.8.0)
|
||||
activerecord (>= 4)
|
||||
vcr (6.2.0)
|
||||
vcr (6.3.1)
|
||||
base64
|
||||
view_component (4.1.1)
|
||||
actionview (>= 7.1.0, < 8.2)
|
||||
activesupport (>= 7.1.0, < 8.2)
|
||||
@@ -935,15 +945,10 @@ GEM
|
||||
activesupport
|
||||
faraday (~> 2.0)
|
||||
faraday-follow_redirects
|
||||
webmock (3.25.1)
|
||||
webmock (3.26.1)
|
||||
addressable (>= 2.8.0)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
webpacker (5.4.4)
|
||||
activesupport (>= 5.2)
|
||||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 5.2)
|
||||
semantic_range (>= 2.3.0)
|
||||
webrick (1.9.2)
|
||||
websocket-driver (0.7.7)
|
||||
base64
|
||||
@@ -1016,7 +1021,7 @@ DEPENDENCIES
|
||||
good_migrations
|
||||
haml
|
||||
haml_lint
|
||||
highline (= 2.0.3)
|
||||
highline
|
||||
i18n
|
||||
i18n-js (~> 3.9.0)
|
||||
i18n-tasks
|
||||
@@ -1080,6 +1085,7 @@ DEPENDENCIES
|
||||
rubocop-rspec_rails
|
||||
sd_notify
|
||||
select2-rails!
|
||||
shakapacker (= 7.2.3)
|
||||
shoulda-matchers
|
||||
sidekiq
|
||||
sidekiq-scheduler
|
||||
@@ -1093,7 +1099,7 @@ DEPENDENCIES
|
||||
stimulus_reflex
|
||||
stimulus_reflex_testing!
|
||||
stringex (~> 2.8.5)
|
||||
stripe (~> 13)
|
||||
stripe (~> 15)
|
||||
turbo-rails
|
||||
turbo_power
|
||||
undercover
|
||||
@@ -1105,13 +1111,12 @@ DEPENDENCIES
|
||||
web!
|
||||
web-console
|
||||
webmock
|
||||
webpacker (~> 5)
|
||||
whenever
|
||||
wicked_pdf
|
||||
wkhtmltopdf-binary
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.2.9p265
|
||||
ruby 3.4.8p72
|
||||
|
||||
BUNDLED WITH
|
||||
2.4.19
|
||||
4.0.3
|
||||
|
||||
2
Procfile
2
Procfile
@@ -1,5 +1,5 @@
|
||||
# Foreman Procfile. Start all dev server processes with: `foreman start`
|
||||
|
||||
rails: DEV_CACHING=true bundle exec rails s -p 3000
|
||||
webpack: ./bin/webpack-dev-server
|
||||
webpack: ./bin/shakacker-dev-server
|
||||
sidekiq: DEV_CACHING=true bundle exec sidekiq -q mailers -q default
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Foreman Procfile for Docker env. Start all dev server processes with: `bundle exec foreman start -f Procfile.docker`
|
||||
|
||||
webpack: WEBPACKER_DEV_SERVER_HOST=0.0.0.0 ./bin/webpack-dev-server
|
||||
webpack: SHAKAPACKER_DEV_SERVER_HOST=0.0.0.0 ./bin/shakapacker-dev-server
|
||||
sidekiq: DEV_CACHING=true bundle exec sidekiq -q mailers -q default
|
||||
rails: WEBPACKER_DEV_SERVER_HOST=0.0.0.0 DEV_CACHING=true bundle exec rails s -p 3000 -b 0.0.0.0
|
||||
rails: SHAKAPACKER_DEV_SERVER_HOST=0.0.0.0 DEV_CACHING=true bundle exec rails s -p 3000 -b 0.0.0.0
|
||||
|
||||
@@ -38,16 +38,13 @@ angular.module("admin.indexUtils").directive "objForUpdate", (switchClass, pendi
|
||||
# To ensure the customer is still updated, we check on the $destroy event to see if
|
||||
# the attribute has changed, if so we queue up the change.
|
||||
scope.$on '$destroy', (value) ->
|
||||
# No update
|
||||
return if scope.object()[scope.attr] is scope.savedValue
|
||||
currentValue = scope.object()[scope.attr] || ""
|
||||
|
||||
# For some reason the code attribute is removed from the object when cleared, so we add
|
||||
# an emptyvalue so it gets updated properly
|
||||
if scope.attr is "code" and scope.object()[scope.attr] is undefined
|
||||
scope.object()["code"] = ""
|
||||
# No update
|
||||
return if currentValue is scope.savedValue
|
||||
|
||||
# Queuing up change
|
||||
addPendingChange(scope.attr, scope.object()[scope.attr])
|
||||
addPendingChange(scope.attr, currentValue)
|
||||
|
||||
# private
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
angular.module('Darkswarm').controller "TmpCtrl", ($scope)->
|
||||
$scope.test = {foo: "bar"}
|
||||
@@ -1,4 +1,4 @@
|
||||
= render ConfirmModalComponent.new(id: dom_id(@order, :ship), confirm_reflexes: "click->Admin::OrdersReflex#ship", controller: "orders", reflex: "Admin::Orders#ship") do
|
||||
= render ConfirmModalComponent.new(id: dom_id(@order, :ship), confirm_actions: "click->modal#close", confirm_reflexes: "click->Admin::OrdersReflex#ship", controller: "orders", reflex: "Admin::Orders#ship") do
|
||||
%div{class: "margin-bottom-30"}
|
||||
%p= t('spree.admin.orders.shipment.mark_as_shipped_message_html')
|
||||
%div{class: "margin-bottom-30"}
|
||||
|
||||
16
app/components/webhook_endpoint_form_component.rb
Normal file
16
app/components/webhook_endpoint_form_component.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class WebhookEndpointFormComponent < ViewComponent::Base
|
||||
def initialize(webhooks:, webhook_type:)
|
||||
@webhooks = webhooks
|
||||
@webhook_type = webhook_type
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :webhooks, :webhook_type
|
||||
|
||||
def is_webhook_payment_status?
|
||||
webhook_type == "payment_status_changed"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
-# Create new endpoints
|
||||
- if webhooks.empty? # Only one allowed for now.
|
||||
%tr
|
||||
%td= t("components.webhook_endpoint_form.event_types.#{webhook_type}")
|
||||
%td
|
||||
= form_with(url: helpers.account_webhook_endpoints_path, id: "#{webhook_type}_webhook_endpoint") do |f|
|
||||
= f.url_field :'webhook_endpoint[url]', id: "#{webhook_type}_webhook_endpoint_url", placeholder: t('components.webhook_endpoint_form.url.create_placeholder'), required: true, size: 64
|
||||
= f.hidden_field :'webhook_endpoint[webhook_type]', id: "#{webhook_type}_webhook_endpoint_webhook_type", value: webhook_type
|
||||
%td.actions
|
||||
= button_tag t(:create), class: 'button primary tiny no-margin', form: "#{webhook_type}_webhook_endpoint"
|
||||
|
||||
-# Existing endpoints
|
||||
- webhooks.each do |webhook_endpoint|
|
||||
%tr
|
||||
%td= t("components.webhook_endpoint_form.event_types.#{webhook_type}")
|
||||
%td= webhook_endpoint.url
|
||||
%td.actions.endpoints-actions
|
||||
- if webhook_endpoint.persisted?
|
||||
= button_to helpers.account_webhook_endpoint_path(webhook_endpoint), method: :delete,
|
||||
class: "tiny alert no-margin",
|
||||
data: { confirm: I18n.t(:are_you_sure) } do
|
||||
= I18n.t(:delete)
|
||||
|
||||
- if is_webhook_payment_status?
|
||||
= form_tag helpers.webhook_endpoint_test_account_path(webhook_endpoint), class: "button_to", 'data-turbo': true do
|
||||
= button_tag type: "submit", class: "tiny alert no-margin", data: { confirm: I18n.t(:are_you_sure) } do
|
||||
= I18n.t("components.webhook_endpoint_form.test_endpoint")
|
||||
@@ -162,6 +162,18 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @object.destroy
|
||||
flash.now[:success] = flash_message_for(@object, :successfully_removed)
|
||||
else
|
||||
flash.now[:error] = @object.errors.full_messages.to_sentence
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.turbo_stream { render :destroy, status: :ok }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def delete_custom_tab
|
||||
|
||||
@@ -7,6 +7,7 @@ module Admin
|
||||
|
||||
before_action :init_filters_params
|
||||
before_action :init_pagination_params
|
||||
before_action :init_none_tag
|
||||
|
||||
def index
|
||||
fetch_products
|
||||
@@ -179,6 +180,8 @@ module Admin
|
||||
product_query = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
.editable_products.merge(product_scope_with_includes).ransack(ransack_query).result
|
||||
|
||||
product_query = apply_tags_filter(product_query)
|
||||
|
||||
# Postgres requires ORDER BY expressions to appear in the SELECT list when using DISTINCT.
|
||||
# When the current ransack sort uses the computed stock columns, include them in the select
|
||||
# so the generated COUNT/DISTINCT query is valid.
|
||||
@@ -225,12 +228,51 @@ module Admin
|
||||
query.merge!(Spree::Variant::SEARCH_KEY => @search_term)
|
||||
end
|
||||
query.merge!(variants_primary_taxon_id_in: @category_id) if @category_id.present?
|
||||
query.merge!(variants_tags_name_in: @tags) if @tags.present?
|
||||
query.merge!(@q) if @q
|
||||
|
||||
query
|
||||
end
|
||||
|
||||
# Apply tags filter with OR logic:
|
||||
# - Products with variants having selected tags
|
||||
# - OR products with variants having no tags (when "None" is selected)
|
||||
#
|
||||
# Note: This cannot be implemented using Ransack because Ransack applies
|
||||
# AND semantics across associations and cannot express OR logic that combines
|
||||
# the presence and absence of the same associated records.
|
||||
def apply_tags_filter(base_query)
|
||||
return base_query if @tags.blank?
|
||||
|
||||
tag_names = Array(@tags).dup
|
||||
has_none_tag = (tag_names.delete(@none_tag_value) == @none_tag_value)
|
||||
|
||||
queries = []
|
||||
|
||||
if tag_names.any?
|
||||
# Products with at least one variant having one of the selected tags
|
||||
tagged_product_ids = Spree::Variant
|
||||
.joins(taggings: :tag)
|
||||
.where(tags: { name: tag_names })
|
||||
.select(:product_id)
|
||||
|
||||
queries << base_query.where(id: tagged_product_ids)
|
||||
end
|
||||
|
||||
if has_none_tag
|
||||
# Products where no variants have any tags
|
||||
tagged_product_ids = Spree::Variant
|
||||
.joins(:taggings)
|
||||
.select(:product_id)
|
||||
|
||||
queries << base_query.where.not(id: tagged_product_ids)
|
||||
end
|
||||
|
||||
return base_query if queries.empty?
|
||||
|
||||
# Combine queries using ActiveRecord's or method
|
||||
queries.reduce { |combined, query| combined.or(query) }
|
||||
end
|
||||
|
||||
# Optimise by pre-loading required columns
|
||||
def product_query_includes
|
||||
[
|
||||
@@ -289,6 +331,10 @@ module Admin
|
||||
t('.error')
|
||||
end
|
||||
end
|
||||
|
||||
def init_none_tag
|
||||
@none_tag_value = '""'
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/ClassLength
|
||||
|
||||
@@ -61,7 +61,7 @@ module Admin
|
||||
|
||||
def destroy
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
flash[:success] = Spree.t(:successfully_removed)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
format.js { render partial: "spree/admin/shared/destroy" }
|
||||
@@ -76,7 +76,7 @@ module Admin
|
||||
protected
|
||||
|
||||
def resource_not_found
|
||||
flash[:error] = flash_message_for(model_class.new, :not_found)
|
||||
flash[:error] = Spree.t(:not_found)
|
||||
redirect_to collection_url
|
||||
end
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ module Admin
|
||||
class StripeAccountsController < Spree::Admin::BaseController
|
||||
def connect
|
||||
payload = params.permit(:enterprise_id).to_h
|
||||
key = Openfoodnetwork::Application.config.secret_token
|
||||
key = Rails.application.secret_key_base
|
||||
url_params = { state: JWT.encode(payload, key, 'HS256'), scope: "read_write" }
|
||||
redirect_to Stripe::OAuth.authorize_url(url_params)
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ module Admin
|
||||
|
||||
status = :ok
|
||||
if @rule.destroy
|
||||
flash[:success] = Spree.t(:successfully_removed, resource: "Tag Rule")
|
||||
flash[:success] = Spree.t(:successfully_removed, resource: Spree.t(:tag_rule))
|
||||
else
|
||||
flash.now[:error] = t(".destroy_error")
|
||||
status = :internal_server_error
|
||||
|
||||
@@ -14,7 +14,7 @@ module Admin
|
||||
)
|
||||
|
||||
if @voucher.save
|
||||
flash[:success] = I18n.t(:successfully_created, resource: "Voucher")
|
||||
flash[:success] = I18n.t(:successfully_created, resource: Spree.t(:voucher))
|
||||
redirect_to edit_admin_enterprise_path(@enterprise, anchor: :vouchers_panel)
|
||||
else
|
||||
render_error
|
||||
|
||||
@@ -68,7 +68,7 @@ module Spree
|
||||
destroy_before
|
||||
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
flash[:success] = Spree.t(:successfully_removed)
|
||||
end
|
||||
|
||||
redirect_to location_after_save
|
||||
|
||||
@@ -11,10 +11,10 @@ module Spree
|
||||
respond_to :html
|
||||
|
||||
PAYMENT_METHODS = %w{
|
||||
Spree::PaymentMethod::Check
|
||||
Spree::Gateway::PayPalExpress
|
||||
Spree::Gateway::StripeSCA
|
||||
}.index_with(&:constantize).freeze
|
||||
Spree::PaymentMethod::Check
|
||||
}.freeze
|
||||
|
||||
def create
|
||||
force_environment
|
||||
@@ -95,7 +95,7 @@ module Spree
|
||||
@payment_method = PaymentMethod.find(params[:pm_id])
|
||||
end
|
||||
else
|
||||
@payment_method = PAYMENT_METHODS.fetch(params[:provider_type], PaymentMethod).new
|
||||
@payment_method = PaymentMethod.new(type: params[:provider_type])
|
||||
end
|
||||
|
||||
render partial: 'provider_settings'
|
||||
@@ -117,7 +117,7 @@ module Spree
|
||||
end
|
||||
|
||||
def validate_payment_method_provider
|
||||
valid_payment_methods = Rails.application.config.spree.payment_methods.map(&:to_s)
|
||||
valid_payment_methods = PAYMENT_METHODS
|
||||
return if valid_payment_methods.include?(params[:payment_method][:type])
|
||||
|
||||
flash[:error] = Spree.t(:invalid_payment_provider)
|
||||
@@ -133,13 +133,11 @@ module Spree
|
||||
end
|
||||
|
||||
def load_providers
|
||||
providers = Gateway.providers.sort_by(&:name)
|
||||
providers = PAYMENT_METHODS.dup
|
||||
|
||||
unless show_stripe?
|
||||
providers.reject! { |provider| stripe_provider?(provider) }
|
||||
end
|
||||
providers.delete("Spree::Gateway::StripeSCA") unless show_stripe?
|
||||
|
||||
providers
|
||||
providers.map(&:constantize)
|
||||
end
|
||||
|
||||
# Show Stripe as an option if enabled, or if the
|
||||
@@ -164,10 +162,6 @@ module Spree
|
||||
@payment_method.try(:type) == "Spree::Gateway::StripeSCA"
|
||||
end
|
||||
|
||||
def stripe_provider?(provider)
|
||||
provider.name.ends_with?("StripeSCA")
|
||||
end
|
||||
|
||||
def base_params
|
||||
@base_params ||= PermittedAttributes::PaymentMethod.new(params[:payment_method]).
|
||||
call.to_h.with_indifferent_access
|
||||
|
||||
@@ -16,7 +16,7 @@ module Spree
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
flash[:success] = Spree.t(:successfully_removed)
|
||||
end
|
||||
# if destroy fails it won't show any errors to the user
|
||||
redirect_to spree.admin_product_product_properties_url(params[:product_id], @url_filters)
|
||||
|
||||
@@ -36,7 +36,7 @@ module Spree
|
||||
end
|
||||
|
||||
@object.touch :deleted_at
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
flash[:success] = Spree.t(:successfully_removed)
|
||||
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
|
||||
@@ -5,7 +5,7 @@ module Spree
|
||||
class TaxCategoriesController < ::Admin::ResourceController
|
||||
def destroy
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
flash[:success] = Spree.t(:successfully_removed)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
format.js { render partial: "spree/admin/shared/destroy" }
|
||||
|
||||
@@ -90,11 +90,13 @@ class VoucherAdjustmentsController < BaseController
|
||||
voucher_code: voucher_params[:voucher_code], enterprise: @order.distributor
|
||||
)
|
||||
voucher = vine_voucher_validator.validate
|
||||
errors = vine_voucher_validator.errors
|
||||
|
||||
return nil if vine_voucher_validator.errors[:not_found_voucher].present?
|
||||
return nil if errors[:not_found_voucher].present?
|
||||
|
||||
if vine_voucher_validator.errors.present?
|
||||
@order.errors.add(:voucher_code, I18n.t('checkout.errors.add_voucher_error'))
|
||||
if errors.present?
|
||||
message = errors[:invalid_voucher] || I18n.t('checkout.errors.add_voucher_error')
|
||||
@order.errors.add(:voucher_code, message)
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class WebhookEndpointsController < BaseController
|
||||
before_action :load_resource, only: :destroy
|
||||
before_action :load_resource, only: [:destroy, :test]
|
||||
|
||||
def create
|
||||
webhook_endpoint = spree_current_user.webhook_endpoints.new(webhook_endpoint_params)
|
||||
@@ -25,12 +25,30 @@ class WebhookEndpointsController < BaseController
|
||||
redirect_to redirect_path
|
||||
end
|
||||
|
||||
def test
|
||||
at = Time.zone.now
|
||||
test_payload = Payments::WebhookPayload.test_data.to_hash
|
||||
|
||||
WebhookDeliveryJob.perform_later(@webhook_endpoint.url, "payment.completed", test_payload, at:)
|
||||
|
||||
flash[:success] = t(".success")
|
||||
respond_with do |format|
|
||||
format.turbo_stream do
|
||||
render turbo_stream: turbo_stream.update(
|
||||
:flashes, partial: "shared/flashes", locals: { flashes: flash }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_resource
|
||||
@webhook_endpoint = spree_current_user.webhook_endpoints.find(params[:id])
|
||||
end
|
||||
|
||||
def webhook_endpoint_params
|
||||
params.require(:webhook_endpoint).permit(:url)
|
||||
params.require(:webhook_endpoint).permit(:url, :webhook_type)
|
||||
end
|
||||
|
||||
def redirect_path
|
||||
|
||||
@@ -72,7 +72,8 @@ module ApplicationHelper
|
||||
end
|
||||
end
|
||||
|
||||
# Update "v1" to invalidate existing cache key
|
||||
def cache_key_with_locale(key, locale)
|
||||
Array.wrap(key) + [locale.to_s, I18nDigests.for_locale(locale)]
|
||||
Array.wrap(key) + ["v2", locale.to_s, I18nDigests.for_locale(locale)]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,8 +63,11 @@ module EnterprisesHelper
|
||||
url = object_url(enterprise)
|
||||
name = t(:delete)
|
||||
options = {}
|
||||
options[:class] = "delete-resource"
|
||||
options[:data] = { action: 'remove', confirm: enterprise_confirm_delete_message(enterprise) }
|
||||
options[:data] = {
|
||||
turbo: true,
|
||||
'turbo-method': 'delete',
|
||||
'turbo-confirm': enterprise_confirm_delete_message(enterprise)
|
||||
}
|
||||
link_to_with_icon 'icon-trash', name, url, options
|
||||
end
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ class ApplicationRecord < ActiveRecord::Base
|
||||
self.include_root_in_json = true
|
||||
|
||||
def self.image_service
|
||||
ENV["S3_BUCKET"].present? ? :amazon_public : :local
|
||||
return :local if ENV["S3_BUCKET"].blank?
|
||||
return :amazon_public if ENV["S3_ENDPOINT"].blank?
|
||||
|
||||
:s3_compatible_storage_public
|
||||
end
|
||||
|
||||
# We might have a development environment without S3 but with a database
|
||||
|
||||
@@ -50,11 +50,11 @@ class Enterprise < ApplicationRecord
|
||||
has_many :distributed_orders, class_name: 'Spree::Order',
|
||||
foreign_key: 'distributor_id',
|
||||
inverse_of: :distributor,
|
||||
dependent: :restrict_with_exception
|
||||
dependent: :restrict_with_error
|
||||
|
||||
belongs_to :address, class_name: 'Spree::Address'
|
||||
belongs_to :business_address, optional: true, class_name: 'Spree::Address', dependent: :destroy
|
||||
has_many :enterprise_fees, dependent: :restrict_with_exception
|
||||
has_many :enterprise_fees, dependent: :restrict_with_error
|
||||
has_many :enterprise_roles, dependent: :destroy
|
||||
has_many :users, through: :enterprise_roles
|
||||
belongs_to :owner, class_name: 'Spree::User',
|
||||
@@ -62,18 +62,18 @@ class Enterprise < ApplicationRecord
|
||||
has_many :distributor_payment_methods,
|
||||
inverse_of: :distributor,
|
||||
foreign_key: :distributor_id,
|
||||
dependent: :restrict_with_exception
|
||||
dependent: :restrict_with_error
|
||||
has_many :distributor_shipping_methods,
|
||||
inverse_of: :distributor,
|
||||
foreign_key: :distributor_id,
|
||||
dependent: :restrict_with_exception
|
||||
dependent: :restrict_with_error
|
||||
has_many :payment_methods, through: :distributor_payment_methods
|
||||
has_many :shipping_methods, through: :distributor_shipping_methods
|
||||
has_many :customers, dependent: :destroy
|
||||
has_many :inventory_items, dependent: :destroy
|
||||
has_many :tag_rules, dependent: :destroy
|
||||
has_one :stripe_account, dependent: :destroy
|
||||
has_many :vouchers, dependent: :restrict_with_exception
|
||||
has_many :vouchers, dependent: :restrict_with_error
|
||||
has_many :connected_apps, dependent: :destroy
|
||||
has_many :dfc_permissions, dependent: :destroy
|
||||
has_one :custom_tab, dependent: :destroy
|
||||
@@ -111,14 +111,14 @@ class Enterprise < ApplicationRecord
|
||||
end
|
||||
|
||||
validates :logo,
|
||||
processable_image: true,
|
||||
content_type: %r{\Aimage/(png|jpeg|gif|jpg|svg\+xml|webp)\Z}
|
||||
processable_file: true,
|
||||
content_type: ::Spree::Image::ACCEPTED_CONTENT_TYPES
|
||||
validates :promo_image,
|
||||
processable_image: true,
|
||||
content_type: %r{\Aimage/(png|jpeg|gif|jpg|svg\+xml|webp)\Z}
|
||||
processable_file: true,
|
||||
content_type: ::Spree::Image::ACCEPTED_CONTENT_TYPES
|
||||
validates :white_label_logo,
|
||||
processable_image: true,
|
||||
content_type: %r{\Aimage/(png|jpeg|gif|jpg|svg\+xml|webp)\Z}
|
||||
processable_file: true,
|
||||
content_type: ::Spree::Image::ACCEPTED_CONTENT_TYPES
|
||||
validates :terms_and_conditions, content_type: {
|
||||
in: "application/pdf",
|
||||
message: I18n.t(:enterprise_terms_and_conditions_type_error),
|
||||
|
||||
@@ -29,11 +29,11 @@ class EnterpriseGroup < ApplicationRecord
|
||||
has_one_attached :promo_image, service: image_service
|
||||
|
||||
validates :logo,
|
||||
processable_image: true,
|
||||
content_type: %r{\Aimage/(png|jpeg|gif|jpg|svg\+xml|webp)\Z}
|
||||
processable_file: true,
|
||||
content_type: ::Spree::Image::ACCEPTED_CONTENT_TYPES
|
||||
validates :promo_image,
|
||||
processable_image: true,
|
||||
content_type: %r{\Aimage/(png|jpeg|gif|jpg|svg\+xml|webp)\Z}
|
||||
processable_file: true,
|
||||
content_type: ::Spree::Image::ACCEPTED_CONTENT_TYPES
|
||||
|
||||
scope :by_position, -> { order('position ASC') }
|
||||
scope :on_front_page, -> { where(on_front_page: true) }
|
||||
|
||||
@@ -31,7 +31,6 @@ module Spree
|
||||
preference :admin_products_per_page, :integer, default: 10
|
||||
# Should only be true if you don't need to track inventory
|
||||
preference :allow_backorder_shipping, :boolean, default: false
|
||||
preference :allow_checkout_on_gateway_error, :boolean, default: false
|
||||
preference :allow_guest_checkout, :boolean, default: true
|
||||
preference :currency_decimal_mark, :string, default: "."
|
||||
preference :currency_symbol_position, :string, default: "before"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
module Spree
|
||||
class Image < Asset
|
||||
ACCEPTED_CONTENT_TYPES = %r{\Aimage/(png|jpeg|gif|jpg|svg\+xml|webp)\Z}
|
||||
|
||||
has_one_attached :attachment, service: image_service do |attachment|
|
||||
attachment.variant :mini, resize_to_fill: [48, 48]
|
||||
attachment.variant :small, resize_to_fill: [227, 227]
|
||||
@@ -11,8 +13,8 @@ module Spree
|
||||
|
||||
validates :attachment,
|
||||
attached: true,
|
||||
processable_image: true,
|
||||
content_type: %r{\Aimage/(png|jpeg|gif|jpg|svg\+xml|webp)\Z}
|
||||
processable_file: true,
|
||||
content_type: ACCEPTED_CONTENT_TYPES
|
||||
validate :no_attachment_errors
|
||||
|
||||
def self.default_image_url(size)
|
||||
|
||||
@@ -437,18 +437,13 @@ module Spree
|
||||
#
|
||||
# Returns:
|
||||
# - true if all pending_payments processed successfully
|
||||
# - true if a payment failed, ie. raised a GatewayError
|
||||
# which gets rescued and converted to TRUE when
|
||||
# :allow_checkout_gateway_error is set to true
|
||||
# - false if a payment failed, ie. raised a GatewayError
|
||||
# which gets rescued and converted to FALSE when
|
||||
# :allow_checkout_on_gateway_error is set to false
|
||||
# which gets rescued and converted to FALSE
|
||||
#
|
||||
def process_payments!
|
||||
process_each_payment(&:process!)
|
||||
rescue Core::GatewayError => e
|
||||
result = !!Spree::Config[:allow_checkout_on_gateway_error]
|
||||
errors.add(:base, e.message) && (return result)
|
||||
errors.add(:base, e.message) && (return false)
|
||||
end
|
||||
|
||||
def process_payments_offline!
|
||||
|
||||
@@ -101,6 +101,24 @@ module Spree
|
||||
end
|
||||
|
||||
after_transition to: :completed, do: :set_captured_at
|
||||
after_transition do |payment, transition|
|
||||
# Catch any exceptions to prevent any rollback potentially
|
||||
# preventing payment from going through
|
||||
ActiveSupport::Notifications.instrument(
|
||||
"ofn.payment_transition", payment: payment, event: transition.to
|
||||
)
|
||||
rescue StandardError => e
|
||||
Rails.logger.fatal "ActiveSupport::Notification.instrument failed params: " \
|
||||
"<event_type:ofn.payment_transition> " \
|
||||
"<payment_id:#{payment.id}> " \
|
||||
"<event:#{transition.to}>"
|
||||
Alert.raise(
|
||||
e,
|
||||
metadata: {
|
||||
event_tye: "ofn.payment_transition", payment_id: payment.id, event: transition.to
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def money
|
||||
|
||||
@@ -52,10 +52,6 @@ module Spree
|
||||
.where(environment: [Rails.env, "", nil])
|
||||
}
|
||||
|
||||
def self.providers
|
||||
Rails.application.config.spree.payment_methods
|
||||
end
|
||||
|
||||
def configured?
|
||||
!stripe? || stripe_configured?
|
||||
end
|
||||
@@ -93,8 +89,8 @@ module Spree
|
||||
type.demodulize.downcase
|
||||
end
|
||||
|
||||
def self.find_with_destroyed(*args)
|
||||
unscoped { find(*args) }
|
||||
def self.find_with_destroyed(*)
|
||||
unscoped { find(*) }
|
||||
end
|
||||
|
||||
def payment_profiles_supported?
|
||||
@@ -118,8 +114,8 @@ module Spree
|
||||
end
|
||||
|
||||
def self.clean_name
|
||||
i18n_key = "spree.admin.payment_methods.providers.#{name.demodulize.downcase}"
|
||||
I18n.t(i18n_key)
|
||||
scope = "spree.admin.payment_methods.providers"
|
||||
I18n.t(name.demodulize.downcase, scope:)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -2,5 +2,11 @@
|
||||
|
||||
# Records a webhook url to send notifications to
|
||||
class WebhookEndpoint < ApplicationRecord
|
||||
WEBHOOK_TYPES = %w(order_cycle_opened payment_status_changed).freeze
|
||||
|
||||
validates :url, presence: true
|
||||
validates :webhook_type, presence: true, inclusion: { in: WEBHOOK_TYPES }
|
||||
|
||||
scope :order_cycle_opened, -> { where(webhook_type: "order_cycle_opened") }
|
||||
scope :payment_status, -> { where(webhook_type: "payment_status_changed") }
|
||||
end
|
||||
|
||||
@@ -11,7 +11,9 @@ class ImageImporter
|
||||
|
||||
image = Spree::Image.create do |img|
|
||||
PrivateAddressCheck.only_public_connections do
|
||||
img.attachment.attach(io: valid_url.open, filename:, metadata:)
|
||||
io = valid_url.open
|
||||
content_type = Marcel::MimeType.for(io)
|
||||
img.attachment.attach(io:, filename:, metadata:, content_type:)
|
||||
end
|
||||
end
|
||||
product.image = image if image
|
||||
|
||||
@@ -11,10 +11,12 @@ module OrderCycles
|
||||
.merge(coordinator_name: order_cycle.coordinator.name)
|
||||
|
||||
# Endpoints for coordinator owner
|
||||
webhook_endpoints = order_cycle.coordinator.owner.webhook_endpoints
|
||||
webhook_endpoints = order_cycle.coordinator.owner.webhook_endpoints.order_cycle_opened
|
||||
|
||||
# Plus unique endpoints for distributor owners (ignore duplicates)
|
||||
webhook_endpoints |= order_cycle.distributors.map(&:owner).flat_map(&:webhook_endpoints)
|
||||
webhook_endpoints |= order_cycle.distributors.map(&:owner).flat_map { |owner|
|
||||
owner.webhook_endpoints.order_cycle_opened
|
||||
}
|
||||
|
||||
webhook_endpoints.each do |endpoint|
|
||||
WebhookDeliveryJob.perform_later(endpoint.url, event, webhook_payload, at:)
|
||||
|
||||
13
app/services/payments/status_changed_listener_service.rb
Normal file
13
app/services/payments/status_changed_listener_service.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Called by "ActiveSupport::Notifications" when an "ofn.payment_transition" occurs
|
||||
# Event originate from Spree::Payment event machine
|
||||
#
|
||||
module Payments
|
||||
class StatusChangedListenerService
|
||||
def call(_name, started, _finished, _unique_id, payload)
|
||||
event = "payment.#{payload[:event]}"
|
||||
Payments::WebhookService.create_webhook_job(payment: payload[:payment], event:, at: started)
|
||||
end
|
||||
end
|
||||
end
|
||||
84
app/services/payments/webhook_payload.rb
Normal file
84
app/services/payments/webhook_payload.rb
Normal file
@@ -0,0 +1,84 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Payments
|
||||
class WebhookPayload
|
||||
def initialize(payment:, order:, enterprise:)
|
||||
@payment = payment
|
||||
@order = order
|
||||
@enterprise = enterprise
|
||||
end
|
||||
|
||||
def to_hash
|
||||
{
|
||||
payment: @payment.slice(:updated_at, :amount, :state),
|
||||
enterprise: @enterprise.slice(:abn, :acn, :name)
|
||||
.merge(address: @enterprise.address.slice(:address1, :address2, :city, :zipcode)),
|
||||
order: @order.slice(:total, :currency).merge(line_items: line_items)
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
def self.test_data
|
||||
new(payment: test_payment, order: test_order, enterprise: test_enterprise)
|
||||
end
|
||||
|
||||
def self.test_payment
|
||||
{
|
||||
updated_at: Time.zone.now,
|
||||
amount: 0.00,
|
||||
state: "completed"
|
||||
}
|
||||
end
|
||||
|
||||
def self.test_order
|
||||
order = Spree::Order.new(
|
||||
total: 0.00,
|
||||
currency: "AUD",
|
||||
)
|
||||
|
||||
tax_category = Spree::TaxCategory.new(name: "VAT")
|
||||
product = Spree::Product.new(name: "Test product")
|
||||
Spree::Variant.new(product:, display_name: "")
|
||||
order.line_items << Spree::LineItem.new(
|
||||
quantity: 1,
|
||||
price: 20.00,
|
||||
tax_category:,
|
||||
product:,
|
||||
unit_presentation: "1kg"
|
||||
)
|
||||
|
||||
order
|
||||
end
|
||||
|
||||
def self.test_enterprise
|
||||
enterprise = Enterprise.new(
|
||||
abn: "65797115831",
|
||||
acn: "",
|
||||
name: "TEST Enterprise",
|
||||
)
|
||||
enterprise.address = Spree::Address.new(
|
||||
address1: "1 testing street",
|
||||
address2: "",
|
||||
city: "TestCity",
|
||||
zipcode: "1234"
|
||||
)
|
||||
|
||||
enterprise
|
||||
end
|
||||
|
||||
private_class_method :test_payment, :test_order, :test_enterprise
|
||||
|
||||
private
|
||||
|
||||
def line_items
|
||||
@order.line_items.map do |li|
|
||||
li.slice(:quantity, :price)
|
||||
.merge(
|
||||
tax_category_name: li.tax_category&.name,
|
||||
product_name: li.product.name,
|
||||
name_to_display: li.display_name,
|
||||
unit_to_display: li.unit_presentation
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
30
app/services/payments/webhook_service.rb
Normal file
30
app/services/payments/webhook_service.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Create a webhook payload for a payment status event.
|
||||
# The payload will be delivered asynchronously.
|
||||
|
||||
module Payments
|
||||
class WebhookService
|
||||
def self.create_webhook_job(payment:, event:, at:)
|
||||
order = payment.order
|
||||
payload = WebhookPayload.new(payment:, order:, enterprise: order.distributor).to_hash
|
||||
|
||||
coordinator = payment.order.order_cycle.coordinator
|
||||
webhook_urls(coordinator).each do |url|
|
||||
WebhookDeliveryJob.perform_later(url, event, payload, at:)
|
||||
end
|
||||
end
|
||||
|
||||
def self.webhook_urls(coordinator)
|
||||
# url for coordinator owner
|
||||
webhook_urls = coordinator.owner.webhook_endpoints.payment_status.pluck(:url)
|
||||
|
||||
# plus url for coordinator manager (ignore duplicate)
|
||||
users_webhook_urls = coordinator.users.flat_map do |user|
|
||||
user.webhook_endpoints.payment_status.pluck(:url)
|
||||
end
|
||||
|
||||
webhook_urls | users_webhook_urls
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
module Vine
|
||||
class VoucherValidatorService
|
||||
VINE_ERRORS = {
|
||||
# https://github.com/openfoodfoundation/vine/blob/main/app/Enums/ApiResponse.php
|
||||
"This voucher has expired." => :expired,
|
||||
}.freeze
|
||||
|
||||
attr_reader :voucher_code, :errors
|
||||
|
||||
def initialize(voucher_code:, enterprise:)
|
||||
@@ -42,8 +47,10 @@ module Vine
|
||||
end
|
||||
|
||||
def handle_errors(response)
|
||||
if response[:status] == 400
|
||||
errors[:invalid_voucher] = I18n.t("vine_voucher_validator_service.errors.invalid_voucher")
|
||||
if [400, 409].include?(response[:status])
|
||||
message = response[:body] && JSON.parse(response[:body]).dig("meta", "message")
|
||||
key = VINE_ERRORS.fetch(message, :invalid_voucher)
|
||||
errors[:invalid_voucher] = I18n.t("vine_voucher_validator_service.errors.#{key}")
|
||||
elsif response[:status] == 404
|
||||
errors[:not_found_voucher] =
|
||||
I18n.t("vine_voucher_validator_service.errors.not_found_voucher")
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
%tbody
|
||||
= f.fields_for :collection do |enterprise_form|
|
||||
- enterprise = enterprise_form.object
|
||||
%tr{class: "enterprise-#{enterprise.id}"}
|
||||
%tr{class: "enterprise-#{enterprise.id}", id: "resource-#{enterprise.id}"}
|
||||
%td= link_to enterprise.name, main_app.edit_admin_enterprise_path(enterprise)
|
||||
%td
|
||||
= enterprise_form.check_box :is_primary_producer
|
||||
|
||||
4
app/views/admin/enterprises/destroy.turbo_stream.haml
Normal file
4
app/views/admin/enterprises/destroy.turbo_stream.haml
Normal file
@@ -0,0 +1,4 @@
|
||||
- unless flash[:error]
|
||||
= turbo_stream.remove "resource-#{@object.id}"
|
||||
= turbo_stream.append "flashes" do
|
||||
= render(partial: 'admin/shared/flashes', locals: { flashes: flash })
|
||||
@@ -18,7 +18,7 @@
|
||||
%span{ "ofn-with-tip": '{{ orderCycle.producerNames }}', "ng-show": 'orderCycle.producers.length > 3' }
|
||||
{{ orderCycle.producers.length }}
|
||||
= t('.suppliers')
|
||||
%span{ "ng-hide": 'orderCycle.producers.length > 3', "ng-bind": 'orderCycle.producerNames' }
|
||||
%span{ "ng-hide": 'orderCycle.producers.length > 3', "ng-bind-html": 'orderCycle.producerNames' }
|
||||
%td.coordinator{ "ng-show": 'columns.coordinator.visible', "ng-bind-html": 'orderCycle.coordinator.name' }
|
||||
%td.shops{ "ng-show": 'columns.shops.visible' }
|
||||
%span{ "ofn-with-tip": '{{ orderCycle.shopNames }}', "ng-show": 'orderCycle.shops.length > 3' }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%fieldset.no-border-top
|
||||
.add_producer_properties
|
||||
= image_pack_tag 'spinner.gif', :plugin => 'spree', :style => 'display:none;', :id => 'busy_indicator'
|
||||
= image_pack_tag 'images/spinner.gif', :plugin => 'spree', :style => 'display:none;', :id => 'busy_indicator'
|
||||
%table.index.sortable{"data-sortable-link" => main_app.update_positions_admin_enterprise_producer_properties_url(@enterprise)}
|
||||
%thead
|
||||
%tr
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
- select_tag_options = { class: "fullwidth",
|
||||
multiple: true ,
|
||||
data: { controller: "tom-select", "tom-select-placeholder-value": t(".select_tag"), "tom-select-options-value": '{ "maxItems": 5 , "plugins": { "remove_button": {} , "no_active_items": {}, "checkbox_options": { "checkedClassNames": ["ts-checked"], "uncheckedClassNames": ["ts-unchecked"] } } }' } }
|
||||
= select_tag :tags_name_in, options_for_select(available_tags, tags), select_tag_options
|
||||
= select_tag :tags_name_in, options_for_select(available_tags.unshift([t('.tags.none'), @none_tag_value]), tags), select_tag_options
|
||||
.submit
|
||||
.search-button
|
||||
= button_tag t(".search"), class: "secondary icon-search relaxed", name: nil
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
#no-products-actions
|
||||
%a{ href: "/admin/products/new", class: "button icon-plus", icon: "icon-plus" }
|
||||
= t(:new_product)
|
||||
%a{ href: "/admin/products/import", class: "button icon-upload secondary", icon: "icon-upload" }
|
||||
%a{ href: admin_product_import_path, class: "button icon-upload secondary", icon: "icon-upload" }
|
||||
= t(".import_products")
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
= cache do
|
||||
%img.spinner{ src: image_pack_path("spinning-circles.svg"), style: "max-width: 100%" }
|
||||
%img.spinner{ src: image_pack_path("images/spinning-circles.svg"), style: "max-width: 100%" }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.row
|
||||
.small-12.text-center.columns
|
||||
%h1
|
||||
%img{src: image_pack_path("logo-white-notext.png"), title: Spree::Config.site_name}
|
||||
%img{src: image_pack_path("images/logo-white-notext.png"), title: Spree::Config.site_name}
|
||||
%br/
|
||||
%a.button.transparent{href: "/shops"}
|
||||
= t :home_shop
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
- else
|
||||
= favicon_link_tag "/favicon-staging.ico"
|
||||
%link{href: "https://fonts.googleapis.com/css?family=Roboto:400,300italic,400italic,300,700,700italic|Oswald:300,400,700", rel: "stylesheet", type: "text/css"}
|
||||
%link{href: asset_pack_path("media/fonts/OFN-v2.woff"), rel: "preload", as: "font", crossorigin: "anonymous"}
|
||||
%link{href: asset_pack_path("static/fonts/OFN-v2.woff"), rel: "preload", as: "font", crossorigin: "anonymous"}
|
||||
= render "layouts/matomo_tag"
|
||||
= language_meta_tags
|
||||
|
||||
= stylesheet_pack_tag "darkswarm", "data-turbo-track": "reload", media: "screen"
|
||||
= javascript_pack_tag "application", "data-turbo-track": "reload"
|
||||
= javascript_pack_tag "application", "data-turbo-track": "reload", defer: false # do not use defer because our javascript currently depend on order of execution of loaded script.
|
||||
|
||||
= render "layouts/shopfront_script" if @shopfront_layout
|
||||
= render "layouts/bugsnag_js"
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
= stylesheet_pack_tag "darkswarm", media: "screen"
|
||||
= javascript_include_tag "darkswarm/all"
|
||||
= javascript_pack_tag "application"
|
||||
= javascript_pack_tag "application", defer: false # do not use defer because our javascript currently depend on order of execution of loaded script.
|
||||
|
||||
= csrf_meta_tags
|
||||
|
||||
%body.off-canvas{ style: "background-image: url(#{image_pack_path('tile-wide.png')})", "data-turbo": "false" }
|
||||
%body.off-canvas{ style: "background-image: url(#{image_pack_path('images/tile-wide.png')})", "data-turbo": "false" }
|
||||
.off-canvas-wrap{offcanvas: true}
|
||||
.inner-wrap
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
%p.word-wrap{"ng-if" => "::producer.whatsapp_phone"}
|
||||
%a{"ng-href" => "{{::producer.whatsapp_url}}", target: "_blank"}
|
||||
%img{ src: image_pack_path("social-logos/whatsapp.svg") }
|
||||
%img{ src: image_pack_path("images/social-logos/whatsapp.svg") }
|
||||
%span{"ng-bind" => "::producer.whatsapp_phone"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "::producer.email_address"}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%h4= t(".message")
|
||||
.row
|
||||
.small-12.medium-3.large-2.columns.text-right.hide-for-small-only
|
||||
%img{:src => image_pack_path("potatoes.png") }
|
||||
%img{:src => image_pack_path("images/potatoes.png") }
|
||||
.small-12.medium-9.large-10.columns
|
||||
%p
|
||||
= t(".text")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.row
|
||||
.small-12.columns.text-center
|
||||
.logo
|
||||
%img{src: image_pack_path("logo-white-notext.png") }
|
||||
%img{src: image_pack_path("images/logo-white-notext.png") }
|
||||
.row
|
||||
.small-12.medium-8.medium-offset-2.columns.text-center
|
||||
.alert-box
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
%span
|
||||
= t '.cart'
|
||||
%span.count
|
||||
%img{ src: image_pack_path("menu/icn-cart.svg") }
|
||||
%img{ src: image_pack_path("images/menu/icn-cart.svg") }
|
||||
%span
|
||||
{{ Cart.total_item_count() }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
%nav.tab-bar.show-for-medium-down
|
||||
%section.left
|
||||
%a.left-off-canvas-toggle.menu-icon
|
||||
= image_pack_tag "menu/btn-menu-mobile.png"
|
||||
= image_pack_tag "images/menu/btn-menu-mobile.png"
|
||||
|
||||
%section.left
|
||||
.ofn-logo
|
||||
@@ -18,7 +18,7 @@
|
||||
%span
|
||||
= t '.cart'
|
||||
%span.count
|
||||
= image_pack_tag "menu/icn-cart.svg"
|
||||
= image_pack_tag "images/menu/icn-cart.svg"
|
||||
%span
|
||||
{{ Cart.total_item_count() }}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%li.user-menu.has-dropdown.not-click
|
||||
|
||||
%a{href: "#", class: "top-bar--menu-item-with-icon"}
|
||||
%img{ src: image_pack_path("menu/icn-profile.svg") }
|
||||
%img{ src: image_pack_path("images/menu/icn-profile.svg") }
|
||||
%span
|
||||
= t '.profile'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
= cache_with_locale do
|
||||
%li#login-link{ "data-controller": "login-modal" }
|
||||
%a{"auth": "login", "data-action": "click->login-modal#call" }
|
||||
%img{ src: image_pack_path("menu/icn-login.svg") }
|
||||
%img{ src: image_pack_path("images/menu/icn-login.svg") }
|
||||
%span
|
||||
= t 'label_login'
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"ng-debounce" => "200",
|
||||
"disable-enter-with-blur" => true}
|
||||
%a.clear{ type: 'button', "focus-search": true, "ng-show": 'query', "ng-click": 'clearQuery()' }
|
||||
= image_pack_tag "icn-close.png"
|
||||
= image_pack_tag "images/icn-close.png"
|
||||
|
||||
.hide-for-large-up
|
||||
%button{ type: 'button', "ng-click": 'toggleFilterSidebar()' }
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
%br
|
||||
- if current_distributor.whatsapp_phone.present?
|
||||
%a{href: current_distributor.whatsapp_url, target: "_blank" }
|
||||
%img{ src: image_pack_path("social-logos/whatsapp.svg") }
|
||||
%img{ src: image_pack_path("images/social-logos/whatsapp.svg") }
|
||||
= current_distributor.whatsapp_phone
|
||||
%br
|
||||
- if current_distributor.website.present?
|
||||
|
||||
@@ -41,5 +41,5 @@
|
||||
%a.info.cvvLink{href: "/content/cvv", target: "_blank"}
|
||||
(#{t(:what_is_this)})
|
||||
.nine.columns
|
||||
= image_pack_tag 'credit_cards/credit_card.gif', class: 'credit-card-image'
|
||||
= image_pack_tag 'images/credit_cards/credit_card.gif', class: 'credit-card-image'
|
||||
.clear
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
= form_for @product, url: admin_product_url(@product, @url_filters), method: :put do |f|
|
||||
%fieldset.no-border-top
|
||||
.add_product_properties
|
||||
= image_pack_tag 'select2-spinner.gif', plugin: 'spree', style: 'display:none;', id: 'busy_indicator'
|
||||
= image_pack_tag 'images/select2-spinner.gif', plugin: 'spree', style: 'display:none;', id: 'busy_indicator'
|
||||
|
||||
%table.index.sortable{"data-sortable-link" => update_positions_admin_product_product_properties_url}
|
||||
%thead
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
= render "spree/admin/shared/translations"
|
||||
= render "spree/admin/shared/routes"
|
||||
|
||||
= javascript_pack_tag "admin", "data-turbo-track": "reload"
|
||||
= javascript_pack_tag "admin", "data-turbo-track": "reload", defer: false # do not use defer because our javascript currently depend on order of execution of loaded script.
|
||||
|
||||
%script
|
||||
= raw "var AUTH_TOKEN = \"#{form_authenticity_token}\";"
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
- databaseurl = "#{admin_states_path(format: :js)}?country_id="
|
||||
%select#country.observe_field.select2.fullwidth{"data-base-url" => databaseurl, "data-update" => "#state-list"}
|
||||
= options_from_collection_for_select(@countries, :id, :name, @country.id)
|
||||
= image_pack_tag 'select2-spinner.gif', plugin: 'spree', style: 'display:none;', id: 'busy_indicator'
|
||||
= image_pack_tag 'images/select2-spinner.gif', plugin: 'spree', style: 'display:none;', id: 'busy_indicator'
|
||||
#state-list
|
||||
= render partial: 'state_list'
|
||||
|
||||
@@ -10,24 +10,5 @@
|
||||
%th= t('.url.header')
|
||||
%th.actions
|
||||
%tbody
|
||||
-# Existing endpoints
|
||||
- @user.webhook_endpoints.each do |webhook_endpoint|
|
||||
%tr
|
||||
%td= t('.event_types.order_cycle_opened') # For now, we only support one type.
|
||||
%td= webhook_endpoint.url
|
||||
%td.actions
|
||||
- if webhook_endpoint.persisted?
|
||||
= button_to account_webhook_endpoint_path(webhook_endpoint), method: :delete,
|
||||
class: "tiny alert no-margin",
|
||||
data: { confirm: I18n.t(:are_you_sure)} do
|
||||
= I18n.t(:delete)
|
||||
|
||||
-# Create new
|
||||
- if @user.webhook_endpoints.empty? # Only one allowed for now.
|
||||
%tr
|
||||
%td= t('.event_types.order_cycle_opened') # For now, we only support one type.
|
||||
%td
|
||||
= form_for(@user.webhook_endpoints.build, url: account_webhook_endpoints_path, id: 'new_webhook_endpoint') do |f|
|
||||
= f.url_field :url, placeholder: t('.url.create_placeholder'), required: true, size: 64
|
||||
%td.actions
|
||||
= button_tag t(:create), class: 'button primary tiny no-margin', form: 'new_webhook_endpoint'
|
||||
= render WebhookEndpointFormComponent.new(webhooks: @user.webhook_endpoints.order_cycle_opened, webhook_type: "order_cycle_opened")
|
||||
= render WebhookEndpointFormComponent.new(webhooks: @user.webhook_endpoints.payment_status, webhook_type: "payment_status_changed")
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
// While in feature-toggle, we inherit all files from old admin design.
|
||||
// Individual files may be copied in order to replace the old files.
|
||||
|
||||
@import "vendor/assets/stylesheets/normalize";
|
||||
@import "vendor/assets/stylesheets/responsive-tables";
|
||||
@import "vendor/assets/stylesheets/jquery.powertip";
|
||||
@import "~jquery-ui/themes/base/core";
|
||||
@import "~jquery-ui/themes/base/button";
|
||||
@import "~jquery-ui/themes/base/resizable";
|
||||
@import "vendor/assets/stylesheets/jquery-ui-theme";
|
||||
@import "~jquery-ui/themes/base/dialog";
|
||||
@import "assets/stylesheets/normalize";
|
||||
@import "assets/stylesheets/responsive-tables";
|
||||
@import "assets/stylesheets/jquery.powertip";
|
||||
@import "jquery-ui/themes/base/core";
|
||||
@import "jquery-ui/themes/base/button";
|
||||
@import "jquery-ui/themes/base/resizable";
|
||||
@import "assets/stylesheets/jquery-ui-theme";
|
||||
@import "jquery-ui/themes/base/dialog";
|
||||
@import "../shared/ng-tags-input.min";
|
||||
@import "vendor/assets/stylesheets/select2.css.scss";
|
||||
@import "~flatpickr/dist/flatpickr";
|
||||
@import "~flatpickr/dist/themes/material_blue";
|
||||
@import "~shortcut-buttons-flatpickr/dist/themes/light";
|
||||
@import "assets/stylesheets/select2";
|
||||
@import "flatpickr/dist/flatpickr";
|
||||
@import "flatpickr/dist/themes/material_blue";
|
||||
@import "shortcut-buttons-flatpickr/dist/themes/light";
|
||||
|
||||
@import "../admin/globals/functions";
|
||||
@import "globals/palette"; // admin_v3
|
||||
@@ -123,13 +123,13 @@
|
||||
@import "shared/question-mark-icon";
|
||||
@import "../admin/question-mark-tooltip";
|
||||
|
||||
@import "~tom-select/src/scss/tom-select.default";
|
||||
@import "tom-select/src/scss/tom-select.default";
|
||||
@import "components/tom_select"; // admin_v3
|
||||
|
||||
@import "app/components/modal_component/modal_component";
|
||||
@import "app/components/vertical_ellipsis_menu_component/vertical_ellipsis_menu_component"; // admin_v3 and only V3
|
||||
@import "app/components/tag_list_input_component/tag_list_input_component";
|
||||
@import "app/webpacker/css/admin/trix.scss";
|
||||
@import "modal_component/modal_component";
|
||||
@import "vertical_ellipsis_menu_component/vertical_ellipsis_menu_component"; // admin_v3 and only V3
|
||||
@import "tag_list_input_component/tag_list_input_component";
|
||||
@import "admin/trix";
|
||||
|
||||
@import "terms_of_service_banner"; // admin_v3
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.saved_cards, .no_cards {
|
||||
.saved_cards,
|
||||
.no_cards {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.authorised_shops{
|
||||
.authorised_shops {
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -39,7 +40,9 @@
|
||||
a {
|
||||
color: $clr-brick;
|
||||
|
||||
&:hover, &:active, &:focus {
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
color: $clr-brick-med-bright;
|
||||
}
|
||||
}
|
||||
@@ -60,7 +63,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
i.ofn-i_059-producer, i.ofn-i_060-producer-reversed {
|
||||
i.ofn-i_059-producer,
|
||||
i.ofn-i_060-producer-reversed {
|
||||
font-size: 3rem;
|
||||
display: inline-block;
|
||||
margin-right: 0.25rem;
|
||||
@@ -92,7 +96,8 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.transaction-group {}
|
||||
.transaction-group {
|
||||
}
|
||||
|
||||
table {
|
||||
border-radius: $radius-medium $radius-medium 0 0;
|
||||
@@ -161,6 +166,15 @@ table {
|
||||
//
|
||||
// Unfortunately we can't use Scss's interpolation
|
||||
// https://sass-lang.com/documentation/interpolation. We're using a too old version perhaps?
|
||||
right: calc(12px + 2*2px + 2*1px);
|
||||
right: calc(12px + 2 * 2px + 2 * 1px);
|
||||
}
|
||||
}
|
||||
|
||||
// Webhook Endpoints
|
||||
td.endpoints-actions {
|
||||
display: flex;
|
||||
|
||||
form {
|
||||
padding-right: $padding-small;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
@import 'vendor/assets/stylesheets/autocomplete';
|
||||
@import 'vendor/assets/stylesheets/leaflet';
|
||||
@import 'assets/stylesheets/autocomplete';
|
||||
@import 'assets/stylesheets/leaflet';
|
||||
@import 'variables';
|
||||
@import '../shared/variables/layout';
|
||||
@import '../shared/utilities';
|
||||
@import '~foundation-sites/scss/foundation';
|
||||
@import 'foundation-sites/scss/foundation';
|
||||
|
||||
@import 'big-input';
|
||||
@import 'branding';
|
||||
@@ -77,4 +77,4 @@ ofn-modal {
|
||||
@import "../shared/question-mark-icon";
|
||||
@import '../admin/shared/scroll_bar';
|
||||
|
||||
@import 'app/components/modal_component/modal_component';
|
||||
@import 'modal_component/modal_component';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "~foundation-sites/scss/foundation/components/global";
|
||||
@import "foundation-sites/scss/foundation/components/global";
|
||||
|
||||
// Brand guide colours:
|
||||
// International: #81c26e
|
||||
|
||||
@@ -1,72 +1,6 @@
|
||||
module.exports = function(api) {
|
||||
var validEnv = ['development', 'test', 'production']
|
||||
var currentEnv = api.env()
|
||||
var isDevelopmentEnv = api.env('development')
|
||||
var isProductionEnv = api.env('production')
|
||||
var isTestEnv = api.env('test')
|
||||
module.exports = function (api) {
|
||||
const defaultConfigFunc = require("shakapacker/package/babel/preset.js");
|
||||
const resultConfig = defaultConfigFunc(api);
|
||||
|
||||
if (!validEnv.includes(currentEnv)) {
|
||||
throw new Error(
|
||||
'Please specify a valid `NODE_ENV` or ' +
|
||||
'`BABEL_ENV` environment variables. Valid values are "development", ' +
|
||||
'"test", and "production". Instead, received: ' +
|
||||
JSON.stringify(currentEnv) +
|
||||
'.'
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
presets: [
|
||||
isTestEnv && [
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
node: 'current'
|
||||
}
|
||||
}
|
||||
],
|
||||
(isProductionEnv || isDevelopmentEnv) && [
|
||||
'@babel/preset-env',
|
||||
{
|
||||
forceAllTransforms: true,
|
||||
useBuiltIns: 'entry',
|
||||
corejs: 3,
|
||||
modules: false,
|
||||
exclude: ['transform-typeof-symbol']
|
||||
}
|
||||
]
|
||||
].filter(Boolean),
|
||||
plugins: [
|
||||
'babel-plugin-macros',
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
isTestEnv && 'babel-plugin-dynamic-import-node',
|
||||
'@babel/plugin-transform-destructuring',
|
||||
[
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
{
|
||||
loose: true
|
||||
}
|
||||
],
|
||||
[
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
{
|
||||
useBuiltIns: true
|
||||
}
|
||||
],
|
||||
[
|
||||
'@babel/plugin-transform-runtime',
|
||||
{
|
||||
helpers: false
|
||||
}
|
||||
],
|
||||
[
|
||||
'@babel/plugin-transform-regenerator',
|
||||
{
|
||||
async: false
|
||||
}
|
||||
],
|
||||
["@babel/plugin-proposal-private-property-in-object", { "loose": true }],
|
||||
["@babel/plugin-proposal-private-methods", { "loose": true }]
|
||||
].filter(Boolean)
|
||||
}
|
||||
}
|
||||
return resultConfig;
|
||||
};
|
||||
|
||||
22
bin/setup
22
bin/setup
@@ -1,4 +1,10 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# Install dependencies and migrate data during production deployments or
|
||||
# when updating your development environment.
|
||||
#
|
||||
# Take care when changing it and consider the ofn-install repository for
|
||||
# the context of deployments.
|
||||
require "fileutils"
|
||||
|
||||
# path to your application root.
|
||||
@@ -16,13 +22,13 @@ FileUtils.chdir APP_ROOT do
|
||||
# Add necessary setup steps to this file.
|
||||
|
||||
puts "== Installing dependencies =="
|
||||
system! "script/install-bundler"
|
||||
|
||||
# Check first (it's quicker), then install new gems if necessary
|
||||
system("bundle check 2> /dev/null") || system!(BUNDLE_ENV, "bundle install")
|
||||
|
||||
# Install JavaScript dependencies
|
||||
system("script/nodenv-install.sh")
|
||||
system("bin/yarn")
|
||||
system!("script/nodenv-install.sh")
|
||||
system!("bin/yarn")
|
||||
|
||||
# puts "\n== Copying sample files =="
|
||||
# unless File.exist?("config/database.yml")
|
||||
@@ -31,6 +37,16 @@ FileUtils.chdir APP_ROOT do
|
||||
|
||||
puts "\n== Preparing database, removing old logs and tempfiles =="
|
||||
system! "bin/rails db:prepare log:clear tmp:clear"
|
||||
system! "rm -f tmp/capybara/screenshots/*.png"
|
||||
system! "rm -f tmp/invoices/*.pdf"
|
||||
system! "rm -f tmp/javascripts/*.js"
|
||||
system! "rm -f tmp/karma_unit.js*"
|
||||
system! "rm -f tmp/product_import-*"
|
||||
|
||||
puts "\n== Removing any precompiled assets that would be out of date now =="
|
||||
system! "rm -rf public/assets/"
|
||||
system! "rm -rf public/packs/"
|
||||
system! "rm -rf public/packs-test/"
|
||||
|
||||
puts "\n== Restarting application server =="
|
||||
# system! "bin/rails restart"
|
||||
|
||||
13
bin/shakapacker
Executable file
13
bin/shakapacker
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
ENV["RAILS_ENV"] ||= "development"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
||||
|
||||
require "bundler/setup"
|
||||
require "shakapacker"
|
||||
require "shakapacker/webpack_runner"
|
||||
|
||||
APP_ROOT = File.expand_path("..", __dir__)
|
||||
Dir.chdir(APP_ROOT) do
|
||||
Shakapacker::WebpackRunner.run(ARGV)
|
||||
end
|
||||
13
bin/shakapacker-dev-server
Executable file
13
bin/shakapacker-dev-server
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
ENV["RAILS_ENV"] ||= "development"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
||||
|
||||
require "bundler/setup"
|
||||
require "shakapacker"
|
||||
require "shakapacker/dev_server_runner"
|
||||
|
||||
APP_ROOT = File.expand_path("..", __dir__)
|
||||
Dir.chdir(APP_ROOT) do
|
||||
Shakapacker::DevServerRunner.run(ARGV)
|
||||
end
|
||||
19
bin/webpack
19
bin/webpack
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
|
||||
ENV["NODE_ENV"] ||= "development"
|
||||
ENV["NODE_OPTIONS"] ||= "--openssl-legacy-provider"
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
|
||||
require "bundler/setup"
|
||||
|
||||
require "webpacker"
|
||||
require "webpacker/webpack_runner"
|
||||
|
||||
APP_ROOT = File.expand_path("..", __dir__)
|
||||
Dir.chdir(APP_ROOT) do
|
||||
Webpacker::WebpackRunner.run(ARGV)
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
|
||||
ENV["NODE_ENV"] ||= "development"
|
||||
ENV["NODE_OPTIONS"] ||= "--openssl-legacy-provider"
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
|
||||
require "bundler/setup"
|
||||
|
||||
require "webpacker"
|
||||
require "webpacker/dev_server_runner"
|
||||
|
||||
APP_ROOT = File.expand_path("..", __dir__)
|
||||
Dir.chdir(APP_ROOT) do
|
||||
Webpacker::DevServerRunner.run(ARGV)
|
||||
end
|
||||
15
bin/yarn
15
bin/yarn
@@ -1,9 +1,16 @@
|
||||
#!/usr/bin/env ruby
|
||||
APP_ROOT = File.expand_path('..', __dir__)
|
||||
|
||||
APP_ROOT = File.expand_path("..", __dir__)
|
||||
Dir.chdir(APP_ROOT) do
|
||||
begin
|
||||
exec "yarnpkg", *ARGV
|
||||
rescue Errno::ENOENT
|
||||
yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
|
||||
select { |dir| File.expand_path(dir) != __dir__ }.
|
||||
product(["yarn", "yarnpkg", "yarn.cmd", "yarn.ps1"]).
|
||||
map { |dir, file| File.expand_path(file, dir) }.
|
||||
find { |file| File.executable?(file) }
|
||||
|
||||
if yarn
|
||||
exec yarn, *ARGV
|
||||
else
|
||||
$stderr.puts "Yarn executable was not detected in the system."
|
||||
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
|
||||
exit 1
|
||||
|
||||
10
compose.yaml
10
compose.yaml
@@ -53,9 +53,9 @@ services:
|
||||
OFN_REDIS_URL: redis://redis/
|
||||
OFN_REDIS_JOBS_URL: redis://redis
|
||||
OFN_REDIS_TEST_URL: redis://redis/3
|
||||
WEBPACKER_DEV_SERVER_HOST: webpack
|
||||
WEBPACKER_DEV_SERVER_PORT: 3035
|
||||
WEBPACKER_DEV_SERVER_PUBLIC: localhost:3035
|
||||
SHAKAPACKER_DEV_SERVER_HOST: webpack
|
||||
SHAKAPACKER_DEV_SERVER_PORT: 3035
|
||||
SHAKAPACKER_DEV_SERVER_PUBLIC: localhost:3035
|
||||
|
||||
command: >
|
||||
sh -lc 'rm -f tmp/pids/server.pid;
|
||||
@@ -89,7 +89,7 @@ services:
|
||||
build: .
|
||||
command: >
|
||||
sh -lc 'until [ -f /bundles/.Gemfile.lock.sha ] && sha256sum -c /bundles/.Gemfile.lock.sha >/dev/null 2>&1; do sleep 0.5; done;
|
||||
exec ./bin/webpack-dev-server'
|
||||
exec ./bin/shakapacker-dev-server'
|
||||
ports:
|
||||
- "3035:3035"
|
||||
volumes:
|
||||
@@ -102,7 +102,7 @@ services:
|
||||
retries: 30
|
||||
|
||||
environment:
|
||||
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
|
||||
SHAKAPACKER_DEV_SERVER_HOST: 0.0.0.0
|
||||
volumes:
|
||||
gems:
|
||||
postgres:
|
||||
|
||||
@@ -58,10 +58,15 @@ module Openfoodnetwork
|
||||
Spree::Core::Engine.routes.default_url_options[:host] = ENV["SITE_URL"] if Rails.env == 'test'
|
||||
end
|
||||
|
||||
# We reload the routes here
|
||||
# so that the appended/prepended routes are available to the application.
|
||||
config.after_initialize do
|
||||
# We reload the routes here
|
||||
# so that the appended/prepended routes are available to the application.
|
||||
Rails.application.routes_reloader.reload!
|
||||
|
||||
# Subscribe to payment transition events
|
||||
ActiveSupport::Notifications.subscribe(
|
||||
"ofn.payment_transition", Payments::StatusChangedListenerService.new
|
||||
)
|
||||
end
|
||||
|
||||
initializer "spree.environment", before: :load_config_initializers do |app|
|
||||
@@ -71,14 +76,6 @@ module Openfoodnetwork
|
||||
end
|
||||
end
|
||||
|
||||
initializer "spree.register.payment_methods" do |app|
|
||||
Rails.application.reloader.to_prepare do
|
||||
app.config.spree.payment_methods = [
|
||||
Spree::PaymentMethod::Check
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
initializer "spree.mail.settings" do |_app|
|
||||
Rails.application.reloader.to_prepare do
|
||||
Spree::Core::MailSettings.init
|
||||
@@ -126,14 +123,6 @@ module Openfoodnetwork
|
||||
end
|
||||
end
|
||||
|
||||
# Register Spree payment methods
|
||||
initializer "spree.gateway.payment_methods", :after => "spree.register.payment_methods" do |app|
|
||||
Rails.application.reloader.to_prepare do
|
||||
app.config.spree.payment_methods << Spree::Gateway::StripeSCA
|
||||
app.config.spree.payment_methods << Spree::Gateway::PayPalExpress
|
||||
end
|
||||
end
|
||||
|
||||
initializer "ofn.reports" do |app|
|
||||
module ::Reporting; end
|
||||
Rails.application.reloader.to_prepare do
|
||||
@@ -206,7 +195,16 @@ module Openfoodnetwork
|
||||
|
||||
Rails.autoloaders.main.ignore(Rails.root.join('app/webpacker'))
|
||||
|
||||
config.active_storage.service = ENV["S3_BUCKET"].present? ? :amazon : :local
|
||||
config.active_storage.service =
|
||||
if ENV["S3_BUCKET"].present?
|
||||
if ENV["S3_ENDPOINT"].present?
|
||||
:s3_compatible_storage
|
||||
else
|
||||
:amazon
|
||||
end
|
||||
else
|
||||
:local
|
||||
end
|
||||
config.active_storage.content_types_to_serve_as_binary -= ["image/svg+xml"]
|
||||
config.active_storage.variable_content_types += ["image/svg+xml"]
|
||||
config.active_storage.url_options = config.action_controller.default_url_options
|
||||
|
||||
@@ -74,9 +74,6 @@ Rails.application.configure do
|
||||
allowed_warnings = [
|
||||
# List strings here to allow matching deprecations.
|
||||
#
|
||||
# `Rails.application.secrets` is deprecated in favor of `Rails.application.credentials` and will be removed in Rails 7.2
|
||||
"Rails.application.secrets",
|
||||
|
||||
"Passing the class as positional argument",
|
||||
|
||||
# Spree::CreditCard model aliases `cc_type` and has a method called `cc_type=` defined. Starting in Rails 7.2 `brand=` will not be calling `cc_type=` anymore. You may want to additionally define `brand=` to preserve the current behavior.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Rails.application.config.content_security_policy do |policy|
|
||||
policy.default_src :self, :https
|
||||
policy.font_src :self, :https, :data, "fonts.gstatic.com"
|
||||
policy.img_src :self, :https, :data, "*.s3.amazonaws.com"
|
||||
policy.img_src :self, :https, :data, ENV.fetch("S3_CORS_POLICY_DOMAIN", "*.s3.amazonaws.com")
|
||||
policy.img_src :self, :http, :data, ENV["SITE_URL"] if Rails.env.development?
|
||||
policy.object_src :none
|
||||
policy.frame_ancestors :none
|
||||
|
||||
@@ -27,18 +27,6 @@ end
|
||||
Flipper.register(:new_2024_07_03) do |actor|
|
||||
actor.respond_to?(:created_at?) && actor.created_at >= Time.zone.parse("2024-07-03")
|
||||
end
|
||||
Flipper.register(:enterprise_created_before_2025_08_11) do |actor|
|
||||
# This group applies to enterprises only, so we return false if the actor is not an Enterprise
|
||||
next false unless actor.actor.instance_of? Enterprise
|
||||
|
||||
actor.respond_to?(:created_at?) && actor.created_at < Time.zone.parse("2025-08-11")
|
||||
end
|
||||
Flipper.register(:enterprise_created_after_2025_08_11) do |actor|
|
||||
# This group applies to enterprises only, so we return false if the actor is not an Enterprise
|
||||
next false unless actor.actor.instance_of? Enterprise
|
||||
|
||||
actor.respond_to?(:created_at?) && actor.created_at >= Time.zone.parse("2025-08-11")
|
||||
end
|
||||
|
||||
Flipper.register(:enterprise_with_no_inventory) do |actor|
|
||||
# This group applies to enterprises only, so we return false if the actor is not an Enterprise
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
# `button_to` view helper will render `<button>` element, regardless of whether
|
||||
# or not the content is passed as the first argument or as a block.
|
||||
# Rails.application.config.action_view.button_to_generates_button_tag = true
|
||||
Rails.application.config.action_view.button_to_generates_button_tag = true
|
||||
|
||||
# `stylesheet_link_tag` view helper will not render the media attribute by default.
|
||||
Rails.application.config.action_view.apply_stylesheet_media_default = false
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
# serializer. Therefore, this setting should only be enabled after all replicas
|
||||
# have been successfully upgraded to Rails 7.1.
|
||||
#++
|
||||
# Rails.application.config.active_job.use_big_decimal_serializer = true
|
||||
Rails.application.config.active_job.use_big_decimal_serializer = true
|
||||
|
||||
###
|
||||
# Specify if an `ArgumentError` should be raised if `Rails.cache` `fetch` or
|
||||
|
||||
@@ -6,7 +6,4 @@
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
|
||||
# Rails 4+ key for signing and encrypting cookies.
|
||||
Openfoodnetwork::Application.config.secret_key_base = ENV["SECRET_TOKEN"]
|
||||
|
||||
# Legacy secret_token variable. This is still used directly for encryption.
|
||||
Openfoodnetwork::Application.config.secret_token = ENV["SECRET_TOKEN"]
|
||||
Openfoodnetwork::Application.credentials.secret_key_base = ENV["SECRET_TOKEN"]
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
module WebpackImageExtension
|
||||
def image_pack_path(image)
|
||||
# The Webpacker::Helper#resolve_path_to_image method is incredibly useful
|
||||
# for nicely fetching Webpacker image paths, but it's private.
|
||||
resolve_path_to_image(image)
|
||||
end
|
||||
end
|
||||
|
||||
Webpacker::Helper.include WebpackImageExtension
|
||||
@@ -716,6 +716,7 @@ ar:
|
||||
label: التصنيفات
|
||||
tags:
|
||||
label: الاوسمة
|
||||
none: لا شيء
|
||||
search: بحث
|
||||
sort:
|
||||
pagination:
|
||||
@@ -4358,13 +4359,10 @@ ar:
|
||||
webhook_endpoints:
|
||||
title: نقاط نهاية Webhook
|
||||
description: قد تؤدي الأحداث في النظام إلى تشغيل webhooks للأنظمة الخارجية.
|
||||
event_types:
|
||||
order_cycle_opened: تم فتح دورة الطلب
|
||||
event_type:
|
||||
header: نوع الحدث
|
||||
url:
|
||||
header: عنوان URL لنقطة النهاية
|
||||
create_placeholder: 'أدخل عنوان URL لنقطة نهاية webhook '
|
||||
developer_settings:
|
||||
title: إعدادات المطور
|
||||
form:
|
||||
@@ -4564,3 +4562,8 @@ ar:
|
||||
add_tag_rule_modal:
|
||||
select_rule_type: "اختر نوع القاعدة:"
|
||||
add_rule: "أضف قاعدة "
|
||||
webhook_endpoint_form:
|
||||
url:
|
||||
create_placeholder: 'أدخل عنوان URL لنقطة نهاية webhook '
|
||||
event_types:
|
||||
order_cycle_opened: تم فتح دورة الطلب
|
||||
|
||||
@@ -89,17 +89,6 @@ ca:
|
||||
messages:
|
||||
blank: "no es pot deixar en blanc"
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "té un tipus de contingut no vàlid"
|
||||
file_size_out_of_range: "la mida %{file_size} no és entre el rang necessari"
|
||||
limit_out_of_range: "el total està fora del marge"
|
||||
image_metadata_missing: "no és una imatge vàlida"
|
||||
aspect_ratio_not_square: "ha de ser una imatge quadrada"
|
||||
aspect_ratio_not_portrait: "ha de ser una imatge vertical"
|
||||
aspect_ratio_not_landscape: "ha de ser una imatge horitzontal"
|
||||
aspect_ratio_is_not: "ha de tenir una relació d'aspecte de %{aspect_ratio} "
|
||||
aspect_ratio_unknown: "té una relació d'aspecte desconeguda"
|
||||
image_not_processable: "no és una imatge vàlida"
|
||||
not_found:
|
||||
title: "La pàgina que esteu cridant no existeix (404)"
|
||||
message_html: "<b>Si us plau torna-ho a provar</b> Això podria ser un problema temporal. Feu clic al botó Enrere per tornar a la pantalla anterior o torneu a <a href='/'>Inici</a> i torneu-ho a provar. <b>Contacteu amb suport</b><p> Si el problema persisteix o és urgent, si us plau, digueu-nos-ho. Esn pots enviar un correua a <a href='https://openfoodnetwork.org/ofn-local/' target='blank'>suport<p>katuma.org </a>.</p><p> Ens ajuda molt si pots donar tants detalls com sigui possible sobre de què estaves fent quan va aparèixer l'error.</p>"
|
||||
@@ -773,6 +762,7 @@ ca:
|
||||
label: Categories
|
||||
tags:
|
||||
label: Etiquetes
|
||||
none: Cap
|
||||
search: Cerca
|
||||
sort:
|
||||
pagination:
|
||||
@@ -4249,8 +4239,6 @@ ca:
|
||||
title: Clau API
|
||||
webhook_endpoints:
|
||||
title: Webhook Endpoints
|
||||
event_types:
|
||||
order_cycle_opened: Cicle de comanda obert
|
||||
form:
|
||||
account_settings: Configuració del compte
|
||||
show:
|
||||
@@ -4393,3 +4381,6 @@ ca:
|
||||
add_tag_rule_modal:
|
||||
select_rule_type: "Selecciona un tipus de regla:"
|
||||
add_rule: "Afegeix una regla"
|
||||
webhook_endpoint_form:
|
||||
event_types:
|
||||
order_cycle_opened: Cicle de comanda obert
|
||||
|
||||
@@ -115,27 +115,6 @@ cy:
|
||||
blank: "ni chaniateir ei adael yn wag"
|
||||
too_short: "rhy fyr (o leiaf %{count} cymeriad)"
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "math o gynnwys annilys"
|
||||
file_size_out_of_range: "nid yw'r maint %{file_size} rhwng yr ystod ofynnol"
|
||||
limit_out_of_range: "mae'r cyfanswm rhif tu hwnt i'r ystod"
|
||||
image_metadata_missing: "nid yw'n llun dilys"
|
||||
dimension_min_inclusion: "mae'n gorfod bod yn fwy neu'r un faint â %{width} x %{height} picsel."
|
||||
dimension_max_inclusion: "mae'n gorfod bod yn llai neu'r un faint â %{width} x %{height} picsel."
|
||||
dimension_width_inclusion: "nid yw lled yn cael ei gynnwys rhwng %{min} ac %{max} picsel."
|
||||
dimension_height_inclusion: "nid yw uchder yn cael ei gynnwys rhwng %{min} acd %{max} picsel."
|
||||
dimension_width_greater_than_or_equal_to: "mae'r lled yn gorfod bod yn fwy neu'r un faint â %{length} picsel."
|
||||
dimension_height_greater_than_or_equal_to: "mae'r uchder yn gorfod bod yn fwy neu'r un faint â %{length} picsel."
|
||||
dimension_width_less_than_or_equal_to: "mae'r lled yn gorfod bod yn llai neu'r un faint â %{length} picsel."
|
||||
dimension_height_less_than_or_equal_to: "mae'r uchder yn gorfod bod yn llai neu'r un faint â %{length} picsel."
|
||||
dimension_width_equal_to: "mae'r lled yn gorfod bod yr un faint â %{length} picsel."
|
||||
dimension_height_equal_to: "mae'r uchder yn gorfod bod yr un faint â %{length} picsel."
|
||||
aspect_ratio_not_square: "mae'n gorfod bod yn llun sgwâr"
|
||||
aspect_ratio_not_portrait: "mae'n gorfod bod yn llun siâp portread"
|
||||
aspect_ratio_not_landscape: "mae'n gorfod bod yn llun siâp tirlun"
|
||||
aspect_ratio_is_not: "mae'n rhaid cael cymhareb agwedd o %{aspect_ratio}"
|
||||
aspect_ratio_unknown: "yn meddu ar gymhareb agwedd anhysbys"
|
||||
image_not_processable: "nid yw'n llun dilys"
|
||||
not_found:
|
||||
title: "Nid yw'r dudalen rydych yn chwilio amdani'n bodoli (404)"
|
||||
message_html: "<b>Rhowch gynnig arall</b> <p>. Hwyrach taw problem dros dro yw hon. Cliciwch y botwm ‘yn ôl’ i ddychwelyd at y sgrin flaenorol, neu ewch yn ôl i’r <a href='/'> Hafan </a>, a rhowch gynnig arall </p>. <b> Cysylltwch â’r ddesg</b> <p>Gymorth os bydd y broblem yn parhau neu os bydd yn fater brys, cofiwch ddweud wrthym amdano. Mae ein manylion cyswllt ar gael ar dudalen ‘Lleol’ <a href='https://openfoodnetwork.org/ofn-local/' target='blank'> y Rhwydwaith Bwyd Agored byd-eang </a>. </p> <p> Bydd o gymorth mawr inni os gallwch roi cymaint o fanylion â phosibl am y dudalen sydd ar goll.</p>"
|
||||
@@ -902,6 +881,7 @@ cy:
|
||||
label: Categorïau
|
||||
tags:
|
||||
label: Tagiau
|
||||
none: Dim
|
||||
search: Chwilio
|
||||
sort:
|
||||
pagination:
|
||||
@@ -4034,6 +4014,7 @@ cy:
|
||||
logourl: "url Logo"
|
||||
are_you_sure_delete: "Ydych chi'n siŵr eich bod chi am ddileu'r cofnod hwn?"
|
||||
confirm_delete: "Cadarnhau Dileu"
|
||||
voucher: "Taleb"
|
||||
configurations: "Cyfluniadau"
|
||||
general_settings: "Gosodiadau Cyffredinol"
|
||||
site_name: "Enw'r Safle"
|
||||
@@ -4758,13 +4739,10 @@ cy:
|
||||
webhook_endpoints:
|
||||
title: Webhook Endpoints
|
||||
description: Events in the system may trigger webhooks to external systems.
|
||||
event_types:
|
||||
order_cycle_opened: Order Cycle Opened
|
||||
event_type:
|
||||
header: Event type
|
||||
url:
|
||||
header: Endpoint URL
|
||||
create_placeholder: Enter the URL of the remote webhook endpoint
|
||||
developer_settings:
|
||||
title: Gosodiadau'r Datblygwr
|
||||
form:
|
||||
@@ -4938,6 +4916,11 @@ cy:
|
||||
add_tag_rule_modal:
|
||||
select_rule_type: "Dewis math o reol:"
|
||||
add_rule: "Ychwanegu Rheol"
|
||||
webhook_endpoint_form:
|
||||
url:
|
||||
create_placeholder: Enter the URL of the remote webhook endpoint
|
||||
event_types:
|
||||
order_cycle_opened: Order Cycle Opened
|
||||
invisible_captcha:
|
||||
sentence_for_humans: "Gadewch yn wag os gwelwch yn dda."
|
||||
timestamp_error_message: "Rhowch gynnig arall ar ôl 5 eiliad."
|
||||
|
||||
@@ -89,27 +89,6 @@ de_CH:
|
||||
messages:
|
||||
blank: "darf nicht leer sein"
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "hat ein ungültiges Datenformat"
|
||||
file_size_out_of_range: "Dateigrösse %{file_size} liegt ausserhalb des zulässigen Bereichs"
|
||||
limit_out_of_range: "Gesamtzahl liegt ausserhalb des zulässigen Bereichs"
|
||||
image_metadata_missing: "ist kein gültiges Bild"
|
||||
dimension_min_inclusion: "muss grösser oder gleich %{width} x %{height} Pixel sein"
|
||||
dimension_max_inclusion: "muss kleiner oder gleich %{width} x %{height} Pixel sein"
|
||||
dimension_width_inclusion: "Breite liegt nicht zwischen %{min} und %{max} Pixel"
|
||||
dimension_height_inclusion: "Höhe liegt nicht zwischen %{min} und %{max} Pixel"
|
||||
dimension_width_greater_than_or_equal_to: "Breite muss grösser oder gleich %{length} Pixel sein"
|
||||
dimension_height_greater_than_or_equal_to: "Höhe muss grösser oder gleich %{length} Pixel sein"
|
||||
dimension_width_less_than_or_equal_to: "Breite muss kleiner oder gleich %{length} Pixel sein"
|
||||
dimension_height_less_than_or_equal_to: "Höhe muss kleiner oder gleich %{length} Pixel sein"
|
||||
dimension_width_equal_to: "Breite muss %{length} Pixel sein"
|
||||
dimension_height_equal_to: "Höhe muss %{length} Pixel sein"
|
||||
aspect_ratio_not_square: "muss ein quadratisches Bild sein"
|
||||
aspect_ratio_not_portrait: "muss ein Bild im Hochformat sein"
|
||||
aspect_ratio_not_landscape: "muss ein Bild im Querformat sein"
|
||||
aspect_ratio_is_not: "muss ein Seitenverhältnis von %{aspect_ratio} haben"
|
||||
aspect_ratio_unknown: "hat ein unbekanntes Seitenverhältnis"
|
||||
image_not_processable: "ist kein gültiges Bild"
|
||||
not_found:
|
||||
title: "Die gesuchte Seite existiert nicht (404)"
|
||||
stripe:
|
||||
@@ -752,6 +731,7 @@ de_CH:
|
||||
label: Lieferkategorien
|
||||
tags:
|
||||
label: Stichwörter
|
||||
none: Keine
|
||||
search: Suche
|
||||
sort:
|
||||
pagination:
|
||||
@@ -3615,6 +3595,7 @@ de_CH:
|
||||
logourl: "URL des Logos"
|
||||
are_you_sure_delete: "Möchten Sie diesen Datensatz wirklich löschen?"
|
||||
confirm_delete: "Löschen bestätigen"
|
||||
voucher: "Gutschein"
|
||||
configurations: "Konfiguration"
|
||||
general_settings: "Allgemeine Einstellungen"
|
||||
site_name: "Name der Website"
|
||||
|
||||
@@ -105,27 +105,6 @@ de_DE:
|
||||
blank: "darf nicht leer sein."
|
||||
too_short: "ist zu kurz (mindestens %{count} Zeichen)"
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "hat ein ungültiges Datenformat"
|
||||
file_size_out_of_range: "Dateigröße %{file_size} liegt außerhalb des zulässigen Bereichs"
|
||||
limit_out_of_range: "Gesamtzahl liegt außerhalb des zulässigen Bereichs"
|
||||
image_metadata_missing: "ist kein gültiges Bild"
|
||||
dimension_min_inclusion: "muss größer oder gleich %{width} x %{height} Pixel sein"
|
||||
dimension_max_inclusion: "muss kleiner oder gleich %{width} x %{height} Pixel sein"
|
||||
dimension_width_inclusion: "Breite liegt nicht zwischen %{min} und %{max} Pixel"
|
||||
dimension_height_inclusion: "Höhe liegt nicht zwischen %{min} und %{max} Pixel"
|
||||
dimension_width_greater_than_or_equal_to: "Breite muss größer oder gleich %{length} Pixel sein"
|
||||
dimension_height_greater_than_or_equal_to: "Höhe muss größer oder gleich %{length} Pixel sein"
|
||||
dimension_width_less_than_or_equal_to: "Breite muss kleiner oder gleich %{length} Pixel sein"
|
||||
dimension_height_less_than_or_equal_to: "Höhe muss kleiner oder gleich %{length} Pixel sein"
|
||||
dimension_width_equal_to: "Breite muss %{length} Pixel sein"
|
||||
dimension_height_equal_to: "Höhe muss %{length} Pixel sein"
|
||||
aspect_ratio_not_square: "muss ein quadratisches Bild sein"
|
||||
aspect_ratio_not_portrait: "muss ein Bild im Hochformat sein"
|
||||
aspect_ratio_not_landscape: "muss ein Bild im Querformat sein"
|
||||
aspect_ratio_is_not: "muss ein Seitenverhältnis von %{aspect_ratio} haben"
|
||||
aspect_ratio_unknown: "hat ein unbekanntes Seitenverhältnis"
|
||||
image_not_processable: "ist kein gültiges Bild"
|
||||
not_found:
|
||||
title: "Die gesuchte Seite existiert nicht (404). "
|
||||
message_html: "<b>Bitte versuchen Sie es erneut</b><p> Dies könnte ein vorübergehendes Problem sein. Bitte klicken Sie auf die Zurück-Schaltfläche, um zum vorherigen Bildschirm zurückzukehren, oder gehen Sie zurück zur <a href='/'>Startseite</a> und versuchen Sie es erneut.</p> <b>Kontaktieren Sie den Support</b><p> Wenn das Problem weiterhin besteht oder dringend ist, teilen Sie uns dies bitte mit. Unsere Kontaktdaten finden Sie auf der <a href='https://openfoodnetwork.org/ofn-local/' target='blank'>lokalen Seite des globalen Open Food Network</a> .</p><p> Es hilft uns sehr, wenn Sie so detailliert wie möglich angeben können, worum es auf der fehlenden Seite geht.</p>"
|
||||
@@ -795,14 +774,17 @@ de_DE:
|
||||
cancellation_text: "Produktvariante beibehalten"
|
||||
filters:
|
||||
search_products: Nach Produkten suchen
|
||||
search_for_producers: Produzenten suchen
|
||||
all_producers: Alle Produzenten
|
||||
search_for_categories: Kategorie suchen
|
||||
all_categories: Alle Kategorien
|
||||
producers:
|
||||
label: Unsere Produzenten
|
||||
categories:
|
||||
label: Lieferkategorien
|
||||
label: Produktkategorie
|
||||
tags:
|
||||
label: Stichwörter
|
||||
none: Nichts
|
||||
search: Suche
|
||||
sort:
|
||||
pagination:
|
||||
@@ -845,6 +827,7 @@ de_DE:
|
||||
category_field_name: "Kategorie"
|
||||
tax_category_field_name: "Steuerkategorie"
|
||||
producer_field_name: "Produzent"
|
||||
select_unit_scale: Einheit auswählen
|
||||
add_a_tag: Stichwort hinzufügen
|
||||
clone:
|
||||
success: Das Produkt wurde dupliziert.
|
||||
@@ -1098,6 +1081,7 @@ de_DE:
|
||||
images:
|
||||
legend: "Bilder"
|
||||
logo: Logo
|
||||
logo_size: "300 x 300 Pixel"
|
||||
inventory_settings:
|
||||
legend: "Katalog"
|
||||
text1: Sie verwalten optional Ihre Lagerbestände und Preise auch in Ihrem
|
||||
@@ -1259,7 +1243,7 @@ de_DE:
|
||||
vouchers:
|
||||
legend: Gutscheine
|
||||
voucher_code: Gutschein-Code
|
||||
rate: Steuersatz
|
||||
rate: Gutscheinwert
|
||||
label: Bezeichnung
|
||||
purpose: Zweck
|
||||
expiry: Gültigkeit
|
||||
@@ -1516,6 +1500,7 @@ de_DE:
|
||||
shared:
|
||||
attachment_field:
|
||||
logo_label: "Logo"
|
||||
logo_hint: 300 x 300 Pixel
|
||||
logo_remove: "Bild löschen"
|
||||
logo_remove_confirm: "Das Logo wird sofort nach Ihrer Bestätigung gelöscht."
|
||||
promo_image_note1: 'BITTE BEACHTEN SIE:'
|
||||
@@ -3078,6 +3063,8 @@ de_DE:
|
||||
report_header_transaction_fee: Transaktionsgebühr (keine Steuern)
|
||||
report_header_total_untaxable_admin: Summe nicht steuerpflichtiger Admin-Anpassungen (keine Steuern)
|
||||
report_header_total_taxable_admin: Summe steuerpflichtiger Admin-Anpassungen (inkl. Steuern)
|
||||
report_header_voucher_label: Gutschein-Code
|
||||
report_header_voucher_amount: "Gutscheinwert"
|
||||
report_line_cost_of_produce: Produktkosten
|
||||
report_line_line_items: Einzelposten
|
||||
report_header_last_completed_order_date: Letzte Bestellung
|
||||
@@ -3795,6 +3782,7 @@ de_DE:
|
||||
logourl: "URL des Logos"
|
||||
are_you_sure_delete: "Möchten Sie diesen Datensatz wirklich löschen?"
|
||||
confirm_delete: "Löschen bestätigen"
|
||||
voucher: "Gutschein"
|
||||
configurations: "Konfiguration"
|
||||
general_settings: "Allgemeine Einstellungen"
|
||||
site_name: "Name der Website"
|
||||
@@ -4248,6 +4236,7 @@ de_DE:
|
||||
product_name: Produktname
|
||||
primary_taxon_form:
|
||||
product_category: Produktkategorie
|
||||
search_for_categories: "Lieferkategorie suchen"
|
||||
group_buy_form:
|
||||
group_buy: "Gruppenkauf aktivieren?"
|
||||
bulk_unit_size: Erforderliche Gesamtbestellmenge (in Gramm, Liter oder Stück)
|
||||
@@ -4500,13 +4489,10 @@ de_DE:
|
||||
webhook_endpoints:
|
||||
title: Webhook-Endpunkte
|
||||
description: Ereignisse im System können Webhooks zu externen Systemen auslösen.
|
||||
event_types:
|
||||
order_cycle_opened: Bestellzyklus eröffnet
|
||||
event_type:
|
||||
header: Ereignistyp
|
||||
url:
|
||||
header: Endpunkt-URL
|
||||
create_placeholder: Geben Sie die URL des Remote-Webhook-Endpunkts ein
|
||||
developer_settings:
|
||||
title: Entwicklereinstellungen
|
||||
form:
|
||||
@@ -4654,3 +4640,8 @@ de_DE:
|
||||
add_tag_rule_modal:
|
||||
select_rule_type: "Wählen Sie einen Regelart aus:"
|
||||
add_rule: "Regel hinzufügen"
|
||||
webhook_endpoint_form:
|
||||
url:
|
||||
create_placeholder: Geben Sie die URL des Remote-Webhook-Endpunkts ein
|
||||
event_types:
|
||||
order_cycle_opened: Bestellzyklus eröffnet
|
||||
|
||||
@@ -106,27 +106,6 @@ el:
|
||||
blank: "δεν μπορεί να είναι κενό"
|
||||
too_short: "είναι πολύ σύντομο (το ελάχιστο είναι %{count} χαρακτήρες)"
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "περιέχει λανθασμένο τύπο περιεχομένου"
|
||||
file_size_out_of_range: "μέγεθος %{file_size} δεν είναι εντός της απαιτούμενης εμβέλειας"
|
||||
limit_out_of_range: "Ο συνολικός αριθμός βρίσκεται εκτός εύρους"
|
||||
image_metadata_missing: "δεν είναι έγκυρη εικόνα"
|
||||
dimension_min_inclusion: "πρέπει να είναι μεγαλύτερο η ίσο με %{width} x %{height} pixels."
|
||||
dimension_max_inclusion: "πρέπει να είναι μικρότερο από ή ίσο με %{width} x %{height} pixels."
|
||||
dimension_width_inclusion: "Το πλάτος δεν είναι μεταξύ %{min} και %{max} pixels."
|
||||
dimension_height_inclusion: "Το ύψος δεν είναι μεταξύ %{min} και %{max} pixels. "
|
||||
dimension_width_greater_than_or_equal_to: "Το πλάτος πρέπει να είναι μεγαλύτερο από η ίσο με %{length} pixels."
|
||||
dimension_height_greater_than_or_equal_to: "Το ύψος πρέπει να είναι μεγαλύτερο από η ίσο με %{length} pixels."
|
||||
dimension_width_less_than_or_equal_to: "Το πλάτος πρέπει να είναι μικρότερο από ή ίσο με %{length} pixels."
|
||||
dimension_height_less_than_or_equal_to: "Το ύψος πρέπει να είναι μικρότερο από η ίσο με %{length} pixels."
|
||||
dimension_width_equal_to: "Το πλάτος πρέπει να είναι ίσο με %{length} pixels."
|
||||
dimension_height_equal_to: "Το ύψος πρέπει να είναι ίσο με %{length} pixels."
|
||||
aspect_ratio_not_square: "πρέπει να είναι τετράγωνη εικόνα. "
|
||||
aspect_ratio_not_portrait: "πρέπει να είναι εικόνα πορτρέτο. "
|
||||
aspect_ratio_not_landscape: "πρέπει να είναι εικόνα τοπίου."
|
||||
aspect_ratio_is_not: "πρέπει να έχει λόγο διαστάσεων %{aspect_ratio}"
|
||||
aspect_ratio_unknown: "έχει άγνωστη αναλογία εμφάνισης (aspect ratio)."
|
||||
image_not_processable: "δεν είναι έγκυρη εικόνα"
|
||||
not_found:
|
||||
title: "Η συγκεκριμένη σελίδα δεν υπάρχει (404) "
|
||||
message_html: "<b>Παρακαλούμε προσπαθήστε ξανά</b> <p>Πιθανόν να πρόκειται για προσωρινό σφάλμα. Παρακαλούμε επιστρέψτε στην προηγούμενη σελίδα ή πηγαίνετε πίσω στην <a href='/'>Αρχική σελίδα</a> και προσπαθήστε ξανά.</p> <b>Επικοινωνήστε με την εξυπηρέτηση πελατών</b> <p>Εάν το πρόβλημα παραμένει η επείγει, παρακαλούμε να μας ενημερώσετε. Βρείτε τα στοιχεία επικοινωνίας μας στο <a href='https://openfoodnetwork.org/ofn-local/' target='blank'>Open Food Network Local page</a>. </p><p>Θα μας είναι απόλυτα χρήσιμο το να μας δώσετε όσες περισσότερες πληροφορίες γίνεται αναφορικά με τα στοιχεία της σελίδας που λείπουν.</p>"
|
||||
@@ -817,6 +796,7 @@ el:
|
||||
label: Κατηγορίες
|
||||
tags:
|
||||
label: Ετικέτες
|
||||
none: Κανένας
|
||||
search: Αναζήτηση
|
||||
sort:
|
||||
pagination:
|
||||
@@ -3798,6 +3778,7 @@ el:
|
||||
logourl: "Logourl"
|
||||
are_you_sure_delete: "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την εγγραφή;"
|
||||
confirm_delete: "Επιβεβαίωση διαγραφής"
|
||||
voucher: "Κουπόνι"
|
||||
configurations: "Διαμορφώσεις"
|
||||
general_settings: "Γενικές Ρυθμίσεις"
|
||||
site_name: "Ονομα ιστοσελίδας"
|
||||
@@ -4513,11 +4494,8 @@ el:
|
||||
webhook_endpoints:
|
||||
title: Webhook Endpoints
|
||||
description: Συμβάντα στο σύστημα μπορεί να πυροδοτήσουν webhooks σε εξωτερικά συστήματα.
|
||||
event_types:
|
||||
order_cycle_opened: Ο Κύκλος παραγγελίας άνοιξε
|
||||
url:
|
||||
header: Endpoint URL
|
||||
create_placeholder: Εισάγετε το URL απο το απομακρυσμένο webhook endpoint.
|
||||
developer_settings:
|
||||
title: Ρυθμίσεις Developer
|
||||
form:
|
||||
@@ -4665,6 +4643,11 @@ el:
|
||||
add_tag_rule_modal:
|
||||
select_rule_type: "Επιλέξτε έναν τύπο κανόνα:"
|
||||
add_rule: "Προσθήκη κανόνα"
|
||||
webhook_endpoint_form:
|
||||
url:
|
||||
create_placeholder: Εισάγετε το URL απο το απομακρυσμένο webhook endpoint.
|
||||
event_types:
|
||||
order_cycle_opened: Ο Κύκλος παραγγελίας άνοιξε
|
||||
invisible_captcha:
|
||||
sentence_for_humans: "Παρακαλώ αφήστε κενό"
|
||||
timestamp_error_message: "Παρακαλώ δοκιμάστε ξανά σε 5 δευτερόλεπτα."
|
||||
|
||||
@@ -138,26 +138,66 @@ en:
|
||||
# Used by active_storage_validations
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "has an invalid content type"
|
||||
file_size_out_of_range: "size %{file_size} is not between required range"
|
||||
limit_out_of_range: "total number is out of range"
|
||||
image_metadata_missing: "is not a valid image"
|
||||
dimension_min_inclusion: "must be greater than or equal to %{width} x %{height} pixel."
|
||||
dimension_max_inclusion: "must be less than or equal to %{width} x %{height} pixel."
|
||||
dimension_width_inclusion: "width is not included between %{min} and %{max} pixel."
|
||||
dimension_height_inclusion: "height is not included between %{min} and %{max} pixel."
|
||||
dimension_width_greater_than_or_equal_to: "width must be greater than or equal to %{length} pixel."
|
||||
dimension_height_greater_than_or_equal_to: "height must be greater than or equal to %{length} pixel."
|
||||
dimension_width_less_than_or_equal_to: "width must be less than or equal to %{length} pixel."
|
||||
dimension_height_less_than_or_equal_to: "height must be less than or equal to %{length} pixel."
|
||||
dimension_width_equal_to: "width must be equal to %{length} pixel."
|
||||
dimension_height_equal_to: "height must be equal to %{length} pixel."
|
||||
aspect_ratio_not_square: "must be a square image"
|
||||
aspect_ratio_not_portrait: "must be a portrait image"
|
||||
aspect_ratio_not_landscape: "must be a landscape image"
|
||||
aspect_ratio_is_not: "must have an aspect ratio of %{aspect_ratio}"
|
||||
aspect_ratio_unknown: "has an unknown aspect ratio"
|
||||
image_not_processable: "is not a valid image"
|
||||
content_type_invalid:
|
||||
one: "has an invalid content type (authorized content type is %{authorized_human_content_types})"
|
||||
other: "has an invalid content type (authorized content types are %{authorized_human_content_types})"
|
||||
content_type_spoofed:
|
||||
one: "has a content type that is not equivalent to the one that is detected through its content (authorized content type is %{authorized_human_content_types})"
|
||||
other: "has a content type that is not equivalent to the one that is detected through its content (authorized content types are %{authorized_human_content_types})"
|
||||
file_size_not_less_than: "file size must be less than %{max} (current size is %{file_size})"
|
||||
file_size_not_less_than_or_equal_to: "file size must be less than or equal to %{max} (current size is %{file_size})"
|
||||
file_size_not_greater_than: "file size must be greater than %{min} (current size is %{file_size})"
|
||||
file_size_not_greater_than_or_equal_to: "file size must be greater than or equal to %{min} (current size is %{file_size})"
|
||||
file_size_not_between: "file size must be between %{min} and %{max} (current size is %{file_size})"
|
||||
file_size_not_equal_to: "file size must be equal to %{exact} (current size is %{file_size})"
|
||||
total_file_size_not_less_than: "total file size must be less than %{max} (current size is %{total_file_size})"
|
||||
total_file_size_not_less_than_or_equal_to: "total file size must be less than or equal to %{max} (current size is %{total_file_size})"
|
||||
total_file_size_not_greater_than: "total file size must be greater than %{min} (current size is %{total_file_size})"
|
||||
total_file_size_not_greater_than_or_equal_to: "total file size must be greater than or equal to %{min} (current size is %{total_file_size})"
|
||||
total_file_size_not_between: "total file size must be between %{min} and %{max} (current size is %{total_file_size})"
|
||||
total_file_size_not_equal_to: "total file size must be equal to %{exact} (current size is %{total_file_size})"
|
||||
duration_not_less_than: "duration must be less than %{max} (current duration is %{duration})"
|
||||
duration_not_less_than_or_equal_to: "duration must be less than or equal to %{max} (current duration is %{duration})"
|
||||
duration_not_greater_than: "duration must be greater than %{min} (current duration is %{duration})"
|
||||
duration_not_greater_than_or_equal_to: "duration must be greater than or equal to %{min} (current duration is %{duration})"
|
||||
duration_not_between: "duration must be between %{min} and %{max} (current duration is %{duration})"
|
||||
duration_not_equal_to: "duration must be equal to %{exact} (current duration is %{duration})"
|
||||
limit_out_of_range:
|
||||
zero: "no files attached (must have between %{min} and %{max} files)"
|
||||
one: "only 1 file attached (must have between %{min} and %{max} files)"
|
||||
other: "total number of files must be between %{min} and %{max} files (there are %{count} files attached)"
|
||||
limit_min_not_reached:
|
||||
zero: "no files attached (must have at least %{min} files)"
|
||||
one: "only 1 file attached (must have at least %{min} files)"
|
||||
other: "%{count} files attached (must have at least %{min} files)"
|
||||
limit_max_exceeded:
|
||||
zero: "no files attached (maximum is %{max} files)"
|
||||
one: "too many files attached (maximum is %{max} files, got %{count})"
|
||||
other: "too many files attached (maximum is %{max} files, got %{count})"
|
||||
attachment_missing: "is missing its attachment"
|
||||
media_metadata_missing: "is not a valid media file"
|
||||
dimension_min_not_included_in: "must be greater than or equal to %{width} x %{height} pixels"
|
||||
dimension_max_not_included_in: "must be less than or equal to %{width} x %{height} pixels"
|
||||
dimension_width_not_included_in: "width is not included between %{min} and %{max} pixels"
|
||||
dimension_height_not_included_in: "height is not included between %{min} and %{max} pixels"
|
||||
dimension_width_not_greater_than_or_equal_to: "width must be greater than or equal to %{length} pixels"
|
||||
dimension_height_not_greater_than_or_equal_to: "height must be greater than or equal to %{length} pixels"
|
||||
dimension_width_not_less_than_or_equal_to: "width must be less than or equal to %{length} pixels"
|
||||
dimension_height_not_less_than_or_equal_to: "height must be less than or equal to %{length} pixels"
|
||||
dimension_width_not_equal_to: "width must be equal to %{length} pixels"
|
||||
dimension_height_not_equal_to: "height must be equal to %{length} pixels"
|
||||
aspect_ratio_not_square: "must be square (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_not_portrait: "must be portrait (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_not_landscape: "must be landscape (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_not_x_y: "must be %{authorized_aspect_ratios} (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_invalid: "has an invalid aspect ratio (valid aspect ratios are %{authorized_aspect_ratios})"
|
||||
file_not_processable: "is not identified as a valid media file"
|
||||
pages_not_less_than: "page count must be less than %{max} (current page count is %{pages})"
|
||||
pages_not_less_than_or_equal_to: "page count must be less than or equal to %{max} (current page count is %{pages})"
|
||||
pages_not_greater_than: "page count must be greater than %{min} (current page count is %{pages})"
|
||||
pages_not_greater_than_or_equal_to: "page count must be greater than or equal to %{min} (current page count is %{pages})"
|
||||
pages_not_between: "page count must be between %{min} and %{max} (current page count is %{pages})"
|
||||
pages_not_equal_to: "page count must be equal to %{exact} (current page count is %{pages})"
|
||||
not_found:
|
||||
title: "The page you were looking for doesn't exist (404)"
|
||||
message_html: "<b>Please try again</b>
|
||||
@@ -587,6 +627,7 @@ en:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API, please try again later."
|
||||
invalid_voucher: "The voucher is not valid"
|
||||
expired: "The voucher has expired"
|
||||
not_found_voucher: "Sorry, we couldn't find that voucher, please check the code."
|
||||
vine_voucher_redeemer_service:
|
||||
errors:
|
||||
@@ -977,6 +1018,7 @@ en:
|
||||
label: Categories
|
||||
tags:
|
||||
label: Tags
|
||||
none: None
|
||||
search: Search
|
||||
sort:
|
||||
pagination:
|
||||
@@ -4088,6 +4130,8 @@ en:
|
||||
destroy:
|
||||
success: Webhook endpoint successfully deleted
|
||||
error: Webhook endpoint failed to delete
|
||||
test:
|
||||
success: Some test data will be sent to the webhook url
|
||||
|
||||
spree:
|
||||
order_updated: "Order Updated"
|
||||
@@ -4195,6 +4239,8 @@ en:
|
||||
logourl: "Logourl"
|
||||
are_you_sure_delete: "Are you sure you want to delete this record?"
|
||||
confirm_delete: "Confirm Deletion"
|
||||
tag_rule: "Tag Rule"
|
||||
voucher: "Voucher"
|
||||
|
||||
configurations: "Configurations"
|
||||
general_settings: "General Settings"
|
||||
@@ -4938,13 +4984,10 @@ en:
|
||||
webhook_endpoints:
|
||||
title: Webhook Endpoints
|
||||
description: Events in the system may trigger webhooks to external systems.
|
||||
event_types:
|
||||
order_cycle_opened: Order Cycle Opened
|
||||
event_type:
|
||||
header: Event type
|
||||
url:
|
||||
header: Endpoint URL
|
||||
create_placeholder: Enter the URL of the remote webhook endpoint
|
||||
developer_settings:
|
||||
title: Developer Settings
|
||||
form:
|
||||
@@ -5093,7 +5136,13 @@ en:
|
||||
add_tag_rule_modal:
|
||||
select_rule_type: "Select a rule type:"
|
||||
add_rule: "Add Rule"
|
||||
|
||||
webhook_endpoint_form:
|
||||
url:
|
||||
create_placeholder: Enter the URL of the remote webhook endpoint
|
||||
event_types:
|
||||
order_cycle_opened: Order Cycle Opened
|
||||
payment_status_changed: Post webhook on Payment status change
|
||||
test_endpoint: Test webhook endpoint
|
||||
|
||||
# Gem to prevent bot form submissions
|
||||
invisible_captcha:
|
||||
|
||||
@@ -561,6 +561,7 @@ en_AU:
|
||||
label: Categories
|
||||
tags:
|
||||
label: Tags
|
||||
none: None
|
||||
search: Search
|
||||
sort:
|
||||
pagination:
|
||||
|
||||
@@ -526,6 +526,7 @@ en_BE:
|
||||
label: Categories
|
||||
tags:
|
||||
label: Tags
|
||||
none: None
|
||||
search: Search
|
||||
product_variant_row:
|
||||
new_variant: New variant
|
||||
|
||||
@@ -116,26 +116,66 @@ en_CA:
|
||||
too_short: "is too short (minimum is %{count} characters)"
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "has an invalid content type"
|
||||
file_size_out_of_range: "size %{file_size} is not within required range"
|
||||
limit_out_of_range: "total number is out of range"
|
||||
image_metadata_missing: "is not a valid image"
|
||||
dimension_min_inclusion: "must be greater than or equal to %{width} x %{height} pixels."
|
||||
dimension_max_inclusion: "must be less than or equal to %{width} x %{height} pixels."
|
||||
dimension_width_inclusion: "width is not between %{min} and %{max} pixels."
|
||||
dimension_height_inclusion: "height is not between %{min} and %{max} pixels."
|
||||
dimension_width_greater_than_or_equal_to: "width must be greater than or equal to %{length} pixels."
|
||||
dimension_height_greater_than_or_equal_to: "height must be greater than or equal to %{length} pixels."
|
||||
dimension_width_less_than_or_equal_to: "width must be less than or equal to %{length} pixels."
|
||||
dimension_height_less_than_or_equal_to: "height must be less than or equal to %{length} pixels."
|
||||
dimension_width_equal_to: "width must be equal to %{length} pixels."
|
||||
dimension_height_equal_to: "height must be equal to %{length} pixels."
|
||||
aspect_ratio_not_square: "must be a square image"
|
||||
aspect_ratio_not_portrait: "must be a portrait image"
|
||||
aspect_ratio_not_landscape: "must be a landscape image"
|
||||
aspect_ratio_is_not: "must have an aspect ration of %{aspect_ratio}"
|
||||
aspect_ratio_unknown: "has an unknown aspect ration"
|
||||
image_not_processable: "is not a valid image"
|
||||
content_type_invalid:
|
||||
one: "has an invalid content type (authorized content type is %{authorized_human_content_types})"
|
||||
other: "has an invalid content type (authorized content types are %{authorized_human_content_types})"
|
||||
content_type_spoofed:
|
||||
one: "has a content type that is not equivalent to the one that is detected through its content (authorized content type is %{authorized_human_content_types})"
|
||||
other: "has a content type that is not equivalent to the one that is detected through its content (authorized content types are %{authorized_human_content_types})"
|
||||
file_size_not_less_than: "file size must be less than %{max} (current size is %{file_size})"
|
||||
file_size_not_less_than_or_equal_to: "file size must be less than or equal to %{max} (current size is %{file_size})"
|
||||
file_size_not_greater_than: "file size must be greater than %{min} (current size is %{file_size})"
|
||||
file_size_not_greater_than_or_equal_to: "file size must be greater than or equal to %{min} (current size is %{file_size})"
|
||||
file_size_not_between: "file size must be between %{min} and %{max} (current size is %{file_size})"
|
||||
file_size_not_equal_to: "file size must be equal to %{exact} (current size is %{file_size})"
|
||||
total_file_size_not_less_than: "total file size must be less than %{max} (current size is %{total_file_size})"
|
||||
total_file_size_not_less_than_or_equal_to: "total file size must be less than or equal to %{max} (current size is %{total_file_size})"
|
||||
total_file_size_not_greater_than: "total file size must be greater than %{min} (current size is %{total_file_size})"
|
||||
total_file_size_not_greater_than_or_equal_to: "total file size must be greater than or equal to %{min} (current size is %{total_file_size})"
|
||||
total_file_size_not_between: "total file size must be between %{min} and %{max} (current size is %{total_file_size})"
|
||||
total_file_size_not_equal_to: "total file size must be equal to %{exact} (current size is %{total_file_size})"
|
||||
duration_not_less_than: "duration must be less than %{max} (current duration is %{duration})"
|
||||
duration_not_less_than_or_equal_to: "duration must be less than or equal to %{max} (current duration is %{duration})"
|
||||
duration_not_greater_than: "duration must be greater than %{min} (current duration is %{duration})"
|
||||
duration_not_greater_than_or_equal_to: "duration must be greater than or equal to %{min} (current duration is %{duration})"
|
||||
duration_not_between: "duration must be between %{min} and %{max} (current duration is %{duration})"
|
||||
duration_not_equal_to: "duration must be equal to %{exact} (current duration is %{duration})"
|
||||
limit_out_of_range:
|
||||
zero: "no files attached (must have between %{min} and %{max} files)"
|
||||
one: "only 1 file attached (must have between %{min} and %{max} files)"
|
||||
other: "total number of files must be between %{min} and %{max} files (there are %{count} files attached)"
|
||||
limit_min_not_reached:
|
||||
zero: "no files attached (must have at least %{min} files)"
|
||||
one: "only 1 file attached (must have at least %{min} files)"
|
||||
other: "%{count} files attached (must have at least %{min} files)"
|
||||
limit_max_exceeded:
|
||||
zero: "no files attached (maximum is %{max} files)"
|
||||
one: "too many files attached (maximum is %{max} files, got %{count})"
|
||||
other: "too many files attached (maximum is %{max} files, got %{count})"
|
||||
attachment_missing: "is missing its attachment"
|
||||
media_metadata_missing: "is not a valid media file"
|
||||
dimension_min_not_included_in: "must be greater than or equal to %{width} x %{height} pixels"
|
||||
dimension_max_not_included_in: "must be less than or equal to %{width} x %{height} pixels"
|
||||
dimension_width_not_included_in: "width is not included between %{min} and %{max} pixels"
|
||||
dimension_height_not_included_in: "height is not included between %{min} and %{max} pixels"
|
||||
dimension_width_not_greater_than_or_equal_to: "width must be greater than or equal to %{length} pixels"
|
||||
dimension_height_not_greater_than_or_equal_to: "height must be greater than or equal to %{length} pixels"
|
||||
dimension_width_not_less_than_or_equal_to: "width must be less than or equal to %{length} pixels"
|
||||
dimension_height_not_less_than_or_equal_to: "height must be less than or equal to %{length} pixels"
|
||||
dimension_width_not_equal_to: "width must be equal to %{length} pixels"
|
||||
dimension_height_not_equal_to: "height must be equal to %{length} pixels"
|
||||
aspect_ratio_not_square: "must be square (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_not_portrait: "must be portrait (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_not_landscape: "must be landscape (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_not_x_y: "must be %{authorized_aspect_ratios} (current file is %{width}x%{height}px)"
|
||||
aspect_ratio_invalid: "has an invalid aspect ratio (valid aspect ratios are %{authorized_aspect_ratios})"
|
||||
file_not_processable: "is not identified as a valid media file"
|
||||
pages_not_less_than: "page count must be less than %{max} (current page count is %{pages})"
|
||||
pages_not_less_than_or_equal_to: "page count must be less than or equal to %{max} (current page count is %{pages})"
|
||||
pages_not_greater_than: "page count must be greater than %{min} (current page count is %{pages})"
|
||||
pages_not_greater_than_or_equal_to: "page count must be greater than or equal to %{min} (current page count is %{pages})"
|
||||
pages_not_between: "page count must be between %{min} and %{max} (current page count is %{pages})"
|
||||
pages_not_equal_to: "page count must be equal to %{exact} (current page count is %{pages})"
|
||||
not_found:
|
||||
title: "The page you were looking for doesn't exist (404)"
|
||||
message_html: "<b>Please try again</b> <p>This might be a temporary problem. Please click the back button to return to the previous screen or go back to <a href='/'>Home</a>and try again.</p> <b>Contact support <p>If the problem persists or is urgent, please tell us about it. Find our contact details from the global <a href='https://openfoodnetwork.org/ofn-local/' target='blank'>Open Food Network Local page</a>.</p> <p>It really helps us if you can give as much detail as possible about what the missing page is about.</p>"
|
||||
@@ -541,6 +581,7 @@ en_CA:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API, please try again later."
|
||||
invalid_voucher: "The voucher is not valid"
|
||||
expired: "The voucher has expired"
|
||||
not_found_voucher: "Sorry, we couldn't find that voucher, please check the code."
|
||||
vine_voucher_redeemer_service:
|
||||
errors:
|
||||
@@ -906,6 +947,7 @@ en_CA:
|
||||
label: Categories
|
||||
tags:
|
||||
label: Tags
|
||||
none: None
|
||||
search: Search
|
||||
sort:
|
||||
pagination:
|
||||
@@ -3929,6 +3971,8 @@ en_CA:
|
||||
destroy:
|
||||
success: Webhook endpoint successfully deleted
|
||||
error: Webhood endpoint failed to delete
|
||||
test:
|
||||
success: Some test data will be sent to the webhook url
|
||||
spree:
|
||||
order_updated: "Order Updated"
|
||||
cannot_perform_operation: "Can not perform this operation"
|
||||
@@ -4035,6 +4079,8 @@ en_CA:
|
||||
logourl: "Logourl"
|
||||
are_you_sure_delete: "Are you sure you want to delete this record?"
|
||||
confirm_delete: "Confirm Deletion"
|
||||
tag_rule: "Tag Rule"
|
||||
voucher: "Voucher"
|
||||
configurations: "Configurations"
|
||||
general_settings: "General Settings"
|
||||
site_name: "Site Name"
|
||||
@@ -4760,13 +4806,10 @@ en_CA:
|
||||
webhook_endpoints:
|
||||
title: Webhook Endpoints
|
||||
description: Events in the system may trigger webhooks to external systems.
|
||||
event_types:
|
||||
order_cycle_opened: Order Cycle Opened
|
||||
event_type:
|
||||
header: Event type
|
||||
url:
|
||||
header: Endpoint URL
|
||||
create_placeholder: Enter the URL of the remove webhook endpoint
|
||||
developer_settings:
|
||||
title: Developer Settings
|
||||
form:
|
||||
@@ -4915,6 +4958,13 @@ en_CA:
|
||||
add_tag_rule_modal:
|
||||
select_rule_type: "Select a rule type:"
|
||||
add_rule: "Add Rule"
|
||||
webhook_endpoint_form:
|
||||
url:
|
||||
create_placeholder: Enter the URL of the remove webhook endpoint
|
||||
event_types:
|
||||
order_cycle_opened: Order Cycle Opened
|
||||
payment_status_changed: Post webhook on Payment status change
|
||||
test_endpoint: Test webhook endpoint
|
||||
invisible_captcha:
|
||||
sentence_for_humans: "Please leave empty"
|
||||
timestamp_error_message: "Please try again after 5 seconds."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user