Compare commits

...

279 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
Pau Pérez Fabregat
be19d50639 Merge pull request #4768 from openfoodfoundation/transifex
Transifex
2020-02-06 11:11:23 +01:00
Transifex-Openfoodnetwork
0ceb8ab6c4 Updating translations for config/locales/ca.yml 2020-02-06 21:09:16 +11:00
Pau Pérez Fabregat
e387c7db83 Merge pull request #4548 from luisramos0/improve_truncate_data
Improve truncate data process
2020-02-06 11:01:36 +01:00
Pau Pérez Fabregat
d5df48f3c0 Merge pull request #4737 from openfoodfoundation/transifex
Transifex
2020-02-06 11:00:46 +01:00
Pau Pérez Fabregat
c9abdac2e0 Merge pull request #4722 from mkllnk/code-climate-rubocop
Bump Code Climate's Rubocop version to their latest
2020-02-06 10:32:46 +01:00
Transifex-Openfoodnetwork
ff08d9f210 Updating translations for config/locales/nb.yml 2020-02-06 09:39:52 +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
9313a57d19 Merge pull request #4511 from luisramos0/backend_ctrl_search
Bring spree_backend search controller to OFN
2020-02-05 15:54:30 +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
luisramos0
b0f2e01c70 Delete extra inventory_units that are for some unknown reason connected to shipments of orders to delete but not to orders to delete 2020-02-05 16:30:14 +11:00
Maikel
747be81aec Link to new release template 2020-02-05 15:21:26 +11:00
Maikel
fd124daf50 Add task to notify instance managers of upcoming changes 2020-02-05 14:58:57 +11:00
Transifex-Openfoodnetwork
ef33d27e6c Updating translations for config/locales/en_FR.yml 2020-02-05 06:55:27 +11:00
Transifex-Openfoodnetwork
3a01e00d7b Updating translations for config/locales/fr.yml 2020-02-05 06:51:14 +11:00
Luis Ramos
81103f3f71 Merge pull request #4742 from CSCI-462-01-2020/Issue4109
Edit new_resource partial
2020-02-04 19:44:16 +00: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
Luis Ramos
a8b48a561f Merge pull request #4733 from lin-d-hop/master
Fixing incorrect payment and balance calculation
2020-02-04 18:11:48 +00:00
Luis Ramos
c7038f6ac9 Merge pull request #4620 from luisramos0/spree_backend_css
Bring basic CSS rules from spree backend
2020-02-04 18:06:15 +00:00
Luis Ramos
ea75714561 Merge pull request #4635 from luisramos0/main_app_routes
Replace use of spree.root_path and root_url with main_app.root_path and main_app.root_url
2020-02-04 16:02:48 +00:00
luisramos0
b7d19dd34c Remove unused route from Spree.routes 2020-02-04 14:55:34 +00:00
luisramos0
44d1b3f00c Remove unused search/users controller action 2020-02-04 14:55:34 +00:00
luisramos0
f8376c0aeb Remove unused route search_customer_addresses 2020-02-04 14:55:34 +00:00
luisramos0
88464d58c2 Fix some rubocop issues and extract ransack hash to reduce repetition 2020-02-04 14:55:34 +00:00
luisramos0
962779bba1 Merge search controller with decorator 2020-02-04 14:54:51 +00:00
luisramos0
1ae73dd6ae Add search_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-02-04 14:54:51 +00:00
luisramos0
f48ab57782 Add explicit css import statements where they are needed 2020-02-04 14:52:44 +00:00
luisramos0
8b6ebfb351 Add imports for new css files from spree_backend 2020-02-04 14:52:44 +00:00
luisramos0
9c0788c3e0 Bring shared css rules from spree_backend 2020-02-04 14:52:17 +00:00
luisramos0
f61258d0b4 Bring components css from spree_backend
pagination and navigation rules were merged
2020-02-04 14:52:17 +00:00
luisramos0
289f62f115 Bring and require date picker css from spree_backend 2020-02-04 14:52:17 +00:00
luisramos0
c3a98d5a4f Bring css dependencies from spree_backend
These dependencies are in spree_core so we dont need to bring them to ofn right now
2020-02-04 14:52:17 +00:00
Luis Ramos
d8374e9caa Merge pull request #4614 from luisramos0/base_admin_js
Bring some basic js functions and dependencies from spree_backend
2020-02-04 14:48:38 +00:00
luisramos0
0648f23e94 Move css dependencies to specific css files and add some required dependencies from spree_backend 2020-02-04 14:47:51 +00:00
luisramos0
e37cb2d63f Remove underscope from select2 css file name 2020-02-04 14:47:51 +00:00
luisramos0
ee64238bdd Add jquery.adaptivemenu require but commeent out the activation for now because it is already called in spree_backend
This can be reverted when spree_backend is removed
2020-02-04 14:47:51 +00:00
luisramos0
d3130e111f Remove on click events
These events can only be added to OFN when spree_backend is removed otherwise the evetns will be registered twice
2020-02-04 14:47:51 +00:00
luisramos0
93f4eee887 Make newly imported js files compatible with the karma build 2020-02-04 14:47:51 +00:00
luisramos0
408ada9097 Remove unnecessary build exception 2020-02-04 14:47:51 +00:00
luisramos0
e14ebd9503 Add required variables from spree_backend 2020-02-04 14:47:51 +00:00
luisramos0
289b99c30e Bring and require equalize from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
f85c36a17e Bring and require select2 from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
4715df3258 Bring and require jquery.horizontalNav.js from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
b20be101cc Bring and require spin from spree_backend and respective progress indicator js and css 2020-02-04 14:47:26 +00:00
luisramos0
d424987587 Bring and require jquery.vAlign.js from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
a0575430dd Require spree.js from spree_core for some basic functions like Spree.url 2020-02-04 14:46:57 +00:00
luisramos0
c1e6344b18 Merge spree js function and override 2020-02-04 14:46:57 +00:00
luisramos0
ed0198382f Bring spree_backend admin.js.erb, rename it to base.js.erb and remove requires that are not used in ofn 2020-02-04 14:46:57 +00:00
blainebillings
577fb88843 Move Create and Cancel References to Actions Namespace 2020-02-04 09:39:01 -05:00
Pau Pérez Fabregat
2b879221b2 Merge pull request #4756 from kristinalim/fix/4489-flaky_spec_for_editing_oc
4489 Flaky spec when editing outgoing exchanges in OC
2020-02-04 15:38:37 +01:00
blainebillings
22db2e99f0 Merge branch 'Issue4109' of https://github.com/CSCI-462-01-2020/openfoodnetwork into Issue4109 2020-02-04 09:38:19 -05:00
blainebillings
ef4aa488c3 Moves Create and Cancel References to Actions Namespace 2020-02-04 09:34:28 -05:00
Pau Pérez Fabregat
57775f49bc Merge pull request #4739 from openfoodfoundation/dependabot/bundler/rack-mini-profiler-1.1.6
Bump rack-mini-profiler from 1.1.4 to 1.1.6
2020-02-04 15:29:20 +01:00
Pau Pérez Fabregat
e8a12d9897 Merge pull request #4738 from openfoodfoundation/dependabot/bundler/oj-3.10.2
Bump oj from 3.10.1 to 3.10.2
2020-02-04 15:28:40 +01:00
Pau Pérez Fabregat
f3b8d5b868 Merge pull request #4741 from openfoodfoundation/dependabot/bundler/bugsnag-6.13.0
Bump bugsnag from 6.12.2 to 6.13.0
2020-02-04 15:28:00 +01:00
Pau Pérez Fabregat
246235b921 Merge pull request #4667 from Matt-Yorkley/rails-4-prep
Rails 4 prep
2020-02-04 15:20:28 +01:00
Luis Ramos
0ded41afee Merge pull request #4513 from luisramos0/backend_ctrl_orders
Bring spree_backend orders controller to OFN
2020-02-04 11:51:54 +00:00
luisramos0
d32e106bf0 Add partials needed in the orders edit page 2020-02-04 11:51:13 +00:00
luisramos0
bbb3748d3c Simplify orders events logic 2020-02-04 11:51:13 +00:00
luisramos0
08dd992344 Merge orders_helper with decorator 2020-02-04 11:51:13 +00:00
luisramos0
914244a1ee Bring orders helper from spree_backend 2020-02-04 11:51:13 +00:00
luisramos0
e5f089610c Bring admin orders routes from spree_backend 2020-02-04 11:51:13 +00:00
luisramos0
6e26841817 Fix load_order before filter and remove unused open and close adjustments actions 2020-02-04 11:50:44 +00:00
luisramos0
ab60c4a9dd Remove unnecessary index action override because this is no longer a decorator
Remove useless todo comment
2020-02-04 11:50:44 +00:00
luisramos0
7009cd89e0 Fix rubocop issues in customer details controller and update rubocop manual todo accordingly 2020-02-04 11:50:44 +00:00
luisramos0
b93af37ea9 Merge customer details decorator with controller 2020-02-04 11:50:03 +00:00
luisramos0
76b6a85509 Merge spree/admin/orders_controller and its decorator and fix a few rubocop issues 2020-02-04 11:50:03 +00:00
luisramos0
a1d4b4ee98 Add orders_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-02-04 11:50:03 +00:00
luisramos0
51bca7ce2f Add customer_details_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-02-04 11:50:03 +00:00
Luis Ramos
70147f908a Merge pull request #4611 from luisramos0/taxonomies_js
Bring js code to make taxonomies admin work without spree_backend
2020-02-04 11:47:27 +00:00
Luis Ramos
c4bf4f001f Merge pull request #4509 from luisramos0/backend_ctrl_payments
Bring spree_backend payments controller to OFN
2020-02-04 11:46:23 +00:00
Matt-Yorkley
7d71f21753 Add frozen_string_literal comment to new class 2020-02-04 11:11:24 +01:00
Matt-Yorkley
285c78a5e4 Remove use of #pluck and ensure subquery does not include all columns 2020-02-04 11:10:13 +01:00
luisramos0
6e78ae762a Make it work even if preferred_enterprise_id is null 2020-02-04 10:01:18 +00:00
luisramos0
9a2ad16926 Make explicit the dependency to font-awesome css rules 2020-02-04 09:34:59 +00:00
luisramos0
afec21eb3d Move imports to where they are needed 2020-02-04 09:34:59 +00:00
luisramos0
651ee720c6 Remove underscore from new jstree css file 2020-02-04 09:34:40 +00:00
luisramos0
2e6c5e1fad Add dependencies from spree_backend required by jstree 2020-02-04 09:34:40 +00:00
luisramos0
87366ae7fc Remove usage of jConfirm so that we dont have to bring dependency jquery.alerts from spree_backend 2020-02-04 09:33:58 +00:00
luisramos0
27aea0b277 Bring js code from spree_backend to make taxons admin work 2020-02-04 09:33:58 +00:00
luisramos0
d4edc9f20d Bring jstress css from spree_backend 2020-02-04 09:33:58 +00:00
luisramos0
6c7991be75 Bring jquery.jstree from spree_backend 2020-02-04 09:33:34 +00:00
luisramos0
3f81352df5 Bring jquery.cookie from spree_backend 2020-02-04 09:33:34 +00:00
Kristina Lim
9d0e26ae28 Wait for products panel to show in outgoing exchanges feature spec 2020-02-04 16:20:47 +08:00
Luis Ramos
d80554a14a Merge pull request #4744 from luisramos0/oc_pag_bug
Make pagination optional in the ExchangeProductsController
2020-02-03 17:19:06 +00:00
luisramos0
a5fe5fb448 Remove usage of deleted const DEFAULT_PAGE
If params[:page] is not in the request, the results will not be paginated now
2020-02-03 15:04:34 +00:00
luisramos0
4c51d60bfd Make pagination optional in the ExchangeProductsController 2020-02-03 13:11:26 +00:00
blainebillings
9218008530 Edit new_resource Partial 2020-02-02 11:22:54 -05:00
myersca1
f36c5b8938 Edit new_resource partial 2020-02-02 11:19:10 -05:00
dependabot-preview[bot]
67199fd2d6 Bump bugsnag from 6.12.2 to 6.13.0
Bumps [bugsnag](https://github.com/bugsnag/bugsnag-ruby) from 6.12.2 to 6.13.0.
- [Release notes](https://github.com/bugsnag/bugsnag-ruby/releases)
- [Changelog](https://github.com/bugsnag/bugsnag-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bugsnag/bugsnag-ruby/compare/v6.12.2...v6.13.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-31 19:15:09 +00:00
Transifex-Openfoodnetwork
18d17ec674 Updating translations for config/locales/fr_CA.yml 2020-02-01 04:02:53 +11:00
Transifex-Openfoodnetwork
3981ee7ec1 Updating translations for config/locales/en_CA.yml 2020-02-01 03:54:02 +11:00
Luis Ramos
a0475ee8a4 Merge pull request #4613 from luisramos0/autocomplete
Bring remaining variants autocomplete (and related) JS code from spree_backend
2020-01-31 16:08:50 +00:00
Luis Ramos
4cdc604f45 Merge pull request #4718 from luisramos0/variant_count
Make Order Cycle exchange tab summary not count inventory variants that are hidden
2020-01-31 16:03:21 +00:00
Luis Ramos
dbf44c41b2 Merge pull request #4657 from luisramos0/pi-xls
Remove Product import code for xls suppport
2020-01-31 12:12:25 +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]
25c4aed368 Bump rack-mini-profiler from 1.1.4 to 1.1.6
Bumps [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler) from 1.1.4 to 1.1.6.
- [Release notes](https://github.com/MiniProfiler/rack-mini-profiler/releases)
- [Changelog](https://github.com/MiniProfiler/rack-mini-profiler/blob/master/CHANGELOG.md)
- [Commits](https://github.com/MiniProfiler/rack-mini-profiler/compare/v1.1.4...v1.1.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-30 19:28:45 +00:00
dependabot-preview[bot]
c5a6ef673c Bump oj from 3.10.1 to 3.10.2
Bumps [oj](https://github.com/ohler55/oj) from 3.10.1 to 3.10.2.
- [Release notes](https://github.com/ohler55/oj/releases)
- [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/ohler55/oj/compare/v3.10.1...v3.10.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-30 19:26:07 +00:00
Transifex-Openfoodnetwork
79ba15fe9a Updating translations for config/locales/en_GB.yml 2020-01-31 03:53:48 +11:00
luisramos0
e192207f4e Fix bug in before filters migration, needs to load payment for the show action 2020-01-30 10:27:26 +00: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
lin-d-hop
baf1ecb436 Fixing incorrect payment and balance calculation
Corrections and added specs
2020-01-29 16:06:06 +00:00
luisramos0
947914724a Add frozen string literal magic comment 2020-01-28 18:02:58 +00:00
luisramos0
b5004f1cbf Add specs for ExchangeProductsRenderer#exchange_variants 2020-01-28 18:02:58 +00:00
luisramos0
4596399bc2 Extract logic from controller to renderer service
Re-using the filter_visible method for both products and variants
2020-01-28 18:02:58 +00:00
luisramos0
685abccb61 Make variant count consider oc config and not count variants that are hidden in the inventory of the coordinator of the OC 2020-01-28 18:02:58 +00:00
luisramos0
9254928656 Remove underscore from product_autocomplete css file 2020-01-28 13:53:04 +00:00
luisramos0
228997c35b Add handlebars dependency from spree_backend 2020-01-28 13:53:04 +00:00
luisramos0
667f44336d Remove unused split logic from variant autocomplete, the split functionality is not used in ofn because we only have one stock location 2020-01-28 13:53:04 +00:00
luisramos0
0a136ff2fb Comment out click event registration as this will duplicate events until the spree_backend code is there
These can be activated when spree_backend is removed
2020-01-28 13:53:04 +00:00
luisramos0
3f3577e73c Remove encoding tag from admin/spree/orders js files 2020-01-28 13:53:04 +00:00
luisramos0
cf1664bed3 Bring some variant autocomplete styling from spree_backend 2020-01-28 13:53:04 +00:00
luisramos0
b8aee4e857 Bring address_states as is from spre_backend 2020-01-28 13:53:04 +00:00
luisramos0
cfe3435851 Bring shipments.js as is from spree_backend 2020-01-28 13:53:04 +00:00
luisramos0
53e342ba1a Bring variant_autocomplete from spree_backend as is 2020-01-28 13:53:04 +00:00
luisramos0
6bdb14248c Require lodash.underscore to support _. calls in js
spree_backend relies on Underscore.js 1.4.4, from Jan 2013, in some auto complete functions, here we will be depending on Lo-Dash 2.4.1, from Dec 2013
2020-01-28 13:53:03 +00:00
luisramos0
8e27291b15 require handlebars extensions from spree_core to allow translations inside handlebar templates 2020-01-28 13:52:19 +00:00
Maikel Linke
ec67736dff Bump Code Climate's Rubocop version to their latest
Our used version is still higher than that.
2020-01-28 17:12:28 +11:00
luisramos0
766303b332 Add required payment_helper from spree_backend 2020-01-22 20:22:28 +00:00
luisramos0
74226fbdf8 Fix one rubocop issue and update rubocop todo manual for the new controller 2020-01-22 20:22:28 +00:00
luisramos0
dc5374e284 Merge filter_payment_methods and load_data 2020-01-22 20:21:21 +00:00
luisramos0
f6ecf57737 Make before filters easier to understand using the fact that there are only index, create, new and fire actions in this controller 2020-01-22 20:21:21 +00:00
luisramos0
940953b043 Add missing translations for payments 2020-01-22 20:21:21 +00:00
luisramos0
fbc5887fa6 Bring payments routes from spree_backend 2020-01-22 20:21:21 +00:00
luisramos0
61ce849546 Merge spree/admin/payments_controller with its decorator and fix a few rubocop issues 2020-01-22 20:21:21 +00:00
luisramos0
afddaed9fc Add empty but needed payments templates for check payment method 2020-01-22 20:21:21 +00:00
luisramos0
12158d73fa Add payments_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-01-22 20:21:21 +00:00
Matt-Yorkley
5f3abbf00e Refactor BaseController 2020-01-22 12:17:23 +01:00
Matt-Yorkley
a02c58e231 Add join_table to enterprise groups relation
has_and_belongs_to_many relationships now require a join_table
2020-01-22 12:17:23 +01:00
Matt-Yorkley
59ebfb9bd4 Fix subquery errors triggered by #warn_invalid_order_cycles 2020-01-22 12:17:23 +01:00
Matt-Yorkley
57ca1d54bb Fix issue with each_serializer not being called in some cases in Rails 4. 2020-01-22 12:17:23 +01:00
luisramos0
138248e1c9 Product import only works with csv right now. Here we remove dead code
This can be reverted if we start suppporting xls and ods in the future
2020-01-16 09:59:27 +00:00
luisramos0
5fccd5fe58 Add rubocop exception for application controller class length and fix one line length issue 2020-01-12 19:42:07 +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
luisramos0
4658b7a533 Fix rubocop issues in app/controllers/application_controller 2019-12-28 19:10:02 +00:00
luisramos0
d0f33e7c8a Avoid code in devise that is not needed and simply return the root path
This fixes a broken spec with error "No route matches {:controller=>"home"}"
2019-12-28 18:47:14 +00:00
luisramos0
55bb328d48 Prefix all calls to root_url with main_app 2019-12-28 18:46:50 +00:00
luisramos0
a8a6fce385 Prefix root_path with main_app so that ofn's route is used. The spree root path will no longer be defined when spree_backend is dropped 2019-12-28 18:45:57 +00:00
luisramos0
60677a2414 Make login nav use main_app router 2019-12-28 18:41:16 +00:00
169 changed files with 16014 additions and 1152 deletions

View File

@@ -2,7 +2,7 @@ version: "2"
plugins:
rubocop:
enabled: true
channel: "rubocop-0-57"
channel: "rubocop-0-76"
config:
file: ".rubocop_styleguide.yml"
scss-lint:

View File

@@ -1,7 +1,7 @@
---
name: Release task
about: Track the process of a new release
title: ''
title: 'Release v'
labels: ''
assignees: ''
@@ -10,10 +10,13 @@ assignees: ''
Steps:
- [ ] Include translations
- [ ] Draft: https://github.com/openfoodfoundation/openfoodnetwork/releases/new <!-- replace the URL -->
- [ ] [Draft new release]
- [ ] Notify #instance-managers of user-facing changes.
- [ ] Test: https://semaphoreci.com/openfoodfoundation/openfoodnetwork-2/branches/master <!-- replace the URL -->
- [ ] Publish and notify #global-community
- [ ] Deploy and notify #instance-managers
- [ ] Nudge next release manager
The full process is described at https://github.com/openfoodfoundation/openfoodnetwork/wiki/Releasing.
[Draft new release]: https://github.com/openfoodfoundation/openfoodnetwork/releases/new?tag=v&title=v+Code+Name&body=Congrats%0A%0ADescription%0A%0A%23%23+User+facing+changes+:eyes:%0A%0A%0A%0A%23%23+Technical+changes+:wrench:%0A%0A

View File

@@ -39,11 +39,8 @@ 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/application_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/admin/payments_controller_decorator.rb
- app/controllers/spree/credit_cards_controller.rb
- app/controllers/spree/paypal_controller_decorator.rb
- app/controllers/stripe/callbacks_controller.rb
@@ -356,24 +353,22 @@ 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
- app/controllers/spree/admin/image_settings_controller.rb
- app/controllers/spree/admin/orders/customer_details_controller_decorator.rb
- app/controllers/spree/admin/orders_controller_decorator.rb
- app/controllers/spree/admin/orders/customer_details_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/overview_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/payments_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/search_controller_decorator.rb
- app/controllers/spree/admin/search_controller.rb
- 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
@@ -495,8 +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/payments_controller_decorator.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/orders_controller.rb
- app/helpers/checkout_helper.rb
@@ -526,8 +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/payments_controller_decorator.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/orders_controller.rb
- app/helpers/checkout_helper.rb
@@ -564,16 +555,15 @@ 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_decorator.rb
- app/controllers/spree/admin/orders/customer_details_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/payments_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/search_controller_decorator.rb
- app/controllers/spree/admin/tax_categories_controller.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/admin/users_controller.rb
@@ -652,8 +642,10 @@ Metrics/ClassLength:
- app/controllers/admin/order_cycles_controller.rb
- app/controllers/admin/subscriptions_controller.rb
- app/controllers/api/products_controller.rb
- app/controllers/application_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/base_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb

View File

@@ -335,6 +335,7 @@ Rails/OutputSafety:
- 'app/helpers/spree/admin/zones_helper.rb'
- 'app/helpers/spree/reports_helper.rb'
- 'app/helpers/spree/admin/navigation_helper.rb'
- 'app/helpers/spree/admin/orders_helper.rb'
- 'app/serializers/api/product_serializer.rb'
- 'lib/spree/money_decorator.rb'
- 'spec/features/admin/orders_spec.rb'

34
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,34 +92,31 @@ gem 'wkhtmltopdf-binary'
gem 'foreigner'
gem 'immigrant'
gem 'roo', '~> 2.8.2'
gem 'roo-xls', '~> 1.1.0'
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)
@@ -166,7 +154,7 @@ GEM
bcrypt-ruby (3.1.5)
bcrypt (>= 3.1.3)
blockenspiel (0.5.0)
bugsnag (6.12.2)
bugsnag (6.13.0)
concurrent-ruby (~> 1.0)
builder (3.0.4)
byebug (9.0.6)
@@ -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,13 +474,13 @@ 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)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
oj (3.10.1)
oj (3.10.2)
orm_adapter (0.5.0)
paper_trail (5.2.3)
activerecord (>= 3.0, < 6.0)
@@ -530,7 +518,7 @@ GEM
rack (1.4.7)
rack-cache (1.9.0)
rack (>= 0.4)
rack-mini-profiler (1.1.4)
rack-mini-profiler (1.1.6)
rack (>= 1.2.0)
rack-protection (1.5.5)
rack
@@ -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,19 +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)
roo-xls (1.1.0)
nokogiri
roo (>= 2.0.0beta1, < 3)
spreadsheet (> 0.9.0)
rubyzip (>= 1.3.0, < 3.0.0)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
@@ -614,17 +599,17 @@ 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)
rack (>= 1.1)
rubocop (>= 0.72.0)
ruby-ole (1.2.12.1)
ruby-progressbar (1.10.1)
ruby-rc4 (0.1.5)
rubyzip (1.3.0)
@@ -653,8 +638,6 @@ GEM
tilt (>= 1.3, < 3)
spinjs-rails (1.4)
rails (>= 3.1)
spreadsheet (1.1.7)
ruby-ole (>= 1.0)
spring (1.7.2)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
@@ -665,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)
@@ -683,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)
@@ -760,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)
@@ -773,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!
@@ -790,20 +770,19 @@ DEPENDENCIES
rails_safe_tasks (~> 1.0)
redcarpet
roadie-rails (~> 1.3.0)
roo (~> 2.8.2)
roo-xls (~> 1.1.0)
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

@@ -12,6 +12,11 @@
//= require jquery.ui.all
//= require jquery-ui-timepicker-addon
//= require jquery.powertip
//= require jquery.cookie
//= require jquery.jstree/jquery.jstree
//= require jquery.vAlign
//= require jquery.horizontalNav
//= require jquery.adaptivemenu
//= require angular
//= require angular-resource
//= require angular-animate
@@ -20,13 +25,18 @@
//= require ../shared/ng-infinite-scroll.min.js
//= require ../shared/ng-tags-input.min.js
//= require angular-rails-templates
//= require lodash.underscore.js
// spree
//= require admin/spree_backend
//= require spree
//= require admin/spree/spree-select2
//= require modernizr
//= require spin
//= require equalize
//= require css_browser_selector_dev
//= require responsive-tables
//= require admin/spree_paypal_express
//= require admin/handlebar_extensions
// OFN specific
//= require_tree ../templates/admin

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

@@ -8,7 +8,7 @@ angular.module('admin.orderCycles').factory('ExchangeProduct', ($resource) ->
index: (params={}, callback=null) ->
ExchangeProductResource.index params, (data) =>
(callback || angular.noop)(data.products, data.pagination.pages, data.pagination.results)
(callback || angular.noop)(data.products, data.pagination?.pages, data.pagination?.results)
countVariants: (params={}, callback=null) ->
ExchangeProductResource.variant_count params, (data) =>

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

@@ -0,0 +1,252 @@
//= require_self
//= require admin/handlebar_extensions
//= require admin/spree/orders/variant_autocomplete
/**
This is a collection of javascript functions and whatnot
under the spree namespace that do stuff we find helpful.
Hopefully, this will evolve into a propper class.
**/
jQuery(function($) {
// Make main menu use full width
mainMenu = $('.fullwidth-menu')
if (typeof mainMenu.horizontalNav === 'function' )
mainMenu.horizontalNav({
tableDisplay: false,
responsiveDelay: 0
});
// Vertical align of checkbox fields
if (typeof $('.field.checkbox label').vAlign === 'function' )
$('.field.checkbox label').vAlign()
// 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' ) {
$('.with-tip').powerTip({
smartPlacement: true,
fadeInTime: 50,
fadeOutTime: 50,
intentPollInterval: 300
});
$('.with-tip').on({
powerTipPreRender: function(){
$('#powerTip').addClass($(this).attr("data-action"));
$('#powerTip').addClass($(this).attr("data-tip-color"));
},
powerTipClose: function(){
$('#powerTip').removeClass($(this).attr("data-action"))
}
});
}
// Make flash messages dissapear
setTimeout('$(".flash").fadeOut()', 5000);
// Highlight hovered table column
$('table tbody tr td.actions a').hover(function(){
var tr = $(this).closest('tr');
var klass = 'highlight action-' + $(this).attr('data-action')
tr.addClass(klass)
tr.prev().addClass('before-' + klass);
}, function(){
var tr = $(this).closest('tr');
var klass = 'highlight action-' + $(this).attr('data-action')
tr.removeClass(klass)
tr.prev().removeClass('before-' + klass);
});
// Trunkate text in page_title that didn't fit
var truncate_elements = $('.truncate');
truncate_elements.each(function(){
$(this).trunk8();
});
$(window).resize(function (event) {
truncate_elements.each(function(){
$(this).trunk8();
})
});
// Make height of dt/dd elements the same
if (typeof $("dl").equalize === 'function' )
$("dl").equalize('outerHeight');
});
$.fn.visible = function(cond) { this[cond ? 'show' : 'hide' ]() };
// Overriding a broken function in Spree. Bug report at
// https://github.com/spree/spree/issues/4032
show_flash_error = function(message) {
error_div = $('.flash.error');
if (error_div.length > 0) {
error_div.html(message);
error_div.show();
} else {
if ($("#content .toolbar").length > 0) {
$("#content .toolbar").before('<div class="flash error">' + message + '</div>');
} else {
$("#progress").before('<div class="flash error">' + message + '</div>');
}
}
}
// Apply to individual radio button that makes another element visible when checked
$.fn.radioControlsVisibilityOfElement = function(dependentElementSelector){
if(!this.get(0)){ return }
showValue = this.get(0).value;
radioGroup = $("input[name='" + this.get(0).name + "']");
radioGroup.each(function(){
$(this).click(function(){
$(dependentElementSelector).visible(this.checked && this.value == showValue)
});
if(this.checked){ this.click() }
});
}
$(document).ready(function() {
if (typeof Spree !== 'undefined') {
handle_date_picker_fields = function(){
$('.datepicker').datepicker({
dateFormat: Spree.translations.date_picker,
dayNames: Spree.translations.abbr_day_names,
dayNamesMin: Spree.translations.abbr_day_names,
monthNames: Spree.translations.month_names,
prevText: Spree.translations.previous,
nextText: Spree.translations.next,
showOn: "focus"
});
// Correctly display range dates
$('.date-range-filter .datepicker-from').datepicker('option', 'onSelect', function(selectedDate) {
$(".date-range-filter .datepicker-to" ).datepicker( "option", "minDate", selectedDate );
});
$('.date-range-filter .datepicker-to').datepicker('option', 'onSelect', function(selectedDate) {
$(".date-range-filter .datepicker-from" ).datepicker( "option", "maxDate", selectedDate );
});
}
handle_date_picker_fields();
}
$(".observe_field").on('change', function() {
target = $(this).attr("data-update");
ajax_indicator = $(this).attr("data-ajax-indicator") || '#busy_indicator';
$(target).hide();
$(ajax_indicator).show();
$.ajax({ dataType: 'html',
url: $(this).attr("data-base-url")+encodeURIComponent($(this).val()),
type: 'get',
success: function(data){
$(target).html(data);
$(ajax_indicator).hide();
$(target).show();
}
});
});
$('.spree_add_fields').click(function() {
var target = $(this).data("target");
var new_table_row = $(target + ' tr:visible:last').clone();
var new_id = new Date().getTime();
new_table_row.find("input, select").each(function () {
var el = $(this);
el.val("");
if (typeof el.attr("id") !== 'undefined') el.attr("id", el.attr("id").replace(/\d+/, new_id))
if (typeof el.attr("name") !== 'undefined') el.attr("name", el.attr("name").replace(/\d+/, new_id))
})
// When cloning a new row, set the href of all icons to be an empty "#"
// This is so that clicking on them does not perform the actions for the
// duplicated row
new_table_row.find("a").each(function () {
var el = $(this);
el.attr('href', '#');
})
$(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() {
$(this).width($(this).width());
});
return ui;
};
$('table.sortable').ready(function(){
var td_count = $(this).find('tbody tr:first-child td').length
if (typeof $('table.sortable tbody').sortable !== 'function' )
return
$('table.sortable tbody').sortable(
{
handle: '.handle',
helper: fixHelper,
placeholder: 'ui-sortable-placeholder',
update: function(event, ui) {
$("#progress").show();
positions = {};
$.each($('table.sortable tbody tr'), function(position, obj){
reg = /spree_(\w+_?)+_(\d+)/;
parts = reg.exec($(obj).attr('id'));
if (parts) {
positions['positions['+parts[2]+']'] = position;
}
});
$.ajax({
type: 'POST',
dataType: 'script',
url: $(ui.item).closest("table.sortable").data("sortable-link"),
data: positions,
success: function(data){ $("#progress").hide(); }
});
},
start: function (event, ui) {
// Set correct height for placehoder (from dragged tr)
ui.placeholder.height(ui.item.height())
// Fix placeholder content to make it correct width
ui.placeholder.html("<td colspan='"+(td_count-1)+"'></td><td class='actions'></td>")
},
stop: function (event, ui) {
// Fix odd/even classes after reorder
$("table.sortable tr:even").removeClass("odd even").addClass("even");
$("table.sortable tr:odd").removeClass("odd even").addClass("odd");
}
});
});
});

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

@@ -0,0 +1,27 @@
var update_state = function(region) {
var country = $('span#' + region + 'country .select2').select2('val');
var state_select = $('span#' + region + 'state select.select2');
var state_input = $('span#' + region + 'state input.state_name');
$.get(Spree.routes.states_search + "?country_id=" + country, function(data) {
var states = data["states"]
if (states.length > 0) {
state_select.html('');
var states_with_blank = [{name: '', id: ''}].concat(states);
$.each(states_with_blank, function(pos,state) {
var opt = $(document.createElement('option'))
.attr('value', state.id)
.html(state.name);
state_select.append(opt);
});
state_select.prop("disabled", false).show();
state_select.select2();
state_input.hide().prop("disabled", true);
} else {
state_input.prop("disabled", false).show();
state_select.select2('destroy').hide();
}
})
};

View File

@@ -0,0 +1,64 @@
// Shipments AJAX API
$(document).ready(function() {
handle_ship_click = function(){
var link = $(this);
var shipment_number = link.data('shipment-number');
var url = Spree.url( Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipment_number + "/ship.json");
$.ajax({
type: "PUT",
url: url
}).done(function( msg ) {
window.location.reload();
}).error(function( msg ) {
console.log(msg);
});
}
$('[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);
handle_shipping_method_save = function(){
var link = $(this);
var shipment_number = link.data('shipment-number');
var selected_shipping_rate_id = link.parents('tbody').find("select#selected_shipping_rate_id[data-shipment-number='" + shipment_number + "']").val();
var unlock = link.parents('tbody').find("input[name='open_adjustment'][data-shipment-number='" + shipment_number + "']:checked").val();
var url = Spree.url( Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipment_number + ".json");
$.ajax({
type: "PUT",
url: url,
data: { shipment: { selected_shipping_rate_id: selected_shipping_rate_id, unlock: unlock } }
}).done(function( msg ) {
window.location.reload();
}).error(function( msg ) {
console.log(msg);
});
}
$('[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);
handle_tracking_save = function(){
var link = $(this);
var shipment_number = link.data('shipment-number');
var tracking = link.parents('tbody').find('input#tracking').val();
var url = Spree.url( Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipment_number + ".json");
$.ajax({
type: "PUT",
url: url,
data: { shipment: { tracking: tracking } }
}).done(function( msg ) {
window.location.reload();
}).error(function( msg ) {
console.log(msg);
});
}
$('[data-hook=admin_order_edit_form] a.save-tracking').click(handle_tracking_save);
});

View File

@@ -0,0 +1,141 @@
// variant autocompletion
$(document).ready(function() {
if ($('#variant_autocomplete_template').length > 0) {
window.variantTemplate = Handlebars.compile($('#variant_autocomplete_template').text());
window.variantStockTemplate = Handlebars.compile($('#variant_autocomplete_stock_template').text());
// handle variant selection, show stock level.
$('#add_variant_id').change(function(){
var variant_id = $(this).val();
var variant = _.find(window.variants, function(variant){
return variant.id == variant_id
})
$('#stock_details').html(variantStockTemplate({variant: variant}));
$('#stock_details').show();
$('button.add_variant').click(addVariantFromStockLocation);
// Add some tips
$('.with-tip').powerTip({
smartPlacement: true,
fadeInTime: 50,
fadeOutTime: 50,
intentPollInterval: 300
});
});
//handle edit click
$('a.edit-item').click(toggleItemEdit);
//handle cancel click
$('a.cancel-item').click(toggleItemEdit);
handle_save_click = function(){
var save = $(this);
var shipment_number = save.data('shipment-number');
var variant_id = save.data('variant-id');
var quantity = parseInt(save.parents('tr').find('input.line_item_quantity').val());
toggleItemEdit();
adjustItems(shipment_number, variant_id, quantity);
return false;
}
$('a.save-item').click(handle_save_click);
handle_delete_click = function(){
var del = $(this);
var shipment_number = del.data('shipment-number');
var variant_id = del.data('variant-id');
toggleItemEdit();
adjustItems(shipment_number, variant_id, 0);
}
$('a.delete-item').click(handle_delete_click);
}
});
adjustItems = function(shipment_number, variant_id, quantity){
var shipment = _.findWhere(shipments, {number: shipment_number + ''});
var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id});
var url = Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipment_number;
var new_quantity = 0;
if(inventory_units.length<quantity){
url += "/add"
new_quantity = (quantity - inventory_units.length);
}else if(inventory_units.length>quantity){
url += "/remove"
new_quantity = (inventory_units.length - quantity);
}
url += '.json';
if(new_quantity!=0){
$.ajax({
type: "PUT",
url: Spree.url(url),
data: { variant_id: variant_id, quantity: new_quantity }
}).done(function( msg ) {
window.location.reload();
});
}
}
toggleTrackingEdit = function(){
var link = $(this);
link.parents('tbody').find('tr.edit-tracking').toggle();
link.parents('tbody').find('tr.show-tracking').toggle();
}
toggleMethodEdit = function(){
var link = $(this);
link.parents('tbody').find('tr.edit-method').toggle();
link.parents('tbody').find('tr.show-method').toggle();
}
toggleItemEdit = function(){
var link = $(this);
link.parent().find('a.edit-item').toggle();
link.parent().find('a.cancel-item').toggle();
link.parent().find('a.save-item').toggle();
link.parent().find('a.delete-item').toggle();
link.parents('tr').find('td.item-qty-show').toggle();
link.parents('tr').find('td.item-qty-edit').toggle();
return false;
}
addVariantFromStockLocation = function() {
$('#stock_details').hide();
var variant_id = $('input.variant_autocomplete').val();
var stock_location_id = $(this).data('stock-location-id');
var quantity = $("input.quantity[data-stock-location-id='" + stock_location_id + "']").val();
var shipment = _.find(shipments, function(shipment){
return shipment.stock_location_id == stock_location_id && (shipment.state == 'ready' || shipment.state == 'pending');
});
if(shipment==undefined){
$.ajax({
type: "POST",
url: Spree.url(Spree.routes.orders_api + "/" + order_number + "/shipments.json"),
data: { variant_id: variant_id, quantity: quantity, stock_location_id: stock_location_id }
}).done(function( msg ) {
window.location.reload();
}).error(function( msg ) {
console.log(msg);
});
}else{
//add to existing shipment
adjustItems(shipment.number, variant_id, quantity);
}
return 1
}

View File

@@ -0,0 +1,27 @@
$(document).ready ->
opts =
lines: 11
length: 2
width: 3
radius: 9
corners: 1
rotate: 0
color: '#fff'
speed: 0.8
trail: 48
shadow: false
hwaccel: true
className: 'spinner'
zIndex: 2e9
top: 'auto'
left: 'auto'
target = document.getElementById("spinner")
$(document).ajaxStart ->
$("#progress").fadeIn()
spinner = new Spinner(opts).spin(target)
$(document).ajaxStop ->
$("#progress").fadeOut()

View File

@@ -0,0 +1,8 @@
//= require select2
jQuery(function($) {
// Make select beautiful
if (typeof $('select.select2').select2 === 'function' )
$('select.select2').select2({
allowClear: true
});
})

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,22 @@
root = exports ? this
root.taxon_tree_menu = (obj, context) ->
base_url = Spree.url(Spree.routes.taxonomy_taxons_path)
admin_base_url = Spree.url(Spree.routes.admin_taxonomy_taxons_path)
edit_url = admin_base_url.clone()
edit_url.setPath(edit_url.path() + '/' + obj.attr("id") + "/edit");
create:
label: "<i class='icon-plus'></i> " + Spree.translations.add,
action: (obj) -> context.create(obj)
rename:
label: "<i class='icon-pencil'></i> " + Spree.translations.rename,
action: (obj) -> context.rename(obj)
remove:
label: "<i class='icon-trash'></i> " + Spree.translations.remove,
action: (obj) -> context.remove(obj)
edit:
separator_before: true,
label: "<i class='icon-edit'></i> " + Spree.translations.edit,
action: (obj) -> window.location = edit_url.toString()

View File

@@ -0,0 +1,127 @@
handle_ajax_error = (XMLHttpRequest, textStatus, errorThrown) ->
$.jstree.rollback(last_rollback)
$("#ajax_error").show().html("<strong>" + server_error + "</strong><br />" + taxonomy_tree_error)
handle_move = (e, data) ->
last_rollback = data.rlbk
position = data.rslt.cp
node = data.rslt.o
new_parent = data.rslt.np
url = Spree.url(base_url).clone()
url.setPath url.path() + '/' + node.attr("id")
$.ajax
type: "POST",
dataType: "json",
url: url.toString(),
data: ({_method: "put", "taxon[parent_id]": new_parent.attr("id"), "taxon[position]": position }),
error: handle_ajax_error
true
handle_create = (e, data) ->
last_rollback = data.rlbk
node = data.rslt.obj
name = data.rslt.name
position = data.rslt.position
new_parent = data.rslt.parent
$.ajax
type: "POST",
dataType: "json",
url: base_url.toString(),
data: ({"taxon[name]": name, "taxon[parent_id]": new_parent.attr("id"), "taxon[position]": position }),
error: handle_ajax_error,
success: (data,result) ->
node.attr('id', data.id)
handle_rename = (e, data) ->
last_rollback = data.rlbk
node = data.rslt.obj
name = data.rslt.new_name
url = Spree.url(base_url).clone()
url.setPath(url.path() + '/' + node.attr("id"))
$.ajax
type: "POST",
dataType: "json",
url: url.toString(),
data: {_method: "put", "taxon[name]": name },
error: handle_ajax_error
handle_delete = (e, data) ->
last_rollback = data.rlbk
node = data.rslt.obj
delete_url = base_url.clone()
delete_url.setPath delete_url.path() + '/' + node.attr("id")
if confirm(Spree.translations.are_you_sure_delete)
$.ajax
type: "POST",
dataType: "json",
url: delete_url.toString(),
data: {_method: "delete"},
error: handle_ajax_error
else
$.jstree.rollback(last_rollback)
last_rollback = null
root = exports ? this
root.setup_taxonomy_tree = (taxonomy_id) ->
if taxonomy_id != undefined
# this is defined within admin/taxonomies/edit
root.base_url = Spree.url(Spree.routes.taxonomy_taxons_path)
$.ajax
url: base_url.path().replace("/taxons", "/jstree"),
success: (taxonomy) ->
last_rollback = null
conf =
json_data:
data: taxonomy,
ajax:
url: (e) ->
base_url.path() + '/' + e.attr('id') + '/jstree'
themes:
theme: "apple",
url: "/assets/jquery.jstree/themes/apple/style.css"
strings:
new_node: new_taxon,
loading: Spree.translations.loading + "..."
crrm:
move:
check_move: (m) ->
position = m.cp
node = m.o
new_parent = m.np
# no parent or cant drag and drop
if !new_parent || node.attr("rel") == "root"
return false
# can't drop before root
if new_parent.attr("id") == "taxonomy_tree" && position == 0
return false
true
contextmenu:
items: (obj) ->
taxon_tree_menu(obj, this)
plugins: ["themes", "json_data", "dnd", "crrm", "contextmenu"]
$("#taxonomy_tree").jstree(conf)
.bind("move_node.jstree", handle_move)
.bind("remove.jstree", handle_delete)
.bind("create.jstree", handle_create)
.bind("rename.jstree", handle_rename)
.bind "loaded.jstree", ->
$(this).jstree("core").toggle_node($('.jstree-icon').first())
$("#taxonomy_tree a").on "dblclick", (e) ->
$("#taxonomy_tree").jstree("rename", this)
# surpress form submit on enter/return
$(document).keypress (e) ->
if e.keyCode == 13
e.preventDefault()

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

@@ -16,22 +16,6 @@ $(document).ready(function() {
});
});
// Overriding a broken function in Spree. Bug report at
// https://github.com/spree/spree/issues/4032
show_flash_error = function(message) {
error_div = $('.flash.error');
if (error_div.length > 0) {
error_div.html(message);
error_div.show();
} else {
if ($("#content .toolbar").length > 0) {
$("#content .toolbar").before('<div class="flash error">' + message + '</div>');
} else {
$("#progress").before('<div class="flash error">' + message + '</div>');
}
}
}
$(document).ready(function(){
$('a.close').click(function(event){
event.preventDefault();

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,25 +4,45 @@
* 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 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
*/
//************************************************************************//
//************************************************************************//
@import 'globals/functions';
@import 'globals/variables';
@import 'variables';
@import 'globals/mixins';
@import 'shared/typography';
@import 'shared/tables';
@import 'shared/icons';
@import 'shared/forms';
@import 'shared/layout';
@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';
@import 'hacks/ie';
@import 'variables';
@import 'components/*';
@import 'plugins/font-awesome';
@import 'pages/*';
@import '*';

View File

@@ -0,0 +1,33 @@
@import 'admin/globals/variables';
table tbody tr {
&.highlight {
@each $action in $actions {
&.action-#{$action} td {
background-color: get-value($actions, $actions-bg-colors, $action);
border-color: get-value($actions, $actions-brd-colors, $action);
}
}
&.action-remove td, &.action-void td {
text-decoration: line-through;
&.actions {
text-decoration: none;
}
}
}
&.before-highlight {
@each $action in $actions {
&.action-#{$action} td {
border-bottom-color: get-value($actions, $actions-brd-colors, $action);
}
}
}
td.actions {
background-color: transparent !important;
}
}

View File

@@ -1,12 +0,0 @@
#admin-menu {
li {
a {
font-weight: 600;
}
a::before {
font-weight: normal;
padding-top: 0;
}
}
}

View File

@@ -0,0 +1,158 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
@import 'admin/plugins/font-awesome';
.date-range-filter {
.range-divider {
padding: 0;
}
input.datepicker {
width: 96px !important;
}
}
#ui-datepicker-div {
@include border-radius($border-radius);
border-color: $color-3;
padding: 0;
margin-top: 10px;
&:before {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $color-3;
top: 0px;
margin-top: -10px;
left: 25px;
z-index: 1;
}
.ui-datepicker-header {
padding: 0;
background-image: none;
background-color: $color-3;
border: none;
border-bottom: none;
border-radius: 0;
height: 32px;
.ui-datepicker-prev, .ui-datepicker-next {
border-radius: 0;
top: 0;
height: 32px;
&:hover {
border: none;
background-image: none;
background-color: $color-3;
cursor: pointer;
}
.ui-icon {
background-image: none;
text-indent: 0;
color: $color-1;
width: 10px;
margin-left: -5px;
@extend [class^="icon-"]:before;
&:hover {
color: very-light($color-2, 25);
}
}
}
.ui-datepicker-prev {
left: 0;
.ui-icon {
@extend .icon-arrow-left;
}
}
.ui-datepicker-next {
right: 0;
.ui-icon {
@extend .icon-arrow-right;
}
&:hover {
.ui-icon {
margin-left: -5px;
}
}
}
.ui-datepicker-title {
color: $color-1;
text-transform: uppercase;
font-size: 85% !important;
padding: 6px 10px;
}
}
table.ui-datepicker-calendar {
border: none;
thead {
th {
border-bottom: 1px solid $color-border;
border-right: 1px solid $color-border;
color: $color-body-text;
width: 33px;
&:last-child {
border-right: none;
}
}
}
tbody {
tr:hover {
td {
background-color: transparent !important;
}
}
&:last-child tr:last-child td {
border-bottom: none;
}
td {
a {
border: 1px solid transparent;
background-color: $color-1;
background-image: none;
font-size: 85%;
color: $color-body-text;
&.ui-state-active {
background-color: $color-2;
color: $color-1;
}
&:hover {
background-color: $color-2;
color: $color-1;
border-color: darken($color-2, 5);
}
}
&.ui-state-disabled {
.ui-state-default {
border: none;
background-image: none;
background-color: transparent;
}
}
&.ui-datepicker-today {
a {
background-color: $color-6;
color: $color-1;
border: 1px solid darken($color-6, 5);
}
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
@import 'admin/globals/variables';
.errorExplanation {
padding: 5px;
border: 1px solid very-light($color-error, 12);
background-color: very-light($color-error, 6);
border-radius: 3px;
color: very-light($color-error, 30);
margin-bottom: 15px;
h2 {
font-size: 140%;
color: very-light($color-error, 30);
margin-bottom: 5px;
}
p {
padding: 10px 0;
}
ul {
list-style-position: inside;
li {
font-weight: $font-weight-bold;
}
}
}
.flash {
position: fixed;
top: 0;
left: 0;
width: 100%;
padding: 16px;
text-align: center;
z-index: 1000;
font-size: 120%;
color: $color-1;
font-weight: 600;
&.notice { background-color: rgba($color-notice, 0.8) }
&.success { background-color: rgba($color-success, 0.8) }
&.error { background-color: rgba($color-error, 0.8) }
}

View File

@@ -0,0 +1,162 @@
@import 'admin/globals/variables';
// Navigation
//---------------------------------------------------
.inline-menu {
margin: 0;
-webkit-margin-before: 0;
-webkit-padding-start: 0;
}
nav.menu {
ul {
list-style: none;
li {
a {
padding: 10px 0;
display: block;
position: relative;
text-align: left;
border: 1px solid transparent;
text-transform: uppercase;
font-weight: 600;
font-size: 90%;
}
&.active a {
color: $color-2;
border-left-width: 0;
border-bottom-color: $color-2;
}
&:hover a {
color: $color-2;
}
}
}
}
[data-hook="admin_login_navigation_bar"] {
ul {
text-align: right;
li {
padding: 5px 0 5px 10px;
text-align: right;
font-size: 90%;
color: $color-link;
margin-top: 8px;
&[data-hook="user-logged-in-as"] {
width: 50%;
color: $color-body-text;
}
&:hover {
i {
color: $color-2;
}
}
}
}
}
#admin-menu {
background-color: $color-3;
li {
min-width: 90px;
a {
display: block;
padding: 25px 20px;
color: $color-1 !important;
text-transform: uppercase;
position: relative;
text-align: center;
font-weight: 600;
i {
display: inline;
}
&:hover {
background-color: $color-2;
&:after {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 5px solid $color-2;
bottom: 0px;
margin-bottom: -5px;
left: 50%;
margin-left: -10px;
z-index: 1;
}
}
span.text {
font-weight: 600;
}
}
a::before {
font-weight: normal;
padding-top: 0;
}
.dropdown {
width: 300px;
background-color: $color-3;
width: 200px;
z-index: 100000;
> li {
width: 200px !important;
a:after {
display: none;
}
}
}
&.selected a {
@extend a:hover;
}
}
}
#sub-menu {
background-color: $color-2;
padding-bottom: 0;
li {
a {
display: block;
padding: 12px 20px;
color: $color-1;
text-align: center;
text-transform: uppercase;
position: relative;
font-size: 85%;
}
&.selected a, a:hover {
&:after {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 5px solid $color-2;
bottom: 0px;
margin-bottom: -5px;
left: 50%;
margin-left: -10px;
z-index: 1;
}
}
}
}

View File

@@ -1,8 +1,23 @@
@import 'admin/globals/variables';
@import "admin/variables";
.pagination {
text-align: center;
margin: 2em 0 1em;
padding: 10px 0;
.page {
padding: 5px 8px;
text-align: center;
display: inline-block;
text-align: center;
&.current {
background-color: $color-2;
border-radius: 3px;
color: $color-1;
}
}
button {
margin: 0 0.35em;

View File

@@ -0,0 +1,29 @@
.select2-result-label {
.variant-autocomplete-item {
.variant-details {
padding: 0 10px;
float: left;
}
.variant-image {
margin-top: 5px;
background-color: white;
float: left;
margin-right: 10px;
}
ul.variant-details {
li {
display: inline-block;
&:after {
content: ' / ';
}
&:last-child:after {
content: '';
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
#progress {
display: none;
position: fixed;
top: 0;
z-index: 1000;
opacity: 0.8;
width: 100%;
.wrapper {
@include border-radius(10px);
top: -10px;
position: absolute;
left: 50%;
width: 200px;
margin-left: -100px;
padding: 11px 0;
background-color: $color-3;
color: $color-1;
text-align: center;
}
#spinner {
position: absolute;
top: 10px;
left: 50%;
margin-left: -5px;
}
.progress-message {
font-size: 120%;
font-weight: $font-weight-bold;
margin-top: 20px;
text-transform: uppercase;
}
}

View File

@@ -0,0 +1,28 @@
@import 'admin/globals/variables';
// Sidebar
//---------------------------------------------------
#sidebar {
overflow: visible;
border-top: 1px solid $color-border;
margin-top: 17px;
.sidebar-title {
color: $color-2;
text-transform: uppercase;
text-align: center;
font-size: 14px;
font-weight: 600;
> span {
display: inline;
background: #fff;
padding: 5px 10px;
position: relative;
top: -14px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}

View File

@@ -0,0 +1,36 @@
@import 'admin/globals/variables';
.state {
text-transform: uppercase;
font-size: 80%;
font-weight: 600;
&:before {
content: '';
position: relative;
display: inline-block;
margin-right: 3px;
border-radius: $body-font-size/2;
width: $body-font-size - 4px;
height: $body-font-size - 4px;
}
@each $state in $states {
&.#{$state}:before {
background-color: get-value($states, $states-bg-colors, $state);
// &, a {
// color: get-value($states, $states-text-colors, $state);
// }
}
}
}
table tbody tr {
&[class*="state"] td:first-child {
border-left-width: 3px;
}
&.state-complete td:first-child { border-left-color: $color-success }
&.state-cart td:first-child { border-left-color: very-light($color-notice, 6) }
&.state-canceled td:first-child { border-left-color: $color-error }
}

View File

@@ -0,0 +1,14 @@
#table-filter {
.field {
input[type="text"], input[type="phone"],
input[type="email"], input[type="number"],
input[type="url"] {
width: 100%;
}
}
.actions {
text-align: center;
}
}

View File

@@ -0,0 +1,25 @@
// Make color very close to white
@function very-light($color, $adjust: 3){
@if type-of($adjust) == 'number' and $adjust > 0 {
@for $i from 0 through 100 {
@if lighten($color, $i) == white and ($i - $adjust) > $adjust {
@return lighten($color, $i - $adjust);
}
}
}
@else {
@debug "Please correct $adjust value. It should be number and larger then 0. Currently it is '#{type-of($adjust)}' with value '#{$adjust}'"
}
};
// Quick fix for dynamic variables missing in SASS
@function get-value($prop, $val, $search) {
$n1: index($prop, $search);
$n2: index($val, $search);
@if($n1) {
@return nth($val, $n1);
} @else {
@return nth($prop, $n2);
}
}

View File

@@ -0,0 +1,135 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
@import 'admin/plugins/font-awesome';
#taxonomy_tree {
> ul, .jstree-icon {
background-image: none;
}
.jstree-icon {
@extend [class^="icon-"]:before;
}
.jstree-open > .jstree-icon {
@extend .icon-caret-down;
}
.jstree-closed > .jstree-icon {
@extend .icon-caret-right;
}
li {
background-image: none;
a {
background-color: very-light($color-3);
border: 1px solid $color-border;
color: $color-body-text;
font-weight: $font-weight-bold;
text-shadow: none;
width: 90%;
height: auto;
line-height: inherit;
padding: 5px 0 5px 10px;
margin-bottom: 10px;
.jstree-icon {
padding-left: 0px;
@extend .icon-move;
}
}
}
}
#vakata-dragged.jstree-apple .jstree-invalid,
#vakata-dragged.jstree-apple .jstree-ok,
#jstree-marker {
background-image: none !important;
background-color: transparent !important;
@extend [class^="icon-"]:before;
}
#vakata-dragged.jstree-apple .jstree-invalid {
@extend .icon-remove;
color: $color-5;
}
#vakata-dragged.jstree-apple .jstree-ok {
@extend .icon-ok;
color: $color-2;
}
#jstree-marker {
@extend .icon-caret-right;
color: $color-body-text !important;
width: 4px !important;
}
#jstree-marker-line {
@include border-radius($border-radius !important);
height: 0px !important;
margin-left: 5px !important;
margin-top: -2px !important;
border: none !important;
border-bottom: 1px solid $color-body-text !important;
background-color: very-light($color-3) !important;
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
box-shadow: none !important;
}
#vakata-contextmenu {
background-color: $color-3 !important;
-moz-box-shadow: none !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
border: none !important;
@include border-radius($border-radius !important);
&:before {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $color-3;
top: 0px;
margin-top: -10px;
left: 25px;
z-index: 1;
}
a {
color: $color-1 !important;
line-height: inherit !important;
padding: 5px 10px !important;
margin: 0 !important;
font-size: 90% !important;
&:hover {
@include border-radius($border-radius !important);
background-color: $color-2 !important;
border: none !important;
-moz-box-shadow: none !important;
-webkit-box-shadow: none !important;
line-height: inherit !important;
padding: 5px 10px !important;
margin: 0 !important;
}
}
li:first-child a:hover:before {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $color-2;
top: 0px;
margin-top: -10px;
left: 25px;
z-index: 1;
}
li.vakata-separator {
display: none;
}
}

