Compare commits

..

5 Commits

Author SHA1 Message Date
Matt-Yorkley
49de11567b Report environment correctly in Bugsnag JS 2020-03-31 17:16:13 +01:00
Matt-Yorkley
3af0365c6b Rename partial to bugsnag_js for clarity 2020-03-31 17:16:13 +01:00
Matt-Yorkley
be92b0049b Move conditional inside partial and use default key as fallback 2020-03-31 17:16:13 +01:00
Matt-Yorkley
a1c94d0d9f Add bugsnag js script to admin layout above all.js 2020-03-31 17:16:13 +01:00
Maikel Linke
f6bb8a9a04 Add Bugsnag JS logging 2020-03-31 17:16:13 +01:00
774 changed files with 13177 additions and 23453 deletions

1
.gitignore vendored
View File

@@ -31,7 +31,6 @@ public/system
public/stylesheets
public/images
public/spree
public/assets
config/abr.yml
config/initializers/feature_toggle.rb
NERD_tree*

View File

@@ -33,6 +33,7 @@ Layout/LineLength:
- app/controllers/admin/inventory_items_controller.rb
- app/controllers/admin/manager_invitations_controller.rb
- app/controllers/admin/product_import_controller.rb
- app/controllers/admin/proxy_orders_controller.rb
- app/controllers/admin/schedules_controller.rb
- app/controllers/admin/subscriptions_controller.rb
- app/controllers/admin/variant_overrides_controller.rb
@@ -88,6 +89,7 @@ Layout/LineLength:
- app/models/spree/tax_rate_decorator.rb
- app/models/spree/taxon_decorator.rb
- app/models/spree/user.rb
- app/models/spree/variant_decorator.rb
- app/models/subscription.rb
- app/models/variant_override.rb
- app/models/variant_override_set.rb
@@ -96,6 +98,7 @@ Layout/LineLength:
- app/services/embedded_page_service.rb
- app/services/order_cycle_form.rb
- app/services/order_factory.rb
- app/services/subscriptions_count.rb
- app/services/variants_stock_levels.rb
- engines/web/app/helpers/web/cookies_policy_helper.rb
- lib/discourse/single_sign_on.rb
@@ -155,6 +158,7 @@ Layout/LineLength:
- spec/controllers/spree/admin/orders/customer_details_controller_spec.rb
- spec/controllers/spree/admin/orders_controller_spec.rb
- spec/controllers/spree/admin/payment_methods_controller_spec.rb
- spec/controllers/spree/admin/payments_controller_spec.rb
- spec/controllers/spree/admin/products_controller_spec.rb
- spec/controllers/spree/admin/reports_controller_spec.rb
- spec/controllers/spree/admin/variants_controller_spec.rb
@@ -179,6 +183,7 @@ Layout/LineLength:
- spec/features/admin/image_settings_spec.rb
- spec/features/admin/multilingual_spec.rb
- spec/features/admin/order_cycles_spec.rb
- spec/features/admin/orders_spec.rb
- spec/features/admin/overview_spec.rb
- spec/features/admin/payment_method_spec.rb
- spec/features/admin/product_import_spec.rb
@@ -234,7 +239,10 @@ Layout/LineLength:
- spec/lib/open_food_network/packing_report_spec.rb
- spec/lib/open_food_network/permissions_spec.rb
- spec/lib/open_food_network/products_and_inventory_report_spec.rb
- spec/lib/open_food_network/proxy_order_syncer_spec.rb
- spec/lib/open_food_network/scope_variant_to_hub_spec.rb
- spec/lib/open_food_network/subscription_payment_updater_spec.rb
- spec/lib/open_food_network/subscription_summarizer_spec.rb
- spec/lib/open_food_network/tag_rule_applicator_spec.rb
- spec/lib/open_food_network/users_and_enterprises_report_spec.rb
- spec/lib/open_food_network/xero_invoices_report_spec.rb
@@ -309,6 +317,10 @@ Layout/LineLength:
- spec/services/permissions/order_spec.rb
- spec/services/product_tag_rules_filterer_spec.rb
- spec/services/products_renderer_spec.rb
- spec/services/subscription_estimator_spec.rb
- spec/services/subscription_form_spec.rb
- spec/services/subscription_validator_spec.rb
- spec/services/subscription_variants_service_spec.rb
- spec/spec_helper.rb
- spec/support/cancan_helper.rb
- spec/support/delayed_job_helper.rb
@@ -374,6 +386,7 @@ Metrics/AbcSize:
- app/helpers/spree/admin/base_helper.rb
- app/helpers/spree/admin/zones_helper.rb
- app/helpers/spree/orders_helper.rb
- app/mailers/producer_mailer.rb
- app/models/calculator/flat_percent_per_item.rb
- app/models/column_preference.rb
- app/models/enterprise.rb
@@ -398,7 +411,7 @@ Metrics/AbcSize:
- app/services/cart_service.rb
- app/services/create_order_cycle.rb
- app/services/order_syncer.rb
- engines/order_management/app/services/order_management/subscriptions/validator.rb
- app/services/subscription_validator.rb
- lib/active_merchant/billing/gateways/stripe_decorator.rb
- lib/active_merchant/billing/gateways/stripe_payment_intents.rb
- lib/discourse/single_sign_on.rb
@@ -464,6 +477,7 @@ Metrics/BlockLength:
- spec/factories/shipping_method_factory.rb
- spec/factories/subscription_factory.rb
- spec/factories/variant_factory.rb
- spec/features/admin/orders_spec.rb
- spec/features/consumer/shopping/embedded_shopfronts_spec.rb
- spec/lib/open_food_network/group_buy_report_spec.rb
- spec/models/tag_rule/discount_order_spec.rb
@@ -569,6 +583,7 @@ Metrics/MethodLength:
- app/helpers/spree/admin/navigation_helper.rb
- app/helpers/spree/admin/base_helper.rb
- app/jobs/subscription_placement_job.rb
- app/mailers/producer_mailer.rb
- app/models/column_preference.rb
- app/models/enterprise.rb
- app/models/enterprise_relationship.rb
@@ -671,12 +686,6 @@ Metrics/ModuleLength:
- app/helpers/injection_helper.rb
- app/helpers/spree/admin/navigation_helper.rb
- app/helpers/spree/admin/base_helper.rb
- engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb
- engines/order_management/spec/services/order_management/subscriptions/form_spec.rb
- engines/order_management/spec/services/order_management/subscriptions/proxy_order_syncer_spec.rb
- engines/order_management/spec/services/order_management/subscriptions/summarizer_spec.rb
- engines/order_management/spec/services/order_management/subscriptions/validator_spec.rb
- engines/order_management/spec/services/order_management/subscriptions/variants_list_spec.rb
- lib/open_food_network/column_preference_defaults.rb
- spec/controllers/admin/enterprises_controller_spec.rb
- spec/controllers/admin/order_cycles_controller_spec.rb
@@ -692,7 +701,9 @@ Metrics/ModuleLength:
- spec/lib/open_food_network/order_grouper_spec.rb
- spec/lib/open_food_network/permissions_spec.rb
- spec/lib/open_food_network/products_and_inventory_report_spec.rb
- spec/lib/open_food_network/proxy_order_syncer_spec.rb
- spec/lib/open_food_network/scope_variant_to_hub_spec.rb
- spec/lib/open_food_network/subscription_payment_updater_spec.rb
- spec/lib/open_food_network/tag_rule_applicator_spec.rb
- spec/lib/open_food_network/users_and_enterprises_report_spec.rb
- spec/models/spree/ability_spec.rb

View File

@@ -71,6 +71,7 @@ Lint/DuplicateHashKey:
Lint/DuplicateMethods:
Exclude:
- 'lib/discourse/single_sign_on.rb'
- 'lib/open_food_network/subscription_summary.rb'
# Offense count: 10
Lint/IneffectiveAccessModifier:
@@ -158,7 +159,7 @@ Naming/MethodParameterName:
Exclude:
- 'app/helpers/spree/admin/base_helper_decorator.rb'
- 'app/helpers/spree/base_helper_decorator.rb'
- 'engines/order_management/app/services/order_management/subscriptions/validator.rb'
- 'app/services/subscription_validator.rb'
- 'lib/open_food_network/reports/bulk_coop_report.rb'
- 'lib/open_food_network/xero_invoices_report.rb'
- 'spec/lib/open_food_network/reports/report_spec.rb'
@@ -173,6 +174,7 @@ Naming/MethodParameterName:
Naming/PredicateName:
Exclude:
- 'spec/**/*'
- 'app/mailers/producer_mailer.rb'
- 'app/models/enterprise.rb'
- 'app/models/enterprise_relationship.rb'
- 'app/models/order_cycle.rb'
@@ -629,6 +631,7 @@ Style/FrozenStringLiteralComment:
- 'app/jobs/subscription_placement_job.rb'
- 'app/jobs/welcome_enterprise_job.rb'
- 'app/mailers/enterprise_mailer.rb'
- 'app/mailers/producer_mailer.rb'
- 'app/mailers/spree/base_mailer_decorator.rb'
- 'app/mailers/spree/order_mailer_decorator.rb'
- 'app/mailers/spree/user_mailer.rb'
@@ -846,6 +849,11 @@ Style/FrozenStringLiteralComment:
- 'app/services/reset_order_service.rb'
- 'app/services/restart_checkout.rb'
- 'app/services/search_orders.rb'
- 'app/services/subscription_estimator.rb'
- 'app/services/subscription_form.rb'
- 'app/services/subscription_validator.rb'
- 'app/services/subscription_variants_service.rb'
- 'app/services/subscriptions_count.rb'
- 'app/services/tax_rate_finder.rb'
- 'app/services/upload_sanitizer.rb'
- 'app/services/variant_deleter.rb'
@@ -853,6 +861,7 @@ Style/FrozenStringLiteralComment:
- 'app/validators/date_time_string_validator.rb'
- 'app/validators/distributors_validator.rb'
- 'app/validators/integer_array_validator.rb'
- 'app/views/spree/admin/taxons/search.rabl'
- 'config.ru'
- 'engines/order_management/app/controllers/order_management/application_controller.rb'
- 'engines/order_management/app/services/order_management/reports/enterprise_fee_summary/authorizer.rb'
@@ -883,7 +892,6 @@ Style/FrozenStringLiteralComment:
- 'engines/order_management/lib/order_management/engine.rb'
- 'engines/order_management/lib/order_management/version.rb'
- 'engines/order_management/order_management.gemspec'
- 'engines/order_management/spec/performance/order_management/subscriptions/proxy_order_syncer_spec.rb'
- 'engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/authorizer_spec.rb'
- 'engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/parameters_spec.rb'
- 'engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/permissions_spec.rb'
@@ -941,6 +949,7 @@ Style/FrozenStringLiteralComment:
- 'lib/open_food_network/products_and_inventory_report.rb'
- 'lib/open_food_network/products_and_inventory_report_base.rb'
- 'lib/open_food_network/property_merge.rb'
- 'lib/open_food_network/proxy_order_syncer.rb'
- 'lib/open_food_network/rack_request_blocker.rb'
- 'lib/open_food_network/referer_parser.rb'
- 'lib/open_food_network/reports/bulk_coop_allocation_report.rb'
@@ -957,6 +966,8 @@ Style/FrozenStringLiteralComment:
- 'lib/open_food_network/scope_variants_for_search.rb'
- 'lib/open_food_network/spree_api_key_loader.rb'
- 'lib/open_food_network/subscription_payment_updater.rb'
- 'lib/open_food_network/subscription_summarizer.rb'
- 'lib/open_food_network/subscription_summary.rb'
- 'lib/open_food_network/tag_rule_applicator.rb'
- 'lib/open_food_network/user_balance_calculator.rb'
- 'lib/open_food_network/users_and_enterprises_report.rb'
@@ -1198,6 +1209,7 @@ Style/FrozenStringLiteralComment:
- 'spec/lib/open_food_network/permissions_spec.rb'
- 'spec/lib/open_food_network/products_and_inventory_report_spec.rb'
- 'spec/lib/open_food_network/property_merge_spec.rb'
- 'spec/lib/open_food_network/proxy_order_syncer_spec.rb'
- 'spec/lib/open_food_network/referer_parser_spec.rb'
- 'spec/lib/open_food_network/reports/report_spec.rb'
- 'spec/lib/open_food_network/reports/row_spec.rb'
@@ -1206,6 +1218,8 @@ Style/FrozenStringLiteralComment:
- 'spec/lib/open_food_network/scope_variant_to_hub_spec.rb'
- 'spec/lib/open_food_network/scope_variants_to_search_spec.rb'
- 'spec/lib/open_food_network/subscription_payment_updater_spec.rb'
- 'spec/lib/open_food_network/subscription_summarizer_spec.rb'
- 'spec/lib/open_food_network/subscription_summary_spec.rb'
- 'spec/lib/open_food_network/tag_rule_applicator_spec.rb'
- 'spec/lib/open_food_network/user_balance_calculator_spec.rb'
- 'spec/lib/open_food_network/users_and_enterprises_report_spec.rb'
@@ -1290,6 +1304,7 @@ Style/FrozenStringLiteralComment:
- 'spec/models/variant_override_spec.rb'
- 'spec/performance/injection_helper_spec.rb'
- 'spec/performance/orders_controller_spec.rb'
- 'spec/performance/proxy_order_syncer_spec.rb'
- 'spec/performance/shop_controller_spec.rb'
- 'spec/requests/checkout/failed_checkout_spec.rb'
- 'spec/requests/checkout/paypal_spec.rb'
@@ -1340,6 +1355,11 @@ Style/FrozenStringLiteralComment:
- 'spec/services/reset_order_service_spec.rb'
- 'spec/services/restart_checkout_spec.rb'
- 'spec/services/search_orders_spec.rb'
- 'spec/services/subscription_estimator_spec.rb'
- 'spec/services/subscription_form_spec.rb'
- 'spec/services/subscription_validator_spec.rb'
- 'spec/services/subscription_variants_service_spec.rb'
- 'spec/services/subscriptions_count_spec.rb'
- 'spec/services/tax_rate_finder_spec.rb'
- 'spec/services/upload_sanitizer_spec.rb'
- 'spec/services/variants_stock_levels_spec.rb'
@@ -1537,6 +1557,7 @@ Style/Send:
- 'spec/lib/open_food_network/products_and_inventory_report_spec.rb'
- 'spec/lib/open_food_network/sales_tax_report_spec.rb'
- 'spec/lib/open_food_network/subscription_payment_updater_spec.rb'
- 'spec/lib/open_food_network/subscription_summarizer_spec.rb'
- 'spec/lib/open_food_network/tag_rule_applicator_spec.rb'
- 'spec/lib/open_food_network/xero_invoices_report_spec.rb'
- 'spec/lib/stripe/webhook_handler_spec.rb'

