Compare commits

..

104 Commits

Author SHA1 Message Date
Transifex-Openfoodnetwork
a1a2a66d21 Updating translations for config/locales/fr.yml [skip ci] 2017-08-21 06:20:59 +10:00
Transifex-Openfoodnetwork
0117e2e8b5 Updating translations for config/locales/es.yml [skip ci] 2017-08-19 02:22:36 +10:00
Continuous Integration
2650dc209e Merge remote-tracking branch 'origin/master' into HEAD 2017-08-12 20:52:20 +10:00
Enrico Stano
58d7d8f016 Merge pull request #1753 from coopdevs/complete-seed-data
Complete seed data to purchase to Enterprise 2
2017-08-11 15:42:03 +02:00
Enrico Stano
1fbb4b25d1 Merge pull request #1746 from oeoeaio/fix-flash-error-color
Fix styling of error flash in admin section
2017-08-11 11:45:31 +02:00
Continuous Integration
b43b92dcfd Merge remote-tracking branch 'origin/master' into HEAD 2017-08-11 18:16:25 +10:00
Pau Perez
649c25622a Add doc to method 2017-08-11 14:41:02 +10:00
Pau Perez
1f2820f6d4 Add #delivery? in ShippingMethod 2017-08-11 14:41:02 +10:00
Pau Perez
22f018f2bc Fix all specs of LastUsedAddress 2017-08-11 14:41:02 +10:00
Pau Perez
8c5ac4cb23 Fix extra empty line reported by rubocop 2017-08-10 11:35:26 +02:00
Lynne
b9ff5674af Correction for Transifex name mismatch 2017-08-04 16:18:57 +01:00
Lynne
f0968109c6 Copy transifex updates to en-GB 2017-08-03 20:33:26 +01:00
Transifex-Openfoodnetwork
eeb41ccfdd Updating translations for config/locales/en_GB.yml [skip ci] 2017-08-04 04:30:40 +10:00
Continuous Integration
587a53d36d Merge remote-tracking branch 'origin/master' into HEAD 2017-08-04 03:56:40 +10:00
Transifex-Openfoodnetwork
ec7b7e0391 Updating translations for config/locales/sv.yml [skip ci] 2017-08-03 17:43:53 +10:00
Pau Perez
7f982c0c90 Complete seed data to purchase to Enterprise 2 2017-08-02 13:11:41 +02:00
Rob Harrington
6c71ef8760 Fix styling of error flash in admin section 2017-08-02 19:50:18 +10:00
Enrico Stano
936355d54b Merge pull request #1681 from coopdevs/release-notes-in-template
Add release notes section in github template
2017-08-02 10:59:30 +02:00
Enrico Stano
07620c2e62 Merge pull request #1707 from oeoeaio/mirror-db-session-data
Exclude session data when mirroring data
2017-08-02 10:45:46 +02:00
Maikel Linke
686a8f3af9 Add legacy and default values for LOCALE
This makes sure there is a value in `config.i18n.available_locales` so
that i18n-js doesn't crash.
2017-08-02 10:44:55 +10:00
Maikel Linke
199bfe531e Correct typo in comment 2017-08-02 10:01:12 +10:00
Julius Pabrinkis
e4627fe0d0 Update README 2017-08-02 09:57:33 +10:00
Julius Pabrinkis
ec6a365227 Add test coverage for switching language in darkswarm and admin 2017-08-02 09:57:33 +10:00
Julius Pabrinkis
c6f6f5bc55 Adapt karma js tests for i18n-js 2017-08-02 09:57:33 +10:00
Julius Pabrinkis
5166a3d958 Add available_locales config feature 2017-08-02 09:57:33 +10:00
Julius Pabrinkis
9429695e15 Add i18n helper for controllers to switch language by params 2017-08-02 09:57:32 +10:00
Julius Pabrinkis
f396d30747 Render i18n-js config inside darkswarm and admin layouts 2017-08-02 09:57:32 +10:00
Julius Pabrinkis
2637574c93 Require new i18n-js translations in darkswarm and admin 2017-08-02 09:57:32 +10:00
Julius Pabrinkis
d2ba4650e5 Add temporary i18n-js workaround for Spree translations until upgrade 2017-08-02 09:57:32 +10:00
Julius Pabrinkis
3adb13e62c Add i18n-js gem 2017-08-02 09:57:32 +10:00
Transifex-Openfoodnetwork
f69d86ab8f Updating translations for config/locales/nb.yml [skip ci] 2017-07-31 20:50:37 +10:00
Rob Harrington
7c0feab08f Fix #1526: add descriptions for reports *before* they are filtered 2017-07-28 17:15:57 +10:00
Matt-Yorkley
ea784d6362 Invoice date and translation adjustments 2017-07-28 16:34:43 +10:00
Maikel
6e57f917d2 Merge pull request #1736 from oeoeaio/fix-zeus-crash
Fix zeus issue caused by location of iframe_test.html
2017-07-28 16:31:41 +10:00
Maikel Linke
ba97f61c9e Move translations into right scope 2017-07-28 15:23:18 +10:00
Maikel Linke
c5eca68d79 Remove unused translation 2017-07-28 15:23:18 +10:00
Maikel Linke
92814162dc Remove unused translation 2017-07-28 15:23:18 +10:00
Maikel Linke
44374e8499 Display "+1 More" correctly 2017-07-28 15:23:18 +10:00
Rob Harrington
2ca04bb84e Revert translations of LettuceShare report headers 2017-07-28 12:07:58 +10:00
Rob Harrington
66a85bb99f Revert translations of Xero report headers 2017-07-28 12:07:52 +10:00
Rob Harrington
9f6931ba18 Move embedded shopfronts iframe view into spec/support/views
Was causing issues with zeus where it was (in spec/dummy)
Didn't get to the bottom of what was happening, this was
just a quick, simple and zero-cost solution
2017-07-28 11:54:48 +10:00
Rob Harrington
8fe6800151 Add documentation to the top of mirror_db script 2017-07-27 12:58:54 +10:00
Rob Harrington
e86122cb3e Exclude session data when mirroring data
Probably a better long term solution would be to add a job to clean
up old session data on the server, but this is a quick & dirty fix
to speed mirroring up on a slow connection.
2017-07-27 12:58:54 +10:00
Laura Turk
7641dcc1be Add media query to panepadding mixin 2017-07-26 16:29:44 +10:00
Leta Keane
8648070a05 Add disabled class to shopfront property selectors 2017-07-26 15:46:00 +10:00
Matt-Yorkley
5200937165 Safari/iOS iframe issue fix 2017-07-26 13:56:36 +10:00
Matt-Yorkley
6215777986 Shopfront review adjustments 2017-07-26 13:56:36 +10:00
Matt-Yorkley
0eb4c7f7ba Require https for embedding sites 2017-07-26 13:56:36 +10:00
Matt-Yorkley
782a812596 Basic Embedded Shopfronts 2017-07-26 13:56:36 +10:00
Matt-Yorkley
113f6565be Enable iframes for embedded shopfronts 2017-07-26 13:56:36 +10:00
Maikel Linke
b1452f097d Add spanish translations manually
A change in the Transifex API made the automated commit fail. Hence
doing it manually here.
2017-07-26 13:38:35 +10:00
Transifex-Openfoodnetwork
6384b5abb3 Updating translations for config/locales/fr.yml [skip ci] 2017-07-26 13:38:35 +10:00
Transifex-Openfoodnetwork
2c14ed848f Updating translations for config/locales/nb.yml [skip ci] 2017-07-26 13:38:35 +10:00
Maikel Linke
5dfac10599 Mention upgrade_bundler.sh in README 2017-07-26 13:37:42 +10:00
Maikel Linke
250062bd2f Upgrade bundler according to Gemfile.lock on CI 2017-07-26 13:37:42 +10:00
Maikel Linke
3f2299e52e Add script to upgrade bundler to Gemfile version
Useful to sync your bundler version or the CI bundler version with the
rest of the team.
2017-07-26 13:37:42 +10:00
Rob Harrington
327753b7ca Remove zeus and guard-zeus from the bundle
Having guard-zeus specified as a dependency is problematic because
it also pulls in the zeus gem as a dependency. This makes it impo-
ssible to update or switch zeus versions locally without affecting
other developers.

The maintainers of zeus say that it is designed to be installed and
run outside of the bundle: https://github.com/burke/zeus
2017-07-26 13:36:58 +10:00
Matt-Yorkley
ba447b547d Order tooltip localisation 2017-07-26 13:36:16 +10:00
Matt-Yorkley
8ebd49ec0f Company number localisation 2017-07-26 13:35:46 +10:00
Maikel Linke
155a2574bb Fix typo to display email address 2017-07-21 12:17:14 +10:00
Maikel Linke
b8c2e54194 Fix i18n key and spec 2017-07-21 12:17:14 +10:00
Maikel Linke
9f243e6d3c Fix title of /admin/content/edit
Spree uses the global i18n key `contents` to print the title. A previous
change made that an object containing other i18n keys which was then
displayed as title.

This change moves the i18n content to the scope of the view where they
are displayed.
2017-07-21 12:17:13 +10:00
Maikel Linke
ece8d8b518 Fix typo to display "Producer signup page" 2017-07-21 12:17:13 +10:00
Maikel Linke
0624c49a4f Fix typo to display "Tax Rates" report 2017-07-21 12:17:13 +10:00
Maikel Linke
71742a80b5 Make two more strings translatable 2017-07-21 12:17:13 +10:00
Maikel Linke
f4b1667005 Replace global translations by local ones 2017-07-21 12:17:13 +10:00
Maikel Linke
e5c9845b10 Remove duplicate haml code 2017-07-21 12:17:13 +10:00
Maikel Linke
d3fc89f42a Unify haml code for colouring 2017-07-21 12:17:13 +10:00
Maikel Linke
9c6454b47a Remove duplicated code
A label was accidentally inserted twice. Also removed some duplicate
translation.
2017-07-21 12:17:13 +10:00
Maikel Linke
7d2484c8bf Remove superfluous string interpolation 2017-07-21 12:17:13 +10:00
Maikel Linke
9723c8b82b Move translation into the right place
The dashboard couldn't find a translation, because it is in the spree
namespace.

Also simplified the translation using the `count` feature.
2017-07-21 12:17:13 +10:00
Julius Pabrinkis
8b2b51d511 Fix code style for Rubocop 2017-07-21 12:17:13 +10:00
Julius Pabrinkis
872a150c7d Refactor some translations to use interpolation 2017-07-21 12:17:13 +10:00
Julius Pabrinkis
3a0c0fd638 Fix failing tests 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
739d06cf03 Extract translations from javascript 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
9fa7a30c7e Fix failing tests and extract validation message Procs into methods 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
ba0b17e168 Extract translations from controllers 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
5caaec8ef3 Extract translations from mailers and helpers 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
9971c9f923 Extract translations from models 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
974099747b Fix failing specs after text extraction 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
1920ee7e88 Extract translations from serializers and overrides 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
55b2c19b64 Extract translations from lib folder 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
60060a7017 Start admin/reports extract translations 2017-07-21 12:17:12 +10:00
Julius Pabrinkis
ef488133e8 Add missing translations from files list. 2017-07-21 12:17:12 +10:00
clairezed
5c66a2fc9d Fix wrong key replacement for producer_shop_description_text 2017-07-21 11:15:03 +10:00
clairezed
5f8890e963 update producers pack translation key from sell_description_text to producer_shop_description_text 2017-07-21 11:15:03 +10:00
clairezed
58c463497a #1541 fixing wrong translation key in producers packs 2017-07-21 11:15:03 +10:00
Rob Harrington
3bb6d68adf Exclude node_modules from rubocop analysis
I don't need to see offences for node modules when I run rubocop locally
2017-07-21 11:06:16 +10:00
Duende13
705295049e Improved test for variant serializer 2017-07-21 10:18:55 +10:00
Duende13
a07fd854f6 New test for variant serializer 2017-07-21 10:18:55 +10:00
Duende13
b2bae242d9 Sorting variants by name_to_display and unit_value. Issue 1604. 2017-07-21 10:18:55 +10:00
Maikel Linke
1a57a0b3ca Revert changes in fr.yml 2017-07-19 09:46:23 +10:00
François Turbelin
a0595bc45a Add missing translations on views 2017-07-19 09:45:11 +10:00
Enrico Stano
8853340fa1 Merge pull request #1655 from oeoeaio/update-eventmachine
Bump eventmachine version to resolve openssl issue on macOS
2017-07-13 13:04:28 +02:00
Enrico Stano
bde3fa4ce6 Merge pull request #1671 from coopdevs/multiline-method-calls
Use indented style for multiline method calls
2017-07-12 18:40:34 +02:00
Pau Perez
cee24dcca7 Use indented style for multiline method calls
This enables the Rubocop's Style/MultilineMethodCallIndentation cop with
indentend enforced style. Which makes you split multiline method calls like:

  orders = Spree::Order
    .an_scope
    .another_scope
    .where(id: list_of_ids)

It also autofixes the current violations and updates the
rubocop_todo.yml
2017-07-12 10:40:53 +02:00
Pau Perez
c1789c4833 Add release notes section in github template
Hopefully, this will make it easier for Kirsten to fill in the release
notes from all the pull requests included in a release.
2017-07-12 08:26:45 +02:00
Maikel
6fbf902562 Merge pull request #1680 from mkllnk/entreprise-typo
Correct typo raised by Sergi
2017-07-12 15:14:06 +10:00
Maikel Linke
dc0da6f7b7 Correct typo raised by Sergi 2017-07-12 14:40:44 +10:00
Pau Perez
385847d7da Doc why FinalizeAccount uses order objects
Read the top-level class documentation for the details.
2017-07-12 11:49:04 +10:00
Rob Harrington
9d7f63db42 Bump eventmachine version to resolve openssl issue on macOS 2017-07-12 11:42:15 +10:00
Pau Perez
d0c6292e9d Add github template for pull requests 2017-07-07 13:56:12 +10:00
Matt-Yorkley
994023ec10 Update codeclimate version 2017-07-06 18:15:24 +10:00
Pau Perez
1028b49719 Stop using Order#shipment as it will be deprecated
Spree 2.0 adds a deprecation warning to it and Spree 2.1 removes it.
2017-07-05 16:33:04 +10:00
210 changed files with 6011 additions and 1078 deletions