View File

@@ -0,0 +1,193 @@
@import 'admin/globals/functions';
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
@import 'admin/shared/forms';
@import 'admin/plugins/font-awesome';
.select2-container {
&:hover .select2-choice, &.select2-container-active .select2-choice {
background-color: $color-sel-hover-bg !important;
border-color: $color-sel-hover-bg !important;
}
.select2-choice {
background-image: none !important;
background-color: $color-sel-bg;
border: none !important;
box-shadow: none !important;
@include border-radius($border-radius);
color: $color-1 !important;
font-size: 90%;
height: 31px;
line-height: inherit !important;
padding: 5px 15px 7px;
span {
display: block;
padding: 2px;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 100% !important;
@extend .icon-remove;
@extend [class^="icon-"]:before;
margin-top: 2px;
}
}
&.select2-container-active {
.select2-choice {
box-shadow: none !important;
}
&.select2-dropdown-open .select2-choice div b {
@extend .icon-caret-up
}
}
}
.select2-drop {
border-color: $color-sel-hover-bg;
box-shadow: none !important;
z-index: 1000000;
&.select2-drop-above {
border-color: $color-sel-hover-bg;
}
}
.select2-search {
@extend .icon-search;
font-size: 100%;
color: darken($color-border, 15);
padding: 0 9px 0 0;
&:before {
@extend [class^="icon-"]:before;
position: absolute;
top: 13px;
left: 13px;
}
input {
@extend input[type="text"];
padding: 6px 0 6px 25px;
margin: 5px 0 0 5px;
font-family: $base-font-family;
font-size: 90%;
box-shadow: none;
background-image: none;
}
}
.select2-container .select2-choice .select2-arrow {
background-image: none;
background: transparent;
border: 0;
b {
padding-top: 7px;
display: block;
width: 100%;
height: 100%;
background: none;
font-family: FontAwesome;
font-weight: 200 !important;
&:before {
content: "\f0d7";
}
}
}
.select2-results {
padding-left: 0 !important;
li {
font-size: 85% !important;
&.select2-highlighted {
.select2-result-label {
&, h6 {
color: $color-1 !important;
}
}
}
.select2-result-label {
color: $color-body-text;
min-height: 22px;
clear: both;
overflow: auto;
}
&.select2-no-results, &.select2-searching {
padding: 5px;
background-color: transparent;
color: $color-body-text;
text-align: center;
font-weight: $font-weight-bold;
text-transform: uppercase;
}
}
.select2-highlighted {
background-color: $color-sel-bg;
}
}
.select2-container-multi {
&.select2-container-active, &.select2-dropdown-open {
.select2-choices {
border-color: $color-sel-hover-bg !important;
box-shadow: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
.select2-choices {
@extend input[type="text"];
padding: 6px 3px 3px 3px;
box-shadow: none;
background-image: none !important;
.select2-search-choice {
@include border-radius($border-radius);
margin: 0 0 3px 3px;
background-image: none;
background-color: $color-sel-bg;
border: none;
box-shadow: none;
color: $color-1 !important;
font-size: 85%;
&:hover {
background-color: $color-sel-hover-bg;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 85% !important;
@extend .icon-remove;
@extend [class^="icon-"]:before;
margin-left: 2px;
color: $color-1;
}
}
}
}
label .select2-container {
margin-top: -6px;
.select2-choice {
span {
text-transform: none;
font-weight: normal;
}
}
}

View File

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

View File

@@ -0,0 +1,270 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
input[type="text"],
input[type="password"],
input[type="email"],
input[type="date"],
input[type="datetime"],
input[type="time"],
input[type="url"],
input[type="number"],
input[type="tel"],
textarea, fieldset {
@include border-radius($border-radius);
padding: 7px 10px;
border: 1px solid $color-txt-brd;
color: $color-txt-text;
font-size: 90%;
&:focus {
outline: none;
border-color: $color-txt-hover-brd;
}
&[disabled] {
opacity: 0.7;
}
}
textarea {
line-height: 19px;
}
.fullwidth {
width: 100%;
}
label {
font-weight: 600;
text-transform: uppercase;
font-size: 85%;
display: inline;
margin-bottom: 5px;
color: $color-4;
&.inline {
display: inline-block !important;
}
&.block {
display: block !important;
}
}
.label-block label { display: block }
input[type="submit"],
input[type="button"],
button, .button {
@include border-radius($border-radius);
display: inline-block;
padding: 8px 15px;
border: none;
background-color: $color-btn-bg;
color: $color-btn-text;
text-transform: uppercase;
font-weight: 600 !important;
&:before {
font-weight: normal !important;
}
&:visited, &:active, &:focus { color: $color-btn-text }
&:hover {
background-color: $color-btn-hover-bg;
color: $color-btn-hover-text;
}
&:active:focus {
box-shadow: 0 0 8px 0 darken($color-btn-hover-bg, 5) inset;
}
&.fullwidth {
width: 100%;
text-align: center;
}
}
span.info {
font-style: italic;
font-size: 85%;
color: lighten($color-body-text, 15);
display: block;
line-height: 20px;
margin: 5px 0;
}
.field {
padding: 10px 0;
&.checkbox {
min-height: 73px;
input[type="checkbox"] {
display: inline-block;
width: auto;
}
label {
cursor: pointer;
display: block;
}
}
ul {
border-top: 1px solid $color-border;
list-style: none;
padding-top: 5px;
li {
display: inline-block;
padding-right: 10px;
label {
font-weight: normal;
text-transform: none;
}
&.white-space-nowrap {
white-space: nowrap;
}
}
}
&.withError {
.field_with_errors {
label {
color: very-light($color-error, 30);
}
input {
border-color: very-light($color-error, 15);
}
}
.formError {
color: very-light($color-error, 30);
font-style: italic;
font-size: 85%;
}
}
}
fieldset {
box-shadow: none;
box-sizing: border-box;
border-color: $color-border;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
margin-left: 0;
margin-right: 0;
position: relative;
margin-bottom: 35px;
padding: 10px 0 15px 0;
background-color: transparent;
border-left: none;
border-right: none;
border-radius: 0;
&.no-border-bottom {
border-bottom: none;
margin-bottom: 0;
}
&.no-border-top {
border-top: none;
padding-top: 0;
}
legend {
background-color: $color-1;
color: $color-2;
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
text-align: center;
padding: 8px 15px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
i {
color: $color-link;
}
}
label {
color: lighten($color-body-text, 8);
}
.filter-actions {
margin-bottom: -32px;
margin-top: 15px;
text-align: center;
form {
display: inline-block;
}
button, .button, input[type="submit"], input[type="button"], span.or {
@include border-radius($border-radius);
-webkit-box-shadow: 0 0 0 15px $color-1;
-moz-box-shadow: 0 0 0 15px $color-1;
-ms-box-shadow: 0 0 0 15px $color-1;
-o-box-shadow: 0 0 0 15px $color-1;
box-shadow: 0 0 0 15px $color-1;
&:hover {
border-color: $color-1;
}
}
span.or {
background-color: $color-1;
border-width: 5px;
margin-left: 5px;
margin-right: 5px;
position: relative;
-webkit-box-shadow: 0 0 0 5px $color-1;
-moz-box-shadow: 0 0 0 5px $color-1;
-ms-box-shadow: 0 0 0 5px $color-1;
-o-box-shadow: 0 0 0 5px $color-1;
box-shadow: 0 0 0 5px $color-1;
}
}
&.labels-inline {
.field {
margin-bottom: 0;
display: table;
width: 100%;
label, input {
display: table-cell !important;
}
input {
width: 100%;
}
&.checkbox {
input {
width: auto !important
}
}
}
.actions {
padding: 0;
text-align: right;
}
}
}
.form-actions {
margin-top: 18px;
}
.form-buttons {
text-align: center;
}

View File

@@ -0,0 +1,25 @@
@import 'admin/plugins/font-awesome';
// Some fixes for fontwesome stylesheets
[class^="icon-"], [class*=" icon-"] {
&:before {
padding-right: 5px;
}
&.button, &.icon_link {
width: auto;
&:before {
padding-top: 3px;
}
}
}
.icon-email:before { @extend .icon-envelope:before }
.icon-resume:before { @extend .icon-refresh:before }
.icon-cancel:before,
.icon-void:before { @extend .icon-remove:before }
.icon-capture:before { @extend .icon-ok:before }
.icon-credit:before { @extend .icon-ok:before }

View File

@@ -0,0 +1,92 @@
@import 'admin/globals/variables';
// Basics
//---------------------------------------------------
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
// Helpers
.block-table {
display: table;
width: 100%;
.table-cell {
display: table-cell;
vertical-align: middle;
padding: 0 10px;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
}
.hidden {
display: none;
}
// For block grids
.frameless {
margin-left: -10px;
margin-right: -10px;
}
// Header
//---------------------------------------------------
#header {
background-color: $color-1;
padding: 5px 0;
}
#logo { height: 40px }
[data-hook="admin-title"] { font-size: 14px }
.page-title {
i {
color: $color-2;
}
}
// Content
//---------------------------------------------------
#content {
background-color: $color-1;
position: relative;
z-index: 0;
padding: 0;
margin-top: 15px;
}
#content-header {
padding: 15px 0;
background-color: very-light($color-3, 4);
border-bottom: 1px solid $color-border;
.page-title {
font-size: 20px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.page-actions {
text-align: right;
form {
display: inline-block;
}
}
}
// Footer
//---------------------------------------------------
#footer {
margin-top: 15px;
border-top: 1px solid $color-border;
padding: 10px 0;
}

