Compare commits

...

233 Commits

Author SHA1 Message Date
Maikel Linke
12fde5b9fc Update all locales with the latest Transifex translations 2020-01-16 15:28:57 +11:00
Maikel
0da6275d41 Merge pull request #4675 from Matt-Yorkley/rails-4-prep-3
Rails 4 prep continued
2020-01-16 15:08:11 +11:00
Maikel
52d2d1d23c Merge pull request #4668 from Matt-Yorkley/rails-4-prep-2
Rails 4 prep: admin dashboard route
2020-01-16 14:16:32 +11:00
Maikel
4dfc020eaa Merge pull request #4666 from openfoodfoundation/transifex
Transifex
2020-01-16 12:10:12 +11:00
Maikel
8ef52f97e5 Merge pull request #4665 from openfoodfoundation/dependabot/bundler/selenium-webdriver-3.142.7
Bump selenium-webdriver from 3.142.6 to 3.142.7
2020-01-16 12:09:29 +11:00
Maikel
68a7f547b1 Merge pull request #4664 from openfoodfoundation/dependabot/bundler/test-unit-3.3.5
Bump test-unit from 3.3.4 to 3.3.5
2020-01-16 12:08:51 +11:00
Maikel
7a0f2d47a3 Merge pull request #4660 from openfoodfoundation/dependabot/bundler/activerecord-import-1.0.4
Bump activerecord-import from 1.0.3 to 1.0.4
2020-01-16 12:06:15 +11:00
Luis Ramos
4affd01b7b Merge pull request #4627 from luisramos0/mini_racer
Update libv8 and keep it only in Gemfile.lock as a dependency of mini_racer
2020-01-15 22:25:25 +00:00
Luis Ramos
0432c73f19 Merge pull request #4510 from luisramos0/backend_ctrl_resource
Bring spree_backend resource controller to OFN
2020-01-15 22:22:24 +00:00
Matt-Yorkley
103902c006 Replace deprecated arguments in #find_by
Failure/Error: enterprise = Enterprise.find_by(name: enterprise_name, select: 'id, is_primary_producer')

       ActiveRecord::StatementInvalid:
         PG::UndefinedColumn: ERROR:  column enterprises.select does not exist
         LINE 1: ...HERE "enterprises"."name" = 'User Enterprise' AND "enterpris...
         : SELECT  "enterprises".* FROM "enterprises"  WHERE "enterprises"."name" = 'User Enterprise' AND "enterprises"."select" = 'id, is_primary_producer' LIMIT 1
       # ./app/models/product_import/spreadsheet_data.rb:48:in `block in create_enterprises_index'
       # ./app/models/product_import/spreadsheet_data.rb:43:in `each'
2020-01-15 16:39:33 +01:00
Matt-Yorkley
d2933e35f1 Explicitly require Spree::Admin::BaseHelper
NameError: undefined method `preference_field_tag' for module `Spree::Admin::BaseHelper'
/home/runner/openfoodnetwork/vendor/bundle/ruby/2.3.0/gems/activesupport-4.0.13/lib/active_support/core_ext/module/aliasing.rb:32:in `alias_method'
/home/runner/openfoodnetwork/vendor/bundle/ruby/2.3.0/gems/activesupport-4.0.13/lib/active_support/core_ext/module/aliasing.rb:32:in `alias_method_chain'
/home/runner/openfoodnetwork/app/helpers/spree/admin/base_helper_decorator.rb:11:in `<module:BaseHelper>'
/home/runner/openfoodnetwork/app/helpers/spree/admin/base_helper_decorator.rb:3:in `<module:Admin>'
2020-01-15 13:07:50 +01:00
Matt-Yorkley
0b5e341ae7 Explicitly require Spree::Admin::NavigationHelper
NameError: undefined method `klass_for' for module `Spree::Admin::NavigationHelper'
/home/runner/openfoodnetwork/vendor/bundle/ruby/2.3.0/gems/activesupport-4.0.13/lib/active_support/core_ext/module/aliasing.rb:32:in `alias_method'
/home/runner/openfoodnetwork/vendor/bundle/ruby/2.3.0/gems/activesupport-4.0.13/lib/active_support/core_ext/module/aliasing.rb:32:in `alias_method_chain'
/home/runner/openfoodnetwork/app/helpers/spree/admin/navigation_helper_decorator.rb:18:in `<module:NavigationHelper>'
2020-01-15 13:07:46 +01:00
Matt-Yorkley
7d36c3b5aa Make some private methods public in orders_and_fulfillments_report.rb
Fixes errors for "call to private method ..."
2020-01-15 13:05:36 +01:00
Matt-Yorkley
d511763733 Replace deprecated #in? method 2020-01-15 12:57:38 +01:00
Matt-Yorkley
a059c11d0f Update post/delete calls in credit_cards_controller_spec.rb
ActionController::UrlGenerationError:
       No route matches {:action=>"new_from_token", :cc_type=>"visa", :controller=>"spree/credit_cards", :exp_month=>12, :exp_year=>2020, :format=>:json, :last4=>4242, :token=>"tok_234bd2c22"}
     # ./spec/controllers/spree/credit_cards_controller_spec.rb:36:in `block (5 levels) in <top (required)>'
     # ./spec/controllers/spree/credit_cards_controller_spec.rb:36:in `block (4 levels) in <top (required)>'