View File

@@ -1,6 +1,7 @@
engines:
rubocop:
enabled: true
channel: rubocop-0-48
scss-lint:
enabled: false
ratings:

28
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,28 @@
#### What? Why?
[Explain why is this change needed and the solution you propose. Provide
context for others to understand it]
#### What should we test?
[List which features should be tested and how]
#### Release notes
[In case this should be present in the release notes, please write them or
remove this section otherwise]
#### How is this related to the Spree upgrade?
[Any known conflicts with the Spree Upgrade? explain them or remove this section
otherwise]
#### Discourse thread
[Is there a discussion about this in Discourse? add the link if so or remove
this section otherwise]
#### Dependencies
[Does this PR depend on another one? add the link of so or remove this section
otherwise]

View File

@@ -11,6 +11,8 @@ AllCops:
- 'db/**/*'
- 'config/**/*'
- 'script/**/*'
- 'vendor/**/*'
- 'node_modules/**/*'
- !ruby/regexp /old_and_unused\.rb$/
# OFN SETTINGS
@@ -25,6 +27,10 @@ Style/Documentation:
Style/StringLiterals:
Enabled: false
Layout/MultilineMethodCallIndentation:
Enabled: true
EnforcedStyle: indented
# TEMPORARY/CONTESTED SETTINGS
# These are still to be decided upon, but recommended for inclusion by
# oeoeaio after scrutinising offenses the codebase

View File