View File

@@ -0,0 +1,208 @@
@import 'admin/globals/variables';
@import 'admin/plugins/font-awesome';
table {
width: 100%;
margin-bottom: 15px;
border-collapse: separate;
th, td {
padding: 7px 5px;
border-right: 1px solid $color-border;
border-bottom: 1px solid $color-border;
vertical-align: middle;
text-overflow: ellipsis;
img {
border: 1px solid transparent;
}
&:first-child {
border-left: 1px solid $color-border;
}
a {
border-bottom: 1px dotted lighten($color-link, 10);
&:hover {
border-color: lighten($color-link-hover, 10);
}
}
.handle {
display: block !important;
text-align: center;
padding-right: 0;
}
&.actions {
background-color: transparent;
border: none !important;
text-align: center;
span.text {
font-size: $body-font-size;
}
[class*='icon-'].no-text {
font-size: 120%;
background-color: very-light($color-3);
border: 1px solid $color-border;
border-radius: 15px;
width: 29px;
height: 29px;
display: inline-block;
padding-top: 2px;
&:before {
text-align: center !important;
width: 27px;
display: inline-block;
}
&:hover {
border-color: transparent;
}
}
button[class*='icon-'] {
color: $color-link;
padding: 0 !important;
}
.icon-envelope-alt, .icon-eye-open {
color: $color-link;
padding-left: 0px;
&:hover {
background-color: $color-3;
color: $color-1;
}
}
.icon-trash:hover, .icon-void:hover {
background-color: $color-error;
color: $color-1;
}
.icon-cancel:hover {
background-color: $color-notice;
color: $color-1;
}
.icon-edit:hover, .icon-capture:hover, .icon-ok:hover, .icon-plus:hover {
background-color: $color-success;
color: $color-1;
}
.icon-copy:hover {
background-color: $color-notice;
color: $color-1;
}
}
input[type="number"],
input[type="text"] {
width: 100%;
}
&.no-border {
border-right: none;
}
.handle {
@extend [class^="icon-"]:before;
@extend .icon-reorder;
cursor: move;
}
}
&.no-borders {
td, th {
border: none !important;
}
}
thead {
th {
padding: 10px;
border-top: 1px solid $color-border;
border-bottom: none;
background-color: $color-tbl-thead;
text-transform: uppercase;
font-size: 85%;
font-weight: $font-weight-bold;
}
}
tbody {
tr {
&:first-child th,
&:first-child td {
border-top: 1px solid $color-border;
}
&.even td {
background-color: $color-tbl-even;
img {
border: 1px solid very-light($color-3, 6);
}
}
&:hover td {
background-color: very-light($color-3, 5);
img {
border: 1px solid $color-border;
}
}
&.deleted td {
background-color: very-light($color-error, 6);
border-color: very-light($color-error, 15);
}
&.ui-sortable-placeholder td {
border: 1px solid $color-2 !important;
visibility: visible !important;
&.actions {
background-color: transparent;
border-right: none !important;
border-top: none !important;
border-bottom: none !important;
border-left: 1px solid $color-2 !important;
}
}
&.ui-sortable-helper {
width: 100%;
td {
background-color: lighten($color-3, 33);
border-bottom: 1px solid $color-border;
&.actions {
display: none;
}
}
}
}
&.no-border-top tr:first-child td {
border-top: none;
}
&.grand-total {
td {
border-color: $color-2 !important;
text-transform: uppercase;
font-size: 110%;
font-weight: 600;
background-color: lighten($color-2, 50);
}
.total {
background-color: $color-2;
color: $color-1;
}
}
}
}

