mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-17 19:26:48 +00:00
Compare commits
233 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12fde5b9fc | ||
|
|
0da6275d41 | ||
|
|
52d2d1d23c | ||
|
|
4dfc020eaa | ||
|
|
8ef52f97e5 | ||
|
|
68a7f547b1 | ||
|
|
7a0f2d47a3 | ||
|
|
4affd01b7b | ||
|
|
0432c73f19 | ||
|
|
103902c006 | ||
|
|
d2933e35f1 | ||
|
|
0b5e341ae7 | ||
|
|
7d36c3b5aa | ||
|
|
d511763733 | ||
|
|
a059c11d0f | ||
|
|
cecc19ae1d | ||
|
|
d4311a848e | ||
|
|
d64573f7fd | ||
|
|
a9fe6ec1b5 | ||
|
|
f14bbc5ed9 | ||
|
|
5ba8efec2c | ||
|
|
3bf38b7c08 | ||
|
|
a591e0736f | ||
|
|
3080eb9dfd | ||
|
|
ed98a16eec | ||
|
|
7a924bd9ca | ||
|
|
7639e19184 | ||
|
|
71aff7e1d2 | ||
|
|
2506667bca | ||
|
|
f87a553230 | ||
|
|
3171b60d6f | ||
|
|
516398fbd6 | ||
|
|
4a1b74c136 | ||
|
|
b9edea7c0e | ||
|
|
b9053f9fd2 | ||
|
|
f297cff8c7 | ||
|
|
7563d38b4b | ||
|
|
83523a676f | ||
|
|
abcfb5ce8d | ||
|
|
8ee6d1c320 | ||
|
|
1bc19ad6a4 | ||
|
|
191b8064ed | ||
|
|
e28274db14 | ||
|
|
02dec1d6cd | ||
|
|
df04c837a5 | ||
|
|
7a6c085b63 | ||
|
|
a4317b70f4 | ||
|
|
cb90fb052d | ||
|
|
18e5f9ba64 | ||
|
|
e9a5b889de | ||
|
|
cc57b0c200 | ||
|
|
a8040e986d | ||
|
|
2269f824c0 | ||
|
|
c45a3c2303 | ||
|
|
1327d80446 | ||
|
|
43a3ac0a7b | ||
|
|
b948312de7 | ||
|
|
7063de4734 | ||
|
|
56c1a9cca2 | ||
|
|
9555bfcc93 | ||
|
|
e455a47135 | ||
|
|
e15e71a3a7 | ||
|
|
91d959b7d6 | ||
|
|
108f57a705 | ||
|
|
af42159e09 | ||
|
|
8e55c39ca0 | ||
|
|
6cfb060184 | ||
|
|
0cfb7269c8 | ||
|
|
cbec495620 | ||
|
|
55eea21bb0 | ||
|
|
f63c7cf54f | ||
|
|
13633e8bea | ||
|
|
093edb66d3 | ||
|
|
fb25ddd219 | ||
|
|
d54850f097 | ||
|
|
f8451a2511 | ||
|
|
1a88549954 | ||
|
|
f79182253a | ||
|
|
8cfd7c610b | ||
|
|
486b5e9edc | ||
|
|
8fe3abfd45 | ||
|
|
0e7dafea46 | ||
|
|
4c9cc7460a | ||
|
|
c9e3f58aed | ||
|
|
4136306abf | ||
|
|
9f1eaf0b66 | ||
|
|
4771612adb | ||
|
|
7ce3dfe365 | ||
|
|
6f13707b9d | ||
|
|
64cb104434 | ||
|
|
1606f9900f | ||
|
|
9f0e8b0b2e | ||
|
|
d796e96470 | ||
|
|
ba7f78ef60 | ||
|
|
988e146240 | ||
|
|
e6d9ec7bd7 | ||
|
|
3acc53a389 | ||
|
|
9c9fc999de | ||
|
|
d824c84ce6 | ||
|
|
1a301f3dbb | ||
|
|
fad4f3b22a | ||
|
|
6080c99850 | ||
|
|
2944acff8a | ||
|
|
2068a59b72 | ||
|
|
3063439ed1 | ||
|
|
6bed05c721 | ||
|
|
a3ee6674ea | ||
|
|
e59077e63e | ||
|
|
f9f8d85841 | ||
|
|
0042690e18 | ||
|
|
5f1111b52b | ||
|
|
25ded0d23c | ||
|
|
a5458150ca | ||
|
|
96eebbabf3 | ||
|
|
c58e6fa964 | ||
|
|
fbe8f5195c | ||
|
|
f587bbb7d5 | ||
|
|
2793693a7c | ||
|
|
07e2317369 | ||
|
|
042162eda8 | ||
|
|
795f13d73a | ||
|
|
f1814f1b67 | ||
|
|
4ab7b78cb8 | ||
|
|
11631c3a33 | ||
|
|
0212381362 | ||
|
|
e6ca6bacac | ||
|
|
59df45b8cf | ||
|
|
5892e85869 | ||
|
|
c59326743b | ||
|
|
cb3397fd1a | ||
|
|
2bd4de3e29 | ||
|
|
b2c5be775e | ||
|
|
d22212ccfa | ||
|
|
dd600cd163 | ||
|
|
f189ca8004 | ||
|
|
db7146014c | ||
|
|
c6af55d9ae | ||
|
|
0f588dbe0b | ||
|
|
9c14d8ff36 | ||
|
|
a104bf8efd | ||
|
|
a039ef13f4 | ||
|
|
7ad8951375 | ||
|
|
99e59595b4 | ||
|
|
3264355f12 | ||
|
|
7e3b6e2b5d | ||
|
|
a9598c5d97 | ||
|
|
3e5b7ebbf1 | ||
|
|
1a9c3007b0 | ||
|
|
2f7fd1482a | ||
|
|
0416521772 | ||
|
|
cfe3f72d0e | ||
|
|
00478cc57c | ||
|
|
d5e42ee1e5 | ||
|
|
9451f1b66d | ||
|
|
ff584f9be9 | ||
|
|
a589ba38da | ||
|
|
a4a2f98b6e | ||
|
|
f5ddbfbac3 | ||
|
|
a66a4c3edb | ||
|
|
8179252924 | ||
|
|
0bec492208 | ||
|
|
5cf50f0adf | ||
|
|
197fb36524 | ||
|
|
62e6f09d94 | ||
|
|
79b2460664 | ||
|
|
66f3656bb5 | ||
|
|
6b087adab8 | ||
|
|
3653b88da6 | ||
|
|
3223bf930d | ||
|
|
2b3bc6d1ff | ||
|
|
24d7672abb | ||
|
|
89628c27f3 | ||
|
|
9adbdc377d | ||
|
|
883cd81058 | ||
|
|
0d7d029255 | ||
|
|
ce31a059bf | ||
|
|
17bac20c65 | ||
|
|
066243057f | ||
|
|
ea40547fd7 | ||
|
|
0ebc6d4b1e | ||
|
|
62c2e4709a | ||
|
|
c5229dd763 | ||
|
|
99d4190814 | ||
|
|
f086c02e13 | ||
|
|
b726f961fc | ||
|
|
4c17cf0087 | ||
|
|
9fe143cf94 | ||
|
|
e2d783c385 | ||
|
|
81cb162884 | ||
|
|
c7b6dd2677 | ||
|
|
d1fd73fd2b | ||
|
|
b0221d264e | ||
|
|
0f64badc74 | ||
|
|
7ccfdc8d21 | ||
|
|
4799293996 | ||
|
|
58a93c27ae | ||
|
|
0202b59634 | ||
|
|
9f351607d1 | ||
|
|
c45e3c9cca | ||
|
|
71bf3f5f71 | ||
|
|
ef142de5f2 | ||
|
|
f64e8bf50e | ||
|
|
e8d68e3b89 | ||
|
|
1b29d474d0 | ||
|
|
baae58ecb6 | ||
|
|
6411871ecb | ||
|
|
22833ae79b | ||
|
|
ac20b0e7fb | ||
|
|
e9e6aa77d8 | ||
|
|
29e30c388e | ||
|
|
54a40fe79c | ||
|
|
7840118dea | ||
|
|
5e27bd6d6d | ||
|
|
d4512904ea | ||
|
|
52dc288470 | ||
|
|
302de04e73 | ||
|
|
41767936d6 | ||
|
|
0ccf30202e | ||
|
|
00f36e4686 | ||
|
|
4d77f30bc0 | ||
|
|
f38b1b95f0 | ||
|
|
852adfd436 | ||
|
|
2673a6efee | ||
|
|
6ffe7f1a99 | ||
|
|
ba1ad0a6dd | ||
|
|
4e7b397c5a | ||
|
|
842e191c5f | ||
|
|
feaa928674 | ||
|
|
c8d359a0da | ||
|
|
210757641c | ||
|
|
68bf599a1a | ||
|
|
a10966b66b | ||
|
|
08003f2003 |
@@ -4,6 +4,7 @@
|
||||
#
|
||||
# The configuration is split into three files. Look into those files for more details.
|
||||
#
|
||||
require: rubocop-rails
|
||||
inherit_from:
|
||||
|
||||
# The automatically generated todo list to ignore all current violations.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#
|
||||
# This process probably doesn't need repeating. Otherwise there is plenty
|
||||
# of room for improvements and automation.
|
||||
Metrics/LineLength:
|
||||
Layout/LineLength:
|
||||
Max: 100
|
||||
Exclude:
|
||||
- Gemfile
|
||||
@@ -42,7 +42,6 @@ Metrics/LineLength:
|
||||
- app/controllers/application_controller.rb
|
||||
- app/controllers/checkout_controller.rb
|
||||
- app/controllers/spree/admin/adjustments_controller_decorator.rb
|
||||
- app/controllers/spree/admin/base_controller_decorator.rb
|
||||
- app/controllers/spree/admin/orders_controller_decorator.rb
|
||||
- app/controllers/spree/admin/payments_controller_decorator.rb
|
||||
- app/controllers/spree/credit_cards_controller.rb
|
||||
@@ -115,7 +114,6 @@ Metrics/LineLength:
|
||||
- lib/open_food_network/enterprise_issue_validator.rb
|
||||
- lib/open_food_network/group_buy_report.rb
|
||||
- lib/open_food_network/lettuce_share_report.rb
|
||||
- lib/open_food_network/order_and_distributor_report.rb
|
||||
- lib/open_food_network/order_cycle_form_applicator.rb
|
||||
- lib/open_food_network/order_cycle_management_report.rb
|
||||
- lib/open_food_network/payments_report.rb
|
||||
@@ -144,6 +142,7 @@ Metrics/LineLength:
|
||||
- spec/controllers/admin/subscriptions_controller_spec.rb
|
||||
- spec/controllers/admin/variant_overrides_controller_spec.rb
|
||||
- spec/controllers/api/base_controller_spec.rb
|
||||
- spec/controllers/api/exchange_products_controller_spec.rb
|
||||
- spec/controllers/api/logos_controller_spec.rb
|
||||
- spec/controllers/api/order_cycles_controller_spec.rb
|
||||
- spec/controllers/api/orders_controller_spec.rb
|
||||
@@ -305,6 +304,7 @@ Metrics/LineLength:
|
||||
- spec/serializers/api/admin/exchange_serializer_spec.rb
|
||||
- spec/serializers/api/admin/for_order_cycle/enterprise_serializer_spec.rb
|
||||
- spec/serializers/api/admin/for_order_cycle/supplied_product_serializer_spec.rb
|
||||
- spec/serializers/api/admin/order_cycle_serializer_spec.rb
|
||||
- spec/serializers/api/admin/subscription_customer_serializer_spec.rb
|
||||
- spec/serializers/api/admin/variant_override_serializer_spec.rb
|
||||
- spec/serializers/api/current_order_serializer_spec.rb
|
||||
@@ -312,11 +312,13 @@ Metrics/LineLength:
|
||||
- spec/serializers/api/order_serializer_spec.rb
|
||||
- spec/services/cart_service_spec.rb
|
||||
- spec/services/embedded_page_service_spec.rb
|
||||
- spec/services/exchange_products_renderer_spec.rb
|
||||
- spec/services/order_cycle_distributed_products_spec.rb
|
||||
- spec/services/order_cycle_distributed_variants_spec.rb
|
||||
- spec/services/order_cycle_form_spec.rb
|
||||
- spec/services/order_factory_spec.rb
|
||||
- spec/services/order_syncer_spec.rb
|
||||
- spec/services/permissions/order_spec.rb
|
||||
- spec/services/product_tag_rules_filterer_spec.rb
|
||||
- spec/services/products_renderer_spec.rb
|
||||
- spec/services/subscription_estimator_spec.rb
|
||||
@@ -362,11 +364,12 @@ Metrics/AbcSize:
|
||||
- app/controllers/spree/admin/image_settings_controller.rb
|
||||
- app/controllers/spree/admin/orders/customer_details_controller_decorator.rb
|
||||
- app/controllers/spree/admin/orders_controller_decorator.rb
|
||||
- app/controllers/spree/admin/overview_controller_decorator.rb
|
||||
- app/controllers/spree/admin/overview_controller.rb
|
||||
- app/controllers/spree/admin/payment_methods_controller.rb
|
||||
- app/controllers/spree/admin/payments_controller_decorator.rb
|
||||
- app/controllers/spree/admin/products_controller_decorator.rb
|
||||
- app/controllers/spree/admin/reports_controller_decorator.rb
|
||||
- app/controllers/spree/admin/reports_controller.rb
|
||||
- app/controllers/spree/admin/resource_controller.rb
|
||||
- app/controllers/spree/admin/search_controller_decorator.rb
|
||||
- app/controllers/spree/admin/taxons_controller.rb
|
||||
- app/controllers/spree/admin/users_controller.rb
|
||||
@@ -565,7 +568,8 @@ Metrics/MethodLength:
|
||||
- app/controllers/spree/admin/payment_methods_controller.rb
|
||||
- app/controllers/spree/admin/payments_controller_decorator.rb
|
||||
- app/controllers/spree/admin/products_controller_decorator.rb
|
||||
- app/controllers/spree/admin/reports_controller_decorator.rb
|
||||
- app/controllers/spree/admin/reports_controller.rb
|
||||
- app/controllers/spree/admin/resource_controller.rb
|
||||
- app/controllers/spree/admin/search_controller_decorator.rb
|
||||
- app/controllers/spree/admin/tax_categories_controller.rb
|
||||
- app/controllers/spree/admin/taxons_controller.rb
|
||||
@@ -644,7 +648,10 @@ Metrics/ClassLength:
|
||||
- app/controllers/admin/subscriptions_controller.rb
|
||||
- app/controllers/api/products_controller.rb
|
||||
- app/controllers/checkout_controller.rb
|
||||
- app/controllers/spree/admin/base_controller.rb
|
||||
- app/controllers/spree/admin/payment_methods_controller.rb
|
||||
- app/controllers/spree/admin/reports_controller.rb
|
||||
- app/controllers/spree/admin/resource_controller.rb
|
||||
- app/controllers/spree/admin/users_controller.rb
|
||||
- app/controllers/spree/orders_controller.rb
|
||||
- app/models/enterprise.rb
|
||||
@@ -700,6 +707,7 @@ Metrics/ModuleLength:
|
||||
- spec/models/spree/payment_spec.rb
|
||||
- spec/models/spree/product_spec.rb
|
||||
- spec/models/spree/variant_spec.rb
|
||||
- spec/services/permissions/order_spec.rb
|
||||
- spec/support/request/web_helper.rb
|
||||
|
||||
Metrics/ParameterLists:
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
# rubocop locally, the default configuration file `.rubocop.yml` loads
|
||||
# our "todo lists" to ignore all current violations.
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.2
|
||||
TargetRailsVersion: 3.2
|
||||
Exclude:
|
||||
- 'bin/**/*'
|
||||
@@ -41,7 +40,7 @@ Layout/MultilineMethodCallIndentation:
|
||||
Enabled: true
|
||||
EnforcedStyle: indented
|
||||
|
||||
Metrics/LineLength:
|
||||
Layout/LineLength:
|
||||
Max: 100
|
||||
|
||||
## TEMPORARY/CONTESTED SETTINGS
|
||||
|
||||
1201
.rubocop_todo.yml
1201
.rubocop_todo.yml
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
2.2.10
|
||||
2.3.7
|
||||
|
||||
18
Gemfile
18
Gemfile
@@ -1,9 +1,9 @@
|
||||
source 'https://rubygems.org'
|
||||
ruby "2.2.10"
|
||||
ruby "2.3.7"
|
||||
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
|
||||
|
||||
gem 'i18n', '~> 0.6.11'
|
||||
gem 'i18n-js', '~> 3.5.0'
|
||||
gem 'i18n-js', '~> 3.5.1'
|
||||
gem 'rails', '~> 3.2.22'
|
||||
gem 'rails-i18n', '~> 3.0.0'
|
||||
gem 'rails_safe_tasks', '~> 1.0'
|
||||
@@ -93,7 +93,7 @@ gem 'wkhtmltopdf-binary'
|
||||
|
||||
gem 'foreigner'
|
||||
gem 'immigrant'
|
||||
gem 'roo', '~> 2.7.0'
|
||||
gem 'roo', '~> 2.8.2'
|
||||
gem 'roo-xls', '~> 1.1.0'
|
||||
|
||||
gem 'whenever', require: false
|
||||
@@ -106,10 +106,7 @@ group :assets do
|
||||
gem 'coffee-rails', '~> 3.2.1'
|
||||
gem 'compass-rails'
|
||||
|
||||
gem 'mini_racer', '0.1.15'
|
||||
# Previously we found that libv8 6.7.288.46.1 breakis the compilation of mini_racer.
|
||||
# Now we see that we need to set the version explicitly. Nothing else depends on libv8.
|
||||
gem 'libv8', '6.3.292.48.1'
|
||||
gem 'mini_racer', '0.2.4'
|
||||
|
||||
gem 'uglifier', '>= 1.0.3'
|
||||
|
||||
@@ -135,7 +132,7 @@ group :test, :development do
|
||||
# Pretty printed test output
|
||||
gem 'atomic'
|
||||
gem 'awesome_print'
|
||||
gem 'capybara', '>= 2.15.4'
|
||||
gem 'capybara', '>= 2.18.0' # 3.0 requires nokogiri 1.8
|
||||
gem 'database_cleaner', '0.7.1', require: false
|
||||
gem "factory_bot_rails", require: false
|
||||
gem 'fuubar', '~> 2.5.0'
|
||||
@@ -148,7 +145,7 @@ group :test, :development do
|
||||
gem 'shoulda-matchers'
|
||||
gem 'timecop'
|
||||
gem 'unicorn-rails'
|
||||
gem 'webdrivers', '3.8.1'
|
||||
gem 'webdrivers'
|
||||
end
|
||||
|
||||
group :test do
|
||||
@@ -163,7 +160,8 @@ group :development do
|
||||
gem 'debugger-linecache'
|
||||
gem "newrelic_rpm", "~> 3.0"
|
||||
gem 'pry-byebug', '>= 3.4.3'
|
||||
gem 'rubocop', '>= 0.49.1'
|
||||
gem 'rubocop'
|
||||
gem 'rubocop-rails'
|
||||
gem 'spring', '1.7.2'
|
||||
gem 'spring-commands-rspec'
|
||||
|
||||
|
||||
85
Gemfile.lock
85
Gemfile.lock
@@ -129,7 +129,7 @@ GEM
|
||||
activesupport (= 3.2.22.5)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activerecord-import (1.0.3)
|
||||
activerecord-import (1.0.4)
|
||||
activerecord (>= 3.2)
|
||||
activerecord-postgresql-adapter (0.0.1)
|
||||
pg
|
||||
@@ -178,8 +178,7 @@ GEM
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (>= 2.0, < 4.0)
|
||||
childprocess (0.9.0)
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
childprocess (3.0.0)
|
||||
chronic (0.10.2)
|
||||
chunky_png (1.3.10)
|
||||
climate_control (0.2.0)
|
||||
@@ -213,7 +212,6 @@ GEM
|
||||
sass-rails (< 5.1)
|
||||
sprockets (< 4.0)
|
||||
concurrent-ruby (1.1.5)
|
||||
connection_pool (2.2.2)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
css_parser (1.7.0)
|
||||
@@ -225,7 +223,7 @@ GEM
|
||||
activerecord (>= 3.2.0, < 5.0)
|
||||
fog (~> 1.0)
|
||||
rails (>= 3.2.0, < 5.0)
|
||||
ddtrace (0.29.0)
|
||||
ddtrace (0.31.0)
|
||||
msgpack
|
||||
debugger-linecache (1.2.0)
|
||||
deface (1.0.2)
|
||||
@@ -256,17 +254,17 @@ GEM
|
||||
dry-inflector (0.1.2)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.2.7)
|
||||
excon (0.62.0)
|
||||
excon (0.71.1)
|
||||
execjs (2.7.0)
|
||||
factory_bot (4.10.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_bot_rails (4.10.0)
|
||||
factory_bot (~> 4.10.0)
|
||||
railties (>= 3.0.0)
|
||||
faraday (0.15.4)
|
||||
faraday (0.17.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffaker (1.22.1)
|
||||
ffi (1.10.0)
|
||||
ffi (1.11.3)
|
||||
figaro (1.1.1)
|
||||
thor (~> 0.14)
|
||||
fission (0.5.0)
|
||||
@@ -439,7 +437,7 @@ GEM
|
||||
httparty (0.16.2)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.6.11)
|
||||
i18n-js (3.5.0)
|
||||
i18n-js (3.5.1)
|
||||
i18n (>= 0.6.6)
|
||||
immigrant (0.3.6)
|
||||
activerecord (>= 3.0)
|
||||
@@ -467,7 +465,7 @@ GEM
|
||||
addressable (~> 2.3)
|
||||
letter_opener (1.7.0)
|
||||
launchy (~> 2.2)
|
||||
libv8 (6.3.292.48.1)
|
||||
libv8 (7.3.492.27.1)
|
||||
mail (2.5.5)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
@@ -475,8 +473,8 @@ GEM
|
||||
mime-types (1.25.1)
|
||||
mini_mime (1.0.1)
|
||||
mini_portile2 (2.1.0)
|
||||
mini_racer (0.1.15)
|
||||
libv8 (~> 6.3)
|
||||
mini_racer (0.2.4)
|
||||
libv8 (>= 6.3)
|
||||
momentjs-rails (2.20.1)
|
||||
railties (>= 3.1)
|
||||
money (5.1.1)
|
||||
@@ -485,8 +483,6 @@ GEM
|
||||
multi_json (1.14.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
net-http-persistent (3.1.0)
|
||||
connection_pool (~> 2.2)
|
||||
newrelic_rpm (3.18.1.330)
|
||||
nokogiri (1.6.8.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
@@ -496,7 +492,7 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
oj (3.7.12)
|
||||
oj (3.10.0)
|
||||
orm_adapter (0.5.0)
|
||||
paper_trail (5.2.3)
|
||||
activerecord (>= 3.0, < 6.0)
|
||||
@@ -507,10 +503,10 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
cocaine (~> 0.5.0)
|
||||
mime-types
|
||||
parallel (1.18.0)
|
||||
parallel (1.19.1)
|
||||
paranoia (1.3.4)
|
||||
activerecord (~> 3.1)
|
||||
parser (2.6.5.0)
|
||||
parser (2.7.0.2)
|
||||
ast (~> 2.4.0)
|
||||
paypal-sdk-core (0.2.10)
|
||||
multi_json (~> 1.0)
|
||||
@@ -534,7 +530,7 @@ GEM
|
||||
rack (1.4.7)
|
||||
rack-cache (1.9.0)
|
||||
rack (>= 0.4)
|
||||
rack-mini-profiler (1.0.0)
|
||||
rack-mini-profiler (1.1.4)
|
||||
rack (>= 1.2.0)
|
||||
rack-protection (1.5.5)
|
||||
rack
|
||||
@@ -588,9 +584,9 @@ GEM
|
||||
roadie-rails (1.3.0)
|
||||
railties (>= 3.0, < 5.3)
|
||||
roadie (~> 3.1)
|
||||
roo (2.7.1)
|
||||
roo (2.8.2)
|
||||
nokogiri (~> 1)
|
||||
rubyzip (~> 1.1, < 2.0.0)
|
||||
rubyzip (>= 1.2.1, < 2.0.0)
|
||||
roo-xls (1.1.0)
|
||||
nokogiri
|
||||
roo (>= 2.0.0beta1, < 3)
|
||||
@@ -618,13 +614,16 @@ GEM
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.9.0)
|
||||
rubocop (0.68.1)
|
||||
rubocop (0.79.0)
|
||||
jaro_winkler (~> 1.5.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.5, != 2.5.1.1)
|
||||
parser (>= 2.7.0.1)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 1.6)
|
||||
unicode-display_width (>= 1.4.0, < 1.7)
|
||||
rubocop-rails (2.4.1)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 0.72.0)
|
||||
ruby-ole (1.2.12.1)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby-rc4 (0.1.5)
|
||||
@@ -638,9 +637,9 @@ GEM
|
||||
select2-rails (3.4.9)
|
||||
sass-rails
|
||||
thor (~> 0.14)
|
||||
selenium-webdriver (3.141.0)
|
||||
childprocess (~> 0.5)
|
||||
rubyzip (~> 1.2, >= 1.2.2)
|
||||
selenium-webdriver (3.142.7)
|
||||
childprocess (>= 0.5, < 4.0)
|
||||
rubyzip (>= 1.2.2)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
simplecov (0.17.1)
|
||||
@@ -666,10 +665,8 @@ GEM
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.5.1)
|
||||
stripe (4.24.0)
|
||||
faraday (~> 0.13)
|
||||
net-http-persistent (~> 3.0)
|
||||
test-unit (3.3.4)
|
||||
stripe (5.11.0)
|
||||
test-unit (3.3.5)
|
||||
power_assert
|
||||
thor (0.20.3)
|
||||
tilt (1.4.1)
|
||||
@@ -682,11 +679,11 @@ GEM
|
||||
turbo-sprockets-rails3 (0.3.14)
|
||||
railties (> 3.2.8, < 4.0.0)
|
||||
sprockets (>= 2.2.0)
|
||||
tzinfo (0.3.55)
|
||||
tzinfo (0.3.56)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.5.0)
|
||||
unicorn (5.5.1)
|
||||
unicode-display_width (1.6.0)
|
||||
unicorn (5.5.2)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
unicorn-rails (2.2.1)
|
||||
@@ -699,10 +696,10 @@ GEM
|
||||
railties (>= 3.0)
|
||||
warden (1.2.7)
|
||||
rack (>= 1.0)
|
||||
webdrivers (3.8.1)
|
||||
webdrivers (4.2.0)
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (~> 1.0)
|
||||
selenium-webdriver (~> 3.0)
|
||||
rubyzip (>= 1.3.0)
|
||||
selenium-webdriver (>= 3.0, < 4.0)
|
||||
webmock (3.7.6)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
@@ -734,7 +731,7 @@ DEPENDENCIES
|
||||
blockenspiel
|
||||
bugsnag
|
||||
byebug (~> 9.0.0)
|
||||
capybara (>= 2.15.4)
|
||||
capybara (>= 2.18.0)
|
||||
coffee-rails (~> 3.2.1)
|
||||
combine_pdf
|
||||
compass-rails
|
||||
@@ -763,7 +760,7 @@ DEPENDENCIES
|
||||
gmaps4rails
|
||||
haml
|
||||
i18n (~> 0.6.11)
|
||||
i18n-js (~> 3.5.0)
|
||||
i18n-js (~> 3.5.1)
|
||||
immigrant
|
||||
jquery-migrate-rails
|
||||
jquery-rails (= 3.0.4)
|
||||
@@ -772,8 +769,7 @@ DEPENDENCIES
|
||||
kaminari (~> 0.14.1)
|
||||
knapsack
|
||||
letter_opener (>= 1.4.1)
|
||||
libv8 (= 6.3.292.48.1)
|
||||
mini_racer (= 0.1.15)
|
||||
mini_racer (= 0.2.4)
|
||||
momentjs-rails
|
||||
newrelic_rpm (~> 3.0)
|
||||
nokogiri (>= 1.6.7.1)
|
||||
@@ -794,11 +790,12 @@ DEPENDENCIES
|
||||
rails_safe_tasks (~> 1.0)
|
||||
redcarpet
|
||||
roadie-rails (~> 1.3.0)
|
||||
roo (~> 2.7.0)
|
||||
roo (~> 2.8.2)
|
||||
roo-xls (~> 1.1.0)
|
||||
rspec-rails (>= 3.5.2)
|
||||
rspec-retry
|
||||
rubocop (>= 0.49.1)
|
||||
rubocop
|
||||
rubocop-rails
|
||||
sass (~> 3.3)
|
||||
sass-rails (~> 3.2.3)
|
||||
selenium-webdriver
|
||||
@@ -821,14 +818,14 @@ DEPENDENCIES
|
||||
unicorn
|
||||
unicorn-rails
|
||||
web!
|
||||
webdrivers (= 3.8.1)
|
||||
webdrivers
|
||||
webmock
|
||||
whenever
|
||||
wicked_pdf
|
||||
wkhtmltopdf-binary
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.2.10p489
|
||||
ruby 2.3.7p456
|
||||
|
||||
BUNDLED WITH
|
||||
1.17.2
|
||||
|
||||
@@ -142,7 +142,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
if confirm("Are you sure?")
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.id + "/soft_delete"
|
||||
url: "/api/products/" + product.id
|
||||
).success (data) ->
|
||||
$scope.products.splice $scope.products.indexOf(product), 1
|
||||
DirtyProducts.deleteProduct product.id
|
||||
@@ -157,7 +157,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
if confirm(t("are_you_sure"))
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id
|
||||
).success (data) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $controller, $location, Enterprise, ocInstance) ->
|
||||
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $controller, $location, Enterprise, OrderCycle, ExchangeProduct, ocInstance) ->
|
||||
$controller('AdminOrderCycleExchangesCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
|
||||
|
||||
$scope.enterpriseTotalVariants = (enterprise) ->
|
||||
Enterprise.totalVariants(enterprise)
|
||||
$scope.view = 'incoming'
|
||||
|
||||
$scope.exchangeTotalVariants = (exchange) ->
|
||||
return unless $scope.enterprises? && $scope.enterprises[exchange.enterprise_id]?
|
||||
|
||||
enterprise = $scope.enterprises[exchange.enterprise_id]
|
||||
return enterprise.numVariants if enterprise.numVariants?
|
||||
|
||||
enterprise.numVariants = 0
|
||||
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: true}
|
||||
ExchangeProduct.countVariants params, (variants_count) ->
|
||||
enterprise.numVariants = variants_count
|
||||
$scope.setSelectAllVariantsCheckboxValue(exchange, enterprise.numVariants)
|
||||
|
||||
return enterprise.numVariants
|
||||
|
||||
$scope.addSupplier = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addSupplier $scope.new_supplier_id
|
||||
|
||||
# To select all variants we first need to load them all from the server
|
||||
#
|
||||
# This is only needed in Incoming exchanges as here we use supplied_products,
|
||||
# in Outgoing Exchanges the variants are loaded as part of the Exchange payload
|
||||
$scope.selectAllVariants = (exchange, selected) ->
|
||||
$scope.loadAllExchangeProducts(exchange).then ->
|
||||
$scope.setExchangeVariants(exchange, $scope.suppliedVariants(exchange.enterprise_id), selected)
|
||||
$scope.$apply()
|
||||
|
||||
@@ -18,11 +18,11 @@ angular.module('admin.orderCycles')
|
||||
$scope.cancel = (destination) ->
|
||||
$window.location = destination
|
||||
|
||||
# Used in panels/exchange_supplied_products.html
|
||||
# Used in panels/exchange_products_supplied.html
|
||||
$scope.suppliedVariants = (enterprise_id) ->
|
||||
Enterprise.suppliedVariants(enterprise_id)
|
||||
|
||||
# Used in panels/exchange_supplied_products.html and panels/exchange_distributed_products.html
|
||||
# Used in panels/exchange_products_supplied.html and panels/exchange_products_distributed.html
|
||||
$scope.setExchangeVariants = (exchange, variants, selected) ->
|
||||
OrderCycle.setExchangeVariants(exchange, variants, selected)
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
angular.module('admin.orderCycles')
|
||||
.controller 'AdminOrderCycleExchangesCtrl', ($scope, $controller, $filter, $window, $location, $timeout, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, ocInstance, StatusMessage) ->
|
||||
.controller 'AdminOrderCycleExchangesCtrl', ($scope, $controller, $filter, $window, $location, $timeout, OrderCycle, ExchangeProduct, Enterprise, EnterpriseFee, Schedules, RequestMonitor, ocInstance, StatusMessage) ->
|
||||
$controller('AdminEditOrderCycleCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
|
||||
|
||||
$scope.supplier_enterprises = Enterprise.producer_enterprises
|
||||
$scope.distributor_enterprises = Enterprise.hub_enterprises
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
|
||||
$scope.productsLoading = ->
|
||||
RequestMonitor.loading
|
||||
|
||||
$scope.setSelectAllVariantsCheckboxValue = (exchange, totalNumberOfVariants) ->
|
||||
exchange.select_all_variants = $scope.exchangeSelectedVariants(exchange) >= totalNumberOfVariants
|
||||
|
||||
$scope.exchangeSelectedVariants = (exchange) ->
|
||||
OrderCycle.exchangeSelectedVariants(exchange)
|
||||
@@ -29,14 +34,6 @@ angular.module('admin.orderCycles')
|
||||
OrderCycle.removeExchangeFee(exchange, index)
|
||||
$scope.order_cycle_form.$dirty = true
|
||||
|
||||
$scope.addSupplier = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addSupplier($scope.new_supplier_id)
|
||||
|
||||
$scope.addDistributor = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addDistributor($scope.new_distributor_id)
|
||||
|
||||
$scope.setPickupTimeFieldDirty = (index) ->
|
||||
$timeout ->
|
||||
pickup_time_field_name = "order_cycle_outgoing_exchange_" + index + "_pickup_time"
|
||||
@@ -44,3 +41,36 @@ angular.module('admin.orderCycles')
|
||||
|
||||
$scope.removeDistributionOfVariant = (variant_id) ->
|
||||
OrderCycle.removeDistributionOfVariant(variant_id)
|
||||
|
||||
$scope.loadExchangeProducts = (exchange, page = 1) ->
|
||||
enterprise = $scope.enterprises[exchange.enterprise_id]
|
||||
enterprise.supplied_products ?= []
|
||||
|
||||
return if enterprise.last_page_loaded? && enterprise.last_page_loaded >= page
|
||||
enterprise.last_page_loaded = page
|
||||
|
||||
incoming = true if $scope.view == 'incoming'
|
||||
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: incoming, page: page}
|
||||
ExchangeProduct.index params, (products, num_of_pages, num_of_products) ->
|
||||
enterprise.num_of_pages = num_of_pages
|
||||
enterprise.num_of_products = num_of_products
|
||||
enterprise.supplied_products.push products...
|
||||
|
||||
$scope.loadMoreExchangeProducts = (exchange) ->
|
||||
$scope.loadExchangeProducts(exchange, $scope.enterprises[exchange.enterprise_id].last_page_loaded + 1)
|
||||
|
||||
$scope.loadAllExchangeProducts = (exchange) ->
|
||||
enterprise = $scope.enterprises[exchange.enterprise_id]
|
||||
|
||||
if enterprise.last_page_loaded < enterprise.num_of_pages
|
||||
for page_to_load in [(enterprise.last_page_loaded + 1)..enterprise.num_of_pages]
|
||||
RequestMonitor.load $scope.loadExchangeProducts(exchange, page_to_load).$promise
|
||||
|
||||
RequestMonitor.loadQueue
|
||||
|
||||
# initialize exchange products panel if not yet done
|
||||
$scope.exchangeProdutsPanelInitialized = []
|
||||
$scope.initializeExchangeProductsPanel = (exchange) ->
|
||||
return if $scope.exchangeProdutsPanelInitialized[exchange.enterprise_id]
|
||||
RequestMonitor.load $scope.loadExchangeProducts(exchange).$promise
|
||||
$scope.exchangeProdutsPanelInitialized[exchange.enterprise_id] = true
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
angular.module('admin.orderCycles').controller 'AdminOrderCycleOutgoingCtrl', ($scope, $controller, $filter, $location, OrderCycle, ocInstance, StatusMessage) ->
|
||||
$controller('AdminOrderCycleExchangesCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
|
||||
|
||||
$scope.productSuppliedToOrderCycle = (product) ->
|
||||
OrderCycle.productSuppliedToOrderCycle(product)
|
||||
$scope.view = 'outgoing'
|
||||
|
||||
$scope.variantSuppliedToOrderCycle = (variant) ->
|
||||
OrderCycle.variantSuppliedToOrderCycle(variant)
|
||||
@@ -10,6 +9,15 @@ angular.module('admin.orderCycles').controller 'AdminOrderCycleOutgoingCtrl', ($
|
||||
$scope.incomingExchangeVariantsFor = (enterprise_id) ->
|
||||
$filter('filterExchangeVariants')(OrderCycle.incomingExchangesVariants(), $scope.order_cycle.visible_variants_for_outgoing_exchanges[enterprise_id])
|
||||
|
||||
$scope.exchangeTotalVariants = (exchange) ->
|
||||
totalNumberOfVariants = $scope.incomingExchangeVariantsFor(exchange.enterprise_id).length
|
||||
$scope.setSelectAllVariantsCheckboxValue(exchange, totalNumberOfVariants)
|
||||
totalNumberOfVariants
|
||||
|
||||
$scope.addDistributor = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addDistributor $scope.new_distributor_id
|
||||
|
||||
$scope.submit = ($event, destination) ->
|
||||
$event.preventDefault()
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $controller, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $controller, $window, OrderCycle, Enterprise, EnterpriseFee, ExchangeProduct, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
|
||||
$controller('AdminOrderCycleBasicCtrl', {$scope: $scope, ocInstance: ocInstance})
|
||||
|
||||
$scope.order_cycle = OrderCycle.new {coordinator_id: ocInstance.coordinator_id}, =>
|
||||
# TODO: make this a get method, which only fetches one enterprise
|
||||
$scope.enterprises = Enterprise.index {coordinator_id: ocInstance.coordinator_id}, (enterprises) =>
|
||||
$scope.init(enterprises)
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
|
||||
$scope.init = (enterprises) ->
|
||||
enterprise = enterprises[Object.keys(enterprises)[0]]
|
||||
OrderCycle.addSupplier enterprise.id
|
||||
OrderCycle.addDistributor enterprise.id
|
||||
OrderCycle.order_cycle.coordinator_id = enterprise.id
|
||||
|
||||
OrderCycle.addDistributor enterprise.id, $scope.setOutgoingExchange
|
||||
OrderCycle.addSupplier enterprise.id, $scope.loadExchangeProducts
|
||||
|
||||
$scope.setOutgoingExchange = ->
|
||||
$scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0]
|
||||
|
||||
# All variants start as checked
|
||||
OrderCycle.setExchangeVariants(OrderCycle.order_cycle.incoming_exchanges[0],
|
||||
Enterprise.suppliedVariants(enterprise.id), true)
|
||||
$scope.loadExchangeProducts = ->
|
||||
$scope.incoming_exchange = OrderCycle.order_cycle.incoming_exchanges[0]
|
||||
|
||||
OrderCycle.order_cycle.coordinator_id = enterprise.id
|
||||
params = { enterprise_id: $scope.incoming_exchange.enterprise_id, incoming: true }
|
||||
ExchangeProduct.index params, $scope.storeProductsAndSelectAllVariants
|
||||
|
||||
$scope.storeProductsAndSelectAllVariants = (products) ->
|
||||
$scope.enterprises[$scope.incoming_exchange.enterprise_id].supplied_products = products
|
||||
|
||||
# All variants start as checked
|
||||
OrderCycle.setExchangeVariants($scope.incoming_exchange,
|
||||
Enterprise.suppliedVariants($scope.incoming_exchange.enterprise_id), true)
|
||||
|
||||
$scope.removeDistributionOfVariant = angular.noop
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $controller, $location, $window, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, StatusMessage, ocInstance) ->
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $controller, $location, $window, OrderCycle, Enterprise, EnterpriseFee, ExchangeProduct, Schedules, RequestMonitor, StatusMessage, ocInstance) ->
|
||||
$controller('AdminOrderCycleBasicCtrl', {$scope: $scope, ocInstance: ocInstance})
|
||||
|
||||
$scope.orderCycleId = ->
|
||||
@@ -11,6 +11,12 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
|
||||
$scope.init = ->
|
||||
$scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0]
|
||||
$scope.loadExchangeProducts()
|
||||
|
||||
$scope.loadExchangeProducts = ->
|
||||
exchange = OrderCycle.order_cycle.incoming_exchanges[0]
|
||||
ExchangeProduct.index { exchange_id: exchange.id }, (products) ->
|
||||
$scope.enterprises[exchange.enterprise_id].supplied_products = products
|
||||
|
||||
$scope.removeDistributionOfVariant = angular.noop
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ angular.module('admin.orderCycles').factory('Enterprise', ($resource) ->
|
||||
enterprises: {}
|
||||
producer_enterprises: []
|
||||
hub_enterprises: []
|
||||
supplied_products: []
|
||||
loaded: false
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
@@ -22,9 +21,6 @@ angular.module('admin.orderCycles').factory('Enterprise', ($resource) ->
|
||||
@producer_enterprises.push(enterprise) if enterprise.is_primary_producer
|
||||
@hub_enterprises.push(enterprise) if enterprise.sells == 'any'
|
||||
|
||||
for product in enterprise.supplied_products
|
||||
@supplied_products.push(product)
|
||||
|
||||
@loaded = true
|
||||
(callback || angular.noop)(@enterprises)
|
||||
|
||||
@@ -39,13 +35,4 @@ angular.module('admin.orderCycles').factory('Enterprise', ($resource) ->
|
||||
variant.id for variant in product.variants
|
||||
else
|
||||
[product.master_id]
|
||||
|
||||
totalVariants: (enterprise) ->
|
||||
numVariants = 0
|
||||
|
||||
if enterprise
|
||||
counts = for product in enterprise.supplied_products
|
||||
numVariants += if product.variants.length == 0 then 1 else product.variants.length
|
||||
|
||||
numVariants
|
||||
})
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
angular.module('admin.orderCycles').factory('ExchangeProduct', ($resource) ->
|
||||
ExchangeProductResource = $resource('/api/exchanges/:exchange_id/products.json', {}, {
|
||||
'index': { method: 'GET' }
|
||||
'variant_count': { method: 'GET', params: { action_name: "variant_count" }}
|
||||
})
|
||||
{
|
||||
ExchangeProductResource: ExchangeProductResource
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
ExchangeProductResource.index params, (data) =>
|
||||
(callback || angular.noop)(data.products, data.pagination.pages, data.pagination.results)
|
||||
|
||||
countVariants: (params={}, callback=null) ->
|
||||
ExchangeProductResource.variant_count params, (data) =>
|
||||
(callback || angular.noop)(data.count)
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, StatusMessage, Panels) ->
|
||||
angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, $timeout, StatusMessage, Panels) ->
|
||||
OrderCycleResource = $resource '/admin/order_cycles/:action_name/:order_cycle_id.json', {}, {
|
||||
'index': { method: 'GET', isArray: true}
|
||||
'new' : { method: 'GET', params: { action_name: "new" } }
|
||||
@@ -44,11 +44,15 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
|
||||
@removeDistributionOfVariant(variant.id) if exchange.incoming
|
||||
|
||||
|
||||
addSupplier: (new_supplier_id) ->
|
||||
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
|
||||
addSupplier: (new_supplier_id, callback) ->
|
||||
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
|
||||
$timeout ->
|
||||
(callback || angular.noop)()
|
||||
|
||||
addDistributor: (new_distributor_id) ->
|
||||
this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: []})
|
||||
addDistributor: (new_distributor_id, callback) ->
|
||||
this.order_cycle.outgoing_exchanges.push({ enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: [] })
|
||||
$timeout ->
|
||||
(callback || angular.noop)()
|
||||
|
||||
removeExchange: (exchange) ->
|
||||
if exchange.incoming
|
||||
@@ -71,18 +75,6 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
|
||||
removeExchangeFee: (exchange, index) ->
|
||||
exchange.enterprise_fees.splice(index, 1)
|
||||
|
||||
productSuppliedToOrderCycle: (product) ->
|
||||
product_variant_ids = (variant.id for variant in product.variants)
|
||||
variant_ids = [product.master_id].concat(product_variant_ids)
|
||||
incomingExchangesVariants = this.incomingExchangesVariants()
|
||||
|
||||
# TODO: This is an O(n^2) implementation of set intersection and thus is slooow.
|
||||
# Use a better algorithm if needed.
|
||||
# Also, incomingExchangesVariants is called every time, when it only needs to be
|
||||
# called once per change to incoming variants. Some sort of caching?
|
||||
ids = (variant_id for variant_id in variant_ids when incomingExchangesVariants.indexOf(variant_id) != -1)
|
||||
ids.length > 0
|
||||
|
||||
variantSuppliedToOrderCycle: (variant) ->
|
||||
this.incomingExchangesVariants().indexOf(variant.id) != -1
|
||||
|
||||
@@ -143,7 +135,8 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
|
||||
delete(service.order_cycle.exchanges)
|
||||
service.loaded = true
|
||||
|
||||
(callback || angular.noop)(service.order_cycle)
|
||||
$timeout ->
|
||||
(callback || angular.noop)(service.order_cycle)
|
||||
|
||||
this.order_cycle
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor, Orders, SortOptions, $window, $filter) ->
|
||||
angular.module("admin.orders").controller "ordersCtrl", ($scope, $timeout, RequestMonitor, Orders, SortOptions, $window, $filter) ->
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.pagination = Orders.pagination
|
||||
$scope.orders = Orders.all
|
||||
@@ -13,6 +13,7 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
|
||||
$scope.selected = false
|
||||
$scope.select_all = false
|
||||
$scope.poll = 0
|
||||
$scope.rowStatus = {}
|
||||
|
||||
$scope.initialise = ->
|
||||
$scope.per_page = 15
|
||||
@@ -69,6 +70,23 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
|
||||
$scope.fetchResults()
|
||||
, true
|
||||
|
||||
$scope.capturePayment = (order) ->
|
||||
$scope.rowAction('capture', order)
|
||||
|
||||
$scope.shipOrder = (order) ->
|
||||
$scope.rowAction('ship', order)
|
||||
|
||||
$scope.rowAction = (action, order) ->
|
||||
$scope.rowStatus[order.id] = "loading"
|
||||
|
||||
Orders[action](order).$promise.then (data) ->
|
||||
$scope.rowStatus[order.id] = "success"
|
||||
$timeout(->
|
||||
$scope.rowStatus[order.id] = null
|
||||
, 1500)
|
||||
, (error) ->
|
||||
$scope.rowStatus[order.id] = "error"
|
||||
|
||||
$scope.changePage = (newPage) ->
|
||||
$scope.page = newPage
|
||||
$scope.fetchResults(newPage)
|
||||
|
||||
@@ -5,4 +5,14 @@ angular.module("admin.resources").factory 'OrderResource', ($resource) ->
|
||||
method: 'GET'
|
||||
'update':
|
||||
method: 'PUT'
|
||||
'capture':
|
||||
url: '/api/orders/:id/capture.json'
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
'ship':
|
||||
url: '/api/orders/:id/ship.json'
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
})
|
||||
|
||||
@@ -44,5 +44,19 @@ angular.module("admin.resources").factory 'Orders', ($q, OrderResource, RequestM
|
||||
changed.push attr unless attr is "$$hashKey"
|
||||
changed
|
||||
|
||||
capture: (order) ->
|
||||
@processAction('capture', order)
|
||||
|
||||
ship: (order) ->
|
||||
@processAction('ship', order)
|
||||
|
||||
processAction: (action, order) ->
|
||||
OrderResource[action] {id: order.number}, (data) =>
|
||||
if data.id
|
||||
angular.merge(order, data)
|
||||
data
|
||||
, (response) =>
|
||||
response.data
|
||||
|
||||
resetAttribute: (order, attribute) ->
|
||||
order[attribute] = @pristineByID[order.id][attribute]
|
||||
|
||||
@@ -20,4 +20,4 @@ angular.module("admin.subscriptions").controller "ProductsPanelController", ($sc
|
||||
keys = Object.keys(response.data.errors)
|
||||
StatusMessage.display 'failure', response.data.errors[keys[0]][0]
|
||||
else
|
||||
StatusMessage.display 'success', t('js.changes_saved')
|
||||
StatusMessage.display 'failure', t('js.admin.subscriptions.error_saving')
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.row.exchange-distributed-products
|
||||
.sixteen.columns.alpha.omega
|
||||
.row.exchange-distributed-products{'ng-init' => 'initializeExchangeProductsPanel(exchange)'}
|
||||
.sixteen.columns.alpha.omega{ 'ng-show' => 'enterprises[exchange.enterprise_id].supplied_products.length != 0' }
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_header.html'" }
|
||||
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants',
|
||||
@@ -7,11 +9,10 @@
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, incomingExchangeVariantsFor(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' }
|
||||
{{ 'admin.select_all' | t }}
|
||||
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
|
||||
|
||||
.exchange-products
|
||||
-# Scope product list based on permissions the current user has to view variants in this exchange
|
||||
.exchange-product{'ng-repeat' => 'product in supplied_products | filter:productSuppliedToOrderCycle | visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges' }
|
||||
.exchange-products{ 'ng-hide' => 'productsLoading()' }
|
||||
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products | filter:visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges' }
|
||||
.exchange-product-details
|
||||
%label
|
||||
%img{'ng-src' => '{{ product.image_url }}'}
|
||||
@@ -26,3 +27,5 @@
|
||||
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
'ng-disabled' => '!order_cycle.editable_variants_for_outgoing_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_outgoing_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
|
||||
{{ variant.label }}
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_footer.html'" }
|
||||
@@ -0,0 +1,11 @@
|
||||
.pagination{ 'ng-show' => 'enterprises[exchange.enterprise_id].last_page_loaded < enterprises[exchange.enterprise_id].num_of_pages && !productsLoading()'}
|
||||
.button{ 'ng-click' => 'loadMoreExchangeProducts(exchange)' }
|
||||
{{ 'js.admin.panels.exchange_products.load_more_products' | t }}
|
||||
.button{ 'ng-click' => 'loadAllExchangeProducts(exchange)' }
|
||||
{{ 'js.admin.panels.exchange_products.load_all_products' | t }}
|
||||
|
||||
.sixteen.columns.alpha#loading{ 'ng-show' => 'productsLoading()' }
|
||||
%br
|
||||
%img.spinner{ src: "/assets/spinning-circles.svg" }
|
||||
%h1
|
||||
{{ 'js.admin.panels.exchange_products.loading_products' | t }}
|
||||
@@ -0,0 +1,5 @@
|
||||
.exchange-load-all-variants
|
||||
%div
|
||||
{{ 'js.admin.panels.exchange_products.products_loaded' | t:{ num_of_products_loaded: enterprises[exchange.enterprise_id].supplied_products.length, total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
|
||||
%a{ 'ng-click' => 'loadAllExchangeProducts(exchange)', 'ng-show' => 'enterprises[exchange.enterprise_id].last_page_loaded < enterprises[exchange.enterprise_id].num_of_pages' }
|
||||
{{ 'js.admin.panels.exchange_products.load_all_products' | t }}
|
||||
@@ -0,0 +1,12 @@
|
||||
.row.exchange-supplied-products
|
||||
.sixteen.columns.alpha.omega
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
|
||||
{{ 'admin.select_all' | t }}
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }
|
||||
@@ -0,0 +1,16 @@
|
||||
.row.exchange-supplied-products{'ng-init' => 'initializeExchangeProductsPanel(exchange)'}
|
||||
.sixteen.columns.alpha.omega{ 'ng-show' => 'enterprises[exchange.enterprise_id].supplied_products.length != 0' }
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_header.html'" }
|
||||
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'selectAllVariants(exchange, exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
|
||||
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_footer.html'" }
|
||||
@@ -0,0 +1,16 @@
|
||||
.exchange-products{ 'ng-hide' => 'productsLoading()' }
|
||||
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
|
||||
.exchange-product-details
|
||||
%label
|
||||
%img{'ng-src' => '{{ product.image_url }}'}
|
||||
{{ product.name }}
|
||||
|
||||
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.variants[variant.id]',
|
||||
'ofn-sync-distributions' => '{{ variant.id }}',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
|
||||
{{ variant.label }}
|
||||
@@ -1,29 +0,0 @@
|
||||
.row.exchange-supplied-products
|
||||
.sixteen.columns.alpha.omega
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
|
||||
{{ 'admin.select_all' | t }}
|
||||
|
||||
.exchange-products
|
||||
-# No need to scope product list based on permissions, because if an incoming exchange is visible,
|
||||
-# then all of the variants within it should be visible. May change in the future?
|
||||
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
|
||||
.exchange-product-details
|
||||
%label
|
||||
%img{'ng-src' => '{{ product.image_url }}'}
|
||||
{{ product.name }}
|
||||
|
||||
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.variants[variant.id]',
|
||||
'ofn-sync-distributions' => '{{ variant.id }}',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
|
||||
{{ variant.label }}
|
||||
@@ -1,9 +1,9 @@
|
||||
#save-bar.animate-show{ ng: { show: 'dirty || persist || StatusMessage.active()' } }
|
||||
.container
|
||||
.eight.columns.alpha
|
||||
.seven.columns.alpha
|
||||
%h5#status-message{ ng: { show: "StatusMessage.invalidMessage == ''", style: 'StatusMessage.statusMessage.style' } }
|
||||
{{ StatusMessage.statusMessage.text || " " }}
|
||||
%h5#status-message{ ng: { show: "StatusMessage.invalidMessage !== ''" }, style: 'color: #da5354' }
|
||||
{{ StatusMessage.invalidMessage || " " }}
|
||||
.eight.columns.omega.text-right{ ng: { transclude: true } }
|
||||
.nine.columns.omega.text-right{ ng: { transclude: true } }
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
@import '../variables';
|
||||
|
||||
.row-loading {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.row-loading-icons {
|
||||
margin-left: 3em;
|
||||
position: absolute;
|
||||
|
||||
.spinner {
|
||||
border: 0;
|
||||
width: 2.3em;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 2.3em;
|
||||
opacity: .75;
|
||||
|
||||
&::before {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&.success {
|
||||
color: $spree-green;
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: $warning-red;
|
||||
}
|
||||
}
|
||||
}
|
||||
4
app/assets/stylesheets/admin/components/tooltip.css.scss
Normal file
4
app/assets/stylesheets/admin/components/tooltip.css.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
#powerTip {
|
||||
max-width: 240px;
|
||||
white-space: normal;
|
||||
}
|
||||
@@ -104,9 +104,13 @@ form.order_cycle {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.exchange-load-all-variants {
|
||||
margin: 0px 5px 20px 5px;
|
||||
}
|
||||
|
||||
.exchange-select-all-variants {
|
||||
clear: both;
|
||||
margin: 5px;
|
||||
margin: 15px 5px 25px 5px;
|
||||
}
|
||||
|
||||
.exchange-products {
|
||||
@@ -209,6 +213,7 @@ table#listing_enterprise_groups {
|
||||
#loading {
|
||||
text-align: center;
|
||||
img.spinner {
|
||||
border: 0px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
@@ -28,15 +28,12 @@ module Admin
|
||||
|
||||
def bulk_update
|
||||
@enterprise_fee_set = EnterpriseFeeSet.new(params[:enterprise_fee_set])
|
||||
if @enterprise_fee_set.save
|
||||
redirect_path = main_app.admin_enterprise_fees_path
|
||||
if params.key? :enterprise_id
|
||||
redirect_path = main_app.admin_enterprise_fees_path(enterprise_id: params[:enterprise_id])
|
||||
end
|
||||
redirect_to redirect_path, notice: I18n.t(:enterprise_fees_update_notice)
|
||||
|
||||
if @enterprise_fee_set.save
|
||||
redirect_to redirect_path, notice: I18n.t(:enterprise_fees_update_notice)
|
||||
else
|
||||
render :index
|
||||
redirect_to redirect_path,
|
||||
flash: { error: @enterprise_fee_set.errors.full_messages.to_sentence }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -73,5 +70,13 @@ module Admin
|
||||
def current_enterprise
|
||||
Enterprise.find params[:enterprise_id] if params.key? :enterprise_id
|
||||
end
|
||||
|
||||
def redirect_path
|
||||
if params.key? :enterprise_id
|
||||
return main_app.admin_enterprise_fees_path(enterprise_id: params[:enterprise_id])
|
||||
end
|
||||
|
||||
main_app.admin_enterprise_fees_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -66,7 +66,7 @@ module Admin
|
||||
|
||||
if @enterprise.update_attributes(attributes)
|
||||
flash[:success] = I18n.t(:enterprise_register_success_notice, enterprise: @enterprise.name)
|
||||
redirect_to admin_path
|
||||
redirect_to admin_dashboard_path
|
||||
else
|
||||
flash[:error] = I18n.t(:enterprise_register_error, enterprise: @enterprise.name)
|
||||
render :welcome, layout: "spree/layouts/bare_admin"
|
||||
|
||||
@@ -22,7 +22,7 @@ module Admin
|
||||
redirect_to main_app.edit_admin_enterprise_path(stripe_account.enterprise)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
flash[:error] = "Failed to disconnect Stripe."
|
||||
redirect_to spree.admin_path
|
||||
redirect_to spree.admin_dashboard_path
|
||||
end
|
||||
|
||||
def status
|
||||
|
||||
92
app/controllers/api/exchange_products_controller.rb
Normal file
92
app/controllers/api/exchange_products_controller.rb
Normal file
@@ -0,0 +1,92 @@
|
||||
# This controller lists products that can be added to an exchange
|
||||
module Api
|
||||
class ExchangeProductsController < Api::BaseController
|
||||
DEFAULT_PAGE = 1
|
||||
DEFAULT_PER_PAGE = 100
|
||||
|
||||
skip_authorization_check only: [:index]
|
||||
|
||||
# If exchange_id is present in the URL:
|
||||
# Lists Products that can be added to that Exchange
|
||||
#
|
||||
# If exchange_id is not present in the URL:
|
||||
# Lists Products of the Enterprise given that can be added to the given Order Cycle
|
||||
# In this case parameters are: enterprise_id, order_cycle_id and incoming
|
||||
# (order_cycle_id is not necessary for incoming exchanges)
|
||||
def index
|
||||
if params[:exchange_id].present?
|
||||
load_data_from_exchange
|
||||
else
|
||||
load_data_from_other_params
|
||||
end
|
||||
|
||||
render_variant_count && return if params[:action_name] == "variant_count"
|
||||
|
||||
render_paginated_products paginated_products
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_variant_count
|
||||
render text: {
|
||||
count: Spree::Variant.
|
||||
not_master.
|
||||
where(product_id: products).
|
||||
count
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def products
|
||||
ExchangeProductsRenderer.
|
||||
new(@order_cycle, spree_current_user).
|
||||
exchange_products(@incoming, @enterprise)
|
||||
end
|
||||
|
||||
def paginated_products
|
||||
products.
|
||||
page(params[:page] || DEFAULT_PAGE).
|
||||
per(params[:per_page] || DEFAULT_PER_PAGE)
|
||||
end
|
||||
|
||||
def load_data_from_exchange
|
||||
exchange = Exchange.find_by_id(params[:exchange_id])
|
||||
|
||||
@order_cycle = exchange.order_cycle
|
||||
@incoming = exchange.incoming
|
||||
@enterprise = exchange.sender
|
||||
end
|
||||
|
||||
def load_data_from_other_params
|
||||
@enterprise = Enterprise.find_by_id(params[:enterprise_id])
|
||||
|
||||
if params[:order_cycle_id]
|
||||
@order_cycle = OrderCycle.find_by_id(params[:order_cycle_id])
|
||||
elsif !params[:incoming]
|
||||
raise "order_cycle_id is required to list products for new outgoing exchange"
|
||||
end
|
||||
@incoming = params[:incoming]
|
||||
end
|
||||
|
||||
def render_paginated_products(paginated_products)
|
||||
serializer = ActiveModel::ArraySerializer.new(
|
||||
paginated_products,
|
||||
each_serializer: Api::Admin::ForOrderCycle::SuppliedProductSerializer,
|
||||
order_cycle: @order_cycle
|
||||
)
|
||||
|
||||
render text: {
|
||||
products: serializer,
|
||||
pagination: pagination_data(paginated_products)
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def pagination_data(paginated_products)
|
||||
{
|
||||
results: paginated_products.total_count,
|
||||
pages: paginated_products.num_pages,
|
||||
page: (params[:page] || DEFAULT_PAGE).to_i,
|
||||
per_page: (params[:per_page] || DEFAULT_PER_PAGE).to_i
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -16,8 +16,38 @@ module Api
|
||||
}
|
||||
end
|
||||
|
||||
def ship
|
||||
authorize! :admin, order
|
||||
|
||||
if order.ship
|
||||
render json: order.reload, serializer: Api::Admin::OrderSerializer, status: :ok
|
||||
else
|
||||
render json: { error: I18n.t('api.orders.failed_to_update') }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def capture
|
||||
authorize! :admin, order
|
||||
|
||||
pending_payment = order.pending_payments.first
|
||||
|
||||
return payment_capture_failed unless order.payment_required? && pending_payment
|
||||
|
||||
if pending_payment.capture!
|
||||
render json: order.reload, serializer: Api::Admin::OrderSerializer, status: :ok
|
||||
else
|
||||
payment_capture_failed
|
||||
end
|
||||
rescue Spree::Core::GatewayError => e
|
||||
error_during_processing(e)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def payment_capture_failed
|
||||
render json: { error: t(:payment_processing_failed) }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def serialized_orders(orders)
|
||||
ActiveModel::ArraySerializer.new(
|
||||
orders,
|
||||
|
||||
@@ -42,8 +42,8 @@ module Api
|
||||
def destroy
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:id])
|
||||
@product.update_attribute(:deleted_at, Time.zone.now)
|
||||
@product.variants_including_master.update_all(deleted_at: Time.zone.now)
|
||||
authorize! :delete, @product
|
||||
@product.destroy
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: :no_content
|
||||
end
|
||||
|
||||
@@ -71,14 +71,6 @@ module Api
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:product_id])
|
||||
authorize! :delete, @product
|
||||
@product.destroy
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: :no_content
|
||||
end
|
||||
|
||||
# POST /api/products/:product_id/clone
|
||||
#
|
||||
def clone
|
||||
|
||||
@@ -35,18 +35,12 @@ module Api
|
||||
end
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
@variant = scope.find(params[:variant_id])
|
||||
authorize! :delete, @variant
|
||||
|
||||
VariantDeleter.new.delete(@variant)
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: :no_content
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Spree::Variant
|
||||
@variant = scope.find(params[:id])
|
||||
@variant.destroy
|
||||
authorize! :delete, @variant
|
||||
|
||||
VariantDeleter.new.delete(@variant)
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: :no_content
|
||||
end
|
||||
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
module Spree
|
||||
module Admin
|
||||
AdjustmentsController.class_eval do
|
||||
class AdjustmentsController < ResourceController
|
||||
belongs_to 'spree/order', find_by: :number
|
||||
destroy.after :reload_order
|
||||
|
||||
prepend_before_filter :set_included_tax, only: [:create, :update]
|
||||
before_filter :set_default_tax_rate, only: :edit
|
||||
before_filter :enable_updates, only: :update
|
||||
|
||||
private
|
||||
|
||||
def reload_order
|
||||
@order.reload
|
||||
end
|
||||
|
||||
def collection
|
||||
parent.adjustments.eligible
|
||||
end
|
||||
|
||||
# Choose a default tax rate to show on the edit form. The adjustment stores its included
|
||||
# tax in dollars, but doesn't store the source of the tax (ie. TaxRate that generated it).
|
||||
# We guess which tax rate here, choosing:
|
||||
@@ -15,28 +26,34 @@ module Spree
|
||||
# When we have to go with 2, we show an error message to ask the admin to check that the
|
||||
# correct tax is being applied.
|
||||
def set_default_tax_rate
|
||||
if @adjustment.included_tax > 0
|
||||
trs = TaxRate.match(@order)
|
||||
tr_yielding_matching_tax = trs.select { |tr| tr.compute_tax(@adjustment.amount) == @adjustment.included_tax }.first.andand.id
|
||||
tr_valid_for_order = TaxRate.match(@order).first.andand.id
|
||||
return if @adjustment.included_tax <= 0
|
||||
|
||||
@tax_rate_id = tr_yielding_matching_tax || tr_valid_for_order
|
||||
tax_rates = TaxRate.match(@order)
|
||||
tax_rate_with_matching_tax = find_tax_rate_with_matching_tax(tax_rates)
|
||||
tax_rate_valid_for_order = tax_rates.first.andand.id
|
||||
|
||||
if tr_yielding_matching_tax.nil?
|
||||
@adjustment.errors.add :tax_rate_id, I18n.t(:adjustments_tax_rate_error)
|
||||
end
|
||||
@tax_rate_id = tax_rate_with_matching_tax || tax_rate_valid_for_order
|
||||
|
||||
return unless tax_rate_with_matching_tax.nil?
|
||||
|
||||
@adjustment.errors.add :tax_rate_id, I18n.t(:adjustments_tax_rate_error)
|
||||
end
|
||||
|
||||
def find_tax_rate_with_matching_tax(tax_rates)
|
||||
tax_rates_yielding_matching_tax = tax_rates.select do |tr|
|
||||
tr.compute_tax(@adjustment.amount) == @adjustment.included_tax
|
||||
end
|
||||
tax_rates_yielding_matching_tax.first.andand.id
|
||||
end
|
||||
|
||||
def set_included_tax
|
||||
included_tax = 0
|
||||
if params[:tax_rate_id].present?
|
||||
tax_rate = TaxRate.find params[:tax_rate_id]
|
||||
amount = params[:adjustment][:amount].to_f
|
||||
params[:adjustment][:included_tax] = tax_rate.compute_tax amount
|
||||
|
||||
else
|
||||
params[:adjustment][:included_tax] = 0
|
||||
included_tax = tax_rate.compute_tax amount
|
||||
end
|
||||
params[:adjustment][:included_tax] = included_tax
|
||||
end
|
||||
|
||||
# Spree 2.0 keeps shipping fee adjustments open unless they are manually
|
||||
142
app/controllers/spree/admin/base_controller.rb
Normal file
142
app/controllers/spree/admin/base_controller.rb
Normal file
@@ -0,0 +1,142 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class BaseController < Spree::BaseController
|
||||
ssl_required
|
||||
|
||||
helper 'spree/admin/navigation'
|
||||
layout '/spree/layouts/admin'
|
||||
|
||||
include I18nHelper
|
||||
|
||||
before_filter :authorize_admin
|
||||
before_filter :set_locale
|
||||
before_filter :warn_invalid_order_cycles, if: :html_request?
|
||||
|
||||
# Warn the user when they have an active order cycle with hubs that are not ready
|
||||
# for checkout (ie. does not have valid shipping and payment methods).
|
||||
def warn_invalid_order_cycles
|
||||
distributors = active_distributors_not_ready_for_checkout
|
||||
|
||||
return if distributors.empty? || flash[:notice].present?
|
||||
|
||||
flash[:notice] = active_distributors_not_ready_for_checkout_message(distributors)
|
||||
end
|
||||
|
||||
# This is in Spree::Core::ControllerHelpers::Auth
|
||||
# But you can't easily reopen modules in Ruby
|
||||
def unauthorized
|
||||
if try_spree_current_user
|
||||
flash[:error] = t(:authorization_failure)
|
||||
redirect_to '/unauthorized'
|
||||
else
|
||||
store_location
|
||||
redirect_to root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def model_class
|
||||
const_name = controller_name.classify
|
||||
return "Spree::#{const_name}".constantize if Spree.const_defined?(const_name)
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def action
|
||||
params[:action].to_sym
|
||||
end
|
||||
|
||||
def authorize_admin
|
||||
if respond_to?(:model_class, true) && model_class
|
||||
record = model_class
|
||||
else
|
||||
# This allows specificity for each non-resource controller
|
||||
# (to be consistent with "authorize_resource :class => false", see https://github.com/ryanb/cancan/blob/60cf6a67ef59c0c9b63bc27ea0101125c4193ea6/lib/cancan/controller_resource.rb#L146)
|
||||
record = self.class.to_s.
|
||||
sub("Controller", "").
|
||||
underscore.split('/').last.singularize.to_sym
|
||||
end
|
||||
authorize! :admin, record
|
||||
authorize! resource_authorize_action, record
|
||||
end
|
||||
|
||||
def resource_authorize_action
|
||||
action
|
||||
end
|
||||
|
||||
def flash_message_for(object, event_sym)
|
||||
resource_desc = object.class.model_name.human
|
||||
resource_desc += " \"#{object.name}\"" if object.respond_to?(:name) && object.name.present?
|
||||
Spree.t(event_sym, resource: resource_desc)
|
||||
end
|
||||
|
||||
def render_js_for_destroy
|
||||
render partial: '/spree/admin/shared/destroy'
|
||||
end
|
||||
|
||||
# Index request for JSON needs to pass a CSRF token in order to prevent JSON Hijacking
|
||||
def check_json_authenticity
|
||||
return unless request.format.js? || request.format.json?
|
||||
|
||||
return unless protect_against_forgery?
|
||||
|
||||
auth_token = params[request_forgery_protection_token]
|
||||
return if auth_token && form_authenticity_token == CGI.unescape(auth_token)
|
||||
|
||||
raise(ActionController::InvalidAuthenticityToken)
|
||||
end
|
||||
|
||||
def config_locale
|
||||
Spree::Backend::Config[:locale]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def active_distributors_not_ready_for_checkout
|
||||
ocs = OrderCycle.managed_by(spree_current_user).active
|
||||
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
|
||||
Enterprise.where('enterprises.id IN (?)', distributors).not_ready_for_checkout
|
||||
end
|
||||
|
||||
def active_distributors_not_ready_for_checkout_message(distributors)
|
||||
distributor_names = distributors.map(&:name).join ', '
|
||||
|
||||
if distributors.count > 1
|
||||
I18n.t(:active_distributors_not_ready_for_checkout_message_plural,
|
||||
distributor_names: distributor_names)
|
||||
else
|
||||
I18n.t(:active_distributors_not_ready_for_checkout_message_singular,
|
||||
distributor_names: distributor_names)
|
||||
end
|
||||
end
|
||||
|
||||
def html_request?
|
||||
request.format.html?
|
||||
end
|
||||
|
||||
def json_request?
|
||||
request.format.json?
|
||||
end
|
||||
|
||||
def render_as_json(data, options = {})
|
||||
ams_prefix = options.delete :ams_prefix
|
||||
if [Array, ActiveRecord::Relation].include? data.class
|
||||
render options.merge(json: data, each_serializer: serializer(ams_prefix))
|
||||
else
|
||||
render options.merge(json: data, serializer: serializer(ams_prefix))
|
||||
end
|
||||
end
|
||||
|
||||
def serializer(ams_prefix)
|
||||
unless ams_prefix.nil? || ams_prefix_whitelist.include?(ams_prefix.to_sym)
|
||||
raise "Suffix '#{ams_prefix}' not found in ams_prefix_whitelist for #{self.class.name}."
|
||||
end
|
||||
|
||||
prefix = ams_prefix.andand.classify || ""
|
||||
name = controller_name.classify
|
||||
"::Api::Admin::#{prefix}#{name}Serializer".constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,105 +0,0 @@
|
||||
require 'spree/core/controller_helpers/respond_with_decorator'
|
||||
|
||||
Spree::Admin::BaseController.class_eval do
|
||||
include I18nHelper
|
||||
|
||||
layout 'spree/layouts/admin'
|
||||
|
||||
before_filter :set_locale
|
||||
before_filter :warn_invalid_order_cycles, if: :html_request?
|
||||
|
||||
# Warn the user when they have an active order cycle with hubs that are not ready
|
||||
# for checkout (ie. does not have valid shipping and payment methods).
|
||||
def warn_invalid_order_cycles
|
||||
distributors = active_distributors_not_ready_for_checkout
|
||||
|
||||
if distributors.any? && flash[:notice].nil?
|
||||
flash[:notice] = active_distributors_not_ready_for_checkout_message(distributors)
|
||||
end
|
||||
end
|
||||
|
||||
# Override Spree method
|
||||
# It's a shame Spree doesn't just let CanCan handle this in it's own way
|
||||
def authorize_admin
|
||||
if respond_to?(:model_class, true) && model_class
|
||||
record = model_class
|
||||
else
|
||||
# this line changed to allow specificity for each non-resource controller (to be consistent with "authorize_resource :class => false", see https://github.com/ryanb/cancan/blob/60cf6a67ef59c0c9b63bc27ea0101125c4193ea6/lib/cancan/controller_resource.rb#L146)
|
||||
record = self.class.to_s.sub("Controller", "").underscore.split('/').last.singularize.to_sym
|
||||
end
|
||||
authorize! :admin, record
|
||||
authorize! resource_authorize_action, record
|
||||
end
|
||||
|
||||
def resource_authorize_action
|
||||
action
|
||||
end
|
||||
|
||||
# This is in Spree::Core::ControllerHelpers::Auth
|
||||
# But you can't easily reopen modules in Ruby
|
||||
def unauthorized
|
||||
if try_spree_current_user
|
||||
flash[:error] = t(:authorization_failure)
|
||||
redirect_to '/unauthorized'
|
||||
else
|
||||
store_location
|
||||
redirect_to root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def model_class
|
||||
const_name = controller_name.classify
|
||||
if Spree.const_defined?(const_name)
|
||||
return "Spree::#{const_name}".constantize
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def active_distributors_not_ready_for_checkout
|
||||
ocs = OrderCycle.managed_by(spree_current_user).active
|
||||
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
|
||||
Enterprise.where('enterprises.id IN (?)', distributors).not_ready_for_checkout
|
||||
end
|
||||
|
||||
def active_distributors_not_ready_for_checkout_message(distributors)
|
||||
distributor_names = distributors.map(&:name).join ', '
|
||||
|
||||
if distributors.count > 1
|
||||
I18n.t(:active_distributors_not_ready_for_checkout_message_plural, distributor_names: distributor_names)
|
||||
else
|
||||
I18n.t(:active_distributors_not_ready_for_checkout_message_singular, distributor_names: distributor_names)
|
||||
end
|
||||
end
|
||||
|
||||
def html_request?
|
||||
request.format.html?
|
||||
end
|
||||
|
||||
def json_request?
|
||||
request.format.json?
|
||||
end
|
||||
|
||||
def render_as_json(data, options = {})
|
||||
ams_prefix = options.delete :ams_prefix
|
||||
if [Array, ActiveRecord::Relation].include? data.class
|
||||
render options.merge(json: data, each_serializer: serializer(ams_prefix))
|
||||
else
|
||||
render options.merge(json: data, serializer: serializer(ams_prefix))
|
||||
end
|
||||
end
|
||||
|
||||
def serializer(ams_prefix)
|
||||
if ams_prefix.nil? || ams_prefix_whitelist.include?(ams_prefix.to_sym)
|
||||
prefix = ams_prefix.andand.classify || ""
|
||||
name = controller_name.classify
|
||||
"Api::Admin::#{prefix}#{name}Serializer".constantize
|
||||
else
|
||||
raise "Suffix '#{ams_prefix}' not found in ams_prefix_whitelist for #{self.class.name}."
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,8 +5,7 @@ module Spree
|
||||
@preferences_general = [:site_name, :default_seo_title, :default_meta_keywords,
|
||||
:default_meta_description, :site_url, :bugherd_api_key]
|
||||
@preferences_security = [:allow_ssl_in_production,
|
||||
:allow_ssl_in_staging, :allow_ssl_in_development_and_test,
|
||||
:check_for_spree_alerts]
|
||||
:allow_ssl_in_staging, :allow_ssl_in_development_and_test]
|
||||
@preferences_currency = [:display_currency, :hide_cents]
|
||||
end
|
||||
|
||||
@@ -20,18 +19,6 @@ module Spree
|
||||
|
||||
redirect_to edit_admin_general_settings_path
|
||||
end
|
||||
|
||||
def dismiss_alert
|
||||
return unless request.xhr? && params[:alert_id]
|
||||
|
||||
dismissed = Spree::Config[:dismissed_spree_alerts] || ''
|
||||
Spree::Config.set(dismissed_spree_alerts: dismissed.
|
||||
split(',').
|
||||
push(params[:alert_id]).
|
||||
join(','))
|
||||
filter_dismissed_alerts
|
||||
render nothing: true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
79
app/controllers/spree/admin/overview_controller.rb
Normal file
79
app/controllers/spree/admin/overview_controller.rb
Normal file
@@ -0,0 +1,79 @@
|
||||
# this clas was inspired (heavily) from the mephisto admin architecture
|
||||
module Spree
|
||||
module Admin
|
||||
class OverviewController < Spree::Admin::BaseController
|
||||
def index
|
||||
@enterprises = Enterprise
|
||||
.managed_by(spree_current_user)
|
||||
.order('is_primary_producer ASC, name')
|
||||
@product_count = Spree::Product.active.managed_by(spree_current_user).count
|
||||
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
|
||||
|
||||
if first_access
|
||||
redirect_to enterprises_path
|
||||
else
|
||||
render dashboard_view
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Checks whether the user is accessing the admin for the first time
|
||||
#
|
||||
# @return [Boolean]
|
||||
def first_access
|
||||
outside_referral && incomplete_enterprise_registration?
|
||||
end
|
||||
|
||||
# Checks whether the request comes from another admin page or not
|
||||
#
|
||||
# @return [Boolean]
|
||||
def outside_referral
|
||||
!URI(request.referer.to_s).path.match(%r{/admin})
|
||||
end
|
||||
|
||||
# Checks that all of the enterprises owned by the current user have a 'sells'
|
||||
# property specified, which indicates that the registration process has been
|
||||
# completed
|
||||
#
|
||||
# @return [Boolean]
|
||||
def incomplete_enterprise_registration?
|
||||
@incomplete_enterprise_registration ||= spree_current_user
|
||||
.owned_enterprises
|
||||
.where(sells: 'unspecified')
|
||||
.exists?
|
||||
end
|
||||
|
||||
# Returns the appropriate enterprise path for the current user
|
||||
#
|
||||
# @return [String]
|
||||
def enterprises_path
|
||||
if managed_enterprises.size == 1
|
||||
@enterprise = @enterprises.first
|
||||
main_app.welcome_admin_enterprise_path(@enterprise)
|
||||
else
|
||||
main_app.admin_enterprises_path
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the appropriate dashboard view for the current user
|
||||
#
|
||||
# @return [String]
|
||||
def dashboard_view
|
||||
if managed_enterprises.size == 1
|
||||
@enterprise = @enterprises.first
|
||||
:single_enterprise_dashboard
|
||||
else
|
||||
:multi_enterprise_dashboard
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the list of enterprises the current user is manager of
|
||||
#
|
||||
# @return [ActiveRecord::Relation<Enterprise>]
|
||||
def managed_enterprises
|
||||
spree_current_user.enterprises
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,74 +0,0 @@
|
||||
Spree::Admin::OverviewController.class_eval do
|
||||
def index
|
||||
@enterprises = Enterprise
|
||||
.managed_by(spree_current_user)
|
||||
.order('is_primary_producer ASC, name')
|
||||
@product_count = Spree::Product.active.managed_by(spree_current_user).count
|
||||
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
|
||||
|
||||
if first_access
|
||||
redirect_to enterprises_path
|
||||
else
|
||||
render dashboard_view
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Checks whether the user is accessing the admin for the first time
|
||||
#
|
||||
# @return [Boolean]
|
||||
def first_access
|
||||
outside_referral && incomplete_enterprise_registration?
|
||||
end
|
||||
|
||||
# Checks whether the request comes from another admin page or not
|
||||
#
|
||||
# @return [Boolean]
|
||||
def outside_referral
|
||||
!URI(request.referer.to_s).path.match(%r{/admin})
|
||||
end
|
||||
|
||||
# Checks that all of the enterprises owned by the current user have a 'sells'
|
||||
# property specified, which indicates that the registration process has been
|
||||
# completed
|
||||
#
|
||||
# @return [Boolean]
|
||||
def incomplete_enterprise_registration?
|
||||
@incomplete_enterprise_registration ||= spree_current_user
|
||||
.owned_enterprises
|
||||
.where(sells: 'unspecified')
|
||||
.exists?
|
||||
end
|
||||
|
||||
# Returns the appropriate enterprise path for the current user
|
||||
#
|
||||
# @return [String]
|
||||
def enterprises_path
|
||||
if managed_enterprises.size == 1
|
||||
@enterprise = @enterprises.first
|
||||
main_app.welcome_admin_enterprise_path(@enterprise)
|
||||
else
|
||||
main_app.admin_enterprises_path
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the appropriate dashboard view for the current user
|
||||
#
|
||||
# @return [String]
|
||||
def dashboard_view
|
||||
if managed_enterprises.size == 1
|
||||
@enterprise = @enterprises.first
|
||||
:single_enterprise_dashboard
|
||||
else
|
||||
:multi_enterprise_dashboard
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the list of enterprises the current user is manager of
|
||||
#
|
||||
# @return [ActiveRecord::Relation<Enterprise>]
|
||||
def managed_enterprises
|
||||
spree_current_user.enterprises
|
||||
end
|
||||
end
|
||||
317
app/controllers/spree/admin/reports_controller.rb
Normal file
317
app/controllers/spree/admin/reports_controller.rb
Normal file
@@ -0,0 +1,317 @@
|
||||
require 'csv'
|
||||
|
||||
require 'open_food_network/reports/list'
|
||||
require 'open_food_network/order_and_distributor_report'
|
||||
require 'open_food_network/products_and_inventory_report'
|
||||
require 'open_food_network/lettuce_share_report'
|
||||
require 'open_food_network/group_buy_report'
|
||||
require 'open_food_network/order_grouper'
|
||||
require 'open_food_network/customers_report'
|
||||
require 'open_food_network/users_and_enterprises_report'
|
||||
require 'open_food_network/order_cycle_management_report'
|
||||
require 'open_food_network/packing_report'
|
||||
require 'open_food_network/sales_tax_report'
|
||||
require 'open_food_network/xero_invoices_report'
|
||||
require 'open_food_network/bulk_coop_report'
|
||||
require 'open_food_network/payments_report'
|
||||
require 'open_food_network/orders_and_fulfillments_report'
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
class ReportsController < Spree::Admin::BaseController
|
||||
include Spree::ReportsHelper
|
||||
|
||||
helper_method :render_content?
|
||||
|
||||
before_filter :cache_search_state
|
||||
# Fetches user's distributors, suppliers and order_cycles
|
||||
before_filter :load_data,
|
||||
only: [:customers, :products_and_inventory, :order_cycle_management, :packing]
|
||||
|
||||
respond_to :html
|
||||
|
||||
def report_types
|
||||
OpenFoodNetwork::Reports::List.all
|
||||
end
|
||||
|
||||
def index
|
||||
@reports = authorized_reports
|
||||
respond_with(@reports)
|
||||
end
|
||||
|
||||
def customers
|
||||
@report_types = report_types[:customers]
|
||||
@report_type = params[:report_type]
|
||||
@report = OpenFoodNetwork::CustomersReport.new spree_current_user, params, render_content?
|
||||
render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def order_cycle_management
|
||||
params[:q] ||= {}
|
||||
|
||||
@report_types = report_types[:order_cycle_management]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
@table = @report.table_items
|
||||
|
||||
render_report(@report.header, @table, params[:csv],
|
||||
"order_cycle_management_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def packing
|
||||
params[:q] ||= {}
|
||||
|
||||
@report_types = report_types[:packing]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::PackingReport.new spree_current_user, params, render_content?
|
||||
@table = order_grouper_table
|
||||
|
||||
render_report(@report.header, @table, params[:csv], "packing_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def orders_and_distributors
|
||||
@report = OpenFoodNetwork::OrderAndDistributorReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
@search = @report.search
|
||||
csv_file_name = "orders_and_distributors_#{timestamp}.csv"
|
||||
render_report(@report.header, @report.table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def sales_tax
|
||||
@distributors = my_distributors
|
||||
@report_type = params[:report_type]
|
||||
@report = OpenFoodNetwork::SalesTaxReport.new spree_current_user, params, render_content?
|
||||
render_report(@report.header, @report.table, params[:csv], "sales_tax.csv")
|
||||
end
|
||||
|
||||
def bulk_coop
|
||||
# -- Prepare form options
|
||||
@distributors = my_distributors
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::BulkCoopReport.new spree_current_user, params, render_content?
|
||||
@table = order_grouper_table
|
||||
csv_file_name = "bulk_coop_#{params[:report_type]}_#{timestamp}.csv"
|
||||
|
||||
render_report(@report.header, @table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def payments
|
||||
# -- Prepare Form Options
|
||||
@distributors = my_distributors
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::PaymentsReport.new spree_current_user, params, render_content?
|
||||
@table = order_grouper_table
|
||||
csv_file_name = "payments_#{timestamp}.csv"
|
||||
|
||||
render_report(@report.header, @table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def orders_and_fulfillment
|
||||
params[:q] ||= orders_and_fulfillment_default_filters
|
||||
|
||||
# -- Prepare Form Options
|
||||
permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
# My distributors and any distributors distributing products I supply
|
||||
@distributors = permissions.visible_enterprises_for_order_reports.is_distributor
|
||||
# My suppliers and any suppliers supplying products I distribute
|
||||
@suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer
|
||||
|
||||
@order_cycles = my_order_cycles
|
||||
|
||||
@report_types = report_types[:orders_and_fulfillment]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
@include_blank = I18n.t(:all)
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
@table = order_grouper_table
|
||||
csv_file_name = "#{params[:report_type]}_#{timestamp}.csv"
|
||||
|
||||
render_report(@report.header, @table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def products_and_inventory
|
||||
@report_types = report_types[:products_and_inventory]
|
||||
@report = if params[:report_type] != 'lettuce_share'
|
||||
OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
else
|
||||
OpenFoodNetwork::LettuceShareReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
end
|
||||
|
||||
render_report @report.header,
|
||||
@report.table,
|
||||
params[:csv],
|
||||
"products_and_inventory_#{timestamp}.csv"
|
||||
end
|
||||
|
||||
def users_and_enterprises
|
||||
@report = OpenFoodNetwork::UsersAndEnterprisesReport.new params, render_content?
|
||||
render_report(@report.header, @report.table, params[:csv],
|
||||
"users_and_enterprises_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def xero_invoices
|
||||
params[:q] ||= {}
|
||||
|
||||
@distributors = my_distributors
|
||||
@order_cycles = my_order_cycles
|
||||
|
||||
@report = OpenFoodNetwork::XeroInvoicesReport.new(spree_current_user,
|
||||
params,
|
||||
render_content?)
|
||||
render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def model_class
|
||||
Spree::Admin::ReportsController
|
||||
end
|
||||
|
||||
# Some actions are changing the `params` object. That is unfortunate Spree
|
||||
# behavior and we are building on it. So we have to look at `params` early
|
||||
# to check if we are searching or just displaying a report search form.
|
||||
def cache_search_state
|
||||
search_keys = [
|
||||
# search parameter for ransack
|
||||
:q,
|
||||
# common in all reports, only set for CSV rendering
|
||||
:csv,
|
||||
# `button` is included in all forms. It's not important for searching,
|
||||
# but the Users & Enterprises report doesn't have any other parameter
|
||||
# for an empty search. So we use this one to display data.
|
||||
:button,
|
||||
# Some reports use filtering by enterprise or order cycle
|
||||
:distributor_id,
|
||||
:supplier_id,
|
||||
:order_cycle_id,
|
||||
# Xero Invoices can be filtered by date
|
||||
:invoice_date,
|
||||
:due_date
|
||||
]
|
||||
@searching = search_keys.any? { |key| params.key? key }
|
||||
end
|
||||
|
||||
# We don't want to render data unless search params are supplied.
|
||||
# Compiling data can take a long time.
|
||||
def render_content?
|
||||
@searching
|
||||
end
|
||||
|
||||
def render_report(header, table, create_csv, csv_file_name)
|
||||
send_data csv_report(header, table), filename: csv_file_name if create_csv
|
||||
@header = header
|
||||
@table = table
|
||||
# Rendering HTML is the default.
|
||||
end
|
||||
|
||||
def csv_report(header, table)
|
||||
CSV.generate do |csv|
|
||||
csv << header
|
||||
table.each { |row| csv << row }
|
||||
end
|
||||
end
|
||||
|
||||
def load_data
|
||||
@distributors = my_distributors
|
||||
@suppliers = my_suppliers | suppliers_of_products_distributed_by(@distributors)
|
||||
@order_cycles = my_order_cycles
|
||||
end
|
||||
|
||||
# Load managed distributor enterprises of current user
|
||||
def my_distributors
|
||||
Enterprise.is_distributor.managed_by(spree_current_user)
|
||||
end
|
||||
|
||||
# Load managed producer enterprises of current user
|
||||
def my_suppliers
|
||||
Enterprise.is_primary_producer.managed_by(spree_current_user)
|
||||
end
|
||||
|
||||
def suppliers_of_products_distributed_by(distributors)
|
||||
distributors.map { |d| Spree::Product.in_distributor(d).includes(:supplier).all }.
|
||||
flatten.map(&:supplier).uniq
|
||||
end
|
||||
|
||||
# Load order cycles the current user has access to
|
||||
def my_order_cycles
|
||||
OrderCycle.
|
||||
active_or_complete.
|
||||
accessible_by(spree_current_user).
|
||||
order('orders_close_at DESC')
|
||||
end
|
||||
|
||||
def order_grouper_table
|
||||
order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns
|
||||
order_grouper.table(@report.table_items)
|
||||
end
|
||||
|
||||
def authorized_reports
|
||||
all_reports = [
|
||||
:orders_and_distributors,
|
||||
:bulk_coop,
|
||||
:payments,
|
||||
:orders_and_fulfillment,
|
||||
:customers,
|
||||
:products_and_inventory,
|
||||
:users_and_enterprises,
|
||||
:enterprise_fee_summary,
|
||||
:order_cycle_management,
|
||||
:sales_tax,
|
||||
:xero_invoices,
|
||||
:packing
|
||||
]
|
||||
reports = all_reports.select { |action| can? action, Spree::Admin::ReportsController }
|
||||
reports.map { |report| [report, describe_report(report)] }.to_h
|
||||
end
|
||||
|
||||
def describe_report(report)
|
||||
name = I18n.t(:name, scope: [:admin, :reports, report])
|
||||
description = begin
|
||||
I18n.t!(:description, scope: [:admin, :reports, report])
|
||||
rescue I18n::MissingTranslationData
|
||||
render_to_string(
|
||||
partial: "#{report}_description",
|
||||
layout: false,
|
||||
locals: { report_types: report_types[report] }
|
||||
).html_safe
|
||||
end
|
||||
{ name: name, url: url_for_report(report), description: description }
|
||||
end
|
||||
|
||||
def url_for_report(report)
|
||||
public_send("#{report}_admin_reports_url".to_sym)
|
||||
rescue NoMethodError
|
||||
url_for([:new, :admin, :reports, report.to_s.singularize])
|
||||
end
|
||||
|
||||
def timestamp
|
||||
Time.zone.now.strftime("%Y%m%d")
|
||||
end
|
||||
|
||||
def orders_and_fulfillment_default_filters
|
||||
now = Time.zone.now
|
||||
{ completed_at_gt: (now - 1.month).beginning_of_day,
|
||||
completed_at_lt: (now + 1.day).beginning_of_day }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,302 +0,0 @@
|
||||
require 'csv'
|
||||
|
||||
require 'open_food_network/reports/list'
|
||||
require 'open_food_network/order_and_distributor_report'
|
||||
require 'open_food_network/products_and_inventory_report'
|
||||
require 'open_food_network/lettuce_share_report'
|
||||
require 'open_food_network/group_buy_report'
|
||||
require 'open_food_network/order_grouper'
|
||||
require 'open_food_network/customers_report'
|
||||
require 'open_food_network/users_and_enterprises_report'
|
||||
require 'open_food_network/order_cycle_management_report'
|
||||
require 'open_food_network/packing_report'
|
||||
require 'open_food_network/sales_tax_report'
|
||||
require 'open_food_network/xero_invoices_report'
|
||||
require 'open_food_network/bulk_coop_report'
|
||||
require 'open_food_network/payments_report'
|
||||
require 'open_food_network/orders_and_fulfillments_report'
|
||||
|
||||
Spree::Admin::ReportsController.class_eval do
|
||||
include Spree::ReportsHelper
|
||||
|
||||
helper_method :render_content?
|
||||
|
||||
before_filter :cache_search_state
|
||||
# Fetches user's distributors, suppliers and order_cycles
|
||||
before_filter :load_data,
|
||||
only: [:customers, :products_and_inventory, :order_cycle_management, :packing]
|
||||
|
||||
def report_types
|
||||
OpenFoodNetwork::Reports::List.all
|
||||
end
|
||||
|
||||
# Override spree reports list.
|
||||
def index
|
||||
@reports = authorized_reports
|
||||
respond_with(@reports)
|
||||
end
|
||||
|
||||
def customers
|
||||
@report_types = report_types[:customers]
|
||||
@report_type = params[:report_type]
|
||||
@report = OpenFoodNetwork::CustomersReport.new spree_current_user, params, render_content?
|
||||
render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def order_cycle_management
|
||||
params[:q] ||= {}
|
||||
|
||||
@report_types = report_types[:order_cycle_management]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
@table = @report.table_items
|
||||
|
||||
render_report(@report.header, @table, params[:csv], "order_cycle_management_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def packing
|
||||
params[:q] ||= {}
|
||||
|
||||
@report_types = report_types[:packing]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::PackingReport.new spree_current_user, params, render_content?
|
||||
@table = order_grouper_table
|
||||
|
||||
render_report(@report.header, @table, params[:csv], "packing_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def orders_and_distributors
|
||||
@report = OpenFoodNetwork::OrderAndDistributorReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
@search = @report.search
|
||||
csv_file_name = "orders_and_distributors_#{timestamp}.csv"
|
||||
render_report(@report.header, @report.table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def sales_tax
|
||||
@distributors = my_distributors
|
||||
@report_type = params[:report_type]
|
||||
@report = OpenFoodNetwork::SalesTaxReport.new spree_current_user, params, render_content?
|
||||
render_report(@report.header, @report.table, params[:csv], "sales_tax.csv")
|
||||
end
|
||||
|
||||
def bulk_coop
|
||||
# -- Prepare form options
|
||||
@distributors = my_distributors
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::BulkCoopReport.new spree_current_user, params, render_content?
|
||||
@table = order_grouper_table
|
||||
csv_file_name = "bulk_coop_#{params[:report_type]}_#{timestamp}.csv"
|
||||
|
||||
render_report(@report.header, @table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def payments
|
||||
# -- Prepare Form Options
|
||||
@distributors = my_distributors
|
||||
@report_type = params[:report_type]
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::PaymentsReport.new spree_current_user, params, render_content?
|
||||
@table = order_grouper_table
|
||||
csv_file_name = "payments_#{timestamp}.csv"
|
||||
|
||||
render_report(@report.header, @table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def orders_and_fulfillment
|
||||
params[:q] ||= orders_and_fulfillment_default_filters
|
||||
|
||||
# -- Prepare Form Options
|
||||
permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
# My distributors and any distributors distributing products I supply
|
||||
@distributors = permissions.visible_enterprises_for_order_reports.is_distributor
|
||||
# My suppliers and any suppliers supplying products I distribute
|
||||
@suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer
|
||||
|
||||
@order_cycles = my_order_cycles
|
||||
|
||||
@report_types = report_types[:orders_and_fulfillment]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
@include_blank = I18n.t(:all)
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
@table = order_grouper_table
|
||||
csv_file_name = "#{params[:report_type]}_#{timestamp}.csv"
|
||||
|
||||
render_report(@report.header, @table, params[:csv], csv_file_name)
|
||||
end
|
||||
|
||||
def products_and_inventory
|
||||
@report_types = report_types[:products_and_inventory]
|
||||
@report = if params[:report_type] != 'lettuce_share'
|
||||
OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user,
|
||||
params,
|
||||
render_content?
|
||||
else
|
||||
OpenFoodNetwork::LettuceShareReport.new spree_current_user, params, render_content?
|
||||
end
|
||||
render_report(@report.header,
|
||||
@report.table,
|
||||
params[:csv],
|
||||
"products_and_inventory_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def users_and_enterprises
|
||||
@report = OpenFoodNetwork::UsersAndEnterprisesReport.new params, render_content?
|
||||
render_report(@report.header,
|
||||
@report.table,
|
||||
params[:csv],
|
||||
"users_and_enterprises_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def xero_invoices
|
||||
params[:q] ||= {}
|
||||
|
||||
@distributors = my_distributors
|
||||
@order_cycles = my_order_cycles
|
||||
|
||||
@report = OpenFoodNetwork::XeroInvoicesReport.new spree_current_user, params, render_content?
|
||||
render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Some actions are changing the `params` object. That is unfortunate Spree
|
||||
# behavior and we are building on it. So we have to look at `params` early
|
||||
# to check if we are searching or just displaying a report search form.
|
||||
def cache_search_state
|
||||
search_keys = [
|
||||
# search parameter for ransack
|
||||
:q,
|
||||
# common in all reports, only set for CSV rendering
|
||||
:csv,
|
||||
# `button` is included in all forms. It's not important for searching,
|
||||
# but the Users & Enterprises report doesn't have any other parameter
|
||||
# for an empty search. So we use this one to display data.
|
||||
:button,
|
||||
# Some reports use filtering by enterprise or order cycle
|
||||
:distributor_id,
|
||||
:supplier_id,
|
||||
:order_cycle_id,
|
||||
# Xero Invoices can be filtered by date
|
||||
:invoice_date,
|
||||
:due_date
|
||||
]
|
||||
@searching = search_keys.any? { |key| params.key? key }
|
||||
end
|
||||
|
||||
# We don't want to render data unless search params are supplied.
|
||||
# Compiling data can take a long time.
|
||||
def render_content?
|
||||
@searching
|
||||
end
|
||||
|
||||
def render_report(header, table, create_csv, csv_file_name)
|
||||
send_data csv_report(header, table), filename: csv_file_name if create_csv
|
||||
@header = header
|
||||
@table = table
|
||||
# Rendering HTML is the default.
|
||||
end
|
||||
|
||||
def csv_report(header, table)
|
||||
CSV.generate do |csv|
|
||||
csv << header
|
||||
table.each { |row| csv << row }
|
||||
end
|
||||
end
|
||||
|
||||
def load_data
|
||||
@distributors = my_distributors
|
||||
@suppliers = my_suppliers | suppliers_of_products_distributed_by(@distributors)
|
||||
@order_cycles = my_order_cycles
|
||||
end
|
||||
|
||||
# Load managed distributor enterprises of current user
|
||||
def my_distributors
|
||||
Enterprise.is_distributor.managed_by(spree_current_user)
|
||||
end
|
||||
|
||||
# Load managed producer enterprises of current user
|
||||
def my_suppliers
|
||||
Enterprise.is_primary_producer.managed_by(spree_current_user)
|
||||
end
|
||||
|
||||
def suppliers_of_products_distributed_by(distributors)
|
||||
distributors.map { |d| Spree::Product.in_distributor(d).includes(:supplier).all }.
|
||||
flatten.map(&:supplier).uniq
|
||||
end
|
||||
|
||||
# Load order cycles the current user has access to
|
||||
def my_order_cycles
|
||||
OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
|
||||
end
|
||||
|
||||
def order_grouper_table
|
||||
order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns
|
||||
order_grouper.table(@report.table_items)
|
||||
end
|
||||
|
||||
def authorized_reports
|
||||
all_reports = [
|
||||
:orders_and_distributors,
|
||||
:bulk_coop,
|
||||
:payments,
|
||||
:orders_and_fulfillment,
|
||||
:customers,
|
||||
:products_and_inventory,
|
||||
:sales_total,
|
||||
:users_and_enterprises,
|
||||
:enterprise_fee_summary,
|
||||
:order_cycle_management,
|
||||
:sales_tax,
|
||||
:xero_invoices,
|
||||
:packing
|
||||
]
|
||||
reports = all_reports.select { |action| can? action, Spree::Admin::ReportsController }
|
||||
reports.map { |report| [report, describe_report(report)] }.to_h
|
||||
end
|
||||
|
||||
def describe_report(report)
|
||||
name = I18n.t(:name, scope: [:admin, :reports, report])
|
||||
description = begin
|
||||
I18n.t!(:description, scope: [:admin, :reports, report])
|
||||
rescue I18n::MissingTranslationData
|
||||
render_to_string(
|
||||
partial: "#{report}_description",
|
||||
layout: false,
|
||||
locals: { report_types: report_types[report] }
|
||||
).html_safe
|
||||
end
|
||||
{ name: name, url: url_for_report(report), description: description }
|
||||
end
|
||||
|
||||
def url_for_report(report)
|
||||
public_send("#{report}_admin_reports_url".to_sym)
|
||||
rescue NoMethodError
|
||||
url_for([:new, :admin, :reports, report.to_s.singularize])
|
||||
end
|
||||
|
||||
def timestamp
|
||||
Time.zone.now.strftime("%Y%m%d")
|
||||
end
|
||||
|
||||
def orders_and_fulfillment_default_filters
|
||||
now = Time.zone.now
|
||||
{ completed_at_gt: (now - 1.month).beginning_of_day,
|
||||
completed_at_lt: (now + 1.day).beginning_of_day }
|
||||
end
|
||||
end
|
||||
275
app/controllers/spree/admin/resource_controller.rb
Normal file
275
app/controllers/spree/admin/resource_controller.rb
Normal file
@@ -0,0 +1,275 @@
|
||||
require 'action_callbacks'
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
class ResourceController < Spree::Admin::BaseController
|
||||
helper_method :new_object_url, :edit_object_url, :object_url, :collection_url
|
||||
before_filter :load_resource, except: [:update_positions]
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :resource_not_found
|
||||
rescue_from CanCan::AccessDenied, with: :unauthorized
|
||||
|
||||
respond_to :html
|
||||
respond_to :js, except: [:show, :index]
|
||||
|
||||
def new
|
||||
invoke_callbacks(:new_action, :before)
|
||||
respond_with(@object) do |format|
|
||||
format.html { render layout: !request.xhr? }
|
||||
format.js { render layout: false }
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
respond_with(@object) do |format|
|
||||
format.html { render layout: !request.xhr? }
|
||||
format.js { render layout: false }
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
invoke_callbacks(:update, :before)
|
||||
if @object.update_attributes(params[object_name])
|
||||
invoke_callbacks(:update, :after)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to location_after_save }
|
||||
format.js { render layout: false }
|
||||
end
|
||||
else
|
||||
invoke_callbacks(:update, :fails)
|
||||
respond_with(@object)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
invoke_callbacks(:create, :before)
|
||||
@object.attributes = params[object_name]
|
||||
if @object.save
|
||||
invoke_callbacks(:create, :after)
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to location_after_save }
|
||||
format.js { render layout: false }
|
||||
end
|
||||
else
|
||||
invoke_callbacks(:create, :fails)
|
||||
respond_with(@object)
|
||||
end
|
||||
end
|
||||
|
||||
def update_positions
|
||||
params[:positions].each do |id, index|
|
||||
model_class.where(id: id).update_all(position: index)
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render text: 'Ok' }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
invoke_callbacks(:destroy, :before)
|
||||
if @object.destroy
|
||||
invoke_callbacks(:destroy, :after)
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
format.js { render partial: "spree/admin/shared/destroy" }
|
||||
end
|
||||
else
|
||||
invoke_callbacks(:destroy, :fails)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def resource_not_found
|
||||
flash[:error] = flash_message_for(model_class.new, :not_found)
|
||||
redirect_to collection_url
|
||||
end
|
||||
|
||||
class << self
|
||||
attr_accessor :parent_data
|
||||
attr_accessor :callbacks
|
||||
|
||||
def belongs_to(model_name, options = {})
|
||||
@parent_data ||= {}
|
||||
@parent_data[:model_name] = model_name
|
||||
@parent_data[:model_class] = model_name.to_s.classify.constantize
|
||||
@parent_data[:find_by] = options[:find_by] || :id
|
||||
end
|
||||
|
||||
def new_action
|
||||
@callbacks ||= {}
|
||||
@callbacks[:new_action] ||= ActionCallbacks.new
|
||||
end
|
||||
|
||||
def create
|
||||
@callbacks ||= {}
|
||||
@callbacks[:create] ||= ActionCallbacks.new
|
||||
end
|
||||
|
||||
def update
|
||||
@callbacks ||= {}
|
||||
@callbacks[:update] ||= ActionCallbacks.new
|
||||
end
|
||||
|
||||
def destroy
|
||||
@callbacks ||= {}
|
||||
@callbacks[:destroy] ||= ActionCallbacks.new
|
||||
end
|
||||
end
|
||||
|
||||
def model_class
|
||||
"Spree::#{controller_name.classify}".constantize
|
||||
end
|
||||
|
||||
def model_name
|
||||
parent_data[:model_name].gsub('spree/', '')
|
||||
end
|
||||
|
||||
def object_name
|
||||
controller_name.singularize
|
||||
end
|
||||
|
||||
def load_resource
|
||||
if member_action?
|
||||
@object ||= load_resource_instance
|
||||
|
||||
# call authorize! a third time (called twice already in Admin::BaseController)
|
||||
# this time we pass the actual instance so fine-grained abilities can control
|
||||
# access to individual records, not just entire models.
|
||||
authorize! action, @object
|
||||
|
||||
instance_variable_set("@#{object_name}", @object)
|
||||
|
||||
# If we don't have access, clear the object
|
||||
unless can? action, @object
|
||||
instance_variable_set("@#{object_name}", nil)
|
||||
end
|
||||
|
||||
authorize! action, @object
|
||||
else
|
||||
@collection ||= collection
|
||||
|
||||
# note: we don't call authorize here as the collection method should use
|
||||
# CanCan's accessible_by method to restrict the actual records returned
|
||||
|
||||
instance_variable_set("@#{controller_name}", @collection)
|
||||
end
|
||||
end
|
||||
|
||||
def load_resource_instance
|
||||
if new_actions.include?(action)
|
||||
build_resource
|
||||
elsif params[:id]
|
||||
find_resource
|
||||
end
|
||||
end
|
||||
|
||||
def parent_data
|
||||
self.class.parent_data
|
||||
end
|
||||
|
||||
def parent
|
||||
return nil if parent_data.blank?
|
||||
|
||||
@parent ||= parent_data[:model_class].
|
||||
public_send("find_by_#{parent_data[:find_by]}", params["#{model_name}_id"])
|
||||
instance_variable_set("@#{model_name}", @parent)
|
||||
end
|
||||
|
||||
def find_resource
|
||||
if parent_data.present?
|
||||
parent.public_send(controller_name).find(params[:id])
|
||||
else
|
||||
model_class.find(params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
def build_resource
|
||||
if parent_data.present?
|
||||
parent.public_send(controller_name).build
|
||||
else
|
||||
model_class.new
|
||||
end
|
||||
end
|
||||
|
||||
def collection
|
||||
return parent.public_send(controller_name) if parent_data.present?
|
||||
|
||||
if model_class.respond_to?(:accessible_by) &&
|
||||
!current_ability.has_block?(params[:action], model_class)
|
||||
model_class.accessible_by(current_ability, action)
|
||||
else
|
||||
model_class.scoped
|
||||
end
|
||||
end
|
||||
|
||||
def location_after_save
|
||||
collection_url
|
||||
end
|
||||
|
||||
def invoke_callbacks(action, callback_type)
|
||||
callbacks = self.class.callbacks || {}
|
||||
return if callbacks[action].nil?
|
||||
|
||||
case callback_type.to_sym
|
||||
when :before then callbacks[action].before_methods.each { |method| __send__ method }
|
||||
when :after then callbacks[action].after_methods.each { |method| __send__ method }
|
||||
when :fails then callbacks[action].fails_methods.each { |method| __send__ method }
|
||||
end
|
||||
end
|
||||
|
||||
# URL helpers
|
||||
|
||||
def new_object_url(options = {})
|
||||
if parent_data.present?
|
||||
spree.new_polymorphic_url([:admin, parent, model_class], options)
|
||||
else
|
||||
spree.new_polymorphic_url([:admin, model_class], options)
|
||||
end
|
||||
end
|
||||
|
||||
def edit_object_url(object, options = {})
|
||||
if parent_data.present?
|
||||
spree.public_send "edit_admin_#{model_name}_#{object_name}_url", parent, object, options
|
||||
else
|
||||
spree.public_send "edit_admin_#{object_name}_url", object, options
|
||||
end
|
||||
end
|
||||
|
||||
def object_url(object = nil, options = {})
|
||||
target = object || @object
|
||||
if parent_data.present?
|
||||
spree.public_send "admin_#{model_name}_#{object_name}_url", parent, target, options
|
||||
else
|
||||
spree.public_send "admin_#{object_name}_url", target, options
|
||||
end
|
||||
end
|
||||
|
||||
def collection_url(options = {})
|
||||
if parent_data.present?
|
||||
spree.polymorphic_url([:admin, parent, model_class], options)
|
||||
else
|
||||
spree.polymorphic_url([:admin, model_class], options)
|
||||
end
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
[:index]
|
||||
end
|
||||
|
||||
def member_action?
|
||||
!collection_actions.include? action
|
||||
end
|
||||
|
||||
def new_actions
|
||||
[:new, :create]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,20 +0,0 @@
|
||||
module AuthorizeOnLoadResource
|
||||
def load_resource
|
||||
super
|
||||
|
||||
if member_action?
|
||||
# If we don't have access, clear the object
|
||||
unless can? action, @object
|
||||
instance_variable_set("@#{object_name}", nil)
|
||||
end
|
||||
|
||||
authorize! action, @object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Spree::Admin::ResourceController.prepend(AuthorizeOnLoadResource)
|
||||
|
||||
Spree::Admin::ResourceController.class_eval do
|
||||
rescue_from CanCan::AccessDenied, with: :unauthorized
|
||||
end
|
||||
@@ -176,7 +176,7 @@ module Spree
|
||||
previous_states = @order.adjustments.each_with_object({}) do |adjustment, hash|
|
||||
hash[adjustment.id] = adjustment.state
|
||||
end
|
||||
@order.adjustments.each(&:open)
|
||||
@order.adjustments.each { |adjustment| adjustment.fire_events(:open) }
|
||||
|
||||
yield
|
||||
|
||||
|
||||
11
app/helpers/admin/enterprises_helper.rb
Normal file
11
app/helpers/admin/enterprises_helper.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
module Admin
|
||||
module EnterprisesHelper
|
||||
def add_check_if_single(count)
|
||||
if count == 1
|
||||
{ checked: true }
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -20,12 +20,27 @@ module ShopHelper
|
||||
)
|
||||
end
|
||||
|
||||
def shop_tabs
|
||||
def base_shop_tabs(column_sizes)
|
||||
[
|
||||
{ name: 'about', title: t(:shopping_tabs_about, distributor: current_distributor.name), cols: 6 },
|
||||
{ name: 'producers', title: t(:label_producers), cols: 2 },
|
||||
{ name: 'contact', title: t(:shopping_tabs_contact), cols: 2 },
|
||||
{ name: 'groups', title: t(:label_groups), cols: 2 },
|
||||
{ name: 'about', cols: column_sizes[0],
|
||||
title: t(:shopping_tabs_about, distributor: current_distributor.name) },
|
||||
{ name: 'producers', cols: column_sizes[1],
|
||||
title: t(:label_producers) },
|
||||
{ name: 'contact', cols: column_sizes[2],
|
||||
title: t(:shopping_tabs_contact) }
|
||||
]
|
||||
end
|
||||
|
||||
def tabs_with_groups
|
||||
tabs = base_shop_tabs([6, 2, 2])
|
||||
tabs << { name: 'groups', title: t(:label_groups), cols: 2 }
|
||||
end
|
||||
|
||||
def tabs_without_groups
|
||||
base_shop_tabs([4, 4, 4])
|
||||
end
|
||||
|
||||
def shop_tabs
|
||||
current_distributor.groups.present? ? tabs_with_groups : tabs_without_groups
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'spree/admin/base_helper'
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
module BaseHelper
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'spree/admin/navigation_helper'
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
module NavigationHelper
|
||||
|
||||
@@ -25,7 +25,7 @@ module Calculator
|
||||
end
|
||||
|
||||
def line_item_weight(line_item)
|
||||
if line_item.final_weight_volume.present?
|
||||
if final_weight_volume_present?(line_item)
|
||||
weight_per_final_weight_volume(line_item)
|
||||
else
|
||||
weight_per_variant(line_item) * line_item.quantity
|
||||
@@ -33,13 +33,18 @@ module Calculator
|
||||
end
|
||||
|
||||
def weight_per_variant(line_item)
|
||||
line_item.variant.andand.weight || 0
|
||||
if variant_unit(line_item) == 'weight'
|
||||
# The calculator price is per_kg so we need to convert unit_value to kg
|
||||
convert_g_to_kg(line_item.variant.andand.unit_value)
|
||||
else
|
||||
line_item.variant.andand.weight || 0
|
||||
end
|
||||
end
|
||||
|
||||
def weight_per_final_weight_volume(line_item)
|
||||
if line_item.variant.product.andand.variant_unit == 'weight'
|
||||
# Divided by 1000 because grams is the base weight unit and the calculator price is per_kg
|
||||
line_item.final_weight_volume / 1000.0
|
||||
if variant_unit(line_item) == 'weight'
|
||||
# The calculator price is per_kg so we need to convert final_weight_volume to kg
|
||||
convert_g_to_kg(line_item.final_weight_volume)
|
||||
else
|
||||
weight_per_variant(line_item) * quantity_implied_in_final_weight_volume(line_item)
|
||||
end
|
||||
@@ -51,5 +56,19 @@ module Calculator
|
||||
def quantity_implied_in_final_weight_volume(line_item)
|
||||
(1.0 * line_item.final_weight_volume / line_item.variant.unit_value).round(3)
|
||||
end
|
||||
|
||||
def final_weight_volume_present?(line_item)
|
||||
line_item.respond_to?(:final_weight_volume) && line_item.final_weight_volume.present?
|
||||
end
|
||||
|
||||
def variant_unit(line_item)
|
||||
line_item.variant.product.andand.variant_unit
|
||||
end
|
||||
|
||||
def convert_g_to_kg(value)
|
||||
return 0 unless value
|
||||
|
||||
value / 1000
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
class EnterpriseRelationshipPermission < ActiveRecord::Base
|
||||
default_scope order('name')
|
||||
default_scope { order('name') }
|
||||
end
|
||||
|
||||
@@ -142,9 +142,9 @@ class OrderCycle < ActiveRecord::Base
|
||||
oc.name = I18n.t("models.order_cycle.cloned_order_cycle_name", order_cycle: oc.name)
|
||||
oc.orders_open_at = oc.orders_close_at = nil
|
||||
oc.coordinator_fee_ids = coordinator_fee_ids
|
||||
# rubocop:disable Metrics/LineLength
|
||||
# rubocop:disable Layout/LineLength
|
||||
oc.preferred_product_selection_from_coordinator_inventory_only = preferred_product_selection_from_coordinator_inventory_only
|
||||
# rubocop:enable Metrics/LineLength
|
||||
# rubocop:enable Layout/LineLength
|
||||
oc.save!
|
||||
exchanges.each { |e| e.clone!(oc) }
|
||||
oc.reload
|
||||
|
||||
@@ -2,7 +2,7 @@ class ProducerProperty < ActiveRecord::Base
|
||||
belongs_to :producer, class_name: 'Enterprise', touch: true
|
||||
belongs_to :property, class_name: 'Spree::Property'
|
||||
|
||||
default_scope order("#{table_name}.position")
|
||||
default_scope { order("#{table_name}.position") }
|
||||
|
||||
scope :ever_sold_by, ->(shop) {
|
||||
joins(producer: { supplied_products: { variants: { exchanges: :order_cycle } } }).
|
||||
|
||||
@@ -214,7 +214,9 @@ module ProductImport
|
||||
end
|
||||
|
||||
def accepted_mimetype
|
||||
File.extname(@file.path).in?('.csv', '.xls', '.xlsx', '.ods') ? @file.path.split('.').last.to_sym : false
|
||||
return false unless ['.csv'].include? File.extname(@file.path)
|
||||
|
||||
@file.path.split('.').last.to_sym
|
||||
end
|
||||
|
||||
def headers
|
||||
|
||||
@@ -45,11 +45,11 @@ module ProductImport
|
||||
|
||||
next if @enterprises_index.key? enterprise_name
|
||||
|
||||
enterprise = Enterprise.find_by_name(enterprise_name, select: 'id, is_primary_producer')
|
||||
enterprise = Enterprise.select([:id, :is_primary_producer]).
|
||||
where(name: enterprise_name).first
|
||||
|
||||
@enterprises_index[enterprise_name] =
|
||||
{ id: enterprise.try(:id),
|
||||
is_primary_producer: enterprise.try(:is_primary_producer) }
|
||||
{ id: enterprise.try(:id), is_primary_producer: enterprise.try(:is_primary_producer) }
|
||||
end
|
||||
@enterprises_index
|
||||
end
|
||||
@@ -60,7 +60,8 @@ module ProductImport
|
||||
next unless entry.producer
|
||||
|
||||
producer_name = entry.producer
|
||||
producer_id = @producers_index[producer_name] || Enterprise.find_by_name(producer_name, select: 'id, name').try(:id)
|
||||
producer_id = @producers_index[producer_name] ||
|
||||
Enterprise.select([:id, :name]).where(name: producer_name).first.try(:id)
|
||||
@producers_index[producer_name] = producer_id
|
||||
end
|
||||
@producers_index
|
||||
@@ -70,7 +71,8 @@ module ProductImport
|
||||
@categories_index = {}
|
||||
@entries.each do |entry|
|
||||
category_name = entry.category
|
||||
category_id = @categories_index[category_name] || Spree::Taxon.find_by_name(category_name, select: 'id, name').try(:id)
|
||||
category_id = @categories_index[category_name] ||
|
||||
Spree::Taxon.select([:id, :name]).where(name: category_name).first.try(:id)
|
||||
@categories_index[category_name] = category_id
|
||||
end
|
||||
@categories_index
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
module Spree
|
||||
class User < ActiveRecord::Base
|
||||
include Core::UserBanners
|
||||
|
||||
devise :database_authenticatable, :token_authenticatable, :registerable, :recoverable,
|
||||
:rememberable, :trackable, :validatable, :encryptable, encryptor: 'authlogic_sha512'
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ class SubscriptionLineItem < ActiveRecord::Base
|
||||
validates :variant, presence: true
|
||||
validates :quantity, presence: true, numericality: { only_integer: true }
|
||||
|
||||
default_scope { order('id ASC') }
|
||||
|
||||
def total_estimate
|
||||
(price_estimate || 0) * (quantity || 0)
|
||||
end
|
||||
@@ -22,6 +24,4 @@ class SubscriptionLineItem < ActiveRecord::Base
|
||||
def price
|
||||
price_estimate
|
||||
end
|
||||
|
||||
default_scope order('id ASC')
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ class VariantOverride < ActiveRecord::Base
|
||||
# Default stock can be nil, indicating stock should not be reset or zero, meaning reset to zero. Need to ensure this can be set by the user.
|
||||
validates :default_stock, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
|
||||
|
||||
default_scope where(permission_revoked_at: nil)
|
||||
default_scope { where(permission_revoked_at: nil) }
|
||||
|
||||
scope :for_hubs, lambda { |hubs|
|
||||
where(hub_id: hubs)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'open_food_network/enterprise_issue_validator'
|
||||
|
||||
class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :managed, :supplied_products,
|
||||
attributes :id, :name, :managed,
|
||||
:issues_summary_supplier, :issues_summary_distributor,
|
||||
:is_primary_producer, :is_distributor, :sells
|
||||
|
||||
@@ -25,12 +25,6 @@ class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer
|
||||
Enterprise.managed_by(options[:spree_current_user]).include? object
|
||||
end
|
||||
|
||||
def supplied_products
|
||||
serializer = Api::Admin::ForOrderCycle::SuppliedProductSerializer
|
||||
ActiveModel::ArraySerializer.new(products, each_serializer: serializer,
|
||||
order_cycle: order_cycle)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def products_scope
|
||||
|
||||
@@ -14,7 +14,8 @@ class Api::Admin::ForOrderCycle::SuppliedProductSerializer < ActiveModel::Serial
|
||||
end
|
||||
|
||||
def variants
|
||||
variants = if order_cycle.prefers_product_selection_from_coordinator_inventory_only?
|
||||
variants = if order_cycle.present? &&
|
||||
order_cycle.prefers_product_selection_from_coordinator_inventory_only?
|
||||
object.variants.visible_for(order_cycle.coordinator)
|
||||
else
|
||||
object.variants
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
class Api::Admin::OrderSerializer < ActiveModel::Serializer
|
||||
attributes :id, :number, :user_id, :full_name, :email, :phone, :completed_at, :display_total,
|
||||
:edit_path, :state, :payment_state, :shipment_state,
|
||||
:payments_path, :ship_path, :ready_to_ship, :created_at,
|
||||
:distributor_name, :special_instructions, :payment_capture_path,
|
||||
:payments_path, :ready_to_ship, :ready_to_capture, :created_at,
|
||||
:distributor_name, :special_instructions,
|
||||
:item_total, :adjustment_total, :payment_total, :total
|
||||
|
||||
has_one :distributor, serializer: Api::Admin::IdSerializer
|
||||
@@ -28,15 +28,9 @@ class Api::Admin::OrderSerializer < ActiveModel::Serializer
|
||||
spree_routes_helper.admin_order_payments_path(object)
|
||||
end
|
||||
|
||||
def ship_path
|
||||
spree_routes_helper.fire_admin_order_path(object, e: 'ship')
|
||||
end
|
||||
|
||||
def payment_capture_path
|
||||
def ready_to_capture
|
||||
pending_payment = object.pending_payments.first
|
||||
return '' unless object.payment_required? && pending_payment
|
||||
|
||||
spree_routes_helper.fire_admin_order_payment_path(object, pending_payment.id, e: 'capture')
|
||||
object.payment_required? && pending_payment
|
||||
end
|
||||
|
||||
def ready_to_ship
|
||||
|
||||
23
app/services/action_callbacks.rb
Normal file
23
app/services/action_callbacks.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class ActionCallbacks
|
||||
attr_reader :before_methods
|
||||
attr_reader :after_methods
|
||||
attr_reader :fails_methods
|
||||
|
||||
def initialize
|
||||
@before_methods = []
|
||||
@after_methods = []
|
||||
@fails_methods = []
|
||||
end
|
||||
|
||||
def before(method)
|
||||
@before_methods << method
|
||||
end
|
||||
|
||||
def after(method)
|
||||
@after_methods << method
|
||||
end
|
||||
|
||||
def fails(method)
|
||||
@fails_methods << method
|
||||
end
|
||||
end
|
||||
86
app/services/exchange_products_renderer.rb
Normal file
86
app/services/exchange_products_renderer.rb
Normal file
@@ -0,0 +1,86 @@
|
||||
class ExchangeProductsRenderer
|
||||
def initialize(order_cycle, user)
|
||||
@order_cycle = order_cycle
|
||||
@user = user
|
||||
end
|
||||
|
||||
def exchange_products(incoming, enterprise)
|
||||
if incoming
|
||||
products_for_incoming_exchange(enterprise)
|
||||
else
|
||||
products_for_outgoing_exchange
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def products_for_incoming_exchange(enterprise)
|
||||
supplied_products(enterprise.id)
|
||||
end
|
||||
|
||||
def supplied_products(enterprises_query_matcher)
|
||||
products_relation = Spree::Product.where(supplier_id: enterprises_query_matcher)
|
||||
|
||||
if @order_cycle.present? &&
|
||||
@order_cycle.prefers_product_selection_from_coordinator_inventory_only?
|
||||
products_relation = products_relation.visible_for(@order_cycle.coordinator)
|
||||
end
|
||||
|
||||
products_relation
|
||||
end
|
||||
|
||||
def products_for_outgoing_exchange
|
||||
supplied_products(enterprises_for_outgoing_exchange.select(:id)).
|
||||
includes(:variants).
|
||||
where("spree_variants.id": incoming_exchanges_variants)
|
||||
end
|
||||
|
||||
def incoming_exchanges_variants
|
||||
return @incoming_exchanges_variants if @incoming_exchanges_variants.present?
|
||||
|
||||
@incoming_exchanges_variants = []
|
||||
visible_incoming_exchanges.each do |incoming_exchange|
|
||||
@incoming_exchanges_variants.push(
|
||||
*incoming_exchange.variants.merge(
|
||||
visible_incoming_variants(incoming_exchange.sender)
|
||||
).map(&:id).to_a
|
||||
)
|
||||
end
|
||||
@incoming_exchanges_variants
|
||||
end
|
||||
|
||||
def visible_incoming_exchanges
|
||||
OpenFoodNetwork::OrderCyclePermissions.
|
||||
new(@user, @order_cycle).
|
||||
visible_exchanges.
|
||||
by_enterprise_name.
|
||||
incoming
|
||||
end
|
||||
|
||||
def visible_incoming_variants(incoming_exchange_sender)
|
||||
variants_relation = permitted_incoming_variants(incoming_exchange_sender)
|
||||
|
||||
if @order_cycle.prefers_product_selection_from_coordinator_inventory_only?
|
||||
variants_relation = variants_relation.visible_for(@order_cycle.coordinator)
|
||||
end
|
||||
|
||||
variants_relation
|
||||
end
|
||||
|
||||
def permitted_incoming_variants(incoming_exchange_sender)
|
||||
OpenFoodNetwork::OrderCyclePermissions.
|
||||
new(@user, @order_cycle).
|
||||
visible_variants_for_incoming_exchanges_from(incoming_exchange_sender)
|
||||
end
|
||||
|
||||
def enterprises_for_outgoing_exchange
|
||||
enterprises = OpenFoodNetwork::OrderCyclePermissions.
|
||||
new(@user, @order_cycle)
|
||||
.visible_enterprises
|
||||
return enterprises if enterprises.empty?
|
||||
|
||||
enterprises.includes(
|
||||
supplied_products: [:supplier, :variants, master: [:images]]
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -7,17 +7,17 @@ module Permissions
|
||||
|
||||
# Find orders that the user can see
|
||||
def visible_orders
|
||||
Spree::Order.where(id:
|
||||
managed_orders.select(:id) |
|
||||
coordinated_orders.select(:id) |
|
||||
produced_orders.select("spree_orders.id"))
|
||||
Spree::Order.
|
||||
with_line_items_variants_and_products_outer.
|
||||
where(visible_orders_where_values)
|
||||
end
|
||||
|
||||
# Any orders that the user can edit
|
||||
def editable_orders
|
||||
Spree::Order.where(id:
|
||||
managed_orders.select(:id) |
|
||||
coordinated_orders.select(:id) )
|
||||
Spree::Order.where(
|
||||
managed_orders_where_values.
|
||||
or(coordinated_orders_where_values)
|
||||
)
|
||||
end
|
||||
|
||||
def visible_line_items
|
||||
@@ -28,27 +28,45 @@ module Permissions
|
||||
|
||||
# Any line items that I can edit
|
||||
def editable_line_items
|
||||
Spree::LineItem.where(order_id: editable_orders)
|
||||
Spree::LineItem.where(order_id: editable_orders.select(:id))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def visible_orders_where_values
|
||||
# Grouping keeps the 2 where clauses from produced_orders_where_values inside parentheses
|
||||
# This way it makes the OR work between the 3 types of orders:
|
||||
# produced, managed and coordinated
|
||||
Spree::Order.arel_table.
|
||||
grouping(produced_orders_where_values).
|
||||
or(managed_orders_where_values).
|
||||
or(coordinated_orders_where_values)
|
||||
end
|
||||
|
||||
# Any orders placed through any hub that I manage
|
||||
def managed_orders
|
||||
Spree::Order.where(distributor_id: @permissions.managed_enterprises.select("enterprises.id"))
|
||||
def managed_orders_where_values
|
||||
Spree::Order.
|
||||
where(distributor_id: @permissions.managed_enterprises.select("enterprises.id")).
|
||||
where_values.
|
||||
reduce(:and)
|
||||
end
|
||||
|
||||
# Any order that is placed through an order cycle one of my managed enterprises coordinates
|
||||
def coordinated_orders
|
||||
Spree::Order.where(order_cycle_id: @permissions.coordinated_order_cycles.select(:id))
|
||||
def coordinated_orders_where_values
|
||||
Spree::Order.
|
||||
where(order_cycle_id: @permissions.coordinated_order_cycles.select(:id)).
|
||||
where_values.
|
||||
reduce(:and)
|
||||
end
|
||||
|
||||
def produced_orders
|
||||
def produced_orders_where_values
|
||||
Spree::Order.with_line_items_variants_and_products_outer.
|
||||
where(
|
||||
distributor_id: granted_distributor_ids,
|
||||
spree_products: { supplier_id: enterprises_with_associated_orders }
|
||||
)
|
||||
).
|
||||
where_values.
|
||||
reduce(:and)
|
||||
end
|
||||
|
||||
def enterprises_with_associated_orders
|
||||
@@ -69,7 +87,7 @@ module Permissions
|
||||
|
||||
# Any from visible orders, where the product is produced by one of my managed producers
|
||||
def produced_line_items
|
||||
Spree::LineItem.where(order_id: visible_orders.select(:id)).
|
||||
Spree::LineItem.where(order_id: visible_orders.select("DISTINCT spree_orders.id")).
|
||||
joins(:product).
|
||||
where(spree_products:
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ class ProductsRenderer
|
||||
.split(",").map { |id| "spree_products.primary_taxon_id=#{id} DESC" }
|
||||
.join(", ") + ", spree_products.name ASC, spree_products.id ASC"
|
||||
else
|
||||
"spree_products.name ASC"
|
||||
"spree_products.name ASC, spree_products.id"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
%tr{ ng: { class: "'#{type} #{type}-{{ exchange.enterprise_id }}'" } }
|
||||
%td{:class => "#{type}_name"} {{ enterprises[exchange.enterprise_id].name }}
|
||||
%td.products.panel-toggle.text-center{ name: "products" }
|
||||
{{ exchangeSelectedVariants(exchange) }} /
|
||||
- if type == 'supplier'
|
||||
{{ enterpriseTotalVariants(enterprises[exchange.enterprise_id]) }}
|
||||
- else
|
||||
{{ (incomingExchangeVariantsFor(exchange.enterprise_id)).length }}
|
||||
{{ exchangeSelectedVariants(exchange) }} / {{ exchangeTotalVariants(exchange) }}
|
||||
= t('.selected')
|
||||
- if type == 'supplier'
|
||||
%td.receival-details
|
||||
@@ -34,11 +30,11 @@
|
||||
|
||||
- if type == 'supplier'
|
||||
%tr.panel-row{ object: "exchange",
|
||||
panels: "{products: 'exchange_supplied_products'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,suppliedVariants,removeDistributionOfVariant",
|
||||
panels: "{products: 'exchange_products_supplied'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,selectAllVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
|
||||
colspan: 4 }
|
||||
- if type == 'distributor'
|
||||
%tr.panel-row{ object: "exchange",
|
||||
panels: "{products: 'exchange_distributed_products', tags: 'exchange_tags'}",
|
||||
locals: "$index,order_cycle,exchange,supplied_products,setExchangeVariants,incomingExchangeVariantsFor,productSuppliedToOrderCycle,variantSuppliedToOrderCycle",
|
||||
panels: "{products: 'exchange_products_distributed', tags: 'exchange_tags'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
|
||||
colspan: 5 }
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
%table.exchanges
|
||||
%tbody{ng: {repeat: "exchange in order_cycle.incoming_exchanges"}}
|
||||
%tr.products
|
||||
%td{ ng: { include: "'admin/panels/exchange_supplied_products.html'" } }
|
||||
%td{ ng: { include: "'admin/panels/exchange_products_simple.html'" } }
|
||||
|
||||
%br/
|
||||
= label_tag t('.fees')
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
= render 'wizard_progress'
|
||||
|
||||
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
|
||||
%input{ type: "button", value: t('.previous'), ng: { click: "cancel('#{main_app.edit_admin_order_cycle_path(@order_cycle)}')", disabled: "order_cycle_form.$dirty" } }
|
||||
%input.red{ type: "button", value: t('.save'), ng: { click: "submit($event, null)", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
|
||||
%input.red{ type: "button", value: t('.save_and_next'), ng: { click: "submit($event, '#{main_app.admin_order_cycle_outgoing_path(@order_cycle)}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
|
||||
%input{ type: "button", value: t('.next'), ng: { click: "cancel('#{main_app.admin_order_cycle_outgoing_path(@order_cycle)}')", disabled: "order_cycle_form.$dirty" } }
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
= render 'wizard_progress'
|
||||
|
||||
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
|
||||
%input{ type: "button", value: t('.previous'), ng: { click: "cancel('#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", disabled: "order_cycle_form.$dirty" } }
|
||||
%input.red{ type: "button", value: t('.save'), ng: { click: "submit($event, null)", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
|
||||
%input.red{ type: "button", value: t('.save_and_back_to_list'), ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
|
||||
%input{ type: "button", ng: { value: "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", click: "cancel('#{main_app.admin_order_cycles_path}')" } }
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
%p
|
||||
= t(".email_userguide_html", link: link_to(t(".userguide"), ContentConfig.user_guide_link))
|
||||
%p
|
||||
= t(".email_admin_html", link: link_to(t(".admin_panel"), spree.admin_url))
|
||||
= t(".email_admin_html", link: link_to(t(".admin_panel"), spree.admin_dashboard_url))
|
||||
|
||||
%p
|
||||
= t(".email_community_html", link: link_to(t(".join_community"), ContentConfig.community_forum_url))
|
||||
|
||||
@@ -8,38 +8,6 @@
|
||||
.small-12.medium-8.medium-offset-2.columns.text-center
|
||||
.alert-box
|
||||
= render 'shared/register_call'
|
||||
.row
|
||||
.small-12.medium-4.medium-offset-2.columns.text-center
|
||||
%h6
|
||||
= t '.footer_global_headline'
|
||||
%p
|
||||
%a{href: "http://www.openfoodnetwork.org", target: "_blank"}
|
||||
= t '.footer_global_home'
|
||||
%span |
|
||||
%a{href: "http://www.openfoodnetwork.org/news/", target: "_blank"}
|
||||
= t '.footer_global_news'
|
||||
%span |
|
||||
%a{href: "http://www.openfoodnetwork.org/about/history-team/", target: "_blank"}
|
||||
= t '.footer_global_about'
|
||||
%span |
|
||||
%a{href: "http://www.openfoodnetwork.org/contact/", target: "_blank"}
|
||||
= t '.footer_global_contact'
|
||||
|
||||
.small-12.medium-4.columns.text-center
|
||||
%h6
|
||||
= t '.footer_sites_headline'
|
||||
%p
|
||||
%a{href: "http://dev.openfoodnetwork.org", target: "_blank"}
|
||||
= t '.footer_sites_developer'
|
||||
%span |
|
||||
%a{href: "http://community.openfoodnetwork.org", target: "_blank"}
|
||||
= t '.footer_sites_community'
|
||||
%span |
|
||||
%a{href: "http://www.openfoodnetwork.org/platform/user-guide/", target: "_blank"}
|
||||
= t '.footer_sites_userguide'
|
||||
|
||||
.medium-2.columns.text-center
|
||||
/ Placeholder
|
||||
|
||||
.footer-local
|
||||
.row
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
%section.right{"ng-cloak" => true}
|
||||
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
|
||||
%a.icon{href: main_app.checkout_path}
|
||||
%a.icon{href: main_app.cart_path}
|
||||
%span
|
||||
= t '.cart'
|
||||
%span.count
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
- if admin_user? or enterprise_user?
|
||||
%li
|
||||
%a{href: spree.admin_path, target:'_blank'}
|
||||
%a{href: spree.admin_dashboard_path, target:'_blank'}
|
||||
%i.ofn-i_021-tools
|
||||
= t 'label_administration'
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
- if admin_user? or enterprise_user?
|
||||
%li
|
||||
%a{href: spree.admin_path, target:'_blank'}
|
||||
%a{href: spree.admin_dashboard_path, target:'_blank'}
|
||||
%i.ofn-i_021-tools
|
||||
= t 'label_admin'
|
||||
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
|
||||
= render :partial => 'adjustments_table'
|
||||
|
||||
= button_link_to t(:continue), @order.cart? ? new_admin_order_payment_url(@order) : admin_orders_url, :icon => 'icon-arrow-right'
|
||||
= button_link_to t(:continue), admin_order_payments_url(@order), :icon => 'icon-arrow-right'
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
%th.actions
|
||||
%tbody
|
||||
%tr{ng: {repeat: 'order in orders track by $index', class: {even: "'even'", odd: "'odd'"}}, 'ng-class' => "'state-{{order.state}}'"}
|
||||
%tr{ng: {repeat: 'order in orders track by order.id', class: {even: "'even'", odd: "'odd'"}}, 'ng-class' => "{'state-{{order.state}}': true, 'row-loading': rowStatus[order.id] == 'loading'}"}
|
||||
%td.align-center
|
||||
%input{type: 'checkbox', 'ng-model' => 'checkboxes[order.id]', 'ng-change' => 'toggleSelection(order.id)'}
|
||||
%td.align-center
|
||||
@@ -78,11 +78,15 @@
|
||||
%td.align-center
|
||||
%span{'ng-bind-html' => 'order.display_total'}
|
||||
%td.actions
|
||||
%div.row-loading-icons
|
||||
%img.spinner{src: "/assets/spinning-circles.svg", ng: {show: 'rowStatus[order.id] == "loading"'} }
|
||||
%i.success.icon-ok-sign{ng: {show: 'rowStatus[order.id] == "success"'} }
|
||||
%i.error.icon-remove-sign.with-tip{ng: {show: 'rowStatus[order.id] == "error"'}, 'ofn-with-tip' => t('.order_not_updated')}
|
||||
%a.icon_link.with-tip.icon-edit.no-text{'ng-href' => '{{order.edit_path}}', 'data-action' => 'edit', 'ofn-with-tip' => t('.edit')}
|
||||
%div{'ng-if' => 'order.ready_to_ship'}
|
||||
%a.icon-road.icon_link.with-tip.no-text{'ng-href' => '{{order.ship_path}}', 'data-action' => 'ship', 'data-confirm' => t(:are_you_sure), 'data-method' => 'put', rel: 'nofollow', 'ofn-with-tip' => t('.ship')}
|
||||
%div{'ng-if' => 'order.payment_capture_path'}
|
||||
%a.icon-capture.icon_link.no-text{'ng-href' => '{{order.payment_capture_path}}', 'data-action' => 'capture', 'data-method' => 'put', rel: 'nofollow', 'ofn-with-tip' => t('.capture')}
|
||||
%button.icon-road.icon_link.with-tip.no-text{'ng-click' => 'shipOrder(order)', 'data-confirm' => t(:are_you_sure), rel: 'nofollow', 'ofn-with-tip' => t('.ship')}
|
||||
%div{'ng-if' => 'order.ready_to_capture'}
|
||||
%button.icon-capture.icon_link.no-text{'ng-click' => 'capturePayment(order)', rel: 'nofollow', 'ofn-with-tip' => t('.capture')}
|
||||
|
||||
.orders-loading{'ng-show' => 'RequestMonitor.loading'}
|
||||
.row
|
||||
|
||||
@@ -44,14 +44,14 @@
|
||||
%td{ :align => "right" }
|
||||
= t :invoice_billing_address
|
||||
%br
|
||||
%strong= @order.ship_address.full_name
|
||||
%strong= @order.bill_address.full_name
|
||||
- if @order.andand.customer.andand.code.present?
|
||||
%br
|
||||
= "Code: #{@order.customer.code}"
|
||||
%br
|
||||
= @order.ship_address.address_part1
|
||||
= @order.bill_address.address_part1
|
||||
%br
|
||||
= @order.ship_address.address_part2
|
||||
= @order.bill_address.address_part2
|
||||
|
||||
= render 'spree/admin/orders/invoice_table2'
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<% content_for :page_title do %>
|
||||
<%= t(:listing_reports) %>
|
||||
<% end %>
|
||||
|
||||
<table class="index">
|
||||
<thead>
|
||||
<tr data-hook="reports_header">
|
||||
<th><%= t(:name) %></th>
|
||||
<th><%= t(:description) %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @reports.each do |key, value| %>
|
||||
<tr data-hook="reports_row">
|
||||
<td><%= link_to value[:name], value[:url] %></td>
|
||||
<td><%= value[:description] %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
13
app/views/spree/admin/reports/index.html.haml
Normal file
13
app/views/spree/admin/reports/index.html.haml
Normal file
@@ -0,0 +1,13 @@
|
||||
- content_for :page_title do
|
||||
= t(:listing_reports)
|
||||
|
||||
%table.index
|
||||
%thead
|
||||
%tr
|
||||
%th= t(:name)
|
||||
%th= t(:description)
|
||||
%tbody
|
||||
- @reports.each do |key, value|
|
||||
%tr
|
||||
%td= link_to value[:name], value[:url]
|
||||
%td= value[:description]
|
||||
@@ -1,24 +0,0 @@
|
||||
%tr{"data-hook" => "address1"}
|
||||
%td
|
||||
= t(:admin_shared_address_1):
|
||||
%td= f.text_field :address1
|
||||
%tr{"data-hook" => "address2" }
|
||||
%td
|
||||
= t(:admin_shared_address_2):
|
||||
%td= f.text_field :address2
|
||||
%tr{"data-hook" => "city" }
|
||||
%td
|
||||
= t(:admin_share_city):
|
||||
%td= f.text_field :city
|
||||
%tr{"data-hook" => "zipcode" }
|
||||
%td
|
||||
= t(:admin_share_zipcode):
|
||||
%td= f.text_field :zipcode
|
||||
%tr{"data-hook" => "country" }
|
||||
%td
|
||||
= t(:admin_share_country):
|
||||
%td= f.collection_select(:country_id, available_countries, :id, :name)
|
||||
%tr{"data-hook" => "state" }
|
||||
%td
|
||||
= t(:admin_share_state):
|
||||
%td= f.collection_select(:state_id, f.object.country.states, :id, :name)
|
||||
@@ -12,7 +12,7 @@
|
||||
%span.four.columns
|
||||
%span.three.columns.alpha
|
||||
%label
|
||||
= check_box klass, :distributor_ids, { multiple: true }, hub.id, nil
|
||||
= check_box klass, :distributor_ids, { multiple: true }.merge(add_check_if_single(@hubs.count)), hub.id, nil
|
||||
= hub.name
|
||||
%a.one.column.omega{ href: "#{main_app.edit_admin_enterprise_path(hub)}" }
|
||||
%span.icon-arrow-right
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
= tab :dashboard, :route => :admin, :icon => 'icon-dashboard'
|
||||
= tab :overview, label: 'dashboard', url: spree.admin_dashboard_path, icon: 'icon-dashboard'
|
||||
= tab :products, :option_types, :properties, :variants, :product_properties, :taxons, :url => admin_products_path, :icon => 'icon-th-large'
|
||||
= tab :order_cycles, :url => main_app.admin_order_cycles_path, :icon => 'icon-refresh'
|
||||
= tab :orders, :payments, :creditcard_payments, :shipments, :credit_cards, :return_authorizations, :url => admin_orders_path('q[s]' => 'completed_at desc'), :icon => 'icon-shopping-cart'
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
= Spree.t(:loading)
|
||||
\...
|
||||
|
||||
= render :partial => 'spree/admin/shared/alert', :collection => session[:alerts]
|
||||
|
||||
%header#header{"data-hook" => ""}
|
||||
.container
|
||||
%figure.columns.five{"data-hook" => "logo-wrapper"}
|
||||
= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_path
|
||||
= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_dashboard_path
|
||||
%nav.columns.eleven{"data-hook" => "admin_login_navigation_bar"}
|
||||
= render :partial => 'spree/layouts/admin/login_nav'
|
||||
|
||||
|
||||
@@ -14,11 +14,10 @@
|
||||
.progress-message
|
||||
= t(:loading)
|
||||
\...
|
||||
= render :partial => 'spree/admin/shared/alert', :collection => session[:alerts]
|
||||
|
||||
%header#header{"data-hook" => ""}
|
||||
.container
|
||||
%figure.columns.five{"data-hook" => "logo-wrapper"}= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_path
|
||||
%figure.columns.five{"data-hook" => "logo-wrapper"}= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_dashboard_path
|
||||
%nav.columns.eleven{"data-hook" => "admin_login_navigation_bar"}
|
||||
= render partial: "spree/layouts/admin/login_nav"
|
||||
|
||||
|
||||
1
config/initializers/paper_trail.rb
Normal file
1
config/initializers/paper_trail.rb
Normal file
@@ -0,0 +1 @@
|
||||
PaperTrail.config.track_associations = false
|
||||
@@ -2,6 +2,8 @@ ar:
|
||||
language_name: "الانجيلزي"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: نوع الرسوم
|
||||
spree/order:
|
||||
payment_state: حالة الدفعة
|
||||
shipment_state: حالة الشحن
|
||||
@@ -48,6 +50,8 @@ ar:
|
||||
shipping_method_ids: "طرق الشحن"
|
||||
payment_method_ids: "طريقة الدفع"
|
||||
errors:
|
||||
messages:
|
||||
inclusion: "غير مدرجة في القائمة"
|
||||
models:
|
||||
subscription_validator:
|
||||
attributes:
|
||||
@@ -847,7 +851,6 @@ ar:
|
||||
save_and_back_to_list: "حفظ والعودة إلى القائمة"
|
||||
choose_products_from: "اختر المنتجات من:"
|
||||
incoming:
|
||||
previous: "السابق"
|
||||
save: "حفظ"
|
||||
save_and_next: "حفظ والتالي"
|
||||
next: "التالى"
|
||||
@@ -986,9 +989,6 @@ ar:
|
||||
name: العملاء
|
||||
products_and_inventory:
|
||||
name: المنتجات والمخزون
|
||||
sales_total:
|
||||
name: إجمالي المبيعات
|
||||
description: إجمالي المبيعات لجميع الطلبات
|
||||
users_and_enterprises:
|
||||
name: المستخدمين والمؤسسات
|
||||
description: ملكية الشركات وحالتها
|
||||
@@ -1127,15 +1127,6 @@ ar:
|
||||
selling_on_ofn: "هل أنت مهتم بالحصول على شبكة الغذاء المفتوح؟"
|
||||
register: "سجل هنا"
|
||||
footer:
|
||||
footer_global_headline: "شبكة الغذاء المفتوحة العالمية"
|
||||
footer_global_home: "الصفحة الرئيسية"
|
||||
footer_global_news: "أخبار"
|
||||
footer_global_about: "حول"
|
||||
footer_global_contact: "اتصل"
|
||||
footer_sites_headline: "مواقع شبكة الغذاء المفتوحة"
|
||||
footer_sites_developer: "مطور"
|
||||
footer_sites_community: "تواصل اجتماعي"
|
||||
footer_sites_userguide: "دليل المستخدم"
|
||||
footer_secure: "آمن وموثوق به."
|
||||
footer_secure_text: "تستخدم شبكة الغذاء المفتوح تشفير( SSL 2048 بت RSA) في كل مكان للحفاظ على خصوصية معلومات التسوق والدفع. لا تقوم خوادمنا بتخزين تفاصيل بطاقة الائتمان الخاصة بك ، وتتم معالجة المدفوعات بواسطة خدمات متوافقة مع PCI."
|
||||
footer_contact_headline: "أبق على اتصال"
|
||||
@@ -2426,6 +2417,12 @@ ar:
|
||||
severity: خطورة
|
||||
description: وصف
|
||||
resolve: حل
|
||||
exchange_products:
|
||||
load_more_products: "تحميل المزيد من المنتجات"
|
||||
load_all_products: "تحميل جميع المنتجات"
|
||||
select_all_products: "حدد جميع المنتجات %{total_number_of_products}"
|
||||
products_loaded: "%{num_of_products_loaded} من %{total_number_of_products} المنتجات المحملة"
|
||||
loading_products: "تحميل المنتجات"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "طرق الشحن الموسومة"
|
||||
shipping_method_tagged_bottom: "هي:"
|
||||
@@ -2508,6 +2505,7 @@ ar:
|
||||
customer_placeholder: "customer@example.org"
|
||||
valid_email_error: "من فضلك أدخل بريد أليكترونى صحيح"
|
||||
subscriptions:
|
||||
error_saving: "خطأ في حفظ الاشتراك"
|
||||
new:
|
||||
please_select_a_shop: "يرجى اختيار متجر"
|
||||
insufficient_stock: "مخزون غير متوفر ، تبقى %{on_hand}"
|
||||
@@ -2708,7 +2706,6 @@ ar:
|
||||
allow_ssl_in_development_and_test: "السماح باستخدام طبقة المقابس الآمنة SSL عندما تكون في أوضاع التطوير والاختبار"
|
||||
allow_ssl_in_production: "السماح باستخدام طبقة المقابس الآمنة في وضع الإنتاج"
|
||||
allow_ssl_in_staging: "اسمح باستخدام طبقة المقابس الآمنة في وضع التدريج"
|
||||
check_for_spree_alerts: "تحقق من وجود تنبيهات Spree"
|
||||
currency_decimal_mark: "العملة العشرية"
|
||||
currency_settings: "إعدادات العملة"
|
||||
currency_symbol_position: ضع "رمز العملة قبل أو بعد مبلغ الدولار؟"
|
||||
|
||||
@@ -2,6 +2,8 @@ ca:
|
||||
language_name: "Català"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Tipus de comissió
|
||||
spree/order:
|
||||
payment_state: Estat del Pagament
|
||||
shipment_state: Estat de la Tramesa
|
||||
@@ -434,9 +436,12 @@ ca:
|
||||
infinity: "Infinit"
|
||||
to_order_tip: "Els articles preparats per encàrrec no tenen un nivell fixat d'existències, com ara pa fet sota comanda."
|
||||
back_to_products_list: "Torna a la llista de productes"
|
||||
editing_product: "Editant el producte"
|
||||
tabs:
|
||||
product_details: "Detalls del producte"
|
||||
group_buy_options: "Opcions de compra en grup"
|
||||
images: "Imatges"
|
||||
variants: "Variants"
|
||||
product_properties: "Propietats del producte"
|
||||
product_import:
|
||||
title: Importació de productes
|
||||
@@ -836,21 +841,32 @@ ca:
|
||||
new:
|
||||
create: "Crear"
|
||||
cancel: "Cancel·lar"
|
||||
back_to_list: "Tornar a la llista"
|
||||
edit:
|
||||
advanced_settings: "Configuració avançada"
|
||||
save: "Desa"
|
||||
save_and_next: "Desa i següent"
|
||||
next: "Següent"
|
||||
cancel: "Cancel·lar"
|
||||
back_to_list: "Tornar a la llista"
|
||||
save_and_back_to_list: "Desa i torna a la llista"
|
||||
choose_products_from: "Trieu Productes des de:"
|
||||
incoming:
|
||||
previous: "Anterior"
|
||||
save: "Desa"
|
||||
save_and_next: "Desa i següent"
|
||||
next: "Següent"
|
||||
cancel: "Cancel·lar"
|
||||
back_to_list: "Tornar a la llista"
|
||||
outgoing:
|
||||
previous: "Anterior"
|
||||
save: "Desa"
|
||||
save_and_back_to_list: "Desa i torna a la llista"
|
||||
cancel: "Cancel·lar"
|
||||
back_to_list: "Tornar a la llista"
|
||||
wizard_progress:
|
||||
edit: "1. Configuració general"
|
||||
incoming: "2. Productes entrants"
|
||||
outgoing: "3. Productes sortints"
|
||||
exchange_form:
|
||||
pickup_time_tip: Quan les comandes d'aquest cicle de comandes estiguin preparades per a les consumidores
|
||||
pickup_instructions_placeholder: "Instruccions de recollida"
|
||||
@@ -974,9 +990,6 @@ ca:
|
||||
name: Consumidores
|
||||
products_and_inventory:
|
||||
name: Productes & Inventari
|
||||
sales_total:
|
||||
name: Total de vendes
|
||||
description: Total de vendes per a totes les comandes
|
||||
users_and_enterprises:
|
||||
name: Usuaris & Organitzacions
|
||||
description: Propietat i estatus de l'organització
|
||||
@@ -1115,15 +1128,6 @@ ca:
|
||||
selling_on_ofn: "Estàs interessat en formar part d'Open Food Network?"
|
||||
register: "Registra't aquí"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Inici"
|
||||
footer_global_news: "Notícies"
|
||||
footer_global_about: "Sobre"
|
||||
footer_global_contact: "Contacte"
|
||||
footer_sites_headline: "Pàgines d'OFN"
|
||||
footer_sites_developer: "Desenvolupador"
|
||||
footer_sites_community: "Comunitat"
|
||||
footer_sites_userguide: "Guia de l'usuari"
|
||||
footer_secure: "Segur i de confiança."
|
||||
footer_secure_text: "Open Food Network utilitza el xifrat SSL (RSA de 2048 bits) a tot arreu per mantenir les vostres dades comercials i de pagament privades. Els nostres servidors no emmagatzemen els detalls de la targeta de crèdit i els pagaments es processen mitjançant serveis compatibles amb PCI."
|
||||
footer_contact_headline: "Mantén el contacte"
|
||||
@@ -2698,7 +2702,6 @@ ca:
|
||||
allow_ssl_in_development_and_test: "Permet que s'utilitzi SSL quan s'utilitzi el desenvolupament i els modes de prova"
|
||||
allow_ssl_in_production: "Permet que SSL s'utilitzi en mode de producció"
|
||||
allow_ssl_in_staging: "Permet que SSL s'utilitzi en mode de staging"
|
||||
check_for_spree_alerts: "Comproveu si hi ha alertes Spree"
|
||||
currency_decimal_mark: "Separador decimal de moneda"
|
||||
currency_settings: "Configuració de moneda"
|
||||
currency_symbol_position: Posa "símbol de moneda abans o després d'una quantitat"?
|
||||
@@ -2798,6 +2801,12 @@ ca:
|
||||
minimal_amount: "Quantitat mínima"
|
||||
normal_amount: "Quantitat normal"
|
||||
discount_amount: "Import de descompte"
|
||||
no_images_found: "No s'han trobat imatges"
|
||||
new_image: "Nova imatge"
|
||||
filename: "Nom de l'arxiu"
|
||||
alt_text: "Text alternatiu"
|
||||
thumbnail: "Miniatura"
|
||||
back_to_images_list: "Torna a la llista d’imatges"
|
||||
email: Correu electrònic
|
||||
account_updated: "Compte actualitzat!"
|
||||
email_updated: "El compte s’actualitzarà un cop es confirmi el nou correu electrònic."
|
||||
@@ -2809,6 +2818,7 @@ ca:
|
||||
zipcode: Codi postal
|
||||
weight: Pes (per kg)
|
||||
error_user_destroy_with_orders: "No es poden esborrar usuaris amb comandes completades"
|
||||
options: "Opcions"
|
||||
actions:
|
||||
update: "Actualitzar"
|
||||
errors:
|
||||
@@ -2840,27 +2850,53 @@ ca:
|
||||
product_properties:
|
||||
index:
|
||||
inherits_properties_checkbox_hint: "heredar propietats de %{supplier}? (llevat que es sobreescrigui a dalt)"
|
||||
add_product_properties: "Afegeix propietats del producte"
|
||||
select_from_prototype: "Seleccioneu d'un prototip"
|
||||
properties:
|
||||
index:
|
||||
properties: "Propietats"
|
||||
new_property: "Nova propietat"
|
||||
name: "Nom"
|
||||
presentation: "Presentació"
|
||||
new:
|
||||
new_property: "Nova propietat"
|
||||
edit:
|
||||
editing_property: "Edició de propietats"
|
||||
back_to_properties_list: "Torna a la llista de propietats"
|
||||
form:
|
||||
name: "Nom"
|
||||
presentation: "Presentació"
|
||||
return_authorizations:
|
||||
index:
|
||||
new_return_authorization: "Nova autorització de devolució"
|
||||
return_authorizations: "Autoritzacions de devolució"
|
||||
back_to_orders_list: "Tornar a la llista de comandes"
|
||||
rma_number: "Número RMA"
|
||||
status: "Estat"
|
||||
amount: "Quantitat"
|
||||
cannot_create_returns: "No es poden crear devolucions ja que aquesta comanda no té cap unitat enviada."
|
||||
continue: "Continua"
|
||||
new:
|
||||
new_return_authorization: "Nova autorització de devolució"
|
||||
back_to_return_authorizations_list: "Tornar a la llista d'autorització"
|
||||
continue: "Continua"
|
||||
edit:
|
||||
receive: "rebre"
|
||||
are_you_sure: "Estàs segur?"
|
||||
return_authorization: "Autorització de devolució"
|
||||
form:
|
||||
product: "Producte"
|
||||
quantity_shipped: "Quantitat enviada"
|
||||
quantity_returned: "Quantitat retornada"
|
||||
return_quantity: "Devolució de la quantitat"
|
||||
amount: "Quantitat"
|
||||
rma_value: "Valor RMA"
|
||||
reason: "Raó"
|
||||
stock_location: "Ubicació d'estoc"
|
||||
states:
|
||||
authorized: "Autoritzat"
|
||||
received: "Rebut"
|
||||
canceled: "Cancel·lat"
|
||||
orders:
|
||||
index:
|
||||
listing_orders: "Llistat comandes"
|
||||
@@ -3051,12 +3087,23 @@ ca:
|
||||
index:
|
||||
sku: "Número de referència (SKU)"
|
||||
price: "Preu"
|
||||
options: "Opcions"
|
||||
no_results: "Sense resultats"
|
||||
to_add_variants_you_must_first_define: "Per afegir variants, primer heu de definir"
|
||||
option_types: "Tipus d'opcions"
|
||||
option_values: "Valors d’opció"
|
||||
and: "i"
|
||||
new_variant: "Nova variant"
|
||||
show_active: "Mostra actiu"
|
||||
show_deleted: "Mostra esborrats"
|
||||
new:
|
||||
new_variant: "Nova variant"
|
||||
form:
|
||||
cost_price: "Preu de cost"
|
||||
sku: "Número de referència (SKU)"
|
||||
price: "Preu"
|
||||
display_as: "Mostra com"
|
||||
display_name: "Nom de visualització"
|
||||
autocomplete:
|
||||
producer_name: "Productor"
|
||||
unit: "Unitat"
|
||||
@@ -3196,3 +3243,19 @@ ca:
|
||||
allow_charges?: "Permetre càrrecs?"
|
||||
localized_number:
|
||||
invalid_format: té un format no vàlid. Si us plau introdueix un número.
|
||||
api:
|
||||
invalid_api_key: "No s’ha especificat una clau d’API vàlida (%{key})."
|
||||
unauthorized: "No teniu autorització per realitzar aquesta acció."
|
||||
invalid_resource: "Recurs invàlid. Corregiu els errors i torneu-ho a provar."
|
||||
resource_not_found: "No s'ha trobat el recurs que buscaves."
|
||||
access: "Accés a l'API"
|
||||
key: "Clau"
|
||||
clear_key: "Esborra la clau"
|
||||
regenerate_key: "Regenerar la clau"
|
||||
no_key: "Sense clau"
|
||||
generate_key: "Generar clau d’API"
|
||||
key_generated: "Clau generada"
|
||||
key_cleared: "La clau esborrada"
|
||||
shipment:
|
||||
cannot_ready: "No es pot fer l'enviament."
|
||||
invalid_taxonomy_id: "Identificador de taxonomia no vàlid."
|
||||
|
||||
@@ -2,6 +2,8 @@ de_DE:
|
||||
language_name: "Deutsch"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Art der Gebühr
|
||||
spree/order:
|
||||
payment_state: Zahlungsstatus
|
||||
shipment_state: Lieferstatus
|
||||
@@ -850,7 +852,6 @@ de_DE:
|
||||
save_and_back_to_list: "Speichern und zurück zur Liste"
|
||||
choose_products_from: "Wählen Sie Produkte von:"
|
||||
incoming:
|
||||
previous: "Bisherige"
|
||||
save: "Speichern"
|
||||
save_and_next: "Speichern und weiter"
|
||||
next: "Weiter"
|
||||
@@ -989,9 +990,6 @@ de_DE:
|
||||
name: Kunden
|
||||
products_and_inventory:
|
||||
name: Produkte und Katalog
|
||||
sales_total:
|
||||
name: Gesamtumsatz
|
||||
description: Gesamtumsatz für alle Bestellungen
|
||||
users_and_enterprises:
|
||||
name: Benutzer und Unternehmen
|
||||
description: Unternehmenseigentum & Status
|
||||
@@ -1130,15 +1128,6 @@ de_DE:
|
||||
selling_on_ofn: "Interesse am Open Food Network?"
|
||||
register: "Hier anmelden"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Startseite"
|
||||
footer_global_news: "Aktuelles"
|
||||
footer_global_about: "Über Uns"
|
||||
footer_global_contact: "Kontakt"
|
||||
footer_sites_headline: "OFN Webseiten"
|
||||
footer_sites_developer: "Entwickler"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "Benutzerhandbuch"
|
||||
footer_secure: "Sicher und vertrauenswürdig."
|
||||
footer_secure_text: "Open Food Network verwendet überall SSL-Verschlüsselung (2048 Bit RSA), um Ihre Einkaufs- und Zahlungsinformationen geheim zu halten. Unsere Server speichern Ihre Kreditkartendetails nicht und Zahlungen werden von PCI-konformen Dienstleistern verarbeitet."
|
||||
footer_contact_headline: "In Verbindung bleiben"
|
||||
@@ -2713,7 +2702,6 @@ de_DE:
|
||||
allow_ssl_in_development_and_test: "Erlauben Sie SSL in Entwicklungs- und Testmodi"
|
||||
allow_ssl_in_production: "Zulassen, dass SSL im Produktionsmodus verwendet wird"
|
||||
allow_ssl_in_staging: "Zulassen, dass SSL im Staging-Modus verwendet wird"
|
||||
check_for_spree_alerts: "Suchen Sie nach Spree-Benachrichtigungen"
|
||||
currency_decimal_mark: "Dezimalzeichen der Währung"
|
||||
currency_settings: "Währungseinstellungen"
|
||||
currency_symbol_position: Setzen Sie "Währungssymbol vor oder nach dem Dollarbetrag?"
|
||||
|
||||
@@ -23,6 +23,8 @@ en:
|
||||
language_name: "English" # Localised name of this language
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Fee Type
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
@@ -69,6 +71,8 @@ en:
|
||||
shipping_method_ids: "Shipping Methods"
|
||||
payment_method_ids: "Payment Methods"
|
||||
errors:
|
||||
messages:
|
||||
inclusion: "is not included in the list"
|
||||
models:
|
||||
subscription_validator:
|
||||
attributes:
|
||||
@@ -903,7 +907,6 @@ en:
|
||||
save_and_back_to_list: "Save and Back to List"
|
||||
choose_products_from: "Choose Products From:"
|
||||
incoming:
|
||||
previous: "Previous"
|
||||
save: "Save"
|
||||
save_and_next: "Save and Next"
|
||||
next: "Next"
|
||||
@@ -1046,9 +1049,6 @@ en:
|
||||
products_and_inventory:
|
||||
name: Products & Inventory
|
||||
description:
|
||||
sales_total:
|
||||
name: Sales Total
|
||||
description: Sales Total For All Orders
|
||||
users_and_enterprises:
|
||||
name: Users & Enterprises
|
||||
description: Enterprise Ownership & Status
|
||||
@@ -1169,6 +1169,8 @@ en:
|
||||
destroy_attachment_does_not_exist: "Logo does not exist"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "Promo image does not exist"
|
||||
orders:
|
||||
failed_to_update: "Failed to update order"
|
||||
|
||||
# Frontend views
|
||||
#
|
||||
@@ -1199,15 +1201,6 @@ en:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Home"
|
||||
footer_global_news: "News"
|
||||
footer_global_about: "About"
|
||||
footer_global_contact: "Contact"
|
||||
footer_sites_headline: "OFN Sites"
|
||||
footer_sites_developer: "Developer"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "User Guide"
|
||||
footer_secure: "Secure and trusted."
|
||||
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
|
||||
footer_contact_headline: "Keep in touch"
|
||||
@@ -2560,6 +2553,12 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
severity: Severity
|
||||
description: Description
|
||||
resolve: Resolve
|
||||
exchange_products:
|
||||
load_more_products: "Load More Products"
|
||||
load_all_products: "Load All Products"
|
||||
select_all_products: "Select All %{total_number_of_products} Products"
|
||||
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
|
||||
loading_products: "Loading Products"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2642,6 +2641,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
customer_placeholder: "customer@example.org"
|
||||
valid_email_error: "Please enter a valid email address"
|
||||
subscriptions:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
@@ -2850,7 +2850,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
|
||||
allow_ssl_in_production: "Allow SSL to be used in production mode"
|
||||
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
|
||||
check_for_spree_alerts: "Check for Spree alerts"
|
||||
currency_decimal_mark: "Currency decimal mark"
|
||||
currency_settings: "Currency Settings"
|
||||
currency_symbol_position: Put "currency symbol before or after dollar amount?"
|
||||
@@ -3072,6 +3071,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
capture: "Capture"
|
||||
ship: "Ship"
|
||||
edit: "Edit"
|
||||
order_not_updated: "The order could not be updated"
|
||||
note: "Note"
|
||||
first: "First"
|
||||
last: "Last"
|
||||
|
||||
@@ -2,6 +2,8 @@ en_AU:
|
||||
language_name: "English"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Fee Type
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
@@ -848,7 +850,6 @@ en_AU:
|
||||
save_and_back_to_list: "Save and Back to List"
|
||||
choose_products_from: "Choose Products From:"
|
||||
incoming:
|
||||
previous: "Previous"
|
||||
save: "Save"
|
||||
save_and_next: "Save and Next"
|
||||
next: "Next"
|
||||
@@ -987,9 +988,6 @@ en_AU:
|
||||
name: Customers
|
||||
products_and_inventory:
|
||||
name: Products & Inventory
|
||||
sales_total:
|
||||
name: Sales Total
|
||||
description: Sales Total For All Orders
|
||||
users_and_enterprises:
|
||||
name: Users & Enterprises
|
||||
description: Enterprise Ownership & Status
|
||||
@@ -1128,15 +1126,6 @@ en_AU:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Home"
|
||||
footer_global_news: "News"
|
||||
footer_global_about: "About"
|
||||
footer_global_contact: "Contact"
|
||||
footer_sites_headline: "OFN Sites"
|
||||
footer_sites_developer: "Developer"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "User Guide"
|
||||
footer_secure: "Secure and trusted."
|
||||
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
|
||||
footer_contact_headline: "Keep in touch"
|
||||
@@ -1603,11 +1592,11 @@ en_AU:
|
||||
producers_signup_title: Sign up as a producer
|
||||
producers_signup_headline: Food producers, empowered.
|
||||
producers_signup_motivation: Sell your food and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field.
|
||||
producers_signup_send: Join now
|
||||
producers_signup_send: Register
|
||||
producers_signup_enterprise: Enterprise Accounts
|
||||
producers_signup_studies: Stories from our producers.
|
||||
producers_signup_cta_headline: Join now!
|
||||
producers_signup_cta_action: Join now
|
||||
producers_signup_cta_action: Register
|
||||
producers_signup_detail: Here's the detail.
|
||||
products_item: Item
|
||||
products_description: Description
|
||||
@@ -1637,7 +1626,7 @@ en_AU:
|
||||
shops_signup_title: Sign up as a hub
|
||||
shops_signup_headline: Food hubs, unlimited.
|
||||
shops_signup_motivation: Whatever your model, we support you. However you change, we're with you. We're non-profit, independent, and open-sourced. We're the software partners you've dreamed of.
|
||||
shops_signup_action: Join now
|
||||
shops_signup_action: Register
|
||||
shops_signup_pricing: Enterprise Accounts
|
||||
shops_signup_stories: Stories from our hubs.
|
||||
shops_signup_help: We're ready to help.
|
||||
@@ -1858,7 +1847,7 @@ en_AU:
|
||||
finished:
|
||||
headline: "Finished!"
|
||||
thanks: "Thanks for filling out the details for %{enterprise}."
|
||||
login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin."
|
||||
login: "To manage your new Enterprise, go to openfoodnetwork.org.au/admin"
|
||||
action: "Open Food Network home"
|
||||
back: "Back"
|
||||
continue: "Continue"
|
||||
@@ -2708,7 +2697,6 @@ en_AU:
|
||||
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
|
||||
allow_ssl_in_production: "Allow SSL to be used in production mode"
|
||||
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
|
||||
check_for_spree_alerts: "Check for Spree alerts"
|
||||
currency_decimal_mark: "Currency decimal mark"
|
||||
currency_settings: "Currency Settings"
|
||||
currency_symbol_position: Put "currency symbol before or after dollar amount?"
|
||||
|
||||
@@ -2,6 +2,8 @@ en_BE:
|
||||
language_name: "English"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Fee Type
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
@@ -833,7 +835,6 @@ en_BE:
|
||||
cancel: "Cancel"
|
||||
choose_products_from: "Choose Products From:"
|
||||
incoming:
|
||||
previous: "Previous"
|
||||
save: "Save"
|
||||
next: "Next"
|
||||
cancel: "Cancel"
|
||||
@@ -964,9 +965,6 @@ en_BE:
|
||||
name: Customers
|
||||
products_and_inventory:
|
||||
name: Products & Inventory
|
||||
sales_total:
|
||||
name: Sales Total
|
||||
description: Sales Total For All Orders
|
||||
users_and_enterprises:
|
||||
name: Users & Enterprises
|
||||
description: Enterprise Ownership & Status
|
||||
@@ -1103,15 +1101,6 @@ en_BE:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Home"
|
||||
footer_global_news: "News"
|
||||
footer_global_about: "About"
|
||||
footer_global_contact: "Contact"
|
||||
footer_sites_headline: "OFN Sites"
|
||||
footer_sites_developer: "Developer"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "User Guide"
|
||||
footer_secure: "Secure and trusted."
|
||||
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
|
||||
footer_contact_headline: "Keep in touch"
|
||||
@@ -2681,7 +2670,6 @@ en_BE:
|
||||
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
|
||||
allow_ssl_in_production: "Allow SSL to be used in production mode"
|
||||
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
|
||||
check_for_spree_alerts: "Check for Spree alerts"
|
||||
currency_decimal_mark: "Currency decimal mark"
|
||||
currency_settings: "Currency Settings"
|
||||
currency_symbol_position: Put "currency symbol before or after euros amount?"
|
||||
|
||||
@@ -2,6 +2,8 @@ en_CA:
|
||||
language_name: "English"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Fee Type
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
@@ -48,6 +50,8 @@ en_CA:
|
||||
shipping_method_ids: "Shipping Methods"
|
||||
payment_method_ids: "Payment Methods"
|
||||
errors:
|
||||
messages:
|
||||
inclusion: "is not included in the list"
|
||||
models:
|
||||
subscription_validator:
|
||||
attributes:
|
||||
@@ -117,7 +121,7 @@ en_CA:
|
||||
userguide: "Open Food Network User Guide"
|
||||
email_admin_html: "You can manage your account by logging into the %{link} or by clicking on the cog in the top right hand side of the homepage, and selecting Administration."
|
||||
admin_panel: "Admin Panel"
|
||||
email_community_html: "We also have an online forum for community discussion related to OFN software and the unique challenges of running a food enterprise. You are encouraged to join in. We are constantly evolving and your input into this forum will shape what happens next. %{link}"
|
||||
email_community_html: "We also have an online forum for community discussion related to OFN software and the unique challenges of tech-enabling local enterprises. You are encouraged to join in. We are constantly evolving and your input into this forum will shape what happens next. %{link}"
|
||||
join_community: "Join the community"
|
||||
invite_manager:
|
||||
subject: "%{enterprise} has invited you to be a manager"
|
||||
@@ -612,7 +616,7 @@ en_CA:
|
||||
name: Name
|
||||
name_placeholder: eg. Gustav Plum
|
||||
email_address: Public Email Address
|
||||
email_address_placeholder: eg. inquiries@fresh-food.com
|
||||
email_address_placeholder: eg. inquiries@localproducts.com
|
||||
email_address_tip: "This email address will be displayed in your public profile"
|
||||
phone: Phone
|
||||
phone_placeholder: eg. 519 885 8888
|
||||
@@ -654,7 +658,7 @@ en_CA:
|
||||
groups_tip: Select any groups or regions that you are a member of. This will help customers find your enterprise.
|
||||
groups_placeholder: Start typing to search available groups...
|
||||
primary_producer: Primary Producer?
|
||||
primary_producer_tip: Select 'Producer' if you are a primary producer of food.
|
||||
primary_producer_tip: Select 'Producer' if you are a primary producer, grower, maker or designer
|
||||
producer: Producer
|
||||
any: Any
|
||||
none: None
|
||||
@@ -778,18 +782,18 @@ en_CA:
|
||||
always_free: ALWAYS FREE
|
||||
producer_description_text: Add your products to Open Food Network, allowing hubs to stock your products in their stores.
|
||||
producer_shop: Producer Shop
|
||||
sell_your_produce: Sell your own produce
|
||||
sell_your_produce: Sell your own products
|
||||
producer_shop_description_text: Sell your products directly to customers through your very own Open Food Network shopfront.
|
||||
producer_shop_description_text2: A Producer Shop is for your produce only, if you want to sell produce grown/produced off site, select 'Producer Hub'.
|
||||
producer_shop_description_text2: A Producer Shop is for your products only, if you want to sell producyd grown/produced off site, select 'Producer Hub'.
|
||||
producer_hub: Producer Hub
|
||||
producer_hub_text: Sell produce from self and others
|
||||
producer_hub_description_text: Your enterprise is the backbone of your local food system. You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
|
||||
producer_hub_text: Sell products from self and others
|
||||
producer_hub_description_text: Your enterprise is the backbone of your local food system. You can sell your own products as well as products aggregated from other enterprises through your shopfront on the Open Food Network.
|
||||
profile: Profile Only
|
||||
get_listing: Get a listing
|
||||
profile_description_text: People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings.
|
||||
hub_shop: Hub Shop
|
||||
hub_shop_text: Sell produce from others
|
||||
hub_shop_description_text: Your enterprise is the backbone of your local food system. You aggregate produce from other enterprises and can sell it through your shop on the Open Food Network.
|
||||
hub_shop_text: Sell products from others
|
||||
hub_shop_description_text: Your enterprise is the backbone of your local community. You aggregate products from other enterprises and can sell them through your shop on the Open Food Network.
|
||||
choose_option: Please choose one of the options above.
|
||||
change_now: Change now
|
||||
enterprise_user_index:
|
||||
@@ -848,7 +852,6 @@ en_CA:
|
||||
save_and_back_to_list: "Save and Back to List"
|
||||
choose_products_from: "Choose Products From:"
|
||||
incoming:
|
||||
previous: "Previous"
|
||||
save: "Save"
|
||||
save_and_next: "Save and Next"
|
||||
next: "Next"
|
||||
@@ -987,9 +990,6 @@ en_CA:
|
||||
name: Customers
|
||||
products_and_inventory:
|
||||
name: Products & Inventory
|
||||
sales_total:
|
||||
name: Sales Total
|
||||
description: Sales Total For All Orders
|
||||
users_and_enterprises:
|
||||
name: Users & Enterprises
|
||||
description: Enterprise Ownership & Status
|
||||
@@ -1104,6 +1104,8 @@ en_CA:
|
||||
destroy_attachment_does_not_exist: "Logo does not exist"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "Promo image does not exist"
|
||||
orders:
|
||||
failed_to_update: "Failed to update order"
|
||||
checkout:
|
||||
already_ordered:
|
||||
cart: "cart"
|
||||
@@ -1128,15 +1130,6 @@ en_CA:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Home"
|
||||
footer_global_news: "News"
|
||||
footer_global_about: "About"
|
||||
footer_global_contact: "Contact"
|
||||
footer_sites_headline: "OFN Sites"
|
||||
footer_sites_developer: "Developer"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "User Guide"
|
||||
footer_secure: "Secure and trusted."
|
||||
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
|
||||
footer_contact_headline: "Keep in touch"
|
||||
@@ -1297,7 +1290,7 @@ en_CA:
|
||||
cookies_policy:
|
||||
header: "How We Use Cookies"
|
||||
desc_part_1: "Cookies are very small text files that are stored on your computer when you visit some websites."
|
||||
desc_part_2: "In OFN we are fully respectful of your privacy. We use only the cookies that are necessary for delivering you the service of selling/buying food online. We don’t sell any of your data. We might in the future propose you to share some of your data to build new commons services that could be useful for the ecosystem (like logistics services for short food systems) but we are not yet there, and we won’t do it without your authorization :-)"
|
||||
desc_part_2: "In OFN we are fully respectful of your privacy. We use only the cookies that are necessary for delivering you the service of selling/buying products online. We don’t sell any of your data. We might in the future propose you to share some of your data to build new commons services that could be useful for the ecosystem (like logistics or local delivery services) but we are not yet there, and we won’t do it without your authorization :-)"
|
||||
desc_part_3: "We use cookies mainly to remember who you are if you 'log in' to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website. Here is the list of cookies we use!"
|
||||
essential_cookies: "Essential Cookies"
|
||||
essential_cookies_desc: "The following cookies are strictly necessary for the operation of our website."
|
||||
@@ -1331,7 +1324,7 @@ en_CA:
|
||||
cookies_banner:
|
||||
cookies_usage: "This site uses cookies in order to make your navigation frictionless and secure, and to help us understand how you use it in order to improve the features we offer."
|
||||
cookies_definition: "Cookies are very small text files that are stored on your computer when you visit some websites."
|
||||
cookies_desc: "We use only the cookies that are necessary for delivering you the service of selling/buying food online. We don’t sell any of your data. We use cookies mainly to remember who you are if you ‘log in’ to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website."
|
||||
cookies_desc: "We use only the cookies that are necessary for delivering you the service of selling/buying products online. We don’t sell any of your data. We use cookies mainly to remember who you are if you ‘log in’ to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website."
|
||||
cookies_policy_link_desc: "If you want to learn more, check our"
|
||||
cookies_policy_link: "cookies policy"
|
||||
cookies_accept_button: "Accept Cookies"
|
||||
@@ -1339,29 +1332,29 @@ en_CA:
|
||||
brandstory_headline: "Food, unincorporated."
|
||||
brandstory_intro: "Sometimes the best way to fix the system is to start a new one…"
|
||||
brandstory_part1: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can seriously change the world."
|
||||
brandstory_part2: "Then we need a way to make it real. A way to empower everyone who grows, sells and buys food. A way to tell all the stories, to handle all the logistics. A way to turn transaction into transformation every day."
|
||||
brandstory_part2: "Then we need a way to make it real. A way to empower everyone who makes, grows, sells and buys local sustainable products. A way to tell all the stories, to handle all the logistics. A way to turn transaction into transformation every day."
|
||||
brandstory_part3: "So we build an online marketplace that levels the playing field. It’s transparent, so it creates real relationships. It’s open source, so it’s owned by everyone. It scales to regions and nations, so people start versions across the world."
|
||||
brandstory_part4: "It works everywhere. It changes everything."
|
||||
brandstory_part5_strong: "We call it Open Food Network."
|
||||
brandstory_part6: "We all love food. Now we can love our food system too."
|
||||
learn_body: "Explore models, stories and resources to support you to develop your fair food business or organisation. Find training, events and other opportunities to learn from peers."
|
||||
learn_body: "Explore models, stories and resources to support you to develop your local business or organisation. Find training, events and other opportunities to learn from peers."
|
||||
learn_cta: "Get Inspired"
|
||||
connect_body: "Search our full directories of producers, hubs and groups to find fair food traders near you. List your business or organisation on the OFN so buyers can find you. Join the community to get advice and solve problems together."
|
||||
connect_body: "Search our full directories of producers, hubs and groups to find fair and sustainably produced products near you. List your business or organisation on the OFN so buyers can find you. Join the community to get advice and solve problems together."
|
||||
connect_cta: "Go Exploring"
|
||||
system_headline: "Shopping - here's how it works."
|
||||
system_step1: "1. Search"
|
||||
system_step1_text: "Search our diverse, independent shops for seasonal local food. Search by neighbourhood and food category, or whether you prefer delivery or pickup."
|
||||
system_step1_text: "Search our diverse, independent shops for seasonal, sustainably produced products locally. Search by neighbourhood and food category, or whether you prefer delivery or pickup."
|
||||
system_step2: "2. Shop"
|
||||
system_step2_text: "Transform your transactions with affordable local food from diverse producers and hubs. Know the stories behind your food and the people who make it!"
|
||||
system_step2_text: "Transform your transactions with affordable local products from diverse producers, makers and hubs. Know the stories behind their products and the people who make them!"
|
||||
system_step3: "3. Pick-up / Delivery"
|
||||
system_step3_text: "Hang on for your delivery, or visit your producer or hub for a more personal connection with your food. Food shopping as diverse as nature intended it."
|
||||
system_step3_text: "Hang on for your delivery, or connect with the producer, maker or artisan directly. Shopping as diverse as nature intended it."
|
||||
cta_headline: "Shopping that makes the world a better place."
|
||||
cta_label: "I'm Ready"
|
||||
stats_headline: "We're creating a new food system."
|
||||
stats_producers: "food producers"
|
||||
stats_shops: "food shops"
|
||||
stats_shoppers: "food shoppers"
|
||||
stats_orders: "food orders"
|
||||
stats_producers: "producers"
|
||||
stats_shops: "shops"
|
||||
stats_shoppers: "shoppers"
|
||||
stats_orders: "orders"
|
||||
checkout_title: Checkout
|
||||
checkout_now: Checkout now
|
||||
checkout_order_ready: Order ready for
|
||||
@@ -1397,7 +1390,7 @@ en_CA:
|
||||
order_special_instructions: "Your notes:"
|
||||
order_pickup_time: Ready for collection
|
||||
order_pickup_instructions: Collection Instructions
|
||||
order_produce: Produce
|
||||
order_produce: Subtotal
|
||||
order_total_price: Total
|
||||
order_includes_tax: (includes tax)
|
||||
order_payment_paypal_successful: Your payment via PayPal has been processed successfully.
|
||||
@@ -1471,7 +1464,7 @@ en_CA:
|
||||
email_signup_welcome: "Welcome to %{sitename}!"
|
||||
email_signup_confirmed_email: "Thanks for confirming your email."
|
||||
email_signup_shop_html: "You can now log in at %{link}."
|
||||
email_signup_text: "Thanks for joining the network. If you are a customer, we look forward to introducing you to many fantastic farmers, wonderful food hubs and delicious food! If you are a producer or food enterprise, we are excited to have you as a part of the network."
|
||||
email_signup_text: "Thanks for joining the network. If you are a customer, we look forward to introducing you to many fantastic growers, artisans and makers, and wonderful hubs and marketplaces. If you are a grower, artisan or maker we are excited to have you as a part of the network."
|
||||
email_signup_help_html: "We welcome all your questions and feedback; you can use the <em>Send Feedback</em> button on the site or email us at %{email}"
|
||||
invite_email:
|
||||
greeting: "Hello!"
|
||||
@@ -1562,9 +1555,9 @@ en_CA:
|
||||
groups_signup_motivation2: It's why we get out of bed every day. We're a global non-profit, based on open source code. We play fair. You can always trust us.
|
||||
groups_signup_motivation3: We know you have big ideas, and we want to help. We'll share our knowledge, networks and resources. We know that isolation doesn't create change, so we'll partner with you.
|
||||
groups_signup_motivation4: We meet you where you are.
|
||||
groups_signup_motivation5: You might be an alliance of food hubs, producers, or distributors, and an industry body, or a local government.
|
||||
groups_signup_motivation6: Whatever your role in your local food movement, we're ready to help. However you come to wonder what Open Food Network would look like or is doing in your part of the world, let's start the conversation.
|
||||
groups_signup_motivation7: We make food movements make more sense.
|
||||
groups_signup_motivation5: You might be an alliance of food hubs or initiatives, a local flower marketplace, a network of makers or crafters, a food re-distribution network, an industry body, or a local government.
|
||||
groups_signup_motivation6: Whatever your role in supporting sustainable production and fair distribution we're ready to help. However you come to wonder what Open Food Network would look like or is doing in your part of the world, let's start the conversation.
|
||||
groups_signup_motivation7: We make local food and artisanal food movements make more sense.
|
||||
groups_signup_motivation8: You need to activate and enable your networks, we offer a platform for conversation and action. You need real engagement. We’ll help reach all the players, all the stakeholders, all the sectors.
|
||||
groups_signup_motivation9: You need resourcing. We’ll bring all our experience to bear. You need cooperation. We’ll better connect you to a global network of peers.
|
||||
groups_signup_pricing: Group Account
|
||||
@@ -1573,22 +1566,22 @@ en_CA:
|
||||
groups_signup_contact_text: "Get in touch to discover what OFN can do for you:"
|
||||
groups_signup_detail: "Here's the detail."
|
||||
login_invalid: "Invalid email or password"
|
||||
modal_hubs: "Food Hubs"
|
||||
modal_hubs_abstract: Our food hubs are the point of contact between you and the people who make your food!
|
||||
modal_hubs_content1: You can search for a convenient hub by location or name. Some hubs have multiple points where you can pick-up your purchases, and some will also provide delivery options. Each food hub is a sales point with independent business operations and logistics - so variations between hubs are to be expected.
|
||||
modal_hubs_content2: You can only shop at one food hub at a time.
|
||||
modal_hubs: "Hubs"
|
||||
modal_hubs_abstract: Our hubs are the point of contact between you and the people who grow & make local sustainable things!
|
||||
modal_hubs_content1: You can search for a convenient hub by location or name. Some hubs have multiple points where you can pick-up your purchases, and some will also provide delivery options. Each fhub is a sales/distribution point with independent operations and logistics - so variations between hubs are to be expected.
|
||||
modal_hubs_content2: You can only shop at one hub at a time.
|
||||
modal_groups: "Groups / Regions"
|
||||
modal_groups_content1: These are the organisations and relationships between hubs which make up the Open Food Network.
|
||||
modal_groups_content2: Some groups are clustered by location or council, others by non-geographic similarities.
|
||||
modal_how: "How it works"
|
||||
modal_how_shop: Shop the Open Food Network
|
||||
modal_how_shop_explained: Search for a food hub near you to start shopping! You can expand each food hub to see what kinds of goodies are available, and click through to start shopping. (You can only shop one food hub at a time.)
|
||||
modal_how_shop_explained: Search for a hub near you to start shopping! You can expand each hub to see what kinds of products are available, and click through to start. (You can only shop one hub at a time.)
|
||||
modal_how_pickup: Pick-ups, delivery and shipping costs
|
||||
modal_how_pickup_explained: Some food hubs deliver to your door, while others require you to pick-up your purchases. You can see which options are available on the homepage, and select which you'd like at the shopping and check-out pages. Delivery will cost more, and pricing differs from hub-to-hub. Each food hub is a sales point with independent business operations and logisitics - so variations between hubs are to be expected.
|
||||
modal_how_pickup_explained: Some hubs deliver to your door, while others require you to pick-up your purchases. You can see which options are available on the homepage, and select which you'd like at the shopping and check-out pages. Delivery will cost more, and pricing differs from hub-to-hub. Each hub is a sales point with independent operations and logisitics - so variations between hubs are to be expected.
|
||||
modal_how_more: Learn more
|
||||
modal_how_more_explained: "If you want to learn more about the Open Food Network, how it works, and get involved, check out:"
|
||||
modal_producers: "Producers"
|
||||
modal_producers_explained: "Our producers make all the delicious food you can shop for on the Open Food Network."
|
||||
modal_producers_explained: "Our producers make things you can shop for on the Open Food Network."
|
||||
producers_about: About us
|
||||
producers_buy: Shop for
|
||||
producers_contact: Contact
|
||||
@@ -1601,8 +1594,8 @@ en_CA:
|
||||
producers_title: Producers
|
||||
producers_headline: Find local producers
|
||||
producers_signup_title: Sign up as a producer
|
||||
producers_signup_headline: Food producers, empowered.
|
||||
producers_signup_motivation: Sell your food and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field.
|
||||
producers_signup_headline: Producers & makers, empowered.
|
||||
producers_signup_motivation: Sell your products and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field.
|
||||
producers_signup_send: Join now
|
||||
producers_signup_enterprise: Enterprise Accounts
|
||||
producers_signup_studies: Stories from our producers.
|
||||
@@ -1620,22 +1613,22 @@ en_CA:
|
||||
register_title: Register
|
||||
sell_title: "Register"
|
||||
sell_headline: "Get on the Open Food Network!"
|
||||
sell_motivation: "Showcase your beautiful food."
|
||||
sell_motivation: "Showcase your beautiful products."
|
||||
sell_producers: "Producers"
|
||||
sell_hubs: "Hubs"
|
||||
sell_groups: "Groups"
|
||||
sell_producers_detail: "Set up a profile for your business on the OFN in just minutes. At any time you can upgrade your profile to an online store and sell your products direct to customers."
|
||||
sell_hubs_detail: "Set up a profile for your food enterprise or organisation on the OFN. At any time you can upgrade your profile to a multi-producer shop."
|
||||
sell_groups_detail: "Set up a tailored directory of enterprises (producers and other food enterprises) for your region or for your organisation."
|
||||
sell_hubs_detail: "Set up a profile for your enterprise or organisation on the OFN. At any time you can upgrade your profile to a multi-producer shop."
|
||||
sell_groups_detail: "Set up a tailored directory of enterprises (producers and other local enterprises) for your region or for your organisation."
|
||||
sell_user_guide: "Find out more in our user guide."
|
||||
sell_listing_price: "Listing on the OFN is free. Opening and running a shop on OFN is free up to $500 of monthly sales. If you sell more we will invoice you for 2% of sales to a maximum of $150/month. For more detail on pricing visit the Software Platform section via the About link in the top menu."
|
||||
sell_embed: "We can also embed an OFN shop in your own customised website or build a customised local food network website for your region."
|
||||
sell_ask_services: "Ask us about OFN services."
|
||||
shops_title: Shops
|
||||
shops_headline: Shopping, transformed.
|
||||
shops_text: Food grows in cycles, farmers harvest in cycles, and we order food in cycles. If you find an order cycle closed, check back soon.
|
||||
shops_text: Products grow and are made in cycles so we order these products in cycles. If you find an order cycle closed, check back soon.
|
||||
shops_signup_title: Sign up as a hub
|
||||
shops_signup_headline: Food hubs, unlimited.
|
||||
shops_signup_headline: Hubs & Markeplaces, unlimited.
|
||||
shops_signup_motivation: Whatever your model, we support you. However you change, we're with you. We're non-profit, independent, and open-sourced. We're the software partners you've dreamed of.
|
||||
shops_signup_action: Join now
|
||||
shops_signup_pricing: Enterprise Accounts
|
||||
@@ -1651,7 +1644,7 @@ en_CA:
|
||||
orders_edit_continue: Continue shopping
|
||||
orders_edit_checkout: Checkout
|
||||
orders_form_empty_cart: "Empty cart"
|
||||
orders_form_subtotal: Produce subtotal
|
||||
orders_form_subtotal: Subtotal
|
||||
orders_form_admin: Admin & Handling
|
||||
orders_form_total: Total
|
||||
orders_oc_expired_headline: Orders have closed for this order cycle
|
||||
@@ -1794,8 +1787,8 @@ en_CA:
|
||||
yes_producer: "Yes, I'm a producer"
|
||||
no_producer: "No, I'm not a producer"
|
||||
producer_field_error: "Please choose one. Are you are producer?"
|
||||
yes_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it."
|
||||
no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other."
|
||||
yes_producer_help: "Producers make things. You're a producer if you make it, grow it, raise it, brew it, bake it, ferment it, milk it, mould it or design it."
|
||||
no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes the things they produce or make. You might be a hub, coop, buying group, retailer, wholesaler or other."
|
||||
create_profile: "Create Profile"
|
||||
about:
|
||||
title: "About"
|
||||
@@ -2092,14 +2085,14 @@ en_CA:
|
||||
report_header_ship_street_2: Ship Street 2
|
||||
report_header_ship_city: Ship City
|
||||
report_header_ship_postcode: Ship Postal Code
|
||||
report_header_ship_state: Ship State
|
||||
report_header_ship_state: Ship Province
|
||||
report_header_billing_street: Billing Street
|
||||
report_header_billing_street_2: Billing Street 2
|
||||
report_header_billing_street_3: Billing Street 3
|
||||
report_header_billing_street_4: Billing Street 4
|
||||
report_header_billing_city: Billing City
|
||||
report_header_billing_postcode: Billing Postal Code
|
||||
report_header_billing_state: Billing State
|
||||
report_header_billing_state: Billing Province
|
||||
report_header_incoming_transport: Incoming Transport
|
||||
report_header_special_instructions: Special Instructions
|
||||
report_header_order_number: Order number
|
||||
@@ -2192,7 +2185,7 @@ en_CA:
|
||||
report_header_not_confirmed: Not Confirmed
|
||||
report_header_gst_on_income: Sales Tax on Income
|
||||
report_header_gst_free_income: Tax Free Income
|
||||
report_header_total_untaxable_produce: Total untaxable produce (no tax)
|
||||
report_header_total_untaxable_produce: Total untaxable products (no tax)
|
||||
report_header_total_taxable_produce: Total taxable produce (tax inclusive)
|
||||
report_header_total_untaxable_fees: Total untaxable fees (no tax)
|
||||
report_header_total_taxable_fees: Total taxable fees (tax inclusive)
|
||||
@@ -2344,16 +2337,16 @@ en_CA:
|
||||
People can find and contact you on the Open Food Network. Your enterprise
|
||||
will be visible on the map, and will be searchable in listings.
|
||||
hub_profile_text2: >
|
||||
Having a profile, and making connections within your local food system
|
||||
through the Open Food Network will always be free.
|
||||
Having a profile, and making connections within your local networks
|
||||
and communities through the Open Food Network will always be free.
|
||||
hub_shop: Hub Shop
|
||||
hub_shop_text1: >
|
||||
Your enterprise is the backbone of your local food system. You aggregate
|
||||
produce from other enterprises and can sell it through your shop on
|
||||
Your enterprise is the backbone of your local community. You aggregate
|
||||
products from other enterprises and sell them through your shop on
|
||||
the Open Food Network.
|
||||
hub_shop_text2: >
|
||||
Hubs can take many forms, whether they be a food co-op, a buying group,
|
||||
a veggie-box program, or a local grocery store.
|
||||
Hubs can take many forms - a local co-op, a buying group, a food-box
|
||||
program, or an on-line markeplace for crafts or flowers....
|
||||
hub_shop_text3: >
|
||||
If you also want to sell your own products, you will need to switch
|
||||
this enterprise to be a producer.
|
||||
@@ -2370,9 +2363,9 @@ en_CA:
|
||||
A profile makes you visible and contactable to others and is a way to
|
||||
share your story.
|
||||
profile_only_text2: >
|
||||
If you prefer to focus on producing food, and want to leave the work
|
||||
of selling it to someone else, you won't require a shop on the Open
|
||||
Food Network.
|
||||
If you prefer to focus on producing, designing and making, and want
|
||||
to leave the work of selling it to someone else, you won't require a
|
||||
shop on the Open Food Network.
|
||||
profile_only_text3: >
|
||||
Add your products to Open Food Network, allowing hubs to stock your
|
||||
products in their stores.
|
||||
@@ -2381,51 +2374,56 @@ en_CA:
|
||||
Sell your products directly to customers through your very own Open
|
||||
Food Network shopfront.
|
||||
producer_shop_text2: >
|
||||
A Producer Shop is for your produce only, if you want to sell produce
|
||||
grown/produced off site, please select 'Producer Hub'.
|
||||
A Producer Shop is for your products only, if you want to sell products
|
||||
grown/made/created off site, please select 'Producer Hub'.
|
||||
producer_hub: Producer Hub
|
||||
producer_hub_text1: >
|
||||
Your enterprise is the backbone of your local food system. You can sell
|
||||
your own produce as well as produce aggregated from other enterprises
|
||||
Your enterprise is the backbone of your local community. You can sell
|
||||
your own products as well as products aggregated from other enterprises
|
||||
through your shopfront on the Open Food Network.
|
||||
producer_hub_text2: >
|
||||
Producer Hubs can take many forms, whether they be a CSA, a veggie-box
|
||||
program, or a food co-op with a rooftop garden.
|
||||
Producer Hubs can take many forms, whether they be a CSA, a food box
|
||||
program, a co-op, cut flower marketplace.....
|
||||
producer_hub_text3: >
|
||||
The Open Food Network aims to support as many hub models as possible,
|
||||
so no matter your situation, we want to provide the tools you need to
|
||||
run your organisation or local food business.
|
||||
get_listing: Get a listing
|
||||
always_free: ALWAYS FREE
|
||||
sell_produce_others: Sell produce from others
|
||||
sell_own_produce: Sell your own produce
|
||||
sell_both: Sell produce from self and others
|
||||
sell_produce_others: Sell products from others
|
||||
sell_own_produce: Sell your own products
|
||||
sell_both: Sell products from self and others
|
||||
enterprise_producer:
|
||||
producer: Producer
|
||||
producer_text1: >
|
||||
Producers make yummy things to eat or drink. You're a producer if you
|
||||
grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
|
||||
Producers make things. You're a producer if you make it, grow it, raise
|
||||
it, brew it, bake it, ferment it, milk it, mould it, design it.....
|
||||
producer_text2: >
|
||||
Producers can also perform other functions, such as aggregating food
|
||||
from other enterprises and selling it through a shop on the Open Food
|
||||
Producers can also perform other functions, such as aggregating products
|
||||
from other enterprises and selling them through a shop on the Open Food
|
||||
Network.
|
||||
non_producer: Non-producer
|
||||
non_producer_text1: >
|
||||
Non-producers do not produce any food themselves, meaning that they
|
||||
Non-producers do not produce any products themselves, meaning that they
|
||||
cannot create their own products for sale through the Open Food Network.
|
||||
non_producer_text2: >
|
||||
Instead, non-producers specialise in linking producers to the end eater,
|
||||
whether it be by aggregating, grading, packing, selling or delivering
|
||||
food.
|
||||
producer_desc: Producers of food
|
||||
Instead, non-producers specialise in linking producers and their products
|
||||
to the end buyer/user, by aggregating, packing, selling or distributing.
|
||||
producer_desc: 'Producers '
|
||||
producer_example: eg. GROWERS, BAKERS, BREWERS, MAKERS
|
||||
non_producer_desc: All other food enterprises
|
||||
non_producer_example: eg. Grocery stores, Food co-ops, Buying groups
|
||||
non_producer_desc: All other enterprises
|
||||
non_producer_example: eg. Grocery stores, Co-ops, Buying groups, Markets
|
||||
enterprise_status:
|
||||
status_title: "%{name} is set up and ready to go!"
|
||||
severity: Severity
|
||||
description: Description
|
||||
resolve: Resolve
|
||||
exchange_products:
|
||||
load_more_products: "Load More Products"
|
||||
load_all_products: "Load All Products"
|
||||
select_all_products: "Select All %{total_number_of_products}Products"
|
||||
products_loaded: "%{num_of_products_loaded}of %{total_number_of_products} Products Loaded"
|
||||
loading_products: "Loading Products"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2508,6 +2506,7 @@ en_CA:
|
||||
customer_placeholder: "customer@example.org"
|
||||
valid_email_error: "Please enter a valid email address"
|
||||
subscriptions:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
@@ -2687,7 +2686,7 @@ en_CA:
|
||||
city: "City"
|
||||
zip: "Postal Code"
|
||||
country: "Country"
|
||||
state: "State"
|
||||
state: "Province"
|
||||
phone: "Phone"
|
||||
update: "Update"
|
||||
use_billing_address: "Use Billing Address"
|
||||
@@ -2708,7 +2707,6 @@ en_CA:
|
||||
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
|
||||
allow_ssl_in_production: "Allow SSL to be used in production mode"
|
||||
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
|
||||
check_for_spree_alerts: "Check for Spree alerts"
|
||||
currency_decimal_mark: "Currency decimal mark"
|
||||
currency_settings: "Currency Settings"
|
||||
currency_symbol_position: Put "currency symbol before or after dollar amount?"
|
||||
@@ -2875,19 +2873,35 @@ en_CA:
|
||||
presentation: "Presentation"
|
||||
return_authorizations:
|
||||
index:
|
||||
new_return_authorization: "New Return Authorization"
|
||||
return_authorizations: "Return Authoriations"
|
||||
back_to_orders_list: "Back to Orders List"
|
||||
rma_number: "RMA Number"
|
||||
status: "Status"
|
||||
amount: "Amount"
|
||||
cannot_create_returns: "Cannot create returns as this order has no shipped units"
|
||||
continue: "Continue"
|
||||
new:
|
||||
new_return_authorization: "New Return Authorization"
|
||||
back_to_return_authorizations_list: "Back to Return Authorization List"
|
||||
continue: "Continue"
|
||||
edit:
|
||||
receive: "receive"
|
||||
are_you_sure: "Are you sure?"
|
||||
return_authorization: "Return Authorization"
|
||||
form:
|
||||
product: "Product"
|
||||
quantity_shipped: "Quantity Shipped"
|
||||
quantity_returned: "Quantity Returned"
|
||||
return_quantity: "Return Quantity"
|
||||
amount: "Amount"
|
||||
rma_value: "RMA Value"
|
||||
reason: "Reason"
|
||||
stock_location: "Stock Location"
|
||||
states:
|
||||
authorized: "Authorized"
|
||||
received: "Received"
|
||||
canceled: "Canceled"
|
||||
orders:
|
||||
index:
|
||||
listing_orders: "Listing Orders"
|
||||
@@ -2895,6 +2909,7 @@ en_CA:
|
||||
capture: "Capture"
|
||||
ship: "Ship"
|
||||
edit: "Edit"
|
||||
order_not_updated: "The order could not be updated"
|
||||
note: "Note"
|
||||
first: "First"
|
||||
last: "Last"
|
||||
|
||||
@@ -2,6 +2,8 @@ en_DE:
|
||||
language_name: "English"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Fee Type
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
@@ -841,7 +843,6 @@ en_DE:
|
||||
cancel: "Cancel"
|
||||
choose_products_from: "Choose Products From:"
|
||||
incoming:
|
||||
previous: "Previous"
|
||||
save: "Save"
|
||||
next: "Next"
|
||||
cancel: "Cancel"
|
||||
@@ -972,9 +973,6 @@ en_DE:
|
||||
name: Customers
|
||||
products_and_inventory:
|
||||
name: Products & Inventory
|
||||
sales_total:
|
||||
name: Sales Total
|
||||
description: Sales Total For All Orders
|
||||
users_and_enterprises:
|
||||
name: Users & Enterprises
|
||||
description: Enterprise Ownership & Status
|
||||
@@ -1113,15 +1111,6 @@ en_DE:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Home"
|
||||
footer_global_news: "News"
|
||||
footer_global_about: "About"
|
||||
footer_global_contact: "Contact"
|
||||
footer_sites_headline: "OFN Sites"
|
||||
footer_sites_developer: "Developer"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "User Guide"
|
||||
footer_secure: "Secure and trusted."
|
||||
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
|
||||
footer_contact_headline: "Keep in touch"
|
||||
@@ -2693,7 +2682,6 @@ en_DE:
|
||||
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
|
||||
allow_ssl_in_production: "Allow SSL to be used in production mode"
|
||||
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
|
||||
check_for_spree_alerts: "Check for Spree alerts"
|
||||
currency_decimal_mark: "Currency decimal mark"
|
||||
currency_settings: "Currency Settings"
|
||||
currency_symbol_position: Put "currency symbol before or after dollar amount?"
|
||||
|
||||
@@ -2,6 +2,8 @@ en_FR:
|
||||
language_name: "English"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Fee Type
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
@@ -48,6 +50,8 @@ en_FR:
|
||||
shipping_method_ids: "Shipping Methods"
|
||||
payment_method_ids: "Payment Methods"
|
||||
errors:
|
||||
messages:
|
||||
inclusion: "is not included in the list"
|
||||
models:
|
||||
subscription_validator:
|
||||
attributes:
|
||||
@@ -848,7 +852,6 @@ en_FR:
|
||||
save_and_back_to_list: "Save and Back to List"
|
||||
choose_products_from: "Choose Products From:"
|
||||
incoming:
|
||||
previous: "Previous"
|
||||
save: "Save"
|
||||
save_and_next: "Save and Next"
|
||||
next: "Next"
|
||||
@@ -987,9 +990,6 @@ en_FR:
|
||||
name: Customers
|
||||
products_and_inventory:
|
||||
name: Products & Inventory
|
||||
sales_total:
|
||||
name: Sales Total
|
||||
description: Sales Total For All Orders
|
||||
users_and_enterprises:
|
||||
name: Users & Enterprises
|
||||
description: Enterprise Ownership & Status
|
||||
@@ -1104,6 +1104,8 @@ en_FR:
|
||||
destroy_attachment_does_not_exist: "Logo does not exist"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "Promo image does not exist"
|
||||
orders:
|
||||
failed_to_update: "Failed to update order"
|
||||
checkout:
|
||||
already_ordered:
|
||||
cart: "cart"
|
||||
@@ -1128,15 +1130,6 @@ en_FR:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Home"
|
||||
footer_global_news: "News"
|
||||
footer_global_about: "About"
|
||||
footer_global_contact: "Contact"
|
||||
footer_sites_headline: "OFN Sites"
|
||||
footer_sites_developer: "Developer"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "User Guide"
|
||||
footer_secure: "Secure and trusted."
|
||||
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
|
||||
footer_contact_headline: "Keep in touch"
|
||||
@@ -2426,6 +2419,12 @@ en_FR:
|
||||
severity: Severity
|
||||
description: Description
|
||||
resolve: Resolve
|
||||
exchange_products:
|
||||
load_more_products: "Load More Products"
|
||||
load_all_products: "Load All Products"
|
||||
select_all_products: "Select All %{total_number_of_products} Products"
|
||||
products_loaded: "%{num_of_products_loaded}of %{total_number_of_products} Products Loaded"
|
||||
loading_products: "Loading Products"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2508,6 +2507,7 @@ en_FR:
|
||||
customer_placeholder: "customer@example.org"
|
||||
valid_email_error: "Please enter a valid email address"
|
||||
subscriptions:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
@@ -2708,7 +2708,6 @@ en_FR:
|
||||
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
|
||||
allow_ssl_in_production: "Allow SSL to be used in production mode"
|
||||
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
|
||||
check_for_spree_alerts: "Check for Spree alerts"
|
||||
currency_decimal_mark: "Currency decimal mark"
|
||||
currency_settings: "Currency Settings"
|
||||
currency_symbol_position: Put "currency symbol before or after dollar amount?"
|
||||
@@ -2911,6 +2910,7 @@ en_FR:
|
||||
capture: "Capture"
|
||||
ship: "Ship"
|
||||
edit: "Edit"
|
||||
order_not_updated: "The order could not be updated"
|
||||
note: "Note"
|
||||
first: "First"
|
||||
last: "Last"
|
||||
|
||||
@@ -2,6 +2,8 @@ en_GB:
|
||||
language_name: "English"
|
||||
activerecord:
|
||||
attributes:
|
||||
enterprise_fee:
|
||||
fee_type: Fee Type
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
@@ -48,6 +50,8 @@ en_GB:
|
||||
shipping_method_ids: "Shipping Methods"
|
||||
payment_method_ids: "Payment Methods"
|
||||
errors:
|
||||
messages:
|
||||
inclusion: "is not included in the list"
|
||||
models:
|
||||
subscription_validator:
|
||||
attributes:
|
||||
@@ -848,7 +852,6 @@ en_GB:
|
||||
save_and_back_to_list: "Save and Back to List"
|
||||
choose_products_from: "Choose Products From:"
|
||||
incoming:
|
||||
previous: "Previous"
|
||||
save: "Save"
|
||||
save_and_next: "Save and Next"
|
||||
next: "Next"
|
||||
@@ -987,9 +990,6 @@ en_GB:
|
||||
name: Customers
|
||||
products_and_inventory:
|
||||
name: Products & Inventory
|
||||
sales_total:
|
||||
name: Sales Total
|
||||
description: Sales Total For All Orders
|
||||
users_and_enterprises:
|
||||
name: Users & Enterprises
|
||||
description: Enterprise Ownership & Status
|
||||
@@ -1128,15 +1128,6 @@ en_GB:
|
||||
selling_on_ofn: "Interested in selling through the Open Food Network?"
|
||||
register: "Register here"
|
||||
footer:
|
||||
footer_global_headline: "OFN Global"
|
||||
footer_global_home: "Home"
|
||||
footer_global_news: "News"
|
||||
footer_global_about: "About"
|
||||
footer_global_contact: "Contact"
|
||||
footer_sites_headline: "OFN Sites"
|
||||
footer_sites_developer: "Developer"
|
||||
footer_sites_community: "Community"
|
||||
footer_sites_userguide: "User Guide"
|
||||
footer_secure: "Secure and trusted."
|
||||
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
|
||||
footer_contact_headline: "Keep in touch"
|
||||
@@ -1512,7 +1503,7 @@ en_GB:
|
||||
hubs_filter_type: "Type"
|
||||
hubs_filter_delivery: "Delivery"
|
||||
hubs_filter_property: "Property"
|
||||
hubs_matches: "Did you mean?"
|
||||
hubs_matches: "Showing results for"
|
||||
hubs_intro: Shop in your local area
|
||||
hubs_distance: Closest to
|
||||
hubs_distance_filter: "Show me shops near %{location}"
|
||||
@@ -2432,6 +2423,12 @@ en_GB:
|
||||
severity: Severity
|
||||
description: Description
|
||||
resolve: Resolve
|
||||
exchange_products:
|
||||
load_more_products: "Load More Products"
|
||||
load_all_products: "Load All Products"
|
||||
select_all_products: "Select All %{total_number_of_products} Products"
|
||||
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
|
||||
loading_products: "Loading Products"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2514,6 +2511,7 @@ en_GB:
|
||||
customer_placeholder: "customer@example.org"
|
||||
valid_email_error: "Please enter a valid email address"
|
||||
subscriptions:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
@@ -2714,7 +2712,6 @@ en_GB:
|
||||
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
|
||||
allow_ssl_in_production: "Allow SSL to be used in production mode"
|
||||
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
|
||||
check_for_spree_alerts: "Check for Spree alerts"
|
||||
currency_decimal_mark: "Currency decimal mark"
|
||||
currency_settings: "Currency Settings"
|
||||
currency_symbol_position: Put "currency symbol before or after pound amount?"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user