View File

@@ -35,22 +35,13 @@ Download the Docker images and build the containers:
$ docker-compose build
```
Setup the database and seed it with sample data:
```sh
$ docker-compose run web bundle exec rake db:reset
$ docker-compose run web bundle exec rake db:test:prepare
$ docker-compose run web bundle exec rake ofn:sample_data
```
Finally, run the app with all the required containers:
Run the app with all the required containers:
```sh
$ docker-compose up
```
The default admin user is 'ofn@example.com' with 'ofn123' password.
This command will setup the database and seed it with sample data. The default admin user is 'ofn@example.com' with 'ofn123' password.
Check the app in the browser at `http://localhost:3000`.
You will then get the trace of the containers in the terminal. You can stop the containers using Ctrl-C in the terminal.
You can find some useful tips and commands [here](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Docker:-useful-tips-and-commands).

View File

@@ -12,7 +12,7 @@ ENV BUNDLE_PATH /bundles
WORKDIR /usr/src/app
COPY .ruby-version .
# Install Rbenv & Ruby
# Rbenv & Ruby part
RUN git clone https://github.com/rbenv/rbenv.git ${RBENV_ROOT} && \
git clone https://github.com/rbenv/ruby-build.git ${RBENV_ROOT}/plugins/ruby-build && \
${RBENV_ROOT}/plugins/ruby-build/install.sh && \
@@ -21,15 +21,12 @@ RUN git clone https://github.com/rbenv/rbenv.git ${RBENV_ROOT} && \
rbenv global $(cat .ruby-version) && \
gem install bundler --version=1.17.2
# Install Postgres
# Postgres
RUN sh -c "echo 'deb https://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main' > /etc/apt/sources.list.d/pgdg.list" && \
wget --quiet -O - https://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | apt-key add - && \
apt-get update && \
apt-get install -yqq --no-install-recommends postgresql-client-9.5 libpq-dev
# Install node
RUN apt-get install -y nodejs
# Install Chrome
RUN wget --quiet -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
sh -c "echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' >> /etc/apt/sources.list.d/google-chrome.list" && \
@@ -41,6 +38,4 @@ RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.z
unzip chromedriver_linux64.zip -d /usr/bin && \
chmod u+x /usr/bin/chromedriver
# Copy code and install app dependencies
COPY . /usr/src/app/
RUN bundle install

View File

@@ -2,8 +2,6 @@
This is a general guide to setting up an Open Food Network development environment on your local machine.
The fastest way to make it work locally is to use Docker, see the [Docker setup guide](DOCKER.md).
The following guides are located in the wiki and provide more OS-specific step-by-step instructions:
- [Ubuntu Setup Guide][ubuntu]
@@ -13,7 +11,7 @@ The following guides are located in the wiki and provide more OS-specific step-b
### Dependencies
* Rails 3.2.x
* Ruby 2.3.7
* Ruby 2.1.9
* PostgreSQL database
* PhantomJS (for testing)
* See Gemfile for a list of gems required
@@ -60,10 +58,10 @@ Now, your dreams of spinning up a development server can be realised:
bundle exec rails server
To login as the default user, use:
To login as Spree default user, use:
email: ofn@example.com
password: ofn123
email: spree@example.com
password: spree123
### Testing
@@ -120,7 +118,7 @@ $ createdb open_food_network_test --owner=ofn
If these commands succeed, you should be able to [continue the setup process](#get-it-running).
[developer-wiki]: https://github.com/openfoodfoundation/openfoodnetwork/wiki
[sierra]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Development-Environment-Setup%3A-macOS-%28Sierra%2C-HighSierra%2C-Mojave-and-Catalina%29
[sierra]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Development-Environment-Setup%3A-macOS-%28Sierra%2C-HighSierra-and-Mojave%29
[el-capitan]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Development-Environment-Setup:-OS-X-(El-Capitan)
[ubuntu]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Development-Environment-Setup:-Ubuntu
[wiki]: https://github.com/openfoodfoundation/openfoodnetwork/wiki

14
Gemfile
View File

@@ -9,6 +9,8 @@ gem 'rails-i18n', '~> 3.0.0'
gem 'rails_safe_tasks', '~> 1.0'
gem "activerecord-import"
# Patched version. See http://rubysec.com/advisories/CVE-2015-5312/.
gem 'nokogiri', '>= 1.6.7.1'
gem "catalog", path: "./engines/catalog"
gem "order_management", path: "./engines/order_management"
@@ -43,6 +45,10 @@ gem 'daemons'
gem 'delayed_job_active_record'
gem 'delayed_job_web'
# Fix bug in simple_form preventing collection_check_boxes usage within form_for block
# When merged, revert to upstream gem
gem 'simple_form', github: 'RohanM/simple_form'
# Spree's default pagination gem (locked to the current version used by Spree)
# We use it's methods in OFN code as well, so this is a direct dependency
gem 'kaminari', '~> 0.14.1'
@@ -53,6 +59,7 @@ gem 'aws-sdk'
gem 'bugsnag'
gem 'db2fog'
gem 'haml'
gem 'rabl'
gem 'redcarpet'
gem 'sass', "~> 3.3"
gem 'sass-rails', '~> 3.2.3'
@@ -67,6 +74,7 @@ gem 'angularjs-file-upload-rails', '~> 2.4.1'
gem 'blockenspiel'
gem 'custom_error_message', github: 'jeremydurham/custom-err-msg'
gem 'dalli'
gem 'deface', '1.0.2'
gem 'diffy'
gem 'figaro'
gem 'geocoder'
@@ -94,7 +102,7 @@ gem 'test-unit', '~> 3.3'
gem 'coffee-rails', '~> 3.2.1'
gem 'compass-rails'
gem 'mini_racer', '0.2.10'
gem 'mini_racer', '0.2.9'
gem 'uglifier', '>= 1.0.3'
@@ -104,6 +112,7 @@ gem 'momentjs-rails'
gem 'turbo-sprockets-rails3'
gem "foundation-rails"
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
gem 'jquery-migrate-rails'
gem 'jquery-rails', '3.1.5'
@@ -114,14 +123,13 @@ gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz', ref: '60da2ae4c44cbb4c8d602f5
group :production, :staging do
gem 'ddtrace'
gem 'unicorn-worker-killer'
end
group :test, :development do
# Pretty printed test output
gem 'atomic'
gem 'awesome_print'
gem 'capybara', '>= 2.18.0' # 3.0 requires rack 1.6 that only works with Rails 4.2
gem 'capybara', '>= 2.18.0' # 3.0 requires nokogiri 1.8
gem 'database_cleaner', '0.7.1', require: false
gem "factory_bot_rails", require: false
gem 'fuubar', '~> 2.5.0'

View File

@@ -1,3 +1,11 @@
GIT
remote: https://github.com/RohanM/simple_form.git
revision: 45f08a213b40f3d4bda5f5398db841137587160a
specs:
simple_form (2.0.2)
actionpack (~> 3.0)
activemodel (~> 3.0)
GIT
remote: https://github.com/jeremydurham/custom-err-msg.git
revision: 3a8ec9dddc7a5b0aab7c69a6060596de300c68f4
@@ -23,7 +31,7 @@ GIT
GIT
remote: https://github.com/openfoodfoundation/spree.git
revision: e10ca1f689b1658040b081939b7523f6fb68895a
revision: 8a8585a43cd04d1a50dc65227f337a91b18d66d5
branch: 2-0-4-stable
specs:
spree_core (2.0.4)
@@ -32,13 +40,14 @@ GIT
awesome_nested_set (= 2.1.5)
aws-sdk (~> 1.11.1)
cancan (~> 1.6.10)
deface (>= 0.9.1)
ffaker (~> 1.16)
highline (= 1.6.18)
httparty (~> 0.11)
json (>= 1.7.7)
kaminari (~> 0.14.1)
money (= 5.1.1)
paperclip (~> 3.4.1)
paperclip (~> 3.0)
paranoia (~> 1.3)
rails (~> 3.2.14)
ransack (= 0.7.2)
@@ -56,6 +65,16 @@ GIT
rails-i18n
spree_core (>= 1.1)
GIT
remote: https://github.com/willrjmarshall/foundation_rails_helper.git
revision: 4d5d53fdc4b1fb71e66524d298c5c635de82cfbb
branch: rails3
specs:
foundation_rails_helper (0.4)
actionpack (>= 3.0)
activemodel (>= 3.0)
railties (>= 3.0)
PATH
remote: engines/catalog
specs:
@@ -154,7 +173,7 @@ GEM
xpath (>= 2.0, < 4.0)
childprocess (3.0.0)
chronic (0.10.2)
chunky_png (1.3.11)
chunky_png (1.3.10)
climate_control (0.2.0)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
@@ -166,6 +185,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.10.0)
colorize (0.8.1)
combine_pdf (1.0.16)
ruby-rc4 (>= 0.1.5)
compass (1.0.3)
@@ -180,7 +200,7 @@ GEM
sass (>= 3.3.0, < 3.5)
compass-import-once (1.0.5)
sass (>= 3.2, < 3.5)
compass-rails (4.0.0)
compass-rails (3.1.0)
compass (~> 1.0.0)
sass-rails (< 5.1)
sprockets (< 4.0)
@@ -196,9 +216,14 @@ GEM
activerecord (>= 3.2.0, < 5.0)
fog (~> 1.0)
rails (>= 3.2.0, < 5.0)
ddtrace (0.35.1)
ddtrace (0.33.1)
msgpack
debugger-linecache (1.2.0)
deface (1.0.2)
colorize (>= 0.5.8)
nokogiri (~> 1.6.0)
polyglot
rails (>= 3.1)
delayed_job (4.1.8)
activesupport (>= 3.0, < 6.1)
delayed_job_active_record (4.1.4)
@@ -231,8 +256,8 @@ GEM
railties (>= 3.0.0)
faraday (1.0.0)
multipart-post (>= 1.2, < 3)
ffaker (1.32.1)
ffi (1.12.2)
ffaker (1.22.1)
ffi (1.11.3)
figaro (1.1.1)
thor (~> 0.14)
fission (0.5.0)
@@ -396,8 +421,6 @@ GEM
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
geocoder (1.1.8)
get_process_mem (0.2.5)
ffi (~> 1.0)
gmaps4rails (1.5.6)
haml (4.0.7)
tilt
@@ -442,9 +465,9 @@ GEM
method_source (0.9.2)
mime-types (1.25.1)
mini_mime (1.0.1)
mini_portile2 (2.4.0)
mini_racer (0.2.10)
libv8 (> 7.3)
mini_portile2 (2.1.0)
mini_racer (0.2.9)
libv8 (>= 6.9.411)
momentjs-rails (2.20.1)
railties (>= 3.1)
money (5.1.1)
@@ -454,15 +477,15 @@ GEM
multi_xml (0.6.0)
multipart-post (2.1.1)
newrelic_rpm (3.18.1.330)
nokogiri (1.10.9)
mini_portile2 (~> 2.4.0)
nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
oauth2 (1.4.4)
faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
oj (3.10.6)
oj (3.10.5)
orm_adapter (0.5.0)
paper_trail (5.2.3)
activerecord (>= 3.0, < 6.0)
@@ -476,7 +499,7 @@ GEM
parallel (1.19.1)
paranoia (1.3.4)
activerecord (~> 3.1)
parser (2.7.1.0)
parser (2.7.0.5)
ast (~> 2.4.0)
paypal-sdk-core (0.2.10)
multi_json (~> 1.0)
@@ -495,6 +518,8 @@ GEM
byebug (>= 9.0, < 9.1)
pry (~> 0.10)
public_suffix (4.0.3)
rabl (0.8.4)
activesupport (>= 2.3.14)
rack (1.4.7)
rack-cache (1.11.0)
rack (>= 0.4)
@@ -534,8 +559,8 @@ GEM
activerecord (~> 3.0)
polyamorous (~> 0.5.0)
rb-fsevent (0.10.3)
rb-inotify (0.10.1)
ffi (~> 1.0)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
rbvmomi (1.13.0)
builder (~> 3.0)
json (>= 1.8)
@@ -579,15 +604,15 @@ GEM
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-support (3.9.2)
rubocop (0.81.0)
rubocop (0.80.1)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
rexml
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-rails (2.5.2)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-rails (2.5.0)
activesupport
rack (>= 1.1)
rubocop (>= 0.72.0)
@@ -646,16 +671,13 @@ GEM
tzinfo (0.3.56)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.7.0)
unicorn (5.5.5)
unicode-display_width (1.6.1)
unicorn (5.5.4)
kgio (~> 2.6)
raindrops (~> 0.7)
unicorn-rails (2.2.1)
rack
unicorn
unicorn-worker-killer (0.4.4)
get_process_mem (~> 0)
unicorn (>= 4, < 6)
uuidtools (2.1.5)
warden (1.2.7)
rack (>= 1.0)
@@ -706,6 +728,7 @@ DEPENDENCIES
db2fog
ddtrace
debugger-linecache
deface (= 1.0.2)
delayed_job_active_record
delayed_job_web
devise (~> 2.2.5)
@@ -717,6 +740,7 @@ DEPENDENCIES
foreigner
foundation-icons-sass-rails
foundation-rails
foundation_rails_helper!
fuubar (~> 2.5.0)
geocoder
gmaps4rails
@@ -732,9 +756,10 @@ DEPENDENCIES
kaminari (~> 0.14.1)
knapsack
letter_opener (>= 1.4.1)
mini_racer (= 0.2.10)
mini_racer (= 0.2.9)
momentjs-rails
newrelic_rpm (~> 3.0)
nokogiri (>= 1.6.7.1)
oauth2 (~> 1.4.4)
ofn-qz!
oj
@@ -743,6 +768,7 @@ DEPENDENCIES
paperclip (~> 3.4.1)
pg (~> 0.21.0)
pry-byebug (>= 3.4.3)
rabl
rack-mini-profiler (< 3.0.0)
rack-rewrite
rack-ssl
@@ -761,6 +787,7 @@ DEPENDENCIES
select2-rails (~> 3.4.7)
selenium-webdriver
shoulda-matchers
simple_form!
simplecov
spinjs-rails
spree_core!
@@ -776,7 +803,6 @@ DEPENDENCIES
uglifier (>= 1.0.3)
unicorn
unicorn-rails
unicorn-worker-killer
web!
webdrivers
webmock