View File

@@ -0,0 +1,134 @@
@import 'admin/globals/variables';
// Base
//--------------------------------------------------------------
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; font-size: 13px; }
body {
font-family: $base-font-family;
font-size: $body-font-size;
font-weight: 400;
color: $color-body-text;
text-rendering: optimizeLegibility;
}
hr {
border-top: 1px solid $color-border;
border-bottom: 1px solid white;
border-left: none;
}
strong, b {
font-weight: 600;
}
// links
//--------------------------------------------------------------
a {
color: $color-link;
text-decoration: none;
line-height: inherit;
&, &:hover, &:active, &:visited, &:focus {
outline: none;
}
&:visited {
color: $color-link-visited;
}
&:focus {
color: $color-link-focus;
}
&:active {
color: $color-link-active;
}
&:hover {
color: $color-link-hover;
}
}
// Headings
//--------------------------------------------------------------
h1,h2,h3,h4,h5,h6 {
font-weight: 600;
color: $color-headers;
line-height: 1.1;
}
h1 { font-size: $h1-size; line-height: $h1-size + 6 }
h2 { font-size: $h2-size; line-height: $h1-size + 4 }
h3 { font-size: $h3-size; line-height: $h1-size + 2 }
h4 { font-size: $h4-size; line-height: $h1-size }
h5 { font-size: $h5-size; line-height: $h1-size }
h6 { font-size: $h6-size; line-height: $h1-size }
// Lists
//--------------------------------------------------------------
ul {
&.inline-menu {
li {
display: inline-block;
}
}
&.fields {
list-style: none;
padding: 0;
margin: 0;
}
}
dl {
width: 100%;
overflow: hidden;
margin: 5px 0;
color: lighten($color-body-text, 15);
dt, dd {
float: left;
line-height: 16px;
padding: 5px;
text-align: justify;
}
dt {
width: 40%;
font-weight: 600;
padding-left: 0;
text-transform: uppercase;
font-size: 85%;
}
dd {
width: 60%;
padding-right: 0;
}
dd:after {
content: '';
clear: both;
}
}
// Helpers
.align-center { text-align: center }
.align-right { text-align: right }
.align-left { text-align: left }
.align-justify { text-align: justify }
.uppercase { text-transform: uppercase }
.green { color: $color-2 }
.blue { color: $color-3 }
.red { color: $color-5 }
.yellow { color: $color-6 }
.no-objects-found {
text-align: center;
font-size: 120%;
text-transform: uppercase;
padding: 40px 0px;
color: lighten($color-body-text, 15);
}