@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 100`
# on 2017-06-29 08:50:47 +1000 using RuboCop version 0.49.1.
# on 2017-07-12 10:36:44 +0200 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -526,54 +526,6 @@ Layout/MultilineMethodCallBraceLayout:
- 'lib/open_food_network/products_renderer.rb'
- 'spec/lib/open_food_network/products_and_inventory_report_spec.rb'
# Offense count: 191
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented, indented_relative_to_receiver
Layout/MultilineMethodCallIndentation:
Exclude:
- 'app/controllers/admin/order_cycles_controller.rb'
- 'app/controllers/admin/variant_overrides_controller.rb'
- 'app/controllers/api/order_cycles_controller.rb'
- 'app/controllers/base_controller.rb'
- 'app/controllers/checkout_controller.rb'
- 'app/controllers/spree/admin/orders_controller_decorator.rb'
- 'app/controllers/spree/admin/products_controller_decorator.rb'
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'app/controllers/spree/admin/search_controller_decorator.rb'
- 'app/controllers/spree/api/products_controller_decorator.rb'
- 'app/controllers/spree/orders_controller_decorator.rb'
- 'app/jobs/update_billable_periods.rb'
- 'app/models/column_preference.rb'
- 'app/models/enterprise.rb'
- 'app/models/enterprise_relationship.rb'
- 'app/models/exchange.rb'
- 'app/models/order_cycle.rb'
- 'app/models/product_importer.rb'
- 'app/models/spree/ability_decorator.rb'
- 'app/models/spree/calculator/default_tax_decorator.rb'
- 'app/models/spree/line_item_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/payment_method_decorator.rb'
- 'app/models/spree/product_decorator.rb'
- 'app/models/spree/shipping_method_decorator.rb'
- 'app/models/spree/taxon_decorator.rb'
- 'app/models/spree/user_decorator.rb'
- 'app/models/spree/variant_decorator.rb'
- 'app/serializers/api/admin/exchange_serializer.rb'
- 'lib/open_food_network/lettuce_share_report.rb'
- 'lib/open_food_network/order_cycle_form_applicator.rb'
- 'lib/open_food_network/order_cycle_permissions.rb'
- 'lib/open_food_network/permissions.rb'
- 'lib/open_food_network/products_cache.rb'
- 'spec/controllers/spree/admin/reports_controller_spec.rb'
- 'spec/helpers/order_cycles_helper_spec.rb'
- 'spec/jobs/update_account_invoices_spec.rb'
- 'spec/jobs/update_billable_periods_spec.rb'
- 'spec/lib/open_food_network/enterprise_fee_calculator_spec.rb'
- 'spec/mailers/producer_mailer_spec.rb'
- 'spec/support/matchers/table_matchers.rb'
# Offense count: 34
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
@@ -1064,7 +1016,70 @@ Lint/UselessAccessModifier:
Lint/Void:
Exclude:
- 'app/serializers/api/enterprise_serializer.rb'
- 'spec/**/*'
- 'spec/archive/features/consumer/checkout_spec.rb'
- 'spec/controllers/api/order_cycles_controller_spec.rb'
- 'spec/controllers/base_controller_spec.rb'
- 'spec/controllers/cart_controller_spec.rb'
- 'spec/controllers/checkout_controller_spec.rb'
- 'spec/controllers/enterprises_controller_spec.rb'
- 'spec/controllers/shop_controller_spec.rb'
- 'spec/controllers/spree/admin/adjustments_controller_spec.rb'
- 'spec/controllers/spree/admin/line_items_controller_spec.rb'
- 'spec/controllers/spree/admin/orders_controller_spec.rb'
- 'spec/controllers/spree/admin/variants_controller_spec.rb'
- 'spec/controllers/spree/api/products_controller_spec.rb'
- 'spec/controllers/spree/api/variants_controller_spec.rb'
- 'spec/controllers/spree/checkout_controller_spec.rb'
- 'spec/controllers/spree/orders_controller_spec.rb'
- 'spec/controllers/user_passwords_controller_spec.rb'
- 'spec/controllers/user_registrations_controller_spec.rb'
- 'spec/features/admin/enterprise_fees_spec.rb'
- 'spec/features/admin/enterprise_groups_spec.rb'
- 'spec/features/admin/enterprise_user_spec.rb'
- 'spec/features/admin/enterprises/index_spec.rb'
- 'spec/features/admin/enterprises_spec.rb'
- 'spec/features/admin/order_cycles_spec.rb'
- 'spec/features/admin/orders_spec.rb'
- 'spec/features/admin/payment_method_spec.rb'
- 'spec/features/admin/product_import_spec.rb'
- 'spec/features/admin/products_spec.rb'
- 'spec/features/admin/reports_spec.rb'
- 'spec/features/admin/shipping_methods_spec.rb'
- 'spec/features/admin/variant_overrides_spec.rb'
- 'spec/features/admin/variants_spec.rb'
- 'spec/features/consumer/shopping/checkout_spec.rb'
- 'spec/features/consumer/shopping/shopping_spec.rb'
- 'spec/features/consumer/shopping/variant_overrides_spec.rb'
- 'spec/helpers/html_helper_spec.rb'
- 'spec/helpers/products_helper_spec.rb'
- 'spec/lib/open_food_network/bulk_coop_report_spec.rb'
- 'spec/lib/open_food_network/enterprise_fee_applicator_spec.rb'
- 'spec/lib/open_food_network/enterprise_fee_calculator_spec.rb'
- 'spec/lib/open_food_network/enterprise_issue_validator_spec.rb'
- 'spec/lib/open_food_network/group_buy_report_spec.rb'
- 'spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb'
- 'spec/lib/open_food_network/packing_report_spec.rb'
- 'spec/lib/open_food_network/reports/report_spec.rb'
- 'spec/lib/open_food_network/reports/rule_spec.rb'
- 'spec/mailers/enterprise_mailer_spec.rb'
- 'spec/mailers/order_mailer_spec.rb'
- 'spec/models/cart_spec.rb'
- 'spec/models/enterprise_relationship_spec.rb'
- 'spec/models/enterprise_spec.rb'
- 'spec/models/exchange_spec.rb'
- 'spec/models/order_cycle_spec.rb'
- 'spec/models/product_distribution_spec.rb'
- 'spec/models/spree/adjustment_spec.rb'
- 'spec/models/spree/line_item_spec.rb'
- 'spec/models/spree/order_populator_spec.rb'
- 'spec/models/spree/order_spec.rb'
- 'spec/models/spree/payment_method_spec.rb'
- 'spec/models/spree/payment_spec.rb'
- 'spec/models/spree/product_spec.rb'
- 'spec/models/spree/variant_spec.rb'
- 'spec/models/variant_override_spec.rb'
- 'spec/serializers/enterprise_serializer_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 706
# Configuration parameters: CountComments, ExcludedMethods.

View File

@@ -22,6 +22,9 @@ env:
- CI_NODE_INDEX=3
- CI_NODE_INDEX=4 KARMA="true" GITHUB_DEPLOY="true"
before_install:
- ./script/upgrade_bundler.sh
before_script:
- cp config/database.travis.yml config/database.yml
- cp config/application.yml.example config/application.yml

View File

@@ -4,6 +4,7 @@ ruby "2.1.5"
gem 'rails', '3.2.21'
gem 'rails-i18n', '~> 3.0.0'
gem 'i18n', '~> 0.6.11'
gem 'i18n-js', '~> 3.0.0'
# Patched version. See http://rubysec.com/advisories/CVE-2015-5312/.
gem 'nokogiri', '>= 1.6.7.1'
@@ -126,8 +127,12 @@ group :development do
gem 'guard-livereload'
gem 'rack-livereload'
gem 'guard-rails'
gem 'guard-zeus'
gem 'guard-rspec'
gem 'parallel_tests'
gem 'rubocop', '>= 0.49.1'
# 1.0.9 fixed openssl issues on macOS https://github.com/eventmachine/eventmachine/issues/602
# While we don't require this gem directly, no dependents forced the upgrade to a version
# greater than 1.0.9, so we just required the latest available version here.
gem 'eventmachine', '>= 1.2.3'
end

View File

@@ -258,7 +258,7 @@ GEM
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.5.3)
erubis (2.7.0)
eventmachine (1.0.8)
eventmachine (1.2.3)
excon (0.45.4)
execjs (2.6.0)
factory_girl (3.3.0)
@@ -408,9 +408,6 @@ GEM
guard-rspec (4.0.4)
guard (>= 2.1.1)
rspec (~> 2.14)
guard-zeus (0.0.1)
guard
zeus
haml (4.0.4)
tilt
highline (1.6.11)
@@ -420,6 +417,8 @@ GEM
multi_json (~> 1.0)
multi_xml
i18n (0.6.11)
i18n-js (3.0.0)
i18n (~> 0.6, >= 0.6.6)
immigrant (0.1.6)
activerecord (>= 3.0)
foreigner (>= 1.2.1)
@@ -662,8 +661,6 @@ GEM
xml-simple (1.1.4)
xpath (2.0.0)
nokogiri (~> 1.3)
zeus (0.15.4)
method_source (>= 0.6.7)
PLATFORMS
ruby
@@ -693,6 +690,7 @@ DEPENDENCIES
deface!
delayed_job_active_record
diffy
eventmachine (>= 1.2.3)
factory_girl_rails
figaro
foreigner
@@ -706,9 +704,9 @@ DEPENDENCIES
guard-livereload
guard-rails
guard-rspec
guard-zeus
haml
i18n (~> 0.6.11)
i18n-js (~> 3.0.0)
immigrant
jquery-migrate-rails
jquery-rails
@@ -764,4 +762,4 @@ RUBY VERSION
ruby 2.1.5p273
BUNDLED WITH
1.15.1
1.15.2

View File

@@ -54,6 +54,7 @@ First, check your dependencies: Ensure that you have Ruby 2.1.5 installed:
Install the project's gem dependencies:
cd openfoodnetwork
./script/upgrade_bundler.sh
bundle install
Configure the site:
@@ -107,6 +108,9 @@ If you want karma to automatically rerun the tests on file modification, use:
./script/karma start
### Multilingual
Do not forget to run `rake tmp:cache:clear` after locales are updated to reload I18n js translations.
## Credits
* Andrew Spinks (http://github.com/andrewspinks)

View File

@@ -48,7 +48,7 @@
//= require textAngular-rangy.min.js
//= require textAngular-sanitize.min.js
//= require textAngular.min.js
//= require darkswarm/i18n.js
//= require i18n/translations
//= require darkswarm/i18n.translate.js

View File

@@ -14,8 +14,8 @@ angular.module("admin.businessModelConfiguration").controller "BusinessModelConf
$scope.cappedBill()
$scope.capReached = ->
return "No" if !$scope.cap? || Number($scope.cap) == 0
if $scope.bill() >= Number($scope.cap) then "Yes" else "No"
return t('no') if !$scope.cap? || Number($scope.cap) == 0
if $scope.bill() >= Number($scope.cap) then t('yes') else t('no')
$scope.includedTax = ->
return 0 if !$scope.taxRate? || Number($scope.taxRate) == 0

View File

@@ -21,7 +21,7 @@ angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $tem
if response.data.errors
scope.errors.push(error) for error in response.data.errors
else
scope.errors.push("Sorry! Could not create '#{scope.email}'")
scope.errors.push(t('js.customers.could_not_create') + " '#{scope.email}'")
return
# Compile modal template
@@ -35,4 +35,4 @@ angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $tem
if CurrentShop.shop.id
template.dialog('open')
else
alert('Please select a shop first')
alert(t('js.customers.select_shop'))

View File

@@ -2,7 +2,7 @@ angular.module('admin.enterpriseFees').directive 'spreeDeleteResource', ->
(scope, element, attrs) ->
if scope.enterprise_fee.id
url = '/admin/enterprise_fees/' + scope.enterprise_fee.id
html = '<a href="' + url + '" class="delete-resource icon_link icon-trash no-text" data-action="remove" data-confirm="Are you sure?" url="' + url + '"></a>'
html = '<a href="' + url + '" class="delete-resource icon_link icon-trash no-text" data-action="remove" data-confirm="' + t('are_you_sure') + '" url="' + url + '"></a>'
#var html = '<a href="'+url+'" class="delete-resource" data-confirm="Are you sure?"><img alt="Delete" src="/assets/admin/icons/delete.png" /> Delete</a>';
element.append html
return

View File

@@ -30,27 +30,27 @@ angular.module("admin.enterprises").controller 'enterprisesCtrl', ($scope, $q, E
$scope.producerTextFor = (enterprise) ->
switch enterprise.is_primary_producer
when true
"Producer"
t('js.enterprises.producer')
else
"Non-Producer"
t('js.enterprises.non_producer')
$scope.packageTextFor = (enterprise) ->
switch enterprise.is_primary_producer
when true
switch enterprise.sells
when "none"
"Profile"
t('js.profile')
when "own"
"Shop"
t('js.shop')
when "any"
"Hub"
t('js.hub')
else
"Choose"
t('js.choose')
else
switch enterprise.sells
when "none"
"Profile"
t('js.profile')
when "any"
"Hub"
t('js.hub')
else
"Choose"
t('js.choose')

View File

@@ -14,7 +14,7 @@ angular.module("admin.enterprises").controller 'indexPanelCtrl', ($scope, Enterp
, (response) ->
$scope.saving = false
if response.status == 422 && response.data.errors?
message = 'Please resolve the following errors:\n'
message = t('js.resolve_errors') + ':\n'
for attr, msg of response.data.errors
message += "#{attr} #{msg}\n"
alert(message)

View File

@@ -19,16 +19,16 @@ angular.module("admin.enterprises").factory 'PermalinkChecker', ($q, $http) ->
if data.length > @MAX_PERMALINK_LENGTH || !data.match(/^[\w-]+$/)
deferredRequest.resolve
permalink: permalink
available: "Error"
available: t('js.error')
else
deferredRequest.resolve
permalink: data
available: "Available"
available: t('available')
).error (data,status) =>
if status == 409
deferredRequest.resolve
permalink: data
available: "Unavailable"
available: t('js.unavailable')
else
# Something went wrong or request was aborted
deferredRequest.reject()

View File

@@ -21,16 +21,16 @@ angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, Sta
submitAll: (form=null) =>
all = []
@errors = []
StatusMessage.display('progress', "Saving...")
StatusMessage.display('progress', t('js.saving'))
for id, objectChanges of @pendingChanges
for attrName, change of objectChanges
all.push @submit(change)
$q.all(all).then =>
if @errors.length == 0
StatusMessage.display('success', "All changes saved successfully")
StatusMessage.display('success', t('js.all_changes_saved_successfully'))
form.$setPristine() if form?
else
StatusMessage.display('failure', "Oh no! I was unable to save your changes")
StatusMessage.display('failure', t('js.oh_no'))
all
submit: (change) ->

View File

@@ -10,7 +10,7 @@ angular.module("admin.indexUtils").factory "SpreeApiAuth", ($q, $http, SpreeApiK
deferred.resolve()
.error (response) ->
error = response?.error || "You are unauthorised to access this page."
error = response?.error || t('js.unauthorized')
deferred.reject(error)
deferred.promise

View File

@@ -51,13 +51,13 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
$scope.$watch 'bulk_order_form.$dirty', (newVal, oldVal) ->
if newVal == true
StatusMessage.display 'notice', "You have unsaved changes"
StatusMessage.display 'notice', t('js.unsaved_changes')
$scope.submit = ->
if $scope.bulk_order_form.$valid
StatusMessage.display 'progress', "Saving..."
StatusMessage.display 'progress', t('js.saving')
$q.all(LineItems.saveAll()).then(->
StatusMessage.display 'success', "All changes saved"
StatusMessage.display 'success', t('js.all_changes_saved')
$scope.bulk_order_form.$setPristine()
).catch ->
StatusMessage.display 'failure', t "unsaved_changes_error"

View File

@@ -84,7 +84,7 @@ angular.module('admin.orderCycles')
$scope.submit = ($event, destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
StatusMessage.display 'progress', t('js.saving')
OrderCycle.create(destination)
$scope.cancel = (destination) ->

View File

@@ -87,11 +87,11 @@ angular.module('admin.orderCycles')
$scope.submit = (destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
StatusMessage.display 'progress', t('js.saving')
$scope.submit = ($event, destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
StatusMessage.display 'progress', t('js.saving')
OrderCycle.update(destination, $scope.order_cycle_form)
$scope.cancel = (destination) ->

View File

@@ -49,7 +49,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl"
$scope.submit = ($event, destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
StatusMessage.display 'progress', t('js.saving')
OrderCycle.mirrorIncomingToOutgoingProducts()
OrderCycle.create(destination)

View File

@@ -42,7 +42,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
$scope.submit = ($event, destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
StatusMessage.display 'progress', t('js.saving')
OrderCycle.mirrorIncomingToOutgoingProducts()
OrderCycle.update(destination, $scope.order_cycle_form)

View File

@@ -165,13 +165,13 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
if destination?
$window.location = destination
else
StatusMessage.display 'success', 'Your order cycle has been updated.'
StatusMessage.display 'success', t('js.order_cycles.update_success')
else
console.log('Failed to update order cycle')
confirmNoDistributors: ->
if @order_cycle.outgoing_exchanges.length == 0
confirm 'There are no distributors in this order cycle. This order cycle will not be visible to customers until you add one. Would you like to continue saving this order cycle?'
confirm t('js.order_cycles.no_distributors')
else
true

View File

@@ -1,8 +1,7 @@
angular.module("ofn.admin").controller "ImportOptionsFormCtrl", ($scope, $rootScope, ProductImportService) ->
$scope.toggleResetAbsent = () ->
confirmed = confirm 'This will set stock level to zero on all products for this \n' +
'enterprise that are not present in the uploaded file.' if $scope.resetAbsent
confirmed = confirm t('js.product_import.confirmation') if $scope.resetAbsent
if confirmed or !$scope.resetAbsent
ProductImportService.updateResetAbsent($scope.supplierId, $scope.resetCount, $scope.resetAbsent)

View File

@@ -24,7 +24,7 @@ angular.module("admin.resources").factory "Customers", ($q, InfoDialog, RequestM
if errors?
InfoDialog.open 'error', errors[0]
else
InfoDialog.open 'error', "Could not delete customer: #{customer.email}"
InfoDialog.open 'error', t('js.resources.could_not_delete_customer') + ": #{customer.email}"
index: (params) ->
@clear()

View File

@@ -1,6 +1,6 @@
angular.module("ofn.admin").factory "ofnConfirmHandler", (pendingChanges, $compile, $q) ->
return (scope, callback) ->
template = "<div id='dialog-div' style='padding: 10px'><h6>Unsaved changes currently exist, save now or ignore?</h6></div>"
template = "<div id='dialog-div' style='padding: 10px'><h6>" + t('js.services.unsaved_changes_message') + "</h6></div>"
dialogDiv = $compile(template)(scope)
return ->
if pendingChanges.changeCount(pendingChanges.pendingChanges) > 0

View File

@@ -26,7 +26,7 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
permission_presentation: (permission) ->
switch permission
when "add_to_order_cycle" then "add to order cycle"
when "manage_products" then "manage products"
when "edit_profile" then "edit profile"
when "create_variant_overrides" then "add products to inventory"
when "add_to_order_cycle" then t('js.services.add_to_order_cycle')
when "manage_products" then t('js.services.manage_products')
when "edit_profile" then t('js.services.edit_profile')
when "create_variant_overrides" then t('js.services.add_products_to_inventory')

View File

@@ -2,7 +2,7 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil
$scope.tagGroups = enterprise.tag_groups
$scope.defaultTagGroup = enterprise.default_tag_group
$scope.visibilityOptions = [ { id: "visible", name: "VISIBLE" }, { id: "hidden", name: "NOT VISIBLE" } ]
$scope.visibilityOptions = [ { id: "visible", name: t('js.tag_rules.visible') }, { id: "hidden", name: t('js.tag_rules.not_visible') } ]
$scope.updateRuleCounts = ->
index = $scope.defaultTagGroup.rules.length
@@ -57,4 +57,4 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil
.success ->
tagGroup.rules.splice(index, 1)
$scope.updateRuleCounts()
$scope.enterprise_form.$setDirty()
$scope.enterprise_form.$setDirty()

View File

@@ -9,10 +9,10 @@ angular.module("admin.tagRules").directive 'newTagRuleDialog', ($compile, $templ
scope.ruleTypes = [
# { id: "DiscountOrder", name: 'Apply a discount to orders' }
{ id: "FilterProducts", name: 'Show or Hide variants in my shopfront' }
{ id: "FilterShippingMethods", name: 'Show or Hide shipping methods at checkout' }
{ id: "FilterPaymentMethods", name: 'Show or Hide payment methods at checkout' }
{ id: "FilterOrderCycles", name: 'Show or Hide order cycles in my shopfront' }
{ id: "FilterProducts", name: t('js.tag_rules.show_hide_variants') }
{ id: "FilterShippingMethods", name: t('js.tag_rules.show_hide_shipping') }
{ id: "FilterPaymentMethods", name: t('js.tag_rules.show_hide_payment') }
{ id: "FilterOrderCycles", name: t('js.tag_rules.show_hide_order_cycles') }
]
scope.ruleType = scope.ruleTypes[0].id

View File

@@ -15,11 +15,11 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
$scope.currentView = -> Views.currentView
$scope.views = Views.setViews
inventory: { name: "Inventory Products", visible: true }
hidden: { name: "Hidden Products", visible: false }
new: { name: "New Products", visible: false }
inventory: { name: t('js.variant_overrides.inventory_products'), visible: true }
hidden: { name: t('js.variant_overrides.hidden_products'), visible: false }
new: { name: t('js.variant_overrides.new_products'), visible: false }
$scope.bulkActions = [ name: "Reset Stock Levels To Defaults", callback: 'resetStock' ]
$scope.bulkActions = [ name: t('js.variant_overrides.reset_stock_levels'), callback: 'resetStock' ]
$scope.columns = Columns.columns
@@ -52,22 +52,22 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
$scope.displayDirty = ->
if DirtyVariantOverrides.count() > 0
num = if DirtyVariantOverrides.count() == 1 then "one override" else "#{DirtyVariantOverrides.count()} overrides"
StatusMessage.display 'notice', "Changes to #{num} remain unsaved."
num = if DirtyVariantOverrides.count() == 1 then t('js.variant_overrides.one_override') else "#{DirtyVariantOverrides.count()} " + t('js.variant_overrides.overrides')
StatusMessage.display 'notice', t('js.variant_overrides.changes_to') + ' ' + num + ' ' + t('js.variant_overrides.remain_unsaved')
else
StatusMessage.clear()
$scope.update = ->
if DirtyVariantOverrides.count() == 0
StatusMessage.display 'alert', 'No changes to save.'
StatusMessage.display 'alert', t('js.variant_overrides.no_changes_to_save')
else
StatusMessage.display 'progress', 'Saving...'
StatusMessage.display 'progress', t('js.saving')
DirtyVariantOverrides.save()
.success (updatedVos) ->
DirtyVariantOverrides.clear()
VariantOverrides.updateIds updatedVos
$scope.variant_overrides_form.$setPristine()
StatusMessage.display 'success', 'Changes saved.'
StatusMessage.display 'success', t('js.changes_saved')
VariantOverrides.updateData updatedVos # Refresh page data
.error (data, status) ->
StatusMessage.display 'failure', $scope.updateError(data, status)
@@ -75,32 +75,32 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
$scope.updateError = (data, status) ->
if status == 401
"I couldn't get authorisation to save those changes, so they remain unsaved."
t('js.variant_overrides.no_authorisation')
else if status == 400 && data.errors?
errors = []
for field, field_errors of data.errors
errors = errors.concat field_errors
errors = errors.join ', '
"I had some trouble saving: #{errors}"
t('js.variant_overrides.some_trouble', {errors: errors})
else
"Oh no! I was unable to save your changes."
t('js.oh_no')
$scope.resetStock = ->
if DirtyVariantOverrides.count() > 0
StatusMessage.display 'alert', 'Save changes first.'
StatusMessage.display 'alert', t('js.save_changes_first')
$timeout ->
$scope.displayDirty()
, 3000 # 3 second delay
else
return unless $scope.hub_id?
StatusMessage.display 'progress', 'Changing on hand stock levels...'
StatusMessage.display 'progress', t('js.variant_overrides.changing_on_hand_stock')
$http
method: "POST"
url: "/admin/variant_overrides/bulk_reset"
data: { hub_id: $scope.hub_id }
.success (updatedVos) ->
VariantOverrides.updateData updatedVos
StatusMessage.display 'success', 'Stocks reset to defaults.'
StatusMessage.display 'success', t('js.variant_overrides.stock_reset')
.error (data, status) ->
$timeout -> StatusMessage.display 'failure', $scope.updateError(data, status)

View File

@@ -16,7 +16,7 @@
#= require ../shared/angular-local-storage.js
#= require ../shared/angular-slideables.js
#= require angularjs-file-upload
#= require i18n/translations
#= require angular-rails-templates
#= require_tree ../templates

View File

@@ -1,9 +0,0 @@
<%# Defines a global I18n object containing the language of the current locale %>
<%
# Invalidate this asset if locale changes.
Dir[Rails.root.join('config', 'locales', "#{I18n.default_locale}.yml").to_s].each do |f|
depend_on(f)
end
%>
<%- I18n.backend.send(:init_translations) unless I18n.backend.initialized? %>
window.I18n = <%= I18n.backend.send(:translations)[I18n.default_locale].with_indifferent_access.to_json.html_safe %>

View File

@@ -1,17 +1,11 @@
# Old aliases before i18n-js was introduced.
# TODO - delete it after everything is moved to i18n-js
# Declares the translation function t.
# You can use translate('login') or t('login') in Javascript.
window.translate = (key, options = {}) ->
unless 'I18n' of window
console.log 'The I18n object is undefined. Cannot translate text.'
return key
dict = I18n
parts = key.split '.'
while (parts.length)
part = parts.shift()
return key unless part of dict
dict = dict[part]
text = dict
for name, value of options
text = text.split("%{#{name}}").join(value)
text
I18n.t(key, options)
window.t = window.translate

View File

@@ -6,4 +6,4 @@
{{ message }}
.action-buttons.text-center
%button{ ng: { click: "close()" } }
OK
= t(:ok)

View File

@@ -7,7 +7,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' }
Select all
= t('admin.select_all')
.exchange-products
-# Scope product list based on permissions the current user has to view variants in this exchange

View File

@@ -7,7 +7,7 @@
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
Select all
= t('admin.select_all')
.exchange-products
-# No need to scope product list based on permissions, because if an incoming exchange is visible,
@@ -36,7 +36,7 @@
'ofn-sync-distributions' => '{{ product.master_id }}',
'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(product.master_id) < 0' }
Obsolete master
= t('admin.obsolete_master')
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
%label

View File

@@ -1,5 +1,6 @@
.row.exchange-tags
.sixteen.columns.alpha.omega
%span.text-normal Tags
%span.text-normal
= t('admin.tags')
%br
%tags-with-translation.fullwidth{ object: 'object' }

View File

@@ -7,4 +7,5 @@
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_order_cycles_visibility",
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_order_cycles_visibility]",
ng: { value: "'hidden'", if: "rule.is_default" } }
%span.text-normal{ ng: { if: "rule.is_default" } } not visible
%span.text-normal{ ng: { if: "rule.is_default" } }
=t(:not_visible)

View File

@@ -7,4 +7,5 @@
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_payment_methods_visibility",
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_payment_methods_visibility]",
ng: { value: "'hidden'", if: "rule.is_default" } }
%span.text-normal{ ng: { if: "rule.is_default" } } not visible
%span.text-normal{ ng: { if: "rule.is_default" } }
= t(:not_visible)

View File

@@ -7,4 +7,5 @@
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_variants_visibility",
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_variants_visibility]",
ng: { value: "'hidden'", if: "rule.is_default" } }
%span.text-normal{ ng: { if: "rule.is_default" } } not visible
%span.text-normal{ ng: { if: "rule.is_default" } }
= t(:not_visible)

View File

@@ -7,4 +7,6 @@
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_shipping_methods_visibility",
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_shipping_methods_visibility]",
ng: { value: "'hidden'", if: "rule.is_default" } }
%span.text-normal{ ng: { if: "rule.is_default" } } not visible
%span.text-normal{ ng: { if: "rule.is_default" } }
= t(:not_visible)

View File

@@ -11,7 +11,7 @@
%span.filter-shopfront.property-selectors.pad-top
%ul.inline-block
%li{"ng-repeat" => "property in enterprise.supplied_properties"}
%a.button.tiny{"ng-bind" => "property.presentation"}
%a.button.tiny.disabled{"ng-bind" => "property.presentation"}
.about-container.pad-top
%img.enterprise-logo{"ng-src" => "{{::enterprise.logo}}", "ng-if" => "::enterprise.logo"}

View File

@@ -5,7 +5,7 @@
%li.more
%a.dropdown{ data: { dropdown: "{{ 'show-more-' + selectorName }}" }, ng: { class: "{active: selectedOverFlowSelectors().length > 0}" } }
%span
+ {{ overFlowSelectors().length }} more
= t('js.more_items', count: "{{ overFlowSelectors().length }}")
%i.ofn-i_052-point-down
.f-dropdown.text-right.content{ ng: { attr: { id: "{{ 'show-more-' + selectorName }}" } } }
%ul

View File

@@ -28,8 +28,8 @@ text-angular .ta-editor {
left: 275px;
}
span.error, div.error {
color: #DA5354;
span.error, div.error:not(.flash) {
color: #DA5354;
}
/* Fix conflict between Spree and elRTE's styles */

View File

@@ -0,0 +1,71 @@
body.embedded {
nav.top-bar {
ul.left, ul.center, ul.right li.current_hub {
display: none;
}
ul.right {
width: auto !important;
li {
float: left;
line-height: 4.6875rem;
height: 4.6875rem;
vertical-align: top;
}
li.powered-by {
display: inline-block;
}
}
&.show-for-large-up {
display: inherit !important;
}
&.show-for-medium-down {
display: none !important;
}
}
footer {
display: none;
}
}
nav.top-bar ul.right li.powered-by {
display: none;
margin-right: 0.4rem;
opacity: 0.6;
img {
height: 1.8em;
margin: 0px 0.4em 0.4em 0px;
}
span, a {
font-family: "Oswald", sans-serif;
font-size: 1rem;
font-weight: 300;
color: #555;
padding: 0 !important;
}
a:hover {
color: #000;
}
}
.blocked-cookies {
text-align: center;
margin-bottom: 0 !important;
&.hidden {
display: none;
}
a.button.allow {
background-color: rgba(0,0,0,0.25);
margin-bottom: 0.4em;
&:hover {
background-color: rgba(0,0,0,0.35);
}
}
}

View File

@@ -15,6 +15,10 @@
@mixin panepadding {
padding-top: 100px;
padding-bottom: 100px;
@media all and (max-width: 640px) {
padding-top: 25px;
}
}
@mixin paneWhiteText {

View File

@@ -15,11 +15,11 @@ class Admin::AccountsAndBillingSettingsController < Spree::Admin::BaseController
def start_job
if @update_account_invoices_job || @finalize_account_invoices_job
flash[:error] = "A task is already running, please wait until it has finished"
flash[:error] = I18n.t(:accounts_and_billing_task_already_running_error)
else
new_job = "#{params[:job][:name]}".camelize.constantize.new
Delayed::Job.enqueue new_job
flash[:success] = "Task Queued"
flash[:success] = I18n.t(:accounts_and_billing_start_task_notice)
end
redirect_to_edit

View File

@@ -1,12 +1,12 @@
module Admin
class ContentsController < Spree::Admin::BaseController
def edit
@preference_sections = [{name: 'Header', preferences: [:logo, :logo_mobile, :logo_mobile_svg]},
{name: 'Home page', preferences: [:home_hero, :home_show_stats]},
{name: 'Producer signup page', preferences: [:producer_signup_pricing_table_html, :producer_signup_case_studies_html, :producer_signup_detail_html]},
{name: 'Hub signup page', preferences: [:hub_signup_pricing_table_html, :hub_signup_case_studies_html, :hub_signup_detail_html]},
{name: 'Group signup page', preferences: [:group_signup_pricing_table_html, :group_signup_case_studies_html, :group_signup_detail_html]},
{name: 'Footer and External Links', preferences: [:footer_logo,
@preference_sections = [{name: I18n.t('admin.contents.edit.header'), preferences: [:logo, :logo_mobile, :logo_mobile_svg]},
{name: I18n.t('admin.contents.edit.home_page'), preferences: [:home_hero, :home_show_stats]},
{name: I18n.t('admin.contents.edit.producer_signup_page'), preferences: [:producer_signup_pricing_table_html, :producer_signup_case_studies_html, :producer_signup_detail_html]},
{name: I18n.t('admin.contents.edit.hub_signup_page'), preferences: [:hub_signup_pricing_table_html, :hub_signup_case_studies_html, :hub_signup_detail_html]},
{name: I18n.t('admin.contents.edit.group_signup_page'), preferences: [:group_signup_pricing_table_html, :group_signup_case_studies_html, :group_signup_detail_html]},
{name: I18n.t('admin.contents.edit.footer_and_external_links'), preferences: [:footer_logo,
:footer_facebook_url, :footer_twitter_url, :footer_instagram_url, :footer_linkedin_url, :footer_googleplus_url, :footer_pinterest_url,
:footer_email, :community_forum_url, :footer_links_md, :footer_about_url, :footer_tos_url]}]
end
@@ -21,7 +21,7 @@ module Admin
# Save any uploaded images
ContentConfig.save
flash[:success] = t(:successfully_updated, :resource => "Your content")
flash[:success] = t(:successfully_updated, :resource => I18n.t('admin.contents.edit.your_content'))
redirect_to main_app.edit_admin_content_path
end

View File

@@ -35,7 +35,7 @@ module Admin
if params.key? :enterprise_id
redirect_path = main_app.admin_enterprise_fees_path(enterprise_id: params[:enterprise_id])
end
redirect_to redirect_path, :notice => 'Your enterprise fees have been updated.'
redirect_to redirect_path, :notice => I18n.t(:enterprise_fees_update_notice)
else
render :index
@@ -49,7 +49,7 @@ module Admin
product_distribution = ProductDistribution.where(:enterprise_fee_id => @object).first
if product_distribution
p = product_distribution.product
error = "That enterprise fee cannot be deleted as it is referenced by a product distribution: #{p.id} - #{p.name}."
error = I18n.t(:enterprise_fees_destroy_error, id: p.id, name: p.name)
respond_with(@object) do |format|
format.html do

View File

@@ -57,7 +57,7 @@ module Admin
def register
if params[:sells] == 'unspecified'
flash[:error] = "Please select a package"
flash[:error] = I18n.t(:enterprise_register_package_error)
return render :welcome, layout: "spree/layouts/bare_admin"
end
@@ -68,10 +68,10 @@ module Admin
end
if @enterprise.update_attributes(attributes)
flash[:success] = "Congratulations! Registration for #{@enterprise.name} is complete!"
flash[:success] = I18n.t(:enterprise_register_success_notice, enterprise: @enterprise.name)
redirect_to admin_path
else
flash[:error] = "Could not complete registration for #{@enterprise.name}"
flash[:error] = I18n.t(:enterprise_register_error, enterprise: @enterprise.name)
render :welcome, layout: "spree/layouts/bare_admin"
end
end
@@ -80,19 +80,19 @@ module Admin
@enterprise_set = EnterpriseSet.new(collection, params[:enterprise_set])
touched_enterprises = @enterprise_set.collection.select(&:changed?)
if @enterprise_set.save
flash[:success] = "Enterprises updated successfully"
flash[:success] = I18n.t(:enterprise_bulk_update_success_notice)
# 18-3-2015: It seems that the form for this action sometimes loads bogus values for
# the 'sells' field, and submitting that form results in a bunch of enterprises with
# values that have mysteriously changed. This statement is here to help debug that
# issue, and should be removed (along with its display in index.html.haml) when the
# issue has been resolved.
flash[:action] = "Updated #{pluralize(touched_enterprises.count, 'enterprise')}: #{touched_enterprises.map(&:name).join(', ')}"
flash[:action] = "#{I18n.t(:updated)} #{pluralize(touched_enterprises.count, 'enterprise')}: #{touched_enterprises.map(&:name).join(', ')}"
redirect_to main_app.admin_enterprises_path
else
@enterprise_set.collection.select! { |e| touched_enterprises.include? e }
flash[:error] = 'Update failed'
flash[:error] = I18n.t(:enterprise_bulk_update_error)
render :index
end
end

View File

@@ -45,7 +45,7 @@ module Admin
if @order_cycle.save
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, spree_current_user).go!
flash[:notice] = 'Your order cycle has been created.'
flash[:notice] = I18n.t(:order_cycles_create_notice)
format.html { redirect_to admin_order_cycles_path }
format.json { render :json => {:success => true} }
else
@@ -64,7 +64,7 @@ module Admin
# Only update apply exchange information if it is actually submmitted
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, spree_current_user).go!
end
flash[:notice] = 'Your order cycle has been updated.' if params[:reloading] == '1'
flash[:notice] = I18n.t(:order_cycles_update_notice) if params[:reloading] == '1'
format.html { redirect_to main_app.edit_admin_order_cycle_path(@order_cycle) }
format.json { render :json => {:success => true} }
else
@@ -76,7 +76,7 @@ module Admin
def bulk_update
@order_cycle_set = params[:order_cycle_set] && OrderCycleSet.new(params[:order_cycle_set])
if @order_cycle_set.andand.save
redirect_to main_app.admin_order_cycles_path, :notice => 'Order cycles have been updated.'
redirect_to main_app.admin_order_cycles_path, notice: I18n.t(:order_cycles_bulk_update_notice)
else
render :index
end
@@ -85,14 +85,14 @@ module Admin
def clone
@order_cycle = OrderCycle.find params[:id]
@order_cycle.clone!
redirect_to main_app.admin_order_cycles_path, :notice => "Your order cycle #{@order_cycle.name} has been cloned."
redirect_to main_app.admin_order_cycles_path, notice: I18n.t(:order_cycles_clone_notice, name: @order_cycle.name)
end
# Send notifications to all producers who are part of the order cycle
def notify_producers
Delayed::Job.enqueue OrderCycleNotificationJob.new(params[:id].to_i)
redirect_to main_app.admin_order_cycles_path, :notice => 'Emails to be sent to producers have been queued for sending.'
redirect_to main_app.admin_order_cycles_path, notice: I18n.t(:order_cycles_email_to_producers_notice)
end
@@ -100,10 +100,10 @@ module Admin
def collection
ocs = if params[:as] == "distributor"
OrderCycle.ransack(params[:q]).result.
involving_managed_distributors_of(spree_current_user).order('updated_at DESC')
involving_managed_distributors_of(spree_current_user).order('updated_at DESC')
elsif params[:as] == "producer"
OrderCycle.ransack(params[:q]).result.
involving_managed_producers_of(spree_current_user).order('updated_at DESC')
involving_managed_producers_of(spree_current_user).order('updated_at DESC')
else
OrderCycle.ransack(params[:q]).result.accessible_by(spree_current_user)
end
@@ -138,12 +138,12 @@ module Admin
available_coordinators = permitted_coordinating_enterprises_for(@order_cycle).select(&:confirmed?)
case available_coordinators.count
when 0
flash[:error] = "None of your enterprises have permission to coordinate an order cycle"
flash[:error] = I18n.t(:order_cycles_no_permission_to_coordinate_error)
redirect_to main_app.admin_order_cycles_path
when 1
@order_cycle.coordinator = available_coordinators.first
else
flash[:error] = "You don't have permission to create an order cycle coordinated by that enterprise" if params[:coordinator_id]
flash[:error] = I18n.t(:order_cycles_no_permission_to_create_error) if params[:coordinator_id]
render :set_coordinator
end
end
@@ -153,7 +153,7 @@ module Admin
yield
rescue ActiveRecord::InvalidForeignKey
redirect_to main_app.admin_order_cycles_url
flash[:error] = "That order cycle has been selected by a customer and cannot be deleted. To prevent customers from accessing it, please close it instead."
flash[:error] = I18n.t(:order_cycles_no_permission_to_delete_error)
end
end

View File

@@ -25,7 +25,7 @@ class Admin::ProductImportController < Spree::Admin::BaseController
def validate_upload_presence
unless params[:file] || (params[:filepath] && File.exist?(params[:filepath]))
redirect_to '/admin/product_import', notice: 'File not found or could not be opened'
redirect_to '/admin/product_import', notice: I18n.t(:product_import_file_not_found_notice)
return
end
end
@@ -39,7 +39,7 @@ class Admin::ProductImportController < Spree::Admin::BaseController
def check_spreadsheet_has_data(importer)
unless importer.item_count
redirect_to '/admin/product_import', notice: 'No data found in spreadsheet'
redirect_to '/admin/product_import', notice: I18n.t(:product_import_no_data_in_spreadsheet_notice)
return
end
end

View File

@@ -11,10 +11,10 @@ module Api
def accessible
@order_cycles = if params[:as] == "distributor"
OrderCycle.ransack(params[:q]).result.
involving_managed_distributors_of(current_api_user).order('updated_at DESC')
involving_managed_distributors_of(current_api_user).order('updated_at DESC')
elsif params[:as] == "producer"
OrderCycle.ransack(params[:q]).result.
involving_managed_producers_of(current_api_user).order('updated_at DESC')
involving_managed_producers_of(current_api_user).order('updated_at DESC')
else
OrderCycle.ransack(params[:q]).result.accessible_by(current_api_user)
end

View File

@@ -3,6 +3,8 @@ require 'open_food_network/referer_parser'
class ApplicationController < ActionController::Base
protect_from_forgery
prepend_before_filter :restrict_iframes
include EnterprisesHelper
helper CssSplitter::ApplicationHelper
@@ -18,8 +20,70 @@ class ApplicationController < ActionController::Base
end
end
def shopfront_session
session[:safari_fix] = true
render 'shop/shopfront_session', layout: false
end
def enable_embedded_styles
session[:embedded_shopfront] = true
render json: {}, status: 200
end
def disable_embedded_styles
session.delete :embedded_shopfront
session.delete :shopfront_redirect
render json: {}, status: 200
end
protected
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)
end
def after_sign_out_path_for(_resource_or_scope)
session[:shopfront_redirect] ? session[:shopfront_redirect] : root_path
end
private
def restrict_iframes
response.headers['X-Frame-Options'] = 'DENY'
response.headers['Content-Security-Policy'] = "frame-ancestors 'none'"
end
def enable_embedded_shopfront
whitelist = Spree::Config[:embedded_shopfronts_whitelist]
return unless Spree::Config[:enable_embedded_shopfronts] && whitelist.present?
return if request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test?
response.headers.delete 'X-Frame-Options'
response.headers['Content-Security-Policy'] = "frame-ancestors #{whitelist}"
check_embedded_request
set_embedded_layout
end
def check_embedded_request
return unless params[:embedded_shopfront]
# Show embedded shopfront CSS
session[:embedded_shopfront] = true
# Get shopfront slug and set redirect path
if params[:controller] == 'enterprises' && params[:action] == 'shop' && params[:id]
slug = params[:id]
session[:shopfront_redirect] = '/' + slug + '/shop?embedded_shopfront=true'
end
end
def set_embedded_layout
return unless session[:embedded_shopfront]
@shopfront_layout = 'embedded'
end
def action
params[:action].to_sym
end

View File

@@ -8,6 +8,7 @@ class BaseController < ApplicationController
include Spree::Core::ControllerHelpers::Order
include Spree::Core::ControllerHelpers::RespondWith
include I18nHelper
include EnterprisesHelper
include OrderCyclesHelper
@@ -17,9 +18,9 @@ class BaseController < ApplicationController
# include Spree::ProductsHelper so that method is available on the controller
include Spree::ProductsHelper
before_filter :set_locale
before_filter :check_order_cycle_expiry
private
def set_order_cycles
@@ -29,7 +30,7 @@ class BaseController < ApplicationController
end
@order_cycles = OrderCycle.with_distributor(@distributor).active
.order(@distributor.preferred_shopfront_order_cycle_order)
.order(@distributor.preferred_shopfront_order_cycle_order)
applicator = OpenFoodNetwork::TagRuleApplicator.new(@distributor, "FilterOrderCycles", current_customer.andand.tag_list)
applicator.filter!(@order_cycles)

View File

@@ -9,6 +9,7 @@ class CheckoutController < Spree::CheckoutController
prepend_before_filter :require_distributor_chosen
skip_before_filter :check_registration
before_filter :enable_embedded_shopfront
include OrderCyclesHelper
include EnterprisesHelper
@@ -88,7 +89,7 @@ class CheckoutController < Spree::CheckoutController
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")
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"), {

View File

@@ -10,6 +10,7 @@ class EnterprisesController < BaseController
before_filter :check_stock_levels, only: :shop
before_filter :clean_permalink, only: :check_permalink
before_filter :enable_embedded_shopfront
respond_to :js, only: :permalink_checker

View File

@@ -1,6 +1,8 @@
class HomeController < BaseController
layout 'darkswarm'
before_filter :enable_embedded_shopfront
def index
if ContentConfig.home_show_stats
@num_distributors = Enterprise.is_distributor.activated.visible.count

View File

@@ -1,6 +1,8 @@
class ProducersController < BaseController
layout 'darkswarm'
before_filter :enable_embedded_shopfront
def index
end
end

View File

@@ -2,8 +2,8 @@ require 'open_food_network/cached_products_renderer'
class ShopController < BaseController
layout "darkswarm"
before_filter :require_distributor_chosen
before_filter :set_order_cycles
before_filter :require_distributor_chosen, :set_order_cycles, except: :changeable_orders_alert
before_filter :enable_embedded_shopfront
def show
redirect_to main_app.enterprise_shop_path(current_distributor)

View File

@@ -1,6 +1,8 @@
class ShopsController < BaseController
layout 'darkswarm'
before_filter :enable_embedded_shopfront
def index
end
end

View File

@@ -23,7 +23,7 @@ module Spree
@tax_rate_id = tr_yielding_matching_tax || tr_valid_for_order
if tr_yielding_matching_tax.nil?
@adjustment.errors.add :tax_rate_id, "^Please check that the tax rate for this adjustment is correct."
@adjustment.errors.add :tax_rate_id, I18n.t(:adjustments_tax_rate_error)
end
end
end

View File

@@ -1,6 +1,9 @@
require 'spree/core/controller_helpers/respond_with_decorator'
Spree::Admin::BaseController.class_eval do
include I18nHelper
before_filter :set_locale
before_filter :warn_invalid_order_cycles
# Warn the user when they have an active order cycle with hubs that are not ready
@@ -51,13 +54,9 @@ Spree::Admin::BaseController.class_eval do
distributor_names = distributors.map(&:name).join ', '
if distributors.count > 1
"The hubs #{distributor_names} are listed in an active order cycle, " +
"but do not have valid shipping and payment methods. " +
"Until you set these up, customers will not be able to shop at these hubs."
I18n.t(:active_distributors_not_ready_for_checkout_message_plural, distributor_names: distributor_names)
else
"The hub #{distributor_names} is listed in an active order cycle, " +
"but does not have valid shipping and payment methods. " +
"Until you set these up, customers will not be able to shop at this hub."
I18n.t(:active_distributors_not_ready_for_checkout_message_singular, distributor_names: distributor_names)
end
end

View File

@@ -112,9 +112,9 @@ Spree::Admin::OrdersController.class_eval do
# Replaced this search to filter orders to only show those distributed by current user (or all for admin user)
@search.result.includes([:user, :shipments, :payments]).
distributed_by_user(spree_current_user).
page(params[:page]).
per(params[:per_page] || Spree::Config[:orders_per_page])
distributed_by_user(spree_current_user).
page(params[:page]).
per(params[:per_page] || Spree::Config[:orders_per_page])
end
end

View File

@@ -18,55 +18,40 @@ Spree::Admin::ReportsController.class_eval do
include Spree::ReportsHelper
REPORT_TYPES = {
orders_and_fulfillment: [
['Order Cycle Supplier Totals',:order_cycle_supplier_totals],
['Order Cycle Supplier Totals by Distributor',:order_cycle_supplier_totals_by_distributor],
['Order Cycle Distributor Totals by Supplier',:order_cycle_distributor_totals_by_supplier],
['Order Cycle Customer Totals',:order_cycle_customer_totals]
],
products_and_inventory: [
['All products', :all_products],
['Inventory (on hand)', :inventory],
['LettuceShare', :lettuce_share]
],
customers: [
["Mailing List", :mailing_list],
["Addresses", :addresses]
],
order_cycle_management: [
["Payment Methods Report", :payment_methods],
["Delivery Report", :delivery]
],
sales_tax: [
["Tax Types", :tax_types],
["Tax Rates", :tax_rates]
],
packing: [
["Pack By Customer", :pack_by_customer],
["Pack By Supplier", :pack_by_supplier]
]
}
# Fetches user's distributors, suppliers and order_cycles
before_filter :load_data, only: [:customers, :products_and_inventory, :order_cycle_management, :packing]
# Render a partial for orders and fulfillment description
respond_override :index => { :html => { :success => lambda {
@reports[:orders_and_fulfillment][:description] =
render_to_string(partial: 'orders_and_fulfillment_description', layout: false, locals: {report_types: REPORT_TYPES[:orders_and_fulfillment]}).html_safe
@reports[:products_and_inventory][:description] =
render_to_string(partial: 'products_and_inventory_description', layout: false, locals: {report_types: REPORT_TYPES[:products_and_inventory]}).html_safe
@reports[:customers][:description] =
render_to_string(partial: 'customers_description', layout: false, locals: {report_types: REPORT_TYPES[:customers]}).html_safe
@reports[:order_cycle_management][:description] =
render_to_string(partial: 'order_cycle_management_description', layout: false, locals: {report_types: REPORT_TYPES[:order_cycle_management]}).html_safe
@reports[:packing][:description] =
render_to_string(partial: 'packing_description', layout: false, locals: {report_types: REPORT_TYPES[:packing]}).html_safe
@reports[:sales_tax][:description] =
render_to_string(partial: 'sales_tax_description', layout: false, locals: {report_types: REPORT_TYPES[:sales_tax]}).html_safe
} } }
def report_types
{
orders_and_fulfillment: [
[I18n.t('admin.reports.supplier_totals'), :order_cycle_supplier_totals],
[I18n.t('admin.reports.supplier_totals_by_distributor'), :order_cycle_supplier_totals_by_distributor],
[I18n.t('admin.reports.totals_by_supplier'), :order_cycle_distributor_totals_by_supplier],
[I18n.t('admin.reports.customer_totals'), :order_cycle_customer_totals]
],
products_and_inventory: [
[I18n.t('admin.reports.all_products'), :all_products],
[I18n.t('admin.reports.inventory'), :inventory],
[I18n.t('admin.reports.lettuce_share'), :lettuce_share]
],
customers: [
[I18n.t('admin.reports.mailing_list'), :mailing_list],
[I18n.t('admin.reports.addresses'), :addresses]
],
order_cycle_management: [
[I18n.t('admin.reports.payment_methods'), :payment_methods],
[I18n.t('admin.reports.delivery'), :delivery]
],
sales_tax: [
[I18n.t('admin.reports.tax_types'), :tax_types],
[I18n.t('admin.reports.tax_rates'), :tax_rates]
],
packing: [
[I18n.t('admin.reports.pack_by_customer'), :pack_by_customer],
[I18n.t('admin.reports.pack_by_supplier'), :pack_by_supplier]
]
}
end
# Overide spree reports list.
def index
@@ -76,7 +61,7 @@ Spree::Admin::ReportsController.class_eval do
# This action is short because we refactored it like bosses
def customers
@report_types = REPORT_TYPES[:customers]
@report_types = report_types[:customers]
@report_type = params[:report_type]
@report = OpenFoodNetwork::CustomersReport.new spree_current_user, params
render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv")
@@ -95,7 +80,7 @@ Spree::Admin::ReportsController.class_eval do
@suppliers = my_suppliers | my_distributors.map { |d| Spree::Product.in_distributor(d) }.flatten.map(&:supplier).uniq
@order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
@report_types = REPORT_TYPES[:order_cycle_management]
@report_types = report_types[:order_cycle_management]
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@@ -118,7 +103,7 @@ Spree::Admin::ReportsController.class_eval do
# My suppliers and any suppliers supplying products I distribute
@suppliers = my_suppliers | my_distributors.map { |d| Spree::Product.in_distributor(d) }.flatten.map(&:supplier).uniq
@order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
@report_types = REPORT_TYPES[:packing]
@report_types = report_types[:packing]
@report_type = params[:report_type]
# -- Build Report with Order Grouper
@@ -143,9 +128,9 @@ Spree::Admin::ReportsController.class_eval do
orders.select{ |order| orders_with_hidden_details.include? order }.each do |order|
# TODO We should really be hiding customer code here too, but until we
# have an actual association between order and customer, it's a bit tricky
order.bill_address.andand.assign_attributes(firstname: "HIDDEN", lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
order.ship_address.andand.assign_attributes(firstname: "HIDDEN", lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
order.assign_attributes(email: "HIDDEN")
order.bill_address.andand.assign_attributes(firstname: I18n.t('admin.reports.hidden'), lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
order.ship_address.andand.assign_attributes(firstname: I18n.t('admin.reports.hidden'), lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
order.assign_attributes(email: I18n.t('admin.reports.hidden'))
end
@report = OpenFoodNetwork::OrderAndDistributorReport.new orders
@@ -224,9 +209,9 @@ Spree::Admin::ReportsController.class_eval do
@suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer
@order_cycles = OrderCycle.active_or_complete.
involving_managed_distributors_of(spree_current_user).order('orders_close_at DESC')
involving_managed_distributors_of(spree_current_user).order('orders_close_at DESC')
@report_types = REPORT_TYPES[:orders_and_fulfillment]
@report_types = report_types[:orders_and_fulfillment]
@report_type = params[:report_type]
@include_blank = I18n.t(:all)
@@ -242,7 +227,7 @@ Spree::Admin::ReportsController.class_eval do
end
def products_and_inventory
@report_types = REPORT_TYPES[:products_and_inventory]
@report_types = report_types[:products_and_inventory]
if params[:report_type] != 'lettuce_share'
@report = OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user, params
else
@@ -252,7 +237,7 @@ Spree::Admin::ReportsController.class_eval do
end
def users_and_enterprises
# @report_types = REPORT_TYPES[:users_and_enterprises]
# @report_types = report_types[:users_and_enterprises]
@report = OpenFoodNetwork::UsersAndEnterprisesReport.new params
render_report(@report.header, @report.table, params[:csv], "users_and_enterprises_#{timestamp}.csv")
end
@@ -313,19 +298,33 @@ Spree::Admin::ReportsController.class_eval do
def authorized_reports
reports = {
:orders_and_distributors => {:name => "Orders And Distributors", :description => "Orders with distributor details"},
:bulk_coop => {:name => "Bulk Co-Op", :description => "Reports for Bulk Co-Op orders"},
:payments => {:name => "Payment Reports", :description => "Reports for Payments"},
:orders_and_fulfillment => {:name => "Orders & Fulfillment Reports", :description => ''},
:customers => {:name => "Customers", :description => 'Customer details'},
:products_and_inventory => {:name => "Products & Inventory", :description => ''},
:sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" },
:users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" },
:order_cycle_management => {:name => "Order Cycle Management", :description => ''},
:sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" },
:xero_invoices => { :name => "Xero Invoices", :description => 'Invoices for import into Xero' },
:packing => { :name => "Packing Reports", :description => '' }
:orders_and_distributors => {:name => I18n.t('admin.reports.orders_and_distributors.name'), :description => I18n.t('admin.reports.orders_and_distributors.description')},
:bulk_coop => {:name => I18n.t('admin.reports.bulk_coop.name'), :description => I18n.t('admin.reports.bulk_coop.description')},
:payments => {:name => I18n.t('admin.reports.payments.name'), :description => I18n.t('admin.reports.payments.description')},
:orders_and_fulfillment => {:name => I18n.t('admin.reports.orders_and_fulfillment.name'), :description => ''},
:customers => {:name => I18n.t('admin.reports.customers.name'), :description => ''},
:products_and_inventory => {:name => I18n.t('admin.reports.products_and_inventory.name'), :description => ''},
:sales_total => {:name => I18n.t('admin.reports.sales_total.name'), :description => I18n.t('admin.reports.sales_total.description')},
:users_and_enterprises => {:name => I18n.t('admin.reports.users_and_enterprises.name'), :description => I18n.t('admin.reports.users_and_enterprises.description')},
:order_cycle_management => {:name => I18n.t('admin.reports.order_cycle_management.name'), :description => ''},
:sales_tax => {:name => I18n.t('admin.reports.sales_tax.name'), :description => ''},
:xero_invoices => {:name => I18n.t('admin.reports.xero_invoices.name'), :description => I18n.t('admin.reports.xero_invoices.description')},
:packing => {:name => I18n.t('admin.reports.packing.name'), :description => ''}
}
reports[:orders_and_fulfillment][:description] =
render_to_string(partial: 'orders_and_fulfillment_description', layout: false, locals: {report_types: report_types[:orders_and_fulfillment]}).html_safe
reports[:products_and_inventory][:description] =
render_to_string(partial: 'products_and_inventory_description', layout: false, locals: {report_types: report_types[:products_and_inventory]}).html_safe
reports[:customers][:description] =
render_to_string(partial: 'customers_description', layout: false, locals: {report_types: report_types[:customers]}).html_safe
reports[:order_cycle_management][:description] =
render_to_string(partial: 'order_cycle_management_description', layout: false, locals: {report_types: report_types[:order_cycle_management]}).html_safe
reports[:packing][:description] =
render_to_string(partial: 'packing_description', layout: false, locals: {report_types: report_types[:packing]}).html_safe
reports[:sales_tax][:description] =
render_to_string(partial: 'sales_tax_description', layout: false, locals: {report_types: report_types[:sales_tax]}).html_safe
# Return only reports the user is authorized to view.
reports.select { |action| can? action, :report }
end

View File

@@ -19,7 +19,7 @@ Spree::Admin::SearchController.class_eval do
def 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])
.result.where(enterprise_id: params[:distributor_id])
else
@customers = []
end

View File

@@ -38,7 +38,7 @@ module Spree
def do_not_destroy_referenced_shipping_methods
order = Order.where(:shipping_method_id => @object).first
if order
flash[:error] = "That shipping method cannot be deleted as it is referenced by an order: #{order.number}."
flash[:error] = I18n.t(:shipping_method_destroy_error, number: order.number)
redirect_to collection_url and return
end
end

View File

@@ -4,6 +4,8 @@ Spree::CheckoutController.class_eval do
include CheckoutHelper
before_filter :enable_embedded_shopfront
def edit
flash.keep
redirect_to main_app.checkout_path

View File

@@ -4,6 +4,7 @@ Spree::OrdersController.class_eval do
after_filter :populate_variant_attributes, only: :populate
before_filter :update_distribution, only: :update
before_filter :filter_order_params, only: :update
before_filter :enable_embedded_shopfront
prepend_before_filter :require_order_cycle, only: :edit
prepend_before_filter :require_distributor_chosen, only: :edit
@@ -132,7 +133,7 @@ Spree::OrdersController.class_eval do
distributor = Enterprise.is_distributor.find params[:order][:distributor_id]
@order.set_distributor! distributor
flash[:notice] = 'Your hub has been selected.'
flash[:notice] = I18n.t(:order_choosing_hub_notice)
redirect_to request.referer
elsif params[:commit] == 'Choose Order Cycle'
@@ -140,7 +141,7 @@ Spree::OrdersController.class_eval do
order_cycle = OrderCycle.active.find params[:order][:order_cycle_id]
@order.set_order_cycle! order_cycle
flash[:notice] = 'Your order cycle has been selected.'
flash[:notice] = I18n.t(:order_choosing_hub_notice)
redirect_to request.referer
end
end
@@ -239,7 +240,7 @@ Spree::OrdersController.class_eval do
return unless order_to_update.andand.complete?
items = params[:order][:line_items_attributes]
.andand.select{ |k,attrs| attrs["quantity"].to_i > 0 }
.andand.select{ |k,attrs| attrs["quantity"].to_i > 0 }
if items.empty?
flash[:error] = I18n.t(:orders_cannot_remove_the_final_item)

View File

@@ -2,6 +2,7 @@ Spree::PaypalController.class_eval do
include CheckoutHelper
after_filter :reset_order_when_complete, only: :confirm
before_filter :enable_embedded_shopfront
def cancel
flash[:notice] = t('flash.cancel', :scope => 'paypal')

View File

@@ -1,3 +1,5 @@
Spree::UsersController.class_eval do
layout 'darkswarm'
before_filter :enable_embedded_shopfront
end

View File

@@ -48,7 +48,7 @@ module EnterprisesHelper
def enterprise_type_name(enterprise)
if enterprise.sells == 'none'
enterprise.producer_profile_only ? 'Profile' : 'Supplier Only'
enterprise.producer_profile_only ? I18n.t(:profile) : I18n.t(:supplier_only)
else
"Has Shopfront"
end
@@ -56,7 +56,7 @@ module EnterprisesHelper
def enterprise_confirm_delete_message(enterprise)
if enterprise.supplied_products.present?
"This will also delete the #{pluralize enterprise.supplied_products.count, 'product'} that this enterprise supplies. Are you sure you want to continue?"
I18n.t(:enterprise_confirm_delete_message, product: pluralize(enterprise.supplied_products.count, 'product'))
else
t(:are_you_sure)
end

View File

@@ -0,0 +1,7 @@
module I18nHelper
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end

View File

@@ -85,14 +85,14 @@ module OrderCyclesHelper
disabled_message = nil
if options[:shipping_and_payment_methods] && (e.shipping_methods.empty? || e.payment_methods.available.empty?)
if e.shipping_methods.empty? && e.payment_methods.available.empty?
disabled_message = 'no shipping or payment methods'
disabled_message = I18n.t(:no_shipping_or_payment)
elsif e.shipping_methods.empty?
disabled_message = 'no shipping methods'
disabled_message = I18n.t(:no_shipping)
elsif e.payment_methods.available.empty?
disabled_message = 'no payment methods'
disabled_message = I18n.t(:no_payment)
end
elsif options[:confirmed] && !e.confirmed?
disabled_message = 'unconfirmed'
disabled_message = I18n.t(:unconfirmed)
end
if disabled_message

View File

@@ -15,9 +15,9 @@ module Spree
end
def product_variant_unit_options
[['Weight', 'weight'],
['Volume', 'volume'],
['Items', 'items']]
[[I18n.t(:weight), 'weight'],
[I18n.t(:volume), 'volume'],
[I18n.t(:items), 'items']]
end
end
end

View File

@@ -25,8 +25,8 @@ module Spree
end
def xero_report_types
[['Summary', 'summary'],
['Detailed', 'detailed']]
[[I18n.t(:summary), 'summary'],
[I18n.t(:detailed), 'detailed']]
end
def currency_symbol

View File

@@ -1,3 +1,17 @@
# This class is part of the system that charges hubs for using OFN. It does so
# by creating orders. These are not orders for food that customers place, but
# instead are orders for OFN usage, so to speak. Thus, they're technically not
# "shipped" anywhere, so they're just given a default shipping method.
#
# The "orders" used by this class are not real orders, they are basically
# "invoices" that enterprise owners need to pay for use of an open food network
# instance. The amount that the enterprise owner is charged is configurable by
# the instance, and can be based on a combination of a percentage of their
# turnover, fixed fees, caps and floors and trial periods. This "orders" hold
# the billing information for a particular enterprise owner for a given month.
#
# We assign them also a default shipping method because there is a validation
# on Spree::Shipment that requires it.
class FinalizeAccountInvoices
attr_reader :year, :month, :start_date, :end_date

View File

@@ -106,8 +106,8 @@ class UpdateBillablePeriods
end
obsolete_billable_periods.includes({ account_invoice: :order}).
where('spree_orders.state <> \'complete\' OR account_invoices.order_id IS NULL').
each(&:delete)
where('spree_orders.state <> \'complete\' OR account_invoices.order_id IS NULL').
each(&:delete)
end
private

View File

@@ -10,7 +10,7 @@ class ProducerMailer < Spree::BaseMailer
@total = total_from_line_items(line_items)
@tax_total = tax_total_from_line_items(line_items)
subject = "[#{Spree::Config.site_name}] Order cycle report for #{producer.name}"
subject = "[#{Spree::Config.site_name}] #{I18n.t('producer_mailer.order_cycle.subject', producer: producer.name)}"
if has_orders? order_cycle, producer
mail(to: @producer.email,

View File

@@ -25,7 +25,7 @@ class BillablePeriod < ActiveRecord::Base
def label
enterprise_version = enterprise.version_at(begins_at)
category = enterprise_version.category.to_s.titleize
category += (trial ? " Trial" : "")
category += (trial ? " #{I18n.t(:trial)}" : "")
"#{enterprise_version.name} (#{category})"
end

View File

@@ -17,19 +17,19 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration
has_attached_file :home_hero, default_url: "/assets/home/home.jpg"
# Producer sign-up page
preference :producer_signup_pricing_table_html, :text, default: "(TODO: Pricing table)"
preference :producer_signup_case_studies_html, :text, default: "(TODO: Case studies)"
preference :producer_signup_detail_html, :text, default: "(TODO: Detail)"
preference :producer_signup_pricing_table_html, :text, default: I18n.t(:content_configuration_pricing_table)
preference :producer_signup_case_studies_html, :text, default: I18n.t(:content_configuration_case_studies)
preference :producer_signup_detail_html, :text, default: I18n.t(:content_configuration_detail)
# Hubs sign-up page
preference :hub_signup_pricing_table_html, :text, default: "(TODO: Pricing table)"
preference :hub_signup_case_studies_html, :text, default: "(TODO: Case studies)"
preference :hub_signup_detail_html, :text, default: "(TODO: Detail)"
preference :hub_signup_pricing_table_html, :text, default: I18n.t(:content_configuration_pricing_table)
preference :hub_signup_case_studies_html, :text, default: I18n.t(:content_configuration_case_studies)
preference :hub_signup_detail_html, :text, default: I18n.t(:content_configuration_detail)
# Groups sign-up page
preference :group_signup_pricing_table_html, :text, default: "(TODO: Pricing table)"
preference :group_signup_case_studies_html, :text, default: "(TODO: Case studies)"
preference :group_signup_detail_html, :text, default: "(TODO: Detail)"
preference :group_signup_pricing_table_html, :text, default: I18n.t(:content_configuration_pricing_table)
preference :group_signup_case_studies_html, :text, default: I18n.t(:content_configuration_case_studies)
preference :group_signup_detail_html, :text, default: I18n.t(:content_configuration_detail)
# Footer
preference :footer_logo, :file

View File

@@ -41,7 +41,7 @@ class Customer < ActiveRecord::Base
def check_for_orders
return true unless orders.any?
errors[:base] << "Delete failed: customer has associated orders"
errors[:base] << I18n.t('admin.customers.destroy.has_associated_orders')
false
end
end

View File

@@ -103,9 +103,9 @@ class Enterprise < ActiveRecord::Base
scope :activated, where("confirmed_at IS NOT NULL AND sells != 'unspecified'")
scope :ready_for_checkout, lambda {
joins(:shipping_methods).
joins(:payment_methods).
merge(Spree::PaymentMethod.available).
select('DISTINCT enterprises.*')
joins(:payment_methods).
merge(Spree::PaymentMethod.available).
select('DISTINCT enterprises.*')
}
scope :not_ready_for_checkout, lambda {
# When ready_for_checkout is empty, ActiveRecord generates the SQL:
@@ -152,25 +152,25 @@ class Enterprise < ActiveRecord::Base
scope :active_distributors, lambda {
with_distributed_products_outer.with_order_cycles_as_distributor_outer.
where('(product_distributions.product_id IS NOT NULL AND spree_products.deleted_at IS NULL AND spree_products.available_on <= ? AND spree_products.count_on_hand > 0) OR (order_cycles.id IS NOT NULL AND order_cycles.orders_open_at <= ? AND order_cycles.orders_close_at >= ?)', Time.zone.now, Time.zone.now, Time.zone.now).
select('DISTINCT enterprises.*')
where('(product_distributions.product_id IS NOT NULL AND spree_products.deleted_at IS NULL AND spree_products.available_on <= ? AND spree_products.count_on_hand > 0) OR (order_cycles.id IS NOT NULL AND order_cycles.orders_open_at <= ? AND order_cycles.orders_close_at >= ?)', Time.zone.now, Time.zone.now, Time.zone.now).
select('DISTINCT enterprises.*')
}
scope :distributors_with_active_order_cycles, lambda {
with_order_cycles_as_distributor_outer.
merge(OrderCycle.active).
select('DISTINCT enterprises.*')
merge(OrderCycle.active).
select('DISTINCT enterprises.*')
}
scope :distributing_products, lambda { |products|
# TODO: remove this when we pull out product distributions
pds = joins("INNER JOIN product_distributions ON product_distributions.distributor_id = enterprises.id").
where("product_distributions.product_id IN (?)", products).select('DISTINCT enterprises.id')
where("product_distributions.product_id IN (?)", products).select('DISTINCT enterprises.id')
exs = joins("INNER JOIN exchanges ON (exchanges.receiver_id = enterprises.id AND exchanges.incoming = 'f')").
joins('INNER JOIN exchange_variants ON (exchange_variants.exchange_id = exchanges.id)').
joins('INNER JOIN spree_variants ON (spree_variants.id = exchange_variants.variant_id)').
where('spree_variants.product_id IN (?)', products).select('DISTINCT enterprises.id')
joins('INNER JOIN exchange_variants ON (exchange_variants.exchange_id = exchanges.id)').
joins('INNER JOIN spree_variants ON (spree_variants.id = exchange_variants.variant_id)').
where('spree_variants.product_id IN (?)', products).select('DISTINCT enterprises.id')
where(id: pds | exs)
}
@@ -378,7 +378,7 @@ class Enterprise < ActiveRecord::Base
dups = dups.where('id != ?', id) unless new_record?
if dups.any?
errors.add :name, "has already been taken. If this is your enterprise and you would like to claim ownership, please contact the current manager of this profile at #{dups.first.owner.email}."
errors.add :name, I18n.t(:enterprise_name_error, email: dups.first.owner.email)
end
end
@@ -427,7 +427,7 @@ class Enterprise < ActiveRecord::Base
def enforce_ownership_limit
unless owner.can_own_more_enterprises?
errors.add(:owner, "^#{owner.email} is not permitted to own any more enterprises (limit is #{owner.enterprise_limit}).")
errors.add(:owner, I18n.t(:enterprise_owner_error, email: owner.email, enterprise_limit: owner.enterprise_limit ))
end
end

View File

@@ -58,23 +58,23 @@ class EnterpriseGroup < ActiveRecord::Base
}
def set_unused_address_fields
address.firstname = address.lastname = 'unused'
address.firstname = address.lastname = I18n.t(:unused)
end
def set_undefined_address_fields
address.phone.present? || address.phone = 'undefined'
address.address1.present? || address.address1 = 'undefined'
address.city.present? || address.city = 'undefined'
address.phone.present? || address.phone = I18n.t(:undefined)
address.address1.present? || address.address1 = I18n.t(:undefined)
address.city.present? || address.city = I18n.t(:undefined)
address.state.present? || address.state = address.country.states.first
address.zipcode.present? || address.zipcode = 'undefined'
address.zipcode.present? || address.zipcode = I18n.t(:undefined)
end
def unset_undefined_address_fields
return unless address.present?
address.phone.sub!(/^undefined$/, '')
address.address1.sub!(/^undefined$/, '')
address.city.sub!(/^undefined$/, '')
address.zipcode.sub!(/^undefined$/, '')
address.phone.sub!(/^#{I18n.t(:undefined)}$/, '')
address.address1.sub!(/^#{I18n.t(:undefined)}$/, '')
address.city.sub!(/^#{I18n.t(:undefined)}$/, '')
address.zipcode.sub!(/^#{I18n.t(:undefined)}$/, '')
end
def to_param

View File

@@ -21,7 +21,7 @@ class EnterpriseRelationship < ActiveRecord::Base
scope :with_permission, ->(permission) {
joins(:permissions).
where('enterprise_relationship_permissions.name = ?', permission)
where('enterprise_relationship_permissions.name = ?', permission)
}
scope :by_name, with_enterprises.order('child_enterprises.name, parent_enterprises.name')

View File

@@ -3,7 +3,7 @@ class EnterpriseRole < ActiveRecord::Base
belongs_to :enterprise
validates_presence_of :user_id, :enterprise_id
validates_uniqueness_of :enterprise_id, scope: :user_id, message: "^That role is already present."
validates_uniqueness_of :enterprise_id, scope: :user_id, message: I18n.t(:enterprise_role_uniqueness_error)
scope :by_user_email, joins(:user).order('spree_users.email ASC')
end

View File

@@ -33,14 +33,14 @@ class Exchange < ActiveRecord::Base
scope :with_any_variant, lambda { |variants| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', variants).select('DISTINCT exchanges.*') }
scope :with_product, lambda { |product| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', product.variants_including_master) }
scope :by_enterprise_name, joins('INNER JOIN enterprises AS sender ON (sender.id = exchanges.sender_id)').
joins('INNER JOIN enterprises AS receiver ON (receiver.id = exchanges.receiver_id)').
order("CASE WHEN exchanges.incoming='t' THEN sender.name ELSE receiver.name END")
joins('INNER JOIN enterprises AS receiver ON (receiver.id = exchanges.receiver_id)').
order("CASE WHEN exchanges.incoming='t' THEN sender.name ELSE receiver.name END")
# Exchanges on order cycles that are dated and are upcoming or open are cached
scope :cachable, outgoing.
joins(:order_cycle).
merge(OrderCycle.dated).
merge(OrderCycle.not_closed)
joins(:order_cycle).
merge(OrderCycle.dated).
merge(OrderCycle.not_closed)
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')

View File

@@ -9,7 +9,7 @@ class InventoryItem < ActiveRecord::Base
validates :variant_id, uniqueness: { scope: :enterprise_id }
validates :enterprise_id, presence: true
validates :variant_id, presence: true
validates :visible, inclusion: { in: [true, false], message: "must be true or false" }
validates :visible, inclusion: { in: [true, false], message: I18n.t(:inventory_item_visibility_error) }
scope :visible, where(visible: true)
scope :hidden, where(visible: false)

View File

@@ -36,9 +36,9 @@ class OrderCycle < ActiveRecord::Base
scope :distributing_product, lambda { |product|
joins(:exchanges).
merge(Exchange.outgoing).
merge(Exchange.with_product(product)).
select('DISTINCT order_cycles.*') }
merge(Exchange.outgoing).
merge(Exchange.with_product(product)).
select('DISTINCT order_cycles.*') }
scope :with_distributor, lambda { |distributor|
joins(:exchanges).merge(Exchange.outgoing).merge(Exchange.to_enterprise(distributor))
@@ -59,14 +59,14 @@ class OrderCycle < ActiveRecord::Base
scoped
else
with_exchanging_enterprises_outer.
where('order_cycles.coordinator_id IN (?) OR enterprises.id IN (?)', user.enterprises, user.enterprises).
select('DISTINCT order_cycles.*')
where('order_cycles.coordinator_id IN (?) OR enterprises.id IN (?)', user.enterprises, user.enterprises).
select('DISTINCT order_cycles.*')
end
}
scope :with_exchanging_enterprises_outer, lambda {
joins('LEFT OUTER JOIN exchanges ON (exchanges.order_cycle_id = order_cycles.id)').
joins('LEFT OUTER JOIN enterprises ON (enterprises.id = exchanges.sender_id OR enterprises.id = exchanges.receiver_id)')
joins('LEFT OUTER JOIN enterprises ON (enterprises.id = exchanges.sender_id OR enterprises.id = exchanges.receiver_id)')
}
scope :involving_managed_distributors_of, lambda { |user|
@@ -75,8 +75,8 @@ class OrderCycle < ActiveRecord::Base
# Order cycles where I managed an enterprise at either end of an outgoing exchange
# ie. coordinator or distibutor
joins(:exchanges).merge(Exchange.outgoing).
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises).
select('DISTINCT order_cycles.*')
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises).
select('DISTINCT order_cycles.*')
}
scope :involving_managed_producers_of, lambda { |user|
@@ -85,8 +85,8 @@ class OrderCycle < ActiveRecord::Base
# Order cycles where I managed an enterprise at either end of an incoming exchange
# ie. coordinator or producer
joins(:exchanges).merge(Exchange.incoming).
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises).
select('DISTINCT order_cycles.*')
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises).
select('DISTINCT order_cycles.*')
}
def self.first_opening_for(distributor)
@@ -106,12 +106,12 @@ class OrderCycle < ActiveRecord::Base
def self.earliest_closing_times
Hash[
Exchange.
outgoing.
joins(:order_cycle).
merge(OrderCycle.active).
group('exchanges.receiver_id').
select('exchanges.receiver_id AS receiver_id, MIN(order_cycles.orders_close_at) AS earliest_close_at').
map { |ex| [ex.receiver_id, ex.earliest_close_at.to_time] }
outgoing.
joins(:order_cycle).
merge(OrderCycle.active).
group('exchanges.receiver_id').
select('exchanges.receiver_id AS receiver_id, MIN(order_cycles.orders_close_at) AS earliest_close_at').
map { |ex| [ex.receiver_id, ex.earliest_close_at.to_time] }
]
end

View File

@@ -22,6 +22,6 @@ class ProductDistribution < ActiveRecord::Base
end
def adjustment_label_for(line_item)
"Product distribution by #{distributor.name} for #{line_item.product.name}"
I18n.t(:products_distribution_adjustment_label, distributor: distributor.name, product: line_item.product.name )
end
end

View File

@@ -18,7 +18,7 @@ class ProductImporter
@products_to_create = {}
@variants_to_create = {}
@variants_to_update = {}
@products_created = 0
@variants_created = 0
@variants_updated = 0
@@ -33,7 +33,7 @@ class ProductImporter
init_product_importer if @sheet
else
self.errors.add(:importer, 'error: no file uploaded')
self.errors.add(:importer, I18n.t(:product_importer_file_error))
end
end
@@ -140,7 +140,7 @@ class ProductImporter
if accepted_mimetype
Roo::Spreadsheet.open(@file, extension: accepted_mimetype)
else
self.errors.add(:importer, 'could not process file: invalid filetype')
self.errors.add(:importer, I18n.t(:product_importer_spreadsheet_error))
delete_uploaded_file
nil
end
@@ -212,17 +212,17 @@ class ProductImporter
supplier_name = entry.supplier
if supplier_name.blank?
mark_as_invalid(entry, attribute: "supplier", error: "can't be blank")
mark_as_invalid(entry, attribute: "supplier", error: I18n.t(:error_required))
return
end
unless supplier_exists?(supplier_name)
mark_as_invalid(entry, attribute: "supplier", error: "\"#{supplier_name}\" not found in database")
mark_as_invalid(entry, attribute: "supplier", error: I18n.t(:error_not_found_in_database, name: supplier_name))
return
end
unless permission_by_name?(supplier_name)
mark_as_invalid(entry, attribute: "supplier", error: "\"#{supplier_name}\": you do not have permission to manage products for this enterprise")
mark_as_invalid(entry, attribute: "supplier", error: I18n.t(:error_no_permission_for_enterprise, name: supplier_name))
return
end
@@ -237,14 +237,14 @@ class ProductImporter
category_name = entry.category
if category_name.blank?
mark_as_invalid(entry, attribute: "category", error: "can't be blank")
mark_as_invalid(entry, attribute: "category", error: I18n.t(:error_required))
return
end
if category_exists?(category_name)
entry.primary_taxon_id = @categories_index[category_name]
else
mark_as_invalid(entry, attribute: "category", error: "\"#{category_name}\" not found in database")
mark_as_invalid(entry, attribute: "category", error: I18n.t(:error_not_found_in_database, name: category_name))
end
end
@@ -335,7 +335,7 @@ class ProductImporter
end
end
self.errors.add(:importer, "did not save any products successfully") if total_saved_count.zero?
self.errors.add(:importer, I18n.t(:product_importer_products_save_error)) if total_saved_count.zero?
reset_absent_products
total_saved_count

View File

@@ -4,6 +4,10 @@ Spree::AppConfiguration.class_eval do
# we can allow to be modified in the UI by adding appropriate form
# elements to existing or new configuration pages.
# Embedded Shopfronts
preference :enable_embedded_shopfronts, :boolean, default: false
preference :embedded_shopfronts_whitelist, :text, default: nil
# Terms of Service Preferences
preference :enterprises_require_tos, :boolean, default: false

View File

@@ -19,9 +19,9 @@ Spree::Calculator::DefaultTax.class_eval do
# Added this block, finds relevant fees for each line_item, calculates the tax on them, and returns the total tax
per_item_fees_total = order.line_items.sum do |line_item|
calculator.send(:per_item_enterprise_fee_applicators_for, line_item.variant)
.select { |applicator| (!applicator.enterprise_fee.inherits_tax_category && applicator.enterprise_fee.tax_category == rate.tax_category) ||
(applicator.enterprise_fee.inherits_tax_category && line_item.product.tax_category == rate.tax_category) }
.sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) }
.select { |applicator| (!applicator.enterprise_fee.inherits_tax_category && applicator.enterprise_fee.tax_category == rate.tax_category) ||
(applicator.enterprise_fee.inherits_tax_category && line_item.product.tax_category == rate.tax_category) }
.sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) }
end
# Added this block, finds relevant fees for whole order, calculates the tax on them, and returns the total tax

View File

@@ -13,7 +13,7 @@ Spree::Classification.class_eval do
def dont_destroy_if_primary_taxon
if product.primary_taxon == taxon
errors.add :base, "Taxon #{taxon.name} is the primary taxon of #{product.name} and cannot be deleted"
errors.add :base, I18n.t(:spree_classification_primary_taxon_error, taxon: taxon.name, product: product.name)
return false
end
end

View File

@@ -19,28 +19,28 @@ Spree::LineItem.class_eval do
else
# Find line items that are from orders distributed by the user or supplied by the user
joins(:variant => :product).
joins(:order).
where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)', user.enterprises, user.enterprises).
select('spree_line_items.*')
joins(:order).
where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)', user.enterprises, user.enterprises).
select('spree_line_items.*')
end
}
scope :supplied_by, lambda { |enterprise|
joins(:product).
where('spree_products.supplier_id = ?', enterprise)
where('spree_products.supplier_id = ?', enterprise)
}
scope :supplied_by_any, lambda { |enterprises|
joins(:product).
where('spree_products.supplier_id IN (?)', enterprises)
where('spree_products.supplier_id IN (?)', enterprises)
}
scope :with_tax, joins(:adjustments).
where('spree_adjustments.originator_type = ?', 'Spree::TaxRate').
select('DISTINCT spree_line_items.*')
where('spree_adjustments.originator_type = ?', 'Spree::TaxRate').
select('DISTINCT spree_line_items.*')
# Line items without a Spree::TaxRate-originated adjustment
scope :without_tax, joins("LEFT OUTER JOIN spree_adjustments ON (spree_adjustments.adjustable_id=spree_line_items.id AND spree_adjustments.adjustable_type = 'Spree::LineItem' AND spree_adjustments.originator_type='Spree::TaxRate')").
where('spree_adjustments.id IS NULL')
where('spree_adjustments.id IS NULL')
def cap_quantity_at_stock!

View File

@@ -29,7 +29,7 @@ Spree::Order.class_eval do
go_to_state :delivery
go_to_state :payment, :if => lambda { |order|
# Fix for #2191
if order.shipping_method.andand.require_ship_address and
if order.shipping_method.andand.delivery?
if order.ship_address.andand.valid?
order.create_shipment!
order.update_totals
@@ -50,8 +50,8 @@ Spree::Order.class_eval do
# Find orders that are distributed by the user or have products supplied by the user
# WARNING: This only filters orders, you'll need to filter line items separately using LineItem.managed_by
with_line_items_variants_and_products_outer.
where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)', user.enterprises, user.enterprises).
select('DISTINCT spree_orders.*')
where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)', user.enterprises, user.enterprises).
select('DISTINCT spree_orders.*')
end
}
@@ -65,8 +65,8 @@ Spree::Order.class_eval do
scope :with_line_items_variants_and_products_outer, lambda {
joins('LEFT OUTER JOIN spree_line_items ON (spree_line_items.order_id = spree_orders.id)').
joins('LEFT OUTER JOIN spree_variants ON (spree_variants.id = spree_line_items.variant_id)').
joins('LEFT OUTER JOIN spree_products ON (spree_products.id = spree_variants.product_id)')
joins('LEFT OUTER JOIN spree_variants ON (spree_variants.id = spree_line_items.variant_id)').
joins('LEFT OUTER JOIN spree_products ON (spree_products.id = spree_variants.product_id)')
}
scope :not_state, lambda { |state|
@@ -76,7 +76,7 @@ Spree::Order.class_eval do
# -- Methods
def products_available_from_new_distribution
# Check that the line_items in the current order are available from a newly selected distribution
errors.add(:base, "Distributor or order cycle cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distribution?(distributor, order_cycle)
errors.add(:base, I18n.t(:spree_order_availability_error)) unless DistributionChangeValidator.new(self).can_change_to_distribution?(distributor, order_cycle)
end
def empty_with_clear_shipping_and_payments!

View File

@@ -8,7 +8,7 @@ Spree::OrderPopulator.class_eval do
# Refactor: We may not need this validation - we can't change distribution here, so
# this validation probably can't fail
if !distribution_can_supply_products_in_cart(@distributor, @order_cycle)
errors.add(:base, "That distributor or order cycle can't supply all the products in your cart. Please choose another.")
errors.add(:base, I18n.t(:spree_order_populator_error))
end
if valid?
@@ -124,7 +124,7 @@ Spree::OrderPopulator.class_eval do
if DistributionChangeValidator.new(@order).variants_available_for_distribution(@distributor, @order_cycle).include? variant
return true
else
errors.add(:base, "That product is not available from the chosen distributor or order cycle.")
errors.add(:base, I18n.t(:spree_order_populator_availability_error))
return false
end
end

View File

@@ -11,7 +11,7 @@ Spree::PaymentMethod.class_eval do
after_initialize :init
validates :distributors, presence: { message: "^At least one hub must be selected" }
validates_with DistributorsValidator
# -- Scopes
scope :managed_by, lambda { |user|
@@ -19,14 +19,14 @@ Spree::PaymentMethod.class_eval do
scoped
else
joins(:distributors).
where('distributors_payment_methods.distributor_id IN (?)', user.enterprises).
select('DISTINCT spree_payment_methods.*')
where('distributors_payment_methods.distributor_id IN (?)', user.enterprises).
select('DISTINCT spree_payment_methods.*')
end
}
scope :for_distributor, lambda { |distributor|
joins(:distributors).
where('enterprises.id = ?', distributor)
where('enterprises.id = ?', distributor)
}
scope :by_name, order('spree_payment_methods.name ASC')
@@ -34,8 +34,8 @@ Spree::PaymentMethod.class_eval do
# Rewrite Spree's ruby-land class method as a scope
scope :available, lambda { |display_on='both'|
where(active: true).
where('spree_payment_methods.display_on=? OR spree_payment_methods.display_on=? OR spree_payment_methods.display_on IS NULL', display_on, '').
where('spree_payment_methods.environment=? OR spree_payment_methods.environment=? OR spree_payment_methods.environment IS NULL', Rails.env, '')
where('spree_payment_methods.display_on=? OR spree_payment_methods.display_on=? OR spree_payment_methods.display_on IS NULL', display_on, '').
where('spree_payment_methods.environment=? OR spree_payment_methods.environment=? OR spree_payment_methods.environment IS NULL', Rails.env, '')
}
def init

View File

@@ -47,17 +47,17 @@ Spree::Product.class_eval do
scope :with_product_distributions_outer, joins('LEFT OUTER JOIN product_distributions ON product_distributions.product_id = spree_products.id')
scope :with_order_cycles_outer, joins('LEFT OUTER JOIN spree_variants AS o_spree_variants ON (o_spree_variants.product_id = spree_products.id)').
joins('LEFT OUTER JOIN exchange_variants AS o_exchange_variants ON (o_exchange_variants.variant_id = o_spree_variants.id)').
joins('LEFT OUTER JOIN exchanges AS o_exchanges ON (o_exchanges.id = o_exchange_variants.exchange_id)').
joins('LEFT OUTER JOIN order_cycles AS o_order_cycles ON (o_order_cycles.id = o_exchanges.order_cycle_id)')
joins('LEFT OUTER JOIN exchange_variants AS o_exchange_variants ON (o_exchange_variants.variant_id = o_spree_variants.id)').
joins('LEFT OUTER JOIN exchanges AS o_exchanges ON (o_exchanges.id = o_exchange_variants.exchange_id)').
joins('LEFT OUTER JOIN order_cycles AS o_order_cycles ON (o_order_cycles.id = o_exchanges.order_cycle_id)')
scope :with_order_cycles_inner, joins(:variants_including_master => {:exchanges => :order_cycle})
scope :visible_for, lambda { |enterprise|
joins('LEFT OUTER JOIN spree_variants AS o_spree_variants ON (o_spree_variants.product_id = spree_products.id)').
joins('LEFT OUTER JOIN inventory_items AS o_inventory_items ON (o_spree_variants.id = o_inventory_items.variant_id)').
where('o_inventory_items.enterprise_id = (?) AND visible = (?)', enterprise, true).
select('DISTINCT spree_products.*')
joins('LEFT OUTER JOIN inventory_items AS o_inventory_items ON (o_spree_variants.id = o_inventory_items.variant_id)').
where('o_inventory_items.enterprise_id = (?) AND visible = (?)', enterprise, true).
select('DISTINCT spree_products.*')
}
@@ -73,16 +73,16 @@ Spree::Product.class_eval do
distributor = distributor.respond_to?(:id) ? distributor.id : distributor.to_i
with_product_distributions_outer.with_order_cycles_outer.
where('product_distributions.distributor_id = ? OR (o_exchanges.incoming = ? AND o_exchanges.receiver_id = ?)', distributor, false, distributor).
select('distinct spree_products.*')
where('product_distributions.distributor_id = ? OR (o_exchanges.incoming = ? AND o_exchanges.receiver_id = ?)', distributor, false, distributor).
select('distinct spree_products.*')
}
scope :in_product_distribution_by, lambda { |distributor|
distributor = distributor.respond_to?(:id) ? distributor.id : distributor.to_i
with_product_distributions_outer.
where('product_distributions.distributor_id = ?', distributor).
select('distinct spree_products.*')
where('product_distributions.distributor_id = ?', distributor).
select('distinct spree_products.*')
}
# Find products that are supplied by a given enterprise or distributed via that enterprise EITHER through a product distribution OR through an order cycle
@@ -90,19 +90,19 @@ Spree::Product.class_eval do
enterprise = enterprise.respond_to?(:id) ? enterprise.id : enterprise.to_i
with_product_distributions_outer.with_order_cycles_outer.
where('spree_products.supplier_id = ? OR product_distributions.distributor_id = ? OR (o_exchanges.incoming = ? AND o_exchanges.receiver_id = ?)', enterprise, enterprise, false, enterprise).
select('distinct spree_products.*')
where('spree_products.supplier_id = ? OR product_distributions.distributor_id = ? OR (o_exchanges.incoming = ? AND o_exchanges.receiver_id = ?)', enterprise, enterprise, false, enterprise).
select('distinct spree_products.*')
}
# Find products that are distributed by the given order cycle
scope :in_order_cycle, lambda { |order_cycle| with_order_cycles_inner.
merge(Exchange.outgoing).
where('order_cycles.id = ?', order_cycle) }
merge(Exchange.outgoing).
where('order_cycles.id = ?', order_cycle) }
scope :in_an_active_order_cycle, lambda { with_order_cycles_inner.
merge(OrderCycle.active).
merge(Exchange.outgoing).
where('order_cycles.id IS NOT NULL') }
merge(OrderCycle.active).
merge(Exchange.outgoing).
where('order_cycles.id IS NOT NULL') }
scope :by_producer, joins(:supplier).order('enterprises.name')
scope :by_name, order('name')

View File

@@ -8,21 +8,21 @@ Spree::ShippingMethod.class_eval do
attr_accessible :distributor_ids, :description
attr_accessible :require_ship_address, :tag_list
validates :distributors, presence: { message: "^At least one hub must be selected" }
validates_with DistributorsValidator
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
scoped
else
joins(:distributors).
where('distributors_shipping_methods.distributor_id IN (?)', user.enterprises).
select('DISTINCT spree_shipping_methods.*')
where('distributors_shipping_methods.distributor_id IN (?)', user.enterprises).
select('DISTINCT spree_shipping_methods.*')
end
}
scope :for_distributor, lambda { |distributor|
joins(:distributors).
where('enterprises.id = ?', distributor)
where('enterprises.id = ?', distributor)
}
scope :by_name, order('spree_shipping_methods.name ASC')
@@ -33,12 +33,12 @@ Spree::ShippingMethod.class_eval do
def self.services
Hash[
Spree::ShippingMethod.
joins(:distributor_shipping_methods).
group('distributor_id').
select("distributor_id").
select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup").
select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery").
map { |sm| [sm.distributor_id.to_i, {pickup: sm.pickup == 't', delivery: sm.delivery == 't'}] }
joins(:distributor_shipping_methods).
group('distributor_id').
select("distributor_id").
select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup").
select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery").
map { |sm| [sm.distributor_id.to_i, {pickup: sm.pickup == 't', delivery: sm.delivery == 't'}] }
]
end
@@ -64,6 +64,15 @@ Spree::ShippingMethod.class_eval do
'Shipping'
end
# Checks whether the shipping method is of delivery type, meaning that it
# requires the user to specify a ship address at checkout. Note this is
# a setting we added onto the +spree_shipping_methods+ table.
#
# @return [Boolean]
def delivery?
require_ship_address
end
private
def touch_distributors

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