2020-01-15 12:57:38 +01:00
Matt-Yorkley
cecc19ae1d Add recommended paper_trail config
DEPRECATION WARNING: PaperTrail.track_associations has not been set. As of PaperTrail 5, it defaults to false. Tracking associations is an experimental feature so we recommend setting PaperTrail.config.track_associations = false in your config/initializers/paper_trail.rb . (called from block (3 levels) in <top (required)> at /home/user/Github/openfoodnetwork/spec/controllers/admin/column_preferences_controller_spec.rb:10)
2020-01-15 12:57:38 +01:00
Matt-Yorkley
d4311a848e Fix default_scope deprecated syntax 2020-01-15 12:57:38 +01:00
Transifex-Openfoodnetwork
d64573f7fd Updating translations for config/locales/nb.yml 2020-01-15 22:29:37 +11:00
Transifex-Openfoodnetwork
a9fe6ec1b5 Updating translations for config/locales/nb.yml 2020-01-15 22:26:30 +11:00
Transifex-Openfoodnetwork
f14bbc5ed9 Updating translations for config/locales/nb.yml 2020-01-15 22:23:20 +11:00
Matt-Yorkley
5ba8efec2c Fix enterprise group spec
EnterpriseGroup.by_position now returns an ActiveRecord::Relation in Rails 4, so in this test case it doesn't respond as an array
2020-01-15 11:19:14 +01:00
Luis Ramos
3bf38b7c08 Merge pull request #4549 from luisramos0/arelize_order_permissions
Use arel in order permissions visible orders and editable orders so that we dont have queries with gigantic IN clauses
2020-01-14 14:24:34 +00:00
Transifex-Openfoodnetwork
a591e0736f Updating translations for config/locales/en_CA.yml 2020-01-14 23:41:38 +11:00
Luis Ramos
3080eb9dfd Merge pull request #4578 from kshlyk/remove_soft_delete_from_product_and_variant_api
Removing duplicate API method soft_delete for both products and variants
2020-01-14 11:32:10 +00:00
Transifex-Openfoodnetwork
ed98a16eec Updating translations for config/locales/fr.yml 2020-01-14 20:18:13 +11:00
Transifex-Openfoodnetwork
7a924bd9ca Updating translations for config/locales/fr.yml 2020-01-14 20:15:05 +11:00
Transifex-Openfoodnetwork
7639e19184 Updating translations for config/locales/en_FR.yml 2020-01-14 20:13:12 +11:00
Transifex-Openfoodnetwork
71aff7e1d2 Updating translations for config/locales/fr.yml 2020-01-14 20:11:56 +11:00
dependabot-preview[bot]
2506667bca Bump selenium-webdriver from 3.142.6 to 3.142.7
Bumps [selenium-webdriver](https://github.com/SeleniumHQ/selenium) from 3.142.6 to 3.142.7.
- [Release notes](https://github.com/SeleniumHQ/selenium/releases)
- [Changelog](https://github.com/SeleniumHQ/selenium/blob/master/rb/CHANGES)
- [Commits](https://github.com/SeleniumHQ/selenium/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-13 19:37:48 +00:00
Luis Ramos
f87a553230 Merge pull request #4648 from openfoodfoundation/dependabot/bundler/rubocop-0.79.0
Bump rubocop from 0.68.1 to 0.79.0
2020-01-13 19:35:50 +00:00
Luis Ramos
3171b60d6f Merge pull request #4580 from Matt-Yorkley/order_capture
Use asynchronous requests for order capture and ship actions
2020-01-13 17:14:40 +00:00
Luis Ramos
516398fbd6 Merge pull request #4638 from luisramos0/fix_cart_s2
Replace adjustment.open with adjustment.fire_events(open) to avoid method name conflict
2020-01-13 14:16:56 +00:00
Luis Ramos
4a1b74c136 Merge pull request #4634 from luisramos0/remove_dead_code
Remove some dead code
2020-01-13 11:09:04 +00:00
Matt-Yorkley
b9edea7c0e Rename 'admin/overview#index' route from :admin to :admin_dashboard
Fixes issues with route declarations in Rails 4
2020-01-12 13:11:33 +01:00
Transifex-Openfoodnetwork
b9053f9fd2 Updating translations for config/locales/en_NZ.yml 2020-01-12 18:37:55 +11:00
dependabot-preview[bot]
f297cff8c7 Bump test-unit from 3.3.4 to 3.3.5
Bumps [test-unit](https://github.com/test-unit/test-unit) from 3.3.4 to 3.3.5.
- [Release notes](https://github.com/test-unit/test-unit/releases)
- [Commits](https://github.com/test-unit/test-unit/compare/3.3.4...3.3.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-10 19:17:47 +00:00
Luis Ramos
7563d38b4b Merge pull request #4658 from openfoodfoundation/dependabot/bundler/ddtrace-0.31.0
Bump ddtrace from 0.30.0 to 0.31.0
2020-01-10 10:52:04 +00:00
Luis Ramos
83523a676f Merge pull request #4659 from openfoodfoundation/dependabot/bundler/webdrivers-4.2.0
Bump webdrivers from 4.1.3 to 4.2.0
2020-01-10 10:51:10 +00:00
Maikel Linke
abcfb5ce8d Update Rubocop config for new version
- A couple of cops moved into a different namespace.
- The target ruby version doesn't have to be specified, it's read from
  .ruby-version which has been updated to Ruby 2.3.
- Some files were missing in the todo lists.
2020-01-10 08:59:44 +11:00
Maikel Linke
8ee6d1c320 Add rubocop-rails gem
The rails cops used to be in the rubocop gem itself but moved into their
own gem recently. Our style guide refers to these cops though.
2020-01-10 08:59:44 +11:00
dependabot-preview[bot]
1bc19ad6a4 Bump rubocop from 0.68.1 to 0.79.0
Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 0.68.1 to 0.79.0.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.68.1...v0.79.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-10 08:59:44 +11:00
Maikel
191b8064ed Merge pull request #4629 from openfoodfoundation/dependabot/bundler/unicorn-5.5.2
Bump unicorn from 5.5.1 to 5.5.2
2020-01-10 08:29:17 +11:00
dependabot-preview[bot]
e28274db14 Bump activerecord-import from 1.0.3 to 1.0.4
Bumps [activerecord-import](https://github.com/zdennis/activerecord-import) from 1.0.3 to 1.0.4.
- [Release notes](https://github.com/zdennis/activerecord-import/releases)
- [Changelog](https://github.com/zdennis/activerecord-import/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zdennis/activerecord-import/compare/v1.0.3...v1.0.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-09 19:16:47 +00:00
Luis Ramos
02dec1d6cd Merge pull request #4649 from tomekr/4623-remove-additional-footeer-links
Remove duplicate footer links
2020-01-09 18:04:30 +00:00
Luis Ramos
df04c837a5 Merge pull request #4631 from Matt-Yorkley/oc_buttons
Increase space for buttons in savebar layout
2020-01-09 17:56:01 +00:00
Luis Ramos
7a6c085b63 Merge pull request #4625 from openfoodfoundation/dependabot/bundler/roo-2.8.2
Bump roo from 2.7.1 to 2.8.2
2020-01-09 17:55:24 +00:00
dependabot-preview[bot]
a4317b70f4 Bump webdrivers from 4.1.3 to 4.2.0
Bumps [webdrivers](https://github.com/titusfortner/webdrivers) from 4.1.3 to 4.2.0.
- [Release notes](https://github.com/titusfortner/webdrivers/releases)
- [Changelog](https://github.com/titusfortner/webdrivers/blob/master/CHANGELOG.md)
- [Commits](https://github.com/titusfortner/webdrivers/compare/v4.1.3...v4.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-08 19:16:43 +00:00
dependabot-preview[bot]
cb90fb052d Bump ddtrace from 0.30.0 to 0.31.0
Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 0.30.0 to 0.31.0.
- [Release notes](https://github.com/DataDog/dd-trace-rb/releases)
- [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/DataDog/dd-trace-rb/compare/v0.30.0...v0.31.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-08 19:15:48 +00:00
Luis Ramos
18e5f9ba64 Merge pull request #4647 from jeduardo824/remove-groups-tab
remove group link from shop menu when there are no groups
2020-01-08 11:44:51 +00:00
Luis Ramos
e9a5b889de Merge pull request #4606 from cyrillefr/lone-hub-checked-by-default-4428
Select by default single Hub/Shop option on creation of payment/shipping method
2020-01-08 11:44:16 +00:00
Luis Ramos
cc57b0c200 Merge pull request #4609 from openfoodfoundation/dependabot/bundler/excon-0.71.1
[Security] Bump excon from 0.62.0 to 0.71.1
2020-01-08 09:49:13 +00:00
Maikel
a8040e986d Merge pull request #4626 from openfoodfoundation/dependabot/bundler/i18n-js-3.5.1
Bump i18n-js from 3.5.0 to 3.5.1
2020-01-08 17:58:53 +11:00
Maikel
2269f824c0 Merge pull request #4637 from openfoodfoundation/transifex
Transifex
2020-01-08 17:56:37 +11:00
Eduardo
c45a3c2303 remove group tabs from shop view when there are no groups 2020-01-07 11:24:46 -03:00
Tomek Rabczak
1327d80446 fixup: Revert non en.yml locale changes as they are generated via transifex 2020-01-06 16:33:36 -06:00
Tomek Rabczak
43a3ac0a7b Remove no longer used locales 2020-01-06 13:56:35 -06:00
Tomek Rabczak
b948312de7 Remove additional footer links 2020-01-06 13:47:54 -06:00
Transifex-Openfoodnetwork
7063de4734 Updating translations for config/locales/fr_CA.yml 2020-01-04 06:22:08 +11:00
Transifex-Openfoodnetwork
56c1a9cca2 Updating translations for config/locales/fr_CA.yml 2020-01-04 06:19:02 +11:00
Transifex-Openfoodnetwork
9555bfcc93 Updating translations for config/locales/fr.yml 2020-01-04 06:17:34 +11:00
Transifex-Openfoodnetwork
e455a47135 Updating translations for config/locales/fr.yml 2020-01-04 06:14:27 +11:00
Transifex-Openfoodnetwork
e15e71a3a7 Updating translations for config/locales/en_CA.yml 2020-01-04 06:07:34 +11:00
Matt-Yorkley
91d959b7d6 Remove "previous" button from order cycle savebar 2020-01-03 16:25:26 +01:00
luisramos0
108f57a705 Replace adjustment.open with adjustment.fire_events(open) to avoid method name conflict 2020-01-02 16:58:11 +00:00
Transifex-Openfoodnetwork
af42159e09 Updating translations for config/locales/en_GB.yml 2020-01-03 01:37:14 +11:00
Transifex-Openfoodnetwork
8e55c39ca0 Updating translations for config/locales/en_GB.yml 2020-01-03 01:34:04 +11:00
luisramos0
6cfb060184 Update all locales with the latest Transifex translations 2020-01-02 10:37:13 +00:00
Luis Ramos
0cfb7269c8 Merge pull request #4596 from openfoodfoundation/transifex
Transifex
2020-01-02 10:34:20 +00:00
luisramos0
cbec495620 Fix some rubocop issues in order_and_distributor_report 2019-12-29 19:01:44 +00:00
luisramos0
55eea21bb0 Adapt order_and_distributor_report to the new editable_orders query 2019-12-29 19:01:44 +00:00
luisramos0
f63c7cf54f Extract visible_orders_where_values to a private method 2019-12-29 19:01:44 +00:00
luisramos0
13633e8bea Use arel in order permissions visible orders and editable orders so that we dont have queries with gigantic IN clauses
The | operators here were converting the relations to long lists of IDs, in our current particular issue, an IN clause with 100k order_ids
2019-12-29 19:01:44 +00:00
luisramos0
093edb66d3 Remove unused view
This was introduced in 2013 and removed in 2014, see log below:

git log -Saddress_form_simple
commit 510333288c
Author: Maikel Linke <mkllnk@web.de>
Date:   Sun Mar 2 13:05:15 2014 +1100

    first steps of new design

commit 2e1de9a6d3
Author: Rohan Mitchell <rohan@rohanmitchell.com>
Date:   Fri Aug 23 13:12:36 2013 +1000

    Fix admin create order - remove override on spree address form, update to spree patched to fix respond_override (spree issue #2210), fix nil state error
2019-12-28 18:25:28 +00:00
luisramos0
fb25ddd219 Remove reference to user banners, this code is not used in OFN. 2019-12-28 18:13:04 +00:00
luisramos0
d54850f097 Move ActionCallBacks out of the spree namespace 2019-12-27 17:04:40 +00:00
luisramos0
f8451a2511 Bring needed action_callbacks from spree_backend 2019-12-27 17:04:31 +00:00
luisramos0
1a88549954 Update rubocop todo lists 2019-12-27 17:04:23 +00:00
luisramos0
f79182253a Fix some rubocop issues 2019-12-27 17:03:39 +00:00
luisramos0
8cfd7c610b Use nested module instead of class Spree::Admin:: 2019-12-27 17:03:39 +00:00
luisramos0
486b5e9edc Merge resource_decorator into resource controller 2019-12-27 17:03:39 +00:00
luisramos0
8fe3abfd45 Add resource_controller from spree_backend so that we can now merge it with the OFN's decorator 2019-12-27 17:03:39 +00:00
Luis Ramos
0e7dafea46 Merge pull request #4560 from kshlyk/fix_billing_addres_in_pdf_invoice
Billing address in pdf invoice fixed
2019-12-27 16:45:06 +00:00
Matt-Yorkley
4c9cc7460a Increase space for buttons in savebar layout 2019-12-27 17:08:37 +01:00
dependabot-preview[bot]
c9e3f58aed Bump unicorn from 5.5.1 to 5.5.2
Bumps [unicorn](https://bogomips.org/unicorn/) from 5.5.1 to 5.5.2.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-26 19:16:30 +00:00
Luis Ramos
4136306abf Updating mini_racer and libv8 at the same time 2019-12-26 11:01:09 +00:00
Luis Ramos
9f1eaf0b66 Merge pull request #4512 from luisramos0/backend_ctrl_base
Bring spree_backend base controller to OFN
2019-12-24 12:01:07 +00:00
dependabot-preview[bot]
4771612adb Bump i18n-js from 3.5.0 to 3.5.1
Bumps [i18n-js](https://github.com/fnando/i18n-js) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/fnando/i18n-js/releases)
- [Changelog](https://github.com/fnando/i18n-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fnando/i18n-js/compare/v3.5.0...v3.5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-23 19:21:17 +00:00
dependabot-preview[bot]
7ce3dfe365 Bump roo from 2.7.1 to 2.8.2
Bumps [roo](https://github.com/roo-rb/roo) from 2.7.1 to 2.8.2.
- [Release notes](https://github.com/roo-rb/roo/releases)
- [Changelog](https://github.com/roo-rb/roo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/roo-rb/roo/compare/v2.7.1...v2.8.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-23 19:17:19 +00:00
Luis Ramos
6f13707b9d Merge pull request #4556 from openfoodfoundation/dependabot/bundler/stripe-5.11.0
Bump stripe from 4.24.0 to 5.11.0
2019-12-23 16:19:05 +00:00
Luis Ramos
64cb104434 Merge pull request #4577 from openfoodfoundation/dependabot/bundler/oj-3.10.0
Bump oj from 3.7.12 to 3.10.0
2019-12-23 16:14:33 +00:00
Luis Ramos
1606f9900f Merge pull request #4507 from luisramos0/backend_ctrl_reports
Bring spree_backend reports controller to OFN
2019-12-23 16:14:07 +00:00
Luis Ramos
9f0e8b0b2e Merge pull request #4558 from openfoodfoundation/dependabot/bundler/mini_racer-0.2.4
Bump mini_racer from 0.1.15 to 0.2.4
2019-12-23 16:13:10 +00:00
Luis Ramos
d796e96470 Merge pull request #4575 from Matt-Yorkley/admin_orders
Fix route on "continue" button on admin adjustments page
2019-12-23 16:12:28 +00:00
Luis Ramos
ba7f78ef60 Merge pull request #4515 from luisramos0/backend_ctrl_adjustments
Bring spree_backend adjustments controller to OFN
2019-12-23 16:05:04 +00:00
Maikel
988e146240 Merge pull request #4564 from openfoodfoundation/dependabot/bundler/rack-mini-profiler-1.1.4
Bump rack-mini-profiler from 1.0.0 to 1.1.4
2019-12-20 17:42:04 +11:00
cyrillefr
e6d9ec7bd7 Small fixes for default single Hub/Shop options issue
- removed mode variable
 - reverted html template accordingly
 - added a more specific helper
 - fixed some short variable names
2019-12-19 21:08:34 +01:00
Transifex-Openfoodnetwork
3acc53a389 Updating translations for config/locales/ar.yml 2019-12-20 04:33:09 +11:00
Transifex-Openfoodnetwork
9c9fc999de Updating translations for config/locales/ar.yml 2019-12-20 04:30:00 +11:00
Transifex-Openfoodnetwork
d824c84ce6 Updating translations for config/locales/fr.yml 2019-12-19 19:14:24 +11:00
Transifex-Openfoodnetwork
1a301f3dbb Updating translations for config/locales/fr.yml 2019-12-19 19:11:16 +11:00
Transifex-Openfoodnetwork
fad4f3b22a Updating translations for config/locales/en_FR.yml 2019-12-19 19:08:18 +11:00
Transifex-Openfoodnetwork
6080c99850 Updating translations for config/locales/fr.yml 2019-12-19 19:08:07 +11:00
Transifex-Openfoodnetwork
2944acff8a Updating translations for config/locales/nb.yml 2019-12-19 09:52:35 +11:00
dependabot-preview[bot]
2068a59b72 [Security] Bump excon from 0.62.0 to 0.71.1
Bumps [excon](https://github.com/excon/excon) from 0.62.0 to 0.71.1. **This update includes a security fix.**
- [Release notes](https://github.com/excon/excon/releases)
- [Changelog](https://github.com/excon/excon/blob/master/changelog.txt)
- [Commits](https://github.com/excon/excon/compare/v0.62.0...v0.71.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-18 19:33:23 +00:00
Luis Ramos
3063439ed1 Merge pull request #4541 from Matt-Yorkley/new_fee_errors
Handle validation messages when saving new fees
2019-12-18 13:35:45 +00:00
Matt-Yorkley
6bed05c721 Add missing feature test for order "Ship" button 2019-12-18 14:15:48 +01:00
Matt-Yorkley
a3ee6674ea Use asynchronous requests for order capture and ship actions 2019-12-18 14:15:46 +01:00
cyrillefr
e59077e63e Select by default single Hub/Shop option on creation of payment/shipping method
- added a helper
- added mode(new/edit) in payment/shipping views
- updated checkbox creation
- added tests
2019-12-18 10:45:00 +01:00
Transifex-Openfoodnetwork
f9f8d85841 Updating translations for config/locales/fr.yml 2019-12-18 04:37:36 +11:00
Transifex-Openfoodnetwork
0042690e18 Updating translations for config/locales/en_FR.yml 2019-12-18 04:35:31 +11:00
Transifex-Openfoodnetwork
5f1111b52b Updating translations for config/locales/fr.yml 2019-12-18 04:34:28 +11:00
Luis Ramos
25ded0d23c Merge pull request #4471 from luisramos0/paginate_exc_prods
Paginate Exchange Products API endpoint
2019-12-17 15:25:15 +00:00
Luis Ramos
a5458150ca Merge pull request #4455 from luisramos0/oc_prods
In the OC edit page, load products only when each products tab is opened by user
2019-12-17 13:40:19 +00:00
Pau Pérez Fabregat
96eebbabf3 Merge pull request #4590 from luisramos0/capybara
Upgrade capybara and webdrivers
2019-12-17 10:55:59 +01:00
luisramos0
c58e6fa964 Upgrade capybara 2019-12-16 15:25:45 +00:00
luisramos0
fbe8f5195c Upgrade webdrivers to latest 2019-12-16 15:25:36 +00:00
luisramos0
f587bbb7d5 Remove unnecessary helper 2019-12-15 21:03:53 +00:00
luisramos0
2793693a7c Improve if clause readability 2019-12-15 21:03:53 +00:00
luisramos0
07e2317369 Replace deprecated URI.unescape with CGI.unescape 2019-12-15 21:03:53 +00:00
luisramos0
042162eda8 Delete unused method 2019-12-15 21:03:53 +00:00
luisramos0
795f13d73a Remove spree alerts feature that would check spree website for security alerts
This is not something we need running such an old version of spree
2019-12-15 21:03:53 +00:00
luisramos0
f1814f1b67 Fix most rubocop issues in spree/admin/base_controller 2019-12-15 21:03:53 +00:00
luisramos0
4ab7b78cb8 Merge base_controller with its decorator 2019-12-15 21:03:53 +00:00
luisramos0
11631c3a33 Add base_controller from spree_backend so that we can now merge it with the OFN's decorator 2019-12-15 21:03:53 +00:00
Konstantin Shlyk
0212381362 fix for api/variants_controller_spec 2019-12-14 21:43:38 +03:00
Konstantin Shlyk
e6ca6bacac soft_delete api method deleted for products and variants 2019-12-14 01:05:35 +03:00
dependabot-preview[bot]
59df45b8cf Bump oj from 3.7.12 to 3.10.0
Bumps [oj](https://github.com/ohler55/oj) from 3.7.12 to 3.10.0.
- [Release notes](https://github.com/ohler55/oj/releases)
- [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/ohler55/oj/compare/v3.7.12...v3.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-13 19:17:46 +00:00
Luis Ramos
5892e85869 Merge pull request #4559 from openfoodfoundation/dependabot/bundler/selenium-webdriver-3.142.6
Bump selenium-webdriver from 3.141.0 to 3.142.6
2019-12-13 18:05:03 +00:00
luisramos0
c59326743b Remove sales total report 2019-12-13 16:44:46 +00:00
luisramos0
cb3397fd1a Convert reports index and sales_total views from erb to haml 2019-12-13 16:44:46 +00:00
luisramos0
2bd4de3e29 Add sales total report view 2019-12-13 16:44:46 +00:00
luisramos0
b2c5be775e Fix some rubocop issues 2019-12-13 16:44:46 +00:00
luisramos0
d22212ccfa Merge spree/admin/reports_controller with its decorator 2019-12-13 16:44:44 +00:00
luisramos0
dd600cd163 Add reports_controller from spree_backend so that we can now merge it with the OFN's decorator 2019-12-13 15:20:03 +00:00
Matt-Yorkley
f189ca8004 Fix route on "continue" button on admin adjustments page 2019-12-13 13:51:41 +01:00
Luis Ramos
db7146014c Rename exchange products file names to increase clarity 2019-12-13 12:24:19 +00:00
Luis Ramos
c6af55d9ae Restructure exchange products panels so that OC simple form does not include header and footer (product count and pagination) of the non-simple OC form 2019-12-13 12:24:16 +00:00
Maikel
0f588dbe0b Merge pull request #4561 from openfoodfoundation/transifex
Transifex
2019-12-13 17:02:32 +11:00
dependabot-preview[bot]
9c14d8ff36 Bump rack-mini-profiler from 1.0.0 to 1.1.4
Bumps [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler) from 1.0.0 to 1.1.4.
- [Release notes](https://github.com/MiniProfiler/rack-mini-profiler/releases)
- [Changelog](https://github.com/MiniProfiler/rack-mini-profiler/blob/master/CHANGELOG.md)
- [Commits](https://github.com/MiniProfiler/rack-mini-profiler/compare/v1.0.0...v1.1.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-12 19:14:17 +00:00
luisramos0
a104bf8efd Add feature spec to validate load all and select all exchange products 2019-12-12 18:49:11 +00:00
luisramos0
a039ef13f4 Add spec for exchange products controller pagination 2019-12-12 18:49:11 +00:00
luisramos0
7ad8951375 DRY exchange products templates by extracting header and footer content to partial templates 2019-12-12 18:49:11 +00:00
luisramos0
99e59595b4 Add spinner when loading all products in an exchange 2019-12-12 18:48:36 +00:00
luisramos0
3264355f12 Add some basic test coverage to exchange_products_controller and exchange_products_renderer 2019-12-12 18:48:36 +00:00
luisramos0
7e3b6e2b5d Fix select all checkbox state in both incoming and outgoing exchanges by using the total count of variants to see if all variants are selected or not, even if not all variants are loaded 2019-12-12 18:48:36 +00:00
luisramos0
a9598c5d97 Only show load more and load all if not all products are loaded already 2019-12-12 18:48:36 +00:00
luisramos0
3e5b7ebbf1 Show exchange products list only after first page of products is loaded 2019-12-12 18:48:36 +00:00
luisramos0
1a9c3007b0 Make select all work again in incoming exchanges by loading alll products before triggering the select all process 2019-12-12 18:48:35 +00:00
luisramos0
2f7fd1482a Add link to load all products at the top of the list of products and include summary of number of products loaded already 2019-12-12 18:48:35 +00:00
luisramos0
0416521772 Add load all prouducts button to list of exchange products 2019-12-12 18:48:35 +00:00
luisramos0
cfe3f72d0e Add load more button to list of exchange products 2019-12-12 18:48:35 +00:00
luisramos0
00478cc57c Add count variants endpoint and use it instead of loading exchange products 2019-12-12 18:48:35 +00:00
luisramos0
d5e42ee1e5 Paginate exchange products results
This commit breaks the OC page when there are more than 100 products in an exchange
2019-12-12 18:48:35 +00:00
luisramos0
9451f1b66d Remove funky panel open listener code and initialize the panel data with a ng-init in the panel template 2019-12-12 18:44:45 +00:00
luisramos0
ff584f9be9 Adapt exchange products routes to make api/exchanges/products (without exchange_id) also go to exchange_products#index 2019-12-12 18:44:45 +00:00
luisramos0
a589ba38da Rename exchanges_products_controller to better exchange_products_controller 2019-12-12 18:44:45 +00:00
luisramos0
a4a2f98b6e Rename Product service to more appropriate ExchangeProduct 2019-12-12 18:44:45 +00:00
luisramos0
f5ddbfbac3 Make Product service more simple, there's no need to keep the data structure, that is already kept in the controller 2019-12-12 18:44:45 +00:00
luisramos0
a66a4c3edb Remove unnecessary passing of scopes around in controllers 2019-12-12 18:44:45 +00:00
luisramos0
8179252924 Replace the use of this with 2019-12-12 18:44:45 +00:00
luisramos0
0bec492208 Fix some rubocop issues 2019-12-12 18:44:45 +00:00
luisramos0
5cf50f0adf Convert the manipulation of arrays into active record relations: let the DB do the matching job 2019-12-12 18:44:45 +00:00
luisramos0
197fb36524 Extract ExchangeProductsRenderer from ExchangesProductsController 2019-12-12 18:44:45 +00:00
luisramos0
62e6f09d94 Make exchange products more simple 2019-12-12 18:44:45 +00:00
luisramos0
79b2460664 Make simple create and edit OC load exchange products on init
Simple create makes a new type of call to exchange products with no exchange_id and no prder_cycle_id, it simply lists supplied products for a given enterprise
2019-12-12 18:44:44 +00:00
luisramos0
66f3656bb5 Register products panel listeners after OrderCycle is loaded instead of using recurrent timeouts
Also, use this same approach for the case where a new distributor or new supplier is added to the list of exchanges
2019-12-12 18:44:44 +00:00
luisramos0
6b087adab8 Add route to process requests to exchanges/products without exchange id
This is needed when products for an exchange that is not yet saved are requested
2019-12-12 18:44:44 +00:00
luisramos0
3653b88da6 Make exchanges_products_controller more independent of the exchange field 2019-12-12 18:44:44 +00:00
luisramos0
3223bf930d Make total number of products in exchange work again.
Currently we are just loading the products from the server and count them.
This can be improved easily in two ways:
- we can switch this to a specific product count call to the server so that we dont load all products all the time
- or we paginate the products result and fetch the total_number from the payload of the first page.
2019-12-12 18:44:44 +00:00
luisramos0
2b3bc6d1ff Remove supplied products from enterprise serializer and from UI side
This list of products s now loaded in a specific call to ExchangeProducts and for each specific exchange
2019-12-12 18:44:44 +00:00
luisramos0
24d7672abb Use new exchange products endpoint for outgoing exchanges and make the exchange products panel work for outgoing exchanges 2019-12-12 18:44:44 +00:00
luisramos0
89628c27f3 Move exchange products endpoint to api namespace and make it work for outgoing exchanges 2019-12-12 18:44:44 +00:00
luisramos0
9adbdc377d Add new admin/exchange/products endpoint that replaces Enterprise/for_order_cycle#supplied_products 2019-12-12 18:44:44 +00:00
luisramos0
883cd81058 Load enterprise supplied products when the exchange products panel is opened for the first time 2019-12-12 18:44:44 +00:00
Transifex-Openfoodnetwork
0d7d029255 Updating translations for config/locales/en_GB.yml 2019-12-13 02:07:44 +11:00
Kristina Lim
ce31a059bf Merge pull request #4553 from openfoodfoundation/transifex
Transifex
2019-12-12 22:46:22 +08:00
Luis Ramos
17bac20c65 Merge pull request #4550 from luisramos0/fix_of_report
Remove eager loding of shipping_methods and shipping_rates from customer_totals so that report runs faster
2019-12-12 14:15:19 +00:00
Pau Pérez Fabregat
066243057f Merge pull request #4545 from coopdevs/fix-db-backups
Make whenever properly read the S3 bucket
2019-12-12 11:39:54 +01:00
Transifex-Openfoodnetwork
ea40547fd7 Updating translations for config/locales/fr_CA.yml 2019-12-12 10:22:26 +11:00
Transifex-Openfoodnetwork
0ebc6d4b1e Updating translations for config/locales/en_CA.yml 2019-12-12 09:28:07 +11:00
Transifex-Openfoodnetwork
62c2e4709a Updating translations for config/locales/en_CA.yml 2019-12-12 09:25:01 +11:00
Konstantin Shlyk
c5229dd763 billing address in pdf invoice fixed 2019-12-11 23:10:51 +03:00
dependabot-preview[bot]
99d4190814 Bump selenium-webdriver from 3.141.0 to 3.142.6
Bumps [selenium-webdriver](https://github.com/SeleniumHQ/selenium) from 3.141.0 to 3.142.6.
- [Release notes](https://github.com/SeleniumHQ/selenium/releases)
- [Changelog](https://github.com/SeleniumHQ/selenium/blob/master/rb/CHANGES)
- [Commits](https://github.com/SeleniumHQ/selenium/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-11 19:35:45 +00:00
dependabot-preview[bot]
f086c02e13 Bump mini_racer from 0.1.15 to 0.2.4
Bumps [mini_racer](https://github.com/discourse/mini_racer) from 0.1.15 to 0.2.4.
- [Release notes](https://github.com/discourse/mini_racer/releases)
- [Changelog](https://github.com/rubyjs/mini_racer/blob/master/CHANGELOG)
- [Commits](https://github.com/discourse/mini_racer/compare/v0.1.15...v0.2.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-11 19:35:03 +00:00
dependabot-preview[bot]
b726f961fc Bump stripe from 4.24.0 to 5.11.0
Bumps [stripe](https://github.com/stripe/stripe-ruby) from 4.24.0 to 5.11.0.
- [Release notes](https://github.com/stripe/stripe-ruby/releases)
- [Changelog](https://github.com/stripe/stripe-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-ruby/compare/v4.24.0...v5.11.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-11 19:33:30 +00:00
Transifex-Openfoodnetwork
4c17cf0087 Updating translations for config/locales/fr.yml 2019-12-12 04:29:14 +11:00
Transifex-Openfoodnetwork
9fe143cf94 Updating translations for config/locales/en_FR.yml 2019-12-12 04:26:13 +11:00
Transifex-Openfoodnetwork
e2d783c385 Updating translations for config/locales/fr.yml 2019-12-12 04:26:05 +11:00
Transifex-Openfoodnetwork
81cb162884 Updating translations for config/locales/nb.yml 2019-12-12 03:34:25 +11:00
Transifex-Openfoodnetwork
c7b6dd2677 Updating translations for config/locales/nb.yml 2019-12-12 03:31:14 +11:00
Transifex-Openfoodnetwork
d1fd73fd2b Updating translations for config/locales/ar.yml 2019-12-12 03:16:38 +11:00
Transifex-Openfoodnetwork
b0221d264e Updating translations for config/locales/ar.yml 2019-12-12 03:13:31 +11:00
Transifex-Openfoodnetwork
0f64badc74 Updating translations for config/locales/ar.yml 2019-12-12 03:10:21 +11:00
Luis Ramos
7ccfdc8d21 Merge pull request #4546 from kshlyk/fix_cart_link_on_mobile
Cart link in header on mobile leads to cart page instead of checkout …
2019-12-11 13:45:56 +00:00
Luis Ramos
4799293996 Merge pull request #4518 from Matt-Yorkley/ruby-2.3.7
Bump Ruby to 2.3.7
2019-12-11 13:29:01 +00:00
Luis Ramos
58a93c27ae Merge pull request #4539 from luisramos0/subs_s3
Make weight calculator work for SubscriptionLineItems
2019-12-11 11:20:53 +00:00
luisramos0
0202b59634 Remove eager loding of shipping_methods and shipping_rates from customer_totals so that report runs faster
Something makes the query run much slower with these includes
2019-12-10 21:18:17 +00:00
Luis Ramos
9f351607d1 Merge pull request #4538 from mkllnk/4537-paginated-product-order
Make product order deterministic
2019-12-10 18:00:45 +00:00
Maikel
c45e3c9cca Merge pull request #4543 from openfoodfoundation/transifex
Transifex
2019-12-10 20:10:23 +11:00
Luis Ramos
71bf3f5f71 Merge pull request #4514 from luisramos0/backend_ctrl_overview
Bring spree_backend overview controller to OFN
2019-12-09 23:36:32 +00:00
Konstantin Shlyk
ef142de5f2 Cart link in header on mobile leads to cart page instead of checkout page 2019-12-09 22:58:00 +03:00
luisramos0
f64e8bf50e Make user aware of server side errors when saving subscription products and unit test products_panel_controller 2019-12-09 17:49:38 +00:00
Pau Perez
e8d68e3b89 Make whenever properly read the S3 bucket
For unknown reasons the magic
[Figaro](https://github.com/laserlemon/figaro) does to turn keys in
`config/application.yml` into ENV vars that can be read through Ruby's
`ENV[]` is not working in `config/schedule.rb`.

As a result, the `db2fog` tasks are not translated into cron entries
which led to not having automatic backups.
2019-12-09 17:16:11 +01:00
luisramos0
1b29d474d0 Add specs to cover case where updating subscriptions products quantity fails 2019-12-09 15:11:32 +00:00
Luis Ramos
baae58ecb6 Merge pull request #4288 from luisramos0/oc_serializer_spec
Add spec for api/admin/order_cycle_serializer
2019-12-09 11:16:04 +00:00
Pau Pérez Fabregat
6411871ecb Merge pull request #4540 from openfoodfoundation/dependabot/bundler/ddtrace-0.30.0
Bump ddtrace from 0.29.1 to 0.30.0
2019-12-09 09:48:27 +01:00
Transifex-Openfoodnetwork
22833ae79b Updating translations for config/locales/it.yml 2019-12-09 19:28:13 +11:00
Transifex-Openfoodnetwork
ac20b0e7fb Updating translations for config/locales/it.yml 2019-12-09 19:25:06 +11:00
luisramos0
e9e6aa77d8 Make weight calculator work for SubscriptionLineItems by making it test if line_item responds to final_weight_volume field (final_weight_volume_present?)
We also add logic to weight_per_variant so that we use variant.unit_value if final_weight_volume is not available but variant_unit is weight
Adapt some test case to test unit_value (in grams) instead of weight (in kgs)
2019-12-08 17:36:21 +00:00
Matt-Yorkley
29e30c388e Make error message translatable 2019-12-07 15:48:46 +01:00
Matt-Yorkley
54a40fe79c Handle validation messages when saving new fees 2019-12-07 14:51:17 +01:00
dependabot-preview[bot]
7840118dea Bump ddtrace from 0.29.1 to 0.30.0
Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 0.29.1 to 0.30.0.
- [Release notes](https://github.com/DataDog/dd-trace-rb/releases)
- [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/DataDog/dd-trace-rb/compare/v0.29.1...v0.30.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-06 19:18:08 +00:00
luisramos0
5e27bd6d6d Add for now very basic spec to api/admin/order_cycle_serializer 2019-12-06 16:41:54 +00:00
Maikel Linke
d4512904ea Make product order deterministic
When products are sorted by name and two products have the same name,
their order is undefined. With pagination, two pages can have a
different order of products with the same name which then means that two
pages can return the same product.

Sorting by product id makes sure that the result is always in the same
order, for every page.
2019-12-05 15:37:10 +11:00
Maikel
52dc288470 Merge pull request #4530 from openfoodfoundation/transifex
Transifex
2019-12-05 11:01:30 +11:00
Luis Ramos
302de04e73 Merge pull request #4526 from kristinalim/fix/3149-fix_tool_tips_in_orders_list
3149 Fix tooltips in orders list
2019-12-04 10:38:28 +00:00
Transifex-Openfoodnetwork
41767936d6 Updating translations for config/locales/ca.yml 2019-12-03 22:50:13 +11:00
Transifex-Openfoodnetwork
0ccf30202e Updating translations for config/locales/ca.yml 2019-12-03 22:47:06 +11:00
Transifex-Openfoodnetwork
00f36e4686 Updating translations for config/locales/ca.yml 2019-12-03 22:43:57 +11:00
Maikel
4d77f30bc0 Merge pull request #4506 from openfoodfoundation/dependabot/bundler/ddtrace-0.29.1
Bump ddtrace from 0.29.0 to 0.29.1
2019-12-03 20:39:58 +11:00
Maikel
f38b1b95f0 Merge pull request #4525 from kristinalim/fix/4489-flaky_spec_for_editing_oc
4489 Improve waiting in feature spec for edit Order Cycle page
2019-12-03 20:36:37 +11:00
Kristina Lim
852adfd436 Improve waiting in feature spec for order cycle page 2019-12-02 20:06:43 +08:00
Kristina Lim
2673a6efee Fix Angular tracking of row in orders list
The tooltip content for the order in index n in page x was being used
for the order in index n in page y.

This was because ng-repeat was tracking the items/rows by index.
As far as ng-repeat is aware, rows with the same index in any page
were the same items/rows, so it didn't bother relinking the ofn-with-tip
directive.
2019-11-30 03:53:20 +08:00
Kristina Lim
6ffe7f1a99 Set width and enable wrapping for tooltips 2019-11-30 03:53:16 +08:00
luisramos0
ba1ad0a6dd Rename decorator to controller so that the rubocop exception for the index action keeps being seen by code climate 2019-11-28 16:47:02 +00:00
luisramos0
4e7b397c5a Bring orders adjustments route from spree_backend 2019-11-28 16:26:22 +00:00
luisramos0
842e191c5f Remove toggle_state action that is not used in OFN 2019-11-28 16:20:35 +00:00
Matt-Yorkley
feaa928674 Bump Ruby to 2.3.7 🎉 2019-11-28 10:42:13 +01:00
luisramos0
c8d359a0da Merge spree/admin/overview_controller with its decorator 2019-11-27 22:08:46 +00:00
luisramos0
210757641c Add overview_controller from spree_backend so that we can now merge it with the OFN's decorator 2019-11-27 22:08:06 +00:00
luisramos0
68bf599a1a Merge spree/admin/adjustments_controller with decorator 2019-11-27 21:59:15 +00:00
luisramos0
a10966b66b Add adjustments_controller from spree_backend so that we can now merge it with the OFN's decorator 2019-11-27 21:59:15 +00:00
dependabot-preview[bot]
08003f2003 Bump ddtrace from 0.29.0 to 0.29.1
Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 0.29.0 to 0.29.1.
- [Release notes](https://github.com/DataDog/dd-trace-rb/releases)
- [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/DataDog/dd-trace-rb/compare/v0.29.0...v0.29.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-27 19:17:20 +00:00
166 changed files with 4082 additions and 1812 deletions

View File

@@ -4,6 +4,7 @@
#
# The configuration is split into three files. Look into those files for more details.
#
require: rubocop-rails
inherit_from:
# The automatically generated todo list to ignore all current violations.

View File

@@ -18,7 +18,7 @@
#
# This process probably doesn't need repeating. Otherwise there is plenty
# of room for improvements and automation.
Metrics/LineLength:
Layout/LineLength:
Max: 100
Exclude:
- Gemfile
@@ -42,7 +42,6 @@ Metrics/LineLength:
- app/controllers/application_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/adjustments_controller_decorator.rb
- app/controllers/spree/admin/base_controller_decorator.rb
- app/controllers/spree/admin/orders_controller_decorator.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/credit_cards_controller.rb
@@ -115,7 +114,6 @@ Metrics/LineLength:
- lib/open_food_network/enterprise_issue_validator.rb
- lib/open_food_network/group_buy_report.rb
- lib/open_food_network/lettuce_share_report.rb
- lib/open_food_network/order_and_distributor_report.rb
- lib/open_food_network/order_cycle_form_applicator.rb
- lib/open_food_network/order_cycle_management_report.rb
- lib/open_food_network/payments_report.rb
@@ -144,6 +142,7 @@ Metrics/LineLength:
- spec/controllers/admin/subscriptions_controller_spec.rb
- spec/controllers/admin/variant_overrides_controller_spec.rb
- spec/controllers/api/base_controller_spec.rb
- spec/controllers/api/exchange_products_controller_spec.rb
- spec/controllers/api/logos_controller_spec.rb
- spec/controllers/api/order_cycles_controller_spec.rb
- spec/controllers/api/orders_controller_spec.rb
@@ -305,6 +304,7 @@ Metrics/LineLength:
- spec/serializers/api/admin/exchange_serializer_spec.rb
- spec/serializers/api/admin/for_order_cycle/enterprise_serializer_spec.rb
- spec/serializers/api/admin/for_order_cycle/supplied_product_serializer_spec.rb
- spec/serializers/api/admin/order_cycle_serializer_spec.rb
- spec/serializers/api/admin/subscription_customer_serializer_spec.rb
- spec/serializers/api/admin/variant_override_serializer_spec.rb
- spec/serializers/api/current_order_serializer_spec.rb
@@ -312,11 +312,13 @@ Metrics/LineLength:
- spec/serializers/api/order_serializer_spec.rb
- spec/services/cart_service_spec.rb
- spec/services/embedded_page_service_spec.rb
- spec/services/exchange_products_renderer_spec.rb
- spec/services/order_cycle_distributed_products_spec.rb
- spec/services/order_cycle_distributed_variants_spec.rb
- spec/services/order_cycle_form_spec.rb
- spec/services/order_factory_spec.rb
- spec/services/order_syncer_spec.rb
- spec/services/permissions/order_spec.rb
- spec/services/product_tag_rules_filterer_spec.rb
- spec/services/products_renderer_spec.rb
- spec/services/subscription_estimator_spec.rb
@@ -362,11 +364,12 @@ Metrics/AbcSize:
- app/controllers/spree/admin/image_settings_controller.rb
- app/controllers/spree/admin/orders/customer_details_controller_decorator.rb
- app/controllers/spree/admin/orders_controller_decorator.rb
- app/controllers/spree/admin/overview_controller_decorator.rb
- app/controllers/spree/admin/overview_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/products_controller_decorator.rb
- app/controllers/spree/admin/reports_controller_decorator.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb
- app/controllers/spree/admin/search_controller_decorator.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/admin/users_controller.rb
@@ -565,7 +568,8 @@ Metrics/MethodLength:
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/products_controller_decorator.rb
- app/controllers/spree/admin/reports_controller_decorator.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb
- app/controllers/spree/admin/search_controller_decorator.rb
- app/controllers/spree/admin/tax_categories_controller.rb
- app/controllers/spree/admin/taxons_controller.rb
@@ -644,7 +648,10 @@ Metrics/ClassLength:
- app/controllers/admin/subscriptions_controller.rb
- app/controllers/api/products_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/base_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb
- app/controllers/spree/admin/users_controller.rb
- app/controllers/spree/orders_controller.rb
- app/models/enterprise.rb
@@ -700,6 +707,7 @@ Metrics/ModuleLength:
- spec/models/spree/payment_spec.rb
- spec/models/spree/product_spec.rb
- spec/models/spree/variant_spec.rb
- spec/services/permissions/order_spec.rb
- spec/support/request/web_helper.rb
Metrics/ParameterLists:

View File

@@ -5,7 +5,6 @@
# rubocop locally, the default configuration file `.rubocop.yml` loads
# our "todo lists" to ignore all current violations.
AllCops:
TargetRubyVersion: 2.2
TargetRailsVersion: 3.2
Exclude:
- 'bin/**/*'
@@ -41,7 +40,7 @@ Layout/MultilineMethodCallIndentation:
Enabled: true
EnforcedStyle: indented
Metrics/LineLength:
Layout/LineLength:
Max: 100
## TEMPORARY/CONTESTED SETTINGS

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
2.2.10
2.3.7

18
Gemfile
View File

@@ -1,9 +1,9 @@
source 'https://rubygems.org'
ruby "2.2.10"
ruby "2.3.7"
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
gem 'i18n', '~> 0.6.11'
gem 'i18n-js', '~> 3.5.0'
gem 'i18n-js', '~> 3.5.1'
gem 'rails', '~> 3.2.22'
gem 'rails-i18n', '~> 3.0.0'
gem 'rails_safe_tasks', '~> 1.0'
@@ -93,7 +93,7 @@ gem 'wkhtmltopdf-binary'
gem 'foreigner'
gem 'immigrant'
gem 'roo', '~> 2.7.0'
gem 'roo', '~> 2.8.2'
gem 'roo-xls', '~> 1.1.0'
gem 'whenever', require: false
@@ -106,10 +106,7 @@ group :assets do
gem 'coffee-rails', '~> 3.2.1'
gem 'compass-rails'
gem 'mini_racer', '0.1.15'
# Previously we found that libv8 6.7.288.46.1 breakis the compilation of mini_racer.
# Now we see that we need to set the version explicitly. Nothing else depends on libv8.
gem 'libv8', '6.3.292.48.1'
gem 'mini_racer', '0.2.4'
gem 'uglifier', '>= 1.0.3'
@@ -135,7 +132,7 @@ group :test, :development do
# Pretty printed test output
gem 'atomic'
gem 'awesome_print'
gem 'capybara', '>= 2.15.4'
gem 'capybara', '>= 2.18.0' # 3.0 requires nokogiri 1.8
gem 'database_cleaner', '0.7.1', require: false
gem "factory_bot_rails", require: false
gem 'fuubar', '~> 2.5.0'
@@ -148,7 +145,7 @@ group :test, :development do
gem 'shoulda-matchers'
gem 'timecop'
gem 'unicorn-rails'
gem 'webdrivers', '3.8.1'
gem 'webdrivers'
end
group :test do
@@ -163,7 +160,8 @@ group :development do
gem 'debugger-linecache'
gem "newrelic_rpm", "~> 3.0"
gem 'pry-byebug', '>= 3.4.3'
gem 'rubocop', '>= 0.49.1'
gem 'rubocop'
gem 'rubocop-rails'
gem 'spring', '1.7.2'
gem 'spring-commands-rspec'

View File

@@ -129,7 +129,7 @@ GEM
activesupport (= 3.2.22.5)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activerecord-import (1.0.3)
activerecord-import (1.0.4)
activerecord (>= 3.2)
activerecord-postgresql-adapter (0.0.1)
pg
@@ -178,8 +178,7 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (>= 2.0, < 4.0)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
childprocess (3.0.0)
chronic (0.10.2)
chunky_png (1.3.10)
climate_control (0.2.0)
@@ -213,7 +212,6 @@ GEM
sass-rails (< 5.1)
sprockets (< 4.0)
concurrent-ruby (1.1.5)
connection_pool (2.2.2)
crack (0.4.3)
safe_yaml (~> 1.0.0)
css_parser (1.7.0)
@@ -225,7 +223,7 @@ GEM
activerecord (>= 3.2.0, < 5.0)
fog (~> 1.0)
rails (>= 3.2.0, < 5.0)
ddtrace (0.29.0)
ddtrace (0.31.0)
msgpack
debugger-linecache (1.2.0)
deface (1.0.2)
@@ -256,17 +254,17 @@ GEM
dry-inflector (0.1.2)
erubis (2.7.0)
eventmachine (1.2.7)
excon (0.62.0)
excon (0.71.1)
execjs (2.7.0)
factory_bot (4.10.0)
activesupport (>= 3.0.0)
factory_bot_rails (4.10.0)
factory_bot (~> 4.10.0)
railties (>= 3.0.0)
faraday (0.15.4)
faraday (0.17.1)
multipart-post (>= 1.2, < 3)
ffaker (1.22.1)
ffi (1.10.0)
ffi (1.11.3)
figaro (1.1.1)
thor (~> 0.14)
fission (0.5.0)
@@ -439,7 +437,7 @@ GEM
httparty (0.16.2)
multi_xml (>= 0.5.2)
i18n (0.6.11)
i18n-js (3.5.0)
i18n-js (3.5.1)
i18n (>= 0.6.6)
immigrant (0.3.6)
activerecord (>= 3.0)
@@ -467,7 +465,7 @@ GEM
addressable (~> 2.3)
letter_opener (1.7.0)
launchy (~> 2.2)
libv8 (6.3.292.48.1)
libv8 (7.3.492.27.1)
mail (2.5.5)
mime-types (~> 1.16)
treetop (~> 1.4.8)
@@ -475,8 +473,8 @@ GEM
mime-types (1.25.1)
mini_mime (1.0.1)
mini_portile2 (2.1.0)
mini_racer (0.1.15)
libv8 (~> 6.3)
mini_racer (0.2.4)
libv8 (>= 6.3)
momentjs-rails (2.20.1)
railties (>= 3.1)
money (5.1.1)
@@ -485,8 +483,6 @@ GEM
multi_json (1.14.1)
multi_xml (0.6.0)
multipart-post (2.1.1)
net-http-persistent (3.1.0)
connection_pool (~> 2.2)
newrelic_rpm (3.18.1.330)
nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
@@ -496,7 +492,7 @@ GEM
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
oj (3.7.12)
oj (3.10.0)
orm_adapter (0.5.0)
paper_trail (5.2.3)
activerecord (>= 3.0, < 6.0)
@@ -507,10 +503,10 @@ GEM
activesupport (>= 3.0.0)
cocaine (~> 0.5.0)
mime-types
parallel (1.18.0)
parallel (1.19.1)
paranoia (1.3.4)
activerecord (~> 3.1)
parser (2.6.5.0)
parser (2.7.0.2)
ast (~> 2.4.0)
paypal-sdk-core (0.2.10)
multi_json (~> 1.0)
@@ -534,7 +530,7 @@ GEM
rack (1.4.7)
rack-cache (1.9.0)
rack (>= 0.4)
rack-mini-profiler (1.0.0)
rack-mini-profiler (1.1.4)
rack (>= 1.2.0)
rack-protection (1.5.5)
rack
@@ -588,9 +584,9 @@ GEM
roadie-rails (1.3.0)
railties (>= 3.0, < 5.3)
roadie (~> 3.1)
roo (2.7.1)
roo (2.8.2)
nokogiri (~> 1)
rubyzip (~> 1.1, < 2.0.0)
rubyzip (>= 1.2.1, < 2.0.0)
roo-xls (1.1.0)
nokogiri
roo (>= 2.0.0beta1, < 3)
@@ -618,13 +614,16 @@ GEM
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-support (3.9.0)
rubocop (0.68.1)
rubocop (0.79.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.6)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-rails (2.4.1)
rack (>= 1.1)
rubocop (>= 0.72.0)
ruby-ole (1.2.12.1)
ruby-progressbar (1.10.1)
ruby-rc4 (0.1.5)
@@ -638,9 +637,9 @@ GEM
select2-rails (3.4.9)
sass-rails
thor (~> 0.14)
selenium-webdriver (3.141.0)
childprocess (~> 0.5)
rubyzip (~> 1.2, >= 1.2.2)
selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
simplecov (0.17.1)
@@ -666,10 +665,8 @@ GEM
tilt (~> 1.1, != 1.3.0)
state_machine (1.2.0)
stringex (1.5.1)
stripe (4.24.0)
faraday (~> 0.13)
net-http-persistent (~> 3.0)
test-unit (3.3.4)
stripe (5.11.0)
test-unit (3.3.5)
power_assert
thor (0.20.3)
tilt (1.4.1)
@@ -682,11 +679,11 @@ GEM
turbo-sprockets-rails3 (0.3.14)
railties (> 3.2.8, < 4.0.0)
sprockets (>= 2.2.0)
tzinfo (0.3.55)
tzinfo (0.3.56)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.5.0)
unicorn (5.5.1)
unicode-display_width (1.6.0)
unicorn (5.5.2)
kgio (~> 2.6)
raindrops (~> 0.7)
unicorn-rails (2.2.1)
@@ -699,10 +696,10 @@ GEM
railties (>= 3.0)
warden (1.2.7)
rack (>= 1.0)
webdrivers (3.8.1)
webdrivers (4.2.0)
nokogiri (~> 1.6)
rubyzip (~> 1.0)
selenium-webdriver (~> 3.0)
rubyzip (>= 1.3.0)
selenium-webdriver (>= 3.0, < 4.0)
webmock (3.7.6)
addressable (>= 2.3.6)
crack (>= 0.3.2)
@@ -734,7 +731,7 @@ DEPENDENCIES
blockenspiel
bugsnag
byebug (~> 9.0.0)
capybara (>= 2.15.4)
capybara (>= 2.18.0)
coffee-rails (~> 3.2.1)
combine_pdf
compass-rails
@@ -763,7 +760,7 @@ DEPENDENCIES
gmaps4rails
haml
i18n (~> 0.6.11)
i18n-js (~> 3.5.0)
i18n-js (~> 3.5.1)
immigrant
jquery-migrate-rails
jquery-rails (= 3.0.4)
@@ -772,8 +769,7 @@ DEPENDENCIES
kaminari (~> 0.14.1)
knapsack
letter_opener (>= 1.4.1)
libv8 (= 6.3.292.48.1)
mini_racer (= 0.1.15)
mini_racer (= 0.2.4)
momentjs-rails
newrelic_rpm (~> 3.0)
nokogiri (>= 1.6.7.1)
@@ -794,11 +790,12 @@ DEPENDENCIES
rails_safe_tasks (~> 1.0)
redcarpet
roadie-rails (~> 1.3.0)
roo (~> 2.7.0)
roo (~> 2.8.2)
roo-xls (~> 1.1.0)
rspec-rails (>= 3.5.2)
rspec-retry
rubocop (>= 0.49.1)
rubocop
rubocop-rails
sass (~> 3.3)
sass-rails (~> 3.2.3)
selenium-webdriver
@@ -821,14 +818,14 @@ DEPENDENCIES
unicorn
unicorn-rails
web!
webdrivers (= 3.8.1)
webdrivers
webmock
whenever
wicked_pdf
wkhtmltopdf-binary
RUBY VERSION
ruby 2.2.10p489
ruby 2.3.7p456
BUNDLED WITH
1.17.2

View File

@@ -142,7 +142,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
if confirm("Are you sure?")
$http(
method: "DELETE"
url: "/api/products/" + product.id + "/soft_delete"
url: "/api/products/" + product.id
).success (data) ->
$scope.products.splice $scope.products.indexOf(product), 1
DirtyProducts.deleteProduct product.id
@@ -157,7 +157,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
if confirm(t("are_you_sure"))
$http(
method: "DELETE"
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id
).success (data) ->
$scope.removeVariant(product, variant)
else

View File

@@ -1,5 +1,31 @@
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $controller, $location, Enterprise, ocInstance) ->
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $controller, $location, Enterprise, OrderCycle, ExchangeProduct, ocInstance) ->
$controller('AdminOrderCycleExchangesCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
$scope.enterpriseTotalVariants = (enterprise) ->
Enterprise.totalVariants(enterprise)
$scope.view = 'incoming'
$scope.exchangeTotalVariants = (exchange) ->
return unless $scope.enterprises? && $scope.enterprises[exchange.enterprise_id]?
enterprise = $scope.enterprises[exchange.enterprise_id]
return enterprise.numVariants if enterprise.numVariants?
enterprise.numVariants = 0
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: true}
ExchangeProduct.countVariants params, (variants_count) ->
enterprise.numVariants = variants_count
$scope.setSelectAllVariantsCheckboxValue(exchange, enterprise.numVariants)
return enterprise.numVariants
$scope.addSupplier = ($event) ->
$event.preventDefault()
OrderCycle.addSupplier $scope.new_supplier_id
# To select all variants we first need to load them all from the server
#
# This is only needed in Incoming exchanges as here we use supplied_products,
# in Outgoing Exchanges the variants are loaded as part of the Exchange payload
$scope.selectAllVariants = (exchange, selected) ->
$scope.loadAllExchangeProducts(exchange).then ->
$scope.setExchangeVariants(exchange, $scope.suppliedVariants(exchange.enterprise_id), selected)
$scope.$apply()

View File

@@ -18,11 +18,11 @@ angular.module('admin.orderCycles')
$scope.cancel = (destination) ->
$window.location = destination
# Used in panels/exchange_supplied_products.html
# Used in panels/exchange_products_supplied.html
$scope.suppliedVariants = (enterprise_id) ->
Enterprise.suppliedVariants(enterprise_id)
# Used in panels/exchange_supplied_products.html and panels/exchange_distributed_products.html
# Used in panels/exchange_products_supplied.html and panels/exchange_products_distributed.html
$scope.setExchangeVariants = (exchange, variants, selected) ->
OrderCycle.setExchangeVariants(exchange, variants, selected)

View File

@@ -1,10 +1,15 @@
angular.module('admin.orderCycles')
.controller 'AdminOrderCycleExchangesCtrl', ($scope, $controller, $filter, $window, $location, $timeout, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, ocInstance, StatusMessage) ->
.controller 'AdminOrderCycleExchangesCtrl', ($scope, $controller, $filter, $window, $location, $timeout, OrderCycle, ExchangeProduct, Enterprise, EnterpriseFee, Schedules, RequestMonitor, ocInstance, StatusMessage) ->
$controller('AdminEditOrderCycleCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
$scope.supplier_enterprises = Enterprise.producer_enterprises
$scope.distributor_enterprises = Enterprise.hub_enterprises
$scope.supplied_products = Enterprise.supplied_products
$scope.productsLoading = ->
RequestMonitor.loading
$scope.setSelectAllVariantsCheckboxValue = (exchange, totalNumberOfVariants) ->
exchange.select_all_variants = $scope.exchangeSelectedVariants(exchange) >= totalNumberOfVariants
$scope.exchangeSelectedVariants = (exchange) ->
OrderCycle.exchangeSelectedVariants(exchange)
@@ -29,14 +34,6 @@ angular.module('admin.orderCycles')
OrderCycle.removeExchangeFee(exchange, index)
$scope.order_cycle_form.$dirty = true
$scope.addSupplier = ($event) ->
$event.preventDefault()
OrderCycle.addSupplier($scope.new_supplier_id)
$scope.addDistributor = ($event) ->
$event.preventDefault()
OrderCycle.addDistributor($scope.new_distributor_id)
$scope.setPickupTimeFieldDirty = (index) ->
$timeout ->
pickup_time_field_name = "order_cycle_outgoing_exchange_" + index + "_pickup_time"
@@ -44,3 +41,36 @@ angular.module('admin.orderCycles')
$scope.removeDistributionOfVariant = (variant_id) ->
OrderCycle.removeDistributionOfVariant(variant_id)
$scope.loadExchangeProducts = (exchange, page = 1) ->
enterprise = $scope.enterprises[exchange.enterprise_id]
enterprise.supplied_products ?= []
return if enterprise.last_page_loaded? && enterprise.last_page_loaded >= page
enterprise.last_page_loaded = page
incoming = true if $scope.view == 'incoming'
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: incoming, page: page}
ExchangeProduct.index params, (products, num_of_pages, num_of_products) ->
enterprise.num_of_pages = num_of_pages
enterprise.num_of_products = num_of_products
enterprise.supplied_products.push products...
$scope.loadMoreExchangeProducts = (exchange) ->
$scope.loadExchangeProducts(exchange, $scope.enterprises[exchange.enterprise_id].last_page_loaded + 1)
$scope.loadAllExchangeProducts = (exchange) ->
enterprise = $scope.enterprises[exchange.enterprise_id]
if enterprise.last_page_loaded < enterprise.num_of_pages
for page_to_load in [(enterprise.last_page_loaded + 1)..enterprise.num_of_pages]
RequestMonitor.load $scope.loadExchangeProducts(exchange, page_to_load).$promise
RequestMonitor.loadQueue
# initialize exchange products panel if not yet done
$scope.exchangeProdutsPanelInitialized = []
$scope.initializeExchangeProductsPanel = (exchange) ->
return if $scope.exchangeProdutsPanelInitialized[exchange.enterprise_id]
RequestMonitor.load $scope.loadExchangeProducts(exchange).$promise
$scope.exchangeProdutsPanelInitialized[exchange.enterprise_id] = true

View File

@@ -1,8 +1,7 @@
angular.module('admin.orderCycles').controller 'AdminOrderCycleOutgoingCtrl', ($scope, $controller, $filter, $location, OrderCycle, ocInstance, StatusMessage) ->
$controller('AdminOrderCycleExchangesCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
$scope.productSuppliedToOrderCycle = (product) ->
OrderCycle.productSuppliedToOrderCycle(product)
$scope.view = 'outgoing'
$scope.variantSuppliedToOrderCycle = (variant) ->
OrderCycle.variantSuppliedToOrderCycle(variant)
@@ -10,6 +9,15 @@ angular.module('admin.orderCycles').controller 'AdminOrderCycleOutgoingCtrl', ($
$scope.incomingExchangeVariantsFor = (enterprise_id) ->
$filter('filterExchangeVariants')(OrderCycle.incomingExchangesVariants(), $scope.order_cycle.visible_variants_for_outgoing_exchanges[enterprise_id])
$scope.exchangeTotalVariants = (exchange) ->
totalNumberOfVariants = $scope.incomingExchangeVariantsFor(exchange.enterprise_id).length
$scope.setSelectAllVariantsCheckboxValue(exchange, totalNumberOfVariants)
totalNumberOfVariants
$scope.addDistributor = ($event) ->
$event.preventDefault()
OrderCycle.addDistributor $scope.new_distributor_id
$scope.submit = ($event, destination) ->
$event.preventDefault()
StatusMessage.display 'progress', t('js.saving')

View File

@@ -1,23 +1,33 @@
angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $controller, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $controller, $window, OrderCycle, Enterprise, EnterpriseFee, ExchangeProduct, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
$controller('AdminOrderCycleBasicCtrl', {$scope: $scope, ocInstance: ocInstance})
$scope.order_cycle = OrderCycle.new {coordinator_id: ocInstance.coordinator_id}, =>
# TODO: make this a get method, which only fetches one enterprise
$scope.enterprises = Enterprise.index {coordinator_id: ocInstance.coordinator_id}, (enterprises) =>
$scope.init(enterprises)
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
$scope.init = (enterprises) ->
enterprise = enterprises[Object.keys(enterprises)[0]]
OrderCycle.addSupplier enterprise.id
OrderCycle.addDistributor enterprise.id
OrderCycle.order_cycle.coordinator_id = enterprise.id
OrderCycle.addDistributor enterprise.id, $scope.setOutgoingExchange
OrderCycle.addSupplier enterprise.id, $scope.loadExchangeProducts
$scope.setOutgoingExchange = ->
$scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0]
# All variants start as checked
OrderCycle.setExchangeVariants(OrderCycle.order_cycle.incoming_exchanges[0],
Enterprise.suppliedVariants(enterprise.id), true)
$scope.loadExchangeProducts = ->
$scope.incoming_exchange = OrderCycle.order_cycle.incoming_exchanges[0]
OrderCycle.order_cycle.coordinator_id = enterprise.id
params = { enterprise_id: $scope.incoming_exchange.enterprise_id, incoming: true }
ExchangeProduct.index params, $scope.storeProductsAndSelectAllVariants
$scope.storeProductsAndSelectAllVariants = (products) ->
$scope.enterprises[$scope.incoming_exchange.enterprise_id].supplied_products = products
# All variants start as checked
OrderCycle.setExchangeVariants($scope.incoming_exchange,
Enterprise.suppliedVariants($scope.incoming_exchange.enterprise_id), true)
$scope.removeDistributionOfVariant = angular.noop

View File

@@ -1,4 +1,4 @@
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $controller, $location, $window, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, StatusMessage, ocInstance) ->
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $controller, $location, $window, OrderCycle, Enterprise, EnterpriseFee, ExchangeProduct, Schedules, RequestMonitor, StatusMessage, ocInstance) ->
$controller('AdminOrderCycleBasicCtrl', {$scope: $scope, ocInstance: ocInstance})
$scope.orderCycleId = ->
@@ -11,6 +11,12 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
$scope.init = ->
$scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0]
$scope.loadExchangeProducts()
$scope.loadExchangeProducts = ->
exchange = OrderCycle.order_cycle.incoming_exchanges[0]
ExchangeProduct.index { exchange_id: exchange.id }, (products) ->
$scope.enterprises[exchange.enterprise_id].supplied_products = products
$scope.removeDistributionOfVariant = angular.noop

View File

@@ -12,7 +12,6 @@ angular.module('admin.orderCycles').factory('Enterprise', ($resource) ->
enterprises: {}
producer_enterprises: []
hub_enterprises: []
supplied_products: []
loaded: false
index: (params={}, callback=null) ->
@@ -22,9 +21,6 @@ angular.module('admin.orderCycles').factory('Enterprise', ($resource) ->
@producer_enterprises.push(enterprise) if enterprise.is_primary_producer
@hub_enterprises.push(enterprise) if enterprise.sells == 'any'
for product in enterprise.supplied_products
@supplied_products.push(product)
@loaded = true
(callback || angular.noop)(@enterprises)
@@ -39,13 +35,4 @@ angular.module('admin.orderCycles').factory('Enterprise', ($resource) ->
variant.id for variant in product.variants
else
[product.master_id]
totalVariants: (enterprise) ->
numVariants = 0
if enterprise
counts = for product in enterprise.supplied_products
numVariants += if product.variants.length == 0 then 1 else product.variants.length
numVariants
})

View File

@@ -0,0 +1,16 @@
angular.module('admin.orderCycles').factory('ExchangeProduct', ($resource) ->
ExchangeProductResource = $resource('/api/exchanges/:exchange_id/products.json', {}, {
'index': { method: 'GET' }
'variant_count': { method: 'GET', params: { action_name: "variant_count" }}
})
{
ExchangeProductResource: ExchangeProductResource
index: (params={}, callback=null) ->
ExchangeProductResource.index params, (data) =>
(callback || angular.noop)(data.products, data.pagination.pages, data.pagination.results)
countVariants: (params={}, callback=null) ->
ExchangeProductResource.variant_count params, (data) =>
(callback || angular.noop)(data.count)
})

View File

@@ -1,4 +1,4 @@
angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, StatusMessage, Panels) ->
angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, $timeout, StatusMessage, Panels) ->
OrderCycleResource = $resource '/admin/order_cycles/:action_name/:order_cycle_id.json', {}, {
'index': { method: 'GET', isArray: true}
'new' : { method: 'GET', params: { action_name: "new" } }
@@ -44,11 +44,15 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
@removeDistributionOfVariant(variant.id) if exchange.incoming
addSupplier: (new_supplier_id) ->
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
addSupplier: (new_supplier_id, callback) ->
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
$timeout ->
(callback || angular.noop)()
addDistributor: (new_distributor_id) ->
this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: []})
addDistributor: (new_distributor_id, callback) ->
this.order_cycle.outgoing_exchanges.push({ enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: [] })
$timeout ->
(callback || angular.noop)()
removeExchange: (exchange) ->
if exchange.incoming
@@ -71,18 +75,6 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
removeExchangeFee: (exchange, index) ->
exchange.enterprise_fees.splice(index, 1)
productSuppliedToOrderCycle: (product) ->
product_variant_ids = (variant.id for variant in product.variants)
variant_ids = [product.master_id].concat(product_variant_ids)
incomingExchangesVariants = this.incomingExchangesVariants()
# TODO: This is an O(n^2) implementation of set intersection and thus is slooow.
# Use a better algorithm if needed.
# Also, incomingExchangesVariants is called every time, when it only needs to be
# called once per change to incoming variants. Some sort of caching?
ids = (variant_id for variant_id in variant_ids when incomingExchangesVariants.indexOf(variant_id) != -1)
ids.length > 0
variantSuppliedToOrderCycle: (variant) ->
this.incomingExchangesVariants().indexOf(variant.id) != -1
@@ -143,7 +135,8 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
delete(service.order_cycle.exchanges)
service.loaded = true
(callback || angular.noop)(service.order_cycle)
$timeout ->
(callback || angular.noop)(service.order_cycle)
this.order_cycle

View File

@@ -1,4 +1,4 @@
angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor, Orders, SortOptions, $window, $filter) ->
angular.module("admin.orders").controller "ordersCtrl", ($scope, $timeout, RequestMonitor, Orders, SortOptions, $window, $filter) ->
$scope.RequestMonitor = RequestMonitor
$scope.pagination = Orders.pagination
$scope.orders = Orders.all
@@ -13,6 +13,7 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
$scope.selected = false
$scope.select_all = false
$scope.poll = 0
$scope.rowStatus = {}
$scope.initialise = ->
$scope.per_page = 15
@@ -69,6 +70,23 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
$scope.fetchResults()
, true
$scope.capturePayment = (order) ->
$scope.rowAction('capture', order)
$scope.shipOrder = (order) ->
$scope.rowAction('ship', order)
$scope.rowAction = (action, order) ->
$scope.rowStatus[order.id] = "loading"
Orders[action](order).$promise.then (data) ->
$scope.rowStatus[order.id] = "success"
$timeout(->
$scope.rowStatus[order.id] = null
, 1500)
, (error) ->
$scope.rowStatus[order.id] = "error"
$scope.changePage = (newPage) ->
$scope.page = newPage
$scope.fetchResults(newPage)

View File

@@ -5,4 +5,14 @@ angular.module("admin.resources").factory 'OrderResource', ($resource) ->
method: 'GET'
'update':
method: 'PUT'
'capture':
url: '/api/orders/:id/capture.json'
method: 'PUT'
params:
id: '@id'
'ship':
url: '/api/orders/:id/ship.json'
method: 'PUT'
params:
id: '@id'
})

View File

@@ -44,5 +44,19 @@ angular.module("admin.resources").factory 'Orders', ($q, OrderResource, RequestM
changed.push attr unless attr is "$$hashKey"
changed
capture: (order) ->
@processAction('capture', order)
ship: (order) ->
@processAction('ship', order)
processAction: (action, order) ->
OrderResource[action] {id: order.number}, (data) =>
if data.id
angular.merge(order, data)
data
, (response) =>
response.data
resetAttribute: (order, attribute) ->
order[attribute] = @pristineByID[order.id][attribute]

View File

@@ -20,4 +20,4 @@ angular.module("admin.subscriptions").controller "ProductsPanelController", ($sc
keys = Object.keys(response.data.errors)
StatusMessage.display 'failure', response.data.errors[keys[0]][0]
else
StatusMessage.display 'success', t('js.changes_saved')
StatusMessage.display 'failure', t('js.admin.subscriptions.error_saving')

View File

@@ -1,5 +1,7 @@
.row.exchange-distributed-products
.sixteen.columns.alpha.omega
.row.exchange-distributed-products{'ng-init' => 'initializeExchangeProductsPanel(exchange)'}
.sixteen.columns.alpha.omega{ 'ng-show' => 'enterprises[exchange.enterprise_id].supplied_products.length != 0' }
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_header.html'" }
.exchange-select-all-variants
%label
%input{ type: 'checkbox', name: 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants',
@@ -7,11 +9,10 @@
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'setExchangeVariants(exchange, incomingExchangeVariantsFor(exchange.enterprise_id), exchange.select_all_variants)',
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' }
{{ 'admin.select_all' | t }}
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
.exchange-products
-# Scope product list based on permissions the current user has to view variants in this exchange
.exchange-product{'ng-repeat' => 'product in supplied_products | filter:productSuppliedToOrderCycle | visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges' }
.exchange-products{ 'ng-hide' => 'productsLoading()' }
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products | filter:visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges' }
.exchange-product-details
%label
%img{'ng-src' => '{{ product.image_url }}'}
@@ -26,3 +27,5 @@
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
'ng-disabled' => '!order_cycle.editable_variants_for_outgoing_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_outgoing_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
{{ variant.label }}
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_footer.html'" }

View File

@@ -0,0 +1,11 @@
.pagination{ 'ng-show' => 'enterprises[exchange.enterprise_id].last_page_loaded < enterprises[exchange.enterprise_id].num_of_pages && !productsLoading()'}
.button{ 'ng-click' => 'loadMoreExchangeProducts(exchange)' }
{{ 'js.admin.panels.exchange_products.load_more_products' | t }}
.button{ 'ng-click' => 'loadAllExchangeProducts(exchange)' }
{{ 'js.admin.panels.exchange_products.load_all_products' | t }}
.sixteen.columns.alpha#loading{ 'ng-show' => 'productsLoading()' }
%br
%img.spinner{ src: "/assets/spinning-circles.svg" }
%h1
{{ 'js.admin.panels.exchange_products.loading_products' | t }}

View File

@@ -0,0 +1,5 @@
.exchange-load-all-variants
%div
{{ 'js.admin.panels.exchange_products.products_loaded' | t:{ num_of_products_loaded: enterprises[exchange.enterprise_id].supplied_products.length, total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
%a{ 'ng-click' => 'loadAllExchangeProducts(exchange)', 'ng-show' => 'enterprises[exchange.enterprise_id].last_page_loaded < enterprises[exchange.enterprise_id].num_of_pages' }
{{ 'js.admin.panels.exchange_products.load_all_products' | t }}

View File

@@ -0,0 +1,12 @@
.row.exchange-supplied-products
.sixteen.columns.alpha.omega
.exchange-select-all-variants
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
value: 1,
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
{{ 'admin.select_all' | t }}
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }

View File

@@ -0,0 +1,16 @@
.row.exchange-supplied-products{'ng-init' => 'initializeExchangeProductsPanel(exchange)'}
.sixteen.columns.alpha.omega{ 'ng-show' => 'enterprises[exchange.enterprise_id].supplied_products.length != 0' }
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_header.html'" }
.exchange-select-all-variants
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
value: 1,
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'selectAllVariants(exchange, exchange.select_all_variants)',
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_footer.html'" }

View File

@@ -0,0 +1,16 @@
.exchange-products{ 'ng-hide' => 'productsLoading()' }
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
.exchange-product-details
%label
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
value: 1,
'ng-model' => 'exchange.variants[variant.id]',
'ofn-sync-distributions' => '{{ variant.id }}',
'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
{{ variant.label }}

View File

@@ -1,29 +0,0 @@
.row.exchange-supplied-products
.sixteen.columns.alpha.omega
.exchange-select-all-variants
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
value: 1,
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
{{ 'admin.select_all' | t }}
.exchange-products
-# No need to scope product list based on permissions, because if an incoming exchange is visible,
-# then all of the variants within it should be visible. May change in the future?
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
.exchange-product-details
%label
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
value: 1,
'ng-model' => 'exchange.variants[variant.id]',
'ofn-sync-distributions' => '{{ variant.id }}',
'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
{{ variant.label }}

View File

@@ -1,9 +1,9 @@
#save-bar.animate-show{ ng: { show: 'dirty || persist || StatusMessage.active()' } }
.container
.eight.columns.alpha
.seven.columns.alpha
%h5#status-message{ ng: { show: "StatusMessage.invalidMessage == ''", style: 'StatusMessage.statusMessage.style' } }
{{ StatusMessage.statusMessage.text || "&nbsp;" }}
%h5#status-message{ ng: { show: "StatusMessage.invalidMessage !== ''" }, style: 'color: #da5354' }
{{ StatusMessage.invalidMessage || "&nbsp;" }}
.eight.columns.omega.text-right{ ng: { transclude: true } }
.nine.columns.omega.text-right{ ng: { transclude: true } }

View File

@@ -0,0 +1,32 @@
@import '../variables';
.row-loading {
opacity: .5;
}
.row-loading-icons {
margin-left: 3em;
position: absolute;
.spinner {
border: 0;
width: 2.3em;
}
i {
font-size: 2.3em;
opacity: .75;
&::before {
vertical-align: top;
}
&.success {
color: $spree-green;
}
&.error {
color: $warning-red;
}
}
}

View File

@@ -0,0 +1,4 @@
#powerTip {
max-width: 240px;
white-space: normal;
}

View File

@@ -104,9 +104,13 @@ form.order_cycle {
width: 20px;
}
.exchange-load-all-variants {
margin: 0px 5px 20px 5px;
}
.exchange-select-all-variants {
clear: both;
margin: 5px;
margin: 15px 5px 25px 5px;
}
.exchange-products {
@@ -209,6 +213,7 @@ table#listing_enterprise_groups {
#loading {
text-align: center;
img.spinner {
border: 0px;
width: 100px;
height: 100px;
}

View File

@@ -28,15 +28,12 @@ module Admin
def bulk_update
@enterprise_fee_set = EnterpriseFeeSet.new(params[:enterprise_fee_set])
if @enterprise_fee_set.save
redirect_path = main_app.admin_enterprise_fees_path
if params.key? :enterprise_id
redirect_path = main_app.admin_enterprise_fees_path(enterprise_id: params[:enterprise_id])
end
redirect_to redirect_path, notice: I18n.t(:enterprise_fees_update_notice)
if @enterprise_fee_set.save
redirect_to redirect_path, notice: I18n.t(:enterprise_fees_update_notice)
else
render :index
redirect_to redirect_path,
flash: { error: @enterprise_fee_set.errors.full_messages.to_sentence }
end
end
@@ -73,5 +70,13 @@ module Admin
def current_enterprise
Enterprise.find params[:enterprise_id] if params.key? :enterprise_id
end
def redirect_path
if params.key? :enterprise_id
return main_app.admin_enterprise_fees_path(enterprise_id: params[:enterprise_id])
end
main_app.admin_enterprise_fees_path
end
end
end

View File

@@ -66,7 +66,7 @@ module Admin
if @enterprise.update_attributes(attributes)
flash[:success] = I18n.t(:enterprise_register_success_notice, enterprise: @enterprise.name)
redirect_to admin_path
redirect_to admin_dashboard_path
else
flash[:error] = I18n.t(:enterprise_register_error, enterprise: @enterprise.name)
render :welcome, layout: "spree/layouts/bare_admin"

View File

@@ -22,7 +22,7 @@ module Admin
redirect_to main_app.edit_admin_enterprise_path(stripe_account.enterprise)
rescue ActiveRecord::RecordNotFound
flash[:error] = "Failed to disconnect Stripe."
redirect_to spree.admin_path
redirect_to spree.admin_dashboard_path
end
def status

View File

@@ -0,0 +1,92 @@
# This controller lists products that can be added to an exchange
module Api
class ExchangeProductsController < Api::BaseController
DEFAULT_PAGE = 1
DEFAULT_PER_PAGE = 100
skip_authorization_check only: [:index]
# If exchange_id is present in the URL:
# Lists Products that can be added to that Exchange
#
# If exchange_id is not present in the URL:
# Lists Products of the Enterprise given that can be added to the given Order Cycle
# In this case parameters are: enterprise_id, order_cycle_id and incoming
# (order_cycle_id is not necessary for incoming exchanges)
def index
if params[:exchange_id].present?
load_data_from_exchange
else
load_data_from_other_params
end
render_variant_count && return if params[:action_name] == "variant_count"
render_paginated_products paginated_products
end
private
def render_variant_count
render text: {
count: Spree::Variant.
not_master.
where(product_id: products).
count
}.to_json
end
def products
ExchangeProductsRenderer.
new(@order_cycle, spree_current_user).
exchange_products(@incoming, @enterprise)
end
def paginated_products
products.
page(params[:page] || DEFAULT_PAGE).
per(params[:per_page] || DEFAULT_PER_PAGE)
end
def load_data_from_exchange
exchange = Exchange.find_by_id(params[:exchange_id])
@order_cycle = exchange.order_cycle
@incoming = exchange.incoming
@enterprise = exchange.sender
end
def load_data_from_other_params
@enterprise = Enterprise.find_by_id(params[:enterprise_id])
if params[:order_cycle_id]
@order_cycle = OrderCycle.find_by_id(params[:order_cycle_id])
elsif !params[:incoming]
raise "order_cycle_id is required to list products for new outgoing exchange"
end
@incoming = params[:incoming]
end
def render_paginated_products(paginated_products)
serializer = ActiveModel::ArraySerializer.new(
paginated_products,
each_serializer: Api::Admin::ForOrderCycle::SuppliedProductSerializer,
order_cycle: @order_cycle
)
render text: {
products: serializer,
pagination: pagination_data(paginated_products)
}.to_json
end
def pagination_data(paginated_products)
{
results: paginated_products.total_count,
pages: paginated_products.num_pages,
page: (params[:page] || DEFAULT_PAGE).to_i,
per_page: (params[:per_page] || DEFAULT_PER_PAGE).to_i
}
end
end
end

View File

@@ -16,8 +16,38 @@ module Api
}
end
def ship
authorize! :admin, order
if order.ship
render json: order.reload, serializer: Api::Admin::OrderSerializer, status: :ok
else
render json: { error: I18n.t('api.orders.failed_to_update') }, status: :unprocessable_entity
end
end
def capture
authorize! :admin, order
pending_payment = order.pending_payments.first
return payment_capture_failed unless order.payment_required? && pending_payment
if pending_payment.capture!
render json: order.reload, serializer: Api::Admin::OrderSerializer, status: :ok
else
payment_capture_failed
end
rescue Spree::Core::GatewayError => e
error_during_processing(e)
end
private
def payment_capture_failed
render json: { error: t(:payment_processing_failed) }, status: :unprocessable_entity
end
def serialized_orders(orders)
ActiveModel::ArraySerializer.new(
orders,

View File

@@ -42,8 +42,8 @@ module Api
def destroy
authorize! :delete, Spree::Product
@product = find_product(params[:id])
@product.update_attribute(:deleted_at, Time.zone.now)
@product.variants_including_master.update_all(deleted_at: Time.zone.now)
authorize! :delete, @product
@product.destroy
render json: @product, serializer: Api::Admin::ProductSerializer, status: :no_content
end
@@ -71,14 +71,6 @@ module Api
render_paged_products @products
end
def soft_delete
authorize! :delete, Spree::Product
@product = find_product(params[:product_id])
authorize! :delete, @product
@product.destroy
render json: @product, serializer: Api::Admin::ProductSerializer, status: :no_content
end
# POST /api/products/:product_id/clone
#
def clone

View File

@@ -35,18 +35,12 @@ module Api
end
end
def soft_delete
@variant = scope.find(params[:variant_id])
authorize! :delete, @variant
VariantDeleter.new.delete(@variant)
render json: @variant, serializer: Api::VariantSerializer, status: :no_content
end
def destroy
authorize! :delete, Spree::Variant
@variant = scope.find(params[:id])
@variant.destroy
authorize! :delete, @variant
VariantDeleter.new.delete(@variant)
render json: @variant, serializer: Api::VariantSerializer, status: :no_content
end

View File

@@ -1,12 +1,23 @@
module Spree
module Admin
AdjustmentsController.class_eval do
class AdjustmentsController < ResourceController
belongs_to 'spree/order', find_by: :number
destroy.after :reload_order
prepend_before_filter :set_included_tax, only: [:create, :update]
before_filter :set_default_tax_rate, only: :edit
before_filter :enable_updates, only: :update
private
def reload_order
@order.reload
end
def collection
parent.adjustments.eligible
end
# Choose a default tax rate to show on the edit form. The adjustment stores its included
# tax in dollars, but doesn't store the source of the tax (ie. TaxRate that generated it).
# We guess which tax rate here, choosing:
@@ -15,28 +26,34 @@ module Spree
# When we have to go with 2, we show an error message to ask the admin to check that the
# correct tax is being applied.
def set_default_tax_rate
if @adjustment.included_tax > 0
trs = TaxRate.match(@order)
tr_yielding_matching_tax = trs.select { |tr| tr.compute_tax(@adjustment.amount) == @adjustment.included_tax }.first.andand.id
tr_valid_for_order = TaxRate.match(@order).first.andand.id
return if @adjustment.included_tax <= 0
@tax_rate_id = tr_yielding_matching_tax || tr_valid_for_order
tax_rates = TaxRate.match(@order)
tax_rate_with_matching_tax = find_tax_rate_with_matching_tax(tax_rates)
tax_rate_valid_for_order = tax_rates.first.andand.id
if tr_yielding_matching_tax.nil?
@adjustment.errors.add :tax_rate_id, I18n.t(:adjustments_tax_rate_error)
end
@tax_rate_id = tax_rate_with_matching_tax || tax_rate_valid_for_order
return unless tax_rate_with_matching_tax.nil?
@adjustment.errors.add :tax_rate_id, I18n.t(:adjustments_tax_rate_error)
end
def find_tax_rate_with_matching_tax(tax_rates)
tax_rates_yielding_matching_tax = tax_rates.select do |tr|
tr.compute_tax(@adjustment.amount) == @adjustment.included_tax
end
tax_rates_yielding_matching_tax.first.andand.id
end
def set_included_tax
included_tax = 0
if params[:tax_rate_id].present?
tax_rate = TaxRate.find params[:tax_rate_id]
amount = params[:adjustment][:amount].to_f
params[:adjustment][:included_tax] = tax_rate.compute_tax amount
else
params[:adjustment][:included_tax] = 0
included_tax = tax_rate.compute_tax amount
end
params[:adjustment][:included_tax] = included_tax
end
# Spree 2.0 keeps shipping fee adjustments open unless they are manually

View File

@@ -0,0 +1,142 @@
module Spree
module Admin
class BaseController < Spree::BaseController
ssl_required
helper 'spree/admin/navigation'
layout '/spree/layouts/admin'
include I18nHelper
before_filter :authorize_admin
before_filter :set_locale
before_filter :warn_invalid_order_cycles, if: :html_request?
# Warn the user when they have an active order cycle with hubs that are not ready
# for checkout (ie. does not have valid shipping and payment methods).
def warn_invalid_order_cycles
distributors = active_distributors_not_ready_for_checkout
return if distributors.empty? || flash[:notice].present?
flash[:notice] = active_distributors_not_ready_for_checkout_message(distributors)
end
# This is in Spree::Core::ControllerHelpers::Auth
# But you can't easily reopen modules in Ruby
def unauthorized
if try_spree_current_user
flash[:error] = t(:authorization_failure)
redirect_to '/unauthorized'
else
store_location
redirect_to root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
end
end
protected
def model_class
const_name = controller_name.classify
return "Spree::#{const_name}".constantize if Spree.const_defined?(const_name)
nil
end
def action
params[:action].to_sym
end
def authorize_admin
if respond_to?(:model_class, true) && model_class
record = model_class
else
# This allows specificity for each non-resource controller
# (to be consistent with "authorize_resource :class => false", see https://github.com/ryanb/cancan/blob/60cf6a67ef59c0c9b63bc27ea0101125c4193ea6/lib/cancan/controller_resource.rb#L146)
record = self.class.to_s.
sub("Controller", "").
underscore.split('/').last.singularize.to_sym
end
authorize! :admin, record
authorize! resource_authorize_action, record
end
def resource_authorize_action
action
end
def flash_message_for(object, event_sym)
resource_desc = object.class.model_name.human
resource_desc += " \"#{object.name}\"" if object.respond_to?(:name) && object.name.present?
Spree.t(event_sym, resource: resource_desc)
end
def render_js_for_destroy
render partial: '/spree/admin/shared/destroy'
end
# Index request for JSON needs to pass a CSRF token in order to prevent JSON Hijacking
def check_json_authenticity
return unless request.format.js? || request.format.json?
return unless protect_against_forgery?
auth_token = params[request_forgery_protection_token]
return if auth_token && form_authenticity_token == CGI.unescape(auth_token)
raise(ActionController::InvalidAuthenticityToken)
end
def config_locale
Spree::Backend::Config[:locale]
end
private
def active_distributors_not_ready_for_checkout
ocs = OrderCycle.managed_by(spree_current_user).active
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
Enterprise.where('enterprises.id IN (?)', distributors).not_ready_for_checkout
end
def active_distributors_not_ready_for_checkout_message(distributors)
distributor_names = distributors.map(&:name).join ', '
if distributors.count > 1
I18n.t(:active_distributors_not_ready_for_checkout_message_plural,
distributor_names: distributor_names)
else
I18n.t(:active_distributors_not_ready_for_checkout_message_singular,
distributor_names: distributor_names)
end
end
def html_request?
request.format.html?
end
def json_request?
request.format.json?
end
def render_as_json(data, options = {})
ams_prefix = options.delete :ams_prefix
if [Array, ActiveRecord::Relation].include? data.class
render options.merge(json: data, each_serializer: serializer(ams_prefix))
else
render options.merge(json: data, serializer: serializer(ams_prefix))
end
end
def serializer(ams_prefix)
unless ams_prefix.nil? || ams_prefix_whitelist.include?(ams_prefix.to_sym)
raise "Suffix '#{ams_prefix}' not found in ams_prefix_whitelist for #{self.class.name}."
end
prefix = ams_prefix.andand.classify || ""
name = controller_name.classify
"::Api::Admin::#{prefix}#{name}Serializer".constantize
end
end
end
end

View File

@@ -1,105 +0,0 @@
require 'spree/core/controller_helpers/respond_with_decorator'
Spree::Admin::BaseController.class_eval do
include I18nHelper
layout 'spree/layouts/admin'
before_filter :set_locale
before_filter :warn_invalid_order_cycles, if: :html_request?
# Warn the user when they have an active order cycle with hubs that are not ready
# for checkout (ie. does not have valid shipping and payment methods).
def warn_invalid_order_cycles
distributors = active_distributors_not_ready_for_checkout
if distributors.any? && flash[:notice].nil?
flash[:notice] = active_distributors_not_ready_for_checkout_message(distributors)
end
end
# Override Spree method
# It's a shame Spree doesn't just let CanCan handle this in it's own way
def authorize_admin
if respond_to?(:model_class, true) && model_class
record = model_class
else
# this line changed to allow specificity for each non-resource controller (to be consistent with "authorize_resource :class => false", see https://github.com/ryanb/cancan/blob/60cf6a67ef59c0c9b63bc27ea0101125c4193ea6/lib/cancan/controller_resource.rb#L146)
record = self.class.to_s.sub("Controller", "").underscore.split('/').last.singularize.to_sym
end
authorize! :admin, record
authorize! resource_authorize_action, record
end
def resource_authorize_action
action
end
# This is in Spree::Core::ControllerHelpers::Auth
# But you can't easily reopen modules in Ruby
def unauthorized
if try_spree_current_user
flash[:error] = t(:authorization_failure)
redirect_to '/unauthorized'
else
store_location
redirect_to root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
end
end
protected
def model_class
const_name = controller_name.classify
if Spree.const_defined?(const_name)
return "Spree::#{const_name}".constantize
end
nil
end
private
def active_distributors_not_ready_for_checkout
ocs = OrderCycle.managed_by(spree_current_user).active
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
Enterprise.where('enterprises.id IN (?)', distributors).not_ready_for_checkout
end
def active_distributors_not_ready_for_checkout_message(distributors)
distributor_names = distributors.map(&:name).join ', '
if distributors.count > 1
I18n.t(:active_distributors_not_ready_for_checkout_message_plural, distributor_names: distributor_names)
else
I18n.t(:active_distributors_not_ready_for_checkout_message_singular, distributor_names: distributor_names)
end
end
def html_request?
request.format.html?
end
def json_request?
request.format.json?
end
def render_as_json(data, options = {})
ams_prefix = options.delete :ams_prefix
if [Array, ActiveRecord::Relation].include? data.class
render options.merge(json: data, each_serializer: serializer(ams_prefix))
else
render options.merge(json: data, serializer: serializer(ams_prefix))
end
end
def serializer(ams_prefix)
if ams_prefix.nil? || ams_prefix_whitelist.include?(ams_prefix.to_sym)
prefix = ams_prefix.andand.classify || ""
name = controller_name.classify
"Api::Admin::#{prefix}#{name}Serializer".constantize
else
raise "Suffix '#{ams_prefix}' not found in ams_prefix_whitelist for #{self.class.name}."
end
end
end

View File

@@ -5,8 +5,7 @@ module Spree
@preferences_general = [:site_name, :default_seo_title, :default_meta_keywords,
:default_meta_description, :site_url, :bugherd_api_key]
@preferences_security = [:allow_ssl_in_production,
:allow_ssl_in_staging, :allow_ssl_in_development_and_test,
:check_for_spree_alerts]
:allow_ssl_in_staging, :allow_ssl_in_development_and_test]
@preferences_currency = [:display_currency, :hide_cents]
end
@@ -20,18 +19,6 @@ module Spree
redirect_to edit_admin_general_settings_path
end
def dismiss_alert
return unless request.xhr? && params[:alert_id]
dismissed = Spree::Config[:dismissed_spree_alerts] || ''
Spree::Config.set(dismissed_spree_alerts: dismissed.
split(',').
push(params[:alert_id]).
join(','))
filter_dismissed_alerts
render nothing: true
end
end
end
end

View File

@@ -0,0 +1,79 @@
# this clas was inspired (heavily) from the mephisto admin architecture
module Spree
module Admin
class OverviewController < Spree::Admin::BaseController
def index
@enterprises = Enterprise
.managed_by(spree_current_user)
.order('is_primary_producer ASC, name')
@product_count = Spree::Product.active.managed_by(spree_current_user).count
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
if first_access
redirect_to enterprises_path
else
render dashboard_view
end
end
private
# Checks whether the user is accessing the admin for the first time
#
# @return [Boolean]
def first_access
outside_referral && incomplete_enterprise_registration?
end
# Checks whether the request comes from another admin page or not
#
# @return [Boolean]
def outside_referral
!URI(request.referer.to_s).path.match(%r{/admin})
end
# Checks that all of the enterprises owned by the current user have a 'sells'
# property specified, which indicates that the registration process has been
# completed
#
# @return [Boolean]
def incomplete_enterprise_registration?
@incomplete_enterprise_registration ||= spree_current_user
.owned_enterprises
.where(sells: 'unspecified')
.exists?
end
# Returns the appropriate enterprise path for the current user
#
# @return [String]
def enterprises_path
if managed_enterprises.size == 1
@enterprise = @enterprises.first
main_app.welcome_admin_enterprise_path(@enterprise)
else
main_app.admin_enterprises_path
end
end
# Returns the appropriate dashboard view for the current user
#
# @return [String]
def dashboard_view
if managed_enterprises.size == 1
@enterprise = @enterprises.first
:single_enterprise_dashboard
else
:multi_enterprise_dashboard
end
end
# Returns the list of enterprises the current user is manager of
#
# @return [ActiveRecord::Relation<Enterprise>]
def managed_enterprises
spree_current_user.enterprises
end
end
end
end

View File

@@ -1,74 +0,0 @@
Spree::Admin::OverviewController.class_eval do
def index
@enterprises = Enterprise
.managed_by(spree_current_user)
.order('is_primary_producer ASC, name')
@product_count = Spree::Product.active.managed_by(spree_current_user).count
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
if first_access
redirect_to enterprises_path
else
render dashboard_view
end
end
private
# Checks whether the user is accessing the admin for the first time
#
# @return [Boolean]
def first_access
outside_referral && incomplete_enterprise_registration?
end
# Checks whether the request comes from another admin page or not
#
# @return [Boolean]
def outside_referral
!URI(request.referer.to_s).path.match(%r{/admin})
end
# Checks that all of the enterprises owned by the current user have a 'sells'
# property specified, which indicates that the registration process has been
# completed
#
# @return [Boolean]
def incomplete_enterprise_registration?
@incomplete_enterprise_registration ||= spree_current_user
.owned_enterprises
.where(sells: 'unspecified')
.exists?
end
# Returns the appropriate enterprise path for the current user
#
# @return [String]
def enterprises_path
if managed_enterprises.size == 1
@enterprise = @enterprises.first
main_app.welcome_admin_enterprise_path(@enterprise)
else
main_app.admin_enterprises_path
end
end
# Returns the appropriate dashboard view for the current user
#
# @return [String]
def dashboard_view
if managed_enterprises.size == 1
@enterprise = @enterprises.first
:single_enterprise_dashboard
else
:multi_enterprise_dashboard
end
end
# Returns the list of enterprises the current user is manager of
#
# @return [ActiveRecord::Relation<Enterprise>]
def managed_enterprises
spree_current_user.enterprises
end
end

View File

@@ -0,0 +1,317 @@
require 'csv'
require 'open_food_network/reports/list'
require 'open_food_network/order_and_distributor_report'
require 'open_food_network/products_and_inventory_report'
require 'open_food_network/lettuce_share_report'
require 'open_food_network/group_buy_report'
require 'open_food_network/order_grouper'
require 'open_food_network/customers_report'
require 'open_food_network/users_and_enterprises_report'
require 'open_food_network/order_cycle_management_report'
require 'open_food_network/packing_report'
require 'open_food_network/sales_tax_report'
require 'open_food_network/xero_invoices_report'
require 'open_food_network/bulk_coop_report'
require 'open_food_network/payments_report'
require 'open_food_network/orders_and_fulfillments_report'
module Spree
module Admin
class ReportsController < Spree::Admin::BaseController
include Spree::ReportsHelper
helper_method :render_content?
before_filter :cache_search_state
# Fetches user's distributors, suppliers and order_cycles
before_filter :load_data,
only: [:customers, :products_and_inventory, :order_cycle_management, :packing]
respond_to :html
def report_types
OpenFoodNetwork::Reports::List.all
end
def index
@reports = authorized_reports
respond_with(@reports)
end
def customers
@report_types = report_types[:customers]
@report_type = params[:report_type]
@report = OpenFoodNetwork::CustomersReport.new spree_current_user, params, render_content?
render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv")
end
def order_cycle_management
params[:q] ||= {}
@report_types = report_types[:order_cycle_management]
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user,
params,
render_content?
@table = @report.table_items
render_report(@report.header, @table, params[:csv],
"order_cycle_management_#{timestamp}.csv")
end
def packing
params[:q] ||= {}
@report_types = report_types[:packing]
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::PackingReport.new spree_current_user, params, render_content?
@table = order_grouper_table
render_report(@report.header, @table, params[:csv], "packing_#{timestamp}.csv")
end
def orders_and_distributors
@report = OpenFoodNetwork::OrderAndDistributorReport.new spree_current_user,
params,
render_content?
@search = @report.search
csv_file_name = "orders_and_distributors_#{timestamp}.csv"
render_report(@report.header, @report.table, params[:csv], csv_file_name)
end
def sales_tax
@distributors = my_distributors
@report_type = params[:report_type]
@report = OpenFoodNetwork::SalesTaxReport.new spree_current_user, params, render_content?
render_report(@report.header, @report.table, params[:csv], "sales_tax.csv")
end
def bulk_coop
# -- Prepare form options
@distributors = my_distributors
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::BulkCoopReport.new spree_current_user, params, render_content?
@table = order_grouper_table
csv_file_name = "bulk_coop_#{params[:report_type]}_#{timestamp}.csv"
render_report(@report.header, @table, params[:csv], csv_file_name)
end
def payments
# -- Prepare Form Options
@distributors = my_distributors
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::PaymentsReport.new spree_current_user, params, render_content?
@table = order_grouper_table
csv_file_name = "payments_#{timestamp}.csv"
render_report(@report.header, @table, params[:csv], csv_file_name)
end
def orders_and_fulfillment
params[:q] ||= orders_and_fulfillment_default_filters
# -- Prepare Form Options
permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
# My distributors and any distributors distributing products I supply
@distributors = permissions.visible_enterprises_for_order_reports.is_distributor
# My suppliers and any suppliers supplying products I distribute
@suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer
@order_cycles = my_order_cycles
@report_types = report_types[:orders_and_fulfillment]
@report_type = params[:report_type]
@include_blank = I18n.t(:all)
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user,
params,
render_content?
@table = order_grouper_table
csv_file_name = "#{params[:report_type]}_#{timestamp}.csv"
render_report(@report.header, @table, params[:csv], csv_file_name)
end
def products_and_inventory
@report_types = report_types[:products_and_inventory]
@report = if params[:report_type] != 'lettuce_share'
OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user,
params,
render_content?
else
OpenFoodNetwork::LettuceShareReport.new spree_current_user,
params,
render_content?
end
render_report @report.header,
@report.table,
params[:csv],
"products_and_inventory_#{timestamp}.csv"
end
def users_and_enterprises
@report = OpenFoodNetwork::UsersAndEnterprisesReport.new params, render_content?
render_report(@report.header, @report.table, params[:csv],
"users_and_enterprises_#{timestamp}.csv")
end
def xero_invoices
params[:q] ||= {}
@distributors = my_distributors
@order_cycles = my_order_cycles
@report = OpenFoodNetwork::XeroInvoicesReport.new(spree_current_user,
params,
render_content?)
render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv")
end
private
def model_class
Spree::Admin::ReportsController
end
# Some actions are changing the `params` object. That is unfortunate Spree
# behavior and we are building on it. So we have to look at `params` early
# to check if we are searching or just displaying a report search form.
def cache_search_state
search_keys = [
# search parameter for ransack
:q,
# common in all reports, only set for CSV rendering
:csv,
# `button` is included in all forms. It's not important for searching,
# but the Users & Enterprises report doesn't have any other parameter
# for an empty search. So we use this one to display data.
:button,
# Some reports use filtering by enterprise or order cycle
:distributor_id,
:supplier_id,
:order_cycle_id,
# Xero Invoices can be filtered by date
:invoice_date,
:due_date
]
@searching = search_keys.any? { |key| params.key? key }
end
# We don't want to render data unless search params are supplied.
# Compiling data can take a long time.
def render_content?
@searching
end
def render_report(header, table, create_csv, csv_file_name)
send_data csv_report(header, table), filename: csv_file_name if create_csv
@header = header
@table = table
# Rendering HTML is the default.
end
def csv_report(header, table)
CSV.generate do |csv|
csv << header
table.each { |row| csv << row }
end
end
def load_data
@distributors = my_distributors
@suppliers = my_suppliers | suppliers_of_products_distributed_by(@distributors)
@order_cycles = my_order_cycles
end
# Load managed distributor enterprises of current user
def my_distributors
Enterprise.is_distributor.managed_by(spree_current_user)
end
# Load managed producer enterprises of current user
def my_suppliers
Enterprise.is_primary_producer.managed_by(spree_current_user)
end
def suppliers_of_products_distributed_by(distributors)
distributors.map { |d| Spree::Product.in_distributor(d).includes(:supplier).all }.
flatten.map(&:supplier).uniq
end
# Load order cycles the current user has access to
def my_order_cycles
OrderCycle.
active_or_complete.
accessible_by(spree_current_user).
order('orders_close_at DESC')
end
def order_grouper_table
order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns
order_grouper.table(@report.table_items)
end
def authorized_reports
all_reports = [
:orders_and_distributors,
:bulk_coop,
:payments,
:orders_and_fulfillment,
:customers,
:products_and_inventory,
:users_and_enterprises,
:enterprise_fee_summary,
:order_cycle_management,
:sales_tax,
:xero_invoices,
:packing
]
reports = all_reports.select { |action| can? action, Spree::Admin::ReportsController }
reports.map { |report| [report, describe_report(report)] }.to_h
end
def describe_report(report)
name = I18n.t(:name, scope: [:admin, :reports, report])
description = begin
I18n.t!(:description, scope: [:admin, :reports, report])
rescue I18n::MissingTranslationData
render_to_string(
partial: "#{report}_description",
layout: false,
locals: { report_types: report_types[report] }
).html_safe
end
{ name: name, url: url_for_report(report), description: description }
end
def url_for_report(report)
public_send("#{report}_admin_reports_url".to_sym)
rescue NoMethodError
url_for([:new, :admin, :reports, report.to_s.singularize])
end
def timestamp
Time.zone.now.strftime("%Y%m%d")
end
def orders_and_fulfillment_default_filters
now = Time.zone.now
{ completed_at_gt: (now - 1.month).beginning_of_day,
completed_at_lt: (now + 1.day).beginning_of_day }
end
end
end
end

View File

@@ -1,302 +0,0 @@
require 'csv'
require 'open_food_network/reports/list'
require 'open_food_network/order_and_distributor_report'
require 'open_food_network/products_and_inventory_report'
require 'open_food_network/lettuce_share_report'
require 'open_food_network/group_buy_report'
require 'open_food_network/order_grouper'
require 'open_food_network/customers_report'
require 'open_food_network/users_and_enterprises_report'
require 'open_food_network/order_cycle_management_report'
require 'open_food_network/packing_report'
require 'open_food_network/sales_tax_report'
require 'open_food_network/xero_invoices_report'
require 'open_food_network/bulk_coop_report'
require 'open_food_network/payments_report'
require 'open_food_network/orders_and_fulfillments_report'
Spree::Admin::ReportsController.class_eval do
include Spree::ReportsHelper
helper_method :render_content?
before_filter :cache_search_state
# Fetches user's distributors, suppliers and order_cycles
before_filter :load_data,
only: [:customers, :products_and_inventory, :order_cycle_management, :packing]
def report_types
OpenFoodNetwork::Reports::List.all
end
# Override spree reports list.
def index
@reports = authorized_reports
respond_with(@reports)
end
def customers
@report_types = report_types[:customers]
@report_type = params[:report_type]
@report = OpenFoodNetwork::CustomersReport.new spree_current_user, params, render_content?
render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv")
end
def order_cycle_management
params[:q] ||= {}
@report_types = report_types[:order_cycle_management]
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user,
params,
render_content?
@table = @report.table_items
render_report(@report.header, @table, params[:csv], "order_cycle_management_#{timestamp}.csv")
end
def packing
params[:q] ||= {}
@report_types = report_types[:packing]
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::PackingReport.new spree_current_user, params, render_content?
@table = order_grouper_table
render_report(@report.header, @table, params[:csv], "packing_#{timestamp}.csv")
end
def orders_and_distributors
@report = OpenFoodNetwork::OrderAndDistributorReport.new spree_current_user,
params,
render_content?
@search = @report.search
csv_file_name = "orders_and_distributors_#{timestamp}.csv"
render_report(@report.header, @report.table, params[:csv], csv_file_name)
end
def sales_tax
@distributors = my_distributors
@report_type = params[:report_type]
@report = OpenFoodNetwork::SalesTaxReport.new spree_current_user, params, render_content?
render_report(@report.header, @report.table, params[:csv], "sales_tax.csv")
end
def bulk_coop
# -- Prepare form options
@distributors = my_distributors
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::BulkCoopReport.new spree_current_user, params, render_content?
@table = order_grouper_table
csv_file_name = "bulk_coop_#{params[:report_type]}_#{timestamp}.csv"
render_report(@report.header, @table, params[:csv], csv_file_name)
end
def payments
# -- Prepare Form Options
@distributors = my_distributors
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::PaymentsReport.new spree_current_user, params, render_content?
@table = order_grouper_table
csv_file_name = "payments_#{timestamp}.csv"
render_report(@report.header, @table, params[:csv], csv_file_name)
end
def orders_and_fulfillment
params[:q] ||= orders_and_fulfillment_default_filters
# -- Prepare Form Options
permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
# My distributors and any distributors distributing products I supply
@distributors = permissions.visible_enterprises_for_order_reports.is_distributor
# My suppliers and any suppliers supplying products I distribute
@suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer
@order_cycles = my_order_cycles
@report_types = report_types[:orders_and_fulfillment]
@report_type = params[:report_type]
@include_blank = I18n.t(:all)
# -- Build Report with Order Grouper
@report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user,
params,
render_content?
@table = order_grouper_table
csv_file_name = "#{params[:report_type]}_#{timestamp}.csv"
render_report(@report.header, @table, params[:csv], csv_file_name)
end
def products_and_inventory
@report_types = report_types[:products_and_inventory]
@report = if params[:report_type] != 'lettuce_share'
OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user,
params,
render_content?
else
OpenFoodNetwork::LettuceShareReport.new spree_current_user, params, render_content?
end
render_report(@report.header,
@report.table,
params[:csv],
"products_and_inventory_#{timestamp}.csv")
end
def users_and_enterprises
@report = OpenFoodNetwork::UsersAndEnterprisesReport.new params, render_content?
render_report(@report.header,
@report.table,
params[:csv],
"users_and_enterprises_#{timestamp}.csv")
end
def xero_invoices
params[:q] ||= {}
@distributors = my_distributors
@order_cycles = my_order_cycles
@report = OpenFoodNetwork::XeroInvoicesReport.new spree_current_user, params, render_content?
render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv")
end
private
# Some actions are changing the `params` object. That is unfortunate Spree
# behavior and we are building on it. So we have to look at `params` early
# to check if we are searching or just displaying a report search form.
def cache_search_state
search_keys = [
# search parameter for ransack
:q,
# common in all reports, only set for CSV rendering
:csv,
# `button` is included in all forms. It's not important for searching,
# but the Users & Enterprises report doesn't have any other parameter
# for an empty search. So we use this one to display data.
:button,
# Some reports use filtering by enterprise or order cycle
:distributor_id,
:supplier_id,
:order_cycle_id,
# Xero Invoices can be filtered by date
:invoice_date,
:due_date
]
@searching = search_keys.any? { |key| params.key? key }
end
# We don't want to render data unless search params are supplied.
# Compiling data can take a long time.
def render_content?
@searching
end
def render_report(header, table, create_csv, csv_file_name)
send_data csv_report(header, table), filename: csv_file_name if create_csv
@header = header
@table = table
# Rendering HTML is the default.
end
def csv_report(header, table)
CSV.generate do |csv|
csv << header
table.each { |row| csv << row }
end
end
def load_data
@distributors = my_distributors
@suppliers = my_suppliers | suppliers_of_products_distributed_by(@distributors)
@order_cycles = my_order_cycles
end
# Load managed distributor enterprises of current user
def my_distributors
Enterprise.is_distributor.managed_by(spree_current_user)
end
# Load managed producer enterprises of current user
def my_suppliers
Enterprise.is_primary_producer.managed_by(spree_current_user)
end
def suppliers_of_products_distributed_by(distributors)
distributors.map { |d| Spree::Product.in_distributor(d).includes(:supplier).all }.
flatten.map(&:supplier).uniq
end
# Load order cycles the current user has access to
def my_order_cycles
OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
end
def order_grouper_table
order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns
order_grouper.table(@report.table_items)
end
def authorized_reports
all_reports = [
:orders_and_distributors,
:bulk_coop,
:payments,
:orders_and_fulfillment,
:customers,
:products_and_inventory,
:sales_total,
:users_and_enterprises,
:enterprise_fee_summary,
:order_cycle_management,
:sales_tax,
:xero_invoices,
:packing
]
reports = all_reports.select { |action| can? action, Spree::Admin::ReportsController }
reports.map { |report| [report, describe_report(report)] }.to_h
end
def describe_report(report)
name = I18n.t(:name, scope: [:admin, :reports, report])
description = begin
I18n.t!(:description, scope: [:admin, :reports, report])
rescue I18n::MissingTranslationData
render_to_string(
partial: "#{report}_description",
layout: false,
locals: { report_types: report_types[report] }
).html_safe
end
{ name: name, url: url_for_report(report), description: description }
end
def url_for_report(report)
public_send("#{report}_admin_reports_url".to_sym)
rescue NoMethodError
url_for([:new, :admin, :reports, report.to_s.singularize])
end
def timestamp
Time.zone.now.strftime("%Y%m%d")
end
def orders_and_fulfillment_default_filters
now = Time.zone.now
{ completed_at_gt: (now - 1.month).beginning_of_day,
completed_at_lt: (now + 1.day).beginning_of_day }
end
end

View File

@@ -0,0 +1,275 @@
require 'action_callbacks'
module Spree
module Admin
class ResourceController < Spree::Admin::BaseController
helper_method :new_object_url, :edit_object_url, :object_url, :collection_url
before_filter :load_resource, except: [:update_positions]
rescue_from ActiveRecord::RecordNotFound, with: :resource_not_found
rescue_from CanCan::AccessDenied, with: :unauthorized
respond_to :html
respond_to :js, except: [:show, :index]
def new
invoke_callbacks(:new_action, :before)
respond_with(@object) do |format|
format.html { render layout: !request.xhr? }
format.js { render layout: false }
end
end
def edit
respond_with(@object) do |format|
format.html { render layout: !request.xhr? }
format.js { render layout: false }
end
end
def update
invoke_callbacks(:update, :before)
if @object.update_attributes(params[object_name])
invoke_callbacks(:update, :after)
flash[:success] = flash_message_for(@object, :successfully_updated)
respond_with(@object) do |format|
format.html { redirect_to location_after_save }
format.js { render layout: false }
end
else
invoke_callbacks(:update, :fails)
respond_with(@object)
end
end
def create
invoke_callbacks(:create, :before)
@object.attributes = params[object_name]
if @object.save
invoke_callbacks(:create, :after)
flash[:success] = flash_message_for(@object, :successfully_created)
respond_with(@object) do |format|
format.html { redirect_to location_after_save }
format.js { render layout: false }
end
else
invoke_callbacks(:create, :fails)
respond_with(@object)
end
end
def update_positions
params[:positions].each do |id, index|
model_class.where(id: id).update_all(position: index)
end
respond_to do |format|
format.js { render text: 'Ok' }
end
end
def destroy
invoke_callbacks(:destroy, :before)
if @object.destroy
invoke_callbacks(:destroy, :after)
flash[:success] = flash_message_for(@object, :successfully_removed)
respond_with(@object) do |format|
format.html { redirect_to collection_url }
format.js { render partial: "spree/admin/shared/destroy" }
end
else
invoke_callbacks(:destroy, :fails)
respond_with(@object) do |format|
format.html { redirect_to collection_url }
end
end
end
protected
def resource_not_found
flash[:error] = flash_message_for(model_class.new, :not_found)
redirect_to collection_url
end
class << self
attr_accessor :parent_data
attr_accessor :callbacks
def belongs_to(model_name, options = {})
@parent_data ||= {}
@parent_data[:model_name] = model_name
@parent_data[:model_class] = model_name.to_s.classify.constantize
@parent_data[:find_by] = options[:find_by] || :id
end
def new_action
@callbacks ||= {}
@callbacks[:new_action] ||= ActionCallbacks.new
end
def create
@callbacks ||= {}
@callbacks[:create] ||= ActionCallbacks.new
end
def update
@callbacks ||= {}
@callbacks[:update] ||= ActionCallbacks.new
end
def destroy
@callbacks ||= {}
@callbacks[:destroy] ||= ActionCallbacks.new
end
end
def model_class
"Spree::#{controller_name.classify}".constantize
end
def model_name
parent_data[:model_name].gsub('spree/', '')
end
def object_name
controller_name.singularize
end
def load_resource
if member_action?
@object ||= load_resource_instance
# call authorize! a third time (called twice already in Admin::BaseController)
# this time we pass the actual instance so fine-grained abilities can control
# access to individual records, not just entire models.
authorize! action, @object
instance_variable_set("@#{object_name}", @object)
# If we don't have access, clear the object
unless can? action, @object
instance_variable_set("@#{object_name}", nil)
end
authorize! action, @object
else
@collection ||= collection
# note: we don't call authorize here as the collection method should use
# CanCan's accessible_by method to restrict the actual records returned
instance_variable_set("@#{controller_name}", @collection)
end
end
def load_resource_instance
if new_actions.include?(action)
build_resource
elsif params[:id]
find_resource
end
end
def parent_data
self.class.parent_data
end
def parent
return nil if parent_data.blank?
@parent ||= parent_data[:model_class].
public_send("find_by_#{parent_data[:find_by]}", params["#{model_name}_id"])
instance_variable_set("@#{model_name}", @parent)
end
def find_resource
if parent_data.present?
parent.public_send(controller_name).find(params[:id])
else
model_class.find(params[:id])
end
end
def build_resource
if parent_data.present?
parent.public_send(controller_name).build
else
model_class.new
end
end
def collection
return parent.public_send(controller_name) if parent_data.present?
if model_class.respond_to?(:accessible_by) &&
!current_ability.has_block?(params[:action], model_class)
model_class.accessible_by(current_ability, action)
else
model_class.scoped
end
end
def location_after_save
collection_url
end
def invoke_callbacks(action, callback_type)
callbacks = self.class.callbacks || {}
return if callbacks[action].nil?
case callback_type.to_sym
when :before then callbacks[action].before_methods.each { |method| __send__ method }
when :after then callbacks[action].after_methods.each { |method| __send__ method }
when :fails then callbacks[action].fails_methods.each { |method| __send__ method }
end
end
# URL helpers
def new_object_url(options = {})
if parent_data.present?
spree.new_polymorphic_url([:admin, parent, model_class], options)
else
spree.new_polymorphic_url([:admin, model_class], options)
end
end
def edit_object_url(object, options = {})
if parent_data.present?
spree.public_send "edit_admin_#{model_name}_#{object_name}_url", parent, object, options
else
spree.public_send "edit_admin_#{object_name}_url", object, options
end
end
def object_url(object = nil, options = {})
target = object || @object
if parent_data.present?
spree.public_send "admin_#{model_name}_#{object_name}_url", parent, target, options
else
spree.public_send "admin_#{object_name}_url", target, options
end
end
def collection_url(options = {})
if parent_data.present?
spree.polymorphic_url([:admin, parent, model_class], options)
else
spree.polymorphic_url([:admin, model_class], options)
end
end
def collection_actions
[:index]
end
def member_action?
!collection_actions.include? action
end
def new_actions
[:new, :create]
end
end
end
end

View File

@@ -1,20 +0,0 @@
module AuthorizeOnLoadResource
def load_resource
super
if member_action?
# If we don't have access, clear the object
unless can? action, @object
instance_variable_set("@#{object_name}", nil)
end
authorize! action, @object
end
end
end
Spree::Admin::ResourceController.prepend(AuthorizeOnLoadResource)
Spree::Admin::ResourceController.class_eval do
rescue_from CanCan::AccessDenied, with: :unauthorized
end

View File

@@ -176,7 +176,7 @@ module Spree
previous_states = @order.adjustments.each_with_object({}) do |adjustment, hash|
hash[adjustment.id] = adjustment.state
end
@order.adjustments.each(&:open)
@order.adjustments.each { |adjustment| adjustment.fire_events(:open) }
yield

View File

@@ -0,0 +1,11 @@
module Admin
module EnterprisesHelper
def add_check_if_single(count)
if count == 1
{ checked: true }
else
{}
end
end
end
end

View File

@@ -20,12 +20,27 @@ module ShopHelper
)
end
def shop_tabs
def base_shop_tabs(column_sizes)
[
{ name: 'about', title: t(:shopping_tabs_about, distributor: current_distributor.name), cols: 6 },
{ name: 'producers', title: t(:label_producers), cols: 2 },
{ name: 'contact', title: t(:shopping_tabs_contact), cols: 2 },
{ name: 'groups', title: t(:label_groups), cols: 2 },
{ name: 'about', cols: column_sizes[0],
title: t(:shopping_tabs_about, distributor: current_distributor.name) },
{ name: 'producers', cols: column_sizes[1],
title: t(:label_producers) },
{ name: 'contact', cols: column_sizes[2],
title: t(:shopping_tabs_contact) }
]
end
def tabs_with_groups
tabs = base_shop_tabs([6, 2, 2])
tabs << { name: 'groups', title: t(:label_groups), cols: 2 }
end
def tabs_without_groups
base_shop_tabs([4, 4, 4])
end
def shop_tabs
current_distributor.groups.present? ? tabs_with_groups : tabs_without_groups
end
end

View File

@@ -1,3 +1,5 @@
require 'spree/admin/base_helper'
module Spree
module Admin
module BaseHelper

View File

@@ -1,3 +1,5 @@
require 'spree/admin/navigation_helper'
module Spree
module Admin
module NavigationHelper

View File

@@ -25,7 +25,7 @@ module Calculator
end
def line_item_weight(line_item)
if line_item.final_weight_volume.present?
if final_weight_volume_present?(line_item)
weight_per_final_weight_volume(line_item)
else
weight_per_variant(line_item) * line_item.quantity
@@ -33,13 +33,18 @@ module Calculator
end
def weight_per_variant(line_item)
line_item.variant.andand.weight || 0
if variant_unit(line_item) == 'weight'
# The calculator price is per_kg so we need to convert unit_value to kg
convert_g_to_kg(line_item.variant.andand.unit_value)
else
line_item.variant.andand.weight || 0
end
end
def weight_per_final_weight_volume(line_item)
if line_item.variant.product.andand.variant_unit == 'weight'
# Divided by 1000 because grams is the base weight unit and the calculator price is per_kg
line_item.final_weight_volume / 1000.0
if variant_unit(line_item) == 'weight'
# The calculator price is per_kg so we need to convert final_weight_volume to kg
convert_g_to_kg(line_item.final_weight_volume)
else
weight_per_variant(line_item) * quantity_implied_in_final_weight_volume(line_item)
end
@@ -51,5 +56,19 @@ module Calculator
def quantity_implied_in_final_weight_volume(line_item)
(1.0 * line_item.final_weight_volume / line_item.variant.unit_value).round(3)
end
def final_weight_volume_present?(line_item)
line_item.respond_to?(:final_weight_volume) && line_item.final_weight_volume.present?
end
def variant_unit(line_item)
line_item.variant.product.andand.variant_unit
end
def convert_g_to_kg(value)
return 0 unless value
value / 1000
end
end
end

View File

@@ -1,3 +1,3 @@
class EnterpriseRelationshipPermission < ActiveRecord::Base
default_scope order('name')
default_scope { order('name') }
end

View File

@@ -142,9 +142,9 @@ class OrderCycle < ActiveRecord::Base
oc.name = I18n.t("models.order_cycle.cloned_order_cycle_name", order_cycle: oc.name)
oc.orders_open_at = oc.orders_close_at = nil
oc.coordinator_fee_ids = coordinator_fee_ids
# rubocop:disable Metrics/LineLength
# rubocop:disable Layout/LineLength
oc.preferred_product_selection_from_coordinator_inventory_only = preferred_product_selection_from_coordinator_inventory_only
# rubocop:enable Metrics/LineLength
# rubocop:enable Layout/LineLength
oc.save!
exchanges.each { |e| e.clone!(oc) }
oc.reload

View File

@@ -2,7 +2,7 @@ class ProducerProperty < ActiveRecord::Base
belongs_to :producer, class_name: 'Enterprise', touch: true
belongs_to :property, class_name: 'Spree::Property'
default_scope order("#{table_name}.position")
default_scope { order("#{table_name}.position") }
scope :ever_sold_by, ->(shop) {
joins(producer: { supplied_products: { variants: { exchanges: :order_cycle } } }).

View File

@@ -214,7 +214,9 @@ module ProductImport
end
def accepted_mimetype
File.extname(@file.path).in?('.csv', '.xls', '.xlsx', '.ods') ? @file.path.split('.').last.to_sym : false
return false unless ['.csv'].include? File.extname(@file.path)
@file.path.split('.').last.to_sym
end
def headers

View File

@@ -45,11 +45,11 @@ module ProductImport
next if @enterprises_index.key? enterprise_name
enterprise = Enterprise.find_by_name(enterprise_name, select: 'id, is_primary_producer')
enterprise = Enterprise.select([:id, :is_primary_producer]).
where(name: enterprise_name).first
@enterprises_index[enterprise_name] =
{ id: enterprise.try(:id),
is_primary_producer: enterprise.try(:is_primary_producer) }
{ id: enterprise.try(:id), is_primary_producer: enterprise.try(:is_primary_producer) }
end
@enterprises_index
end
@@ -60,7 +60,8 @@ module ProductImport
next unless entry.producer
producer_name = entry.producer
producer_id = @producers_index[producer_name] || Enterprise.find_by_name(producer_name, select: 'id, name').try(:id)
producer_id = @producers_index[producer_name] ||
Enterprise.select([:id, :name]).where(name: producer_name).first.try(:id)
@producers_index[producer_name] = producer_id
end
@producers_index
@@ -70,7 +71,8 @@ module ProductImport
@categories_index = {}
@entries.each do |entry|
category_name = entry.category
category_id = @categories_index[category_name] || Spree::Taxon.find_by_name(category_name, select: 'id, name').try(:id)
category_id = @categories_index[category_name] ||
Spree::Taxon.select([:id, :name]).where(name: category_name).first.try(:id)
@categories_index[category_name] = category_id
end
@categories_index

View File

@@ -1,7 +1,5 @@
module Spree
class User < ActiveRecord::Base
include Core::UserBanners
devise :database_authenticatable, :token_authenticatable, :registerable, :recoverable,
:rememberable, :trackable, :validatable, :encryptable, encryptor: 'authlogic_sha512'

View File

@@ -6,6 +6,8 @@ class SubscriptionLineItem < ActiveRecord::Base
validates :variant, presence: true
validates :quantity, presence: true, numericality: { only_integer: true }
default_scope { order('id ASC') }
def total_estimate
(price_estimate || 0) * (quantity || 0)
end
@@ -22,6 +24,4 @@ class SubscriptionLineItem < ActiveRecord::Base
def price
price_estimate
end
default_scope order('id ASC')
end

View File

@@ -12,7 +12,7 @@ class VariantOverride < ActiveRecord::Base
# Default stock can be nil, indicating stock should not be reset or zero, meaning reset to zero. Need to ensure this can be set by the user.
validates :default_stock, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
default_scope where(permission_revoked_at: nil)
default_scope { where(permission_revoked_at: nil) }
scope :for_hubs, lambda { |hubs|
where(hub_id: hubs)

View File

@@ -1,7 +1,7 @@
require 'open_food_network/enterprise_issue_validator'
class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer
attributes :id, :name, :managed, :supplied_products,
attributes :id, :name, :managed,
:issues_summary_supplier, :issues_summary_distributor,
:is_primary_producer, :is_distributor, :sells
@@ -25,12 +25,6 @@ class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer
Enterprise.managed_by(options[:spree_current_user]).include? object
end
def supplied_products
serializer = Api::Admin::ForOrderCycle::SuppliedProductSerializer
ActiveModel::ArraySerializer.new(products, each_serializer: serializer,
order_cycle: order_cycle)
end
private
def products_scope

View File

@@ -14,7 +14,8 @@ class Api::Admin::ForOrderCycle::SuppliedProductSerializer < ActiveModel::Serial
end
def variants
variants = if order_cycle.prefers_product_selection_from_coordinator_inventory_only?
variants = if order_cycle.present? &&
order_cycle.prefers_product_selection_from_coordinator_inventory_only?
object.variants.visible_for(order_cycle.coordinator)
else
object.variants

View File

@@ -1,8 +1,8 @@
class Api::Admin::OrderSerializer < ActiveModel::Serializer
attributes :id, :number, :user_id, :full_name, :email, :phone, :completed_at, :display_total,
:edit_path, :state, :payment_state, :shipment_state,
:payments_path, :ship_path, :ready_to_ship, :created_at,
:distributor_name, :special_instructions, :payment_capture_path,
:payments_path, :ready_to_ship, :ready_to_capture, :created_at,
:distributor_name, :special_instructions,
:item_total, :adjustment_total, :payment_total, :total
has_one :distributor, serializer: Api::Admin::IdSerializer
@@ -28,15 +28,9 @@ class Api::Admin::OrderSerializer < ActiveModel::Serializer
spree_routes_helper.admin_order_payments_path(object)
end
def ship_path
spree_routes_helper.fire_admin_order_path(object, e: 'ship')
end
def payment_capture_path
def ready_to_capture
pending_payment = object.pending_payments.first
return '' unless object.payment_required? && pending_payment
spree_routes_helper.fire_admin_order_payment_path(object, pending_payment.id, e: 'capture')
object.payment_required? && pending_payment
end
def ready_to_ship

View File

@@ -0,0 +1,23 @@
class ActionCallbacks
attr_reader :before_methods
attr_reader :after_methods
attr_reader :fails_methods
def initialize
@before_methods = []
@after_methods = []
@fails_methods = []
end
def before(method)
@before_methods << method
end
def after(method)
@after_methods << method
end
def fails(method)
@fails_methods << method
end
end

View File

@@ -0,0 +1,86 @@
class ExchangeProductsRenderer
def initialize(order_cycle, user)
@order_cycle = order_cycle
@user = user
end
def exchange_products(incoming, enterprise)
if incoming
products_for_incoming_exchange(enterprise)
else
products_for_outgoing_exchange
end
end
private
def products_for_incoming_exchange(enterprise)
supplied_products(enterprise.id)
end
def supplied_products(enterprises_query_matcher)
products_relation = Spree::Product.where(supplier_id: enterprises_query_matcher)
if @order_cycle.present? &&
@order_cycle.prefers_product_selection_from_coordinator_inventory_only?
products_relation = products_relation.visible_for(@order_cycle.coordinator)
end
products_relation
end
def products_for_outgoing_exchange
supplied_products(enterprises_for_outgoing_exchange.select(:id)).
includes(:variants).
where("spree_variants.id": incoming_exchanges_variants)
end
def incoming_exchanges_variants
return @incoming_exchanges_variants if @incoming_exchanges_variants.present?
@incoming_exchanges_variants = []
visible_incoming_exchanges.each do |incoming_exchange|
@incoming_exchanges_variants.push(
*incoming_exchange.variants.merge(
visible_incoming_variants(incoming_exchange.sender)
).map(&:id).to_a
)
end
@incoming_exchanges_variants
end
def visible_incoming_exchanges
OpenFoodNetwork::OrderCyclePermissions.
new(@user, @order_cycle).
visible_exchanges.
by_enterprise_name.
incoming
end
def visible_incoming_variants(incoming_exchange_sender)
variants_relation = permitted_incoming_variants(incoming_exchange_sender)
if @order_cycle.prefers_product_selection_from_coordinator_inventory_only?
variants_relation = variants_relation.visible_for(@order_cycle.coordinator)
end
variants_relation
end
def permitted_incoming_variants(incoming_exchange_sender)
OpenFoodNetwork::OrderCyclePermissions.
new(@user, @order_cycle).
visible_variants_for_incoming_exchanges_from(incoming_exchange_sender)
end
def enterprises_for_outgoing_exchange
enterprises = OpenFoodNetwork::OrderCyclePermissions.
new(@user, @order_cycle)
.visible_enterprises
return enterprises if enterprises.empty?
enterprises.includes(
supplied_products: [:supplier, :variants, master: [:images]]
)
end
end

View File

@@ -7,17 +7,17 @@ module Permissions
# Find orders that the user can see
def visible_orders
Spree::Order.where(id:
managed_orders.select(:id) |
coordinated_orders.select(:id) |
produced_orders.select("spree_orders.id"))
Spree::Order.
with_line_items_variants_and_products_outer.
where(visible_orders_where_values)
end
# Any orders that the user can edit
def editable_orders
Spree::Order.where(id:
managed_orders.select(:id) |
coordinated_orders.select(:id) )
Spree::Order.where(
managed_orders_where_values.
or(coordinated_orders_where_values)
)
end
def visible_line_items
@@ -28,27 +28,45 @@ module Permissions
# Any line items that I can edit
def editable_line_items
Spree::LineItem.where(order_id: editable_orders)
Spree::LineItem.where(order_id: editable_orders.select(:id))
end
private
def visible_orders_where_values
# Grouping keeps the 2 where clauses from produced_orders_where_values inside parentheses
# This way it makes the OR work between the 3 types of orders:
# produced, managed and coordinated
Spree::Order.arel_table.
grouping(produced_orders_where_values).
or(managed_orders_where_values).
or(coordinated_orders_where_values)
end
# Any orders placed through any hub that I manage
def managed_orders
Spree::Order.where(distributor_id: @permissions.managed_enterprises.select("enterprises.id"))
def managed_orders_where_values
Spree::Order.
where(distributor_id: @permissions.managed_enterprises.select("enterprises.id")).
where_values.
reduce(:and)
end
# Any order that is placed through an order cycle one of my managed enterprises coordinates
def coordinated_orders
Spree::Order.where(order_cycle_id: @permissions.coordinated_order_cycles.select(:id))
def coordinated_orders_where_values
Spree::Order.
where(order_cycle_id: @permissions.coordinated_order_cycles.select(:id)).
where_values.
reduce(:and)
end
def produced_orders
def produced_orders_where_values
Spree::Order.with_line_items_variants_and_products_outer.
where(
distributor_id: granted_distributor_ids,
spree_products: { supplier_id: enterprises_with_associated_orders }
)
).
where_values.
reduce(:and)
end
def enterprises_with_associated_orders
@@ -69,7 +87,7 @@ module Permissions
# Any from visible orders, where the product is produced by one of my managed producers
def produced_line_items
Spree::LineItem.where(order_id: visible_orders.select(:id)).
Spree::LineItem.where(order_id: visible_orders.select("DISTINCT spree_orders.id")).
joins(:product).
where(spree_products:
{

View File

@@ -66,7 +66,7 @@ class ProductsRenderer
.split(",").map { |id| "spree_products.primary_taxon_id=#{id} DESC" }
.join(", ") + ", spree_products.name ASC, spree_products.id ASC"
else
"spree_products.name ASC"
"spree_products.name ASC, spree_products.id"
end
end

View File

@@ -1,11 +1,7 @@
%tr{ ng: { class: "'#{type} #{type}-{{ exchange.enterprise_id }}'" } }
%td{:class => "#{type}_name"} {{ enterprises[exchange.enterprise_id].name }}
%td.products.panel-toggle.text-center{ name: "products" }
{{ exchangeSelectedVariants(exchange) }} /
- if type == 'supplier'
{{ enterpriseTotalVariants(enterprises[exchange.enterprise_id]) }}
- else
{{ (incomingExchangeVariantsFor(exchange.enterprise_id)).length }}
{{ exchangeSelectedVariants(exchange) }} / {{ exchangeTotalVariants(exchange) }}
= t('.selected')
- if type == 'supplier'
%td.receival-details
@@ -34,11 +30,11 @@
- if type == 'supplier'
%tr.panel-row{ object: "exchange",
panels: "{products: 'exchange_supplied_products'}",
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,suppliedVariants,removeDistributionOfVariant",
panels: "{products: 'exchange_products_supplied'}",
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,selectAllVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
colspan: 4 }
- if type == 'distributor'
%tr.panel-row{ object: "exchange",
panels: "{products: 'exchange_distributed_products', tags: 'exchange_tags'}",
locals: "$index,order_cycle,exchange,supplied_products,setExchangeVariants,incomingExchangeVariantsFor,productSuppliedToOrderCycle,variantSuppliedToOrderCycle",
panels: "{products: 'exchange_products_distributed', tags: 'exchange_tags'}",
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
colspan: 5 }

View File

@@ -17,7 +17,7 @@
%table.exchanges
%tbody{ng: {repeat: "exchange in order_cycle.incoming_exchanges"}}
%tr.products
%td{ ng: { include: "'admin/panels/exchange_supplied_products.html'" } }
%td{ ng: { include: "'admin/panels/exchange_products_simple.html'" } }
%br/
= label_tag t('.fees')

View File

@@ -7,7 +7,6 @@
= render 'wizard_progress'
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
%input{ type: "button", value: t('.previous'), ng: { click: "cancel('#{main_app.edit_admin_order_cycle_path(@order_cycle)}')", disabled: "order_cycle_form.$dirty" } }
%input.red{ type: "button", value: t('.save'), ng: { click: "submit($event, null)", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
%input.red{ type: "button", value: t('.save_and_next'), ng: { click: "submit($event, '#{main_app.admin_order_cycle_outgoing_path(@order_cycle)}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
%input{ type: "button", value: t('.next'), ng: { click: "cancel('#{main_app.admin_order_cycle_outgoing_path(@order_cycle)}')", disabled: "order_cycle_form.$dirty" } }

View File

@@ -7,7 +7,6 @@
= render 'wizard_progress'
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
%input{ type: "button", value: t('.previous'), ng: { click: "cancel('#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", disabled: "order_cycle_form.$dirty" } }
%input.red{ type: "button", value: t('.save'), ng: { click: "submit($event, null)", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
%input.red{ type: "button", value: t('.save_and_back_to_list'), ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
%input{ type: "button", ng: { value: "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", click: "cancel('#{main_app.admin_order_cycles_path}')" } }

View File

@@ -8,7 +8,7 @@
%p
= t(".email_userguide_html", link: link_to(t(".userguide"), ContentConfig.user_guide_link))
%p
= t(".email_admin_html", link: link_to(t(".admin_panel"), spree.admin_url))
= t(".email_admin_html", link: link_to(t(".admin_panel"), spree.admin_dashboard_url))
%p
= t(".email_community_html", link: link_to(t(".join_community"), ContentConfig.community_forum_url))

View File

@@ -8,38 +8,6 @@
.small-12.medium-8.medium-offset-2.columns.text-center
.alert-box
= render 'shared/register_call'
.row
.small-12.medium-4.medium-offset-2.columns.text-center
%h6
= t '.footer_global_headline'
%p
%a{href: "http://www.openfoodnetwork.org", target: "_blank"}
= t '.footer_global_home'
%span &#124;
%a{href: "http://www.openfoodnetwork.org/news/", target: "_blank"}
= t '.footer_global_news'
%span &#124;
%a{href: "http://www.openfoodnetwork.org/about/history-team/", target: "_blank"}
= t '.footer_global_about'
%span &#124;
%a{href: "http://www.openfoodnetwork.org/contact/", target: "_blank"}
= t '.footer_global_contact'
.small-12.medium-4.columns.text-center
%h6
= t '.footer_sites_headline'
%p
%a{href: "http://dev.openfoodnetwork.org", target: "_blank"}
= t '.footer_sites_developer'
%span &#124;
%a{href: "http://community.openfoodnetwork.org", target: "_blank"}
= t '.footer_sites_community'
%span &#124;
%a{href: "http://www.openfoodnetwork.org/platform/user-guide/", target: "_blank"}
= t '.footer_sites_userguide'
.medium-2.columns.text-center
/ Placeholder
.footer-local
.row

View File

@@ -10,7 +10,7 @@
%section.right{"ng-cloak" => true}
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
%a.icon{href: main_app.checkout_path}
%a.icon{href: main_app.cart_path}
%span
= t '.cart'
%span.count

View File

@@ -15,7 +15,7 @@
- if admin_user? or enterprise_user?
%li
%a{href: spree.admin_path, target:'_blank'}
%a{href: spree.admin_dashboard_path, target:'_blank'}
%i.ofn-i_021-tools
= t 'label_administration'

View File

@@ -7,7 +7,7 @@
- if admin_user? or enterprise_user?
%li
%a{href: spree.admin_path, target:'_blank'}
%a{href: spree.admin_dashboard_path, target:'_blank'}
%i.ofn-i_021-tools
= t 'label_admin'

View File

@@ -10,4 +10,4 @@
= render :partial => 'adjustments_table'
= button_link_to t(:continue), @order.cart? ? new_admin_order_payment_url(@order) : admin_orders_url, :icon => 'icon-arrow-right'
= button_link_to t(:continue), admin_order_payments_url(@order), :icon => 'icon-arrow-right'

View File

@@ -47,7 +47,7 @@
%th.actions
%tbody
%tr{ng: {repeat: 'order in orders track by $index', class: {even: "'even'", odd: "'odd'"}}, 'ng-class' => "'state-{{order.state}}'"}
%tr{ng: {repeat: 'order in orders track by order.id', class: {even: "'even'", odd: "'odd'"}}, 'ng-class' => "{'state-{{order.state}}': true, 'row-loading': rowStatus[order.id] == 'loading'}"}
%td.align-center
%input{type: 'checkbox', 'ng-model' => 'checkboxes[order.id]', 'ng-change' => 'toggleSelection(order.id)'}
%td.align-center
@@ -78,11 +78,15 @@
%td.align-center
%span{'ng-bind-html' => 'order.display_total'}
%td.actions
%div.row-loading-icons
%img.spinner{src: "/assets/spinning-circles.svg", ng: {show: 'rowStatus[order.id] == "loading"'} }
%i.success.icon-ok-sign{ng: {show: 'rowStatus[order.id] == "success"'} }
%i.error.icon-remove-sign.with-tip{ng: {show: 'rowStatus[order.id] == "error"'}, 'ofn-with-tip' => t('.order_not_updated')}
%a.icon_link.with-tip.icon-edit.no-text{'ng-href' => '{{order.edit_path}}', 'data-action' => 'edit', 'ofn-with-tip' => t('.edit')}
%div{'ng-if' => 'order.ready_to_ship'}
%a.icon-road.icon_link.with-tip.no-text{'ng-href' => '{{order.ship_path}}', 'data-action' => 'ship', 'data-confirm' => t(:are_you_sure), 'data-method' => 'put', rel: 'nofollow', 'ofn-with-tip' => t('.ship')}
%div{'ng-if' => 'order.payment_capture_path'}
%a.icon-capture.icon_link.no-text{'ng-href' => '{{order.payment_capture_path}}', 'data-action' => 'capture', 'data-method' => 'put', rel: 'nofollow', 'ofn-with-tip' => t('.capture')}
%button.icon-road.icon_link.with-tip.no-text{'ng-click' => 'shipOrder(order)', 'data-confirm' => t(:are_you_sure), rel: 'nofollow', 'ofn-with-tip' => t('.ship')}
%div{'ng-if' => 'order.ready_to_capture'}
%button.icon-capture.icon_link.no-text{'ng-click' => 'capturePayment(order)', rel: 'nofollow', 'ofn-with-tip' => t('.capture')}
.orders-loading{'ng-show' => 'RequestMonitor.loading'}
.row

View File

@@ -44,14 +44,14 @@
%td{ :align => "right" }
= t :invoice_billing_address
%br
%strong= @order.ship_address.full_name
%strong= @order.bill_address.full_name
- if @order.andand.customer.andand.code.present?
%br
= "Code: #{@order.customer.code}"
%br
= @order.ship_address.address_part1
= @order.bill_address.address_part1
%br
= @order.ship_address.address_part2
= @order.bill_address.address_part2
= render 'spree/admin/orders/invoice_table2'

View File

@@ -1,21 +0,0 @@
<% content_for :page_title do %>
<%= t(:listing_reports) %>
<% end %>
<table class="index">
<thead>
<tr data-hook="reports_header">
<th><%= t(:name) %></th>
<th><%= t(:description) %></th>
</tr>
</thead>
<tbody>
<% @reports.each do |key, value| %>
<tr data-hook="reports_row">
<td><%= link_to value[:name], value[:url] %></td>
<td><%= value[:description] %></td>
</tr>
<% end %>
</tbody>
</table>

View File

@@ -0,0 +1,13 @@
- content_for :page_title do
= t(:listing_reports)
%table.index
%thead
%tr
%th= t(:name)
%th= t(:description)
%tbody
- @reports.each do |key, value|
%tr
%td= link_to value[:name], value[:url]
%td= value[:description]

View File

@@ -1,24 +0,0 @@
%tr{"data-hook" => "address1"}
%td
= t(:admin_shared_address_1):
%td= f.text_field :address1
%tr{"data-hook" => "address2" }
%td
= t(:admin_shared_address_2):
%td= f.text_field :address2
%tr{"data-hook" => "city" }
%td
= t(:admin_share_city):
%td= f.text_field :city
%tr{"data-hook" => "zipcode" }
%td
= t(:admin_share_zipcode):
%td= f.text_field :zipcode
%tr{"data-hook" => "country" }
%td
= t(:admin_share_country):
%td= f.collection_select(:country_id, available_countries, :id, :name)
%tr{"data-hook" => "state" }
%td
= t(:admin_share_state):
%td= f.collection_select(:state_id, f.object.country.states, :id, :name)

View File

@@ -12,7 +12,7 @@
%span.four.columns
%span.three.columns.alpha
%label
= check_box klass, :distributor_ids, { multiple: true }, hub.id, nil
= check_box klass, :distributor_ids, { multiple: true }.merge(add_check_if_single(@hubs.count)), hub.id, nil
= hub.name
%a.one.column.omega{ href: "#{main_app.edit_admin_enterprise_path(hub)}" }
%span.icon-arrow-right

View File

@@ -1,4 +1,4 @@
= tab :dashboard, :route => :admin, :icon => 'icon-dashboard'
= tab :overview, label: 'dashboard', url: spree.admin_dashboard_path, icon: 'icon-dashboard'
= tab :products, :option_types, :properties, :variants, :product_properties, :taxons, :url => admin_products_path, :icon => 'icon-th-large'
= tab :order_cycles, :url => main_app.admin_order_cycles_path, :icon => 'icon-refresh'
= tab :orders, :payments, :creditcard_payments, :shipments, :credit_cards, :return_authorizations, :url => admin_orders_path('q[s]' => 'completed_at desc'), :icon => 'icon-shopping-cart'

View File

@@ -16,12 +16,10 @@
= Spree.t(:loading)
\...
= render :partial => 'spree/admin/shared/alert', :collection => session[:alerts]
%header#header{"data-hook" => ""}
.container
%figure.columns.five{"data-hook" => "logo-wrapper"}
= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_path
= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_dashboard_path
%nav.columns.eleven{"data-hook" => "admin_login_navigation_bar"}
= render :partial => 'spree/layouts/admin/login_nav'

View File

@@ -14,11 +14,10 @@
.progress-message
= t(:loading)
\...
= render :partial => 'spree/admin/shared/alert', :collection => session[:alerts]
%header#header{"data-hook" => ""}
.container
%figure.columns.five{"data-hook" => "logo-wrapper"}= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_path
%figure.columns.five{"data-hook" => "logo-wrapper"}= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_dashboard_path
%nav.columns.eleven{"data-hook" => "admin_login_navigation_bar"}
= render partial: "spree/layouts/admin/login_nav"

View File

@@ -0,0 +1 @@
PaperTrail.config.track_associations = false

View File

@@ -2,6 +2,8 @@ ar:
language_name: "الانجيلزي"
activerecord:
attributes:
enterprise_fee:
fee_type: نوع الرسوم
spree/order:
payment_state: حالة الدفعة
shipment_state: حالة الشحن
@@ -48,6 +50,8 @@ ar:
shipping_method_ids: "طرق الشحن"
payment_method_ids: "طريقة الدفع"
errors:
messages:
inclusion: "غير مدرجة في القائمة"
models:
subscription_validator:
attributes:
@@ -847,7 +851,6 @@ ar:
save_and_back_to_list: "حفظ والعودة إلى القائمة"
choose_products_from: "اختر المنتجات من:"
incoming:
previous: "السابق"
save: "حفظ"
save_and_next: "حفظ والتالي"
next: "التالى"
@@ -986,9 +989,6 @@ ar:
name: العملاء
products_and_inventory:
name: المنتجات والمخزون
sales_total:
name: إجمالي المبيعات
description: إجمالي المبيعات لجميع الطلبات
users_and_enterprises:
name: المستخدمين والمؤسسات
description: ملكية الشركات وحالتها
@@ -1127,15 +1127,6 @@ ar:
selling_on_ofn: "هل أنت مهتم بالحصول على شبكة الغذاء المفتوح؟"
register: "سجل هنا"
footer:
footer_global_headline: "شبكة الغذاء المفتوحة العالمية"
footer_global_home: "الصفحة الرئيسية"
footer_global_news: "أخبار"
footer_global_about: "حول"
footer_global_contact: "اتصل"
footer_sites_headline: "مواقع شبكة الغذاء المفتوحة"
footer_sites_developer: "مطور"
footer_sites_community: "تواصل اجتماعي"
footer_sites_userguide: "دليل المستخدم"
footer_secure: "آمن وموثوق به."
footer_secure_text: "تستخدم شبكة الغذاء المفتوح تشفير( SSL 2048 بت RSA) في كل مكان للحفاظ على خصوصية معلومات التسوق والدفع. لا تقوم خوادمنا بتخزين تفاصيل بطاقة الائتمان الخاصة بك ، وتتم معالجة المدفوعات بواسطة خدمات متوافقة مع PCI."
footer_contact_headline: "أبق على اتصال"
@@ -2426,6 +2417,12 @@ ar:
severity: خطورة
description: وصف
resolve: حل
exchange_products:
load_more_products: "تحميل المزيد من المنتجات"
load_all_products: "تحميل جميع المنتجات"
select_all_products: "حدد جميع المنتجات %{total_number_of_products}"
products_loaded: "%{num_of_products_loaded} من %{total_number_of_products} المنتجات المحملة"
loading_products: "تحميل المنتجات"
tag_rules:
shipping_method_tagged_top: "طرق الشحن الموسومة"
shipping_method_tagged_bottom: "هي:"
@@ -2508,6 +2505,7 @@ ar:
customer_placeholder: "customer@example.org"
valid_email_error: "من فضلك أدخل بريد أليكترونى صحيح"
subscriptions:
error_saving: "خطأ في حفظ الاشتراك"
new:
please_select_a_shop: "يرجى اختيار متجر"
insufficient_stock: "مخزون غير متوفر ، تبقى %{on_hand}"
@@ -2708,7 +2706,6 @@ ar:
allow_ssl_in_development_and_test: "السماح باستخدام طبقة المقابس الآمنة SSL عندما تكون في أوضاع التطوير والاختبار"
allow_ssl_in_production: "السماح باستخدام طبقة المقابس الآمنة في وضع الإنتاج"
allow_ssl_in_staging: "اسمح باستخدام طبقة المقابس الآمنة في وضع التدريج"
check_for_spree_alerts: "تحقق من وجود تنبيهات Spree"
currency_decimal_mark: "العملة العشرية"
currency_settings: "إعدادات العملة"
currency_symbol_position: ضع &quot;رمز العملة قبل أو بعد مبلغ الدولار؟&quot;

View File

@@ -2,6 +2,8 @@ ca:
language_name: "Català"
activerecord:
attributes:
enterprise_fee:
fee_type: Tipus de comissió
spree/order:
payment_state: Estat del Pagament
shipment_state: Estat de la Tramesa
@@ -434,9 +436,12 @@ ca:
infinity: "Infinit"
to_order_tip: "Els articles preparats per encàrrec no tenen un nivell fixat d'existències, com ara pa fet sota comanda."
back_to_products_list: "Torna a la llista de productes"
editing_product: "Editant el producte"
tabs:
product_details: "Detalls del producte"
group_buy_options: "Opcions de compra en grup"
images: "Imatges"
variants: "Variants"
product_properties: "Propietats del producte"
product_import:
title: Importació de productes
@@ -836,21 +841,32 @@ ca:
new:
create: "Crear"
cancel: "Cancel·lar"
back_to_list: "Tornar a la llista"
edit:
advanced_settings: "Configuració avançada"
save: "Desa"
save_and_next: "Desa i següent"
next: "Següent"
cancel: "Cancel·lar"
back_to_list: "Tornar a la llista"
save_and_back_to_list: "Desa i torna a la llista"
choose_products_from: "Trieu Productes des de:"
incoming:
previous: "Anterior"
save: "Desa"
save_and_next: "Desa i següent"
next: "Següent"
cancel: "Cancel·lar"
back_to_list: "Tornar a la llista"
outgoing:
previous: "Anterior"
save: "Desa"
save_and_back_to_list: "Desa i torna a la llista"
cancel: "Cancel·lar"
back_to_list: "Tornar a la llista"
wizard_progress:
edit: "1. Configuració general"
incoming: "2. Productes entrants"
outgoing: "3. Productes sortints"
exchange_form:
pickup_time_tip: Quan les comandes d'aquest cicle de comandes estiguin preparades per a les consumidores
pickup_instructions_placeholder: "Instruccions de recollida"
@@ -974,9 +990,6 @@ ca:
name: Consumidores
products_and_inventory:
name: Productes & Inventari
sales_total:
name: Total de vendes
description: Total de vendes per a totes les comandes
users_and_enterprises:
name: Usuaris & Organitzacions
description: Propietat i estatus de l'organització
@@ -1115,15 +1128,6 @@ ca:
selling_on_ofn: "Estàs interessat en formar part d'Open Food Network?"
register: "Registra't aquí"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Inici"
footer_global_news: "Notícies"
footer_global_about: "Sobre"
footer_global_contact: "Contacte"
footer_sites_headline: "Pàgines d'OFN"
footer_sites_developer: "Desenvolupador"
footer_sites_community: "Comunitat"
footer_sites_userguide: "Guia de l'usuari"
footer_secure: "Segur i de confiança."
footer_secure_text: "Open Food Network utilitza el xifrat SSL (RSA de 2048 bits) a tot arreu per mantenir les vostres dades comercials i de pagament privades. Els nostres servidors no emmagatzemen els detalls de la targeta de crèdit i els pagaments es processen mitjançant serveis compatibles amb PCI."
footer_contact_headline: "Mantén el contacte"
@@ -2698,7 +2702,6 @@ ca:
allow_ssl_in_development_and_test: "Permet que s'utilitzi SSL quan s'utilitzi el desenvolupament i els modes de prova"
allow_ssl_in_production: "Permet que SSL s'utilitzi en mode de producció"
allow_ssl_in_staging: "Permet que SSL s'utilitzi en mode de staging"
check_for_spree_alerts: "Comproveu si hi ha alertes Spree"
currency_decimal_mark: "Separador decimal de moneda"
currency_settings: "Configuració de moneda"
currency_symbol_position: Posa "símbol de moneda abans o després d'una quantitat"?
@@ -2798,6 +2801,12 @@ ca:
minimal_amount: "Quantitat mínima"
normal_amount: "Quantitat normal"
discount_amount: "Import de descompte"
no_images_found: "No s'han trobat imatges"
new_image: "Nova imatge"
filename: "Nom de l'arxiu"
alt_text: "Text alternatiu"
thumbnail: "Miniatura"
back_to_images_list: "Torna a la llista dimatges"
email: Correu electrònic
account_updated: "Compte actualitzat!"
email_updated: "El compte sactualitzarà un cop es confirmi el nou correu electrònic."
@@ -2809,6 +2818,7 @@ ca:
zipcode: Codi postal
weight: Pes (per kg)
error_user_destroy_with_orders: "No es poden esborrar usuaris amb comandes completades"
options: "Opcions"
actions:
update: "Actualitzar"
errors:
@@ -2840,27 +2850,53 @@ ca:
product_properties:
index:
inherits_properties_checkbox_hint: "heredar propietats de %{supplier}? (llevat que es sobreescrigui a dalt)"
add_product_properties: "Afegeix propietats del producte"
select_from_prototype: "Seleccioneu d'un prototip"
properties:
index:
properties: "Propietats"
new_property: "Nova propietat"
name: "Nom"
presentation: "Presentació"
new:
new_property: "Nova propietat"
edit:
editing_property: "Edició de propietats"
back_to_properties_list: "Torna a la llista de propietats"
form:
name: "Nom"
presentation: "Presentació"
return_authorizations:
index:
new_return_authorization: "Nova autorització de devolució"
return_authorizations: "Autoritzacions de devolució"
back_to_orders_list: "Tornar a la llista de comandes"
rma_number: "Número RMA"
status: "Estat"
amount: "Quantitat"
cannot_create_returns: "No es poden crear devolucions ja que aquesta comanda no té cap unitat enviada."
continue: "Continua"
new:
new_return_authorization: "Nova autorització de devolució"
back_to_return_authorizations_list: "Tornar a la llista d'autorització"
continue: "Continua"
edit:
receive: "rebre"
are_you_sure: "Estàs segur?"
return_authorization: "Autorització de devolució"
form:
product: "Producte"
quantity_shipped: "Quantitat enviada"
quantity_returned: "Quantitat retornada"
return_quantity: "Devolució de la quantitat"
amount: "Quantitat"
rma_value: "Valor RMA"
reason: "Raó"
stock_location: "Ubicació d'estoc"
states:
authorized: "Autoritzat"
received: "Rebut"
canceled: "Cancel·lat"
orders:
index:
listing_orders: "Llistat comandes"
@@ -3051,12 +3087,23 @@ ca:
index:
sku: "Número de referència (SKU)"
price: "Preu"
options: "Opcions"
no_results: "Sense resultats"
to_add_variants_you_must_first_define: "Per afegir variants, primer heu de definir"
option_types: "Tipus d'opcions"
option_values: "Valors dopció"
and: "i"
new_variant: "Nova variant"
show_active: "Mostra actiu"
show_deleted: "Mostra esborrats"
new:
new_variant: "Nova variant"
form:
cost_price: "Preu de cost"
sku: "Número de referència (SKU)"
price: "Preu"
display_as: "Mostra com"
display_name: "Nom de visualització"
autocomplete:
producer_name: "Productor"
unit: "Unitat"
@@ -3196,3 +3243,19 @@ ca:
allow_charges?: "Permetre càrrecs?"
localized_number:
invalid_format: té un format no vàlid. Si us plau introdueix un número.
api:
invalid_api_key: "No sha especificat una clau dAPI vàlida (%{key})."
unauthorized: "No teniu autorització per realitzar aquesta acció."
invalid_resource: "Recurs invàlid. Corregiu els errors i torneu-ho a provar."
resource_not_found: "No s'ha trobat el recurs que buscaves."
access: "Accés a l'API"
key: "Clau"
clear_key: "Esborra la clau"
regenerate_key: "Regenerar la clau"
no_key: "Sense clau"
generate_key: "Generar clau dAPI"
key_generated: "Clau generada"
key_cleared: "La clau esborrada"
shipment:
cannot_ready: "No es pot fer l'enviament."
invalid_taxonomy_id: "Identificador de taxonomia no vàlid."

View File

@@ -2,6 +2,8 @@ de_DE:
language_name: "Deutsch"
activerecord:
attributes:
enterprise_fee:
fee_type: Art der Gebühr
spree/order:
payment_state: Zahlungsstatus
shipment_state: Lieferstatus
@@ -850,7 +852,6 @@ de_DE:
save_and_back_to_list: "Speichern und zurück zur Liste"
choose_products_from: "Wählen Sie Produkte von:"
incoming:
previous: "Bisherige"
save: "Speichern"
save_and_next: "Speichern und weiter"
next: "Weiter"
@@ -989,9 +990,6 @@ de_DE:
name: Kunden
products_and_inventory:
name: Produkte und Katalog
sales_total:
name: Gesamtumsatz
description: Gesamtumsatz für alle Bestellungen
users_and_enterprises:
name: Benutzer und Unternehmen
description: Unternehmenseigentum & Status
@@ -1130,15 +1128,6 @@ de_DE:
selling_on_ofn: "Interesse am Open Food Network?"
register: "Hier anmelden"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Startseite"
footer_global_news: "Aktuelles"
footer_global_about: "Über Uns"
footer_global_contact: "Kontakt"
footer_sites_headline: "OFN Webseiten"
footer_sites_developer: "Entwickler"
footer_sites_community: "Community"
footer_sites_userguide: "Benutzerhandbuch"
footer_secure: "Sicher und vertrauenswürdig."
footer_secure_text: "Open Food Network verwendet überall SSL-Verschlüsselung (2048 Bit RSA), um Ihre Einkaufs- und Zahlungsinformationen geheim zu halten. Unsere Server speichern Ihre Kreditkartendetails nicht und Zahlungen werden von PCI-konformen Dienstleistern verarbeitet."
footer_contact_headline: "In Verbindung bleiben"
@@ -2713,7 +2702,6 @@ de_DE:
allow_ssl_in_development_and_test: "Erlauben Sie SSL in Entwicklungs- und Testmodi"
allow_ssl_in_production: "Zulassen, dass SSL im Produktionsmodus verwendet wird"
allow_ssl_in_staging: "Zulassen, dass SSL im Staging-Modus verwendet wird"
check_for_spree_alerts: "Suchen Sie nach Spree-Benachrichtigungen"
currency_decimal_mark: "Dezimalzeichen der Währung"
currency_settings: "Währungseinstellungen"
currency_symbol_position: Setzen Sie "Währungssymbol vor oder nach dem Dollarbetrag?"

View File

@@ -23,6 +23,8 @@ en:
language_name: "English" # Localised name of this language
activerecord:
attributes:
enterprise_fee:
fee_type: Fee Type
spree/order:
payment_state: Payment State
shipment_state: Shipment State
@@ -69,6 +71,8 @@ en:
shipping_method_ids: "Shipping Methods"
payment_method_ids: "Payment Methods"
errors:
messages:
inclusion: "is not included in the list"
models:
subscription_validator:
attributes:
@@ -903,7 +907,6 @@ en:
save_and_back_to_list: "Save and Back to List"
choose_products_from: "Choose Products From:"
incoming:
previous: "Previous"
save: "Save"
save_and_next: "Save and Next"
next: "Next"
@@ -1046,9 +1049,6 @@ en:
products_and_inventory:
name: Products & Inventory
description:
sales_total:
name: Sales Total
description: Sales Total For All Orders
users_and_enterprises:
name: Users & Enterprises
description: Enterprise Ownership & Status
@@ -1169,6 +1169,8 @@ en:
destroy_attachment_does_not_exist: "Logo does not exist"
enterprise_promo_image:
destroy_attachment_does_not_exist: "Promo image does not exist"
orders:
failed_to_update: "Failed to update order"
# Frontend views
#
@@ -1199,15 +1201,6 @@ en:
selling_on_ofn: "Interested in getting on the Open Food Network?"
register: "Register here"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Home"
footer_global_news: "News"
footer_global_about: "About"
footer_global_contact: "Contact"
footer_sites_headline: "OFN Sites"
footer_sites_developer: "Developer"
footer_sites_community: "Community"
footer_sites_userguide: "User Guide"
footer_secure: "Secure and trusted."
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
footer_contact_headline: "Keep in touch"
@@ -2560,6 +2553,12 @@ See the %{link} to find out more about %{sitename}'s features and to start using
severity: Severity
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products} Products"
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2642,6 +2641,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
customer_placeholder: "customer@example.org"
valid_email_error: "Please enter a valid email address"
subscriptions:
error_saving: "Error saving subscription"
new:
please_select_a_shop: "Please select a shop"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
@@ -2850,7 +2850,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
allow_ssl_in_production: "Allow SSL to be used in production mode"
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
check_for_spree_alerts: "Check for Spree alerts"
currency_decimal_mark: "Currency decimal mark"
currency_settings: "Currency Settings"
currency_symbol_position: Put "currency symbol before or after dollar amount?"
@@ -3072,6 +3071,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
capture: "Capture"
ship: "Ship"
edit: "Edit"
order_not_updated: "The order could not be updated"
note: "Note"
first: "First"
last: "Last"

View File

@@ -2,6 +2,8 @@ en_AU:
language_name: "English"
activerecord:
attributes:
enterprise_fee:
fee_type: Fee Type
spree/order:
payment_state: Payment State
shipment_state: Shipment State
@@ -848,7 +850,6 @@ en_AU:
save_and_back_to_list: "Save and Back to List"
choose_products_from: "Choose Products From:"
incoming:
previous: "Previous"
save: "Save"
save_and_next: "Save and Next"
next: "Next"
@@ -987,9 +988,6 @@ en_AU:
name: Customers
products_and_inventory:
name: Products & Inventory
sales_total:
name: Sales Total
description: Sales Total For All Orders
users_and_enterprises:
name: Users & Enterprises
description: Enterprise Ownership & Status
@@ -1128,15 +1126,6 @@ en_AU:
selling_on_ofn: "Interested in getting on the Open Food Network?"
register: "Register here"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Home"
footer_global_news: "News"
footer_global_about: "About"
footer_global_contact: "Contact"
footer_sites_headline: "OFN Sites"
footer_sites_developer: "Developer"
footer_sites_community: "Community"
footer_sites_userguide: "User Guide"
footer_secure: "Secure and trusted."
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
footer_contact_headline: "Keep in touch"
@@ -1603,11 +1592,11 @@ en_AU:
producers_signup_title: Sign up as a producer
producers_signup_headline: Food producers, empowered.
producers_signup_motivation: Sell your food and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field.
producers_signup_send: Join now
producers_signup_send: Register
producers_signup_enterprise: Enterprise Accounts
producers_signup_studies: Stories from our producers.
producers_signup_cta_headline: Join now!
producers_signup_cta_action: Join now
producers_signup_cta_action: Register
producers_signup_detail: Here's the detail.
products_item: Item
products_description: Description
@@ -1637,7 +1626,7 @@ en_AU:
shops_signup_title: Sign up as a hub
shops_signup_headline: Food hubs, unlimited.
shops_signup_motivation: Whatever your model, we support you. However you change, we're with you. We're non-profit, independent, and open-sourced. We're the software partners you've dreamed of.
shops_signup_action: Join now
shops_signup_action: Register
shops_signup_pricing: Enterprise Accounts
shops_signup_stories: Stories from our hubs.
shops_signup_help: We're ready to help.
@@ -1858,7 +1847,7 @@ en_AU:
finished:
headline: "Finished!"
thanks: "Thanks for filling out the details for %{enterprise}."
login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin."
login: "To manage your new Enterprise, go to openfoodnetwork.org.au/admin"
action: "Open Food Network home"
back: "Back"
continue: "Continue"
@@ -2708,7 +2697,6 @@ en_AU:
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
allow_ssl_in_production: "Allow SSL to be used in production mode"
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
check_for_spree_alerts: "Check for Spree alerts"
currency_decimal_mark: "Currency decimal mark"
currency_settings: "Currency Settings"
currency_symbol_position: Put "currency symbol before or after dollar amount?"

View File

@@ -2,6 +2,8 @@ en_BE:
language_name: "English"
activerecord:
attributes:
enterprise_fee:
fee_type: Fee Type
spree/order:
payment_state: Payment State
shipment_state: Shipment State
@@ -833,7 +835,6 @@ en_BE:
cancel: "Cancel"
choose_products_from: "Choose Products From:"
incoming:
previous: "Previous"
save: "Save"
next: "Next"
cancel: "Cancel"
@@ -964,9 +965,6 @@ en_BE:
name: Customers
products_and_inventory:
name: Products & Inventory
sales_total:
name: Sales Total
description: Sales Total For All Orders
users_and_enterprises:
name: Users & Enterprises
description: Enterprise Ownership & Status
@@ -1103,15 +1101,6 @@ en_BE:
selling_on_ofn: "Interested in getting on the Open Food Network?"
register: "Register here"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Home"
footer_global_news: "News"
footer_global_about: "About"
footer_global_contact: "Contact"
footer_sites_headline: "OFN Sites"
footer_sites_developer: "Developer"
footer_sites_community: "Community"
footer_sites_userguide: "User Guide"
footer_secure: "Secure and trusted."
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
footer_contact_headline: "Keep in touch"
@@ -2681,7 +2670,6 @@ en_BE:
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
allow_ssl_in_production: "Allow SSL to be used in production mode"
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
check_for_spree_alerts: "Check for Spree alerts"
currency_decimal_mark: "Currency decimal mark"
currency_settings: "Currency Settings"
currency_symbol_position: Put "currency symbol before or after euros amount?"

View File

@@ -2,6 +2,8 @@ en_CA:
language_name: "English"
activerecord:
attributes:
enterprise_fee:
fee_type: Fee Type
spree/order:
payment_state: Payment State
shipment_state: Shipment State
@@ -48,6 +50,8 @@ en_CA:
shipping_method_ids: "Shipping Methods"
payment_method_ids: "Payment Methods"
errors:
messages:
inclusion: "is not included in the list"
models:
subscription_validator:
attributes:
@@ -117,7 +121,7 @@ en_CA:
userguide: "Open Food Network User Guide"
email_admin_html: "You can manage your account by logging into the %{link} or by clicking on the cog in the top right hand side of the homepage, and selecting Administration."
admin_panel: "Admin Panel"
email_community_html: "We also have an online forum for community discussion related to OFN software and the unique challenges of running a food enterprise. You are encouraged to join in. We are constantly evolving and your input into this forum will shape what happens next. %{link}"
email_community_html: "We also have an online forum for community discussion related to OFN software and the unique challenges of tech-enabling local enterprises. You are encouraged to join in. We are constantly evolving and your input into this forum will shape what happens next. %{link}"
join_community: "Join the community"
invite_manager:
subject: "%{enterprise} has invited you to be a manager"
@@ -612,7 +616,7 @@ en_CA:
name: Name
name_placeholder: eg. Gustav Plum
email_address: Public Email Address
email_address_placeholder: eg. inquiries@fresh-food.com
email_address_placeholder: eg. inquiries@localproducts.com
email_address_tip: "This email address will be displayed in your public profile"
phone: Phone
phone_placeholder: eg. 519 885 8888
@@ -654,7 +658,7 @@ en_CA:
groups_tip: Select any groups or regions that you are a member of. This will help customers find your enterprise.
groups_placeholder: Start typing to search available groups...
primary_producer: Primary Producer?
primary_producer_tip: Select 'Producer' if you are a primary producer of food.
primary_producer_tip: Select 'Producer' if you are a primary producer, grower, maker or designer
producer: Producer
any: Any
none: None
@@ -778,18 +782,18 @@ en_CA:
always_free: ALWAYS FREE
producer_description_text: Add your products to Open Food Network, allowing hubs to stock your products in their stores.
producer_shop: Producer Shop
sell_your_produce: Sell your own produce
sell_your_produce: Sell your own products
producer_shop_description_text: Sell your products directly to customers through your very own Open Food Network shopfront.
producer_shop_description_text2: A Producer Shop is for your produce only, if you want to sell produce grown/produced off site, select 'Producer Hub'.
producer_shop_description_text2: A Producer Shop is for your products only, if you want to sell producyd grown/produced off site, select 'Producer Hub'.
producer_hub: Producer Hub
producer_hub_text: Sell produce from self and others
producer_hub_description_text: Your enterprise is the backbone of your local food system. You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
producer_hub_text: Sell products from self and others
producer_hub_description_text: Your enterprise is the backbone of your local food system. You can sell your own products as well as products aggregated from other enterprises through your shopfront on the Open Food Network.
profile: Profile Only
get_listing: Get a listing
profile_description_text: People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings.
hub_shop: Hub Shop
hub_shop_text: Sell produce from others
hub_shop_description_text: Your enterprise is the backbone of your local food system. You aggregate produce from other enterprises and can sell it through your shop on the Open Food Network.
hub_shop_text: Sell products from others
hub_shop_description_text: Your enterprise is the backbone of your local community. You aggregate products from other enterprises and can sell them through your shop on the Open Food Network.
choose_option: Please choose one of the options above.
change_now: Change now
enterprise_user_index:
@@ -848,7 +852,6 @@ en_CA:
save_and_back_to_list: "Save and Back to List"
choose_products_from: "Choose Products From:"
incoming:
previous: "Previous"
save: "Save"
save_and_next: "Save and Next"
next: "Next"
@@ -987,9 +990,6 @@ en_CA:
name: Customers
products_and_inventory:
name: Products & Inventory
sales_total:
name: Sales Total
description: Sales Total For All Orders
users_and_enterprises:
name: Users & Enterprises
description: Enterprise Ownership & Status
@@ -1104,6 +1104,8 @@ en_CA:
destroy_attachment_does_not_exist: "Logo does not exist"
enterprise_promo_image:
destroy_attachment_does_not_exist: "Promo image does not exist"
orders:
failed_to_update: "Failed to update order"
checkout:
already_ordered:
cart: "cart"
@@ -1128,15 +1130,6 @@ en_CA:
selling_on_ofn: "Interested in getting on the Open Food Network?"
register: "Register here"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Home"
footer_global_news: "News"
footer_global_about: "About"
footer_global_contact: "Contact"
footer_sites_headline: "OFN Sites"
footer_sites_developer: "Developer"
footer_sites_community: "Community"
footer_sites_userguide: "User Guide"
footer_secure: "Secure and trusted."
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
footer_contact_headline: "Keep in touch"
@@ -1297,7 +1290,7 @@ en_CA:
cookies_policy:
header: "How We Use Cookies"
desc_part_1: "Cookies are very small text files that are stored on your computer when you visit some websites."
desc_part_2: "In OFN we are fully respectful of your privacy. We use only the cookies that are necessary for delivering you the service of selling/buying food online. We dont sell any of your data. We might in the future propose you to share some of your data to build new commons services that could be useful for the ecosystem (like logistics services for short food systems) but we are not yet there, and we wont do it without your authorization :-)"
desc_part_2: "In OFN we are fully respectful of your privacy. We use only the cookies that are necessary for delivering you the service of selling/buying products online. We dont sell any of your data. We might in the future propose you to share some of your data to build new commons services that could be useful for the ecosystem (like logistics or local delivery services) but we are not yet there, and we wont do it without your authorization :-)"
desc_part_3: "We use cookies mainly to remember who you are if you 'log in' to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website. Here is the list of cookies we use!"
essential_cookies: "Essential Cookies"
essential_cookies_desc: "The following cookies are strictly necessary for the operation of our website."
@@ -1331,7 +1324,7 @@ en_CA:
cookies_banner:
cookies_usage: "This site uses cookies in order to make your navigation frictionless and secure, and to help us understand how you use it in order to improve the features we offer."
cookies_definition: "Cookies are very small text files that are stored on your computer when you visit some websites."
cookies_desc: "We use only the cookies that are necessary for delivering you the service of selling/buying food online. We dont sell any of your data. We use cookies mainly to remember who you are if you log in to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website."
cookies_desc: "We use only the cookies that are necessary for delivering you the service of selling/buying products online. We dont sell any of your data. We use cookies mainly to remember who you are if you log in to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website."
cookies_policy_link_desc: "If you want to learn more, check our"
cookies_policy_link: "cookies policy"
cookies_accept_button: "Accept Cookies"
@@ -1339,29 +1332,29 @@ en_CA:
brandstory_headline: "Food, unincorporated."
brandstory_intro: "Sometimes the best way to fix the system is to start a new one…"
brandstory_part1: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can seriously change the world."
brandstory_part2: "Then we need a way to make it real. A way to empower everyone who grows, sells and buys food. A way to tell all the stories, to handle all the logistics. A way to turn transaction into transformation every day."
brandstory_part2: "Then we need a way to make it real. A way to empower everyone who makes, grows, sells and buys local sustainable products. A way to tell all the stories, to handle all the logistics. A way to turn transaction into transformation every day."
brandstory_part3: "So we build an online marketplace that levels the playing field. Its transparent, so it creates real relationships. Its open source, so its owned by everyone. It scales to regions and nations, so people start versions across the world."
brandstory_part4: "It works everywhere. It changes everything."
brandstory_part5_strong: "We call it Open Food Network."
brandstory_part6: "We all love food. Now we can love our food system too."
learn_body: "Explore models, stories and resources to support you to develop your fair food business or organisation. Find training, events and other opportunities to learn from peers."
learn_body: "Explore models, stories and resources to support you to develop your local business or organisation. Find training, events and other opportunities to learn from peers."
learn_cta: "Get Inspired"
connect_body: "Search our full directories of producers, hubs and groups to find fair food traders near you. List your business or organisation on the OFN so buyers can find you. Join the community to get advice and solve problems together."
connect_body: "Search our full directories of producers, hubs and groups to find fair and sustainably produced products near you. List your business or organisation on the OFN so buyers can find you. Join the community to get advice and solve problems together."
connect_cta: "Go Exploring"
system_headline: "Shopping - here's how it works."
system_step1: "1. Search"
system_step1_text: "Search our diverse, independent shops for seasonal local food. Search by neighbourhood and food category, or whether you prefer delivery or pickup."
system_step1_text: "Search our diverse, independent shops for seasonal, sustainably produced products locally. Search by neighbourhood and food category, or whether you prefer delivery or pickup."
system_step2: "2. Shop"
system_step2_text: "Transform your transactions with affordable local food from diverse producers and hubs. Know the stories behind your food and the people who make it!"
system_step2_text: "Transform your transactions with affordable local products from diverse producers, makers and hubs. Know the stories behind their products and the people who make them!"
system_step3: "3. Pick-up / Delivery"
system_step3_text: "Hang on for your delivery, or visit your producer or hub for a more personal connection with your food. Food shopping as diverse as nature intended it."
system_step3_text: "Hang on for your delivery, or connect with the producer, maker or artisan directly. Shopping as diverse as nature intended it."
cta_headline: "Shopping that makes the world a better place."
cta_label: "I'm Ready"
stats_headline: "We're creating a new food system."
stats_producers: "food producers"
stats_shops: "food shops"
stats_shoppers: "food shoppers"
stats_orders: "food orders"
stats_producers: "producers"
stats_shops: "shops"
stats_shoppers: "shoppers"
stats_orders: "orders"
checkout_title: Checkout
checkout_now: Checkout now
checkout_order_ready: Order ready for
@@ -1397,7 +1390,7 @@ en_CA:
order_special_instructions: "Your notes:"
order_pickup_time: Ready for collection
order_pickup_instructions: Collection Instructions
order_produce: Produce
order_produce: Subtotal
order_total_price: Total
order_includes_tax: (includes tax)
order_payment_paypal_successful: Your payment via PayPal has been processed successfully.
@@ -1471,7 +1464,7 @@ en_CA:
email_signup_welcome: "Welcome to %{sitename}!"
email_signup_confirmed_email: "Thanks for confirming your email."
email_signup_shop_html: "You can now log in at %{link}."
email_signup_text: "Thanks for joining the network. If you are a customer, we look forward to introducing you to many fantastic farmers, wonderful food hubs and delicious food! If you are a producer or food enterprise, we are excited to have you as a part of the network."
email_signup_text: "Thanks for joining the network. If you are a customer, we look forward to introducing you to many fantastic growers, artisans and makers, and wonderful hubs and marketplaces. If you are a grower, artisan or maker we are excited to have you as a part of the network."
email_signup_help_html: "We welcome all your questions and feedback; you can use the <em>Send Feedback</em> button on the site or email us at %{email}"
invite_email:
greeting: "Hello!"
@@ -1562,9 +1555,9 @@ en_CA:
groups_signup_motivation2: It's why we get out of bed every day. We're a global non-profit, based on open source code. We play fair. You can always trust us.
groups_signup_motivation3: We know you have big ideas, and we want to help. We'll share our knowledge, networks and resources. We know that isolation doesn't create change, so we'll partner with you.
groups_signup_motivation4: We meet you where you are.
groups_signup_motivation5: You might be an alliance of food hubs, producers, or distributors, and an industry body, or a local government.
groups_signup_motivation6: Whatever your role in your local food movement, we're ready to help. However you come to wonder what Open Food Network would look like or is doing in your part of the world, let's start the conversation.
groups_signup_motivation7: We make food movements make more sense.
groups_signup_motivation5: You might be an alliance of food hubs or initiatives, a local flower marketplace, a network of makers or crafters, a food re-distribution network, an industry body, or a local government.
groups_signup_motivation6: Whatever your role in supporting sustainable production and fair distribution we're ready to help. However you come to wonder what Open Food Network would look like or is doing in your part of the world, let's start the conversation.
groups_signup_motivation7: We make local food and artisanal food movements make more sense.
groups_signup_motivation8: You need to activate and enable your networks, we offer a platform for conversation and action. You need real engagement. Well help reach all the players, all the stakeholders, all the sectors.
groups_signup_motivation9: You need resourcing. Well bring all our experience to bear. You need cooperation. Well better connect you to a global network of peers.
groups_signup_pricing: Group Account
@@ -1573,22 +1566,22 @@ en_CA:
groups_signup_contact_text: "Get in touch to discover what OFN can do for you:"
groups_signup_detail: "Here's the detail."
login_invalid: "Invalid email or password"
modal_hubs: "Food Hubs"
modal_hubs_abstract: Our food hubs are the point of contact between you and the people who make your food!
modal_hubs_content1: You can search for a convenient hub by location or name. Some hubs have multiple points where you can pick-up your purchases, and some will also provide delivery options. Each food hub is a sales point with independent business operations and logistics - so variations between hubs are to be expected.
modal_hubs_content2: You can only shop at one food hub at a time.
modal_hubs: "Hubs"
modal_hubs_abstract: Our hubs are the point of contact between you and the people who grow & make local sustainable things!
modal_hubs_content1: You can search for a convenient hub by location or name. Some hubs have multiple points where you can pick-up your purchases, and some will also provide delivery options. Each fhub is a sales/distribution point with independent operations and logistics - so variations between hubs are to be expected.
modal_hubs_content2: You can only shop at one hub at a time.
modal_groups: "Groups / Regions"
modal_groups_content1: These are the organisations and relationships between hubs which make up the Open Food Network.
modal_groups_content2: Some groups are clustered by location or council, others by non-geographic similarities.
modal_how: "How it works"
modal_how_shop: Shop the Open Food Network
modal_how_shop_explained: Search for a food hub near you to start shopping! You can expand each food hub to see what kinds of goodies are available, and click through to start shopping. (You can only shop one food hub at a time.)
modal_how_shop_explained: Search for a hub near you to start shopping! You can expand each hub to see what kinds of products are available, and click through to start. (You can only shop one hub at a time.)
modal_how_pickup: Pick-ups, delivery and shipping costs
modal_how_pickup_explained: Some food hubs deliver to your door, while others require you to pick-up your purchases. You can see which options are available on the homepage, and select which you'd like at the shopping and check-out pages. Delivery will cost more, and pricing differs from hub-to-hub. Each food hub is a sales point with independent business operations and logisitics - so variations between hubs are to be expected.
modal_how_pickup_explained: Some hubs deliver to your door, while others require you to pick-up your purchases. You can see which options are available on the homepage, and select which you'd like at the shopping and check-out pages. Delivery will cost more, and pricing differs from hub-to-hub. Each hub is a sales point with independent operations and logisitics - so variations between hubs are to be expected.
modal_how_more: Learn more
modal_how_more_explained: "If you want to learn more about the Open Food Network, how it works, and get involved, check out:"
modal_producers: "Producers"
modal_producers_explained: "Our producers make all the delicious food you can shop for on the Open Food Network."
modal_producers_explained: "Our producers make things you can shop for on the Open Food Network."
producers_about: About us
producers_buy: Shop for
producers_contact: Contact
@@ -1601,8 +1594,8 @@ en_CA:
producers_title: Producers
producers_headline: Find local producers
producers_signup_title: Sign up as a producer
producers_signup_headline: Food producers, empowered.
producers_signup_motivation: Sell your food and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field.
producers_signup_headline: Producers & makers, empowered.
producers_signup_motivation: Sell your products and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field.
producers_signup_send: Join now
producers_signup_enterprise: Enterprise Accounts
producers_signup_studies: Stories from our producers.
@@ -1620,22 +1613,22 @@ en_CA:
register_title: Register
sell_title: "Register"
sell_headline: "Get on the Open Food Network!"
sell_motivation: "Showcase your beautiful food."
sell_motivation: "Showcase your beautiful products."
sell_producers: "Producers"
sell_hubs: "Hubs"
sell_groups: "Groups"
sell_producers_detail: "Set up a profile for your business on the OFN in just minutes. At any time you can upgrade your profile to an online store and sell your products direct to customers."
sell_hubs_detail: "Set up a profile for your food enterprise or organisation on the OFN. At any time you can upgrade your profile to a multi-producer shop."
sell_groups_detail: "Set up a tailored directory of enterprises (producers and other food enterprises) for your region or for your organisation."
sell_hubs_detail: "Set up a profile for your enterprise or organisation on the OFN. At any time you can upgrade your profile to a multi-producer shop."
sell_groups_detail: "Set up a tailored directory of enterprises (producers and other local enterprises) for your region or for your organisation."
sell_user_guide: "Find out more in our user guide."
sell_listing_price: "Listing on the OFN is free. Opening and running a shop on OFN is free up to $500 of monthly sales. If you sell more we will invoice you for 2% of sales to a maximum of $150/month. For more detail on pricing visit the Software Platform section via the About link in the top menu."
sell_embed: "We can also embed an OFN shop in your own customised website or build a customised local food network website for your region."
sell_ask_services: "Ask us about OFN services."
shops_title: Shops
shops_headline: Shopping, transformed.
shops_text: Food grows in cycles, farmers harvest in cycles, and we order food in cycles. If you find an order cycle closed, check back soon.
shops_text: Products grow and are made in cycles so we order these products in cycles. If you find an order cycle closed, check back soon.
shops_signup_title: Sign up as a hub
shops_signup_headline: Food hubs, unlimited.
shops_signup_headline: Hubs & Markeplaces, unlimited.
shops_signup_motivation: Whatever your model, we support you. However you change, we're with you. We're non-profit, independent, and open-sourced. We're the software partners you've dreamed of.
shops_signup_action: Join now
shops_signup_pricing: Enterprise Accounts
@@ -1651,7 +1644,7 @@ en_CA:
orders_edit_continue: Continue shopping
orders_edit_checkout: Checkout
orders_form_empty_cart: "Empty cart"
orders_form_subtotal: Produce subtotal
orders_form_subtotal: Subtotal
orders_form_admin: Admin & Handling
orders_form_total: Total
orders_oc_expired_headline: Orders have closed for this order cycle
@@ -1794,8 +1787,8 @@ en_CA:
yes_producer: "Yes, I'm a producer"
no_producer: "No, I'm not a producer"
producer_field_error: "Please choose one. Are you are producer?"
yes_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it."
no_producer_help: "If youre not a producer, youre probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other."
yes_producer_help: "Producers make things. You're a producer if you make it, grow it, raise it, brew it, bake it, ferment it, milk it, mould it or design it."
no_producer_help: "If youre not a producer, youre probably someone who sells and distributes the things they produce or make. You might be a hub, coop, buying group, retailer, wholesaler or other."
create_profile: "Create Profile"
about:
title: "About"
@@ -2092,14 +2085,14 @@ en_CA:
report_header_ship_street_2: Ship Street 2
report_header_ship_city: Ship City
report_header_ship_postcode: Ship Postal Code
report_header_ship_state: Ship State
report_header_ship_state: Ship Province
report_header_billing_street: Billing Street
report_header_billing_street_2: Billing Street 2
report_header_billing_street_3: Billing Street 3
report_header_billing_street_4: Billing Street 4
report_header_billing_city: Billing City
report_header_billing_postcode: Billing Postal Code
report_header_billing_state: Billing State
report_header_billing_state: Billing Province
report_header_incoming_transport: Incoming Transport
report_header_special_instructions: Special Instructions
report_header_order_number: Order number
@@ -2192,7 +2185,7 @@ en_CA:
report_header_not_confirmed: Not Confirmed
report_header_gst_on_income: Sales Tax on Income
report_header_gst_free_income: Tax Free Income
report_header_total_untaxable_produce: Total untaxable produce (no tax)
report_header_total_untaxable_produce: Total untaxable products (no tax)
report_header_total_taxable_produce: Total taxable produce (tax inclusive)
report_header_total_untaxable_fees: Total untaxable fees (no tax)
report_header_total_taxable_fees: Total taxable fees (tax inclusive)
@@ -2344,16 +2337,16 @@ en_CA:
People can find and contact you on the Open Food Network. Your enterprise
will be visible on the map, and will be searchable in listings.
hub_profile_text2: >
Having a profile, and making connections within your local food system
through the Open Food Network will always be free.
Having a profile, and making connections within your local networks
and communities through the Open Food Network will always be free.
hub_shop: Hub Shop
hub_shop_text1: >
Your enterprise is the backbone of your local food system. You aggregate
produce from other enterprises and can sell it through your shop on
Your enterprise is the backbone of your local community. You aggregate
products from other enterprises and sell them through your shop on
the Open Food Network.
hub_shop_text2: >
Hubs can take many forms, whether they be a food co-op, a buying group,
a veggie-box program, or a local grocery store.
Hubs can take many forms - a local co-op, a buying group, a food-box
program, or an on-line markeplace for crafts or flowers....
hub_shop_text3: >
If you also want to sell your own products, you will need to switch
this enterprise to be a producer.
@@ -2370,9 +2363,9 @@ en_CA:
A profile makes you visible and contactable to others and is a way to
share your story.
profile_only_text2: >
If you prefer to focus on producing food, and want to leave the work
of selling it to someone else, you won't require a shop on the Open
Food Network.
If you prefer to focus on producing, designing and making, and want
to leave the work of selling it to someone else, you won't require a
shop on the Open Food Network.
profile_only_text3: >
Add your products to Open Food Network, allowing hubs to stock your
products in their stores.
@@ -2381,51 +2374,56 @@ en_CA:
Sell your products directly to customers through your very own Open
Food Network shopfront.
producer_shop_text2: >
A Producer Shop is for your produce only, if you want to sell produce
grown/produced off site, please select 'Producer Hub'.
A Producer Shop is for your products only, if you want to sell products
grown/made/created off site, please select 'Producer Hub'.
producer_hub: Producer Hub
producer_hub_text1: >
Your enterprise is the backbone of your local food system. You can sell
your own produce as well as produce aggregated from other enterprises
Your enterprise is the backbone of your local community. You can sell
your own products as well as products aggregated from other enterprises
through your shopfront on the Open Food Network.
producer_hub_text2: >
Producer Hubs can take many forms, whether they be a CSA, a veggie-box
program, or a food co-op with a rooftop garden.
Producer Hubs can take many forms, whether they be a CSA, a food box
program, a co-op, cut flower marketplace.....
producer_hub_text3: >
The Open Food Network aims to support as many hub models as possible,
so no matter your situation, we want to provide the tools you need to
run your organisation or local food business.
get_listing: Get a listing
always_free: ALWAYS FREE
sell_produce_others: Sell produce from others
sell_own_produce: Sell your own produce
sell_both: Sell produce from self and others
sell_produce_others: Sell products from others
sell_own_produce: Sell your own products
sell_both: Sell products from self and others
enterprise_producer:
producer: Producer
producer_text1: >
Producers make yummy things to eat or drink. You're a producer if you
grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
Producers make things. You're a producer if you make it, grow it, raise
it, brew it, bake it, ferment it, milk it, mould it, design it.....
producer_text2: >
Producers can also perform other functions, such as aggregating food
from other enterprises and selling it through a shop on the Open Food
Producers can also perform other functions, such as aggregating products
from other enterprises and selling them through a shop on the Open Food
Network.
non_producer: Non-producer
non_producer_text1: >
Non-producers do not produce any food themselves, meaning that they
Non-producers do not produce any products themselves, meaning that they
cannot create their own products for sale through the Open Food Network.
non_producer_text2: >
Instead, non-producers specialise in linking producers to the end eater,
whether it be by aggregating, grading, packing, selling or delivering
food.
producer_desc: Producers of food
Instead, non-producers specialise in linking producers and their products
to the end buyer/user, by aggregating, packing, selling or distributing.
producer_desc: 'Producers '
producer_example: eg. GROWERS, BAKERS, BREWERS, MAKERS
non_producer_desc: All other food enterprises
non_producer_example: eg. Grocery stores, Food co-ops, Buying groups
non_producer_desc: All other enterprises
non_producer_example: eg. Grocery stores, Co-ops, Buying groups, Markets
enterprise_status:
status_title: "%{name} is set up and ready to go!"
severity: Severity
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products}Products"
products_loaded: "%{num_of_products_loaded}of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2508,6 +2506,7 @@ en_CA:
customer_placeholder: "customer@example.org"
valid_email_error: "Please enter a valid email address"
subscriptions:
error_saving: "Error saving subscription"
new:
please_select_a_shop: "Please select a shop"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
@@ -2687,7 +2686,7 @@ en_CA:
city: "City"
zip: "Postal Code"
country: "Country"
state: "State"
state: "Province"
phone: "Phone"
update: "Update"
use_billing_address: "Use Billing Address"
@@ -2708,7 +2707,6 @@ en_CA:
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
allow_ssl_in_production: "Allow SSL to be used in production mode"
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
check_for_spree_alerts: "Check for Spree alerts"
currency_decimal_mark: "Currency decimal mark"
currency_settings: "Currency Settings"
currency_symbol_position: Put "currency symbol before or after dollar amount?"
@@ -2875,19 +2873,35 @@ en_CA:
presentation: "Presentation"
return_authorizations:
index:
new_return_authorization: "New Return Authorization"
return_authorizations: "Return Authoriations"
back_to_orders_list: "Back to Orders List"
rma_number: "RMA Number"
status: "Status"
amount: "Amount"
cannot_create_returns: "Cannot create returns as this order has no shipped units"
continue: "Continue"
new:
new_return_authorization: "New Return Authorization"
back_to_return_authorizations_list: "Back to Return Authorization List"
continue: "Continue"
edit:
receive: "receive"
are_you_sure: "Are you sure?"
return_authorization: "Return Authorization"
form:
product: "Product"
quantity_shipped: "Quantity Shipped"
quantity_returned: "Quantity Returned"
return_quantity: "Return Quantity"
amount: "Amount"
rma_value: "RMA Value"
reason: "Reason"
stock_location: "Stock Location"
states:
authorized: "Authorized"
received: "Received"
canceled: "Canceled"
orders:
index:
listing_orders: "Listing Orders"
@@ -2895,6 +2909,7 @@ en_CA:
capture: "Capture"
ship: "Ship"
edit: "Edit"
order_not_updated: "The order could not be updated"
note: "Note"
first: "First"
last: "Last"

View File

@@ -2,6 +2,8 @@ en_DE:
language_name: "English"
activerecord:
attributes:
enterprise_fee:
fee_type: Fee Type
spree/order:
payment_state: Payment State
shipment_state: Shipment State
@@ -841,7 +843,6 @@ en_DE:
cancel: "Cancel"
choose_products_from: "Choose Products From:"
incoming:
previous: "Previous"
save: "Save"
next: "Next"
cancel: "Cancel"
@@ -972,9 +973,6 @@ en_DE:
name: Customers
products_and_inventory:
name: Products & Inventory
sales_total:
name: Sales Total
description: Sales Total For All Orders
users_and_enterprises:
name: Users & Enterprises
description: Enterprise Ownership & Status
@@ -1113,15 +1111,6 @@ en_DE:
selling_on_ofn: "Interested in getting on the Open Food Network?"
register: "Register here"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Home"
footer_global_news: "News"
footer_global_about: "About"
footer_global_contact: "Contact"
footer_sites_headline: "OFN Sites"
footer_sites_developer: "Developer"
footer_sites_community: "Community"
footer_sites_userguide: "User Guide"
footer_secure: "Secure and trusted."
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
footer_contact_headline: "Keep in touch"
@@ -2693,7 +2682,6 @@ en_DE:
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
allow_ssl_in_production: "Allow SSL to be used in production mode"
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
check_for_spree_alerts: "Check for Spree alerts"
currency_decimal_mark: "Currency decimal mark"
currency_settings: "Currency Settings"
currency_symbol_position: Put "currency symbol before or after dollar amount?"

View File

@@ -2,6 +2,8 @@ en_FR:
language_name: "English"
activerecord:
attributes:
enterprise_fee:
fee_type: Fee Type
spree/order:
payment_state: Payment State
shipment_state: Shipment State
@@ -48,6 +50,8 @@ en_FR:
shipping_method_ids: "Shipping Methods"
payment_method_ids: "Payment Methods"
errors:
messages:
inclusion: "is not included in the list"
models:
subscription_validator:
attributes:
@@ -848,7 +852,6 @@ en_FR:
save_and_back_to_list: "Save and Back to List"
choose_products_from: "Choose Products From:"
incoming:
previous: "Previous"
save: "Save"
save_and_next: "Save and Next"
next: "Next"
@@ -987,9 +990,6 @@ en_FR:
name: Customers
products_and_inventory:
name: Products & Inventory
sales_total:
name: Sales Total
description: Sales Total For All Orders
users_and_enterprises:
name: Users & Enterprises
description: Enterprise Ownership & Status
@@ -1104,6 +1104,8 @@ en_FR:
destroy_attachment_does_not_exist: "Logo does not exist"
enterprise_promo_image:
destroy_attachment_does_not_exist: "Promo image does not exist"
orders:
failed_to_update: "Failed to update order"
checkout:
already_ordered:
cart: "cart"
@@ -1128,15 +1130,6 @@ en_FR:
selling_on_ofn: "Interested in getting on the Open Food Network?"
register: "Register here"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Home"
footer_global_news: "News"
footer_global_about: "About"
footer_global_contact: "Contact"
footer_sites_headline: "OFN Sites"
footer_sites_developer: "Developer"
footer_sites_community: "Community"
footer_sites_userguide: "User Guide"
footer_secure: "Secure and trusted."
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
footer_contact_headline: "Keep in touch"
@@ -2426,6 +2419,12 @@ en_FR:
severity: Severity
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products} Products"
products_loaded: "%{num_of_products_loaded}of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2508,6 +2507,7 @@ en_FR:
customer_placeholder: "customer@example.org"
valid_email_error: "Please enter a valid email address"
subscriptions:
error_saving: "Error saving subscription"
new:
please_select_a_shop: "Please select a shop"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
@@ -2708,7 +2708,6 @@ en_FR:
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
allow_ssl_in_production: "Allow SSL to be used in production mode"
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
check_for_spree_alerts: "Check for Spree alerts"
currency_decimal_mark: "Currency decimal mark"
currency_settings: "Currency Settings"
currency_symbol_position: Put "currency symbol before or after dollar amount?"
@@ -2911,6 +2910,7 @@ en_FR:
capture: "Capture"
ship: "Ship"
edit: "Edit"
order_not_updated: "The order could not be updated"
note: "Note"
first: "First"
last: "Last"

View File

@@ -2,6 +2,8 @@ en_GB:
language_name: "English"
activerecord:
attributes:
enterprise_fee:
fee_type: Fee Type
spree/order:
payment_state: Payment State
shipment_state: Shipment State
@@ -48,6 +50,8 @@ en_GB:
shipping_method_ids: "Shipping Methods"
payment_method_ids: "Payment Methods"
errors:
messages:
inclusion: "is not included in the list"
models:
subscription_validator:
attributes:
@@ -848,7 +852,6 @@ en_GB:
save_and_back_to_list: "Save and Back to List"
choose_products_from: "Choose Products From:"
incoming:
previous: "Previous"
save: "Save"
save_and_next: "Save and Next"
next: "Next"
@@ -987,9 +990,6 @@ en_GB:
name: Customers
products_and_inventory:
name: Products & Inventory
sales_total:
name: Sales Total
description: Sales Total For All Orders
users_and_enterprises:
name: Users & Enterprises
description: Enterprise Ownership & Status
@@ -1128,15 +1128,6 @@ en_GB:
selling_on_ofn: "Interested in selling through the Open Food Network?"
register: "Register here"
footer:
footer_global_headline: "OFN Global"
footer_global_home: "Home"
footer_global_news: "News"
footer_global_about: "About"
footer_global_contact: "Contact"
footer_sites_headline: "OFN Sites"
footer_sites_developer: "Developer"
footer_sites_community: "Community"
footer_sites_userguide: "User Guide"
footer_secure: "Secure and trusted."
footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
footer_contact_headline: "Keep in touch"
@@ -1512,7 +1503,7 @@ en_GB:
hubs_filter_type: "Type"
hubs_filter_delivery: "Delivery"
hubs_filter_property: "Property"
hubs_matches: "Did you mean?"
hubs_matches: "Showing results for"
hubs_intro: Shop in your local area
hubs_distance: Closest to
hubs_distance_filter: "Show me shops near %{location}"
@@ -2432,6 +2423,12 @@ en_GB:
severity: Severity
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products} Products"
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2514,6 +2511,7 @@ en_GB:
customer_placeholder: "customer@example.org"
valid_email_error: "Please enter a valid email address"
subscriptions:
error_saving: "Error saving subscription"
new:
please_select_a_shop: "Please select a shop"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
@@ -2714,7 +2712,6 @@ en_GB:
allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
allow_ssl_in_production: "Allow SSL to be used in production mode"
allow_ssl_in_staging: "Allow SSL to be used in staging mode"
check_for_spree_alerts: "Check for Spree alerts"
currency_decimal_mark: "Currency decimal mark"
currency_settings: "Currency Settings"
currency_symbol_position: Put "currency symbol before or after pound amount?"

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