View File

@@ -1,5 +1,6 @@
require 'open_food_network/referer_parser'
require 'open_food_network/permissions'
require 'open_food_network/order_cycle_permissions'
module Admin
class EnterprisesController < ResourceController

View File

@@ -1,7 +1,10 @@
# frozen_string_literal: true
# This controller lists products that can be added to an exchange
#
# Pagination is optional and can be required by using param[:page]
module Api
class ExchangeProductsController < Api::BaseController
DEFAULT_PAGE = 1
DEFAULT_PER_PAGE = 100
skip_authorization_check only: [:index]
@@ -29,22 +32,28 @@ module Api
def render_variant_count
render text: {
count: Spree::Variant.
not_master.
where(product_id: products).
count
count: variants.count
}.to_json
end
def variants
renderer.exchange_variants(@incoming, @enterprise)
end
def products
ExchangeProductsRenderer.
new(@order_cycle, spree_current_user).
exchange_products(@incoming, @enterprise)
renderer.exchange_products(@incoming, @enterprise)
end
def renderer
@renderer ||= ExchangeProductsRenderer.
new(@order_cycle, spree_current_user)
end
def paginated_products
return products unless pagination_required?
products.
page(params[:page] || DEFAULT_PAGE).
page(params[:page]).
per(params[:per_page] || DEFAULT_PER_PAGE)
end
@@ -74,19 +83,23 @@ module Api
order_cycle: @order_cycle
)
render text: {
products: serializer,
pagination: pagination_data(paginated_products)
}.to_json
result = { products: serializer }
result = result.merge(pagination: pagination_data(paginated_products)) if pagination_required?
render text: result.to_json
end
def pagination_data(paginated_products)
{
results: paginated_products.total_count,
pages: paginated_products.num_pages,
page: (params[:page] || DEFAULT_PAGE).to_i,
page: params[:page].to_i,
per_page: (params[:per_page] || DEFAULT_PER_PAGE).to_i
}
end
def pagination_required?
params[:page].present?
end
end
end

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

