mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-14 18:56:49 +00:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d280bf0d4d | ||
|
|
03c91dfac1 | ||
|
|
60e12063cd | ||
|
|
e5b57af315 | ||
|
|
a396a7f0af | ||
|
|
d084789c56 | ||
|
|
dafac32e70 | ||
|
|
6ca39f3aa5 | ||
|
|
234a9ef1b4 | ||
|
|
24a1327805 | ||
|
|
33d77d57f4 | ||
|
|
0571b657aa | ||
|
|
e4958baddc | ||
|
|
c985747297 | ||
|
|
f5ffdfc258 | ||
|
|
a3a61967a8 | ||
|
|
1bdeda4a21 | ||
|
|
49ba83da6d | ||
|
|
19d1497c4b | ||
|
|
0c4f22f847 | ||
|
|
1803ea3c38 | ||
|
|
93fda02e43 | ||
|
|
77958f9afe | ||
|
|
82e402f31a | ||
|
|
35aeb98d45 | ||
|
|
d99cba3b6e | ||
|
|
4c6fd96bcc | ||
|
|
ff088c6203 | ||
|
|
a1cb6928db | ||
|
|
40a5b60dcb | ||
|
|
2711736004 | ||
|
|
18c165e893 | ||
|
|
0aaa04295b | ||
|
|
7639e9a38d | ||
|
|
d783bd771f | ||
|
|
9dd9d14107 | ||
|
|
e942266dd7 | ||
|
|
c8f78904d6 | ||
|
|
a982fd1e2b | ||
|
|
7e8b2f6be5 | ||
|
|
921c7bbc3a | ||
|
|
eaff6b0c68 | ||
|
|
e1ab424481 | ||
|
|
e59c9720fc | ||
|
|
b25f0007f0 | ||
|
|
65c5cdd52f | ||
|
|
a2873ea553 | ||
|
|
3a593ff255 | ||
|
|
92e1193ffb | ||
|
|
016968dcb9 | ||
|
|
9d8608f210 | ||
|
|
323ca906bc | ||
|
|
c43b34e0fa | ||
|
|
bc7f0e0962 | ||
|
|
cf4f7c562a | ||
|
|
4c7bd4d6a8 | ||
|
|
523b266308 | ||
|
|
212413c8b3 | ||
|
|
b248dc598e | ||
|
|
e7b74b99ba | ||
|
|
89d2750fc4 | ||
|
|
7100111f93 | ||
|
|
3dcb66014e | ||
|
|
06971b7198 | ||
|
|
56f9adc5b7 | ||
|
|
38374a9835 | ||
|
|
8d6a8ee214 | ||
|
|
fec653186a | ||
|
|
ebe7456b66 | ||
|
|
8187669a25 | ||
|
|
a6aa0df53b | ||
|
|
116695b1d9 | ||
|
|
387ac40dc9 | ||
|
|
66320b5055 | ||
|
|
858d2cc6c2 | ||
|
|
43280da187 | ||
|
|
e1eface5f8 | ||
|
|
5cd14253d0 | ||
|
|
be691df7ac | ||
|
|
7783b28ca2 | ||
|
|
6d51856821 | ||
|
|
890704b75c | ||
|
|
922484b2e7 | ||
|
|
3e7288648b | ||
|
|
f0f537ff8f | ||
|
|
b7f920c4b6 | ||
|
|
e5c9468d09 | ||
|
|
8aed173127 | ||
|
|
61ecca7257 | ||
|
|
7eba657b2f | ||
|
|
784de340d1 | ||
|
|
9191628f29 | ||
|
|
88410b1efd | ||
|
|
afea032361 | ||
|
|
3decb4056c | ||
|
|
8e9b08feca | ||
|
|
694995ea5d | ||
|
|
22de7252d0 | ||
|
|
2acf8e5125 | ||
|
|
e1f61e645d | ||
|
|
687d827ceb | ||
|
|
2885e38113 | ||
|
|
9f3ca58b55 | ||
|
|
ffe3228848 | ||
|
|
834231eb8f | ||
|
|
68f5aabd3f | ||
|
|
7e7ea92833 | ||
|
|
ebf22ceb19 | ||
|
|
c38c7c35bc | ||
|
|
2663f74767 | ||
|
|
b41de52012 | ||
|
|
214eb43122 | ||
|
|
01fc4e0513 | ||
|
|
6ce50a5fa5 | ||
|
|
4fbd2cfa52 | ||
|
|
383b28e170 | ||
|
|
bf55a15f81 | ||
|
|
eb7e6dc5b8 | ||
|
|
139ecfe604 | ||
|
|
43a6798db2 | ||
|
|
06d6579486 | ||
|
|
76df526002 | ||
|
|
06569ea24c | ||
|
|
25431f851b | ||
|
|
bab2420bb3 | ||
|
|
0b2acb3a76 | ||
|
|
27db9e604f | ||
|
|
c4e58ebb9e | ||
|
|
9a0ee254af | ||
|
|
5ce3e1e0d2 | ||
|
|
4b345d928c | ||
|
|
52b1e6c71a | ||
|
|
140e0b9cb1 | ||
|
|
b3f05d1a98 | ||
|
|
9644b145cc | ||
|
|
6f644936b0 | ||
|
|
b86759d7a7 | ||
|
|
9d1e3f0318 | ||
|
|
67adf3c801 | ||
|
|
6e78ae762a | ||
|
|
9535c5647f | ||
|
|
6f8bb793e1 | ||
|
|
2476050f29 | ||
|
|
1cce106977 | ||
|
|
98b55287f1 | ||
|
|
48a75c956f | ||
|
|
bec73adc89 | ||
|
|
23ec66e338 |
@@ -39,7 +39,6 @@ Layout/LineLength:
|
||||
- app/controllers/admin/variant_overrides_controller.rb
|
||||
- app/controllers/api/enterprise_attachment_controller.rb
|
||||
- app/controllers/api/product_images_controller.rb
|
||||
- app/controllers/checkout_controller.rb
|
||||
- app/controllers/spree/admin/adjustments_controller_decorator.rb
|
||||
- app/controllers/spree/admin/orders_controller_decorator.rb
|
||||
- app/controllers/spree/credit_cards_controller.rb
|
||||
@@ -354,7 +353,6 @@ Metrics/AbcSize:
|
||||
- app/controllers/api/variants_controller.rb
|
||||
- app/controllers/base_controller.rb
|
||||
- app/controllers/cart_controller.rb
|
||||
- app/controllers/checkout_controller.rb
|
||||
- app/controllers/discourse_sso_controller.rb
|
||||
- app/controllers/enterprises_controller.rb
|
||||
- app/controllers/spree/admin/adjustments_controller_decorator.rb
|
||||
@@ -371,7 +369,6 @@ Metrics/AbcSize:
|
||||
- app/controllers/spree/admin/taxons_controller.rb
|
||||
- app/controllers/spree/admin/users_controller.rb
|
||||
- app/controllers/spree/admin/variants_controller.rb
|
||||
- app/controllers/spree/checkout_controller.rb
|
||||
- app/controllers/spree/credit_cards_controller.rb
|
||||
- app/controllers/spree/orders_controller.rb
|
||||
- app/controllers/spree/user_passwords_controller.rb
|
||||
@@ -493,7 +490,6 @@ Metrics/CyclomaticComplexity:
|
||||
Exclude:
|
||||
- app/controllers/admin/enterprise_fees_controller.rb
|
||||
- app/controllers/admin/enterprises_controller.rb
|
||||
- app/controllers/checkout_controller.rb
|
||||
- app/controllers/spree/admin/taxons_controller.rb
|
||||
- app/controllers/spree/orders_controller.rb
|
||||
- app/helpers/checkout_helper.rb
|
||||
@@ -523,7 +519,6 @@ Metrics/PerceivedComplexity:
|
||||
Exclude:
|
||||
- app/controllers/admin/enterprises_controller.rb
|
||||
- app/controllers/api/variants_controller.rb
|
||||
- app/controllers/checkout_controller.rb
|
||||
- app/controllers/spree/admin/taxons_controller.rb
|
||||
- app/controllers/spree/orders_controller.rb
|
||||
- app/helpers/checkout_helper.rb
|
||||
@@ -560,7 +555,6 @@ Metrics/MethodLength:
|
||||
- app/controllers/api/variants_controller.rb
|
||||
- app/controllers/base_controller.rb
|
||||
- app/controllers/cart_controller.rb
|
||||
- app/controllers/checkout_controller.rb
|
||||
- app/controllers/shop_controller.rb
|
||||
- app/controllers/spree/admin/image_settings_controller.rb
|
||||
- app/controllers/spree/admin/orders/customer_details_controller.rb
|
||||
|
||||
33
Gemfile
33
Gemfile
@@ -3,7 +3,7 @@ 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.1'
|
||||
gem 'i18n-js', '~> 3.6.0'
|
||||
gem 'rails', '~> 3.2.22'
|
||||
gem 'rails-i18n', '~> 3.0.0'
|
||||
gem 'rails_safe_tasks', '~> 1.0'
|
||||
@@ -19,9 +19,8 @@ gem 'activerecord-postgresql-adapter'
|
||||
gem 'pg', '~> 0.21.0'
|
||||
|
||||
# OFN-maintained and patched version of Spree v2.0.4. See
|
||||
# https://github.com/openfoodfoundation/openfoodnetwork/wiki/Spree-2.0-upgrade
|
||||
# https://github.com/openfoodfoundation/openfoodnetwork/wiki/Tech-Doc:-OFN's-Spree-fork%F0%9F%8D%B4
|
||||
# for details.
|
||||
gem 'spree_backend', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
|
||||
gem 'spree_core', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
|
||||
|
||||
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
|
||||
@@ -39,7 +38,7 @@ gem 'activemerchant', '~> 1.78'
|
||||
gem 'devise', '~> 2.2.5'
|
||||
gem 'devise-encryptable', '0.2.0'
|
||||
gem 'jwt', '~> 2.2'
|
||||
gem 'oauth2', '~> 1.4.2' # Used for Stripe Connect
|
||||
gem 'oauth2', '~> 1.4.4' # Used for Stripe Connect
|
||||
|
||||
gem 'daemons'
|
||||
gem 'delayed_job_active_record'
|
||||
@@ -62,7 +61,7 @@ gem 'haml'
|
||||
gem 'rabl'
|
||||
gem 'redcarpet'
|
||||
gem 'sass', "~> 3.3"
|
||||
gem 'sass-rails', '~> 3.2.3', groups: [:default, :assets]
|
||||
gem 'sass-rails', '~> 3.2.3'
|
||||
gem 'truncate_html'
|
||||
gem 'unicorn'
|
||||
|
||||
@@ -93,33 +92,31 @@ gem 'wkhtmltopdf-binary'
|
||||
|
||||
gem 'foreigner'
|
||||
gem 'immigrant'
|
||||
gem 'roo', '~> 2.8.2'
|
||||
gem 'roo', '~> 2.8.3'
|
||||
|
||||
gem 'whenever', require: false
|
||||
|
||||
gem 'test-unit', '~> 3.3'
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
group :assets do
|
||||
gem 'coffee-rails', '~> 3.2.1'
|
||||
gem 'compass-rails'
|
||||
gem 'coffee-rails', '~> 3.2.1'
|
||||
gem 'compass-rails'
|
||||
|
||||
gem 'mini_racer', '0.2.9'
|
||||
gem 'mini_racer', '0.2.9'
|
||||
|
||||
gem 'uglifier', '>= 1.0.3'
|
||||
gem 'uglifier', '>= 1.0.3'
|
||||
|
||||
gem 'angular-rails-templates', '~> 0.3.0'
|
||||
gem 'foundation-icons-sass-rails'
|
||||
gem 'momentjs-rails'
|
||||
gem 'turbo-sprockets-rails3'
|
||||
end
|
||||
gem 'angular-rails-templates', '~> 0.3.0'
|
||||
gem 'foundation-icons-sass-rails'
|
||||
gem 'momentjs-rails'
|
||||
gem 'turbo-sprockets-rails3'
|
||||
|
||||
gem "foundation-rails"
|
||||
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
|
||||
|
||||
gem 'jquery-migrate-rails'
|
||||
gem 'jquery-rails', '3.0.4'
|
||||
gem 'jquery-ui-rails', '~> 4.0.0'
|
||||
gem 'select2-rails', '~> 3.4.7'
|
||||
|
||||
gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz', ref: '60da2ae4c44cbb4c8d602f59fb5fff8d0f21db3c'
|
||||
|
||||
|
||||
49
Gemfile.lock
49
Gemfile.lock
@@ -34,18 +34,6 @@ GIT
|
||||
revision: 8a8585a43cd04d1a50dc65227f337a91b18d66d5
|
||||
branch: 2-0-4-stable
|
||||
specs:
|
||||
spree_api (2.0.4)
|
||||
rabl (= 0.8.4)
|
||||
spree_core (= 2.0.4)
|
||||
versioncake (= 1.0.0)
|
||||
spree_backend (2.0.4)
|
||||
deface (>= 0.9.0)
|
||||
jquery-rails (~> 3.0.0)
|
||||
jquery-ui-rails (~> 4.0.0)
|
||||
rails (~> 3.2.8)
|
||||
select2-rails (~> 3.4.7)
|
||||
spree_api (= 2.0.4)
|
||||
spree_core (= 2.0.4)
|
||||
spree_core (2.0.4)
|
||||
activemerchant (~> 1.34)
|
||||
acts_as_list (= 0.2.0)
|
||||
@@ -261,7 +249,7 @@ GEM
|
||||
factory_bot_rails (4.10.0)
|
||||
factory_bot (~> 4.10.0)
|
||||
railties (>= 3.0.0)
|
||||
faraday (0.17.1)
|
||||
faraday (1.0.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffaker (1.22.1)
|
||||
ffi (1.11.3)
|
||||
@@ -437,7 +425,7 @@ GEM
|
||||
httparty (0.16.2)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.6.11)
|
||||
i18n-js (3.5.1)
|
||||
i18n-js (3.6.0)
|
||||
i18n (>= 0.6.6)
|
||||
immigrant (0.3.6)
|
||||
activerecord (>= 3.0)
|
||||
@@ -458,7 +446,7 @@ GEM
|
||||
kaminari (0.14.1)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
kgio (2.11.2)
|
||||
kgio (2.11.3)
|
||||
knapsack (1.18.0)
|
||||
rake
|
||||
launchy (2.4.3)
|
||||
@@ -486,7 +474,7 @@ GEM
|
||||
newrelic_rpm (3.18.1.330)
|
||||
nokogiri (1.6.8.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
oauth2 (1.4.2)
|
||||
oauth2 (1.4.4)
|
||||
faraday (>= 0.8, < 2.0)
|
||||
jwt (>= 1.0, < 3.0)
|
||||
multi_json (~> 1.3)
|
||||
@@ -559,7 +547,7 @@ GEM
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.19.0)
|
||||
raindrops (0.19.1)
|
||||
rake (13.0.0)
|
||||
ransack (0.7.2)
|
||||
actionpack (~> 3.0)
|
||||
@@ -578,15 +566,16 @@ GEM
|
||||
redcarpet (3.5.0)
|
||||
request_store (1.4.1)
|
||||
rack (>= 1.4)
|
||||
rexml (3.2.4)
|
||||
roadie (3.4.0)
|
||||
css_parser (~> 1.4)
|
||||
nokogiri (~> 1.5)
|
||||
roadie-rails (1.3.0)
|
||||
railties (>= 3.0, < 5.3)
|
||||
roadie (~> 3.1)
|
||||
roo (2.8.2)
|
||||
roo (2.8.3)
|
||||
nokogiri (~> 1)
|
||||
rubyzip (>= 1.2.1, < 2.0.0)
|
||||
rubyzip (>= 1.3.0, < 3.0.0)
|
||||
rspec (3.9.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
@@ -610,11 +599,12 @@ GEM
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.9.0)
|
||||
rubocop (0.79.0)
|
||||
rubocop (0.80.0)
|
||||
jaro_winkler (~> 1.5.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.0.1)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
rexml
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 1.7)
|
||||
rubocop-rails (2.4.2)
|
||||
@@ -658,7 +648,7 @@ GEM
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.5.1)
|
||||
stripe (5.11.0)
|
||||
stripe (5.15.0)
|
||||
test-unit (3.3.5)
|
||||
power_assert
|
||||
thor (0.20.3)
|
||||
@@ -676,24 +666,20 @@ GEM
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.6.1)
|
||||
unicorn (5.5.2)
|
||||
unicorn (5.5.3)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
unicorn-rails (2.2.1)
|
||||
rack
|
||||
unicorn
|
||||
uuidtools (2.1.5)
|
||||
versioncake (1.0.0)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
warden (1.2.7)
|
||||
rack (>= 1.0)
|
||||
webdrivers (4.2.0)
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (>= 1.3.0)
|
||||
selenium-webdriver (>= 3.0, < 4.0)
|
||||
webmock (3.8.0)
|
||||
webmock (3.8.2)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
@@ -753,10 +739,11 @@ DEPENDENCIES
|
||||
gmaps4rails
|
||||
haml
|
||||
i18n (~> 0.6.11)
|
||||
i18n-js (~> 3.5.1)
|
||||
i18n-js (~> 3.6.0)
|
||||
immigrant
|
||||
jquery-migrate-rails
|
||||
jquery-rails (= 3.0.4)
|
||||
jquery-ui-rails (~> 4.0.0)
|
||||
json_spec (~> 1.1.4)
|
||||
jwt (~> 2.2)
|
||||
kaminari (~> 0.14.1)
|
||||
@@ -766,7 +753,7 @@ DEPENDENCIES
|
||||
momentjs-rails
|
||||
newrelic_rpm (~> 3.0)
|
||||
nokogiri (>= 1.6.7.1)
|
||||
oauth2 (~> 1.4.2)
|
||||
oauth2 (~> 1.4.4)
|
||||
ofn-qz!
|
||||
oj
|
||||
order_management!
|
||||
@@ -783,19 +770,19 @@ DEPENDENCIES
|
||||
rails_safe_tasks (~> 1.0)
|
||||
redcarpet
|
||||
roadie-rails (~> 1.3.0)
|
||||
roo (~> 2.8.2)
|
||||
roo (~> 2.8.3)
|
||||
rspec-rails (>= 3.5.2)
|
||||
rspec-retry
|
||||
rubocop
|
||||
rubocop-rails
|
||||
sass (~> 3.3)
|
||||
sass-rails (~> 3.2.3)
|
||||
select2-rails (~> 3.4.7)
|
||||
selenium-webdriver
|
||||
shoulda-matchers
|
||||
simple_form!
|
||||
simplecov
|
||||
spinjs-rails
|
||||
spree_backend!
|
||||
spree_core!
|
||||
spree_i18n!
|
||||
spree_paypal_express!
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
//= require jquery.jstree/jquery.jstree
|
||||
//= require jquery.vAlign
|
||||
//= require jquery.horizontalNav
|
||||
//= require jquery.adaptivemenu
|
||||
//= require angular
|
||||
//= require angular-resource
|
||||
//= require angular-animate
|
||||
@@ -28,11 +29,9 @@
|
||||
|
||||
// spree
|
||||
//= require spree
|
||||
//= require admin/spree-select2
|
||||
//= require admin/spree_backend
|
||||
//= require admin/spree/spree-select2
|
||||
//= require modernizr
|
||||
//= require spin
|
||||
//= require jquery.adaptivemenu
|
||||
//= require equalize
|
||||
//= require css_browser_selector_dev
|
||||
//= require responsive-tables
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor) ->
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser) ->
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.columns = Columns.columns
|
||||
@@ -38,6 +38,8 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
$scope.sortOptions = SortOptions
|
||||
|
||||
$scope.initialise = ->
|
||||
$scope.fetchProducts()
|
||||
|
||||
@@ -54,6 +56,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
'q[name_cont]': $scope.query,
|
||||
'q[supplier_id_eq]': $scope.producerFilter,
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter,
|
||||
'q[s]': $scope.sorting,
|
||||
import_date: $scope.importDateFilter,
|
||||
page: $scope.page,
|
||||
per_page: $scope.per_page
|
||||
@@ -103,9 +106,16 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.categoryFilter = "0"
|
||||
$scope.importDateFilter = "0"
|
||||
|
||||
$scope.$watch 'sortOptions', (sort) ->
|
||||
return unless sort && sort.predicate != ""
|
||||
|
||||
$scope.sorting = sort.getSortingExpr()
|
||||
$scope.fetchProducts()
|
||||
, true
|
||||
|
||||
confirm_unsaved_changes = () ->
|
||||
(DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
|
||||
|
||||
|
||||
editProductUrl = (product, variant) ->
|
||||
"/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
|
||||
@@ -220,10 +230,9 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
BulkProducts.updateVariantLists(data.products || [])
|
||||
$timeout -> $scope.displaySuccess()
|
||||
).error (data, status) ->
|
||||
if status == 400 && data.errors? && data.errors.length > 0
|
||||
errors = error + "\n" for error in data.errors
|
||||
alert t("products_update_error") + "\n" + errors
|
||||
$scope.displayFailure t("products_update_error")
|
||||
if status == 400 && data.errors?
|
||||
errorsString = ErrorsParser.toString(data.errors, status)
|
||||
$scope.displayFailure t("products_update_error") + "\n" + errorsString
|
||||
else
|
||||
$scope.displayFailure t("products_update_error_data") + status
|
||||
|
||||
@@ -274,7 +283,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
|
||||
$scope.displayFailure = (failMessage) ->
|
||||
StatusMessage.display 'failure', t("products_update_error_msg") + "#{failMessage}"
|
||||
StatusMessage.display 'failure', t("products_update_error_msg") + " #{failMessage}"
|
||||
|
||||
|
||||
$scope.displayDirtyProducts = ->
|
||||
|
||||
@@ -3,6 +3,11 @@ angular.module("admin.indexUtils").factory 'SortOptions', ->
|
||||
predicate: ""
|
||||
reverse: true
|
||||
|
||||
getSortingExpr: () ->
|
||||
sortingExpr = this.predicate + ' desc' if this.reverse
|
||||
sortingExpr = this.predicate + ' asc' if !this.reverse
|
||||
sortingExpr
|
||||
|
||||
toggle: (predicate) ->
|
||||
@reverse = (@predicate == predicate) && !@reverse
|
||||
@predicate = predicate
|
||||
|
||||
@@ -48,13 +48,15 @@ angular.module('admin.orderCycles')
|
||||
|
||||
return if enterprise.last_page_loaded? && enterprise.last_page_loaded >= page
|
||||
enterprise.last_page_loaded = page
|
||||
enterprise.loaded_variants ?= 0
|
||||
|
||||
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) ->
|
||||
ExchangeProduct.index params, (products, num_of_pages) ->
|
||||
enterprise.num_of_pages = num_of_pages
|
||||
enterprise.num_of_products = num_of_products
|
||||
enterprise.supplied_products.push products...
|
||||
angular.forEach products, (product) ->
|
||||
enterprise.loaded_variants += product.variants.length
|
||||
|
||||
$scope.loadMoreExchangeProducts = (exchange) ->
|
||||
$scope.loadExchangeProducts(exchange, $scope.enterprises[exchange.enterprise_id].last_page_loaded + 1)
|
||||
|
||||
@@ -64,10 +64,10 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, $timeout, Reque
|
||||
$scope.selected_orders.push order.id if $scope.select_all
|
||||
|
||||
$scope.$watch 'sortOptions', (sort) ->
|
||||
if sort && sort.predicate != ""
|
||||
$scope.sorting = sort.predicate + ' desc' if sort.reverse
|
||||
$scope.sorting = sort.predicate + ' asc' if !sort.reverse
|
||||
$scope.fetchResults()
|
||||
return unless sort && sort.predicate != ""
|
||||
|
||||
$scope.sorting = sort.getSortingExpr()
|
||||
$scope.fetchProducts()
|
||||
, true
|
||||
|
||||
$scope.capturePayment = (order) ->
|
||||
|
||||
@@ -3,6 +3,9 @@ angular.module("admin.orders").directive 'customerSearchOverride', ->
|
||||
scope:
|
||||
distributorId: '@'
|
||||
link: (scope, element, attr) ->
|
||||
if $('#customer_autocomplete_template').length > 0
|
||||
customerTemplate = Handlebars.compile($('#customer_autocomplete_template').text())
|
||||
|
||||
formatCustomerResult = (customer) ->
|
||||
customerTemplate
|
||||
customer: customer
|
||||
|
||||
@@ -21,9 +21,7 @@ angular.module("admin.products").factory "OptionValueNamer", (VariantUnitManager
|
||||
|
||||
else
|
||||
value = @variant.unit_value
|
||||
unit_name = @variant.product.variant_unit_name
|
||||
# TODO needs to add pluralize to line below
|
||||
# unit_name = unit_name if value > 1
|
||||
unit_name = @pluralize(@variant.product.variant_unit_name, value)
|
||||
|
||||
value = parseInt(value, 10) if value == parseInt(value, 10)
|
||||
|
||||
@@ -32,6 +30,21 @@ angular.module("admin.products").factory "OptionValueNamer", (VariantUnitManager
|
||||
|
||||
[value, unit_name]
|
||||
|
||||
pluralize: (unit_name, count) ->
|
||||
return unit_name if count == undefined
|
||||
unit_key = @unit_key(unit_name)
|
||||
return unit_name unless unit_key
|
||||
I18n.t(["inflections", unit_key], {count: count, defaultValue: unit_name})
|
||||
|
||||
unit_key: (unit_name) ->
|
||||
unless I18n.unit_keys
|
||||
I18n.unit_keys = {}
|
||||
for key, translations of I18n.t("inflections")
|
||||
for quantifier, translation of translations
|
||||
I18n.unit_keys[translation.toLowerCase()] = key
|
||||
|
||||
I18n.unit_keys[unit_name.toLowerCase()]
|
||||
|
||||
option_value_value_unit_scaled: ->
|
||||
[unit_scale, unit_name] = @scale_for_unit_value()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//= require_self
|
||||
//= require admin/handlebar_extensions
|
||||
//= require admin/variant_autocomplete
|
||||
//= require admin/spree/orders/variant_autocomplete
|
||||
|
||||
/**
|
||||
This is a collection of javascript functions and whatnot
|
||||
@@ -21,12 +21,14 @@ jQuery(function($) {
|
||||
if (typeof $('.field.checkbox label').vAlign === 'function' )
|
||||
$('.field.checkbox label').vAlign()
|
||||
|
||||
// if (typeof Spree !== 'undefined') {
|
||||
// $('.main-menu-wrapper ul').AdaptiveMenu({
|
||||
// text: "<a href='#'><i class='icon-chevron-down'></i> " + Spree.translations.more + "</a>",
|
||||
// klass: "dropdown"
|
||||
// });
|
||||
// }
|
||||
// We activate AdaptiveMenu only if not on webdriver
|
||||
// Re-adjusting the admin menu during tests causes tests to fail.
|
||||
if (!navigator.webdriver && typeof Spree !== 'undefined') {
|
||||
$('.main-menu-wrapper ul').AdaptiveMenu({
|
||||
text: "<a href='#'><i class='icon-chevron-down'></i> " + Spree.translations.more + "</a>",
|
||||
klass: "dropdown"
|
||||
});
|
||||
}
|
||||
|
||||
// Add some tips
|
||||
if (typeof $('.with-tip').powerTip === 'function' ) {
|
||||
@@ -174,6 +176,28 @@ $(document).ready(function() {
|
||||
$(target).prepend(new_table_row);
|
||||
})
|
||||
|
||||
$('body').on('click', '.delete-resource', function() {
|
||||
var el = $(this);
|
||||
if (confirm(el.data("confirm"))) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: $(this).attr("href"),
|
||||
data: {
|
||||
_method: 'delete',
|
||||
authenticity_token: AUTH_TOKEN
|
||||
},
|
||||
dataType: 'html',
|
||||
success: function(response) {
|
||||
el.parents("tr").fadeOut('hide');
|
||||
},
|
||||
error: function(response, textStatus, errorThrown) {
|
||||
show_flash_error(response.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Fix sortable helper
|
||||
var fixHelper = function(e, ui) {
|
||||
ui.children().each(function() {
|
||||
|
||||
16
app/assets/javascripts/admin/spree/calculator.js
Normal file
16
app/assets/javascripts/admin/spree/calculator.js
Normal file
@@ -0,0 +1,16 @@
|
||||
$(function() {
|
||||
var calculator_select = $('select#calc_type')
|
||||
var original_calc_type = calculator_select.attr('value');
|
||||
$('.calculator-settings-warning').hide();
|
||||
calculator_select.change(function() {
|
||||
if (calculator_select.attr('value') == original_calc_type) {
|
||||
$('div.calculator-settings').show();
|
||||
$('.calculator-settings-warning').hide();
|
||||
$('.calculator-settings').find('input,textarea').prop("disabled", false);
|
||||
} else {
|
||||
$('div.calculator-settings').hide();
|
||||
$('.calculator-settings-warning').show();
|
||||
$('.calculator-settings').find('input,texttarea').prop("disabled", true);
|
||||
}
|
||||
});
|
||||
})
|
||||
59
app/assets/javascripts/admin/spree/image_settings.js.erb
Normal file
59
app/assets/javascripts/admin/spree/image_settings.js.erb
Normal file
@@ -0,0 +1,59 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
if ($('input#preferences_use_s3[type="checkbox"]:checked').length > 0) {
|
||||
$('#s3_settings, #s3_headers').show();
|
||||
}
|
||||
|
||||
// Toggle display of S3 settings based on value of use_s3 checkbox
|
||||
$('input#preferences_use_s3[type="checkbox"]').click(function() {
|
||||
$('#s3_settings, #s3_headers').toggle();
|
||||
});
|
||||
|
||||
$(document).on('click', '.destroy_style', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).parent().remove();
|
||||
});
|
||||
|
||||
$(document).on('click', '.destroy_new_attachment_styles', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest('.new_attachment_styles').remove();
|
||||
});
|
||||
|
||||
$(document).on('click', '.destroy_new_s3_headers', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest('.new_s3_headers').remove();
|
||||
});
|
||||
|
||||
// Handle adding new styles
|
||||
var styles_hash_index = 1;
|
||||
$(document).on('click', '.add_new_style', function(e) {
|
||||
e.preventDefault();
|
||||
$('#new-styles').append(generate_html_for_hash("new_attachment_styles", styles_hash_index));
|
||||
});
|
||||
|
||||
// Handle adding new headers
|
||||
var headers_hash_index = 1;
|
||||
$(document).on('click', '.add_header', function(e) {
|
||||
e.preventDefault();
|
||||
$('#headers_list').append(generate_html_for_hash("new_s3_headers", headers_hash_index));
|
||||
});
|
||||
|
||||
// Generates html for new paperclip styles form fields
|
||||
generate_html_for_hash = function(hash_name, index) {
|
||||
var html = '<div class="' + hash_name + ' row"><div class="field">';
|
||||
html += '<div class="five columns">';
|
||||
html += '<label for="' + hash_name + '_' + index + '_name">';
|
||||
html += Spree.translations.name + '</label>';
|
||||
html += '<input id="' + hash_name + '_' + index + '_name" name="' + hash_name + '[' + index + '][name]" type="text" class="fullwidth"><br>';
|
||||
html += '</div><div class="five columns">'
|
||||
html += '<label for="' + hash_name + '_' + index + '_value">';
|
||||
html += Spree.translations.value + '</label>';
|
||||
html += '<input id="' + hash_name + '_' + index + '_value" name="' + hash_name + '[' + index + '][value]" type="text" class="fullwidth">';
|
||||
html += '</div><div class="two columns">'
|
||||
html += '<a href="#" title="' + Spree.translations.destroy + '" class="destroy_' + hash_name + ' with-tip button" style="margin-top: 19px;"><i class="icon-trash"></i> ' + Spree.translations.destroy + '</a>';
|
||||
html += '</div></div></div>';
|
||||
|
||||
index += 1;
|
||||
return html;
|
||||
};
|
||||
});
|
||||
23
app/assets/javascripts/admin/spree/nested-attribute.js
Normal file
23
app/assets/javascripts/admin/spree/nested-attribute.js
Normal file
@@ -0,0 +1,23 @@
|
||||
//On page load
|
||||
replace_ids = function(s){
|
||||
var new_id = new Date().getTime();
|
||||
return s.replace(/NEW_RECORD/g, new_id);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$('a[id*=nested]').click(function() {
|
||||
var template = $(this).attr('href').replace(/.*#/, '');
|
||||
html = replace_ids(eval(template));
|
||||
$('#ul-' + $(this).attr('id')).append(html);
|
||||
update_remove_links();
|
||||
});
|
||||
update_remove_links();
|
||||
})
|
||||
|
||||
var update_remove_links = function() {
|
||||
$('.remove').click(function() {
|
||||
$(this).prevAll(':first').val(1);
|
||||
$(this).parent().hide();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
@@ -15,11 +15,11 @@ $(document).ready(function() {
|
||||
console.log(msg);
|
||||
});
|
||||
}
|
||||
// $('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click);
|
||||
$('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click);
|
||||
|
||||
//handle shipping method edit click
|
||||
// $('a.edit-method').click(toggleMethodEdit);
|
||||
// $('a.cancel-method').click(toggleMethodEdit);
|
||||
$('a.edit-method').click(toggleMethodEdit);
|
||||
$('a.cancel-method').click(toggleMethodEdit);
|
||||
|
||||
handle_shipping_method_save = function(){
|
||||
var link = $(this);
|
||||
@@ -38,11 +38,11 @@ $(document).ready(function() {
|
||||
console.log(msg);
|
||||
});
|
||||
}
|
||||
// $('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save);
|
||||
$('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save);
|
||||
|
||||
//handle tracking edit click
|
||||
// $('a.edit-tracking').click(toggleTrackingEdit);
|
||||
// $('a.cancel-tracking').click(toggleTrackingEdit);
|
||||
$('a.edit-tracking').click(toggleTrackingEdit);
|
||||
$('a.cancel-tracking').click(toggleTrackingEdit);
|
||||
|
||||
handle_tracking_save = function(){
|
||||
var link = $(this);
|
||||
|
||||
@@ -29,10 +29,10 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
//handle edit click
|
||||
// $('a.edit-item').click(toggleItemEdit);
|
||||
$('a.edit-item').click(toggleItemEdit);
|
||||
|
||||
//handle cancel click
|
||||
// $('a.cancel-item').click(toggleItemEdit);
|
||||
$('a.cancel-item').click(toggleItemEdit);
|
||||
|
||||
handle_save_click = function(){
|
||||
var save = $(this);
|
||||
@@ -46,7 +46,7 @@ $(document).ready(function() {
|
||||
adjustItems(shipment_number, variant_id, quantity);
|
||||
return false;
|
||||
}
|
||||
// $('a.save-item').click(handle_save_click);
|
||||
$('a.save-item').click(handle_save_click);
|
||||
|
||||
handle_delete_click = function(){
|
||||
var del = $(this);
|
||||
@@ -57,7 +57,7 @@ $(document).ready(function() {
|
||||
|
||||
adjustItems(shipment_number, variant_id, 0);
|
||||
}
|
||||
// $('a.delete-item').click(handle_delete_click);
|
||||
$('a.delete-item').click(handle_delete_click);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -139,39 +139,3 @@ addVariantFromStockLocation = function() {
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
formatVariantResult = function(variant) {
|
||||
if (variant["images"][0] != undefined && variant["images"][0].urls != undefined) {
|
||||
variant.image = variant.images[0].urls.mini
|
||||
}
|
||||
return variantTemplate({ variant: variant })
|
||||
}
|
||||
|
||||
$.fn.variantAutocomplete = function() {
|
||||
this.parent().children(".options_placeholder").attr('id', this.parent().data('index'))
|
||||
this.select2({
|
||||
placeholder: Spree.translations.variant_placeholder,
|
||||
minimumInputLength: 3,
|
||||
ajax: {
|
||||
url: Spree.url(Spree.routes.variants_search),
|
||||
datatype: 'json',
|
||||
data: function(term, page) {
|
||||
return {
|
||||
q: {
|
||||
"product_name_or_sku_cont": term
|
||||
}
|
||||
}
|
||||
},
|
||||
results: function (data, page) {
|
||||
window.variants = data['variants'];
|
||||
|
||||
return { results: data['variants'] }
|
||||
}
|
||||
},
|
||||
formatResult: formatVariantResult,
|
||||
formatSelection: function (variant) {
|
||||
$(this.element).parent().children('.options_placeholder').html(variant.options_text)
|
||||
return variant.name;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
8
app/assets/javascripts/admin/spree/states.js
Executable file
8
app/assets/javascripts/admin/spree/states.js
Executable file
@@ -0,0 +1,8 @@
|
||||
$(document).ready(function() {
|
||||
$("#country").change(function() {
|
||||
var new_state_link_href = $('#new_state_link a').attr('href');
|
||||
var selected_country_id = $('#country option:selected').attr('value');
|
||||
var new_link = new_state_link_href.replace(/countries\/(\d+)/, 'countries/'+selected_country_id);
|
||||
$('#new_state_link a').attr('href', new_link);
|
||||
});
|
||||
});
|
||||
43
app/assets/javascripts/admin/spree/zone.js.coffee
Normal file
43
app/assets/javascripts/admin/spree/zone.js.coffee
Normal file
@@ -0,0 +1,43 @@
|
||||
$ ->
|
||||
($ '#country_based').click ->
|
||||
show_country()
|
||||
|
||||
($ '#state_based').click ->
|
||||
show_state()
|
||||
|
||||
if ($ '#country_based').is(':checked')
|
||||
show_country()
|
||||
else if ($ '#state_based').is(':checked')
|
||||
show_state()
|
||||
else
|
||||
show_state()
|
||||
($ '#state_based').click()
|
||||
|
||||
|
||||
show_country = ->
|
||||
($ '#state_members :input').each ->
|
||||
($ this).prop 'disabled', true
|
||||
|
||||
($ '#state_members').hide()
|
||||
($ '#zone_members :input').each ->
|
||||
($ this).prop 'disabled', true
|
||||
|
||||
($ '#zone_members').hide()
|
||||
($ '#country_members :input').each ->
|
||||
($ this).prop 'disabled', false
|
||||
|
||||
($ '#country_members').show()
|
||||
|
||||
show_state = ->
|
||||
($ '#country_members :input').each ->
|
||||
($ this).prop 'disabled', true
|
||||
|
||||
($ '#country_members').hide()
|
||||
($ '#zone_members :input').each ->
|
||||
($ this).prop 'disabled', true
|
||||
|
||||
($ '#zone_members').hide()
|
||||
($ '#state_members :input').each ->
|
||||
($ this).prop 'disabled', false
|
||||
|
||||
($ '#state_members').show()
|
||||
0
app/assets/javascripts/admin/spree_backend.js
Normal file
0
app/assets/javascripts/admin/spree_backend.js
Normal file
@@ -1,10 +1,6 @@
|
||||
angular.module("admin.utils").directive "variantAutocomplete", ($timeout) ->
|
||||
restrict: 'C'
|
||||
link: (scope, element, attrs) ->
|
||||
# Make variantAutocomplete do nothing because it is called
|
||||
# from core/app/assets/javascripts/admin/orders/edit.js
|
||||
$.fn.variantAutocomplete = angular.noop
|
||||
|
||||
$timeout ->
|
||||
if $("#variant_autocomplete_template").length > 0
|
||||
variantTemplate = Handlebars.compile($("#variant_autocomplete_template").text())
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Parses a structure of errors that came from the server
|
||||
angular.module("admin.utils").factory "ErrorsParser", ->
|
||||
new class ErrorsParser
|
||||
toString: (errors, defaultContent = "") =>
|
||||
return defaultContent unless errors?
|
||||
|
||||
errorsString = ""
|
||||
if errors.length > 0
|
||||
# it is an array of errors
|
||||
errorsString = errors.join("\n") + "\n"
|
||||
else
|
||||
# it is a hash of errors
|
||||
keys = Object.keys(errors)
|
||||
for key in keys
|
||||
errorsString += errors[key].join("\n") + "\n"
|
||||
|
||||
this.defaultIfEmpty(errorsString, defaultContent)
|
||||
|
||||
defaultIfEmpty: (content, defaultContent) =>
|
||||
return defaultContent if content == ""
|
||||
content
|
||||
@@ -9,7 +9,7 @@
|
||||
'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' }
|
||||
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
|
||||
{{ 'js.admin.panels.exchange_products.select_all_variants' | t:{ total_number_of_variants: exchangeTotalVariants(exchange) } }}
|
||||
|
||||
.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' }
|
||||
|
||||
@@ -1,11 +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 }}
|
||||
{{ 'js.admin.panels.exchange_products.load_more_variants' | t }}
|
||||
.button{ 'ng-click' => 'loadAllExchangeProducts(exchange)' }
|
||||
{{ 'js.admin.panels.exchange_products.load_all_products' | t }}
|
||||
{{ 'js.admin.panels.exchange_products.load_all_variants' | 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 }}
|
||||
{{ 'js.admin.panels.exchange_products.loading_variants' | t }}
|
||||
|
||||
@@ -1,5 +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 } }}
|
||||
{{ 'js.admin.panels.exchange_products.variants_loaded' | t:{ num_of_variants_loaded: enterprises[exchange.enterprise_id].loaded_variants, total_number_of_variants: exchangeTotalVariants(exchange) } }}
|
||||
%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 }}
|
||||
{{ 'js.admin.panels.exchange_products.load_all_variants' | t }}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
'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 } }}
|
||||
{{ 'js.admin.panels.exchange_products.select_all_variants' | t:{ total_number_of_variants: exchangeTotalVariants(exchange) } }}
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||
*
|
||||
|
||||
*= require admin/spree_backend
|
||||
*= require jquery.powertip
|
||||
*= require responsive-tables
|
||||
*= require normalize
|
||||
*= require skeleton
|
||||
*= require responsive-tables
|
||||
*= require jquery.powertip
|
||||
*= require jquery.ui.datepicker
|
||||
*= require jquery-ui-timepicker-addon
|
||||
*= require shared/textAngular
|
||||
*= require shared/ng-tags-input.min
|
||||
*= require select2
|
||||
|
||||
*= require_self
|
||||
*/
|
||||
@@ -33,6 +33,11 @@
|
||||
@import 'plugins/powertip';
|
||||
@import 'plugins/jstree';
|
||||
@import 'plugins/font-awesome';
|
||||
@import 'plugins/select2';
|
||||
|
||||
@import 'sections/image_settings';
|
||||
@import 'sections/orders';
|
||||
@import 'sections/products';
|
||||
|
||||
@import 'hacks/mozilla';
|
||||
@import 'hacks/opera';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.destroy_style, .destroy_header {
|
||||
float: right;
|
||||
}
|
||||
@@ -48,16 +48,22 @@ module Api
|
||||
end
|
||||
|
||||
def bulk_products
|
||||
product_query = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
editable_products.merge(product_scope)
|
||||
product_query = OpenFoodNetwork::Permissions.
|
||||
new(current_api_user).
|
||||
editable_products.
|
||||
merge(product_scope)
|
||||
|
||||
if params[:import_date].present?
|
||||
product_query = product_query.imported_on(params[:import_date]).group_by_products_id
|
||||
product_query = product_query.
|
||||
imported_on(params[:import_date]).
|
||||
group_by_products_id
|
||||
end
|
||||
|
||||
@products = product_query.order('created_at DESC').
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page] || DEFAULT_PAGE).per(params[:per_page] || DEFAULT_PER_PAGE)
|
||||
@products = product_query.
|
||||
ransack(query_params_with_defaults).
|
||||
result.
|
||||
page(params[:page] || DEFAULT_PAGE).
|
||||
per(params[:per_page] || DEFAULT_PER_PAGE)
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
@@ -136,6 +142,10 @@ module Api
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def query_params_with_defaults
|
||||
params[:q].to_h.reverse_merge(s: 'created_at desc')
|
||||
end
|
||||
|
||||
def pagination_data(results)
|
||||
{
|
||||
results: results.total_count,
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'open_food_network/address_finder'
|
||||
|
||||
class CheckoutController < Spree::CheckoutController
|
||||
class CheckoutController < Spree::StoreController
|
||||
layout 'darkswarm'
|
||||
|
||||
include CheckoutHelper
|
||||
include OrderCyclesHelper
|
||||
include EnterprisesHelper
|
||||
|
||||
ssl_required
|
||||
|
||||
# We need pessimistic locking to avoid race conditions.
|
||||
# Otherwise we fail on duplicate indexes or end up with negative stock.
|
||||
prepend_around_filter CurrentOrderLocker, only: :update
|
||||
@@ -12,10 +20,19 @@ class CheckoutController < Spree::CheckoutController
|
||||
prepend_before_filter :require_order_cycle
|
||||
prepend_before_filter :require_distributor_chosen
|
||||
|
||||
before_filter :load_order
|
||||
|
||||
before_filter :ensure_order_not_completed
|
||||
before_filter :ensure_checkout_allowed
|
||||
before_filter :ensure_sufficient_stock_lines
|
||||
|
||||
before_filter :associate_user
|
||||
before_filter :check_authorization
|
||||
before_filter :enable_embedded_shopfront
|
||||
|
||||
include OrderCyclesHelper
|
||||
include EnterprisesHelper
|
||||
helper 'spree/orders'
|
||||
|
||||
rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error
|
||||
|
||||
def edit
|
||||
# This is only required because of spree_paypal_express. If we implement
|
||||
@@ -25,54 +42,16 @@ class CheckoutController < Spree::CheckoutController
|
||||
end
|
||||
|
||||
def update
|
||||
shipping_method_id = object_params.delete(:shipping_method_id)
|
||||
params_adapter = Checkout::FormDataAdapter.new(params, @order, spree_current_user)
|
||||
return update_failed unless @order.update_attributes(params_adapter.order_params)
|
||||
|
||||
return update_failed unless @order.update_attributes(object_params)
|
||||
|
||||
check_order_for_phantom_fees
|
||||
fire_event('spree.checkout.update')
|
||||
|
||||
while @order.state != "complete"
|
||||
if @order.state == "payment"
|
||||
return if redirect_to_paypal_express_form_if_needed
|
||||
end
|
||||
|
||||
if @order.state == "delivery"
|
||||
@order.select_shipping_method(shipping_method_id)
|
||||
end
|
||||
|
||||
next if advance_order_state(@order)
|
||||
|
||||
flash[:error] = if @order.errors.present?
|
||||
@order.errors.full_messages.to_sentence
|
||||
else
|
||||
t(:payment_processing_failed)
|
||||
end
|
||||
update_failed
|
||||
return
|
||||
end
|
||||
return update_failed unless @order.state == "complete" || @order.completed?
|
||||
|
||||
set_default_bill_address
|
||||
set_default_ship_address
|
||||
|
||||
ResetOrderService.new(self, current_order).call
|
||||
session[:access_token] = current_order.token
|
||||
|
||||
flash[:notice] = t(:order_processed_successfully)
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
respond_with(@order, location: order_path(@order))
|
||||
end
|
||||
format.json do
|
||||
render json: { path: order_path(@order) }, status: :ok
|
||||
end
|
||||
end
|
||||
rescue Spree::Core::GatewayError => error
|
||||
# This is done for all actions in the Spree::CheckoutController.
|
||||
rescue_from_spree_gateway_error(error)
|
||||
rescue StandardError => error
|
||||
Bugsnag.notify(error)
|
||||
checkout_workflow(params_adapter.shipping_method_id)
|
||||
rescue Spree::Core::GatewayError => e
|
||||
rescue_from_spree_gateway_error(e)
|
||||
rescue StandardError => e
|
||||
Bugsnag.notify(e)
|
||||
flash[:error] = I18n.t("checkout.failed")
|
||||
update_failed
|
||||
end
|
||||
@@ -87,111 +66,38 @@ class CheckoutController < Spree::CheckoutController
|
||||
|
||||
private
|
||||
|
||||
def set_default_bill_address
|
||||
if params[:order][:default_bill_address]
|
||||
new_bill_address = @order.bill_address.clone.attributes
|
||||
|
||||
user_bill_address_id = spree_current_user.bill_address.andand.id
|
||||
spree_current_user.update_attributes(
|
||||
bill_address_attributes: new_bill_address.merge('id' => user_bill_address_id)
|
||||
)
|
||||
|
||||
customer_bill_address_id = @order.customer.bill_address.andand.id
|
||||
@order.customer.update_attributes(
|
||||
bill_address_attributes: new_bill_address.merge('id' => customer_bill_address_id)
|
||||
)
|
||||
end
|
||||
def check_authorization
|
||||
authorize!(:edit, current_order, session[:access_token])
|
||||
end
|
||||
|
||||
def set_default_ship_address
|
||||
if params[:order][:default_ship_address]
|
||||
new_ship_address = @order.ship_address.clone.attributes
|
||||
|
||||
user_ship_address_id = spree_current_user.ship_address.andand.id
|
||||
spree_current_user.update_attributes(
|
||||
ship_address_attributes: new_ship_address.merge('id' => user_ship_address_id)
|
||||
)
|
||||
|
||||
customer_ship_address_id = @order.customer.ship_address.andand.id
|
||||
@order.customer.update_attributes(
|
||||
ship_address_attributes: new_ship_address.merge('id' => customer_ship_address_id)
|
||||
)
|
||||
end
|
||||
def ensure_checkout_allowed
|
||||
redirect_to main_app.cart_path unless @order.checkout_allowed?
|
||||
end
|
||||
|
||||
def check_order_for_phantom_fees
|
||||
phantom_fees = @order.adjustments.
|
||||
joins("LEFT OUTER JOIN spree_line_items"\
|
||||
" ON spree_line_items.id = spree_adjustments.source_id").
|
||||
where("originator_type = 'EnterpriseFee'"\
|
||||
" AND source_type = 'Spree::LineItem' AND spree_line_items.id IS NULL")
|
||||
|
||||
if phantom_fees.any?
|
||||
Bugsnag.notify(RuntimeError.new("Phantom Fees"),
|
||||
phantom_fees: {
|
||||
phantom_total: phantom_fees.sum(&:amount).to_s,
|
||||
phantom_fees: phantom_fees.as_json
|
||||
})
|
||||
end
|
||||
def ensure_order_not_completed
|
||||
redirect_to main_app.cart_path if @order.completed?
|
||||
end
|
||||
|
||||
# Copied and modified from spree. Remove check for order state, since the state machine is
|
||||
# progressed all the way in one go with the one page checkout.
|
||||
def object_params
|
||||
# For payment step, filter order parameters to produce the expected
|
||||
# nested attributes for a single payment and its source,
|
||||
# discarding attributes for payment methods other than the one selected
|
||||
if params[:payment_source].present? && source_params = params.delete(:payment_source)[params[:order][:payments_attributes].first[:payment_method_id].underscore]
|
||||
params[:order][:payments_attributes].first[:source_attributes] = source_params
|
||||
end
|
||||
if params[:order][:payments_attributes]
|
||||
params[:order][:payments_attributes].first[:amount] = @order.total
|
||||
end
|
||||
if params[:order][:existing_card_id]
|
||||
construct_saved_card_attributes
|
||||
end
|
||||
params[:order]
|
||||
end
|
||||
|
||||
# Perform order.next, guarding against StaleObjectErrors
|
||||
def advance_order_state(order)
|
||||
tries ||= 3
|
||||
order.next
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
retry unless (tries -= 1).zero?
|
||||
false
|
||||
end
|
||||
|
||||
def update_failed
|
||||
current_order.updater.shipping_address_from_distributor
|
||||
RestartCheckout.new(@order).call
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
render :edit
|
||||
end
|
||||
format.json do
|
||||
render json: { errors: @order.errors, flash: flash.to_hash }.to_json, status: :bad_request
|
||||
end
|
||||
def ensure_sufficient_stock_lines
|
||||
if @order.insufficient_stock_lines.present?
|
||||
flash[:error] = Spree.t(:inventory_error_flash_for_insufficient_quantity)
|
||||
redirect_to main_app.cart_path
|
||||
end
|
||||
end
|
||||
|
||||
def load_order
|
||||
@order = current_order
|
||||
redirect_to(main_app.shop_path) && return unless @order && @order.checkout_allowed?
|
||||
|
||||
redirect_to(main_app.shop_path) && return if redirect_to_shop?
|
||||
redirect_to_cart_path && return unless valid_order_line_items?
|
||||
redirect_to(main_app.shop_path) && return if @order.completed?
|
||||
before_address
|
||||
setup_for_current_state
|
||||
end
|
||||
|
||||
def before_address
|
||||
associate_user
|
||||
|
||||
finder = OpenFoodNetwork::AddressFinder.new(@order.email, @order.customer, spree_current_user)
|
||||
|
||||
@order.bill_address = finder.bill_address
|
||||
@order.ship_address = finder.ship_address
|
||||
def redirect_to_shop?
|
||||
!@order ||
|
||||
!@order.checkout_allowed? ||
|
||||
@order.completed?
|
||||
end
|
||||
|
||||
def valid_order_line_items?
|
||||
@@ -212,32 +118,29 @@ class CheckoutController < Spree::CheckoutController
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_to_paypal_express_form_if_needed
|
||||
return unless params[:order][:payments_attributes]
|
||||
|
||||
payment_method_id = params[:order][:payments_attributes].first[:payment_method_id]
|
||||
payment_method = Spree::PaymentMethod.find(payment_method_id)
|
||||
return unless payment_method.is_a?(Spree::Gateway::PayPalExpress)
|
||||
|
||||
render json: { path: spree.paypal_express_path(payment_method_id: payment_method.id) },
|
||||
status: :ok
|
||||
true
|
||||
def setup_for_current_state
|
||||
method_name = :"before_#{@order.state}"
|
||||
__send__(method_name) if respond_to?(method_name, true)
|
||||
end
|
||||
|
||||
def construct_saved_card_attributes
|
||||
existing_card_id = params[:order].delete(:existing_card_id)
|
||||
return if existing_card_id.blank?
|
||||
def before_address
|
||||
associate_user
|
||||
|
||||
credit_card = Spree::CreditCard.find(existing_card_id)
|
||||
if credit_card.try(:user_id).blank? || credit_card.user_id != spree_current_user.try(:id)
|
||||
raise Spree::Core::GatewayError, I18n.t(:invalid_credit_card)
|
||||
end
|
||||
finder = OpenFoodNetwork::AddressFinder.new(@order.email, @order.customer, spree_current_user)
|
||||
|
||||
# Not currently supported but maybe we should add it...?
|
||||
credit_card.verification_value = params[:cvc_confirm] if params[:cvc_confirm].present?
|
||||
@order.bill_address = finder.bill_address
|
||||
@order.ship_address = finder.ship_address
|
||||
end
|
||||
|
||||
params[:order][:payments_attributes].first[:source] = credit_card
|
||||
params[:order][:payments_attributes].first.delete :source_attributes
|
||||
def before_delivery
|
||||
return if params[:order].present?
|
||||
|
||||
packages = @order.shipments.map(&:to_package)
|
||||
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
|
||||
end
|
||||
|
||||
def before_payment
|
||||
current_order.payments.destroy_all if request.put?
|
||||
end
|
||||
|
||||
def rescue_from_spree_gateway_error(error)
|
||||
@@ -247,4 +150,91 @@ class CheckoutController < Spree::CheckoutController
|
||||
format.json { render json: { flash: flash.to_hash }, status: :bad_request }
|
||||
end
|
||||
end
|
||||
|
||||
def checkout_workflow(shipping_method_id)
|
||||
while @order.state != "complete"
|
||||
if @order.state == "payment"
|
||||
return if redirect_to_payment_gateway
|
||||
end
|
||||
|
||||
@order.select_shipping_method(shipping_method_id) if @order.state == "delivery"
|
||||
|
||||
next if advance_order_state(@order)
|
||||
|
||||
flash[:error] = order_workflow_error
|
||||
return update_failed
|
||||
end
|
||||
|
||||
update_result
|
||||
end
|
||||
|
||||
def redirect_to_payment_gateway
|
||||
redirect_path = Checkout::PaymentRedirect.new(params).path
|
||||
return if redirect_path.blank?
|
||||
|
||||
render json: { path: redirect_path }, status: :ok
|
||||
true
|
||||
end
|
||||
|
||||
# Perform order.next, guarding against StaleObjectErrors
|
||||
def advance_order_state(order)
|
||||
tries ||= 3
|
||||
order.next
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
retry unless (tries -= 1).zero?
|
||||
false
|
||||
end
|
||||
|
||||
def order_workflow_error
|
||||
if @order.errors.present?
|
||||
@order.errors.full_messages.to_sentence
|
||||
else
|
||||
t(:payment_processing_failed)
|
||||
end
|
||||
end
|
||||
|
||||
def update_result
|
||||
if @order.state == "complete" || @order.completed?
|
||||
save_order_addresses_as_user_default
|
||||
ResetOrderService.new(self, current_order).call
|
||||
|
||||
update_succeeded
|
||||
else
|
||||
update_failed
|
||||
end
|
||||
end
|
||||
|
||||
def save_order_addresses_as_user_default
|
||||
user_default_address_setter = UserDefaultAddressSetter.new(@order, spree_current_user)
|
||||
user_default_address_setter.set_default_bill_address if params[:order][:default_bill_address]
|
||||
user_default_address_setter.set_default_ship_address if params[:order][:default_ship_address]
|
||||
end
|
||||
|
||||
def update_succeeded
|
||||
session[:access_token] = current_order.token
|
||||
flash[:notice] = t(:order_processed_successfully)
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
respond_with(@order, location: order_path(@order))
|
||||
end
|
||||
format.json do
|
||||
render json: { path: order_path(@order) }, status: :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_failed
|
||||
current_order.updater.shipping_address_from_distributor
|
||||
RestartCheckout.new(@order).call
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
render :edit
|
||||
end
|
||||
format.json do
|
||||
render json: { errors: @order.errors, flash: flash.to_hash }.to_json, status: :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -70,10 +70,6 @@ module Spree
|
||||
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?
|
||||
@@ -86,10 +82,6 @@ module Spree
|
||||
raise(ActionController::InvalidAuthenticityToken)
|
||||
end
|
||||
|
||||
def config_locale
|
||||
Spree::Backend::Config[:locale]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def html_request?
|
||||
|
||||
@@ -1,93 +1,16 @@
|
||||
require 'open_food_network/address_finder'
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This controller (and respective route in the Spree engine)
|
||||
# is only needed for the spree_paypal_express gem that redirects here explicitly.
|
||||
#
|
||||
# According to the rails docs it would be possible to redirect
|
||||
# to CheckoutController directly in the routes
|
||||
# with a slash like "to: '/checkout#edit'", but it does not work in this case.
|
||||
module Spree
|
||||
class CheckoutController < Spree::StoreController
|
||||
include CheckoutHelper
|
||||
|
||||
ssl_required
|
||||
|
||||
before_filter :load_order
|
||||
|
||||
before_filter :ensure_order_not_completed
|
||||
before_filter :ensure_checkout_allowed
|
||||
before_filter :ensure_sufficient_stock_lines
|
||||
|
||||
before_filter :associate_user
|
||||
before_filter :check_authorization
|
||||
before_filter :enable_embedded_shopfront
|
||||
|
||||
helper 'spree/orders'
|
||||
|
||||
rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error
|
||||
|
||||
def edit
|
||||
flash.keep
|
||||
redirect_to main_app.checkout_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_order
|
||||
@order = current_order
|
||||
redirect_to(main_app.cart_path) && return unless @order
|
||||
|
||||
if params[:state]
|
||||
redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state])
|
||||
@order.state = params[:state]
|
||||
end
|
||||
setup_for_current_state
|
||||
end
|
||||
|
||||
def ensure_checkout_allowed
|
||||
redirect_to main_app.cart_path unless @order.checkout_allowed?
|
||||
end
|
||||
|
||||
def ensure_order_not_completed
|
||||
redirect_to main_app.cart_path if @order.completed?
|
||||
end
|
||||
|
||||
def ensure_sufficient_stock_lines
|
||||
if @order.insufficient_stock_lines.present?
|
||||
flash[:error] = Spree.t(:inventory_error_flash_for_insufficient_quantity)
|
||||
redirect_to main_app.cart_path
|
||||
end
|
||||
end
|
||||
|
||||
def setup_for_current_state
|
||||
method_name = :"before_#{@order.state}"
|
||||
send(method_name) if respond_to?(method_name, true)
|
||||
end
|
||||
|
||||
# Adapted from spree_last_address gem: https://github.com/TylerRick/spree_last_address
|
||||
# Originally, we used a forked version of this gem, but encountered strange errors where
|
||||
# it worked in dev but only intermittently in staging/prod.
|
||||
def before_address
|
||||
associate_user
|
||||
|
||||
finder = OpenFoodNetwork::AddressFinder.new(@order.email)
|
||||
|
||||
@order.bill_address = finder.bill_address
|
||||
@order.ship_address = finder.ship_address
|
||||
end
|
||||
|
||||
def before_delivery
|
||||
return if params[:order].present?
|
||||
|
||||
packages = @order.shipments.map(&:to_package)
|
||||
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
|
||||
end
|
||||
|
||||
def before_payment
|
||||
current_order.payments.destroy_all if request.put?
|
||||
end
|
||||
|
||||
def rescue_from_spree_gateway_error
|
||||
flash[:error] = Spree.t(:spree_gateway_error_flash_for_checkout)
|
||||
render :edit
|
||||
end
|
||||
|
||||
def check_authorization
|
||||
authorize!(:edit, current_order, session[:access_token])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
module NavigationHelper
|
||||
@@ -34,7 +36,9 @@ module Spree
|
||||
end
|
||||
|
||||
selected = if options[:match_path]
|
||||
request.fullpath.starts_with?("#{spree.root_path}admin#{options[:match_path]}")
|
||||
request.
|
||||
fullpath.
|
||||
starts_with?("#{main_app.root_path}admin#{options[:match_path]}")
|
||||
else
|
||||
args.include?(controller.controller_name.to_sym)
|
||||
end
|
||||
|
||||
68
app/services/checkout/form_data_adapter.rb
Normal file
68
app/services/checkout/form_data_adapter.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Adapts checkout form data (params) so that the order can be directly saved to the database
|
||||
module Checkout
|
||||
class FormDataAdapter
|
||||
attr_reader :shipping_method_id
|
||||
|
||||
def initialize(params, order, current_user)
|
||||
@params = params.dup
|
||||
@order = order
|
||||
@current_user = current_user
|
||||
|
||||
move_payment_source_to_payment_attributes!
|
||||
|
||||
set_amount_in_payments_attributes
|
||||
|
||||
construct_saved_card_attributes if @params[:order][:existing_card_id]
|
||||
|
||||
@shipping_method_id = @params[:order].delete(:shipping_method_id)
|
||||
end
|
||||
|
||||
def order_params
|
||||
@params[:order]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# For payment step, filter order parameters to produce the expected
|
||||
# nested attributes for a single payment and its source,
|
||||
# discarding attributes for payment methods other than the one selected
|
||||
def move_payment_source_to_payment_attributes!
|
||||
return unless @params[:payment_source].present? &&
|
||||
payment_source_params = delete_payment_source_params!
|
||||
|
||||
@params[:order][:payments_attributes].first[:source_attributes] = payment_source_params
|
||||
end
|
||||
|
||||
def delete_payment_source_params!
|
||||
@params.delete(:payment_source)[
|
||||
@params[:order][:payments_attributes].first[:payment_method_id].underscore
|
||||
]
|
||||
end
|
||||
|
||||
def set_amount_in_payments_attributes
|
||||
return unless @params[:order][:payments_attributes]
|
||||
|
||||
@params[:order][:payments_attributes].first[:amount] = @order.total
|
||||
end
|
||||
|
||||
def construct_saved_card_attributes
|
||||
existing_card_id = @params[:order].delete(:existing_card_id)
|
||||
return if existing_card_id.blank?
|
||||
|
||||
add_to_payment_attributes(existing_card_id)
|
||||
|
||||
@params[:order][:payments_attributes].first.delete :source_attributes
|
||||
end
|
||||
|
||||
def add_to_payment_attributes(existing_card_id)
|
||||
credit_card = Spree::CreditCard.find(existing_card_id)
|
||||
if credit_card.try(:user_id).blank? || credit_card.user_id != @current_user.try(:id)
|
||||
raise Spree::Core::GatewayError, I18n.t(:invalid_credit_card)
|
||||
end
|
||||
|
||||
@params[:order][:payments_attributes].first[:source] = credit_card
|
||||
end
|
||||
end
|
||||
end
|
||||
27
app/services/checkout/payment_redirect.rb
Normal file
27
app/services/checkout/payment_redirect.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides the redirect path if a redirect to the payment gateway is needed
|
||||
module Checkout
|
||||
class PaymentRedirect
|
||||
def initialize(params)
|
||||
@params = params
|
||||
end
|
||||
|
||||
# Returns the path to the Paypal Express form if a redirect is needed
|
||||
def path
|
||||
return unless @params[:order][:payments_attributes]
|
||||
|
||||
payment_method_id = @params[:order][:payments_attributes].first[:payment_method_id]
|
||||
payment_method = Spree::PaymentMethod.find(payment_method_id)
|
||||
return unless payment_method.is_a?(Spree::Gateway::PayPalExpress)
|
||||
|
||||
spree_routes_helper.paypal_express_path(payment_method_id: payment_method.id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def spree_routes_helper
|
||||
Spree::Core::Engine.routes_url_helpers
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'open_food_network/permissions'
|
||||
|
||||
module Permissions
|
||||
class Order
|
||||
def initialize(user)
|
||||
|
||||
39
app/services/user_default_address_setter.rb
Normal file
39
app/services/user_default_address_setter.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Sets the order addresses as the user default addresses
|
||||
class UserDefaultAddressSetter
|
||||
def initialize(order, current_user)
|
||||
@order = order
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
# Sets the order bill address as the user default bill address
|
||||
def set_default_bill_address
|
||||
new_bill_address = @order.bill_address.clone.attributes
|
||||
|
||||
set_bill_address_attributes(@current_user, new_bill_address)
|
||||
set_bill_address_attributes(@order.customer, new_bill_address)
|
||||
end
|
||||
|
||||
# Sets the order ship address as the user default ship address
|
||||
def set_default_ship_address
|
||||
new_ship_address = @order.ship_address.clone.attributes
|
||||
|
||||
set_ship_address_attributes(@current_user, new_ship_address)
|
||||
set_ship_address_attributes(@order.customer, new_ship_address)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_bill_address_attributes(object, new_address)
|
||||
object.update_attributes(
|
||||
bill_address_attributes: new_address.merge('id' => object.bill_address.andand.id)
|
||||
)
|
||||
end
|
||||
|
||||
def set_ship_address_attributes(object, new_address)
|
||||
object.update_attributes(
|
||||
ship_address_attributes: new_address.merge('id' => object.ship_address.andand.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -31,10 +31,10 @@
|
||||
- if type == 'supplier'
|
||||
%tr.panel-row{ object: "exchange",
|
||||
panels: "{products: 'exchange_products_supplied'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,selectAllVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
|
||||
locals: "$index,exchangeTotalVariants,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_products_distributed', tags: 'exchange_tags'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
|
||||
locals: "$index,exchangeTotalVariants,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
|
||||
colspan: 5 }
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
= t('.variants')
|
||||
|
||||
%td.actions
|
||||
%a.edit-order-cycle.icon-edit.no-text{ ng: { href: '{{orderCycle.edit_path}}'} }
|
||||
%a.edit-order-cycle.icon-edit.no-text{ ng: { href: '{{orderCycle.edit_path}}'}, 'ofn-with-tip' => t(:edit) }
|
||||
%td.actions{ ng: { if: 'orderCycle.viewing_as_coordinator' } }
|
||||
%a.clone-order-cycle.icon-copy.no-text{ ng: { href: '{{orderCycle.clone_path}}'} }
|
||||
%td.actions{ ng: { if: 'orderCycle.deletable && orderCycle.viewing_as_coordinator' } }
|
||||
%a.delete-order-cycle.icon-trash.no-text{ ng: { href: '{{orderCycle.delete_path}}'}, data: { method: 'delete', confirm: t(:are_you_sure) } }
|
||||
%a.clone-order-cycle.icon-copy.no-text{ ng: { href: '{{orderCycle.clone_path}}'}, 'ofn-with-tip' => t(:clone) }
|
||||
%td.actions{ ng: { if: 'orderCycle.deletable && orderCycle.viewing_as_coordinator' }}
|
||||
%a.delete-order-cycle.icon-trash.no-text{ ng: { href: '{{orderCycle.delete_path}}'}, data: { method: 'delete', confirm: t(:are_you_sure) }, 'ofn-with-tip' => t(:remove) }
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
%span.or= t('spree.or')
|
||||
= link_to_with_icon 'icon-remove', t('spree.actions.cancel'), admin_product_images_url(@product), id: 'cancel_link', class: 'button'
|
||||
|
||||
= javascript_include_tag 'admin/images/new.js'
|
||||
= javascript_include_tag 'admin/spree/images/new.js'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
%div{"data-hook" => "admin_orders_index_search"}
|
||||
= form_tag false, {name: "orders_form", "ng-submit" => "fetchResults()"} do
|
||||
= form_tag nil, {name: "orders_form", "ng-submit" => "fetchResults()"} do
|
||||
.field-block.alpha.four.columns
|
||||
.date-range-filter.field
|
||||
= label_tag nil, t(:date_range)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<script type='text/template' id='customer_autocomplete_template'>
|
||||
<div class='customer-autocomplete-item'>
|
||||
<div class='customer-details'>
|
||||
<h5>{{customer.email}}</h5>
|
||||
{{#if bill_address.firstname }}
|
||||
<strong>{{t 'bill_address' }}</strong>
|
||||
{{bill_address.firstname}} {{bill_address.lastname}}<br>
|
||||
{{bill_address.address1}}, {{bill_address.address2}}<br>
|
||||
{{bill_address.city}}<br>
|
||||
{{#if bill_address.state_id }}
|
||||
{{bill_address.state.name}}
|
||||
{{else}}
|
||||
{{bill_address.state_name}}
|
||||
{{/if}}
|
||||
{{bill_address.country.name}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
- ['number', 'state', 'payment_state', 'shipment_state', 'email', 'total'].each do |column_name|
|
||||
%th
|
||||
= render partial: 'sortable_header', locals: {column_name: column_name}
|
||||
= render partial: 'spree/admin/shared/sortable_header', locals: {column_name: column_name}
|
||||
|
||||
%th.actions
|
||||
%tbody
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
%th.image{ 'ng-show' => 'columns.image.visible' }
|
||||
%th.producer{ 'ng-show' => 'columns.producer.visible' }=t('admin.producer')
|
||||
%th.sku{ 'ng-show' => 'columns.sku.visible' }=t('admin.sku')
|
||||
%th.name{ 'ng-show' => 'columns.name.visible' }=t('.name')
|
||||
%th.name{ 'ng-show' => 'columns.name.visible' }
|
||||
= render partial: 'spree/admin/shared/sortable_header', locals: {column_name: 'name'}
|
||||
%th.unit{ 'ng-show' => 'columns.unit.visible' }=t('.unit')
|
||||
%th.display_as{ 'ng-show' => 'columns.unit.visible' }=t('.display_as')
|
||||
%th.price{ 'ng-show' => 'columns.price.visible' }=t('admin.price')
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
= render "spree/admin/shared/routes"
|
||||
|
||||
%script
|
||||
= "jQuery.alerts.dialogClass = 'spree';"
|
||||
= raw "var AUTH_TOKEN = \"#{form_authenticity_token}\";"
|
||||
|
||||
= render "layouts/bugherd_script"
|
||||
|
||||
@@ -34,10 +34,14 @@ Openfoodnetwork::Application.configure do
|
||||
config.action_mailer.default_url_options = { protocol: 'https' }
|
||||
|
||||
# See everything in the log (default is :info)
|
||||
config.log_level = :info
|
||||
# config.log_level = :debug
|
||||
|
||||
# Use a different logger for distributed setups
|
||||
# config.logger = SyslogLogger.new
|
||||
# Configure logging for Rails 3.2:
|
||||
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(Rails.root.join("log", "#{Rails.env}.log")))
|
||||
config.logger.formatter = Logger::Formatter.new
|
||||
config.logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
||||
# Once we get to Rails 4.0, we can replace the above with:
|
||||
#config.log_formatter = Logger::Formatter.new.tap { |f| f.datetime_format = "%Y-%m-%d %H:%M:%S" }
|
||||
|
||||
# Use a different cache store in production
|
||||
memcached_value_max_megabytes = ENV.fetch("MEMCACHED_VALUE_MAX_MEGABYTES", 1).to_i
|
||||
|
||||
@@ -36,8 +36,12 @@ Openfoodnetwork::Application.configure do
|
||||
# See everything in the log (default is :info)
|
||||
# config.log_level = :debug
|
||||
|
||||
# Use a different logger for distributed setups
|
||||
# config.logger = SyslogLogger.new
|
||||
# Configure logging for Rails 3.2:
|
||||
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(Rails.root.join("log", "#{Rails.env}.log")))
|
||||
config.logger.formatter = Logger::Formatter.new
|
||||
config.logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
||||
# Once we get to Rails 4.0, we can replace the above with:
|
||||
#config.log_formatter = Logger::Formatter.new.tap { |f| f.datetime_format = "%Y-%m-%d %H:%M:%S" }
|
||||
|
||||
# Use a different cache store in production
|
||||
memcached_value_max_megabytes = ENV.fetch("MEMCACHED_VALUE_MAX_MEGABYTES", 1).to_i
|
||||
|
||||
15
config/initializers/form_builder.rb
Normal file
15
config/initializers/form_builder.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Allow some application_helper methods to be used in the scoped form_for manner
|
||||
#
|
||||
class ActionView::Helpers::FormBuilder
|
||||
def field_container(method, options = {}, &block)
|
||||
@template.field_container(@object_name,method,options,&block)
|
||||
end
|
||||
|
||||
def error_message_on(method, options = {})
|
||||
@template.error_message_on(@object_name, method, objectify_options(options))
|
||||
end
|
||||
end
|
||||
|
||||
ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "<span class=\"field_with_errors\">#{html_tag}</span>".html_safe }
|
||||
|
||||
@@ -1281,6 +1281,7 @@ ar:
|
||||
saving_credit_card: جارٍ حفظ بطاقة الائتمان ...
|
||||
card_has_been_removed: "تمت إزالة بطاقتك (الرقم: %{number})"
|
||||
card_could_not_be_removed: عذرًا ، تعذرت إزالة البطاقة
|
||||
invalid_credit_card: "بطاقة الائتمان غير صالحة"
|
||||
ie_warning_headline: "متصفحك غير محدث :-("
|
||||
ie_warning_text: "للحصول على أفضل تجربة لشبكة الغذاء المفتوح ، نوصي بشدة بترقية متصفحك:"
|
||||
ie_warning_chrome: تحميل متصفح كروم
|
||||
@@ -2425,11 +2426,11 @@ ar:
|
||||
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: "تحميل المنتجات"
|
||||
load_more_variants: "تحميل المزيد من المتغيرات"
|
||||
load_all_variants: "تحميل جميع المتغيرات"
|
||||
select_all_variants: "حدد كل %{total_number_of_variants} المتغيرات"
|
||||
variants_loaded: "%{num_of_variants_loaded} من %{total_number_of_variants} تم تحميل المتغيرات"
|
||||
loading_variants: "تحميل المتغيرات"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "طرق الشحن الموسومة"
|
||||
shipping_method_tagged_bottom: "هي:"
|
||||
@@ -2588,6 +2589,21 @@ ar:
|
||||
signup_or_login: "البدء بالتسجيل (أو تسجيل الدخول)"
|
||||
have_an_account: "هل لديك حساب؟"
|
||||
action_login: "تسجيل الدخول الآن."
|
||||
inflections:
|
||||
each:
|
||||
zero: "كل"
|
||||
one: "كل"
|
||||
two: "كل"
|
||||
few: "كل"
|
||||
many: "كل"
|
||||
other: "كل"
|
||||
pack:
|
||||
zero: "حزم"
|
||||
one: "رزمة"
|
||||
two: "حزم"
|
||||
few: "حزم"
|
||||
many: "حزم"
|
||||
other: "حزم"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "ابدأ بملف تعريف مجاني ، وتوسع عندما تكون جاهزًا!"
|
||||
@@ -2830,6 +2846,8 @@ ar:
|
||||
zipcode: الرمز البريدي
|
||||
weight: الوزن (لكل كجم)
|
||||
error_user_destroy_with_orders: "لا يمكن حذف المستخدمين الذين لديهم طلبات مكتملة"
|
||||
cannot_create_payment_without_payment_methods: "لا يمكنك إنشاء دفعة لطلب بدون تحديد طرقة الدفع."
|
||||
please_define_payment_methods: "يرجى تحديد بعض طرق الدفع أولاً."
|
||||
options: "خيارات"
|
||||
actions:
|
||||
update: "تحديث"
|
||||
|
||||
@@ -2430,12 +2430,6 @@ ca:
|
||||
severity: Severitat
|
||||
description: Descripció
|
||||
resolve: Resoldre
|
||||
exchange_products:
|
||||
load_more_products: "Carrega més productes"
|
||||
load_all_products: "Carrega tots els productes"
|
||||
select_all_products: "Seleccioneu tots els productes %{total_number_of_products}"
|
||||
products_loaded: "%{num_of_products_loaded} de %{total_number_of_products} productes carregats"
|
||||
loading_products: "Carregant productes"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Els mètodes d'enviament etiquetats"
|
||||
shipping_method_tagged_bottom: "son:"
|
||||
|
||||
@@ -2575,6 +2575,10 @@ de_DE:
|
||||
signup_or_login: "Beginnen Sie mit der Anmeldung (oder melden Sie sich an)"
|
||||
have_an_account: "Hast du schon ein Konto?"
|
||||
action_login: "Jetzt einloggen."
|
||||
inflections:
|
||||
bottle:
|
||||
one: "Flasche"
|
||||
other: "Flaschen"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Beginnen Sie mit einem kostenlosen Profil und erweitern Sie es, wenn Sie fertig sind!"
|
||||
|
||||
@@ -1364,6 +1364,7 @@ en:
|
||||
saving_credit_card: Saving credit card...
|
||||
card_has_been_removed: "Your card has been removed (number: %{number})"
|
||||
card_could_not_be_removed: Sorry, the card could not be removed
|
||||
invalid_credit_card: "Invalid credit card"
|
||||
|
||||
ie_warning_headline: "Your browser is out of date :-("
|
||||
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
|
||||
@@ -2557,11 +2558,11 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
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"
|
||||
load_more_variants: "Load More Variants"
|
||||
load_all_variants: "Load All Variants"
|
||||
select_all_variants: "Select All %{total_number_of_variants} Variants"
|
||||
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
|
||||
loading_variants: "Loading Variants"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2721,6 +2722,90 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
have_an_account: "Already have an account?"
|
||||
action_login: "Log in now."
|
||||
|
||||
# Singular and plural forms of commonly used words.
|
||||
# We use these entries to pluralize unit names in every language.
|
||||
#
|
||||
# Extracted with the following query:
|
||||
# Spree::Product.group(:variant_unit_name).order("count_all DESC").count.each { |name, count|
|
||||
# puts " # Used #{count} times."
|
||||
# puts " #{name&.parameterize('_')}:"
|
||||
# puts " one: \"#{name}\""
|
||||
# puts " other: \"#{name}s\"";
|
||||
# }
|
||||
inflections:
|
||||
each:
|
||||
one: "each"
|
||||
other: "each"
|
||||
bunch:
|
||||
one: "bunch"
|
||||
other: "bunches"
|
||||
pack:
|
||||
one: "pack"
|
||||
other: "packs"
|
||||
box:
|
||||
one: "box"
|
||||
other: "boxes"
|
||||
bottle:
|
||||
one: "bottle"
|
||||
other: "bottles"
|
||||
jar:
|
||||
one: "jar"
|
||||
other: "jars"
|
||||
head:
|
||||
one: "head"
|
||||
other: "heads"
|
||||
bag:
|
||||
one: "bag"
|
||||
other: "bags"
|
||||
loaf:
|
||||
one: "loaf"
|
||||
other: "loaves"
|
||||
single:
|
||||
one: "single"
|
||||
other: "singles"
|
||||
tub:
|
||||
one: "tub"
|
||||
other: "tubs"
|
||||
punnet:
|
||||
one: "punnet"
|
||||
other: "punnets"
|
||||
packet:
|
||||
one: "packet"
|
||||
other: "packets"
|
||||
item:
|
||||
one: "item"
|
||||
other: "items"
|
||||
dozen:
|
||||
one: "dozen"
|
||||
other: "dozens"
|
||||
unit:
|
||||
one: "unit"
|
||||
other: "units"
|
||||
serve:
|
||||
one: "serve"
|
||||
other: "serves"
|
||||
tray:
|
||||
one: "tray"
|
||||
other: "trays"
|
||||
piece:
|
||||
one: "piece"
|
||||
other: "pieces"
|
||||
pot:
|
||||
one: "pot"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "bundle"
|
||||
other: "bundles"
|
||||
flask:
|
||||
one: "flask"
|
||||
other: "flasks"
|
||||
basket:
|
||||
one: "basket"
|
||||
other: "baskets"
|
||||
sack:
|
||||
one: "sack"
|
||||
other: "sacks"
|
||||
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Start with a free profile, and expand when you're ready!"
|
||||
|
||||
@@ -782,7 +782,14 @@ en_AU:
|
||||
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_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_description_text: 'You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
|
||||
|
||||
|
||||
Free to use for shopfronts with turnover of less than $500 a month.
|
||||
|
||||
1% of turnover for shopfronts with turnover of more than $500 a month.
|
||||
|
||||
2-3% of turnover for solidarity partners who choose to collaborate on growing a new food system.'
|
||||
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.
|
||||
@@ -1617,7 +1624,7 @@ en_AU:
|
||||
sell_groups_detail: "Set up a tailored directory of enterprises (producers and other food 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 you can choose your community contribution between 1% and 3% of sales. 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_embed: "In addition to the Open Food Network platform, our social enterprise consultancy offers a range of services that help power a better, fairer food system. We can help with customised business and online solutions for your farm or food enterprise, lean enterprise support, regional food system development as well as food systems research and consulting."
|
||||
sell_ask_services: "Ask us about OFN services."
|
||||
shops_title: Shops
|
||||
shops_headline: Shopping, transformed.
|
||||
|
||||
@@ -919,7 +919,7 @@ en_CA:
|
||||
distributors: distributors
|
||||
variants: variants
|
||||
simple_form:
|
||||
ready_for: Ready for
|
||||
ready_for: Options
|
||||
ready_for_placeholder: Date / time
|
||||
customer_instructions: Customer instructions
|
||||
customer_instructions_placeholder: 'Notes:'
|
||||
@@ -1282,6 +1282,7 @@ en_CA:
|
||||
saving_credit_card: Saving credit card...
|
||||
card_has_been_removed: "Your card has been removed (number: %{number})"
|
||||
card_could_not_be_removed: Sorry, the card could not be removed
|
||||
invalid_credit_card: "Invalid credit card"
|
||||
ie_warning_headline: "Your browser is out of date :-("
|
||||
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
|
||||
ie_warning_chrome: Download Chrome
|
||||
@@ -2424,11 +2425,11 @@ en_CA:
|
||||
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"
|
||||
load_more_variants: "Load More Variants"
|
||||
load_all_variants: "Load All Variants"
|
||||
select_all_variants: "Select All %{total_number_of_variants}Variants"
|
||||
variants_loaded: "%{num_of_variants_loaded}of%{total_number_of_variants}Variants Loaded"
|
||||
loading_variants: "Loading Variants"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2587,6 +2588,79 @@ en_CA:
|
||||
signup_or_login: "Start By Signing Up (or logging in)"
|
||||
have_an_account: "Already have an account?"
|
||||
action_login: "Log in now."
|
||||
inflections:
|
||||
each:
|
||||
one: "each"
|
||||
other: "each"
|
||||
bunch:
|
||||
one: "bunch"
|
||||
other: "bunches"
|
||||
pack:
|
||||
one: "pack"
|
||||
other: "packs"
|
||||
box:
|
||||
one: "box"
|
||||
other: "boxes"
|
||||
bottle:
|
||||
one: "bottle"
|
||||
other: "bottles"
|
||||
jar:
|
||||
one: "jar"
|
||||
other: "jars"
|
||||
head:
|
||||
one: "head"
|
||||
other: "heads"
|
||||
bag:
|
||||
one: "bag"
|
||||
other: "bags"
|
||||
loaf:
|
||||
one: "loaf"
|
||||
other: "loaves"
|
||||
single:
|
||||
one: "single"
|
||||
other: "singles"
|
||||
tub:
|
||||
one: "tub"
|
||||
other: "tubs"
|
||||
punnet:
|
||||
one: "punnet"
|
||||
other: "punnets"
|
||||
packet:
|
||||
one: "packet"
|
||||
other: "packets"
|
||||
item:
|
||||
one: "item"
|
||||
other: "items"
|
||||
dozen:
|
||||
one: "dozen"
|
||||
other: "dozens"
|
||||
unit:
|
||||
one: "unit"
|
||||
other: "units"
|
||||
serve:
|
||||
one: "serve"
|
||||
other: "serves"
|
||||
tray:
|
||||
one: "tray"
|
||||
other: "trays"
|
||||
piece:
|
||||
one: "piece"
|
||||
other: "pieces"
|
||||
pot:
|
||||
one: "pot"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "bundle"
|
||||
other: "bundles"
|
||||
flask:
|
||||
one: "flask"
|
||||
other: "flasks"
|
||||
basket:
|
||||
one: "basket"
|
||||
other: "baskets"
|
||||
sack:
|
||||
one: "sack"
|
||||
other: "sacks"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Start with a free profile, and expand when you're ready!"
|
||||
@@ -2829,6 +2903,8 @@ en_CA:
|
||||
zipcode: Postal Code
|
||||
weight: Weight (per kg)
|
||||
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
|
||||
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
|
||||
please_define_payment_methods: "Please define some payment methods first."
|
||||
options: "Options"
|
||||
actions:
|
||||
update: "Update"
|
||||
@@ -2935,7 +3011,7 @@ en_CA:
|
||||
email: "Customer E-Mail"
|
||||
invoice:
|
||||
issued_on: "Issued on"
|
||||
tax_invoice: "TAX INVOICE"
|
||||
tax_invoice: "Order Number"
|
||||
code: "Code"
|
||||
from: "From"
|
||||
to: "To"
|
||||
|
||||
@@ -1282,6 +1282,7 @@ en_FR:
|
||||
saving_credit_card: Saving credit card...
|
||||
card_has_been_removed: "Your card has been removed (number: %{number})"
|
||||
card_could_not_be_removed: Sorry, the card could not be removed
|
||||
invalid_credit_card: "Invalid credit card"
|
||||
ie_warning_headline: "Your browser is out of date :-("
|
||||
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
|
||||
ie_warning_chrome: Download Chrome
|
||||
@@ -2425,11 +2426,11 @@ en_FR:
|
||||
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"
|
||||
load_more_variants: "Load All Variants"
|
||||
load_all_variants: "Load All Variants"
|
||||
select_all_variants: "Select All %{total_number_of_variants} Variants"
|
||||
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
|
||||
loading_variants: "Loading Variants"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2588,6 +2589,79 @@ en_FR:
|
||||
signup_or_login: "Start By Signing Up (or logging in)"
|
||||
have_an_account: "Already have an account?"
|
||||
action_login: "Log in now."
|
||||
inflections:
|
||||
each:
|
||||
one: "each"
|
||||
other: "each"
|
||||
bunch:
|
||||
one: "bunch"
|
||||
other: "bunches"
|
||||
pack:
|
||||
one: "pack"
|
||||
other: "packs"
|
||||
box:
|
||||
one: "box"
|
||||
other: "boxes"
|
||||
bottle:
|
||||
one: "bottle"
|
||||
other: "bottles"
|
||||
jar:
|
||||
one: "jar"
|
||||
other: "jars"
|
||||
head:
|
||||
one: "head"
|
||||
other: "heads"
|
||||
bag:
|
||||
one: "bag"
|
||||
other: "bags"
|
||||
loaf:
|
||||
one: "loaf"
|
||||
other: "loaves"
|
||||
single:
|
||||
one: "single"
|
||||
other: "singles"
|
||||
tub:
|
||||
one: "tub"
|
||||
other: "tubs"
|
||||
punnet:
|
||||
one: "punnet"
|
||||
other: "punnets"
|
||||
packet:
|
||||
one: "packet"
|
||||
other: "packets"
|
||||
item:
|
||||
one: "item"
|
||||
other: "items"
|
||||
dozen:
|
||||
one: "dozen"
|
||||
other: "dozens"
|
||||
unit:
|
||||
one: "unit"
|
||||
other: "units"
|
||||
serve:
|
||||
one: "serve"
|
||||
other: "serves"
|
||||
tray:
|
||||
one: "tray"
|
||||
other: "trays"
|
||||
piece:
|
||||
one: "piece"
|
||||
other: "pieces"
|
||||
pot:
|
||||
one: "pot"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "bundle"
|
||||
other: "bundles"
|
||||
flask:
|
||||
one: "flask"
|
||||
other: "flasks"
|
||||
basket:
|
||||
one: "basket"
|
||||
other: "baskets"
|
||||
sack:
|
||||
one: "sack"
|
||||
other: "sacks"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Start with a free profile, and expand when you're ready!"
|
||||
|
||||
@@ -1282,6 +1282,7 @@ en_GB:
|
||||
saving_credit_card: Saving credit card...
|
||||
card_has_been_removed: "Your card has been removed (number: %{number})"
|
||||
card_could_not_be_removed: Sorry, the card could not be removed
|
||||
invalid_credit_card: "Invalid credit card"
|
||||
ie_warning_headline: "Your browser is out of date :-("
|
||||
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
|
||||
ie_warning_chrome: Download Chrome
|
||||
@@ -2188,8 +2189,8 @@ en_GB:
|
||||
report_header_temp_controlled: TempControlled?
|
||||
report_header_is_producer: Producer?
|
||||
report_header_not_confirmed: Not Confirmed
|
||||
report_header_gst_on_income: VAT on Income
|
||||
report_header_gst_free_income: VAT Free Income
|
||||
report_header_gst_on_income: 20%(VAT on Income)
|
||||
report_header_gst_free_income: Zero Rated Income
|
||||
report_header_total_untaxable_produce: Total untaxable produce (no tax)
|
||||
report_header_total_taxable_produce: Total taxable produce (tax inclusive)
|
||||
report_header_total_untaxable_fees: Total untaxable fees (no tax)
|
||||
@@ -2431,11 +2432,11 @@ en_GB:
|
||||
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"
|
||||
load_more_variants: "Load More Variants"
|
||||
load_all_variants: "Load All Variants"
|
||||
select_all_variants: "Select All %{total_number_of_variants} Variants"
|
||||
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
|
||||
loading_variants: "Loading Variants"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2594,6 +2595,79 @@ en_GB:
|
||||
signup_or_login: "Start By signing up (or logging in)"
|
||||
have_an_account: "Already have an account?"
|
||||
action_login: "Log in now."
|
||||
inflections:
|
||||
each:
|
||||
one: "each"
|
||||
other: "each"
|
||||
bunch:
|
||||
one: "bunch"
|
||||
other: "bunches"
|
||||
pack:
|
||||
one: "pack"
|
||||
other: "packs"
|
||||
box:
|
||||
one: "box"
|
||||
other: "boxes"
|
||||
bottle:
|
||||
one: "bottle"
|
||||
other: "bottles"
|
||||
jar:
|
||||
one: "jar"
|
||||
other: "jars"
|
||||
head:
|
||||
one: "head"
|
||||
other: "heads"
|
||||
bag:
|
||||
one: "bag"
|
||||
other: "bags"
|
||||
loaf:
|
||||
one: "loaf"
|
||||
other: "loaves"
|
||||
single:
|
||||
one: "single"
|
||||
other: "singles"
|
||||
tub:
|
||||
one: "tub"
|
||||
other: "tubs"
|
||||
punnet:
|
||||
one: "punnet"
|
||||
other: "punnets"
|
||||
packet:
|
||||
one: "packet"
|
||||
other: "packets"
|
||||
item:
|
||||
one: "item"
|
||||
other: "items"
|
||||
dozen:
|
||||
one: "dozen"
|
||||
other: "dozens"
|
||||
unit:
|
||||
one: "unit"
|
||||
other: "units"
|
||||
serve:
|
||||
one: "serve"
|
||||
other: "serves"
|
||||
tray:
|
||||
one: "tray"
|
||||
other: "trays"
|
||||
piece:
|
||||
one: "piece"
|
||||
other: "pieces"
|
||||
pot:
|
||||
one: "pot"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "bundle"
|
||||
other: "bundles"
|
||||
flask:
|
||||
one: "flask"
|
||||
other: "flasks"
|
||||
basket:
|
||||
one: "basket"
|
||||
other: "baskets"
|
||||
sack:
|
||||
one: "sack"
|
||||
other: "sacks"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Start with a free profile, and expand when you're ready!"
|
||||
@@ -2836,6 +2910,8 @@ en_GB:
|
||||
zipcode: Postcode
|
||||
weight: Weight (per kg)
|
||||
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
|
||||
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
|
||||
please_define_payment_methods: "Please define some payment methods first."
|
||||
options: "Options"
|
||||
actions:
|
||||
update: "Update"
|
||||
|
||||
@@ -1282,6 +1282,7 @@ en_NZ:
|
||||
saving_credit_card: Saving credit card...
|
||||
card_has_been_removed: "Your card has been removed (number: %{number})"
|
||||
card_could_not_be_removed: Sorry, the card could not be removed
|
||||
invalid_credit_card: "Invalid credit card"
|
||||
ie_warning_headline: "Your browser is out of date :-("
|
||||
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
|
||||
ie_warning_chrome: Download Chrome
|
||||
@@ -2425,11 +2426,11 @@ en_NZ:
|
||||
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"
|
||||
load_more_variants: "Load More Variants"
|
||||
load_all_variants: "Load All Variants"
|
||||
select_all_variants: "Select All %{total_number_of_variants} Variants"
|
||||
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
|
||||
loading_variants: "Loading Variants"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
@@ -2588,6 +2589,79 @@ en_NZ:
|
||||
signup_or_login: "Start By Signing Up (or logging in)"
|
||||
have_an_account: "Already have an account?"
|
||||
action_login: "Log in now."
|
||||
inflections:
|
||||
each:
|
||||
one: "each"
|
||||
other: "each"
|
||||
bunch:
|
||||
one: "bunch"
|
||||
other: "bunches"
|
||||
pack:
|
||||
one: "pack"
|
||||
other: "packs"
|
||||
box:
|
||||
one: "box"
|
||||
other: "boxes"
|
||||
bottle:
|
||||
one: "bottle"
|
||||
other: "bottles"
|
||||
jar:
|
||||
one: "jar"
|
||||
other: "jars"
|
||||
head:
|
||||
one: "head"
|
||||
other: "heads"
|
||||
bag:
|
||||
one: "bag"
|
||||
other: "bags"
|
||||
loaf:
|
||||
one: "loaf"
|
||||
other: "loaves"
|
||||
single:
|
||||
one: "single"
|
||||
other: "singles"
|
||||
tub:
|
||||
one: "tub"
|
||||
other: "tubs"
|
||||
punnet:
|
||||
one: "punnet"
|
||||
other: "punnets"
|
||||
packet:
|
||||
one: "packet"
|
||||
other: "packets"
|
||||
item:
|
||||
one: "item"
|
||||
other: "items"
|
||||
dozen:
|
||||
one: "dozen"
|
||||
other: "dozens"
|
||||
unit:
|
||||
one: "unit"
|
||||
other: "units"
|
||||
serve:
|
||||
one: "serve"
|
||||
other: "serves"
|
||||
tray:
|
||||
one: "tray"
|
||||
other: "trays"
|
||||
piece:
|
||||
one: "piece"
|
||||
other: "pieces"
|
||||
pot:
|
||||
one: "pot"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "bundle"
|
||||
other: "bundles"
|
||||
flask:
|
||||
one: "flask"
|
||||
other: "flasks"
|
||||
basket:
|
||||
one: "basket"
|
||||
other: "baskets"
|
||||
sack:
|
||||
one: "sack"
|
||||
other: "sacks"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Start with a basic profile, and expand when you're ready!"
|
||||
@@ -2830,6 +2904,8 @@ en_NZ:
|
||||
zipcode: Postcode
|
||||
weight: Weight (per kg)
|
||||
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
|
||||
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
|
||||
please_define_payment_methods: "Please define some payment methods first."
|
||||
options: "Options"
|
||||
actions:
|
||||
update: "Update"
|
||||
|
||||
@@ -1284,6 +1284,7 @@ fr:
|
||||
saving_credit_card: Enregistrement de la carte de crédit...
|
||||
card_has_been_removed: "Votre carte a été supprimée (numéro : %{number})"
|
||||
card_could_not_be_removed: Désolée, la carte n'a pas pu être supprimée :-(
|
||||
invalid_credit_card: "Cette carte de crédit n'est pas valide"
|
||||
ie_warning_headline: "Votre navigateur n'est pas à jour :-("
|
||||
ie_warning_text: "Pour une expérience optimale sur Open Food France, nous vous recommandons fortement de mettre à jour votre navigateur:"
|
||||
ie_warning_chrome: Télécharger Chrome
|
||||
@@ -2454,11 +2455,11 @@ fr:
|
||||
description: Description
|
||||
resolve: Résoudre
|
||||
exchange_products:
|
||||
load_more_products: "Voir plus de produits"
|
||||
load_all_products: "Voir tous les produits"
|
||||
select_all_products: "Sélectionner tous les %{total_number_of_products}produits"
|
||||
products_loaded: "%{num_of_products_loaded}sur %{total_number_of_products}produits affichés"
|
||||
loading_products: "Produits en cours de chargement"
|
||||
load_more_variants: "Afficher plus de variantes"
|
||||
load_all_variants: "Afficher toutes les variantes"
|
||||
select_all_variants: "Sélectionnez toutes les %{total_number_of_variants} variantes"
|
||||
variants_loaded: " %{num_of_variants_loaded}sur %{total_number_of_variants} variantes"
|
||||
loading_variants: "Chargement des variantes"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Les méthodes de livraison taguées"
|
||||
shipping_method_tagged_bottom: "sont:"
|
||||
@@ -2618,6 +2619,79 @@ fr:
|
||||
signup_or_login: "Commencez par vous inscrire (ou connexion)"
|
||||
have_an_account: "Déjà inscrit?"
|
||||
action_login: "Se connecter."
|
||||
inflections:
|
||||
each:
|
||||
one: "chacun"
|
||||
other: "chacun"
|
||||
bunch:
|
||||
one: "bouquet"
|
||||
other: "bouquets"
|
||||
pack:
|
||||
one: "caisse"
|
||||
other: "caisses"
|
||||
box:
|
||||
one: "boîte"
|
||||
other: "boîtes"
|
||||
bottle:
|
||||
one: "bouteille"
|
||||
other: "bouteilles"
|
||||
jar:
|
||||
one: "bocal"
|
||||
other: "bocaux"
|
||||
head:
|
||||
one: "tête"
|
||||
other: "têtes"
|
||||
bag:
|
||||
one: "sac"
|
||||
other: "sacs"
|
||||
loaf:
|
||||
one: "miche"
|
||||
other: "miches"
|
||||
single:
|
||||
one: "unité"
|
||||
other: "unités"
|
||||
tub:
|
||||
one: "bac"
|
||||
other: "bacs"
|
||||
punnet:
|
||||
one: "barquette"
|
||||
other: "barquettes"
|
||||
packet:
|
||||
one: "paquet"
|
||||
other: "paquets"
|
||||
item:
|
||||
one: "article"
|
||||
other: "articles"
|
||||
dozen:
|
||||
one: "dizaine"
|
||||
other: "dizaines"
|
||||
unit:
|
||||
one: "unité"
|
||||
other: "unités"
|
||||
serve:
|
||||
one: "service"
|
||||
other: "services"
|
||||
tray:
|
||||
one: "plateau"
|
||||
other: "plateaux"
|
||||
piece:
|
||||
one: "pièce"
|
||||
other: "pièces"
|
||||
pot:
|
||||
one: "pot"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "botte"
|
||||
other: "bottes"
|
||||
flask:
|
||||
one: "flacon"
|
||||
other: "flacons"
|
||||
basket:
|
||||
one: "panier"
|
||||
other: "paniers"
|
||||
sack:
|
||||
one: "sachet"
|
||||
other: "sachets"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Commencez par créer votre profil entreprise, et changez de formule quand vous êtes prêt !"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1284,6 +1284,7 @@ fr_CA:
|
||||
saving_credit_card: Enregistrement de la carte de crédit...
|
||||
card_has_been_removed: "Votre carte a été supprimée (numéro : %{number})"
|
||||
card_could_not_be_removed: Désolée, la carte n'a pas pu être supprimée :-(
|
||||
invalid_credit_card: "Cette carte de crédit n'est pas valide"
|
||||
ie_warning_headline: "Votre navigateur n'est pas à jour :-("
|
||||
ie_warning_text: "Pour une expérience optimale sur Open Food Network, nous vous recommandons fortement de mettre à jour votre navigateur:"
|
||||
ie_warning_chrome: Télécharger Chrome
|
||||
@@ -2437,11 +2438,11 @@ fr_CA:
|
||||
description: Description
|
||||
resolve: Résoudre
|
||||
exchange_products:
|
||||
load_more_products: "Voir plus de produits"
|
||||
load_all_products: "Voir tous les produits"
|
||||
select_all_products: "Sélectionner tous les %{total_number_of_products} produits"
|
||||
products_loaded: "%{num_of_products_loaded}sur %{total_number_of_products}produits affichés"
|
||||
loading_products: "Produits en cours de chargement..."
|
||||
load_more_variants: "Afficher plus de variantes"
|
||||
load_all_variants: "Afficher toutes les variantes"
|
||||
select_all_variants: "Sélectionnez toutes les%{total_number_of_variants}variantes"
|
||||
variants_loaded: "%{num_of_variants_loaded}sur%{total_number_of_variants}variantes"
|
||||
loading_variants: "Chargement des variantes"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Les méthodes de livraison taggées"
|
||||
shipping_method_tagged_bottom: "sont:"
|
||||
@@ -2601,6 +2602,79 @@ fr_CA:
|
||||
signup_or_login: "Commencez par vous inscrire (ou vous connecter)"
|
||||
have_an_account: "Déjà inscrit?"
|
||||
action_login: "Se connecter."
|
||||
inflections:
|
||||
each:
|
||||
one: "chacun"
|
||||
other: "chacun"
|
||||
bunch:
|
||||
one: "bouquet"
|
||||
other: "bouquets"
|
||||
pack:
|
||||
one: "caisse"
|
||||
other: "caisses"
|
||||
box:
|
||||
one: "boîte"
|
||||
other: "boîtes"
|
||||
bottle:
|
||||
one: "bouteille"
|
||||
other: "bouteilles"
|
||||
jar:
|
||||
one: "bocal"
|
||||
other: "bocaux"
|
||||
head:
|
||||
one: "tête"
|
||||
other: "têtes"
|
||||
bag:
|
||||
one: "sac"
|
||||
other: "sacs"
|
||||
loaf:
|
||||
one: "miche"
|
||||
other: "miches"
|
||||
single:
|
||||
one: "unité"
|
||||
other: "unités"
|
||||
tub:
|
||||
one: "bac"
|
||||
other: "bacs"
|
||||
punnet:
|
||||
one: "barquette"
|
||||
other: "barquettes"
|
||||
packet:
|
||||
one: "paquets"
|
||||
other: "paquets"
|
||||
item:
|
||||
one: "article"
|
||||
other: "articles"
|
||||
dozen:
|
||||
one: "dizaine"
|
||||
other: "dizaines"
|
||||
unit:
|
||||
one: "unité"
|
||||
other: "unités"
|
||||
serve:
|
||||
one: "service"
|
||||
other: "services"
|
||||
tray:
|
||||
one: "plateau"
|
||||
other: "plateaux"
|
||||
piece:
|
||||
one: "pièce"
|
||||
other: "pièces"
|
||||
pot:
|
||||
one: "pots"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "botte"
|
||||
other: "bottes"
|
||||
flask:
|
||||
one: "flacons"
|
||||
other: "flacon"
|
||||
basket:
|
||||
one: "panier"
|
||||
other: "paniers"
|
||||
sack:
|
||||
one: "sachet"
|
||||
other: "sachets"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Commencez par créer votre profil entreprise, c'est gratuit, et changez de formule quand vous êtes prêt !"
|
||||
@@ -2843,6 +2917,8 @@ fr_CA:
|
||||
zipcode: Code postal
|
||||
weight: Poids (au kg)
|
||||
error_user_destroy_with_orders: "Les utilisateurs avec des commandes finalisées pourraient ne pas être supprimés"
|
||||
cannot_create_payment_without_payment_methods: "Vous ne pouvez pas ajouter un paiement pour une commande sans avoir défini de méthode de paiement au préalable."
|
||||
please_define_payment_methods: "Il faut que vous définissiez une méthode de paiement avant tout !"
|
||||
options: "Options"
|
||||
actions:
|
||||
update: "Mettre à jour"
|
||||
|
||||
@@ -1282,6 +1282,7 @@ nb:
|
||||
saving_credit_card: Lagrer kredittkort ...
|
||||
card_has_been_removed: "Ditt kort er fjernet (nummer: %{number})"
|
||||
card_could_not_be_removed: Beklager, kortet kunne ikke fjernes
|
||||
invalid_credit_card: "Ugyldig kort"
|
||||
ie_warning_headline: "Din nettleser er for gammel :-("
|
||||
ie_warning_text: "For den beste opplevelsen med Open Food Network anbefaler vi på det sterkeste å oppgradere nettleseren din:"
|
||||
ie_warning_chrome: Last ned Chrome
|
||||
@@ -2425,11 +2426,11 @@ nb:
|
||||
description: Beskrivelse
|
||||
resolve: Løse
|
||||
exchange_products:
|
||||
load_more_products: "Last inn flere produkter"
|
||||
load_all_products: "Last inn alle produkter"
|
||||
select_all_products: "Velg alle %{total_number_of_products} produkter"
|
||||
products_loaded: "%{num_of_products_loaded} av %{total_number_of_products} produkter lastet"
|
||||
loading_products: "Laster inn produkter"
|
||||
load_more_variants: "Last inn flere varianter"
|
||||
load_all_variants: "Last inn alle varianter"
|
||||
select_all_variants: "Velg alle %{total_number_of_variants} varianter"
|
||||
variants_loaded: "%{num_of_variants_loaded} av %{total_number_of_variants} Varianter lastet"
|
||||
loading_variants: "Laster varianter"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Leveringsmetoder merket"
|
||||
shipping_method_tagged_bottom: "er:"
|
||||
@@ -2587,6 +2588,79 @@ nb:
|
||||
signup_or_login: "Kom i gang ved å registrere deg (eller logge inn)"
|
||||
have_an_account: "Har du allerede en konto?"
|
||||
action_login: "Logg inn nå."
|
||||
inflections:
|
||||
each:
|
||||
one: "Hver"
|
||||
other: "hver"
|
||||
bunch:
|
||||
one: "bunke"
|
||||
other: "bunker"
|
||||
pack:
|
||||
one: "pakke"
|
||||
other: "pakker"
|
||||
box:
|
||||
one: "eske"
|
||||
other: "esker"
|
||||
bottle:
|
||||
one: "flaske"
|
||||
other: "flasker"
|
||||
jar:
|
||||
one: "krukke"
|
||||
other: "krukker"
|
||||
head:
|
||||
one: "hode"
|
||||
other: "hoder"
|
||||
bag:
|
||||
one: "pose"
|
||||
other: "poser"
|
||||
loaf:
|
||||
one: "skive"
|
||||
other: "skiver"
|
||||
single:
|
||||
one: "enkelt"
|
||||
other: "enkle"
|
||||
tub:
|
||||
one: "kar"
|
||||
other: "kar"
|
||||
punnet:
|
||||
one: "eske"
|
||||
other: "esker"
|
||||
packet:
|
||||
one: "pakke"
|
||||
other: "pakker"
|
||||
item:
|
||||
one: "stk"
|
||||
other: "stk"
|
||||
dozen:
|
||||
one: "dusin"
|
||||
other: "dusin"
|
||||
unit:
|
||||
one: "enhet"
|
||||
other: "enheter"
|
||||
serve:
|
||||
one: "porsjon"
|
||||
other: "porsjoner"
|
||||
tray:
|
||||
one: "brett"
|
||||
other: "brett"
|
||||
piece:
|
||||
one: "stykke"
|
||||
other: "stykker"
|
||||
pot:
|
||||
one: "gryte"
|
||||
other: "gryter"
|
||||
bundle:
|
||||
one: "bunt"
|
||||
other: "bunter"
|
||||
flask:
|
||||
one: "kolbe"
|
||||
other: "kolber"
|
||||
basket:
|
||||
one: "kurv"
|
||||
other: "kurver"
|
||||
sack:
|
||||
one: "sekk"
|
||||
other: "sekker"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Start med en gratis profil, og utvid når du er klar!"
|
||||
|
||||
@@ -702,6 +702,10 @@ pt_BR:
|
||||
enable_subscriptions_false: "Desativado"
|
||||
enable_subscriptions_true: "ativado"
|
||||
shopfront_message: "Mensagem da vitrine da loja"
|
||||
shopfront_message_placeholder: >
|
||||
Uma mensagem opcional para dar as boas-vindas aos clientes e explicar
|
||||
como comprar com você. Se o texto for inserido aqui, ele será exibido
|
||||
em uma guia inicial quando os clientes chegarem à sua loja.
|
||||
shopfront_message_link_tooltip: "Inserir / editar link"
|
||||
shopfront_message_link_prompt: "Digite um URL para inserir"
|
||||
shopfront_closed_message: "Mensagem de loja fechada"
|
||||
@@ -1106,6 +1110,7 @@ pt_BR:
|
||||
already_ordered:
|
||||
cart: "Carrinho"
|
||||
message_html: "Você já possui um pedido para esta compra. Verifique o %{cart} para ver os itens já encomendados. Você também pode cancelar itens enquanto o ciclo estiver aberto."
|
||||
failed: "O checkout falhou. Informe-nos para que possamos processar seu pedido."
|
||||
shops:
|
||||
hubs:
|
||||
show_closed_shops: "Mostrar lojas fechadas"
|
||||
@@ -1276,6 +1281,7 @@ pt_BR:
|
||||
saving_credit_card: Salvando cartão de crédito...
|
||||
card_has_been_removed: "O seu cartão foi removido (número: %{number})"
|
||||
card_could_not_be_removed: Desculpe, o cartão não pode ser removido
|
||||
invalid_credit_card: "Cartão de crédito inválido"
|
||||
ie_warning_headline: "Seu navegador está desatualizado :("
|
||||
ie_warning_text: "Para a melhor experiência na Open Food Brasil, recomendamos que você atualize seu navegador:"
|
||||
ie_warning_chrome: Baixar Chrome
|
||||
@@ -1936,6 +1942,7 @@ pt_BR:
|
||||
tax_category: "Categoria de taxa"
|
||||
calculator: "Calculadora"
|
||||
calculator_values: "Valores da calculadora"
|
||||
calculator_settings_warning: "Se você estiver alterando o tipo de calculadora, salve primeiro antes de poder editar as configurações da calculadora."
|
||||
flat_percent_per_item: "Percentual (por unidade)"
|
||||
flat_rate_per_item: "Taxa fixa (por item)"
|
||||
flat_rate_per_order: "Taxa fixa ( por pedido)"
|
||||
@@ -2423,11 +2430,11 @@ pt_BR:
|
||||
description: Descrição
|
||||
resolve: Resolver
|
||||
exchange_products:
|
||||
load_more_products: "Carregar Mais Produtos"
|
||||
load_all_products: "Carregar Todos os Produtos"
|
||||
select_all_products: "Selecionar %{total_number_of_products}Produto(s)"
|
||||
products_loaded: "%{num_of_products_loaded} de %{total_number_of_products}Produtos Carregados"
|
||||
loading_products: "Carregando Produtos"
|
||||
load_more_variants: "Carregar mais variantes"
|
||||
load_all_variants: "Carregar todas as variantes"
|
||||
select_all_variants: "Selecionar todas as %{total_number_of_variants} variantes"
|
||||
variants_loaded: "%{num_of_variants_loaded} de %{total_number_of_variants} Variantes carregadas"
|
||||
loading_variants: "Carregando variantes"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Métodos de envio selecionados"
|
||||
shipping_method_tagged_bottom: "são:"
|
||||
@@ -2828,6 +2835,8 @@ pt_BR:
|
||||
zipcode: CEP
|
||||
weight: Peso (por kg)
|
||||
error_user_destroy_with_orders: "Usuários com pedidos concluídos não podem ser excluídos"
|
||||
cannot_create_payment_without_payment_methods: "Você não pode criar um pagamento para um pedido sem métodos de pagamento definidos."
|
||||
please_define_payment_methods: "Defina primeiro algum método de pagamento."
|
||||
options: "Opções"
|
||||
actions:
|
||||
update: "Atualizar"
|
||||
|
||||
3346
config/locales/tr.yml
Normal file
3346
config/locales/tr.yml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -83,6 +83,8 @@ Spree::Core::Engine.routes.draw do
|
||||
|
||||
get '/variants/search', :to => "variants#search", :as => :search_variants
|
||||
|
||||
resources :properties
|
||||
|
||||
resources :orders do
|
||||
member do
|
||||
put :fire
|
||||
@@ -110,8 +112,16 @@ Spree::Core::Engine.routes.draw do
|
||||
end
|
||||
|
||||
resource :customer, :controller => "orders/customer_details"
|
||||
|
||||
resources :return_authorizations do
|
||||
member do
|
||||
put :fire
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
resources :reports
|
||||
|
||||
resources :users do
|
||||
member do
|
||||
put :generate_api_key
|
||||
@@ -126,6 +136,7 @@ Spree::Core::Engine.routes.draw do
|
||||
end
|
||||
|
||||
resource :image_settings
|
||||
resources :trackers
|
||||
|
||||
resources :zones
|
||||
resources :countries do
|
||||
@@ -152,6 +163,10 @@ Spree::Core::Engine.routes.draw do
|
||||
resources :tax_rates
|
||||
resource :tax_settings
|
||||
resources :tax_categories
|
||||
|
||||
resources :shipping_methods
|
||||
resources :shipping_categories
|
||||
resources :payment_methods
|
||||
end
|
||||
|
||||
resources :orders do
|
||||
|
||||
@@ -15,9 +15,9 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def stripe_configuration_incomplete?(payment_method)
|
||||
return true if payment_method.preferred_enterprise_id.zero?
|
||||
|
||||
payment_method.stripe_account_id.blank?
|
||||
payment_method.preferred_enterprise_id.nil? ||
|
||||
payment_method.preferred_enterprise_id.zero? ||
|
||||
payment_method.stripe_account_id.blank?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
65
lib/open_food_network/i18n_inflections.rb
Normal file
65
lib/open_food_network/i18n_inflections.rb
Normal file
@@ -0,0 +1,65 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module OpenFoodNetwork
|
||||
# Pluralize or singularize words.
|
||||
#
|
||||
# We store some inflection data in locales and use a reverse lookup of a word
|
||||
# to find the plural or singular of the same word.
|
||||
#
|
||||
# Here is one example with a French user:
|
||||
#
|
||||
# - We have a product with the variant unit name "bouquet".
|
||||
# - The I18n.locale is set to :fr.
|
||||
# - The French locale contains:
|
||||
# bunch:
|
||||
# one: "bouquet"
|
||||
# other: "bouquets"
|
||||
# - We create a table containing:
|
||||
# "bouquet" => "bunch"
|
||||
# "bouquets" => "bunch"
|
||||
# - Looking up "bouquet" gives us the I18n key "bunch".
|
||||
# - We find the right plural by calling I18n:
|
||||
#
|
||||
# I18n.t("inflections.bunch", count: 2, default: "bouquet")
|
||||
#
|
||||
# - This returns the correct plural "bouquets".
|
||||
# - It returns the original "bouquet" if the word is missing from the locale.
|
||||
module I18nInflections
|
||||
# Make this a singleton to cache lookup tables.
|
||||
extend self
|
||||
|
||||
def pluralize(word, count)
|
||||
return word if count.nil?
|
||||
|
||||
key = i18n_key(word)
|
||||
|
||||
return word unless key
|
||||
|
||||
I18n.t(key, scope: "inflections", count: count, default: word)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def i18n_key(word)
|
||||
@lookup ||= {}
|
||||
|
||||
# The user may switch the locale. `I18n.t` is always using the current
|
||||
# locale and we need a lookup table for each of them.
|
||||
unless @lookup.key?(I18n.locale)
|
||||
@lookup[I18n.locale] = build_i18n_key_lookup
|
||||
end
|
||||
|
||||
@lookup[I18n.locale][word.downcase]
|
||||
end
|
||||
|
||||
def build_i18n_key_lookup
|
||||
lookup = {}
|
||||
I18n.t("inflections")&.each do |key, translations|
|
||||
translations.values.each do |translation|
|
||||
lookup[translation.downcase] = key
|
||||
end
|
||||
end
|
||||
lookup
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "open_food_network/i18n_inflections"
|
||||
|
||||
module OpenFoodNetwork
|
||||
class OptionValueNamer
|
||||
def initialize(variant = nil)
|
||||
@@ -38,8 +42,7 @@ module OpenFoodNetwork
|
||||
|
||||
else
|
||||
value = @variant.unit_value
|
||||
unit_name = @variant.product.variant_unit_name
|
||||
unit_name = unit_name.pluralize if value > 1
|
||||
unit_name = pluralize(@variant.product.variant_unit_name, value)
|
||||
end
|
||||
|
||||
value = value.to_i if value == value.to_i
|
||||
@@ -72,5 +75,9 @@ module OpenFoodNetwork
|
||||
|
||||
unit
|
||||
end
|
||||
|
||||
def pluralize(unit_name, count)
|
||||
I18nInflections.pluralize(unit_name, count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -207,62 +207,62 @@ describe Api::ProductsController, type: :controller do
|
||||
expect(json_response['name']).to eq("COPY OF #{product_with_image.name}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#bulk_products' do
|
||||
context "as an enterprise user" do
|
||||
let!(:taxon) { create(:taxon) }
|
||||
let!(:product2) { create(:product, supplier: supplier, primary_taxon: taxon) }
|
||||
let!(:product3) { create(:product, supplier: supplier2, primary_taxon: taxon) }
|
||||
let!(:product4) { create(:product, supplier: supplier2) }
|
||||
let(:current_api_user) { supplier_enterprise_user(supplier) }
|
||||
describe '#bulk_products' do
|
||||
context "as an enterprise user" do
|
||||
let!(:taxon) { create(:taxon) }
|
||||
let!(:product2) { create(:product, supplier: supplier, primary_taxon: taxon) }
|
||||
let!(:product3) { create(:product, supplier: supplier2, primary_taxon: taxon) }
|
||||
let!(:product4) { create(:product, supplier: supplier2) }
|
||||
let(:current_api_user) { supplier_enterprise_user(supplier) }
|
||||
|
||||
before { current_api_user.enterprise_roles.create(enterprise: supplier2) }
|
||||
before { current_api_user.enterprise_roles.create(enterprise: supplier2) }
|
||||
|
||||
it "returns a list of products" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
|
||||
expect(returned_product_ids).to eq [product4.id, product3.id, product2.id, inactive_product.id, product.id]
|
||||
end
|
||||
it "returns a list of products" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
|
||||
expect(returned_product_ids).to eq [product4.id, product3.id, product2.id, inactive_product.id, product.id]
|
||||
end
|
||||
|
||||
it "returns pagination data" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
|
||||
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
|
||||
end
|
||||
it "returns pagination data" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
|
||||
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
|
||||
end
|
||||
|
||||
it "uses defaults when page and per_page are not supplied" do
|
||||
api_get :bulk_products, format: :json
|
||||
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
|
||||
end
|
||||
it "uses defaults when page and per_page are not supplied" do
|
||||
api_get :bulk_products, format: :json
|
||||
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
|
||||
end
|
||||
|
||||
it "returns paginated products by page" do
|
||||
api_get :bulk_products, { page: 1, per_page: 2 }, format: :json
|
||||
expect(returned_product_ids).to eq [product4.id, product3.id]
|
||||
it "returns paginated products by page" do
|
||||
api_get :bulk_products, { page: 1, per_page: 2 }, format: :json
|
||||
expect(returned_product_ids).to eq [product4.id, product3.id]
|
||||
|
||||
api_get :bulk_products, { page: 2, per_page: 2 }, format: :json
|
||||
expect(returned_product_ids).to eq [product2.id, inactive_product.id]
|
||||
end
|
||||
api_get :bulk_products, { page: 2, per_page: 2 }, format: :json
|
||||
expect(returned_product_ids).to eq [product2.id, inactive_product.id]
|
||||
end
|
||||
|
||||
it "filters results by supplier" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15, q: { supplier_id_eq: supplier.id } }, format: :json
|
||||
expect(returned_product_ids).to eq [product2.id, inactive_product.id, product.id]
|
||||
end
|
||||
it "filters results by supplier" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15, q: { supplier_id_eq: supplier.id } }, format: :json
|
||||
expect(returned_product_ids).to eq [product2.id, inactive_product.id, product.id]
|
||||
end
|
||||
|
||||
it "filters results by product category" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15, q: { primary_taxon_id_eq: taxon.id } }, format: :json
|
||||
expect(returned_product_ids).to eq [product3.id, product2.id]
|
||||
end
|
||||
it "filters results by product category" do
|
||||
api_get :bulk_products, { page: 1, per_page: 15, q: { primary_taxon_id_eq: taxon.id } }, format: :json
|
||||
expect(returned_product_ids).to eq [product3.id, product2.id]
|
||||
end
|
||||
|
||||
it "filters results by import_date" do
|
||||
product.variants.first.import_date = 1.day.ago
|
||||
product2.variants.first.import_date = 2.days.ago
|
||||
product3.variants.first.import_date = 1.day.ago
|
||||
it "filters results by import_date" do
|
||||
product.variants.first.import_date = 1.day.ago
|
||||
product2.variants.first.import_date = 2.days.ago
|
||||
product3.variants.first.import_date = 1.day.ago
|
||||
|
||||
product.save
|
||||
product2.save
|
||||
product3.save
|
||||
product.save
|
||||
product2.save
|
||||
product3.save
|
||||
|
||||
api_get :bulk_products, { page: 1, per_page: 15, import_date: 1.day.ago.to_date.to_s }, format: :json
|
||||
expect(returned_product_ids).to eq [product3.id, product.id]
|
||||
end
|
||||
api_get :bulk_products, { page: 1, per_page: 15, import_date: 1.day.ago.to_date.to_s }, format: :json
|
||||
expect(returned_product_ids).to eq [product3.id, product.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,8 +30,11 @@ describe CheckoutController, concurrency: true, type: :controller do
|
||||
# New threads start running straight away. The breakpoint is after loading
|
||||
# the order and before advancing the order's state and making payments.
|
||||
breakpoint.lock
|
||||
allow(controller).to receive(:check_order_for_phantom_fees) do
|
||||
expect(controller).to receive(:fire_event).with("spree.checkout.update") do
|
||||
breakpoint.synchronize {}
|
||||
# This is what fire_event does.
|
||||
# I did not find out how to call the original code otherwise.
|
||||
ActiveSupport::Notifications.instrument("spree.checkout.update")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
require 'spec_helper'
|
||||
require 'support/request/authentication_workflow'
|
||||
|
||||
describe Spree::CheckoutController, type: :controller do
|
||||
context 'rendering edit from within spree for the current checkout state' do
|
||||
let(:order) { controller.current_order(true) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
create(:line_item, order: order)
|
||||
|
||||
allow(controller).to receive(:spree_current_user) { user }
|
||||
end
|
||||
|
||||
it "redirects to the OFN checkout page" do
|
||||
expect(spree_get(:edit)).to redirect_to checkout_path
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -542,7 +542,7 @@ feature '
|
||||
page.find("tr.supplier-#{supplier_enterprise.id} td.products").click
|
||||
expect(page).to have_selector ".exchange-product-details"
|
||||
|
||||
expect(page).to have_content "1 of 2 Products Loaded"
|
||||
expect(page).to have_content "1 of 2 Variants Loaded"
|
||||
expect(page).to_not have_content new_product.name
|
||||
end
|
||||
|
||||
@@ -562,7 +562,7 @@ feature '
|
||||
|
||||
def expect_all_products_loaded
|
||||
expect(page).to have_content new_product.name.upcase
|
||||
expect(page).to have_content "2 of 2 Products Loaded"
|
||||
expect(page).to have_content "2 of 2 Variants Loaded"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -203,6 +203,16 @@ feature '
|
||||
expect(p.reload.property('fooprop')).to be_nil
|
||||
end
|
||||
|
||||
scenario "loading new image page", js: true do
|
||||
product = create(:simple_product, supplier: @supplier2)
|
||||
|
||||
visit spree.admin_product_images_path(product)
|
||||
expect(page).to have_selector ".no-objects-found"
|
||||
|
||||
page.find('a#new_image_link').click
|
||||
expect(page).to have_selector "#image_attachment"
|
||||
end
|
||||
|
||||
scenario "deleting product images", js: true do
|
||||
product = create(:simple_product, supplier: @supplier2)
|
||||
image = File.open(File.expand_path('../../../app/assets/images/logo-white.png', __dir__))
|
||||
|
||||
@@ -710,13 +710,22 @@ describe "AdminProductEditCtrl", ->
|
||||
$httpBackend.flush()
|
||||
expect($scope.displayFailure).toHaveBeenCalled()
|
||||
|
||||
it "shows an alert with error information when post returns 400 with an errors array", ->
|
||||
spyOn(window, "alert")
|
||||
$scope.products = "updated list of products"
|
||||
$httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": ["an error"] }
|
||||
$scope.updateProducts "updated list of products"
|
||||
$httpBackend.flush()
|
||||
expect(window.alert).toHaveBeenCalledWith("Saving failed with the following error(s):\nan error\n")
|
||||
describe "displaying the error information when post returns 400", ->
|
||||
beforeEach ->
|
||||
spyOn $scope, "displayFailure"
|
||||
$scope.products = "updated list of products"
|
||||
|
||||
it "displays errors in an array", ->
|
||||
$httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": ["an error"] }
|
||||
$scope.updateProducts "updated list of products"
|
||||
$httpBackend.flush()
|
||||
expect($scope.displayFailure).toHaveBeenCalledWith("Saving failed with the following error(s):\nan error\n")
|
||||
|
||||
it "displays errors in a hash", ->
|
||||
$httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": { "base": ["a basic error"] } }
|
||||
$scope.updateProducts "updated list of products"
|
||||
$httpBackend.flush()
|
||||
expect($scope.displayFailure).toHaveBeenCalledWith("Saving failed with the following error(s):\na basic error\n")
|
||||
|
||||
|
||||
describe "adding variants", ->
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
describe "OptionValueNamer", ->
|
||||
subject = null
|
||||
|
||||
beforeEach ->
|
||||
module('admin.products')
|
||||
inject (_OptionValueNamer_) ->
|
||||
subject = new _OptionValueNamer_
|
||||
|
||||
describe "pluralize a variant unit name", ->
|
||||
it "returns the same word if no plural is known", ->
|
||||
expect(subject.pluralize("foo", 2)).toEqual "foo"
|
||||
|
||||
it "returns the same word if we omit the quantity", ->
|
||||
expect(subject.pluralize("loaf")).toEqual "loaf"
|
||||
|
||||
it "finds the plural of a word", ->
|
||||
expect(subject.pluralize("loaf", 2)).toEqual "loaves"
|
||||
|
||||
it "finds the singular of a word", ->
|
||||
expect(subject.pluralize("loaves", 1)).toEqual "loaf"
|
||||
|
||||
it "finds the zero form of a word", ->
|
||||
expect(subject.pluralize("loaf", 0)).toEqual "loaves"
|
||||
|
||||
it "ignores upper case", ->
|
||||
expect(subject.pluralize("Loaf", 2)).toEqual "loaves"
|
||||
@@ -0,0 +1,20 @@
|
||||
describe "ErrorsParser service", ->
|
||||
errorsParser = null
|
||||
|
||||
beforeEach ->
|
||||
module('admin.utils')
|
||||
inject (ErrorsParser) ->
|
||||
errorsParser = ErrorsParser
|
||||
|
||||
describe "toString", ->
|
||||
it "returns empty string for nil errors", ->
|
||||
expect(errorsParser.toString(null)).toEqual ""
|
||||
|
||||
it "returns the elements in the array if an array is provided", ->
|
||||
expect(errorsParser.toString(["1", "2"])).toEqual "1\n2\n"
|
||||
|
||||
it "returns the elements in the hash if a hash is provided", ->
|
||||
expect(errorsParser.toString({ "keyname": ["1", "2"] })).toEqual "1\n2\n"
|
||||
|
||||
it "returns all elements in all hash keys provided", ->
|
||||
expect(errorsParser.toString({ "keyname1": ["1", "2"], "keyname2": ["3", "4"] })).toEqual "1\n2\n3\n4\n"
|
||||
40
spec/lib/open_food_network/i18n_inflections_spec.rb
Normal file
40
spec/lib/open_food_network/i18n_inflections_spec.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'open_food_network/i18n_inflections'
|
||||
|
||||
describe OpenFoodNetwork::I18nInflections do
|
||||
let(:subject) { described_class }
|
||||
|
||||
it "returns the same word if no plural is known" do
|
||||
expect(subject.pluralize("foo", 2)).to eq "foo"
|
||||
end
|
||||
|
||||
it "finds the plural of a word" do
|
||||
expect(subject.pluralize("bunch", 2)).to eq "bunches"
|
||||
end
|
||||
|
||||
it "finds the singular of a word" do
|
||||
expect(subject.pluralize("bunch", 1)).to eq "bunch"
|
||||
end
|
||||
|
||||
it "ignores upper case" do
|
||||
expect(subject.pluralize("Bunch", 2)).to eq "bunches"
|
||||
end
|
||||
|
||||
it "switches locales" do
|
||||
skip "French plurals not available yet"
|
||||
I18n.with_locale(:fr) do
|
||||
expect(subject.pluralize("bouquet", 2)).to eq "bouquets"
|
||||
end
|
||||
end
|
||||
|
||||
it "builds the lookup table once" do
|
||||
# Cache the table:
|
||||
subject.pluralize("bunch", 2)
|
||||
|
||||
# Expect only one call for the plural:
|
||||
expect(I18n).to receive(:t).once.and_call_original
|
||||
subject.pluralize("bunch", 2)
|
||||
end
|
||||
end
|
||||
72
spec/services/checkout/form_data_adapter_spec.rb
Normal file
72
spec/services/checkout/form_data_adapter_spec.rb
Normal file
@@ -0,0 +1,72 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Checkout::FormDataAdapter do
|
||||
describe '#order_params' do
|
||||
let(:params) { { order: { order_id: "123" } } }
|
||||
let(:order) { create(:order) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
let(:adapter) { Checkout::FormDataAdapter.new(params, order, user) }
|
||||
|
||||
it "returns the :order item in the params provided" do
|
||||
order_params = adapter.order_params
|
||||
|
||||
expect(order_params).to eq params[:order]
|
||||
end
|
||||
|
||||
describe "when payment_attributes are provided" do
|
||||
before { params[:order][:payments_attributes] = [{ payment_method_id: "123" }] }
|
||||
|
||||
describe "and source attributes are provided" do
|
||||
let(:source_attributes) { { payment_method_name: "Pay at the farm" } }
|
||||
|
||||
before { params[:payment_source] = { "123" => source_attributes } }
|
||||
|
||||
it "moves payment source attributes to the order payment attributes" do
|
||||
order_params = adapter.order_params
|
||||
|
||||
expect(order_params[:payments_attributes].
|
||||
first[:source_attributes]).to eq source_attributes
|
||||
end
|
||||
end
|
||||
|
||||
describe "and order total is not zero" do
|
||||
before { order.total = "50.0" }
|
||||
|
||||
it "sets the payment attributes amount to the order total" do
|
||||
order_params = adapter.order_params
|
||||
|
||||
expect(order_params[:payments_attributes].first[:amount]).to eq order.total
|
||||
end
|
||||
end
|
||||
|
||||
describe "and existing credit card is provided" do
|
||||
before { params[:order][:existing_card_id] = credit_card.id }
|
||||
|
||||
describe "and credit card is owned by current user" do
|
||||
let(:credit_card) { create(:credit_card, user_id: user.id) }
|
||||
|
||||
before { params[:order][:existing_card_id] = credit_card.id }
|
||||
|
||||
it "adds card details to payment attributes" do
|
||||
order_params = adapter.order_params
|
||||
|
||||
expect(order_params[:payments_attributes].first[:source][:id]).to eq credit_card.id
|
||||
expect(order_params[:payments_attributes].
|
||||
first[:source][:last_digits]).to eq credit_card.last_digits
|
||||
end
|
||||
end
|
||||
|
||||
describe "and credit card is not owned by current user" do
|
||||
let(:credit_card) { create(:credit_card) }
|
||||
|
||||
it "raises exception if credit card provided doesnt belong to the current user" do
|
||||
expect { adapter.order_params }.to raise_error Spree::Core::GatewayError
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
47
spec/services/checkout/payment_redirect_spec.rb
Normal file
47
spec/services/checkout/payment_redirect_spec.rb
Normal file
@@ -0,0 +1,47 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Checkout::PaymentRedirect do
|
||||
describe '#order_params' do
|
||||
let(:params) { { order: { order_id: "123" } } }
|
||||
|
||||
let(:redirect) { Checkout::PaymentRedirect.new(params) }
|
||||
|
||||
it "returns nil if payment_attributes are not provided" do
|
||||
expect(redirect.path).to be nil
|
||||
end
|
||||
|
||||
describe "when payment_attributes are provided" do
|
||||
it "raises an error if payment method does not exist" do
|
||||
params[:order][:payments_attributes] = [{ payment_method_id: "123" }]
|
||||
|
||||
expect { redirect.path }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
describe "when payment method provided exists" do
|
||||
before { params[:order][:payments_attributes] = [{ payment_method_id: payment_method.id }] }
|
||||
|
||||
describe "and the payment method is not a paypal payment method" do
|
||||
let(:payment_method) { create(:payment_method) }
|
||||
|
||||
it "returns nil" do
|
||||
expect(redirect.path).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "and the payment method is a paypal method" do
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:payment_method) do
|
||||
Spree::Gateway::PayPalExpress.create!(name: "PayPalExpress",
|
||||
distributor_ids: [distributor.id])
|
||||
end
|
||||
|
||||
it "returns the redirect path" do
|
||||
expect(redirect.path).to include payment_method.id.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
35
spec/services/user_default_address_setter_spec.rb
Normal file
35
spec/services/user_default_address_setter_spec.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe UserDefaultAddressSetter do
|
||||
let(:customer_address) { create(:address, address1: "customer road") }
|
||||
let(:order_address) { create(:address, address1: "order road") }
|
||||
let(:customer) do
|
||||
create(:customer, bill_address: customer_address, ship_address: customer_address)
|
||||
end
|
||||
let(:order) do
|
||||
create(:order, customer: customer, bill_address: order_address, ship_address: order_address)
|
||||
end
|
||||
let(:user) { create(:user) }
|
||||
|
||||
let(:setter) { UserDefaultAddressSetter.new(order, user) }
|
||||
|
||||
describe '#set_default_bill_address' do
|
||||
it "sets the user and customer bill address to the order bill address" do
|
||||
setter.set_default_bill_address
|
||||
|
||||
expect(user.bill_address).to eq order.bill_address
|
||||
expect(order.customer.bill_address).to eq order.bill_address
|
||||
end
|
||||
end
|
||||
|
||||
describe '#set_default_ship_address' do
|
||||
it "sets the user and customer ship address to the order ship address" do
|
||||
setter.set_default_ship_address
|
||||
|
||||
expect(user.ship_address).to eq order.ship_address
|
||||
expect(order.customer.ship_address).to eq order.ship_address
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user