Merge remote-tracking branch 'origin/master' into HEAD

This commit is contained in:
Continuous Integration
2017-10-13 18:57:25 +11:00
280 changed files with 6305 additions and 1341 deletions

View File

@@ -143,6 +143,10 @@ Style/WordArray:
Enabled: false
StyleGuide: http://relaxed.ruby.style/#stylewordarray
Style/SymbolArray:
Enabled: false
StyleGuide: https://rubocop.readthedocs.io/en/latest/cops_style/#stylesymbolarray
Lint/AmbiguousRegexpLiteral:
Enabled: false
StyleGuide: http://relaxed.ruby.style/#lintambiguousregexpliteral

View File

@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 100`
# on 2017-07-12 10:36:44 +0200 using RuboCop version 0.49.1.
# on 2017-08-25 14:27:48 +1000 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -14,7 +14,7 @@ Bundler/OrderedGems:
Exclude:
- 'Gemfile'
# Offense count: 77
# Offense count: 128
# Cop supports --auto-correct.
Layout/AlignArray:
Exclude:
@@ -59,7 +59,7 @@ Layout/AlignHash:
- 'spec/models/spree/shipping_method_spec.rb'
- 'spec/models/spree/variant_spec.rb'
# Offense count: 42
# Offense count: 43
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: with_first_parameter, with_fixed_indentation
@@ -113,11 +113,12 @@ Layout/CaseIndentation:
- 'app/models/enterprise.rb'
- 'app/models/product_importer.rb'
# Offense count: 2
# Offense count: 3
# Cop supports --auto-correct.
Layout/ClosingParenthesisIndentation:
Exclude:
- 'app/overrides/add_capture_order_shortcut.rb'
- 'spec/serializers/variant_serializer_spec.rb'
# Offense count: 8
# Cop supports --auto-correct.
@@ -137,7 +138,7 @@ Layout/ElseAlignment:
- 'app/serializers/api/admin/order_cycle_serializer.rb'
- 'lib/open_food_network/sales_tax_report.rb'
# Offense count: 223
# Offense count: 215
# Cop supports --auto-correct.
Layout/EmptyLines:
Enabled: false
@@ -152,7 +153,7 @@ Layout/EmptyLinesAroundAccessModifier:
- 'spec/helpers/products_helper_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 73
# Offense count: 70
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty_lines, no_empty_lines
@@ -170,7 +171,6 @@ Layout/EmptyLinesAroundBlockBody:
- 'app/models/spree/calculator_decorator.rb'
- 'app/models/spree/money_decorator.rb'
- 'app/models/spree/option_value_decorator.rb'
- 'app/models/spree/payment_decorator.rb'
- 'lib/open_food_network/group_buy_report.rb'
- 'lib/spree/money_decorator.rb'
- 'lib/tasks/dev.rake'
@@ -188,10 +188,10 @@ Layout/EmptyLinesAroundBlockBody:
- 'spec/features/admin/orders_spec.rb'
- 'spec/features/admin/reports_spec.rb'
- 'spec/features/admin/variant_overrides_spec.rb'
- 'spec/features/consumer/shopping/embedded_shopfronts_spec.rb'
- 'spec/features/consumer/shopping/shopping_spec.rb'
- 'spec/features/consumer/shopping/variant_overrides_spec.rb'
- 'spec/helpers/admin/business_model_configuration_helper_spec.rb'
- 'spec/helpers/injection_helper_spec.rb'
- 'spec/helpers/shared_helper_spec.rb'
- 'spec/helpers/shop_helper_spec.rb'
- 'spec/helpers/spree/orders_helper_spec.rb'
@@ -212,8 +212,7 @@ Layout/EmptyLinesAroundBlockBody:
- 'spec/models/tag_rule/filter_shipping_methods_spec.rb'
- 'spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb'
- 'spec/serializers/admin/for_order_cycle/supplied_product_serializer_spec.rb'
- 'spec/serializers/order_serializer_spec.rb'
- 'spec/serializers/orders_by_distributor_serializer_spec.rb'
- 'spec/serializers/variant_serializer_spec.rb'
- 'spec/support/matchers/delegate_matchers.rb'
- 'spec/support/matchers/select2_matchers.rb'
- 'spec/support/matchers/table_matchers.rb'
@@ -270,7 +269,7 @@ Layout/EmptyLinesAroundMethodBody:
- 'app/serializers/api/product_serializer.rb'
- 'lib/open_food_network/orders_and_fulfillments_report.rb'
# Offense count: 13
# Offense count: 12
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
@@ -278,7 +277,6 @@ Layout/EmptyLinesAroundModuleBody:
Exclude:
- 'app/helpers/add_to_cart_helper.rb'
- 'app/helpers/groups_helper.rb'
- 'app/helpers/injection_helper.rb'
- 'app/helpers/spree/admin/base_helper_decorator.rb'
- 'lib/open_food_network/column_preference_defaults.rb'
- 'lib/open_food_network/group_buy_report.rb'
@@ -289,7 +287,7 @@ Layout/EmptyLinesAroundModuleBody:
- 'spec/support/request/distribution_helper.rb'
- 'spec/support/request/ui_component_helper.rb'
# Offense count: 54
# Offense count: 55
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Layout/ExtraSpacing:
@@ -326,29 +324,28 @@ Layout/ExtraSpacing:
- 'spec/models/enterprise_spec.rb'
- 'spec/models/order_cycle_spec.rb'
- 'spec/models/spree/adjustment_spec.rb'
- 'spec/models/spree/gateway/stripe_connect_spec.rb'
- 'spec/models/spree/order_spec.rb'
- 'spec/models/variant_override_spec.rb'
- 'spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb'
- 'spec/serializers/admin/for_order_cycle/supplied_product_serializer_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 1
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: consistent, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
Layout/FirstParameterIndentation:
Exclude:
- 'lib/open_food_network/permissions.rb'
- 'spec/serializers/variant_serializer_spec.rb'
# Offense count: 6
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# Configuration parameters: SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
Layout/IndentArray:
Exclude:
- 'lib/open_food_network/users_and_enterprises_report.rb'
- 'spec/features/admin/reports_spec.rb'
- 'spec/lib/open_food_network/products_and_inventory_report_spec.rb'
EnforcedStyle: consistent
# Offense count: 2
# Cop supports --auto-correct.
@@ -403,7 +400,7 @@ Layout/IndentationConsistency:
- 'spec/models/spree/line_item_spec.rb'
- 'spec/models/spree/product_spec.rb'
# Offense count: 20
# Offense count: 18
# Cop supports --auto-correct.
# Configuration parameters: Width, IgnoredPatterns.
Layout/IndentationWidth:
@@ -411,13 +408,11 @@ Layout/IndentationWidth:
- 'app/controllers/admin/invoice_settings_controller.rb'
- 'app/controllers/admin/order_cycles_controller.rb'
- 'app/controllers/api/order_cycles_controller.rb'
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'app/models/spree/line_item_decorator.rb'
- 'app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb'
- 'app/serializers/api/admin/for_order_cycle/supplied_product_serializer.rb'
- 'app/serializers/api/admin/order_cycle_serializer.rb'
- 'lib/discourse/single_sign_on.rb'
- 'lib/open_food_network/last_used_address.rb'
- 'spec/features/consumer/shopping/variant_overrides_spec.rb'
- 'spec/helpers/admin/business_model_configuration_helper_spec.rb'
- 'spec/helpers/groups_helper_spec.rb'
@@ -455,7 +450,6 @@ Layout/LeadingCommentSpace:
- 'spec/factories.rb'
- 'spec/features/admin/products_spec.rb'
- 'spec/features/admin/reports_spec.rb'
- 'spec/features/consumer/shops_spec.rb'
- 'spec/jobs/finalize_account_invoices_spec.rb'
- 'spec/lib/open_food_network/order_and_distributor_report_spec.rb'
- 'spec/lib/open_food_network/order_grouper_spec.rb'
@@ -526,7 +520,15 @@ Layout/MultilineMethodCallBraceLayout:
- 'lib/open_food_network/products_renderer.rb'
- 'spec/lib/open_food_network/products_and_inventory_report_spec.rb'
# Offense count: 34
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented, indented_relative_to_receiver
Layout/MultilineMethodCallIndentation:
Exclude:
- 'spec/serializers/variant_serializer_spec.rb'
# Offense count: 33
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented
@@ -539,7 +541,6 @@ Layout/MultilineOperationIndentation:
- 'app/models/producer_property.rb'
- 'app/models/product_importer.rb'
- 'app/models/spree/ability_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/product_set.rb'
- 'app/models/variant_override_set.rb'
- 'lib/open_food_network/accounts_and_billing_settings_validator.rb'
@@ -559,20 +560,18 @@ Layout/SpaceAfterColon:
- 'spec/models/variant_override_spec.rb'
- 'spec/spec_helper.rb'
# Offense count: 58
# Offense count: 53
# Cop supports --auto-correct.
Layout/SpaceAfterComma:
Exclude:
- 'app/controllers/admin/order_cycles_controller.rb'
- 'app/controllers/spree/admin/products_controller_decorator.rb'
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'app/controllers/spree/orders_controller_decorator.rb'
- 'app/models/column_preference.rb'
- 'app/models/product_importer.rb'
- 'lib/discourse/single_sign_on.rb'
- 'lib/open_food_network/accounts_and_billing_settings_validator.rb'
- 'lib/open_food_network/business_model_configuration_validator.rb'
- 'lib/open_food_network/order_and_distributor_report.rb'
- 'lib/open_food_network/order_cycle_form_applicator.rb'
- 'lib/open_food_network/users_and_enterprises_report.rb'
- 'spec/controllers/admin/enterprises_controller_spec.rb'
@@ -649,7 +648,7 @@ Layout/SpaceAroundEqualsInParameterDefault:
- 'spec/support/request/distribution_helper.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 58
# Offense count: 60
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Layout/SpaceAroundOperators:
@@ -678,6 +677,7 @@ Layout/SpaceAroundOperators:
- 'spec/helpers/order_cycles_helper_spec.rb'
- 'spec/jobs/update_billable_periods_spec.rb'
- 'spec/lib/open_food_network/order_grouper_spec.rb'
- 'spec/lib/stripe/account_connector_spec.rb'
- 'spec/models/calculator/weight_spec.rb'
- 'spec/support/cancan_helper.rb'
- 'spec/support/seeds.rb'
@@ -716,7 +716,7 @@ Layout/SpaceInLambdaLiteral:
- 'app/models/spree/product_decorator.rb'
- 'app/models/spree/variant_decorator.rb'
# Offense count: 194
# Offense count: 187
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
@@ -766,11 +766,9 @@ Layout/SpaceInsideBlockBraces:
- 'spec/models/spree/order_spec.rb'
- 'spec/models/spree/payment_spec.rb'
- 'spec/models/spree/product_spec.rb'
- 'spec/models/spree/user_spec.rb'
- 'spec/models/tag_rule/discount_order_spec.rb'
- 'spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb'
- 'spec/serializers/admin/for_order_cycle/supplied_product_serializer_spec.rb'
- 'spec/serializers/orders_by_distributor_serializer_spec.rb'
- 'spec/spec_helper.rb'
- 'spec/support/cancan_helper.rb'
@@ -797,7 +795,7 @@ Layout/SpaceInsideBrackets:
- 'spec/lib/open_food_network/users_and_enterprises_report_spec.rb'
- 'spec/performance/orders_controller_spec.rb'
# Offense count: 729
# Offense count: 766
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces.
# SupportedStyles: space, no_space, compact
@@ -824,12 +822,11 @@ Layout/Tab:
- 'spec/lib/spree/product_filters_spec.rb'
- 'spec/models/spree/line_item_spec.rb'
# Offense count: 32
# Offense count: 42
# Cop supports --auto-correct.
Layout/TrailingWhitespace:
Exclude:
- 'app/models/distributor_shipping_method.rb'
- 'app/models/product_importer.rb'
- 'app/models/spree/money_decorator.rb'
- 'app/serializers/api/image_serializer.rb'
- 'app/serializers/api/shipping_method_serializer.rb'
@@ -837,7 +834,6 @@ Layout/TrailingWhitespace:
- 'app/views/json/_enterprises.rabl'
- 'app/views/json/_producer.rabl'
- 'app/views/json/partials/_producer.rabl'
- 'lib/open_food_network/group_buy_report.rb'
- 'lib/tasks/dev.rake'
- 'spec/controllers/spree/store_controller_spec.rb'
- 'spec/features/admin/enterprise_user_spec.rb'
@@ -845,17 +841,16 @@ Layout/TrailingWhitespace:
- 'spec/lib/open_food_network/option_value_namer_spec.rb'
- 'spec/lib/open_food_network/order_grouper_spec.rb'
- 'spec/serializers/admin/enterprise_serializer_spec.rb'
- 'spec/serializers/variant_serializer_spec.rb'
- 'spec/support/request/menu_helper.rb'
- 'spec/views/json/producers.json.rabl_spec.rb'
# Offense count: 8
# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleAlignWith, SupportedStylesAlignWith.
# SupportedStylesAlignWith: either, start_of_block, start_of_line
Lint/BlockAlignment:
Exclude:
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'lib/open_food_network/last_used_address.rb'
- 'spec/lib/open_food_network/enterprise_fee_calculator_spec.rb'
- 'spec/models/enterprise_spec.rb'
- 'spec/models/spree/calculator/flat_percent_item_total_spec.rb'
@@ -1012,7 +1007,7 @@ Lint/UselessAccessModifier:
- 'lib/open_food_network/reports/bulk_coop_report.rb'
- 'spec/lib/open_food_network/reports/report_spec.rb'
# Offense count: 340
# Offense count: 341
Lint/Void:
Exclude:
- 'app/serializers/api/enterprise_serializer.rb'
@@ -1081,7 +1076,7 @@ Lint/Void:
- 'spec/serializers/enterprise_serializer_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 706
# Offense count: 747
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 711
@@ -1166,7 +1161,7 @@ Rails/Delegate:
- 'app/serializers/api/admin/tag_rule_serializer.rb'
- 'app/serializers/api/variant_serializer.rb'
# Offense count: 6
# Offense count: 7
Rails/FilePath:
Exclude:
- 'lib/tasks/karma.rake'
@@ -1204,7 +1199,7 @@ Rails/HasAndBelongsToMany:
- 'app/models/spree/line_item_decorator.rb'
- 'app/models/spree/payment_method_decorator.rb'
# Offense count: 11
# Offense count: 10
Rails/OutputSafety:
Exclude:
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
@@ -1212,7 +1207,6 @@ Rails/OutputSafety:
- 'app/helpers/spree/reports_helper.rb'
- 'app/serializers/api/product_serializer.rb'
- 'lib/spree/money_decorator.rb'
- 'lib/tasks/karma.rake'
# Offense count: 6
# Cop supports --auto-correct.
@@ -1303,15 +1297,16 @@ Rails/Validation:
- 'app/models/spree/variant_decorator.rb'
- 'app/models/variant_override.rb'
# Offense count: 6
# Offense count: 7
Style/AccessorMethodName:
Exclude:
- 'app/models/product_importer.rb'
- 'app/models/spree/adjustment_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'spec/support/request/shop_workflow.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 35
# Offense count: 34
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: always, conditionals
@@ -1327,7 +1322,6 @@ Style/AndOr:
- 'app/models/product_importer.rb'
- 'app/models/spreadsheet_entry.rb'
- 'app/models/spree/adjustment_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/product_set.rb'
- 'app/views/json/partials/_enterprise.rabl'
- 'lib/spree/core/controller_helpers/respond_with_decorator.rb'
@@ -1341,7 +1335,7 @@ Style/BarePercentLiterals:
- 'spec/features/admin/variants_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 209
# Offense count: 208
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: braces, no_braces, context_dependent
@@ -1411,7 +1405,6 @@ Style/BracesAroundHashParameters:
- 'spec/models/spree/product_spec.rb'
- 'spec/models/spree/taxon_spec.rb'
- 'spec/serializers/admin/customer_serializer_spec.rb'
- 'spec/serializers/orders_by_distributor_serializer_spec.rb'
- 'spec/spec_helper.rb'
- 'spec/support/cancan_helper.rb'
- 'spec/support/request/authentication_workflow.rb'
@@ -1423,7 +1416,7 @@ Style/CaseEquality:
- 'app/helpers/angular_form_helper.rb'
- 'spec/models/spree/payment_spec.rb'
# Offense count: 86
# Offense count: 88
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
@@ -1469,7 +1462,9 @@ Style/ClassAndModuleChildren:
- 'app/serializers/api/admin/line_item_serializer.rb'
- 'app/serializers/api/admin/order_cycle_serializer.rb'
- 'app/serializers/api/admin/order_serializer.rb'
- 'app/serializers/api/admin/payment_method_serializer.rb'
- 'app/serializers/api/admin/payment_method/base_serializer.rb'
- 'app/serializers/api/admin/payment_method/payment_method_serializer.rb'
- 'app/serializers/api/admin/payment_method/stripe_serializer.rb'
- 'app/serializers/api/admin/product_serializer.rb'
- 'app/serializers/api/admin/shipping_method_serializer.rb'
- 'app/serializers/api/admin/tag_rule_serializer.rb'
@@ -1602,7 +1597,7 @@ Style/FileName:
Style/FormatStringToken:
EnforcedStyle: template
# Offense count: 88
# Offense count: 89
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Exclude:
@@ -1656,7 +1651,7 @@ Style/GuardClause:
- 'spec/support/request/distribution_helper.rb'
- 'spec/support/request/shop_workflow.rb'
# Offense count: 1241
# Offense count: 1255
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
@@ -1686,11 +1681,10 @@ Style/InverseMethods:
- 'app/controllers/admin/column_preferences_controller.rb'
- 'spec/support/cancan_helper.rb'
# Offense count: 9
# Offense count: 5
# Cop supports --auto-correct.
Style/LineEndConcatenation:
Exclude:
- 'app/controllers/spree/admin/base_controller_decorator.rb'
- 'lib/spree/core/controller_helpers/respond_with_decorator.rb'
- 'spec/controllers/spree/admin/base_controller_spec.rb'
@@ -1737,11 +1731,10 @@ Style/MultilineIfModifier:
- 'lib/open_food_network/enterprise_issue_validator.rb'
- 'lib/spree/core/controller_helpers/respond_with_decorator.rb'
# Offense count: 8
# Offense count: 7
# Cop supports --auto-correct.
Style/MutableConstant:
Exclude:
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'app/models/enterprise.rb'
- 'app/models/enterprise_fee.rb'
- 'app/models/spree/payment_method_decorator.rb'
@@ -1799,7 +1792,7 @@ Style/NumericLiteralPrefix:
Exclude:
- 'spec/features/admin/order_cycles_spec.rb'
# Offense count: 16
# Offense count: 15
# Cop supports --auto-correct.
# Configuration parameters: Strict.
Style/NumericLiterals:
@@ -2026,7 +2019,7 @@ Style/StructInheritance:
Exclude:
- 'lib/open_food_network/enterprise_fee_applicator.rb'
# Offense count: 182
# Offense count: 183
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinSize, SupportedStyles.
# SupportedStyles: percent, brackets
@@ -2070,7 +2063,7 @@ Style/SymbolArray:
- 'spec/models/exchange_spec.rb'
- 'spec/models/spree/ability_spec.rb'
# Offense count: 97
# Offense count: 96
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
@@ -2102,7 +2095,6 @@ Style/SymbolProc:
- 'spec/features/admin/order_cycles_spec.rb'
- 'spec/lib/open_food_network/group_buy_report_spec.rb'
- 'spec/lib/open_food_network/order_grouper_spec.rb'
- 'spec/models/spree/user_spec.rb'
# Offense count: 6
# Cop supports --auto-correct.

14
Gemfile
View File

@@ -10,15 +10,20 @@ gem 'i18n-js', '~> 3.0.0'
gem 'nokogiri', '>= 1.6.7.1'
gem 'pg'
gem 'spree', github: 'openfoodfoundation/spree', branch: 'spree-upgrade-step1c'
gem 'spree', github: 'openfoodfoundation/spree', branch: 'step-6a', ref: '5a76d45'
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '1-3-stable'
gem 'spree_auth_devise', github: 'openfoodfoundation/spree_auth_devise', branch: 'spree-upgrade-intermediate'
# Our branch contains two changes
# - Pass customer email and phone number to PayPal (merged to upstream master)
# - Change type of password from string to password to hide it in the form
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "hide-password"
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "spree-upgrade-intermediate"
#gem 'spree_paypal_express', :github => "spree-contrib/better_spree_paypal_express", :branch => "1-3-stable"
gem 'stripe', '~> 3.3.1'
gem 'activemerchant', '~> 1.71.0'
gem 'oauth2', '~> 1.2.0' # Used for Stripe Connect
gem 'jwt', '~> 1.5'
gem 'delayed_job_active_record'
gem 'daemons'
@@ -121,7 +126,8 @@ group :test do
end
group :development do
gem 'pry-byebug'
gem 'byebug', '~> 9.0.0' # 9.1 requires ruby 2.2
gem 'pry-byebug', '>= 3.4.3'
gem 'debugger-linecache'
gem 'guard'
gem 'guard-livereload'

View File

@@ -14,12 +14,12 @@ GIT
GIT
remote: git://github.com/openfoodfoundation/better_spree_paypal_express.git
revision: 840d973cd5bd3250b17674a624dad494aeb09eb3
branch: hide-password
revision: 8d95f4544c682634812becaf50999fba0cd04df0
branch: spree-upgrade-intermediate
specs:
spree_paypal_express (2.0.3)
paypal-sdk-merchant (= 1.106.1)
spree_core (~> 1.3.4)
spree_core (~> 1.3.99)
GIT
remote: git://github.com/openfoodfoundation/ofn-qz.git
@@ -30,49 +30,78 @@ GIT
GIT
remote: git://github.com/openfoodfoundation/spree.git
revision: a4c439570b77afa50f9e36299811f293232bd281
branch: spree-upgrade-step1c
revision: 5a76d456ff70aea7aae3d25156558d71eb7febf2
ref: 5a76d45
branch: step-6a
specs:
spree (1.3.99)
spree_api (= 1.3.99)
spree_backend (= 1.3.99)
spree_cmd (= 1.3.99)
spree_core (= 1.3.99)
spree_dash (= 1.3.99)
spree_promo (= 1.3.99)
spree_frontend (= 1.3.99)
spree_sample (= 1.3.99)
spree_api (1.3.99)
rabl (= 0.7.2)
spree_core (= 1.3.99)
versioncake (= 0.4.0)
spree_backend (1.3.99)
deface (>= 0.9.0)
jquery-rails (~> 2.0)
rails (~> 3.2.8)
select2-rails (~> 3.2)
spree_api (= 1.3.99)
spree_core (= 1.3.99)
stringex (~> 1.3.2)
spree_cmd (1.3.99)
thor (>= 0.14.6)
spree_core (1.3.99)
activemerchant (~> 1.50.0)
acts_as_list (= 0.1.4)
activemerchant (~> 1.50)
acts_as_list (= 0.1.9)
awesome_nested_set (= 2.1.5)
aws-sdk (~> 1.11.1)
cancan (= 1.6.8)
deface (>= 0.9.0)
ffaker (~> 1.15.0)
highline (= 1.6.11)
jquery-rails (~> 2.0)
highline (= 1.6.15)
httparty (= 0.9.0)
json (>= 1.5.5)
kaminari (= 0.13.0)
money (= 5.0.0)
money (= 5.1.0)
paperclip (~> 3.0)
rabl (= 0.7.2)
rails (~> 3.2.13)
ransack (= 0.7.2)
select2-rails (~> 3.2)
state_machine (= 1.2.0)
stringex (~> 1.3.2)
truncate_html (= 0.9.2)
spree_dash (1.3.99)
httparty (~> 0.8.1)
spree_core (= 1.3.99)
spree_promo (1.3.99)
httparty (~> 0.9.0)
spree_backend (= 1.3.99)
spree_frontend (= 1.3.99)
spree_frontend (1.3.99)
deface (>= 0.9.0)
jquery-rails (~> 2.2.1)
rails (~> 3.2.8)
select2-rails (~> 3.2)
spree_api (= 1.3.99)
spree_core (= 1.3.99)
stringex (~> 1.3.2)
spree_sample (1.3.99)
spree_core (= 1.3.99)
GIT
remote: git://github.com/openfoodfoundation/spree_auth_devise.git
revision: da9eecefc6fe13dedf4c6f3febec79caad839ec3
branch: spree-upgrade-intermediate
specs:
spree_auth_devise (2.0.0)
devise (~> 2.2.5)
devise-encryptable (= 0.1.2)
spree_backend (~> 1.3.6)
spree_core (~> 1.3.6)
spree_frontend (~> 1.3.6)
GIT
remote: git://github.com/spree/deface.git
revision: 1110a1336252109bce7f98f9182042e0bc2930ae
@@ -83,17 +112,6 @@ GIT
nokogiri (~> 1.6.0)
rails (>= 3.1)
GIT
remote: git://github.com/spree/spree_auth_devise.git
revision: ba95589a85368297c844f096c2a0c121e5b08138
branch: 1-3-stable
specs:
spree_auth_devise (1.3.0)
cancan (~> 1.6.7)
devise (~> 2.2.3)
devise-encryptable (= 0.1.2)
spree_core
GIT
remote: git://github.com/spree/spree_i18n.git
revision: 752eb67204e9c5a4e22b62591a8fd55fe2285e43
@@ -133,8 +151,8 @@ GEM
sprockets (~> 2.2.1)
active_model_serializers (0.8.3)
activemodel (>= 3.0)
activemerchant (1.50.0)
activesupport (>= 3.2.14, < 5.0.0)
activemerchant (1.71.0)
activesupport (>= 3.2.14, < 6.x)
builder (>= 2.1.2, < 4.0.0)
i18n (>= 0.6.9)
nokogiri (~> 1.4)
@@ -154,8 +172,8 @@ GEM
multi_json (~> 1.0)
acts-as-taggable-on (3.5.0)
activerecord (>= 3.2, < 5)
acts_as_list (0.1.4)
addressable (2.3.3)
acts_as_list (0.1.9)
addressable (2.4.0)
andand (1.3.3)
angular-rails-templates (0.2.0)
railties (>= 3.1)
@@ -174,15 +192,13 @@ GEM
json (~> 1.4)
nokogiri (>= 1.4.4)
uuidtools (~> 2.1)
bcrypt (3.1.7)
bcrypt (3.1.11)
bcrypt-ruby (3.1.5)
bcrypt (>= 3.1.3)
blockenspiel (0.4.5)
bugsnag (4.1.0)
builder (3.0.4)
byebug (2.7.0)
columnize (~> 0.3)
debugger-linecache (~> 1.2)
byebug (9.0.6)
cancan (1.6.8)
capybara (2.7.1)
addressable
@@ -195,12 +211,11 @@ GEM
timers (~> 1.1.0)
chronic (0.10.2)
chunky_png (1.3.4)
climate_control (0.0.3)
activesupport (>= 3.0)
climate_control (0.1.0)
cliver (0.3.2)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
coderay (1.0.9)
coderay (1.1.2)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
@@ -208,8 +223,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.10.0)
colorize (0.7.7)
columnize (0.9.0)
colorize (0.8.1)
compass (1.0.3)
chunky_png (~> 1.2)
compass-core (~> 1.0.2)
@@ -226,8 +240,8 @@ GEM
compass (~> 1.0.0)
sass-rails (<= 5.0.1)
sprockets (< 2.13)
crack (0.4.1)
safe_yaml (~> 0.9.0)
crack (0.4.3)
safe_yaml (~> 1.0.0)
css_parser (1.3.5)
addressable
css_splitter (0.4.5)
@@ -266,6 +280,8 @@ GEM
factory_girl_rails (3.3.0)
factory_girl (~> 3.3.0)
railties (>= 3.0.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
ffaker (1.15.0)
ffi (1.9.3)
figaro (0.7.0)
@@ -410,10 +426,10 @@ GEM
rspec (~> 2.14)
haml (4.0.4)
tilt
highline (1.6.11)
highline (1.6.15)
hike (1.2.3)
http_parser.rb (0.5.3)
httparty (0.8.3)
httparty (0.9.0)
multi_json (~> 1.0)
multi_xml
i18n (0.6.11)
@@ -426,13 +442,14 @@ GEM
ipaddress (0.8.0)
journey (1.0.4)
jquery-migrate-rails (1.2.1)
jquery-rails (2.3.0)
jquery-rails (2.2.2)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
json (1.8.6)
json_spec (1.1.1)
multi_json (~> 1.0)
rspec (~> 2.0)
jwt (1.5.4)
kaminari (0.13.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
@@ -454,19 +471,25 @@ GEM
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
method_source (0.8.2)
method_source (0.9.0)
mime-types (1.25.1)
mini_portile2 (2.0.0)
mini_portile2 (2.1.0)
momentjs-rails (2.5.1)
railties (>= 3.1)
money (5.0.0)
i18n (~> 0.4)
json
money (5.1.0)
i18n (~> 0.6.0)
multi_json (1.12.1)
multi_xml (0.5.5)
multi_xml (0.6.0)
multipart-post (2.0.0)
newrelic_rpm (3.12.0.288)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
oauth2 (1.2.0)
faraday (>= 0.8, < 0.10)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
oj (2.1.2)
orm_adapter (0.5.0)
paper_trail (3.0.8)
@@ -497,18 +520,17 @@ GEM
activerecord (~> 3.0)
polyglot (0.3.5)
powerpack (0.1.1)
pry (0.9.12.2)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
pry-byebug (1.3.2)
byebug (~> 2.7)
pry (~> 0.9.12)
pry (0.11.1)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.4.3)
byebug (>= 9.0, < 9.1)
pry (~> 0.10)
rabl (0.7.2)
activesupport (>= 2.3.14)
multi_json (~> 1.0)
rack (1.4.7)
rack-cache (1.6.1)
rack-cache (1.7.0)
rack (>= 0.4)
rack-livereload (0.3.15)
rack
@@ -537,7 +559,7 @@ GEM
rainbow (2.2.2)
rake
raindrops (0.13.0)
rake (11.3.0)
rake (10.5.0)
ransack (0.7.2)
actionpack (~> 3.0)
activerecord (~> 3.0)
@@ -574,8 +596,9 @@ GEM
rspec-expectations (2.14.0)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.2)
rspec-rails (2.14.0)
rspec-rails (2.14.2)
actionpack (>= 3.0)
activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.14.0)
@@ -592,7 +615,7 @@ GEM
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.1)
rubyzip (1.2.0)
safe_yaml (0.9.5)
safe_yaml (1.0.4)
sass (3.3.14)
sass-rails (3.2.6)
railties (~> 3.2.0)
@@ -602,7 +625,6 @@ GEM
thor (~> 0.14)
shoulda-matchers (1.1.0)
activesupport (>= 3.0.0)
slop (3.4.5)
spinjs-rails (1.3)
rails (>= 3.1)
sprockets (2.2.3)
@@ -612,23 +634,25 @@ GEM
tilt (~> 1.1, != 1.3.0)
state_machine (1.2.0)
stringex (1.3.3)
stripe (3.3.1)
faraday (~> 0.9)
therubyracer (0.12.0)
libv8 (~> 3.16.14.0)
ref
thor (0.19.1)
thor (0.19.4)
tilt (1.4.1)
timecop (0.8.1)
timers (1.1.0)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
truncate_html (0.5.5)
truncate_html (0.9.2)
turbo-sprockets-rails3 (0.3.6)
railties (> 3.2.8, < 4.0.0)
sprockets (>= 2.0.0)
turn (0.8.3)
ansi
tzinfo (0.3.49)
tzinfo (0.3.53)
uglifier (2.7.1)
execjs (>= 0.3.0)
json (>= 1.8.0)
@@ -645,11 +669,11 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
warden (1.2.3)
warden (1.2.6)
rack (>= 1.0)
webmock (1.13.0)
webmock (1.8.11)
addressable (>= 2.2.7)
crack (>= 0.3.2)
crack (>= 0.1.7)
websocket-driver (0.6.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
@@ -658,7 +682,7 @@ GEM
chronic (>= 0.6.3)
wicked_pdf (1.1.0)
wkhtmltopdf-binary (0.12.3.1)
xml-simple (1.1.4)
xml-simple (1.1.5)
xpath (2.0.0)
nokogiri (~> 1.3)
@@ -667,6 +691,7 @@ PLATFORMS
DEPENDENCIES
active_model_serializers
activemerchant (~> 1.71.0)
acts-as-taggable-on (~> 3.4)
andand
angular-rails-templates (~> 0.2.0)
@@ -677,6 +702,7 @@ DEPENDENCIES
aws-sdk
blockenspiel
bugsnag
byebug (~> 9.0.0)
capybara
coffee-rails (~> 3.2.1)
compass-rails
@@ -711,11 +737,13 @@ DEPENDENCIES
jquery-migrate-rails
jquery-rails
json_spec
jwt (~> 1.5)
knapsack
letter_opener
momentjs-rails
newrelic_rpm
nokogiri (>= 1.6.7.1)
oauth2 (~> 1.2.0)
ofn-qz!
oj
paper_trail (~> 3.0.8)
@@ -723,7 +751,7 @@ DEPENDENCIES
parallel_tests
pg
poltergeist
pry-byebug
pry-byebug (>= 3.4.3)
rabl
rack-livereload
rack-ssl
@@ -745,6 +773,7 @@ DEPENDENCIES
spree_auth_devise!
spree_i18n!
spree_paypal_express!
stripe (~> 3.3.1)
therubyracer
timecop
truncate_html
@@ -762,4 +791,4 @@ RUBY VERSION
ruby 2.1.5p273
BUNDLED WITH
1.15.2
1.15.4

View File

@@ -123,7 +123,7 @@ Do not forget to run `rake tmp:cache:clear` after locales are updated to reload
* Maikel Linke (https://github.com/mkllnk)
* Lynne Davis (https://github.com/lin-d-hop)
* Paul Mackay (https://github.com/pmackay)
* Steve Petitt (https://github.com/stveep)
* Steve Pettitt (https://github.com/stveep)
## Licence

View File

@@ -14,9 +14,8 @@
//= require angular-resource
//= require angular-animate
//= require angular-sanitize
//= require admin/spree_core
//= require admin/spree_backend
//= require admin/spree_auth
//= require admin/spree_promo
//= require admin/spree_paypal_express
//= require ../shared/ng-infinite-scroll.min.js
//= require ../shared/ng-tags-input.min.js

View File

@@ -22,7 +22,7 @@ angular.module("admin.enterprises")
{ name: 'users', label: t('users'), icon_class: "icon-user" }
]
$scope.select(0)
SideMenu.init()
$scope.showItem = (item) ->
if item.show?

View File

@@ -0,0 +1,18 @@
angular.module("admin.paymentMethods").controller "StripeController", ($scope, $http, shops) ->
$scope.shops = shops
$scope.stripe_account = {}
$scope.$watch "paymentMethod.preferred_enterprise_id", (newID, oldID) ->
return unless newID?
$scope.stripe_account = {}
$http.get("/admin/stripe_accounts/status.json?enterprise_id=#{newID}").success (data) ->
angular.extend($scope.stripe_account, data)
.error (response) ->
$scope.stripe_account.status = "request_failed"
$scope.current_enterprise_stripe_path = ->
return unless $scope.paymentMethod.preferred_enterprise_id?
permalink = shops.filter((shop) ->
shop.id == $scope.paymentMethod.preferred_enterprise_id
)[0].permalink
"/admin/enterprises/#{permalink}/edit#/payment_methods"

View File

@@ -0,0 +1,33 @@
// Override of Spree's logic in the file of the same name
// Changes made as per https://github.com/spree/spree/commit/8a3a80b08abf80fbed2fcee4b429ba1caf68baf1
// which allows the form partial in admin/payments/new to be switched using radio buttons
// We can remove this file when we reach 2.3.0
$(document).ready(function() {
if ($("#new_payment").is("*")) {
$('.payment_methods_radios').click(
function() {
$('.payment-methods').hide();
if (this.checked) {
$('#payment_method_' + this.value).show();
}
}
);
$('.payment_methods_radios').each(
function() {
if (this.checked) {
$('#payment_method_' + this.value).show();
} else {
$('#payment_method_' + this.value).hide();
}
}
);
$(".card_new").radioControlsVisibilityOfElement('.card_form');
$('select.jump_menu').change(function(){
window.location = this.options[this.selectedIndex].value;
});
}
});

View File

@@ -1,5 +1,5 @@
angular.module("admin.resources").factory 'LineItemResource', ($resource) ->
$resource('/admin/:orders/:order_number/line_items/:id.json', {}, {
$resource('/admin/bulk_line_items/:id.json', {}, {
'index':
method: 'GET'
isArray: true

View File

@@ -26,7 +26,7 @@ angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
save: (lineItem) ->
deferred = $q.defer()
lineItem.errors = {}
lineItem.$update({id: lineItem.id, orders: "orders", order_number: lineItem.order.number})
lineItem.$update({id: lineItem.id})
.then( (data) =>
@pristineByID[lineItem.id] = angular.copy(lineItem)
deferred.resolve(data)
@@ -54,7 +54,7 @@ angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
delete: (lineItem, callback=null) ->
deferred = $q.defer()
lineItem.$delete({id: lineItem.id, orders: "orders", order_number: lineItem.order.number})
lineItem.$delete({id: lineItem.id})
.then( (data) =>
delete @byID[lineItem.id]
delete @pristineByID[lineItem.id]

View File

@@ -1,4 +1,4 @@
angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher) ->
angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher, $http) ->
new class BulkProducts
products: []
@@ -11,14 +11,8 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher)
PagedFetcher.fetch url, (data) => @addProducts data.products
cloneProduct: (product) ->
dataFetcher("/admin/products/" + product.permalink_live + "/clone.json").then (data) =>
# Ideally we would use Spree's built in respond_override helper here to redirect the
# user after a successful clone with .json in the accept headers
# However, at the time of writing there appears to be an issue which causes the
# respond_with block in the destroy action of Spree::Admin::Product to break
# when a respond_overrride for the clone action is used.
id = data.product.id
dataFetcher("/api/products/" + id + "?template=bulk_show").then (newProduct) =>
$http.post("/api/products/" + product.id + "/clone").success (data) =>
dataFetcher("/api/products/" + data.id + "?template=bulk_show").then (newProduct) =>
@unpackProduct newProduct
@insertProductAfter(product, newProduct)

View File

@@ -1,9 +1,21 @@
angular.module("admin.side_menu")
.factory "SideMenu", ->
.factory "SideMenu", ($location) ->
new class SideMenu
items: []
selected: null
# Checks for path and uses it to set the view
# If no path, loads first view
init: =>
path = $location.path()?.match(/^\/\w+$/)?[0]
index = if path
name = path[1..]
@items.indexOf(@find_by_name(name))
else
0
@select(index)
setItems: (items) =>
@items = items
item.visible = true for item in @items
@@ -13,6 +25,7 @@ angular.module("admin.side_menu")
@selected.selected = false if @selected
@selected = @items[index]
@selected.selected = true
$location.path(@selected.name)
find_by_name: (name) =>
for item in @items when item.name is name

View File

@@ -1,4 +1,4 @@
angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout, $filter) ->
angular.module("admin.utils").directive "ofnSelect2", ($sanitize, $timeout, $filter) ->
require: 'ngModel'
restrict: 'C'
scope:

View File

@@ -13,8 +13,9 @@ Darkswarm.controller "AccordionCtrl", ($scope, localStorageService, $timeout, $d
# scroll location is closed by show(), scrollTo() will scroll to the old location of
# the element. Putting this in a 50 ms timeout is enough delay for the DOM to
# have updated.
$timeout (->
$document.scrollTo $("##{section}"), offset_height, 500), 50
$timeout ->
$document.scrollTo($("##{section}"), offset_height, 500)
, 50
$scope.$on 'purchaseFormInvalid', (event, form) ->
# Scroll to first invalid section

View File

@@ -22,6 +22,6 @@ Darkswarm.controller "CheckoutCtrl", ($scope, localStorageService, Checkout, Cur
event.preventDefault()
$scope.submitted = true
if form.$valid
$scope.Checkout.submit()
$scope.Checkout.purchase()
else
$scope.$broadcast 'purchaseFormInvalid', form

View File

@@ -1,23 +1,11 @@
Darkswarm.controller "PaymentCtrl", ($scope, $timeout) ->
Darkswarm.controller "PaymentCtrl", ($scope, $timeout, savedCreditCards, Dates) ->
angular.extend(this, new FieldsetMixin($scope))
$scope.savedCreditCards = savedCreditCards
$scope.name = "payment"
$scope.months = Dates.months
$scope.years = Dates.years
$scope.months = [
{key: t("january"), value: "1"},
{key: t("february"), value: "2"},
{key: t("march"), value: "3"},
{key: t("april"), value: "4"},
{key: t("may"), value: "5"},
{key: t("june"), value: "6"},
{key: t("july"), value: "7"},
{key: t("august"), value: "8"},
{key: t("september"), value: "9"},
{key: t("october"), value: "10"},
{key: t("november"), value: "11"},
{key: t("december"), value: "12"},
]
$scope.years = [moment().year()..(moment().year()+15)]
$scope.secrets.card_month = "1"
$scope.secrets.card_year = moment().year()

View File

@@ -0,0 +1,12 @@
Darkswarm.controller "CreditCardsCtrl", ($scope, $timeout, CreditCard, CreditCards, Dates) ->
angular.extend(this, new FieldsetMixin($scope))
$scope.savedCreditCards = CreditCards.saved
$scope.CreditCard = CreditCard
$scope.secrets = CreditCard.secrets
$scope.showForm = CreditCard.show
$scope.storeCard = ->
if $scope.new_card_form.$valid
CreditCard.requestToken()
$scope.allow_name_change = true
$scope.disable_fields = false

View File

@@ -1,9 +0,0 @@
Darkswarm.controller "DistributorNodeCtrl", ($scope, HashNavigation, $anchorScroll) ->
$scope.toggle = ->
HashNavigation.toggle $scope.distributor.hash
$scope.open = ->
HashNavigation.active($scope.distributor.hash)
if $scope.open()
$anchorScroll()

View File

@@ -6,10 +6,9 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location
$scope.openModal = EnterpriseModal.open
$scope.activeTaxons = []
$scope.show_profiles = false
$scope.show_closed = false
$scope.filtersActive = false
$scope.distanceMatchesShown = false
$scope.filterExpression = {active: true}
$scope.$watch "query", (query)->
Enterprises.flagMatching query
@@ -36,7 +35,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location
# When filter settings change, this could change which name match is at the top, or even
# result in no matches. This affects the reference point that the distance matches are
# calculated from, so we need to recalculate distances.
$scope.$watch '[activeTaxons, activeProperties, shippingTypes, show_profiles]', ->
$scope.$watch '[activeTaxons, activeProperties, shippingTypes, show_profiles, show_closed]', ->
$timeout ->
Enterprises.calculateDistance $scope.query, $scope.firstNameMatch()
$rootScope.$broadcast 'enterprisesChanged'
@@ -74,9 +73,9 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location
undefined
$scope.showClosedShops = ->
delete $scope.filterExpression['active']
$scope.show_closed = true
$location.search('show_closed', '1')
$scope.hideClosedShops = ->
$scope.filterExpression['active'] = true
$scope.show_closed = false
$location.search('show_closed', null)

View File

@@ -1,2 +1,2 @@
Darkswarm.controller "OrdersCtrl", ($scope, $rootScope, $timeout, Orders, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) ->
Darkswarm.controller "OrdersCtrl", ($scope, Orders) ->
$scope.Orders = Orders

View File

@@ -1,15 +1,23 @@
Darkswarm.controller "RegistrationFormCtrl", ($scope, RegistrationService, EnterpriseRegistrationService) ->
$scope.submitted = false
$scope.isDisabled = false
$scope.valid = (form) ->
$scope.submitted = !form.$valid
form.$valid
$scope.create = (form) ->
EnterpriseRegistrationService.create() if $scope.valid(form)
$scope.disableButton()
EnterpriseRegistrationService.create($scope.enableButton) if $scope.valid(form)
$scope.update = (nextStep, form) ->
EnterpriseRegistrationService.update(nextStep) if $scope.valid(form)
$scope.selectIfValid = (nextStep, form) ->
RegistrationService.select(nextStep) if $scope.valid(form)
$scope.disableButton = ->
$scope.isDisabled = true
$scope.enableButton = ->
$scope.isDisabled = false

View File

@@ -0,0 +1,9 @@
Darkswarm.controller "ShopNodeCtrl", ($scope, HashNavigation, $anchorScroll) ->
$scope.toggle = ->
HashNavigation.toggle $scope.shop.hash
$scope.open = ->
HashNavigation.active($scope.shop.hash)
if $scope.open()
$anchorScroll()

View File

@@ -0,0 +1,35 @@
Darkswarm.directive "stripeElements", ($injector, StripeElements) ->
restrict: 'E'
template: "<label for='card-element'>\
<div id='card-element'></div>\
<div id='card-errors' class='error'></div>\
</label>"
link: (scope, elem, attr)->
if $injector.has('stripeObject')
stripe = $injector.get('stripeObject')
card = stripe.elements().create 'card',
hidePostalCode: false
style:
base:
fontFamily: "Roboto, Arial, sans-serif"
fontSize: '16px'
color: '#5c5c5c'
'::placeholder':
color: '#6c6c6c'
card.mount('#card-element')
# Elements validates user input as it is typed. To help your customers
# catch mistakes, you should listen to change events on the card Element
# and display any errors:
card.addEventListener 'change', (event) ->
displayError = document.getElementById('card-errors')
if event.error
displayError.textContent = event.error.message
else
displayError.textContent = ''
return
StripeElements.stripe = stripe
StripeElements.card = card

View File

@@ -0,0 +1,12 @@
Darkswarm.directive "tab", ->
restrict: "C"
require: "^^tabsetCtrl"
scope:
name: "@"
link: (scope, element, attrs, ctrl) ->
element.on "click", ->
scope.$apply ->
ctrl.toggle(scope.name)
ctrl.registerSelectionListener (prefix, selection) ->
element.toggleClass('selected', selection == scope.name)

View File

@@ -0,0 +1,15 @@
Darkswarm.directive "tabView", ->
restrict: "C"
require: "^^tabsetCtrl"
template: "<div ng-include='template'></div>"
scope:
templates: "="
link: (scope, element, attrs, ctrl) ->
scope.template = null
ctrl.registerSelectionListener (prefix, selection) ->
if selection?
selection = "#{prefix}/#{selection}" if prefix?
scope.template = "#{selection}.html"
else
scope.template = null

View File

@@ -0,0 +1,28 @@
Darkswarm.directive "tabsetCtrl", (Tabsets, $location) ->
restrict: "C"
scope:
id: "@"
selected: "@"
navigate: "="
prefix: "@?"
controller: ($scope, $element) ->
if $scope.navigate
path = $location.path()?.match(/^\/\w+$/)?[0]
$scope.selected = path[1..] if path
this.toggle = (name) ->
Tabsets.toggle($scope.id, name)
this.select = (selection) ->
$scope.$broadcast("selection:changed", selection)
$element.toggleClass("expanded", selection?)
$location.path(selection) if $scope.navigate
this.registerSelectionListener = (callback) ->
$scope.$on "selection:changed", (event, selection) ->
callback($scope.prefix, selection)
this
link: (scope, element, attrs, ctrl) ->
Tabsets.register(ctrl, scope.id, scope.selected)

View File

@@ -0,0 +1,7 @@
Darkswarm.filter 'closedShops', ->
(enterprises, show_closed) ->
enterprises ||= []
show_closed ?= false
enterprises.filter (enterprise) =>
show_closed or enterprise.active or !enterprise.is_distributor

View File

@@ -3,13 +3,12 @@ Darkswarm.filter "localizeCurrency", (currencyConfig)->
(amount) ->
# Set country code (eg. "US").
currency_code = if currencyConfig.display_currency then " " + currencyConfig.currency else ""
# Set decimal points, 2 or 0 if hide_cents.
# Set decimal points, 2 or 0 if hide_cents.
decimals = if currencyConfig.hide_cents == "true" then 0 else 2
# We need to use parseFloat before toFixed as the amount should come in as a string.
amount_fixed = parseFloat(amount).toFixed(decimals)
# Set format if the currency symbol should come after the number, otherwise (default) use the locale setting.
format = if currencyConfig.symbol_position == "after" then "%n %u" else undefined
# We need to use parseFloat as the amount should come in as a string.
amount = parseFloat(amount)
# Build the final price string. TODO use spree decimal point and spacer character settings.
if currencyConfig.symbol_position == 'before'
currencyConfig.symbol + amount_fixed + currency_code
else
amount_fixed + " " + currencyConfig.symbol + currency_code
# Build the final price string.
I18n.toCurrency(amount, {precision: decimals, unit: currencyConfig.symbol, format: format}) + currency_code

View File

@@ -1,6 +1,7 @@
window.FieldsetMixin = ($scope)->
$scope.next = (event = false)->
event.preventDefault() if event
return unless $scope.nextPanel
$scope.show $scope.nextPanel
$scope.onTimeout = ->

View File

@@ -1,12 +1,18 @@
Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $http, Navigation, CurrentHub, RailsFlashLoader, Loading)->
Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeElements, PaymentMethods, $http, Navigation, CurrentHub, RailsFlashLoader, Loading)->
new class Checkout
errors: {}
secrets: {}
order: CurrentOrder.order
submit: ->
purchase: ->
if @paymentMethod()?.method_type == 'stripe' && !@secrets.selected_card
StripeElements.requestToken(@secrets, @submit)
else
@submit()
submit: =>
Loading.message = t 'submitting_order'
$http.put('/checkout', {order: @preprocess()}).success (data, status)=>
$http.put('/checkout.json', {order: @preprocess()}).success (data, status)=>
Navigation.go data.path
.error (response, status)=>
if response.path
@@ -53,6 +59,23 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
last_name: @order.bill_address.lastname
}
if @paymentMethod()?.method_type == 'stripe'
if @secrets.selected_card
angular.extend munged_order, {
existing_card_id: @secrets.selected_card
}
else
angular.extend munged_order.payments_attributes[0], {
source_attributes:
gateway_payment_profile_id: @secrets.token
cc_type: @secrets.cc_type
last_digits: @secrets.card.last4
month: @secrets.card.exp_month
year: @secrets.card.exp_year
first_name: @order.bill_address.firstname
last_name: @order.bill_address.lastname
save_requested_by_customer: @secrets.save_requested_by_customer
}
munged_order
shippingMethod: ->

View File

@@ -0,0 +1,41 @@
Darkswarm.factory 'CreditCard', ($injector, $rootScope, CreditCards, StripeElements, Navigation, $http, RailsFlashLoader, Loading)->
new class CreditCard
visible: false
errors: {}
secrets: {}
requestToken: =>
@setFullName()
StripeElements.requestToken(@secrets, @submit, t("saving_credit_card"))
submit: =>
params = @process_params()
$http.put('/credit_cards/new_from_token', params )
.success (data, status) =>
Loading.clear()
@reset()
CreditCards.add(data)
.error (response, status) =>
if response.path
Navigation.go response.path
else
Loading.clear()
@errors = response.errors
RailsFlashLoader.loadFlash(response.flash)
setFullName: ->
@secrets.name = "#{@secrets.first_name} #{@secrets.last_name}"
process_params: ->
{"exp_month": @secrets.card.exp_month,
"exp_year": @secrets.card.exp_year,
"last4": @secrets.card.last4,
"token": @secrets.token,
"cc_type": @secrets.cc_type}
show: => @visible = true
reset: =>
@visible = false
delete @secrets[k] for k, v of @secrets
delete @errors[k] for k, v of @errors

View File

@@ -0,0 +1,6 @@
Darkswarm.factory 'CreditCards', (savedCreditCards)->
new class CreditCard
saved: savedCreditCards
add: (card) ->
@saved.push card

View File

@@ -0,0 +1,18 @@
Darkswarm.factory "Dates", ->
new class Dates
months: [
{key: t("january"), value: "1"},
{key: t("february"), value: "2"},
{key: t("march"), value: "3"},
{key: t("april"), value: "4"},
{key: t("may"), value: "5"},
{key: t("june"), value: "6"},
{key: t("july"), value: "7"},
{key: t("august"), value: "8"},
{key: t("september"), value: "9"},
{key: t("october"), value: "10"},
{key: t("november"), value: "11"},
{key: t("december"), value: "12"},
]
years: [moment().year()..(moment().year()+15)]

View File

@@ -11,7 +11,11 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
for key, value of enterpriseAttributes
@enterprise[key] = value
create: =>
# Creates the enterprise and redirects to the about step on success.
#
# @param callback [Function] executed at the end of the operation both in
# case of success or failure.
create: (callback) =>
Loading.message = t('creating') + " " + @enterprise.name
$http(
method: "POST"
@@ -33,6 +37,7 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
else
alert(t('failed_to_create_enterprise_unknown'))
)
callback.call() if callback?
update: (step) =>
Loading.message = t('updating') + " " + @enterprise.name

View File

@@ -21,3 +21,6 @@ Darkswarm.factory 'Navigation', ($location, $window) ->
$window.location.href = path
else
$window.location.pathname = path
reload: ->
$window.location.reload()

View File

@@ -1,22 +1,25 @@
Darkswarm.factory 'Orders', (orders_by_distributor, currencyConfig, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)->
Darkswarm.factory 'Orders', (orders, shops, currencyConfig)->
new class Orders
all: orders
changeable: []
shops: shops
shopsByID: {}
currencySymbol = currencyConfig.symbol
constructor: ->
# Populate Orders.orders from json in page.
@orders_by_distributor = orders_by_distributor
@changeable_orders = []
@currency_symbol = currencyConfig.symbol
for shop in @shops
shop.orders = []
shop.balance = 0.0
@shopsByID[shop.id] = shop
for distributor in @orders_by_distributor
@findChangeableOrders(distributor.distributed_orders)
@updateRunningBalance(distributor.distributed_orders)
for order in @all by -1
shop = @shopsByID[order.shop_id]
shop.orders.unshift order
@changeable.unshift(order) if order.changes_allowed
updateRunningBalance: (orders) ->
for order, i in orders
balances = orders.slice(i,orders.length).map (o) -> parseFloat(o.outstanding_balance)
running_balance = balances.reduce (a,b) -> a+b
order.running_balance = running_balance.toFixed(2)
@updateRunningBalance(shop, order)
findChangeableOrders: (orders) ->
for order in orders when order.changes_allowed
@changeable_orders.push(order)
updateRunningBalance: (shop, order) ->
shop.balance += parseFloat(order.outstanding_balance)
order.runningBalance = shop.balance.toFixed(2)

View File

@@ -1,7 +1,18 @@
Darkswarm.factory 'RailsFlashLoader', (flash, railsFlash)->
new class RailsFlashLoader
# The 'flash' service requires type key to
# be one of: success, info, warn, error
typePairings:
success: 'success'
error: 'error'
notice: 'success'
info: 'info'
warn: 'warn'
initFlash: ->
@loadFlash railsFlash
loadFlash: (rails_flash)->
for type, message of rails_flash
type = @typePairings[type]
flash[type] = message

View File

@@ -0,0 +1,47 @@
Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
new class StripeElements
# TODO: add locale here for translations of error messages etc. from Stripe
# These are both set from the StripeElements directive
stripe: null
card: null
# New Stripe Elements method
requestToken: (secrets, submit, loading_message = t("processing_payment")) ->
return unless @stripe? && @card?
Loading.message = loading_message
cardData = @makeCardData(secrets)
@stripe.createToken(@card, cardData).then (response) =>
if(response.error)
Loading.clear()
RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"})
else
secrets.token = response.token.id
secrets.cc_type = @mapCC(response.token.card.brand)
secrets.card = response.token.card
submit()
# Maps the brand returned by Stripe to that required by activemerchant
mapCC: (ccType) ->
if ccType == 'MasterCard'
return 'master'
else if ccType == 'Visa'
return 'visa'
else if ccType == 'American Express'
return 'american_express'
else if ccType == 'Discover'
return 'discover'
else if ccType == 'JCB'
return 'jcb'
else if ccType == 'Diners Club'
return 'diners_club'
return
# It doesn't matter if any of these are nil, all are optional.
makeCardData: (secrets) ->
{'name': secrets.name,
'address1': secrets.address1,
'city': secrets.city,
'zipcode': secrets.zipcode}

View File

@@ -0,0 +1,22 @@
Darkswarm.factory 'Tabsets', ->
new class Tabsets
tabsets: []
register: (ctrl, id, selected=null) ->
if ctrl? && id?
@tabsets.push { ctrl: ctrl, id: id, selected: selected }
ctrl.select(selected) if selected?
toggle: (id, name, state=null) ->
tabset = @findTabsetByObject(id)
if tabset.selected == name
@select(tabset, null) unless state == "open"
else
@select(tabset, name) unless state == "closed"
select: (tabset, name) ->
tabset.selected = name
tabset.ctrl.select(name)
findTabsetByObject: (id) ->
(tabset for tabset in @tabsets when tabset.id == id)[0]

View File

@@ -6,8 +6,7 @@
//
//= require 'jquery'
//= require store/spree_core
//= require store/spree_frontend
//= require store/spree_auth
//= require store/spree_promo
//= require_tree .

View File

@@ -4,9 +4,8 @@
* the top of the compiled file, but it's generally better to create a new file per style scope.
*
*= require admin/spree_core
*= require admin/spree_backend
*= require admin/spree_auth
*= require admin/spree_promo
*= require shared/jquery-ui-timepicker-addon
*= require shared/textAngular

View File

@@ -0,0 +1,80 @@
@import "../../darkswarm/mixins";
.alert-box {
position: relative;
display: block;
background-color: #eff5dc;
border: 1px solid #9fc820;
color: #666;
margin-top: 1em;
margin-bottom: 1em;
@include border-radius(3px);
transition: opacity 300ms ease-out;
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
a.close {
position: absolute;
right: 5px;
top: 5px;
font-size: 1.5em;
}
&.ok {
border: 1px solid #9fc820;
background-color: #fbffee;
color: #9fc820;
font-weight: bold;
a.button {
padding: 3px 10px;
background-color: #a7c44d;
&:hover {
background-color: #9fc820;
}
}
a.close {
color: #9fc820;
}
}
&.error {
border: 1px solid #c82020;
background-color: #f5dcdc;
color: #c82020;
font-weight: bold;
a.button {
padding: 3px 10px;
background-color: #c85252;
&:hover {
background-color: #c82020;
}
}
a.close {
color: #c82020;
}
}
&.warning {
border: 1px solid #e6912e;
background-color: #fff4e6;
color: #e6912e;
font-weight: bold;
a.button {
padding: 3px 10px;
background-color: #db9350;
&:hover {
background-color: #e6912e;
}
}
a.close {
color: #e6912e;
}
}
}

View File

@@ -24,8 +24,6 @@ light: #ccc
}
}
/*.ui-dialog .ui-icon-closethick{background:url(/static/assets/dialogCloseButton.png);}*/
.ui-dialog .ui-widget-header{
background-image: none;
background-color: #ffffff;
@@ -42,21 +40,18 @@ light: #ccc
.ui-dialog .ui-corner-all{
border-radius: 8px;
}
.ui-dialog {
.ui-state-hover, .ui-state-focus{
border: none;
background: none;
color: #545454;
}
}
.ui-state-hover, .ui-widget-header .ui-state-hover, .ui-widget-content .ui-state-hover {
background-color: #ffffff;
background: none;
}
.ui-dialog-titlebar-close {
.ui-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close {
float: right;
border: none;
background: none;
&:before {
color: #000000;
font-size: 2em;
@@ -76,9 +71,18 @@ light: #ccc
display: none;
}
}
.ui-button-text {
display: none;
}
}
.ui-widget-overlay {
background: #000000;
opacity: 0.5;
position: fixed;
height: 100vh;
width: 100vw;
left: 0px;
top: 0px;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,27 +1,5 @@
@import "../darkswarm/mixins";
.alert-box {
position: relative;
display: block;
background-color: #eff5dc;
border: 1px solid #9fc820;
color: #666;
margin-top: 1em;
margin-bottom: 1em;
@include border-radius(3px);
transition: opacity 300ms ease-out;
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
a.close {
position: absolute;
right: 5px;
top: 0px;
font-size: 1.5em;
}
}
.dashboard_item.single-ent {
.header {
padding: 0.77778em 1.33333em 0.77778em 0.77778em;

View File

@@ -43,6 +43,13 @@ input.red {
margin-right: 5px;
}
a.button.red {
&:not(:hover) {
color: #fff;
background-color: #DA5354;
}
}
input.orange {
background-color: #FF9848;
margin-right: 5px;

View File

@@ -69,4 +69,10 @@ table#listing_products.bulk {
margin-bottom: 0.5em;
}
}
td.left-actions {
a.view-variants, a.add-variant {
cursor: pointer;
}
}
}

View File

@@ -5,9 +5,32 @@
color: #4a4a4a;
}
.credit_cards {
.saved_cards {
table {
width: 100%;
}
}
.saved_cards, .no_cards {
margin-bottom: 1em;
}
.new_card {
opacity: 0;
-webkit-transition: opacity 0.4s linear;
transition: opacity 0.4s linear;
&.visible {
opacity: 1;
}
input.ng-invalid {
margin-bottom: 0px;
}
}
}
.orders {
margin-top: 50px;
margin-bottom: 100px;
a {
@@ -24,6 +47,10 @@
height: auto;
}
&.active_table {
margin: 0px;
}
.active_table_row {
h3 {
margin-top: 0.5em;

View File

@@ -81,3 +81,6 @@ checkout
display: inline
span.accordion-down
display: none
.error
color: #c82020

View File

@@ -0,0 +1,16 @@
stripe-elements {
margin-bottom: 15px;
display: block;
#card-element {
background: white;
box-sizing: border-box;
font-weight: 400;
padding: 0.6rem 0.5rem;
border: 1px solid #cccccc;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 0px;
height: 42px;
width: 100%;
}
}

View File

@@ -0,0 +1,71 @@
@import "typography";
@import "mixins";
@import "branding";
.tabset-ctrl {
.tab-view {
padding-top: 30px;
}
.tab {
text-align: center;
@media all and (max-width: 640px) {
text-align: left;
}
a {
@include headingFont;
background: transparent;
text-transform: uppercase;
font-size: 1.5em;
text-shadow: 0 -1px 1px #ffffff;
padding: 1em;
border: none;
@media all and (max-width: 640px) {
padding: 0.35em 0 0.65em 0;
text-shadow: none;
}
}
border-bottom: 4px solid transparent;
&:hover, &:focus, &:active {
transition: all 0.4s ease-in-out;
border-bottom: 4px solid $clr-brick-bright;
cursor: pointer;
@media all and (max-width: 640px) {
transition: none;
color: white;
background-color: $clr-brick-bright;
}
a {
color: $clr-brick-bright;
@media all and (max-width: 640px) {
color: #ffffff;
}
}
}
&.selected {
border-bottom: 4px solid $clr-brick;
@media all and (max-width: 640px) {
background-color: $clr-brick;
}
a {
color: $clr-brick;
@media all and (max-width: 640px) {
color: #ffffff;
}
}
}
}
}

View File

@@ -408,3 +408,12 @@ ul {
display: inline-block;
margin: 0px;
}
/*
* Fix overlapping table header on second page of long invoices.
* Problem description: https://github.com/openfoodfoundation/openfoodnetwork/issues/1738
* Solution: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1770#issuecomment-73530576
*/
thead { display: table-header-group }
tfoot { display: table-row-group }
tr { page-break-inside: avoid }

View File

@@ -4,9 +4,8 @@
* the top of the compiled file, but it's generally better to create a new file per style scope.
*
*= require store/spree_core
*= require store/spree_frontend
*= require store/spree_auth
*= require store/spree_promo
*= require_self
*= require_tree .

View File

@@ -0,0 +1,68 @@
module Admin
class BulkLineItemsController < Spree::Admin::BaseController
# GET /admin/bulk_line_items.json
#
def index
order_params = params[:q].andand.delete :order
orders = OpenFoodNetwork::Permissions.new(spree_current_user).editable_orders.ransack(order_params).result
line_items = OpenFoodNetwork::Permissions.new(spree_current_user).editable_line_items.where(order_id: orders).ransack(params[:q])
render_as_json line_items.result.reorder('order_id ASC, id ASC')
end
# PUT /admin/bulk_line_items/:id.json
#
def update
load_line_item
authorize_update!
# `with_lock` acquires an exclusive row lock on order so no other
# requests can update it until the transaction is commited.
# See https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/locking/pessimistic.rb#L69
# and https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE
order.with_lock do
if @line_item.update_attributes(params[:line_item])
order.update_distribution_charge!
render nothing: true, status: 204 # No Content, does not trigger ng resource auto-update
else
render json: { errors: @line_item.errors }, status: 412
end
end
end
# DELETE /admin/bulk_line_items/:id.json
#
def destroy
load_line_item
authorize! :update, order
@line_item.destroy
render nothing: true, status: 204 # No Content, does not trigger ng resource auto-update
end
private
def load_line_item
@line_item = Spree::LineItem.find(params[:id])
end
def model_class
Spree::LineItem
end
# Returns the appropriate serializer for this controller
#
# @return [Api::Admin::LineItemSerializer]
def serializer(_ams_prefix)
Api::Admin::LineItemSerializer
end
def authorize_update!
authorize! :update, order
authorize! :read, order
end
def order
@line_item.order
end
end
end

View File

@@ -0,0 +1,49 @@
require 'stripe/account_connector'
module Admin
class StripeAccountsController < Spree::Admin::BaseController
def connect
payload = params.slice(:enterprise_id)
key = Openfoodnetwork::Application.config.secret_token
url_params = { state: JWT.encode(payload, key, 'HS256'), scope: "read_write" }
redirect_to Stripe::OAuth.authorize_url(url_params)
end
def destroy
stripe_account = StripeAccount.find(params[:id])
authorize! :destroy, stripe_account
if stripe_account.deauthorize_and_destroy
flash[:success] = "Stripe account disconnected."
else
flash[:error] = "Failed to disconnect Stripe."
end
redirect_to main_app.edit_admin_enterprise_path(stripe_account.enterprise)
rescue ActiveRecord::RecordNotFound
flash[:error] = "Failed to disconnect Stripe."
redirect_to spree.admin_path
end
def status
return render json: { status: :stripe_disabled } unless Spree::Config.stripe_connect_enabled
stripe_account = StripeAccount.find_by_enterprise_id(params[:enterprise_id])
return render json: { status: :account_missing } unless stripe_account
authorize! :status, stripe_account
begin
status = Stripe::Account.retrieve(stripe_account.stripe_user_id)
attrs = %i[id business_name charges_enabled]
render json: status.to_hash.slice(*attrs).merge( status: :connected)
rescue Stripe::APIError
render json: { status: :access_revoked }
end
end
private
def model_class
StripeAccount
end
end
end

View File

@@ -0,0 +1,40 @@
# This controller is used by super admin users to update the settings the app is using
module Admin
class StripeConnectSettingsController < Spree::Admin::BaseController
StripeConnectSettings = Struct.new(:stripe_connect_enabled)
before_filter :load_settings, only: [:edit]
def edit
return @stripe_account = { status: :empty_api_key } if Stripe.api_key.blank?
attrs = %i[id business_name charges_enabled]
@obfuscated_secret_key = obfuscated_secret_key
@stripe_account = Stripe::Account.retrieve.to_hash.slice(*attrs).merge(status: :ok)
rescue Stripe::AuthenticationError
@stripe_account = { status: :auth_fail }
end
def update
Spree::Config.set(params[:settings])
resource = t('admin.controllers.stripe_connect_settings.resource')
flash[:success] = t(:successfully_updated, :resource => resource)
redirect_to_edit
end
private
def load_settings
@settings = StripeConnectSettings.new(Spree::Config[:stripe_connect_enabled])
end
def redirect_to_edit
redirect_to main_app.edit_admin_stripe_connect_settings_path
end
def obfuscated_secret_key
key = Stripe.api_key
key.first(8) + "****" + key.last(4)
end
end
end

View File

@@ -57,7 +57,7 @@ class ApplicationController < ActionController::Base
def enable_embedded_shopfront
whitelist = Spree::Config[:embedded_shopfronts_whitelist]
return unless Spree::Config[:enable_embedded_shopfronts] && whitelist.present?
return if request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test?
return if request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test? && !Rails.env.development?
response.headers.delete 'X-Frame-Options'
response.headers['Content-Security-Policy'] = "frame-ancestors #{whitelist}"

View File

@@ -15,6 +15,10 @@ class CheckoutController < Spree::CheckoutController
include EnterprisesHelper
def edit
# This is only required because of spree_paypal_express. If we implement
# a version of paypal that uses this controller, and more specifically
# the #update_failed method, then we can remove this call
restart_checkout
end
def update
@@ -26,28 +30,29 @@ class CheckoutController < Spree::CheckoutController
return if redirect_to_paypal_express_form_if_needed
end
if advance_order_state(@order)
state_callback(:after)
next if advance_order_state(@order)
if @order.errors.present?
flash[:error] = @order.errors.full_messages.to_sentence
else
if @order.errors.present?
flash[:error] = @order.errors.full_messages.to_sentence
else
flash[:error] = t(:payment_processing_failed)
end
update_failed
return
flash[:error] = t(:payment_processing_failed)
end
update_failed
return
end
if @order.state == "complete" || @order.completed?
set_default_bill_address
set_default_ship_address
flash[:success] = t(:order_processed_successfully)
ResetOrderService.new(self, current_order).call
session[:access_token] = current_order.token
flash[:notice] = t(:order_processed_successfully)
respond_to do |format|
format.html do
respond_with(@order, :location => order_path(@order))
end
format.js do
format.json do
render json: {path: order_path(@order)}, status: 200
end
end
@@ -59,6 +64,13 @@ class CheckoutController < Spree::CheckoutController
end
end
# Clears the cached order. Required for #current_order to return a new order
# to serve as cart. See https://github.com/spree/spree/blob/1-3-stable/core/lib/spree/core/controller_helpers/order.rb#L14
# for details.
def expire_current_order
session[:order_id] = nil
@current_order = nil
end
private
@@ -111,6 +123,9 @@ class CheckoutController < Spree::CheckoutController
if (params[:order][:payments_attributes])
params[:order][:payments_attributes].first[:amount] = @order.total
end
if params[:order][:existing_card_id]
construct_saved_card_attributes
end
params[:order]
end
@@ -126,11 +141,12 @@ class CheckoutController < Spree::CheckoutController
def update_failed
clear_ship_address
restart_checkout
respond_to do |format|
format.html do
render :edit
end
format.js do
format.json do
render json: {errors: @order.errors, flash: flash.to_hash}.to_json, status: 400
end
end
@@ -144,6 +160,15 @@ class CheckoutController < Spree::CheckoutController
end
end
def restart_checkout
return if @order.state == 'cart'
@order.restart_checkout! # resets state to 'cart'
@order.update_attributes!(shipping_method_id: nil)
@order.shipments.with_state(:pending).destroy_all
@order.payments.with_state(:checkout).destroy_all
@order.reload
end
def skip_state_validation?
true
end
@@ -154,7 +179,7 @@ class CheckoutController < Spree::CheckoutController
raise_insufficient_quantity and return if @order.insufficient_stock_lines.present?
redirect_to main_app.shop_path and return if @order.completed?
before_address
state_callback(:before)
setup_for_current_state
end
def before_address
@@ -172,14 +197,6 @@ class CheckoutController < Spree::CheckoutController
@order.ship_address ||= customer_preferred_ship_address || preferred_ship_address || last_used_ship_address || Spree::Address.default
end
def after_payment
# object_params sets the payment amount to the order total, but it does this before
# the shipping method is set. This results in the customer not being charged for their
# order's shipping. To fix this, we refresh the payment amount here.
@order.update_totals
@order.payments.first.update_attribute :amount, @order.total
end
# Overriding Spree's methods
def raise_insufficient_quantity
respond_to do |format|
@@ -202,4 +219,28 @@ class CheckoutController < Spree::CheckoutController
render json: {path: spree.paypal_express_url(payment_method_id: payment_method.id)}, status: 200
true
end
def construct_saved_card_attributes
existing_card_id = params[:order].delete(:existing_card_id)
return if existing_card_id.blank?
credit_card = Spree::CreditCard.find(existing_card_id)
if credit_card.try(:user_id).blank? || credit_card.user_id != spree_current_user.try(:id)
raise Spree::Core::GatewayError, I18n.t(:invalid_credit_card)
end
# Not currently supported but maybe we should add it...?
credit_card.verification_value = params[:cvc_confirm] if params[:cvc_confirm].present?
params[:order][:payments_attributes].first[:source] = credit_card
params[:order][:payments_attributes].first.delete :source_attributes
end
def rescue_from_spree_gateway_error(error)
flash[:error] = t(:spree_gateway_error_flash_for_checkout, error: error.message)
respond_to do |format|
format.html { render :edit }
format.json { render json: { flash: flash.to_hash }, status: 400 }
end
end
end

View File

@@ -15,10 +15,11 @@ class EnterprisesController < BaseController
respond_to :js, only: :permalink_checker
def relatives
set_enterprise
respond_to do |format|
format.json do
enterprise = Enterprise.find(params[:id])
enterprises = enterprise.andand.relatives.andand.activated
enterprises = @enterprise.andand.relatives.andand.activated
render(json: enterprises,
each_serializer: Api::EnterpriseSerializer,
data: OpenFoodNetwork::EnterpriseInjectionData.new)
@@ -40,6 +41,10 @@ class EnterprisesController < BaseController
private
def set_enterprise
@enterprise = Enterprise.find_by_id(params[:id])
end
def clean_permalink
params[:permalink] = params[:permalink].parameterize
end

View File

@@ -6,6 +6,8 @@ class GroupsController < BaseController
end
def show
enable_embedded_shopfront
@hide_menu = true if @shopfront_layout == 'embedded'
@group = EnterpriseGroup.find_by_permalink(params[:id]) || EnterpriseGroup.find(params[:id])
end
end

View File

@@ -2,21 +2,6 @@ Spree::Admin::LineItemsController.class_eval do
prepend_before_filter :load_order, except: :index
around_filter :apply_enterprise_fees_with_lock, only: :update
respond_to :json
# TODO make updating line items faster by creating a bulk update method
def index
respond_to do |format|
format.json do
order_params = params[:q].andand.delete :order
orders = OpenFoodNetwork::Permissions.new(spree_current_user).editable_orders.ransack(order_params).result
line_items = OpenFoodNetwork::Permissions.new(spree_current_user).editable_line_items.where(order_id: orders).ransack(params[:q])
render_as_json line_items.result.reorder('order_id ASC, id ASC')
end
end
end
def create
variant = Spree::Variant.find(params[:line_item][:variant_id])
OpenFoodNetwork::ScopeVariantToHub.new(@order.distributor).scope(variant)
@@ -34,9 +19,30 @@ Spree::Admin::LineItemsController.class_eval do
end
end
# TODO: simplify this, 3 formats per action is too much
# we need `js` format for admin/orders/edit (jquery-rails gem)
# we don't know if `html` format is needed
def update
respond_to do |format|
format.html { render_order_form }
format.js {
if @line_item.update_attributes(params[:line_item])
render nothing: true, status: 204 # No Content, does not trigger ng resource auto-update
else
render json: { errors: @line_item.errors }, status: 412
end
}
end
end
private
def render_order_form
respond_to do |format|
format.html { render partial: 'spree/admin/orders/form', locals: {order: @order.reload} }
end
end
def load_order
@order = Spree::Order.find_by_number!(params[:order_id])
authorize! :update, @order

View File

@@ -4,11 +4,7 @@ Spree::Admin::OrdersController.class_eval do
include OpenFoodNetwork::SpreeApiKeyLoader
helper CheckoutHelper
before_filter :load_spree_api_key, :only => :bulk_management
# We need to add expections for collection actions other than :index here
# because spree_auth_devise causes load_order to be called, which results
# in an auth failure as the @order object is nil for collection actions
before_filter :check_authorization, except: [:bulk_management, :managed]
before_filter :load_order, only: %i[show edit update fire resend invoice print]
before_filter :load_distribution_choices, only: [:new, :edit, :update]
@@ -83,7 +79,7 @@ Spree::Admin::OrdersController.class_eval do
template = if Spree::Config.invoice_style2? then "spree/admin/orders/invoice2" else "spree/admin/orders/invoice" end
pdf = render_to_string pdf: "invoice-#{@order.number}.pdf", template: template, formats: [:html], encoding: "UTF-8"
Spree::OrderMailer.invoice_email(@order.id, pdf).deliver
flash[:success] = t(:invoice_email_sent)
flash[:success] = t('admin.orders.invoice_email_sent')
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end

View File

@@ -1,6 +1,7 @@
module Spree
module Admin
PaymentMethodsController.class_eval do
before_filter :restrict_stripe_account_change, only: [:update]
before_filter :force_environment, only: [:create, :update]
skip_before_filter :load_resource, only: [:show_provider_preferences]
before_filter :load_hubs, only: [:new, :edit, :update]
@@ -57,12 +58,30 @@ module Spree
else
@providers = Gateway.providers.reject{ |p| p.name.include? "Bogus" }.sort{|p1, p2| p1.name <=> p2.name }
end
@providers.reject!{ |p| p.name.ends_with? "StripeConnect" } unless show_stripe?
@calculators = PaymentMethod.calculators.sort_by(&:name)
end
def load_hubs
@hubs = Enterprise.managed_by(spree_current_user).is_distributor.sort_by!{ |d| [(@payment_method.has_distributor? d) ? 0 : 1, d.name] }
end
# Show Stripe as an option if enabled, or if the
# current payment_method is already a Stripe method
def show_stripe?
Spree::Config.stripe_connect_enabled || @payment_method.try(:type) == "Spree::Gateway::StripeConnect"
end
def restrict_stripe_account_change
return unless @payment_method
return unless @payment_method.type == "Spree::Gateway::StripeConnect"
return unless @payment_method.preferred_enterprise_id.andand > 0
@stripe_account_holder = Enterprise.find(@payment_method.preferred_enterprise_id)
return if spree_current_user.enterprises.include? @stripe_account_holder
params[:payment_method][:preferred_enterprise_id] = @stripe_account_holder.id
end
end
end
end

View File

@@ -1,21 +1,32 @@
Spree::Admin::PaymentsController.class_eval do
# When a user fires an event, take them back to where they came from
# Responder: http://guides.spreecommerce.com/developer/logic.html#overriding-controller-action-responses
# For some strange reason, adding PaymentsController.class_eval will cause gems/spree/app/controllers/spree/admin/payments_controller.rb:37 to error:
# payments_url not defined.
# This could be fixed by replacing line 37 with:
# respond_with(@payment, location: admin_order_payments_url) { |format| format.html { redirect_to admin_order_payments_path(@order) } }
respond_override :fire => { :html => { :success => lambda {
redirect_to request.referer # Keeps any filter and sort prefs
} } }
append_before_filter :filter_payment_methods
# When a user fires an event, take them back to where they came from
# (we can't use respond_override because Spree no longer uses respond_with)
def fire
event = params[:e]
return unless event && @payment.payment_source
# Because we have a transition method also called void, we do this to avoid conflicts.
event = "void_transaction" if event == "void"
if @payment.send("#{event}!")
flash[:success] = t(:payment_updated)
else
flash[:error] = t(:cannot_perform_operation)
end
rescue Spree::Core::GatewayError => ge
flash[:error] = ge.message
ensure
redirect_to request.referer
end
private
# Only show payments for the order's distributor
def filter_payment_methods
@payment_methods = @payment_methods.select{ |pm| pm.has_distributor? @order.distributor}
@payment_method ||= @payment_methods.first
end
end

View File

@@ -8,9 +8,6 @@ Spree::Admin::ProductsController.class_eval do
before_filter :load_spree_api_key, :only => [:bulk_edit, :variant_overrides]
before_filter :strip_new_properties, only: [:create, :update]
respond_to :json, :only => :clone
respond_override create: { html: {
success: lambda {
if params[:button] == "add_another"
@@ -22,7 +19,6 @@ Spree::Admin::ProductsController.class_eval do
failure: lambda {
render :new
} } }
#respond_override :clone => { :json => {:success => lambda { redirect_to bulk_index_admin_products_url+"?q[id_eq]=#{@new.id}" } } }
def product_distributions
end

View File

@@ -37,6 +37,17 @@ Spree::Api::ProductsController.class_eval do
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

View File

@@ -32,8 +32,4 @@ Spree::CheckoutController.class_eval do
@order.bill_address ||= preferred_bill_address || last_used_bill_address || Spree::Address.default
@order.ship_address ||= preferred_ship_address || last_used_ship_address || nil
end
def after_complete
reset_order
end
end

View File

@@ -0,0 +1,69 @@
module Spree
class CreditCardsController < BaseController
def new_from_token
# A new Customer is created for every credit card (same as via ActiveMerchant)
# Note that default_source is the card represented by the token
@customer = create_customer(params[:token])
@credit_card = build_card_from(stored_card_attributes)
if @credit_card.save
render json: @credit_card, serializer: ::Api::CreditCardSerializer, status: :ok
else
message = t(:card_could_not_be_saved)
render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout, error: message) } }, status: 400
end
rescue Stripe::CardError => e
return render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout, error: e.message) } }, status: 400
end
def destroy
@credit_card = Spree::CreditCard.find_by_id(params[:id])
if @credit_card
authorize! :destroy, @credit_card
destroy_at_stripe
end
# Using try because we may not have a card here
if @credit_card.try(:destroy)
flash[:success] = I18n.t(:card_has_been_removed, number: "x-#{@credit_card.last_digits}")
else
flash[:error] = I18n.t(:card_could_not_be_removed)
end
redirect_to account_path(anchor: 'cards')
rescue Stripe::CardError
flash[:error] = I18n.t(:card_could_not_be_removed)
redirect_to account_path(anchor: 'cards')
end
private
# Currently can only destroy the whole customer object
def destroy_at_stripe
stripe_customer = Stripe::Customer.retrieve(@credit_card.gateway_customer_profile_id)
stripe_customer.delete if stripe_customer
end
def create_customer(token)
Stripe::Customer.create(email: spree_current_user.email, source: token)
end
def stored_card_attributes
return {} unless @customer.try(:default_source)
{
month: params[:exp_month],
year: params[:exp_year],
last_digits: params[:last4],
gateway_payment_profile_id: @customer.default_source,
gateway_customer_profile_id: @customer.id,
cc_type: params[:cc_type]
}
end
def build_card_from(attrs)
card = Spree::CreditCard.new(attrs)
# Can't mass assign user:
card.user_id = spree_current_user.id
card
end
end
end

View File

@@ -1,21 +1,44 @@
Spree::PaypalController.class_eval do
include CheckoutHelper
after_filter :reset_order_when_complete, only: :confirm
before_filter :enable_embedded_shopfront
before_filter :destroy_orphaned_paypal_payments, only: :confirm
after_filter :reset_order_when_complete, only: :confirm
def cancel
flash[:notice] = t('flash.cancel', :scope => 'paypal')
flash[:notice] = Spree.t('flash.cancel', :scope => 'paypal')
redirect_to main_app.checkout_path
end
# Clears the cached order. Required for #current_order to return a new order
# to serve as cart. See https://github.com/spree/spree/blob/1-3-stable/core/lib/spree/core/controller_helpers/order.rb#L14
# for details.
def expire_current_order
session[:order_id] = nil
@current_order = nil
end
private
def reset_order_when_complete
if current_order.complete?
flash[:success] = t(:order_processed_successfully)
reset_order
flash[:notice] = t(:order_processed_successfully)
ResetOrderService.new(self, current_order).call
session[:access_token] = current_order.token
end
end
# See #1074 and #1837 for more detail on why we need this
# An 'orphaned' Spree::Payment is created for every call to CheckoutController#update
# for orders that are processed using a Spree::Gateway::PayPalExpress payment method
# These payments are 'orphaned' because they are never used by the spree_paypal_express gem
# which creates a brand new Spree::Payment from scratch in PayPalController#confirm
# However, the 'orphaned' payments are useful when applying a transaction fee, because the fees
# need to be calculated before the order details are sent to PayPal for confirmation
# This is our best hook for removing the orphaned payments at an appropriate time. ie. after
# the payment details have been confirmed, but before any payments have been processed
def destroy_orphaned_paypal_payments
return unless payment_method.is_a?(Spree::Gateway::PayPalExpress)
orphaned_payments = current_order.payments.where(payment_method_id: payment_method.id, source_id: nil)
orphaned_payments.each(&:destroy)
end
end

View File

@@ -2,4 +2,14 @@ Spree::UsersController.class_eval do
layout 'darkswarm'
before_filter :enable_embedded_shopfront
# Override of spree_auth_devise default
# Ignores invoice orders, only order where state: 'complete'
def show
@orders = @user.orders.where(state: 'complete').order('completed_at desc')
return unless Spree::Config.accounts_distributor_id
@orders = @orders.where('distributor_id != ?', Spree::Config.accounts_distributor_id)
end
end

View File

@@ -0,0 +1,20 @@
require 'stripe/account_connector'
module Stripe
class CallbacksController < BaseController
def index
connector = Stripe::AccountConnector.new(spree_current_user, params)
if connector.create_account
flash[:success] = t('admin.controllers.enterprises.stripe_connect_success')
elsif connector.connection_cancelled_by_user?
flash[:notice] = t('admin.controllers.enterprises.stripe_connect_cancelled')
else
flash[:error] = t('admin.controllers.enterprises.stripe_connect_fail')
end
redirect_to main_app.edit_admin_enterprise_path(connector.enterprise, anchor: 'payment_methods')
rescue Stripe::StripeError => e
render text: e.message, status: 500
end
end
end

View File

@@ -0,0 +1,38 @@
require 'stripe/webhook_handler'
module Stripe
class WebhooksController < BaseController
protect_from_forgery except: :create
before_filter :verify_webhook
# POST /stripe/webhook
def create
handler = WebhookHandler.new(@event)
result = handler.handle
render nothing: true, status: status_mappings[result] || 200
end
private
def verify_webhook
payload = request.raw_post
signature = request.headers["HTTP_STRIPE_SIGNATURE"]
@event = Webhook.construct_event(payload, signature, Stripe.endpoint_secret)
rescue JSON::ParserError
render nothing: true, status: 400
rescue Stripe::SignatureVerificationError
render nothing: true, status: 401
end
# Stripe interprets a 4xx or 3xx response as a failure to receive the webhook,
# and will stop sending events if too many of either of these are returned.
def status_mappings
{
success: 200, # The event was handled successfully
unknown: 202, # The event was of an unknown type
ignored: 204 # No action was taken in response to the event
}
end
end
end

View File

@@ -20,4 +20,10 @@ module ApplicationHelper
super
end
end
def body_classes
classes = []
classes << "off-canvas" unless @hide_menu
classes << @shopfront_layout
end
end

View File

@@ -104,20 +104,6 @@ module CheckoutHelper
render "shared/validated_select", name: name, path: path, options: options, attributes: attributes
end
def reset_order
distributor = current_order.distributor
token = current_order.token
session[:order_id] = nil
@current_order = nil
current_order(true)
current_order.set_distributor!(distributor)
current_order.tokenized_permission.token = token
current_order.tokenized_permission.save!
session[:access_token] = token
end
def payment_method_price(method, order)
price = method.compute_amount(order)
if price == 0

View File

@@ -1,3 +1,5 @@
require 'open_food_network/available_payment_method_filter'
module EnterprisesHelper
def current_distributor
@current_distributor ||= current_order(false).andand.distributor
@@ -22,6 +24,9 @@ module EnterprisesHelper
return [] unless current_distributor.present?
payment_methods = current_distributor.payment_methods.available(:front_end).all
filter = OpenFoodNetwork::AvailablePaymentMethodFilter.new
filter.filter!(payment_methods)
applicator = OpenFoodNetwork::TagRuleApplicator.new(current_distributor, "FilterPaymentMethods", current_customer.andand.tag_list)
applicator.filter!(payment_methods)

View File

@@ -1,7 +1,16 @@
module I18nHelper
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
# Save a given locale
if params[:locale] && Rails.application.config.i18n.available_locales.include?(params[:locale])
spree_current_user.update_attributes!(locale: params[:locale]) if spree_current_user
cookies[:locale] = params[:locale]
end
# After logging in, check if the user chose a locale before
if spree_current_user && spree_current_user.locale.nil? && cookies[:locale]
spree_current_user.update_attributes!(locale: params[:locale])
end
I18n.locale = spree_current_user.andand.locale || cookies[:locale] || I18n.default_locale
end
end

View File

@@ -64,9 +64,21 @@ module InjectionHelper
render partial: "json/injection_ams", locals: {name: 'enterpriseAttributes', json: "#{@enterprise_attributes.to_json}"}
end
def inject_orders_by_distributor
data_array = spree_current_user.orders_by_distributor
inject_json_ams "orders_by_distributor", data_array, Api::OrdersByDistributorSerializer
def inject_orders
inject_json_ams "orders", @orders.all, Api::OrderSerializer
end
def inject_shops
shops = Enterprise.where(id: @orders.pluck(:distributor_id).uniq)
inject_json_ams "shops", shops.all, Api::ShopForOrdersSerializer
end
def inject_saved_credit_cards
if spree_current_user
data = spree_current_user.credit_cards.with_payment_profile.all
end
inject_json_ams "savedCreditCards", data, Api::CreditCardSerializer
end
def inject_json(name, partial, opts = {})
@@ -89,5 +101,4 @@ module InjectionHelper
@enterprise_injection_data ||= OpenFoodNetwork::EnterpriseInjectionData.new
{data: @enterprise_injection_data}
end
end

View File

@@ -22,7 +22,6 @@ module Spree
link_to_with_icon('icon-trash', name, '#', html_options) + f.hidden_field(:_destroy)
end
end
end
end

View File

@@ -71,7 +71,7 @@ class BillablePeriod < ActiveRecord::Base
source: self,
originator: nil, # enterprise.package
mandatory: true,
locked: false
state: 'closed'
}
end
end

View File

@@ -42,6 +42,7 @@ class Enterprise < ActiveRecord::Base
has_many :billable_periods
has_many :inventory_items
has_many :tag_rules
has_one :stripe_account, dependent: :destroy
delegate :latitude, :longitude, :city, :state_name, :to => :address
@@ -66,7 +67,6 @@ class Enterprise < ActiveRecord::Base
supports_s3 :logo
supports_s3 :promo_image
validates :name, presence: true
validate :name_is_unique
validates :sells, presence: true, inclusion: {in: SELLS}
@@ -78,7 +78,6 @@ class Enterprise < ActiveRecord::Base
validate :enforce_ownership_limit, if: lambda { owner_id_changed? && !owner_id.nil? }
validates_length_of :description, :maximum => 255
before_save :confirmation_check, if: lambda { email_changed? }
before_validation :initialize_permalink, if: lambda { permalink.nil? }
@@ -95,7 +94,6 @@ class Enterprise < ActiveRecord::Base
after_rollback :restore_permalink
scope :by_name, order('name')
scope :visible, where(visible: true)
scope :confirmed, where('confirmed_at IS NOT NULL')

View File

@@ -1,4 +1,6 @@
class EnterpriseFee < ActiveRecord::Base
include Spree::Core::CalculatedAdjustments
belongs_to :enterprise
belongs_to :tax_category, class_name: 'Spree::TaxCategory', foreign_key: 'tax_category_id'
@@ -14,9 +16,6 @@ class EnterpriseFee < ActiveRecord::Base
# coordinator_fees and exchange_fees
calculated_adjustments
attr_accessible :enterprise_id, :fee_type, :name, :tax_category_id, :calculator_type, :inherits_tax_category
FEE_TYPES = %w(packing transport admin sales fundraising)
@@ -54,19 +53,6 @@ class EnterpriseFee < ActiveRecord::Base
order.adjustments.where(originator_type: 'EnterpriseFee').destroy_all
end
# Create an adjustment that starts as locked. Preferable to making an adjustment and locking it since
# the unlocked adjustment tends to get hit by callbacks before we have a chance to lock it.
def create_locked_adjustment(label, target, calculable, mandatory=false)
amount = compute_amount(calculable)
return if amount == 0 && !mandatory
target.adjustments.create({ :amount => amount,
:source => calculable,
:originator => self,
:label => label,
:mandatory => mandatory,
:locked => true}, :without_protection => true)
end
private

View File

@@ -17,7 +17,7 @@ class ProductDistribution < ActiveRecord::Base
end
def create_adjustment_for(line_item)
a = enterprise_fee.create_locked_adjustment(adjustment_label_for(line_item), line_item.order, line_item, true)
a = enterprise_fee.create_adjustment(adjustment_label_for(line_item), line_item.order, line_item, true)
AdjustmentMetadata.create! adjustment: a, enterprise: enterprise_fee.enterprise, fee_name: enterprise_fee.name, fee_type: enterprise_fee.fee_type, enterprise_role: 'distributor'
end

View File

@@ -1,7 +1,7 @@
class AbilityDecorator
include CanCan::Ability
# All abilites are allocated from this initialiser, currently in 5 chunks.
# All abilites are allocated from this initialiser.
# Spree also defines other abilities.
def initialize(user)
add_shopping_abilities user
@@ -56,9 +56,14 @@ class AbilityDecorator
user == item.order.user &&
item.order.changes_allowed?
end
can [:cancel], Spree::Order do |order|
order.user == user
end
can [:destroy], Spree::CreditCard do |credit_card|
credit_card.user == user
end
end
# New users can create an enterprise, and gain other permissions from doing this.
@@ -118,12 +123,16 @@ class AbilityDecorator
can [:admin, :bulk_update], ColumnPreference do |column_preference|
column_preference.user == user
end
can [:admin, :connect, :status, :destroy], StripeAccount do |stripe_account|
user.enterprises.include? stripe_account.enterprise
end
end
def add_product_management_abilities(user)
# Enterprise User can only access products that they are a supplier for
can [:create], Spree::Product
can [:admin, :read, :update, :product_distributions, :bulk_edit, :bulk_update, :clone, :delete, :destroy], Spree::Product do |product|
can [:admin, :read, :update, :product_distributions, :seo, :group_buy_options, :bulk_edit, :bulk_update, :clone, :delete, :destroy], Spree::Product do |product|
OpenFoodNetwork::Permissions.new(user).managed_product_enterprises.include? product.supplier
end
@@ -193,6 +202,7 @@ class AbilityDecorator
end
can [:admin, :bulk_management, :managed], Spree::Order if user.admin? || user.enterprises.any?(&:is_distributor)
can [:admin , :for_line_items], Enterprise
can [:admin, :index, :create, :update, :destroy], :line_item
can [:admin, :index, :create], Spree::LineItem
can [:destroy, :update], Spree::LineItem do |item|
order = item.order

View File

@@ -39,4 +39,7 @@ Spree::AppConfiguration.class_eval do
# Invoices & Receipts
preference :invoice_style2?, :boolean, default: false
preference :enable_receipt_printing?, :boolean, default: false
# Stripe Connect
preference :stripe_connect_enabled, :boolean, default: false
end

View File

@@ -0,0 +1,28 @@
Spree::CreditCard.class_eval do
# Allows user to submit these attributes with checkout request
# Required to be able to correctly store details for token-based charges
# Obviously can be removed once we are using strong params
attr_accessible :cc_type, :last_digits
# For holding customer preference in memory
attr_accessible :save_requested_by_customer
attr_writer :save_requested_by_customer
# Should be able to remove once we reach Spree v2.2.0
# https://github.com/spree/spree/commit/411010f3975c919ab298cb63962ee492455b415c
belongs_to :payment_method
belongs_to :user
# Allows us to use a gateway_payment_profile_id to store Stripe Tokens
# Should be able to remove once we reach Spree v2.2.0
# Commit: https://github.com/spree/spree/commit/5a4d690ebc64b264bf12904a70187e7a8735ef3f
# See also: https://github.com/spree/spree_gateway/issues/111
def has_payment_profile? # rubocop:disable Style/PredicateName
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?
end
def save_requested_by_customer?
!!@save_requested_by_customer
end
end

View File

@@ -0,0 +1,106 @@
require 'stripe/profile_storer'
module Spree
class Gateway
class StripeConnect < Gateway
preference :enterprise_id, :integer
validate :ensure_enterprise_selected
attr_accessible :preferred_enterprise_id
CARD_TYPE_MAPPING = {
'American Express' => 'american_express',
'Diners Club' => 'diners_club',
'Visa' => 'visa'
}.freeze
def method_type
'stripe'
end
def provider_class
ActiveMerchant::Billing::StripeGateway
end
def payment_profiles_supported?
true
end
def stripe_account_id
StripeAccount.find_by_enterprise_id(preferred_enterprise_id).andand.stripe_user_id
end
def purchase(money, creditcard, gateway_options)
provider.purchase(*options_for_purchase_or_auth(money, creditcard, gateway_options))
rescue Stripe::StripeError => e
# This will be an error caused by generating a stripe token
failed_activemerchant_billing_response(e.message)
end
def void(response_code, _creditcard, gateway_options)
gateway_options[:stripe_account] = stripe_account_id
provider.void(response_code, gateway_options)
end
def create_profile(payment)
return unless payment.source.gateway_customer_profile_id.nil?
profile_storer = Stripe::ProfileStorer.new(payment, provider)
profile_storer.create_customer_from_token
end
private
# In this gateway, what we call 'secret_key' is the 'login'
def options
options = super
options.merge(:login => Stripe.api_key)
end
def options_for_purchase_or_auth(money, creditcard, gateway_options)
options = {}
options[:description] = "Spree Order ID: #{gateway_options[:order_id]}"
options[:currency] = gateway_options[:currency]
options[:stripe_account] = stripe_account_id
creditcard = token_from_card_profile_ids(creditcard)
[money, creditcard, options]
end
def update_source!(source)
source.cc_type = CARD_TYPE_MAPPING[source.cc_type] if CARD_TYPE_MAPPING.include?(source.cc_type)
source
end
def token_from_card_profile_ids(creditcard)
token_or_card_id = creditcard.gateway_payment_profile_id
customer = creditcard.gateway_customer_profile_id
return nil if token_or_card_id.blank?
# Assume the gateway_payment_profile_id is a token generated by StripeJS
return token_or_card_id if customer.blank?
# Assume the gateway_payment_profile_id is a Stripe card_id
# So generate a new token, using the customer_id and card_id
tokenize_instance_customer_card(customer, token_or_card_id)
end
def tokenize_instance_customer_card(customer, card)
token = Stripe::Token.create({card: card, customer: customer}, stripe_account: stripe_account_id)
token.id
end
def failed_activemerchant_billing_response(error_message)
ActiveMerchant::Billing::Response.new(false, error_message)
end
def ensure_enterprise_selected
return if preferred_enterprise_id.andand > 0
errors.add(:stripe_account_owner, I18n.t(:error_required))
end
end
end
end

View File

@@ -60,7 +60,7 @@ Spree::LineItem.class_eval do
end
def price_with_adjustments
# EnterpriseFee#create_locked_adjustment applies adjustments on line items to their parent order,
# EnterpriseFee#create_adjustment applies adjustments on line items to their parent order,
# so line_item.adjustments returns an empty array
return 0 if quantity == 0
(price + order.adjustments.where(source_id: id).sum(&:amount) / quantity).round(2)

View File

@@ -37,7 +37,8 @@ Spree::Order.class_eval do
end
order.payment_required?
}
go_to_state :confirm, :if => lambda { |order| order.confirmation_required? }
# NOTE: :confirm step was removed because we were not actually using it
# go_to_state :confirm, :if => lambda { |order| order.confirmation_required? }
go_to_state :complete
remove_transition :from => :delivery, :to => :confirm
end
@@ -181,6 +182,10 @@ Spree::Order.class_eval do
end
def update_distribution_charge!
# `with_lock` acquires an exclusive row lock on order so no other
# requests can update it until the transaction is commited.
# See https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/locking/pessimistic.rb#L69
# and https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE
with_lock do
EnterpriseFee.clear_all_adjustments_on_order self
@@ -289,6 +294,24 @@ Spree::Order.class_eval do
complete? && distributor.andand.allow_order_changes? && order_cycle.andand.open?
end
# Override of existing Spree method. Can remove when we reach 2-0-stable
# See commit: https://github.com/spree/spree/commit/5fca58f658273451193d5711081d018c317814ed
# Allows GatewayError to show useful error messages in checkout
def process_payments!
pending_payments.each do |payment|
break if payment_total >= total
payment.process!
if payment.completed?
self.payment_total += payment.amount
end
end
rescue Spree::Core::GatewayError => e # This section changed
result = !!Spree::Config[:allow_checkout_on_gateway_error]
errors.add(:base, e.message) and return result
end
private
def shipping_address_from_distributor
@@ -344,9 +367,23 @@ Spree::Order.class_eval do
end
def update_adjustment!(adjustment)
locked = adjustment.locked
adjustment.locked = false
state = adjustment.state
adjustment.state = 'open'
adjustment.update!(self)
adjustment.locked = locked
adjustment.state = state
end
# object_params sets the payment amount to the order total, but it does this before
# the shipping method is set. This results in the customer not being charged for their
# order's shipping. To fix this, we refresh the payment amount here.
def charge_shipping_and_payment_fees!
update_totals
return unless payments.any?
payments.first.update_attribute :amount, total
end
end
Spree::Order.state_machine.after_transition to: :payment, do: :charge_shipping_and_payment_fees!
Spree::Order.state_machine.event :restart_checkout do
transition :to => :cart, unless: :completed?
end

View File

@@ -4,13 +4,13 @@ module Spree
after_save :ensure_correct_adjustment, :update_order
attr_accessible :source
def ensure_correct_adjustment
# Don't charge for invalid payments.
# PayPalExpress always creates a payment that is invalidated later.
# Unknown: What about failed payments?
if state == "invalid"
adjustment.andand.destroy
elsif adjustment
revoke_adjustment_eligibility if ['failed', 'invalid'].include?(state)
return if adjustment.try(:finalized?)
if adjustment
adjustment.originator = payment_method
adjustment.label = adjustment_label
adjustment.save
@@ -73,6 +73,15 @@ module Spree
end
end
# Import from future Spree v.2.3.0 d470b31798f37
def build_source
return if source_attributes.nil?
return unless payment_method.andand.payment_source_class
self.source = payment_method.payment_source_class.new(source_attributes)
source.payment_method_id = payment_method.id
source.user_id = order.user_id if order
end
private
@@ -81,5 +90,25 @@ module Spree
refund_amount.to_f
end
def create_payment_profile
return unless source.is_a?(CreditCard)
return unless source.try(:save_requested_by_customer?)
return unless source.number || source.gateway_payment_profile_id
return unless source.gateway_customer_profile_id.nil?
payment_method.create_profile(self)
rescue ActiveMerchant::ConnectionError => e
gateway_error e
end
# Don't charge fees for invalid or failed payments.
# This is called twice for failed payments, because the persistence of the 'failed'
# state is acheived through some trickery using an after_rollback callback on the
# payment model. See Spree::Payment#persist_invalid
def revoke_adjustment_eligibility
return unless adjustment.try(:reload)
return if adjustment.finalized?
adjustment.update_attribute(:eligible, false)
adjustment.finalize!
end
end
end

View File

@@ -1,14 +1,15 @@
Spree::PaymentMethod.class_eval do
include Spree::Core::CalculatedAdjustments
Spree::PaymentMethod::DISPLAY = [:both, :front_end, :back_end]
acts_as_taggable
has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', :class_name => 'Enterprise', association_foreign_key: 'distributor_id'
has_many :credit_cards, class_name: "Spree::CreditCard" # from Spree v.2.3.0 d470b31798f37
attr_accessible :distributor_ids, :tag_list
calculated_adjustments
after_initialize :init
validates_with DistributorsValidator
@@ -39,7 +40,10 @@ Spree::PaymentMethod.class_eval do
}
def init
self.class.calculated_adjustments unless reflections.keys.include? :calculator
unless reflections.keys.include? :calculator
self.class.include Spree::Core::CalculatedAdjustments
end
self.calculator ||= Spree::Calculator::FlatRate.new(preferred_amount: 0)
end
@@ -55,6 +59,8 @@ Spree::PaymentMethod.class_eval do
"MasterCard Internet Gateway Service (MIGS)"
when "Spree::Gateway::Pin"
"Pin Payments"
when "Spree::Gateway::StripeConnect"
"Stripe"
when "Spree::Gateway::PayPalExpress"
"PayPal Express"
else

View File

@@ -42,8 +42,8 @@ Spree::ShippingMethod.class_eval do
]
end
def available_to_order_with_distributor_check?(order, display_on=nil)
available_to_order_without_distributor_check?(order, display_on) &&
def available_to_order_with_distributor_check?(order)
available_to_order_without_distributor_check?(order) &&
self.distributors.include?(order.distributor)
end
alias_method_chain :available_to_order?, :distributor_check

View File

@@ -11,13 +11,14 @@ Spree.user_class.class_eval do
has_many :billable_periods, foreign_key: :owner_id, inverse_of: :owner
has_one :cart
has_many :customers
has_many :credit_cards
accepts_nested_attributes_for :enterprise_roles, :allow_destroy => true
accepts_nested_attributes_for :bill_address
accepts_nested_attributes_for :ship_address
attr_accessible :enterprise_ids, :enterprise_roles_attributes, :enterprise_limit, :bill_address_attributes, :ship_address_attributes
attr_accessible :enterprise_ids, :enterprise_roles_attributes, :enterprise_limit, :locale, :bill_address_attributes, :ship_address_attributes
after_create :send_signup_confirmation
validate :limit_owned_enterprises
@@ -53,32 +54,6 @@ Spree.user_class.class_eval do
owned_enterprises(:reload).size < enterprise_limit
end
# Returns Enterprise IDs for distributors that the user has shopped at
def enterprises_ordered_from
enterprise_ids = orders.where(state: :complete).map(&:distributor_id).uniq
# Exclude the accounts distributor
if Spree::Config.accounts_distributor_id
enterprise_ids = enterprise_ids.keep_if { |a| a != Spree::Config.accounts_distributor_id }
end
enterprise_ids
end
# Returns orders and their associated payments for all distributors that have been ordered from
def complete_orders_by_distributor
Enterprise
.includes(distributed_orders: { payments: :payment_method })
.where(enterprises: { id: enterprises_ordered_from },
spree_orders: { state: 'complete', user_id: id })
.order('spree_orders.completed_at DESC')
end
def orders_by_distributor
# Remove uncompleted payments as these will not be reflected in order balance
data_array = complete_orders_by_distributor.to_a
remove_payments_in_checkout(data_array)
data_array.sort! { |a, b| b.distributed_orders.length <=> a.distributed_orders.length }
end
private
def limit_owned_enterprises

View File

@@ -0,0 +1,21 @@
class StripeAccount < ActiveRecord::Base
belongs_to :enterprise
validates :stripe_user_id, :stripe_publishable_key, presence: true
validates :enterprise_id, uniqueness: true
def deauthorize_and_destroy
accounts = StripeAccount.where(stripe_user_id: stripe_user_id)
# Only deauthorize the user if it is not linked to multiple accounts
return destroy if accounts.count > 1
destroy && Stripe::OAuth.deauthorize(stripe_user_id: stripe_user_id)
rescue Stripe::OAuth::OAuthError
Bugsnag.notify(
RuntimeError.new("StripeDeauthorizeFailure"),
stripe_account: stripe_user_id,
enterprise_id: enterprise_id
)
true
end
end

View File

@@ -1,5 +1,5 @@
class TagRule::DiscountOrder < TagRule
calculated_adjustments
include Spree::Core::CalculatedAdjustments
private

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
:insert_top => "[data-hook='admin_product_form_right']",
:partial => "spree/admin/products/group_buy_form",
:name => "add_group_buy_to_admin_product_edit",
:original => '0c0e8d714989e48ee246a8253fb2b362f108621a')

View File

@@ -1,6 +1,7 @@
/ replace "div[data-hook='admin_payment_method_form_fields']"
= admin_inject_payment_method
= admin_inject_json_ams_array "admin.paymentMethods", "shops", @hubs, Api::Admin::BasicEnterpriseSerializer
%div.alpha.eleven.columns{ "ng-app" => "admin.paymentMethods", "ng-controller" => "paymentMethodCtrl" }
.row
.alpha.three.columns

View File

@@ -1,6 +0,0 @@
/ insert_bottom "[data-hook='admin_product_form_additional_fields']"
= f.field_container :notes do
= f.label :notes, t(:notes)
= f.text_area :notes, { :class => 'fullwidth', rows: 5 }
= f.error_message_on :notes

View File

@@ -1,3 +1,3 @@
/ insert_top "[data-hook='admin_product_form_right']"
/ insert_after "div[class='variant_units_form']"
= render 'spree/admin/products/primary_taxon_form', f: f

View File

@@ -1,7 +1,6 @@
/ insert_top "[data-hook='admin_product_form_right']"
/ insert_before "code[erb-loud]:contains('f.field_container :price')"
= f.field_container :supplier do
= f.label :supplier
= f.label :supplier, t(:spree_admin_supplier)
%br
= f.collection_select(:supplier_id, @producers, :id, :name, {:include_blank => true}, {:class => "select2"})
= f.error_message_on :supplier
= f.error_message_on :supplier

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