@@ -23,7 +23,11 @@ class ApplicationController < ActionController::Base
referer_path = OpenFoodNetwork::RefererParser.path(request.referer)
if referer_path
is_checkout_path_the_referer = [main_app.checkout_path].include?(referer_path)
session["spree_user_return_to"] = is_checkout_path_the_referer ? referer_path : root_path
session["spree_user_return_to"] = if is_checkout_path_the_referer
referer_path
else
main_app.root_path
end
end
end
@@ -48,11 +52,11 @@ class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource_or_scope)
return session[:shopfront_redirect] if session[:shopfront_redirect]
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
stored_location_for(resource_or_scope) || main_app.root_path
end
def after_sign_out_path_for(_resource_or_scope)
session[:shopfront_redirect] || root_path
session[:shopfront_redirect] || main_app.root_path
end
private
@@ -74,7 +78,7 @@ class ApplicationController < ActionController::Base
def require_distributor_chosen
unless @distributor = current_distributor
redirect_to spree.root_path
redirect_to main_app.root_path
false
end
end
@@ -86,26 +90,29 @@ class ApplicationController < ActionController::Base
end
def check_hub_ready_for_checkout
# This condition is more rigourous than required by development to avoid coupling this
# condition to every controller spec
if current_distributor && current_order &&
current_distributor.respond_to?(:ready_for_checkout?) &&
!current_distributor.ready_for_checkout?
if current_distributor_closed?
current_order.empty!
current_order.set_distribution! nil, nil
flash[:info] = "The hub you have selected is temporarily closed for orders. Please try again later."
redirect_to root_url
flash[:info] = "The hub you have selected is temporarily closed for orders. "\
"Please try again later."
redirect_to main_app.root_url
end
end
def current_distributor_closed?
current_distributor &&
current_order &&
current_distributor.respond_to?(:ready_for_checkout?) &&
!current_distributor.ready_for_checkout?
end
def check_order_cycle_expiry
if current_order_cycle.andand.closed?
session[:expired_order_cycle_id] = current_order_cycle.id
current_order.empty!
current_order.set_order_cycle! nil
flash[:info] = "The order cycle you've selected has just closed. Please try again!"
redirect_to root_url
redirect_to main_app.root_url
end
end

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