View File

@@ -29,7 +29,7 @@ angular.module("admin.enterprises")
# from a directive "nav-check" in the page - if we pass it here it will be called in the test suite,
# and on all new uses of this contoller, and we might not want that.
enterpriseNavCallback = ->
if $scope.enterprise_form?.$dirty
if $scope.enterprise_form != undefined && $scope.enterprise_form.$dirty
t('admin.unsaved_confirm_leave')
# Register the NavigationCheck callback

View File

@@ -2,24 +2,19 @@ angular.module("admin.indexUtils").factory "PagedFetcher", (dataFetcher) ->
new class PagedFetcher
# Given a URL like http://example.com/foo?page=::page::&per_page=20
# And the response includes an attribute pages with the number of pages to fetch
# Fetch each page async, and call the pageCallback callback with the resulting data
# Developer note: this class should not be re-used!
page: 1
last_page: 1
# Fetch each page async, and call the processData callback with the resulting data
fetch: (url, processData, onLastPageComplete) ->
dataFetcher(@urlForPage(url, 1)).then (data) =>
processData data
fetch: (url, pageCallback) ->
@fetchPages(url, @page, pageCallback)
if data.pages > 1
for page in [2..data.pages]
lastPromise = dataFetcher(@urlForPage(url, page)).then (data) ->
processData data
onLastPageComplete && lastPromise.then onLastPageComplete
return
else
onLastPageComplete && onLastPageComplete()
urlForPage: (url, page) ->
url.replace("::page::", page)
fetchPages: (url, page, pageCallback) ->
dataFetcher(@urlForPage(url, page)).then (data) =>
@page++
@last_page = data.pages
pageCallback(data) if pageCallback
if @page <= @last_page
@fetchPages(url, @page, pageCallback)

View File

@@ -1,7 +1,7 @@
angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, SortOptions, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) ->
$scope.initialized = false
$scope.RequestMonitor = RequestMonitor
$scope.line_items = LineItems.all
$scope.filteredLineItems = []
$scope.confirmDelete = true
$scope.startDate = moment().startOf('day').subtract(7, 'days').format('YYYY-MM-DD')
$scope.endDate = moment().startOf('day').format('YYYY-MM-DD')
@@ -15,77 +15,50 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
$scope.confirmRefresh = ->
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
$scope.resetFilters = ->
$scope.distributorFilter = ''
$scope.supplierFilter = ''
$scope.orderCycleFilter = ''
$scope.quickSearch = ''
$scope.resetSelectFilters = ->
$scope.resetFilters()
$scope.refreshData()
$scope.distributorFilter = 0
$scope.supplierFilter = 0
$scope.orderCycleFilter = 0
$scope.quickSearch = ""
$scope.refreshData = ->
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == ''
$scope.setOrderCycleDateRange()
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == 0
$scope.startDate = moment(OrderCycles.byID[$scope.orderCycleFilter].orders_open_at).format('YYYY-MM-DD')
$scope.endDate = moment(OrderCycles.byID[$scope.orderCycleFilter].orders_close_at).startOf('day').format('YYYY-MM-DD')
$scope.formattedStartDate = moment($scope.startDate).format()
$scope.formattedEndDate = moment($scope.endDate).add(1,'day').format()
formatted_start_date = moment($scope.startDate).format()
formatted_end_date = moment($scope.endDate).add(1,'day').format()
return unless moment($scope.formattedStartDate).isValid() and moment($scope.formattedEndDate).isValid()
$scope.loadOrders()
$scope.loadLineItems()
unless $scope.initialized
$scope.loadAssociatedData()
$scope.dereferenceLoadedData()
$scope.setOrderCycleDateRange = ->
start_date = OrderCycles.byID[$scope.orderCycleFilter].orders_open_at
end_date = OrderCycles.byID[$scope.orderCycleFilter].orders_close_at
format = "YYYY-MM-DD HH:mm:ss Z"
$scope.startDate = moment(start_date, format).format('YYYY-MM-DD')
$scope.endDate = moment(end_date, format).startOf('day').format('YYYY-MM-DD')
$scope.loadOrders = ->
RequestMonitor.load $scope.orders = Orders.index(
"q[state_not_eq]": "canceled",
"q[completed_at_not_null]": "true",
"q[distributor_id_eq]": $scope.distributorFilter,
"q[order_cycle_id_eq]": $scope.orderCycleFilter,
"q[completed_at_gteq]": $scope.formattedStartDate,
"q[completed_at_lt]": $scope.formattedEndDate
"q[completed_at_gteq]": formatted_start_date,
"q[completed_at_lt]": formatted_end_date
)
$scope.loadLineItems = ->
RequestMonitor.load LineItems.index(
"q[order_state_not_eq]": "canceled",
"q[order_completed_at_not_null]": "true",
"q[order_distributor_id_eq]": $scope.distributorFilter,
"q[variant_product_supplier_id_eq]": $scope.supplierFilter,
"q[order_order_cycle_id_eq]": $scope.orderCycleFilter,
"q[order_completed_at_gteq]": $scope.formattedStartDate,
"q[order_completed_at_lt]": $scope.formattedEndDate
RequestMonitor.load $scope.lineItems = LineItems.index(
"q[order][state_not_eq]": "canceled",
"q[order][completed_at_not_null]": "true",
"q[order][completed_at_gteq]": formatted_start_date,
"q[order][completed_at_lt]": formatted_end_date
)
$scope.loadAssociatedData = ->
RequestMonitor.load $scope.distributors = Enterprises.index(action: "visible", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{moment().subtract(90,'days').format()}")
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "visible", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
unless $scope.initialized
RequestMonitor.load $scope.distributors = Enterprises.index(action: "visible", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{moment().subtract(90,'days').format()}")
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "visible", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
$scope.dereferenceLoadedData = ->
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise, $scope.suppliers.$promise, $scope.line_items.$promise]).then ->
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise, $scope.suppliers.$promise, $scope.lineItems.$promise]).then ->
Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.byID
Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.byID
Dereferencer.dereferenceAttr $scope.line_items, "supplier", Enterprises.byID
Dereferencer.dereferenceAttr $scope.line_items, "order", Orders.byID
Dereferencer.dereferenceAttr $scope.lineItems, "supplier", Enterprises.byID
Dereferencer.dereferenceAttr $scope.lineItems, "order", Orders.byID
$scope.bulk_order_form.$setPristine()
StatusMessage.clear()
unless $scope.initialized
$scope.initialized = true
$timeout ->
$scope.resetSelectFilters()
$scope.$watch 'bulk_order_form.$dirty', (newVal, oldVal) ->
if newVal == true
@@ -104,12 +77,13 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
$scope.deleteLineItem = (lineItem) ->
if ($scope.confirmDelete && confirm(t "are_you_sure")) || !$scope.confirmDelete
LineItems.delete lineItem
LineItems.delete lineItem, =>
$scope.lineItems.splice $scope.lineItems.indexOf(lineItem), 1
$scope.deleteLineItems = (lineItemsToDelete) ->
$scope.deleteLineItems = (lineItems) ->
existingState = $scope.confirmDelete
$scope.confirmDelete = false
$scope.deleteLineItem lineItem for lineItem in lineItemsToDelete when lineItem.checked
$scope.deleteLineItem lineItem for lineItem in lineItems when lineItem.checked
$scope.confirmDelete = existingState
$scope.allBoxesChecked = ->
@@ -180,5 +154,4 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
lineItem.final_weight_volume = LineItems.pristineByID[lineItem.id].final_weight_volume * lineItem.quantity / LineItems.pristineByID[lineItem.id].quantity
$scope.weightAdjustedPrice(lineItem)
$scope.resetFilters()
$scope.refreshData()

View File

