Compare commits

...

148 Commits

Author SHA1 Message Date
Matt-Yorkley
d280bf0d4d Update all locales with the latest Transifex translations 2020-02-27 11:42:02 +01:00
Luis Ramos
03c91dfac1 Merge pull request #4780 from luisramos0/bulk_prod_errors
Fix javascript logic that parses server errors in the bulk product edit page
2020-02-25 18:49:54 +00:00
Luis Ramos
60e12063cd Merge pull request #4758 from luisramos0/fix_incomplete_stripe
Make the payment methods filter handle misconfigured stripe payment methods
2020-02-25 18:47:09 +00:00
Pau Pérez Fabregat
e5b57af315 Merge pull request #4815 from openfoodfoundation/transifex
Transifex
2020-02-25 13:37:30 +01:00
Pau Pérez Fabregat
a396a7f0af Merge pull request #4818 from luisramos0/delete_dead_code
Delete dead code after PRs 4512 and 4508
2020-02-25 13:32:23 +01:00
Transifex-Openfoodnetwork
d084789c56 Updating translations for config/locales/nb.yml 2020-02-25 19:57:08 +11:00
Transifex-Openfoodnetwork
dafac32e70 Updating translations for config/locales/nb.yml 2020-02-25 19:53:59 +11:00
Transifex-Openfoodnetwork
6ca39f3aa5 Updating translations for config/locales/fr_CA.yml 2020-02-25 09:10:13 +11:00
Transifex-Openfoodnetwork
234a9ef1b4 Updating translations for config/locales/en_CA.yml 2020-02-25 08:41:07 +11:00
Luis Ramos
24a1327805 Merge pull request #4785 from openfoodfoundation/dependabot/bundler/stripe-5.15.0
Bump stripe from 5.11.0 to 5.15.0
2020-02-24 20:12:39 +00:00
Luis Ramos
33d77d57f4 Merge pull request #4776 from luisramos0/remove_assets_group
Remove the assets group from the gemfile (taken from spree upgrade branch)
2020-02-24 20:12:01 +00:00
Transifex-Openfoodnetwork
0571b657aa Updating translations for config/locales/en_FR.yml 2020-02-25 04:39:02 +11:00
Transifex-Openfoodnetwork
e4958baddc Updating translations for config/locales/en_FR.yml 2020-02-25 04:35:52 +11:00
Transifex-Openfoodnetwork
c985747297 Updating translations for config/locales/fr.yml 2020-02-25 04:31:33 +11:00
Transifex-Openfoodnetwork
f5ffdfc258 Updating translations for config/locales/en_NZ.yml 2020-02-23 22:32:56 +11:00
Luis Ramos
a3a61967a8 Merge pull request #4621 from luisramos0/spree_backend_js
OFN without spree_backend 🎉
2020-02-22 10:24:50 +00:00
Luis Ramos
1bdeda4a21 Delete dead code after PRs 4512 and 4508 2020-02-21 12:25:07 +00:00
Transifex-Openfoodnetwork
49ba83da6d Updating translations for config/locales/en_GB.yml 2020-02-21 05:32:39 +11:00
Transifex-Openfoodnetwork
19d1497c4b Updating translations for config/locales/en_GB.yml 2020-02-21 05:29:31 +11:00
Luis Ramos
0c4f22f847 Fix images/new.js path and add simple spec to verify the page loads correctly
Testing the file upload would be a bit more complicated
2020-02-20 11:18:22 +00:00
Luis Ramos
1803ea3c38 Add traling breakline to case where errors come in a array 2020-02-20 10:06:10 +00:00
Pau Pérez Fabregat
93fda02e43 Merge pull request #4803 from openfoodfoundation/dependabot/bundler/rubocop-0.80.0
Bump rubocop from 0.79.0 to 0.80.0
2020-02-20 09:34:10 +01:00
Pau Pérez Fabregat
77958f9afe Merge pull request #4796 from openfoodfoundation/dependabot/bundler/i18n-js-3.6.0
Bump i18n-js from 3.5.1 to 3.6.0
2020-02-20 09:32:02 +01:00
Maikel Linke
82e402f31a Update translations from Transifex 2020-02-20 16:20:06 +11:00
Maikel
35aeb98d45 Merge pull request #4792 from openfoodfoundation/transifex
Transifex
2020-02-20 10:43:45 +11:00
Luis Ramos
d99cba3b6e Merge pull request #4709 from mkllnk/4172-js-pluralize
Pluralize common variant unit names
2020-02-19 22:28:54 +00:00
dependabot-preview[bot]
4c6fd96bcc Bump rubocop from 0.79.0 to 0.80.0
Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 0.79.0 to 0.80.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.79.0...v0.80.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 19:18:53 +00:00
dependabot-preview[bot]
ff088c6203 Bump stripe from 5.11.0 to 5.15.0
Bumps [stripe](https://github.com/stripe/stripe-ruby) from 5.11.0 to 5.15.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/v5.11.0...v5.15.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 12:01:10 +00:00
Luis Ramos
a1cb6928db Merge pull request #4793 from openfoodfoundation/dependabot/bundler/webmock-3.8.2
Bump webmock from 3.8.1 to 3.8.2
2020-02-18 11:59:14 +00:00
Luis Ramos
40a5b60dcb Merge pull request #4794 from openfoodfoundation/dependabot/bundler/oauth2-1.4.4
Bump oauth2 from 1.4.3 to 1.4.4
2020-02-18 11:58:58 +00:00
Luis Ramos
2711736004 Use Array#join and make code simpler 2020-02-18 10:49:41 +00:00
Luis Ramos
18c165e893 Merge pull request #4784 from CSCI-462-01-2020/Issue4731
Add Order Cycle Button Tooltips
2020-02-17 19:32:39 +00:00
Luis Ramos
0aaa04295b Improve and unit test errorsParser 2020-02-17 11:21:21 +00:00
Luis Ramos
7639e9a38d Extrac ErrorsParser to separate class and make it handle the rails error structure with keys 2020-02-17 11:21:21 +00:00
Transifex-Openfoodnetwork
d783bd771f Updating translations for config/locales/ar.yml 2020-02-15 09:33:06 +11:00
Transifex-Openfoodnetwork
9dd9d14107 Updating translations for config/locales/ar.yml 2020-02-15 09:29:56 +11:00
Transifex-Openfoodnetwork
e942266dd7 Updating translations for config/locales/pt_BR.yml 2020-02-15 07:05:18 +11:00
dependabot-preview[bot]
c8f78904d6 Bump i18n-js from 3.5.1 to 3.6.0
Bumps [i18n-js](https://github.com/fnando/i18n-js) from 3.5.1 to 3.6.0.
- [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.1...v3.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-14 19:24:49 +00:00
Transifex-Openfoodnetwork
a982fd1e2b Updating translations for config/locales/tr.yml 2020-02-14 22:27:33 +11:00
Transifex-Openfoodnetwork
7e8b2f6be5 Updating translations for config/locales/tr.yml 2020-02-14 22:24:23 +11:00
Transifex-Openfoodnetwork
921c7bbc3a Updating translations for config/locales/tr.yml 2020-02-14 22:21:12 +11:00
Transifex-Openfoodnetwork
eaff6b0c68 Updating translations for config/locales/nb.yml 2020-02-14 19:26:01 +11:00
Transifex-Openfoodnetwork
e1ab424481 Updating translations for config/locales/nb.yml 2020-02-14 19:22:51 +11:00
Transifex-Openfoodnetwork
e59c9720fc Updating translations for config/locales/en_GB.yml 2020-02-14 06:53:13 +11:00
dependabot-preview[bot]
b25f0007f0 Bump oauth2 from 1.4.3 to 1.4.4
Bumps [oauth2](https://github.com/oauth-xx/oauth2) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/oauth-xx/oauth2/releases)
- [Changelog](https://github.com/oauth-xx/oauth2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/oauth-xx/oauth2/compare/v1.4.3...v1.4.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-13 19:19:44 +00:00
dependabot-preview[bot]
65c5cdd52f Bump webmock from 3.8.1 to 3.8.2
Bumps [webmock](https://github.com/bblimke/webmock) from 3.8.1 to 3.8.2.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.8.1...v3.8.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-13 19:16:18 +00:00
Transifex-Openfoodnetwork
a2873ea553 Updating translations for config/locales/fr.yml 2020-02-14 05:05:51 +11:00
Transifex-Openfoodnetwork
3a593ff255 Updating translations for config/locales/fr.yml 2020-02-14 05:02:42 +11:00
Transifex-Openfoodnetwork
92e1193ffb Updating translations for config/locales/en_FR.yml 2020-02-14 05:01:02 +11:00
Transifex-Openfoodnetwork
016968dcb9 Updating translations for config/locales/fr.yml 2020-02-14 04:59:33 +11:00
Luis Ramos
9d8608f210 Merge pull request #4630 from Matt-Yorkley/product_counts
Show counts including all variants in order cycle exchanges
2020-02-13 11:33:58 +00:00
Luis Ramos
323ca906bc Merge pull request #4759 from pacodelaluna/order-admin-products
Order admin products
2020-02-13 11:33:05 +00:00
Luis Ramos
c43b34e0fa Merge pull request #4760 from luisramos0/checkout_ctrl
Merge Spree::CheckoutController with CheckoutController and clean it up
2020-02-13 11:31:15 +00:00
Luis Ramos
bc7f0e0962 Update all locales with the latest Transifex translations 2020-02-13 11:19:07 +00:00
Luis Ramos
cf4f7c562a Merge pull request #4778 from openfoodfoundation/transifex
Transifex
2020-02-13 11:08:01 +00:00
François Turbelin
4c7bd4d6a8 Fix mess with order 2020-02-13 06:38:13 +01:00
François Turbelin
523b266308 Put back created_at desc as default order 2020-02-13 06:38:13 +01:00
François Turbelin
212413c8b3 Avoid mutable q params 2020-02-13 06:38:13 +01:00
François Turbelin
b248dc598e Cosmetics 2020-02-13 06:38:13 +01:00
François Turbelin
e7b74b99ba Refactor SortingOptions JS 2020-02-13 06:38:13 +01:00
François Turbelin
89d2750fc4 Set default value at backend side 2020-02-13 06:38:13 +01:00
François Turbelin
7100111f93 Fix specs and cosmetics 2020-02-13 06:38:13 +01:00
François Turbelin
3dcb66014e Factorize column sorter partial 2020-02-13 06:38:13 +01:00
François Turbelin
06971b7198 Add sortable name column for Admin Products 2020-02-13 06:38:13 +01:00
François Turbelin
56f9adc5b7 Filter Admin products by name asc 2020-02-13 06:38:13 +01:00
Luis Ramos
38374a9835 Merge pull request #4761 from openfoodfoundation/dependabot/bundler/unicorn-5.5.3
Bump unicorn from 5.5.2 to 5.5.3
2020-02-12 20:56:19 +00:00
Luis Ramos
8d6a8ee214 Merge pull request #4763 from mkllnk/rails4-form-rendering
Future proof form rendering in admin orders
2020-02-12 20:56:00 +00:00
blainebillings
fec653186a Add Order Cycle Button Tooltips 2020-02-11 10:10:39 -05:00
Transifex-Openfoodnetwork
ebe7456b66 Updating translations for config/locales/tr.yml 2020-02-11 21:48:53 +11:00
Transifex-Openfoodnetwork
8187669a25 Updating translations for config/locales/tr.yml 2020-02-11 21:45:44 +11:00
Transifex-Openfoodnetwork
a6aa0df53b Updating translations for config/locales/fr_BE.yml 2020-02-10 03:32:33 +11:00
Transifex-Openfoodnetwork
116695b1d9 Updating translations for config/locales/en_NZ.yml 2020-02-08 18:53:00 +11:00
Transifex-Openfoodnetwork
387ac40dc9 Updating translations for config/locales/en_NZ.yml 2020-02-08 18:49:51 +11:00
luisramos0
66320b5055 Remove the assets group from the gemfile, it will disappear in rails 4 2020-02-07 12:29:02 +00:00
luisramos0
858d2cc6c2 Add doc to Spree::CheckoutController to make it more obvious why this controller exists 2020-02-07 11:50:23 +00:00
luisramos0
43280da187 Dup params to avoid nasty effects of a mutated params object in the controller 2020-02-07 10:26:04 +00:00
Luis Ramos
e1eface5f8 Merge pull request #4542 from luisramos0/logger
Add timestamp to log entries
2020-02-07 10:02:55 +00:00
Luis Ramos
5cd14253d0 Merge pull request #4770 from openfoodfoundation/dependabot/bundler/webmock-3.8.1
Bump webmock from 3.8.0 to 3.8.1
2020-02-07 09:31:19 +00:00
Maikel
be691df7ac Merge pull request #4769 from openfoodfoundation/transifex
Transifex
2020-02-07 18:09:31 +11:00
Maikel Linke
7783b28ca2 Update concurrency spec after refactor
In order to make the spec fail if the controller was not thread safe, it
uses breakpoints. One of those breakpoints was set for a method that has
now been removed.

I changed the method that is used for the breakpoint and changed `allow`
to `expect` so that this spec will fail if we remove that method as
well. Future version of Rspec will check if a mocked method actually
exists but our version just mocks it anyway. This is one way how specs
can become invalid after refactoring.
2020-02-07 17:46:42 +11:00
Maikel
6d51856821 Merge pull request #4734 from openfoodfoundation/dependabot/bundler/oauth2-1.4.3
Bump oauth2 from 1.4.2 to 1.4.3
2020-02-07 16:48:42 +11:00
dependabot-preview[bot]
890704b75c Bump webmock from 3.8.0 to 3.8.1
Bumps [webmock](https://github.com/bblimke/webmock) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.8.0...v3.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-06 19:17:54 +00:00
Transifex-Openfoodnetwork
922484b2e7 Updating translations for config/locales/en_GB.yml 2020-02-07 05:02:38 +11:00
Luis Ramos
3e7288648b Merge pull request #4762 from openfoodfoundation/dependabot/bundler/roo-2.8.3
Bump roo from 2.8.2 to 2.8.3
2020-02-06 14:44:21 +00:00
luisramos0
f0f537ff8f Fix path of spree-select2.js pointing to the file in ofn rather the file in spree_backend 2020-02-06 11:21:47 +00:00
Transifex-Openfoodnetwork
b7f920c4b6 Updating translations for config/locales/ca.yml 2020-02-06 21:12:27 +11:00
luisramos0
e5c9468d09 Fix rubocop issues in navigation_helper 2020-02-05 22:16:20 +00:00
luisramos0
8aed173127 Uncomment events in order edit page and remove unused spree autocomplete js code 2020-02-05 20:04:15 +00:00
luisramos0
61ecca7257 Move template loading to directive of customer search override 2020-02-05 20:04:15 +00:00
luisramos0
7eba657b2f Add missing templates from spree_backend 2020-02-05 20:04:15 +00:00
luisramos0
784de340d1 Disable adaptive menu when running tests, this is what spree_backend was doing before 2020-02-05 20:04:15 +00:00
luisramos0
9191628f29 Bring custom form_builder initializer from spree_backend 2020-02-05 20:04:15 +00:00
luisramos0
88410b1efd Add missing general config routes from spree_backend 2020-02-05 20:04:12 +00:00
luisramos0
afea032361 Add return_authorizations route from spree_backend 2020-02-05 16:02:43 +00:00
luisramos0
3decb4056c Remove repeated include spree_paypal_express and add require css select2 2020-02-05 16:02:43 +00:00
luisramos0
8e9b08feca Remove jquery-alerts from head html 2020-02-05 16:02:43 +00:00
luisramos0
694995ea5d Prefix root_path with main_app so that ofn's route is used. The spree root path is no longer defined, we dont need it 2020-02-05 16:02:43 +00:00
luisramos0
22de7252d0 Fix route in login nav and bring reports and properties resource route from spree_backend 2020-02-05 16:02:43 +00:00
luisramos0
2acf8e5125 Remove config_locale from base controller, in OFN we dont have separate locales for frontoffice and backoffice 2020-02-05 16:02:43 +00:00
luisramos0
e1f61e645d Remove dependency to spree_backend and add dependencies still required: jquery-ui-rails and select2-rails 2020-02-05 16:02:43 +00:00
luisramos0
687d827ceb Add required css require for select2 2020-02-05 16:02:43 +00:00
luisramos0
2885e38113 Re-activate/re-add click events that were registered in spree_backend code before 2020-02-05 16:02:43 +00:00
luisramos0
9f3ca58b55 Add empty admin/spree_backend.js
This file is required by spree_paypal_express that we still need after leaving spree_backend
2020-02-05 16:02:43 +00:00
luisramos0
ffe3228848 Remove spree_backend dependencies from all.js and all.css and fix some dependencies path problems 2020-02-05 16:02:43 +00:00
luisramos0
834231eb8f Add js code needed for the zones admin page 2020-02-05 16:02:43 +00:00
luisramos0
68f5aabd3f Add js code needed where calculators are used: ship methods and payment methods config pages 2020-02-05 16:02:43 +00:00
luisramos0
7e7ea92833 Add js code needed in the states admin page 2020-02-05 16:02:43 +00:00
luisramos0
ebf22ceb19 Add js and css code for image settings from spree_backend 2020-02-05 16:02:43 +00:00
Luis Ramos
c38c7c35bc Add spec for user default address setter 2020-02-05 14:49:17 +00:00
luisramos0
2663f74767 Add specs for new services 2020-02-05 14:49:17 +00:00
luisramos0
b41de52012 Moved checkout services into a specific folder under app/services 2020-02-05 14:49:17 +00:00
luisramos0
214eb43122 Add frozen string literal magic comment 2020-02-05 14:49:17 +00:00
luisramos0
01fc4e0513 Add Spree::CheckoutController only to redirect to CheckoutController
I have not managed to make the spree checkout route, that paypal express uses, go to CheckoutController directly. According to the rails docs "to: '/checkout#edit'" should do it, but it doesnt work here.
2020-02-05 14:49:17 +00:00
luisramos0
6ce50a5fa5 Extract paypal redirect logic to service class 2020-02-05 14:49:17 +00:00
luisramos0
4fbd2cfa52 Extract UserDefaultAddress logic into separate class to take more 30 lines out of CheckoutController 2020-02-05 14:49:17 +00:00
luisramos0
383b28e170 Add order and current_user to checkout_form_data_adapter where they are required
Also re-add order.state condition to update_result: in some tests, the order state is complete but no completion data (completed?) is present
2020-02-05 14:49:17 +00:00
luisramos0
bf55a15f81 Extract checkout params adaptation logic into a service class 2020-02-05 14:49:17 +00:00
luisramos0
eb7e6dc5b8 Remove spree checkout controller spec, it is no longer necessary 2020-02-05 14:49:17 +00:00
luisramos0
139ecfe604 Remove rubocop exceptions resolved so far in checkout controller 2020-02-05 14:49:17 +00:00
luisramos0
43a6798db2 Move methods around in checkout controller into a more logical organisation: first the filters code and then support code for the update action 2020-02-05 14:49:17 +00:00
luisramos0
06d6579486 Refactor construct_saved_card_attributes to fix rubocop issues 2020-02-05 14:49:17 +00:00
luisramos0
76df526002 Remove dead code from construct_saved_card_attributes 2020-02-05 14:49:17 +00:00
luisramos0
06569ea24c Refactor load_order to fix rubocop issues 2020-02-05 14:49:17 +00:00
luisramos0
25431f851b Refactor object_params to fix rubocop issues 2020-02-05 14:49:17 +00:00
luisramos0
bab2420bb3 Break up default address methods to fix rubocop issues 2020-02-05 14:49:17 +00:00
luisramos0
0b2acb3a76 Extracted two methods from checkout_workflow to fix rubocop issues 2020-02-05 14:49:17 +00:00
luisramos0
27db9e604f Extract respond_to_update_succeeded from update_succeeded 2020-02-05 14:49:17 +00:00
luisramos0
c4e58ebb9e Extract update_succeeded from checkout#update 2020-02-05 14:49:17 +00:00
luisramos0
9a0ee254af Extract checkout_workflow from checkout#update 2020-02-05 14:49:17 +00:00
luisramos0
5ce3e1e0d2 Fix some rubocop issues in checkout controller 2020-02-05 14:49:17 +00:00
luisramos0
4b345d928c Remove old code to detect Phantom Fees, no bugsnag events detected at all 2020-02-05 14:49:17 +00:00
luisramos0
52b1e6c71a Move all logic required in Spree::CheckoutController to CheckoutController 2020-02-05 14:49:17 +00:00
Matt-Yorkley
140e0b9cb1 Refactor #exchangeLoadedVariants 2020-02-05 15:11:34 +01:00
Matt-Yorkley
b3f05d1a98 Use "Variants" instead of "Products" in order cycle exchanges UI 2020-02-05 15:11:34 +01:00
Matt-Yorkley
9644b145cc Remove num_of_products 2020-02-05 15:11:34 +01:00
Matt-Yorkley
6f644936b0 Show counts including all variants in order cycle exchanges 2020-02-05 15:10:26 +01:00
Matt-Yorkley
b86759d7a7 Fix form rendering in admin orders
ActionView::Template::Error: Nil location provided. Can't build URI.
  0) Account and Billing Settings updating as an admin user loads the page
     Failure/Error: = form_tag false, {name: "orders_form", "ng-submit" => "fetchResults()"} do
2020-02-05 16:37:23 +11:00
dependabot-preview[bot]
9d1e3f0318 Bump roo from 2.8.2 to 2.8.3
Bumps [roo](https://github.com/roo-rb/roo) from 2.8.2 to 2.8.3.
- [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.8.2...v2.8.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-04 19:23:42 +00:00
dependabot-preview[bot]
67adf3c801 Bump unicorn from 5.5.2 to 5.5.3
Bumps [unicorn](https://yhbt.net/unicorn/) from 5.5.2 to 5.5.3.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-04 19:22:39 +00:00
luisramos0
6e78ae762a Make it work even if preferred_enterprise_id is null 2020-02-04 10:01:18 +00:00
Maikel Linke
9535c5647f Make pluralisation code an independent lib
I considered moving the code to a service but I think that this code
can be completely independent of the Open Food Network use case. It
would be easy to move to a gem. The downcasing may need reconsidering
for general use.
2020-01-31 09:48:32 +11:00
Maikel Linke
6f8bb793e1 Add unit names commonly used in French 2020-01-31 09:48:32 +11:00
Maikel Linke
2476050f29 Remove usage count comments 2020-01-31 09:48:32 +11:00
Maikel Linke
1cce106977 Use our unit name pluralization in Ruby
This code will be used for the shop front and reports.
2020-01-31 09:48:32 +11:00
Maikel Linke
98b55287f1 Pluralize common variant unit names
This adds the most popular unit names as singular and plural to our
locale for translation. The added Javascript performs a reverse lookup
to find the right singular/plural form of a unit name in that language.
2020-01-31 09:48:32 +11:00
dependabot-preview[bot]
48a75c956f Bump oauth2 from 1.4.2 to 1.4.3
Bumps [oauth2](https://github.com/oauth-xx/oauth2) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/oauth-xx/oauth2/releases)
- [Changelog](https://github.com/oauth-xx/oauth2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/oauth-xx/oauth2/compare/v1.4.2...v1.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-29 19:24:24 +00:00
Maikel Linke
bec73adc89 Restore file logging for custom format logger
The new custom logger was directed to stdout instead of a file.
2020-01-08 15:06:19 +11:00
luisramos0
23ec66e338 Add timestamp to Rails logger in staging and prod so that info in logs can be accurately compared with data in the DB 2020-01-08 15:05:55 +11:00
79 changed files with 5403 additions and 757 deletions

View File

@@ -39,7 +39,6 @@ Layout/LineLength:
- app/controllers/admin/variant_overrides_controller.rb
- app/controllers/api/enterprise_attachment_controller.rb
- app/controllers/api/product_images_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/adjustments_controller_decorator.rb
- app/controllers/spree/admin/orders_controller_decorator.rb
- app/controllers/spree/credit_cards_controller.rb
@@ -354,7 +353,6 @@ Metrics/AbcSize:
- app/controllers/api/variants_controller.rb
- app/controllers/base_controller.rb
- app/controllers/cart_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/discourse_sso_controller.rb
- app/controllers/enterprises_controller.rb
- app/controllers/spree/admin/adjustments_controller_decorator.rb
@@ -371,7 +369,6 @@ Metrics/AbcSize:
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/admin/users_controller.rb
- app/controllers/spree/admin/variants_controller.rb
- app/controllers/spree/checkout_controller.rb
- app/controllers/spree/credit_cards_controller.rb
- app/controllers/spree/orders_controller.rb
- app/controllers/spree/user_passwords_controller.rb
@@ -493,7 +490,6 @@ Metrics/CyclomaticComplexity:
Exclude:
- app/controllers/admin/enterprise_fees_controller.rb
- app/controllers/admin/enterprises_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/orders_controller.rb
- app/helpers/checkout_helper.rb
@@ -523,7 +519,6 @@ Metrics/PerceivedComplexity:
Exclude:
- app/controllers/admin/enterprises_controller.rb
- app/controllers/api/variants_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/orders_controller.rb
- app/helpers/checkout_helper.rb
@@ -560,7 +555,6 @@ Metrics/MethodLength:
- app/controllers/api/variants_controller.rb
- app/controllers/base_controller.rb
- app/controllers/cart_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/shop_controller.rb
- app/controllers/spree/admin/image_settings_controller.rb
- app/controllers/spree/admin/orders/customer_details_controller.rb

33
Gemfile
View File

@@ -3,7 +3,7 @@ ruby "2.3.7"
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
gem 'i18n', '~> 0.6.11'
gem 'i18n-js', '~> 3.5.1'
gem 'i18n-js', '~> 3.6.0'
gem 'rails', '~> 3.2.22'
gem 'rails-i18n', '~> 3.0.0'
gem 'rails_safe_tasks', '~> 1.0'
@@ -19,9 +19,8 @@ gem 'activerecord-postgresql-adapter'
gem 'pg', '~> 0.21.0'
# OFN-maintained and patched version of Spree v2.0.4. See
# https://github.com/openfoodfoundation/openfoodnetwork/wiki/Spree-2.0-upgrade
# https://github.com/openfoodfoundation/openfoodnetwork/wiki/Tech-Doc:-OFN's-Spree-fork%F0%9F%8D%B4
# for details.
gem 'spree_backend', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
gem 'spree_core', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
@@ -39,7 +38,7 @@ gem 'activemerchant', '~> 1.78'
gem 'devise', '~> 2.2.5'
gem 'devise-encryptable', '0.2.0'
gem 'jwt', '~> 2.2'
gem 'oauth2', '~> 1.4.2' # Used for Stripe Connect
gem 'oauth2', '~> 1.4.4' # Used for Stripe Connect
gem 'daemons'
gem 'delayed_job_active_record'
@@ -62,7 +61,7 @@ gem 'haml'
gem 'rabl'
gem 'redcarpet'
gem 'sass', "~> 3.3"
gem 'sass-rails', '~> 3.2.3', groups: [:default, :assets]
gem 'sass-rails', '~> 3.2.3'
gem 'truncate_html'
gem 'unicorn'
@@ -93,33 +92,31 @@ gem 'wkhtmltopdf-binary'
gem 'foreigner'
gem 'immigrant'
gem 'roo', '~> 2.8.2'
gem 'roo', '~> 2.8.3'
gem 'whenever', require: false
gem 'test-unit', '~> 3.3'
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'coffee-rails', '~> 3.2.1'
gem 'compass-rails'
gem 'coffee-rails', '~> 3.2.1'
gem 'compass-rails'
gem 'mini_racer', '0.2.9'
gem 'mini_racer', '0.2.9'
gem 'uglifier', '>= 1.0.3'
gem 'uglifier', '>= 1.0.3'
gem 'angular-rails-templates', '~> 0.3.0'
gem 'foundation-icons-sass-rails'
gem 'momentjs-rails'
gem 'turbo-sprockets-rails3'
end
gem 'angular-rails-templates', '~> 0.3.0'
gem 'foundation-icons-sass-rails'
gem 'momentjs-rails'
gem 'turbo-sprockets-rails3'
gem "foundation-rails"
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
gem 'jquery-migrate-rails'
gem 'jquery-rails', '3.0.4'
gem 'jquery-ui-rails', '~> 4.0.0'
gem 'select2-rails', '~> 3.4.7'
gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz', ref: '60da2ae4c44cbb4c8d602f59fb5fff8d0f21db3c'

View File

@@ -34,18 +34,6 @@ GIT
revision: 8a8585a43cd04d1a50dc65227f337a91b18d66d5
branch: 2-0-4-stable
specs:
spree_api (2.0.4)
rabl (= 0.8.4)
spree_core (= 2.0.4)
versioncake (= 1.0.0)
spree_backend (2.0.4)
deface (>= 0.9.0)
jquery-rails (~> 3.0.0)
jquery-ui-rails (~> 4.0.0)
rails (~> 3.2.8)
select2-rails (~> 3.4.7)
spree_api (= 2.0.4)
spree_core (= 2.0.4)
spree_core (2.0.4)
activemerchant (~> 1.34)
acts_as_list (= 0.2.0)
@@ -261,7 +249,7 @@ GEM
factory_bot_rails (4.10.0)
factory_bot (~> 4.10.0)
railties (>= 3.0.0)
faraday (0.17.1)
faraday (1.0.0)
multipart-post (>= 1.2, < 3)
ffaker (1.22.1)
ffi (1.11.3)
@@ -437,7 +425,7 @@ GEM
httparty (0.16.2)
multi_xml (>= 0.5.2)
i18n (0.6.11)
i18n-js (3.5.1)
i18n-js (3.6.0)
i18n (>= 0.6.6)
immigrant (0.3.6)
activerecord (>= 3.0)
@@ -458,7 +446,7 @@ GEM
kaminari (0.14.1)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
kgio (2.11.2)
kgio (2.11.3)
knapsack (1.18.0)
rake
launchy (2.4.3)
@@ -486,7 +474,7 @@ GEM
newrelic_rpm (3.18.1.330)
nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
oauth2 (1.4.2)
oauth2 (1.4.4)
faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
@@ -559,7 +547,7 @@ GEM
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rainbow (3.0.0)
raindrops (0.19.0)
raindrops (0.19.1)
rake (13.0.0)
ransack (0.7.2)
actionpack (~> 3.0)
@@ -578,15 +566,16 @@ GEM
redcarpet (3.5.0)
request_store (1.4.1)
rack (>= 1.4)
rexml (3.2.4)
roadie (3.4.0)
css_parser (~> 1.4)
nokogiri (~> 1.5)
roadie-rails (1.3.0)
railties (>= 3.0, < 5.3)
roadie (~> 3.1)
roo (2.8.2)
roo (2.8.3)
nokogiri (~> 1)
rubyzip (>= 1.2.1, < 2.0.0)
rubyzip (>= 1.3.0, < 3.0.0)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
@@ -610,11 +599,12 @@ GEM
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-support (3.9.0)
rubocop (0.79.0)
rubocop (0.80.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
rexml
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-rails (2.4.2)
@@ -658,7 +648,7 @@ GEM
tilt (~> 1.1, != 1.3.0)
state_machine (1.2.0)
stringex (1.5.1)
stripe (5.11.0)
stripe (5.15.0)
test-unit (3.3.5)
power_assert
thor (0.20.3)
@@ -676,24 +666,20 @@ GEM
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.6.1)
unicorn (5.5.2)
unicorn (5.5.3)
kgio (~> 2.6)
raindrops (~> 0.7)
unicorn-rails (2.2.1)
rack
unicorn
uuidtools (2.1.5)
versioncake (1.0.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
warden (1.2.7)
rack (>= 1.0)
webdrivers (4.2.0)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (>= 3.0, < 4.0)
webmock (3.8.0)
webmock (3.8.2)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
@@ -753,10 +739,11 @@ DEPENDENCIES
gmaps4rails
haml
i18n (~> 0.6.11)
i18n-js (~> 3.5.1)
i18n-js (~> 3.6.0)
immigrant
jquery-migrate-rails
jquery-rails (= 3.0.4)
jquery-ui-rails (~> 4.0.0)
json_spec (~> 1.1.4)
jwt (~> 2.2)
kaminari (~> 0.14.1)
@@ -766,7 +753,7 @@ DEPENDENCIES
momentjs-rails
newrelic_rpm (~> 3.0)
nokogiri (>= 1.6.7.1)
oauth2 (~> 1.4.2)
oauth2 (~> 1.4.4)
ofn-qz!
oj
order_management!
@@ -783,19 +770,19 @@ DEPENDENCIES
rails_safe_tasks (~> 1.0)
redcarpet
roadie-rails (~> 1.3.0)
roo (~> 2.8.2)
roo (~> 2.8.3)
rspec-rails (>= 3.5.2)
rspec-retry
rubocop
rubocop-rails
sass (~> 3.3)
sass-rails (~> 3.2.3)
select2-rails (~> 3.4.7)
selenium-webdriver
shoulda-matchers
simple_form!
simplecov
spinjs-rails
spree_backend!
spree_core!
spree_i18n!
spree_paypal_express!

View File

@@ -16,6 +16,7 @@
//= require jquery.jstree/jquery.jstree
//= require jquery.vAlign
//= require jquery.horizontalNav
//= require jquery.adaptivemenu
//= require angular
//= require angular-resource
//= require angular-animate
@@ -28,11 +29,9 @@
// spree
//= require spree
//= require admin/spree-select2
//= require admin/spree_backend
//= require admin/spree/spree-select2
//= require modernizr
//= require spin
//= require jquery.adaptivemenu
//= require equalize
//= require css_browser_selector_dev
//= require responsive-tables

View File

@@ -1,4 +1,4 @@
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor) ->
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser) ->
$scope.StatusMessage = StatusMessage
$scope.columns = Columns.columns
@@ -38,6 +38,8 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.query = ""
$scope.DisplayProperties = DisplayProperties
$scope.sortOptions = SortOptions
$scope.initialise = ->
$scope.fetchProducts()
@@ -54,6 +56,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
'q[name_cont]': $scope.query,
'q[supplier_id_eq]': $scope.producerFilter,
'q[primary_taxon_id_eq]': $scope.categoryFilter,
'q[s]': $scope.sorting,
import_date: $scope.importDateFilter,
page: $scope.page,
per_page: $scope.per_page
@@ -103,9 +106,16 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.categoryFilter = "0"
$scope.importDateFilter = "0"
$scope.$watch 'sortOptions', (sort) ->
return unless sort && sort.predicate != ""
$scope.sorting = sort.getSortingExpr()
$scope.fetchProducts()
, true
confirm_unsaved_changes = () ->
(DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
editProductUrl = (product, variant) ->
"/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
@@ -220,10 +230,9 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
BulkProducts.updateVariantLists(data.products || [])
$timeout -> $scope.displaySuccess()
).error (data, status) ->
if status == 400 && data.errors? && data.errors.length > 0
errors = error + "\n" for error in data.errors
alert t("products_update_error") + "\n" + errors
$scope.displayFailure t("products_update_error")
if status == 400 && data.errors?
errorsString = ErrorsParser.toString(data.errors, status)
$scope.displayFailure t("products_update_error") + "\n" + errorsString
else
$scope.displayFailure t("products_update_error_data") + status
@@ -274,7 +283,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.displayFailure = (failMessage) ->
StatusMessage.display 'failure', t("products_update_error_msg") + "#{failMessage}"
StatusMessage.display 'failure', t("products_update_error_msg") + " #{failMessage}"
$scope.displayDirtyProducts = ->

View File

@@ -3,6 +3,11 @@ angular.module("admin.indexUtils").factory 'SortOptions', ->
predicate: ""
reverse: true
getSortingExpr: () ->
sortingExpr = this.predicate + ' desc' if this.reverse
sortingExpr = this.predicate + ' asc' if !this.reverse
sortingExpr
toggle: (predicate) ->
@reverse = (@predicate == predicate) && !@reverse
@predicate = predicate

View File

@@ -48,13 +48,15 @@ angular.module('admin.orderCycles')
return if enterprise.last_page_loaded? && enterprise.last_page_loaded >= page
enterprise.last_page_loaded = page
enterprise.loaded_variants ?= 0
incoming = true if $scope.view == 'incoming'
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: incoming, page: page}
ExchangeProduct.index params, (products, num_of_pages, num_of_products) ->
ExchangeProduct.index params, (products, num_of_pages) ->
enterprise.num_of_pages = num_of_pages
enterprise.num_of_products = num_of_products
enterprise.supplied_products.push products...
angular.forEach products, (product) ->
enterprise.loaded_variants += product.variants.length
$scope.loadMoreExchangeProducts = (exchange) ->
$scope.loadExchangeProducts(exchange, $scope.enterprises[exchange.enterprise_id].last_page_loaded + 1)

View File

@@ -64,10 +64,10 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, $timeout, Reque
$scope.selected_orders.push order.id if $scope.select_all
$scope.$watch 'sortOptions', (sort) ->
if sort && sort.predicate != ""
$scope.sorting = sort.predicate + ' desc' if sort.reverse
$scope.sorting = sort.predicate + ' asc' if !sort.reverse
$scope.fetchResults()
return unless sort && sort.predicate != ""
$scope.sorting = sort.getSortingExpr()
$scope.fetchProducts()
, true
$scope.capturePayment = (order) ->

View File

@@ -3,6 +3,9 @@ angular.module("admin.orders").directive 'customerSearchOverride', ->
scope:
distributorId: '@'
link: (scope, element, attr) ->
if $('#customer_autocomplete_template').length > 0
customerTemplate = Handlebars.compile($('#customer_autocomplete_template').text())
formatCustomerResult = (customer) ->
customerTemplate
customer: customer

View File

@@ -21,9 +21,7 @@ angular.module("admin.products").factory "OptionValueNamer", (VariantUnitManager
else
value = @variant.unit_value
unit_name = @variant.product.variant_unit_name
# TODO needs to add pluralize to line below
# unit_name = unit_name if value > 1
unit_name = @pluralize(@variant.product.variant_unit_name, value)
value = parseInt(value, 10) if value == parseInt(value, 10)
@@ -32,6 +30,21 @@ angular.module("admin.products").factory "OptionValueNamer", (VariantUnitManager
[value, unit_name]
pluralize: (unit_name, count) ->
return unit_name if count == undefined
unit_key = @unit_key(unit_name)
return unit_name unless unit_key
I18n.t(["inflections", unit_key], {count: count, defaultValue: unit_name})
unit_key: (unit_name) ->
unless I18n.unit_keys
I18n.unit_keys = {}
for key, translations of I18n.t("inflections")
for quantifier, translation of translations
I18n.unit_keys[translation.toLowerCase()] = key
I18n.unit_keys[unit_name.toLowerCase()]
option_value_value_unit_scaled: ->
[unit_scale, unit_name] = @scale_for_unit_value()

View File

@@ -1,6 +1,6 @@
//= require_self
//= require admin/handlebar_extensions
//= require admin/variant_autocomplete
//= require admin/spree/orders/variant_autocomplete
/**
This is a collection of javascript functions and whatnot
@@ -21,12 +21,14 @@ jQuery(function($) {
if (typeof $('.field.checkbox label').vAlign === 'function' )
$('.field.checkbox label').vAlign()
// if (typeof Spree !== 'undefined') {
// $('.main-menu-wrapper ul').AdaptiveMenu({
// text: "<a href='#'><i class='icon-chevron-down'></i> " + Spree.translations.more + "</a>",
// klass: "dropdown"
// });
// }
// We activate AdaptiveMenu only if not on webdriver
// Re-adjusting the admin menu during tests causes tests to fail.
if (!navigator.webdriver && typeof Spree !== 'undefined') {
$('.main-menu-wrapper ul').AdaptiveMenu({
text: "<a href='#'><i class='icon-chevron-down'></i> " + Spree.translations.more + "</a>",
klass: "dropdown"
});
}
// Add some tips
if (typeof $('.with-tip').powerTip === 'function' ) {
@@ -174,6 +176,28 @@ $(document).ready(function() {
$(target).prepend(new_table_row);
})
$('body').on('click', '.delete-resource', function() {
var el = $(this);
if (confirm(el.data("confirm"))) {
$.ajax({
type: 'POST',
url: $(this).attr("href"),
data: {
_method: 'delete',
authenticity_token: AUTH_TOKEN
},
dataType: 'html',
success: function(response) {
el.parents("tr").fadeOut('hide');
},
error: function(response, textStatus, errorThrown) {
show_flash_error(response.responseText);
}
});
}
return false;
});
// Fix sortable helper
var fixHelper = function(e, ui) {
ui.children().each(function() {

View File

@@ -0,0 +1,16 @@
$(function() {
var calculator_select = $('select#calc_type')
var original_calc_type = calculator_select.attr('value');
$('.calculator-settings-warning').hide();
calculator_select.change(function() {
if (calculator_select.attr('value') == original_calc_type) {
$('div.calculator-settings').show();
$('.calculator-settings-warning').hide();
$('.calculator-settings').find('input,textarea').prop("disabled", false);
} else {
$('div.calculator-settings').hide();
$('.calculator-settings-warning').show();
$('.calculator-settings').find('input,texttarea').prop("disabled", true);
}
});
})

View File

@@ -0,0 +1,59 @@
$(document).ready(function() {
if ($('input#preferences_use_s3[type="checkbox"]:checked').length > 0) {
$('#s3_settings, #s3_headers').show();
}
// Toggle display of S3 settings based on value of use_s3 checkbox
$('input#preferences_use_s3[type="checkbox"]').click(function() {
$('#s3_settings, #s3_headers').toggle();
});
$(document).on('click', '.destroy_style', function(e) {
e.preventDefault();
$(this).parent().remove();
});
$(document).on('click', '.destroy_new_attachment_styles', function(e) {
e.preventDefault();
$(this).closest('.new_attachment_styles').remove();
});
$(document).on('click', '.destroy_new_s3_headers', function(e) {
e.preventDefault();
$(this).closest('.new_s3_headers').remove();
});
// Handle adding new styles
var styles_hash_index = 1;
$(document).on('click', '.add_new_style', function(e) {
e.preventDefault();
$('#new-styles').append(generate_html_for_hash("new_attachment_styles", styles_hash_index));
});
// Handle adding new headers
var headers_hash_index = 1;
$(document).on('click', '.add_header', function(e) {
e.preventDefault();
$('#headers_list').append(generate_html_for_hash("new_s3_headers", headers_hash_index));
});
// Generates html for new paperclip styles form fields
generate_html_for_hash = function(hash_name, index) {
var html = '<div class="' + hash_name + ' row"><div class="field">';
html += '<div class="five columns">';
html += '<label for="' + hash_name + '_' + index + '_name">';
html += Spree.translations.name + '</label>';
html += '<input id="' + hash_name + '_' + index + '_name" name="' + hash_name + '[' + index + '][name]" type="text" class="fullwidth"><br>';
html += '</div><div class="five columns">'
html += '<label for="' + hash_name + '_' + index + '_value">';
html += Spree.translations.value + '</label>';
html += '<input id="' + hash_name + '_' + index + '_value" name="' + hash_name + '[' + index + '][value]" type="text" class="fullwidth">';
html += '</div><div class="two columns">'
html += '<a href="#" title="' + Spree.translations.destroy + '" class="destroy_' + hash_name + ' with-tip button" style="margin-top: 19px;"><i class="icon-trash"></i> &nbsp; ' + Spree.translations.destroy + '</a>';
html += '</div></div></div>';
index += 1;
return html;
};
});

View File

@@ -0,0 +1,23 @@
//On page load
replace_ids = function(s){
var new_id = new Date().getTime();
return s.replace(/NEW_RECORD/g, new_id);
}
$(function() {
$('a[id*=nested]').click(function() {
var template = $(this).attr('href').replace(/.*#/, '');
html = replace_ids(eval(template));
$('#ul-' + $(this).attr('id')).append(html);
update_remove_links();
});
update_remove_links();
})
var update_remove_links = function() {
$('.remove').click(function() {
$(this).prevAll(':first').val(1);
$(this).parent().hide();
return false;
});
};

View File

@@ -15,11 +15,11 @@ $(document).ready(function() {
console.log(msg);
});
}
// $('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click);
$('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click);
//handle shipping method edit click
// $('a.edit-method').click(toggleMethodEdit);
// $('a.cancel-method').click(toggleMethodEdit);
$('a.edit-method').click(toggleMethodEdit);
$('a.cancel-method').click(toggleMethodEdit);
handle_shipping_method_save = function(){
var link = $(this);
@@ -38,11 +38,11 @@ $(document).ready(function() {
console.log(msg);
});
}
// $('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save);
$('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save);
//handle tracking edit click
// $('a.edit-tracking').click(toggleTrackingEdit);
// $('a.cancel-tracking').click(toggleTrackingEdit);
$('a.edit-tracking').click(toggleTrackingEdit);
$('a.cancel-tracking').click(toggleTrackingEdit);
handle_tracking_save = function(){
var link = $(this);

View File

@@ -29,10 +29,10 @@ $(document).ready(function() {
});
//handle edit click
// $('a.edit-item').click(toggleItemEdit);
$('a.edit-item').click(toggleItemEdit);
//handle cancel click
// $('a.cancel-item').click(toggleItemEdit);
$('a.cancel-item').click(toggleItemEdit);
handle_save_click = function(){
var save = $(this);
@@ -46,7 +46,7 @@ $(document).ready(function() {
adjustItems(shipment_number, variant_id, quantity);
return false;
}
// $('a.save-item').click(handle_save_click);
$('a.save-item').click(handle_save_click);
handle_delete_click = function(){
var del = $(this);
@@ -57,7 +57,7 @@ $(document).ready(function() {
adjustItems(shipment_number, variant_id, 0);
}
// $('a.delete-item').click(handle_delete_click);
$('a.delete-item').click(handle_delete_click);
}
});
@@ -139,39 +139,3 @@ addVariantFromStockLocation = function() {
}
return 1
}
formatVariantResult = function(variant) {
if (variant["images"][0] != undefined && variant["images"][0].urls != undefined) {
variant.image = variant.images[0].urls.mini
}
return variantTemplate({ variant: variant })
}
$.fn.variantAutocomplete = function() {
this.parent().children(".options_placeholder").attr('id', this.parent().data('index'))
this.select2({
placeholder: Spree.translations.variant_placeholder,
minimumInputLength: 3,
ajax: {
url: Spree.url(Spree.routes.variants_search),
datatype: 'json',
data: function(term, page) {
return {
q: {
"product_name_or_sku_cont": term
}
}
},
results: function (data, page) {
window.variants = data['variants'];
return { results: data['variants'] }
}
},
formatResult: formatVariantResult,
formatSelection: function (variant) {
$(this.element).parent().children('.options_placeholder').html(variant.options_text)
return variant.name;
}
})
}

View File

@@ -0,0 +1,8 @@
$(document).ready(function() {
$("#country").change(function() {
var new_state_link_href = $('#new_state_link a').attr('href');
var selected_country_id = $('#country option:selected').attr('value');
var new_link = new_state_link_href.replace(/countries\/(\d+)/, 'countries/'+selected_country_id);
$('#new_state_link a').attr('href', new_link);
});
});

View File

@@ -0,0 +1,43 @@
$ ->
($ '#country_based').click ->
show_country()
($ '#state_based').click ->
show_state()
if ($ '#country_based').is(':checked')
show_country()
else if ($ '#state_based').is(':checked')
show_state()
else
show_state()
($ '#state_based').click()
show_country = ->
($ '#state_members :input').each ->
($ this).prop 'disabled', true
($ '#state_members').hide()
($ '#zone_members :input').each ->
($ this).prop 'disabled', true
($ '#zone_members').hide()
($ '#country_members :input').each ->
($ this).prop 'disabled', false
($ '#country_members').show()
show_state = ->
($ '#country_members :input').each ->
($ this).prop 'disabled', true
($ '#country_members').hide()
($ '#zone_members :input').each ->
($ this).prop 'disabled', true
($ '#zone_members').hide()
($ '#state_members :input').each ->
($ this).prop 'disabled', false
($ '#state_members').show()

View File

@@ -1,10 +1,6 @@
angular.module("admin.utils").directive "variantAutocomplete", ($timeout) ->
restrict: 'C'
link: (scope, element, attrs) ->
# Make variantAutocomplete do nothing because it is called
# from core/app/assets/javascripts/admin/orders/edit.js
$.fn.variantAutocomplete = angular.noop
$timeout ->
if $("#variant_autocomplete_template").length > 0
variantTemplate = Handlebars.compile($("#variant_autocomplete_template").text())

View File

@@ -0,0 +1,21 @@
# Parses a structure of errors that came from the server
angular.module("admin.utils").factory "ErrorsParser", ->
new class ErrorsParser
toString: (errors, defaultContent = "") =>
return defaultContent unless errors?
errorsString = ""
if errors.length > 0
# it is an array of errors
errorsString = errors.join("\n") + "\n"
else
# it is a hash of errors
keys = Object.keys(errors)
for key in keys
errorsString += errors[key].join("\n") + "\n"
this.defaultIfEmpty(errorsString, defaultContent)
defaultIfEmpty: (content, defaultContent) =>
return defaultContent if content == ""
content

View File

@@ -9,7 +9,7 @@
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'setExchangeVariants(exchange, incomingExchangeVariantsFor(exchange.enterprise_id), exchange.select_all_variants)',
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' }
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
{{ 'js.admin.panels.exchange_products.select_all_variants' | t:{ total_number_of_variants: exchangeTotalVariants(exchange) } }}
.exchange-products{ 'ng-hide' => 'productsLoading()' }
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products | filter:visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges' }

View File

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

View File

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

View File

@@ -9,7 +9,7 @@
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'selectAllVariants(exchange, exchange.select_all_variants)',
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
{{ 'js.admin.panels.exchange_products.select_all_variants' | t:{ total_number_of_variants: exchangeTotalVariants(exchange) } }}
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }

View File

@@ -4,15 +4,15 @@
* the top of the compiled file, but it's generally better to create a new file per style scope.
*
*= require admin/spree_backend
*= require jquery.powertip
*= require responsive-tables
*= require normalize
*= require skeleton
*= require responsive-tables
*= require jquery.powertip
*= require jquery.ui.datepicker
*= require jquery-ui-timepicker-addon
*= require shared/textAngular
*= require shared/ng-tags-input.min
*= require select2
*= require_self
*/
@@ -33,6 +33,11 @@
@import 'plugins/powertip';
@import 'plugins/jstree';
@import 'plugins/font-awesome';
@import 'plugins/select2';
@import 'sections/image_settings';
@import 'sections/orders';
@import 'sections/products';
@import 'hacks/mozilla';
@import 'hacks/opera';

View File

@@ -0,0 +1,3 @@
.destroy_style, .destroy_header {
float: right;
}

View File

@@ -48,16 +48,22 @@ module Api
end
def bulk_products
product_query = OpenFoodNetwork::Permissions.new(current_api_user).
editable_products.merge(product_scope)
product_query = OpenFoodNetwork::Permissions.
new(current_api_user).
editable_products.
merge(product_scope)
if params[:import_date].present?
product_query = product_query.imported_on(params[:import_date]).group_by_products_id
product_query = product_query.
imported_on(params[:import_date]).
group_by_products_id
end
@products = product_query.order('created_at DESC').
ransack(params[:q]).result.
page(params[:page] || DEFAULT_PAGE).per(params[:per_page] || DEFAULT_PER_PAGE)
@products = product_query.
ransack(query_params_with_defaults).
result.
page(params[:page] || DEFAULT_PAGE).
per(params[:per_page] || DEFAULT_PER_PAGE)
render_paged_products @products
end
@@ -136,6 +142,10 @@ module Api
}.to_json
end
def query_params_with_defaults
params[:q].to_h.reverse_merge(s: 'created_at desc')
end
def pagination_data(results)
{
results: results.total_count,

View File

@@ -1,8 +1,16 @@
# frozen_string_literal: true
require 'open_food_network/address_finder'
class CheckoutController < Spree::CheckoutController
class CheckoutController < Spree::StoreController
layout 'darkswarm'
include CheckoutHelper
include OrderCyclesHelper
include EnterprisesHelper
ssl_required
# We need pessimistic locking to avoid race conditions.
# Otherwise we fail on duplicate indexes or end up with negative stock.
prepend_around_filter CurrentOrderLocker, only: :update
@@ -12,10 +20,19 @@ class CheckoutController < Spree::CheckoutController
prepend_before_filter :require_order_cycle
prepend_before_filter :require_distributor_chosen
before_filter :load_order
before_filter :ensure_order_not_completed
before_filter :ensure_checkout_allowed
before_filter :ensure_sufficient_stock_lines
before_filter :associate_user
before_filter :check_authorization
before_filter :enable_embedded_shopfront
include OrderCyclesHelper
include EnterprisesHelper
helper 'spree/orders'
rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error
def edit
# This is only required because of spree_paypal_express. If we implement
@@ -25,54 +42,16 @@ class CheckoutController < Spree::CheckoutController
end
def update
shipping_method_id = object_params.delete(:shipping_method_id)
params_adapter = Checkout::FormDataAdapter.new(params, @order, spree_current_user)
return update_failed unless @order.update_attributes(params_adapter.order_params)
return update_failed unless @order.update_attributes(object_params)
check_order_for_phantom_fees
fire_event('spree.checkout.update')
while @order.state != "complete"
if @order.state == "payment"
return if redirect_to_paypal_express_form_if_needed
end
if @order.state == "delivery"
@order.select_shipping_method(shipping_method_id)
end
next if advance_order_state(@order)
flash[:error] = if @order.errors.present?
@order.errors.full_messages.to_sentence
else
t(:payment_processing_failed)
end
update_failed
return
end
return update_failed unless @order.state == "complete" || @order.completed?
set_default_bill_address
set_default_ship_address
ResetOrderService.new(self, current_order).call
session[:access_token] = current_order.token
flash[:notice] = t(:order_processed_successfully)
respond_to do |format|
format.html do
respond_with(@order, location: order_path(@order))
end
format.json do
render json: { path: order_path(@order) }, status: :ok
end
end
rescue Spree::Core::GatewayError => error
# This is done for all actions in the Spree::CheckoutController.
rescue_from_spree_gateway_error(error)
rescue StandardError => error
Bugsnag.notify(error)
checkout_workflow(params_adapter.shipping_method_id)
rescue Spree::Core::GatewayError => e
rescue_from_spree_gateway_error(e)
rescue StandardError => e
Bugsnag.notify(e)
flash[:error] = I18n.t("checkout.failed")
update_failed
end
@@ -87,111 +66,38 @@ class CheckoutController < Spree::CheckoutController
private
def set_default_bill_address
if params[:order][:default_bill_address]
new_bill_address = @order.bill_address.clone.attributes
user_bill_address_id = spree_current_user.bill_address.andand.id
spree_current_user.update_attributes(
bill_address_attributes: new_bill_address.merge('id' => user_bill_address_id)
)
customer_bill_address_id = @order.customer.bill_address.andand.id
@order.customer.update_attributes(
bill_address_attributes: new_bill_address.merge('id' => customer_bill_address_id)
)
end
def check_authorization
authorize!(:edit, current_order, session[:access_token])
end
def set_default_ship_address
if params[:order][:default_ship_address]
new_ship_address = @order.ship_address.clone.attributes
user_ship_address_id = spree_current_user.ship_address.andand.id
spree_current_user.update_attributes(
ship_address_attributes: new_ship_address.merge('id' => user_ship_address_id)
)
customer_ship_address_id = @order.customer.ship_address.andand.id
@order.customer.update_attributes(
ship_address_attributes: new_ship_address.merge('id' => customer_ship_address_id)
)
end
def ensure_checkout_allowed
redirect_to main_app.cart_path unless @order.checkout_allowed?
end
def check_order_for_phantom_fees
phantom_fees = @order.adjustments.
joins("LEFT OUTER JOIN spree_line_items"\
" ON spree_line_items.id = spree_adjustments.source_id").
where("originator_type = 'EnterpriseFee'"\
" AND source_type = 'Spree::LineItem' AND spree_line_items.id IS NULL")
if phantom_fees.any?
Bugsnag.notify(RuntimeError.new("Phantom Fees"),
phantom_fees: {
phantom_total: phantom_fees.sum(&:amount).to_s,
phantom_fees: phantom_fees.as_json
})
end
def ensure_order_not_completed
redirect_to main_app.cart_path if @order.completed?
end
# Copied and modified from spree. Remove check for order state, since the state machine is
# progressed all the way in one go with the one page checkout.
def object_params
# For payment step, filter order parameters to produce the expected
# nested attributes for a single payment and its source,
# discarding attributes for payment methods other than the one selected
if params[:payment_source].present? && source_params = params.delete(:payment_source)[params[:order][:payments_attributes].first[:payment_method_id].underscore]
params[:order][:payments_attributes].first[:source_attributes] = source_params
end
if params[:order][:payments_attributes]
params[:order][:payments_attributes].first[:amount] = @order.total
end
if params[:order][:existing_card_id]
construct_saved_card_attributes
end
params[:order]
end
# Perform order.next, guarding against StaleObjectErrors
def advance_order_state(order)
tries ||= 3
order.next
rescue ActiveRecord::StaleObjectError
retry unless (tries -= 1).zero?
false
end
def update_failed
current_order.updater.shipping_address_from_distributor
RestartCheckout.new(@order).call
respond_to do |format|
format.html do
render :edit
end
format.json do
render json: { errors: @order.errors, flash: flash.to_hash }.to_json, status: :bad_request
end
def ensure_sufficient_stock_lines
if @order.insufficient_stock_lines.present?
flash[:error] = Spree.t(:inventory_error_flash_for_insufficient_quantity)
redirect_to main_app.cart_path
end
end
def load_order
@order = current_order
redirect_to(main_app.shop_path) && return unless @order && @order.checkout_allowed?
redirect_to(main_app.shop_path) && return if redirect_to_shop?
redirect_to_cart_path && return unless valid_order_line_items?
redirect_to(main_app.shop_path) && return if @order.completed?
before_address
setup_for_current_state
end
def before_address
associate_user
finder = OpenFoodNetwork::AddressFinder.new(@order.email, @order.customer, spree_current_user)
@order.bill_address = finder.bill_address
@order.ship_address = finder.ship_address
def redirect_to_shop?
!@order ||
!@order.checkout_allowed? ||
@order.completed?
end
def valid_order_line_items?
@@ -212,32 +118,29 @@ class CheckoutController < Spree::CheckoutController
end
end
def redirect_to_paypal_express_form_if_needed
return unless params[:order][:payments_attributes]
payment_method_id = params[:order][:payments_attributes].first[:payment_method_id]
payment_method = Spree::PaymentMethod.find(payment_method_id)
return unless payment_method.is_a?(Spree::Gateway::PayPalExpress)
render json: { path: spree.paypal_express_path(payment_method_id: payment_method.id) },
status: :ok
true
def setup_for_current_state
method_name = :"before_#{@order.state}"
__send__(method_name) if respond_to?(method_name, true)
end
def construct_saved_card_attributes
existing_card_id = params[:order].delete(:existing_card_id)
return if existing_card_id.blank?
def before_address
associate_user
credit_card = Spree::CreditCard.find(existing_card_id)
if credit_card.try(:user_id).blank? || credit_card.user_id != spree_current_user.try(:id)
raise Spree::Core::GatewayError, I18n.t(:invalid_credit_card)
end
finder = OpenFoodNetwork::AddressFinder.new(@order.email, @order.customer, spree_current_user)
# Not currently supported but maybe we should add it...?
credit_card.verification_value = params[:cvc_confirm] if params[:cvc_confirm].present?
@order.bill_address = finder.bill_address
@order.ship_address = finder.ship_address
end
params[:order][:payments_attributes].first[:source] = credit_card
params[:order][:payments_attributes].first.delete :source_attributes
def before_delivery
return if params[:order].present?
packages = @order.shipments.map(&:to_package)
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
end
def before_payment
current_order.payments.destroy_all if request.put?
end
def rescue_from_spree_gateway_error(error)
@@ -247,4 +150,91 @@ class CheckoutController < Spree::CheckoutController
format.json { render json: { flash: flash.to_hash }, status: :bad_request }
end
end
def checkout_workflow(shipping_method_id)
while @order.state != "complete"
if @order.state == "payment"
return if redirect_to_payment_gateway
end
@order.select_shipping_method(shipping_method_id) if @order.state == "delivery"
next if advance_order_state(@order)
flash[:error] = order_workflow_error
return update_failed
end
update_result
end
def redirect_to_payment_gateway
redirect_path = Checkout::PaymentRedirect.new(params).path
return if redirect_path.blank?
render json: { path: redirect_path }, status: :ok
true
end
# Perform order.next, guarding against StaleObjectErrors
def advance_order_state(order)
tries ||= 3
order.next
rescue ActiveRecord::StaleObjectError
retry unless (tries -= 1).zero?
false
end
def order_workflow_error
if @order.errors.present?
@order.errors.full_messages.to_sentence
else
t(:payment_processing_failed)
end
end
def update_result
if @order.state == "complete" || @order.completed?
save_order_addresses_as_user_default
ResetOrderService.new(self, current_order).call
update_succeeded
else
update_failed
end
end
def save_order_addresses_as_user_default
user_default_address_setter = UserDefaultAddressSetter.new(@order, spree_current_user)
user_default_address_setter.set_default_bill_address if params[:order][:default_bill_address]
user_default_address_setter.set_default_ship_address if params[:order][:default_ship_address]
end
def update_succeeded
session[:access_token] = current_order.token
flash[:notice] = t(:order_processed_successfully)
respond_to do |format|
format.html do
respond_with(@order, location: order_path(@order))
end
format.json do
render json: { path: order_path(@order) }, status: :ok
end
end
end
def update_failed
current_order.updater.shipping_address_from_distributor
RestartCheckout.new(@order).call
respond_to do |format|
format.html do
render :edit
end
format.json do
render json: { errors: @order.errors, flash: flash.to_hash }.to_json, status: :bad_request
end
end
end
end

View File

@@ -70,10 +70,6 @@ module Spree
Spree.t(event_sym, resource: resource_desc)
end
def render_js_for_destroy
render partial: '/spree/admin/shared/destroy'
end
# Index request for JSON needs to pass a CSRF token in order to prevent JSON Hijacking
def check_json_authenticity
return unless request.format.js? || request.format.json?
@@ -86,10 +82,6 @@ module Spree
raise(ActionController::InvalidAuthenticityToken)
end
def config_locale
Spree::Backend::Config[:locale]
end
private
def html_request?

View File

@@ -1,93 +1,16 @@
require 'open_food_network/address_finder'
# frozen_string_literal: true
# This controller (and respective route in the Spree engine)
# is only needed for the spree_paypal_express gem that redirects here explicitly.
#
# According to the rails docs it would be possible to redirect
# to CheckoutController directly in the routes
# with a slash like "to: '/checkout#edit'", but it does not work in this case.
module Spree
class CheckoutController < Spree::StoreController
include CheckoutHelper
ssl_required
before_filter :load_order
before_filter :ensure_order_not_completed
before_filter :ensure_checkout_allowed
before_filter :ensure_sufficient_stock_lines
before_filter :associate_user
before_filter :check_authorization
before_filter :enable_embedded_shopfront
helper 'spree/orders'
rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error
def edit
flash.keep
redirect_to main_app.checkout_path
end
private
def load_order
@order = current_order
redirect_to(main_app.cart_path) && return unless @order
if params[:state]
redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state])
@order.state = params[:state]
end
setup_for_current_state
end
def ensure_checkout_allowed
redirect_to main_app.cart_path unless @order.checkout_allowed?
end
def ensure_order_not_completed
redirect_to main_app.cart_path if @order.completed?
end
def ensure_sufficient_stock_lines
if @order.insufficient_stock_lines.present?
flash[:error] = Spree.t(:inventory_error_flash_for_insufficient_quantity)
redirect_to main_app.cart_path
end
end
def setup_for_current_state
method_name = :"before_#{@order.state}"
send(method_name) if respond_to?(method_name, true)
end
# Adapted from spree_last_address gem: https://github.com/TylerRick/spree_last_address
# Originally, we used a forked version of this gem, but encountered strange errors where
# it worked in dev but only intermittently in staging/prod.
def before_address
associate_user
finder = OpenFoodNetwork::AddressFinder.new(@order.email)
@order.bill_address = finder.bill_address
@order.ship_address = finder.ship_address
end
def before_delivery
return if params[:order].present?
packages = @order.shipments.map(&:to_package)
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
end
def before_payment
current_order.payments.destroy_all if request.put?
end
def rescue_from_spree_gateway_error
flash[:error] = Spree.t(:spree_gateway_error_flash_for_checkout)
render :edit
end
def check_authorization
authorize!(:edit, current_order, session[:access_token])
end
end
end

View File

@@ -1,3 +1,5 @@
# frozen_string_literal: false
module Spree
module Admin
module NavigationHelper
@@ -34,7 +36,9 @@ module Spree
end
selected = if options[:match_path]
request.fullpath.starts_with?("#{spree.root_path}admin#{options[:match_path]}")
request.
fullpath.
starts_with?("#{main_app.root_path}admin#{options[:match_path]}")
else
args.include?(controller.controller_name.to_sym)
end

View File

@@ -0,0 +1,68 @@
# frozen_string_literal: true
# Adapts checkout form data (params) so that the order can be directly saved to the database
module Checkout
class FormDataAdapter
attr_reader :shipping_method_id
def initialize(params, order, current_user)
@params = params.dup
@order = order
@current_user = current_user
move_payment_source_to_payment_attributes!
set_amount_in_payments_attributes
construct_saved_card_attributes if @params[:order][:existing_card_id]
@shipping_method_id = @params[:order].delete(:shipping_method_id)
end
def order_params
@params[:order]
end
private
# For payment step, filter order parameters to produce the expected
# nested attributes for a single payment and its source,
# discarding attributes for payment methods other than the one selected
def move_payment_source_to_payment_attributes!
return unless @params[:payment_source].present? &&
payment_source_params = delete_payment_source_params!
@params[:order][:payments_attributes].first[:source_attributes] = payment_source_params
end
def delete_payment_source_params!
@params.delete(:payment_source)[
@params[:order][:payments_attributes].first[:payment_method_id].underscore
]
end
def set_amount_in_payments_attributes
return unless @params[:order][:payments_attributes]
@params[:order][:payments_attributes].first[:amount] = @order.total
end
def construct_saved_card_attributes
existing_card_id = @params[:order].delete(:existing_card_id)
return if existing_card_id.blank?
add_to_payment_attributes(existing_card_id)
@params[:order][:payments_attributes].first.delete :source_attributes
end
def add_to_payment_attributes(existing_card_id)
credit_card = Spree::CreditCard.find(existing_card_id)
if credit_card.try(:user_id).blank? || credit_card.user_id != @current_user.try(:id)
raise Spree::Core::GatewayError, I18n.t(:invalid_credit_card)
end
@params[:order][:payments_attributes].first[:source] = credit_card
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
# Provides the redirect path if a redirect to the payment gateway is needed
module Checkout
class PaymentRedirect
def initialize(params)
@params = params
end
# Returns the path to the Paypal Express form if a redirect is needed
def path
return unless @params[:order][:payments_attributes]
payment_method_id = @params[:order][:payments_attributes].first[:payment_method_id]
payment_method = Spree::PaymentMethod.find(payment_method_id)
return unless payment_method.is_a?(Spree::Gateway::PayPalExpress)
spree_routes_helper.paypal_express_path(payment_method_id: payment_method.id)
end
private
def spree_routes_helper
Spree::Core::Engine.routes_url_helpers
end
end
end

View File

@@ -1,3 +1,5 @@
require 'open_food_network/permissions'
module Permissions
class Order
def initialize(user)

View File

@@ -0,0 +1,39 @@
# frozen_string_literal: true
# Sets the order addresses as the user default addresses
class UserDefaultAddressSetter
def initialize(order, current_user)
@order = order
@current_user = current_user
end
# Sets the order bill address as the user default bill address
def set_default_bill_address
new_bill_address = @order.bill_address.clone.attributes
set_bill_address_attributes(@current_user, new_bill_address)
set_bill_address_attributes(@order.customer, new_bill_address)
end
# Sets the order ship address as the user default ship address
def set_default_ship_address
new_ship_address = @order.ship_address.clone.attributes
set_ship_address_attributes(@current_user, new_ship_address)
set_ship_address_attributes(@order.customer, new_ship_address)
end
private
def set_bill_address_attributes(object, new_address)
object.update_attributes(
bill_address_attributes: new_address.merge('id' => object.bill_address.andand.id)
)
end
def set_ship_address_attributes(object, new_address)
object.update_attributes(
ship_address_attributes: new_address.merge('id' => object.ship_address.andand.id)
)
end
end

View File

@@ -31,10 +31,10 @@
- if type == 'supplier'
%tr.panel-row{ object: "exchange",
panels: "{products: 'exchange_products_supplied'}",
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,selectAllVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
locals: "$index,exchangeTotalVariants,order_cycle,exchange,enterprises,setExchangeVariants,selectAllVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
colspan: 4 }
- if type == 'distributor'
%tr.panel-row{ object: "exchange",
panels: "{products: 'exchange_products_distributed', tags: 'exchange_tags'}",
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
locals: "$index,exchangeTotalVariants,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
colspan: 5 }

View File

@@ -33,8 +33,8 @@
= t('.variants')
%td.actions
%a.edit-order-cycle.icon-edit.no-text{ ng: { href: '{{orderCycle.edit_path}}'} }
%a.edit-order-cycle.icon-edit.no-text{ ng: { href: '{{orderCycle.edit_path}}'}, 'ofn-with-tip' => t(:edit) }
%td.actions{ ng: { if: 'orderCycle.viewing_as_coordinator' } }
%a.clone-order-cycle.icon-copy.no-text{ ng: { href: '{{orderCycle.clone_path}}'} }
%td.actions{ ng: { if: 'orderCycle.deletable && orderCycle.viewing_as_coordinator' } }
%a.delete-order-cycle.icon-trash.no-text{ ng: { href: '{{orderCycle.delete_path}}'}, data: { method: 'delete', confirm: t(:are_you_sure) } }
%a.clone-order-cycle.icon-copy.no-text{ ng: { href: '{{orderCycle.clone_path}}'}, 'ofn-with-tip' => t(:clone) }
%td.actions{ ng: { if: 'orderCycle.deletable && orderCycle.viewing_as_coordinator' }}
%a.delete-order-cycle.icon-trash.no-text{ ng: { href: '{{orderCycle.delete_path}}'}, data: { method: 'delete', confirm: t(:are_you_sure) }, 'ofn-with-tip' => t(:remove) }

View File

@@ -7,4 +7,4 @@
%span.or= t('spree.or')
= link_to_with_icon 'icon-remove', t('spree.actions.cancel'), admin_product_images_url(@product), id: 'cancel_link', class: 'button'
= javascript_include_tag 'admin/images/new.js'
= javascript_include_tag 'admin/spree/images/new.js'

View File

@@ -1,5 +1,5 @@
%div{"data-hook" => "admin_orders_index_search"}
= form_tag false, {name: "orders_form", "ng-submit" => "fetchResults()"} do
= form_tag nil, {name: "orders_form", "ng-submit" => "fetchResults()"} do
.field-block.alpha.four.columns
.date-range-filter.field
= label_tag nil, t(:date_range)

View File

@@ -0,0 +1,19 @@
<script type='text/template' id='customer_autocomplete_template'>
<div class='customer-autocomplete-item'>
<div class='customer-details'>
<h5>{{customer.email}}</h5>
{{#if bill_address.firstname }}
<strong>{{t 'bill_address' }}</strong>
{{bill_address.firstname}} {{bill_address.lastname}}<br>
{{bill_address.address1}}, {{bill_address.address2}}<br>
{{bill_address.city}}<br>
{{#if bill_address.state_id }}
{{bill_address.state.name}}
{{else}}
{{bill_address.state_name}}
{{/if}}
{{bill_address.country.name}}
{{/if}}
</div>
</div>
</script>

View File

@@ -43,7 +43,7 @@
- ['number', 'state', 'payment_state', 'shipment_state', 'email', 'total'].each do |column_name|
%th
= render partial: 'sortable_header', locals: {column_name: column_name}
= render partial: 'spree/admin/shared/sortable_header', locals: {column_name: column_name}
%th.actions
%tbody

View File

@@ -26,7 +26,8 @@
%th.image{ 'ng-show' => 'columns.image.visible' }
%th.producer{ 'ng-show' => 'columns.producer.visible' }=t('admin.producer')
%th.sku{ 'ng-show' => 'columns.sku.visible' }=t('admin.sku')
%th.name{ 'ng-show' => 'columns.name.visible' }=t('.name')
%th.name{ 'ng-show' => 'columns.name.visible' }
= render partial: 'spree/admin/shared/sortable_header', locals: {column_name: 'name'}
%th.unit{ 'ng-show' => 'columns.unit.visible' }=t('.unit')
%th.display_as{ 'ng-show' => 'columns.unit.visible' }=t('.display_as')
%th.price{ 'ng-show' => 'columns.price.visible' }=t('admin.price')

View File

@@ -18,7 +18,6 @@
= render "spree/admin/shared/routes"
%script
= "jQuery.alerts.dialogClass = 'spree';"
= raw "var AUTH_TOKEN = \"#{form_authenticity_token}\";"
= render "layouts/bugherd_script"

View File

@@ -34,10 +34,14 @@ Openfoodnetwork::Application.configure do
config.action_mailer.default_url_options = { protocol: 'https' }
# See everything in the log (default is :info)
config.log_level = :info
# config.log_level = :debug
# Use a different logger for distributed setups
# config.logger = SyslogLogger.new
# Configure logging for Rails 3.2:
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(Rails.root.join("log", "#{Rails.env}.log")))
config.logger.formatter = Logger::Formatter.new
config.logger.datetime_format = "%Y-%m-%d %H:%M:%S"
# Once we get to Rails 4.0, we can replace the above with:
#config.log_formatter = Logger::Formatter.new.tap { |f| f.datetime_format = "%Y-%m-%d %H:%M:%S" }
# Use a different cache store in production
memcached_value_max_megabytes = ENV.fetch("MEMCACHED_VALUE_MAX_MEGABYTES", 1).to_i

View File

@@ -36,8 +36,12 @@ Openfoodnetwork::Application.configure do
# See everything in the log (default is :info)
# config.log_level = :debug
# Use a different logger for distributed setups
# config.logger = SyslogLogger.new
# Configure logging for Rails 3.2:
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(Rails.root.join("log", "#{Rails.env}.log")))
config.logger.formatter = Logger::Formatter.new
config.logger.datetime_format = "%Y-%m-%d %H:%M:%S"
# Once we get to Rails 4.0, we can replace the above with:
#config.log_formatter = Logger::Formatter.new.tap { |f| f.datetime_format = "%Y-%m-%d %H:%M:%S" }
# Use a different cache store in production
memcached_value_max_megabytes = ENV.fetch("MEMCACHED_VALUE_MAX_MEGABYTES", 1).to_i

View File

@@ -0,0 +1,15 @@
#
# Allow some application_helper methods to be used in the scoped form_for manner
#
class ActionView::Helpers::FormBuilder
def field_container(method, options = {}, &block)
@template.field_container(@object_name,method,options,&block)
end
def error_message_on(method, options = {})
@template.error_message_on(@object_name, method, objectify_options(options))
end
end
ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "<span class=\"field_with_errors\">#{html_tag}</span>".html_safe }

View File

@@ -1281,6 +1281,7 @@ ar:
saving_credit_card: جارٍ حفظ بطاقة الائتمان ...
card_has_been_removed: "تمت إزالة بطاقتك (الرقم: %{number})"
card_could_not_be_removed: عذرًا ، تعذرت إزالة البطاقة
invalid_credit_card: "بطاقة الائتمان غير صالحة"
ie_warning_headline: "متصفحك غير محدث :-("
ie_warning_text: "للحصول على أفضل تجربة لشبكة الغذاء المفتوح ، نوصي بشدة بترقية متصفحك:"
ie_warning_chrome: تحميل متصفح كروم
@@ -2425,11 +2426,11 @@ ar:
description: وصف
resolve: حل
exchange_products:
load_more_products: "تحميل المزيد من المنتجات"
load_all_products: "تحميل جميع المنتجات"
select_all_products: "حدد جميع المنتجات %{total_number_of_products}"
products_loaded: "%{num_of_products_loaded} من %{total_number_of_products} المنتجات المحملة"
loading_products: "تحميل المنتجات"
load_more_variants: "تحميل المزيد من المتغيرات"
load_all_variants: "تحميل جميع المتغيرات"
select_all_variants: "حدد كل %{total_number_of_variants} المتغيرات"
variants_loaded: "%{num_of_variants_loaded} من %{total_number_of_variants} تم تحميل المتغيرات"
loading_variants: "تحميل المتغيرات"
tag_rules:
shipping_method_tagged_top: "طرق الشحن الموسومة"
shipping_method_tagged_bottom: "هي:"
@@ -2588,6 +2589,21 @@ ar:
signup_or_login: "البدء بالتسجيل (أو تسجيل الدخول)"
have_an_account: "هل لديك حساب؟"
action_login: "تسجيل الدخول الآن."
inflections:
each:
zero: "كل"
one: "كل"
two: "كل"
few: "كل"
many: "كل"
other: "كل"
pack:
zero: "حزم"
one: "رزمة"
two: "حزم"
few: "حزم"
many: "حزم"
other: "حزم"
producers:
signup:
start_free_profile: "ابدأ بملف تعريف مجاني ، وتوسع عندما تكون جاهزًا!"
@@ -2830,6 +2846,8 @@ ar:
zipcode: الرمز البريدي
weight: الوزن (لكل كجم)
error_user_destroy_with_orders: "لا يمكن حذف المستخدمين الذين لديهم طلبات مكتملة"
cannot_create_payment_without_payment_methods: "لا يمكنك إنشاء دفعة لطلب بدون تحديد طرقة الدفع."
please_define_payment_methods: "يرجى تحديد بعض طرق الدفع أولاً."
options: "خيارات"
actions:
update: "تحديث"

View File

@@ -2430,12 +2430,6 @@ ca:
severity: Severitat
description: Descripció
resolve: Resoldre
exchange_products:
load_more_products: "Carrega més productes"
load_all_products: "Carrega tots els productes"
select_all_products: "Seleccioneu tots els productes %{total_number_of_products}"
products_loaded: "%{num_of_products_loaded} de %{total_number_of_products} productes carregats"
loading_products: "Carregant productes"
tag_rules:
shipping_method_tagged_top: "Els mètodes d'enviament etiquetats"
shipping_method_tagged_bottom: "son:"

View File

@@ -2575,6 +2575,10 @@ de_DE:
signup_or_login: "Beginnen Sie mit der Anmeldung (oder melden Sie sich an)"
have_an_account: "Hast du schon ein Konto?"
action_login: "Jetzt einloggen."
inflections:
bottle:
one: "Flasche"
other: "Flaschen"
producers:
signup:
start_free_profile: "Beginnen Sie mit einem kostenlosen Profil und erweitern Sie es, wenn Sie fertig sind!"

View File

@@ -1364,6 +1364,7 @@ en:
saving_credit_card: Saving credit card...
card_has_been_removed: "Your card has been removed (number: %{number})"
card_could_not_be_removed: Sorry, the card could not be removed
invalid_credit_card: "Invalid credit card"
ie_warning_headline: "Your browser is out of date :-("
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
@@ -2557,11 +2558,11 @@ See the %{link} to find out more about %{sitename}'s features and to start using
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products} Products"
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
load_more_variants: "Load More Variants"
load_all_variants: "Load All Variants"
select_all_variants: "Select All %{total_number_of_variants} Variants"
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
loading_variants: "Loading Variants"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2721,6 +2722,90 @@ See the %{link} to find out more about %{sitename}'s features and to start using
have_an_account: "Already have an account?"
action_login: "Log in now."
# Singular and plural forms of commonly used words.
# We use these entries to pluralize unit names in every language.
#
# Extracted with the following query:
# Spree::Product.group(:variant_unit_name).order("count_all DESC").count.each { |name, count|
# puts " # Used #{count} times."
# puts " #{name&.parameterize('_')}:"
# puts " one: \"#{name}\""
# puts " other: \"#{name}s\"";
# }
inflections:
each:
one: "each"
other: "each"
bunch:
one: "bunch"
other: "bunches"
pack:
one: "pack"
other: "packs"
box:
one: "box"
other: "boxes"
bottle:
one: "bottle"
other: "bottles"
jar:
one: "jar"
other: "jars"
head:
one: "head"
other: "heads"
bag:
one: "bag"
other: "bags"
loaf:
one: "loaf"
other: "loaves"
single:
one: "single"
other: "singles"
tub:
one: "tub"
other: "tubs"
punnet:
one: "punnet"
other: "punnets"
packet:
one: "packet"
other: "packets"
item:
one: "item"
other: "items"
dozen:
one: "dozen"
other: "dozens"
unit:
one: "unit"
other: "units"
serve:
one: "serve"
other: "serves"
tray:
one: "tray"
other: "trays"
piece:
one: "piece"
other: "pieces"
pot:
one: "pot"
other: "pots"
bundle:
one: "bundle"
other: "bundles"
flask:
one: "flask"
other: "flasks"
basket:
one: "basket"
other: "baskets"
sack:
one: "sack"
other: "sacks"
producers:
signup:
start_free_profile: "Start with a free profile, and expand when you're ready!"

View File

@@ -782,7 +782,14 @@ en_AU:
producer_shop_description_text2: A Producer Shop is for your produce only, if you want to sell produce grown/produced off site, select 'Producer Hub'.
producer_hub: Producer Hub
producer_hub_text: Sell produce from self and others
producer_hub_description_text: Your enterprise is the backbone of your local food system. You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
producer_hub_description_text: 'You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
Free to use for shopfronts with turnover of less than $500 a month. 
1% of turnover for shopfronts with turnover of more than $500 a month.
2-3% of turnover for solidarity partners who choose to collaborate on growing a new food system.'
profile: Profile Only
get_listing: Get a listing
profile_description_text: People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings.
@@ -1617,7 +1624,7 @@ en_AU:
sell_groups_detail: "Set up a tailored directory of enterprises (producers and other food enterprises) for your region or for your organisation."
sell_user_guide: "Find out more in our user guide."
sell_listing_price: "Listing on the OFN is free. Opening and running a shop on OFN is free up to $500 of monthly sales. If you sell more you can choose your community contribution between 1% and 3% of sales. For more detail on pricing visit the Software Platform section via the About link in the top menu."
sell_embed: "We can also embed an OFN shop in your own customised website or build a customised local food network website for your region."
sell_embed: "In addition to the Open Food Network platform, our social enterprise consultancy offers a range of services that help power a better, fairer food system. We can help with customised business and online solutions for your farm or food enterprise, lean enterprise support, regional food system development as well as food systems research and consulting."
sell_ask_services: "Ask us about OFN services."
shops_title: Shops
shops_headline: Shopping, transformed.

View File

@@ -919,7 +919,7 @@ en_CA:
distributors: distributors
variants: variants
simple_form:
ready_for: Ready for
ready_for: Options
ready_for_placeholder: Date / time
customer_instructions: Customer instructions
customer_instructions_placeholder: 'Notes:'
@@ -1282,6 +1282,7 @@ en_CA:
saving_credit_card: Saving credit card...
card_has_been_removed: "Your card has been removed (number: %{number})"
card_could_not_be_removed: Sorry, the card could not be removed
invalid_credit_card: "Invalid credit card"
ie_warning_headline: "Your browser is out of date :-("
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
ie_warning_chrome: Download Chrome
@@ -2424,11 +2425,11 @@ en_CA:
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products}Products"
products_loaded: "%{num_of_products_loaded}of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
load_more_variants: "Load More Variants"
load_all_variants: "Load All Variants"
select_all_variants: "Select All %{total_number_of_variants}Variants"
variants_loaded: "%{num_of_variants_loaded}of%{total_number_of_variants}Variants Loaded"
loading_variants: "Loading Variants"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2587,6 +2588,79 @@ en_CA:
signup_or_login: "Start By Signing Up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
inflections:
each:
one: "each"
other: "each"
bunch:
one: "bunch"
other: "bunches"
pack:
one: "pack"
other: "packs"
box:
one: "box"
other: "boxes"
bottle:
one: "bottle"
other: "bottles"
jar:
one: "jar"
other: "jars"
head:
one: "head"
other: "heads"
bag:
one: "bag"
other: "bags"
loaf:
one: "loaf"
other: "loaves"
single:
one: "single"
other: "singles"
tub:
one: "tub"
other: "tubs"
punnet:
one: "punnet"
other: "punnets"
packet:
one: "packet"
other: "packets"
item:
one: "item"
other: "items"
dozen:
one: "dozen"
other: "dozens"
unit:
one: "unit"
other: "units"
serve:
one: "serve"
other: "serves"
tray:
one: "tray"
other: "trays"
piece:
one: "piece"
other: "pieces"
pot:
one: "pot"
other: "pots"
bundle:
one: "bundle"
other: "bundles"
flask:
one: "flask"
other: "flasks"
basket:
one: "basket"
other: "baskets"
sack:
one: "sack"
other: "sacks"
producers:
signup:
start_free_profile: "Start with a free profile, and expand when you're ready!"
@@ -2829,6 +2903,8 @@ en_CA:
zipcode: Postal Code
weight: Weight (per kg)
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
please_define_payment_methods: "Please define some payment methods first."
options: "Options"
actions:
update: "Update"
@@ -2935,7 +3011,7 @@ en_CA:
email: "Customer E-Mail"
invoice:
issued_on: "Issued on"
tax_invoice: "TAX INVOICE"
tax_invoice: "Order Number"
code: "Code"
from: "From"
to: "To"

View File

@@ -1282,6 +1282,7 @@ en_FR:
saving_credit_card: Saving credit card...
card_has_been_removed: "Your card has been removed (number: %{number})"
card_could_not_be_removed: Sorry, the card could not be removed
invalid_credit_card: "Invalid credit card"
ie_warning_headline: "Your browser is out of date :-("
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
ie_warning_chrome: Download Chrome
@@ -2425,11 +2426,11 @@ en_FR:
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products} Products"
products_loaded: "%{num_of_products_loaded}of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
load_more_variants: "Load All Variants"
load_all_variants: "Load All Variants"
select_all_variants: "Select All %{total_number_of_variants} Variants"
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
loading_variants: "Loading Variants"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2588,6 +2589,79 @@ en_FR:
signup_or_login: "Start By Signing Up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
inflections:
each:
one: "each"
other: "each"
bunch:
one: "bunch"
other: "bunches"
pack:
one: "pack"
other: "packs"
box:
one: "box"
other: "boxes"
bottle:
one: "bottle"
other: "bottles"
jar:
one: "jar"
other: "jars"
head:
one: "head"
other: "heads"
bag:
one: "bag"
other: "bags"
loaf:
one: "loaf"
other: "loaves"
single:
one: "single"
other: "singles"
tub:
one: "tub"
other: "tubs"
punnet:
one: "punnet"
other: "punnets"
packet:
one: "packet"
other: "packets"
item:
one: "item"
other: "items"
dozen:
one: "dozen"
other: "dozens"
unit:
one: "unit"
other: "units"
serve:
one: "serve"
other: "serves"
tray:
one: "tray"
other: "trays"
piece:
one: "piece"
other: "pieces"
pot:
one: "pot"
other: "pots"
bundle:
one: "bundle"
other: "bundles"
flask:
one: "flask"
other: "flasks"
basket:
one: "basket"
other: "baskets"
sack:
one: "sack"
other: "sacks"
producers:
signup:
start_free_profile: "Start with a free profile, and expand when you're ready!"

View File

@@ -1282,6 +1282,7 @@ en_GB:
saving_credit_card: Saving credit card...
card_has_been_removed: "Your card has been removed (number: %{number})"
card_could_not_be_removed: Sorry, the card could not be removed
invalid_credit_card: "Invalid credit card"
ie_warning_headline: "Your browser is out of date :-("
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
ie_warning_chrome: Download Chrome
@@ -2188,8 +2189,8 @@ en_GB:
report_header_temp_controlled: TempControlled?
report_header_is_producer: Producer?
report_header_not_confirmed: Not Confirmed
report_header_gst_on_income: VAT on Income
report_header_gst_free_income: VAT Free Income
report_header_gst_on_income: 20%(VAT on Income)
report_header_gst_free_income: Zero Rated Income
report_header_total_untaxable_produce: Total untaxable produce (no tax)
report_header_total_taxable_produce: Total taxable produce (tax inclusive)
report_header_total_untaxable_fees: Total untaxable fees (no tax)
@@ -2431,11 +2432,11 @@ en_GB:
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products} Products"
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
load_more_variants: "Load More Variants"
load_all_variants: "Load All Variants"
select_all_variants: "Select All %{total_number_of_variants} Variants"
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
loading_variants: "Loading Variants"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2594,6 +2595,79 @@ en_GB:
signup_or_login: "Start By signing up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
inflections:
each:
one: "each"
other: "each"
bunch:
one: "bunch"
other: "bunches"
pack:
one: "pack"
other: "packs"
box:
one: "box"
other: "boxes"
bottle:
one: "bottle"
other: "bottles"
jar:
one: "jar"
other: "jars"
head:
one: "head"
other: "heads"
bag:
one: "bag"
other: "bags"
loaf:
one: "loaf"
other: "loaves"
single:
one: "single"
other: "singles"
tub:
one: "tub"
other: "tubs"
punnet:
one: "punnet"
other: "punnets"
packet:
one: "packet"
other: "packets"
item:
one: "item"
other: "items"
dozen:
one: "dozen"
other: "dozens"
unit:
one: "unit"
other: "units"
serve:
one: "serve"
other: "serves"
tray:
one: "tray"
other: "trays"
piece:
one: "piece"
other: "pieces"
pot:
one: "pot"
other: "pots"
bundle:
one: "bundle"
other: "bundles"
flask:
one: "flask"
other: "flasks"
basket:
one: "basket"
other: "baskets"
sack:
one: "sack"
other: "sacks"
producers:
signup:
start_free_profile: "Start with a free profile, and expand when you're ready!"
@@ -2836,6 +2910,8 @@ en_GB:
zipcode: Postcode
weight: Weight (per kg)
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
please_define_payment_methods: "Please define some payment methods first."
options: "Options"
actions:
update: "Update"

View File

@@ -1282,6 +1282,7 @@ en_NZ:
saving_credit_card: Saving credit card...
card_has_been_removed: "Your card has been removed (number: %{number})"
card_could_not_be_removed: Sorry, the card could not be removed
invalid_credit_card: "Invalid credit card"
ie_warning_headline: "Your browser is out of date :-("
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
ie_warning_chrome: Download Chrome
@@ -2425,11 +2426,11 @@ en_NZ:
description: Description
resolve: Resolve
exchange_products:
load_more_products: "Load More Products"
load_all_products: "Load All Products"
select_all_products: "Select All %{total_number_of_products} Products"
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
loading_products: "Loading Products"
load_more_variants: "Load More Variants"
load_all_variants: "Load All Variants"
select_all_variants: "Select All %{total_number_of_variants} Variants"
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
loading_variants: "Loading Variants"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2588,6 +2589,79 @@ en_NZ:
signup_or_login: "Start By Signing Up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
inflections:
each:
one: "each"
other: "each"
bunch:
one: "bunch"
other: "bunches"
pack:
one: "pack"
other: "packs"
box:
one: "box"
other: "boxes"
bottle:
one: "bottle"
other: "bottles"
jar:
one: "jar"
other: "jars"
head:
one: "head"
other: "heads"
bag:
one: "bag"
other: "bags"
loaf:
one: "loaf"
other: "loaves"
single:
one: "single"
other: "singles"
tub:
one: "tub"
other: "tubs"
punnet:
one: "punnet"
other: "punnets"
packet:
one: "packet"
other: "packets"
item:
one: "item"
other: "items"
dozen:
one: "dozen"
other: "dozens"
unit:
one: "unit"
other: "units"
serve:
one: "serve"
other: "serves"
tray:
one: "tray"
other: "trays"
piece:
one: "piece"
other: "pieces"
pot:
one: "pot"
other: "pots"
bundle:
one: "bundle"
other: "bundles"
flask:
one: "flask"
other: "flasks"
basket:
one: "basket"
other: "baskets"
sack:
one: "sack"
other: "sacks"
producers:
signup:
start_free_profile: "Start with a basic profile, and expand when you're ready!"
@@ -2830,6 +2904,8 @@ en_NZ:
zipcode: Postcode
weight: Weight (per kg)
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
please_define_payment_methods: "Please define some payment methods first."
options: "Options"
actions:
update: "Update"

View File

@@ -1284,6 +1284,7 @@ fr:
saving_credit_card: Enregistrement de la carte de crédit...
card_has_been_removed: "Votre carte a été supprimée (numéro : %{number})"
card_could_not_be_removed: Désolée, la carte n'a pas pu être supprimée :-(
invalid_credit_card: "Cette carte de crédit n'est pas valide"
ie_warning_headline: "Votre navigateur n'est pas à jour :-("
ie_warning_text: "Pour une expérience optimale sur Open Food France, nous vous recommandons fortement de mettre à jour votre navigateur:"
ie_warning_chrome: Télécharger Chrome
@@ -2454,11 +2455,11 @@ fr:
description: Description
resolve: Résoudre
exchange_products:
load_more_products: "Voir plus de produits"
load_all_products: "Voir tous les produits"
select_all_products: "Sélectionner tous les %{total_number_of_products}produits"
products_loaded: "%{num_of_products_loaded}sur %{total_number_of_products}produits affichés"
loading_products: "Produits en cours de chargement"
load_more_variants: "Afficher plus de variantes"
load_all_variants: "Afficher toutes les variantes"
select_all_variants: "Sélectionnez toutes les %{total_number_of_variants} variantes"
variants_loaded: " %{num_of_variants_loaded}sur %{total_number_of_variants} variantes"
loading_variants: "Chargement des variantes"
tag_rules:
shipping_method_tagged_top: "Les méthodes de livraison taguées"
shipping_method_tagged_bottom: "sont:"
@@ -2618,6 +2619,79 @@ fr:
signup_or_login: "Commencez par vous inscrire (ou connexion)"
have_an_account: "Déjà inscrit?"
action_login: "Se connecter."
inflections:
each:
one: "chacun"
other: "chacun"
bunch:
one: "bouquet"
other: "bouquets"
pack:
one: "caisse"
other: "caisses"
box:
one: "boîte"
other: "boîtes"
bottle:
one: "bouteille"
other: "bouteilles"
jar:
one: "bocal"
other: "bocaux"
head:
one: "tête"
other: "têtes"
bag:
one: "sac"
other: "sacs"
loaf:
one: "miche"
other: "miches"
single:
one: "unité"
other: "unités"
tub:
one: "bac"
other: "bacs"
punnet:
one: "barquette"
other: "barquettes"
packet:
one: "paquet"
other: "paquets"
item:
one: "article"
other: "articles"
dozen:
one: "dizaine"
other: "dizaines"
unit:
one: "unité"
other: "unités"
serve:
one: "service"
other: "services"
tray:
one: "plateau"
other: "plateaux"
piece:
one: "pièce"
other: "pièces"
pot:
one: "pot"
other: "pots"
bundle:
one: "botte"
other: "bottes"
flask:
one: "flacon"
other: "flacons"
basket:
one: "panier"
other: "paniers"
sack:
one: "sachet"
other: "sachets"
producers:
signup:
start_free_profile: "Commencez par créer votre profil entreprise, et changez de formule quand vous êtes prêt !"

File diff suppressed because it is too large Load Diff

View File

@@ -1284,6 +1284,7 @@ fr_CA:
saving_credit_card: Enregistrement de la carte de crédit...
card_has_been_removed: "Votre carte a été supprimée (numéro : %{number})"
card_could_not_be_removed: Désolée, la carte n'a pas pu être supprimée :-(
invalid_credit_card: "Cette carte de crédit n'est pas valide"
ie_warning_headline: "Votre navigateur n'est pas à jour :-("
ie_warning_text: "Pour une expérience optimale sur Open Food Network, nous vous recommandons fortement de mettre à jour votre navigateur:"
ie_warning_chrome: Télécharger Chrome
@@ -2437,11 +2438,11 @@ fr_CA:
description: Description
resolve: Résoudre
exchange_products:
load_more_products: "Voir plus de produits"
load_all_products: "Voir tous les produits"
select_all_products: "Sélectionner tous les %{total_number_of_products} produits"
products_loaded: "%{num_of_products_loaded}sur %{total_number_of_products}produits affichés"
loading_products: "Produits en cours de chargement..."
load_more_variants: "Afficher plus de variantes"
load_all_variants: "Afficher toutes les variantes"
select_all_variants: "Sélectionnez toutes les%{total_number_of_variants}variantes"
variants_loaded: "%{num_of_variants_loaded}sur%{total_number_of_variants}variantes"
loading_variants: "Chargement des variantes"
tag_rules:
shipping_method_tagged_top: "Les méthodes de livraison taggées"
shipping_method_tagged_bottom: "sont:"
@@ -2601,6 +2602,79 @@ fr_CA:
signup_or_login: "Commencez par vous inscrire (ou vous connecter)"
have_an_account: "Déjà inscrit?"
action_login: "Se connecter."
inflections:
each:
one: "chacun"
other: "chacun"
bunch:
one: "bouquet"
other: "bouquets"
pack:
one: "caisse"
other: "caisses"
box:
one: "boîte"
other: "boîtes"
bottle:
one: "bouteille"
other: "bouteilles"
jar:
one: "bocal"
other: "bocaux"
head:
one: "tête"
other: "têtes"
bag:
one: "sac"
other: "sacs"
loaf:
one: "miche"
other: "miches"
single:
one: "unité"
other: "unités"
tub:
one: "bac"
other: "bacs"
punnet:
one: "barquette"
other: "barquettes"
packet:
one: "paquets"
other: "paquets"
item:
one: "article"
other: "articles"
dozen:
one: "dizaine"
other: "dizaines"
unit:
one: "unité"
other: "unités"
serve:
one: "service"
other: "services"
tray:
one: "plateau"
other: "plateaux"
piece:
one: "pièce"
other: "pièces"
pot:
one: "pots"
other: "pots"
bundle:
one: "botte"
other: "bottes"
flask:
one: "flacons"
other: "flacon"
basket:
one: "panier"
other: "paniers"
sack:
one: "sachet"
other: "sachets"
producers:
signup:
start_free_profile: "Commencez par créer votre profil entreprise, c'est gratuit, et changez de formule quand vous êtes prêt !"
@@ -2843,6 +2917,8 @@ fr_CA:
zipcode: Code postal
weight: Poids (au kg)
error_user_destroy_with_orders: "Les utilisateurs avec des commandes finalisées pourraient ne pas être supprimés"
cannot_create_payment_without_payment_methods: "Vous ne pouvez pas ajouter un paiement pour une commande sans avoir défini de méthode de paiement au préalable."
please_define_payment_methods: "Il faut que vous définissiez une méthode de paiement avant tout !"
options: "Options"
actions:
update: "Mettre à jour"

View File

@@ -1282,6 +1282,7 @@ nb:
saving_credit_card: Lagrer kredittkort ...
card_has_been_removed: "Ditt kort er fjernet (nummer: %{number})"
card_could_not_be_removed: Beklager, kortet kunne ikke fjernes
invalid_credit_card: "Ugyldig kort"
ie_warning_headline: "Din nettleser er for gammel :-("
ie_warning_text: "For den beste opplevelsen med Open Food Network anbefaler vi på det sterkeste å oppgradere nettleseren din:"
ie_warning_chrome: Last ned Chrome
@@ -2425,11 +2426,11 @@ nb:
description: Beskrivelse
resolve: Løse
exchange_products:
load_more_products: "Last inn flere produkter"
load_all_products: "Last inn alle produkter"
select_all_products: "Velg alle %{total_number_of_products} produkter"
products_loaded: "%{num_of_products_loaded} av %{total_number_of_products} produkter lastet"
loading_products: "Laster inn produkter"
load_more_variants: "Last inn flere varianter"
load_all_variants: "Last inn alle varianter"
select_all_variants: "Velg alle %{total_number_of_variants} varianter"
variants_loaded: "%{num_of_variants_loaded} av %{total_number_of_variants} Varianter lastet"
loading_variants: "Laster varianter"
tag_rules:
shipping_method_tagged_top: "Leveringsmetoder merket"
shipping_method_tagged_bottom: "er:"
@@ -2587,6 +2588,79 @@ nb:
signup_or_login: "Kom i gang ved å registrere deg (eller logge inn)"
have_an_account: "Har du allerede en konto?"
action_login: "Logg inn nå."
inflections:
each:
one: "Hver"
other: "hver"
bunch:
one: "bunke"
other: "bunker"
pack:
one: "pakke"
other: "pakker"
box:
one: "eske"
other: "esker"
bottle:
one: "flaske"
other: "flasker"
jar:
one: "krukke"
other: "krukker"
head:
one: "hode"
other: "hoder"
bag:
one: "pose"
other: "poser"
loaf:
one: "skive"
other: "skiver"
single:
one: "enkelt"
other: "enkle"
tub:
one: "kar"
other: "kar"
punnet:
one: "eske"
other: "esker"
packet:
one: "pakke"
other: "pakker"
item:
one: "stk"
other: "stk"
dozen:
one: "dusin"
other: "dusin"
unit:
one: "enhet"
other: "enheter"
serve:
one: "porsjon"
other: "porsjoner"
tray:
one: "brett"
other: "brett"
piece:
one: "stykke"
other: "stykker"
pot:
one: "gryte"
other: "gryter"
bundle:
one: "bunt"
other: "bunter"
flask:
one: "kolbe"
other: "kolber"
basket:
one: "kurv"
other: "kurver"
sack:
one: "sekk"
other: "sekker"
producers:
signup:
start_free_profile: "Start med en gratis profil, og utvid når du er klar!"

View File

@@ -702,6 +702,10 @@ pt_BR:
enable_subscriptions_false: "Desativado"
enable_subscriptions_true: "ativado"
shopfront_message: "Mensagem da vitrine da loja"
shopfront_message_placeholder: >
Uma mensagem opcional para dar as boas-vindas aos clientes e explicar
como comprar com você. Se o texto for inserido aqui, ele será exibido
em uma guia inicial quando os clientes chegarem à sua loja.
shopfront_message_link_tooltip: "Inserir / editar link"
shopfront_message_link_prompt: "Digite um URL para inserir"
shopfront_closed_message: "Mensagem de loja fechada"
@@ -1106,6 +1110,7 @@ pt_BR:
already_ordered:
cart: "Carrinho"
message_html: "Você já possui um pedido para esta compra. Verifique o %{cart} para ver os itens já encomendados. Você também pode cancelar itens enquanto o ciclo estiver aberto."
failed: "O checkout falhou. Informe-nos para que possamos processar seu pedido."
shops:
hubs:
show_closed_shops: "Mostrar lojas fechadas"
@@ -1276,6 +1281,7 @@ pt_BR:
saving_credit_card: Salvando cartão de crédito...
card_has_been_removed: "O seu cartão foi removido (número: %{number})"
card_could_not_be_removed: Desculpe, o cartão não pode ser removido
invalid_credit_card: "Cartão de crédito inválido"
ie_warning_headline: "Seu navegador está desatualizado :("
ie_warning_text: "Para a melhor experiência na Open Food Brasil, recomendamos que você atualize seu navegador:"
ie_warning_chrome: Baixar Chrome
@@ -1936,6 +1942,7 @@ pt_BR:
tax_category: "Categoria de taxa"
calculator: "Calculadora"
calculator_values: "Valores da calculadora"
calculator_settings_warning: "Se você estiver alterando o tipo de calculadora, salve primeiro antes de poder editar as configurações da calculadora."
flat_percent_per_item: "Percentual (por unidade)"
flat_rate_per_item: "Taxa fixa (por item)"
flat_rate_per_order: "Taxa fixa ( por pedido)"
@@ -2423,11 +2430,11 @@ pt_BR:
description: Descrição
resolve: Resolver
exchange_products:
load_more_products: "Carregar Mais Produtos"
load_all_products: "Carregar Todos os Produtos"
select_all_products: "Selecionar %{total_number_of_products}Produto(s)"
products_loaded: "%{num_of_products_loaded} de %{total_number_of_products}Produtos Carregados"
loading_products: "Carregando Produtos"
load_more_variants: "Carregar mais variantes"
load_all_variants: "Carregar todas as variantes"
select_all_variants: "Selecionar todas as %{total_number_of_variants} variantes"
variants_loaded: "%{num_of_variants_loaded} de %{total_number_of_variants} Variantes carregadas"
loading_variants: "Carregando variantes"
tag_rules:
shipping_method_tagged_top: "Métodos de envio selecionados"
shipping_method_tagged_bottom: "são:"
@@ -2828,6 +2835,8 @@ pt_BR:
zipcode: CEP
weight: Peso (por kg)
error_user_destroy_with_orders: "Usuários com pedidos concluídos não podem ser excluídos"
cannot_create_payment_without_payment_methods: "Você não pode criar um pagamento para um pedido sem métodos de pagamento definidos."
please_define_payment_methods: "Defina primeiro algum método de pagamento."
options: "Opções"
actions:
update: "Atualizar"

3346
config/locales/tr.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -83,6 +83,8 @@ Spree::Core::Engine.routes.draw do
get '/variants/search', :to => "variants#search", :as => :search_variants
resources :properties
resources :orders do
member do
put :fire
@@ -110,8 +112,16 @@ Spree::Core::Engine.routes.draw do
end
resource :customer, :controller => "orders/customer_details"
resources :return_authorizations do
member do
put :fire
end
end
end
resources :reports
resources :users do
member do
put :generate_api_key
@@ -126,6 +136,7 @@ Spree::Core::Engine.routes.draw do
end
resource :image_settings
resources :trackers
resources :zones
resources :countries do
@@ -152,6 +163,10 @@ Spree::Core::Engine.routes.draw do
resources :tax_rates
resource :tax_settings
resources :tax_categories
resources :shipping_methods
resources :shipping_categories
resources :payment_methods
end
resources :orders do

View File

@@ -15,9 +15,9 @@ module OpenFoodNetwork
end
def stripe_configuration_incomplete?(payment_method)
return true if payment_method.preferred_enterprise_id.zero?
payment_method.stripe_account_id.blank?
payment_method.preferred_enterprise_id.nil? ||
payment_method.preferred_enterprise_id.zero? ||
payment_method.stripe_account_id.blank?
end
end
end

View File

@@ -0,0 +1,65 @@
# frozen_string_literal: true
module OpenFoodNetwork
# Pluralize or singularize words.
#
# We store some inflection data in locales and use a reverse lookup of a word
# to find the plural or singular of the same word.
#
# Here is one example with a French user:
#
# - We have a product with the variant unit name "bouquet".
# - The I18n.locale is set to :fr.
# - The French locale contains:
# bunch:
# one: "bouquet"
# other: "bouquets"
# - We create a table containing:
# "bouquet" => "bunch"
# "bouquets" => "bunch"
# - Looking up "bouquet" gives us the I18n key "bunch".
# - We find the right plural by calling I18n:
#
# I18n.t("inflections.bunch", count: 2, default: "bouquet")
#
# - This returns the correct plural "bouquets".
# - It returns the original "bouquet" if the word is missing from the locale.
module I18nInflections
# Make this a singleton to cache lookup tables.
extend self
def pluralize(word, count)
return word if count.nil?
key = i18n_key(word)
return word unless key
I18n.t(key, scope: "inflections", count: count, default: word)
end
private
def i18n_key(word)
@lookup ||= {}
# The user may switch the locale. `I18n.t` is always using the current
# locale and we need a lookup table for each of them.
unless @lookup.key?(I18n.locale)
@lookup[I18n.locale] = build_i18n_key_lookup
end
@lookup[I18n.locale][word.downcase]
end
def build_i18n_key_lookup
lookup = {}
I18n.t("inflections")&.each do |key, translations|
translations.values.each do |translation|
lookup[translation.downcase] = key
end
end
lookup
end
end
end

View File

@@ -1,3 +1,7 @@
# frozen_string_literal: true
require "open_food_network/i18n_inflections"
module OpenFoodNetwork
class OptionValueNamer
def initialize(variant = nil)
@@ -38,8 +42,7 @@ module OpenFoodNetwork
else
value = @variant.unit_value
unit_name = @variant.product.variant_unit_name
unit_name = unit_name.pluralize if value > 1
unit_name = pluralize(@variant.product.variant_unit_name, value)
end
value = value.to_i if value == value.to_i
@@ -72,5 +75,9 @@ module OpenFoodNetwork
unit
end
def pluralize(unit_name, count)
I18nInflections.pluralize(unit_name, count)
end
end
end

View File

@@ -207,62 +207,62 @@ describe Api::ProductsController, type: :controller do
expect(json_response['name']).to eq("COPY OF #{product_with_image.name}")
end
end
end
describe '#bulk_products' do
context "as an enterprise user" do
let!(:taxon) { create(:taxon) }
let!(:product2) { create(:product, supplier: supplier, primary_taxon: taxon) }
let!(:product3) { create(:product, supplier: supplier2, primary_taxon: taxon) }
let!(:product4) { create(:product, supplier: supplier2) }
let(:current_api_user) { supplier_enterprise_user(supplier) }
describe '#bulk_products' do
context "as an enterprise user" do
let!(:taxon) { create(:taxon) }
let!(:product2) { create(:product, supplier: supplier, primary_taxon: taxon) }
let!(:product3) { create(:product, supplier: supplier2, primary_taxon: taxon) }
let!(:product4) { create(:product, supplier: supplier2) }
let(:current_api_user) { supplier_enterprise_user(supplier) }
before { current_api_user.enterprise_roles.create(enterprise: supplier2) }
before { current_api_user.enterprise_roles.create(enterprise: supplier2) }
it "returns a list of products" do
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
expect(returned_product_ids).to eq [product4.id, product3.id, product2.id, inactive_product.id, product.id]
end
it "returns a list of products" do
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
expect(returned_product_ids).to eq [product4.id, product3.id, product2.id, inactive_product.id, product.id]
end
it "returns pagination data" do
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
end
it "returns pagination data" do
api_get :bulk_products, { page: 1, per_page: 15 }, format: :json
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
end
it "uses defaults when page and per_page are not supplied" do
api_get :bulk_products, format: :json
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
end
it "uses defaults when page and per_page are not supplied" do
api_get :bulk_products, format: :json
expect(json_response['pagination']).to eq "results" => 5, "pages" => 1, "page" => 1, "per_page" => 15
end
it "returns paginated products by page" do
api_get :bulk_products, { page: 1, per_page: 2 }, format: :json
expect(returned_product_ids).to eq [product4.id, product3.id]
it "returns paginated products by page" do
api_get :bulk_products, { page: 1, per_page: 2 }, format: :json
expect(returned_product_ids).to eq [product4.id, product3.id]
api_get :bulk_products, { page: 2, per_page: 2 }, format: :json
expect(returned_product_ids).to eq [product2.id, inactive_product.id]
end
api_get :bulk_products, { page: 2, per_page: 2 }, format: :json
expect(returned_product_ids).to eq [product2.id, inactive_product.id]
end
it "filters results by supplier" do
api_get :bulk_products, { page: 1, per_page: 15, q: { supplier_id_eq: supplier.id } }, format: :json
expect(returned_product_ids).to eq [product2.id, inactive_product.id, product.id]
end
it "filters results by supplier" do
api_get :bulk_products, { page: 1, per_page: 15, q: { supplier_id_eq: supplier.id } }, format: :json
expect(returned_product_ids).to eq [product2.id, inactive_product.id, product.id]
end
it "filters results by product category" do
api_get :bulk_products, { page: 1, per_page: 15, q: { primary_taxon_id_eq: taxon.id } }, format: :json
expect(returned_product_ids).to eq [product3.id, product2.id]
end
it "filters results by product category" do
api_get :bulk_products, { page: 1, per_page: 15, q: { primary_taxon_id_eq: taxon.id } }, format: :json
expect(returned_product_ids).to eq [product3.id, product2.id]
end
it "filters results by import_date" do
product.variants.first.import_date = 1.day.ago
product2.variants.first.import_date = 2.days.ago
product3.variants.first.import_date = 1.day.ago
it "filters results by import_date" do
product.variants.first.import_date = 1.day.ago
product2.variants.first.import_date = 2.days.ago
product3.variants.first.import_date = 1.day.ago
product.save
product2.save
product3.save
product.save
product2.save
product3.save
api_get :bulk_products, { page: 1, per_page: 15, import_date: 1.day.ago.to_date.to_s }, format: :json
expect(returned_product_ids).to eq [product3.id, product.id]
end
api_get :bulk_products, { page: 1, per_page: 15, import_date: 1.day.ago.to_date.to_s }, format: :json
expect(returned_product_ids).to eq [product3.id, product.id]
end
end
end

View File

@@ -30,8 +30,11 @@ describe CheckoutController, concurrency: true, type: :controller do
# New threads start running straight away. The breakpoint is after loading
# the order and before advancing the order's state and making payments.
breakpoint.lock
allow(controller).to receive(:check_order_for_phantom_fees) do
expect(controller).to receive(:fire_event).with("spree.checkout.update") do
breakpoint.synchronize {}
# This is what fire_event does.
# I did not find out how to call the original code otherwise.
ActiveSupport::Notifications.instrument("spree.checkout.update")
end
end

View File

@@ -1,19 +0,0 @@
require 'spec_helper'
require 'support/request/authentication_workflow'
describe Spree::CheckoutController, type: :controller do
context 'rendering edit from within spree for the current checkout state' do
let(:order) { controller.current_order(true) }
let(:user) { create(:user) }
before do
create(:line_item, order: order)
allow(controller).to receive(:spree_current_user) { user }
end
it "redirects to the OFN checkout page" do
expect(spree_get(:edit)).to redirect_to checkout_path
end
end
end

View File

@@ -542,7 +542,7 @@ feature '
page.find("tr.supplier-#{supplier_enterprise.id} td.products").click
expect(page).to have_selector ".exchange-product-details"
expect(page).to have_content "1 of 2 Products Loaded"
expect(page).to have_content "1 of 2 Variants Loaded"
expect(page).to_not have_content new_product.name
end
@@ -562,7 +562,7 @@ feature '
def expect_all_products_loaded
expect(page).to have_content new_product.name.upcase
expect(page).to have_content "2 of 2 Products Loaded"
expect(page).to have_content "2 of 2 Variants Loaded"
end
end

View File

@@ -203,6 +203,16 @@ feature '
expect(p.reload.property('fooprop')).to be_nil
end
scenario "loading new image page", js: true do
product = create(:simple_product, supplier: @supplier2)
visit spree.admin_product_images_path(product)
expect(page).to have_selector ".no-objects-found"
page.find('a#new_image_link').click
expect(page).to have_selector "#image_attachment"
end
scenario "deleting product images", js: true do
product = create(:simple_product, supplier: @supplier2)
image = File.open(File.expand_path('../../../app/assets/images/logo-white.png', __dir__))

View File

@@ -710,13 +710,22 @@ describe "AdminProductEditCtrl", ->
$httpBackend.flush()
expect($scope.displayFailure).toHaveBeenCalled()
it "shows an alert with error information when post returns 400 with an errors array", ->
spyOn(window, "alert")
$scope.products = "updated list of products"
$httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": ["an error"] }
$scope.updateProducts "updated list of products"
$httpBackend.flush()
expect(window.alert).toHaveBeenCalledWith("Saving failed with the following error(s):\nan error\n")
describe "displaying the error information when post returns 400", ->
beforeEach ->
spyOn $scope, "displayFailure"
$scope.products = "updated list of products"
it "displays errors in an array", ->
$httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": ["an error"] }
$scope.updateProducts "updated list of products"
$httpBackend.flush()
expect($scope.displayFailure).toHaveBeenCalledWith("Saving failed with the following error(s):\nan error\n")
it "displays errors in a hash", ->
$httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": { "base": ["a basic error"] } }
$scope.updateProducts "updated list of products"
$httpBackend.flush()
expect($scope.displayFailure).toHaveBeenCalledWith("Saving failed with the following error(s):\na basic error\n")
describe "adding variants", ->

View File

@@ -0,0 +1,26 @@
describe "OptionValueNamer", ->
subject = null
beforeEach ->
module('admin.products')
inject (_OptionValueNamer_) ->
subject = new _OptionValueNamer_
describe "pluralize a variant unit name", ->
it "returns the same word if no plural is known", ->
expect(subject.pluralize("foo", 2)).toEqual "foo"
it "returns the same word if we omit the quantity", ->
expect(subject.pluralize("loaf")).toEqual "loaf"
it "finds the plural of a word", ->
expect(subject.pluralize("loaf", 2)).toEqual "loaves"
it "finds the singular of a word", ->
expect(subject.pluralize("loaves", 1)).toEqual "loaf"
it "finds the zero form of a word", ->
expect(subject.pluralize("loaf", 0)).toEqual "loaves"
it "ignores upper case", ->
expect(subject.pluralize("Loaf", 2)).toEqual "loaves"

View File

@@ -0,0 +1,20 @@
describe "ErrorsParser service", ->
errorsParser = null
beforeEach ->
module('admin.utils')
inject (ErrorsParser) ->
errorsParser = ErrorsParser
describe "toString", ->
it "returns empty string for nil errors", ->
expect(errorsParser.toString(null)).toEqual ""
it "returns the elements in the array if an array is provided", ->
expect(errorsParser.toString(["1", "2"])).toEqual "1\n2\n"
it "returns the elements in the hash if a hash is provided", ->
expect(errorsParser.toString({ "keyname": ["1", "2"] })).toEqual "1\n2\n"
it "returns all elements in all hash keys provided", ->
expect(errorsParser.toString({ "keyname1": ["1", "2"], "keyname2": ["3", "4"] })).toEqual "1\n2\n3\n4\n"

View File

@@ -0,0 +1,40 @@
# frozen_string_literal: true
require 'spec_helper'
require 'open_food_network/i18n_inflections'
describe OpenFoodNetwork::I18nInflections do
let(:subject) { described_class }
it "returns the same word if no plural is known" do
expect(subject.pluralize("foo", 2)).to eq "foo"
end
it "finds the plural of a word" do
expect(subject.pluralize("bunch", 2)).to eq "bunches"
end
it "finds the singular of a word" do
expect(subject.pluralize("bunch", 1)).to eq "bunch"
end
it "ignores upper case" do
expect(subject.pluralize("Bunch", 2)).to eq "bunches"
end
it "switches locales" do
skip "French plurals not available yet"
I18n.with_locale(:fr) do
expect(subject.pluralize("bouquet", 2)).to eq "bouquets"
end
end
it "builds the lookup table once" do
# Cache the table:
subject.pluralize("bunch", 2)
# Expect only one call for the plural:
expect(I18n).to receive(:t).once.and_call_original
subject.pluralize("bunch", 2)
end
end

View File

@@ -0,0 +1,72 @@
# frozen_string_literal: true
require 'spec_helper'
describe Checkout::FormDataAdapter do
describe '#order_params' do
let(:params) { { order: { order_id: "123" } } }
let(:order) { create(:order) }
let(:user) { create(:user) }
let(:adapter) { Checkout::FormDataAdapter.new(params, order, user) }
it "returns the :order item in the params provided" do
order_params = adapter.order_params
expect(order_params).to eq params[:order]
end
describe "when payment_attributes are provided" do
before { params[:order][:payments_attributes] = [{ payment_method_id: "123" }] }
describe "and source attributes are provided" do
let(:source_attributes) { { payment_method_name: "Pay at the farm" } }
before { params[:payment_source] = { "123" => source_attributes } }
it "moves payment source attributes to the order payment attributes" do
order_params = adapter.order_params
expect(order_params[:payments_attributes].
first[:source_attributes]).to eq source_attributes
end
end
describe "and order total is not zero" do
before { order.total = "50.0" }
it "sets the payment attributes amount to the order total" do
order_params = adapter.order_params
expect(order_params[:payments_attributes].first[:amount]).to eq order.total
end
end
describe "and existing credit card is provided" do
before { params[:order][:existing_card_id] = credit_card.id }
describe "and credit card is owned by current user" do
let(:credit_card) { create(:credit_card, user_id: user.id) }
before { params[:order][:existing_card_id] = credit_card.id }
it "adds card details to payment attributes" do
order_params = adapter.order_params
expect(order_params[:payments_attributes].first[:source][:id]).to eq credit_card.id
expect(order_params[:payments_attributes].
first[:source][:last_digits]).to eq credit_card.last_digits
end
end
describe "and credit card is not owned by current user" do
let(:credit_card) { create(:credit_card) }
it "raises exception if credit card provided doesnt belong to the current user" do
expect { adapter.order_params }.to raise_error Spree::Core::GatewayError
end
end
end
end
end
end

View File

@@ -0,0 +1,47 @@
# frozen_string_literal: true
require 'spec_helper'
describe Checkout::PaymentRedirect do
describe '#order_params' do
let(:params) { { order: { order_id: "123" } } }
let(:redirect) { Checkout::PaymentRedirect.new(params) }
it "returns nil if payment_attributes are not provided" do
expect(redirect.path).to be nil
end
describe "when payment_attributes are provided" do
it "raises an error if payment method does not exist" do
params[:order][:payments_attributes] = [{ payment_method_id: "123" }]
expect { redirect.path }.to raise_error ActiveRecord::RecordNotFound
end
describe "when payment method provided exists" do
before { params[:order][:payments_attributes] = [{ payment_method_id: payment_method.id }] }
describe "and the payment method is not a paypal payment method" do
let(:payment_method) { create(:payment_method) }
it "returns nil" do
expect(redirect.path).to be nil
end
end
describe "and the payment method is a paypal method" do
let(:distributor) { create(:distributor_enterprise) }
let(:payment_method) do
Spree::Gateway::PayPalExpress.create!(name: "PayPalExpress",
distributor_ids: [distributor.id])
end
it "returns the redirect path" do
expect(redirect.path).to include payment_method.id.to_s
end
end
end
end
end
end

View File

@@ -0,0 +1,35 @@
# frozen_string_literal: true
require 'spec_helper'
describe UserDefaultAddressSetter do
let(:customer_address) { create(:address, address1: "customer road") }
let(:order_address) { create(:address, address1: "order road") }
let(:customer) do
create(:customer, bill_address: customer_address, ship_address: customer_address)
end
let(:order) do
create(:order, customer: customer, bill_address: order_address, ship_address: order_address)
end
let(:user) { create(:user) }
let(:setter) { UserDefaultAddressSetter.new(order, user) }
describe '#set_default_bill_address' do
it "sets the user and customer bill address to the order bill address" do
setter.set_default_bill_address
expect(user.bill_address).to eq order.bill_address
expect(order.customer.bill_address).to eq order.bill_address
end
end
describe '#set_default_ship_address' do
it "sets the user and customer ship address to the order ship address" do
setter.set_default_ship_address
expect(user.ship_address).to eq order.ship_address
expect(order.customer.ship_address).to eq order.ship_address
end
end
end