@@ -15,11 +15,10 @@ module Spree
# Warn the user when they have an active order cycle with hubs that are not ready
# for checkout (ie. does not have valid shipping and payment methods).
def warn_invalid_order_cycles
distributors = active_distributors_not_ready_for_checkout
return if flash[:notice].present?
return if distributors.empty? || flash[:notice].present?
flash[:notice] = active_distributors_not_ready_for_checkout_message(distributors)
warning = OrderCycleWarning.new(spree_current_user).call
flash[:notice] = warning if warning.present?
end
# This is in Spree::Core::ControllerHelpers::Auth
@@ -30,7 +29,7 @@ module Spree
redirect_to '/unauthorized'
else
store_location
redirect_to root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
redirect_to main_app.root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
end
end
@@ -71,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?
@@ -87,30 +82,8 @@ module Spree
raise(ActionController::InvalidAuthenticityToken)
end
def config_locale
Spree::Backend::Config[:locale]
end
private
def active_distributors_not_ready_for_checkout
ocs = OrderCycle.managed_by(spree_current_user).active
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
Enterprise.where('enterprises.id IN (?)', distributors).not_ready_for_checkout
end
def active_distributors_not_ready_for_checkout_message(distributors)
distributor_names = distributors.map(&:name).join ', '
if distributors.count > 1
I18n.t(:active_distributors_not_ready_for_checkout_message_plural,
distributor_names: distributor_names)
else
I18n.t(:active_distributors_not_ready_for_checkout_message_singular,
distributor_names: distributor_names)
end
end
def html_request?
request.format.html?
end
@@ -121,13 +94,17 @@ module Spree
def render_as_json(data, options = {})
ams_prefix = options.delete :ams_prefix
if [Array, ActiveRecord::Relation].include? data.class
if each_serializer_required?(data)
render options.merge(json: data, each_serializer: serializer(ams_prefix))
else
render options.merge(json: data, serializer: serializer(ams_prefix))
end
end
def each_serializer_required?(data)
['Array', 'ActiveRecord::Relation'].include?(data.class.name)
end
def serializer(ams_prefix)
unless ams_prefix.nil? || ams_prefix_whitelist.include?(ams_prefix.to_sym)
raise "Suffix '#{ams_prefix}' not found in ams_prefix_whitelist for #{self.class.name}."

View File

@@ -0,0 +1,71 @@
module Spree
module Admin
module Orders
class CustomerDetailsController < Spree::Admin::BaseController
before_filter :load_order
before_filter :check_authorization
before_filter :set_guest_checkout_status, only: :update
def show
edit
render action: :edit
end
def edit
country_id = Address.default.country.id
@order.build_bill_address(country_id: country_id) if @order.bill_address.nil?
@order.build_ship_address(country_id: country_id) if @order.ship_address.nil?
end
def update
if @order.update_attributes(params[:order])
if params[:guest_checkout] == "false"
@order.associate_user!(Spree.user_class.find_by_email(@order.email))
end
AdvanceOrderService.new(@order).call
@order.shipments.map(&:refresh_rates)
flash[:success] = Spree.t('customer_details_updated')
redirect_to admin_order_customer_path(@order)
else
render action: :edit
end
end
# Inherit CanCan permissions for the current order
def model_class
load_order unless @order
@order
end
private
def load_order
@order = Order.find_by_number!(params[:order_id], include: :adjustments)
end
def check_authorization
load_order
session[:access_token] ||= params[:token]
resource = @order
action = params[:action].to_sym
action = :edit if action == :show # show route renders :edit for this controller
authorize! action, resource, session[:access_token]
end
def set_guest_checkout_status
registered_user = Spree::User.find_by_email(params[:order][:email])
params[:order][:guest_checkout] = registered_user.nil?
return unless registered_user
@order.user_id = registered_user.id
end
end
end
end
end

View File

@@ -1,49 +0,0 @@
Spree::Admin::Orders::CustomerDetailsController.class_eval do
before_filter :check_authorization
before_filter :set_guest_checkout_status, only: :update
def update
if @order.update_attributes(params[:order])
if params[:guest_checkout] == "false"
@order.associate_user!(Spree.user_class.find_by_email(@order.email))
end
AdvanceOrderService.new(@order).call
@order.shipments.map &:refresh_rates
flash[:success] = Spree.t('customer_details_updated')
redirect_to admin_order_customer_path(@order)
else
render action: :edit
end
end
# Inherit CanCan permissions for the current order
def model_class
load_order unless @order
@order
end
private
def check_authorization
load_order
session[:access_token] ||= params[:token]
resource = @order
action = params[:action].to_sym
action = :edit if action == :show # show route renders :edit for this controller
authorize! action, resource, session[:access_token]
end
def set_guest_checkout_status
registered_user = Spree::User.find_by_email(params[:order][:email])
params[:order][:guest_checkout] = registered_user.nil?
return unless registered_user
@order.user_id = registered_user.id
end
end

View File

@@ -0,0 +1,150 @@
require 'open_food_network/spree_api_key_loader'
module Spree
module Admin
class OrdersController < Spree::Admin::BaseController
require 'spree/core/gateway_error'
include OpenFoodNetwork::SpreeApiKeyLoader
helper CheckoutHelper
before_filter :load_order, only: [:edit, :update, :fire, :resend,
:invoice, :print, :print_ticket]
before_filter :load_distribution_choices, only: [:new, :edit, :update]
# Ensure that the distributor is set for an order when
before_filter :ensure_distribution, only: :new
# After updating an order, the fees should be updated as well
# Currently, adding or deleting line items does not trigger updating the
# fees! This is a quick fix for that.
# TODO: update fees when adding/removing line items
# instead of the update_distribution_charge method.
after_filter :update_distribution_charge, only: :update
before_filter :require_distributor_abn, only: :invoice
respond_to :html, :json
def new
@order = Order.create
@order.created_by = try_spree_current_user
@order.save
redirect_to edit_admin_order_url(@order)
end
def edit
@order.shipments.map(&:refresh_rates)
AdvanceOrderService.new(@order).call
# The payment step shows an error of 'No pending payments'
# Clearing the errors from the order object will stop this error
# appearing on the edit page where we don't want it to.
@order.errors.clear
end
def update
unless @order.update_attributes(params[:order]) && @order.line_items.present?
if @order.line_items.empty?
@order.errors.add(:line_items, Spree.t('errors.messages.blank'))
end
return redirect_to(edit_admin_order_path(@order),
flash: { error: @order.errors.full_messages.join(', ') })
end
@order.update!
if @order.complete?
redirect_to edit_admin_order_path(@order)
else
# Jump to next step if order is not complete
redirect_to admin_order_customer_path(@order)
end
end
def bulk_management
load_spree_api_key
end
def fire
event = params[:e]
if @order.public_send(event.to_s)
flash[:success] = Spree.t(:order_updated)
else
flash[:error] = Spree.t(:cannot_perform_operation)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message.to_s
ensure
redirect_to :back
end
def resend
Spree::OrderMailer.confirm_email_for_customer(@order.id, true).deliver
flash[:success] = t(:order_email_resent)
respond_with(@order) { |format| format.html { redirect_to :back } }
end
def invoice
pdf = InvoiceRenderer.new.render_to_string(@order)
Spree::OrderMailer.invoice_email(@order.id, pdf).deliver
flash[:success] = t('admin.orders.invoice_email_sent')
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
def print
render InvoiceRenderer.new.args(@order)
end
def print_ticket
render template: "spree/admin/orders/ticket", layout: false
end
def update_distribution_charge
@order.update_distribution_charge!
end
private
def load_order
@order = Order.find_by_number!(params[:id], include: :adjustments) if params[:id]
authorize! action, @order
end
def model_class
Spree::Order
end
def require_distributor_abn
return if @order.distributor.abn.present?
flash[:error] = t(:must_have_valid_business_number,
enterprise_name: @order.distributor.name)
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
def load_distribution_choices
@shops = Enterprise.is_distributor.managed_by(spree_current_user).by_name
ocs = OrderCycle.managed_by(spree_current_user)
@order_cycles = ocs.soonest_closing +
ocs.soonest_opening +
ocs.closed +
ocs.undated
end
def ensure_distribution
unless @order
@order = Spree::Order.new
@order.generate_order_number
@order.save!
end
return if @order.distribution_set?
render 'set_distribution', locals: { order: @order }
end
end
end
end

View File

@@ -1,120 +0,0 @@
require 'open_food_network/spree_api_key_loader'
Spree::Admin::OrdersController.class_eval do
include OpenFoodNetwork::SpreeApiKeyLoader
helper CheckoutHelper
before_filter :load_order, only: %i[show edit update fire resend invoice print print_ticket]
before_filter :load_distribution_choices, only: [:new, :edit, :update]
# Ensure that the distributor is set for an order when
before_filter :ensure_distribution, only: :new
# After updating an order, the fees should be updated as well
# Currently, adding or deleting line items does not trigger updating the
# fees! This is a quick fix for that.
# TODO: update fees when adding/removing line items
# instead of the update_distribution_charge method.
after_filter :update_distribution_charge, only: :update
before_filter :require_distributor_abn, only: :invoice
respond_to :html, :json
def index
# Overriding the action so we only render the page template. An angular request
# within the page then fetches the data it needs from Api::OrdersController
end
def bulk_management
load_spree_api_key
end
def edit
@order.shipments.map &:refresh_rates
AdvanceOrderService.new(@order).call
# The payment step shows an error of 'No pending payments'
# Clearing the errors from the order object will stop this error
# appearing on the edit page where we don't want it to.
@order.errors.clear
end
# Re-implement spree method so that it redirects to edit instead of rendering edit
# This allows page reloads while adding variants to the order (/edit), without being redirected to customer details page (/update)
def update
unless @order.update_attributes(params[:order]) && @order.line_items.present?
@order.errors.add(:line_items, Spree.t('errors.messages.blank')) if @order.line_items.empty?
return redirect_to edit_admin_order_path(@order), flash: { error: @order.errors.full_messages.join(', ') }
end
@order.update!
if @order.complete?
redirect_to edit_admin_order_path(@order)
else
# Jump to next step if order is not complete
redirect_to admin_order_customer_path(@order)
end
end
# Overwrite to use confirm_email_for_customer instead of confirm_email.
# This uses a new template. See mailers/spree/order_mailer_decorator.rb.
def resend
Spree::OrderMailer.confirm_email_for_customer(@order.id, true).deliver
flash[:success] = t(:order_email_resent)
respond_with(@order) { |format| format.html { redirect_to :back } }
end
def invoice
pdf = InvoiceRenderer.new.render_to_string(@order)
Spree::OrderMailer.invoice_email(@order.id, pdf).deliver
flash[:success] = t('admin.orders.invoice_email_sent')
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
def print
render InvoiceRenderer.new.args(@order)
end
def print_ticket
render template: "spree/admin/orders/ticket", layout: false
end
def update_distribution_charge
@order.update_distribution_charge!
end
private
def require_distributor_abn
if @order.distributor.abn.blank?
flash[:error] = t(:must_have_valid_business_number, enterprise_name: @order.distributor.name)
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
end
def load_distribution_choices
@shops = Enterprise.is_distributor.managed_by(spree_current_user).by_name
ocs = OrderCycle.managed_by(spree_current_user)
@order_cycles = ocs.soonest_closing +
ocs.soonest_opening +
ocs.closed +
ocs.undated
end
def ensure_distribution
unless @order
@order = Spree::Order.new
@order.generate_order_number
@order.save!
end
unless @order.distribution_set?
render 'set_distribution', locals: { order: @order }
end
end
end

View File

@@ -0,0 +1,129 @@
# frozen_string_literal: true
module Spree
module Admin
class PaymentsController < Spree::Admin::BaseController
before_filter :load_order, except: [:show]
before_filter :load_payment, only: [:fire, :show]
before_filter :load_data
before_filter :can_transition_to_payment
respond_to :html
def index
@payments = @order.payments
redirect_to new_admin_order_payment_url(@order) if @payments.empty?
end
def new
@payment = @order.payments.build
end
def create
@payment = @order.payments.build(object_params)
load_payment_source
begin
unless @payment.save
redirect_to admin_order_payments_path(@order)
return
end
if @order.completed?
@payment.process!
flash[:success] = flash_message_for(@payment, :successfully_created)
redirect_to admin_order_payments_path(@order)
else
AdvanceOrderService.new(@order).call!
flash[:success] = Spree.t(:new_order_completed)
redirect_to edit_admin_order_url(@order)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message.to_s
redirect_to new_admin_order_payment_path(@order)
end
end
# When a user fires an event, take them back to where they came from
# (we can't use respond_override because Spree no longer uses respond_with)
def fire
event = params[:e]
return unless event && @payment.payment_source
# Because we have a transition method also called void, we do this to avoid conflicts.
event = "void_transaction" if event == "void"
if @payment.public_send("#{event}!")
flash[:success] = t(:payment_updated)
else
flash[:error] = t(:cannot_perform_operation)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message
ensure
redirect_to request.referer
end
private
def load_payment_source
if @payment.payment_method.is_a?(Spree::Gateway) &&
@payment.payment_method.payment_profiles_supported? &&
params[:card].present? &&
(params[:card] != 'new')
@payment.source = CreditCard.find_by_id(params[:card])
end
end
def object_params
if params[:payment] &&
params[:payment_source] &&
source_params = params.delete(:payment_source)[params[:payment][:payment_method_id]]
params[:payment][:source_attributes] = source_params
end
params[:payment]
end
def load_data
@amount = params[:amount] || load_order.total
# Only show payments for the order's distributor
@payment_methods = PaymentMethod.
available(:back_end).
select{ |pm| pm.has_distributor? @order.distributor }
@payment_method = if @payment && @payment.payment_method
@payment.payment_method
else
@payment_methods.first
end
@previous_cards = @order.credit_cards.with_payment_profile
end
# At this point admin should have passed through Customer Details step
# where order.next is called which leaves the order in payment step
#
# Orders in complete step also allows to access this controller
#
# Otherwise redirect user to that step
def can_transition_to_payment
return if @order.payment? || @order.complete?
flash[:notice] = Spree.t(:fill_in_customer_info)
redirect_to edit_admin_order_customer_url(@order)
end
def load_order
@order = Order.find_by_number!(params[:order_id])
authorize! action, @order
@order
end
def load_payment
@payment = Payment.find(params[:id])
end
end
end
end

