mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-17 19:26:48 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63bcbb8fa5 | ||
|
|
0784d39f8e |
@@ -1,4 +0,0 @@
|
||||
.git
|
||||
.gitignore
|
||||
log/*
|
||||
tmp/*
|
||||
@@ -49,6 +49,7 @@ Metrics/LineLength:
|
||||
- app/controllers/spree/admin/orders_controller_decorator.rb
|
||||
- app/controllers/spree/admin/payments_controller_decorator.rb
|
||||
- app/controllers/spree/admin/payment_methods_controller_decorator.rb
|
||||
- app/controllers/spree/admin/products_controller_decorator.rb
|
||||
- app/controllers/spree/admin/reports_controller_decorator.rb
|
||||
- app/controllers/spree/api/products_controller_decorator.rb
|
||||
- app/controllers/spree/credit_cards_controller.rb
|
||||
@@ -67,6 +68,7 @@ Metrics/LineLength:
|
||||
- app/helpers/shop_helper.rb
|
||||
- app/helpers/spree/admin/base_helper_decorator.rb
|
||||
- app/helpers/spree/admin/navigation_helper_decorator.rb
|
||||
- app/helpers/spree/admin/orders_helper_decorator.rb
|
||||
- app/helpers/spree/orders_helper.rb
|
||||
- app/jobs/subscription_confirm_job.rb
|
||||
- app/mailers/subscription_mailer.rb
|
||||
@@ -79,7 +81,9 @@ Metrics/LineLength:
|
||||
- app/models/enterprise_fee.rb
|
||||
- app/models/enterprise_group.rb
|
||||
- app/models/enterprise_role.rb
|
||||
- app/models/exchange.rb
|
||||
- app/models/inventory_item.rb
|
||||
- app/models/order_cycle.rb
|
||||
- app/models/product_import/entry_processor.rb
|
||||
- app/models/product_import/entry_validator.rb
|
||||
- app/models/product_import/product_importer.rb
|
||||
@@ -122,11 +126,14 @@ Metrics/LineLength:
|
||||
- app/serializers/api/admin/subscription_serializer.rb
|
||||
- app/serializers/api/admin/tag_rule_serializer.rb
|
||||
- app/serializers/api/admin/variant_override_serializer.rb
|
||||
- app/serializers/api/admin/variant_serializer.rb
|
||||
- app/services/cart_service.rb
|
||||
- app/services/default_stock_location.rb
|
||||
- app/services/embedded_page_service.rb
|
||||
- app/services/line_item_syncer.rb
|
||||
- app/services/order_cycle_form.rb
|
||||
- app/services/order_factory.rb
|
||||
- app/services/order_syncer.rb
|
||||
- app/services/subscriptions_count.rb
|
||||
- app/services/variants_stock_levels.rb
|
||||
- app/views/json/_groups.rabl
|
||||
@@ -147,12 +154,15 @@ Metrics/LineLength:
|
||||
- lib/open_food_network/order_and_distributor_report.rb
|
||||
- lib/open_food_network/order_cycle_form_applicator.rb
|
||||
- lib/open_food_network/order_cycle_management_report.rb
|
||||
- lib/open_food_network/order_cycle_permissions.rb
|
||||
- lib/open_food_network/order_grouper.rb
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/open_food_network/payments_report.rb
|
||||
- lib/open_food_network/permalink_generator.rb
|
||||
- lib/open_food_network/permissions.rb
|
||||
- lib/open_food_network/products_cache.rb
|
||||
- lib/open_food_network/products_renderer.rb
|
||||
- lib/open_food_network/proxy_order_syncer.rb
|
||||
- lib/open_food_network/reports/bulk_coop_allocation_report.rb
|
||||
- lib/open_food_network/reports/line_items.rb
|
||||
- lib/open_food_network/sales_tax_report.rb
|
||||
@@ -339,8 +349,11 @@ Metrics/LineLength:
|
||||
- spec/models/tag_rule/filter_shipping_methods_spec.rb
|
||||
- spec/models/variant_override_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
|
||||
- spec/requests/checkout/stripe_connect_spec.rb
|
||||
- spec/requests/embedded_shopfronts_headers_spec.rb
|
||||
- spec/requests/shop_spec.rb
|
||||
- spec/serializers/admin/customer_serializer_spec.rb
|
||||
@@ -416,6 +429,7 @@ Metrics/AbcSize:
|
||||
- app/helpers/checkout_helper.rb
|
||||
- app/helpers/i18n_helper.rb
|
||||
- app/helpers/order_cycles_helper.rb
|
||||
- app/helpers/spree/admin/orders_helper_decorator.rb
|
||||
- app/helpers/spree/orders_helper.rb
|
||||
- app/jobs/subscription_placement_job.rb
|
||||
- app/mailers/producer_mailer.rb
|
||||
@@ -435,6 +449,7 @@ Metrics/AbcSize:
|
||||
- app/models/spree/order_decorator.rb
|
||||
- app/models/spree/payment_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- app/models/spree/taxon_decorator.rb
|
||||
- app/serializers/api/admin/enterprise_serializer.rb
|
||||
- app/serializers/api/product_serializer.rb
|
||||
@@ -457,7 +472,6 @@ Metrics/AbcSize:
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/open_food_network/packing_report.rb
|
||||
- lib/open_food_network/payments_report.rb
|
||||
- lib/open_food_network/permissions.rb
|
||||
- lib/open_food_network/products_and_inventory_report.rb
|
||||
- lib/open_food_network/reports/line_items.rb
|
||||
- lib/open_food_network/sales_tax_report.rb
|
||||
@@ -479,35 +493,6 @@ Metrics/AbcSize:
|
||||
- spec/models/product_importer_spec.rb
|
||||
- spec/support/performance_helper.rb
|
||||
|
||||
Metrics/BlockLength:
|
||||
Max: 25
|
||||
ExcludedMethods: [
|
||||
"class_eval",
|
||||
"collection",
|
||||
"context",
|
||||
"describe",
|
||||
"feature",
|
||||
"it",
|
||||
"member",
|
||||
"namespace",
|
||||
"resource",
|
||||
"resources",
|
||||
"scenario"
|
||||
]
|
||||
Exclude:
|
||||
- lib/tasks/data.rake
|
||||
- lib/tasks/dev.rake
|
||||
- spec/controllers/spree/admin/invoices_controller_spec.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
|
||||
- spec/spec_helper.rb
|
||||
- spec/support/delayed_job_helper.rb
|
||||
- spec/support/matchers/select2_matchers.rb
|
||||
- spec/support/matchers/table_matchers.rb
|
||||
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 6
|
||||
Exclude:
|
||||
@@ -519,7 +504,7 @@ Metrics/CyclomaticComplexity:
|
||||
- app/helpers/checkout_helper.rb
|
||||
- app/helpers/i18n_helper.rb
|
||||
- app/helpers/order_cycles_helper.rb
|
||||
- app/helpers/spree/admin/navigation_helper_decorator.rb
|
||||
- app/helpers/spree/admin/orders_helper_decorator.rb
|
||||
- app/models/enterprise.rb
|
||||
- app/models/enterprise_relationship.rb
|
||||
- app/models/product_import/entry_processor.rb
|
||||
@@ -527,6 +512,7 @@ Metrics/CyclomaticComplexity:
|
||||
- app/models/spree/ability_decorator.rb
|
||||
- app/models/spree/payment_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- app/models/variant_override_set.rb
|
||||
- app/services/cart_service.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
@@ -548,12 +534,14 @@ Metrics/PerceivedComplexity:
|
||||
- app/helpers/checkout_helper.rb
|
||||
- app/helpers/i18n_helper.rb
|
||||
- app/helpers/order_cycles_helper.rb
|
||||
- app/helpers/spree/admin/orders_helper_decorator.rb
|
||||
- app/models/enterprise_relationship.rb
|
||||
- app/models/product_import/entry_processor.rb
|
||||
- app/models/product_import/entry_validator.rb
|
||||
- app/models/spree/ability_decorator.rb
|
||||
- app/models/spree/order_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/enterprise_issue_validator.rb
|
||||
@@ -592,6 +580,7 @@ Metrics/MethodLength:
|
||||
- app/controllers/user_registrations_controller.rb
|
||||
- app/helpers/checkout_helper.rb
|
||||
- app/helpers/order_cycles_helper.rb
|
||||
- app/helpers/spree/admin/orders_helper_decorator.rb
|
||||
- app/jobs/subscription_placement_job.rb
|
||||
- app/mailers/producer_mailer.rb
|
||||
- app/models/column_preference.rb
|
||||
@@ -609,6 +598,7 @@ Metrics/MethodLength:
|
||||
- app/models/spree/payment_decorator.rb
|
||||
- app/models/spree/payment_method_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- app/serializers/api/admin/order_cycle_serializer.rb
|
||||
- app/serializers/api/cached_enterprise_serializer.rb
|
||||
- app/services/order_cycle_form.rb
|
||||
|
||||
@@ -13,6 +13,8 @@ AllCops:
|
||||
- 'script/**/*'
|
||||
- 'vendor/**/*'
|
||||
- 'node_modules/**/*'
|
||||
# The parser gem fails to parse this file with out current Ruby version.
|
||||
- 'spec/factories.rb'
|
||||
# Excluding: inadequate Naming/FileName rule rejects GemFile name with camelcase
|
||||
- 'engines/web/Gemfile'
|
||||
|
||||
@@ -185,20 +187,7 @@ Metrics/AbcSize:
|
||||
Max: 15
|
||||
|
||||
Metrics/BlockLength:
|
||||
Max: 25
|
||||
ExcludedMethods: [
|
||||
"class_eval",
|
||||
"collection",
|
||||
"context",
|
||||
"describe",
|
||||
"feature",
|
||||
"it",
|
||||
"member",
|
||||
"namespace",
|
||||
"resource",
|
||||
"resources",
|
||||
"scenario"
|
||||
]
|
||||
ExcludedMethods: ["collection", "context", "describe", "it", "member", "namespace", "resource", "resources"]
|
||||
|
||||
Metrics/BlockNesting:
|
||||
Max: 3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config --exclude-limit 1400`
|
||||
# on 2019-07-23 14:09:18 +0100 using RuboCop version 0.57.2.
|
||||
# on 2019-05-28 16:29:07 +0100 using RuboCop version 0.57.2.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
@@ -32,6 +32,15 @@ Layout/EndAlignment:
|
||||
Layout/IndentHash:
|
||||
EnforcedStyle: consistent
|
||||
|
||||
# Offense count: 7
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
||||
# SupportedStyles: aligned, indented, indented_relative_to_receiver
|
||||
Layout/MultilineMethodCallIndentation:
|
||||
Exclude:
|
||||
- 'app/models/spree/line_item_decorator.rb'
|
||||
- 'app/models/spree/product_decorator.rb'
|
||||
|
||||
# Offense count: 4
|
||||
Lint/AmbiguousOperator:
|
||||
Exclude:
|
||||
@@ -46,12 +55,13 @@ Lint/DuplicateMethods:
|
||||
- 'lib/discourse/single_sign_on.rb'
|
||||
- 'lib/open_food_network/subscription_summary.rb'
|
||||
|
||||
# Offense count: 8
|
||||
# Offense count: 15
|
||||
Lint/IneffectiveAccessModifier:
|
||||
Exclude:
|
||||
- 'app/models/column_preference.rb'
|
||||
- 'app/services/mail_configuration.rb'
|
||||
- 'lib/open_food_network/feature_toggle.rb'
|
||||
- 'lib/open_food_network/products_cache.rb'
|
||||
- 'spec/lib/open_food_network/reports/report_spec.rb'
|
||||
|
||||
# Offense count: 1
|
||||
@@ -70,63 +80,39 @@ Lint/UnderscorePrefixedVariableName:
|
||||
Exclude:
|
||||
- 'spec/support/cancan_helper.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Lint/UnneededCopDisableDirective:
|
||||
Exclude:
|
||||
- 'app/models/product_import/entry_validator.rb'
|
||||
|
||||
# Offense count: 5
|
||||
# Offense count: 6
|
||||
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
|
||||
Lint/UselessAccessModifier:
|
||||
Exclude:
|
||||
- 'app/models/column_preference.rb'
|
||||
- 'app/services/mail_configuration.rb'
|
||||
- 'lib/open_food_network/feature_toggle.rb'
|
||||
- 'lib/open_food_network/products_cache.rb'
|
||||
- 'lib/open_food_network/reports/bulk_coop_report.rb'
|
||||
- 'spec/lib/open_food_network/reports/report_spec.rb'
|
||||
|
||||
# Offense count: 8
|
||||
# Offense count: 91
|
||||
# Configuration parameters: CheckForMethodsWithNoSideEffects.
|
||||
Lint/Void:
|
||||
Exclude:
|
||||
- 'app/serializers/api/enterprise_serializer.rb'
|
||||
- 'spec/features/admin/bulk_product_update_spec.rb'
|
||||
- 'spec/features/admin/enterprise_groups_spec.rb'
|
||||
- 'spec/features/admin/enterprises/index_spec.rb'
|
||||
- 'spec/features/admin/enterprises_spec.rb'
|
||||
- 'spec/features/admin/order_cycles_spec.rb'
|
||||
- 'spec/features/admin/payment_method_spec.rb'
|
||||
- 'spec/features/admin/products_spec.rb'
|
||||
- 'spec/features/admin/variant_overrides_spec.rb'
|
||||
- 'spec/features/admin/variants_spec.rb'
|
||||
- 'spec/features/consumer/shopping/checkout_spec.rb'
|
||||
- 'spec/features/consumer/shopping/shopping_spec.rb'
|
||||
- 'spec/features/consumer/shopping/variant_overrides_spec.rb'
|
||||
|
||||
# Offense count: 15
|
||||
Metrics/AbcSize:
|
||||
Max: 36
|
||||
|
||||
# Offense count: 13
|
||||
# Offense count: 109
|
||||
# Configuration parameters: CountComments, ExcludedMethods.
|
||||
Metrics/BlockLength:
|
||||
Max: 115
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/ClassLength:
|
||||
Max: 169
|
||||
|
||||
# Offense count: 1
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 8
|
||||
|
||||
# Offense count: 8
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/MethodLength:
|
||||
Max: 31
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/ModuleLength:
|
||||
Max: 208
|
||||
|
||||
# Offense count: 2
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 11
|
||||
Max: 774
|
||||
|
||||
# Offense count: 7
|
||||
Naming/AccessorMethodName:
|
||||
@@ -136,6 +122,11 @@ Naming/AccessorMethodName:
|
||||
- 'spec/support/request/shop_workflow.rb'
|
||||
- 'spec/support/request/web_helper.rb'
|
||||
|
||||
# Offense count: 1
|
||||
Naming/BinaryOperatorParameterName:
|
||||
Exclude:
|
||||
- 'app/models/exchange.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Configuration parameters: Blacklist.
|
||||
# Blacklist: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))
|
||||
@@ -176,7 +167,7 @@ Naming/PredicateName:
|
||||
- 'lib/open_food_network/packing_report.rb'
|
||||
- 'lib/tasks/data.rake'
|
||||
|
||||
# Offense count: 11
|
||||
# Offense count: 12
|
||||
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
||||
# AllowedNames: io, id, to, by, on, in, at
|
||||
Naming/UncommunicativeMethodParamName:
|
||||
@@ -184,6 +175,7 @@ Naming/UncommunicativeMethodParamName:
|
||||
- 'app/helpers/admin/injection_helper.rb'
|
||||
- 'app/helpers/spree/admin/base_helper_decorator.rb'
|
||||
- 'app/helpers/spree/base_helper_decorator.rb'
|
||||
- 'app/models/exchange.rb'
|
||||
- 'app/services/subscription_validator.rb'
|
||||
- 'lib/open_food_network/reports/bulk_coop_report.rb'
|
||||
- 'lib/open_food_network/xero_invoices_report.rb'
|
||||
@@ -304,12 +296,13 @@ Style/CaseEquality:
|
||||
- 'app/helpers/angular_form_helper.rb'
|
||||
- 'spec/models/spree/payment_spec.rb'
|
||||
|
||||
# Offense count: 78
|
||||
# Offense count: 79
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AutoCorrect, EnforcedStyle.
|
||||
# SupportedStyles: nested, compact
|
||||
Style/ClassAndModuleChildren:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/store_controller_decorator.rb'
|
||||
- 'app/helpers/angular_form_helper.rb'
|
||||
- 'app/models/calculator/flat_percent_per_item.rb'
|
||||
- 'app/models/spree/concerns/payment_method_distributors.rb'
|
||||
@@ -394,27 +387,11 @@ Style/CommentedKeyword:
|
||||
Exclude:
|
||||
- 'app/controllers/application_controller.rb'
|
||||
|
||||
# Offense count: 4
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
|
||||
# SupportedStyles: assign_to_condition, assign_inside_condition
|
||||
Style/ConditionalAssignment:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/products_controller.rb'
|
||||
- 'app/controllers/spree/api/taxons_controller.rb'
|
||||
- 'app/controllers/spree/api/variants_controller.rb'
|
||||
|
||||
# Offense count: 2
|
||||
Style/DateTime:
|
||||
Exclude:
|
||||
- 'lib/open_food_network/users_and_enterprises_report.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/EachWithObject:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/base_controller.rb'
|
||||
|
||||
# Offense count: 5
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
# SupportedStyles: annotated, template, unannotated
|
||||
@@ -424,7 +401,7 @@ Style/FormatStringToken:
|
||||
- 'lib/open_food_network/sales_tax_report.rb'
|
||||
- 'spec/models/enterprise_spec.rb'
|
||||
|
||||
# Offense count: 68
|
||||
# Offense count: 69
|
||||
# Configuration parameters: MinBodyLength.
|
||||
Style/GuardClause:
|
||||
Exclude:
|
||||
@@ -441,9 +418,7 @@ Style/GuardClause:
|
||||
- 'app/controllers/spree/admin/products_controller_decorator.rb'
|
||||
- 'app/controllers/spree/admin/resource_controller_decorator.rb'
|
||||
- 'app/controllers/spree/admin/variants_controller_decorator.rb'
|
||||
- 'app/controllers/spree/api/base_controller.rb'
|
||||
- 'app/controllers/spree/checkout_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller_decorator.rb'
|
||||
- 'app/controllers/spree/paypal_controller_decorator.rb'
|
||||
- 'app/jobs/products_cache_integrity_checker_job.rb'
|
||||
- 'app/models/enterprise.rb'
|
||||
@@ -458,6 +433,7 @@ Style/GuardClause:
|
||||
- 'app/services/order_syncer.rb'
|
||||
- 'lib/discourse/single_sign_on.rb'
|
||||
- 'lib/open_food_network/order_cycle_form_applicator.rb'
|
||||
- 'lib/open_food_network/products_cache.rb'
|
||||
- 'lib/open_food_network/products_renderer.rb'
|
||||
- 'lib/open_food_network/rack_request_blocker.rb'
|
||||
- 'lib/open_food_network/variant_and_line_item_naming.rb'
|
||||
@@ -467,23 +443,12 @@ Style/GuardClause:
|
||||
- 'spec/support/request/distribution_helper.rb'
|
||||
- 'spec/support/request/shop_workflow.rb'
|
||||
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
|
||||
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
|
||||
Style/HashSyntax:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/base_controller.rb'
|
||||
- 'app/controllers/spree/checkout_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
|
||||
# Offense count: 4
|
||||
# Offense count: 3
|
||||
Style/IfInsideElse:
|
||||
Exclude:
|
||||
- 'app/controllers/admin/column_preferences_controller.rb'
|
||||
- 'app/controllers/admin/variant_overrides_controller.rb'
|
||||
- 'app/controllers/spree/admin/products_controller_decorator.rb'
|
||||
- 'app/controllers/spree/api/taxons_controller.rb'
|
||||
|
||||
# Offense count: 1
|
||||
Style/MissingRespondToMissing:
|
||||
@@ -536,10 +501,9 @@ Style/RegexpLiteral:
|
||||
- 'spec/mailers/subscription_mailer_spec.rb'
|
||||
- 'spec/models/content_configuration_spec.rb'
|
||||
|
||||
# Offense count: 244
|
||||
# Offense count: 243
|
||||
Style/Send:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/checkout_controller.rb'
|
||||
- 'app/models/spree/shipping_method_decorator.rb'
|
||||
- 'spec/controllers/admin/subscriptions_controller_spec.rb'
|
||||
- 'spec/controllers/checkout_controller_spec.rb'
|
||||
@@ -586,9 +550,3 @@ Style/Send:
|
||||
Style/StructInheritance:
|
||||
Exclude:
|
||||
- 'lib/open_food_network/enterprise_fee_applicator.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/UnlessElse:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/variants_controller.rb'
|
||||
|
||||
60
.travis.yml
Normal file
60
.travis.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
language: ruby
|
||||
sudo: false
|
||||
cache: bundler
|
||||
bundler_args: --without development
|
||||
rvm:
|
||||
- "2.1.5"
|
||||
addons:
|
||||
postgresql: "9.5"
|
||||
|
||||
# Set the timezone for phantomjs with TZ
|
||||
# Set the timezone for karma with TIMEZONE
|
||||
env:
|
||||
global:
|
||||
- TZ="Australia/Melbourne"
|
||||
- TIMEZONE="Australia/Melbourne"
|
||||
- CI_NODE_TOTAL=5
|
||||
matrix:
|
||||
- CI_NODE_INDEX=0
|
||||
- CI_NODE_INDEX=1
|
||||
- CI_NODE_INDEX=2
|
||||
- CI_NODE_INDEX=3 RSPEC_ENGINES="true"
|
||||
- CI_NODE_INDEX=4 KARMA="true" GITHUB_DEPLOY="true"
|
||||
|
||||
before_script:
|
||||
- cp config/database.travis.yml config/database.yml
|
||||
- cp config/application.yml.example config/application.yml
|
||||
- RAILS_ENV=test bundle exec rake db:create db:schema:load
|
||||
|
||||
# Only install PhantomJS if it is not already present (ie. cached)
|
||||
- npm list -g phantomjs-prebuilt@~2.1.7 --depth=0 || npm install -g phantomjs-prebuilt@~2.1.7
|
||||
- export PATH=`npm bin -g`:$PATH
|
||||
|
||||
- >
|
||||
if [ "$KARMA" = "true" ]; then
|
||||
npm install -g npm@'3.8.8'
|
||||
npm install
|
||||
npm install -g karma-cli@0.1.2
|
||||
fi
|
||||
|
||||
script:
|
||||
- 'if [ "$KARMA" = "true" ]; then bundle exec rake karma:run; else echo "Skipping karma run"; fi'
|
||||
- 'if [ "$RSPEC_ENGINES" = "true" ]; then bundle exec rake ofn:specs:engines:rspec; else echo "Skipping RSpec run in engines"; fi'
|
||||
- "bundle exec rake 'knapsack:rspec[--format progress --tag ~performance]'"
|
||||
|
||||
after_success:
|
||||
- >
|
||||
if [ "$GITHUB_DEPLOY" = "true" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$TRAVIS_BRANCH" -a "$TRAVIS_BRANCH" != "transifex" -a -n "$GITHUB_API_SECRET" ]; then
|
||||
description="`git show "$TRAVIS_BRANCH" -s --oneline --no-color`"
|
||||
data="{
|
||||
\"ref\":\"$TRAVIS_BRANCH\",
|
||||
\"description\":\"$description\",
|
||||
\"environment\":\"staging\",
|
||||
\"required_contexts\":[]}"
|
||||
curl -u "$GITHUB_API_SECRET" -d "$data" "https://api.github.com/repos/$TRAVIS_REPO_SLUG/deployments"
|
||||
else
|
||||
echo "Not deploying on this build."
|
||||
fi
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
47
DOCKER.md
47
DOCKER.md
@@ -1,47 +0,0 @@
|
||||
### Docker
|
||||
|
||||
It is possible to setup the Open Food Network app easily with Docker and Docker Compose.
|
||||
The objective is to spare configuration time, in order to help people testing the app and contribute to it.
|
||||
It can also be used as documentation. It is not perfect but it is used in many other projects and many devs are used to it nowadays.
|
||||
|
||||
### Install Docker
|
||||
|
||||
Please check the documentation here, https://docs.docker.com/install/ to install Docker.
|
||||
|
||||
For Docker Compose, information are here: https://docs.docker.com/compose/install/.
|
||||
|
||||
Better to have at least 2GB free on your computer in order to download images and create containers for Open Food Network app.
|
||||
|
||||
|
||||
### Use Docker with Open Food Network
|
||||
|
||||
Open a terminal with a shell.
|
||||
|
||||
Clone the repository:
|
||||
|
||||
```sh
|
||||
$ git clone git@github.com:openfoodfoundation/openfoodnetwork.git
|
||||
```
|
||||
|
||||
Go at the root of the app:
|
||||
|
||||
```sh
|
||||
$ cd openfoodnetwork
|
||||
```
|
||||
|
||||
Download the Docker images and build the containers:
|
||||
|
||||
```sh
|
||||
$ docker-compose build
|
||||
```
|
||||
|
||||
Run the app with all the required containers:
|
||||
|
||||
```sh
|
||||
$ docker-compose up
|
||||
```
|
||||
|
||||
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.
|
||||
31
Dockerfile
31
Dockerfile
@@ -1,31 +0,0 @@
|
||||
FROM ubuntu:18.04
|
||||
|
||||
# Install all the requirements
|
||||
RUN apt-get update && apt-get install -y curl git build-essential software-properties-common wget zlib1g-dev libssl1.0-dev libreadline-dev libyaml-dev libffi-dev libxml2-dev libxslt1-dev wait-for-it
|
||||
|
||||
# Setup ENV variables
|
||||
ENV PATH /usr/local/src/rbenv/shims:/usr/local/src/rbenv/bin:$PATH
|
||||
ENV RBENV_ROOT /usr/local/src/rbenv
|
||||
ENV RUBY_VERSION 2.1.5
|
||||
ENV CONFIGURE_OPTS --disable-install-doc
|
||||
|
||||
# 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 && \
|
||||
echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh && \
|
||||
rbenv install $RUBY_VERSION && \
|
||||
rbenv global $RUBY_VERSION && \
|
||||
gem install bundler --version=1.17.2
|
||||
|
||||
# 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
|
||||
|
||||
ENV BUNDLE_PATH /bundles
|
||||
|
||||
COPY . /usr/src/app/
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
18
Gemfile
18
Gemfile
@@ -3,12 +3,11 @@ ruby "2.1.5"
|
||||
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
|
||||
|
||||
gem 'i18n', '~> 0.6.11'
|
||||
gem 'i18n-js', '~> 3.3.0'
|
||||
gem 'i18n-js', '~> 3.2.2'
|
||||
gem 'rails', '~> 3.2.22'
|
||||
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'
|
||||
|
||||
@@ -20,10 +19,9 @@ gem 'pg'
|
||||
# OFN-maintained and patched version of Spree v2.0.4. See
|
||||
# https://github.com/openfoodfoundation/openfoodnetwork/wiki/Spree-2.0-upgrade
|
||||
# for details.
|
||||
gem 'spree_api', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
|
||||
gem 'spree_backend', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
|
||||
gem 'spree_core', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
|
||||
gem 'spree', github: 'openfoodfoundation/spree', branch: '2-0-4-stable'
|
||||
|
||||
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '2-0-stable'
|
||||
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
|
||||
|
||||
# Our branch contains two changes
|
||||
@@ -36,8 +34,6 @@ gem 'stripe'
|
||||
# which is needed for Pin Payments (and possibly others).
|
||||
gem 'activemerchant', '~> 1.78'
|
||||
|
||||
gem 'devise', '~> 2.2.5'
|
||||
gem 'devise-encryptable', '0.2.0'
|
||||
gem 'jwt', '~> 2.2'
|
||||
gem 'oauth2', '~> 1.4.1' # Used for Stripe Connect
|
||||
|
||||
@@ -49,10 +45,6 @@ gem 'delayed_job_web'
|
||||
# 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'
|
||||
|
||||
gem 'andand'
|
||||
gem 'angularjs-rails', '1.5.5'
|
||||
gem 'aws-sdk'
|
||||
@@ -123,10 +115,6 @@ gem 'jquery-rails', '3.0.4'
|
||||
|
||||
gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz', ref: '60da2ae4c44cbb4c8d602f59fb5fff8d0f21db3c'
|
||||
|
||||
group :production, :staging do
|
||||
gem 'ddtrace'
|
||||
end
|
||||
|
||||
group :test, :development do
|
||||
# Pretty printed test output
|
||||
gem 'atomic'
|
||||
|
||||
94
Gemfile.lock
94
Gemfile.lock
@@ -31,9 +31,16 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: https://github.com/openfoodfoundation/spree.git
|
||||
revision: 8a8585a43cd04d1a50dc65227f337a91b18d66d5
|
||||
revision: 46d6f8f5fd434105b0c69958276d1727a3066a97
|
||||
branch: 2-0-4-stable
|
||||
specs:
|
||||
spree (2.0.4)
|
||||
spree_api (= 2.0.4)
|
||||
spree_backend (= 2.0.4)
|
||||
spree_cmd (= 2.0.4)
|
||||
spree_core (= 2.0.4)
|
||||
spree_frontend (= 2.0.4)
|
||||
spree_sample (= 2.0.4)
|
||||
spree_api (2.0.4)
|
||||
rabl (= 0.8.4)
|
||||
spree_core (= 2.0.4)
|
||||
@@ -46,6 +53,8 @@ GIT
|
||||
select2-rails (~> 3.4.7)
|
||||
spree_api (= 2.0.4)
|
||||
spree_core (= 2.0.4)
|
||||
spree_cmd (2.0.4)
|
||||
thor (>= 0.14.6)
|
||||
spree_core (2.0.4)
|
||||
activemerchant (~> 1.34)
|
||||
acts_as_list (= 0.2.0)
|
||||
@@ -66,6 +75,28 @@ GIT
|
||||
state_machine (= 1.2.0)
|
||||
stringex (~> 1.5.1)
|
||||
truncate_html (= 0.9.2)
|
||||
spree_frontend (2.0.4)
|
||||
canonical-rails
|
||||
deface (>= 0.9.0)
|
||||
jquery-rails (~> 3.0.0)
|
||||
rails (~> 3.2.13)
|
||||
spree_api (= 2.0.4)
|
||||
spree_core (= 2.0.4)
|
||||
stringex (~> 1.5.1)
|
||||
spree_sample (2.0.4)
|
||||
spree_core (= 2.0.4)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/spree/spree_auth_devise.git
|
||||
revision: 0181835fb6ac77a05191d26f6f32a0f4a548d851
|
||||
branch: 2-0-stable
|
||||
specs:
|
||||
spree_auth_devise (2.0.0)
|
||||
devise (~> 2.2.5)
|
||||
devise-encryptable (= 0.1.2)
|
||||
spree_backend (~> 2.0.0)
|
||||
spree_core (~> 2.0.0)
|
||||
spree_frontend (~> 2.0.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/spree/spree_i18n.git
|
||||
@@ -129,8 +160,6 @@ GEM
|
||||
activesupport (= 3.2.22.5)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activerecord-import (1.0.2)
|
||||
activerecord (>= 3.2)
|
||||
activeresource (3.2.22.5)
|
||||
activemodel (= 3.2.22.5)
|
||||
activesupport (= 3.2.22.5)
|
||||
@@ -141,8 +170,8 @@ GEM
|
||||
activerecord (>= 3.2, < 5)
|
||||
acts_as_list (0.2.0)
|
||||
activerecord (>= 3.0)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
addressable (2.6.0)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
andand (1.3.3)
|
||||
angular-rails-templates (0.3.0)
|
||||
railties (>= 3.1)
|
||||
@@ -160,15 +189,17 @@ GEM
|
||||
json (~> 1.4)
|
||||
nokogiri (>= 1.4.4)
|
||||
uuidtools (~> 2.1)
|
||||
bcrypt (3.1.13)
|
||||
bcrypt (3.1.11)
|
||||
bcrypt-ruby (3.1.5)
|
||||
bcrypt (>= 3.1.3)
|
||||
blockenspiel (0.5.0)
|
||||
bugsnag (6.12.0)
|
||||
bugsnag (6.11.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
builder (3.0.4)
|
||||
byebug (9.0.6)
|
||||
cancan (1.6.10)
|
||||
canonical-rails (0.1.0)
|
||||
rails (>= 3.1, < 5.1)
|
||||
capybara (2.18.0)
|
||||
addressable
|
||||
mini_mime (>= 0.1.3)
|
||||
@@ -210,7 +241,7 @@ GEM
|
||||
compass (~> 1.0.0)
|
||||
sass-rails (< 5.1)
|
||||
sprockets (< 4.0)
|
||||
concurrent-ruby (1.1.5)
|
||||
concurrent-ruby (1.1.4)
|
||||
connection_pool (2.2.2)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
@@ -223,18 +254,16 @@ GEM
|
||||
activerecord (>= 3.2.0, < 5.0)
|
||||
fog (~> 1.0)
|
||||
rails (>= 3.2.0, < 5.0)
|
||||
ddtrace (0.26.0)
|
||||
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)
|
||||
activerecord (>= 3.0, < 6.1)
|
||||
delayed_job (4.1.5)
|
||||
activesupport (>= 3.0, < 5.3)
|
||||
delayed_job_active_record (4.1.3)
|
||||
activerecord (>= 3.0, < 5.3)
|
||||
delayed_job (>= 3.0, < 5)
|
||||
delayed_job_web (1.4.3)
|
||||
activerecord (> 3.0.0)
|
||||
@@ -246,11 +275,11 @@ GEM
|
||||
orm_adapter (~> 0.1)
|
||||
railties (~> 3.1)
|
||||
warden (~> 1.2.1)
|
||||
devise-encryptable (0.2.0)
|
||||
devise-encryptable (0.1.2)
|
||||
devise (>= 2.1.0)
|
||||
diff-lcs (1.3)
|
||||
diffy (3.3.0)
|
||||
docile (1.3.2)
|
||||
docile (1.3.1)
|
||||
dry-inflector (0.1.2)
|
||||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
@@ -456,14 +485,14 @@ GEM
|
||||
rspec (>= 2.99.0, < 4.0)
|
||||
haml (4.0.7)
|
||||
tilt
|
||||
hashdiff (1.0.0)
|
||||
hashdiff (0.4.0)
|
||||
highline (1.6.18)
|
||||
hike (1.2.3)
|
||||
http_parser.rb (0.6.0)
|
||||
httparty (0.16.2)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.6.11)
|
||||
i18n-js (3.3.0)
|
||||
i18n-js (3.2.2)
|
||||
i18n (>= 0.6.6)
|
||||
immigrant (0.3.6)
|
||||
activerecord (>= 3.0)
|
||||
@@ -485,7 +514,7 @@ GEM
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
kgio (2.11.2)
|
||||
knapsack (1.18.0)
|
||||
knapsack (1.17.1)
|
||||
rake
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
@@ -507,12 +536,11 @@ GEM
|
||||
railties (>= 3.1)
|
||||
money (5.1.1)
|
||||
i18n (~> 0.6.0)
|
||||
msgpack (1.3.1)
|
||||
multi_json (1.13.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
nenv (0.3.0)
|
||||
net-http-persistent (3.1.0)
|
||||
net-http-persistent (3.0.1)
|
||||
connection_pool (~> 2.2)
|
||||
newrelic_rpm (3.18.1.330)
|
||||
nokogiri (1.6.8.1)
|
||||
@@ -558,7 +586,7 @@ GEM
|
||||
pry-byebug (3.4.3)
|
||||
byebug (>= 9.0, < 9.1)
|
||||
pry (~> 0.10)
|
||||
public_suffix (3.1.1)
|
||||
public_suffix (3.0.3)
|
||||
rabl (0.8.4)
|
||||
activesupport (>= 2.3.14)
|
||||
rack (1.4.7)
|
||||
@@ -594,7 +622,7 @@ GEM
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.19.0)
|
||||
rake (12.3.3)
|
||||
rake (12.3.2)
|
||||
ransack (0.7.2)
|
||||
actionpack (~> 3.0)
|
||||
activerecord (~> 3.0)
|
||||
@@ -609,7 +637,7 @@ GEM
|
||||
trollop (~> 2.1)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
redcarpet (3.5.0)
|
||||
redcarpet (3.4.0)
|
||||
ref (2.0.0)
|
||||
request_store (1.4.1)
|
||||
rack (>= 1.4)
|
||||
@@ -676,7 +704,7 @@ GEM
|
||||
shellany (0.0.1)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
simplecov (0.17.0)
|
||||
simplecov (0.16.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
@@ -701,7 +729,7 @@ GEM
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.5.1)
|
||||
stripe (4.24.0)
|
||||
stripe (4.18.1)
|
||||
faraday (~> 0.13)
|
||||
net-http-persistent (~> 3.0)
|
||||
therubyracer (0.12.0)
|
||||
@@ -739,7 +767,7 @@ GEM
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (~> 1.0)
|
||||
selenium-webdriver (~> 3.0)
|
||||
webmock (3.7.1)
|
||||
webmock (3.6.0)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
@@ -757,7 +785,6 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
active_model_serializers (= 0.8.4)
|
||||
activemerchant (~> 1.78)
|
||||
activerecord-import
|
||||
acts-as-taggable-on (~> 3.4)
|
||||
andand
|
||||
angular-rails-templates (~> 0.3.0)
|
||||
@@ -778,13 +805,10 @@ DEPENDENCIES
|
||||
dalli
|
||||
database_cleaner (= 0.7.1)
|
||||
db2fog
|
||||
ddtrace
|
||||
debugger-linecache
|
||||
deface (= 1.0.2)
|
||||
delayed_job_active_record
|
||||
delayed_job_web
|
||||
devise (~> 2.2.5)
|
||||
devise-encryptable (= 0.2.0)
|
||||
diffy
|
||||
eventmachine (>= 1.2.3)
|
||||
factory_bot_rails
|
||||
@@ -802,13 +826,12 @@ DEPENDENCIES
|
||||
guard-rspec (~> 4.7.3)
|
||||
haml
|
||||
i18n (~> 0.6.11)
|
||||
i18n-js (~> 3.3.0)
|
||||
i18n-js (~> 3.2.2)
|
||||
immigrant
|
||||
jquery-migrate-rails
|
||||
jquery-rails (= 3.0.4)
|
||||
json_spec (~> 1.1.4)
|
||||
jwt (~> 2.2)
|
||||
kaminari (~> 0.14.1)
|
||||
knapsack
|
||||
letter_opener (>= 1.4.1)
|
||||
listen (= 3.0.8)
|
||||
@@ -845,9 +868,8 @@ DEPENDENCIES
|
||||
simplecov
|
||||
skylight (< 2.0)
|
||||
spinjs-rails
|
||||
spree_api!
|
||||
spree_backend!
|
||||
spree_core!
|
||||
spree!
|
||||
spree_auth_devise!
|
||||
spree_i18n!
|
||||
spree_paypal_express!
|
||||
spring (= 1.7.2)
|
||||
|
||||
@@ -27,13 +27,10 @@ If you're interested in provisioning a server, see [ofn-install][ofn-install] fo
|
||||
|
||||
We also have a [Super Admin Guide][super-admin-guide] to help with configuration of new servers.
|
||||
|
||||
## Testing
|
||||
|
||||
We use [BrowserStack](https://www.browserstack.com/) as a manual testing tool. BrowserStack provides open source projects with unlimited and free of charge accounts. A big thanks to them!
|
||||
|
||||
## Licence
|
||||
|
||||
Copyright (c) 2012 - 2019 Open Food Foundation, released under the AGPL licence.
|
||||
Copyright (c) 2012 - 2018 Open Food Foundation, released under the AGPL licence.
|
||||
|
||||
[survey]: https://docs.google.com/a/eaterprises.com.au/forms/d/1zxR5vSiU9CigJ9cEaC8-eJLgYid8CR8er7PPH9Mc-30/edit#
|
||||
[slack-invite]: https://openfoodnetwork.org/slack-invite
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 127 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="18" viewBox="0 0 20 18">
|
||||
<path fill="#FFF" fill-opacity=".5" fill-rule="nonzero" d="M18.338 10.593l1.64-7.312a.841.841 0 0 0-.812-1.031H5.528L5.21.675A.836.836 0 0 0 4.393 0H.833A.839.839 0 0 0 0 .844v.562c0 .466.373.844.833.844H3.26l2.439 12.074c-.584.34-.977.977-.977 1.707 0 1.088.87 1.969 1.945 1.969 1.074 0 1.944-.881 1.944-1.969 0-.55-.224-1.049-.584-1.406h7.28c-.36.357-.585.855-.585 1.406 0 1.088.87 1.969 1.945 1.969 1.074 0 1.944-.881 1.944-1.969 0-.78-.447-1.453-1.096-1.772l.191-.853a.841.841 0 0 0-.812-1.031h-9.32l-.228-1.125h10.179c.389 0 .726-.273.813-.657z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 648 B |
@@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path d="M0 0h16v16H0z"/>
|
||||
<path fill="#F4704C" d="M13.85 5.928h-1.234v-1.54c0-2.338-2.026-4.234-4.525-4.234-2.5 0-4.526 1.896-4.526 4.235v1.54H2.33c-.682 0-1.235.516-1.235 1.154v7.7c0 .637.553 1.154 1.235 1.154h11.52c.681 0 1.234-.517 1.234-1.154v-7.7c0-.638-.553-1.155-1.234-1.155zM4.8 4.388c0-1.7 1.473-3.08 3.29-3.08 1.818 0 3.292 1.38 3.292 3.08v1.54H4.799v-1.54z"/>
|
||||
<path fill="#FFF" d="M8.296 13.23c1.243 0 2.25-.942 2.25-2.105 0-1.162-1.007-2.105-2.25-2.105-1.242 0-2.25.943-2.25 2.105.003 1.162 1.009 2.103 2.25 2.106zm0-3.211c.654 0 1.183.495 1.183 1.106 0 .612-.53 1.107-1.183 1.107s-1.183-.495-1.183-1.107c0-.61.53-1.106 1.183-1.106z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 812 B |
@@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<path id="a" d="M15 15.2a.79.79 0 0 1-.778.8H1.778A.79.79 0 0 1 1 15.2v-2.4c0-2.21 1.741-4 3.889-4h6.222c2.148 0 3.889 1.79 3.889 4v2.4zM8 8C5.852 8 4.111 6.21 4.111 4S5.852 0 8 0c2.148 0 3.889 1.79 3.889 4S10.148 8 8 8z"/>
|
||||
</defs>
|
||||
<use fill="#F4704C" fill-rule="nonzero" xlink:href="#a"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 451 B |
@@ -15,6 +15,7 @@
|
||||
//= require angular-animate
|
||||
//= require angular-sanitize
|
||||
//= require admin/spree_backend
|
||||
//= require admin/spree_auth
|
||||
//= require admin/spree_paypal_express
|
||||
//= require ../shared/ng-infinite-scroll.min.js
|
||||
//= require ../shared/ng-tags-input.min.js
|
||||
|
||||
@@ -1,287 +1,267 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories, RequestMonitor) ->
|
||||
$scope.StatusMessage = StatusMessage
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, $window, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories) ->
|
||||
$scope.loading = true
|
||||
$scope.loadingAllPages = true
|
||||
|
||||
$scope.columns = Columns.columns
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
$scope.columns = Columns.columns
|
||||
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.pagination = BulkProducts.pagination
|
||||
$scope.per_page_options = [
|
||||
{id: 15, name: t('js.admin.orders.index.per_page', results: 15)},
|
||||
{id: 50, name: t('js.admin.orders.index.per_page', results: 50)},
|
||||
{id: 100, name: t('js.admin.orders.index.per_page', results: 100)}
|
||||
]
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
|
||||
$scope.filterableColumns = [
|
||||
{ name: t("label_producers"), db_column: "producer_name" },
|
||||
{ name: t("name"), db_column: "name" }
|
||||
]
|
||||
$scope.filterableColumns = [
|
||||
{ name: t("label_producers"), db_column: "producer_name" },
|
||||
{ name: t("name"), db_column: "name" }
|
||||
]
|
||||
|
||||
$scope.filterTypes = [
|
||||
{ name: t("equals"), predicate: "eq" },
|
||||
{ name: t("contains"), predicate: "cont" }
|
||||
]
|
||||
$scope.filterTypes = [
|
||||
{ name: t("equals"), predicate: "eq" },
|
||||
{ name: t("contains"), predicate: "cont" }
|
||||
]
|
||||
|
||||
$scope.optionTabs =
|
||||
filters: { title: t("filter_products"), visible: false }
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.all
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.producerFilter = ""
|
||||
$scope.categoryFilter = ""
|
||||
$scope.importDateFilter = ""
|
||||
$scope.page = 1
|
||||
$scope.per_page = 15
|
||||
$scope.products = BulkProducts.products
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
$scope.initialise = ->
|
||||
SpreeApiAuth.authorise()
|
||||
.then ->
|
||||
$scope.spree_api_key_ok = true
|
||||
$scope.fetchProducts()
|
||||
.catch (message) ->
|
||||
$scope.api_error_msg = message
|
||||
|
||||
$scope.$watchCollection '[query, producerFilter, categoryFilter, importDateFilter, per_page]', ->
|
||||
$scope.page = 1 # Reset page when changing filters for new search
|
||||
|
||||
$scope.changePage = (newPage) ->
|
||||
$scope.page = newPage
|
||||
$scope.fetchProducts()
|
||||
|
||||
$scope.fetchProducts = ->
|
||||
removeClearedValues()
|
||||
params = {
|
||||
'q[name_cont]': $scope.query,
|
||||
'q[supplier_id_eq]': $scope.producerFilter,
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter,
|
||||
import_date: $scope.importDateFilter,
|
||||
page: $scope.page,
|
||||
per_page: $scope.per_page
|
||||
}
|
||||
RequestMonitor.load(BulkProducts.fetch(params).$promise).then ->
|
||||
$scope.resetProducts()
|
||||
|
||||
removeClearedValues = ->
|
||||
delete $scope.producerFilter if $scope.producerFilter == "0"
|
||||
delete $scope.categoryFilter if $scope.categoryFilter == "0"
|
||||
delete $scope.importDateFilter if $scope.importDateFilter == "0"
|
||||
|
||||
$timeout ->
|
||||
if $scope.showLatestImport
|
||||
$scope.importDateFilter = $scope.importDates[1].id
|
||||
|
||||
$scope.resetProducts = ->
|
||||
DirtyProducts.clear()
|
||||
StatusMessage.clear()
|
||||
|
||||
$scope.updateOnHand = (product) ->
|
||||
on_demand_variants = []
|
||||
if product.variants
|
||||
on_demand_variants = (variant for id, variant of product.variants when variant.on_demand)
|
||||
|
||||
unless product.on_demand || on_demand_variants.length > 0
|
||||
product.on_hand = $scope.onHand(product)
|
||||
$scope.optionTabs =
|
||||
filters: { title: t("filter_products"), visible: false }
|
||||
|
||||
|
||||
$scope.onHand = (product) ->
|
||||
onHand = 0
|
||||
if product.hasOwnProperty("variants") and product.variants instanceof Object
|
||||
for id, variant of product.variants
|
||||
onHand = onHand + parseInt(if variant.on_hand > 0 then variant.on_hand else 0)
|
||||
else
|
||||
onHand = "error"
|
||||
onHand
|
||||
|
||||
$scope.shiftTab = (tab) ->
|
||||
$scope.visibleTab.visible = false unless $scope.visibleTab == tab || $scope.visibleTab == undefined
|
||||
tab.visible = !tab.visible
|
||||
$scope.visibleTab = tab
|
||||
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.query = ""
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.all
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.filterProducers = [{id: "0", name: ""}].concat $scope.producers
|
||||
$scope.filterTaxons = [{id: "0", name: ""}].concat $scope.taxons
|
||||
$scope.producerFilter = "0"
|
||||
$scope.categoryFilter = "0"
|
||||
$scope.importDateFilter = "0"
|
||||
$scope.products = BulkProducts.products
|
||||
$scope.filteredProducts = []
|
||||
$scope.currentFilters = []
|
||||
$scope.limit = 15
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
$scope.editWarn = (product, variant) ->
|
||||
if (DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
|
||||
window.location = "/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
$scope.initialise = ->
|
||||
SpreeApiAuth.authorise()
|
||||
.then ->
|
||||
$scope.spree_api_key_ok = true
|
||||
$scope.fetchProducts()
|
||||
.catch (message) ->
|
||||
$scope.api_error_msg = message
|
||||
|
||||
$scope.$watchCollection '[query, producerFilter, categoryFilter, importDateFilter]', ->
|
||||
$scope.limit = 15 # Reset limit whenever searching
|
||||
|
||||
$scope.toggleShowAllVariants = ->
|
||||
showVariants = !DisplayProperties.showVariants 0
|
||||
$scope.products.forEach (product) ->
|
||||
DisplayProperties.setShowVariants product.id, showVariants
|
||||
DisplayProperties.setShowVariants 0, showVariants
|
||||
$scope.fetchProducts = ->
|
||||
$scope.loading = true
|
||||
$scope.loadingAllPages = true
|
||||
BulkProducts.fetch($scope.currentFilters, ->
|
||||
$scope.loadingAllPages = false
|
||||
).then ->
|
||||
$scope.resetProducts()
|
||||
$scope.loading = false
|
||||
|
||||
$scope.addVariant = (product) ->
|
||||
product.variants.push
|
||||
id: $scope.nextVariantId()
|
||||
unit_value: null
|
||||
unit_description: null
|
||||
on_demand: false
|
||||
display_as: null
|
||||
display_name: null
|
||||
on_hand: null
|
||||
price: null
|
||||
DisplayProperties.setShowVariants product.id, true
|
||||
$timeout ->
|
||||
if $scope.showLatestImport
|
||||
$scope.importDateFilter = $scope.importDates[1].id
|
||||
|
||||
|
||||
$scope.nextVariantId = ->
|
||||
$scope.variantIdCounter = 0 unless $scope.variantIdCounter?
|
||||
$scope.variantIdCounter -= 1
|
||||
$scope.variantIdCounter
|
||||
|
||||
$scope.deleteProduct = (product) ->
|
||||
if confirm("Are you sure?")
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.products.splice $scope.products.indexOf(product), 1
|
||||
DirtyProducts.deleteProduct product.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
|
||||
$scope.deleteVariant = (product, variant) ->
|
||||
if product.variants.length > 1
|
||||
if !$scope.variantSaved(variant)
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
if confirm(t("are_you_sure"))
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
alert(t("delete_product_variant"))
|
||||
|
||||
$scope.removeVariant = (product, variant) ->
|
||||
product.variants.splice product.variants.indexOf(variant), 1
|
||||
DirtyProducts.deleteVariant product.id, variant.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
|
||||
$scope.cloneProduct = (product) ->
|
||||
BulkProducts.cloneProduct product
|
||||
|
||||
$scope.hasVariants = (product) ->
|
||||
product.variants.length > 0
|
||||
|
||||
|
||||
$scope.hasUnit = (product) ->
|
||||
product.variant_unit_with_scale?
|
||||
|
||||
|
||||
$scope.variantSaved = (variant) ->
|
||||
variant.hasOwnProperty('id') && variant.id > 0
|
||||
|
||||
|
||||
$scope.hasOnDemandVariants = (product) ->
|
||||
(variant for id, variant of product.variants when variant.on_demand).length > 0
|
||||
|
||||
|
||||
$scope.submitProducts = ->
|
||||
# Pack pack $scope.products, so they will match the list returned from the server,
|
||||
# then pack $scope.dirtyProducts, ensuring that the correct product info is sent to the server.
|
||||
$scope.packProduct product for id, product of $scope.products
|
||||
$scope.packProduct product for id, product of DirtyProducts.all()
|
||||
|
||||
productsToSubmit = filterSubmitProducts(DirtyProducts.all())
|
||||
if productsToSubmit.length > 0
|
||||
$scope.updateProducts productsToSubmit # Don't submit an empty list
|
||||
else
|
||||
StatusMessage.display 'alert', t("products_change")
|
||||
|
||||
|
||||
$scope.updateProducts = (productsToSubmit) ->
|
||||
$scope.displayUpdating()
|
||||
$http(
|
||||
method: "POST"
|
||||
url: "/admin/products/bulk_update"
|
||||
data:
|
||||
products: productsToSubmit
|
||||
filters:
|
||||
'q[name_cont]': $scope.query
|
||||
'q[supplier_id_eq]': $scope.producerFilter
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter
|
||||
import_date: $scope.importDateFilter
|
||||
page: $scope.page
|
||||
per_page: $scope.per_page
|
||||
).success((data) ->
|
||||
$scope.resetProducts = ->
|
||||
DirtyProducts.clear()
|
||||
BulkProducts.updateVariantLists(data.products || [])
|
||||
$timeout -> $scope.displaySuccess()
|
||||
).error (data, status) ->
|
||||
if status == 400 && data.errors? && data.errors.length > 0
|
||||
errors = error + "\n" for error in data.errors
|
||||
alert t("products_update_error") + "\n" + errors
|
||||
$scope.displayFailure t("products_update_error")
|
||||
StatusMessage.clear()
|
||||
|
||||
$scope.updateOnHand = (product) ->
|
||||
on_demand_variants = []
|
||||
if product.variants
|
||||
on_demand_variants = (variant for id, variant of product.variants when variant.on_demand)
|
||||
|
||||
unless product.on_demand || on_demand_variants.length > 0
|
||||
product.on_hand = $scope.onHand(product)
|
||||
|
||||
|
||||
$scope.onHand = (product) ->
|
||||
onHand = 0
|
||||
if product.hasOwnProperty("variants") and product.variants instanceof Object
|
||||
for id, variant of product.variants
|
||||
onHand = onHand + parseInt(if variant.on_hand > 0 then variant.on_hand else 0)
|
||||
else
|
||||
$scope.displayFailure t("products_update_error_data") + status
|
||||
onHand = "error"
|
||||
onHand
|
||||
|
||||
$scope.cancel = (destination) ->
|
||||
$window.location = destination
|
||||
$scope.shiftTab = (tab) ->
|
||||
$scope.visibleTab.visible = false unless $scope.visibleTab == tab || $scope.visibleTab == undefined
|
||||
tab.visible = !tab.visible
|
||||
$scope.visibleTab = tab
|
||||
|
||||
$scope.packProduct = (product) ->
|
||||
if product.variant_unit_with_scale
|
||||
match = product.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/)
|
||||
if match
|
||||
product.variant_unit = match[1]
|
||||
product.variant_unit_scale = parseFloat(match[2])
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.query = ""
|
||||
$scope.producerFilter = "0"
|
||||
$scope.categoryFilter = "0"
|
||||
$scope.importDateFilter = "0"
|
||||
|
||||
$scope.editWarn = (product, variant) ->
|
||||
if (DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
|
||||
window.location = "/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
|
||||
|
||||
$scope.toggleShowAllVariants = ->
|
||||
showVariants = !DisplayProperties.showVariants 0
|
||||
$scope.filteredProducts.forEach (product) ->
|
||||
DisplayProperties.setShowVariants product.id, showVariants
|
||||
DisplayProperties.setShowVariants 0, showVariants
|
||||
|
||||
$scope.addVariant = (product) ->
|
||||
product.variants.push
|
||||
id: $scope.nextVariantId()
|
||||
unit_value: null
|
||||
unit_description: null
|
||||
on_demand: false
|
||||
display_as: null
|
||||
display_name: null
|
||||
on_hand: null
|
||||
price: null
|
||||
DisplayProperties.setShowVariants product.id, true
|
||||
|
||||
|
||||
$scope.nextVariantId = ->
|
||||
$scope.variantIdCounter = 0 unless $scope.variantIdCounter?
|
||||
$scope.variantIdCounter -= 1
|
||||
$scope.variantIdCounter
|
||||
|
||||
$scope.deleteProduct = (product) ->
|
||||
if confirm("Are you sure?")
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.products.splice $scope.products.indexOf(product), 1
|
||||
DirtyProducts.deleteProduct product.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
|
||||
$scope.deleteVariant = (product, variant) ->
|
||||
if product.variants.length > 1
|
||||
if !$scope.variantSaved(variant)
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
if confirm(t("are_you_sure"))
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
product.variant_unit = product.variant_unit_with_scale
|
||||
product.variant_unit_scale = null
|
||||
else
|
||||
product.variant_unit = product.variant_unit_scale = null
|
||||
alert(t("delete_product_variant"))
|
||||
|
||||
$scope.packVariant product, product.master if product.master
|
||||
|
||||
if product.variants
|
||||
for id, variant of product.variants
|
||||
$scope.packVariant product, variant
|
||||
$scope.removeVariant = (product, variant) ->
|
||||
product.variants.splice product.variants.indexOf(variant), 1
|
||||
DirtyProducts.deleteVariant product.id, variant.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
|
||||
$scope.packVariant = (product, variant) ->
|
||||
if variant.hasOwnProperty("unit_value_with_description")
|
||||
match = variant.unit_value_with_description.match(/^([\d\.]+(?= |$)|)( |)(.*)$/)
|
||||
if match
|
||||
product = BulkProducts.find product.id
|
||||
variant.unit_value = parseFloat(match[1])
|
||||
variant.unit_value = null if isNaN(variant.unit_value)
|
||||
variant.unit_value *= product.variant_unit_scale if variant.unit_value && product.variant_unit_scale
|
||||
variant.unit_description = match[3]
|
||||
$scope.cloneProduct = (product) ->
|
||||
BulkProducts.cloneProduct product
|
||||
|
||||
$scope.incrementLimit = ->
|
||||
if $scope.limit < $scope.products.length
|
||||
$scope.limit = $scope.limit + 5
|
||||
$scope.hasVariants = (product) ->
|
||||
product.variants.length > 0
|
||||
|
||||
|
||||
$scope.displayUpdating = ->
|
||||
StatusMessage.display 'progress', t("saving")
|
||||
$scope.hasUnit = (product) ->
|
||||
product.variant_unit_with_scale?
|
||||
|
||||
|
||||
$scope.displaySuccess = ->
|
||||
StatusMessage.display 'success',t("products_changes_saved")
|
||||
$scope.bulk_product_form.$setPristine()
|
||||
$scope.variantSaved = (variant) ->
|
||||
variant.hasOwnProperty('id') && variant.id > 0
|
||||
|
||||
|
||||
$scope.displayFailure = (failMessage) ->
|
||||
StatusMessage.display 'failure', t("products_update_error_msg") + "#{failMessage}"
|
||||
$scope.hasOnDemandVariants = (product) ->
|
||||
(variant for id, variant of product.variants when variant.on_demand).length > 0
|
||||
|
||||
|
||||
$scope.displayDirtyProducts = ->
|
||||
count = DirtyProducts.count()
|
||||
switch count
|
||||
when 0 then StatusMessage.clear()
|
||||
when 1 then StatusMessage.display 'notice', t("one_product_unsaved")
|
||||
else StatusMessage.display 'notice', t("products_unsaved", n: count)
|
||||
$scope.submitProducts = ->
|
||||
# Pack pack $scope.products, so they will match the list returned from the server,
|
||||
# then pack $scope.dirtyProducts, ensuring that the correct product info is sent to the server.
|
||||
$scope.packProduct product for id, product of $scope.products
|
||||
$scope.packProduct product for id, product of DirtyProducts.all()
|
||||
|
||||
productsToSubmit = filterSubmitProducts(DirtyProducts.all())
|
||||
if productsToSubmit.length > 0
|
||||
$scope.updateProducts productsToSubmit # Don't submit an empty list
|
||||
else
|
||||
StatusMessage.display 'alert', t("products_change")
|
||||
|
||||
|
||||
$scope.updateProducts = (productsToSubmit) ->
|
||||
$scope.displayUpdating()
|
||||
$http(
|
||||
method: "POST"
|
||||
url: "/admin/products/bulk_update"
|
||||
data:
|
||||
products: productsToSubmit
|
||||
filters: $scope.currentFilters
|
||||
).success((data) ->
|
||||
DirtyProducts.clear()
|
||||
BulkProducts.updateVariantLists(data.products || [])
|
||||
$timeout -> $scope.displaySuccess()
|
||||
).error (data, status) ->
|
||||
if status == 400 && data.errors? && data.errors.length > 0
|
||||
errors = error + "\n" for error in data.errors
|
||||
alert t("products_update_error") + "\n" + errors
|
||||
$scope.displayFailure t("products_update_error")
|
||||
else
|
||||
$scope.displayFailure t("products_update_error_data") + status
|
||||
|
||||
$scope.cancel = (destination) ->
|
||||
$window.location = destination
|
||||
|
||||
$scope.packProduct = (product) ->
|
||||
if product.variant_unit_with_scale
|
||||
match = product.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/)
|
||||
if match
|
||||
product.variant_unit = match[1]
|
||||
product.variant_unit_scale = parseFloat(match[2])
|
||||
else
|
||||
product.variant_unit = product.variant_unit_with_scale
|
||||
product.variant_unit_scale = null
|
||||
else
|
||||
product.variant_unit = product.variant_unit_scale = null
|
||||
|
||||
$scope.packVariant product, product.master if product.master
|
||||
|
||||
if product.variants
|
||||
for id, variant of product.variants
|
||||
$scope.packVariant product, variant
|
||||
|
||||
|
||||
$scope.packVariant = (product, variant) ->
|
||||
if variant.hasOwnProperty("unit_value_with_description")
|
||||
match = variant.unit_value_with_description.match(/^([\d\.]+(?= |$)|)( |)(.*)$/)
|
||||
if match
|
||||
product = BulkProducts.find product.id
|
||||
variant.unit_value = parseFloat(match[1])
|
||||
variant.unit_value = null if isNaN(variant.unit_value)
|
||||
variant.unit_value *= product.variant_unit_scale if variant.unit_value && product.variant_unit_scale
|
||||
variant.unit_description = match[3]
|
||||
|
||||
$scope.incrementLimit = ->
|
||||
if $scope.limit < $scope.products.length
|
||||
$scope.limit = $scope.limit + 5
|
||||
|
||||
|
||||
$scope.displayUpdating = ->
|
||||
StatusMessage.display 'progress', t("saving")
|
||||
|
||||
|
||||
$scope.displaySuccess = ->
|
||||
StatusMessage.display 'success',t("products_changes_saved")
|
||||
$scope.bulk_product_form.$setPristine()
|
||||
|
||||
|
||||
$scope.displayFailure = (failMessage) ->
|
||||
StatusMessage.display 'failure', t("products_update_error_msg") + "#{failMessage}"
|
||||
|
||||
|
||||
$scope.displayDirtyProducts = ->
|
||||
count = DirtyProducts.count()
|
||||
switch count
|
||||
when 0 then StatusMessage.clear()
|
||||
when 1 then StatusMessage.display 'notice', t("one_product_unsaved")
|
||||
else StatusMessage.display 'notice', t("products_unsaved", n: count)
|
||||
|
||||
|
||||
filterSubmitProducts = (productsToFilter) ->
|
||||
|
||||
@@ -5,7 +5,7 @@ angular.module('admin.orderCycles')
|
||||
$scope.distributor_enterprises = Enterprise.hub_enterprises
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
$scope.schedules = Schedules.index({enterprise_id: ocInstance.coordinator_id})
|
||||
$scope.schedules = Schedules.index()
|
||||
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.order_cycle = OrderCycle.new({ coordinator_id: ocInstance.coordinator_id})
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
angular.module('admin.orderCycles')
|
||||
.controller 'AdminEditOrderCycleCtrl', ($scope, $filter, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
|
||||
.controller 'AdminEditOrderCycleCtrl', ($scope, $filter, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor) ->
|
||||
order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: order_cycle_id)
|
||||
$scope.supplier_enterprises = Enterprise.producer_enterprises
|
||||
$scope.distributor_enterprises = Enterprise.hub_enterprises
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: order_cycle_id)
|
||||
$scope.schedules = Schedules.index({enterprise_id: ocInstance.coordinator_id})
|
||||
$scope.schedules = Schedules.index()
|
||||
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.order_cycle = OrderCycle.load(order_cycle_id)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
|
||||
$scope.StatusMessage = StatusMessage
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.schedules = Schedules.index({enterprise_id: ocInstance.coordinator_id})
|
||||
$scope.schedules = Schedules.index()
|
||||
$scope.order_cycle = OrderCycle.new {coordinator_id: ocInstance.coordinator_id}, =>
|
||||
# TODO: make this a get method, which only fetches one enterprise
|
||||
$scope.enterprises = Enterprise.index {coordinator_id: ocInstance.coordinator_id}, (enterprises) =>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, $window, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, StatusMessage, ocInstance) ->
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, $window, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, StatusMessage) ->
|
||||
$scope.orderCycleId = ->
|
||||
$location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
|
||||
$scope.StatusMessage = StatusMessage
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.schedules = Schedules.index({enterprise_id: ocInstance.coordinator_id})
|
||||
$scope.schedules = Schedules.index()
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) =>
|
||||
$scope.init()
|
||||
|
||||
@@ -24,3 +24,8 @@ angular.module("admin.orders").controller "orderCtrl", ($scope, shops, orderCycl
|
||||
|
||||
for shop in $scope.shops
|
||||
shop.disabled = !$scope.distributorHasOrderCycles(shop)
|
||||
|
||||
# Removes the split button introduced by spree in the order form
|
||||
# We only have one stock location in OFN so it's meaningless to split the order between stock locations
|
||||
# We delete it instead of hiding or changing CSS so that, when spree code toggles the element, nothing hapens
|
||||
$('.split-item').remove()
|
||||
|
||||
@@ -23,7 +23,7 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
|
||||
|
||||
$scope.fetchResults = (page=1) ->
|
||||
$scope.resetSelected()
|
||||
params = {
|
||||
Orders.index({
|
||||
'q[completed_at_lt]': $scope['q']['completed_at_lt'],
|
||||
'q[completed_at_gt]': $scope['q']['completed_at_gt'],
|
||||
'q[state_eq]': $scope['q']['state_eq'],
|
||||
@@ -39,8 +39,7 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
|
||||
'q[s]': $scope.sorting || 'completed_at desc',
|
||||
per_page: $scope.per_page,
|
||||
page: page
|
||||
}
|
||||
RequestMonitor.load(Orders.index(params).$promise)
|
||||
})
|
||||
|
||||
$scope.resetSelected = ->
|
||||
$scope.selected_orders.length = 0
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
angular.module("admin.products").directive "setOnDemand", ->
|
||||
link: (scope, element, attr) ->
|
||||
onHand = element.context.querySelector("#variant_on_hand")
|
||||
onDemand = element.context.querySelector("#variant_on_demand")
|
||||
|
||||
disableOnHandIfOnDemand = ->
|
||||
if onDemand.checked
|
||||
onHand.disabled = 'disabled'
|
||||
onHand.dataStock = onHand.value
|
||||
onHand.value = t('admin.products.variants.infinity')
|
||||
|
||||
disableOnHandIfOnDemand()
|
||||
|
||||
onDemand.addEventListener 'change', (event) ->
|
||||
disableOnHandIfOnDemand()
|
||||
|
||||
if !onDemand.checked
|
||||
onHand.removeAttribute('disabled')
|
||||
onHand.value = onHand.dataStock
|
||||
@@ -1,6 +0,0 @@
|
||||
angular.module("admin.resources").factory 'ProductResource', ($resource) ->
|
||||
$resource('/admin/product/:id/:action.json', {}, {
|
||||
'index':
|
||||
url: '/api/products/bulk_products.json'
|
||||
method: 'GET'
|
||||
})
|
||||
@@ -3,8 +3,6 @@ angular.module("admin.resources").factory 'ScheduleResource', ($resource) ->
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
params:
|
||||
enterprise_id: '@enterprise_id'
|
||||
'create':
|
||||
method: 'POST'
|
||||
'update':
|
||||
|
||||
@@ -40,7 +40,7 @@ angular.module("admin.resources").factory "Schedules", ($q, $injector, RequestMo
|
||||
delete @byID[schedule.id]
|
||||
StatusMessage.display 'success', "#{t('js.admin.order_cycles.schedules.deleted_schedule')}: '#{schedule.name}'"
|
||||
|
||||
index: (params) ->
|
||||
request = ScheduleResource.index params, (data) => @load(data)
|
||||
index: ->
|
||||
request = ScheduleResource.index (data) => @load(data)
|
||||
RequestMonitor.load(request.$promise)
|
||||
request
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
angular.module("ofn.admin").factory "BulkProducts", (ProductResource, dataFetcher, $http) ->
|
||||
angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher, $http) ->
|
||||
new class BulkProducts
|
||||
products: []
|
||||
pagination: {}
|
||||
|
||||
fetch: (params) ->
|
||||
ProductResource.index params, (data) =>
|
||||
@products.length = 0
|
||||
@addProducts data.products
|
||||
angular.extend(@pagination, data.pagination)
|
||||
fetch: (filters, onComplete) ->
|
||||
queryString = filters.reduce (qs,f) ->
|
||||
return qs + "q[#{f.property.db_column}_#{f.predicate.predicate}]=#{f.value};"
|
||||
, ""
|
||||
|
||||
url = "/api/products/bulk_products?page=::page::;per_page=20;#{queryString}"
|
||||
processData = (data) => @addProducts data.products
|
||||
PagedFetcher.fetch url, processData, onComplete
|
||||
|
||||
cloneProduct: (product) ->
|
||||
$http.post("/api/products/" + product.id + "/clone").success (data) =>
|
||||
|
||||
@@ -5,7 +5,7 @@ angular.module("admin.subscriptions").controller "OrderUpdateIssuesController",
|
||||
OrderCycles.byID[id].name
|
||||
|
||||
$scope.orderCycleCloses = (id) ->
|
||||
closes_at = moment(OrderCycles.byID[id].orders_close_at, "YYYY-MM-DD HH:mm:SS Z")
|
||||
closes_at = moment(OrderCycles.byID[id].orders_close_at)
|
||||
key = if closes_at > moment() then "closes" else "closed"
|
||||
text = t("js.subscriptions." + key)
|
||||
"#{text} #{closes_at.fromNow()}"
|
||||
|
||||
@@ -15,7 +15,7 @@ angular.module("admin.subscriptions").controller "OrdersPanelController", ($scop
|
||||
$scope.orderCycleCloses = (id) ->
|
||||
oc = OrderCycles.byID[id]
|
||||
return t('js.subscriptions.close_date_not_set') unless oc?.orders_close_at?
|
||||
closes_at = moment(oc.orders_close_at, "YYYY-MM-DD HH:mm:SS Z")
|
||||
closes_at = moment(oc.orders_close_at)
|
||||
text = if closes_at > moment() then t('js.subscriptions.closes') else t('js.subscriptions.closed')
|
||||
"#{text} #{closes_at.fromNow()}"
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ angular.module("admin.subscriptions").controller "ProductsPanelController", ($sc
|
||||
|
||||
$scope.save = ->
|
||||
$scope.saving = true
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
StatusMessage.display 'progress', 'Saving...'
|
||||
$scope.subscription.update().then (response) ->
|
||||
$scope.saving = false
|
||||
StatusMessage.display 'success', t('js.changes_saved')
|
||||
StatusMessage.display 'success', 'Saved'
|
||||
, (response) ->
|
||||
$scope.saving = false
|
||||
if response.data?.errors?
|
||||
keys = Object.keys(response.data.errors)
|
||||
StatusMessage.display 'failure', response.data.errors[keys[0]][0]
|
||||
else
|
||||
StatusMessage.display 'success', t('js.changes_saved')
|
||||
StatusMessage.display 'success', 'Saved'
|
||||
|
||||
@@ -4,8 +4,8 @@ angular.module("admin.tagRules").directive "tagRule", ->
|
||||
link: (scope, element, attrs) ->
|
||||
scope.opt =
|
||||
"TagRule::FilterShippingMethods":
|
||||
textTop: t('js.admin.tag_rules.shipping_method_tagged_top')
|
||||
textBottom: t('js.admin.tag_rules.shipping_method_tagged_bottom')
|
||||
textTop: "Shipping methods tagged"
|
||||
textBottom: "are:"
|
||||
taggable: "shipping_method"
|
||||
tagsAttr: "shipping_method_tags"
|
||||
tagListAttr: "preferred_shipping_method_tags"
|
||||
@@ -13,8 +13,8 @@ angular.module("admin.tagRules").directive "tagRule", ->
|
||||
tagListFor: (rule) ->
|
||||
rule.preferred_shipping_method_tags
|
||||
"TagRule::FilterPaymentMethods":
|
||||
textTop: t('js.admin.tag_rules.payment_method_tagged_top')
|
||||
textBottom: t('js.admin.tag_rules.payment_method_tagged_bottom')
|
||||
textTop: "Payment methods tagged"
|
||||
textBottom: "are:"
|
||||
taggable: "payment_method"
|
||||
tagsAttr: "payment_method_tags"
|
||||
tagListAttr: "preferred_payment_method_tags"
|
||||
@@ -22,8 +22,8 @@ angular.module("admin.tagRules").directive "tagRule", ->
|
||||
tagListFor: (rule) ->
|
||||
rule.preferred_payment_method_tags
|
||||
"TagRule::FilterOrderCycles":
|
||||
textTop: t('js.admin.tag_rules.order_cycle_tagged_top')
|
||||
textBottom: t('js.admin.tag_rules.order_cycle_tagged_bottom')
|
||||
textTop: "Order Cycles tagged"
|
||||
textBottom: "are:"
|
||||
taggable: "exchange"
|
||||
tagsAttr: "exchange_tags"
|
||||
tagListAttr: "preferred_exchange_tags"
|
||||
@@ -31,8 +31,8 @@ angular.module("admin.tagRules").directive "tagRule", ->
|
||||
tagListFor: (rule) ->
|
||||
rule.preferred_exchange_tags
|
||||
"TagRule::FilterProducts":
|
||||
textTop: t('js.admin.tag_rules.inventory_tagged_top')
|
||||
textBottom: t('js.admin.tag_rules.inventory_tagged_bottom')
|
||||
textTop: "Inventory variants tagged"
|
||||
textBottom: "are:"
|
||||
taggable: "variant"
|
||||
tagsAttr: "variant_tags"
|
||||
tagListAttr: "preferred_variant_tags"
|
||||
|
||||
@@ -27,6 +27,8 @@ angular.module("admin.utils").directive "variantAutocomplete", ($timeout) ->
|
||||
window.variants = data # this is how spree auto complete JS code picks up variants
|
||||
results: data
|
||||
formatResult: (variant) ->
|
||||
if variant["images"][0] != undefined && variant["images"][0].image != undefined
|
||||
variant.image = variant.images[0].image.mini_url
|
||||
variantTemplate variant: variant
|
||||
formatSelection: (variant) ->
|
||||
element.parent().children(".options_placeholder").html variant.options_text
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Darkswarm.controller "GroupEnterpriseNodeCtrl", ($scope, CurrentHub) ->
|
||||
|
||||
$scope.active = false
|
||||
|
||||
$scope.toggle = ->
|
||||
$scope.active = !$scope.active
|
||||
|
||||
$scope.open = ->
|
||||
$scope.active
|
||||
|
||||
$scope.current = ->
|
||||
$scope.hub.id is CurrentHub.hub.id
|
||||
@@ -1,6 +1,22 @@
|
||||
Darkswarm.controller "GroupPageCtrl", ($scope, enterprises, Enterprises, MapConfiguration, OfnMap) ->
|
||||
Darkswarm.controller "GroupPageCtrl", ($scope, group_enterprises, Enterprises, MapConfiguration, OfnMap, visibleFilter, Navigation) ->
|
||||
$scope.Enterprises = Enterprises
|
||||
|
||||
all_enterprises_by_id = Enterprises.enterprises_by_id
|
||||
|
||||
dereferenced_enterprises = group_enterprises.map (enterprise) =>
|
||||
all_enterprises_by_id[enterprise.id]
|
||||
|
||||
visible_enterprises = visibleFilter dereferenced_enterprises
|
||||
|
||||
# TODO: this is duplicate code with app/assets/javascripts/darkswarm/services/enterprises.js.coffee
|
||||
# It would be better to load only the needed enterprises (group + related shops).
|
||||
$scope.group_producers = visible_enterprises.filter (enterprise) ->
|
||||
enterprise.category in ["producer_hub", "producer_shop", "producer"]
|
||||
$scope.group_hubs = visible_enterprises.filter (enterprise) ->
|
||||
enterprise.category in ["hub", "hub_profile", "producer_hub", "producer_shop"]
|
||||
|
||||
$scope.producers_to_filter = $scope.group_producers
|
||||
|
||||
$scope.map = angular.copy MapConfiguration.options
|
||||
$scope.mapMarkers = OfnMap.enterprise_markers enterprises
|
||||
$scope.embedded_layout = window.location.search.indexOf("embedded_shopfront=true") != -1
|
||||
$scope.mapMarkers = OfnMap.enterprise_markers visible_enterprises
|
||||
$scope.embedded_layout = window.location.search.indexOf("embedded_shopfront=true") != -1
|
||||
@@ -1,44 +1,9 @@
|
||||
Darkswarm.controller "HubNodeCtrl", ($scope, HashNavigation, CurrentHub, $http, $timeout) ->
|
||||
$scope.shopfront_loading = false
|
||||
$scope.enterprise_details = []
|
||||
Darkswarm.controller "HubNodeCtrl", ($scope, HashNavigation, Navigation, $location, $templateCache, CurrentHub) ->
|
||||
$scope.toggle = (e) ->
|
||||
HashNavigation.toggle $scope.hub.hash if !angular.element(e.target).inheritedData('is-link')
|
||||
|
||||
$timeout ->
|
||||
if $scope.open()
|
||||
$scope.load_shopfront()
|
||||
|
||||
# Toggles shopfront tabs open/closed. Fetches enterprise details from the api, diplays them and adds them
|
||||
# to $scope.enterprise_details, or simply displays the details again if previously fetched
|
||||
$scope.toggle = (event) ->
|
||||
if $scope.open()
|
||||
$scope.toggle_tab(event)
|
||||
return
|
||||
|
||||
if $scope.enterprise_details[$scope.hub.id]
|
||||
$scope.hub = $scope.enterprise_details[$scope.hub.id]
|
||||
$scope.toggle_tab(event)
|
||||
return
|
||||
|
||||
$scope.load_shopfront(event)
|
||||
|
||||
$scope.load_shopfront = (event=null) ->
|
||||
$scope.shopfront_loading = true
|
||||
$scope.toggle_tab(event)
|
||||
|
||||
$http.get("/api/enterprises/" + $scope.hub.id + "/shopfront")
|
||||
.success (data) ->
|
||||
$scope.shopfront_loading = false
|
||||
$scope.hub = data
|
||||
$scope.enterprise_details[$scope.hub.id] = $scope.hub
|
||||
.error (data) ->
|
||||
console.error(data)
|
||||
|
||||
$scope.toggle_tab = (event) ->
|
||||
HashNavigation.toggle $scope.hub.hash if event && !angular.element(event.target).inheritedData('is-link')
|
||||
|
||||
# Returns boolean: pulldown tab is currently open/closed
|
||||
$scope.open = ->
|
||||
HashNavigation.active $scope.hub.hash
|
||||
|
||||
# Returns boolean: is this hub the hub that the user is currently "shopping" in?
|
||||
|
||||
$scope.current = ->
|
||||
$scope.hub.id is CurrentHub.hub.id
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
Darkswarm.controller "OffcanvasCtrl", ($scope) ->
|
||||
$scope.menu = $(".left-off-canvas-menu")
|
||||
|
||||
$scope.setOffcanvasMenuHeight = ->
|
||||
$scope.menu.height($(window).height())
|
||||
|
||||
$scope.bind = ->
|
||||
$(window).on("resize", $scope.setOffcanvasMenuHeight)
|
||||
$scope.setOffcanvasMenuHeight()
|
||||
|
||||
$scope.bind()
|
||||
@@ -1,39 +1,6 @@
|
||||
Darkswarm.controller "ProducerNodeCtrl", ($scope, HashNavigation, $anchorScroll, $http, $timeout) ->
|
||||
$scope.shopfront_loading = false
|
||||
$scope.enterprise_details = []
|
||||
|
||||
$timeout ->
|
||||
if $scope.open()
|
||||
$scope.load_shopfront()
|
||||
|
||||
# Toggles shopfront tabs open/closed. Fetches enterprise details from the api, diplays them and adds them
|
||||
# to $scope.enterprise_details, or simply displays the details again if previously fetched
|
||||
$scope.toggle = (event) ->
|
||||
if $scope.open()
|
||||
$scope.toggle_tab(event)
|
||||
return
|
||||
|
||||
if $scope.enterprise_details[$scope.producer.id]
|
||||
$scope.producer = $scope.enterprise_details[$scope.producer.id]
|
||||
$scope.toggle_tab(event)
|
||||
return
|
||||
|
||||
$scope.load_shopfront(event)
|
||||
|
||||
$scope.load_shopfront = (event=null) ->
|
||||
$scope.shopfront_loading = true
|
||||
$scope.toggle_tab(event)
|
||||
|
||||
$http.get("/api/enterprises/" + $scope.producer.id + "/shopfront")
|
||||
.success (data) ->
|
||||
$scope.shopfront_loading = false
|
||||
$scope.producer = data
|
||||
$scope.enterprise_details[$scope.producer.id] = $scope.producer
|
||||
.error (data) ->
|
||||
console.error(data)
|
||||
|
||||
$scope.toggle_tab = (event) ->
|
||||
HashNavigation.toggle $scope.producer.hash if event && !angular.element(event.target).inheritedData('is-link')
|
||||
Darkswarm.controller "ProducerNodeCtrl", ($scope, HashNavigation, $anchorScroll) ->
|
||||
$scope.toggle = ->
|
||||
HashNavigation.toggle $scope.producer.hash
|
||||
|
||||
$scope.open = ->
|
||||
HashNavigation.active($scope.producer.hash)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Darkswarm.controller "AboutUsCtrl", ($scope, Shopfront) ->
|
||||
$scope.shopfront = Shopfront.shopfront
|
||||
Darkswarm.controller "AboutUsCtrl", ($scope, CurrentHub) ->
|
||||
$scope.CurrentHub = CurrentHub
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
Darkswarm.controller "ProducersTabCtrl", ($scope, Shopfront, EnterpriseModal) ->
|
||||
$scope.shopfront = Shopfront.shopfront
|
||||
Darkswarm.controller "ProducersTabCtrl", ($scope, CurrentHub, Enterprises, EnterpriseModal) ->
|
||||
# Injecting Enterprises so CurrentHub.producers is dereferenced.
|
||||
# We should probably dereference here instead and separate out CurrentHub dereferencing from the Enterprise factory.
|
||||
$scope.CurrentHub = CurrentHub
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Darkswarm.directive "cart", ->
|
||||
# Toggles visibility of the "cart" popover
|
||||
restrict: 'A'
|
||||
link: (scope, elem, attr)->
|
||||
scope.open = false
|
||||
elem.bind 'click', ->
|
||||
scope.$apply ->
|
||||
scope.open = !scope.open
|
||||
@@ -1,19 +0,0 @@
|
||||
Darkswarm.directive "cartToggle", ($document) ->
|
||||
# Toggles visibility of the "cart" popover
|
||||
restrict: 'A'
|
||||
link: (scope, elem, attr)->
|
||||
scope.open = false
|
||||
|
||||
$document.bind 'click', (event) ->
|
||||
cart_button = elem[0]
|
||||
element_and_parents = [event.target, event.target.parentElement, event.target.parentElement.parentElement]
|
||||
cart_button_clicked = (element_and_parents.indexOf(cart_button) != -1)
|
||||
|
||||
if cart_button_clicked
|
||||
scope.$apply ->
|
||||
scope.open = !scope.open
|
||||
else
|
||||
scope.$apply ->
|
||||
scope.open = false
|
||||
|
||||
return
|
||||
@@ -1,10 +1,15 @@
|
||||
Darkswarm.directive "enterpriseModal", (EnterpriseModal) ->
|
||||
Darkswarm.directive "enterpriseModal", ($modal, Enterprises, EnterpriseResource) ->
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
template: "<a ng-transclude></a>"
|
||||
transclude: true
|
||||
link: (scope, elem, attrs, ctrl) ->
|
||||
elem.on "click", (event) =>
|
||||
event.stopPropagation()
|
||||
|
||||
scope.modalInstance = EnterpriseModal.open scope.enterprise
|
||||
elem.on "click", (ev) =>
|
||||
ev.stopPropagation()
|
||||
params =
|
||||
id: scope.enterprise.id
|
||||
EnterpriseResource.relatives params, (data) =>
|
||||
Enterprises.addEnterprises data
|
||||
scope.enterprise = Enterprises.enterprises_by_id[scope.enterprise.id]
|
||||
Enterprises.dereferenceEnterprise scope.enterprise
|
||||
scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'enterprise_modal.html', scope: scope)
|
||||
|
||||
@@ -13,16 +13,11 @@ Darkswarm.directive "ofnOnHand", ->
|
||||
ngModel.$setDirty = setDirty
|
||||
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
available_quantity = scope.available_quantity()
|
||||
if parseInt(viewValue) > available_quantity
|
||||
alert t("js.insufficient_stock", {on_hand: available_quantity})
|
||||
viewValue = available_quantity
|
||||
on_hand = parseInt(attr.ofnOnHand)
|
||||
if parseInt(viewValue) > on_hand
|
||||
alert t("js.insufficient_stock", {on_hand: on_hand})
|
||||
viewValue = on_hand
|
||||
ngModel.$setViewValue viewValue
|
||||
ngModel.$render()
|
||||
|
||||
viewValue
|
||||
|
||||
scope.available_quantity = ->
|
||||
on_hand = parseInt(attr.ofnOnHand)
|
||||
finalized_quantity = parseInt(attr.finalizedquantity) || 0 # finalizedquantity is optional
|
||||
on_hand + finalized_quantity
|
||||
|
||||
@@ -2,14 +2,7 @@ Darkswarm.directive "ofnPageAlert", ($timeout) ->
|
||||
restrict: 'A'
|
||||
scope: true
|
||||
link: (scope, elem, attrs) ->
|
||||
moveSelectors = [".off-canvas-wrap .inner-wrap",
|
||||
".off-canvas-wrap .inner-wrap .fixed",
|
||||
".off-canvas-fixed .top-bar",
|
||||
".off-canvas-fixed ofn-flash",
|
||||
".off-canvas-fixed nav.tab-bar",
|
||||
".off-canvas-fixed .page-alert"]
|
||||
|
||||
container_elems = $(moveSelectors.join(", "))
|
||||
container_elems = $(".off-canvas-wrap .inner-wrap, .off-canvas-wrap .inner-wrap .fixed, .page-alert")
|
||||
|
||||
# Wait a moment after page load before showing the alert. Otherwise we often miss the
|
||||
# start of the animation.
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
@API_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:SS Z"
|
||||
|
||||
Darkswarm.filter "date_in_words", ->
|
||||
(date, dateFormat) ->
|
||||
dateFormat ?= @API_DATETIME_FORMAT
|
||||
moment(date, dateFormat).fromNow()
|
||||
(date) ->
|
||||
moment(date).fromNow()
|
||||
|
||||
Darkswarm.filter "sensible_timeframe", (date_in_wordsFilter)->
|
||||
(date, dateFormat) ->
|
||||
dateFormat ?= @API_DATETIME_FORMAT
|
||||
|
||||
if moment().add(2, 'days') < moment(date, dateFormat)
|
||||
(date) ->
|
||||
if moment().add(2, 'days') < moment(date)
|
||||
t 'orders_open'
|
||||
else
|
||||
t('closing') + date_in_wordsFilter(date)
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, Matcher, Geo, $rootScope) ->
|
||||
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope) ->
|
||||
new class Enterprises
|
||||
enterprises_by_id: {}
|
||||
|
||||
constructor: ->
|
||||
# Populate Enterprises.enterprises from json in page.
|
||||
@enterprises = enterprises
|
||||
|
||||
# Map enterprises to id/object pairs for lookup.
|
||||
for enterprise in enterprises
|
||||
@enterprises_by_id[enterprise.id] = enterprise
|
||||
|
||||
# Replace enterprise and taxons ids with actual objects.
|
||||
@dereferenceEnterprises()
|
||||
|
||||
@producers = @enterprises.filter (enterprise)->
|
||||
@visible_enterprises = visibleFilter @enterprises
|
||||
@producers = @visible_enterprises.filter (enterprise)->
|
||||
enterprise.category in ["producer_hub", "producer_shop", "producer"]
|
||||
@hubs = @enterprises.filter (enterprise)->
|
||||
@hubs = @visible_enterprises.filter (enterprise)->
|
||||
enterprise.category in ["hub", "hub_profile", "producer_hub", "producer_shop"]
|
||||
|
||||
dereferenceEnterprises: ->
|
||||
@@ -25,6 +22,8 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer,
|
||||
@dereferenceEnterprise enterprise
|
||||
|
||||
dereferenceEnterprise: (enterprise) ->
|
||||
@dereferenceProperty(enterprise, 'hubs', @enterprises_by_id)
|
||||
@dereferenceProperty(enterprise, 'producers', @enterprises_by_id)
|
||||
@dereferenceProperty(enterprise, 'taxons', Taxons.taxons_by_id)
|
||||
@dereferenceProperty(enterprise, 'supplied_taxons', Taxons.taxons_by_id)
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
Darkswarm.factory 'Groups', (groups) ->
|
||||
Darkswarm.factory 'Groups', (groups, Enterprises, Dereferencer) ->
|
||||
new class Groups
|
||||
groups: groups
|
||||
groups_by_id: {}
|
||||
constructor: ->
|
||||
for group in @groups
|
||||
@groups_by_id[group.id] = group
|
||||
@dereference()
|
||||
dereference: ->
|
||||
for group in @groups
|
||||
Dereferencer.dereference group.enterprises, Enterprises.enterprises_by_id
|
||||
for enterprise in Enterprises.enterprises
|
||||
Dereferencer.dereference enterprise.groups, @groups_by_id
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal) ->
|
||||
Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, visibleFilter) ->
|
||||
new class OfnMap
|
||||
constructor: ->
|
||||
@enterprises = @enterprise_markers(Enterprises.enterprises)
|
||||
@@ -6,7 +6,7 @@ Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal) ->
|
||||
enterprise.latitude != null || enterprise.longitude != null # Remove enterprises w/o lat or long
|
||||
|
||||
enterprise_markers: (enterprises) ->
|
||||
@extend(enterprise) for enterprise in enterprises
|
||||
@extend(enterprise) for enterprise in visibleFilter(enterprises)
|
||||
|
||||
# Adding methods to each enterprise
|
||||
extend: (enterprise) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory 'Products', ($resource, Shopfront, Dereferencer, Taxons, Properties, Cart, Variants) ->
|
||||
Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Properties, Cart, Variants) ->
|
||||
new class Products
|
||||
constructor: ->
|
||||
@update()
|
||||
@@ -31,7 +31,7 @@ Darkswarm.factory 'Products', ($resource, Shopfront, Dereferencer, Taxons, Prope
|
||||
|
||||
dereference: ->
|
||||
for product in @products
|
||||
product.supplier = Shopfront.producers_by_id[product.supplier.id]
|
||||
product.supplier = Enterprises.enterprises_by_id[product.supplier.id]
|
||||
Dereferencer.dereference product.taxons, Taxons.taxons_by_id
|
||||
|
||||
product.properties = angular.copy(product.properties_with_values)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
Darkswarm.factory 'Shopfront', (shopfront) ->
|
||||
new class Shopfront
|
||||
shopfront: shopfront
|
||||
producers_by_id: {}
|
||||
|
||||
constructor: ->
|
||||
for producer in shopfront.producers
|
||||
@producers_by_id[producer.id] = producer
|
||||
@@ -1,6 +1,6 @@
|
||||
#new-subscription-dialog
|
||||
.text-normal.margin-bottom-30.text-center
|
||||
= t('js.admin.subscriptions.new.please_select_a_shop')
|
||||
= t('admin.subscriptions.index.please_select_a_shop')
|
||||
|
||||
%form{ name: 'new_subscription_form', novalidate: true, ng: { submit: "newSubscription()" }}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
%input.ofn-select2.fullwidth#new_subscription_shop_id{ ng: { model: 'shop_id' }, required: true, name: 'shop_id', data: 'shops' }
|
||||
%div{ ng: { show: "submitted && new_subscription_form.$pristine" } }
|
||||
.error{ ng: { show: "new_subscription_form.shop_id.$error.required" } }
|
||||
= t('js.admin.subscriptions.new.please_select_a_shop')
|
||||
= t('admin.subscriptions.index.please_select_a_shop')
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'submit', value: t('continue') }
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
%input.ofn-select2.fullwidth{ :id => 'rule_type_selector', ng: { model: "ruleType" }, data: "ruleTypes", 'min-search' => "5" }
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'button', value: "{{ 'js.admin.new_tag_rule_dialog.add_rule' | t }}", ng: { click: 'addRule(tagGroup, ruleType)' } }
|
||||
%input.button.red.icon-plus{ type: 'button', value: "Add Rule", ng: { click: 'addRule(tagGroup, ruleType)' } }
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
-# Do not show this for producer shops selling only their own produce,
|
||||
-# Since a shopping link will already have been displayed in hub_details.html.haml
|
||||
.row.active_table_row.pad-top{ "ng-if" => "enterprise.is_primary_producer && enterprise.hubs.length > 0 && !(enterprise.hubs.length == 1 && enterprise.hubs[0] == enterprise)"}
|
||||
.columns.small-12.cta-container
|
||||
.columns.small-12
|
||||
.row
|
||||
.columns.small-12.fat
|
||||
%div{"ng-if" => "::enterprise.name"}
|
||||
%label{"ng-bind-html" => "::'shop_for_products_html' | t:{enterprise: enterprise.name}"}
|
||||
%label{"ng-html" => "::'shop_for_products_html' | t:{enterprise: enterprise.name}"}
|
||||
%div.show-for-medium-up{"ng-if" => "::!enterprise.name"}
|
||||
|
||||
.row
|
||||
.row.cta-container
|
||||
.columns.small-12
|
||||
%a.cta-hub{"ng-repeat" => "hub in enterprise.hubs | filter:{id: '!'+enterprise.id} | orderBy:'-active'",
|
||||
"ng-href" => "{{::hub.path}}", "ofn-empties-cart" => "hub",
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
*
|
||||
|
||||
*= require admin/spree_backend
|
||||
*= require admin/spree_auth
|
||||
|
||||
*= require jquery-ui-timepicker-addon
|
||||
*= require shared/textAngular
|
||||
*= require shared/ng-tags-input.min
|
||||
*= require admin/custom
|
||||
|
||||
*= require_self
|
||||
*/
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/* Custom fix */
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dl dd { width: 25%; }
|
||||
@@ -1,11 +0,0 @@
|
||||
.add-line-item {
|
||||
fieldset {
|
||||
.vertical-align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding-top: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
.select2-container {
|
||||
.select2-choice {
|
||||
.select2-search-choice-close {
|
||||
display: none !important;
|
||||
display: none;
|
||||
}
|
||||
.select2-arrow {
|
||||
width: 22px;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
@import 'foundation-icons';
|
||||
|
||||
@import 'base/*';
|
||||
@import 'layout/*';
|
||||
@import '*';
|
||||
@import 'pages/*';
|
||||
@import '../web/all';
|
||||
|
||||
@@ -35,6 +35,5 @@ $med-grey: #666;
|
||||
$med-drk-grey: #444;
|
||||
$dark-grey: #333;
|
||||
$light-grey: #ddd;
|
||||
$light-grey-transparency: rgba(0, 0, 0, .1);
|
||||
$black: #000;
|
||||
$white: #fff;
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// A bit arbitrary, works for it's use at time of implementation
|
||||
$collapsible-max-height: 350px;
|
||||
|
||||
.collapsible-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapsible-label > ::before {
|
||||
border-bottom: 5px solid transparent;
|
||||
border-left: 5px solid currentColor;
|
||||
border-top: 5px solid transparent;
|
||||
|
||||
content: ' ';
|
||||
display: inline-block;
|
||||
|
||||
margin-right: .7rem;
|
||||
transform: translateY(-2px);
|
||||
transition: transform .2s ease-out;
|
||||
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.collapsible-content {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
|
||||
transition: max-height .25s ease-in-out;
|
||||
}
|
||||
|
||||
.collapsible-checkbox:checked + .collapsible-label + .collapsible-content {
|
||||
max-height: $collapsible-max-height;
|
||||
}
|
||||
|
||||
.collapsible-checkbox:checked + .collapsible-label > ::before {
|
||||
transform: rotate(90deg) translateX(-3px);
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
// This double class is used to so this rule is more specific than the one in
|
||||
// all.scss
|
||||
.collapsible-label.collapsible-label-md {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.collapsible-label-md > ::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapsible-content-md {
|
||||
max-height: $collapsible-max-height;
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ body.embedded {
|
||||
vertical-align: top;
|
||||
|
||||
&.cart {
|
||||
|
||||
div.joyride-tip-guide { // Cart Dropdown
|
||||
top: 75px;
|
||||
overflow: visible;
|
||||
|
||||
31
app/assets/stylesheets/darkswarm/header.css.scss
Normal file
31
app/assets/stylesheets/darkswarm/header.css.scss
Normal file
@@ -0,0 +1,31 @@
|
||||
@import "variables";
|
||||
|
||||
nav.top-bar {
|
||||
margin-bottom: 0px;
|
||||
|
||||
a.icon {
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
height: $topbar-height;
|
||||
color: white;
|
||||
|
||||
i {
|
||||
font-size: 29px;
|
||||
line-height: $topbar-height;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
display: inline-block;
|
||||
line-height: $topbar-height;
|
||||
height: $topbar-height;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body > section[role='main'] {
|
||||
padding: 0px;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
@import "compass/css3/transition";
|
||||
|
||||
.off-canvas-fixed {
|
||||
@include transition(transform 1000ms ease-in-out);
|
||||
}
|
||||
|
||||
.move-right > .off-canvas-fixed {
|
||||
height: 100%;
|
||||
-webkit-transform: translate3d(15.625rem, 0, 0);
|
||||
transform: translate3d(15.625rem, 0, 0);
|
||||
}
|
||||
|
||||
.left-off-canvas-menu {
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
margin-left: -15.625rem;
|
||||
}
|
||||
@@ -1,213 +1,103 @@
|
||||
@import 'compass';
|
||||
@import 'branding';
|
||||
@import 'mixins';
|
||||
@import 'typography';
|
||||
@import 'variables';
|
||||
@import "compass";
|
||||
@import "branding";
|
||||
@import "mixins";
|
||||
@import "typography";
|
||||
@import "variables";
|
||||
|
||||
nav.top-bar {
|
||||
nav {
|
||||
@include textpress;
|
||||
text-shadow: none;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
margin-bottom: 0;
|
||||
height: $topbar-height;
|
||||
}
|
||||
|
||||
@media #{$large-only} {
|
||||
.top-bar--menu-item-with-icon span {
|
||||
text-shadow: none;
|
||||
|
||||
// Create center style for nav ul (foundation provides left and right)
|
||||
text-align: center;
|
||||
|
||||
.top-bar-section {
|
||||
// Avoid menu items blocking logo
|
||||
li:not(.has-form), li:not(.has-form) a:not(.button), li:not(.has-form) a:not(.button):hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
ul.center {
|
||||
display: inline-block;
|
||||
|
||||
// By default, we center between the left and right uls, but we want to be centered
|
||||
// relative to the whole page. The difference in width between the other uls is 74px,
|
||||
// so we offset by that amount here.
|
||||
margin-left: -74px;
|
||||
}
|
||||
}
|
||||
|
||||
.joyride-tip-guide .button {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
// Default overrides - big menu
|
||||
.top-bar-section .has-dropdown > a {
|
||||
padding-right: ($topbar-height / 3) !important;
|
||||
|
||||
i.ofn-i_022-cog, .ofn-i_071-globe {
|
||||
font-size: 24px;
|
||||
line-height: $topbar-height;
|
||||
}
|
||||
|
||||
i.ofn-i_071-globe {
|
||||
color: #666;
|
||||
font-size: 27px
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar-section .has-dropdown > a:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.top-bar--current-hub-prefix,
|
||||
.top-bar--current-hub-name {
|
||||
display: inline-block;
|
||||
.top-bar-section ul li > a {
|
||||
font-size: 0.75rem;
|
||||
height: $topbar-height;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@include transition(all 0.3s ease-in-out);
|
||||
}
|
||||
|
||||
.top-bar-section ul li.ofn-logo > a {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.top-bar--current-hub-name {
|
||||
max-width: 10em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.nav-branded {
|
||||
color: $brand-colour;
|
||||
|
||||
.top-bar-section ul li > a.top-bar--menu-item-with-icon {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.top-bar--menu-item-with-icon i,
|
||||
.top-bar--menu-item-with-icon img {
|
||||
line-height: $topbar-height;
|
||||
}
|
||||
|
||||
.top-bar-section {
|
||||
border-bottom: 1px solid $light-grey-transparency;
|
||||
|
||||
a.icon {
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
font-weight: 300;
|
||||
height: $topbar-height;
|
||||
line-height: $topbar-height;
|
||||
vertical-align: top;
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid menu items blocking logo
|
||||
li:not(.has-form), li:not(.has-form) a:not(.button), li:not(.has-form) a:not(.button):hover {
|
||||
background-color: transparent;
|
||||
.nav-primary {
|
||||
@include headingFont;
|
||||
|
||||
font-size: 0.875rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
li.cart {
|
||||
background-color: #f4704c;
|
||||
|
||||
a span {
|
||||
color: white;
|
||||
}
|
||||
|
||||
i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.count {
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
height: 26px;
|
||||
margin-top: 16px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
span {
|
||||
background-color: white;
|
||||
border-radius: 20px;
|
||||
color: #f4704c;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: 8px;
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul.center {
|
||||
display: inline-block;
|
||||
|
||||
// By default, we center between the left and right uls, but we want to be centered
|
||||
// relative to the whole page. The difference in width between the other uls is 74px,
|
||||
// so we offset by that amount here.
|
||||
margin-left: -74px;
|
||||
ul .nav-primary {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
ul.dropdown {
|
||||
border: 1px solid $smoke;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
ul.right {
|
||||
> li {
|
||||
border-left: 1px solid #ddd;
|
||||
padding: 0 14px;
|
||||
|
||||
@media screen and (max-width: 1450px) {
|
||||
padding: 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
li > a {
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #f4704c;
|
||||
display: inline-block;
|
||||
margin-right: 2px;
|
||||
margin-top: -3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
img {
|
||||
margin-right: 2px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul li > a {
|
||||
font-size: 16px;
|
||||
height: $topbar-height;
|
||||
}
|
||||
|
||||
ul li.ofn-logo > a {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
ul .nav-primary {
|
||||
@include headingFont;
|
||||
text-transform: uppercase;
|
||||
font-weight: 300;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.joyride-tip-guide .button {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile Menu
|
||||
|
||||
.tab-bar {
|
||||
background-color: white;
|
||||
border-bottom: 1px solid $light-grey-transparency;
|
||||
height: 2.8em;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
|
||||
.cart-span {
|
||||
background-color: #f4704c;
|
||||
padding: 13px;
|
||||
|
||||
a,
|
||||
span {
|
||||
color: white;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.count {
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
margin-left: 2px;
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
span {
|
||||
background-color: white;
|
||||
border-radius: 20px;
|
||||
color: #f4704c;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
position: absolute;
|
||||
right: -10px;
|
||||
text-align: center;
|
||||
top: -9px;
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.off-canvas-list li.language-switcher ul li {
|
||||
@@ -224,6 +114,8 @@ nav.top-bar {
|
||||
}
|
||||
|
||||
.off-canvas-wrap.move-right .tab-bar .menu-icon span {
|
||||
-moz-box-shadow: 0 0px 0 1px #666, 0 7px 0 1px #666, 0 14px 0 1px #666;
|
||||
-webkit-box-shadow: 0 0px 0 1px #666, 0 7px 0 1px #666, 0 14px 0 1px #666;
|
||||
box-shadow: 0 0px 0 1px #666, 0 7px 0 1px #666, 0 14px 0 1px #666;
|
||||
}
|
||||
|
||||
@@ -235,19 +127,10 @@ nav.top-bar {
|
||||
padding: 9px 0 0 9px;
|
||||
}
|
||||
|
||||
// Leave space for tab bar, in screens smaller than large.
|
||||
[role="main"] {
|
||||
margin-top: 2.8em;
|
||||
|
||||
@media #{$large-up} {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar .ofn-logo img {
|
||||
height: auto;
|
||||
width: auto;
|
||||
max-height: 44px;
|
||||
max-height: 51px;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
@@ -255,7 +138,7 @@ nav.top-bar {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.off-canvas-wrap ul.off-canvas-list {
|
||||
.off-canvas-wrap.move-right ul.off-canvas-list {
|
||||
font-size: 0.875rem;
|
||||
|
||||
.li-menu {
|
||||
@@ -275,10 +158,12 @@ nav.top-bar {
|
||||
background-color: transparent;
|
||||
color: $brand-colour;
|
||||
}
|
||||
|
||||
@include transition(all 0.3s ease-in-out);
|
||||
}
|
||||
}
|
||||
|
||||
.off-canvas-wrap ul.off-canvas-list i {
|
||||
.off-canvas-wrap.move-right ul.off-canvas-list i {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
@@ -287,8 +172,7 @@ nav.top-bar {
|
||||
|
||||
@media screen and (max-width: 1450px) {
|
||||
nav .top-bar-section {
|
||||
ul li a,
|
||||
.has-dropdown > a {
|
||||
ul li a, .has-dropdown > a {
|
||||
padding: 0 ($topbar-height / 8) !important;
|
||||
}
|
||||
|
||||
@@ -310,4 +194,10 @@ nav.top-bar {
|
||||
// padding required to placehold for fixed menu bar
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
section.right {
|
||||
.nav-branded {
|
||||
padding: 0 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
@import "animations";
|
||||
@import "compass/css3/transition";
|
||||
|
||||
$page-alert-height: 55px;
|
||||
|
||||
// Basic style \\
|
||||
.page-alert {
|
||||
.alert-box {
|
||||
height: $page-alert-height;
|
||||
height: 55px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba($dark-grey, 0.35);
|
||||
border-left: none;
|
||||
@@ -47,26 +45,33 @@ $page-alert-height: 55px;
|
||||
}
|
||||
|
||||
// Show-hide animation \\
|
||||
|
||||
.off-canvas-wrap .inner-wrap,
|
||||
.off-canvas-fixed .top-bar,
|
||||
.off-canvas-fixed ofn-flash,
|
||||
.off-canvas-fixed nav.tab-bar,
|
||||
.off-canvas-fixed .page-alert {
|
||||
@include transition(all 1000ms ease-in-out);
|
||||
.off-canvas-wrap .inner-wrap, .off-canvas-wrap .inner-wrap .fixed, nav.tab-bar {
|
||||
@include transition(all, 1000ms, ease-in-out);
|
||||
|
||||
&.move-down {
|
||||
margin-top: $page-alert-height;
|
||||
margin-top: 55px;
|
||||
|
||||
@include transition(all, 1000ms, ease-in-out);
|
||||
}
|
||||
}
|
||||
|
||||
.off-canvas-wrap .page-alert {
|
||||
top: -1 * $page-alert-height;
|
||||
z-index: 100;
|
||||
.off-canvas-wrap .inner-wrap .page-alert.fixed {
|
||||
top: -55px;
|
||||
z-index: 1;
|
||||
|
||||
// TODO: Compass to disable transition
|
||||
-moz-transition: none;
|
||||
-webkit-transition: none;
|
||||
-o-transition: color 0 ease-in;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.off-canvas-wrap.move-right .inner-wrap.move-down {
|
||||
.page-alert {
|
||||
top: -55px * 2;
|
||||
}
|
||||
|
||||
.left-off-canvas-menu {
|
||||
top: -1 * $page-alert-height;
|
||||
top: -55px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@import '../base/colors';
|
||||
@import '../collapsible';
|
||||
|
||||
// Styling for login modal to style tabs
|
||||
.reveal-modal.login-modal {
|
||||
@@ -24,10 +23,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1025px) {
|
||||
// make sure styling doesn't get messed up if resizing down and back up
|
||||
.collapsible-menus-container {
|
||||
min-height: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@import "mixins";
|
||||
@import "branding";
|
||||
@import "compass/css3/user-interface";
|
||||
@import 'variables';
|
||||
|
||||
.cart {
|
||||
@include user-select(none);
|
||||
@@ -16,8 +15,8 @@
|
||||
|
||||
.joyride-tip-guide {
|
||||
display: block;
|
||||
right: 0;
|
||||
top: $topbar-height;
|
||||
right: 10px;
|
||||
top: 55px;
|
||||
width: 480px;
|
||||
|
||||
@media screen and (min-width: 641px) {
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
$brand-colour: #f27052;
|
||||
|
||||
// Topbar
|
||||
$topbar-height: rem-calc(64);
|
||||
$topbar-link-padding: $topbar-height / 4;
|
||||
$topbar-arrows: false;
|
||||
$topbar-height: rem-calc(75);
|
||||
$topbar-link-padding: $topbar-height / 3;
|
||||
|
||||
$topbar-bg: $white;
|
||||
$topbar-bg-color: $topbar-bg;
|
||||
|
||||
@@ -31,16 +31,7 @@ module Admin
|
||||
|
||||
def collection
|
||||
return Schedule.where("1=0") unless json_request?
|
||||
if params[:enterprise_id]
|
||||
filter_schedules_by_enterprise_id(permissions.visible_schedules, params[:enterprise_id])
|
||||
else
|
||||
permissions.visible_schedules
|
||||
end
|
||||
end
|
||||
|
||||
# Filter schedules by OCs with a given coordinator id
|
||||
def filter_schedules_by_enterprise_id(schedules, enterprise_id)
|
||||
schedules.joins(:order_cycles).where(order_cycles: { coordinator_id: enterprise_id.to_i })
|
||||
permissions.visible_schedules
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
require 'open_food_network/permissions'
|
||||
require 'open_food_network/proxy_order_syncer'
|
||||
|
||||
module Admin
|
||||
class SubscriptionsController < ResourceController
|
||||
@@ -33,11 +32,21 @@ module Admin
|
||||
end
|
||||
|
||||
def create
|
||||
save_form_and_render(false)
|
||||
form = SubscriptionForm.new(@subscription, params[:subscription])
|
||||
if form.save
|
||||
render_as_json @subscription
|
||||
else
|
||||
render json: { errors: form.json_errors }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
save_form_and_render
|
||||
form = SubscriptionForm.new(@subscription, params[:subscription])
|
||||
if form.save
|
||||
render_as_json @subscription, order_update_issues: form.order_update_issues
|
||||
else
|
||||
render json: { errors: form.json_errors }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def cancel
|
||||
@@ -58,26 +67,12 @@ module Admin
|
||||
end
|
||||
|
||||
def unpause
|
||||
params[:subscription][:paused_at] = nil
|
||||
save_form_and_render
|
||||
@subscription.update_attributes(paused_at: nil)
|
||||
render_as_json @subscription
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def save_form_and_render(render_issues = true)
|
||||
form = SubscriptionForm.new(@subscription, params[:subscription])
|
||||
unless form.save
|
||||
render json: { errors: form.json_errors }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
if render_issues
|
||||
render_as_json @subscription, order_update_issues: form.order_update_issues
|
||||
else
|
||||
render_as_json @subscription
|
||||
end
|
||||
end
|
||||
|
||||
def permissions
|
||||
return @permissions unless @permissions.nil?
|
||||
@permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
|
||||
@@ -9,8 +9,8 @@ module Admin
|
||||
def map_by_tag
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
serializer = ActiveModel::ArraySerializer.new(collection)
|
||||
render json: serializer.to_json
|
||||
serialiser = ActiveModel::ArraySerializer.new(collection)
|
||||
render json: serialiser.to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,7 +5,12 @@ module Api
|
||||
before_filter :override_sells, only: [:create, :update]
|
||||
before_filter :override_visible, only: [:create, :update]
|
||||
respond_to :json
|
||||
skip_authorization_check only: [:shopfront]
|
||||
skip_authorization_check only: [:shopfront, :managed]
|
||||
|
||||
def managed
|
||||
@enterprises = Enterprise.ransack(params[:q]).result.managed_by(current_api_user)
|
||||
render params[:template] || :bulk_index
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Enterprise
|
||||
|
||||
25
app/controllers/api/order_cycles_controller.rb
Normal file
25
app/controllers/api/order_cycles_controller.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
module Api
|
||||
class OrderCyclesController < Spree::Api::BaseController
|
||||
respond_to :json
|
||||
def managed
|
||||
authorize! :admin, OrderCycle
|
||||
authorize! :read, OrderCycle
|
||||
@order_cycles = OrderCycle.ransack(params[:q]).result.managed_by(current_api_user)
|
||||
render params[:template] || :bulk_index
|
||||
end
|
||||
|
||||
def accessible
|
||||
@order_cycles = if params[:as] == "distributor"
|
||||
OrderCycle.ransack(params[:q]).result.
|
||||
involving_managed_distributors_of(current_api_user).order('updated_at DESC')
|
||||
elsif params[:as] == "producer"
|
||||
OrderCycle.ransack(params[:q]).result.
|
||||
involving_managed_producers_of(current_api_user).order('updated_at DESC')
|
||||
else
|
||||
OrderCycle.ransack(params[:q]).result.accessible_by(current_api_user)
|
||||
end
|
||||
|
||||
render params[:template] || :bulk_index
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
module Api
|
||||
class ProductImagesController < BaseController
|
||||
class ProductImagesController < Spree::Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
def update_product_image
|
||||
@@ -8,11 +8,11 @@ module Api
|
||||
|
||||
if @product.images.first.nil?
|
||||
@image = Spree::Image.create(attachment: params[:file], viewable_id: @product.master.id, viewable_type: 'Spree::Variant')
|
||||
render json: @image, serializer: ImageSerializer, status: :created
|
||||
respond_with(@image, status: 201)
|
||||
else
|
||||
@image = @product.images.first
|
||||
@image.update_attributes(attachment: params[:file])
|
||||
render json: @image, serializer: ImageSerializer, status: :ok
|
||||
respond_with(@image, status: 200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
require 'open_food_network/permissions'
|
||||
|
||||
module Api
|
||||
class ProductsController < Api::BaseController
|
||||
respond_to :json
|
||||
DEFAULT_PAGE = 1
|
||||
DEFAULT_PER_PAGE = 15
|
||||
|
||||
skip_authorization_check only: [:show, :bulk_products, :overridable]
|
||||
|
||||
def show
|
||||
@product = find_product(params[:id])
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Spree::Product
|
||||
params[:product][:available_on] ||= Time.zone.now
|
||||
@product = Spree::Product.new(params[:product])
|
||||
begin
|
||||
if @product.save
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 201
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
@product.permalink = nil
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Spree::Product
|
||||
@product = find_product(params[:id])
|
||||
if @product.update_attributes(params[:product])
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 200
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:id])
|
||||
@product.update_attribute(:deleted_at, Time.zone.now)
|
||||
@product.variants_including_master.update_all(deleted_at: Time.zone.now)
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 204
|
||||
end
|
||||
|
||||
# TODO: This should be named 'managed'. Is the action above used? Maybe we should remove it.
|
||||
def bulk_products
|
||||
product_query = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
editable_products.merge(product_scope)
|
||||
|
||||
if params[:import_date].present?
|
||||
product_query = product_query.imported_on(params[:import_date]).group_by_products_id
|
||||
end
|
||||
|
||||
@products = product_query.order('created_at DESC').
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page] || DEFAULT_PAGE).per(params[:per_page] || DEFAULT_PER_PAGE)
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def overridable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name
|
||||
|
||||
@products = paged_products_for_producers producers
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:product_id])
|
||||
authorize! :delete, @product
|
||||
@product.destroy
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 204
|
||||
end
|
||||
|
||||
# POST /api/products/:product_id/clone
|
||||
#
|
||||
def clone
|
||||
authorize! :create, Spree::Product
|
||||
original_product = find_product(params[:product_id])
|
||||
authorize! :update, original_product
|
||||
|
||||
@product = original_product.duplicate
|
||||
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 201
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Copied and modified from SpreeApi::BaseController to allow
|
||||
# enterprise users to access inactive products
|
||||
def product_scope
|
||||
# This line modified
|
||||
if current_api_user.has_spree_role?("admin") || current_api_user.enterprises.present?
|
||||
scope = Spree::Product
|
||||
if params[:show_deleted]
|
||||
scope = scope.with_deleted
|
||||
end
|
||||
else
|
||||
scope = Spree::Product.active
|
||||
end
|
||||
|
||||
scope.includes(:master)
|
||||
end
|
||||
|
||||
def paged_products_for_producers(producers)
|
||||
Spree::Product.scoped.
|
||||
merge(product_scope).
|
||||
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)
|
||||
serializer = ActiveModel::ArraySerializer.new(
|
||||
products,
|
||||
each_serializer: ::Api::Admin::ProductSerializer
|
||||
)
|
||||
|
||||
render text: {
|
||||
products: serializer,
|
||||
# This line is used by the PagedFetcher JS service (inventory).
|
||||
pages: products.num_pages,
|
||||
# This hash is used by the BulkProducts JS service.
|
||||
pagination: pagination_data(products)
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def pagination_data(results)
|
||||
{
|
||||
results: results.total_count,
|
||||
pages: results.num_pages,
|
||||
page: (params[:page] || DEFAULT_PAGE).to_i,
|
||||
per_page: (params[:per_page] || DEFAULT_PER_PAGE).to_i
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,79 +0,0 @@
|
||||
module Api
|
||||
class VariantsController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check only: [:index, :show]
|
||||
before_filter :product
|
||||
|
||||
def index
|
||||
@variants = scope.includes(:option_values).ransack(params[:q]).result
|
||||
render json: @variants, each_serializer: Api::VariantSerializer
|
||||
end
|
||||
|
||||
def show
|
||||
@variant = scope.includes(:option_values).find(params[:id])
|
||||
render json: @variant, serializer: Api::VariantSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Spree::Variant
|
||||
@variant = scope.new(params[:variant])
|
||||
if @variant.save
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 201
|
||||
else
|
||||
invalid_resource!(@variant)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Spree::Variant
|
||||
@variant = scope.find(params[:id])
|
||||
if @variant.update_attributes(params[:variant])
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 200
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
end
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
@variant = scope.find(params[:variant_id])
|
||||
authorize! :delete, @variant
|
||||
|
||||
VariantDeleter.new.delete(@variant)
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 204
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Spree::Variant
|
||||
@variant = scope.find(params[:id])
|
||||
@variant.destroy
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 204
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def product
|
||||
@product ||= Spree::Product.find_by_permalink(params[:product_id]) if params[:product_id]
|
||||
end
|
||||
|
||||
def scope
|
||||
if @product
|
||||
unless current_api_user.has_spree_role?("admin") || params[:show_deleted]
|
||||
variants = @product.variants_including_master
|
||||
else
|
||||
variants = @product.variants_including_master.with_deleted
|
||||
end
|
||||
else
|
||||
variants = Spree::Variant.scoped
|
||||
if current_api_user.has_spree_role?("admin")
|
||||
unless params[:show_deleted]
|
||||
variants = Spree::Variant.active
|
||||
end
|
||||
else
|
||||
variants = variants.active
|
||||
end
|
||||
end
|
||||
variants
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,4 @@
|
||||
require 'open_food_network/referer_parser'
|
||||
require 'spree/authentication_helpers'
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
@@ -8,7 +7,6 @@ class ApplicationController < ActionController::Base
|
||||
before_filter :set_cache_headers # prevent cart emptying via cache when using back button #1213
|
||||
|
||||
include EnterprisesHelper
|
||||
include Spree::AuthenticationHelpers
|
||||
|
||||
def redirect_to(options = {}, response_status = {})
|
||||
::Rails.logger.error("Redirected by #{begin
|
||||
|
||||
@@ -8,6 +8,7 @@ class CheckoutController < Spree::CheckoutController
|
||||
prepend_before_filter :require_order_cycle
|
||||
prepend_before_filter :require_distributor_chosen
|
||||
|
||||
skip_before_filter :check_registration
|
||||
before_filter :enable_embedded_shopfront
|
||||
|
||||
include OrderCyclesHelper
|
||||
@@ -174,6 +175,10 @@ class CheckoutController < Spree::CheckoutController
|
||||
end
|
||||
end
|
||||
|
||||
def skip_state_validation?
|
||||
true
|
||||
end
|
||||
|
||||
def load_order
|
||||
@order = current_order
|
||||
redirect_to(main_app.shop_path) && return unless @order && @order.checkout_allowed?
|
||||
@@ -201,11 +206,11 @@ class CheckoutController < Spree::CheckoutController
|
||||
def redirect_to_cart_path
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to main_app.cart_path
|
||||
redirect_to cart_path
|
||||
end
|
||||
|
||||
format.json do
|
||||
render json: { path: main_app.cart_path }, status: :bad_request
|
||||
render json: { path: cart_path }, status: :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,6 @@ class EnterprisesController < BaseController
|
||||
layout "darkswarm"
|
||||
helper Spree::ProductsHelper
|
||||
include OrderCyclesHelper
|
||||
include SerializerHelper
|
||||
|
||||
# These prepended filters are in the reverse order of execution
|
||||
prepend_before_filter :set_order_cycles, :require_distributor_chosen, :reset_order, only: :shop
|
||||
@@ -15,10 +14,18 @@ class EnterprisesController < BaseController
|
||||
respond_to :js, only: :permalink_checker
|
||||
|
||||
def shop
|
||||
return redirect_to main_app.cart_path unless enough_stock?
|
||||
return redirect_to spree.cart_path unless enough_stock?
|
||||
set_noindex_meta_tag
|
||||
|
||||
@enterprise = current_distributor
|
||||
enterprises = current_distributor
|
||||
.plus_relatives_and_oc_producers(shop_order_cycles)
|
||||
.activated
|
||||
.includes(address: :state)
|
||||
.all
|
||||
|
||||
enterprises = inject_json_ams('enterprises', enterprises)
|
||||
|
||||
render locals: { enterprises: enterprises }
|
||||
end
|
||||
|
||||
def relatives
|
||||
@@ -104,4 +111,14 @@ class EnterprisesController < BaseController
|
||||
def set_noindex_meta_tag
|
||||
@noindex_meta_tag = true unless current_distributor.visible?
|
||||
end
|
||||
|
||||
def inject_json_ams(name, object)
|
||||
options = {
|
||||
each_serializer: Api::EnterpriseSerializer,
|
||||
data: OpenFoodNetwork::EnterpriseInjectionData.new
|
||||
}
|
||||
serializer_instance = ActiveModel::ArraySerializer.new(object, options)
|
||||
|
||||
{ name: name, json: serializer_instance.to_json }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
class GroupsController < BaseController
|
||||
layout 'darkswarm'
|
||||
|
||||
def index
|
||||
@groups = EnterpriseGroup.on_front_page.by_position
|
||||
end
|
||||
|
||||
def show
|
||||
enable_embedded_shopfront
|
||||
@hide_menu = true if @shopfront_layout == 'embedded'
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# For the API
|
||||
ActionController::Metal.class_eval do
|
||||
def spree_current_user
|
||||
@spree_current_user ||= env['warden'].user
|
||||
end
|
||||
end
|
||||
@@ -3,14 +3,5 @@ class ProducersController < BaseController
|
||||
|
||||
before_filter :enable_embedded_shopfront
|
||||
|
||||
def index
|
||||
@enterprises = Enterprise
|
||||
.activated
|
||||
.visible
|
||||
.is_primary_producer
|
||||
.includes(address: :state)
|
||||
.includes(:properties)
|
||||
.includes(supplied_products: :properties)
|
||||
.all
|
||||
end
|
||||
def index; end
|
||||
end
|
||||
|
||||
@@ -27,12 +27,12 @@ class ShopController < BaseController
|
||||
if oc = OrderCycle.with_distributor(@distributor).active.find_by_id(params[:order_cycle_id])
|
||||
current_order(true).set_order_cycle! oc
|
||||
@current_order_cycle = oc
|
||||
render json: @current_order_cycle, serializer: Api::OrderCycleSerializer
|
||||
render partial: "json/order_cycle"
|
||||
else
|
||||
render status: :not_found, json: ""
|
||||
end
|
||||
else
|
||||
render json: current_order_cycle, serializer: Api::OrderCycleSerializer
|
||||
render partial: "json/order_cycle"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ class ShopsController < BaseController
|
||||
def index
|
||||
@enterprises = Enterprise
|
||||
.activated
|
||||
.visible
|
||||
.is_distributor
|
||||
.includes(address: :state)
|
||||
.includes(:properties)
|
||||
.includes(supplied_products: :properties)
|
||||
|
||||
@@ -47,22 +47,12 @@ Spree::Admin::BaseController.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def model_class
|
||||
const_name = controller_name.classify
|
||||
if Spree.const_defined?(const_name)
|
||||
return "Spree::#{const_name}".constantize
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def active_distributors_not_ready_for_checkout
|
||||
ocs = OrderCycle.managed_by(spree_current_user).active
|
||||
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
|
||||
Enterprise.where('enterprises.id IN (?)', distributors).not_ready_for_checkout
|
||||
distributors = ocs.map(&:distributors).flatten.uniq
|
||||
Enterprise.where('id IN (?)', distributors).not_ready_for_checkout
|
||||
end
|
||||
|
||||
def active_distributors_not_ready_for_checkout_message(distributors)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Spree::Admin::Orders::CustomerDetailsController.class_eval do
|
||||
before_filter :check_authorization
|
||||
before_filter :set_guest_checkout_status, only: :update
|
||||
|
||||
def update
|
||||
@@ -26,17 +25,6 @@ Spree::Admin::Orders::CustomerDetailsController.class_eval do
|
||||
|
||||
private
|
||||
|
||||
def check_authorization
|
||||
load_order
|
||||
session[:access_token] ||= params[:token]
|
||||
|
||||
resource = @order
|
||||
action = params[:action].to_sym
|
||||
action = :edit if action == :show # show route renders :edit for this controller
|
||||
|
||||
authorize! action, resource, session[:access_token]
|
||||
end
|
||||
|
||||
def set_guest_checkout_status
|
||||
registered_user = Spree::User.find_by_email(params[:order][:email])
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
require 'open_food_network/spree_api_key_loader'
|
||||
require 'open_food_network/referer_parser'
|
||||
require 'open_food_network/permissions'
|
||||
|
||||
Spree::Admin::ProductsController.class_eval do
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
@@ -34,28 +33,28 @@ Spree::Admin::ProductsController.class_eval do
|
||||
delete_stock_params_and_set_after do
|
||||
super
|
||||
end
|
||||
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
||||
invoke_callbacks(:create, :fails)
|
||||
@object.errors.add(:base, t('spree.admin.products.image_upload_error'))
|
||||
respond_with(@object)
|
||||
end
|
||||
|
||||
def update
|
||||
delete_stock_params_and_set_after do
|
||||
super
|
||||
end
|
||||
|
||||
clear_variants_unit_description if @object.variant_unit == 'items'
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
product_set = product_set_from_params(params)
|
||||
collection_hash = Hash[params[:products].each_with_index.map { |p, i| [i, p] }]
|
||||
product_set = Spree::ProductSet.new(collection_attributes: collection_hash)
|
||||
|
||||
params[:filters] ||= {}
|
||||
bulk_index_query = params[:filters].reduce("") do |string, filter|
|
||||
"#{string}q[#{filter[:property][:db_column]}_#{filter[:predicate][:predicate]}]=#{filter[:value]};"
|
||||
end
|
||||
|
||||
# Ensure we're authorised to update all products
|
||||
product_set.collection.each { |p| authorize! :update, p }
|
||||
|
||||
if product_set.save
|
||||
redirect_to main_app.bulk_products_api_products_path( bulk_index_query(params) )
|
||||
redirect_to "/api/products/bulk_products?page=1;per_page=500;#{bulk_index_query}"
|
||||
else
|
||||
if product_set.errors.present?
|
||||
render json: { errors: product_set.errors }, status: :bad_request
|
||||
@@ -68,8 +67,7 @@ Spree::Admin::ProductsController.class_eval do
|
||||
protected
|
||||
|
||||
def collection
|
||||
# This method is copied directly from the spree product controller
|
||||
# except where we narrow the search below with the managed_by search to support
|
||||
# This method is copied directly from the spree product controller, except where we narrow the search below with the managed_by search to support
|
||||
# enterprise users.
|
||||
# TODO: There has to be a better way!!!
|
||||
return @collection if @collection.present?
|
||||
@@ -104,32 +102,14 @@ Spree::Admin::ProductsController.class_eval do
|
||||
|
||||
private
|
||||
|
||||
def product_set_from_params(params)
|
||||
collection_hash = Hash[params[:products].each_with_index.map { |p, i| [i, p] }]
|
||||
Spree::ProductSet.new(collection_attributes: collection_hash)
|
||||
end
|
||||
|
||||
def bulk_index_query(params)
|
||||
params[:filters].to_h.merge(page: params[:page], per_page: params[:per_page])
|
||||
end
|
||||
|
||||
def load_form_data
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
managed_product_enterprises.is_primary_producer.by_name
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).managed_product_enterprises.is_primary_producer.by_name
|
||||
@taxons = Spree::Taxon.order(:name)
|
||||
@import_dates = product_import_dates.uniq.to_json
|
||||
end
|
||||
|
||||
def product_import_dates
|
||||
options = [{ id: '0', name: '' }]
|
||||
product_import_dates_query.collect(&:import_date).
|
||||
map { |i| options.push(id: i.to_date, name: i.to_date.to_formatted_s(:long)) }
|
||||
|
||||
options
|
||||
end
|
||||
|
||||
def product_import_dates_query
|
||||
Spree::Variant.
|
||||
import_dates = Spree::Variant.
|
||||
select('DISTINCT spree_variants.import_date').
|
||||
joins(:product).
|
||||
where('spree_products.supplier_id IN (?)', editable_enterprises.collect(&:id)).
|
||||
@@ -137,14 +117,18 @@ Spree::Admin::ProductsController.class_eval do
|
||||
where(spree_variants: { is_master: false }).
|
||||
where(spree_variants: { deleted_at: nil }).
|
||||
order('spree_variants.import_date DESC')
|
||||
|
||||
options = [{ id: '0', name: '' }]
|
||||
import_dates.collect(&:import_date).map { |i| options.push(id: i.to_date, name: i.to_date.to_formatted_s(:long)) }
|
||||
|
||||
options
|
||||
end
|
||||
|
||||
def strip_new_properties
|
||||
return if spree_current_user.admin? || params[:product][:product_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:product][:product_properties_attributes].each do |key, property|
|
||||
unless names.include? property[:property_name]
|
||||
params[:product][:product_properties_attributes].delete key
|
||||
unless spree_current_user.admin? || params[:product][:product_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:product][:product_properties_attributes].each do |key, property|
|
||||
params[:product][:product_properties_attributes].delete key unless names.include? property[:property_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -159,41 +143,15 @@ Spree::Admin::ProductsController.class_eval do
|
||||
end
|
||||
|
||||
def set_stock_levels(product, on_hand, on_demand)
|
||||
variant = product_variant(product)
|
||||
|
||||
begin
|
||||
variant.on_demand = on_demand if on_demand.present?
|
||||
variant.on_hand = on_hand.to_i if on_hand.present?
|
||||
rescue StandardError => error
|
||||
notify_bugsnag(error, product, variant)
|
||||
raise error
|
||||
end
|
||||
end
|
||||
|
||||
def notify_bugsnag(error, product, variant)
|
||||
Bugsnag.notify(error) do |report|
|
||||
report.add_tab(:product, product.attributes)
|
||||
report.add_tab(:product_error, product.errors.first) unless product.valid?
|
||||
report.add_tab(:variant, variant.attributes)
|
||||
report.add_tab(:variant_error, variant.errors.first) unless variant.valid?
|
||||
end
|
||||
end
|
||||
|
||||
def product_variant(product)
|
||||
variant = product.master
|
||||
if product.variants.any?
|
||||
product.variants.first
|
||||
else
|
||||
product.master
|
||||
variant = product.variants.first
|
||||
end
|
||||
variant.on_demand = on_demand if on_demand.present?
|
||||
variant.on_hand = on_hand.to_i if on_hand.present?
|
||||
end
|
||||
|
||||
def set_product_master_variant_price_to_zero
|
||||
@product.price = 0 if @product.price.nil?
|
||||
end
|
||||
|
||||
def clear_variants_unit_description
|
||||
@object.variants.each do |variant|
|
||||
variant.update_attribute :unit_description, ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,7 +14,3 @@ module AuthorizeOnLoadResource
|
||||
end
|
||||
|
||||
Spree::Admin::ResourceController.prepend(AuthorizeOnLoadResource)
|
||||
|
||||
Spree::Admin::ResourceController.class_eval do
|
||||
rescue_from CanCan::AccessDenied, :with => :unauthorized
|
||||
end
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class UsersController < ResourceController
|
||||
rescue_from Spree::User::DestroyWithOrdersError, with: :user_destroy_with_orders_error
|
||||
|
||||
after_filter :sign_in_if_change_own_password, only: :update
|
||||
|
||||
# http://spreecommerce.com/blog/2010/11/02/json-hijacking-vulnerability/
|
||||
before_filter :check_json_authenticity, only: :index
|
||||
before_filter :load_roles, only: [:edit, :new, :update, :create,
|
||||
:generate_api_key, :clear_api_key]
|
||||
|
||||
def index
|
||||
respond_with(@collection) do |format|
|
||||
format.html
|
||||
format.json { render json: json_data }
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
if params[:user]
|
||||
roles = params[:user].delete("spree_role_ids")
|
||||
end
|
||||
|
||||
@user = Spree::User.new(params[:user])
|
||||
if @user.save
|
||||
|
||||
if roles
|
||||
@user.spree_roles = roles.reject(&:blank?).collect{ |r| Spree::Role.find(r) }
|
||||
end
|
||||
|
||||
flash.now[:success] = Spree.t(:created_successfully)
|
||||
render :edit
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if params[:user]
|
||||
roles = params[:user].delete("spree_role_ids")
|
||||
end
|
||||
|
||||
if @user.update_attributes(params[:user])
|
||||
if roles
|
||||
@user.spree_roles = roles.reject(&:blank?).collect{ |r| Spree::Role.find(r) }
|
||||
end
|
||||
|
||||
flash.now[:success] = Spree.t(:account_updated)
|
||||
end
|
||||
render :edit
|
||||
end
|
||||
|
||||
def generate_api_key
|
||||
if @user.generate_spree_api_key!
|
||||
flash[:success] = Spree.t('api.key_generated')
|
||||
end
|
||||
redirect_to edit_admin_user_path(@user)
|
||||
end
|
||||
|
||||
def clear_api_key
|
||||
if @user.clear_spree_api_key!
|
||||
flash[:success] = Spree.t('api.key_cleared')
|
||||
end
|
||||
redirect_to edit_admin_user_path(@user)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def collection
|
||||
return @collection if @collection.present?
|
||||
if request.xhr? && params[:q].present?
|
||||
# Disabling proper nested include here due to rails 3.1 bug
|
||||
@collection = Spree::User.
|
||||
includes(:bill_address, :ship_address).
|
||||
where("spree_users.email #{LIKE} :search
|
||||
OR (spree_addresses.firstname #{LIKE} :search
|
||||
AND spree_addresses.id = spree_users.bill_address_id)
|
||||
OR (spree_addresses.lastname #{LIKE} :search
|
||||
AND spree_addresses.id = spree_users.bill_address_id)
|
||||
OR (spree_addresses.firstname #{LIKE} :search
|
||||
AND spree_addresses.id = spree_users.ship_address_id)
|
||||
OR (spree_addresses.lastname #{LIKE} :search
|
||||
AND spree_addresses.id = spree_users.ship_address_id)",
|
||||
search: "#{params[:q].strip}%").
|
||||
limit(params[:limit] || 100)
|
||||
else
|
||||
@search = Spree::User.registered.ransack(params[:q])
|
||||
@collection = @search.
|
||||
result.
|
||||
page(params[:page]).
|
||||
per(Spree::Config[:admin_products_per_page])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# handling raise from Spree::Admin::ResourceController#destroy
|
||||
def user_destroy_with_orders_error
|
||||
invoke_callbacks(:destroy, :fails)
|
||||
render status: :forbidden, text: Spree.t(:error_user_destroy_with_orders)
|
||||
end
|
||||
|
||||
# Allow different formats of json data to suit different ajax calls
|
||||
def json_data
|
||||
json_format = params[:json_format] || 'default'
|
||||
case json_format
|
||||
when 'basic'
|
||||
collection.map { |u| { 'id' => u.id, 'name' => u.email } }.to_json
|
||||
else
|
||||
address_fields = [:firstname, :lastname, :address1, :address2, :city,
|
||||
:zipcode, :phone, :state_name, :state_id, :country_id]
|
||||
includes = { only: address_fields, include: { state: { only: :name },
|
||||
country: { only: :name } } }
|
||||
|
||||
collection.to_json(only: [:id, :email], include:
|
||||
{ bill_address: includes, ship_address: includes })
|
||||
end
|
||||
end
|
||||
|
||||
def sign_in_if_change_own_password
|
||||
return unless spree_current_user == @user && @user.password.present?
|
||||
sign_in(@user, event: :authentication, bypass: true)
|
||||
end
|
||||
|
||||
def load_roles
|
||||
@roles = Spree::Role.scoped
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -18,7 +18,6 @@ Spree::Admin::VariantsController.class_eval do
|
||||
def search
|
||||
scoper = OpenFoodNetwork::ScopeVariantsForSearch.new(params)
|
||||
@variants = scoper.search
|
||||
render json: @variants, each_serializer: Api::Admin::VariantSerializer
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
require_dependency 'spree/api/controller_setup'
|
||||
|
||||
module Spree
|
||||
module Api
|
||||
class BaseController < ActionController::Metal
|
||||
include Spree::Api::ControllerSetup
|
||||
include Spree::Core::ControllerHelpers::SSL
|
||||
include ::ActionController::Head
|
||||
|
||||
self.responder = Spree::Api::Responders::AppResponder
|
||||
|
||||
respond_to :json
|
||||
|
||||
attr_accessor :current_api_user
|
||||
|
||||
before_filter :set_content_type
|
||||
before_filter :check_for_user_or_api_key, :if => :requires_authentication?
|
||||
before_filter :authenticate_user
|
||||
after_filter :set_jsonp_format
|
||||
|
||||
rescue_from Exception, :with => :error_during_processing
|
||||
rescue_from CanCan::AccessDenied, :with => :unauthorized
|
||||
rescue_from ActiveRecord::RecordNotFound, :with => :not_found
|
||||
|
||||
helper Spree::Api::ApiHelpers
|
||||
|
||||
ssl_allowed
|
||||
|
||||
def set_jsonp_format
|
||||
if params[:callback] && request.get?
|
||||
self.response_body = "#{params[:callback]}(#{response_body})"
|
||||
headers["Content-Type"] = 'application/javascript'
|
||||
end
|
||||
end
|
||||
|
||||
def map_nested_attributes_keys(klass, attributes)
|
||||
nested_keys = klass.nested_attributes_options.keys
|
||||
attributes.inject({}) do |h, (k, v)|
|
||||
key = nested_keys.include?(k.to_sym) ? "#{k}_attributes" : k
|
||||
h[key] = v
|
||||
h
|
||||
end.with_indifferent_access
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_content_type
|
||||
content_type = case params[:format]
|
||||
when "json"
|
||||
"application/json"
|
||||
when "xml"
|
||||
"text/xml"
|
||||
end
|
||||
headers["Content-Type"] = content_type
|
||||
end
|
||||
|
||||
def check_for_user_or_api_key
|
||||
# User is already authenticated with Spree, make request this way instead.
|
||||
return true if @current_api_user = try_spree_current_user ||
|
||||
!requires_authentication?
|
||||
|
||||
return if api_key.present?
|
||||
render("spree/api/errors/must_specify_api_key", status: :unauthorized) && return
|
||||
end
|
||||
|
||||
def authenticate_user
|
||||
return if @current_api_user
|
||||
|
||||
if requires_authentication? || api_key.present?
|
||||
unless @current_api_user = Spree.user_class.find_by_spree_api_key(api_key.to_s)
|
||||
render("spree/api/errors/invalid_api_key", status: :unauthorized) && return
|
||||
end
|
||||
else
|
||||
# An anonymous user
|
||||
@current_api_user = Spree.user_class.new
|
||||
end
|
||||
end
|
||||
|
||||
def unauthorized
|
||||
render("spree/api/errors/unauthorized", status: :unauthorized) && return
|
||||
end
|
||||
|
||||
def error_during_processing(exception)
|
||||
render(text: { exception: exception.message }.to_json,
|
||||
status: :unprocessable_entity) && return
|
||||
end
|
||||
|
||||
def requires_authentication?
|
||||
true
|
||||
end
|
||||
|
||||
def not_found
|
||||
render("spree/api/errors/not_found", status: :not_found) && return
|
||||
end
|
||||
|
||||
def current_ability
|
||||
Spree::Ability.new(current_api_user)
|
||||
end
|
||||
|
||||
def invalid_resource!(resource)
|
||||
@resource = resource
|
||||
render "spree/api/errors/invalid_resource", status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def api_key
|
||||
request.headers["X-Spree-Token"] || params[:token]
|
||||
end
|
||||
helper_method :api_key
|
||||
|
||||
def find_product(id)
|
||||
product_scope.find_by_permalink!(id.to_s)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
product_scope.find(id)
|
||||
end
|
||||
|
||||
def product_scope
|
||||
if current_api_user.has_spree_role?("admin")
|
||||
scope = Product
|
||||
if params[:show_deleted]
|
||||
scope = scope.with_deleted
|
||||
end
|
||||
else
|
||||
scope = Product.active
|
||||
end
|
||||
|
||||
scope.includes(:master)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
13
app/controllers/spree/api/line_items_controller_decorator.rb
Normal file
13
app/controllers/spree/api/line_items_controller_decorator.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
Spree::Api::LineItemsController.class_eval do
|
||||
around_filter :apply_enterprise_fees_with_lock, only: :update
|
||||
|
||||
private
|
||||
|
||||
def apply_enterprise_fees_with_lock
|
||||
authorize! :read, order
|
||||
order.with_lock do
|
||||
yield
|
||||
order.update_distribution_charge!
|
||||
end
|
||||
end
|
||||
end
|
||||
86
app/controllers/spree/api/products_controller_decorator.rb
Normal file
86
app/controllers/spree/api/products_controller_decorator.rb
Normal file
@@ -0,0 +1,86 @@
|
||||
require 'open_food_network/permissions'
|
||||
|
||||
Spree::Api::ProductsController.class_eval do
|
||||
def managed
|
||||
authorize! :admin, Spree::Product
|
||||
authorize! :read, Spree::Product
|
||||
|
||||
@products = product_scope.ransack(params[:q]).result.managed_by(current_api_user).page(params[:page]).per(params[:per_page])
|
||||
respond_with(@products, default_template: :index)
|
||||
end
|
||||
|
||||
# TODO: This should be named 'managed'. Is the action above used? Maybe we should remove it.
|
||||
def bulk_products
|
||||
@products = OpenFoodNetwork::Permissions.new(current_api_user).editable_products.
|
||||
merge(product_scope).
|
||||
order('created_at DESC').
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page]).per(params[:per_page])
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def overridable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name
|
||||
|
||||
@products = paged_products_for_producers producers
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:product_id])
|
||||
authorize! :delete, @product
|
||||
@product.destroy
|
||||
respond_with(@product, status: 204)
|
||||
end
|
||||
|
||||
# POST /api/products/:product_id/clone
|
||||
#
|
||||
def clone
|
||||
authorize! :create, Spree::Product
|
||||
original_product = find_product(params[:product_id])
|
||||
authorize! :update, original_product
|
||||
|
||||
@product = original_product.duplicate
|
||||
|
||||
respond_with(@product, status: 201, default_template: :show)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Copied and modified from Spree::Api::BaseController to allow
|
||||
# enterprise users to access inactive products
|
||||
def product_scope
|
||||
if current_api_user.has_spree_role?("admin") || current_api_user.enterprises.present? # This line modified
|
||||
scope = Spree::Product
|
||||
if params[:show_deleted]
|
||||
scope = scope.with_deleted
|
||||
end
|
||||
else
|
||||
scope = Spree::Product.active
|
||||
end
|
||||
|
||||
scope.includes(:master)
|
||||
end
|
||||
|
||||
def paged_products_for_producers(producers)
|
||||
Spree::Product.scoped.
|
||||
merge(product_scope).
|
||||
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)
|
||||
serializer = ActiveModel::ArraySerializer.new(
|
||||
products,
|
||||
each_serializer: Api::Admin::ProductSerializer
|
||||
)
|
||||
|
||||
render text: { products: serializer, pages: products.num_pages }.to_json
|
||||
end
|
||||
end
|
||||
@@ -1,108 +0,0 @@
|
||||
require 'open_food_network/scope_variant_to_hub'
|
||||
|
||||
module Spree
|
||||
module Api
|
||||
class ShipmentsController < Spree::Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
before_filter :find_order
|
||||
before_filter :find_and_update_shipment, only: [:ship, :ready, :add, :remove]
|
||||
|
||||
def create
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
@shipment = get_or_create_shipment(params[:stock_location_id])
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
@shipment.refresh_rates
|
||||
@shipment.save!
|
||||
|
||||
respond_with(@shipment.reload, default_template: :show)
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :read, Shipment
|
||||
@shipment = @order.shipments.find_by_number!(params[:id])
|
||||
params[:shipment] ||= []
|
||||
unlock = params[:shipment].delete(:unlock)
|
||||
|
||||
if unlock == 'yes'
|
||||
@shipment.adjustment.open
|
||||
end
|
||||
|
||||
@shipment.update_attributes(params[:shipment])
|
||||
|
||||
if unlock == 'yes'
|
||||
@shipment.adjustment.close
|
||||
end
|
||||
|
||||
@shipment.reload
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
def ready
|
||||
authorize! :read, Shipment
|
||||
unless @shipment.ready?
|
||||
if @shipment.can_ready?
|
||||
@shipment.ready!
|
||||
else
|
||||
render "spree/api/shipments/cannot_ready_shipment", status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
end
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
def ship
|
||||
authorize! :read, Shipment
|
||||
unless @shipment.shipped?
|
||||
@shipment.ship!
|
||||
end
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
def add
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
def remove
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.remove(variant, quantity, @shipment)
|
||||
@shipment.reload if @shipment.persisted?
|
||||
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_order
|
||||
@order = Spree::Order.find_by_number!(params[:order_id])
|
||||
authorize! :read, @order
|
||||
end
|
||||
|
||||
def find_and_update_shipment
|
||||
@shipment = @order.shipments.find_by_number!(params[:id])
|
||||
@shipment.update_attributes(params[:shipment])
|
||||
@shipment.reload
|
||||
end
|
||||
|
||||
def scoped_variant(variant_id)
|
||||
variant = Spree::Variant.find(variant_id)
|
||||
OpenFoodNetwork::ScopeVariantToHub.new(@order.distributor).scope(variant)
|
||||
variant
|
||||
end
|
||||
|
||||
def get_or_create_shipment(stock_location_id)
|
||||
@order.shipment || @order.shipments.create(stock_location_id: stock_location_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
47
app/controllers/spree/api/shipments_controller_decorator.rb
Normal file
47
app/controllers/spree/api/shipments_controller_decorator.rb
Normal file
@@ -0,0 +1,47 @@
|
||||
require 'open_food_network/scope_variant_to_hub'
|
||||
|
||||
Spree::Api::ShipmentsController.class_eval do
|
||||
def create
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
@shipment = get_or_create_shipment(params[:stock_location_id])
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
@shipment.refresh_rates
|
||||
@shipment.save!
|
||||
|
||||
respond_with(@shipment.reload, default_template: :show)
|
||||
end
|
||||
|
||||
def add
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
def remove
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.remove(variant, quantity, @shipment)
|
||||
@shipment.reload if @shipment.persisted?
|
||||
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scoped_variant(variant_id)
|
||||
variant = Spree::Variant.find(variant_id)
|
||||
OpenFoodNetwork::ScopeVariantToHub.new(@order.distributor).scope(variant)
|
||||
variant
|
||||
end
|
||||
|
||||
def get_or_create_shipment(stock_location_id)
|
||||
@order.shipment || @order.shipments.create(stock_location_id: stock_location_id)
|
||||
end
|
||||
end
|
||||
@@ -1,75 +0,0 @@
|
||||
module Spree
|
||||
module Api
|
||||
class TaxonsController < Spree::Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
if taxonomy
|
||||
@taxons = taxonomy.root.children
|
||||
else
|
||||
if params[:ids]
|
||||
@taxons = Taxon.where(id: params[:ids].split(","))
|
||||
else
|
||||
@taxons = Taxon.ransack(params[:q]).result
|
||||
end
|
||||
end
|
||||
respond_with(@taxons)
|
||||
end
|
||||
|
||||
def show
|
||||
@taxon = taxon
|
||||
respond_with(@taxon)
|
||||
end
|
||||
|
||||
def jstree
|
||||
show
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Taxon
|
||||
@taxon = Taxon.new(params[:taxon])
|
||||
@taxon.taxonomy_id = params[:taxonomy_id]
|
||||
taxonomy = Taxonomy.find_by_id(params[:taxonomy_id])
|
||||
|
||||
if taxonomy.nil?
|
||||
@taxon.errors[:taxonomy_id] = I18n.t(:invalid_taxonomy_id, scope: 'spree.api')
|
||||
invalid_resource!(@taxon) && return
|
||||
end
|
||||
|
||||
@taxon.parent_id = taxonomy.root.id unless params[:taxon][:parent_id]
|
||||
|
||||
if @taxon.save
|
||||
respond_with(@taxon, status: 201, default_template: :show)
|
||||
else
|
||||
invalid_resource!(@taxon)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Taxon
|
||||
if taxon.update_attributes(params[:taxon])
|
||||
respond_with(taxon, status: 200, default_template: :show)
|
||||
else
|
||||
invalid_resource!(taxon)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Taxon
|
||||
taxon.destroy
|
||||
respond_with(taxon, status: 204)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def taxonomy
|
||||
return if params[:taxonomy_id].blank?
|
||||
@taxonomy ||= Taxonomy.find(params[:taxonomy_id])
|
||||
end
|
||||
|
||||
def taxon
|
||||
@taxon ||= taxonomy.taxons.find(params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
Spree::Api::VariantsController.class_eval do
|
||||
def soft_delete
|
||||
@variant = scope.find(params[:variant_id])
|
||||
authorize! :delete, @variant
|
||||
|
||||
VariantDeleter.new.delete(@variant)
|
||||
respond_with @variant, status: 204
|
||||
end
|
||||
end
|
||||
@@ -1,93 +0,0 @@
|
||||
require 'open_food_network/address_finder'
|
||||
|
||||
module Spree
|
||||
class CheckoutController < Spree::StoreController
|
||||
include CheckoutHelper
|
||||
|
||||
ssl_required
|
||||
|
||||
before_filter :load_order
|
||||
|
||||
before_filter :ensure_order_not_completed
|
||||
before_filter :ensure_checkout_allowed
|
||||
before_filter :ensure_sufficient_stock_lines
|
||||
|
||||
before_filter :associate_user
|
||||
before_filter :check_authorization
|
||||
before_filter :enable_embedded_shopfront
|
||||
|
||||
helper 'spree/orders'
|
||||
|
||||
rescue_from Spree::Core::GatewayError, :with => :rescue_from_spree_gateway_error
|
||||
|
||||
def edit
|
||||
flash.keep
|
||||
redirect_to main_app.checkout_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_order
|
||||
@order = current_order
|
||||
redirect_to(main_app.cart_path) && return unless @order
|
||||
|
||||
if params[:state]
|
||||
redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state])
|
||||
@order.state = params[:state]
|
||||
end
|
||||
setup_for_current_state
|
||||
end
|
||||
|
||||
def ensure_checkout_allowed
|
||||
redirect_to main_app.cart_path unless @order.checkout_allowed?
|
||||
end
|
||||
|
||||
def ensure_order_not_completed
|
||||
redirect_to main_app.cart_path if @order.completed?
|
||||
end
|
||||
|
||||
def ensure_sufficient_stock_lines
|
||||
if @order.insufficient_stock_lines.present?
|
||||
flash[:error] = Spree.t(:inventory_error_flash_for_insufficient_quantity)
|
||||
redirect_to main_app.cart_path
|
||||
end
|
||||
end
|
||||
|
||||
def setup_for_current_state
|
||||
method_name = :"before_#{@order.state}"
|
||||
send(method_name) if respond_to?(method_name, true)
|
||||
end
|
||||
|
||||
# Adapted from spree_last_address gem: https://github.com/TylerRick/spree_last_address
|
||||
# Originally, we used a forked version of this gem, but encountered strange errors where
|
||||
# it worked in dev but only intermittently in staging/prod.
|
||||
def before_address
|
||||
associate_user
|
||||
|
||||
finder = OpenFoodNetwork::AddressFinder.new(@order.email)
|
||||
|
||||
@order.bill_address = finder.bill_address
|
||||
@order.ship_address = finder.ship_address
|
||||
end
|
||||
|
||||
def before_delivery
|
||||
return if params[:order].present?
|
||||
|
||||
packages = @order.shipments.map(&:to_package)
|
||||
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
|
||||
end
|
||||
|
||||
def before_payment
|
||||
current_order.payments.destroy_all if request.put?
|
||||
end
|
||||
|
||||
def rescue_from_spree_gateway_error
|
||||
flash[:error] = Spree.t(:spree_gateway_error_flash_for_checkout)
|
||||
render :edit
|
||||
end
|
||||
|
||||
def check_authorization
|
||||
authorize!(:edit, current_order, session[:access_token])
|
||||
end
|
||||
end
|
||||
end
|
||||
30
app/controllers/spree/checkout_controller_decorator.rb
Normal file
30
app/controllers/spree/checkout_controller_decorator.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
require 'open_food_network/address_finder'
|
||||
|
||||
Spree::CheckoutController.class_eval do
|
||||
include CheckoutHelper
|
||||
|
||||
before_filter :enable_embedded_shopfront
|
||||
|
||||
def edit
|
||||
flash.keep
|
||||
redirect_to main_app.checkout_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def before_payment
|
||||
current_order.payments.destroy_all if request.put?
|
||||
end
|
||||
|
||||
# Adapted from spree_last_address gem: https://github.com/TylerRick/spree_last_address
|
||||
# Originally, we used a forked version of this gem, but encountered strange errors where
|
||||
# it worked in dev but only intermittently in staging/prod.
|
||||
def before_address
|
||||
associate_user
|
||||
|
||||
finder = OpenFoodNetwork::AddressFinder.new(@order.email)
|
||||
|
||||
@order.bill_address = finder.bill_address
|
||||
@order.ship_address = finder.ship_address
|
||||
end
|
||||
end
|
||||
@@ -1,7 +0,0 @@
|
||||
module Spree
|
||||
class HomeController < Spree::StoreController
|
||||
respond_to :html
|
||||
|
||||
def index; end
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user