@@ -1,5 +1,5 @@
angular.module('admin.orderCycles')
.controller 'AdminEditOrderCycleCtrl', ($scope, $controller, $filter, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor, NavigationCheck, ocInstance) ->
.controller 'AdminEditOrderCycleCtrl', ($scope, $controller, $filter, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
$controller('AdminOrderCycleBasicCtrl', {$scope: $scope, ocInstance: ocInstance})
order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
@@ -18,12 +18,5 @@ angular.module('admin.orderCycles')
$scope.submit = ($event, destination) ->
$event.preventDefault()
NavigationCheck.clear()
StatusMessage.display 'progress', t('js.saving')
OrderCycle.update(destination, $scope.order_cycle_form)
warnAboutUnsavedChanges = ->
if $scope.order_cycle_form?.$dirty
t('admin.unsaved_confirm_leave')
NavigationCheck.register(warnAboutUnsavedChanges)

View File

@@ -67,7 +67,7 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, $timeout, Reque
return unless sort && sort.predicate != ""
$scope.sorting = sort.getSortingExpr()
$scope.fetchResults()
$scope.fetchProducts()
, true
$scope.capturePayment = (order) ->

View File

@@ -14,10 +14,9 @@ angular.module("admin.payments").factory 'AdminStripeElements', ($rootScope, Sta
@stripe.createToken(@card, cardData).then (response) =>
if(response.error)
StatusMessage.display 'error', response.error.message
console.error(JSON.stringify(response.error))
else
secrets.token = response.token.id
secrets.cc_type = @mapTokenApiCardBrand(response.token.card.brand)
secrets.cc_type = @mapCC(response.token.card.brand)
secrets.card = response.token.card
submit()
@@ -30,16 +29,15 @@ angular.module("admin.payments").factory 'AdminStripeElements', ($rootScope, Sta
@stripe.createPaymentMethod({ type: 'card', card: @card }, @card, cardData).then (response) =>
if(response.error)
StatusMessage.display 'error', response.error.message
console.error(JSON.stringify(response.error))
else
secrets.token = response.paymentMethod.id
secrets.cc_type = @mapPaymentMethodsApiCardBrand(response.paymentMethod.card.brand)
secrets.cc_type = response.paymentMethod.card.brand
secrets.card = response.paymentMethod.card
submit()
# Maps the brand returned by Stripe's tokenAPI to that required by activemerchant
mapTokenApiCardBrand: (cardBrand) ->
switch cardBrand
# Maps the brand returned by Stripe to that required by activemerchant
mapCC: (ccType) ->
switch ccType
when 'MasterCard' then return 'master'
when 'Visa' then return 'visa'
when 'American Express' then return 'american_express'
@@ -47,14 +45,6 @@ angular.module("admin.payments").factory 'AdminStripeElements', ($rootScope, Sta
when 'JCB' then return 'jcb'
when 'Diners Club' then return 'diners_club'
# Maps the brand returned by Stripe's paymentMethodsAPI to that required by activemerchant
mapPaymentMethodsApiCardBrand: (cardBrand) ->
switch cardBrand
when 'mastercard' then return 'master'
when 'amex' then return 'american_express'
when 'diners' then return 'diners_club'
else return cardBrand # a few brands are equal, for example, visa
# It doesn't matter if any of these are nil, all are optional.
makeCardData: (secrets) ->
{'name': secrets.name,

View File

@@ -2,6 +2,7 @@ angular.module("admin.resources").factory 'LineItemResource', ($resource) ->
$resource('/admin/bulk_line_items/:id.json', {}, {
'index':
method: 'GET'
isArray: true
'update':
method: 'PUT'
transformRequest: (data, headersGetter) =>

View File

@@ -1,27 +1,20 @@
angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
new class LineItems
all: []
byID: {}
pristineByID: {}
pagination: {}
index: (params={}, callback=null) ->
request = LineItemResource.index params, (data) =>
LineItemResource.index params, (data) =>
@load(data)
(callback || angular.noop)(data)
@all.$promise = request.$promise
@all
resetData: ->
@all.length = 0
@byID = {}
@pristineByID = {}
load: (data) ->
angular.extend(@pagination, data.pagination)
load: (lineItems) ->
@resetData()
for lineItem in data.line_items
@all.push lineItem
for lineItem in lineItems
@byID[lineItem.id] = lineItem
@pristineByID[lineItem.id] = angular.copy(lineItem)
@@ -32,9 +25,8 @@ angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
save: (lineItem) ->
deferred = $q.defer()
lineItemResource = new LineItemResource(lineItem)
lineItem.errors = {}
lineItemResource.$update({id: lineItem.id})
lineItem.$update({id: lineItem.id})
.then( (data) =>
@pristineByID[lineItem.id] = angular.copy(lineItem)
deferred.resolve(data)
@@ -62,10 +54,8 @@ angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
delete: (lineItem, callback=null) ->
deferred = $q.defer()
lineItemResource = new LineItemResource(lineItem)
lineItemResource.$delete({id: lineItem.id})
lineItem.$delete({id: lineItem.id})
.then( (data) =>
@all.splice(@all.indexOf(lineItem),1)
delete @byID[lineItem.id]
delete @pristineByID[lineItem.id]
(callback || angular.noop)(data)

View File

@@ -43,11 +43,12 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
$scope.fetchProducts = ->
url = "/api/products/overridable?page=::page::;per_page=100"
PagedFetcher.fetch url, $scope.addProducts
PagedFetcher.fetch url, (data) => $scope.addProducts data.products
$scope.addProducts = (data) ->
$scope.products = $scope.products.concat data.products
VariantOverrides.ensureDataFor hubs, data.products
$scope.addProducts = (products) ->
$scope.products = $scope.products.concat products
VariantOverrides.ensureDataFor hubs, products
$scope.displayDirty = ->
if DirtyVariantOverrides.count() > 0

View File

@@ -9,8 +9,6 @@
#= require angular-animate
#= require angular-resource
#= require lodash.underscore.js
# bluebird.js is a dependency of angular-google-maps.js 2.0.0
#= require bluebird.js
#= require angular-scroll.min.js
#= require angular-google-maps.min.js
#= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js

View File

@@ -9,13 +9,8 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location
$scope.show_closed = false
$scope.filtersActive = false
$scope.distanceMatchesShown = false
$scope.closed_shops_loading = false
$scope.closed_shops_loaded = false
$scope.$watch "query", (query)->
$scope.resetSearch(query)
$scope.resetSearch = (query) ->
Enterprises.flagMatching query
Search.search query
$rootScope.$broadcast 'enterprisesChanged'
@@ -24,7 +19,6 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location
$timeout ->
Enterprises.calculateDistance query, $scope.firstNameMatch()
$rootScope.$broadcast 'enterprisesChanged'
$scope.closed_shops_loading = false
$timeout ->
if $location.search()['show_closed']?
@@ -79,12 +73,6 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location
undefined
$scope.showClosedShops = ->
unless $scope.closed_shops_loaded
$scope.closed_shops_loading = true
$scope.closed_shops_loaded = true
Enterprises.loadClosedEnterprises().then ->
$scope.resetSearch($scope.query)
$scope.show_closed = true
$location.search('show_closed', '1')

View File

@@ -24,7 +24,7 @@ Darkswarm.controller "HubNodeCtrl", ($scope, HashNavigation, CurrentHub, $http,
$scope.shopfront_loading = true
$scope.toggle_tab(event)
$http.get("/api/shops/" + $scope.hub.id)
$http.get("/api/enterprises/" + $scope.hub.id + "/shopfront")
.success (data) ->
$scope.shopfront_loading = false
$scope.hub = data

View File

@@ -24,7 +24,7 @@ Darkswarm.controller "ProducerNodeCtrl", ($scope, HashNavigation, $anchorScroll,
$scope.shopfront_loading = true
$scope.toggle_tab(event)
$http.get("/api/shops/" + $scope.producer.id)
$http.get("/api/enterprises/" + $scope.producer.id + "/shopfront")
.success (data) ->
$scope.shopfront_loading = false
$scope.producer = data

View File

@@ -7,7 +7,7 @@ window.Darkswarm = angular.module("Darkswarm", [
'templates',
'ngSanitize',
'ngAnimate',
'uiGmapgoogle-maps',
'google-maps',
'duScroll',
'angularFileUpload',
'angularSlideables'

View File

@@ -1,11 +0,0 @@
Darkswarm.directive "darkerBackground", ->
restrict: "A"
link: (scope, elm, attr)->
toggleClass = (value) ->
elm.closest('.page-view').toggleClass("with-darker-background", value)
toggleClass(true)
# if an OrderCycle is selected, disable darker background
scope.$watch 'order_cycle.order_cycle_id', (newvalue, oldvalue) ->
toggleClass(false) if newvalue

View File

@@ -1,6 +1,6 @@
Darkswarm.directive 'mapOsmTiles', ($timeout) ->
restrict: 'E'
require: '^uiGmapGoogleMap'
require: '^googleMap'
scope: {}
link: (scope, elem, attrs, ctrl) ->
$timeout =>

View File

@@ -1,7 +1,7 @@
Darkswarm.directive 'mapSearch', ($timeout, Search) ->
# Install a basic search field in a map
restrict: 'E'
require: ['^uiGmapGoogleMap', 'ngModel']
require: ['^googleMap', 'ngModel']
replace: true
template: '<input id="pac-input" ng-model="query" placeholder="' + t('location_placeholder') + '"></input>'
scope: {}

View File

@@ -5,9 +5,5 @@ Darkswarm.directive "shopVariant", ->
scope:
variant: '='
controller: ($scope, Cart) ->
$scope.$watchGroup [
'variant.line_item.quantity',
'variant.line_item.max_quantity'
], (new_value, old_value) ->
return if old_value[0] == null && new_value[0] == null
$scope.$watchGroup ['variant.line_item.quantity', 'variant.line_item.max_quantity'], ->
Cart.adjust($scope.variant.line_item)

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService, RailsFlashLoader) ->
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService) ->
# Handles syncing of current cart/order state to server
new class Cart
dirty: false
@@ -50,7 +50,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
@popQueue() if @update_enqueued
.error (response, status)=>
RailsFlashLoader.loadFlash({error: t('js.cart.add_to_cart_failed')})
@scheduleRetry(status)
@update_running = false
compareAndNotifyStockLevels: (stockLevels) =>
@@ -87,6 +87,13 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
max_quantity: li.max_quantity
{variants: variants}
scheduleRetry: (status) =>
console.log "Error updating cart: #{status}. Retrying in 3 seconds..."
$timeout =>
console.log "Retrying cart update"
@orderChanged()
, 3000
saved: =>
@dirty = false
$(window).unbind "beforeunload"

View File

@@ -14,28 +14,15 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeE
submit: =>
Loading.message = t 'submitting_order'
$http.put('/checkout.json', {order: @preprocess()})
.then (response) =>
Navigation.go response.data.path
.catch (response) =>
try
@handle_checkout_error_response(response)
catch error
@loadFlash(error: t("checkout.failed")) # inform the user about the unexpected error
throw error # generate a BugsnagJS alert
handle_checkout_error_response: (response) =>
if response.data.path
Navigation.go response.data.path
else
throw response unless response.data.flash
@errors = response.data.errors
@loadFlash(response.data.flash)
loadFlash: (flash) =>
Loading.clear()
RailsFlashLoader.loadFlash(flash)
$http.put('/checkout.json', {order: @preprocess()}).success (data, status)=>
Navigation.go data.path
.error (response, status)=>
if response.path
Navigation.go response.path
else
Loading.clear()
@errors = response.errors
RailsFlashLoader.loadFlash(response.flash)
# Rails wants our Spree::Address data to be provided with _attributes
preprocess: ->

View File

@@ -5,7 +5,7 @@ Darkswarm.factory "EnterpriseModal", ($modal, $rootScope, $http)->
scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise
scope.embedded_layout = window.location.search.indexOf("embedded_shopfront=true") != -1
$http.get("/api/shops/" + enterprise.id).success (data) ->
$http.get("/api/enterprises/" + enterprise.id + "/shopfront").success (data) ->
scope.enterprise = data
$modal.open(templateUrl: "enterprise_modal.html", scope: scope)
.error (data) ->

View File

@@ -1,30 +1,27 @@
Darkswarm.factory 'Enterprises', (enterprises, ShopsResource, CurrentHub, Taxons, Dereferencer, Matcher, Geo, $rootScope) ->
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, Matcher, Geo, $rootScope) ->
new class Enterprises
enterprises: []
enterprises_by_id: {}
constructor: ->
# Populate Enterprises.enterprises from json in page.
@initEnterprises(enterprises)
@enterprises = enterprises
initEnterprises: (enterprises) ->
# Map enterprises to id/object pairs for lookup.
for enterprise in enterprises
@enterprises.push enterprise
@enterprises_by_id[enterprise.id] = enterprise
# Replace enterprise and taxons ids with actual objects.
@dereferenceEnterprises(enterprises)
@dereferenceEnterprises()
@producers = @enterprises.filter (enterprise)->
enterprise.category in ["producer_hub", "producer_shop", "producer"]
@hubs = @enterprises.filter (enterprise)->
enterprise.category in ["hub", "hub_profile", "producer_hub", "producer_shop"]
dereferenceEnterprises: (enteprises) ->
dereferenceEnterprises: ->
if CurrentHub.hub?.id
CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id]
for enterprise in enterprises
for enterprise in @enterprises
@dereferenceEnterprise enterprise
dereferenceEnterprise: (enterprise) ->
@@ -45,12 +42,6 @@ Darkswarm.factory 'Enterprises', (enterprises, ShopsResource, CurrentHub, Taxons
for enterprise in new_enterprises
@enterprises_by_id[enterprise.id] = enterprise
loadClosedEnterprises: ->
request = ShopsResource.closed_shops {}, (data) =>
@initEnterprises(data)
request.$promise
flagMatching: (query) ->
for enterprise in @enterprises
enterprise.matches_name_query = if query? && query.length > 0
@@ -59,7 +50,7 @@ Darkswarm.factory 'Enterprises', (enterprises, ShopsResource, CurrentHub, Taxons
false
calculateDistance: (query, firstMatching) ->
if query?.length > 0 and Geo.OK
if query?.length > 0
if firstMatching?
@setDistanceFrom firstMatching
else

View File

@@ -1,6 +1,6 @@
Darkswarm.service "Geo", ->
new class Geo
OK: google?.maps?.GeocoderStatus?.OK
OK: google.maps.GeocoderStatus.OK
# Usage:
# Geo.geocode address, (results, status) ->

View File

@@ -1,6 +1,6 @@
Darkswarm.factory 'OrderCycle', ($resource, orderCycleData) ->
class OrderCycle
@order_cycle = orderCycleData # Object or {}
@order_cycle = orderCycleData # Object or {} due to RABL
@push_order_cycle: (callback) ->
new $resource("/shop/order_cycle").save {order_cycle_id: @order_cycle.order_cycle_id}, (order_data)->
OrderCycle.order_cycle.orders_close_at = order_data.orders_close_at

View File

@@ -1,7 +0,0 @@
Darkswarm.factory 'ShopsResource', ($resource) ->
$resource('/api/shops/:id.json', {}, {
'closed_shops':
method: 'GET'
isArray: true
url: '/api/shops/closed_shops.json'
})

View File

@@ -15,11 +15,9 @@ Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
if(response.error)
Loading.clear()
RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"})
@triggerAngularDigest()
console.error(JSON.stringify(response.error))
else
secrets.token = response.token.id
secrets.cc_type = @mapTokenApiCardBrand(response.token.card.brand)
secrets.cc_type = @mapCC(response.token.card.brand)
secrets.card = response.token.card
submit()
@@ -34,21 +32,15 @@ Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
if(response.error)
Loading.clear()
RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"})
@triggerAngularDigest()
console.error(JSON.stringify(response.error))
else
secrets.token = response.paymentMethod.id
secrets.cc_type = @mapPaymentMethodsApiCardBrand(response.paymentMethod.card.brand)
secrets.cc_type = response.paymentMethod.card.brand
secrets.card = response.paymentMethod.card
submit()
triggerAngularDigest: ->
# $evalAsync is improved way of triggering a digest without calling $apply
$rootScope.$evalAsync()
# Maps the brand returned by Stripe's tokenAPI to that required by activemerchant
mapTokenApiCardBrand: (cardBrand) ->
switch cardBrand
# Maps the brand returned by Stripe to that required by activemerchant
mapCC: (ccType) ->
switch ccType
when 'MasterCard' then return 'master'
when 'Visa' then return 'visa'
when 'American Express' then return 'american_express'
@@ -56,14 +48,6 @@ Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
when 'JCB' then return 'jcb'
when 'Diners Club' then return 'diners_club'
# Maps the brand returned by Stripe's paymentMethodsAPI to that required by activemerchant
mapPaymentMethodsApiCardBrand: (cardBrand) ->
switch cardBrand
when 'mastercard' then return 'master'
when 'amex' then return 'american_express'
when 'diners' then return 'diners_club'
else return cardBrand # a few brands are equal, for example, visa
# It doesn't matter if any of these are nil, all are optional.
makeCardData: (secrets) ->
{'name': secrets.name,

View File

@@ -8,4 +8,4 @@
%hr
%div.menu_item.text-center
%input.fullwidth.orange{ type: "button", ng: { value: "saved() ? 'Saved': 'Saving'", show: "saved() || saving", disabled: "saved()" } }
%input.fullwidth.red{ type: "button", :value => t('admin.column_save_as_default').html_safe, ng: { show: "!saved() && !saving", click: "saveColumnPreferences(action)"} }
%input.fullwidth.red{ type: "button", value: 'Save As Default', ng: { show: "!saved() && !saving", click: "saveColumnPreferences(action)"} }

View File

@@ -6,8 +6,6 @@
min: 0,
placeholder: "0",
"ofn-disable-scroll" => true,
"ng-debounce" => "500",
onwheel: "this.blur()",
"ng-model" => "variant.line_item.quantity",
"ofn-on-hand" => "{{variant.on_demand && 9999 || variant.on_hand }}",
"ng-disabled" => "!variant.on_demand && variant.on_hand == 0",

View File

@@ -9,8 +9,6 @@
"ng-model" => "variant.line_item.quantity",
placeholder: "{{::'shop_variant_quantity_min' | t}}",
"ofn-disable-scroll" => true,
"ng-debounce" => "500",
onwheel: "this.blur()",
"ofn-on-hand" => "{{variant.on_demand && 9999 || variant.on_hand }}",
name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"}
%span.bulk-input
@@ -21,8 +19,6 @@
"ng-model" => "variant.line_item.max_quantity",
placeholder: "{{::'shop_variant_quantity_max' | t}}",
"ofn-disable-scroll" => true,
"ng-debounce" => "500",
onwheel: "this.blur()",
min: "{{variant.line_item.quantity}}",
name: "variant_attributes[{{::variant.id}}][max_quantity]",
id: "variants_{{::variant.id}}_max"}

View File

@@ -9,9 +9,6 @@
input#search {
@include medium-input(rgba(0, 0, 0, 0.3), #777, $clr-brick);
// avoid zoom on iphone, see issue #4535
font-size: 1rem;
}
// ordering

View File

@@ -49,7 +49,7 @@ ordercycle {
border-radius: 0.25em 0 0 0.25em;
float: left;
font-size: 1em;
line-height: 1.3em;
line-height: 1.5em;
padding: 0.5em 0.75em;
height: 2.35em;
@@ -60,15 +60,6 @@ ordercycle {
}
select {
background-image: url('/assets/white-caret.svg');
}
p {
text-align: left;
}
select,
p {
width: inherit;
display: inline-block;
color: $white;
@@ -76,9 +67,10 @@ ordercycle {
border: 0;
margin-bottom: 0;
font-size: 1em;
line-height: 1.3em;
line-height: 1.5em;
padding: 0.5em 1.25em 0.5em 0.75em;
height: 2.35em;
background-image: url('/assets/white-caret.svg');
background-size: 30px auto;
border-radius: 0 0.25em 0.25em 0;
min-width: 13em;
@@ -88,10 +80,6 @@ ordercycle {
}
}
option {
color: $grey-700;
}
@media all and (max-width: 1024px) {
float: none;
margin-right: 1em;

View File

@@ -38,15 +38,14 @@ $med-drk-grey: #444;
$dark-grey: #333;
$light-grey: #ddd;
$light-grey-transparency: rgba(0, 0, 0, .1);
$very-light-grey-transparency: rgba(0, 0, 0, .05);
$black: #000;
$white: #fff;
$grey-050: #f7f7f7;
$grey-400: #bbb;
$grey-500: #999;
$grey-600: #777;
$grey-650: #666;
$grey-700: #555;
$grey-800: #333;
@@ -55,7 +54,6 @@ $teal-400: #4cb5c5;
$teal-500: #0096ad;
$orange-400: #ff9466;
$orange-450: #f4704c;
$orange-500: #f27052;
$orange-600: #d7583a;

View File

@@ -109,4 +109,9 @@ checkout {
}
}
}
.error {
color: #c82020;
}
}

View File

@@ -14,10 +14,5 @@
.more-controls {
text-align: center;
.spinner {
height: 2.25em;
margin-right: 0.5em;
}
}
}

View File

@@ -114,16 +114,7 @@
margin-bottom: 0px;
}
.select-oc-message {
margin-top: 1rem;
.highlighted {
color: $red-700;
font-weight: bold;
}
}
.open-shop-message {
.shopfront-message {
a {
color: #0096ad;
@@ -134,44 +125,21 @@
}
}
.closed-shop-header {
background-color: $grey-650;
color: $white;
h4 {
color: $white;
}
p {
margin: 1rem 0 0.4rem;
}
.message {
display: inline-block;
}
.shopfront_closed_message, .shopfront_hidden_message {
padding: 15px;
border-radius: 5px;
}
.warning-sign {
margin: 0 10px 0 5px;
display: inline-block;
.shopfront_closed_message {
border: 2px solid #eb4c46;
}
strong {
color: $grey-650;
display: block;
position: relative;
text-align: center;
width: 23px;
}
.shopfront_closed_message {
margin: 2em 0em;
}
.rectangle {
background-color: $white;
border-radius: 4px;
color: $grey-650;
height: 23px;
position: absolute;
top: 27px;
transform: rotate(-315deg);
width: 23px;
}
.shopfront_hidden_message {
border: 2px solid #db4;
margin: 2em 0em;
}
}

View File

@@ -76,9 +76,9 @@
// content revealed in accordion
.page-view {
margin-bottom: 5em;
background: none;
border: none;
padding-bottom: 5em;
.content {
padding: 1.25em 0;
@@ -121,13 +121,5 @@
margin-bottom: 2px;
}
}
&.with-darker-background {
background-color: $very-light-grey-transparency;
a {
color: $teal-500;
}
}
}
}

View File

@@ -115,14 +115,3 @@
height: 36px;
}
}
.links {
.button {
padding: 1.125rem 0 1.1875rem;
width: 210px;
@media all and (max-width: 480px) {
width: 100%;
}
}
}

View File

@@ -64,13 +64,13 @@
.button.primary, button.primary {
font-family: $body-font;
background: $orange-450;
background: $clr-brick;
color: white;
}
.button.primary:hover, .button.primary:active, .button.primary:focus, button.primary:hover, button.primary:active, button.primary:focus {
background: $orange-400;
text-shadow: 0 1px 0 $orange-450;
background: $clr-brick-bright;
text-shadow: 0 1px 0 $clr-brick;
}
button.success, .button.success {

View File

@@ -138,10 +138,6 @@ a {
&.ms {
background-color: #000 !important;
}
&.ig {
background-color: #fb3958 !important;
}
}
.sidebar .soc-btn {

View File

@@ -4,17 +4,18 @@ module Admin
#
def index
order_params = params[:q].andand.delete :order
orders = order_permissions.editable_orders.ransack(order_params).result
@line_items = order_permissions.
order_permissions = ::Permissions::Order.new(spree_current_user)
orders = order_permissions.
editable_orders.ransack(order_params).result
line_items = order_permissions.
editable_line_items.where(order_id: orders).
includes(variant: { option_values: :option_type }).
ransack(params[:q]).result.
reorder('spree_line_items.order_id ASC, spree_line_items.id ASC')
@line_items = @line_items.page(page).per(params[:per_page]) if using_pagination?
render json: { line_items: serialized_line_items, pagination: pagination_data }
render_as_json line_items
end
# PUT /admin/bulk_line_items/:id.json
@@ -64,12 +65,6 @@ module Admin
Api::Admin::LineItemSerializer
end
def serialized_line_items
ActiveModel::ArraySerializer.new(
@line_items, each_serializer: serializer(nil)
)
end
def authorize_update!
authorize! :update, order
authorize! :read, order
@@ -78,28 +73,5 @@ module Admin
def order
@line_item.order
end
def order_permissions
::Permissions::Order.new(spree_current_user)
end
def using_pagination?
params[:per_page]
end
def pagination_data
return unless using_pagination?
{
results: @line_items.total_count,
pages: @line_items.num_pages,
page: page.to_i,
per_page: params[:per_page].to_i
}
end
def page
params[:page] || 1
end
end
end

View File

@@ -17,9 +17,8 @@ module Admin
respond_to do |format|
format.html
format.json do
render_as_json @collection,
tag_rule_mapping: tag_rule_mapping,
customer_tags: customer_tags_by_id
tag_rule_mapping = TagRule.mapping_for(Enterprise.where(id: params[:enterprise_id]))
render_as_json @collection, tag_rule_mapping: tag_rule_mapping
end
end
end
@@ -65,13 +64,8 @@ module Admin
def collection
return Customer.where("1=0") unless json_request? && params[:enterprise_id].present?
Customer.of(managed_enterprise_id).
includes(:bill_address, :ship_address, user: :credit_cards)
end
def managed_enterprise_id
@managed_enterprise_id ||= Enterprise.managed_by(spree_current_user).
select('enterprises.id').find_by_id(params[:enterprise_id])
enterprise = Enterprise.managed_by(spree_current_user).find_by_id(params[:enterprise_id])
Customer.of(enterprise)
end
def load_managed_shops
@@ -86,28 +80,5 @@ module Admin
def ams_prefix_whitelist
[:subscription]
end
def tag_rule_mapping
TagRule.mapping_for(Enterprise.where(id: managed_enterprise_id))
end
# Fetches tags for all customers of the enterprise and returns a hash indexed by customer_id
def customer_tags_by_id
customer_tags = ::ActsAsTaggableOn::Tag.
joins(:taggings).
includes(:taggings).
where(taggings:
{ taggable_type: 'Customer',
taggable_id: Customer.of(managed_enterprise_id),
context: 'tags' })
customer_tags.each_with_object({}) do |tag, indexed_hash|
tag.taggings.each do |tagging|
customer_id = tagging.taggable_id
indexed_hash[customer_id] ||= []
indexed_hash[customer_id] << tag.name
end
end
end
end
end

View File

@@ -1,13 +1,9 @@
module Admin
class EnterpriseRelationshipsController < ResourceController
def index
@my_enterprises = Enterprise.
includes(:shipping_methods, :payment_methods).
managed_by(spree_current_user).by_name
@all_enterprises = Enterprise.includes(:shipping_methods, :payment_methods).by_name
@enterprise_relationships = EnterpriseRelationship.
includes(:parent, :child).
by_name.involving_enterprises @my_enterprises
@my_enterprises = Enterprise.managed_by(spree_current_user).by_name
@all_enterprises = Enterprise.by_name
@enterprise_relationships = EnterpriseRelationship.by_name.involving_enterprises @my_enterprises
end
def create

View File

@@ -16,7 +16,7 @@ module Admin
render_as_json @collection,
ams_prefix: params[:ams_prefix],
current_user: spree_current_user,
subscriptions_count: OrderManagement::Subscriptions::Count.new(@collection)
subscriptions_count: SubscriptionsCount.new(@collection)
end
end
end
@@ -74,7 +74,7 @@ module Admin
render_as_json @order_cycles,
ams_prefix: 'index',
current_user: spree_current_user,
subscriptions_count: OrderManagement::Subscriptions::Count.new(@collection)
subscriptions_count: SubscriptionsCount.new(@collection)
else
order_cycle = order_cycle_set.collection.find{ |oc| oc.errors.present? }
render json: { errors: order_cycle.errors.full_messages }, status: :unprocessable_entity

View File

@@ -9,19 +9,25 @@ module Admin
def cancel
if @proxy_order.cancel
render_as_json @proxy_order
respond_with(@proxy_order) do |format|
format.json { render_as_json @proxy_order }
end
else
render json: { errors: [t('admin.proxy_orders.cancel.could_not_cancel_the_order')] },
status: :unprocessable_entity
respond_with(@proxy_order) do |format|
format.json { render json: { errors: [t('admin.proxy_orders.cancel.could_not_cancel_the_order')] }, status: :unprocessable_entity }
end
end
end
def resume
if @proxy_order.resume
render_as_json @proxy_order
respond_with(@proxy_order) do |format|
format.json { render_as_json @proxy_order }
end
else
render json: { errors: [t('admin.proxy_orders.resume.could_not_resume_the_order')] },
status: :unprocessable_entity
respond_with(@proxy_order) do |format|
format.json { render json: { errors: [t('admin.proxy_orders.resume.could_not_resume_the_order')] }, status: :unprocessable_entity }
end
end
end
end

View File

@@ -1,5 +1,5 @@
require 'open_food_network/permissions'
require 'order_management/subscriptions/proxy_order_syncer'
require 'open_food_network/proxy_order_syncer'
module Admin
class SchedulesController < ResourceController
@@ -81,7 +81,7 @@ module Admin
return unless removed_ids.any? || new_ids.any?
subscriptions = Subscription.where(schedule_id: @schedule)
syncer = OrderManagement::Subscriptions::ProxyOrderSyncer.new(subscriptions)
syncer = OpenFoodNetwork::ProxyOrderSyncer.new(subscriptions)
syncer.sync!
end
end

View File

@@ -56,7 +56,7 @@ module Admin
end
def variant_if_eligible(variant_id)
OrderManagement::Subscriptions::VariantsList.eligible_variants(@shop).find_by_id(variant_id)
SubscriptionVariantsService.eligible_variants(@shop).find_by_id(variant_id)
end
end
end

View File

@@ -1,4 +1,5 @@
require 'open_food_network/permissions'
require 'open_food_network/proxy_order_syncer'
module Admin
class SubscriptionsController < ResourceController
@@ -64,7 +65,7 @@ module Admin
private
def save_form_and_render(render_issues = true)
form = OrderManagement::Subscriptions::Form.new(@subscription, params[:subscription])
form = SubscriptionForm.new(@subscription, params[:subscription])
unless form.save
render json: { errors: form.json_errors }, status: :unprocessable_entity
return

View File

@@ -73,10 +73,8 @@ module Admin
end
def collection
@variant_overrides = VariantOverride.
includes(variant: :product).
for_hubs(params[:hub_id] || @hubs).
select { |vo| vo.variant.present? }
@variant_overrides = VariantOverride.includes(:variant).for_hubs(params[:hub_id] || @hubs)
@variant_overrides.select { |vo| vo.variant.present? }
end
def collection_actions

View File

@@ -5,6 +5,7 @@ module Api
before_filter :override_sells, only: [:create, :update]
before_filter :override_visible, only: [:create, :update]
respond_to :json
skip_authorization_check only: [:shopfront]
def create
authorize! :create, Enterprise
@@ -41,6 +42,12 @@ module Api
end
end
def shopfront
enterprise = Enterprise.find_by_id(params[:id])
render text: Api::EnterpriseShopfrontSerializer.new(enterprise).to_json, status: :ok
end
private
def override_owner

View File

@@ -1,18 +1,11 @@
module Api
class OrderCyclesController < Api::BaseController
include EnterprisesHelper
include ApiActionCaching
respond_to :json
skip_authorization_check
skip_before_filter :authenticate_user, :ensure_api_key, only: [:taxons, :properties]
caches_action :taxons, :properties,
expires_in: CacheService::FILTERS_EXPIRY,
cache_path: proc { |controller| controller.request.url }
def products
return render_no_products unless order_cycle.open?
products = ProductsRenderer.new(
distributor,
order_cycle,
@@ -22,7 +15,7 @@ module Api
render json: products
rescue ProductsRenderer::NoProducts
render_no_products
render status: :not_found, json: ''
end
def taxons
@@ -42,10 +35,6 @@ module Api
private
def render_no_products
render status: :not_found, json: ''
end
def product_properties
Spree::Property.
joins(:products).
@@ -81,11 +70,11 @@ module Api
end
def distributor
@distributor ||= Enterprise.find_by_id(params[:distributor])
Enterprise.find_by_id(params[:distributor])
end
def order_cycle
@order_cycle ||= OrderCycle.find_by_id(params[:id])
OrderCycle.find_by_id(params[:id])
end
def customer

View File

@@ -69,12 +69,12 @@ module Api
end
def overridable
producer_ids = OpenFoodNetwork::Permissions.new(current_api_user).
variant_override_producers.by_name.select('enterprises.id')
producers = OpenFoodNetwork::Permissions.new(current_api_user).
variant_override_producers.by_name
@products = paged_products_for_producers producer_ids
@products = paged_products_for_producers producers
render_paged_products @products, ::Api::Admin::ProductSimpleSerializer
render_paged_products @products
end
# POST /api/products/:product_id/clone
@@ -118,20 +118,19 @@ module Api
]
end
def paged_products_for_producers(producer_ids)
def paged_products_for_producers(producers)
Spree::Product.scoped.
merge(product_scope).
includes(variants: [:product, :default_price, :stock_items]).
where(supplier_id: producer_ids).
where(supplier_id: producers).
by_producer.by_name.
ransack(params[:q]).result.
page(params[:page]).per(params[:per_page])
end
def render_paged_products(products, product_serializer = ::Api::Admin::ProductSerializer)
def render_paged_products(products)
serializer = ActiveModel::ArraySerializer.new(
products,
each_serializer: product_serializer
each_serializer: ::Api::Admin::ProductSerializer
)
render text: {

View File

@@ -1,27 +0,0 @@
# frozen_string_literal: true
module Api
class ShopsController < BaseController
respond_to :json
skip_authorization_check only: [:show, :closed_shops]
def show
enterprise = Enterprise.find_by_id(params[:id])
render text: Api::EnterpriseShopfrontSerializer.new(enterprise).to_json, status: :ok
end
def closed_shops
@active_distributor_ids = []
@earliest_closing_times = []
serialized_closed_shops = ActiveModel::ArraySerializer.new(
ShopsListService.new.closed_shops,
each_serializer: Api::EnterpriseSerializer,
data: OpenFoodNetwork::EnterpriseInjectionData.new
)
render json: serialized_closed_shops
end
end
end

View File

@@ -14,6 +14,10 @@ class BaseController < ApplicationController
helper 'spree/base'
# Spree::Core::ControllerHelpers declares helper_method get_taxonomies, so we need to
# include Spree::ProductsHelper so that method is available on the controller
include Spree::ProductsHelper
before_filter :set_locale
before_filter :check_order_cycle_expiry
@@ -25,19 +29,17 @@ class BaseController < ApplicationController
return
end
@order_cycles = Shop::OrderCyclesList.new(@distributor, current_customer).call
@order_cycles = OrderCycle.with_distributor(@distributor).active
.order(@distributor.preferred_shopfront_order_cycle_order)
set_order_cycle
end
applicator = OpenFoodNetwork::TagRuleApplicator.new(@distributor,
"FilterOrderCycles",
current_customer.andand.tag_list)
applicator.filter!(@order_cycles)
# Default to the only order cycle if there's only one
#
# Here we need to use @order_cycles.size not @order_cycles.count
# because OrderCyclesList returns a modified ActiveRecord::Relation
# and these modifications are not seen if it is reloaded with count
def set_order_cycle
return if @order_cycles.size != 1
current_order(true).set_order_cycle! @order_cycles.first
# And default to the only order cycle if there's only the one
if @order_cycles.count == 1
current_order(true).set_order_cycle! @order_cycles.first
end
end
end

View File

@@ -4,24 +4,24 @@ class CartController < BaseController
before_filter :check_authorization
def populate
order = current_order(true)
# Without intervention, the Spree::Adjustment#update_adjustable callback is called many times
# during cart population, for both taxation and enterprise fees. This operation triggers a
# costly Spree::Order#update!, which only needs to be run once. We avoid this by disabling
# callbacks on Spree::Adjustment and then manually invoke Spree::Order#update! on success.
Spree::Adjustment.without_callbacks do
cart_service = CartService.new(order)
cart_service = CartService.new(current_order(true))
if cart_service.populate(params.slice(:products, :variants, :quantity), true)
order.update_distribution_charge!
order.cap_quantity_at_stock!
order.update!
fire_event('spree.cart.add')
fire_event('spree.order.contents_changed')
current_order.cap_quantity_at_stock!
current_order.update!
variant_ids = variant_ids_in(cart_service.variants_h)
render json: { error: false,
stock_levels: VariantsStockLevels.new.call(order, variant_ids) },
stock_levels: VariantsStockLevels.new.call(current_order, variant_ids) },
status: :ok
else
render json: { error: true }, status: :precondition_failed

View File

@@ -53,8 +53,9 @@ class CheckoutController < Spree::StoreController
rescue Spree::Core::GatewayError => e
rescue_from_spree_gateway_error(e)
rescue StandardError => e
Bugsnag.notify(e)
flash[:error] = I18n.t("checkout.failed")
update_failed(e)
update_failed
end
# Clears the cached order. Required for #current_order to return a new order
@@ -133,6 +134,13 @@ class CheckoutController < Spree::StoreController
@order.ship_address = finder.ship_address
end
def before_delivery
return if params[:order].present?
packages = @order.shipments.map(&:to_package)
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
end
def before_payment
current_order.payments.destroy_all if request.put?
end
@@ -146,12 +154,10 @@ class CheckoutController < Spree::StoreController
end
def valid_payment_intent_provided?
return false unless params["payment_intent"]&.starts_with?("pi_")
last_payment = OrderPaymentFinder.new(@order).last_payment
@order.state == "payment" &&
last_payment&.state == "pending" &&
last_payment&.response_code == params["payment_intent"]
params["payment_intent"]&.starts_with?("pi_") &&
@order.state == "payment" &&
@order.payments.last.state == "pending" &&
@order.payments.last.response_code == params["payment_intent"]
end
def handle_redirect_from_stripe
@@ -159,7 +165,7 @@ class CheckoutController < Spree::StoreController
checkout_succeeded
redirect_to(order_path(@order)) && return
else
flash[:error] = order_error
flash[:error] = order_workflow_error
checkout_failed
end
end
@@ -174,6 +180,7 @@ class CheckoutController < Spree::StoreController
next if advance_order_state(@order)
flash[:error] = order_workflow_error
return update_failed
end
@@ -198,7 +205,7 @@ class CheckoutController < Spree::StoreController
false
end
def order_error
def order_workflow_error
if @order.errors.present?
@order.errors.full_messages.to_sentence
else
@@ -211,7 +218,7 @@ class CheckoutController < Spree::StoreController
checkout_succeeded
update_succeeded_response
else
update_failed(RuntimeError.new("Order not complete after the checkout workflow"))
update_failed
end
end
@@ -237,10 +244,7 @@ class CheckoutController < Spree::StoreController
end
end
def update_failed(error = RuntimeError.new(order_error))
Bugsnag.notify(error)
flash[:error] = order_error if flash.empty?
def update_failed
checkout_failed
update_failed_response
end

View File

@@ -96,8 +96,8 @@ class EnterprisesController < BaseController
end
def reset_order_cycle(order, distributor)
order_cycles = Shop::OrderCyclesList.new(distributor, current_customer).call
order.order_cycle = order_cycles.first if order_cycles.size == 1
order_cycle_options = OrderCycle.active.with_distributor(distributor)
order.order_cycle = order_cycle_options.first if order_cycle_options.count == 1
end
def shop_order_cycles

View File

@@ -5,23 +5,12 @@ class HomeController < BaseController
def index
if ContentConfig.home_show_stats
@num_distributors = cached_count('distributors', Enterprise.is_distributor.activated.visible)
@num_producers = cached_count('producers', Enterprise.is_primary_producer.activated.visible)
@num_orders = cached_count('orders', Spree::Order.complete)
@num_users = cached_count(
'users', Spree::Order.complete.select('DISTINCT spree_orders.user_id')
)
@num_distributors = Enterprise.is_distributor.activated.visible.count
@num_producers = Enterprise.is_primary_producer.activated.visible.count
@num_users = Spree::Order.complete.count('DISTINCT user_id')
@num_orders = Spree::Order.complete.count
end
end
def sell; end
private
# Cache the value of the query count
def cached_count(statistic, query)
CacheService.home_stats(statistic) do
query.count
end
end
end

View File

@@ -4,6 +4,13 @@ class ShopsController < BaseController
before_filter :enable_embedded_shopfront
def index
@enterprises = ShopsListService.new.open_shops
@enterprises = Enterprise
.activated
.visible
.is_distributor
.includes(address: [:state, :country])
.includes(:properties)
.includes(supplied_products: :properties)
.all
end
end

View File

@@ -4,6 +4,10 @@ module Spree
after_filter :initialize_mail_settings
def update
if params[:smtp_password].blank?
params.delete(:smtp_password)
end
params.each do |name, value|
next unless Spree::Config.has_preference? name

View File

@@ -29,8 +29,6 @@ module Spree
return
end
authorize_stripe_sca_payment
if @order.completed?
@payment.process!
flash[:success] = flash_message_for(@payment, :successfully_created)
@@ -95,7 +93,7 @@ module Spree
available(:back_end).
select{ |pm| pm.has_distributor? @order.distributor }
@payment_method = if @payment&.payment_method
@payment_method = if @payment && @payment.payment_method
@payment.payment_method
else
@payment_methods.first
@@ -126,13 +124,6 @@ module Spree
def load_payment
@payment = Payment.find(params[:id])
end
def authorize_stripe_sca_payment
return unless @payment.payment_method.class == Spree::Gateway::StripeSCA
@payment.authorize!
raise Spree::Core::GatewayError, I18n.t('authorization_failure') unless @payment.pending?
end
end
end
end

View File

@@ -0,0 +1,66 @@
module Spree
module Admin
module Reports
class EnterpriseFeeSummariesController < BaseController
before_filter :load_report_parameters
before_filter :load_permissions
def new; end
def create
return respond_to_invalid_parameters unless @report_parameters.valid?
@report_parameters.authorize!(@permissions)
@report = report_klass::ReportService.new(@permissions, @report_parameters)
renderer.render(self)
rescue ::Reports::Authorizer::ParameterNotAllowedError => e
flash[:error] = e.message
render_report_form
end
private
def respond_to_invalid_parameters
flash[:error] = I18n.t("invalid_filter_parameters", scope: i18n_scope)
render_report_form
end
def i18n_scope
"order_management.reports.enterprise_fee_summary"
end
def render_report_form
render action: :new
end
def report_klass
OrderManagement::Reports::EnterpriseFeeSummary
end
def load_report_parameters
@report_parameters = report_klass::Parameters.new(params[:report] || {})
end
def load_permissions
@permissions = report_klass::Permissions.new(spree_current_user)
end
def report_renderer_klass
case params[:report_format]
when "csv"
report_klass::Renderers::CsvRenderer
when nil, "", "html"
report_klass::Renderers::HtmlRenderer
else
raise Reports::UnsupportedReportFormatException
end
end
def renderer
@renderer ||= report_renderer_klass.new(@report)
end
end
end
end
end

View File

@@ -298,20 +298,11 @@ module Spree
end
def url_for_report(report)
if report_in_order_management_engine?(report)
main_app.public_send("new_order_management_reports_#{report}_url".to_sym)
else
public_send("#{report}_admin_reports_url".to_sym)
end
public_send("#{report}_admin_reports_url".to_sym)
rescue NoMethodError
url_for([:new, :admin, :reports, report.to_s.singularize])
end
# List of reports that have been moved to the Order Management engine
def report_in_order_management_engine?(report)
report == :enterprise_fee_summary
end
def timestamp
Time.zone.now.strftime("%Y%m%d")
end

View File

@@ -3,6 +3,14 @@ module Spree
class TaxonsController < Spree::Admin::BaseController
respond_to :html, :json, :js
def search
@taxons = if params[:ids]
Spree::Taxon.where(id: params[:ids].split(','))
else
Spree::Taxon.limit(20).search(name_cont: params[:q]).result
end
end
def create
@taxonomy = Taxonomy.find(params[:taxonomy_id])
@taxon = @taxonomy.taxons.build(params[:taxon])

View File

@@ -1,4 +1,6 @@
module ApplicationHelper
include FoundationRailsHelper::FlashHelper
def feature?(feature)
OpenFoodNetwork::FeatureToggle.enabled? feature
end

View File

@@ -47,7 +47,7 @@ module InjectionHelper
enterprises_and_relatives = current_distributor.
relatives_including_self.
activated.
includes(:properties, address: [:state, :country], supplied_products: :properties).
includes(address: [:state, :country]).
all
inject_json_ams "enterprises",

View File

@@ -47,6 +47,17 @@ module OrderCyclesHelper
end
end
def order_cycle_options
@order_cycles.
with_distributor(current_distributor).
map { |oc| [order_cycle_close_to_s(oc.orders_close_at), oc.id] }
end
def order_cycle_close_to_s(orders_close_at)
"%s (%s)" % [orders_close_at.strftime("#{orders_close_at.day.ordinalize} %b"),
distance_of_time_in_words_to_now(orders_close_at)]
end
def active_order_cycle_for_distributor?(_distributor)
OrderCycle.active.with_distributor(@distributor).present?
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
module OrderHelper
def last_payment_method(order)
OrderPaymentFinder.new(order).last_payment&.payment_method
end
end

View File

@@ -13,7 +13,7 @@ module ShopHelper
end
def require_customer?
@require_customer ||= current_distributor.require_login? && !user_is_related_to_distributor?
current_distributor.require_login? && !user_is_related_to_distributor?
end
def user_is_related_to_distributor?
@@ -48,6 +48,6 @@ module ShopHelper
end
def no_open_order_cycles?
@no_open_order_cycles ||= @order_cycles&.empty?
@order_cycles && @order_cycles.empty?
end
end

View File

@@ -1,13 +0,0 @@
# frozen_string_literal: true
module Spree
module ProductsHelper
def product_has_variant_unit_option_type?(product)
product.option_types.any? { |option_type| variant_unit_option_type? option_type }
end
def variant_unit_option_type?(option_type)
Spree::Product.all_variant_unit_option_types.include? option_type
end
end
end

View File

@@ -0,0 +1,23 @@
module Spree
ProductsHelper.class_eval do
# Return the price of the variant, overriding sprees price diff capability.
# This will allways return the variant price as if the show_variant_full_price is set.
def variant_price_diff(variant)
"(#{Spree::Money.new(variant.price)})"
end
def product_has_variant_unit_option_type?(product)
product.option_types.any? { |option_type| variant_unit_option_type? option_type }
end
def variant_unit_option_type?(option_type)
Spree::Product.all_variant_unit_option_types.include? option_type
end
def product_variant_unit_options
[[I18n.t(:weight), 'weight'],
[I18n.t(:volume), 'volume'],
[I18n.t(:items), 'items']]
end
end
end

View File

@@ -1,9 +1,17 @@
require 'order_management/subscriptions/summarizer'
require 'open_food_network/subscription_payment_updater'
require 'open_food_network/subscription_summarizer'
# Confirms orders of unconfirmed proxy orders in recently closed Order Cycles
class SubscriptionConfirmJob
def perform
confirm_proxy_orders!
ids = proxy_orders.pluck(:id)
proxy_orders.update_all(confirmed_at: Time.zone.now)
ProxyOrder.where(id: ids).each do |proxy_order|
Rails.logger.info "Confirming Order for Proxy Order #{proxy_order.id}"
@order = proxy_order.order
process!
end
send_confirmation_summary_emails
end
private
@@ -12,26 +20,10 @@ class SubscriptionConfirmJob
delegate :record_and_log_error, :send_confirmation_summary_emails, to: :summarizer
def summarizer
@summarizer ||= OrderManagement::Subscriptions::Summarizer.new
@summarizer ||= OpenFoodNetwork::SubscriptionSummarizer.new
end
def confirm_proxy_orders!
# Fetch all unconfirmed proxy orders
unconfirmed_proxy_orders_ids = unconfirmed_proxy_orders.pluck(:id)
# Mark these proxy orders as confirmed
unconfirmed_proxy_orders.update_all(confirmed_at: Time.zone.now)
# Confirm these proxy orders
ProxyOrder.where(id: unconfirmed_proxy_orders_ids).each do |proxy_order|
Rails.logger.info "Confirming Order for Proxy Order #{proxy_order.id}"
confirm_order!(proxy_order.order)
end
send_confirmation_summary_emails
end
def unconfirmed_proxy_orders
def proxy_orders
ProxyOrder.not_canceled.where('confirmed_at IS NULL AND placed_at IS NOT NULL')
.joins(:order_cycle).merge(recently_closed_order_cycles)
.joins(:order).merge(Spree::Order.complete.not_state('canceled'))
@@ -41,55 +33,30 @@ class SubscriptionConfirmJob
OrderCycle.closed.where('order_cycles.orders_close_at BETWEEN (?) AND (?) OR order_cycles.updated_at BETWEEN (?) AND (?)', 1.hour.ago, Time.zone.now, 1.hour.ago, Time.zone.now)
end
# It sets up payments, processes payments and sends confirmation emails
def confirm_order!(order)
record_order(order)
def process!
record_order(@order)
update_payment! if @order.payment_required?
return send_failed_payment_email if @order.errors.present?
if process_payment!(order)
send_confirmation_email(order)
else
send_failed_payment_email(order)
end
@order.process_payments! if @order.payment_required?
return send_failed_payment_email if @order.errors.present?
send_confirm_email
end
def process_payment!(order)
return false if order.errors.present?
return true unless order.payment_required?
setup_payment!(order)
return false if order.errors.any?
authorize_payment!(order)
return false if order.errors.any?
order.process_payments!
return false if order.errors.any?
true
def update_payment!
OpenFoodNetwork::SubscriptionPaymentUpdater.new(@order).update!
end
def setup_payment!(order)
OrderManagement::Subscriptions::PaymentSetup.new(order).call!
return if order.errors.any?
OrderManagement::Subscriptions::StripePaymentSetup.new(order).call!
def send_confirm_email
@order.update!
record_success(@order)
SubscriptionMailer.confirmation_email(@order).deliver
end
def authorize_payment!(order)
return if order.subscription.payment_method.class != Spree::Gateway::StripeSCA
OrderManagement::Subscriptions::StripeScaPaymentAuthorize.new(order).call!
end
def send_confirmation_email(order)
order.update!
record_success(order)
SubscriptionMailer.confirmation_email(order).deliver
end
def send_failed_payment_email(order)
order.update!
record_and_log_error(:failed_payment, order)
SubscriptionMailer.failed_payment_email(order).deliver
def send_failed_payment_email
@order.update!
record_and_log_error(:failed_payment, @order)
SubscriptionMailer.failed_payment_email(@order).deliver
end
end

View File

@@ -1,4 +1,4 @@
require 'order_management/subscriptions/summarizer'
require 'open_food_network/subscription_summarizer'
class SubscriptionPlacementJob
def perform
@@ -17,7 +17,7 @@ class SubscriptionPlacementJob
delegate :record_and_log_error, :send_placement_summary_emails, to: :summarizer
def summarizer
@summarizer ||= OrderManagement::Subscriptions::Summarizer.new
@summarizer ||= OpenFoodNetwork::SubscriptionSummarizer.new
end
def proxy_orders

View File

@@ -1,58 +1,41 @@
# frozen_string_literal: true
class ProducerMailer < Spree::BaseMailer
include I18nHelper
def order_cycle_report(producer, order_cycle)
@producer = producer
@coordinator = order_cycle.coordinator
@order_cycle = order_cycle
line_items = line_items_from(@order_cycle, @producer)
@grouped_line_items = line_items.group_by(&:product_and_full_name)
@receival_instructions = @order_cycle.receival_instructions_for @producer
@total = total_from_line_items(line_items)
@tax_total = tax_total_from_line_items(line_items)
with_unscoped_products_and_variants do
load_data
I18n.with_locale valid_locale(@producer.owner) do
order_cycle_subject = I18n.t('producer_mailer.order_cycle.subject', producer: producer.name)
subject = "[#{Spree::Config.site_name}] #{order_cycle_subject}"
I18n.with_locale(owner_locale) do
return unless orders?(order_cycle, producer)
return unless has_orders?(order_cycle, producer)
mail(
to: @producer.contact.email,
from: from_address,
subject: subject,
reply_to: @coordinator.contact.email,
cc: @coordinator.contact.email
)
end
mail(
to: @producer.contact.email,
from: from_address,
subject: subject,
reply_to: @coordinator.contact.email,
cc: @coordinator.contact.email
)
end
end
private
def owner_locale
valid_locale(@producer.owner)
end
def load_data
@coordinator = @order_cycle.coordinator
line_items = line_items_from(@order_cycle, @producer)
@grouped_line_items = line_items.group_by(&:product_and_full_name)
@receival_instructions = @order_cycle.receival_instructions_for(@producer)
@total = total_from_line_items(line_items)
@tax_total = tax_total_from_line_items(line_items)
end
def subject
order_cycle_subject = I18n.t('producer_mailer.order_cycle.subject', producer: @producer.name)
"[#{Spree::Config.site_name}] #{order_cycle_subject}"
end
def orders?(order_cycle, producer)
def has_orders?(order_cycle, producer)
line_items_from(order_cycle, producer).any?
end
def line_items_from(order_cycle, producer)
@line_items ||= Spree::LineItem.
includes(:option_values, variant: [:product, { option_values: :option_type }]).
Spree::LineItem.
includes(variant: { option_values: :option_type }).
from_order_cycle(order_cycle).
sorted_by_name_and_unit_value.
merge(Spree::Product.in_supplier(producer)).
@@ -66,22 +49,4 @@ class ProducerMailer < Spree::BaseMailer
def tax_total_from_line_items(line_items)
Spree::Money.new line_items.sum(&:included_tax)
end
# This hack makes ActiveRecord skip the default_scope (deleted_at IS NULL)
# when eager loading associations. Further details:
# https://github.com/rails/rails/issues/11036
def with_unscoped_products_and_variants
variant_default_scopes = Spree::Variant.default_scopes
product_default_scopes = Spree::Product.default_scopes
Spree::Variant.default_scopes = []
Spree::Product.default_scopes = []
return_value = yield
Spree::Variant.default_scopes = variant_default_scopes
Spree::Product.default_scopes = product_default_scopes
return_value
end
end

View File

@@ -2,7 +2,6 @@ Spree::OrderMailer.class_eval do
helper HtmlHelper
helper CheckoutHelper
helper SpreeCurrencyHelper
helper OrderHelper
include I18nHelper
def cancel_email(order_or_order_id, resend = false)

View File

@@ -1,7 +1,6 @@
class SubscriptionMailer < Spree::BaseMailer
helper CheckoutHelper
helper ShopMailHelper
helper OrderHelper
include I18nHelper
def confirmation_email(order)

View File

@@ -1,21 +0,0 @@
# frozen_string_literal: true
# API controllers inherit from ActionController::Metal to keep them slim and fast.
# This concern adds the minimum requirements needed to use Action Caching in the API.
module ApiActionCaching
extend ActiveSupport::Concern
included do
include ActionController::Caching
include ActionController::Caching::Actions
include AbstractController::Layouts
# These configs are not assigned to the controller automatically with ActionController::Metal
self.cache_store = Rails.configuration.cache_store
self.perform_caching = true
# ActionController::Caching asks for a controller's layout, but they're not used in the API
layout false
end
end

View File

@@ -40,18 +40,9 @@ module VariantStock
# Checks whether this variant is produced on demand.
def on_demand
# A variant that has not been saved yet or has been soft-deleted doesn't have a stock item
# A variant that has not been saved yet, doesn't have a stock item
# This provides a default value for variant.on_demand using Spree::StockLocation.backorderable_default
return Spree::StockLocation.first.backorderable_default if new_record? || deleted?
# This can be removed unless we have seen this error in Bugsnag recently
if stock_item.nil?
Bugsnag.notify(
RuntimeError.new("Variant #stock_item called, but the stock_item does not exist!"),
object: as_json
)
return Spree::StockLocation.first.backorderable_default
end
return Spree::StockLocation.first.backorderable_default if stock_items.empty?
stock_item.backorderable?
end

View File

@@ -57,8 +57,8 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration
# Other
preference :footer_facebook_url, :string, default: "https://www.facebook.com/OpenFoodNet"
preference :footer_twitter_url, :string, default: "https://twitter.com/OpenFoodNet"
preference :footer_instagram_url, :string, default: "https://www.instagram.com/openfoodnetworkuk/"
preference :footer_linkedin_url, :string, default: "https://www.linkedin.com/company/openfoodnetwork/"
preference :footer_instagram_url, :string, default: ""
preference :footer_linkedin_url, :string, default: "http://www.linkedin.com/groups/Open-Food-Foundation-4743336"
preference :footer_googleplus_url, :string, default: ""
preference :footer_pinterest_url, :string, default: ""
preference :footer_email, :string, default: "hello@openfoodnetwork.org"

View File

@@ -1,5 +1,5 @@
class DistributorShippingMethod < ActiveRecord::Base
self.table_name = "distributors_shipping_methods"
belongs_to :shipping_method, class_name: Spree::ShippingMethod, touch: true
belongs_to :shipping_method, class_name: Spree::ShippingMethod
belongs_to :distributor, class_name: Enterprise, touch: true
end

View File

@@ -16,9 +16,8 @@ class OrderCycle < ActiveRecord::Base
has_many :suppliers, source: :sender, through: :cached_incoming_exchanges, uniq: true
has_many :distributors, source: :receiver, through: :cached_outgoing_exchanges, uniq: true
has_many :schedules, through: :order_cycle_schedules
has_many :order_cycle_schedules
has_paper_trail meta: { custom_data: proc { |order_cycle| order_cycle.schedule_ids.to_s } }
has_and_belongs_to_many :schedules, join_table: 'order_cycle_schedules'
has_paper_trail meta: { custom_data: :schedule_ids }
attr_accessor :incoming_exchanges, :outgoing_exchanges
@@ -241,8 +240,7 @@ class OrderCycle < ActiveRecord::Base
end
def exchanges_supplying(order)
variant_ids_relation = Spree::LineItem.in_orders(order).select(:variant_id)
exchanges.supplying_to(order.distributor).with_any_variant(variant_ids_relation)
exchanges.supplying_to(order.distributor).with_any_variant(order.variants.map(&:id))
end
def coordinated_by?(user)

View File

@@ -1,6 +0,0 @@
# frozen_string_literal: true
class OrderCycleSchedule < ActiveRecord::Base
belongs_to :schedule
belongs_to :order_cycle
end

View File

@@ -4,6 +4,18 @@ class ProducerProperty < ActiveRecord::Base
default_scope { order("#{table_name}.position") }
scope :ever_sold_by, ->(shop) {
joins(producer: { supplied_products: { variants: { exchanges: :order_cycle } } }).
merge(Exchange.outgoing).
merge(Exchange.to_enterprise(shop)).
select('DISTINCT producer_properties.*')
}
scope :currently_sold_by, ->(shop) {
ever_sold_by(shop).
merge(OrderCycle.active)
}
def property_name
property.name if property
end

View File

@@ -1,8 +1,7 @@
class Schedule < ActiveRecord::Base
has_paper_trail meta: { custom_data: proc { |schedule| schedule.order_cycle_ids.to_s } }
has_and_belongs_to_many :order_cycles, join_table: 'order_cycle_schedules'
has_paper_trail meta: { custom_data: :order_cycle_ids }
has_many :order_cycles, through: :order_cycle_schedules
has_many :order_cycle_schedules, dependent: :destroy
has_many :coordinators, uniq: true, through: :order_cycles
attr_accessible :name, :order_cycle_ids

View File

@@ -14,6 +14,7 @@ Spree::AppConfiguration.class_eval do
preference :privacy_policy_url, :string, default: nil
preference :cookies_consent_banner_toggle, :boolean, default: false
preference :cookies_policy_matomo_section, :boolean, default: false
preference :cookies_policy_ga_section, :boolean, default: false
# Tax Preferences
preference :products_require_tax_category, :boolean, default: false

View File

@@ -17,9 +17,9 @@ module Spree
order_amount = line_items_for(object).map { |x| x.price * x.quantity }.sum
if order_amount < min
cost = preferred_normal_amount.to_f
cost = preferred_normal_amount.to_i
elsif order_amount >= min
cost = preferred_discount_amount.to_f
cost = preferred_discount_amount.to_i
end
cost

View File

@@ -1,6 +1,5 @@
Spree::Classification.class_eval do
belongs_to :product, class_name: "Spree::Product", touch: true
belongs_to :taxon, class_name: "Spree::Taxon", touch: true
before_destroy :dont_destroy_if_primary_taxon

View File

@@ -0,0 +1,6 @@
Spree::Money.class_eval do
# return the currency symbol (on it's own) for the current default currency
def self.currency_symbol
Money.new(0, Spree::Config[:currency]).symbol
end
end

View File

@@ -210,7 +210,7 @@ Spree::Order.class_eval do
end
def cap_quantity_at_stock!
line_items.includes(variant: :stock_items).all.each(&:cap_quantity_at_stock!)
line_items.each(&:cap_quantity_at_stock!)
end
def set_distributor!(distributor)
@@ -237,10 +237,7 @@ Spree::Order.class_eval do
with_lock do
EnterpriseFee.clear_all_adjustments_on_order self
loaded_line_items =
line_items.includes(variant: :product, order: [:distributor, :order_cycle]).all
loaded_line_items.each do |line_item|
line_items.each do |line_item|
if provided_by_order_cycle? line_item
OpenFoodNetwork::EnterpriseFeeCalculator.new.create_line_item_adjustments_for line_item
end
@@ -266,11 +263,7 @@ Spree::Order.class_eval do
end
def line_item_variants
if line_items.loaded?
line_items.map(&:variant)
else
line_items.includes(:variant).map(&:variant)
end
line_items.map(&:variant)
end
# Show already bought line items of this order cycle

View File

@@ -12,7 +12,7 @@ Spree::Product.class_eval do
has_many :option_types, through: :product_option_types, dependent: :destroy
belongs_to :supplier, class_name: 'Enterprise', touch: true
belongs_to :primary_taxon, class_name: 'Spree::Taxon', touch: true
belongs_to :primary_taxon, class_name: 'Spree::Taxon'
delegate_belongs_to :master, :unit_value, :unit_description
delegate :images_attributes=, :display_as=, to: :master

View File

@@ -2,16 +2,11 @@ module Spree
class Property < ActiveRecord::Base
has_many :product_properties, dependent: :destroy
has_many :products, through: :product_properties
has_many :producer_properties
attr_accessible :name, :presentation
validates :name, :presentation, presence: true
scope :sorted, -> { order(:name) }
def property
self
end
end
end

View File

@@ -0,0 +1,27 @@
module Spree
Property.class_eval do
has_many :producer_properties
scope :applied_by, ->(enterprise) {
select('DISTINCT spree_properties.*').
joins(:product_properties).
where('spree_product_properties.product_id IN (?)', enterprise.supplied_product_ids)
}
scope :ever_sold_by, ->(shop) {
joins(products: { variants: { exchanges: :order_cycle } }).
merge(Exchange.outgoing).
merge(Exchange.to_enterprise(shop)).
select('DISTINCT spree_properties.*')
}
scope :currently_sold_by, ->(shop) {
ever_sold_by(shop).
merge(OrderCycle.active)
}
def property
self
end
end
end

View File

@@ -1,40 +0,0 @@
# frozen_string_literal: true
module Spree
module Stock
class Quantifier
attr_reader :stock_items
def initialize(variant)
@variant = variant
@stock_items = fetch_stock_items
end
def total_on_hand
# Associated stock_items no longer exist if the variant has been soft-deleted. A variant
# may still be in an active cart after it's deleted, so this will mark it as out of stock.
return 0 if @variant.deleted?
stock_items.sum(&:count_on_hand)
end
def backorderable?
stock_items.any?(&:backorderable)
end
def can_supply?(required)
total_on_hand >= required || backorderable?
end
private
def fetch_stock_items
# Don't re-fetch associated stock items from the DB if we've already eager-loaded them
return @variant.stock_items.to_a if @variant.stock_items.loaded?
Spree::StockItem.joins(:stock_location).
where(:variant_id => @variant, Spree::StockLocation.table_name => { active: true })
end
end
end
end

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