View File

@@ -1,59 +0,0 @@
Spree::Admin::PaymentsController.class_eval do
append_before_filter :filter_payment_methods
def create
@payment = @order.payments.build(object_params)
if @payment.payment_method.is_a?(Spree::Gateway) && @payment.payment_method.payment_profiles_supported? && params[:card].present? && (params[:card] != 'new')
@payment.source = CreditCard.find_by_id(params[:card])
end
begin
unless @payment.save
redirect_to admin_order_payments_path(@order)
return
end
if @order.completed?
@payment.process!
flash[:success] = flash_message_for(@payment, :successfully_created)
redirect_to admin_order_payments_path(@order)
else
AdvanceOrderService.new(@order).call!
flash[:success] = Spree.t(:new_order_completed)
redirect_to edit_admin_order_url(@order)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message.to_s
redirect_to new_admin_order_payment_path(@order)
end
end
# When a user fires an event, take them back to where they came from
# (we can't use respond_override because Spree no longer uses respond_with)
def fire
event = params[:e]
return unless event && @payment.payment_source
# Because we have a transition method also called void, we do this to avoid conflicts.
event = "void_transaction" if event == "void"
if @payment.public_send("#{event}!")
flash[:success] = t(:payment_updated)
else
flash[:error] = t(:cannot_perform_operation)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message
ensure
redirect_to request.referer
end
private
# Only show payments for the order's distributor
def filter_payment_methods
@payment_methods = @payment_methods.select{ |pm| pm.has_distributor? @order.distributor }
@payment_method ||= @payment_methods.first
end
end

View File

@@ -0,0 +1,43 @@
module Spree
module Admin
class SearchController < Spree::Admin::BaseController
# http://spreecommerce.com/blog/2010/11/02/json-hijacking-vulnerability/
before_filter :check_json_authenticity, only: :index
respond_to :json
def known_users
@users = if exact_match = Spree.user_class.find_by_email(params[:q])
[exact_match]
else
spree_current_user.known_users.ransack(ransack_hash).result.limit(10)
end
render json: @users, each_serializer: ::Api::Admin::UserSerializer
end
def customers
@customers = []
if spree_current_user.enterprises.pluck(:id).include? params[:distributor_id].to_i
@customers = Customer.
ransack(m: 'or', email_start: params[:q], name_start: params[:q]).
result.
where(enterprise_id: params[:distributor_id])
end
render json: @customers, each_serializer: ::Api::Admin::CustomerSerializer
end
private
def ransack_hash
{
m: 'or',
email_start: params[:q],
ship_address_firstname_start: params[:q],
ship_address_lastname_start: params[:q],
bill_address_firstname_start: params[:q],
bill_address_lastname_start: params[:q]
}
end
end
end
end

View File

@@ -1,36 +0,0 @@
Spree::Admin::SearchController.class_eval do
def known_users
@users = if exact_match = Spree.user_class.find_by_email(params[:q])
[exact_match]
else
spree_current_user.known_users.ransack(
m: 'or',
email_start: params[:q],
ship_address_firstname_start: params[:q],
ship_address_lastname_start: params[:q],
bill_address_firstname_start: params[:q],
bill_address_lastname_start: params[:q]
).result.limit(10)
end
render json: @users, each_serializer: Api::Admin::UserSerializer
end
def customers
@customers = if spree_current_user.enterprises.pluck(:id).include? params[:distributor_id].to_i
Customer.ransack(m: 'or', email_start: params[:q], name_start: params[:q])
.result.where(enterprise_id: params[:distributor_id])
else
[]
end
render json: @customers, each_serializer: Api::Admin::CustomerSerializer
end
def users_with_ams
users_without_ams
render json: @users, each_serializer: Api::Admin::UserSerializer
end
alias_method_chain :users, :ams
end

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

@@ -71,7 +71,7 @@ module Spree
@order = order_to_update
unless @order
flash[:error] = t(:order_not_found)
redirect_to(root_path) && return
redirect_to(main_app.root_path) && return
end
if @order.update_attributes(params[:order])

View File

@@ -32,7 +32,7 @@ module Spree
session[:guest_token] = nil
end
redirect_back_or_default(root_url)
redirect_back_or_default(main_app.root_url)
else
render :new
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

@@ -1,6 +1,17 @@
module Spree
module Admin
module OrdersHelper
def event_links
links = []
links << event_link("cancel") if @order.can_cancel?
links << event_link("resume") if @order.can_resume?
links.join('&nbsp;').html_safe
end
def line_item_shipment_price(line_item, quantity)
Spree::Money.new(line_item.price * quantity, currency: line_item.currency)
end
def order_links(order)
@order ||= order
links = []
@@ -100,6 +111,14 @@ module Spree
icon: 'icon-trash',
confirm: t(:are_you_sure) }
end
def event_link(event)
button_link_to(Spree.t(event),
fire_admin_order_url(@order, e: event),
method: :put,
icon: "icon-#{event}",
data: { confirm: Spree.t(:order_sure_want_to, event: Spree.t(event)) })
end
end
end
end

View File

@@ -0,0 +1,11 @@
module Spree
module Admin
module PaymentsHelper
def payment_method_name(payment)
# hack to allow us to retrieve the name of a "deleted" payment method
id = payment.payment_method_id
Spree::PaymentMethod.find_with_destroyed(id).name
end
end
end
end

View File

@@ -9,6 +9,6 @@ Spree::BaseMailer.class_eval do
def roadie_options
# This lets us specify assets using relative paths in email templates
super.merge(url_options: { host: URI(spree.root_url).host })
super.merge(url_options: { host: URI(main_app.root_url).host })
end
end

View File

@@ -25,7 +25,8 @@ class Enterprise < ActiveRecord::Base
has_many :relationships_as_child, class_name: 'EnterpriseRelationship',
foreign_key: 'child_id',
dependent: :destroy
has_and_belongs_to_many :groups, class_name: 'EnterpriseGroup'
has_and_belongs_to_many :groups, join_table: 'enterprise_groups_enterprises',
class_name: 'EnterpriseGroup'
has_many :producer_properties, foreign_key: 'producer_id'
has_many :properties, through: :producer_properties
has_many :supplied_products, class_name: 'Spree::Product',
@@ -115,7 +116,10 @@ class Enterprise < ActiveRecord::Base
scope :not_ready_for_checkout, lambda {
# When ready_for_checkout is empty, return all rows when there are no enterprises ready for
# checkout.
ready_enterprises = Enterprise.ready_for_checkout.select('enterprises.id')
ready_enterprises = Enterprise.ready_for_checkout.
except(:select).
select('DISTINCT enterprises.id')
if ready_enterprises.present?
where("enterprises.id NOT IN (?)", ready_enterprises)
else

View File

@@ -5,7 +5,7 @@ class EnterpriseGroup < ActiveRecord::Base
include PermalinkGenerator
acts_as_list
has_and_belongs_to_many :enterprises
has_and_belongs_to_many :enterprises, join_table: 'enterprise_groups_enterprises'
belongs_to :owner, class_name: 'Spree::User', foreign_key: :owner_id, inverse_of: :owned_groups
belongs_to :address, class_name: 'Spree::Address'
accepts_nested_attributes_for :address

View File

@@ -63,7 +63,7 @@ class OrderCycle < ActiveRecord::Base
if user.has_spree_role?('admin')
scoped
else
where('coordinator_id IN (?)', user.enterprises.map(&:id))
where(coordinator_id: user.enterprises)
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,7 @@
# frozen_string_literal: true
require 'open_food_network/order_cycle_permissions'
class ExchangeProductsRenderer
def initialize(order_cycle, user)
@order_cycle = order_cycle
@@ -12,6 +16,14 @@ class ExchangeProductsRenderer
end
end
def exchange_variants(incoming, enterprise)
variants_relation = Spree::Variant.
not_master.
where(product_id: exchange_products(incoming, enterprise).select(&:id))
filter_visible(variants_relation)
end
private
def products_for_incoming_exchange(enterprise)
@@ -21,12 +33,16 @@ class ExchangeProductsRenderer
def supplied_products(enterprises_query_matcher)
products_relation = Spree::Product.where(supplier_id: enterprises_query_matcher)
filter_visible(products_relation)
end
def filter_visible(relation)
if @order_cycle.present? &&
@order_cycle.prefers_product_selection_from_coordinator_inventory_only?
products_relation = products_relation.visible_for(@order_cycle.coordinator)
relation = relation.visible_for(@order_cycle.coordinator)
end
products_relation
relation
end
def products_for_outgoing_exchange

View File

@@ -0,0 +1,37 @@
# frozen_string_literal: true
class OrderCycleWarning
def initialize(current_user)
@current_user = current_user
end
def call
distributors = active_distributors_not_ready_for_checkout
return if distributors.empty?
active_distributors_not_ready_for_checkout_message(distributors)
end
private
attr_reader :current_user
def active_distributors_not_ready_for_checkout
ocs = OrderCycle.managed_by(current_user).active
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
Enterprise.where(id: distributors.map(&:id)).not_ready_for_checkout
end
def active_distributors_not_ready_for_checkout_message(distributors)
distributor_names = distributors.map(&:name).join ', '
if distributors.count > 1
I18n.t(:active_distributors_not_ready_for_checkout_message_plural,
distributor_names: distributor_names)
else
I18n.t(:active_distributors_not_ready_for_checkout_message_singular,
distributor_names: distributor_names)
end
end
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

@@ -54,7 +54,7 @@
.row{ ng: { show: "Enterprise.sells == 'own' || Enterprise.sells == 'any'" } }
.three.columns.alpha
= f.label :permalink, t('.permalink')
%div{'ofn-with-tip' => t('.permalink_tip', link: spree.root_url)}
%div{'ofn-with-tip' => t('.permalink_tip', link: main_app.root_url)}
%a= t('admin.whats_this')
.six.columns
= f.text_field :permalink, { 'ng-model' => "Enterprise.permalink", placeholder: "eg. your-shop-name", 'ng-model-options' => "{ updateOn: 'default blur', debounce: {'default': 300, 'blur': 0} }" }
@@ -69,7 +69,7 @@
%div{'ofn-with-tip' => t('.link_to_front_tip')}
%a= t('admin.whats_this')
.eight.columns.omega
= surround spree.root_url, "/shop" do
= surround main_app.root_url, "/shop" do
{{Enterprise.permalink}}
.row
.three.columns.alpha

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

@@ -42,10 +42,10 @@
%tr
%td{:align => "center"}
%p
%a{:href => "#{ URI.join(spree.root_url, Spree::Config.footer_tos_url).to_s }", :target => "_blank"}
%a{:href => "#{ URI.join(main_app.root_url, Spree::Config.footer_tos_url).to_s }", :target => "_blank"}
= t :terms_of_service
|
%a{:href => "#{ spree.root_url }"}
%a{:href => "#{ main_app.root_url }"}
= Spree::Config[:site_name]
/ | <a href="#"><unsubscribe>Unsubscribe</unsubscribe></a>
%td

View File

@@ -94,7 +94,7 @@
.row
.small-12.medium-3.medium-offset-2.columns.text-left
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.footer_logo.url, width: "220"}
.small-12.medium-5.columns.text-left
%p.text-small

View File

@@ -2,7 +2,7 @@
%section.top-bar-section
%ul.left
%li.ofn-logo
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.logo.url}
%li.powered-by
%img{src: '/favicon.ico'}

View File

@@ -5,7 +5,7 @@
%section.left
.ofn-logo
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.logo_mobile.url, srcset: ContentConfig.logo_mobile_svg.url, width: "75", height: "26"}
%section.right{"ng-cloak" => true}

View File

@@ -1,7 +1,7 @@
%aside.left-off-canvas-menu.show-for-medium-down{ ng: { controller: "OffcanvasCtrl" } }
%ul.off-canvas-list
%li.ofn-logo
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.logo_mobile.url, srcset: ContentConfig.logo_mobile_svg.url, width: "75", height: "26"}
- [*1..7].each do |menu_number|
- menu_name = "menu_#{menu_number}"

View File

@@ -9,6 +9,6 @@
.alert-box.blocked-cookies.hidden
%p= t('blocked_cookies_alert')
%a.button.allow{target: '_blank', href: "#{spree.root_url}embedded_shopfront/shopfront_session/"}
%a.button.allow{target: '_blank', href: "#{main_app.root_url}embedded_shopfront/shopfront_session/"}
= t('allow_cookies')

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

@@ -25,4 +25,4 @@
= button Spree.t('actions.update'), 'icon-refresh'
- content_for :head do
= javascript_include_tag 'admin/address_states.js'
= javascript_include_tag 'admin/spree/orders/address_states.js'

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

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