diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 86e4725518..d37e637543 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -23,10 +23,6 @@ The categories are based on https://keepachangelog.com/en/1.0.0/. --> Changelog Category: Added | Changed | Deprecated | Removed | Fixed | Security -#### How is this related to the Spree upgrade? - - #### Discourse thread diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index e4eea50ed8..fc3411e87a 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -108,7 +108,6 @@ Layout/LineLength: - lib/open_food_network/scope_variants_for_search.rb - lib/open_food_network/variant_and_line_item_naming.rb - lib/open_food_network/xero_invoices_report.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb - lib/spree/localized_number.rb - lib/spree/product_filters.rb - lib/tasks/data.rake @@ -322,6 +321,15 @@ Layout/LineLength: - spec/support/request/shop_workflow.rb - spec/support/request/web_helper.rb - spec/support/seeds.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb + - spec/controllers/base_controller2_spec.rb + - spec/features/consumer/caching/darkswarm_caching_spec.rb + - spec/models/calculator/flexi_rate_spec.rb + - spec/models/calculator/price_sack_spec.rb + - spec/models/spree/stock_item_spec.rb + - spec/requests/api/orders_spec.rb + - spec/swagger_helper.rb + - spec/views/spree/admin/payment_methods/index.html.haml_spec.rb Metrics/AbcSize: Max: 15 @@ -400,6 +408,7 @@ Metrics/AbcSize: - app/services/create_order_cycle.rb - app/services/order_cycle_form.rb - app/services/order_syncer.rb + - engines/order_management/app/services/order_management/order/updater.rb - engines/order_management/app/services/order_management/stock/estimator.rb - engines/order_management/app/services/order_management/stock/package.rb - engines/order_management/app/services/order_management/stock/packer.rb @@ -427,7 +436,9 @@ Metrics/AbcSize: - lib/open_food_network/variant_and_line_item_naming.rb - lib/open_food_network/xero_invoices_report.rb - lib/spree/api/controller_setup.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - lib/stripe/account_connector.rb - lib/tasks/enterprises.rake @@ -443,6 +454,11 @@ Metrics/AbcSize: - spec/models/product_importer_spec.rb - spec/services/order_checkout_restart_spec.rb - spec/support/performance_helper.rb + - app/controllers/application_controller.rb + - app/models/spree/order/checkout.rb + - app/models/spree/payment/processing.rb + - app/models/spree/payment.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb Metrics/BlockLength: Max: 25 @@ -461,6 +477,8 @@ Metrics/BlockLength: ] Exclude: - app/models/spree/shipment.rb + - lib/spree/core/controller_helpers/common.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/tasks/data.rake - spec/controllers/spree/admin/invoices_controller_spec.rb - spec/factories/enterprise_factory.rb @@ -479,6 +497,10 @@ Metrics/BlockLength: - spec/support/delayed_job_helper.rb - spec/support/matchers/select2_matchers.rb - spec/support/matchers/table_matchers.rb + - app/models/spree/order/checkout.rb + - app/models/spree/payment/processing.rb + - spec/requests/api/orders_spec.rb + - spec/swagger_helper.rb Metrics/CyclomaticComplexity: Max: 6 @@ -505,10 +527,14 @@ Metrics/CyclomaticComplexity: - lib/discourse/single_sign_on.rb - lib/open_food_network/bulk_coop_report.rb - lib/open_food_network/enterprise_issue_validator.rb - - lib/spree/core/controller_helpers/order_decorator.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - spec/models/product_importer_spec.rb + - app/models/spree/order/checkout.rb + - app/models/spree/payment.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb Metrics/PerceivedComplexity: Max: 7 @@ -530,10 +556,13 @@ Metrics/PerceivedComplexity: - lib/discourse/single_sign_on.rb - lib/open_food_network/bulk_coop_report.rb - lib/open_food_network/enterprise_issue_validator.rb - - lib/spree/core/controller_helpers/order_decorator.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - spec/models/product_importer_spec.rb + - app/models/spree/order/checkout.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb Metrics/MethodLength: Max: 10 @@ -596,6 +625,7 @@ Metrics/MethodLength: - app/serializers/api/cached_enterprise_serializer.rb - app/services/order_cycle_form.rb - app/services/permitted_attributes/checkout.rb + - engines/order_management/app/services/order_management/order/updater.rb - engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb - engines/order_management/app/services/order_management/stock/estimator.rb - engines/order_management/app/services/order_management/stock/package.rb @@ -626,7 +656,10 @@ Metrics/MethodLength: - lib/open_food_network/users_and_enterprises_report.rb - lib/open_food_network/xero_invoices_report.rb - lib/spree/api/controller_setup.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/auth.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - lib/stripe/profile_storer.rb - lib/tasks/data/truncate_data.rb @@ -636,7 +669,12 @@ Metrics/MethodLength: - spec/features/consumer/shopping/checkout_paypal_spec.rb - spec/features/consumer/shopping/variant_overrides_spec.rb - spec/models/product_importer_spec.rb - - spec/support/request/authentication_workflow.rb + - spec/support/request/authentication_helper.rb + - app/models/spree/order/checkout.rb + - app/models/spree/payment/processing.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_allocation_report.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb Metrics/ClassLength: Max: 100 @@ -666,6 +704,7 @@ Metrics/ClassLength: - app/serializers/api/cached_enterprise_serializer.rb - app/serializers/api/enterprise_shopfront_serializer.rb - app/services/cart_service.rb + - engines/order_management/app/services/order_management/order/updater.rb - engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb - lib/active_merchant/billing/gateways/stripe_payment_intents.rb - lib/open_food_network/bulk_coop_report.rb @@ -678,6 +717,8 @@ Metrics/ClassLength: - lib/open_food_network/permissions.rb - lib/open_food_network/users_and_enterprises_report.rb - lib/open_food_network/xero_invoices_report.rb + - app/models/spree/payment.rb + - engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb Metrics/ModuleLength: Max: 100 @@ -686,6 +727,7 @@ Metrics/ModuleLength: - app/helpers/injection_helper.rb - app/helpers/spree/admin/base_helper.rb - app/helpers/spree/admin/navigation_helper.rb + - engines/order_management/spec/services/order_management/order/updater_spec.rb - engines/order_management/spec/services/order_management/stock/package_spec.rb - engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb - engines/order_management/spec/services/order_management/subscriptions/form_spec.rb @@ -720,6 +762,8 @@ Metrics/ModuleLength: - spec/models/spree/variant_spec.rb - spec/services/permissions/order_spec.rb - spec/support/request/web_helper.rb + - app/models/spree/order/checkout.rb + - app/models/spree/payment/processing.rb Metrics/ParameterLists: Max: 5 @@ -728,3 +772,8 @@ Metrics/ParameterLists: - app/models/product_import/entry_processor.rb - lib/open_food_network/xero_invoices_report.rb - spec/features/admin/reports_spec.rb + +Lint/UselessAssignment: + Exclude: + - 'spec/**/*' + - 'lib/spree/core/controller_helpers/common.rb' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 753aaee48e..aec1f024b9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,79 +1,214 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 1400` -# on 2020-06-22 13:28:10 +0100 using RuboCop version 0.81.0. +# on 2020-08-13 16:05:53 +1000 using RuboCop version 0.81.0. # 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 # versions of RuboCop, may require this file to be generated again. -# Offense count: 139 +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: with_first_argument, with_fixed_indentation +Layout/ArgumentAlignment: + Exclude: + - 'spec/models/spree/order/checkout_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleAlignWith. +# SupportedStylesAlignWith: either, start_of_block, start_of_line +Layout/BlockAlignment: + Exclude: + - 'spec/models/spree/order/checkout_spec.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Layout/EmptyLines: + Exclude: + - 'spec/models/spree/payment_spec.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: empty_lines, no_empty_lines +Layout/EmptyLinesAroundBlockBody: + Exclude: + - 'spec/models/spree/payment_spec.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment. +Layout/ExtraSpacing: + Exclude: + - 'spec/models/spree/payment_spec.rb' + - 'spec/requests/api/orders_spec.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_brackets +Layout/FirstArrayElementIndentation: + Exclude: + - 'spec/views/spree/admin/payment_methods/index.html.haml_spec.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_braces +Layout/FirstHashElementIndentation: + Exclude: + - 'spec/models/spree/payment_spec.rb' + - 'spec/swagger_helper.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/HashAlignment: + Exclude: + - 'spec/models/spree/payment_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: normal, indented_internal_methods +Layout/IndentationConsistency: + Exclude: + - 'spec/models/spree/order/checkout_spec.rb' + +# Offense count: 26 # Cop supports --auto-correct. # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # URISchemes: http, https Layout/LineLength: - Max: 268 + Max: 409 + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineHashBraceLayout: + Exclude: + - 'spec/models/spree/payment_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator. +# SupportedStylesForExponentOperator: space, no_space +Layout/SpaceAroundOperators: + Exclude: + - 'spec/models/spree/payment_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. +# SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideBlockBraces: + Exclude: + - 'spec/models/spree/payment_spec.rb' + +# Offense count: 11 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideHashLiteralBraces: + Exclude: + - 'spec/models/spree/payment_spec.rb' + - 'spec/requests/api/orders_spec.rb' + - 'spec/services/checkout/form_data_adapter_spec.rb' + - 'spec/services/user_locale_setter_spec.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: AllowInHeredoc. +Layout/TrailingWhitespace: + Exclude: + - 'spec/controllers/base_controller2_spec.rb' + - 'spec/features/consumer/shopping/shopping_spec.rb' + - 'spec/requests/api/orders_spec.rb' # Offense count: 2 Lint/DuplicateMethods: Exclude: - 'lib/discourse/single_sign_on.rb' -# Offense count: 9 +# Offense count: 8 Lint/IneffectiveAccessModifier: Exclude: - 'app/models/column_preference.rb' - 'app/models/spree/user.rb' - 'app/services/mail_configuration.rb' - 'lib/open_food_network/feature_toggle.rb' - - 'spec/lib/open_food_network/reports/report_spec.rb' -# Offense count: 5 +# Offense count: 4 +# Cop supports --auto-correct. +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods. +Lint/UnusedMethodArgument: + Exclude: + - 'spec/views/spree/admin/payment_methods/index.html.haml_spec.rb' + +# Offense count: 3 # Configuration parameters: ContextCreatingMethods, MethodCreatingMethods. Lint/UselessAccessModifier: Exclude: - 'app/models/column_preference.rb' - 'app/services/mail_configuration.rb' - 'lib/open_food_network/feature_toggle.rb' - - 'lib/open_food_network/reports/bulk_coop_report.rb' - - 'spec/lib/open_food_network/reports/report_spec.rb' - -# Offense count: 6 -# Configuration parameters: IgnoredMethods. -Metrics/AbcSize: - Max: 37 # Offense count: 1 +Lint/UselessAssignment: + Exclude: + - 'spec/**/*' + - 'lib/spree/core/controller_helpers/common.rb' + +# Offense count: 19 +# Configuration parameters: IgnoredMethods. +Metrics/AbcSize: + Max: 126 + +# Offense count: 7 # Configuration parameters: CountComments, ExcludedMethods. # ExcludedMethods: refine Metrics/BlockLength: - Max: 27 + Max: 102 -# Offense count: 1 +# Offense count: 2 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 101 + Max: 231 -# Offense count: 1 +# Offense count: 3 # Configuration parameters: IgnoredMethods. Metrics/CyclomaticComplexity: - Max: 7 + Max: 23 -# Offense count: 6 +# Offense count: 19 # Configuration parameters: CountComments, ExcludedMethods. Metrics/MethodLength: - Max: 20 + Max: 140 -# Offense count: 1 +# Offense count: 2 # Configuration parameters: CountComments. Metrics/ModuleLength: - Max: 121 + Max: 208 -# Offense count: 8 +# Offense count: 2 +# Configuration parameters: IgnoredMethods. +Metrics/PerceivedComplexity: + Max: 24 + +# Offense count: 9 Naming/AccessorMethodName: Exclude: - 'app/controllers/spree/admin/taxonomies_controller.rb' - 'app/models/spree/adjustment_decorator.rb' - 'app/models/spree/order_decorator.rb' + - 'lib/spree/core/controller_helpers/common.rb' - 'spec/support/request/shop_workflow.rb' - 'spec/support/request/web_helper.rb' @@ -117,6 +252,15 @@ Naming/PredicateName: - 'lib/open_food_network/packing_report.rb' - 'lib/tasks/data.rake' +# Offense count: 7 +# Cop supports --auto-correct. +Rails/ActiveRecordAliases: + Exclude: + - 'spec/controllers/line_items_controller_spec.rb' + - 'spec/controllers/spree/orders_controller_spec.rb' + - 'spec/features/consumer/shopping/orders_spec.rb' + - 'spec/requests/api/orders_spec.rb' + # Offense count: 1 # Configuration parameters: EnforcedStyle. # SupportedStyles: strict, flexible @@ -124,6 +268,13 @@ Rails/Date: Exclude: - 'app/models/order_cycle.rb' +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforceForPrefixed. +Rails/Delegate: + Exclude: + - 'engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb' + # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: Whitelist. @@ -150,7 +301,7 @@ Rails/FilePath: - 'spec/serializers/api/admin/enterprise_serializer_spec.rb' - 'spec/support/downloads_helper.rb' -# Offense count: 7 +# Offense count: 9 # Cop supports --auto-correct. # Configuration parameters: Include. # Include: app/models/**/*.rb @@ -160,15 +311,17 @@ Rails/FindBy: - 'app/models/product_import/entry_processor.rb' - 'app/models/product_import/entry_validator.rb' - 'app/models/product_import/spreadsheet_data.rb' + - 'app/models/spree/shipment.rb' - 'app/models/spree/user.rb' -# Offense count: 1 +# Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: Include. # Include: app/models/**/*.rb Rails/FindEach: Exclude: - 'app/models/spree/order_decorator.rb' + - 'app/models/spree/shipment.rb' # Offense count: 5 # Configuration parameters: Include. @@ -180,7 +333,7 @@ Rails/HasAndBelongsToMany: - 'app/models/spree/concerns/payment_method_distributors.rb' - 'app/models/spree/line_item_decorator.rb' -# Offense count: 25 +# Offense count: 26 # Configuration parameters: Include. # Include: app/models/**/*.rb Rails/HasManyOrHasOneDependent: @@ -192,6 +345,7 @@ Rails/HasManyOrHasOneDependent: - 'app/models/spree/order_decorator.rb' - 'app/models/spree/payment_method_decorator.rb' - 'app/models/spree/property.rb' + - 'app/models/spree/shipment.rb' - 'app/models/spree/shipping_method_decorator.rb' - 'app/models/spree/user.rb' - 'app/models/spree/variant_decorator.rb' @@ -268,7 +422,7 @@ Rails/ReflectionClassName: - 'app/models/enterprise_role.rb' - 'app/models/subscription.rb' -# Offense count: 227 +# Offense count: 233 # Configuration parameters: Blacklist, Whitelist. # Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters Rails/SkipsModelValidations: @@ -287,7 +441,8 @@ Rails/SkipsModelValidations: - 'app/models/spree/address_decorator.rb' - 'app/models/spree/credit_card_decorator.rb' - 'app/models/spree/order_decorator.rb' - - 'app/models/spree/payment_decorator.rb' + - 'app/models/spree/payment.rb' + - 'app/models/spree/shipment.rb' - 'app/models/spree/shipping_method_decorator.rb' - 'app/models/subscription.rb' - 'app/models/variant_override.rb' @@ -355,20 +510,22 @@ Rails/SkipsModelValidations: - 'spec/support/request/shop_workflow.rb' - 'spec/views/spree/shared/_order_details.html.haml_spec.rb' -# Offense count: 2 +# Offense count: 3 # Configuration parameters: Include. # Include: app/models/**/*.rb Rails/UniqueValidationWithoutIndex: Exclude: - 'app/models/customer.rb' - 'app/models/exchange.rb' + - 'app/models/spree/stock_item.rb' -# Offense count: 1 +# Offense count: 2 # Configuration parameters: Environments. # Environments: development, test, production Rails/UnknownEnv: Exclude: - 'app/models/spree/app_configuration_decorator.rb' + - 'lib/spree/core/controller_helpers/ssl.rb' # Offense count: 2 Style/CaseEquality: @@ -376,7 +533,7 @@ Style/CaseEquality: - 'app/helpers/angular_form_helper.rb' - 'spec/models/spree/payment_spec.rb' -# Offense count: 75 +# Offense count: 71 # Cop supports --auto-correct. # Configuration parameters: AutoCorrect, EnforcedStyle. # SupportedStyles: nested, compact @@ -440,20 +597,10 @@ Style/ClassAndModuleChildren: - 'app/serializers/api/property_serializer.rb' - 'app/serializers/api/shipping_method_serializer.rb' - 'app/serializers/api/state_serializer.rb' - - 'app/serializers/api/taxon_image_serializer.rb' - 'app/serializers/api/taxon_serializer.rb' - 'app/serializers/api/variant_serializer.rb' - 'lib/open_food_network/locking.rb' - - 'lib/open_food_network/reports/bulk_coop_allocation_report.rb' - - 'lib/open_food_network/reports/bulk_coop_report.rb' - - 'lib/open_food_network/reports/bulk_coop_supplier_report.rb' - - 'lib/open_food_network/reports/report.rb' - - 'lib/open_food_network/reports/row.rb' - - 'lib/open_food_network/reports/rule.rb' - 'spec/controllers/spree/admin/base_controller_spec.rb' - - 'spec/lib/open_food_network/reports/report_spec.rb' - - 'spec/lib/open_food_network/reports/row_spec.rb' - - 'spec/lib/open_food_network/reports/rule_spec.rb' # Offense count: 2 Style/ClassVars: @@ -468,7 +615,7 @@ Style/FormatStringToken: - 'lib/open_food_network/sales_tax_report.rb' - 'spec/features/admin/bulk_order_management_spec.rb' -# Offense count: 874 +# Offense count: 847 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: always, always_true, never @@ -562,7 +709,6 @@ Style/FrozenStringLiteralComment: - 'app/controllers/spree/admin/variants_controller.rb' - 'app/controllers/spree/admin/zones_controller.rb' - 'app/controllers/spree/credit_cards_controller.rb' - - 'app/controllers/spree/home_controller.rb' - 'app/controllers/spree/orders_controller.rb' - 'app/controllers/spree/store_controller.rb' - 'app/controllers/spree/user_passwords_controller.rb' @@ -617,8 +763,6 @@ Style/FrozenStringLiteralComment: - 'app/jobs/subscription_placement_job.rb' - 'app/jobs/welcome_enterprise_job.rb' - 'app/mailers/enterprise_mailer.rb' - - 'app/mailers/spree/base_mailer_decorator.rb' - - 'app/mailers/spree/order_mailer_decorator.rb' - 'app/mailers/spree/user_mailer.rb' - 'app/mailers/subscription_mailer.rb' - 'app/models/adjustment_metadata.rb' @@ -677,12 +821,6 @@ Style/FrozenStringLiteralComment: - 'app/models/spree/address_decorator.rb' - 'app/models/spree/adjustment_decorator.rb' - 'app/models/spree/app_configuration_decorator.rb' - - 'app/models/spree/calculator/default_tax_decorator.rb' - - 'app/models/spree/calculator/flat_percent_item_total_decorator.rb' - - 'app/models/spree/calculator/flat_rate_decorator.rb' - - 'app/models/spree/calculator/flexi_rate_decorator.rb' - - 'app/models/spree/calculator/per_item_decorator.rb' - - 'app/models/spree/calculator/price_sack_decorator.rb' - 'app/models/spree/calculator_decorator.rb' - 'app/models/spree/classification_decorator.rb' - 'app/models/spree/concerns/payment_method_distributors.rb' @@ -695,7 +833,6 @@ Style/FrozenStringLiteralComment: - 'app/models/spree/line_item_decorator.rb' - 'app/models/spree/option_type_decorator.rb' - 'app/models/spree/order_decorator.rb' - - 'app/models/spree/payment_decorator.rb' - 'app/models/spree/payment_method_decorator.rb' - 'app/models/spree/preferences/file_configuration.rb' - 'app/models/spree/price_decorator.rb' @@ -704,15 +841,12 @@ Style/FrozenStringLiteralComment: - 'app/models/spree/product_property_decorator.rb' - 'app/models/spree/product_set.rb' - 'app/models/spree/property.rb' - - 'app/models/spree/shipment_decorator.rb' - 'app/models/spree/shipping_method_decorator.rb' - - 'app/models/spree/stock/availability_validator_decorator.rb' - 'app/models/spree/stock_location_decorator.rb' - 'app/models/spree/tax_rate_decorator.rb' - 'app/models/spree/taxon_decorator.rb' - 'app/models/spree/user.rb' - 'app/models/spree/variant_decorator.rb' - - 'app/models/stock/package.rb' - 'app/models/stripe_account.rb' - 'app/models/subscription.rb' - 'app/models/subscription_line_item.rb' @@ -796,7 +930,6 @@ Style/FrozenStringLiteralComment: - 'app/serializers/api/shipping_method_serializer.rb' - 'app/serializers/api/shop_for_orders_serializer.rb' - 'app/serializers/api/state_serializer.rb' - - 'app/serializers/api/taxon_image_serializer.rb' - 'app/serializers/api/taxon_jstree_attribute_serializer.rb' - 'app/serializers/api/taxon_jstree_serializer.rb' - 'app/serializers/api/taxon_serializer.rb' @@ -804,7 +937,6 @@ Style/FrozenStringLiteralComment: - 'app/serializers/api/user_serializer.rb' - 'app/serializers/api/variant_serializer.rb' - 'app/services/action_callbacks.rb' - - 'app/services/advance_order_service.rb' - 'app/services/bulk_invoice_service.rb' - 'app/services/cart_service.rb' - 'app/services/create_order_cycle.rb' @@ -824,6 +956,7 @@ Style/FrozenStringLiteralComment: - 'app/services/order_factory.rb' - 'app/services/order_syncer.rb' - 'app/services/order_update_issues.rb' + - 'app/services/order_workflow.rb' - 'app/services/permissions/order.rb' - 'app/services/product_tag_rules_filterer.rb' - 'app/services/products_renderer.rb' @@ -886,7 +1019,6 @@ Style/FrozenStringLiteralComment: - 'lib/discourse/single_sign_on.rb' - 'lib/open_food_network/address_finder.rb' - 'lib/open_food_network/available_payment_method_filter.rb' - - 'lib/open_food_network/bulk_coop_report.rb' - 'lib/open_food_network/column_preference_defaults.rb' - 'lib/open_food_network/customers_report.rb' - 'lib/open_food_network/enterprise_fee_applicator.rb' @@ -899,7 +1031,6 @@ Style/FrozenStringLiteralComment: - 'lib/open_food_network/i18n_config.rb' - 'lib/open_food_network/lettuce_share_report.rb' - 'lib/open_food_network/locking.rb' - - 'lib/open_food_network/model_class_from_controller_name.rb' - 'lib/open_food_network/order_and_distributor_report.rb' - 'lib/open_food_network/order_cycle_form_applicator.rb' - 'lib/open_food_network/order_cycle_management_report.rb' @@ -921,14 +1052,8 @@ Style/FrozenStringLiteralComment: - 'lib/open_food_network/property_merge.rb' - 'lib/open_food_network/rack_request_blocker.rb' - 'lib/open_food_network/referer_parser.rb' - - 'lib/open_food_network/reports/bulk_coop_allocation_report.rb' - - 'lib/open_food_network/reports/bulk_coop_report.rb' - - 'lib/open_food_network/reports/bulk_coop_supplier_report.rb' - 'lib/open_food_network/reports/line_items.rb' - 'lib/open_food_network/reports/list.rb' - - 'lib/open_food_network/reports/report.rb' - - 'lib/open_food_network/reports/row.rb' - - 'lib/open_food_network/reports/rule.rb' - 'lib/open_food_network/sales_tax_report.rb' - 'lib/open_food_network/scope_product_to_hub.rb' - 'lib/open_food_network/scope_variant_to_hub.rb' @@ -942,9 +1067,6 @@ Style/FrozenStringLiteralComment: - 'lib/spree/api/controller_setup.rb' - 'lib/spree/api/testing_support/setup.rb' - 'lib/spree/authentication_helpers.rb' - - 'lib/spree/core/controller_helpers/auth_decorator.rb' - - 'lib/spree/core/controller_helpers/order_decorator.rb' - - 'lib/spree/core/controller_helpers/respond_with_decorator.rb' - 'lib/spree/localized_number.rb' - 'lib/spree/money_decorator.rb' - 'lib/spree/product_filters.rb' @@ -973,7 +1095,6 @@ Style/FrozenStringLiteralComment: - 'lib/tasks/sample_data/user_factory.rb' - 'lib/tasks/specs.rake' - 'lib/tasks/users.rake' - - 'spec/config/application_spec.rb' - 'spec/controllers/admin/bulk_line_items_controller_spec.rb' - 'spec/controllers/admin/column_preferences_controller_spec.rb' - 'spec/controllers/admin/customers_controller_spec.rb' @@ -1004,9 +1125,9 @@ Style/FrozenStringLiteralComment: - 'spec/controllers/api/taxonomies_controller_spec.rb' - 'spec/controllers/api/taxons_controller_spec.rb' - 'spec/controllers/api/variants_controller_spec.rb' + - 'spec/controllers/base_controller2_spec.rb' - 'spec/controllers/base_controller_spec.rb' - 'spec/controllers/cart_controller_spec.rb' - - 'spec/controllers/checkout_controller_concurrency_spec.rb' - 'spec/controllers/checkout_controller_spec.rb' - 'spec/controllers/enterprises_controller_spec.rb' - 'spec/controllers/groups_controller_spec.rb' @@ -1023,7 +1144,6 @@ Style/FrozenStringLiteralComment: - 'spec/controllers/spree/admin/orders_controller_spec.rb' - 'spec/controllers/spree/admin/overview_controller_spec.rb' - 'spec/controllers/spree/admin/payment_methods_controller_spec.rb' - - 'spec/controllers/spree/admin/payments_controller_spec.rb' - 'spec/controllers/spree/admin/products_controller_spec.rb' - 'spec/controllers/spree/admin/reports_controller_spec.rb' - 'spec/controllers/spree/admin/search_controller_spec.rb' @@ -1032,7 +1152,6 @@ Style/FrozenStringLiteralComment: - 'spec/controllers/spree/admin/variants_controller_spec.rb' - 'spec/controllers/spree/credit_cards_controller_spec.rb' - 'spec/controllers/spree/orders_controller_spec.rb' - - 'spec/controllers/spree/store_controller_spec.rb' - 'spec/controllers/spree/user_sessions_controller_spec.rb' - 'spec/controllers/spree/users_controller_spec.rb' - 'spec/controllers/stripe/callbacks_controller_spec.rb' @@ -1140,7 +1259,6 @@ Style/FrozenStringLiteralComment: - 'spec/jobs/subscription_placement_job_spec.rb' - 'spec/jobs/welcome_enterprise_job_spec.rb' - 'spec/lib/open_food_network/address_finder_spec.rb' - - 'spec/lib/open_food_network/bulk_coop_report_spec.rb' - 'spec/lib/open_food_network/customers_report_spec.rb' - 'spec/lib/open_food_network/enterprise_fee_applicator_spec.rb' - 'spec/lib/open_food_network/enterprise_fee_calculator_spec.rb' @@ -1166,9 +1284,6 @@ Style/FrozenStringLiteralComment: - 'spec/lib/open_food_network/products_and_inventory_report_spec.rb' - 'spec/lib/open_food_network/property_merge_spec.rb' - 'spec/lib/open_food_network/referer_parser_spec.rb' - - 'spec/lib/open_food_network/reports/report_spec.rb' - - 'spec/lib/open_food_network/reports/row_spec.rb' - - 'spec/lib/open_food_network/reports/rule_spec.rb' - 'spec/lib/open_food_network/sales_tax_report_spec.rb' - 'spec/lib/open_food_network/scope_variant_to_hub_spec.rb' - 'spec/lib/open_food_network/scope_variants_to_search_spec.rb' @@ -1183,12 +1298,16 @@ Style/FrozenStringLiteralComment: - 'spec/lib/tasks/enterprises_rake_spec.rb' - 'spec/lib/tasks/users_rake_spec.rb' - 'spec/mailers/enterprise_mailer_spec.rb' - - 'spec/mailers/order_mailer_spec.rb' - 'spec/mailers/producer_mailer_spec.rb' - 'spec/mailers/subscription_mailer_spec.rb' - 'spec/mailers/user_mailer_spec.rb' - 'spec/models/adjustment_metadata_spec.rb' + - 'spec/models/calculator/flat_percent_item_total_spec.rb' - 'spec/models/calculator/flat_percent_per_item_spec.rb' + - 'spec/models/calculator/flat_rate_spec.rb' + - 'spec/models/calculator/flexi_rate_spec.rb' + - 'spec/models/calculator/per_item_spec.rb' + - 'spec/models/calculator/price_sack_spec.rb' - 'spec/models/calculator/weight_spec.rb' - 'spec/models/column_preference_spec.rb' - 'spec/models/concerns/order_shipment_spec.rb' @@ -1214,11 +1333,6 @@ Style/FrozenStringLiteralComment: - 'spec/models/spree/ability_spec.rb' - 'spec/models/spree/addresses_spec.rb' - 'spec/models/spree/adjustment_spec.rb' - - 'spec/models/spree/calculator/flat_percent_item_total_spec.rb' - - 'spec/models/spree/calculator/flat_rate_spec.rb' - - 'spec/models/spree/calculator/flexi_rate_spec.rb' - - 'spec/models/spree/calculator/per_item_spec.rb' - - 'spec/models/spree/calculator/price_sack_spec.rb' - 'spec/models/spree/calculator_spec.rb' - 'spec/models/spree/classification_spec.rb' - 'spec/models/spree/credit_card_spec.rb' @@ -1233,14 +1347,12 @@ Style/FrozenStringLiteralComment: - 'spec/models/spree/price_spec.rb' - 'spec/models/spree/product_set_spec.rb' - 'spec/models/spree/product_spec.rb' - - 'spec/models/spree/shipment_spec.rb' - 'spec/models/spree/shipping_method_spec.rb' - 'spec/models/spree/stock/availability_validator_spec.rb' - 'spec/models/spree/tax_rate_spec.rb' - 'spec/models/spree/taxon_spec.rb' - 'spec/models/spree/user_spec.rb' - 'spec/models/spree/variant_spec.rb' - - 'spec/models/stock/package_spec.rb' - 'spec/models/stripe_account_spec.rb' - 'spec/models/subscription_line_item_spec.rb' - 'spec/models/subscription_spec.rb' @@ -1282,7 +1394,6 @@ Style/FrozenStringLiteralComment: - 'spec/serializers/api/product_serializer_spec.rb' - 'spec/serializers/api/shipping_method_serializer_spec.rb' - 'spec/serializers/api/variant_serializer_spec.rb' - - 'spec/services/advance_order_service_spec.rb' - 'spec/services/bulk_invoice_service_spec.rb' - 'spec/services/cart_service_spec.rb' - 'spec/services/default_shipping_category_spec.rb' @@ -1298,6 +1409,7 @@ Style/FrozenStringLiteralComment: - 'spec/services/order_cycle_warning_spec.rb' - 'spec/services/order_factory_spec.rb' - 'spec/services/order_syncer_spec.rb' + - 'spec/services/order_workflow_spec.rb' - 'spec/services/permissions/order_spec.rb' - 'spec/services/product_tag_rules_filterer_spec.rb' - 'spec/services/products_renderer_spec.rb' @@ -1331,7 +1443,7 @@ Style/FrozenStringLiteralComment: - 'spec/support/performance_helper.rb' - 'spec/support/products_helper.rb' - 'spec/support/request/admin_helper.rb' - - 'spec/support/request/authentication_workflow.rb' + - 'spec/support/request/authentication_helper.rb' - 'spec/support/request/checkout_workflow.rb' - 'spec/support/request/cookie_helper.rb' - 'spec/support/request/distribution_helper.rb' @@ -1348,8 +1460,9 @@ Style/FrozenStringLiteralComment: - 'spec/validators/integer_array_validator_spec.rb' - 'spec/views/spree/admin/orders/edit.html.haml_spec.rb' - 'spec/views/spree/admin/orders/index.html.haml_spec.rb' + - 'spec/views/spree/admin/payment_methods/index.html.haml_spec.rb' -# Offense count: 51 +# Offense count: 48 # Configuration parameters: MinBodyLength. Style/GuardClause: Exclude: @@ -1369,32 +1482,35 @@ Style/GuardClause: - 'app/models/spree/order_decorator.rb' - 'app/models/spree/price_decorator.rb' - 'app/models/spree/product_decorator.rb' - - 'app/services/advance_order_service.rb' - 'app/services/order_syncer.rb' - 'lib/discourse/single_sign_on.rb' - 'lib/open_food_network/order_cycle_form_applicator.rb' - 'lib/open_food_network/rack_request_blocker.rb' - 'lib/open_food_network/variant_and_line_item_naming.rb' - - 'lib/spree/core/controller_helpers/order_decorator.rb' - - 'lib/spree/core/controller_helpers/respond_with_decorator.rb' - 'spec/support/delayed_job_helper.rb' - 'spec/support/request/distribution_helper.rb' - 'spec/support/request/shop_workflow.rb' +# Offense count: 54 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. +# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys +Style/HashSyntax: + Exclude: + - 'spec/models/spree/payment_spec.rb' + # Offense count: 1 Style/MissingRespondToMissing: Exclude: - 'app/helpers/application_helper.rb' -# Offense count: 4 +# Offense count: 2 Style/MixinUsage: Exclude: - 'lib/open_food_network/orders_and_fulfillments_report.rb' - - 'spec/lib/open_food_network/bulk_coop_report_spec.rb' - - 'spec/lib/open_food_network/order_cycle_management_report_spec.rb' - 'spec/lib/open_food_network/packing_report_spec.rb' -# Offense count: 41 +# Offense count: 39 # Cop supports --auto-correct. # Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods. # SupportedStyles: predicate, comparison @@ -1409,11 +1525,9 @@ Style/NumericPredicate: - 'app/models/product_import/product_importer.rb' - 'app/models/product_import/spreadsheet_entry.rb' - 'app/models/spree/adjustment_decorator.rb' - - 'app/models/spree/calculator/flexi_rate_decorator.rb' - 'app/models/spree/gateway/stripe_connect.rb' - 'app/models/spree/line_item_decorator.rb' - 'app/models/spree/order_decorator.rb' - - 'app/models/spree/shipment_decorator.rb' - 'app/models/spree/user.rb' - 'app/models/variant_override.rb' - 'app/services/cart_service.rb' @@ -1426,6 +1540,22 @@ Style/NumericPredicate: - 'lib/spree/money_decorator.rb' - 'lib/tasks/sample_data.rake' +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: compact, exploded +Style/RaiseArgs: + Exclude: + - 'spec/controllers/checkout_controller_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, AllowInnerSlashes. +# SupportedStyles: slashes, percent_r, mixed +Style/RegexpLiteral: + Exclude: + - 'lib/spree/core/controller_helpers/auth.rb' + # Offense count: 231 Style/Send: Exclude: diff --git a/DOCKER.md b/DOCKER.md index 65f6815425..935e62b729 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -17,7 +17,13 @@ Better to have at least 2GB free on your computer in order to download images an Open a terminal with a shell. -Clone the repository: +Clone the repository. If you're planning on contributing code to the project (which we [LOVE](CONTRIBUTING.md)), it is a good idea to begin by forking this repo using the Fork button in the top-right corner of this screen. You should then be able to use git clone to copy your fork onto your local machine. + +```sh +$ git clone https://github.com/YOUR_GITHUB_USERNAME_HERE/openfoodnetwork +``` + +Otherwise, if you just want to get things running, clone from the OFN main repo: ```sh $ git clone git@github.com:openfoodfoundation/openfoodnetwork.git diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index b252993215..fd8dc47769 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -1,6 +1,6 @@ ### Getting Started -This is a general guide to setting up an Open Food Network development environment on your local machine. +This is a general guide to setting up an Open Food Network **development environment on your local machine**. If you want to setup OFN on a server, please have a look at the [ofn-install deployment guide](https://github.com/openfoodfoundation/ofn-install/wiki). ### Requirements diff --git a/Gemfile b/Gemfile index eb91b2c147..682b445502 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ ruby "2.3.7" git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" } gem 'i18n', '~> 0.6.11' -gem 'i18n-js', '~> 3.7.0' +gem 'i18n-js', '~> 3.7.1' gem 'rails', '~> 4.0.13' gem 'rails-i18n', '~> 4.0' gem 'rails_safe_tasks', '~> 1.0' @@ -39,18 +39,21 @@ gem 'stringex', '~> 1.5.1' gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable' -# Our branch contains two changes +# Our branch contains the following 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 +# - Skip CA cert file and use the ones provided by the OS gem 'spree_paypal_express', github: 'openfoodfoundation/better_spree_paypal_express', branch: '2-1-0-stable' + gem 'stripe' # We need at least this version to have Digicert's root certificate # which is needed for Pin Payments (and possibly others). gem 'activemerchant', '~> 1.78.0' -gem 'devise', '~> 3.0.1' +gem 'devise', '~> 3.5.10' # v4.0.0 needs rails 4.1 gem 'devise-encryptable' +gem 'devise-token_authenticatable', '~> 0.4.10' # v0.5.0 needs devise v4 gem 'jwt', '~> 2.2' gem 'oauth2', '~> 1.4.4' # Used for Stripe Connect @@ -83,12 +86,11 @@ gem 'acts-as-taggable-on', '~> 4.0' gem 'angularjs-file-upload-rails', '~> 2.4.1' gem 'custom_error_message', github: 'jeremydurham/custom-err-msg' gem 'dalli' -gem 'diffy' gem 'figaro' gem 'geocoder' gem 'gmaps4rails' gem 'oj' -gem 'paper_trail', '~> 5.2.3' +gem 'paper_trail', '~> 7.1.3' gem 'paperclip', '~> 3.4.1' gem 'rack-rewrite' gem 'rack-ssl', require: 'rack/ssl' diff --git a/Gemfile.lock b/Gemfile.lock index 9b627cb940..61a7f746ac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ GIT GIT remote: https://github.com/openfoodfoundation/better_spree_paypal_express.git - revision: e28e4a8c5cedba504eea9cdad4be440d277d7e68 + revision: 1736e3268239a841576d2719a1f276cf9b74c5c5 branch: 2-1-0-stable specs: spree_paypal_express (2.0.3) @@ -108,7 +108,7 @@ GEM activesupport (= 4.0.13) arel (~> 4.0.0) activerecord-deprecated_finders (1.0.4) - activerecord-import (1.0.5) + activerecord-import (1.0.6) activerecord (>= 3.2) activerecord-postgresql-adapter (0.0.1) pg @@ -148,9 +148,7 @@ GEM nokogiri (>= 1.4.4) uuidtools (~> 2.1) bcrypt (3.1.13) - bcrypt-ruby (3.1.5) - bcrypt (>= 3.1.3) - bugsnag (6.13.1) + bugsnag (6.16.0) concurrent-ruby (~> 1.0) builder (3.1.4) byebug (11.0.1) @@ -194,7 +192,7 @@ GEM compass (~> 1.0.0) sass-rails (< 5.1) sprockets (< 4.0) - concurrent-ruby (1.1.6) + concurrent-ruby (1.1.7) crack (0.4.3) safe_yaml (~> 1.0.0) css_parser (1.7.1) @@ -206,7 +204,7 @@ GEM activerecord (>= 3.2.0, < 5.0) fog (~> 1.0) rails (>= 3.2.0, < 5.0) - ddtrace (0.37.0) + ddtrace (0.39.0) msgpack debugger-linecache (1.2.0) delayed_job (4.1.8) @@ -219,15 +217,18 @@ GEM delayed_job (> 2.0.3) rack-protection (>= 1.5.5) sinatra (>= 1.4.4) - devise (3.0.4) - bcrypt-ruby (~> 3.0) + devise (3.5.10) + bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 3.2.6, < 5) + responders + thread_safe (~> 0.1) warden (~> 1.2.3) devise-encryptable (0.2.0) devise (>= 2.1.0) + devise-token_authenticatable (0.4.10) + devise (>= 3.5.2, < 4.0.0) diff-lcs (1.3) - diffy (3.3.0) docile (1.3.2) dry-inflector (0.1.2) erubis (2.7.0) @@ -420,7 +421,7 @@ GEM mime-types (~> 3.0) multi_xml (>= 0.5.2) i18n (0.6.11) - i18n-js (3.7.0) + i18n-js (3.7.1) i18n (>= 0.6.6) immigrant (0.3.6) activerecord (>= 3.0) @@ -466,7 +467,7 @@ GEM money (5.1.1) i18n (~> 0.6.0) msgpack (1.3.3) - multi_json (1.14.1) + multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) newrelic_rpm (3.18.1.330) @@ -478,11 +479,11 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - oj (3.10.6) + oj (3.10.8) optimist (3.0.0) orm_adapter (0.5.0) - paper_trail (5.2.3) - activerecord (>= 3.0, < 6.0) + paper_trail (7.1.3) + activerecord (>= 4.0, < 5.2) request_store (~> 1.1) paperclip (3.4.2) activemodel (>= 3.0.0) @@ -508,7 +509,7 @@ GEM pry-byebug (3.7.0) byebug (~> 11.0) pry (~> 0.10) - public_suffix (4.0.3) + public_suffix (4.0.5) rack (1.5.5) rack-mini-profiler (2.0.2) rack (>= 1.2.0) @@ -553,8 +554,10 @@ GEM nokogiri (~> 1.5) optimist (~> 3.0) redcarpet (3.5.0) - request_store (1.4.1) + request_store (1.5.0) rack (>= 1.4) + responders (1.1.2) + railties (>= 3.2, < 4.2) rexml (3.2.4) roadie (3.4.0) css_parser (~> 1.4) @@ -588,19 +591,19 @@ GEM rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.9.2) - rswag (2.2.0) - rswag-api (= 2.2.0) - rswag-specs (= 2.2.0) - rswag-ui (= 2.2.0) - rswag-api (2.2.0) - railties (>= 3.1, < 6.1) - rswag-specs (2.2.0) - activesupport (>= 3.1, < 6.1) + rswag (2.3.1) + rswag-api (= 2.3.1) + rswag-specs (= 2.3.1) + rswag-ui (= 2.3.1) + rswag-api (2.3.1) + railties (>= 3.1, < 7.0) + rswag-specs (2.3.1) + activesupport (>= 3.1, < 7.0) json-schema (~> 2.2) - railties (>= 3.1, < 6.1) - rswag-ui (2.2.0) - actionpack (>= 3.1, < 6.1) - railties (>= 3.1, < 6.1) + railties (>= 3.1, < 7.0) + rswag-ui (2.3.1) + actionpack (>= 3.1, < 7.0) + railties (>= 3.1, < 7.0) rubocop (0.81.0) jaro_winkler (~> 1.5.1) parallel (~> 1.10) @@ -668,7 +671,7 @@ GEM uglifier (4.2.0) execjs (>= 0.3.0, < 3) unicode-display_width (1.7.0) - unicorn (5.5.5) + unicorn (5.6.0) kgio (~> 2.6) raindrops (~> 0.7) unicorn-rails (2.2.1) @@ -735,10 +738,10 @@ DEPENDENCIES debugger-linecache delayed_job_active_record delayed_job_web - devise (~> 3.0.1) + devise (~> 3.5.10) devise-encryptable + devise-token_authenticatable (~> 0.4.10) dfc_provider! - diffy eventmachine (>= 1.2.3) factory_bot_rails (= 4.10.0) ffaker (~> 1.16) @@ -753,7 +756,7 @@ DEPENDENCIES highline (= 1.6.18) httparty (~> 0.18) i18n (~> 0.6.11) - i18n-js (~> 3.7.0) + i18n-js (~> 3.7.1) immigrant jquery-migrate-rails jquery-rails (= 3.1.5) @@ -772,7 +775,7 @@ DEPENDENCIES ofn-qz! oj order_management! - paper_trail (~> 5.2.3) + paper_trail (~> 7.1.3) paperclip (~> 3.4.1) paranoia (~> 2.0) pg (~> 0.21.0) diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js index eee8a874c9..c43f365cb6 100644 --- a/app/assets/javascripts/admin/all.js +++ b/app/assets/javascripts/admin/all.js @@ -80,7 +80,11 @@ //= require moment/nb.js //= require moment/pt-br.js //= require moment/pt.js +//= require moment/ru.js //= require moment/sv.js +//= require moment/ca.js +//= require moment/ar.js +//= require moment/tr.js // foundation //= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js diff --git a/app/assets/javascripts/darkswarm/all.js.coffee b/app/assets/javascripts/darkswarm/all.js.coffee index 605eeb3b07..51209fadd6 100644 --- a/app/assets/javascripts/darkswarm/all.js.coffee +++ b/app/assets/javascripts/darkswarm/all.js.coffee @@ -37,7 +37,11 @@ #= require moment/nb.js #= require moment/pt-br.js #= require moment/pt.js +#= require moment/ru.js #= require moment/sv.js +#= require moment/ca.js +#= require moment/ar.js +#= require moment/tr.js # #= require modernizr # diff --git a/app/assets/javascripts/darkswarm/directives/disable_enter_with_blur.js.coffee b/app/assets/javascripts/darkswarm/directives/disable_enter_with_blur.js.coffee new file mode 100644 index 0000000000..1704d4c0f9 --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/disable_enter_with_blur.js.coffee @@ -0,0 +1,9 @@ +Darkswarm.directive "disableEnterWithBlur", ()-> + # Stops enter from doing normal enter things, and blurs the input + restrict: 'A' + link: (scope, element, attrs)-> + element.bind "keydown keypress", (e)-> + code = e.keyCode || e.which + if code == 13 + element.blur() + e.preventDefault() diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee index 322fa4bb28..bd46a9c80d 100644 --- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee @@ -43,7 +43,7 @@ Darkswarm.directive 'mapSearch', ($timeout, Search) -> # When the map loads, and we have a search from ?query, perform that search scope.performUrlSearch = (map) -> google.maps.event.addListenerOnce map, "idle", => - google.maps.event.trigger(scope.input, 'focus'); + google.maps.event.trigger(scope.input, 'focus',{}); google.maps.event.trigger(scope.input, 'keydown', {keyCode: 13}); # Bias the SearchBox results towards places that are within the bounds of the diff --git a/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee b/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee index 7dbdc73669..32f0d921b0 100644 --- a/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.directive 'ofnOpenStreetMap', ($window, Enterprises, EnterpriseModal, availableCountries, openStreetMapConfig) -> +Darkswarm.directive 'ofnOpenStreetMap', ($window, MapCentreCalculator, Enterprises, EnterpriseModal, availableCountries, openStreetMapConfig) -> restrict: 'E' replace: true scope: true @@ -11,34 +11,6 @@ Darkswarm.directive 'ofnOpenStreetMap', ($window, Enterprises, EnterpriseModal, openStreetMapProviderName = openStreetMapConfig.open_street_map_provider_name openStreetMapProviderOptions = JSON.parse(openStreetMapConfig.open_street_map_provider_options) - average = (values) -> - total = values.reduce (sum, value) -> - sum = sum + value - , 0 - total / values.length - - averageAngle = (angleName) -> - positiveAngles = [] - negativeAngles = [] - for enterprise in Enterprises.enterprises - if enterprise.latitude? && enterprise.longitude? - if enterprise[angleName] > 0 - positiveAngles.push(enterprise[angleName]) - else - negativeAngles.push(enterprise[angleName]) - - averageNegativeAngle = average(negativeAngles) - averagePositiveAngle = average(positiveAngles) - - if negativeAngles.length == 0 - averagePositiveAngle - else if positiveAngles.length == 0 - averageNegativeAngle - else if averagePositiveAngle > averageNegativeAngle - averagePositiveAngle - averageNegativeAngle - else - averageNegativeAngle - averagePositiveAngle - buildMarker = (enterprise, latlng, title) -> icon = L.icon iconUrl: enterprise.icon @@ -61,28 +33,31 @@ Darkswarm.directive 'ofnOpenStreetMap', ($window, Enterprises, EnterpriseModal, displayMap = -> setMapDimensions() - averageLatitude = averageAngle("latitude") - averageLongitude = averageAngle("longitude") zoomLevel = 6 map = L.map('open-street-map') L.tileLayer.provider(openStreetMapProviderName, openStreetMapProviderOptions).addTo(map) - map.setView([averageLatitude, averageLongitude], zoomLevel) + map.setView([MapCentreCalculator.initialLatitude(), MapCentreCalculator.initialLongitude()], zoomLevel) displayEnterprises = -> - for enterprise in Enterprises.enterprises - if enterprise.latitude? && enterprise.longitude? - marker = buildMarker(enterprise, { lat: enterprise.latitude, lng: enterprise.longitude }, enterprise.name).addTo(map) - enterpriseNames.push(enterpriseName(enterprise)) - markers.push(marker) + for enterprise in Enterprises.geocodedEnterprises() + marker = buildMarker(enterprise, { lat: enterprise.latitude, lng: enterprise.longitude }, enterprise.name).addTo(map) + enterpriseNames.push(enterpriseName(enterprise)) + markers.push(marker) + + disableSearchField = () => + $('#open-street-map--search input').prop("disabled", true) displaySearchField = () -> new Autocomplete('#open-street-map--search', onSubmit: goToEnterprise search: searchEnterprises ) - overwriteInlinePositionRelativeToPositionSearchField = -> - $('#open-street-map--search').css("position", "absolute") - overwriteInlinePositionRelativeToPositionSearchField() + overwriteInlinePositionRelativeToAbsoluteOnSearchField() + if Enterprises.geocodedEnterprises().length == 0 + disableSearchField() + + overwriteInlinePositionRelativeToAbsoluteOnSearchField = -> + $('#open-street-map--search').css("position", "absolute") searchEnterprises = (input) -> if input.length < 1 diff --git a/app/assets/javascripts/darkswarm/services/checkout.js.coffee b/app/assets/javascripts/darkswarm/services/checkout.js.coffee index 4ec3081ad3..d74f075ea3 100644 --- a/app/assets/javascripts/darkswarm/services/checkout.js.coffee +++ b/app/assets/javascripts/darkswarm/services/checkout.js.coffee @@ -24,7 +24,8 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeE try @loadFlash(error: t("checkout.failed")) # inform the user about the unexpected error finally - throw error # generate a BugsnagJS alert + Bugsnag.notify(error) + throw error handle_checkout_error_response: (response) => throw response unless response.data? diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 843749c2e6..d8347c7e41 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -84,3 +84,8 @@ Darkswarm.factory 'Enterprises', (enterprises, ShopsResource, CurrentHub, Taxons resetDistance: -> enterprise.distance = null for enterprise in @enterprises + + geocodedEnterprises: => + @enterprises.filter (enterprise) -> + enterprise.latitude? && enterprise.longitude? + diff --git a/app/assets/javascripts/darkswarm/services/map.js.coffee b/app/assets/javascripts/darkswarm/services/map.js.coffee index 2758f299f8..9aa23a7155 100644 --- a/app/assets/javascripts/darkswarm/services/map.js.coffee +++ b/app/assets/javascripts/darkswarm/services/map.js.coffee @@ -2,9 +2,7 @@ Darkswarm.factory "OfnMap", (Enterprises, EnterpriseListModal, MapConfiguration) new class OfnMap constructor: -> @coordinates = {} - @enterprises = Enterprises.enterprises.filter (enterprise) -> - # Remove enterprises w/o lat or long - enterprise.latitude != null || enterprise.longitude != null + @enterprises = Enterprises.geocodedEnterprises() @enterprises = @enterprise_markers(@enterprises) enterprise_markers: (enterprises) -> diff --git a/app/assets/javascripts/darkswarm/services/map_centre_calculator.js.coffee b/app/assets/javascripts/darkswarm/services/map_centre_calculator.js.coffee new file mode 100644 index 0000000000..978afb5858 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/map_centre_calculator.js.coffee @@ -0,0 +1,30 @@ +Darkswarm.factory 'MapCentreCalculator', (Enterprises, openStreetMapConfig) -> + new class MapCentreCalculator + + initialLatitude: => + if Enterprises.geocodedEnterprises().length > 0 + @_calculate("latitude", Enterprises.geocodedEnterprises()) + else + openStreetMapConfig.open_street_map_default_latitude + + initialLongitude: => + if Enterprises.geocodedEnterprises().length > 0 + @_calculate("longitude", Enterprises.geocodedEnterprises()) + else + openStreetMapConfig.open_street_map_default_longitude + + _calculate: (angleName, coordinates) => + angles = [] + + for coordinate in coordinates + angles.push(coordinate[angleName]) + + minimumAngle = Math.min.apply(null, angles) + maximumAngle = Math.max.apply(null, angles) + + distanceBetweenMinimumAndMaximum = if maximumAngle > minimumAngle + maximumAngle - minimumAngle + else + minimumAngle - maximumAngle + + minimumAngle + (distanceBetweenMinimumAndMaximum / 2) diff --git a/app/assets/stylesheets/admin/shared/layout.scss b/app/assets/stylesheets/admin/shared/layout.scss index 804e32b3a8..71d5fbabed 100644 --- a/app/assets/stylesheets/admin/shared/layout.scss +++ b/app/assets/stylesheets/admin/shared/layout.scss @@ -20,9 +20,11 @@ &:first-child { padding-left: 0; + width: 70%; } &:last-child { padding-right: 0; + width: 30%; } } } diff --git a/app/assets/stylesheets/darkswarm/expanding-sidebar.scss b/app/assets/stylesheets/darkswarm/expanding-sidebar.scss index da1034cf42..8bfcfe824b 100644 --- a/app/assets/stylesheets/darkswarm/expanding-sidebar.scss +++ b/app/assets/stylesheets/darkswarm/expanding-sidebar.scss @@ -16,12 +16,14 @@ width: 100%; background-color: $shop-sidebar-overlay; opacity: 0; - transition: opacity $transition-sidebar; + visibility: hidden; + transition: all $transition-sidebar; } &.shown { .background { opacity: 1; + visibility: visible; } .sidebar, diff --git a/app/assets/stylesheets/darkswarm/home_tagline.scss b/app/assets/stylesheets/darkswarm/home_tagline.scss index c6cc15c9e8..7ad1ea0241 100644 --- a/app/assets/stylesheets/darkswarm/home_tagline.scss +++ b/app/assets/stylesheets/darkswarm/home_tagline.scss @@ -17,10 +17,12 @@ position: fixed; left: 0; right: 0; - bottom: 0; + top: 0; z-index: -1; width: 100%; height: 100%; + // Use vh units for new browsers - fixed issue 1253 + height: 100vh; } h1 { diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 344dd89174..e9d82d19ad 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -1,5 +1,6 @@ # Base controller for OFN's API require_dependency 'spree/api/controller_setup' +require "spree/core/controller_helpers/ssl" module Api class BaseController < ActionController::Metal @@ -53,7 +54,7 @@ module Api # Use logged in user (spree_current_user) for API authentication (current_api_user) def authenticate_user - return if @current_api_user = try_spree_current_user + return if @current_api_user = spree_current_user if api_key.blank? # An anonymous user diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 17585a7237..e9cb17480b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -62,11 +62,15 @@ class ApplicationController < ActionController::Base end def after_sign_out_path_for(_resource_or_scope) - session[:shopfront_redirect] || main_app.root_path + shopfront_redirect || main_app.root_path end private + def shopfront_redirect + session[:shopfront_redirect] + end + def restrict_iframes response.headers['X-Frame-Options'] = 'DENY' response.headers['Content-Security-Policy'] = "frame-ancestors 'none'" diff --git a/app/controllers/base_controller.rb b/app/controllers/base_controller.rb index 6cf878a077..b039a2447d 100644 --- a/app/controllers/base_controller.rb +++ b/app/controllers/base_controller.rb @@ -1,8 +1,10 @@ -require 'spree/core/controller_helpers/respond_with_decorator' +require 'spree/core/controller_helpers/auth' +require 'spree/core/controller_helpers/common' +require 'spree/core/controller_helpers/order' +require 'spree/core/controller_helpers/respond_with' require 'open_food_network/tag_rule_applicator' class BaseController < ApplicationController - include Spree::Core::ControllerHelpers include Spree::Core::ControllerHelpers::Auth include Spree::Core::ControllerHelpers::Common include Spree::Core::ControllerHelpers::Order diff --git a/app/controllers/cart_controller.rb b/app/controllers/cart_controller.rb index 997573899c..1fbf1b2b94 100644 --- a/app/controllers/cart_controller.rb +++ b/app/controllers/cart_controller.rb @@ -1,4 +1,4 @@ -require 'spree/core/controller_helpers/order_decorator' +require 'spree/core/controller_helpers/order' class CartController < BaseController before_action :check_authorization diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index c83b5e361d..c47b112359 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -32,20 +32,20 @@ class CheckoutController < Spree::StoreController helper 'spree/orders' - rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error - def edit return handle_redirect_from_stripe if valid_payment_intent_provided? # 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 + # the #action_failed method, then we can remove this call OrderCheckoutRestart.new(@order).call + rescue Spree::Core::GatewayError => e + rescue_from_spree_gateway_error(e) end def update params_adapter = Checkout::FormDataAdapter.new(permitted_params, @order, spree_current_user) - return update_failed unless @order.update(params_adapter.params[:order]) + return action_failed unless @order.update(params_adapter.params[:order]) fire_event('spree.checkout.update') @@ -54,7 +54,7 @@ class CheckoutController < Spree::StoreController rescue_from_spree_gateway_error(e) rescue StandardError => e flash[:error] = I18n.t("checkout.failed") - update_failed(e) + action_failed(e) end # Clears the cached order. Required for #current_order to return a new order @@ -138,14 +138,6 @@ class CheckoutController < Spree::StoreController current_order.payments.destroy_all if request.put? 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: :bad_request } - end - end - def valid_payment_intent_provided? return false unless params["payment_intent"]&.starts_with?("pi_") @@ -156,11 +148,10 @@ class CheckoutController < Spree::StoreController end def handle_redirect_from_stripe - if advance_order_state(@order) && order_complete? + if OrderWorkflow.new(@order).next && order_complete? checkout_succeeded redirect_to(order_path(@order)) && return else - flash[:error] = order_error checkout_failed end end @@ -171,11 +162,9 @@ class CheckoutController < Spree::StoreController return if redirect_to_payment_gateway end - @order.select_shipping_method(shipping_method_id) if @order.state == "delivery" + next if OrderWorkflow.new(@order).next({ shipping_method_id: shipping_method_id }) - next if advance_order_state(@order) - - return update_failed + return action_failed end update_response @@ -190,15 +179,6 @@ class CheckoutController < Spree::StoreController true end - # Perform order.next, guarding against StaleObjectErrors - def advance_order_state(order) - tries ||= 3 - order.next - rescue ActiveRecord::StaleObjectError - retry unless (tries -= 1).zero? - false - end - def order_error if @order.errors.present? @order.errors.full_messages.to_sentence @@ -212,7 +192,7 @@ class CheckoutController < Spree::StoreController checkout_succeeded update_succeeded_response else - update_failed(RuntimeError.new("Order not complete after the checkout workflow")) + action_failed(RuntimeError.new("Order not complete after the checkout workflow")) end end @@ -238,30 +218,42 @@ class CheckoutController < Spree::StoreController end end - def update_failed(error = RuntimeError.new(order_error)) - Bugsnag.notify(error) - - flash[:error] = order_error if flash.blank? - checkout_failed - update_failed_response + def action_failed(error = RuntimeError.new(order_error)) + checkout_failed(error) + action_failed_response end - def checkout_failed + def checkout_failed(error = RuntimeError.new(order_error)) + Bugsnag.notify(error) + flash[:error] = order_error if flash.blank? Checkout::PostCheckoutActions.new(@order).failure end - def update_failed_response + def action_failed_response respond_to do |format| format.html do render :edit end format.json do + discard_flash_errors render json: { errors: @order.errors, flash: flash.to_hash }.to_json, status: :bad_request end end end + def rescue_from_spree_gateway_error(error) + flash[:error] = t(:spree_gateway_error_flash_for_checkout, error: error.message) + action_failed(error) + end + def permitted_params PermittedAttributes::Checkout.new(params).call end + + def discard_flash_errors + # Marks flash errors for deletion after the current action has completed. + # This ensures flash errors generated during XHR requests are not persisted in the + # session for longer than expected. + flash.discard(:error) + end end diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 6d640b5d7b..7488fa8c4d 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -68,7 +68,7 @@ class EnterprisesController < BaseController # reset_distributor must be called before any call to current_customer or current_distributor order_cart_reset = OrderCartReset.new(order, params[:id]) order_cart_reset.reset_distributor - order_cart_reset.reset_other!(try_spree_current_user, current_customer) + order_cart_reset.reset_other!(spree_current_user, current_customer) rescue ActiveRecord::RecordNotFound flash[:error] = I18n.t(:enterprise_shop_show_error) redirect_to shops_path diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index c585b63839..c7612d3997 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -16,6 +16,10 @@ class HomeController < BaseController def sell; end + def unauthorized + render 'shared/unauthorized', status: :unauthorized + end + private # Cache the value of the query count diff --git a/app/controllers/spree/admin/base_controller.rb b/app/controllers/spree/admin/base_controller.rb index 7ce02d4a38..4f9cdbb4d0 100644 --- a/app/controllers/spree/admin/base_controller.rb +++ b/app/controllers/spree/admin/base_controller.rb @@ -24,7 +24,7 @@ module Spree # This is in Spree::Core::ControllerHelpers::Auth # But you can't easily reopen modules in Ruby def unauthorized - if try_spree_current_user + if spree_current_user flash[:error] = t(:authorization_failure) redirect_to '/unauthorized' else diff --git a/app/controllers/spree/admin/mail_methods_controller.rb b/app/controllers/spree/admin/mail_methods_controller.rb index aba6ad239f..70d573f319 100644 --- a/app/controllers/spree/admin/mail_methods_controller.rb +++ b/app/controllers/spree/admin/mail_methods_controller.rb @@ -15,7 +15,7 @@ module Spree end def testmail - if TestMailer.test_email(try_spree_current_user).deliver + if TestMailer.test_email(spree_current_user).deliver flash[:success] = Spree.t('admin.mail_methods.testmail.delivery_success') else flash[:error] = Spree.t('admin.mail_methods.testmail.delivery_error') diff --git a/app/controllers/spree/admin/orders/customer_details_controller.rb b/app/controllers/spree/admin/orders/customer_details_controller.rb index 82c0c2347e..3239ffff01 100644 --- a/app/controllers/spree/admin/orders/customer_details_controller.rb +++ b/app/controllers/spree/admin/orders/customer_details_controller.rb @@ -23,7 +23,7 @@ module Spree @order.associate_user!(Spree.user_class.find_by(email: @order.email)) end - AdvanceOrderService.new(@order).call + OrderWorkflow.new(@order).complete @order.shipments.map(&:refresh_rates) flash[:success] = Spree.t('customer_details_updated') diff --git a/app/controllers/spree/admin/orders_controller.rb b/app/controllers/spree/admin/orders_controller.rb index 22715108e9..e0b07fbbd9 100644 --- a/app/controllers/spree/admin/orders_controller.rb +++ b/app/controllers/spree/admin/orders_controller.rb @@ -27,7 +27,7 @@ module Spree def new @order = Order.create - @order.created_by = try_spree_current_user + @order.created_by = spree_current_user @order.save redirect_to edit_admin_order_url(@order) end @@ -35,7 +35,7 @@ module Spree def edit @order.shipments.map(&:refresh_rates) - AdvanceOrderService.new(@order).call + OrderWorkflow.new(@order).complete # The payment step shows an error of 'No pending payments' # Clearing the errors from the order object will stop this error diff --git a/app/controllers/spree/admin/payment_methods_controller.rb b/app/controllers/spree/admin/payment_methods_controller.rb index 8825e4ea69..950b97340b 100644 --- a/app/controllers/spree/admin/payment_methods_controller.rb +++ b/app/controllers/spree/admin/payment_methods_controller.rb @@ -97,7 +97,7 @@ module Spree :name, :description, :type, :active, :environment, :display_on, :tag_list, :preferred_enterprise_id, :preferred_server, :preferred_login, :preferred_password, - :calculator_type, + :calculator_type, :preferred_api_key, :preferred_signature, :preferred_solution, :preferred_landing_page, :preferred_logourl, :preferred_test_mode, distributor_ids: [] ) diff --git a/app/controllers/spree/admin/payments_controller.rb b/app/controllers/spree/admin/payments_controller.rb index 215f69972a..bfdb4fd2ff 100644 --- a/app/controllers/spree/admin/payments_controller.rb +++ b/app/controllers/spree/admin/payments_controller.rb @@ -37,7 +37,7 @@ module Spree redirect_to admin_order_payments_path(@order) else - AdvanceOrderService.new(@order).call! + OrderWorkflow.new(@order).complete! flash[:success] = Spree.t(:new_order_completed) redirect_to edit_admin_order_url(@order) @@ -61,7 +61,7 @@ module Spree else flash[:error] = t(:cannot_perform_operation) end - rescue Spree::Core::GatewayError => e + rescue StandardError => e flash[:error] = e.message ensure redirect_to request.referer diff --git a/app/controllers/spree/base_controller.rb b/app/controllers/spree/base_controller.rb new file mode 100644 index 0000000000..4d20570e20 --- /dev/null +++ b/app/controllers/spree/base_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'cancan' + +module Spree + class BaseController < ApplicationController + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::RespondWith + include Spree::Core::ControllerHelpers::SSL + include Spree::Core::ControllerHelpers::Common + + respond_to :html + end +end + +require 'spree/i18n/initializer' diff --git a/app/controllers/spree/home_controller.rb b/app/controllers/spree/home_controller.rb deleted file mode 100644 index 9fbdabe940..0000000000 --- a/app/controllers/spree/home_controller.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Spree - class HomeController < Spree::StoreController - respond_to :html - - def index; end - end -end diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index 545ae1ce60..898ec93f99 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -1,5 +1,5 @@ -require 'spree/core/controller_helpers/order_decorator' -require 'spree/core/controller_helpers/auth_decorator' +require 'spree/core/controller_helpers/order' +require 'spree/core/controller_helpers/auth' module Spree class OrdersController < Spree::StoreController @@ -194,7 +194,7 @@ module Spree return if session[:access_token] || params[:token] || spree_current_user flash[:error] = I18n.t("spree.orders.edit.login_to_view_order") - require_login_then_redirect_to request.env['PATH_INFO'] + redirect_to main_app.root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}") end def order_to_update diff --git a/app/controllers/spree/store_controller.rb b/app/controllers/spree/store_controller.rb index cc4dd9d537..5486912bd3 100644 --- a/app/controllers/spree/store_controller.rb +++ b/app/controllers/spree/store_controller.rb @@ -6,9 +6,5 @@ module Spree include I18nHelper before_action :set_locale - - def unauthorized - render 'shared/unauthorized', status: :unauthorized - end end end diff --git a/app/controllers/spree/user_passwords_controller.rb b/app/controllers/spree/user_passwords_controller.rb index bf8b13d379..4e7fc6e824 100644 --- a/app/controllers/spree/user_passwords_controller.rb +++ b/app/controllers/spree/user_passwords_controller.rb @@ -1,3 +1,10 @@ +# frozen_string_literal: true + +require "spree/core/controller_helpers/auth" +require "spree/core/controller_helpers/common" +require "spree/core/controller_helpers/order" +require "spree/core/controller_helpers/ssl" + module Spree class UserPasswordsController < Devise::PasswordsController helper 'spree/base', 'spree/store' diff --git a/app/controllers/spree/user_registrations_controller.rb b/app/controllers/spree/user_registrations_controller.rb index a55d327ae2..1a2d740da7 100644 --- a/app/controllers/spree/user_registrations_controller.rb +++ b/app/controllers/spree/user_registrations_controller.rb @@ -1,3 +1,10 @@ +# frozen_string_literal: true + +require "spree/core/controller_helpers/auth" +require "spree/core/controller_helpers/common" +require "spree/core/controller_helpers/order" +require "spree/core/controller_helpers/ssl" + module Spree class UserRegistrationsController < Devise::RegistrationsController helper 'spree/base', 'spree/store' @@ -23,7 +30,6 @@ module Spree if resource.save set_flash_message(:notice, :signed_up) sign_in(:spree_user, @user) - session[:spree_user_signup] = true associate_user respond_with resource, location: after_sign_up_path_for(resource) else diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb index df42f622e1..c17eafb892 100644 --- a/app/controllers/spree/user_sessions_controller.rb +++ b/app/controllers/spree/user_sessions_controller.rb @@ -1,3 +1,10 @@ +# frozen_string_literal: true + +require "spree/core/controller_helpers/auth" +require "spree/core/controller_helpers/common" +require "spree/core/controller_helpers/order" +require "spree/core/controller_helpers/ssl" + module Spree class UserSessionsController < Devise::SessionsController helper 'spree/base', 'spree/store' @@ -39,8 +46,18 @@ module Spree end end + def destroy + # Logout will clear session data including shopfront_redirect + # Here we store it before actually logging out so that the redirect works correctly + @shopfront_redirect = session[:shopfront_redirect] + + super + end + private + attr_reader :shopfront_redirect + def accurate_title Spree.t(:login) end diff --git a/app/controllers/spree/users_controller.rb b/app/controllers/spree/users_controller.rb index f524f8d465..c6ce064b57 100644 --- a/app/controllers/spree/users_controller.rb +++ b/app/controllers/spree/users_controller.rb @@ -59,7 +59,7 @@ module Spree if @user authorize! params[:action].to_sym, @user else - redirect_to spree.login_path + redirect_to main_app.login_path end end diff --git a/app/controllers/user_confirmations_controller.rb b/app/controllers/user_confirmations_controller.rb index 1e15a6a296..0915447bc5 100644 --- a/app/controllers/user_confirmations_controller.rb +++ b/app/controllers/user_confirmations_controller.rb @@ -44,9 +44,10 @@ class UserConfirmationsController < DeviseController 'not_confirmed' end - if resource.reset_password_token.present? + if result == 'confirmed' && resource.reset_password_token.present? + raw_reset_password_token = resource.regenerate_reset_password_token return spree.edit_spree_user_password_path( - reset_password_token: resource.reset_password_token + reset_password_token: raw_reset_password_token ) end diff --git a/app/controllers/user_passwords_controller.rb b/app/controllers/user_passwords_controller.rb index e467e915e2..9200b9b6ef 100644 --- a/app/controllers/user_passwords_controller.rb +++ b/app/controllers/user_passwords_controller.rb @@ -10,7 +10,7 @@ class UserPasswordsController < Spree::UserPasswordsController if resource.errors.empty? set_flash_message(:success, :send_instructions) if is_navigational_format? - respond_with resource, location: spree.login_path + respond_with resource, location: main_app.login_path else respond_to do |format| format.html do diff --git a/app/controllers/user_registrations_controller.rb b/app/controllers/user_registrations_controller.rb index d6fdf5ac76..f02309bf71 100644 --- a/app/controllers/user_registrations_controller.rb +++ b/app/controllers/user_registrations_controller.rb @@ -16,7 +16,6 @@ class UserRegistrationsController < Spree::UserRegistrationsController return render_error(@user.errors) end - session[:spree_user_signup] = true session[:confirmation_return_url] = params[:return_url] associate_user diff --git a/app/jobs/subscription_confirm_job.rb b/app/jobs/subscription_confirm_job.rb index 9ed8223d0e..acf241e4e0 100644 --- a/app/jobs/subscription_confirm_job.rb +++ b/app/jobs/subscription_confirm_job.rb @@ -45,27 +45,33 @@ class SubscriptionConfirmJob def confirm_order!(order) record_order(order) - if process_payment!(order) - send_confirmation_email(order) - else + process_payment!(order) + send_confirmation_email(order) + rescue StandardError => e + if order.errors.any? send_failed_payment_email(order) + else + Bugsnag.notify(e, order: order) + send_failed_payment_email(order, e.message) end end + # Process the order payment and raise if it's not successful def process_payment!(order) - return false if order.errors.present? - return true unless order.payment_required? + raise if order.errors.present? + return unless order.payment_required? + prepare_for_payment!(order) + order.process_payments! + raise if order.errors.any? + end + + def prepare_for_payment!(order) setup_payment!(order) - return false if order.errors.any? + raise if order.errors.any? authorize_payment!(order) - return false if order.errors.any? - - order.process_payments! - return false if order.errors.any? - - true + raise if order.errors.any? end def setup_payment!(order) @@ -87,9 +93,11 @@ class SubscriptionConfirmJob SubscriptionMailer.confirmation_email(order).deliver end - def send_failed_payment_email(order) + def send_failed_payment_email(order, error_message = nil) order.update! - record_and_log_error(:failed_payment, order) + record_and_log_error(:failed_payment, order, error_message) SubscriptionMailer.failed_payment_email(order).deliver + rescue StandardError => e + Bugsnag.notify(e, order: order, error_message: error_message) end end diff --git a/app/jobs/subscription_placement_job.rb b/app/jobs/subscription_placement_job.rb index 8b5df2b159..b15947895b 100644 --- a/app/jobs/subscription_placement_job.rb +++ b/app/jobs/subscription_placement_job.rb @@ -29,10 +29,16 @@ class SubscriptionPlacementJob def place_order_for(proxy_order) JobLogger.logger.info("Placing Order for Proxy Order #{proxy_order.id}") - proxy_order.initialise_order! + initialise_order(proxy_order) place_order(proxy_order.order) end + def initialise_order(proxy_order) + proxy_order.initialise_order! + rescue StandardError => e + Bugsnag.notify(e, subscription: proxy_order.subscription, proxy_order: proxy_order) + end + def place_order(order) record_order(order) return record_issue(:complete, order) if order.completed? @@ -42,8 +48,9 @@ class SubscriptionPlacementJob move_to_completion(order) send_placement_email(order, changes) - rescue StateMachine::InvalidTransition - record_and_log_error(:processing, order) + rescue StandardError => e + record_and_log_error(:processing, order, e.message) + Bugsnag.notify(e, order: order) end def cap_quantity_and_store_changes(order) @@ -66,7 +73,7 @@ class SubscriptionPlacementJob end def move_to_completion(order) - AdvanceOrderService.new(order).call! + OrderWorkflow.new(order).complete! end def unavailable_stock_lines_for(order) diff --git a/app/mailers/spree/base_mailer.rb b/app/mailers/spree/base_mailer.rb new file mode 100644 index 0000000000..fb46bf54bc --- /dev/null +++ b/app/mailers/spree/base_mailer.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Spree + class BaseMailer < ActionMailer::Base + # Inline stylesheets + include Roadie::Rails::Automatic + + layout 'mailer' + + def from_address + Spree::Config[:mails_from] + end + + def money(amount) + Spree::Money.new(amount).to_s + end + helper_method :money + + protected + + def roadie_options + # This lets us specify assets using relative paths in email templates + super.merge(url_options: { host: URI(main_app.root_url).host }) + end + end +end diff --git a/app/mailers/spree/base_mailer_decorator.rb b/app/mailers/spree/base_mailer_decorator.rb deleted file mode 100644 index 4c15268676..0000000000 --- a/app/mailers/spree/base_mailer_decorator.rb +++ /dev/null @@ -1,14 +0,0 @@ -Spree::BaseMailer.class_eval do - # Inline stylesheets - include Roadie::Rails::Automatic - - # Define layout - layout 'mailer' - - protected - - def roadie_options - # This lets us specify assets using relative paths in email templates - super.merge(url_options: { host: URI(main_app.root_url).host }) - end -end diff --git a/app/mailers/spree/order_mailer.rb b/app/mailers/spree/order_mailer.rb new file mode 100644 index 0000000000..ce9b79874e --- /dev/null +++ b/app/mailers/spree/order_mailer.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Spree + class OrderMailer < BaseMailer + helper HtmlHelper + helper ::CheckoutHelper + helper SpreeCurrencyHelper + helper OrderHelper + include I18nHelper + + def cancel_email(order_or_order_id, resend = false) + @order = find_order(order_or_order_id) + I18n.with_locale valid_locale(@order.user) do + mail(to: @order.email, + from: from_address, + subject: mail_subject(t('spree.order_mailer.cancel_email.subject'), resend)) + end + end + + def confirm_email_for_customer(order_or_order_id, resend = false) + @order = find_order(order_or_order_id) + I18n.with_locale valid_locale(@order.user) do + subject = mail_subject(t('spree.order_mailer.confirm_email.subject'), resend) + mail(to: @order.email, + from: from_address, + subject: subject, + reply_to: @order.distributor.contact.email) + end + end + + def confirm_email_for_shop(order_or_order_id, resend = false) + @order = find_order(order_or_order_id) + I18n.with_locale valid_locale(@order.user) do + subject = mail_subject(t('spree.order_mailer.confirm_email.subject'), resend) + mail(to: @order.distributor.contact.email, + from: from_address, + subject: subject) + end + end + + def invoice_email(order_or_order_id, pdf) + @order = find_order(order_or_order_id) + attach_file("invoice-#{@order.number}.pdf", pdf) + I18n.with_locale valid_locale(@order.user) do + mail(to: @order.email, + from: from_address, + subject: mail_subject(t(:invoice), false), + reply_to: @order.distributor.contact.email) + end + end + + private + + # Finds an order instance from an order or from an order id + def find_order(order_or_order_id) + order_or_order_id.respond_to?(:id) ? order_or_order_id : Spree::Order.find(order_or_order_id) + end + + def mail_subject(base_subject, resend) + resend_prefix = (resend ? "[#{t(:resend).upcase}] " : '') + "#{resend_prefix}#{Spree::Config[:site_name]} #{base_subject} ##{@order.number}" + end + + def attach_file(filename, file) + attachments[filename] = file if file.present? + end + end +end diff --git a/app/mailers/spree/order_mailer_decorator.rb b/app/mailers/spree/order_mailer_decorator.rb deleted file mode 100644 index fbf17013b8..0000000000 --- a/app/mailers/spree/order_mailer_decorator.rb +++ /dev/null @@ -1,64 +0,0 @@ -Spree::OrderMailer.class_eval do - helper HtmlHelper - helper CheckoutHelper - helper SpreeCurrencyHelper - helper OrderHelper - include I18nHelper - - def cancel_email(order_or_order_id, resend = false) - @order = find_order(order_or_order_id) - I18n.with_locale valid_locale(@order.user) do - mail(to: @order.email, - from: from_address, - subject: mail_subject(t('spree.order_mailer.cancel_email.subject'), resend)) - end - end - - def confirm_email_for_customer(order_or_order_id, resend = false) - @order = find_order(order_or_order_id) - I18n.with_locale valid_locale(@order.user) do - subject = mail_subject(t('spree.order_mailer.confirm_email.subject'), resend) - mail(to: @order.email, - from: from_address, - subject: subject, - reply_to: @order.distributor.contact.email) - end - end - - def confirm_email_for_shop(order_or_order_id, resend = false) - @order = find_order(order_or_order_id) - I18n.with_locale valid_locale(@order.user) do - subject = mail_subject(t('spree.order_mailer.confirm_email.subject'), resend) - mail(to: @order.distributor.contact.email, - from: from_address, - subject: subject) - end - end - - def invoice_email(order_or_order_id, pdf) - @order = find_order(order_or_order_id) - attach_file("invoice-#{@order.number}.pdf", pdf) - I18n.with_locale valid_locale(@order.user) do - mail(to: @order.email, - from: from_address, - subject: mail_subject(t(:invoice), false), - reply_to: @order.distributor.contact.email) - end - end - - private - - # Finds an order instance from an order or from an order id - def find_order(order_or_order_id) - order_or_order_id.respond_to?(:id) ? order_or_order_id : Spree::Order.find(order_or_order_id) - end - - def mail_subject(base_subject, resend) - resend_prefix = (resend ? "[#{t(:resend).upcase}] " : '') - "#{resend_prefix}#{Spree::Config[:site_name]} #{base_subject} ##{@order.number}" - end - - def attach_file(filename, file) - attachments[filename] = file if file.present? - end -end diff --git a/app/mailers/spree/shipment_mailer.rb b/app/mailers/spree/shipment_mailer.rb new file mode 100644 index 0000000000..3b25885f81 --- /dev/null +++ b/app/mailers/spree/shipment_mailer.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Spree + class ShipmentMailer < BaseMailer + def shipped_email(shipment, resend = false) + @shipment = shipment.respond_to?(:id) ? shipment : Spree::Shipment.find(shipment) + subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '') + base_subject = t('spree.shipment_mailer.shipped_email.subject') + subject += "#{Spree::Config[:site_name]} #{base_subject} ##{@shipment.order.number}" + mail(to: @shipment.order.email, from: from_address, subject: subject) + end + end +end diff --git a/app/mailers/spree/test_mailer.rb b/app/mailers/spree/test_mailer.rb new file mode 100644 index 0000000000..316de40341 --- /dev/null +++ b/app/mailers/spree/test_mailer.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Spree + class TestMailer < BaseMailer + def test_email(user) + recipient = user.respond_to?(:id) ? user : Spree.user_class.find(user) + subject = "#{Spree::Config[:site_name]} #{t('spree.test_mailer.test_email.subject')}" + mail(to: recipient.email, from: from_address, subject: subject) + end + end +end diff --git a/app/mailers/spree/user_mailer.rb b/app/mailers/spree/user_mailer.rb index ba25809b5d..a93aff05a5 100644 --- a/app/mailers/spree/user_mailer.rb +++ b/app/mailers/spree/user_mailer.rb @@ -5,12 +5,11 @@ module Spree include I18nHelper # Overrides `Devise::Mailer.reset_password_instructions` - def reset_password_instructions(user) - recipient = user.respond_to?(:id) ? user : Spree.user_class.find(user) + def reset_password_instructions(user, token, _opts = {}) @edit_password_reset_url = spree. - edit_spree_user_password_url(reset_password_token: recipient.reset_password_token) + edit_spree_user_password_url(reset_password_token: token) - mail(to: recipient.email, from: from_address, + mail(to: user.email, from: from_address, subject: Spree::Config[:site_name] + ' ' + I18n.t(:subject, scope: [:devise, :mailer, :reset_password_instructions])) end @@ -25,8 +24,9 @@ module Spree end # Overrides `Devise::Mailer.confirmation_instructions` - def confirmation_instructions(user, _opts) + def confirmation_instructions(user, token, _opts = {}) @user = user + @token = token @instance = Spree::Config[:site_name] @contact = ContentConfig.footer_email diff --git a/app/models/content_configuration.rb b/app/models/content_configuration.rb index 39d4fd9a5c..efe91e05b6 100644 --- a/app/models/content_configuration.rb +++ b/app/models/content_configuration.rb @@ -21,6 +21,8 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration preference :open_street_map_enabled, :boolean, default: false preference :open_street_map_provider_name, :string, default: "OpenStreetMap.Mapnik" preference :open_street_map_provider_options, :text, default: "{}" + preference :open_street_map_default_latitude, :string, default: "-37.4713077" + preference :open_street_map_default_longitude, :string, default: "144.7851531" # Producer sign-up page # All the following defaults using I18n don't work. diff --git a/app/models/order_updater.rb b/app/models/order_updater.rb deleted file mode 100644 index 20fa94e5b4..0000000000 --- a/app/models/order_updater.rb +++ /dev/null @@ -1,92 +0,0 @@ -require 'delegate' - -class OrderUpdater < SimpleDelegator - # TODO: This logic adapted from Spree 2.4, remove when we get there - # Handles state updating in a much more logical way than < 2.4 - # Specifically, doesn't depend on payments.last to determine payment state - # Also swapped: == 0 for .zero?, .size == 0 for empty? and .size > 0 for !empty? - # See: - # https://github.com/spree/spree/commit/38b8456183d11fc1e00e395e7c9154c76ef65b85 - # https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a - def update_payment_state - last_payment_state = order.payment_state - - order.payment_state = infer_payment_state - track_payment_state_change(last_payment_state) - - order.payment_state - end - - def before_save_hook - shipping_address_from_distributor - end - - # Sets the distributor's address as shipping address of the order for those - # shipments using a shipping method that doesn't require address, such us - # a pickup. - def shipping_address_from_distributor - return if order.shipping_method.blank? || order.shipping_method.require_ship_address - - order.ship_address = order.address_from_distributor - end - - private - - def infer_payment_state - if failed_payments? - 'failed' - elsif canceled_and_not_paid_for? - 'void' - else - infer_payment_state_from_balance - end - end - - def infer_payment_state_from_balance - # This part added so that we don't need to override - # order.outstanding_balance - balance = order.outstanding_balance - balance = -1 * order.payment_total if canceled_and_paid_for? - - infer_state(balance) - end - - def infer_state(balance) - if balance > 0 - 'balance_due' - elsif balance < 0 - 'credit_owed' - elsif balance.zero? - 'paid' - end - end - - # Tracks the state transition through a state_change for this order. It - # does so until the last state is reached. That is, when the infered next - # state is the same as the order has now. - # - # @param last_payment_state [String] - def track_payment_state_change(last_payment_state) - return if last_payment_state == order.payment_state - - order.state_changed('payment') - end - - # Taken from order.outstanding_balance in Spree 2.4 - # See: https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a - def canceled_and_paid_for? - order.canceled? && paid? - end - - def canceled_and_not_paid_for? - order.state == 'canceled' && order.payment_total.zero? - end - - def paid? - payments.present? && !payments.completed.empty? - end - - def failed_payments? - payments.present? && payments.valid.empty? - end -end diff --git a/app/models/preference_sections/map_section.rb b/app/models/preference_sections/map_section.rb index cc16939c36..deed329b44 100644 --- a/app/models/preference_sections/map_section.rb +++ b/app/models/preference_sections/map_section.rb @@ -10,7 +10,9 @@ module PreferenceSections [ :open_street_map_enabled, :open_street_map_provider_name, - :open_street_map_provider_options + :open_street_map_provider_options, + :open_street_map_default_latitude, + :open_street_map_default_longitude ] end end diff --git a/app/models/spree/credit_card.rb b/app/models/spree/credit_card.rb new file mode 100644 index 0000000000..948dcf829d --- /dev/null +++ b/app/models/spree/credit_card.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +module Spree + class CreditCard < ActiveRecord::Base + belongs_to :payment_method + belongs_to :user + + has_many :payments, as: :source + + before_save :set_last_digits + + attr_accessor :verification_value + attr_reader :number + attr_writer :save_requested_by_customer # For holding customer preference in memory + + validates :month, :year, numericality: { only_integer: true } + validates :number, presence: true, unless: :has_payment_profile?, on: :create + validates :verification_value, presence: true, unless: :has_payment_profile?, on: :create + validate :expiry_not_in_the_past + + after_create :ensure_single_default_card + after_save :ensure_single_default_card, if: :default_card_needs_updating? + + scope :with_payment_profile, -> { where('gateway_customer_profile_id IS NOT NULL') } + + # needed for some of the ActiveMerchant gateways (eg. SagePay) + alias_attribute :brand, :cc_type + + def expiry=(expiry) + self[:month], self[:year] = expiry.split(" / ") + self[:year] = "20" + self[:year] + end + + def number=(num) + @number = begin + num.gsub(/[^0-9]/, '') + rescue StandardError + nil + end + end + + # cc_type is set by jquery.payment, which helpfully provides different + # types from Active Merchant. Converting them is necessary. + def cc_type=(type) + real_type = case type + when 'mastercard', 'maestro' + 'master' + when 'amex' + 'american_express' + when 'dinersclub' + 'diners_club' + else + type + end + self[:cc_type] = real_type + end + + def set_last_digits + number.to_s.gsub!(/\s/, '') + verification_value.to_s.gsub!(/\s/, '') + self.last_digits ||= number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1) + end + + def name? + first_name? && last_name? + end + + def name + "#{first_name} #{last_name}" + end + + def verification_value? + verification_value.present? + end + + # Show the card number, with all but last 4 numbers replace with "X". (XXXX-XXXX-XXXX-4338) + def display_number + "XXXX-XXXX-XXXX-#{last_digits}" + end + + def actions + %w{capture void credit} + end + + # Indicates whether its possible to capture the payment + def can_capture?(payment) + payment.pending? || payment.checkout? + end + + # Indicates whether its possible to void the payment. + def can_void?(payment) + !payment.void? + end + + # Indicates whether its possible to credit the payment. Note that most gateways require that the + # payment be settled first which generally happens within 12-24 hours of the transaction. + def can_credit?(payment) + return false unless payment.completed? + return false unless payment.order.payment_state == 'credit_owed' + + payment.credit_allowed.positive? + end + + # Allows us to use a gateway_payment_profile_id to store Stripe Tokens + def has_payment_profile? + gateway_customer_profile_id.present? || gateway_payment_profile_id.present? + end + + def to_active_merchant + ActiveMerchant::Billing::CreditCard.new( + number: number, + month: month, + year: year, + verification_value: verification_value, + first_name: first_name, + last_name: last_name + ) + end + + def save_requested_by_customer? + !!@save_requested_by_customer + end + + private + + def expiry_not_in_the_past + return unless year.present? && month.present? + + time = "#{year}-#{month}-1".to_time + return unless time < Time.zone.now.to_time.beginning_of_month + + errors.add(:base, :card_expired) + end + + def reusable? + gateway_customer_profile_id.present? + end + + def default_missing? + !user.credit_cards.exists?(is_default: true) + end + + def default_card_needs_updating? + is_default_changed? || gateway_customer_profile_id_changed? + end + + def ensure_single_default_card + return unless user + return unless is_default? || (reusable? && default_missing?) + + user.credit_cards.update_all(['is_default=(id=?)', id]) + self.is_default = true + end + end +end diff --git a/app/models/spree/credit_card_decorator.rb b/app/models/spree/credit_card_decorator.rb deleted file mode 100644 index b8c78f01b7..0000000000 --- a/app/models/spree/credit_card_decorator.rb +++ /dev/null @@ -1,47 +0,0 @@ -Spree::CreditCard.class_eval do - # For holding customer preference in memory - 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 - - after_create :ensure_single_default_card - after_save :ensure_single_default_card, if: :default_card_needs_updating? - - # 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 Naming/PredicateName - gateway_customer_profile_id.present? || gateway_payment_profile_id.present? - end - - def save_requested_by_customer? - !!@save_requested_by_customer - end - - private - - def reusable? - gateway_customer_profile_id.present? - end - - def default_missing? - !user.credit_cards.exists?(is_default: true) - end - - def default_card_needs_updating? - is_default_changed? || gateway_customer_profile_id_changed? - end - - def ensure_single_default_card - return unless user - return unless is_default? || (reusable? && default_missing?) - - user.credit_cards.update_all(['is_default=(id=?)', id]) - self.is_default = true - end -end diff --git a/app/models/spree/gateway.rb b/app/models/spree/gateway.rb new file mode 100644 index 0000000000..216f0cfe6b --- /dev/null +++ b/app/models/spree/gateway.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spree/concerns/payment_method_distributors' + +module Spree + class Gateway < PaymentMethod + include Spree::PaymentMethodDistributors + + delegate_belongs_to :provider, :authorize, :purchase, :capture, :void, :credit + + validates :name, :type, presence: true + + # Default to live + preference :server, :string, default: 'live' + preference :test_mode, :boolean, default: false + + def payment_source_class + CreditCard + end + + # instantiates the selected gateway and configures with the options stored in the database + def self.current + super + end + + def provider + gateway_options = options + gateway_options.delete :login if gateway_options.key?(:login) && gateway_options[:login].nil? + if gateway_options[:server] + ActiveMerchant::Billing::Base.gateway_mode = gateway_options[:server].to_sym + end + @provider ||= provider_class.new(gateway_options) + end + + def options + preferences.each_with_object({}){ |(key, value), memo| memo[key.to_sym] = value; } + end + + def method_missing(method, *args) + if @provider.nil? || !@provider.respond_to?(method) + super + else + provider.__send__(method, *args) + end + end + + def payment_profiles_supported? + false + end + + def method_type + 'gateway' + end + + def supports?(source) + return true unless provider_class.respond_to? :supports? + return false unless source.brand + + provider_class.supports?(source.brand) + end + end +end diff --git a/app/models/spree/gateway/bogus.rb b/app/models/spree/gateway/bogus.rb new file mode 100644 index 0000000000..76dde5f211 --- /dev/null +++ b/app/models/spree/gateway/bogus.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module Spree + class Gateway + class Bogus < Spree::Gateway + TEST_VISA = ['4111111111111111', '4012888888881881', '4222222222222'].freeze + TEST_MC = ['5500000000000004', '5555555555554444', '5105105105105100'].freeze + TEST_AMEX = ['378282246310005', '371449635398431', + '378734493671000', '340000000000009'].freeze + TEST_DISC = ['6011000000000004', '6011111111111117', '6011000990139424'].freeze + + VALID_CCS = ['1', TEST_VISA, TEST_MC, TEST_AMEX, TEST_DISC].flatten + + attr_accessor :test + + def provider_class + self.class + end + + def preferences + {} + end + + def create_profile(payment) + # simulate the storage of credit card profile using remote service + success = VALID_CCS.include? payment.source.number + payment.source.update(gateway_customer_profile_id: generate_profile_id(success)) + end + + def authorize(_money, credit_card, _options = {}) + profile_id = credit_card.gateway_customer_profile_id + if VALID_CCS.include?(credit_card.number) || profile_id&.starts_with?('BGS-') + ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {}, + test: true, authorization: '12345', + avs_result: { code: 'A' }) + else + ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure', + { message: 'Bogus Gateway: Forced failure' }, + test: true) + end + end + + def purchase(_money, credit_card, _options = {}) + profile_id = credit_card.gateway_customer_profile_id + if VALID_CCS.include?(credit_card.number) || profile_id&.starts_with?('BGS-') + ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {}, + test: true, authorization: '12345', + avs_result: { code: 'A' }) + else + ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure', + message: 'Bogus Gateway: Forced failure', + test: true) + end + end + + def credit(_money, _credit_card, _response_code, _options = {}) + ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {}, + test: true, authorization: '12345') + end + + def capture(authorization, _credit_card, _gateway_options) + if authorization.response_code == '12345' + ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {}, + test: true, authorization: '67890') + else + ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure', + error: 'Bogus Gateway: Forced failure', test: true) + end + end + + def void(_response_code, _credit_card, _options = {}) + ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {}, + test: true, authorization: '12345') + end + + def test? + # Test mode is not really relevant with bogus gateway (no such thing as live server) + true + end + + def payment_profiles_supported? + true + end + + def actions + %w(capture void credit) + end + + private + + def generate_profile_id(success) + record = true + prefix = success ? 'BGS' : 'FAIL' + while record + random = "#{prefix}-#{Array.new(6){ rand(6) }.join}" + record = CreditCard.find_by(gateway_customer_profile_id: random) + end + random + end + end + end +end diff --git a/app/models/spree/gateway/bogus_simple.rb b/app/models/spree/gateway/bogus_simple.rb new file mode 100644 index 0000000000..2a7c9e7778 --- /dev/null +++ b/app/models/spree/gateway/bogus_simple.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Bogus Gateway that doesn't support payment profiles +module Spree + class Gateway + class BogusSimple < Spree::Gateway::Bogus + def payment_profiles_supported? + false + end + + def authorize(_money, credit_card, _options = {}) + if VALID_CCS.include? credit_card.number + ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {}, + test: true, authorization: '12345', + avs_result: { code: 'A' }) + else + ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure', + { message: 'Bogus Gateway: Forced failure' }, + test: true) + end + end + + def purchase(_money, credit_card, _options = {}) + if VALID_CCS.include? credit_card.number + ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {}, + test: true, authorization: '12345', + avs_result: { code: 'A' }) + else + ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure', + message: 'Bogus Gateway: Forced failure', + test: true) + end + end + end + end +end diff --git a/app/models/spree/gateway_decorator.rb b/app/models/spree/gateway_decorator.rb deleted file mode 100644 index c62702a321..0000000000 --- a/app/models/spree/gateway_decorator.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'spree/concerns/payment_method_distributors' - -Spree::Gateway.class_eval do - include Spree::PaymentMethodDistributors - - # Default to live - preference :server, :string, default: 'live' - preference :test_mode, :boolean, default: false -end diff --git a/app/models/spree/order/checkout.rb b/app/models/spree/order/checkout.rb new file mode 100644 index 0000000000..ffecf63f23 --- /dev/null +++ b/app/models/spree/order/checkout.rb @@ -0,0 +1,191 @@ +# frozen_string_literal: true + +module Spree + class Order < ActiveRecord::Base + module Checkout + def self.included(klass) + klass.class_eval do + class_attribute :next_event_transitions + class_attribute :previous_states + class_attribute :checkout_flow + class_attribute :checkout_steps + class_attribute :removed_transitions + + def self.checkout_flow(&block) + if block_given? + @checkout_flow = block + define_state_machine! + else + @checkout_flow + end + end + + def self.define_state_machine! + self.checkout_steps = {} + self.next_event_transitions = [] + self.previous_states = [:cart] + self.removed_transitions = [] + + # Build the checkout flow using the checkout_flow defined either + # within the Order class, or a decorator for that class. + # + # This method may be called multiple times depending on if the + # checkout_flow is re-defined in a decorator or not. + instance_eval(&checkout_flow) + + klass = self + + # To avoid a ton of warnings when the state machine is re-defined + StateMachine::Machine.ignore_method_conflicts = true + # To avoid multiple occurrences of the same transition being defined + # On first definition, state_machines will not be defined + state_machines.clear if respond_to?(:state_machines) + state_machine :state, initial: :cart do + klass.next_event_transitions.each { |t| transition(t.merge(on: :next)) } + + # Persist the state on the order + after_transition do |order| + order.state = order.state + order.save + end + + event :cancel do + transition to: :canceled, if: :allow_cancel? + end + + event :return do + transition to: :returned, from: :awaiting_return, unless: :awaiting_returns? + end + + event :resume do + transition to: :resumed, from: :canceled, if: :allow_resume? + end + + event :authorize_return do + transition to: :awaiting_return + end + + if states[:payment] + before_transition to: :complete do |order| + order.process_payments! if order.payment_required? + end + end + + before_transition from: :cart, do: :ensure_line_items_present + + before_transition to: :delivery, do: :create_proposed_shipments + before_transition to: :delivery, do: :ensure_available_shipping_rates + + after_transition to: :complete, do: :finalize! + after_transition to: :delivery, do: :create_tax_charge! + after_transition to: :resumed, do: :after_resume + after_transition to: :canceled, do: :after_cancel + end + end + + def self.go_to_state(name, options = {}) + checkout_steps[name] = options + previous_states.each do |state| + add_transition({ from: state, to: name }.merge(options)) + end + if options[:if] + previous_states << name + else + self.previous_states = [name] + end + end + + def self.insert_checkout_step(name, options = {}) + before = options.delete(:before) + after = options.delete(:after) unless before + after = checkout_steps.keys.last unless before || after + + cloned_steps = checkout_steps.clone + cloned_removed_transitions = removed_transitions.clone + checkout_flow do + cloned_steps.each_pair do |key, value| + go_to_state(name, options) if key == before + go_to_state(key, value) + go_to_state(name, options) if key == after + end + cloned_removed_transitions.each do |transition| + remove_transition(transition) + end + end + end + + def self.remove_checkout_step(name) + cloned_steps = checkout_steps.clone + cloned_removed_transitions = removed_transitions.clone + checkout_flow do + cloned_steps.each_pair do |key, value| + go_to_state(key, value) unless key == name + end + cloned_removed_transitions.each do |transition| + remove_transition(transition) + end + end + end + + def self.remove_transition(options = {}) + removed_transitions << options + next_event_transitions.delete(find_transition(options)) + end + + def self.find_transition(options = {}) + return nil if options.nil? || !options.include?(:from) || !options.include?(:to) + + next_event_transitions.detect do |transition| + transition[options[:from].to_sym] == options[:to].to_sym + end + end + + def self.next_event_transitions + @next_event_transitions ||= [] + end + + def self.checkout_steps + @checkout_steps ||= {} + end + + def self.add_transition(options) + next_event_transitions << { options.delete(:from) => options.delete(:to) }. + merge(options) + end + + def checkout_steps + steps = self.class.checkout_steps. + each_with_object([]) { |(step, options), checkout_steps| + next if options.include?(:if) && !options[:if].call(self) + + checkout_steps << step + }.map(&:to_s) + # Ensure there is always a complete step + steps << "complete" unless steps.include?("complete") + steps + end + + def checkout_step?(step) + step.present? ? checkout_steps.include?(step) : false + end + + def checkout_step_index(step) + checkout_steps.index(step) + end + + def self.removed_transitions + @removed_transitions ||= [] + end + + def can_go_to_state?(state) + return false unless self.state.present? && + checkout_step?(state) && + checkout_step?(self.state) + + checkout_step_index(state) > checkout_step_index(self.state) + end + end + end + end + end +end diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index 71574359a7..bf125da21d 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -89,6 +89,10 @@ Spree::Order.class_eval do where("state != ?", state) } + def updater + @updater ||= OrderManagement::Order::Updater.new(self) + end + def create_proposed_shipments adjustments.shipping.delete_all shipments.destroy_all @@ -374,6 +378,13 @@ Spree::Order.class_eval do address end + # Update attributes of a record in the database without callbacks, validations etc. + # This was originally an extension to ActiveRecord in Spree but only used for Spree::Order + def update_attributes_without_callbacks(attributes) + assign_attributes(attributes) + Spree::Order.where(id: id).update_all(attributes) + end + private def adjustments_fetcher @@ -432,8 +443,8 @@ Spree::Order.class_eval do # amount here. def charge_shipping_and_payment_fees! update_totals - return unless payments.any? + return unless pending_payments.any? - payments.first.update_attribute :amount, total + pending_payments.first.update_attribute :amount, total end end diff --git a/app/models/spree/order_updater_decorator.rb b/app/models/spree/order_updater_decorator.rb deleted file mode 100644 index b227444c8b..0000000000 --- a/app/models/spree/order_updater_decorator.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -Spree::OrderUpdater.class_eval do - # Override spree method to make it update all adjustments as in Spree v2.0.4 - def update_shipping_adjustments - order.adjustments.reload.each(&:update!) - end -end diff --git a/app/models/spree/payment.rb b/app/models/spree/payment.rb new file mode 100644 index 0000000000..754119034a --- /dev/null +++ b/app/models/spree/payment.rb @@ -0,0 +1,216 @@ +# frozen_string_literal: true + +module Spree + class Payment < ActiveRecord::Base + include Spree::Payment::Processing + extend Spree::LocalizedNumber + + localize_number :amount + + IDENTIFIER_CHARS = (('A'..'Z').to_a + ('0'..'9').to_a - %w(0 1 I O)).freeze + + delegate :line_items, to: :order + delegate :currency, to: :order + + belongs_to :order, class_name: 'Spree::Order' + belongs_to :source, polymorphic: true + belongs_to :payment_method, class_name: 'Spree::PaymentMethod' + + has_many :offsets, -> { where("source_type = 'Spree::Payment' AND amount < 0").completed }, + class_name: "Spree::Payment", foreign_key: :source_id + has_many :log_entries, as: :source, dependent: :destroy + + has_one :adjustment, as: :source, dependent: :destroy + + validate :validate_source + before_save :set_unique_identifier + + after_save :create_payment_profile, if: :profiles_supported? + + # update the order totals, etc. + after_save :ensure_correct_adjustment, :update_order + # invalidate previously entered payments + after_create :invalidate_old_payments + + # Skips the validation of the source (for example, credit card) of the payment. + # + # This is used in refunds as the validation of the card can fail but the refund can go through, + # we trust the payment gateway in these cases. For example, Stripe is accepting refunds with + # source cards that were valid when the payment was placed but are now expired, and we + # consider them invalid. + attr_accessor :skip_source_validation + attr_accessor :source_attributes + + after_initialize :build_source + + scope :from_credit_card, -> { where(source_type: 'Spree::CreditCard') } + scope :with_state, ->(s) { where(state: s.to_s) } + scope :completed, -> { with_state('completed') } + scope :pending, -> { with_state('pending') } + scope :failed, -> { with_state('failed') } + scope :valid, -> { where('state NOT IN (?)', %w(failed invalid)) } + + # order state machine (see http://github.com/pluginaweek/state_machine/tree/master for details) + state_machine initial: :checkout do + # With card payments, happens before purchase or authorization happens + event :started_processing do + transition from: [:checkout, :pending, :completed, :processing], to: :processing + end + # When processing during checkout fails + event :failure do + transition from: [:pending, :processing], to: :failed + end + # With card payments this represents authorizing the payment + event :pend do + transition from: [:checkout, :processing], to: :pending + end + # With card payments this represents completing a purchase or capture transaction + event :complete do + transition from: [:processing, :pending, :checkout], to: :completed + end + event :void do + transition from: [:pending, :completed, :checkout], to: :void + end + # when the card brand isnt supported + event :invalidate do + transition from: [:checkout], to: :invalid + end + end + + def money + Spree::Money.new(amount, currency: currency) + end + alias display_amount money + + def offsets_total + offsets.pluck(:amount).sum + end + + def credit_allowed + amount - offsets_total + end + + def can_credit? + credit_allowed.positive? + end + + 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 + + # Pin payments lacks void and credit methods, but it does have refund + # Here we swap credit out for refund and remove void as a possible action + def actions + return [] unless payment_source&.respond_to?(:actions) + + actions = payment_source.actions.select do |action| + !payment_source.respond_to?("can_#{action}?") || + payment_source.__send__("can_#{action}?", self) + end + + if payment_method.is_a? Gateway::Pin + actions << 'refund' if actions.include? 'credit' + actions.reject! { |a| ['credit', 'void'].include? a } + end + + actions + end + + def payment_source + res = source.is_a?(Payment) ? source.source : source + res || payment_method + end + + def ensure_correct_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 + else + payment_method.create_adjustment(adjustment_label, order, self, true) + association(:adjustment).reload + end + end + + def adjustment_label + I18n.t('payment_method_fee') + end + + private + + # 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 + + def validate_source + if source && !skip_source_validation && !source.valid? + source.errors.each do |field, error| + field_name = I18n.t("activerecord.attributes.#{source.class.to_s.underscore}.#{field}") + errors.add(Spree.t(source.class.to_s.demodulize.underscore), "#{field_name} #{error}") + end + end + errors.blank? + end + + def profiles_supported? + payment_method.respond_to?(:payment_profiles_supported?) && + payment_method.payment_profiles_supported? + 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 + + # Makes newly entered payments invalidate previously entered payments so the most recent payment + # is used by the gateway. + def invalidate_old_payments + order.payments.with_state('checkout').where.not(id: id).each do |payment| + # Using update_column skips validations and so it skips validate_source. As we are just + # invalidating past payments here, we don't want to validate all of them at this stage. + payment.update_column(:state, 'invalid') + payment.ensure_correct_adjustment + end + end + + def update_order + order.payments.reload + order.update! + end + + # Necessary because some payment gateways will refuse payments with + # duplicate IDs. We *were* using the Order number, but that's set once and + # is unchanging. What we need is a unique identifier on a per-payment basis, + # and this is it. Related to #1998. + # See https://github.com/spree/spree/issues/1998#issuecomment-12869105 + def set_unique_identifier + self.identifier = generate_identifier while self.class.exists?(identifier: identifier) + end + + def generate_identifier + Array.new(8){ IDENTIFIER_CHARS.sample }.join + end + end +end diff --git a/app/models/spree/payment/processing.rb b/app/models/spree/payment/processing.rb new file mode 100644 index 0000000000..2579f76de7 --- /dev/null +++ b/app/models/spree/payment/processing.rb @@ -0,0 +1,277 @@ +# frozen_string_literal: true + +module Spree + class Payment < ActiveRecord::Base + module Processing + def process! + return unless payment_method&.source_required? + + raise Core::GatewayError, Spree.t(:payment_processing_failed) unless source + + return if processing? + + unless payment_method.supports?(source) + invalidate! + raise Core::GatewayError, Spree.t(:payment_method_not_supported) + end + + if payment_method.auto_capture? + purchase! + else + authorize! + end + end + + def authorize! + started_processing! + gateway_action(source, :authorize, :pend) + end + + def purchase! + started_processing! + gateway_action(source, :purchase, :complete) + end + + def capture! + return true if completed? + + started_processing! + protect_from_connection_error do + check_environment + + response = if payment_method.payment_profiles_supported? + # Gateways supporting payment profiles will need access to credit + # card object because this stores the payment profile information + # so supply the authorization itself as well as the credit card, + # rather than just the authorization code + payment_method.capture(self, source, gateway_options) + else + # Standard ActiveMerchant capture usage + payment_method.capture(money.money.cents, + response_code, + gateway_options) + end + + handle_response(response, :complete, :failure) + end + end + + def void_transaction! + return true if void? + + protect_from_connection_error do + check_environment + + response = if payment_method.payment_profiles_supported? + # Gateways supporting payment profiles will need access to credit + # card object because this stores the payment profile information + # so supply the authorization itself as well as the credit card, + # rather than just the authorization code + payment_method.void(response_code, source, gateway_options) + else + # Standard ActiveMerchant void usage + payment_method.void(response_code, gateway_options) + end + + record_response(response) + + if response.success? + self.response_code = response.authorization + void + else + gateway_error(response) + end + end + end + + def credit!(credit_amount = nil) + protect_from_connection_error do + check_environment + + credit_amount = calculate_refund_amount(credit_amount) + + response = if payment_method.payment_profiles_supported? + payment_method.credit( + (credit_amount * 100).round, + source, + response_code, + gateway_options + ) + else + payment_method.credit( + (credit_amount * 100).round, + response_code, + gateway_options + ) + end + + record_response(response) + + if response.success? + self.class.create!( + order: order, + source: self, + payment_method: payment_method, + amount: credit_amount.abs * -1, + response_code: response.authorization, + state: 'completed', + skip_source_validation: true + ) + else + gateway_error(response) + end + end + end + + def refund!(refund_amount = nil) + protect_from_connection_error do + check_environment + + refund_amount = calculate_refund_amount(refund_amount) + + response = if payment_method.payment_profiles_supported? + payment_method.refund( + (refund_amount * 100).round, + source, + response_code, + gateway_options + ) + else + payment_method.refund( + (refund_amount * 100).round, + response_code, + gateway_options + ) + end + + record_response(response) + + if response.success? + self.class.create!( + order: order, + source: self, + payment_method: payment_method, + amount: refund_amount.abs * -1, + response_code: response.authorization, + state: 'completed', + skip_source_validation: true + ) + else + gateway_error(response) + end + end + end + + def partial_credit(amount) + return if amount > credit_allowed + + started_processing! + credit!(amount) + end + + def gateway_options + options = { email: order.email, + customer: order.email, + ip: order.last_ip_address, + # Need to pass in a unique identifier here to make some + # payment gateways happy. + # + # For more information, please see Spree::Payment#set_unique_identifier + order_id: gateway_order_id } + + options.merge!({ shipping: order.ship_total * 100, + tax: order.tax_total * 100, + subtotal: order.item_total * 100, + discount: order.promo_total * 100, + currency: currency }) + + options.merge!({ billing_address: order.bill_address.try(:active_merchant_hash), + shipping_address: order.ship_address.try(:active_merchant_hash) }) + + options + end + + private + + def calculate_refund_amount(refund_amount = nil) + refund_amount ||= if credit_allowed >= order.outstanding_balance.abs + order.outstanding_balance.abs + else + credit_allowed.abs + end + refund_amount.to_f + end + + def gateway_action(source, action, success_state) + protect_from_connection_error do + check_environment + + response = payment_method.public_send( + action, + (amount * 100).round, + source, + gateway_options + ) + handle_response(response, success_state, :failure) + end + end + + def handle_response(response, success_state, failure_state) + record_response(response) + + if response.success? + unless response.authorization.nil? + self.response_code = response.authorization + self.avs_response = response.avs_result['code'] + + if response.cvv_result + self.cvv_response_code = response.cvv_result['code'] + self.cvv_response_message = response.cvv_result['message'] + end + end + __send__("#{success_state}!") + else + __send__(failure_state) + gateway_error(response) + end + end + + def record_response(response) + log_entries.create(details: response.to_yaml) + end + + def protect_from_connection_error + yield + rescue ActiveMerchant::ConnectionError => e + gateway_error(e) + end + + def gateway_error(error) + text = if error.is_a? ActiveMerchant::Billing::Response + error.params['message'] || error.params['response_reason_text'] || error.message + elsif error.is_a? ActiveMerchant::ConnectionError + Spree.t(:unable_to_connect_to_gateway) + else + error.to_s + end + logger.error(Spree.t(:gateway_error)) + logger.error(" #{error.to_yaml}") + raise Core::GatewayError, text + end + + # Saftey check to make sure we're not accidentally performing operations on a live gateway. + # Ex. When testing in staging environment with a copy of production data. + def check_environment + return if payment_method.environment == Rails.env + + message = Spree.t(:gateway_config_unavailable) + " - #{Rails.env}" + raise Core::GatewayError, message + end + + # The unique identifier to be passed in to the payment gateway + def gateway_order_id + "#{order.number}-#{identifier}" + end + end + end +end diff --git a/app/models/spree/payment_decorator.rb b/app/models/spree/payment_decorator.rb deleted file mode 100644 index ec84a83a83..0000000000 --- a/app/models/spree/payment_decorator.rb +++ /dev/null @@ -1,117 +0,0 @@ -require 'spree/localized_number' - -module Spree - Payment.class_eval do - extend Spree::LocalizedNumber - - delegate :line_items, to: :order - - has_one :adjustment, as: :source, dependent: :destroy - - after_save :ensure_correct_adjustment, :update_order - - localize_number :amount - - # We bypass this after_rollback callback that is setup in Spree::Payment - # The issues the callback fixes are not experienced in OFN: - # if a payment fails on checkout the state "failed" is persisted correctly - def persist_invalid; end - - def ensure_correct_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 - else - payment_method.create_adjustment(adjustment_label, order, self, true) - association(:adjustment).reload - end - end - - def adjustment_label - I18n.t('payment_method_fee') - end - - # Pin payments lacks void and credit methods, but it does have refund - # Here we swap credit out for refund and remove void as a possible action - def actions_with_pin_payment_adaptations - actions = actions_without_pin_payment_adaptations - if payment_method.is_a? Gateway::Pin - actions << 'refund' if actions.include? 'credit' - actions.reject! { |a| ['credit', 'void'].include? a } - end - actions - end - alias_method_chain :actions, :pin_payment_adaptations - - def refund!(refund_amount = nil) - protect_from_connection_error do - check_environment - - refund_amount = calculate_refund_amount(refund_amount) - - if payment_method.payment_profiles_supported? - response = payment_method.refund((refund_amount * 100).round, source, response_code, gateway_options) - else - response = payment_method.refund((refund_amount * 100).round, response_code, gateway_options) - end - - record_response(response) - - if response.success? - self.class.create(order: order, - source: self, - payment_method: payment_method, - amount: refund_amount.abs * -1, - response_code: response.authorization, - state: 'completed') - else - gateway_error(response) - end - 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 - - def calculate_refund_amount(refund_amount = nil) - refund_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs - 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 diff --git a/app/models/spree/payment_method.rb b/app/models/spree/payment_method.rb new file mode 100644 index 0000000000..39df36486d --- /dev/null +++ b/app/models/spree/payment_method.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true + +require 'spree/concerns/payment_method_distributors' + +module Spree + class PaymentMethod < ActiveRecord::Base + include Spree::Core::CalculatedAdjustments + include Spree::PaymentMethodDistributors + + acts_as_taggable + acts_as_paranoid + + DISPLAY = [:both, :front_end, :back_end].freeze + default_scope -> { where(deleted_at: nil) } + + has_many :credit_cards, class_name: "Spree::CreditCard" + + validates :name, presence: true + validate :distributor_validation + + after_initialize :init + + scope :production, -> { where(environment: 'production') } + + scope :managed_by, lambda { |user| + if user.has_spree_role?('admin') + where(nil) + else + joins(:distributors). + where('distributors_payment_methods.distributor_id IN (?)', + user.enterprises.select(&:id)). + select('DISTINCT spree_payment_methods.*') + end + } + + scope :for_distributors, ->(distributors) { + non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors }) + where(id: non_unique_matches.map(&:id)) + } + + scope :for_distributor, lambda { |distributor| + joins(:distributors). + where('enterprises.id = ?', distributor) + } + + scope :for_subscriptions, -> { where(type: Subscription::ALLOWED_PAYMENT_METHOD_TYPES) } + + scope :by_name, -> { order('spree_payment_methods.name ASC') } + + scope :available, lambda { |display_on = 'both'| + where(active: true). + where('spree_payment_methods.display_on=? OR spree_payment_methods.display_on=? OR spree_payment_methods.display_on IS NULL', display_on, ''). + where('spree_payment_methods.environment=? OR spree_payment_methods.environment=? OR spree_payment_methods.environment IS NULL', Rails.env, '') + } + + def self.providers + Rails.application.config.spree.payment_methods + end + + def provider_class + raise 'You must implement provider_class method for this gateway.' + end + + # The class that will process payments for this payment type, used for @payment.source + # e.g. CreditCard in the case of a the Gateway payment type + # nil means the payment method doesn't require a source e.g. check + def payment_source_class + raise 'You must implement payment_source_class method for this gateway.' + end + + def self.active? + where(type: to_s, environment: Rails.env, active: true).count.positive? + end + + def method_type + type.demodulize.downcase + end + + def self.find_with_destroyed(*args) + unscoped { find(*args) } + end + + def payment_profiles_supported? + false + end + + def source_required? + true + end + + def auto_capture? + Spree::Config[:auto_capture] + end + + def supports?(_source) + true + end + + def init + unless reflections.key?(:calculator) + self.class.include Spree::Core::CalculatedAdjustments + end + + self.calculator ||= Calculator::FlatRate.new(preferred_amount: 0) + end + + def has_distributor?(distributor) + distributors.include?(distributor) + end + + def self.clean_name + case name + when "Spree::PaymentMethod::Check" + "Cash/EFT/etc. (payments for which automatic validation is not required)" + when "Spree::Gateway::Migs" + "MasterCard Internet Gateway Service (MIGS)" + when "Spree::Gateway::Pin" + "Pin Payments" + when "Spree::Gateway::StripeConnect" + "Stripe" + when "Spree::Gateway::StripeSCA" + "Stripe SCA" + when "Spree::Gateway::PayPalExpress" + "PayPal Express" + else + i = name.rindex('::') + 2 + name[i..-1] + end + end + + private + + def distributor_validation + validates_with DistributorsValidator + end + end +end diff --git a/app/models/spree/payment_method/check.rb b/app/models/spree/payment_method/check.rb new file mode 100644 index 0000000000..9819a52c6c --- /dev/null +++ b/app/models/spree/payment_method/check.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Spree + class PaymentMethod + class Check < Spree::PaymentMethod + def actions + %w{capture void} + end + + # Indicates whether its possible to capture the payment + def can_capture?(payment) + ['checkout', 'pending'].include?(payment.state) + end + + # Indicates whether its possible to void the payment. + def can_void?(payment) + payment.state != 'void' + end + + def capture(*_args) + ActiveMerchant::Billing::Response.new(true, "", {}, {}) + end + + def void(*_args) + ActiveMerchant::Billing::Response.new(true, "", {}, {}) + end + + def source_required? + false + end + end + end +end diff --git a/app/models/spree/payment_method_decorator.rb b/app/models/spree/payment_method_decorator.rb deleted file mode 100644 index 4c2770daea..0000000000 --- a/app/models/spree/payment_method_decorator.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'spree/concerns/payment_method_distributors' - -Spree::PaymentMethod.class_eval do - include Spree::Core::CalculatedAdjustments - include Spree::PaymentMethodDistributors - - acts_as_taggable - - has_many :credit_cards, class_name: "Spree::CreditCard" # from Spree v.2.3.0 d470b31798f37 - - after_initialize :init - - validate :distributor_validation - - # -- Scopes - scope :managed_by, lambda { |user| - if user.has_spree_role?('admin') - where(nil) - else - joins(:distributors). - where('distributors_payment_methods.distributor_id IN (?)', user.enterprises.select(&:id)). - select('DISTINCT spree_payment_methods.*') - end - } - - scope :for_distributors, ->(distributors) { - non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors }) - where(id: non_unique_matches.map(&:id)) - } - - scope :for_distributor, lambda { |distributor| - joins(:distributors). - where('enterprises.id = ?', distributor) - } - - scope :for_subscriptions, -> { where(type: Subscription::ALLOWED_PAYMENT_METHOD_TYPES) } - - scope :by_name, -> { order('spree_payment_methods.name ASC') } - - # Rewrite Spree's ruby-land class method as a scope - scope :available, lambda { |display_on = 'both'| - where(active: true). - where('spree_payment_methods.display_on=? OR spree_payment_methods.display_on=? OR spree_payment_methods.display_on IS NULL', display_on, ''). - where('spree_payment_methods.environment=? OR spree_payment_methods.environment=? OR spree_payment_methods.environment IS NULL', Rails.env, '') - } - - def init - unless reflections.key?(:calculator) - self.class.include Spree::Core::CalculatedAdjustments - end - - self.calculator ||= Calculator::FlatRate.new(preferred_amount: 0) - end - - def has_distributor?(distributor) - distributors.include?(distributor) - end - - def self.clean_name - case name - when "Spree::PaymentMethod::Check" - "Cash/EFT/etc. (payments for which automatic validation is not required)" - when "Spree::Gateway::Migs" - "MasterCard Internet Gateway Service (MIGS)" - when "Spree::Gateway::Pin" - "Pin Payments" - when "Spree::Gateway::StripeConnect" - "Stripe" - when "Spree::Gateway::StripeSCA" - "Stripe SCA" - when "Spree::Gateway::PayPalExpress" - "PayPal Express" - else - i = name.rindex('::') + 2 - name[i..-1] - end - end - - private - - def distributor_validation - validates_with DistributorsValidator - end -end diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 602329b5c1..554309f687 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -63,8 +63,7 @@ Spree::Product.class_eval do scope :visible_for, lambda { |enterprise| joins('LEFT OUTER JOIN spree_variants AS o_spree_variants ON (o_spree_variants.product_id = spree_products.id)'). joins('LEFT OUTER JOIN inventory_items AS o_inventory_items ON (o_spree_variants.id = o_inventory_items.variant_id)'). - where('o_inventory_items.enterprise_id = (?) AND visible = (?)', enterprise, true). - select('DISTINCT spree_products.*') + where('o_inventory_items.enterprise_id = (?) AND visible = (?)', enterprise, true) } # -- Scopes diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb new file mode 100644 index 0000000000..e6df19b03a --- /dev/null +++ b/app/models/spree/stock_item.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Spree + class StockItem < ActiveRecord::Base + acts_as_paranoid + + belongs_to :stock_location, class_name: 'Spree::StockLocation' + belongs_to :variant, class_name: 'Spree::Variant' + has_many :stock_movements, dependent: :destroy + + validates :stock_location, :variant, presence: true + validates :variant_id, uniqueness: { scope: [:stock_location_id, :deleted_at] } + validates :count_on_hand, numericality: { greater_than_or_equal_to: 0, unless: :backorderable? } + + delegate :weight, to: :variant + delegate :name, to: :variant, prefix: true + + def backordered_inventory_units + Spree::InventoryUnit.backordered_for_stock_item(self) + end + + def adjust_count_on_hand(value) + with_lock do + self.count_on_hand = count_on_hand + value + process_backorders if in_stock? + + save! + end + end + + def in_stock? + count_on_hand.positive? + end + + # Tells whether it's available to be included in a shipment + def available? + in_stock? || backorderable? + end + + def variant + Spree::Variant.unscoped { super } + end + + private + + def count_on_hand=(value) + self[:count_on_hand] = value + end + + def process_backorders + backordered_inventory_units.each do |unit| + break unless in_stock? + + unit.fill_backorder + end + end + end +end diff --git a/app/models/spree/taxon_decorator.rb b/app/models/spree/taxon_decorator.rb index ad2a85cfdb..f2c6f1e20a 100644 --- a/app/models/spree/taxon_decorator.rb +++ b/app/models/spree/taxon_decorator.rb @@ -1,9 +1,6 @@ Spree::Taxon.class_eval do has_many :classifications, dependent: :destroy - attachment_definitions[:icon][:path] = 'public/images/spree/taxons/:id/:style/:basename.:extension' - attachment_definitions[:icon][:url] = '/images/spree/taxons/:id/:style/:basename.:extension' - # Indicate which filters should be used for this taxon def applicable_filters fs = [] diff --git a/app/models/spree/user.rb b/app/models/spree/user.rb index 3df57a9cf8..da276ec936 100644 --- a/app/models/spree/user.rb +++ b/app/models/spree/user.rb @@ -34,10 +34,6 @@ module Spree # We use the same options as Spree and add :confirmable devise :confirmable, reconfirmable: true - # TODO: Later versions of devise have a dedicated after_confirmation callback, so use that - after_update :welcome_after_confirm, if: lambda { - confirmation_token_changed? && confirmation_token.nil? - } class DestroyWithOrdersError < StandardError; end @@ -49,14 +45,14 @@ module Spree has_spree_role?('admin') end - def send_reset_password_instructions - generate_reset_password_token! - UserMailer.reset_password_instructions(id).deliver - end # handle_asynchronously will define send_reset_password_instructions_with_delay. # If handle_asynchronously is called twice, we get an infinite job loop. handle_asynchronously :send_reset_password_instructions unless method_defined? :send_reset_password_instructions_with_delay + def regenerate_reset_password_token + set_reset_password_token + end + def known_users if admin? Spree::User.where(nil) @@ -82,9 +78,9 @@ module Spree customers.find_by(enterprise_id: enterprise) end - def welcome_after_confirm - # Send welcome email if we are confirming an user's email - # Note: this callback only runs on email confirmation + # This is a Devise Confirmable callback that runs on email confirmation + # It sends a welcome email after the user email is confirmed + def after_confirmation return unless confirmed? && unconfirmed_email.nil? && !unconfirmed_email_changed? send_signup_confirmation diff --git a/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb b/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb index 360f135680..fecf675c5f 100644 --- a/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb +++ b/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb @@ -30,9 +30,10 @@ class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer def products_scope products_relation = object.supplied_products if order_cycle.prefers_product_selection_from_coordinator_inventory_only? - products_relation = products_relation.visible_for(order_cycle.coordinator) + products_relation = products_relation. + visible_for(order_cycle.coordinator) end - products_relation.order(:name) + products_relation end def products diff --git a/app/serializers/api/open_street_map_config_serializer.rb b/app/serializers/api/open_street_map_config_serializer.rb index 8c5aec5dbb..29f87ad34e 100644 --- a/app/serializers/api/open_street_map_config_serializer.rb +++ b/app/serializers/api/open_street_map_config_serializer.rb @@ -4,7 +4,9 @@ module Api class OpenStreetMapConfigSerializer < ActiveModel::Serializer attributes :open_street_map_enabled, :open_street_map_provider_name, - :open_street_map_provider_options + :open_street_map_provider_options, + :open_street_map_default_latitude, + :open_street_map_default_longitude def open_street_map_enabled ContentConfig.open_street_map_enabled @@ -15,7 +17,15 @@ module Api end def open_street_map_provider_options - ContentConfig.open_street_map_provider_options.to_json + ContentConfig.open_street_map_provider_options + end + + def open_street_map_default_latitude + ContentConfig.open_street_map_default_latitude + end + + def open_street_map_default_longitude + ContentConfig.open_street_map_default_longitude end end end diff --git a/app/serializers/api/taxon_image_serializer.rb b/app/serializers/api/taxon_image_serializer.rb deleted file mode 100644 index bc920637cd..0000000000 --- a/app/serializers/api/taxon_image_serializer.rb +++ /dev/null @@ -1,11 +0,0 @@ -class Api::TaxonImageSerializer < ActiveModel::Serializer - attributes :id, :alt, :small_url, :large_url - - def small_url - object.attachment.url(:small, false) - end - - def large_url - object.attachment.url(:large, false) - end -end diff --git a/app/serializers/api/taxon_serializer.rb b/app/serializers/api/taxon_serializer.rb index 775c069a41..43d3ddefd9 100644 --- a/app/serializers/api/taxon_serializer.rb +++ b/app/serializers/api/taxon_serializer.rb @@ -2,9 +2,5 @@ class Api::TaxonSerializer < ActiveModel::Serializer cached delegate :cache_key, to: :object - attributes :id, :name, :permalink, :icon, :pretty_name, :position, :parent_id, :taxonomy_id - - def icon - object.icon(:original) - end + attributes :id, :name, :permalink, :pretty_name, :position, :parent_id, :taxonomy_id end diff --git a/app/services/advance_order_service.rb b/app/services/advance_order_service.rb deleted file mode 100644 index 1377c36147..0000000000 --- a/app/services/advance_order_service.rb +++ /dev/null @@ -1,43 +0,0 @@ -class AdvanceOrderService - attr_reader :order - - def initialize(order) - @order = order - end - - def call - advance_order(advance_order_options) - end - - def call! - advance_order!(advance_order_options) - end - - private - - def advance_order_options - shipping_method_id = order.shipping_method.id if order.shipping_method.present? - { shipping_method_id: shipping_method_id } - end - - def advance_order(options) - until order.state == "complete" - break unless order.next - - after_transition_hook(options) - end - end - - def advance_order!(options) - until order.completed? - order.next! - after_transition_hook(options) - end - end - - def after_transition_hook(options) - if order.state == "delivery" - order.select_shipping_method(options[:shipping_method_id]) if options[:shipping_method_id] - end - end -end diff --git a/app/services/checkout/form_data_adapter.rb b/app/services/checkout/form_data_adapter.rb index a374444637..1333ed5dbd 100644 --- a/app/services/checkout/form_data_adapter.rb +++ b/app/services/checkout/form_data_adapter.rb @@ -12,6 +12,8 @@ module Checkout move_payment_source_to_payment_attributes! + fill_in_card_type + set_amount_in_payments_attributes construct_saved_card_attributes if @params[:order][:existing_card_id] @@ -31,6 +33,28 @@ module Checkout @params[:order][:payments_attributes].first[:source_attributes] = payment_source_params end + # Ensures cc_type is always passed to the model by inferring the type when + # the frontend didn't provide it. This fixes Pin Payments specifically + # although it might be useful for future payment gateways. + # + # More details: app/assets/javascripts/darkswarm/services/checkout.js.coffee#L70-L98 + def fill_in_card_type + return unless payment_source_attributes + + return if payment_source_attributes.dig(:number).blank? + + payment_source_attributes[:cc_type] ||= card_brand(payment_source_attributes[:number]) + end + + def payment_source_attributes + @payment_source_attributes ||= + params[:order][:payments_attributes]&.first&.dig(:source_attributes) + end + + def card_brand(number) + ActiveMerchant::Billing::CreditCard.brand?(number) + end + def delete_payment_source_params! @params.delete(:payment_source)[ @params[:order][:payments_attributes].first[:payment_method_id].underscore diff --git a/app/services/order_adjustments_fetcher.rb b/app/services/order_adjustments_fetcher.rb index 40d78cf6bc..560f04bdb1 100644 --- a/app/services/order_adjustments_fetcher.rb +++ b/app/services/order_adjustments_fetcher.rb @@ -57,11 +57,12 @@ class OrderAdjustmentsFetcher if adjustments_eager_loaded? adjustment_scope = public_send("#{scope}_scope") + # Adjustments are already loaded here, this block is using `Array#select` adjustments.select do |adjustment| - match_by_scope(adjustment, adjustment_scope) + match_by_scope(adjustment, adjustment_scope) && match_by_scope(adjustment, eligible_scope) end else - adjustments.where(nil).public_send scope + adjustments.where(nil).eligible.public_send scope end end diff --git a/app/services/order_workflow.rb b/app/services/order_workflow.rb new file mode 100644 index 0000000000..b55ed43ce1 --- /dev/null +++ b/app/services/order_workflow.rb @@ -0,0 +1,79 @@ +class OrderWorkflow + attr_reader :order + + def initialize(order) + @order = order + end + + def complete + advance_order(advance_order_options) + end + + def complete! + advance_order!(advance_order_options) + end + + def next(options = {}) + result = advance_order_one_step + + after_transition_hook(options) + + result + end + + private + + def advance_order_options + shipping_method_id = order.shipping_method.id if order.shipping_method.present? + { shipping_method_id: shipping_method_id } + end + + def advance_order(options) + until order.state == "complete" + break unless order.next + + after_transition_hook(options) + end + end + + def advance_order!(options) + until order.completed? + order.next! + after_transition_hook(options) + end + end + + def advance_order_one_step + tries ||= 3 + order.next + rescue ActiveRecord::StaleObjectError + retry unless (tries -= 1).zero? + false + end + + def after_transition_hook(options) + if order.state == "delivery" + order.select_shipping_method(options[:shipping_method_id]) if options[:shipping_method_id] + end + + persist_all_payments if order.state == "payment" + end + + # When a payment fails, the order state machine stays in 'payment' and rollbacks all transactions + # This rollback also reverts the payment state from 'failed', 'void' or 'invalid' to 'pending' + # Despite the rollback, the in-memory payment still has the correct state, so we persist it + def persist_all_payments + order.payments.each do |payment| + in_memory_payment_state = payment.state + if different_from_db_payment_state?(in_memory_payment_state, payment.id) + payment.reload.update(state: in_memory_payment_state) + end + end + end + + # Verifies if the in-memory payment state is different from the one stored in the database + # This is be done without reloading the payment so that in-memory data is not changed + def different_from_db_payment_state?(in_memory_payment_state, payment_id) + in_memory_payment_state != Spree::Payment.find(payment_id).state + end +end diff --git a/app/services/permitted_attributes/order_cycle.rb b/app/services/permitted_attributes/order_cycle.rb index 41fd82bead..b81dccef0f 100644 --- a/app/services/permitted_attributes/order_cycle.rb +++ b/app/services/permitted_attributes/order_cycle.rb @@ -11,6 +11,7 @@ module PermittedAttributes @params.require(:order_cycle).permit( :name, :orders_open_at, :orders_close_at, :coordinator_id, + :preferred_product_selection_from_coordinator_inventory_only, incoming_exchanges: permitted_exchange_attributes, outgoing_exchanges: permitted_exchange_attributes, schedule_ids: [], coordinator_fee_ids: [] diff --git a/app/views/admin/subscriptions/_form.html.haml b/app/views/admin/subscriptions/_form.html.haml index 2b3a06673b..cfb4feddaf 100644 --- a/app/views/admin/subscriptions/_form.html.haml +++ b/app/views/admin/subscriptions/_form.html.haml @@ -4,7 +4,7 @@ %a.button{ href: main_app.admin_subscriptions_path, ng: { show: "['details','review'].indexOf(view) >= 0" } }= t(:cancel) %input{ type: "button", value: t(:back), ng: { click: 'back()', show: '!!backCallbacks[view]'} } %input.red{ type: "button", value: t(:next), ng: { click: 'next()', show: '!!nextCallbacks[view]' } } - %input.red{ type: "submit", value: t('admin.subscriptions.create'), ng: { show: "view == 'review'" } } + %input.red{ type: "submit", value: t('.create'), ng: { show: "view == 'review'" } } %div{ ng: { show: 'subscription.id' } } %a.button{ href: main_app.admin_subscriptions_path }= t(:close) %input.red{ type: "button", value: t(:review), ng: { click: "setView('review')", show: "view != 'review'" } } diff --git a/app/views/admin/subscriptions/edit.html.haml b/app/views/admin/subscriptions/edit.html.haml index 2084e9d761..51b4c40045 100644 --- a/app/views/admin/subscriptions/edit.html.haml +++ b/app/views/admin/subscriptions/edit.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - =t('admin.subscriptions.edit') + =t('.title') -# - content_for :page_actions do -# %li= button_link_to "Back to subscriptions list", main_app.admin_subscriptions_path, icon: 'icon-arrow-left' diff --git a/app/views/admin/subscriptions/index.html.haml b/app/views/admin/subscriptions/index.html.haml index 4dd37c4f75..f6688693f7 100644 --- a/app/views/admin/subscriptions/index.html.haml +++ b/app/views/admin/subscriptions/index.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - = t('admin.subscriptions.subscriptions') + = t('.title') - content_for :main_ng_app_name do = "admin.subscriptions" @@ -7,7 +7,7 @@ - content_for :page_actions do %li %a.button.icon-plus#new-subscription{ href: "javascript:void(0)", "new-subscription-dialog" => true } - = t('admin.subscriptions.new') + = t('.new') = render :partial => 'spree/admin/shared/order_sub_menu' diff --git a/app/views/admin/subscriptions/new.html.haml b/app/views/admin/subscriptions/new.html.haml index c82824891c..6ac3749982 100644 --- a/app/views/admin/subscriptions/new.html.haml +++ b/app/views/admin/subscriptions/new.html.haml @@ -1,7 +1,7 @@ -# = render :partial => 'spree/shared/error_messages', :locals => { :target => @enterprise } - content_for :page_title do - =t('admin.subscriptions.new') + =t('.title') -# - content_for :page_actions do -# %li= button_link_to "Back to subscriptions list", main_app.admin_subscriptions_path, icon: 'icon-arrow-left' diff --git a/app/views/admin/subscriptions/setup_explanation.html.haml b/app/views/admin/subscriptions/setup_explanation.html.haml index 676483a55e..a3e7a8017e 100644 --- a/app/views/admin/subscriptions/setup_explanation.html.haml +++ b/app/views/admin/subscriptions/setup_explanation.html.haml @@ -1,4 +1,4 @@ -%h1.text-center.margin-bottom-30= t('admin.subscription.subscriptions') +%h1.text-center.margin-bottom-30= t('.title') .row .four.columns.alpha   diff --git a/app/views/layouts/_bugsnag_js.html.haml b/app/views/layouts/_bugsnag_js.html.haml index b9f3f5a736..9c3b3b9238 100644 --- a/app/views/layouts/_bugsnag_js.html.haml +++ b/app/views/layouts/_bugsnag_js.html.haml @@ -1,10 +1,8 @@ - bugsnag_js_key = ENV['BUGSNAG_JS_KEY'] || ENV['BUGSNAG_API_KEY'] - if bugsnag_js_key.present? - %script{src: "//d2wy8f7a9ursnm.cloudfront.net/v6/bugsnag.min.js"} + %script{src: "//d2wy8f7a9ursnm.cloudfront.net/v7/bugsnag.min.js"} :javascript - window.bugsnagClient = bugsnag({ + Bugsnag.start({ apiKey: "#{bugsnag_js_key}", - beforeSend: function (report) { - report.app.releaseStage = "#{Rails.env}" - } - }); + releaseStage: "#{Rails.env}" + }) diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index 7fd21a35d3..17f256124a 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -9,7 +9,7 @@ %meta{name: "robots", content: "noindex"} %title= content_for?(:title) ? "#{yield(:title)} - #{t(:title)}".html_safe : "#{t(:welcome_to)} #{t(:title)}" - if Rails.env.production? - = favicon_link_tag + = favicon_link_tag "/favicon.ico" - else = favicon_link_tag "/favicon-staging.ico" %link{href: "https://fonts.googleapis.com/css?family=Roboto:400,300italic,400italic,300,700,700italic|Oswald:300,400,700", rel: "stylesheet", type: "text/css"} diff --git a/app/views/layouts/registration.html.haml b/app/views/layouts/registration.html.haml index ebbcd9fd17..9f7e77612c 100644 --- a/app/views/layouts/registration.html.haml +++ b/app/views/layouts/registration.html.haml @@ -5,7 +5,7 @@ %title= content_for?(:title) ? "#{yield(:title)} - #{Spree::Config[:site_name]}" : "#{t(:welcome_to)} #{Spree::Config[:site_name]}" - if Rails.env.production? - = favicon_link_tag + = favicon_link_tag "/favicon.ico" - else = favicon_link_tag "/favicon-staging.ico" %link{href: "https://fonts.googleapis.com/css?family=Roboto:400,300italic,400italic,300,700,700italic|Oswald:300,400,700", rel: "stylesheet", type: "text/css"} diff --git a/app/views/producers/_fat.html.haml b/app/views/producers/_fat.html.haml index 7712d43629..35156e3c51 100644 --- a/app/views/producers/_fat.html.haml +++ b/app/views/producers/_fat.html.haml @@ -22,7 +22,6 @@ %p.trans-sentence %div %span.fat-taxons{"ng-repeat" => "taxon in producer.supplied_taxons"} - %render-svg{path: "{{taxon.icon}}"} %span{"ng-bind" => "::taxon.name"} %div %span.fat-properties{"ng-repeat" => "property in producer.supplied_properties"} @@ -79,8 +78,8 @@ .row.cta-container .columns.small-12 %a.cta-hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'", - "ng-href" => "{{::hub.path}}", "ng-attr-target" => "_blank", - "ng-class" => "::{primary: hub.active, secondary: !hub.active}", "target" => "_blank"} + "ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined }}", + "ng-class" => "::{primary: hub.active, secondary: !hub.active}"} %i.ofn-i_068-shop-reversed{"ng-if" => "::hub.active"} %i.ofn-i_068-shop-reversed{"ng-if" => "::!hub.active"} .hub-name{"ng-bind" => "::hub.name"} diff --git a/app/views/producers/_skinny.html.haml b/app/views/producers/_skinny.html.haml index 8664537362..6e05619d07 100644 --- a/app/views/producers/_skinny.html.haml +++ b/app/views/producers/_skinny.html.haml @@ -3,7 +3,7 @@ %span{"ng-if" => "::producer.is_distributor" } .row.vertical-align-middle .columns.small-12 - %a.is_distributor{"ng-href" => "{{::producer.path}}", "ng-attr-target" => "_blank", "data-is-link" => "true", "target" => "_blank"} + %a.is_distributor{"ng-href" => "{{::producer.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "data-is-link" => "true"} %i{ng: {class: "::producer.producer_icon_font"}} %span.margin-top %strong{"ng-bind" => "::producer.name"} diff --git a/app/views/shared/menu/_cart_sidebar.html.haml b/app/views/shared/menu/_cart_sidebar.html.haml index 03c3f52222..10bef792ab 100644 --- a/app/views/shared/menu/_cart_sidebar.html.haml +++ b/app/views/shared/menu/_cart_sidebar.html.haml @@ -1,4 +1,4 @@ -.expanding-sidebar.cart-sidebar{ng: {controller: 'CartCtrl', show: 'showCartSidebar', class: "{'shown': showCartSidebar, 'hidden': !showCartSidebar}"}} +.expanding-sidebar.cart-sidebar{ng: {controller: 'CartCtrl', class: "{'shown': showCartSidebar}"}} .background{ng: {click: 'toggleCartSidebar()'}} .sidebar .cart-header diff --git a/app/views/shop/products/_searchbar.haml b/app/views/shop/products/_searchbar.haml index f18d9b9382..bda087f4c7 100644 --- a/app/views/shop/products/_searchbar.haml +++ b/app/views/shop/products/_searchbar.haml @@ -6,7 +6,7 @@ type: 'search', placeholder: t(:products_search), "ng-debounce" => "200", - "ofn-disable-enter" => true} + "disable-enter-with-blur" => true} %a.clear{type: 'button', ng: {show: 'query', click: 'clearQuery()'}, 'focus-search' => true} = image_tag "icn-close.png" diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml index 628ae5a161..3c12a68db8 100644 --- a/app/views/shop/products/_summary.html.haml +++ b/app/views/shop/products/_summary.html.haml @@ -18,4 +18,3 @@ %span{"ng-bind" => "::enterprise.name"} .small-2.medium-2.large-1.columns.text-center .taxon-flag - %render-svg{path: "{{::product.primary_taxon.icon}}"} diff --git a/app/views/shops/_fat.html.haml b/app/views/shops/_fat.html.haml index 56772bde40..cd5d9c6f45 100644 --- a/app/views/shops/_fat.html.haml +++ b/app/views/shops/_fat.html.haml @@ -10,7 +10,6 @@ .trans-sentence %div %span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"} - %render-svg{path: "{{taxon.icon}}"} %span{"ng-bind" => "::taxon.name"} %div %span.fat-properties{"ng-repeat" => "property in hub.distributed_properties"} diff --git a/app/views/spree/admin/adjustments/index.html.haml b/app/views/spree/admin/adjustments/index.html.haml index 02433a6e5c..4aa8de7967 100644 --- a/app/views/spree/admin/adjustments/index.html.haml +++ b/app/views/spree/admin/adjustments/index.html.haml @@ -7,6 +7,7 @@ - content_for :page_actions do %li= button_link_to t(:new_adjustment), new_admin_order_adjustment_url(@order), :icon => 'icon-plus' + = render partial: 'spree/admin/shared/order_links' %li= button_link_to t(:back_to_orders_list), admin_orders_path, :icon => 'icon-arrow-left' = render :partial => 'adjustments_table' diff --git a/app/views/spree/admin/orders/bulk_management.html.haml b/app/views/spree/admin/orders/bulk_management.html.haml index 1053235c67..644a9531e4 100644 --- a/app/views/spree/admin/orders/bulk_management.html.haml +++ b/app/views/spree/admin/orders/bulk_management.html.haml @@ -151,7 +151,7 @@ %th.final_weight_volume{ 'ng-show' => 'columns.final_weight_volume.visible' } = t("admin.orders.bulk_management.weight_volume") %th.price{ 'ng-show' => 'columns.price.visible' } - = t("admin.price (#{currency_symbol})") + = "#{t('admin.price')} (#{currency_symbol})" %th.actions %th.actions = t("admin.orders.bulk_management.ask") diff --git a/app/views/spree/admin/orders/customer_details/edit.html.haml b/app/views/spree/admin/orders/customer_details/edit.html.haml index 584c3350b9..765224d247 100644 --- a/app/views/spree/admin/orders/customer_details/edit.html.haml +++ b/app/views/spree/admin/orders/customer_details/edit.html.haml @@ -8,6 +8,7 @@ = Spree.t(:customer_details) - content_for :page_actions do + = render partial: 'spree/admin/shared/order_links' %li= button_link_to Spree.t(:back_to_orders_list), admin_orders_path, :icon => 'icon-arrow-left' - if @order.cart? || @order.address? diff --git a/app/views/spree/admin/orders/edit.html.haml b/app/views/spree/admin/orders/edit.html.haml index d2047e6bf4..ada2ff5953 100644 --- a/app/views/spree/admin/orders/edit.html.haml +++ b/app/views/spree/admin/orders/edit.html.haml @@ -4,7 +4,7 @@ %li= event_links - if can?(:resend, @order) %li= button_link_to Spree.t(:resend), resend_admin_order_url(@order), :method => :post, :icon => 'icon-email' - %li.links-dropdown#links-dropdown{ links: order_links(@order).to_json } + = render partial: 'spree/admin/shared/order_links' - if can?(:admin, Spree::Order) %li= button_link_to t(:back_to_orders_list), admin_orders_path, :icon => 'icon-arrow-left' @@ -29,6 +29,3 @@ %div{"data-hook" => "admin_order_edit_form"} = render :partial => 'form', :locals => { :order => @order } - -:coffee - angular.bootstrap(document.getElementById("links-dropdown"),['admin.dropdown']) diff --git a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml index caa8e925c4..e53f9e436e 100644 --- a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml +++ b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml @@ -37,13 +37,10 @@ .alpha.seven.columns.dashboard_item.single-ent#map .header %h3 - %span.icon-map-marker + %span.icon-user = t "your_profil_live" - %p - = t "on_ofn_map" .list - /-# Can we pass an anchor here to zoom to our enterprise? - %a.button.bottom{href: main_app.map_path, target: '_blank'} + %a.button.bottom{href: main_app.enterprise_shop_url(@enterprise), target: '_blank'} = t "see" = @enterprise.name = t "live" diff --git a/app/views/spree/admin/payments/index.html.haml b/app/views/spree/admin/payments/index.html.haml index 7fbe76429f..c06a473479 100644 --- a/app/views/spree/admin/payments/index.html.haml +++ b/app/views/spree/admin/payments/index.html.haml @@ -5,6 +5,7 @@ - if @order.outstanding_balance? %li#new_payment_section = button_link_to t(:new_payment), new_admin_order_payment_url(@order), icon: 'icon-plus' + = render partial: 'spree/admin/shared/order_links' %li= button_link_to t(:back_to_orders_list), admin_orders_path, icon: 'icon-arrow-left' - content_for :page_title do diff --git a/app/views/spree/admin/payments/source_forms/_paypal.html.haml b/app/views/spree/admin/payments/source_forms/_paypal.html.haml index e26db66846..124139dae0 100644 --- a/app/views/spree/admin/payments/source_forms/_paypal.html.haml +++ b/app/views/spree/admin/payments/source_forms/_paypal.html.haml @@ -5,4 +5,4 @@ -# of the views we are using, so the warning below wasn't displaying without this override. #paypal-warning - %strong= t('no_payment_via_admin_backend', :scope => 'paypal') + %strong= t('.no_payment_via_admin_backend', :scope => 'paypal') diff --git a/app/views/spree/admin/return_authorizations/index.html.haml b/app/views/spree/admin/return_authorizations/index.html.haml index bc8ed9dd80..390551307c 100644 --- a/app/views/spree/admin/return_authorizations/index.html.haml +++ b/app/views/spree/admin/return_authorizations/index.html.haml @@ -5,6 +5,7 @@ - if @order.shipments.any? &:shipped? %li = button_link_to t('.new_return_authorization'), new_admin_order_return_authorization_url(@order), icon: 'icon-plus' + = render partial: 'spree/admin/shared/order_links' %li= button_link_to t('.back_to_orders_list'), spree.admin_orders_path, icon: 'icon-arrow-left' - content_for :page_title do diff --git a/app/views/spree/admin/shared/_order_links.html.haml b/app/views/spree/admin/shared/_order_links.html.haml new file mode 100644 index 0000000000..352371c04a --- /dev/null +++ b/app/views/spree/admin/shared/_order_links.html.haml @@ -0,0 +1,4 @@ +%li.links-dropdown#links-dropdown{ links: order_links(@order).to_json } + +:coffee + angular.bootstrap(document.getElementById("links-dropdown"),['admin.dropdown']) diff --git a/app/views/spree/admin/taxons/_form.html.haml b/app/views/spree/admin/taxons/_form.html.haml index 72ba498a4d..a23a55be0f 100644 --- a/app/views/spree/admin/taxons/_form.html.haml +++ b/app/views/spree/admin/taxons/_form.html.haml @@ -12,11 +12,6 @@ %br/ = @taxon.permalink.split("/")[0...-1].join("/") + "/" = text_field_tag :permalink_part, @permalink_part - = f.field_container :icon do - = f.label :icon, t(:icon) - %br/ - = f.file_field :icon - %img{src: @taxon.icon(:original)} = f.field_container :meta_title do = f.label :meta_title, t(:meta_title) %br/ diff --git a/app/views/spree/layouts/_admin_body.html.haml b/app/views/spree/layouts/_admin_body.html.haml index d5aa05dbee..7b1d643dee 100644 --- a/app/views/spree/layouts/_admin_body.html.haml +++ b/app/views/spree/layouts/_admin_body.html.haml @@ -66,4 +66,4 @@ %div{"data-hook" => "admin_footer_scripts"} %script - = raw "Spree.api_key = \"#{try_spree_current_user.try(:spree_api_key).to_s}\";" + = raw "Spree.api_key = \"#{spree_current_user.try(:spree_api_key).to_s}\";" diff --git a/app/views/spree/shipment_mailer/shipped_email.html.haml b/app/views/spree/shipment_mailer/shipped_email.html.haml new file mode 100644 index 0000000000..c5675a6975 --- /dev/null +++ b/app/views/spree/shipment_mailer/shipped_email.html.haml @@ -0,0 +1,30 @@ +%p + = t('.dear_customer') +%p + = t('.instructions') + +%p + = "============================================================" + %br + = t('.shipment_summary') + %br + = "============================================================" + +%p + - @shipment.manifest.each do |item| + = item.variant.sku + = item.variant.product.name + = item.variant.options_text + %br + = "============================================================" + +- if @shipment.tracking + %p + = t('.track_information', tracking: @shipment.tracking) + +- if @shipment.tracking_url + %p + = t('.track_link', url: @shipment.tracking_url) + +%p + = t('.thanks') diff --git a/app/views/spree/test_mailer/test_email.html.haml b/app/views/spree/test_mailer/test_email.html.haml new file mode 100644 index 0000000000..6f9e2e771c --- /dev/null +++ b/app/views/spree/test_mailer/test_email.html.haml @@ -0,0 +1,4 @@ += t('.greeting') += "================" + += t('.message') diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index e20b748148..5a101fbe4d 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -90,10 +90,6 @@ Devise.setup do |config| # Time interval to unlock the account if :time is enabled as unlock_strategy. # config.unlock_in = 1.hour - # ==> Configuration for :token_authenticatable - # Defines name of the authentication token params key - config.token_authentication_key = :auth_token - # ==> Scopes configuration # Turn scoped views on. Before rendering 'sessions/new', it will first check for # 'users/sessions/new'. It's turned off by default because it's slower if you @@ -141,3 +137,8 @@ Devise.setup do |config| config.case_insensitive_keys = [:email] end + +Devise::TokenAuthenticatable.setup do |config| + # Defines name of the authentication token params key + config.token_authentication_key = :auth_token +end diff --git a/config/initializers/spree.rb b/config/initializers/spree.rb index 6ff230c5f5..9280befea3 100644 --- a/config/initializers/spree.rb +++ b/config/initializers/spree.rb @@ -6,6 +6,7 @@ # In order to initialize a setting do: # config.setting_name = 'new value' +require "spree/core/environment" require 'spree/product_filters' # Due to a bug in ActiveRecord we need to load the tagging code in Gateway which @@ -17,9 +18,6 @@ Spree::Gateway.class_eval do acts_as_taggable end -require "#{Rails.root}/app/models/spree/payment_method_decorator" -require "#{Rails.root}/app/models/spree/gateway_decorator" - Spree.config do |config| config.shipping_instructions = true config.address_requires_state = true @@ -30,8 +28,6 @@ Spree.config do |config| config.auto_capture = true #config.override_actionmailer_config = false - config.order_updater_decorator = OrderUpdater - # S3 settings config.s3_bucket = ENV['S3_BUCKET'] if ENV['S3_BUCKET'] config.s3_access_key = ENV['S3_ACCESS_KEY'] if ENV['S3_ACCESS_KEY'] diff --git a/config/locales/ar.yml b/config/locales/ar.yml index a2dc262509..728504b5d3 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -13,6 +13,8 @@ ar: email: الايميل الالكتروني للعميل spree/payment: amount: القيمة + state: ولاية + source: المصدر spree/product: primary_taxon: "نوع المنتج " supplier: "المورد" @@ -33,6 +35,10 @@ ar: taken: "يوجد حساب متصل بهذا الايميل.\nالرجاء الدخول او اعادة تعيين كلمة السر." spree/order: no_card: لا يوجد بطاقة ائتمان معتمدة متاحة لاتمام عملية الدفع + spree/credit_card: + attributes: + base: + card_expired: "انتهت صلاحيته" order_cycle: attributes: orders_close_at: @@ -178,6 +184,7 @@ ar: explainer: فشلت المعالجة التلقائية لهذه الطلبات لسبب غير معروف. لا ينبغي أن يحدث هذا ، يرجى الاتصال بنا إذا كنت ترى هذا. home: "OFN" title: "شبكة الغذاء المفتوح" + welcome_to: "مرحبا بك في" site_meta_description: "نبدأ من الألف إلى الياء. مع المزارعين والمزارعين على استعداد لرواية قصصهم بفخر وحق. مع الموزعين على استعداد لتوصيل الأشخاص بالمنتجات بطريقة عادلة وبصدق. مع المشترين الذين يعتقدون أن أفضل قرارات التسوق الأسبوعية يمكن ..." search_by_name: البحث بالاسم أو الضاحية ... producers_join: المنتجون الأستراليون مدعوون الآن للانضمام إلى شبكة الغذاء المفتوح. @@ -266,6 +273,9 @@ ar: on hand: "متوفر" ship: "الشحن" shipping_category: "نوع الشحن" + height: "الارتفاع" + width: "العرض" + depth: "العمق" actions: create_and_add_another: "إنشاء وإضافة آخر" create: "انشاء" @@ -321,6 +331,7 @@ ar: show_n_more: عرض %{num} أكثر choose: "أختر..." please_select: الرجاء اختيار ... + column_save_as_default: إحفظ كافتراض اساسي columns: أعمدة actions: أجراءات viewing: "عرض: %{current_view_name}" @@ -365,7 +376,10 @@ ar: title: "إعدادات Matomo" matomo_url: "العنوان الالكتروني ل Matomo " matomo_site_id: "معرف موقع Matomo" + matomo_tag_manager_url: "عنوان URL لبرنامج Matomo " + info_html: "ماتومو هو تطبيق تحليلات الويب والجوال. يمكنك اضافة Matomo محليًا أو استخدام خدمة مستضافة على السحابة. انظر matomo.org لمزيد من المعلومات." config_instructions_html: "هنا يمكنك تهيئة تكامل Matomo لشبكة الغذاء المفتوح. يجب أن يشير عنوان الالكتروني URL الخاص بـ Matomo أدناه إلى مثيل Matomo حيث سيتم إرسال معلومات تتبع المستخدم إلى ؛ إذا تم تركه فارغًا ، فسيتم تعطيل تتبع مستخدم Matomo. حقل معرف الموقع ليس إلزاميًا ولكنه مفيد إذا كنت تتعقب أكثر من موقع ويب على مثيل Matomo ؛ يمكن العثور عليه على وحدة تحكم مثيل Matomo." + config_instructions_tag_manager_html: "يؤدي تعيين عنوان URL لبرنامج Matomo إلى تمكين Matomo . تتيح لك هذه الأداة إعداد أحداث التحليلات. يتم نسخ عنوان URL لبرنامج Matomo من قسم كود التثبيت في Manager. تأكد من تحديد الحاوية والبيئة المناسبة لأن هذه الخيارات تغير عنوان URL." customers: index: new_customer: "عميل جديد" @@ -471,6 +485,7 @@ ar: line_number: "السطر %{number}:" encoding_error: "يرجى التحقق من إعداد اللغة للملف المصدر والتأكد من حفظه بترميز UTF-8" unexpected_error: "واجه استيراد المنتج خطأ غير متوقع أثناء فتح الملف: %{error_message}" + malformed_csv: "صادف استيراد المنتج ملف CSV مشوه: %{error_message}" index: notice: "تنويه" beta_notice: "لا تزال هذه الميزة تجريبية: قد تواجه بعض الأخطاء أثناء استخدامها. من فضلك لا تتردد في الاتصال بالدعم." @@ -683,6 +698,7 @@ ar: ofn_uid_tip: المعرف الفريد المستخدم لتحديد الشركة على شبكة الغذاء المفتوح. shipping_methods: name: "اسم" + applies: "نشيط؟" manage: "إدارة طرق الشحن" create_button: "إنشاء طريقة شحن جديدة" create_one_button: "إنشاء واحدة الآن" @@ -860,6 +876,7 @@ ar: incoming: "الوارد" supplier: "المورد" products: "منتجات" + receival_details: "تفاصيل الاستلام" fees: "رسوم" save: "حفظ" save_and_next: "حفظ والتالي" @@ -871,6 +888,7 @@ ar: distributor: "الموزع" products: "منتجات" tags: "الاوسمة" + delivery_details: "تفاصيل التسليم" fees: "رسوم" previous: "السابق" save: "حفظ" @@ -1020,10 +1038,13 @@ ar: name: "ملخص رسوم الشركات" description: "ملخص رسوم الشركات التي تم جمعها" subscriptions: - subscriptions: الاشتراكات - new: اشتراك جديد - create: إنشاء اشتراك - edit: تحرير الاشتراك + index: + title: "الاشتراكات" + new: "اشتراك جديد" + new: + title: "اشتراك جديد" + edit: + title: "تحرير الاشتراك" table: edit_subscription: تحرير الاشتراك pause_subscription: وقف مؤقت الاشتراك @@ -1032,6 +1053,7 @@ ar: filters: query_placeholder: "البحث عن طريق البريد الإلكتروني ..." setup_explanation: + title: "الاشتراكات" just_a_few_more_steps: 'فقط بضع خطوات أخرى قبل أن تبدأ:' enable_subscriptions: "تمكين الاشتراكات في واحد على الأقل من المتاجر الخاصة بك" enable_subscriptions_step_1_html: 1. انتقل إلى صفحة %{enterprises_link} ، وابحث عن متجرك ، وانقر على "إدارة" @@ -1045,6 +1067,8 @@ ar: create_at_least_one_schedule_step_3: 3. انقر فوق "+ جدول جديد" ، واملأ النموذج once_you_are_done_you_can_html: بمجرد الانتهاء من ذلك ، يمكنك %{reload_this_page_link} reload_this_page: اعد تحميل هذه الصفحة + form: + create: "إنشاء اشتراك" steps: details: 1. التفاصيل الأساسية address: 2. العنوان @@ -1136,7 +1160,12 @@ ar: cart: "سلة" cart_sidebar: checkout: "تابع للخروج" + edit_cart: "تعديل سلة التسوق" + items_in_cart_singular: "%{num} عنصر في سلة التسوق الخاصة بك" + items_in_cart_plural: "%{num} العناصر في سلة التسوق الخاصة بك" close: "إغلاق" + cart_empty: "سلة التسوق فارغة" + take_me_shopping: "خذني للتسوق!" signed_in: profile: "الملف الشخصي" mobile_menu: @@ -1168,7 +1197,11 @@ ar: signup: "سجل" contact: "اتصل" require_customer_login: "يمكن للعملاء المعتمدين فقط الوصول إلى هذا المتجر." + require_login_html: "إذا كنت عميلاً معتمدًا بالفعل ، %{login} أو %{signup} للمتابعة." + require_login_2_html: "تريد أن تبدأ التسوق هنا؟ من فضلك %{contact} %{enterprise} واسأل عن الانضمام." require_customer_html: "إذا كنت ترغب في بدء التسوق هنا ، فيرجى %{contact} %{enterprise} أن تسأل عن الانضمام." + select_oc: + select_oc_html: "يرجى اختيار الوقت الذي تريده لطلبك ، لمعرفة المنتجات المتوفرة." card_could_not_be_updated: لا يمكن تحديث البطاقة card_could_not_be_saved: لا يمكن حفظ البطاقة spree_gateway_error_flash_for_checkout: "حدثت مشكلة في معلومات الدفع الخاصة بك: %{error}" @@ -1280,6 +1313,8 @@ ar: cart_updating: "جارٍ تحديث العربة ..." cart_empty: "السلة فارغة" cart_edit: "تعديل عربة التسوق" + item: "بند" + qty: "الكمية" card_number: رقم البطاقة card_securitycode: "رمز الحماية" card_expiry_date: تاريخ الانتهاء @@ -1532,12 +1567,17 @@ ar: orders_changeable_orders_alert_html: تم تأكيد هذا الطلب ، ولكن يمكنك إجراء تغييرات حتى %{oc_close} . products_clear: ازالة products_showing: "عرض:" + products_results_for: "نتائج" products_or: "أو" products_and: "و" + products_filters_in: "في" products_with: مع + products_search: "بحث..." products_filter_by: "مرشح بواسطة" products_filter_selected: "تم الاختيار" + products_filter_heading: "المرشحات" products_filter_clear: "ازالة" + products_filter_done: "تم" products_loading: "جارٍ تحميل المنتجات ..." products_updating_cart: "جارٍ تحديث سلة المشتريات..." products_cart_empty: "السلة فارغة" @@ -1548,6 +1588,8 @@ ar: products_update_error_msg: "فشل الحفظ." products_update_error_data: "فشل الحفظ بسبب بيانات غير صالحة:" products_changes_saved: "تم حفظ التغييرات." + products_no_results_html: "عذرا ، لم يتم العثور على نتائج لـ %{query}" + products_clear_search: "مسح البحث" search_no_results_html: "عذرًا ، لم يتم العثور على نتائج لـ %{query}. جرب بحث آخر؟" components_profiles_popover: "لا تملك ملفات التعريف واجهة متجر على شبكة الغذاء المفتوح ، ولكن قد يكون لها متجر على ارض الواقع أو عبر الإنترنت في أي مكان آخر" components_profiles_show: "إظهار الملفات الشخصية" @@ -1692,6 +1734,7 @@ ar: remember_me: تذكرنى are_you_sure: "هل أنت واثق؟" orders_open: "الطلب مفتوح" + closing: "إغلاق" going_back_to_home_page: "الرجوع إلى الصفحة الرئيسية" creating: انشاء updating: تحديث @@ -1906,6 +1949,7 @@ ar: admin_enterprise_relationships_permits: "تسمح" admin_enterprise_relationships_seach_placeholder: "بحث" admin_enterprise_relationships_button_create: "انشاء" + admin_enterprise_relationships_to: "إلى" admin_enterprise_groups: "مجموعات المؤسسة" admin_enterprise_groups_name: "اسم" admin_enterprise_groups_owner: "المالك" @@ -1934,6 +1978,8 @@ ar: supplier: "المورد" product_name: "اسم المنتج" product_description: "وصف المنتج" + permalink: "الرابط الثابت" + shipping_categories: "فئات الشحن" units: "حجم الوحدة" coordinator: "منسق" distributor: "الموزع" @@ -2030,6 +2076,8 @@ ar: remove_tax: "إزالة الضريبة" first_name_begins_with: "الاسم الأول يبدأ بـ" last_name_begins_with: "اسم العائلة يبدأ بـ" + shipping_method: "طريقة الشحن" + new_order: "طلب جديد" enterprise_tos_link: "شروط المؤسسة لخدمة الرابط" enterprise_tos_message: "نريد العمل مع أشخاص يشاركوننا أهدافنا وقيمنا. على هذا النحو ، نطلب من المؤسسات الجديدة الموافقة على" enterprise_tos_link_text: "شروط الخدمة." @@ -2048,6 +2096,7 @@ ar: hub_sidebar_at_least: "يجب تحديد مركز واحد على الأقل" hub_sidebar_blue: "أزرق" hub_sidebar_red: "أحمر" + order_cycles_closed_for_hub: "المحور الذي حددته مغلق مؤقتًا للطلبات. الرجاء معاودة المحاولة في وقت لاحق." report_customers_distributor: "الموزع" report_customers_supplier: "المورد" report_customers_cycle: "ترتيب الدورة" @@ -2282,6 +2331,7 @@ ar: order_cycles_email_to_producers_notice: 'رسائل البريد الإلكتروني المراد إرسالها إلى المنتجين تم وضعها في قائمة الانتظار للإرسال.' order_cycles_no_permission_to_coordinate_error: "لا تملك أي من مؤسساتك إذنًا لتنسيق دورة الطلب" order_cycles_no_permission_to_create_error: "ليس لديك إذن لإنشاء دورة طلب تنسقها تلك المؤسسة" + order_cycle_closed: "تم إغلاق دورة الطلب التي حددتها للتو. حاول مرة اخرى!" back_to_orders_list: "العودة إلى قائمة الطلب" no_orders_found: "لم يتم العثور على أية طلبات" order_information: "معلومات الطلب" @@ -2309,6 +2359,10 @@ ar: resolve_errors: يرجى حل الأخطاء التالية more_items: "+ %{count} ايضا" default_card_updated: تم تحديث البطاقة الافتراضية + cart: + add_to_cart_failed: > + حدثت مشكلة أثناء إضافة هذا المنتج إلى عربة التسوق. ربما أصبح غير متوفر أو + أن المحل يغلق. admin: enterprise_limit_reached: "لقد وصلت إلى الحد القياسي للمؤسسات لكل حساب. اكتب %{contact_email} إذا كنت بحاجة إلى زيادته." modals: @@ -2593,6 +2647,13 @@ ar: few: "كل" many: "كل" other: "كل" + bunch: + zero: "عناقيد" + one: "حفنة" + two: "عناقيد" + few: "عناقيد" + many: "عناقيد" + other: "عناقيد" pack: zero: "حزم" one: "رزمة" @@ -2600,6 +2661,13 @@ ar: few: "حزم" many: "حزم" other: "حزم" + box: + zero: "مربعات" + one: "صندوق" + two: "مربعات" + few: "مربعات" + many: "مربعات" + other: "بكسات" bottle: zero: "زجاجات" one: "زجاجة" @@ -2607,6 +2675,62 @@ ar: few: "زجاجات" many: "زجاجات" other: "زجاجات" + jar: + zero: "الجرار" + one: "إناء" + two: "الجرار" + few: "الجرار" + many: "الجرار" + other: "مرتبان" + head: + zero: "رؤساء" + one: "رئيس" + two: "رؤساء" + few: "رؤساء" + many: "رؤساء" + other: "رؤوس" + bag: + zero: "أكياس" + one: "كيس" + two: "أكياس" + few: "أكياس" + many: "أكياس" + other: "أكياس" + loaf: + zero: "أرغفة" + one: "رغيف" + two: "أرغفة" + few: "أرغفة" + many: "أرغفة" + other: "أرغفة" + single: + zero: "الفردي" + one: "غير مرتبطة" + two: "الفردي" + few: "الفردي" + many: "الفردي" + other: "الفردي" + tub: + zero: "أحواض" + one: "حوض" + two: "أحواض" + few: "أحواض" + many: "أحواض" + other: "أحواض" + punnet: + zero: "سلات" + one: "إناء" + two: "سلات" + few: "سلات" + many: "سلات" + other: "سلات" + packet: + zero: "الحزم" + one: "رزمة" + two: "الحزم" + few: "الحزم" + many: "الحزم" + other: "الحزم" item: zero: "العناصر" one: "بند" @@ -2628,6 +2752,62 @@ ar: few: "الوحدات" many: "الوحدات" other: "الوحدات" + serve: + zero: "يخدم" + one: "تخدم" + two: "يخدم" + few: "يخدم" + many: "يخدم" + other: "خدمة" + tray: + zero: "صواني" + one: "صينية" + two: "صواني" + few: "صواني" + many: "صواني" + other: "صواني" + piece: + zero: "قطع" + one: "قطعة" + two: "قطع" + few: "قطع" + many: "قطع" + other: "قطع" + pot: + zero: "الأواني" + one: "وعاء" + two: "الأواني" + few: "الأواني" + many: "الأواني" + other: "اصص" + bundle: + zero: "حزم" + one: "حزمة" + two: "حزم" + few: "حزم" + many: "حزم" + other: "حزم" + flask: + zero: "قوارير" + one: "قارورة" + two: "قوارير" + few: "قوارير" + many: "قوارير" + other: "قوارير" + basket: + zero: "سلال" + one: "سلة" + two: "سلال" + few: "سلال" + many: "سلال" + other: "سلال" + sack: + zero: "أكياس" + one: "كيس" + two: "أكياس" + few: "أكياس" + many: "أكياس" + other: "أكياس" producers: signup: start_free_profile: "ابدأ بملف تعريف مجاني ، وتوسع عندما تكون جاهزًا!" @@ -2757,6 +2937,12 @@ ar: void: "فارغ" login: "تسجيل الدخول" password: "كلمه السر" + signature: "التوقيع" + solution: "المحاليل" + landing_page: "الصفحة المقصودة" + server: "الخادم" + test_mode: "وضع الاختبار" + logourl: "وحدة" configurations: "تهيئة" general_settings: "الاعدادات العامة" site_name: "اسم الموقع" @@ -2873,6 +3059,16 @@ ar: options: "خيارات" actions: update: "تحديث" + shared: + error_messages: + errors_prohibited_this_record_from_being_saved: + zero: "منعت أخطاء %{count} حفظ هذا السجل:" + one: "حظر خطأ واحد حفظ هذا السجل:" + two: "منعت أخطاء %{count} حفظ هذا السجل:" + few: "منعت أخطاء %{count} حفظ هذا السجل:" + many: "منعت أخطاء %{count} حفظ هذا السجل:" + other: "منعت أخطاء %{count} حفظ هذا السجل:" + there_were_problems_with_the_following_fields: "كانت هناك مشاكل مع الحقول التالية" errors: messages: blank: "لا يمكن أن تكون فارغة" @@ -3015,6 +3211,8 @@ ar: zone: "منطقة" calculator: "آلة حاسبة" display: "عرض" + both: "كل من تسجيل الخروج والمكتب الخلفي" + back_end: "المكتب الخلفي فقط" no_shipping_methods_found: "لم يتم العثور على طرق الشحن" new: new_shipping_method: "طريقة الشحن الجديدة" @@ -3026,6 +3224,9 @@ ar: form: categories: "التصنيفات" zones: "مناطق" + both: "كل من تسجيل الخروج والمكتب الخلفي" + back_end: "المكتب الخلفي فقط" + deactivation_warning: "يمكن أن يؤدي إلغاء تنشيط طريقة الشحن إلى اختفاء طريقة الشحن من قائمتك. بدلاً من ذلك ، يمكنك إخفاء طريقة الشحن من صفحة الخروج عن طريق تعيين الخيار\"عرض\" إلى\"المكتب الخلفي فقط\"." payment_methods: index: payment_methods: "طريقة الدفع" @@ -3037,8 +3238,11 @@ ar: display: "عرض" active: "نشط" both: "على حد سواء" + front_end: "الخروج فقط" + back_end: "المكتب الخلفي فقط" active_yes: "نعم" active_no: "لا" + no_payment_methods_found: "لم يتم العثور على طرق دفع" new: new_payment_method: "طريقة الدفع الجديدة" back_to_payment_methods_list: "العودة إلى قائمة طرق الدفع" @@ -3067,7 +3271,11 @@ ar: active: "نشط" active_yes: "نعم" active_no: "لا" + both: "كل من تسجيل الخروج والمكتب الخلفي" + front_end: "الخروج فقط" + back_end: "المكتب الخلفي فقط" tags: "الاوسمة" + deactivation_warning: "يمكن أن يؤدي إلغاء تنشيط طريقة الدفع إلى اختفاء طريقة الدفع من قائمتك. بدلاً من ذلك ، يمكنك إخفاء طريقة الدفع من صفحة الخروج عن طريق تعيين الخيار \"عرض\" إلى\"المكتب الخلفي فقط\"." providers: provider: "مزود" payments: @@ -3075,6 +3283,8 @@ ar: stripe: error_saving_payment: خطأ في حفظ الدفعة submitting_payment: تقديم الدفعة ... + paypal: + no_payment_via_admin_backend: لا يمكن التقاط مدفوعات Paypal في Backoffice products: image_upload_error: "لم يتم التعرف على صورة المنتج. يرجى تحميل صورة بتنسيق PNG أو JPG." new: @@ -3169,6 +3379,8 @@ ar: price: "السعر" display_as: "عرض ب" display_name: "اسم العرض" + display_as_placeholder: 'على سبيل المثال 2 كجم' + display_name_placeholder: 'على سبيل المثال طماطم' autocomplete: out_of_stock: "غير متوفر" producer_name: "المنتج" @@ -3208,6 +3420,7 @@ ar: format: '٪ س-٪ م-%d' js_format: 'يوم-شهر-سنة' orders: + error_flash_for_unavailable_items: "عنصر في سلة التسوق الخاصة بك أصبح غير متوفر. يرجى تحديث الكميات المحددة." edit: login_to_view_order: "يرجى تسجيل الدخول لعرض طلبك." bought: @@ -3235,12 +3448,46 @@ ar: invalid: غير صالحة order_mailer: cancel_email: + customer_greeting: "عزيزي %{name} ،" + instructions_html: "تم إلغاء طلبك مع %{distributor} . يرجى الاحتفاظ بمعلومات الإلغاء هذه في سجلاتك." + dont_cancel: "إذا غيرت رأيك أو لا ترغب في إلغاء هذا الطلب ، فيرجى الاتصال بـ %{email}" + order_summary_canceled_html: "ملخص الطلب # %{number} [ملغي]" + details: "إليك تفاصيل ما طلبته:" + unpaid_order: "لم يتم سداد طلبك ، لذا لم يتم رد الأموال" + paid_order: "تم دفع طلبك حتى أعاد %{distributor} المبلغ بالكامل" + credit_order: "تم دفع طلبك حتى تم إضافة رصيد إلى حسابك" subject: "إلغاء الطلب" confirm_email: subject: "تأكيد الطلب" invoice_email: hi: "مرحبًا %{name}" invoice_attached_text: يرجى الاطلاع على فاتورة مرفقة لطلبك الأخير من + user_mailer: + reset_password_instructions: + request_sent_text: | + تم تقديم طلب لإعادة تعيين كلمة المرور الخاصة بك. + إذا لم تقدم هذا الطلب ، ببساطة تجاهل هذا البريد الإلكتروني. + link_text: > + إذا قمت بهذا الطلب ، فما عليك سوى النقر فوق الرابط أدناه: + issue_text: | + إذا لم يعمل عنوان URL أعلاه ، فحاول نسخه ولصقه في متصفحك. + إذا كنت لا تزال تواجه مشاكل ، فلا تتردد في الاتصال بنا. + confirmation_instructions: + subject: "يرجى تأكيد حسابك OFN" + shipment_mailer: + shipped_email: + dear_customer: "عزيزي العميل،" + instructions: "تم شحن طلبك" + shipment_summary: "ملخص الشحن" + subject: "إشعار الشحن" + thanks: "شكرا لك على اعمالك." + track_information: "معلومات التتبع : %{tracking}" + track_link: "رابط التتبع: %{url}" + test_mailer: + test_email: + greeting: "تهانينا!" + message: "إذا كنت قد تلقيت هذا البريد الإلكتروني ، فإن إعدادات بريدك الإلكتروني صحيحة." + subject: "اختبار البريد" order_state: address: العنوان adjustments: التعديلات @@ -3262,18 +3509,6 @@ ar: ended: انتهى paused: التعليق canceled: الالغاء - user_mailer: - reset_password_instructions: - request_sent_text: | - تم تقديم طلب لإعادة تعيين كلمة المرور الخاصة بك. - إذا لم تقدم هذا الطلب ، ببساطة تجاهل هذا البريد الإلكتروني. - link_text: > - إذا قمت بهذا الطلب ، فما عليك سوى النقر فوق الرابط أدناه: - issue_text: | - إذا لم يعمل عنوان URL أعلاه ، فحاول نسخه ولصقه في متصفحك. - إذا كنت لا تزال تواجه مشاكل ، فلا تتردد في الاتصال بنا. - confirmation_instructions: - subject: يرجى تأكيد حسابك OFN users: form: account_settings: إعدادت الحساب diff --git a/config/locales/ca.yml b/config/locales/ca.yml index a71b762573..c1ac9478a7 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -13,6 +13,8 @@ ca: email: Correu electrònic de la consumidora spree/payment: amount: Import + state: Estat + source: Source spree/product: primary_taxon: "Categoria del producte" supplier: "Proveïdora" @@ -43,7 +45,7 @@ ca: after_orders_open_at: s'ha de fer amb el termini obert variant_override: count_on_hand: - using_producer_stock_settings_but_count_on_hand_set: "ha d'estar en blanc perquè s'utilitza la configuració de l'inventari de la productora" + using_producer_stock_settings_but_count_on_hand_set: "ha d'estar en blanc perquè s'utilitza la configuració d'estoc de la productora" on_demand_but_count_on_hand_set: "ha d'estar en blanc si és sota demanda" limited_stock_but_no_count_on_hand: "cal especificar-se perquè força existències limitades" activemodel: @@ -182,6 +184,7 @@ ca: explainer: El processament automàtic d'aquestes comandes va fallar per un motiu desconegut. Això no hauria de passar, si us plau, contacteu amb nosaltres si esteu veient això. home: "OFN" title: "Open Food Network" + welcome_to: "Benvingut a " site_meta_description: "Comencem des de baix. Amb agricultors i productors disposats a explicar les seves històries amb orgull i sinceritat. Amb distribuïdors connectant persones i productes de manera justa i honesta. Amb compradors que creuen que millors decisions de compra setmanal poden ..." search_by_name: Cercar per nom o barri ... producers_join: Els productors australians son ara benvinguts a unir-se a Open Food Network. @@ -270,6 +273,9 @@ ca: on hand: "Disponibles" ship: "Enviament" shipping_category: "Categoria d'enviament" + height: "Alçada" + width: "Amplada" + depth: "Profunditat" actions: create_and_add_another: "Crea i afegeix-ne una altra" create: "Crear" @@ -1036,10 +1042,13 @@ ca: name: "Resum de les comissions de l'organització" description: "Resum de les comissions de l'organització recollides" subscriptions: - subscriptions: Subscripcions - new: Nova subscripció - create: Crea una subscripció - edit: Edita la subscripció + index: + title: "Subscripcions" + new: "Nova subscripció" + new: + title: "Nova subscripció" + edit: + title: "Edita la subscripció" table: edit_subscription: Edita la subscripció pause_subscription: Pausa la subscripció @@ -1048,6 +1057,7 @@ ca: filters: query_placeholder: "Cerca per correu electrònic ..." setup_explanation: + title: "Subscripcions" just_a_few_more_steps: 'Només uns quants passos més abans de començar:' enable_subscriptions: "Activa les subscripcions d'almenys una de les teves botigues" enable_subscriptions_step_1_html: 1. Aneu a la pàgina %{enterprises_link}, cerqueu la vostra botiga i feu clic a "Gestionar" @@ -1061,6 +1071,8 @@ ca: create_at_least_one_schedule_step_3: 3. Fes clic a '+ Nova programació' i omple el formulari once_you_are_done_you_can_html: Un cop hagueu acabat, podeu %{reload_this_page_link} reload_this_page: tornar a carregar aquesta pàgina + form: + create: "Crea una subscripció" steps: details: 1. Detalls bàsics address: 2. Adreça @@ -1305,6 +1317,8 @@ ca: cart_updating: "Actualitzant la cistella..." cart_empty: "Cistella buida" cart_edit: "Edita la teva cistella" + item: "Article" + qty: "quant." card_number: Número de targeta card_securitycode: "Codi de seguretat" card_expiry_date: Data de caducitat @@ -1526,7 +1540,7 @@ ca: shopping_contact_social: "Segueix" shopping_groups_part_of: "forma part de:" shopping_producers_of_hub: "Productores de%{hub}:" - enterprises_next_closing: "Tancament de la comanda següent" + enterprises_next_closing: "La següent comanda tanca" enterprises_ready_for: "Llest per" enterprises_choose: "Escull quan vols la teva comanda:" maps_open: "Obert" @@ -1716,6 +1730,7 @@ ca: remember_me: Recorda'm are_you_sure: "Estàs segur?" orders_open: "Comandes obertes" + closing: "Tancant" going_back_to_home_page: "Tornant a la pàgina d'inici" creating: Creant updating: Actualitzant @@ -1934,7 +1949,7 @@ ca: admin_enterprise_groups: "Grups d'organització" admin_enterprise_groups_name: "Nom" admin_enterprise_groups_owner: "Propietària" - admin_enterprise_groups_on_front_page: "A la primera pàgina?" + admin_enterprise_groups_on_front_page: "Visible a la web" admin_enterprise_groups_enterprise: "Organitzacions" admin_enterprise_groups_data_powertip: "La usuària principal responsable d'aquest grup." admin_enterprise_groups_data_powertip_logo: "Això és el logotip del grup" @@ -1959,6 +1974,8 @@ ca: supplier: "Proveïdora" product_name: "Nom del producte" product_description: "Descripció del producte" + permalink: "Enllaç permanent" + shipping_categories: "Tipus d'enviament" units: "Mida d'unitat" coordinator: "Coordinador" distributor: "Distribuïdora" @@ -2055,6 +2072,8 @@ ca: remove_tax: "Suprimeix comissions" first_name_begins_with: "El nom comença amb" last_name_begins_with: "El cognom comença amb" + shipping_method: "Mètode d'enviament" + new_order: "Nova comanda" enterprise_tos_link: "Enllaç a les condicions d'ús de l'organització" enterprise_tos_message: "Volem treballar amb persones que comparteixen els nostres objectius i valors. Com a tal, demanem a les noves organitzacions que acceptin la nostra" enterprise_tos_link_text: "Termes del servei." @@ -2073,6 +2092,7 @@ ca: hub_sidebar_at_least: "Cal seleccionar almenys un grup " hub_sidebar_blue: "blau" hub_sidebar_red: "vermell" + order_cycles_closed_for_hub: "La botiga que has triat està temporalment tancada per a fer comandes. Sisplau, prova una mica més tard" report_customers_distributor: "Distribuïdora" report_customers_supplier: "Proveïdora" report_customers_cycle: "Cicle de Comanda" @@ -2309,6 +2329,7 @@ ca: order_cycles_email_to_producers_notice: 'Els correus electrònics per enviar a les productores estan en cua.' order_cycles_no_permission_to_coordinate_error: "Cap de les vostres organitzacions té permís per coordinar un cicle de comanda" order_cycles_no_permission_to_create_error: "No teniu permís per crear un cicle de comandes coordinat per aquesta organització" + order_cycle_closed: "El cicle de comandes que has triat acaba de tancar. Sisplau prova en un altre moment." back_to_orders_list: "Torna a la llista de comandes" no_orders_found: "No s'han trobat comandes" order_information: "Informació de la comanda" @@ -2564,7 +2585,7 @@ ca: 'yes': "Sota demanda" variant_overrides: on_demand: - use_producer_settings: "Utilitzeu la configuració d'inventari de la productora" + use_producer_settings: "Utilitzeu la configuració d'estoc de la productora" 'yes': "Sí" 'no': "No" inventory_products: "Productes de l'inventari" @@ -3168,6 +3189,8 @@ ca: stripe: error_saving_payment: Error en desar el pagament submitting_payment: S'està lliurant el pagament... + paypal: + no_payment_via_admin_backend: Els pagaments amb Paypal no es poden capturar des de l'administració products: image_upload_error: "No s'ha reconegut la imatge del producte. Carregueu una imatge en format PNG o JPG." new: @@ -3345,6 +3368,32 @@ ca: invoice_email: hi: "Hola %{name}" invoice_attached_text: Trobareu adjunta un comprovant de la compra per a la vostra comanda recent + user_mailer: + reset_password_instructions: + request_sent_text: | + S'ha fet una sol·licitud per restablir la teva contrasenya. + Si no has fet aquesta sol·licitud, simplement ignora aquest correu electrònic. + link_text: > + Si has fet aquesta sol·licitud, fes clic a l'enllaç següent: + issue_text: | + Si l'URL anterior no funciona, prova de copiar-lo i enganxar-lo al navegador. + Si continues tenint problemes, no dubtis en contactar-nos. + confirmation_instructions: + subject: "Si us plau confirma el teu compte d'OFN" + shipment_mailer: + shipped_email: + dear_customer: "Benvolguda consumidora:" + instructions: "La vostra comanda s'ha enviat" + shipment_summary: "Resum de l'enviament" + subject: "Notificació d'enviament" + thanks: "Gràcies per la teva compra." + track_information: "Informació del seguiment: %{tracking}" + track_link: "Enllaç del seguiment: %{url}" + test_mailer: + test_email: + greeting: "Enhorabona!" + message: "Si heu rebut aquest correu electrònic, la vostra configuració de correu electrònic és correcta." + subject: "Correu de prova" order_state: address: adreça adjustments: ajustaments @@ -3366,18 +3415,6 @@ ca: ended: acabat paused: en pausa canceled: cancel·lat - user_mailer: - reset_password_instructions: - request_sent_text: | - S'ha fet una sol·licitud per restablir la teva contrasenya. - Si no has fet aquesta sol·licitud, simplement ignora aquest correu electrònic. - link_text: > - Si has fet aquesta sol·licitud, fes clic a l'enllaç següent: - issue_text: | - Si l'URL anterior no funciona, prova de copiar-lo i enganxar-lo al navegador. - Si continues tenint problemes, no dubtis en contactar-nos. - confirmation_instructions: - subject: Si us plau confirma el teu compte d'OFN users: form: account_settings: Configuració del compte diff --git a/config/locales/de_DE.yml b/config/locales/de_DE.yml index de1588cf38..06e334a22a 100644 --- a/config/locales/de_DE.yml +++ b/config/locales/de_DE.yml @@ -13,6 +13,7 @@ de_DE: email: E-Mail des Kunden spree/payment: amount: Betrag + state: Status spree/product: primary_taxon: "Produktkategorie" supplier: "Anbieter" @@ -1028,10 +1029,13 @@ de_DE: name: "Unternehmensgebühr Zusammenfassung" description: "Zusammenfassung der erhobenen Zuschläge" subscriptions: - subscriptions: Abonnements - new: Neues Abonnement - create: Abonnement erstellen - edit: Abonnement bearbeiten + index: + title: "Abonnements" + new: "Neues Abonnement" + new: + title: "Neues Abonnement" + edit: + title: "Abonnement bearbeiten" table: edit_subscription: Abonnement bearbeiten pause_subscription: Abonement pausieren @@ -1040,6 +1044,7 @@ de_DE: filters: query_placeholder: "Suche per E-Mail ..." setup_explanation: + title: "Abonnements" just_a_few_more_steps: 'Nur noch ein paar Schritte bevor Sie beginnen können:' enable_subscriptions: "Aktivieren Sie Abonnements für mindestens einen Ihrer Läden" enable_subscriptions_step_1_html: 1. Gehen Sie zur Seite %{enterprises_link}, suchen Sie Ihren Laden und klicken Sie auf "Verwalten" @@ -1053,6 +1058,8 @@ de_DE: create_at_least_one_schedule_step_3: 3. Klicken Sie auf "+ Neuer Zeitplan" und füllen Sie das Formular aus once_you_are_done_you_can_html: Sobald Sie fertig sind, können Sie %{reload_this_page_link} reload_this_page: diese Seite neu laden + form: + create: "Abonnement erstellen" steps: details: 1. Grundlegendes address: 2. Adresse @@ -1285,6 +1292,8 @@ de_DE: cart_updating: "Warenkorb aktualisieren..." cart_empty: "Warenkorb leer" cart_edit: "Warenkorb bearbeiten" + item: "Artikel" + qty: "Menge" card_number: Kartennummer card_securitycode: "Sicherheitscode" card_expiry_date: Ablaufdatum @@ -1930,6 +1939,7 @@ de_DE: supplier: "Anbieter" product_name: "Produktname" product_description: "Produktbeschreibung" + shipping_categories: "Versandkategorien" units: "Einheitsgröße" coordinator: "Koordinator" distributor: "Verteiler" @@ -3257,6 +3267,27 @@ de_DE: invoice_email: hi: "Hallo %{name}" invoice_attached_text: Im Anhang findest Du eine Rechnung für die letzte Bestellung vom + user_mailer: + reset_password_instructions: + request_sent_text: | + Es wurde angefragt, das Passwort zurückzusetzen. + Sollte kein neues Passwort angefordert werden, bitte dieses E-Mail ignorieren. + link_text: > + Sollte ein neues Passwort angefordert werden, bitte den folgenden Aktivierungslink + bestätigen. + issue_text: | + Falls die URL nicht funktioniert, bitte den Link kopieren und in die Adresszeile Ihres Browsers einfügen + confirmation_instructions: + subject: "Bitte OFN-Konto bestätigen" + shipment_mailer: + shipped_email: + dear_customer: "Sehr geehrter Kunde," + instructions: "Ihre Bestellung wurde versandt" + shipment_summary: "Übersicht" + subject: "Versandbenachrichtigung" + thanks: "Danke für Ihren Einkauf." + track_information: "Tracking-Informationen: %{tracking}" + track_link: "Tracking-Link: %{url}" order_state: address: Adresse adjustments: Verbesserungen @@ -3278,18 +3309,6 @@ de_DE: ended: beendet paused: pausiert canceled: storniert - user_mailer: - reset_password_instructions: - request_sent_text: | - Es wurde angefragt, das Passwort zurückzusetzen. - Sollte kein neues Passwort angefordert werden, bitte dieses E-Mail ignorieren. - link_text: > - Sollte ein neues Passwort angefordert werden, bitte den folgenden Aktivierungslink - bestätigen. - issue_text: | - Falls die URL nicht funktioniert, bitte den Link kopieren und in die Adresszeile Ihres Browsers einfügen - confirmation_instructions: - subject: Bitte OFN-Konto bestätigen users: form: account_settings: Konto Einstellungen diff --git a/config/locales/en.yml b/config/locales/en.yml index 3726167337..8759f90d9b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -34,6 +34,8 @@ en: email: Customer E-Mail spree/payment: amount: Amount + state: State + source: Source spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -82,7 +84,7 @@ en: messages: inclusion: "is not included in the list" models: - order_management/subscriptions/validator: + order_management/subscriptions/validator: attributes: subscription_line_items: at_least_one_product: "^Please add at least one product" @@ -254,6 +256,7 @@ en: enterprises: Enterprises enterprise_groups: Groups reports: Reports + listing_reports: Listing Reports variant_overrides: Inventory import: Import spree_products: Spree Products @@ -303,6 +306,9 @@ en: "on hand": "On Hand" ship: "Ship" shipping_category: "Shipping Category" + height: "Height" + width: "Width" + depth: "Depth" actions: create_and_add_another: "Create and Add Another" @@ -1091,10 +1097,13 @@ en: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1103,6 +1112,7 @@ en: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1116,6 +1126,8 @@ en: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1384,6 +1396,8 @@ en: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" @@ -2088,6 +2102,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + permalink: "Permalink" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2167,7 +2183,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using spree_user_enterprise_limit_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})." spree_variant_product_error: must have at least one variant your_profil_live: "Your profile live" - on_ofn_map: "on the Open Food Network map" see: "See" live: "live" manage: "Manage" @@ -2184,6 +2199,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + shipping_method: "Shipping method" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " @@ -3331,6 +3348,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using stripe: error_saving_payment: Error saving payment submitting_payment: Submitting payment... + paypal: + no_payment_via_admin_backend: Paypal payments cannot be captured in the Backoffice products: image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." new: @@ -3508,6 +3527,32 @@ See the %{link} to find out more about %{sitename}'s features and to start using invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: ! "Tracking Information: %{tracking}" + track_link: ! "Tracking Link: %{url}" + test_mailer: + test_email: + greeting: "Congratulations!" + message: "If you have received this email, then your email settings are correct." + subject: "Test Mail" order_state: address: address adjustments: adjustments @@ -3529,18 +3574,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_AU.yml b/config/locales/en_AU.yml index 528ee44b6d..276534010f 100644 --- a/config/locales/en_AU.yml +++ b/config/locales/en_AU.yml @@ -13,6 +13,7 @@ en_AU: email: Customer E-Mail spree/payment: amount: Amount + state: State spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -1027,10 +1028,13 @@ en_AU: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1039,6 +1043,7 @@ en_AU: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1052,6 +1057,8 @@ en_AU: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1284,6 +1291,8 @@ en_AU: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1927,6 +1936,7 @@ en_AU: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2022,6 +2032,7 @@ en_AU: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3184,6 +3195,27 @@ en_AU: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" order_state: address: address adjustments: adjustments @@ -3205,18 +3237,6 @@ en_AU: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_BE.yml b/config/locales/en_BE.yml index ff1dc8bbc1..e68a2db4ab 100644 --- a/config/locales/en_BE.yml +++ b/config/locales/en_BE.yml @@ -13,6 +13,7 @@ en_BE: email: Customer E-Mail spree/payment: amount: Amount + state: State spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -990,10 +991,13 @@ en_BE: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1002,6 +1006,7 @@ en_BE: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1015,6 +1020,8 @@ en_BE: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1245,6 +1252,8 @@ en_BE: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1887,6 +1896,7 @@ en_BE: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -1982,6 +1992,7 @@ en_BE: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3093,6 +3104,27 @@ en_BE: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" order_state: address: address adjustments: adjustments @@ -3114,18 +3146,6 @@ en_BE: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml index a267d6397d..658cbcf1d4 100644 --- a/config/locales/en_CA.yml +++ b/config/locales/en_CA.yml @@ -13,6 +13,8 @@ en_CA: email: Customer E-Mail spree/payment: amount: Amount + state: State + source: Source spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -182,6 +184,7 @@ en_CA: explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this. home: "OFN" title: "Open Food Network" + welcome_to: "Welcome to" site_meta_description: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can…" search_by_name: Search by name or city producers_join: Producers are welcome to join the Open Food Network. @@ -270,6 +273,9 @@ en_CA: on hand: "On Hand" ship: "Ship" shipping_category: "Shipping Category" + height: "Height" + width: "Width" + depth: "Depth" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1033,10 +1039,13 @@ en_CA: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1045,6 +1054,7 @@ en_CA: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1058,6 +1068,8 @@ en_CA: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1160,7 +1172,7 @@ en_CA: mobile_menu: cart: "Cart" register_call: - selling_on_ofn: "Interested in getting on the Open Food Network?" + selling_on_ofn: "Interested in selling on the Open Food Network?" register: "Register here" footer: footer_secure: "Secure and trusted." @@ -1302,6 +1314,8 @@ en_CA: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1713,6 +1727,7 @@ en_CA: remember_me: Remember Me are_you_sure: "Are you sure?" orders_open: "Orders open" + closing: "Closing" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating @@ -1956,6 +1971,8 @@ en_CA: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + permalink: "Permalink" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2052,6 +2069,8 @@ en_CA: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + shipping_method: "Shipping method" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -2070,6 +2089,7 @@ en_CA: hub_sidebar_at_least: "At least one hub must be selected" hub_sidebar_blue: "blue" hub_sidebar_red: "red" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" @@ -2306,6 +2326,7 @@ en_CA: order_cycles_email_to_producers_notice: 'Emails to be sent to producers have been queued for sending.' order_cycles_no_permission_to_coordinate_error: "None of your enterprises have permission to coordinate an order cycle" order_cycles_no_permission_to_create_error: "You don't have permission to create an order cycle coordinated by that enterprise" + order_cycle_closed: "The order cycle you've selected has just closed. Please try again!" back_to_orders_list: "Back to order list" no_orders_found: "No Orders Found" order_information: "Order Information" @@ -2807,7 +2828,7 @@ en_CA: city: "City" zip: "Postal Code" country: "Country" - state: "Province" + state: "State" phone: "Phone" update: "Update" use_billing_address: "Use Billing Address" @@ -3161,6 +3182,8 @@ en_CA: stripe: error_saving_payment: Error saving payment submitting_payment: Submitting payment... + paypal: + no_payment_via_admin_backend: Paypal payments cannot be captured in the backoffice. products: image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." new: @@ -3338,6 +3361,32 @@ en_CA: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer, " + instructions: "Your order has been shipped or picked up." + shipment_summary: "Shipment/Pick Up Summary" + subject: "Shipment/Pick Up Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" + test_mailer: + test_email: + greeting: "Congratulations!" + message: "If you have received this email, then your OFN email settings are correct." + subject: "Test Mail" order_state: address: address adjustments: adjustments @@ -3359,18 +3408,6 @@ en_CA: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_DE.yml b/config/locales/en_DE.yml index 62e613451c..c854c60e94 100644 --- a/config/locales/en_DE.yml +++ b/config/locales/en_DE.yml @@ -13,6 +13,7 @@ en_DE: email: Customer E-Mail spree/payment: amount: Amount + state: State spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -998,10 +999,13 @@ en_DE: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1010,6 +1014,7 @@ en_DE: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1023,6 +1028,8 @@ en_DE: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1255,6 +1262,8 @@ en_DE: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1897,6 +1906,7 @@ en_DE: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -1992,6 +2002,7 @@ en_DE: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3110,6 +3121,27 @@ en_DE: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" order_state: address: address adjustments: adjustments @@ -3131,18 +3163,6 @@ en_DE: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_FR.yml b/config/locales/en_FR.yml index c514500eff..833ae09d47 100644 --- a/config/locales/en_FR.yml +++ b/config/locales/en_FR.yml @@ -13,6 +13,8 @@ en_FR: email: Customer E-Mail spree/payment: amount: Amount + state: State + source: Source spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -271,6 +273,9 @@ en_FR: on hand: "On Hand" ship: "Ship" shipping_category: "Shipping Category" + height: "Height" + width: "Width" + depth: "Depth" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1034,10 +1039,13 @@ en_FR: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1046,6 +1054,7 @@ en_FR: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1059,6 +1068,8 @@ en_FR: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1303,6 +1314,8 @@ en_FR: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1958,6 +1971,8 @@ en_FR: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + permalink: "Permalink" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2054,6 +2069,8 @@ en_FR: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + shipping_method: "Shipping method" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3166,6 +3183,8 @@ en_FR: stripe: error_saving_payment: Error saving payment submitting_payment: Submitting payment... + paypal: + no_payment_via_admin_backend: Paypal payments cannot be captured in the Backoffice products: image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." new: @@ -3343,6 +3362,32 @@ en_FR: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" + test_mailer: + test_email: + greeting: "Congratulations!" + message: "If you have received this email, then your email settings are correct." + subject: "Test Mail" order_state: address: address adjustments: adjustments @@ -3364,18 +3409,6 @@ en_FR: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml index 2250c91bb5..8885e48054 100644 --- a/config/locales/en_GB.yml +++ b/config/locales/en_GB.yml @@ -13,6 +13,8 @@ en_GB: email: Customer E-Mail spree/payment: amount: Amount + state: State + source: Source spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -182,6 +184,7 @@ en_GB: explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this. home: "OFN" title: "Open Food Network" + welcome_to: "Welcome to" site_meta_description: "The Open Food Network software platform allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" search_by_name: Search by name, town, county or postcode... producers_join: UK producers are now welcome to join Open Food Network UK. @@ -270,6 +273,9 @@ en_GB: on hand: "In Stock" ship: "Ship" shipping_category: "Shipping Category" + height: "Height" + width: "Width" + depth: "Depth" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1033,10 +1039,13 @@ en_GB: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1045,6 +1054,7 @@ en_GB: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1058,6 +1068,8 @@ en_GB: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1302,6 +1314,8 @@ en_GB: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1713,6 +1727,7 @@ en_GB: remember_me: Remember Me are_you_sure: "Are you sure?" orders_open: "Orders open" + closing: "Closing" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating @@ -1956,6 +1971,8 @@ en_GB: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + permalink: "Permalink" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2052,6 +2069,8 @@ en_GB: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Surname begins with" + shipping_method: "Shipping method" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3170,6 +3189,8 @@ en_GB: stripe: error_saving_payment: Error saving payment submitting_payment: Submitting payment... + paypal: + no_payment_via_admin_backend: Paypal payments cannot be captured in the Backoffice products: image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." new: @@ -3347,6 +3368,32 @@ en_GB: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your order with us." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" + test_mailer: + test_email: + greeting: "Congratulations!" + message: "If you have received this email, then your email settings are correct." + subject: "Test Mail" order_state: address: address adjustments: adjustments @@ -3368,18 +3415,6 @@ en_GB: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_IE.yml b/config/locales/en_IE.yml index c9112cfb88..c0743a88b4 100644 --- a/config/locales/en_IE.yml +++ b/config/locales/en_IE.yml @@ -13,6 +13,8 @@ en_IE: email: Customer E-Mail spree/payment: amount: Amount + state: County + source: Source spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -182,7 +184,8 @@ en_IE: explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this. home: "OFN" title: "Open Food Network" - site_meta_description: "The Open Food Network software platform allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" + welcome_to: "Welcome to" + site_meta_description: "Open Food Network Ireland allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" search_by_name: Search by name, town, county or eircode... producers_join: Producers are now welcome to join Open Food Network Ireland. charges_sales_tax: Charges VAT? @@ -270,6 +273,9 @@ en_IE: on hand: "In Stock" ship: "Ship" shipping_category: "Shipping Category" + height: "Height" + width: "Width" + depth: "Depth" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1033,10 +1039,13 @@ en_IE: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1045,6 +1054,7 @@ en_IE: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1058,6 +1068,8 @@ en_IE: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1302,6 +1314,8 @@ en_IE: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1650,7 +1664,7 @@ en_IE: sell_hubs_detail: "Set up a profile for your food enterprise or organisation on the OFN. At any time you can upgrade your profile to a multi-producer shop." sell_groups_detail: "Set up a tailored directory of enterprises (producers and other food enterprises) for your region or for your organisation." sell_user_guide: "Find out more in our user guide." - sell_listing_price: "Listing a profile on OFN Ireland is free. Plans for shops and hubs start from as little as £1 per month. For more detail on pricing visit https://about.openfoodnetwork.org.ie/pricing-and-plans/ ." + sell_listing_price: "Listing a profile on OFN Ireland is free. Plans for shops and hubs start from as little as €1 per month. For more details go to our Pricing page in the top menu." sell_embed: "We collectively budget for new feature development from the international OFN community. This way the huge cost of good software development can be shared. If you want a new feature, chances are someone in France, South Africa, Australia, India or Brazil might want it too! Use the Community Forum to suggest features you'd like to see." sell_ask_services: "Ask us about OFN services." shops_title: Shops @@ -1713,6 +1727,7 @@ en_IE: remember_me: Remember Me are_you_sure: "Are you sure?" orders_open: "Orders open" + closing: "Closing" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating @@ -1862,7 +1877,7 @@ en_IE: enterprise_final_step: "Final step!" enterprise_social_text: "How can people find %{enterprise} online?" website: "Website" - website_placeholder: "eg. openfoodnetwork.org.au" + website_placeholder: "eg. openfoodnetwork.ie" facebook: "Facebook" facebook_placeholder: "eg. www.facebook.com/PageNameHere" linkedin: "LinkedIn" @@ -1956,6 +1971,8 @@ en_IE: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + permalink: "Permalink" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2052,6 +2069,8 @@ en_IE: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Surname begins with" + shipping_method: "Shipping method" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3170,6 +3189,8 @@ en_IE: stripe: error_saving_payment: Error saving payment submitting_payment: Submitting payment... + paypal: + no_payment_via_admin_backend: Paypal payments cannot be captured in the Backoffice products: image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." new: @@ -3347,6 +3368,32 @@ en_IE: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your order with us." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" + test_mailer: + test_email: + greeting: "Congratulations!" + message: "If you have received this email, then your email settings are correct." + subject: "Test Mail" order_state: address: address adjustments: adjustments @@ -3368,18 +3415,6 @@ en_IE: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_IN.yml b/config/locales/en_IN.yml index e3ea0153f7..75a7047ad3 100644 --- a/config/locales/en_IN.yml +++ b/config/locales/en_IN.yml @@ -13,6 +13,7 @@ en_IN: email: Customer E-Mail spree/payment: amount: Amount + state: State spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -1034,10 +1035,13 @@ en_IN: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1046,6 +1050,7 @@ en_IN: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1059,6 +1064,8 @@ en_IN: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1303,6 +1310,8 @@ en_IN: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1958,6 +1967,7 @@ en_IN: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2054,6 +2064,7 @@ en_IN: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Surname begins with" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3349,6 +3360,27 @@ en_IN: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your order with us." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" order_state: address: address adjustments: adjustments @@ -3370,18 +3402,6 @@ en_IN: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_NZ.yml b/config/locales/en_NZ.yml index 226b98a5f6..987b08cdf0 100644 --- a/config/locales/en_NZ.yml +++ b/config/locales/en_NZ.yml @@ -13,6 +13,8 @@ en_NZ: email: Customer E-Mail spree/payment: amount: Amount + state: State + source: Source spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -182,6 +184,7 @@ en_NZ: explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this. home: "OFN" title: "Open Food Network" + welcome_to: "Welcome to" site_meta_description: "We begin from the ground up. With farmers, growers, and producers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can…" search_by_name: Search by name or suburb... producers_join: New Zealand producers are now welcome to join the Open Food Network. @@ -270,6 +273,9 @@ en_NZ: on hand: "On Hand" ship: "Ship" shipping_category: "Shipping Category" + height: "Height" + width: "Width" + depth: "Depth" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1033,10 +1039,13 @@ en_NZ: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1045,6 +1054,7 @@ en_NZ: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1058,6 +1068,8 @@ en_NZ: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1160,7 +1172,7 @@ en_NZ: mobile_menu: cart: "Cart" register_call: - selling_on_ofn: "Interested in getting on the Open Food Network?" + selling_on_ofn: "Want to set up a shop on the Open Food Network?" register: "Register here" footer: footer_secure: "Secure and trusted." @@ -1169,7 +1181,7 @@ en_NZ: footer_contact_email: "Email us" footer_nav_headline: "Navigate" footer_join_headline: "Join us" - footer_join_body: "Create a listing, shop or group directory on the Open Food Network." + footer_join_body: "Create a listing, build a shop or group directory on the Open Food Network." footer_join_cta: "Tell me more!" footer_legal_call: "Read our" footer_legal_tos: "Terms and conditions" @@ -1302,6 +1314,8 @@ en_NZ: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1377,7 +1391,7 @@ en_NZ: system_step1: "1. Search" system_step1_text: "Search our diverse, independent shops for seasonal local food. Search by neighbourhood and food category, or whether you prefer delivery or pickup." system_step2: "2. Shop" - system_step2_text: "Transform your transactions with affordable local food from diverse producers and hubs. Know the stories behind your food and the people who make it!" + system_step2_text: "Choose what you want, checkout as guest or make an account, you are good to go. Its that simple. If you'd like a box every week then ask for a subscription." system_step3: "3. Pick-up / Delivery" system_step3_text: "Hang on for your delivery, or visit your producer or hub for a more personal connection with your food. Food shopping as diverse as nature intended it." cta_headline: "Shopping that makes the world a better place." @@ -1713,6 +1727,7 @@ en_NZ: remember_me: Remember Me are_you_sure: "Are you sure?" orders_open: "Orders open" + closing: "Closing" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating @@ -1764,7 +1779,7 @@ en_NZ: steps: introduction: registration_greeting: "Hi there!" - registration_intro: "You can now create a profile for your Producer or Hub" + registration_intro: "Producer or Hub? You can create a profile" registration_checklist: "What do I need?" registration_time: "5-10 minutes" registration_enterprise_address: "Enterprise address" @@ -1956,6 +1971,8 @@ en_NZ: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + permalink: "Permalink" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2052,6 +2069,8 @@ en_NZ: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + shipping_method: "Shipping method" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3164,6 +3183,8 @@ en_NZ: stripe: error_saving_payment: Error saving payment submitting_payment: Submitting payment... + paypal: + no_payment_via_admin_backend: Paypal payments cannot be captured in the Backoffice products: image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." new: @@ -3341,6 +3362,32 @@ en_NZ: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" + test_mailer: + test_email: + greeting: "Congratulations!" + message: "If you have received this email, then your email settings are correct." + subject: "Test Mail" order_state: address: address adjustments: adjustments @@ -3362,18 +3409,6 @@ en_NZ: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_PH.yml b/config/locales/en_PH.yml index 7ac90cfc1b..25c7dbbe71 100644 --- a/config/locales/en_PH.yml +++ b/config/locales/en_PH.yml @@ -13,6 +13,7 @@ en_PH: email: Customer E-Mail spree/payment: amount: Amount + state: Province spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -1026,10 +1027,13 @@ en_PH: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1038,6 +1042,7 @@ en_PH: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1051,6 +1056,8 @@ en_PH: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1286,6 +1293,8 @@ en_PH: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1932,6 +1941,7 @@ en_PH: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2028,6 +2038,7 @@ en_PH: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3276,6 +3287,27 @@ en_PH: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" order_state: address: address adjustments: adjustments @@ -3297,18 +3329,6 @@ en_PH: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_US.yml b/config/locales/en_US.yml index f8c377e354..8cf511303b 100644 --- a/config/locales/en_US.yml +++ b/config/locales/en_US.yml @@ -13,6 +13,8 @@ en_US: email: Customer E-mail spree/payment: amount: Amount + state: State + source: Source spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -30,7 +32,7 @@ en_US: spree/user: attributes: email: - taken: "There's already an account registered for this email. Please login to reset your password." + taken: "There's already an account registered for this email. Please login or reset your password." spree/order: no_card: There are no authorized credit cards available to charge spree/credit_card: @@ -182,6 +184,7 @@ en_US: explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this. home: "OFN" title: "Open Food Network" + welcome_to: "Welcome to" site_meta_description: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can seriously change the world." search_by_name: Search by name or city... producers_join: US producers are now welcome to join the Open Food Network. @@ -270,6 +273,9 @@ en_US: on hand: "On Hand" ship: "Ship" shipping_category: "Shipping Category" + height: "Height" + width: "Width" + depth: "Depth" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1033,10 +1039,13 @@ en_US: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1045,6 +1054,7 @@ en_US: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1058,6 +1068,8 @@ en_US: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1302,6 +1314,8 @@ en_US: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card number card_securitycode: "Security code" card_expiry_date: Expiry date @@ -1713,6 +1727,7 @@ en_US: remember_me: Remember Me are_you_sure: "Are you sure?" orders_open: "Orders open" + closing: "Closing" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating @@ -1956,6 +1971,8 @@ en_US: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + permalink: "Permalink" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2052,6 +2069,8 @@ en_US: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Last name begins with" + shipping_method: "Shipping method" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3164,6 +3183,8 @@ en_US: stripe: error_saving_payment: Error saving payment submitting_payment: Submitting payment... + paypal: + no_payment_via_admin_backend: Paypal payments cannot be captured in the Backoffice products: image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." new: @@ -3341,6 +3362,32 @@ en_US: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below. + issue_text: | + If the above URL does nor work, try to copy and paste it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your business." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" + test_mailer: + test_email: + greeting: "Congratulations!" + message: "If you have received this email, then your email settings are correct." + subject: "Test Mail" order_state: address: address adjustments: adjustments @@ -3362,18 +3409,6 @@ en_US: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below. - issue_text: | - If the above URL does nor work, try to copy and paste it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/en_ZA.yml b/config/locales/en_ZA.yml index aa488086cc..e35379630c 100644 --- a/config/locales/en_ZA.yml +++ b/config/locales/en_ZA.yml @@ -13,6 +13,7 @@ en_ZA: email: Customer E-Mail spree/payment: amount: Amount + state: Province spree/product: primary_taxon: "Product Category" supplier: "Supplier" @@ -1028,10 +1029,13 @@ en_ZA: name: "Enterprise Fee Summary" description: "Summary of Enterprise Fees collected" subscriptions: - subscriptions: Subscriptions - new: New Subscription - create: Create Subscription - edit: Edit Subscription + index: + title: "Subscriptions" + new: "New Subscription" + new: + title: "New Subscription" + edit: + title: "Edit Subscription" table: edit_subscription: Edit Subscription pause_subscription: Pause Subscription @@ -1040,6 +1044,7 @@ en_ZA: filters: query_placeholder: "Search by email..." setup_explanation: + title: "Subscriptions" just_a_few_more_steps: 'Just a few more steps before you can begin:' enable_subscriptions: "Enable subscriptions for at least one of your shops" enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" @@ -1053,6 +1058,8 @@ en_ZA: create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} reload_this_page: reload this page + form: + create: "Create Subscription" steps: details: 1. Basic Details address: 2. Address @@ -1292,6 +1299,8 @@ en_ZA: cart_updating: "Updating cart..." cart_empty: "Cart empty" cart_edit: "Edit your cart" + item: "Item" + qty: "Qty" card_number: Card Number card_securitycode: "Security Code" card_expiry_date: Expiry Date @@ -1946,6 +1955,7 @@ en_ZA: supplier: "Supplier" product_name: "Product Name" product_description: "Product Description" + shipping_categories: "Shipping Categories" units: "Unit Size" coordinator: "Coordinator" distributor: "Distributor" @@ -2042,6 +2052,7 @@ en_ZA: remove_tax: "Remove tax" first_name_begins_with: "First name begins with" last_name_begins_with: "Surname begins with" + new_order: "New Order" enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." @@ -3169,6 +3180,27 @@ en_ZA: invoice_email: hi: "Hi %{name}" invoice_attached_text: Please find attached an invoice for your recent order from + user_mailer: + reset_password_instructions: + request_sent_text: | + A request to reset your password has been made. + If you did not make this request, simply ignore this email. + link_text: > + If you did make this request just click the link below: + issue_text: | + If the above URL does not work try copying and pasting it into your browser. + If you continue to have problems please feel free to contact us. + confirmation_instructions: + subject: "Please confirm your OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "Your order has been shipped" + shipment_summary: "Shipment Summary" + subject: "Shipment Notification" + thanks: "Thank you for your order with us." + track_information: "Tracking Information: %{tracking}" + track_link: "Tracking Link: %{url}" order_state: address: address adjustments: adjustments @@ -3190,18 +3222,6 @@ en_ZA: ended: ended paused: paused canceled: cancelled - user_mailer: - reset_password_instructions: - request_sent_text: | - A request to reset your password has been made. - If you did not make this request, simply ignore this email. - link_text: > - If you did make this request just click the link below: - issue_text: | - If the above URL does not work try copying and pasting it into your browser. - If you continue to have problems please feel free to contact us. - confirmation_instructions: - subject: Please confirm your OFN account users: form: account_settings: Account Settings diff --git a/config/locales/es.yml b/config/locales/es.yml index 75eed08b9d..206400d614 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -13,6 +13,8 @@ es: email: E-mail del consumidor spree/payment: amount: Cantidad + state: Provincia + source: Source spree/product: primary_taxon: "categoría del producto" supplier: "Proveedora" @@ -182,6 +184,7 @@ es: explainer: El procesamiento automático de estas órdenes falló por un motivo desconocido. Esto no debería ocurrir, contáctanos si estás viendo esto. home: "OFN" title: "Open Food Network" + welcome_to: "Bienvenido a" site_meta_description: "Nosotros empezamos desde abajo. Con granjeros y productoras listas para contar sus historias con orgullo y autenticidad. Con distribuidoras listas para conectar gente con productos de forma justa y honesta. Con compradores que creen que mejores decisiones de compras semanales pueden..." search_by_name: Buscar por nombre o municipio... producers_join: Las productoras australianas ahora son bienvenidas a unirse a Open Food Network. @@ -270,6 +273,9 @@ es: on hand: "Disponibles" ship: "Envío" shipping_category: "Categoría de envío" + height: "Altura" + width: "Anchura" + depth: "Profundidad" actions: create_and_add_another: "Crear y agregar otro" create: "Crear" @@ -1035,10 +1041,13 @@ es: name: "Resumen de las comisiones de la organización" description: "Resumen de las comisiones de la organización recolectadas" subscriptions: - subscriptions: Suscripciones - new: Nueva suscripción - create: Crear suscripción - edit: Editar suscripción + index: + title: "Suscripciones" + new: "Nueva suscripción" + new: + title: "Nueva suscripción" + edit: + title: "Editar suscripción" table: edit_subscription: Editar suscripción pause_subscription: Pausa Suscripción @@ -1047,6 +1056,7 @@ es: filters: query_placeholder: "Buscar por correo electrónico ..." setup_explanation: + title: "Suscripciones" just_a_few_more_steps: 'Solo unos pocos pasos más antes de que pueda comenzar:' enable_subscriptions: "Habilita suscripciones para al menos una de tus tiendas" enable_subscriptions_step_1_html: 1. Vaya a la página %{enterprises_link}, encuentre su tienda y haga clic en "Administrar" @@ -1060,6 +1070,8 @@ es: create_at_least_one_schedule_step_3: 3. Haga clic en '+ Nueva programación' y complete el formulario once_you_are_done_you_can_html: Una vez que haya terminado, puede %{reload_this_page_link} reload_this_page: recarga esta página + form: + create: "Crear suscripción" steps: details: 1. Detalles básicos address: 2. Dirección @@ -1151,7 +1163,12 @@ es: cart: "Carrito" cart_sidebar: checkout: "Validar" + edit_cart: "Editar carrito" + items_in_cart_singular: "%{num} artículo en su carrito" + items_in_cart_plural: "%{num} artículos en su carrito" close: "Cerrar" + cart_empty: "Tu carrito esta vacío" + take_me_shopping: "¡Llévame de compras!" signed_in: profile: "Perfil" mobile_menu: @@ -1299,6 +1316,8 @@ es: cart_updating: "Actualizando el carrito..." cart_empty: "Carrito vacío" cart_edit: "Editar carrito" + item: "Artículo" + qty: "Cantidad" card_number: Número de tarjeta card_securitycode: "Código de seguridad" card_expiry_date: Fecha de expiración @@ -1710,6 +1729,7 @@ es: remember_me: Recordarme are_you_sure: "¿Está seguro?" orders_open: "Pedidos abiertos" + closing: "Cerrando" going_back_to_home_page: "Le estamos llevando de vuelta a la página de inicio" creating: Creando updating: Actualizando @@ -1953,6 +1973,8 @@ es: supplier: "Proveedora" product_name: "nombre del producto" product_description: "Descripción del producto" + permalink: "Enlace permanente" + shipping_categories: "Categorías de envío" units: "Unidad de medida" coordinator: "Coordinadora" distributor: "Distribuidor" @@ -2049,6 +2071,8 @@ es: remove_tax: "Eliminar impuesto" first_name_begins_with: "El nombre comienza con" last_name_begins_with: "El apellido comienza con" + shipping_method: "Método de envío" + new_order: "Nuevo pedido" enterprise_tos_link: "Enlace a los Términos del Servicio de la Organización" enterprise_tos_message: "Queremos trabajar con personas que compartan nuestros objetivos y valores. Por ello, pedimos a las nuevas organizaciones que acepten" enterprise_tos_link_text: "Términos del Servicio." @@ -2067,6 +2091,7 @@ es: hub_sidebar_at_least: "Al menos un grupo debe ser seleccionado" hub_sidebar_blue: "azul" hub_sidebar_red: "rojo" + order_cycles_closed_for_hub: "El grupo que ha seleccionado está temporalmente cerrado para pedidos. Por favor, inténtelo de nuevo más tarde." report_customers_distributor: "Distribuidor" report_customers_supplier: "Proveedora" report_customers_cycle: "Ciclo de Pedido" @@ -2303,6 +2328,7 @@ es: order_cycles_email_to_producers_notice: 'Los correos electrónicos que se enviarán a las productoras se han puesto en cola para enviarlos.' order_cycles_no_permission_to_coordinate_error: "Ninguna de tus organizaciones tiene permiso para coordinar un ciclo de pedido" order_cycles_no_permission_to_create_error: "No tienes permiso para crear un ciclo de pedido coordinado por esta empresa." + order_cycle_closed: "El ciclo de pedido que ha seleccionado se acaba de cerrar. ¡Inténtalo de nuevo!" back_to_orders_list: "Volver a la lista de pedidos" no_orders_found: "No se encontraron pedidos" order_information: "información del pedido" @@ -3163,6 +3189,8 @@ es: stripe: error_saving_payment: Error al guardar el pago submitting_payment: Enviando pago... + paypal: + no_payment_via_admin_backend: Los pagos de PayPal no se pueden capturar desde la administración products: image_upload_error: "La imagen del producto no fue reconocida. Por favor, cargue una imagen en formato PNG o JPG." new: @@ -3340,6 +3368,32 @@ es: invoice_email: hi: "Hola %{name}" invoice_attached_text: Adjunta una factura para su pedido reciente de + user_mailer: + reset_password_instructions: + request_sent_text: | + Se ha solicitado el cambio de tu contraseña. + Si tu no lo has solicitado simplemente ignora este email. + link_text: > + Si has solicitado esta acción haz click en el siguiente enlace: + issue_text: | + Si el enlace no funciona prueba a copiarlo y pegarlo en tu navegador. + Si los problemas continúan no dudes en contactarnos. + confirmation_instructions: + subject: "Por favor, confirma tu cuenta de OFN" + shipment_mailer: + shipped_email: + dear_customer: "Estimada consumidora," + instructions: "Tu pedido ha sido enviado" + shipment_summary: "Resumen de envío" + subject: "Notificación de envío" + thanks: "Gracias por hacer negocios." + track_information: "Información de seguimiento: %{tracking}" + track_link: "Enlace de seguimiento: %{url}" + test_mailer: + test_email: + greeting: "¡Felicidades!" + message: "Si ha recibido este correo electrónico, su configuración de correo electrónico es correcta." + subject: "Correo de prueba" order_state: address: dirección adjustments: ajustes @@ -3361,18 +3415,6 @@ es: ended: terminado paused: pausado canceled: cancelado - user_mailer: - reset_password_instructions: - request_sent_text: | - Se ha solicitado el cambio de tu contraseña. - Si tu no lo has solicitado simplemente ignora este email. - link_text: > - Si has solicitado esta acción haz click en el siguiente enlace: - issue_text: | - Si el enlace no funciona prueba a copiarlo y pegarlo en tu navegador. - Si los problemas continúan no dudes en contactarnos. - confirmation_instructions: - subject: Por favor, confirma tu cuenta de OFN users: form: account_settings: Configuración de la cuenta diff --git a/config/locales/es_CR.yml b/config/locales/es_CR.yml index d22b5cdff1..fd81f7dc12 100644 --- a/config/locales/es_CR.yml +++ b/config/locales/es_CR.yml @@ -13,6 +13,7 @@ es_CR: email: Correo electrónico del cliente spree/payment: amount: Cantidad + state: Provincia spree/product: primary_taxon: "Categoría del producto" supplier: "Proveedor" @@ -1029,10 +1030,13 @@ es_CR: name: "Resumen de las comisiones de la organización" description: "Resumen de las comisiones de la organización recolectadas" subscriptions: - subscriptions: Suscripciones - new: Nueva suscripción - create: Crear suscripción - edit: Editar suscripción + index: + title: "Suscripciones" + new: "Nueva suscripción" + new: + title: "Nueva suscripción" + edit: + title: "Editar suscripción" table: edit_subscription: Editar suscripción pause_subscription: Pausar suscripción @@ -1041,6 +1045,7 @@ es_CR: filters: query_placeholder: "Buscar por correo electrónico ..." setup_explanation: + title: "Suscripciones" just_a_few_more_steps: 'Solo unos pocos pasos más antes de que pueda comenzar:' enable_subscriptions: "Habilita suscripciones para al menos una de sus tiendas" enable_subscriptions_step_1_html: 1. Ir a la página %{enterprises_link}, encuentre su tienda y haga clic en "Administrar" @@ -1054,6 +1059,8 @@ es_CR: create_at_least_one_schedule_step_3: 3. Haga clic en '+ Nueva programación' y complete el formulario once_you_are_done_you_can_html: Una vez que haya terminado, puede %{reload_this_page_link} reload_this_page: recarga esta página + form: + create: "Crear suscripción" steps: details: 1. Detalles básicos address: 2. Dirección @@ -1289,6 +1296,8 @@ es_CR: cart_updating: "Actualizando el carrito..." cart_empty: "Carrito vacío" cart_edit: "Editar carrito" + item: "Artículo" + qty: "Cantidad" card_number: Número de tarjeta card_securitycode: "Código de seguridad" card_expiry_date: Fecha de expiración @@ -1936,6 +1945,7 @@ es_CR: supplier: "Proveedora" product_name: "nombre del producto" product_description: "Descripción del producto" + shipping_categories: "Categorías de envío" units: "Unidad de medida" coordinator: "Coordinadora" distributor: "Distribuidor" @@ -2032,6 +2042,7 @@ es_CR: remove_tax: "Eliminar impuesto" first_name_begins_with: "El nombre comienza con" last_name_begins_with: "El apellido comienza con" + new_order: "Nuevo pedido" enterprise_tos_link: "Enlace a los Términos del Servicio de la Organización" enterprise_tos_message: "Queremos trabajar con personas que compartan nuestros objetivos y valores. Por ello, pedimos a las nuevas organizaciones que acepten" enterprise_tos_link_text: "Términos del Servicio." @@ -3284,6 +3295,27 @@ es_CR: invoice_email: hi: "Hola %{name}" invoice_attached_text: Adjunta una factura para su pedido reciente de + user_mailer: + reset_password_instructions: + request_sent_text: | + La solicitud de restablecer su contraseña se ha realizado. + Si usted no lo ha solicitado, ignora este correo electrónico. + link_text: > + Si has solicitado esta acción haz click en el siguiente enlace: + issue_text: | + Si el enlace anterior no funciona pruebe con copiarlo y pegarlo en su navegador. + Si los problemas continúan no dude en contactarnos. + confirmation_instructions: + subject: "Por favor, confirma tu cuenta de OFN" + shipment_mailer: + shipped_email: + dear_customer: "Estimado cliente," + instructions: "Su pedido ha sido enviado" + shipment_summary: "Resumen de envío" + subject: "Notificación de envío" + thanks: "Gracias por su negocio." + track_information: "Información de seguimiento: %{tracking}" + track_link: "Enlace de seguimiento: %{url}" order_state: address: dirección adjustments: ajustes @@ -3305,18 +3337,6 @@ es_CR: ended: terminado paused: pausado canceled: cancelado - user_mailer: - reset_password_instructions: - request_sent_text: | - La solicitud de restablecer su contraseña se ha realizado. - Si usted no lo ha solicitado, ignora este correo electrónico. - link_text: > - Si has solicitado esta acción haz click en el siguiente enlace: - issue_text: | - Si el enlace anterior no funciona pruebe con copiarlo y pegarlo en su navegador. - Si los problemas continúan no dude en contactarnos. - confirmation_instructions: - subject: Por favor, confirma tu cuenta de OFN users: form: account_settings: Configuración de la cuenta diff --git a/config/locales/fil_PH.yml b/config/locales/fil_PH.yml index 94f2cac702..a22b91439c 100644 --- a/config/locales/fil_PH.yml +++ b/config/locales/fil_PH.yml @@ -13,6 +13,7 @@ fil_PH: email: Email ng Parokyano spree/payment: amount: Halaga + state: province spree/product: primary_taxon: "Kategorya ng Produkto" supplier: "Supplier" @@ -315,7 +316,7 @@ fil_PH: clear_all: alisin lahat start_date: "Petsa ng Pagsimula" end_date: "Petsa ng Pagtatapos" - form_invalid: "ang form ay may nawawala o hindi valid na sagot sa mga patlang" + form_invalid: "ang form ay may kulang o hindi valid na mga sagot" clear_filters: alisin ang mga filter clear: alisin save: i-save @@ -355,7 +356,7 @@ fil_PH: settings: "settings" stripe_connect_enabled: paganahin ang pagtanggap ng mga bayad gamit ang Stripe Connect sa mga Shop? no_api_key_msg: walang Stripe account para sa enterprise na ito - configuration_explanation_html: para sa detalyadong panuto sa pag-configure ng pagsasama ng Stripe Connect, maaari lamang nakumonsulta sa gabay. + configuration_explanation_html: para sa detalyadong panuto sa pag-configure upang magamit ang Stripe Connect, maaari lamang nakumonsulta sa gabay. status: Status ok: Ok instance_secret_key: Instance Secret Key @@ -387,11 +388,11 @@ fil_PH: select_state: 'pumili ng Lalawigan' edit: 'i-edit' update_address: 'i-update ang address' - confirm_delete: 'siguradong tatanggalin?' + confirm_delete: 'siguradong tatanggalin na?' search_by_email: "hanapin gamit ang email/code..." guest_label: 'Guest checkout' destroy: - has_associated_orders: 'hindi tagumpay ang pagtanggal: ang customer ay may mga iniugnay na order sa kaniyang shop' + has_associated_orders: 'hindi tagumpay ang pagtanggal: ang customer ay may iniugnay na mga order sa kaniyang shop' contents: edit: title: nilalaman @@ -423,7 +424,7 @@ fil_PH: form: manages: namamahala enterprise_role: - manages: namamahala + manages: pinamamahalaan products: unit_name_placeholder: 'hal. mga kumpol' index: @@ -541,7 +542,7 @@ fil_PH: products_created: ang mga produkto ay nagawa na products_updated: in-update ang mga produkto inventory_created: ang mga imbentaryo ng item ay nagawa na - inventory_updated: inupdate ang mga inimbentaryong item + inventory_updated: inupdate ang mga naka-imbentaryong item products_reset: na-reset sa zero ang lebel ng stock ng mga produkto inventory_reset: na-reset sa zero ang lebel ng stock ng mga imbentaryo ng item all_saved: "lahat ng mga item ay matagumpay na na-save" @@ -1029,10 +1030,13 @@ fil_PH: name: "buod ng bayad sa enterprise" description: "buod ng mga nakolektang fees para sa enterprise" subscriptions: - subscriptions: mga subscription - new: bagong subscription - create: gumawa ng subscription - edit: i-edit ang subscription + index: + title: "mga nauulit na order" + new: "bagong subscription" + new: + title: "bagong subscription" + edit: + title: "i-edit ang subscription" table: edit_subscription: i-edit ang subscription pause_subscription: panandaliang ihinto ang subscription @@ -1041,6 +1045,7 @@ fil_PH: filters: query_placeholder: "hanapin gamit ang email..." setup_explanation: + title: "mga nauulit na order" just_a_few_more_steps: 'ilang hakbang na lamang bago ka makapagsimula:' enable_subscriptions: "paganahin ang subscription sa kahit isa sa iyong mga shop" enable_subscriptions_step_1_html: 1. pumunta sa%{enterprises_link}pahina, hanapin ang iyong shop at pindutin ang "pamahalaan" @@ -1054,6 +1059,8 @@ fil_PH: create_at_least_one_schedule_step_3: 3. pindutin ang '+ bagong iskedyul' at sagutan ang form once_you_are_done_you_can_html: kapag natapos na ito, maaari mong%{reload_this_page_link} reload_this_page: i-reload ang pahina na ito + form: + create: "gumawa ng subscription" steps: details: 1. pangunahing detalye address: 2. address @@ -1107,7 +1114,7 @@ fil_PH: yes_cancel_them: kanselahin no_keep_them: ituloy yes_i_am_sure: oo, sigurado ako - order_update_issues_msg: ang ibang mga order ay hindi awtomatikong ma-update, sapagkat ito ay manwal na inayos. Tignan ang mga isyu na nakalista sa baba at gawin ang nararapat na pag-aayos sa bawat order kung kinakailangan. + order_update_issues_msg: "ang ibang mga order ay hindi awtomatikong ma-update, sapagkat ito ay manwal na inayos. Tignan ang mga isyu na nakalista sa baba at gawin ang nararapat na pag-aayos sa bawat indibiduwal na \norder kung kinakailangan." no_results: no_subscriptions: wala pang mga subscription.... why_dont_you_add_one: nais mo bang magdagdag ng isa? :) @@ -1165,7 +1172,7 @@ fil_PH: footer_legal_call: "basahin ang aming" footer_legal_tos: "mga tuntunin at kondisyon" footer_legal_visit: "Hanapin kami sa" - footer_legal_text_html: "ang Open Food Network ay isang libre at bukas ang pinagkukuhanang platform. ang mga nilalaman nito ay lisensiyado ng%{content_license}at ang aming mga code ng %{code_license}." + footer_legal_text_html: "ang Open Food Network ay isang libre at open source software platform. ang mga nilalaman nito ay lisensiyado ng%{content_license}at ang aming mga code ng %{code_license}." footer_data_text_with_privacy_policy_html: "Pinangangalagaan namin ang inyong impormasyon. Basahin ang aming%{privacy_policy}at%{cookies_policy}" footer_data_text_without_privacy_policy_html: "Pinangangalagaan namin ang inyong impormasyon. Basahin ang aming%{cookies_policy}" footer_data_privacy_policy: "patakaran ng privacy" @@ -1280,8 +1287,8 @@ fil_PH: label_administration: "administrasyon" label_admin: "admin" label_account: "Account" - label_more: "ipakita lahat" - label_less: "ipakita ang mas kaunti" + label_more: "ipakita ang iba pa" + label_less: "huwag ipakita ang lahat" label_notices: "mga abiso" cart_items: "mga item" cart_headline: "Ang iyong shopping cart" @@ -1289,6 +1296,8 @@ fil_PH: cart_updating: "ina-update ang cart" cart_empty: "walang laman ang cart" cart_edit: "i-edit ang cart" + item: "Item" + qty: "Dami" card_number: numero ng card card_securitycode: "Security code" card_expiry_date: petsa ng pag-expire @@ -1936,6 +1945,7 @@ fil_PH: supplier: "Supplier" product_name: "pangalan ng produkto" product_description: "paglalarawan ng produkto" + shipping_categories: "mga kategorya ng pagpapadala" units: "laki kada yunit" coordinator: "coordinator" distributor: "Distributor" @@ -2032,6 +2042,7 @@ fil_PH: remove_tax: "alisin ang tax" first_name_begins_with: "ang pangalan ay nagsisimula sa" last_name_begins_with: "ang apelyido ay nagsisimula sa" + new_order: "bagong order" enterprise_tos_link: "Link para sa palatuntunan ng serbisyo ng Enterprise" enterprise_tos_message: "nais naming makiisa sa mga taong kapareho ng aming layunin at adhikain. Dahil dito, hinihiling namin sa mga bagong enterprise na sumang-ayon sa aming" enterprise_tos_link_text: "Mga Tuntunin ng Serbisyo." @@ -3289,6 +3300,27 @@ fil_PH: invoice_email: hi: "Hi %{name}" invoice_attached_text: 'tignan ang nakalakip na invoice para sa pinakabagong order mula sa ' + user_mailer: + reset_password_instructions: + request_sent_text: | + may ginawang request para i-reset ang inyong password. + kung hindi ikaw ang gumawa nito, huwag pansinin ang email na ito. + link_text: > + kung ikaw ang gumawa ng request na ito, pindutin ang link sa ilalim: + issue_text: | + kung ang URL sa itaas ay hindi gumagana, subukang kopyahin at i-paste ito sa inyong browser. + kung patuloy na magkakaroon ng mga problema, huwag mag-atubiling makipag-ugnayan sa amin. + confirmation_instructions: + subject: "kumpirmahin ang inyong OFN account" + shipment_mailer: + shipped_email: + dear_customer: "Dear Customer," + instructions: "ang iyong order ay na-ship na " + shipment_summary: "buod ng kargamento" + subject: "notification ukol sa kargamento" + thanks: "Salamat sa inyong pagtangkilik" + track_information: "Impormasyon ukol sa pag-track: %{tracking}" + track_link: "Link ng pag-track:%{url}" order_state: address: tirahan adjustments: mga pagsasaayos @@ -3310,18 +3342,6 @@ fil_PH: ended: natapos na paused: nakahinto canceled: kanselado - user_mailer: - reset_password_instructions: - request_sent_text: | - may ginawang request para i-reset ang inyong password. - kung hindi ikaw ang gumawa nito, huwag pansinin ang email na ito. - link_text: > - kung ikaw ang gumawa ng request na ito, pindutin ang link sa ilalim: - issue_text: | - kung ang URL sa itaas ay hindi gumagana, subukang kopyahin at i-paste ito sa inyong browser. - kung patuloy na magkakaroon ng mga problema, huwag mag-atubiling makipag-ugnayan sa amin. - confirmation_instructions: - subject: kumpirmahin ang inyong OFN account users: form: account_settings: Setting ng Account diff --git a/config/locales/fr.yml b/config/locales/fr.yml index eb8d4e055d..29757b8572 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -13,6 +13,8 @@ fr: email: Email acheteur spree/payment: amount: Montant + state: Statut + source: Source spree/product: primary_taxon: "Catégorie Produit" supplier: "Fournisseur" @@ -271,6 +273,9 @@ fr: on hand: "En stock" ship: "Expédier" shipping_category: "Condition de transport" + height: "Hauteur" + width: "Largeur" + depth: "Profondeur" actions: create_and_add_another: "Créer et ajouter nouveau" create: "Créer" @@ -1036,10 +1041,13 @@ fr: name: "Résumé des marges et commissions" description: "Résumé des marges et commissions collectées" subscriptions: - subscriptions: Abonnements - new: Nouvel abonnement - create: Créer abonnement - edit: Mettre à jour Abonnement + index: + title: "Abonnements" + new: "Nouvel abonnement" + new: + title: "Nouvel abonnement" + edit: + title: "Mettre à jour Abonnement" table: edit_subscription: Mettre à jour Abonnement pause_subscription: Mettre en pause Abonnement @@ -1048,6 +1056,7 @@ fr: filters: query_placeholder: "Recherche par email" setup_explanation: + title: "Abonnements" just_a_few_more_steps: 'Encore quelques étapes avant de pouvoir commencer:' enable_subscriptions: "Activez la fonction abonnements pour au moins une de vos boutiques" enable_subscriptions_step_1_html: 1. Allez à %{enterprises_link}, trouvez votre boutique, et cliquez sur "Gérer" @@ -1061,6 +1070,8 @@ fr: create_at_least_one_schedule_step_3: 3. Cliquez sur "+ Nouveau Rythme d'abonnement", et remplissez le formulaire once_you_are_done_you_can_html: Une fois que c'est fait, vous pouvez %{reload_this_page_link} reload_this_page: recharger cette page + form: + create: "Créer abonnement" steps: details: 1. Informations de base address: 2. Adresse @@ -1151,7 +1162,7 @@ fr: cart: cart: "Panier" cart_sidebar: - checkout: "Etape suivante (coordonnées)" + checkout: "Etape suivante" edit_cart: "Modifier le panier" items_in_cart_singular: "%{num} élément dans le panier" items_in_cart_plural: "%{num} éléments dans le panier" @@ -1305,6 +1316,8 @@ fr: cart_updating: "Mettre à jour le panier" cart_empty: "Panier vide" cart_edit: "Modifier votre panier" + item: "Produit" + qty: "Qté" card_number: Numéro de carte card_securitycode: "Cryptogramme visuel" card_expiry_date: Date d'expiration @@ -1400,7 +1413,7 @@ fr: checkout_details: "Vos informations" checkout_billing: "Informations de facturation" checkout_default_bill_address: "Sauvegarder comme adresse de facturation par défaut" - checkout_shipping: Informations de livraison + checkout_shipping: Informations de livraison ou de retrait checkout_default_ship_address: "Sauvegarder comme adresse de livraison par défaut" checkout_method_free: Pas de frais supplémentaires checkout_address_same: Adresse de livraison identique à l'adresse de facturation? @@ -1960,6 +1973,8 @@ fr: supplier: "Fournisseur" product_name: "Nom du Produit" product_description: "Description du Produit" + permalink: "Permalien" + shipping_categories: "Conditions de transport" units: "Unité de mesure" coordinator: "Coordinateur" distributor: "Distributeur" @@ -2056,6 +2071,8 @@ fr: remove_tax: "Retirer TVA" first_name_begins_with: "Prénom commence par" last_name_begins_with: "Nom de famille commence par" + shipping_method: "Méthode de livraison" + new_order: "Nouvelle commande" enterprise_tos_link: "Lien vers les Conditions Générales d'Utilisation" enterprise_tos_message: "Nous soutenons la mise en place d'un système alimentaire résilient et durable, et souhaitons œuvrer avec des entreprises qui partagent nos valeurs et notre vision. Ainsi, nous demandons aux entreprises s'enregistrant sur Open Food France de valider nos " enterprise_tos_link_text: "Conditions d'utilisation" @@ -3139,12 +3156,12 @@ fr: zones: "Zones" both: "Vu par l'acheteur sur la boutique" back_end: "Visible pour l'administration uniquement" - deactivation_warning: "Désactiver une méthode de livraison peut engendre sa disparition de la liste ici. Si vous souhaitez uniquement ne plus l'afficher pour l'acheteur, modifiez-là et utilisez l'option d'affichage \"visible pour l'administrateur uniquement\"." + deactivation_warning: "Désactiver une méthode de livraison peut engendrer sa disparition de la liste ici. Si vous souhaitez uniquement ne plus l'afficher pour l'acheteur, modifiez-là et utilisez l'option d'affichage \"visible pour l'administrateur uniquement\"." payment_methods: index: payment_methods: "Méthodes de paiement" new_payment_method: "Nouvelle méthode de paiement" - name: "Produit/Variante" + name: "Nom" products_distributor: "Distributeur" provider: "Fournisseur" environment: "Environnement" @@ -3177,7 +3194,7 @@ fr: business_name: Nom de l'entreprise charges_enabled: Frais activés form: - name: "Produit/Variante" + name: "Nom" description: "Description" environment: "Environnement" display: "Afficher" @@ -3196,6 +3213,8 @@ fr: stripe: error_saving_payment: Erreur à l'enregistrement du paiement submitting_payment: Envoi du paiement... + paypal: + no_payment_via_admin_backend: 'Il n''est pas encore possible de payer avec Paypal via l''administration. ' products: image_upload_error: "L'image du produit n'a pas été reconnue. Veuillez importer une image au format PNG ou JPG." new: @@ -3373,6 +3392,33 @@ fr: invoice_email: hi: "Bonjour %{name}" invoice_attached_text: 'Veuillez trouver ci-joint la facture pour votre récente commande auprès de ' + user_mailer: + reset_password_instructions: + request_sent_text: | + Votre demande de nouveau mot de passe a bien été prise en compte. + Si vous n'avez pas demandé de nouveau mot de passe, veuillez ignorer cet e-mail. + link_text: > + Si vous êtes bien à l'origine de cette demande, veuillez cliquer sur le + lien ci-dessous : + issue_text: | + Si le lien ne fonctionne pas, essayez de le copier - coller dans la barre d'adresse de votre navigateur. + Si le problème persiste, n'hésitez pas à nous contacter. + confirmation_instructions: + subject: "Veuillez confirmer votre compte" + shipment_mailer: + shipped_email: + dear_customer: "Cher Acheteur," + instructions: "Votre commande a été expédiée" + shipment_summary: "Résumé de l'envoi" + subject: "Notification d'expédition" + thanks: "Merci pour votre commande." + track_information: "Informations de suivi : %{tracking}" + track_link: "Lien de suivi : %{url}" + test_mailer: + test_email: + greeting: "Félicitations !" + message: "Si vous avez reçu cet email, cela signifie que vos emails sont bien paramétrés." + subject: "Mail de test" order_state: address: adresse adjustments: ajustements @@ -3394,19 +3440,6 @@ fr: ended: terminé paused: mis en pause canceled: annulé - user_mailer: - reset_password_instructions: - request_sent_text: | - Votre demande de nouveau mot de passe a bien été prise en compte. - Si vous n'avez pas demandé de nouveau mot de passe, veuillez ignorer cet e-mail. - link_text: > - Si vous êtes bien à l'origine de cette demande, veuillez cliquer sur le - lien ci-dessous : - issue_text: | - Si le lien ne fonctionne pas, essayez de le copier - coller dans la barre d'adresse de votre navigateur. - Si le problème persiste, n'hésitez pas à nous contacter. - confirmation_instructions: - subject: Veuillez confirmer votre compte users: form: account_settings: Paramètres du Compte diff --git a/config/locales/fr_BE.yml b/config/locales/fr_BE.yml index a8822f7337..0cda69808c 100644 --- a/config/locales/fr_BE.yml +++ b/config/locales/fr_BE.yml @@ -13,6 +13,7 @@ fr_BE: email: Adresse électronique acheteur spree/payment: amount: Montant + state: Statut de la commande spree/product: primary_taxon: "Catégorie de Produit" supplier: "Fournisseur" @@ -1028,10 +1029,13 @@ fr_BE: name: "Récapitulatif de la commission d'entreprise " description: "Récapitulatif des commissions d'entreprise perçues" subscriptions: - subscriptions: Abonnements - new: Nouvel abonnement - create: Créer abonnement - edit: Mettre à jour Abonnement + index: + title: "commandes récurrantes" + new: "Nouvel abonnement" + new: + title: "Nouvel abonnement" + edit: + title: "Mettre à jour Abonnement" table: edit_subscription: Mettre à jour Abonnement pause_subscription: Mettre en pause Abonnement @@ -1040,6 +1044,7 @@ fr_BE: filters: query_placeholder: "Recherche par email ..." setup_explanation: + title: "commandes récurrantes" just_a_few_more_steps: 'Encore quelques étapes avant de pouvoir commencer:' enable_subscriptions: "Activez la fonction abonnements pour au moins une de vos comptoirs" enable_subscriptions_step_1_html: 1. Allez à %{enterprises_link}, trouvez votre comptoir, et cliquez sur "Gérer" @@ -1053,6 +1058,8 @@ fr_BE: create_at_least_one_schedule_step_3: 3. Cliquez sur "+ Nouveau Rythme d'abonnement", et remplissez le formulaire once_you_are_done_you_can_html: Une fois que c'est fait, vous pouvez %{reload_this_page_link} reload_this_page: recharger cette page + form: + create: "Créer abonnement" steps: details: 1. Informations de base address: 2. Adresse @@ -1292,6 +1299,8 @@ fr_BE: cart_updating: "Mettre à jour le panier" cart_empty: "Panier vide" cart_edit: "Modifier votre panier" + item: "Produit" + qty: "Qté" card_number: Numéro de carte card_securitycode: "Cryptogramme visuel" card_expiry_date: Date d'expiration @@ -1939,6 +1948,7 @@ fr_BE: supplier: "Fournisseurs" product_name: "Nom du Produit" product_description: "Description du Produit" + shipping_categories: "Condition de transport" units: "Unité de mesure" coordinator: "Coordinateur" distributor: "Distributeur" @@ -2035,6 +2045,7 @@ fr_BE: remove_tax: "Retirer TVA" first_name_begins_with: "Début du prénom" last_name_begins_with: "Début du nom de famille" + new_order: "Nouvelle commande" enterprise_tos_link: "Lien vers les Conditions Générales d'Utilisation" enterprise_tos_message: "Nous soutenons la mise en place d'un système alimentaire résilient et durable, et souhaitons œuvrer avec des acteurs et actrices qui partagent nos valeurs et notre vision. Ainsi, nous demandons aux acteurs s'enregistrant sur Open Food Network de valider nos " enterprise_tos_link_text: "Conditions d'utilisation" @@ -3227,6 +3238,28 @@ fr_BE: invoice_email: hi: "Bonjour %{name}" invoice_attached_text: 'Veuillez trouver ci-joint la facture pour votre récente commande auprès de ' + user_mailer: + reset_password_instructions: + request_sent_text: | + Votre demande de nouveau mot de passe a bien été prise en compte. + Si vous n'avez pas demandé de nouveau mot de passe, veuillez ignorer cet e-mail. + link_text: > + Si vous êtes bien à l'origine de cette demande, veuillez cliquer sur le + lien ci-dessous : + issue_text: | + Si le lien ne fonctionne pas, essayez de le copier - coller dans la barre d'adresse de votre navigateur. + Si le problème persiste, n'hésitez pas à nous contacter. + confirmation_instructions: + subject: "Veuillez confirmer votre compte" + shipment_mailer: + shipped_email: + dear_customer: "Cher Client," + instructions: "Votre commande a été expédiée" + shipment_summary: "Résumé de l'envoi" + subject: "Notification d'expédition" + thanks: "Merci pour votre commande." + track_information: "Informations de suivi : %{tracking}" + track_link: "Lien de suivi : %{url}" order_state: address: adresse adjustments: ajustements @@ -3248,19 +3281,6 @@ fr_BE: ended: terminé paused: mis en pause canceled: annulé - user_mailer: - reset_password_instructions: - request_sent_text: | - Votre demande de nouveau mot de passe a bien été prise en compte. - Si vous n'avez pas demandé de nouveau mot de passe, veuillez ignorer cet e-mail. - link_text: > - Si vous êtes bien à l'origine de cette demande, veuillez cliquer sur le - lien ci-dessous : - issue_text: | - Si le lien ne fonctionne pas, essayez de le copier - coller dans la barre d'adresse de votre navigateur. - Si le problème persiste, n'hésitez pas à nous contacter. - confirmation_instructions: - subject: Veuillez confirmer votre compte users: form: account_settings: Paramètres du Compte diff --git a/config/locales/fr_CA.yml b/config/locales/fr_CA.yml index 2e57fa8dd7..9fd489c31a 100644 --- a/config/locales/fr_CA.yml +++ b/config/locales/fr_CA.yml @@ -13,6 +13,7 @@ fr_CA: email: Email acheteur spree/payment: amount: Montant + state: Département spree/product: primary_taxon: "Catégorie Produit" supplier: "Fournisseur" @@ -183,6 +184,7 @@ fr_CA: explainer: Le traitement automatique de ces commandes a échoué pour une raison inconnue. Cela n'aurait pas dû arriver, veuillez nous contacter si vous lisez ce message. home: "OFN" title: "Open Food Network " + welcome_to: "Bienvenue sur" site_meta_description: "Tout commence dans le sol. Avec ces paysans, agriculteurs, producteurs, engagés pour une agriculture durable et régénératrice, et désireux de partager leur histoire et leur passion avec fierté. Avec ces distributeurs souhaitant reconnecter les individus à leurs aliments et aux gens qui les produisent, soutenir les prises de conscience, dans une démarche de transparence, d'honnêteté, en assurant une juste rémunération des producteurs. Avec ces acheteurs qui croient que de meilleures décisions d'achats peuvent ..." search_by_name: Recherche par nom ou ville... producers_join: Les producteurs et autres hubs basés au Québec sont invités à rejoindre Open Food Network Canada. @@ -480,6 +482,7 @@ fr_CA: line_number: "Ligne :%{number}" encoding_error: "Veuillez vérifier le paramètre de langue de votre code source et vous assurer qu'il est encodé en UTF-8" unexpected_error: "L'import de fichier produits à rencontré une erreur inconnue à l'ouverture du fichier : %{error_message}" + malformed_csv: "L'outil d'import a rencontré un fichier CSV avec le ou les problèmes suivants :%{error_message}" index: notice: "Notice" beta_notice: "Cette fonctionnalité est en mode bêta : il est possible que vous rencontriez des erreurs en l'utilisant. N'hésitez pas à contacter le support utilisateurs." @@ -1035,10 +1038,13 @@ fr_CA: name: "Résumé des marges et commissions" description: "Résumé des marges et commissions collectées" subscriptions: - subscriptions: Abonnements - new: Nouvel abonnement - create: Créer abonnement - edit: Mettre à jour Abonnement + index: + title: "Abonnements" + new: "Nouvel abonnement" + new: + title: "Nouvel abonnement" + edit: + title: "Mettre à jour Abonnement" table: edit_subscription: Mettre à jour Abonnement pause_subscription: Mettre en pause Abonnement @@ -1047,6 +1053,7 @@ fr_CA: filters: query_placeholder: "Recherche par email" setup_explanation: + title: "Abonnements" just_a_few_more_steps: 'Encore quelques étapes avant de pouvoir commencer:' enable_subscriptions: "Activez la fonction abonnements pour au moins une de vos boutiques" enable_subscriptions_step_1_html: 1. Allez à %{enterprises_link}, trouvez votre boutique, et cliquez sur "Gérer" @@ -1060,6 +1067,8 @@ fr_CA: create_at_least_one_schedule_step_3: 3. Cliquez sur "+ Nouveau Rythme d'abonnement", et remplissez le formulaire once_you_are_done_you_can_html: Une fois que c'est fait, vous pouvez %{reload_this_page_link} reload_this_page: recharger cette page + form: + create: "Créer abonnement" steps: details: 1. Informations de base address: 2. Adresse @@ -1150,7 +1159,12 @@ fr_CA: cart: "Panier" cart_sidebar: checkout: "Finalisation commande" + edit_cart: "Modifier le panier" + items_in_cart_singular: "%{num}élément dans le panier" + items_in_cart_plural: "%{num}éléments dans le panier" close: "Ferme" + cart_empty: "Le panier est vide" + take_me_shopping: "Continuer mes achats" signed_in: profile: "Profil" mobile_menu: @@ -1298,6 +1312,8 @@ fr_CA: cart_updating: "Mettre à jour le panier" cart_empty: "Panier vide" cart_edit: "Modifier votre panier" + item: "Produit" + qty: "Qté" card_number: Numéro de carte card_securitycode: "Cryptogramme visuel" card_expiry_date: Date d'expiration @@ -1709,6 +1725,7 @@ fr_CA: remember_me: Se souvenir de moi are_you_sure: "Confirmer?" orders_open: "Boutique ouverte" + closing: "Fermeture" going_back_to_home_page: "Retour à la page d'accueil" creating: Création updating: Mettre à jour @@ -1952,6 +1969,7 @@ fr_CA: supplier: "Fournisseurs" product_name: "Nom du Produit" product_description: "Description du Produit" + shipping_categories: "Condition de transport" units: "Unité de mesure" coordinator: "Coordinateur" distributor: "Distributeur" @@ -2048,6 +2066,7 @@ fr_CA: remove_tax: "Retirer taxe" first_name_begins_with: "Prénom commence par" last_name_begins_with: "Nom de famille commence par" + new_order: "Nouvelle commande" enterprise_tos_link: "Lien vers les Conditions Générales d'Utilisation" enterprise_tos_message: "Nous soutenons la mise en place d'un système alimentaire résilient et durable, et souhaitons œuvrer avec des entreprises qui partagent nos valeurs et notre vision. Ainsi, nous demandons aux entreprises s'enregistrant sur Open Food Network de valider nos " enterprise_tos_link_text: "Conditions d'utilisation" @@ -2066,6 +2085,7 @@ fr_CA: hub_sidebar_at_least: "Sélectionnez un/des hubs" hub_sidebar_blue: "bleu" hub_sidebar_red: "rouge" + order_cycles_closed_for_hub: "La boutique sélectionnée a fermé temporairement ses commandes. Veuillez essayez à nouveau ultérieurement." report_customers_distributor: "Distributeur" report_customers_supplier: "Fournisseurs" report_customers_cycle: "Cycle de vente" @@ -2304,6 +2324,7 @@ fr_CA: order_cycles_email_to_producers_notice: 'Les emails à destination des producteurs ont été mis en file d''attente pour envoi.' order_cycles_no_permission_to_coordinate_error: "Aucune de vos entreprises n'a les droits requis pour coordonner un cycle de vente" order_cycles_no_permission_to_create_error: "Vous n'avez pas les droits requis pour créer un cycle de vente coordonné par cette entreprise" + order_cycle_closed: "Le cycle de vente que vous avez sélectionné a fermé. " back_to_orders_list: "Retour à la liste des commandes" no_orders_found: "Aucune commande trouvée" order_information: "Info commande" @@ -3346,6 +3367,28 @@ fr_CA: invoice_email: hi: "Bonjour %{name}" invoice_attached_text: 'Veuillez trouver ci-joint la facture pour votre récente commande auprès de ' + user_mailer: + reset_password_instructions: + request_sent_text: | + Votre demande de nouveau mot de passe a bien été prise en compte. + Si vous n'avez pas demandé de nouveau mot de passe, veuillez ignorer cet e-mail. + link_text: > + Si vous êtes bien à l'origine de cette demande, veuillez cliquer sur le + lien ci-dessous : + issue_text: | + Si le lien ne fonctionne pas, essayez de le copier - coller dans la barre d'adresse de votre navigateur. + Si le problème persiste, n'hésitez pas à nous contacter. + confirmation_instructions: + subject: "Veuillez confirmer votre compte" + shipment_mailer: + shipped_email: + dear_customer: "Cher Acheteur," + instructions: "Votre commande a été expédiée" + shipment_summary: "Résumé de l'envoi" + subject: "Notification d'expédition" + thanks: "Merci pour votre commande." + track_information: "Informations de suivi :%{tracking}" + track_link: "Lien de suivi :%{url}" order_state: address: adresse adjustments: ajustements @@ -3367,19 +3410,6 @@ fr_CA: ended: terminé paused: mis en pause canceled: annulé - user_mailer: - reset_password_instructions: - request_sent_text: | - Votre demande de nouveau mot de passe a bien été prise en compte. - Si vous n'avez pas demandé de nouveau mot de passe, veuillez ignorer cet e-mail. - link_text: > - Si vous êtes bien à l'origine de cette demande, veuillez cliquer sur le - lien ci-dessous : - issue_text: | - Si le lien ne fonctionne pas, essayez de le copier - coller dans la barre d'adresse de votre navigateur. - Si le problème persiste, n'hésitez pas à nous contacter. - confirmation_instructions: - subject: Veuillez confirmer votre compte users: form: account_settings: Paramètres du Compte diff --git a/config/locales/it.yml b/config/locales/it.yml index ebbf8932d0..6b1c036ebe 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -13,6 +13,8 @@ it: email: E-Mail Cliente spree/payment: amount: Quantità + state: Stato + source: Fonte spree/product: primary_taxon: "Categoria Prodotto" supplier: "Fornitore" @@ -182,6 +184,7 @@ it: explainer: L'elaborazione automatica di queste gentili richieste non è riuscita per una ragione sconosciuta. Questo non dovrebbe accadere, ti preghiamo di contattarci se visualizzi questo messaggio. home: "OFN" title: "Open Food Network" + welcome_to: "Benvenuto su" site_meta_description: "Cominciamo da zero. Con i produttori e gli allevatori pronti a raccontare le loro storie, sinceramente e orgogliosamente. Con i distributori pronti a connettere le persone con i prodotti in modo giusto ed equo. Con i compratori che credono che migliori decisioni per l'acquisto settimanale possano..." search_by_name: Cerca per nome o zona... producers_join: I Produttori sono ora invitati ad unirsi ad Open Food Network @@ -1034,10 +1037,13 @@ it: name: "Riepilogo commissioni dell'azienda" description: "Riepilogo delle commissioni dell'azienda" subscriptions: - subscriptions: Abbonamenti - new: Nuovo Abbonamento - create: Crea Abbonamento - edit: Modifica Abbonamento + index: + title: "Abbonamenti" + new: "Nuovo Abbonamento" + new: + title: "Nuovo Abbonamento" + edit: + title: "Modifica Abbonamento" table: edit_subscription: Modifica Abbonamento pause_subscription: Metti in pausa l'abbonamento @@ -1046,6 +1052,7 @@ it: filters: query_placeholder: "Cerca per email..." setup_explanation: + title: "Abbonamenti" just_a_few_more_steps: 'Ancora pochi passi prima di cominciare:' enable_subscriptions: "Ativa abbonamento ad almeno uno dei tuoi negozi" enable_subscriptions_step_1_html: 1. Vai alla pagina %{enterprises_link}, trova il tuo negozio e clicca "Gestisci" @@ -1059,6 +1066,8 @@ it: create_at_least_one_schedule_step_3: '3. Clicca su"+ Nuovo programma" e compila il modulo ' once_you_are_done_you_can_html: Quando hai fatto, puoi %{reload_this_page_link} reload_this_page: Ricarica questa pagina + form: + create: "Crea Abbonamento" steps: details: 1. Dettagli base address: 2. Indirizzo @@ -1150,7 +1159,11 @@ it: cart: "Carrello" cart_sidebar: checkout: "Paga" + edit_cart: "Modifica il carrello" + items_in_cart_singular: "%{num} articolo nel tuo carrello" + items_in_cart_plural: "%{num} articoli nel tuo carrello" close: "Chiuso" + cart_empty: "Il tuo carrello è vuoto" signed_in: profile: "Profilo" mobile_menu: @@ -1298,6 +1311,8 @@ it: cart_updating: "Aggiornamento del carrello..." cart_empty: "Carrello vuoto" cart_edit: "Modifica il tuo carrello" + item: "Articolo" + qty: "Qtà" card_number: Numero della carta card_securitycode: "Codice di sicurezza" card_expiry_date: Data di scadenza @@ -1709,6 +1724,7 @@ it: remember_me: Ricordami are_you_sure: "Sei sicuro?" orders_open: "Richieste aperte" + closing: "In chiusura" going_back_to_home_page: "Reindirizzamento alla homepage" creating: In creazione updating: In aggiornamento @@ -1952,6 +1968,7 @@ it: supplier: "Fornitore" product_name: "Nome Prodotto" product_description: "Descrizione prodotto" + shipping_categories: "Categorie Spedizioni" units: "Unità di misura" coordinator: "Coordinatore" distributor: "Distributore" @@ -2048,6 +2065,7 @@ it: remove_tax: "Rimuovi tassa" first_name_begins_with: "Il nome inizia con" last_name_begins_with: "Il cognome inizia con" + new_order: "Nuovo ordine" enterprise_tos_link: "link Termini di Servizio Aziende" enterprise_tos_message: "Abbiamo bisogno di lavorare con persone che condividono i nostri scopi e i nostri valori. Per questo chiediamo alle nuove aziende di sottoscrivere i nostri" enterprise_tos_link_text: "Termini di Servizio" @@ -2066,6 +2084,7 @@ it: hub_sidebar_at_least: "Almeno un hub deve essere selezionato" hub_sidebar_blue: "blu" hub_sidebar_red: "rosso" + order_cycles_closed_for_hub: "L'hub che hai selezionato è temporaneamente chiuso. Riprova più tardi." report_customers_distributor: "Distributore" report_customers_supplier: "Fornitore" report_customers_cycle: "Ciclo di richieste" @@ -2302,6 +2321,7 @@ it: order_cycles_email_to_producers_notice: 'Le email da inviare ai produttori sono state messe in coda per l''invio.' order_cycles_no_permission_to_coordinate_error: "Nessuna delle tue aziende ha il permesso di coordinare un ciclo di richieste" order_cycles_no_permission_to_create_error: "Non hai il permesso di creare un ciclo di richieste coordinato da questa azienda" + order_cycle_closed: "Il ciclo di richieste che hai selezionato è appena chiuso. Riprova per favore!" back_to_orders_list: "Indietro alla lista delle gentili richieste" no_orders_found: "Nessuna gentile richiesta trovata" order_information: "Informazioni Gentile Richiesta" @@ -3338,6 +3358,27 @@ it: invoice_email: hi: "Ciao %{name}" invoice_attached_text: 'Aggiunge una fattura per il tuo recente ordine di ' + user_mailer: + reset_password_instructions: + request_sent_text: | + E' stata fatta una richiesta per resettare la tua password + Se non hai fatto questa richiesta, ignora semplicemente questa email. + link_text: > + Se hai fatto questa richiesta, clicca il link seguente: + issue_text: | + Se l'URL qui sopra non funziona, prova a copiarlo e incollarlo nel tuo browser. + Se continui ad avere problemi, contattaci. + confirmation_instructions: + subject: "Per favore conferma il tuo account OFN" + shipment_mailer: + shipped_email: + dear_customer: "Caro Cliente," + instructions: "Il tuo ordine è stato spedito" + shipment_summary: "Riepilogo della Spedizione" + subject: "Notifica di Spedizione" + thanks: "Grazie per il tuo lavoro." + track_information: "Informazioni Tracking: %{tracking}" + track_link: "Tracking Link: %{url}" order_state: address: indirizzo adjustments: aggiustamenti @@ -3359,18 +3400,6 @@ it: ended: finito paused: in pausa canceled: annullato - user_mailer: - reset_password_instructions: - request_sent_text: | - E' stata fatta una richiesta per resettare la tua password - Se non hai fatto questa richiesta, ignora semplicemente questa email. - link_text: > - Se hai fatto questa richiesta, clicca il link seguente: - issue_text: | - Se l'URL qui sopra non funziona, prova a copiarlo e incollarlo nel tuo browser. - Se continui ad avere problemi, contattaci. - confirmation_instructions: - subject: Per favore conferma il tuo account OFN users: form: account_settings: Impostazioni account diff --git a/config/locales/nb.yml b/config/locales/nb.yml index c47ad93636..6abf1fb797 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -13,6 +13,8 @@ nb: email: Epost Kunde spree/payment: amount: Beløp + state: Tilstand + source: Kilde spree/product: primary_taxon: "Produktkategori" supplier: "Leverandør" @@ -182,6 +184,7 @@ nb: explainer: Automatisk behandling av disse bestillingene mislyktes av en ukjent grunn. Dette bør ikke skje, vennligst kontakt oss hvis du ser dette. home: "OFN" title: "Open Food Network" + welcome_to: "Velkommen til" site_meta_description: "Vi begynner fra grunnen. Med bønder og dyrkere klare til å fortelle sine historier, stolt og virkelig. Med distributører klare til å koble mennesker med produkter på en rettferdig og ærlig måte. Med kunder som tror på at ukentlige innkjøpsrutiner kan..." search_by_name: Søk på navn eller sted... producers_join: Norske produsenter er nå velkommen til å bli med i Open Food Network. @@ -270,6 +273,9 @@ nb: on hand: "Tilgjengelig" ship: "Levere" shipping_category: "Leveringskategori" + height: "Høyde" + width: "Bredde" + depth: "Dybde" actions: create_and_add_another: "Opprett og legg til en annen" create: "Opprett" @@ -1033,10 +1039,13 @@ nb: name: "Sammendrag Bedriftsavgift" description: "Sammendrag av bedriftsavgifter innsamlet" subscriptions: - subscriptions: Abonnement - new: Nytt abonnement - create: Opprett abonnement - edit: Rediger abonnement + index: + title: "Abonnement" + new: "Nytt abonnement" + new: + title: "Nytt abonnement" + edit: + title: "Rediger abonnement" table: edit_subscription: Rediger abonnement pause_subscription: Pause abonnement @@ -1045,6 +1054,7 @@ nb: filters: query_placeholder: "Søk på epost..." setup_explanation: + title: "Abonnement" just_a_few_more_steps: 'Bare noen få skritt før du kan begynne:' enable_subscriptions: "Aktiver abonnementer for minst en av butikkene dine" enable_subscriptions_step_1_html: 1. Gå til siden %{enterprises_link}, finn butikken din, og klikk på "Endre profil" @@ -1058,6 +1068,8 @@ nb: create_at_least_one_schedule_step_3: 3. Klikk på '+ Ny tidsplan', og fyll ut skjemaet once_you_are_done_you_can_html: Når du er ferdig, kan du %{reload_this_page_link} reload_this_page: oppdater denne siden + form: + create: "Opprett abonnement" steps: details: 1. Grunnleggende detaljer address: 2. Adresse @@ -1302,6 +1314,8 @@ nb: cart_updating: "Oppdaterer handlekurv..." cart_empty: "Handlekurven er tom" cart_edit: "Rediger handlekurv" + item: "Vare" + qty: "Antall" card_number: Kortnummer card_securitycode: "Sikkerhetskode" card_expiry_date: Utløpsdato @@ -1713,6 +1727,7 @@ nb: remember_me: Husk meg are_you_sure: "Er du sikker?" orders_open: "Åpen for bestilling" + closing: "Stenger" going_back_to_home_page: "Tar deg tilbake til hjemmesiden" creating: Oppretter updating: Oppdaterer @@ -1956,6 +1971,8 @@ nb: supplier: "Leverandør" product_name: "Produktnavn" product_description: "Produktbeskrivelse" + permalink: "Permalink" + shipping_categories: "Fraktkategorier" units: "Enhetsstørrelse" coordinator: "Koordinator" distributor: "Distributør" @@ -2052,6 +2069,8 @@ nb: remove_tax: "Fjern avgift" first_name_begins_with: "Fornavn begynner med" last_name_begins_with: "Etternavn begynner med" + shipping_method: "Leveringsmetode" + new_order: "Ny bestilling" enterprise_tos_link: "Lenke til Tjenestevilkår for Bedrifter" enterprise_tos_message: "Vi ønsker å jobbe med bedrifter som deler våre mål og verdier. Derfor ber vi nye bedrifter om å godta vår" enterprise_tos_link_text: "Tjenestevilkår." @@ -2070,6 +2089,7 @@ nb: hub_sidebar_at_least: "Minst én hub må være valgt" hub_sidebar_blue: "blå" hub_sidebar_red: "rød" + order_cycles_closed_for_hub: "Huben du har valgt er midlertidig lukket for bestillinger. Vennligst prøv igjen senere." report_customers_distributor: "Distributør" report_customers_supplier: "Leverandør" report_customers_cycle: "Bestillingsrunde" @@ -2306,6 +2326,7 @@ nb: order_cycles_email_to_producers_notice: 'E-poster som skal sendes til produsentene har blitt satt i kø for sending.' order_cycles_no_permission_to_coordinate_error: "Ingen av bedriftene dine har tillatelse til å koordinere en bestillingsrunde" order_cycles_no_permission_to_create_error: "Du har ikke rettigheter til å opprette en bestillingsrunde som er koordinert av den bedriften" + order_cycle_closed: "Bestillingsrunden du har valgt har akkurat stengt. Vennligst prøv igjen!" back_to_orders_list: "Tilbake til bestillingslisten" no_orders_found: "Ingen bestillinger funnet" order_information: "Bestillingsinformasjon" @@ -3161,6 +3182,8 @@ nb: stripe: error_saving_payment: Feil ved lagring av betaling submitting_payment: Sender inn betaling... + paypal: + no_payment_via_admin_backend: Paypal-betalinger kan ikke behandles i Backoffice products: image_upload_error: "Produktbildet ble ikke gjenkjent. Last opp et bilde i PNG- eller JPG-format." new: @@ -3338,6 +3361,32 @@ nb: invoice_email: hi: "Hei %{name}" invoice_attached_text: Vennligst finn vedlagt en faktura for din nylige bestilling fra + user_mailer: + reset_password_instructions: + request_sent_text: | + En forespørsel om å nullstille ditt passord er utført. + Hvis det ikke var du som forespurte dette kan du se bort i fra denne eposten. + link_text: > + Hvis det var du som forespurte dette kan du klikke nedenfor: + issue_text: | + Hvis URL'en ovenfor ikke fungerer prøv å kopier og lim den inn i din nettleser. + Hvis du fortsatt har problemer vennligst ta kontakt. + confirmation_instructions: + subject: "Vennligst bekreft OFN-kontoen din" + shipment_mailer: + shipped_email: + dear_customer: "Kjære Kunde," + instructions: "Din bestilling har blitt sendt" + shipment_summary: "Leveringssammendrag" + subject: "Leveringsvarsling" + thanks: "Takk for handelen." + track_information: "Sporingsinformasjon: %{tracking}" + track_link: "Sporingslink: %{url}" + test_mailer: + test_email: + greeting: "Gratulerer!" + message: "Hvis du har mottatt denne eposten, er epostinnstillingene dine riktige." + subject: "Test Epost" order_state: address: adresse adjustments: justeringer @@ -3359,18 +3408,6 @@ nb: ended: avsluttet paused: pauset canceled: avbrutt - user_mailer: - reset_password_instructions: - request_sent_text: | - En forespørsel om å nullstille ditt passord er utført. - Hvis det ikke var du som forespurte dette kan du se bort i fra denne eposten. - link_text: > - Hvis det var du som forespurte dette kan du klikke nedenfor: - issue_text: | - Hvis URL'en ovenfor ikke fungerer prøv å kopier og lim den inn i din nettleser. - Hvis du fortsatt har problemer vennligst ta kontakt. - confirmation_instructions: - subject: Vennligst bekreft OFN-kontoen din users: form: account_settings: Kontoinnstillinger diff --git a/config/locales/nl_BE.yml b/config/locales/nl_BE.yml index 61e9b4a7d9..52ee2cf0eb 100644 --- a/config/locales/nl_BE.yml +++ b/config/locales/nl_BE.yml @@ -13,6 +13,7 @@ nl_BE: email: Klanten e-mail spree/payment: amount: Bedrag + state: Staat spree/product: primary_taxon: "Product categorie" supplier: "Leverancier" @@ -993,10 +994,13 @@ nl_BE: name: "Samenvatting van de honoraria voor ondernemingen" description: "Overzicht van de geïnde ondernemingsvergoedingen" subscriptions: - subscriptions: Abonnementen - new: Nieuw abonnement - create: Abonnement aanmaken - edit: Abonnement bewerken + index: + title: "Abonnementen" + new: "Nieuw abonnement" + new: + title: "Nieuw abonnement" + edit: + title: "Abonnement bewerken" table: edit_subscription: Abonnement bewerken pause_subscription: Pauze Abonnement @@ -1005,6 +1009,7 @@ nl_BE: filters: query_placeholder: "Zoeken per e-mail ..." setup_explanation: + title: "Abonnementen" just_a_few_more_steps: 'Nog een paar stappen voordat u kunt beginnen:' enable_subscriptions: "Inschrijven voor minstens één van uw winkels mogelijk maken" enable_subscriptions_step_1_html: 1. Ga naar de %{enterprises_link}pagina, vind uw winkel en klik op "Beheren". @@ -1018,6 +1023,8 @@ nl_BE: create_at_least_one_schedule_step_3: 3. Klik '+ Nieuwe Planning', en vul een formulier in once_you_are_done_you_can_html: Eens je klaar bent, kan je %{reload_this_page_link} reload_this_page: herlaad deze pagina + form: + create: "Abonnement aanmaken" steps: details: 1. Basis Specificaties address: 2. Adres @@ -1248,6 +1255,8 @@ nl_BE: cart_updating: "winkelwagentje wordt geüpdatet..." cart_empty: "Winkelwagentje is leeg" cart_edit: "Pas je winkelwagentje aan" + item: "Artikel" + qty: "Aantal" card_number: Kaartnummer card_securitycode: "Veiligheidscode" card_expiry_date: Vervaldatum @@ -1890,6 +1899,7 @@ nl_BE: supplier: "Leverancier" product_name: "Naam produkt" product_description: "Beschrijving product" + shipping_categories: "Verzendingscategorieën" units: "Stukgrootte" coordinator: "Coördinator" distributor: "Distributeur" @@ -1985,6 +1995,7 @@ nl_BE: remove_tax: "Verwijder belasting" first_name_begins_with: "Voornaam begint met" last_name_begins_with: "Familienaam begint met " + new_order: "Nieuwe bestelling" enterprise_tos_link: "Link Voorwaarden Onderneming" enterprise_tos_message: "We willen met mensen werken die onze normen en waarden en delen. Daarom vragen wij aan de nieuwe bedrijven akkoord te gaan met onze " enterprise_tos_link_text: "Dienstvoorwaarden" @@ -3102,6 +3113,28 @@ nl_BE: invoice_email: hi: "Hallo %{name}" invoice_attached_text: 'Gelieve hier de factuur te vinden in veband met de laatste bestelling geplaatst bij ' + user_mailer: + reset_password_instructions: + request_sent_text: | + Uw aanvraag voor een nieuww paswoord is in acht genomen + Indien je geen nieuw paswoord aangevraagd heeft, gelieve hiermee geen rekening te houden. + link_text: > + Indien U wel de aanvraag gedaan hebt, gelieve op de link hieronder te + klikken : + issue_text: | + Indien de link niet functioneert, gelieve die te copiëren-plakken in het adresstrook van uw navigator. + Moest het probleem blijven duren, aarzel niet ons te contacteren + confirmation_instructions: + subject: "Gelieve uw OFN rekening te bevestigen" + shipment_mailer: + shipped_email: + dear_customer: "Geachte klant," + instructions: "Uw bestelling is verzonden" + shipment_summary: "Samenvatting van de zending" + subject: "Kennisgeving van verzending" + thanks: "Bedankt voor uw bedrijf." + track_information: "Tracking informatie: %{tracking}" + track_link: "Tracking Link:%{url} " order_state: address: adres adjustments: aanpassingen @@ -3123,19 +3156,6 @@ nl_BE: ended: ten einde gebracht paused: 'in pause ' canceled: geschrapt - user_mailer: - reset_password_instructions: - request_sent_text: | - Uw aanvraag voor een nieuww paswoord is in acht genomen - Indien je geen nieuw paswoord aangevraagd heeft, gelieve hiermee geen rekening te houden. - link_text: > - Indien U wel de aanvraag gedaan hebt, gelieve op de link hieronder te - klikken : - issue_text: | - Indien de link niet functioneert, gelieve die te copiëren-plakken in het adresstrook van uw navigator. - Moest het probleem blijven duren, aarzel niet ons te contacteren - confirmation_instructions: - subject: Gelieve uw OFN rekening te bevestigen users: form: account_settings: Rekeningsinstellingen diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 0e9da2fb53..bd70c0746e 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -13,6 +13,7 @@ pt: email: Email do/a Consumidor/a spree/payment: amount: Quantia + state: Estado spree/product: primary_taxon: "Categoria de Produto" supplier: "Fornecedor" @@ -978,16 +979,20 @@ pt: name: "Sumário das Taxas de Organização" description: "Sumário das Taxas de Organização cobradas" subscriptions: - subscriptions: Subscrições - new: Nova Subscrição - create: Criar Subscrição - edit: Editar Subscrição + index: + title: "Subscrições" + new: "Nova Subscrição" + new: + title: "Nova Subscrição" + edit: + title: "Editar Subscrição" table: edit_subscription: Editar Subscrição pause_subscription: Pausar Subscrição unpause_subscription: Parar pausa da Subscrição cancel_subscription: Cancelar Subscrição setup_explanation: + title: "Subscrições" just_a_few_more_steps: 'Só mais uns passos antes de poder começar:' enable_subscriptions: "Activar subscrições para pelo menos uma das suas lojas" enable_subscriptions_step_1_html: 1. Vá à página %{enterprises_link}, encontre a sua loja, e clique em "Gerir" @@ -1001,6 +1006,8 @@ pt: create_at_least_one_schedule_step_3: 3. Clique em '+ Novo Horário', e preencha o formulário once_you_are_done_you_can_html: Assim que estiver feito, pode %{reload_this_page_link} reload_this_page: carregar de novo esta página + form: + create: "Criar Subscrição" steps: details: 1. Detalhes Básicos address: 2. Morada @@ -1222,6 +1229,8 @@ pt: cart_updating: "Atualizando carrinho" cart_empty: "Carrinho vazio" cart_edit: "Edite o seu carrinho" + item: "Item" + qty: "Qtd" card_number: Número do Cartão card_securitycode: "Código de Segurança" card_expiry_date: Data de Vencimento @@ -1863,6 +1872,7 @@ pt: supplier: "Fornecedor" product_name: "Nome do Produto" product_description: "Descrição do Produto" + shipping_categories: "Categorias de Envio" units: "Tamanho unitário" coordinator: "Coordenador" distributor: "Distribuidor" @@ -1957,6 +1967,7 @@ pt: remove_tax: "Remover imposto" first_name_begins_with: "Primeiro nome começa com" last_name_begins_with: "Último nome começa com" + new_order: "Nova Encomenda" enterprise_tos_link: "Ligação para Termos de Serviço da Organização" enterprise_tos_message: "Queremos trabalhar com pessoas que partilham os nossos objectivos e valores. Por isso pedimos às organizações novas que concordem com os nossos" enterprise_tos_link_text: "Termos de Serviço." @@ -3038,6 +3049,26 @@ pt: invoice_email: hi: "Olá %{name}" invoice_attached_text: Pode encontrar em anexo um recibo da encomenda que fez recentemente a + user_mailer: + reset_password_instructions: + request_sent_text: | + Recebemos um pedido para redefinir a sua palavra-passe. + Se não fez este pedido, simplesmente ignore esta mensagem. + link_text: > + Se fez este pedido, clique no link abaixo: + issue_text: | + Se o endereço URL acima não funcionar, tente copiá-lo e colá-lo directamente no browser. Se continuar a ter problemas por favor entre em contacto connosco. + confirmation_instructions: + subject: "Por favor confirme a sua conta OFN" + shipment_mailer: + shipped_email: + dear_customer: "Caro Consumidor," + instructions: "A sua encomenda foi enviada" + shipment_summary: "Sumário de Envio" + subject: "Notificação de Envio" + thanks: "Obrigado." + track_information: "Informação de envio: %{tracking}" + track_link: "Link de envio: %{url}" order_state: address: morada adjustments: ajustes @@ -3059,17 +3090,6 @@ pt: ended: terminou paused: em pausa canceled: cancelado - user_mailer: - reset_password_instructions: - request_sent_text: | - Recebemos um pedido para redefinir a sua palavra-passe. - Se não fez este pedido, simplesmente ignore esta mensagem. - link_text: > - Se fez este pedido, clique no link abaixo: - issue_text: | - Se o endereço URL acima não funcionar, tente copiá-lo e colá-lo directamente no browser. Se continuar a ter problemas por favor entre em contacto connosco. - confirmation_instructions: - subject: Por favor confirme a sua conta OFN users: form: account_settings: Definições de Conta diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml index acdf438a4d..0fe3b4ab6c 100644 --- a/config/locales/pt_BR.yml +++ b/config/locales/pt_BR.yml @@ -13,6 +13,8 @@ pt_BR: email: Email do cliente spree/payment: amount: Montante + state: Estado + source: Origem spree/product: primary_taxon: "Categoria de Produto" supplier: "Fornecedor" @@ -271,6 +273,9 @@ pt_BR: on hand: "Disponível" ship: "Envio" shipping_category: "Tipos de Frete" + height: "Altura" + width: "Largura" + depth: "Profundidade" actions: create_and_add_another: "Criar e adicionar outro" create: "Criar" @@ -1012,7 +1017,7 @@ pt_BR: name: Relatórios de pagamento description: Relatórios para pagamentos orders_and_fulfillment: - name: Relatórios de pedidos e de satisfação + name: Relatórios de pedidos e fechamento customers: name: Clientes products_and_inventory: @@ -1033,10 +1038,13 @@ pt_BR: name: "Resumo das taxas da empresa" description: "Resumo das taxas corporativas coletadas" subscriptions: - subscriptions: Assinaturas - new: Nova assinatura - create: Criar assinatura - edit: Editar assinatura + index: + title: "Assinaturas" + new: "Nova Assinatura" + new: + title: "Nova Assinatura" + edit: + title: "Editar assinatura" table: edit_subscription: Editar assinatura pause_subscription: Pausar assinatura @@ -1045,6 +1053,7 @@ pt_BR: filters: query_placeholder: "Pesquisar por email ..." setup_explanation: + title: "Assinaturas" just_a_few_more_steps: 'Apenas mais algumas etapas antes de começar:' enable_subscriptions: "Ative assinaturas para pelo menos uma de suas lojas" enable_subscriptions_step_1_html: '1. Vá para a página %{enterprises_link}, encontre sua loja e clique em "Gerenciar" ' @@ -1058,6 +1067,8 @@ pt_BR: create_at_least_one_schedule_step_3: 3. Clique em "Novo cronograma" e preencha o formulário once_you_are_done_you_can_html: Quando terminar, você pode %{reload_this_page_link} reload_this_page: recarregar esta página + form: + create: "Criar Assinatura" steps: details: 1. Detalhes Básicos address: 2. Endereço @@ -1204,14 +1215,14 @@ pt_BR: invoice_column_price_without_taxes: "Preço total (sem taxas)" invoice_column_tax_rate: "Taxa de imposto" invoice_tax_total: "Total de Imposto sobre Bens e Serviços" - tax_invoice: "NOTA FISCAL" + tax_invoice: "FATURA" tax_total: "Total de imposto (%{rate}):" total_excl_tax: "Total (sem imposto):" total_incl_tax: "Total (com imposto):" abn: "CNPJ" acn: "CNPJ:" - invoice_issued_on: "Nota fiscal emitida em:" - order_number: "Número da nota fiscal:" + invoice_issued_on: "Fatura emitida em:" + order_number: "Número da fatura:" date_of_transaction: "Dia da transação:" ticket_column_qty: "Qtd" ticket_column_item: "Ítem" @@ -1301,6 +1312,8 @@ pt_BR: cart_updating: "Atualizando carrinho" cart_empty: "Carrinho vazio" cart_edit: "Edite seu carrinho" + item: "Ítem" + qty: "Qtd" card_number: Número do Cartão card_securitycode: "Código de Segurança" card_expiry_date: Data de Vencimento @@ -1522,7 +1535,7 @@ pt_BR: shopping_contact_social: "Seguir" shopping_groups_part_of: "é parte de:" shopping_producers_of_hub: "produtores de %{hub}:" - enterprises_next_closing: "Próximo fechamento de pedido" + enterprises_next_closing: "Próximo fechamento" enterprises_ready_for: "Pronto para" enterprises_choose: "Escolha para quando você quer seu pedido:" maps_open: "Aberto" @@ -1956,6 +1969,8 @@ pt_BR: supplier: "Fornecedor" product_name: "Nome do Produto" product_description: "Descrição do Produto" + permalink: "Permalink" + shipping_categories: "Categorias de Remessa" units: "Unidade de medida" coordinator: "Coordenador" distributor: "Distribuidor" @@ -2052,6 +2067,8 @@ pt_BR: remove_tax: "Remover taxa" first_name_begins_with: "O primeiro nome começa com" last_name_begins_with: "O sobrenome começa com" + shipping_method: "Método de Envio" + new_order: "Novo Pedido" enterprise_tos_link: "Link de Termos de Serviço da iniciativa" enterprise_tos_message: "Queremos trabalhar com pessoas que compartilham nossos objetivos e valores. Como tal, pedimos às novas iniciativas que concordem com nossos" enterprise_tos_link_text: "Termos de Serviço." @@ -3059,7 +3076,7 @@ pt_BR: email: "Email do cliente" invoice: issued_on: "Emitida em" - tax_invoice: "NOTA FISCAL" + tax_invoice: "FATURA" code: "Código" from: "De" to: "Informações de cobrança" @@ -3346,6 +3363,32 @@ pt_BR: invoice_email: hi: "Oi %{name}" invoice_attached_text: Encontre anexa uma fatura para sua recente ordem de + user_mailer: + reset_password_instructions: + request_sent_text: | + Foi feito um pedido para redefinir sua senha. + Se você não fez essa solicitação, simplesmente ignore este e-mail. + link_text: > + Se você fez esse pedido, basta clicar no link abaixo: + issue_text: | + Se o URL acima não funcionar, tente copiar e colá-lo em seu navegador. + Se continuar a ter problemas, por favor não hesite em contactar-nos. + confirmation_instructions: + subject: "Confirme sua conta na OFB" + shipment_mailer: + shipped_email: + dear_customer: "Estimado cliente," + instructions: "Seu pedido foi enviado" + shipment_summary: "Resumo de Envio" + subject: "Notificação de envio" + thanks: "Agradeço pelos seus serviços." + track_information: "Informações de rastreamento: %{tracking}" + track_link: "Link de rastreamento: %{url}" + test_mailer: + test_email: + greeting: "Parabéns!" + message: "Se você recebeu este email, então as suas configurações de email estão corretas." + subject: "Email Teste" order_state: address: endereço adjustments: ajustes @@ -3367,18 +3410,6 @@ pt_BR: ended: finalizado paused: pausado canceled: cancelado - user_mailer: - reset_password_instructions: - request_sent_text: | - Foi feito um pedido para redefinir sua senha. - Se você não fez essa solicitação, simplesmente ignore este e-mail. - link_text: > - Se você fez esse pedido, basta clicar no link abaixo: - issue_text: | - Se o URL acima não funcionar, tente copiar e colá-lo em seu navegador. - Se continuar a ter problemas, por favor não hesite em contactar-nos. - confirmation_instructions: - subject: Confirme sua conta na OFB users: form: account_settings: Configurações da conta diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 92d5d360e6..96d65d324e 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -8,6 +8,8 @@ sv: payment_state: Betalningstatus shipment_state: Leveransstatus state: Region + spree/payment: + state: Region spree/product: supplier: "Leverantör" variant_unit: "Enhet för variant" @@ -751,6 +753,8 @@ sv: cart_updating: "Uppdatera din varukorg" cart_empty: "Tom varukorg" cart_edit: "Redigera din varukorg " + item: "Vara" + qty: "Kvantitet" card_number: Kortnummer card_securitycode: "Säkerhetskod" card_expiry_date: Förfallodatum @@ -2106,6 +2110,16 @@ sv: invoice_email: hi: "Hi %{name}" invoice_attached_text: Här är en faktura för din senaste order från + user_mailer: + reset_password_instructions: + request_sent_text: | + En begäran om att återställa ditt lösenord har gjorts. + Om du inte gjorde denna förfrågan ignorerar du bara det här e-postmeddelandet. + link_text: > + Om du gjorde denna förfrågan klickar du bara på länken nedan: + issue_text: | + Om den ovan nämnda webbadressen inte fungerar kan du försöka kopiera och klistra in den i webbläsaren. + Om du får problem, var god kontakta oss. order_state: address: adress adjustments: justeringar @@ -2118,16 +2132,6 @@ sv: resumed: återupptagen returned: returnerad skrill: skrill - user_mailer: - reset_password_instructions: - request_sent_text: | - En begäran om att återställa ditt lösenord har gjorts. - Om du inte gjorde denna förfrågan ignorerar du bara det här e-postmeddelandet. - link_text: > - Om du gjorde denna förfrågan klickar du bara på länken nedan: - issue_text: | - Om den ovan nämnda webbadressen inte fungerar kan du försöka kopiera och klistra in den i webbläsaren. - Om du får problem, var god kontakta oss. users: open_orders: order: Beställningar diff --git a/config/locales/tr.yml b/config/locales/tr.yml index dae3555bb1..e5aa022fee 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -13,6 +13,8 @@ tr: email: Müşteri E-postası spree/payment: amount: Tutar + state: Durum + source: Kaynak spree/product: primary_taxon: "ÜRÜN KATEGORİSİ" supplier: "TEDARİKÇİ" @@ -123,9 +125,9 @@ tr: subject: "Lütfen %{enterprise} için e-posta adresini doğrulayın" welcome: subject: "%{enterprise} şimdi %{sitename} 'de" - email_welcome: "Hoşgeldiniz" + email_welcome: "Aramıza Hoşgeldiniz " email_registered: "şimdi bir parçası" - email_userguide_html: "Tezgah veya Pazar hesapları ayarları ile ilgili ayrıntılı desteğe sahip Kullanıcı Kılavuzu burada: %{link}" + email_userguide_html: "Dükkan veya Pazar hesapları ayarları ile ilgili ayrıntılı desteğe sahip Kullanıcı Kılavuzu burada: %{link}" userguide: "Açık Gıda Ağı Kullanıcı Kılavuzu" email_admin_html: "%{link}'dan oturum açarak veya ana sayfanın sağ üst kısmındaki ayarlar simgesini tıkladıktan sonra Yönetim' butonu üzerinden hesabınızı yönetebilirsiniz." admin_panel: "YönetiİCİ Panelİ" @@ -221,7 +223,7 @@ tr: edit: Düzenle clone: Kopyala distributors: Dağıtımcılar - bulk_order_management: Toplu Sipariş Yönetimi + bulk_order_management: TOPLU SİPARİŞ YÖNETİMİ enterprises: İşletmeler enterprise_groups: AĞLAR reports: Raporlar @@ -256,7 +258,7 @@ tr: processing_payment: "Ödeme İşlemi Gerçekleştiriliyor.." no_pending_payments: "Bekleyen ödeme yok" invalid_payment_state: "Geçersiz ödeme durumu" - filter_results: Sonuçları Filtrele + filter_results: SONUÇLARI FİLTRELE quantity: Miktar pick_up: Teslim Alma copy: Kopyala @@ -271,6 +273,9 @@ tr: on hand: "Mevcut" ship: "Teslimat" shipping_category: "Teslimat KategOrİSİ" + height: "Boy" + width: "En" + depth: "Boy" actions: create_and_add_another: "Oluştur ve Yeni Ekle" create: "Oluştur" @@ -429,7 +434,7 @@ tr: enterprise_role: manages: yönetir products: - unit_name_placeholder: 'örn. demet' + unit_name_placeholder: 'Örn. demet' index: unit: Birim display_as: Gösterme Şekli @@ -593,7 +598,7 @@ tr: product_unit: "Ürün: Birim" weight_volume: "Ağırlık / Hacim" ask: "Sor?" - page_title: "Toplu Sipariş Yönetimi" + page_title: "TOPLU SİPARİŞ YÖNETİMİ" actions_delete: "Seçilenleri Sil" loading: "Siparişler yükleniyor" no_results: "Sipariş bulunamadı." @@ -632,12 +637,12 @@ tr: name: Ad name_placeholder: Örn. Toprak Güneş email_address: E-posta Adresi - email_address_placeholder: Örn. siparis@yesilciftlik.com + email_address_placeholder: Örn. siparis@ciftlik.com email_address_tip: "Bu e-posta adresi profilinizde görüntülenecek" phone: Telefon phone_placeholder: Örn. 0532 123 00 01 website: İnternet sitesi - website_placeholder: 'Örn: www.yesilciftlik.com' + website_placeholder: Örn. www.ciftlik.com enterprise_fees: name: Ad fee_type: Ücret Türü @@ -676,11 +681,11 @@ tr: primary_producer: Birincil üretici misiniz? primary_producer_tip: Siz de birincil üreticisiyseniz 'Üretici' yi seçin. producer: ÜRETİCİ - any: Hepsi - none: SATMIYOR + any: KENDİ VE/VEYA BAŞKASININ ÜRÜNLERİ + none: SATIŞ YAPMIYOR own: KENDİ ÜRÜNLERİ sells: NE SATIYOR - sells_tip: "Hiç - İşletme müşterilere doğrudan satış yapmaz.
Kendi - İşletme müşterilerine kendi ürünlerini satar.
Hepsi - İşletme kendi ürünlerini veya diğer işletmelerin ürünlerini satabilir.
" + sells_tip: "Satış Yapmıyor - İşletme müşterilere doğrudan satış yapmaz.
Kendi Ürünleri - İşletme müşterilerine kendi ürünlerini satar.
Kendi ve/veya başkasının ürünleri - İşletme kendi ürünlerini ve/veya diğer işletmelerin ürünlerini satabilir.
" visible_in_search: ARAMADA GÖRÜNÜR MÜ? visible_in_search_tip: Sitede arama yapılırken bu işletmenin müşteriler tarafından görünür olup olmayacağını belirler. visible: GÖRÜNÜR @@ -730,11 +735,11 @@ tr: sizi ziyaret edenler tarafından görülecek. (örn. neden kapalı olduğunu ve ne zaman açılacağını belirtebilirsiniz) shopfront_category_ordering: "DÜKKAN KATEGORİ SIRALAMASI" - open_date: "Açılış Tarihi" - close_date: "Kapanış Tarih" + open_date: "AÇILIŞ TARİHİ" + close_date: "KAPANIŞ TARİHİ" social: - twitter_placeholder: "Örneğin. @the_usta" - instagram_placeholder: "Örneğin. the_usta" + twitter_placeholder: "Örn. @the_usta" + instagram_placeholder: "Örn. ciftlik (başına @ işareti koymayınız)" facebook_placeholder: "Örn: www.facebook.com/TurkiyeKoop" linkedin_placeholder: "Örn: www.linkedin.com/in/adınızsoyadınız" stripe_connect: @@ -795,21 +800,21 @@ tr: producer: ÜRETİCİ change_type_form: producer_profile: ÜRETİCİ PROFİLİ - connect_ofn: AGA üzerinden bağlan + connect_ofn: AGA PLATFORMUNA KATIL always_free: HER ZAMAN ÜCRETSİZ producer_description_text: Ürünlerinizi Açık Gıda Ağı'na yükleyin. Böylece ürünleriniz pazar hesapları üzerinden satışa sunulabilir. producer_shop: ÜRETİCİ DÜKKANI - sell_your_produce: Kendi ürününü sat + sell_your_produce: KENDİ ÜRÜNÜNÜ SAT producer_shop_description_text: Açık Gıda Ağı üzerinden açtığınız bireysel dükkanınız ile ürünlerinizi doğrudan müşterilere ulaştırabilirsiniz. producer_shop_description_text2: Üretici Dükkanı sadece sizin ürünleriniz içindir. Üretiminiz haricindeki ürünleri satabilmek için lütfen 'Üretici Pazarı' seçeneğini seçin. producer_hub: ÜRETİCİ PAZARI - producer_hub_text: Kendi ürünleriniz ile beraber başkalarının ürünlerini de satın + producer_hub_text: KENDİ ÜRÜNLERİNİZ İLE BERABER BAŞKALARININ ÜRÜNLERİNİ DE SATIN producer_hub_description_text: İşletmeniz, yerel gıda sisteminizin bel kemiğidir. Açık Gıda Ağı'ndaki mağazanız aracılığıyla kendi ürünlerinizi ve çevrenizdeki diğer üreticilerin ürünlerini beraber satabilirsiniz. profile: Yalnızca Profil get_listing: Görünür ol profile_description_text: İnsanlar Açık Gıda Ağı üzerinden sizi bulabilir ve sizinle iletişim kurabilir. İşletmeniz haritada ve listelerde görünür olacak. hub_shop: Türetici Pazarı - hub_shop_text: Başkalarının ürünlerini satın + hub_shop_text: BAŞKALARININ ÜRÜNLERİNİ SATIN hub_shop_description_text: İşletmeniz yerel gıda sisteminizin belkemiğidir. Diğer işletmelerin ürünlerini bir araya getirebilir, Açık Gıda Ağı'na kayıtlı dükkanınız üzerinden alıcılara ulaştırabilirsiniz. choose_option: Lütfen yukarıdaki seçeneklerden birini seçin. change_now: Değiştir @@ -897,10 +902,10 @@ tr: outgoing: "3. GİDEN ÜRÜNLER" exchange_form: pickup_time_tip: Bu sipariş dönemine ait siparişlerin müşteriler için hazır olma tarihi - pickup_instructions_placeholder: "Teslimat Talimatları" + pickup_instructions_placeholder: "TESLİMAT DETAYLARI" pickup_instructions_tip: Bu talimatlar, siparişi tamamladıktan sonra müşterilere iletilir pickup_time_placeholder: "Teslimat (örn. Tarih / Saat)" - receival_instructions_placeholder: "Teslim Alma talimatları" + receival_instructions_placeholder: "TESLİM ALMA TALİMATLARI" add_fee: 'Ücret ekle' remove: 'Kaldır' selected: 'seçildi' @@ -1015,7 +1020,7 @@ tr: orders_and_fulfillment: name: Siparişler ve Gerçekleşme Raporları customers: - name: MÜŞTERİLER + name: Müşteriler products_and_inventory: name: Ürünler ve Stok users_and_enterprises: @@ -1034,10 +1039,13 @@ tr: name: "İşletme Ücreti Özeti" description: "Toplanan İşletme Ücretlerinin Özeti" subscriptions: - subscriptions: Üyelikler - new: Yeni Üyelik - create: Üyelik Oluştur - edit: Üyeliği düzenle + index: + title: "Üyelikler" + new: "Yeni Üyelik" + new: + title: "Yeni Üyelik" + edit: + title: "Üyeliği Düzenle" table: edit_subscription: Üyeliği Düzenle pause_subscription: Üyeliği Duraklat @@ -1046,6 +1054,7 @@ tr: filters: query_placeholder: "E-posta ile ara ..." setup_explanation: + title: "Üyelikler" just_a_few_more_steps: 'Başlamadan önce birkaç adım kaldı:' enable_subscriptions: "Dükkanınızdan en az biri için üyelikleri etkinleştirin" enable_subscriptions_step_1_html: 1. %{enterprises_link} sayfasına gidin, dükkanınızı bulun ve ‘Yönet’i tıklayın @@ -1059,6 +1068,8 @@ tr: create_at_least_one_schedule_step_3: 3. 'Yeni Takvim' butonuna tıklayın ve formu doldurun once_you_are_done_you_can_html: 'İşiniz bittiğinde, %{reload_this_page_link} ' reload_this_page: Sayfayı yeniden yükle + form: + create: "Üyelik Oluştur" steps: details: 1. Temel Bilgiler address: 2. Adres @@ -1303,6 +1314,8 @@ tr: cart_updating: "Sepet güncelleniyor ..." cart_empty: "Sepetiniz boş" cart_edit: "Sepetinizi düzenleyin" + item: "Ürün" + qty: "Miktar" card_number: Kart numarası card_securitycode: "Güvenlik Kodu" card_expiry_date: Son kullanma tarihi @@ -1362,8 +1375,8 @@ tr: cookies_policy_link: "çerezler politikası" cookies_accept_button: "Çerezleri kabul et" home_shop: 'ALIŞVERİŞE BAŞLAYIN ' - brandstory_headline: "Bağımsız, adil ve temiz gıda ..." - brandstory_intro: "Bazen sistemi düzeltmenin en iyi yolu yeni bir sistem yaratmaktır…" + brandstory_headline: "Yerel, adil ve temiz gıda." + brandstory_intro: "Eğer sistemi düzeltemiyorsak en iyi yol yeni bir sistem yaratmaktır." brandstory_part1: "Açık Gıda Ağı, adil, temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dürüstlük ve dayanışmayı destekler." brandstory_part2: "AGA, üreticilere ve alıcılara aracısız ticaret faydaları sağlar ve toplumsal iletişimi ve güveni cesaretlendirir. Gıda yetiştiriciliği ve satışının kendine özgü ihtiyaçlarını karşılamak için geliştirilmiştir. Temiz gıdaya ulaşım sürecini kolaylaştırır." brandstory_part3: "Platform üzerinden yalnızca yerel ve bağımsız gıda üreticileri ve dağıtımcıları satış yapabilir. Siz de ürünlerinizi AGA üzerinden oluşturduğunuz dükan ile doğrudan alıcılara ulaştırabilir, dilerseniz bölgenizdeki diğer üreticiler ile bir araya gelerek kendi ortak 'Üretici Pazarı' veya 'Türetici Pazarı' nızı oluşturabilirsiniz. Bu şekilde çeşitliliği ve bereketi artırır, dayanışmanın getirdiği faydalardan da yararlanabilirsiniz." @@ -1376,17 +1389,17 @@ tr: connect_cta: "Keşfedin" system_headline: "Nasıl çalışıyor ?" system_step1: "1. Ara" - system_step1_text: "Yerel, adil, temiz ve mevsimsel gıda için, bağımsız ve cesur üreticilerimizin ve dağıtımcılarımızın dükkanlarından alışveriş yapın. Konuma, ürün kategorisine, üretici özelliklerine veya teslimat tercihlerine göre arama yapabilirsiniz. " + system_step1_text: "Yerel ve mevsimsel gıda için, bağımsız ve cesur üreticilerimizin ve dağıtımcılarımızın dükkanlarından alışveriş yapın. " system_step2: "2. Alışveriş Yap" - system_step2_text: "Gıdanızı yerel üretici tezgahlarından, üretici ve türetici pazarlarından temin edin. Yaşanabilir bir dünya için alışkanlıklarınızı şimdi değiştirin. Gıdanızın ve onu size getiren insanların hikayelerini öğrenin!" + system_step2_text: "Gıdanızı yerel üreticilerden ve türetici pazarlarından temin edin. Yaşanabilir bir dünya için alışkanlıklarınızı şimdi değiştirin. " system_step3: "3. Teslimat " - system_step3_text: "Gıdanıza ulaşmak için adresinize teslim edilmesini bekleyin. Dilerseniz gıdanız ile daha kişisel bir bağ kurmak için üreticinizi veya pazarını kendiniz ziyaret edin. Doğayla ve gıdayla istediğiniz şekilde ama gerçek bir bağ kurun. " + system_step3_text: "Siparişinizin teslim edilmesini bekleyin veya teslim alım noktasında buluşun. Gıdayla istediğiniz şekilde ama gerçek bir bağ kurun. " cta_headline: "Dünyayı daha iyi bir yer yapan alışveriş biçimi." - cta_label: "Hazırım" + cta_label: "ALIŞVERİŞE HAZIRIM" stats_headline: "Yeni bir gıda sistemi yaratıyoruz." stats_producers: "ÜRETİCİ" stats_shops: "DÜKKAN" - stats_shoppers: "TÜRETİCİ" + stats_shoppers: "ALICI" stats_orders: "ALIŞVERİŞ" checkout_title: Ödeme Yap checkout_now: Alışverişi Tamamla @@ -1521,7 +1534,7 @@ tr: shopping_tabs_contact: "İLETİŞİM" shopping_contact_address: "Adres" shopping_contact_web: "İLETİŞİM" - shopping_contact_social: "Takip et" + shopping_contact_social: "TAKİP ET" shopping_groups_part_of: "şunun parçası:" shopping_producers_of_hub: "%{hub} üreticileri:" enterprises_next_closing: "Bir sonraki sipariş kapanışı" @@ -1542,7 +1555,7 @@ tr: hubs_filter_delivery: "Eve Teslim" hubs_filter_property: "Özellik" hubs_matches: "Bunu mu arıyordunuz?" - hubs_intro: Bulunduğunuz bölgeden alışveriş yapın + hubs_intro: Alışverişe başlayın hubs_distance: En yakın hubs_distance_filter: "Bana %{location} yakınındaki dükkanları göster" shop_changeable_orders_alert_html: @@ -1581,14 +1594,14 @@ tr: components_filters_clearfilters: "TÜM FİLTRELERİ TEMİZLE" groups_title: Gruplar groups_headline: Gruplar - groups_text: "Her üretici özeldir ve her işletmenin ortaya koyabileceği farklı bir değer vardır. Üyelerimiz, ürünlerini, emeklerini ve gıdanın ortak değerleri paylaşan üretici, türetici ve dağıtımcı kolektifleridir. Bu bileşenler, adil ve temiz gıdaya ulaşım yollarını kolaylaştırır ve bozulmuş gıda sistemini hep beraber düzeltmemize yardımcı olur." + groups_text: "Her üretici özeldir ve her işletmenin ortaya koyabileceği farklı bir değer vardır. Üyelerimiz, ürünlerini, emeklerini ve gıdanın ortak değerlerini paylaşan üretici, türetici ve dağıtımcı kolektifleridir. Bu bileşenler, adil ve temiz gıdaya ulaşım yollarını kolaylaştırır ve bozulmuş gıda sistemini düzeltmemize öncülük ederler." groups_search: "İsim veya anahtar kelime ile ara" groups_no_groups: "Ağ bulunamadı" groups_about: "Hakkımızda" groups_producers: "ÜRETİCİLERİMİZ" groups_hubs: "Pazarlarımız" groups_contact_web: İLETİŞİM - groups_contact_social: Takip et + groups_contact_social: TAKİP ET groups_contact_address: Adres groups_contact_email: Bize e-posta gönderin groups_contact_website: İnternet sitemizi ziyaret edin @@ -1615,9 +1628,9 @@ tr: producers_about: Hakkımızda producers_buy: Alışveriş ürünleri producers_contact: İLETİŞİM - producers_contact_phone: Ara - producers_contact_social: Takip et - producers_buy_at_html: "%{enterprise} ürünleri için buradan alışveriş yapın:" + producers_contact_phone: 'Tel:' + producers_contact_social: TAKİP ET + producers_buy_at_html: "%{enterprise} ÜRÜNLERİNİ SATIN ALIN:" producers_filter: Filtrele producers_filter_type: tür producers_filter_property: Özellik @@ -1864,15 +1877,15 @@ tr: enterprise_final_step: "Son adım!" enterprise_social_text: "Kişiler %{enterprise}' nasıl çevrimiçi bulabilir?" website: "İnternet sitesi" - website_placeholder: "Örneğin. yesilciftlik.com" + website_placeholder: "Örn. ciftlik.com" facebook: "Facebook" - facebook_placeholder: "Örneğin. www.facebook.com/SayfaAdı" + facebook_placeholder: "Örn. www.facebook.com/Ciftlik" linkedin: "LinkedIn" - linkedin_placeholder: "Örneğin. www.linkedin.com/Adınız" + linkedin_placeholder: "Örn. www.linkedin.com/Adınız" twitter: "Twitter" - twitter_placeholder: "Örneğin. @twitter_ciftlik" + twitter_placeholder: "Örn. @twitter_ciftlik" instagram: "Instagram" - instagram_placeholder: "Örneğin. @instagram_ciftlik" + instagram_placeholder: "Örn. instagram_ciftlik" limit_reached: headline: "Hayır!" message: "Sınıra ulaştınız!" @@ -1893,10 +1906,10 @@ tr: bulk: "toplu" shop_variant_quantity_min: "min" shop_variant_quantity_max: "maks" - follow: "Takip et" - shop_for_products_html: "%{enterprise} ürünleri için şuradan alışveriş yapın:" + follow: "TAKİP ET" + shop_for_products_html: "%{enterprise} ÜRÜNLERİNİ SATIN ALIN:" change_shop: "Dükkanı şuna değiştir:" - shop_at: "Şimdi alışveriş yapın:" + shop_at: "ŞİMDİ ALIŞVERİŞ YAPIN:" price_breakdown: "Fiyat dökümü" admin_fee: "Yönetim Ücreti" sales_fee: "Satış Ücreti" @@ -1918,7 +1931,7 @@ tr: ok: tamam not_visible: görünmez you_have_no_orders_yet: "Henüz siparişiniz yok" - show_only_complete_orders: "Yalnızca tamamlanan siparişleri göster" + show_only_complete_orders: "YALNIZCA TAMAMLANAN SİPARİŞLERİ GÖSTER" successfully_created: '%{resource} BAŞARIYLA OLUŞTURULDU!' successfully_removed: '%{resource} BAŞARIYLA KALDIRILDI!' successfully_updated: '%{resource} BAŞARIYLA GÜNCELLENDİ!' @@ -1939,25 +1952,27 @@ tr: admin_enterprise_groups_data_powertip_logo: "Grubun logosu" admin_enterprise_groups_data_powertip_promo_image: "Bu resim grup profilinin üstünde görüntülenir" admin_enterprise_groups_contact: "İLETİŞİM" - admin_enterprise_groups_contact_phone_placeholder: "Örneğin. 532 100 05 01" - admin_enterprise_groups_contact_address1_placeholder: "Örneğin. 123 Cadde" + admin_enterprise_groups_contact_phone_placeholder: "Örn. 532 100 05 01" + admin_enterprise_groups_contact_address1_placeholder: "Örn. 123 Cadde" admin_enterprise_groups_contact_city: "İlçe" - admin_enterprise_groups_contact_city_placeholder: "Örneğin. Kadıköy" + admin_enterprise_groups_contact_city_placeholder: "Örn. Kadıköy" admin_enterprise_groups_contact_zipcode: "Posta kodu" admin_enterprise_groups_contact_zipcode_placeholder: "Örn. 34000" admin_enterprise_groups_contact_state_id: "Şehir" admin_enterprise_groups_contact_country_id: "Ülke" admin_enterprise_groups_web: "Web Kaynakları" - admin_enterprise_groups_web_twitter: "Örneğin. @the_prof" - admin_enterprise_groups_web_website_placeholder: "Örneğin. www.ciftlik.com" + admin_enterprise_groups_web_twitter: "Örn. @the_ciftlik" + admin_enterprise_groups_web_website_placeholder: "Örn. www.ciftlik.com" admin_order_cycles: "Yönetici Sipariş Dönemleri" open: "AÇILIŞ" - close: "KAPANIŞ" + close: "Kapat" create: "Oluştur" search: "Ara" supplier: "Tedarikçi" product_name: "Ürün Adı" product_description: "Ürün Açıklaması" + permalink: "Permalink" + shipping_categories: "Teslimat Kategorileri" units: "Ölçü Birimi" coordinator: "KOORDİNATÖR" distributor: "Dağıtımcı" @@ -2025,8 +2040,8 @@ tr: spree_admin_product_category: Ürün Kategorisi spree_admin_variant_unit_name: Varyant Birimi Adı unit_name: "Birim adı" - change_package: "Hesap Türünü Değiştir" - spree_admin_single_enterprise_hint: "İpucu: İnsanların sizi bulmasına izin vermek için, alttaki görünürlük kısmını açın." + change_package: "HESAP TÜRÜNÜ DEĞİŞTİR" + spree_admin_single_enterprise_hint: "İpucu: İnsanların sizi bulmasına izin vermek için 'Görünür' olmayı ayarlamayı unutmayın:" spree_admin_eg_pickup_from_school: "Örn. 'Teslimat noktası: Moda İlkokulu Bahçesi'" spree_admin_eg_collect_your_order: "Örn. Lütfen siparişinizi Moda Cad. No:17 Temiz Dükkan'dan teslim alınız." spree_classification_primary_taxon_error: "%{taxon} cinsi, %{product}ürününün birincil cinsidir ve silinemez" @@ -2054,6 +2069,8 @@ tr: remove_tax: "Vergiyi kaldır" first_name_begins_with: "Adının BAŞ HARFİ" last_name_begins_with: "Soyadının BAŞ HARFİ" + shipping_method: "Teslimat Yöntemi" + new_order: "Yeni Sipariş" enterprise_tos_link: "İşletme Üyelik Sözleşmesi bağlantısı" enterprise_tos_message: "Amaçlarımızı ve değerlerimizi paylaşan insanlarla çalışmak istiyoruz. Yasal zorunluluk gereği de yeni işletmelerden kabul etmesini istiyoruz:" enterprise_tos_link_text: "Üyelik Sözleşmesi" @@ -2129,7 +2146,7 @@ tr: report_header_incoming_transport: Gelen Nakliye report_header_special_instructions: Özel Talimatlar report_header_order_number: Sipariş numarası - report_header_date: tarih + report_header_date: Tarih report_header_confirmation_date: Onay tarihi report_header_tags: ETİKETLER report_header_items: Kalemler @@ -2429,8 +2446,8 @@ tr: en iyi şekilde yönetmeniz için tüm imkanları ve araçları sağlamaya hazırız. get_listing: Görünür Olun always_free: HER ZAMAN ÜCRETSİZ - sell_produce_others: Başkalarının ürünlerini sat - sell_own_produce: Kendi ürününü sat + sell_produce_others: BAŞKALARININ ÜRÜNLERİNİ SAT + sell_own_produce: KENDİ ÜRÜNÜNÜ SAT sell_both: Kendi ürünlerini ve başkalarının ürünlerini sat enterprise_producer: producer: Üretici @@ -2452,12 +2469,12 @@ tr: adına sipariş ve teslimatları yönetebilir, adil ve temiz gıdayı nihai tüketiciler ile buluşturmaya yardımcı olabilirler. producer_desc: Gıda üreticileri - producer_example: 'Örn: ÇİFTÇİLER, FIRINLAR, ÜRETİM KOOPERATİFLERİ vs.' + producer_example: Örn. ÇİFTÇİLER, FIRINLAR, ÜRETİM KOOPERATİFLERİ vs. non_producer_desc: Diğer tüm gıda işletmeleri - non_producer_example: 'Örn: Manavlar, Gıda Kooperatifleri, Gıda Toplulukları vs.' + non_producer_example: Örn. Dükkanlar, Gıda Kooperatifleri, Gıda Toplulukları vs. enterprise_status: status_title: "%{name} kuruldu ve başlamaya hazır!" - severity: Şiddet + severity: ÖNEM description: Açıklama resolve: Çözüm exchange_products: @@ -2966,7 +2983,7 @@ tr: tab: dashboard: "KONTROL PANELİ" orders: "SİPARİŞLER" - bulk_order_management: "Toplu Sipariş Yönetimi" + bulk_order_management: "TOPLU SİPARİŞ YÖNETİMİ" subscriptions: "Üyelikler" products: "Ürünler" option_types: "Seçenek Türleri" @@ -3103,7 +3120,7 @@ tr: new_shipping_method: "YENİ TESLİMAT YÖNTEMİ" back_to_shipping_methods_list: "Teslİmat Yöntemlerİne Gerİ Dön" edit: - editing_shipping_method: "Teslİmat YöntemİNİ Düzenle" + editing_shipping_method: "Teslimat Yöntemini Düzenle" new: "YENİ" back_to_shipping_methods_list: "Teslİmat Yöntemlerİne Gerİ Dön" form: @@ -3168,6 +3185,8 @@ tr: stripe: error_saving_payment: Ödeme kaydedilirken hata oluştu submitting_payment: Ödeme gönderiliyor ... + paypal: + no_payment_via_admin_backend: Paypal ödemeleri alınamıyor. products: image_upload_error: "Ürün resmi tanınamadı. Lütfen PNG veya JPG biçiminde bir resim yükleyin." new: @@ -3184,7 +3203,7 @@ tr: product_description: "Ürün Açıklaması" image: "Görsel" or: "veya" - unit_name_placeholder: 'Örneğin. demet' + unit_name_placeholder: 'Örn. Demet' index: header: title: Ürünleri Toplu Düzenleme @@ -3262,8 +3281,8 @@ tr: price: "Fiyat" display_as: "Gösterme Şekli" display_name: "Ekran adı" - display_as_placeholder: 'örn. 2 kg' - display_name_placeholder: 'örn. Domates' + display_as_placeholder: 'Örn. 2 kg' + display_name_placeholder: 'Örn. Domates' autocomplete: out_of_stock: "Stokta Yok" producer_name: "Üretici" @@ -3345,6 +3364,32 @@ tr: invoice_email: hi: "Merhaba %{name}" invoice_attached_text: 'Son siparişiniz için gelen fatura ektedir:' + user_mailer: + reset_password_instructions: + request_sent_text: | + Şifrenizin değiştirilmesi için bir talepte bulunuldu. + Eğer talepte bulunan siz değilseniz lütfen bu mesajı gözardı edin. + link_text: > + Bu talepte bulunduysanız lütfen aşağıdaki bağlantıya tıklayın: + issue_text: | + Üstteki URL çalışmıyor ise tarayıcınızın adres çubuğuna kopyalayıp yapıştırmayı deneyebilirsiniz. + Sorun yaşamaya devam ederseniz bizimle iletişime geçmekten çekinmeyin. + confirmation_instructions: + subject: "Lütfen AGA hesabınızı onaylayın" + shipment_mailer: + shipped_email: + dear_customer: "Değerli Müşterimiz," + instructions: "Siparişiniz gönderildi" + shipment_summary: "Teslimat Özeti" + subject: "TESLİMAT BİLDİRİMİ" + thanks: "İş birliğiniz için teşekkür ederim." + track_information: "Takip Bilgileri: %{tracking}" + track_link: "Takip Bağlantısı: %{url}" + test_mailer: + test_email: + greeting: "Tebrikler!" + message: "Bu maili teslim aldıysanız e-posta ayarlarınız doğru yapılmıştır demektir." + subject: "Test Maili" order_state: address: adres adjustments: düzenlemeler @@ -3366,18 +3411,6 @@ tr: ended: bitti paused: durduruldu canceled: iptal edildi - user_mailer: - reset_password_instructions: - request_sent_text: | - Şifrenizin değiştirilmesi için bir talepte bulunuldu. - Eğer talepte bulunan siz değilseniz lütfen bu mesajı gözardı edin. - link_text: > - Bu talepte bulunduysanız lütfen aşağıdaki bağlantıya tıklayın: - issue_text: | - Üstteki URL çalışmıyor ise tarayıcınızın adres çubuğuna kopyalayıp yapıştırmayı deneyebilirsiniz. - Sorun yaşamaya devam ederseniz bizimle iletişime geçmekten çekinmeyin. - confirmation_instructions: - subject: Lütfen AGA hesabınızı onaylayın users: form: account_settings: Hesap Ayarları diff --git a/config/routes.rb b/config/routes.rb index ef3380ea79..a657f7f234 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ Openfoodnetwork::Application.routes.draw do get "/about_us", to: redirect(ContentConfig.footer_about_url) get "/login", to: redirect("/#/login") + get '/unauthorized', :to => 'home#unauthorized', :as => :unauthorized get "/discourse/login", to: "discourse_sso#login" get "/discourse/sso", to: "discourse_sso#sso" diff --git a/config/routes/spree.rb b/config/routes/spree.rb index ca5993aca5..5aecadbf49 100644 --- a/config/routes/spree.rb +++ b/config/routes/spree.rb @@ -1,7 +1,5 @@ # Overriding Devise routes to use our own controller Spree::Core::Engine.routes.draw do - root to: 'home#index' - devise_for :spree_user, :class_name => 'Spree::User', :controllers => { :sessions => 'spree/user_sessions', @@ -15,7 +13,6 @@ Spree::Core::Engine.routes.draw do resources :users, :only => [:edit, :update] devise_scope :spree_user do - get '/login' => 'user_sessions#new', :as => :login post '/login' => 'user_sessions#create', :as => :create_new_session get '/logout' => 'user_sessions#destroy', :as => :logout get '/signup' => 'user_registrations#new', :as => :signup @@ -174,8 +171,6 @@ Spree::Core::Engine.routes.draw do # Used by spree_paypal_express get '/checkout/:state', :to => 'checkout#edit', :as => :checkout_state - - get '/unauthorized', :to => 'home#unauthorized', :as => :unauthorized get '/content/cvv', :to => 'content#cvv', :as => :cvv get '/content/*path', :to => 'content#show', :as => :content end diff --git a/db/migrate/20200512070717_add_lock_version_to_stock_items.rb b/db/migrate/20200512070717_add_lock_version_to_stock_items.rb new file mode 100644 index 0000000000..416a43f62e --- /dev/null +++ b/db/migrate/20200512070717_add_lock_version_to_stock_items.rb @@ -0,0 +1,5 @@ +class AddLockVersionToStockItems < ActiveRecord::Migration + def change + add_column :spree_stock_items, :lock_version, :integer, default: 0 + end +end diff --git a/db/migrate/20200514174526_reset_negative_nonbackorderable_count_on_hand_in_stock_items.rb b/db/migrate/20200514174526_reset_negative_nonbackorderable_count_on_hand_in_stock_items.rb new file mode 100644 index 0000000000..c57730c99a --- /dev/null +++ b/db/migrate/20200514174526_reset_negative_nonbackorderable_count_on_hand_in_stock_items.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class ResetNegativeNonbackorderableCountOnHandInStockItems < ActiveRecord::Migration + module Spree + class StockItem < ActiveRecord::Base + self.table_name = "spree_stock_items" + end + end + + def up + Spree::StockItem.where(backorderable: false) + .where("count_on_hand < 0") + .update_all(count_on_hand: 0) + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20200721135726_move_calculators_preferences_outside_spree_namespace.rb b/db/migrate/20200721135726_move_calculators_preferences_outside_spree_namespace.rb new file mode 100644 index 0000000000..2591550dd1 --- /dev/null +++ b/db/migrate/20200721135726_move_calculators_preferences_outside_spree_namespace.rb @@ -0,0 +1,25 @@ +# As we moved the calculators outside the Spree namespace in migration MoveAllCalculatorsOutsideTheSpreeNamespace +# We need to move their preferences too (currency, value, etc), otherwise they are not used +class MoveCalculatorsPreferencesOutsideSpreeNamespace < ActiveRecord::Migration + def up + replace_preferences_key("/spree/calculator", "/calculator") + end + + def down + replace_preferences_key("/calculator", "/spree/calculator") + end + + private + + def replace_preferences_key(from_pattern, to_pattern) + updated_pref_key = "replace( pref.key, '" + from_pattern + "', '" + to_pattern + "')" + Spree::Preference.connection.execute( + "UPDATE spree_preferences pref SET key = " + updated_pref_key + " + WHERE pref.key like '" + from_pattern + "%' + AND NOT EXISTS (SELECT 1 FROM spree_preferences existing_pref + WHERE existing_pref.key = " + updated_pref_key + ")" + ) + + Rails.cache.clear + end +end diff --git a/db/schema.rb b/db/schema.rb index 97ddcb63d2..f56c95f405 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20200702112157) do +ActiveRecord::Schema.define(version: 20200721135726) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -901,6 +901,7 @@ ActiveRecord::Schema.define(version: 20200702112157) do t.datetime "updated_at", null: false t.boolean "backorderable", default: false t.datetime "deleted_at" + t.integer "lock_version", default: 0 end add_index "spree_stock_items", ["stock_location_id", "variant_id"], name: "stock_item_by_loc_and_var_id", using: :btree diff --git a/engines/order_management/app/services/order_management/order/updater.rb b/engines/order_management/app/services/order_management/order/updater.rb new file mode 100644 index 0000000000..e7cb051a4f --- /dev/null +++ b/engines/order_management/app/services/order_management/order/updater.rb @@ -0,0 +1,184 @@ +# frozen_string_literal: true + +module OrderManagement + module Order + class Updater + attr_reader :order + delegate :payments, :line_items, :adjustments, :shipments, :update_hooks, to: :order + + def initialize(order) + @order = order + end + + # This is a multi-purpose method for processing logic related to changes in the Order. + # It is meant to be called from various observers so that the Order is aware of changes + # that affect totals and other values stored in the Order. + # + # This method should never do anything to the Order that results in a save call on the + # object with callbacks (otherwise you will end up in an infinite recursion as the + # associations try to save and then in turn try to call +update!+ again.) + def update + update_totals + + if order.completed? + update_payment_state + + # give each of the shipments a chance to update themselves + shipments.each { |shipment| shipment.update!(order) } + update_shipment_state + end + + update_all_adjustments + # update totals a second time in case updated adjustments have an effect on the total + update_totals + + order.update_attributes_without_callbacks( + payment_state: order.payment_state, + shipment_state: order.shipment_state, + item_total: order.item_total, + adjustment_total: order.adjustment_total, + payment_total: order.payment_total, + total: order.total + ) + + run_hooks + end + + def run_hooks + update_hooks.each { |hook| order.__send__(hook) } + end + + # Updates the following Order total values: + # + # - payment_total - total value of all finalized Payments (excludes non-finalized Payments) + # - item_total - total value of all LineItems + # - adjustment_total - total value of all adjustments + # - total - order total, it's the equivalent to item_total plus adjustment_total + def update_totals + order.payment_total = payments.completed.map(&:amount).sum + order.item_total = line_items.map(&:amount).sum + order.adjustment_total = adjustments.eligible.map(&:amount).sum + order.total = order.item_total + order.adjustment_total + end + + # Updates the +shipment_state+ attribute according to the following logic: + # + # - shipped - when the order shipment is in the "shipped" state + # - ready - when the order shipment is in the "ready" state + # - backorder - when there is backordered inventory associated with an order + # - pending - when the shipment is in the "pending" state + # + # The +shipment_state+ value helps with reporting, etc. since it provides a quick and easy way + # to locate Orders needing attention. + def update_shipment_state + order.shipment_state = if order.shipment&.backordered? + 'backorder' + else + # It returns nil if there is no shipment + order.shipment&.state + end + + order.state_changed('shipment') + end + + # Updates the +payment_state+ attribute according to the following logic: + # + # - paid - when +payment_total+ is equal to +total+ + # - balance_due - when +payment_total+ is less than +total+ + # - credit_owed - when +payment_total+ is greater than +total+ + # - failed - when most recent payment is in the failed state + # + # The +payment_state+ value helps with reporting, etc. since it provides a quick and easy way + # to locate Orders needing attention. + def update_payment_state + last_payment_state = order.payment_state + + order.payment_state = infer_payment_state + track_payment_state_change(last_payment_state) + + order.payment_state + end + + def update_all_adjustments + order.adjustments.reload.each(&:update!) + end + + def before_save_hook + shipping_address_from_distributor + end + + # Sets the distributor's address as shipping address of the order for those + # shipments using a shipping method that doesn't require address, such us + # a pickup. + def shipping_address_from_distributor + return if order.shipping_method.blank? || order.shipping_method.require_ship_address + + order.ship_address = order.address_from_distributor + end + + private + + def round_money(value) + (value * 100).round / 100.0 + end + + def infer_payment_state + if failed_payments? + 'failed' + elsif canceled_and_not_paid_for? + 'void' + else + infer_payment_state_from_balance + end + end + + def infer_payment_state_from_balance + # This part added so that we don't need to override + # order.outstanding_balance + balance = order.outstanding_balance + balance = -1 * order.payment_total if canceled_and_paid_for? + + infer_state(balance) + end + + def infer_state(balance) + if balance.positive? + 'balance_due' + elsif balance.negative? + 'credit_owed' + elsif balance.zero? + 'paid' + end + end + + # Tracks the state transition through a state_change for this order. It + # does so until the last state is reached. That is, when the infered next + # state is the same as the order has now. + # + # @param last_payment_state [String] + def track_payment_state_change(last_payment_state) + return if last_payment_state == order.payment_state + + order.state_changed('payment') + end + + # Taken from order.outstanding_balance in Spree 2.4 + # See: https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a + def canceled_and_paid_for? + order.canceled? && paid? + end + + def canceled_and_not_paid_for? + order.state == 'canceled' && order.payment_total.zero? + end + + def paid? + payments.present? && !payments.completed.empty? + end + + def failed_payments? + payments.present? && payments.valid.empty? + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb index 8adaef7f33..bc44c2b857 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb @@ -138,8 +138,13 @@ module OrderManagement private def line_item_includes - [{ order: [:bill_address], - variant: [{ option_values: :option_type }, { product: :supplier }] }] + [ + { + order: [:bill_address], + variant: [{ option_values: :option_type }, { product: :supplier }] + }, + :option_values + ] end def order_permissions diff --git a/engines/order_management/app/services/order_management/subscriptions/summarizer.rb b/engines/order_management/app/services/order_management/subscriptions/summarizer.rb index 8029716338..f591295d1c 100644 --- a/engines/order_management/app/services/order_management/subscriptions/summarizer.rb +++ b/engines/order_management/app/services/order_management/subscriptions/summarizer.rb @@ -22,12 +22,15 @@ module OrderManagement summary_for(order).record_issue(type, order, message) end - def record_and_log_error(type, order) + def record_and_log_error(type, order, error_message = nil) return record_issue(type, order) unless order.errors.any? error = "Subscription#{type.to_s.camelize}Error" line1 = "#{error}: Cannot process order #{order.number} due to errors" - line2 = "Errors: #{order.errors.full_messages.join(', ')}" + + error_message ||= order.errors.full_messages.join(', ') + line2 = "Errors: #{error_message}" + JobLogger.logger.info("#{line1}\n#{line2}") record_issue(type, order, line2) end diff --git a/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb b/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb index 29caf17a15..2cbc464c75 100644 --- a/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb +++ b/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb @@ -3,12 +3,11 @@ require "spec_helper" feature "bulk coop" do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper scenario "bulk co-op report" do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link 'Bulk Co-Op' click_button 'Generate Report' diff --git a/engines/order_management/spec/features/order_management/reports/enterprise_fee_summaries_spec.rb b/engines/order_management/spec/features/order_management/reports/enterprise_fee_summaries_spec.rb index 553d78d093..8d66b93bfc 100644 --- a/engines/order_management/spec/features/order_management/reports/enterprise_fee_summaries_spec.rb +++ b/engines/order_management/spec/features/order_management/reports/enterprise_fee_summaries_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" feature "enterprise fee summaries", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let!(:distributor) { create(:distributor_enterprise) } diff --git a/engines/order_management/spec/services/order_management/order/updater_spec.rb b/engines/order_management/spec/services/order_management/order/updater_spec.rb new file mode 100644 index 0000000000..1bd901d37c --- /dev/null +++ b/engines/order_management/spec/services/order_management/order/updater_spec.rb @@ -0,0 +1,275 @@ +# frozen_string_literal: true + +require 'spec_helper' + +module OrderManagement + module Order + describe Updater do + let(:order) { build(:order) } + let(:updater) { OrderManagement::Order::Updater.new(order) } + + before { allow(order).to receive(:backordered?) { false } } + + it "updates totals" do + payments = [double(amount: 5), double(amount: 5)] + allow(order).to receive_message_chain(:payments, :completed).and_return(payments) + + line_items = [double(amount: 10), double(amount: 20)] + allow(order).to receive_messages line_items: line_items + + adjustments = [double(amount: 10), double(amount: -20)] + allow(order).to receive_message_chain(:adjustments, :eligible).and_return(adjustments) + + updater.update_totals + expect(order.payment_total).to eq 10 + expect(order.item_total).to eq 30 + expect(order.adjustment_total).to eq(-10) + expect(order.total).to eq 20 + end + + context "updating shipment state" do + let(:shipment) { build(:shipment) } + + before do + allow(order).to receive(:shipments).and_return([shipment]) + end + + it "is backordered" do + allow(shipment).to receive(:backordered?) { true } + updater.update_shipment_state + + expect(order.shipment_state).to eq 'backorder' + end + + it "is nil" do + allow(shipment).to receive(:state).and_return(nil) + + updater.update_shipment_state + expect(order.shipment_state).to be_nil + end + + ["shipped", "ready", "pending"].each do |state| + it "is #{state}" do + allow(shipment).to receive(:state).and_return(state) + updater.update_shipment_state + expect(order.shipment_state).to eq state.to_s + end + end + end + + it "state change" do + order = create(:order) + order.shipment_state = 'shipped' + state_changes = double + allow(order).to receive(:state_changes) { state_changes } + expect(state_changes).to receive(:create).with( + previous_state: nil, + next_state: 'shipped', + name: 'shipment', + user_id: order.user_id + ) + + order.state_changed('shipment') + end + + context "completed order" do + before { allow(order).to receive(:completed?) { true } } + + it "updates payment state" do + expect(updater).to receive(:update_payment_state) + updater.update + end + + it "updates shipment state" do + expect(updater).to receive(:update_shipment_state) + updater.update + end + + it "updates the order shipment" do + shipment = build(:shipment) + allow(order).to receive_messages shipments: [shipment] + + expect(shipment).to receive(:update!).with(order) + updater.update + end + end + + context "incompleted order" do + before { allow(order).to receive_messages completed?: false } + + it "doesnt update payment state" do + expect(updater).not_to receive(:update_payment_state) + updater.update + end + + it "doesnt update shipment state" do + expect(updater).not_to receive(:update_shipment_state) + updater.update + end + + it "doesnt update the order shipment" do + shipment = build(:shipment) + allow(order).to receive_messages shipments: [shipment] + + expect(shipment).not_to receive(:update!).with(order) + updater.update + end + end + + it "updates totals twice" do + expect(updater).to receive(:update_totals).twice + updater.update + end + + it "updates all adjustments" do + expect(updater).to receive(:update_all_adjustments) + updater.update + end + + it "is failed if no valid payments" do + allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(true) + + updater.update_payment_state + expect(order.payment_state).to eq('failed') + end + + context "payment total is greater than order total" do + it "is credit_owed" do + order.payment_total = 2 + order.total = 1 + + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'credit_owed' + end + end + + context "order total is greater than payment total" do + it "is credit_owed" do + order.payment_total = 1 + order.total = 2 + + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'balance_due' + end + end + + context "order total equals payment total" do + it "is paid" do + order.payment_total = 30 + order.total = 30 + + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'paid' + end + end + + context "order is canceled" do + before do + order.state = 'canceled' + end + + context "and is still unpaid" do + it "is void" do + order.payment_total = 0 + order.total = 30 + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'void' + end + end + + context "and is paid" do + it "is credit_owed" do + order.payment_total = 30 + order.total = 30 + allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(false) + allow(order).to receive_message_chain(:payments, :completed, :empty?).and_return(false) + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'credit_owed' + end + end + + context "and payment is refunded" do + it "is void" do + order.payment_total = 0 + order.total = 30 + allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(false) + allow(order).to receive_message_chain(:payments, :completed, :empty?).and_return(false) + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'void' + end + end + end + + context 'when the set payment_state does not match the last payment_state' do + before { order.payment_state = 'previous_to_paid' } + + context 'and the order is being updated' do + before { allow(order).to receive(:persisted?) { true } } + + it 'creates a new state_change for the order' do + expect { updater.update_payment_state } + .to change { order.state_changes.size }.by(1) + end + end + + context 'and the order is being created' do + before { allow(order).to receive(:persisted?) { false } } + + it 'creates a new state_change for the order' do + expect { updater.update_payment_state } + .not_to change { order.state_changes.size } + end + end + end + + context 'when the set payment_state matches the last payment_state' do + before { order.payment_state = 'paid' } + + it 'does not create any state_change' do + expect { updater.update_payment_state } + .not_to change { order.state_changes.size } + end + end + + context '#before_save_hook' do + let(:distributor) { build(:distributor_enterprise) } + let(:shipment) { + create(:shipment_with, :shipping_method, shipping_method: shipping_method) + } + + before do + order.distributor = distributor + order.shipments = [shipment] + end + + context 'when shipping method is pickup' do + let(:shipping_method) { create(:shipping_method_with, :pickup) } + let(:address) { build(:address, firstname: 'joe') } + before { distributor.address = address } + + it "populates the shipping address from distributor" do + updater.before_save_hook + expect(order.ship_address.address1).to eq(distributor.address.address1) + end + end + + context 'when shipping_method is delivery' do + let(:shipping_method) { create(:shipping_method_with, :delivery) } + let(:address) { build(:address, firstname: 'will') } + before { order.ship_address = address } + + it "does not populate the shipping address from distributor" do + updater.before_save_hook + expect(order.ship_address.firstname).to eq("will") + end + end + end + end + end +end diff --git a/knapsack_rspec_report.json b/knapsack_rspec_report.json index 91499ba40e..f745a4438d 100644 --- a/knapsack_rspec_report.json +++ b/knapsack_rspec_report.json @@ -113,7 +113,6 @@ "spec/models/subscription_line_item_spec.rb": 0.021193265914916992, "spec/controllers/api/statuses_controller_spec.rb": 0.02451467514038086, "spec/lib/open_food_network/referer_parser_spec.rb": 0.015799283981323242, - "spec/lib/open_food_network/reports/rule_spec.rb": 0.01628732681274414, "spec/helpers/serializer_helper_spec.rb": 0.004682064056396484, "spec/jobs/heartbeat_job_spec.rb": 0.013271570205688477, "spec/services/mail_configuration_spec.rb": 0.01050567626953125, @@ -246,7 +245,6 @@ "spec/validators/integer_array_validator_spec.rb": 0.04994392395019531, "spec/validators/date_time_string_validator_spec.rb": 0.05316734313964844, "spec/models/product_import/reset_absent_spec.rb": 0.04071307182312012, - "spec/lib/open_food_network/reports/report_spec.rb": 0.04329681396484375, "spec/jobs/confirm_signup_job_spec.rb": 0.03060293197631836, "spec/services/order_cycle_distributed_variants_spec.rb": 0.02808237075805664, "spec/lib/open_food_network/feature_toggle_spec.rb": 0.0240786075592041, @@ -255,7 +253,6 @@ "spec/models/spree/calculator/flat_rate_spec.rb": 0.014808177947998047, "spec/models/spree/image_spec.rb": 0.014715909957885742, "spec/helpers/spree/admin/base_helper_spec.rb": 0.008042573928833008, - "spec/lib/open_food_network/reports/row_spec.rb": 0.005358695983886719, "engines/order_management/spec/controllers/order_management/reports/enterprise_fee_summaries_controller_spec.rb": 0.7100100517272949, "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/parameters_spec.rb": 4.190261602401733, "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_data/enterprise_fee_type_total_spec.rb": 0.006247282028198242, diff --git a/lib/open_food_network/model_class_from_controller_name.rb b/lib/open_food_network/model_class_from_controller_name.rb deleted file mode 100644 index 97b92a18d7..0000000000 --- a/lib/open_food_network/model_class_from_controller_name.rb +++ /dev/null @@ -1,8 +0,0 @@ -module OpenFoodNetwork - module ModelClassFromControllerName - # Equivalent to CanCan's "authorize_resource :class => false" (see https://github.com/ryanb/cancan/blob/master/lib/cancan/controller_resource.rb#L146) - def model_class - self.class.to_s.sub("Controller", "").underscore.split('/').last.singularize.to_sym - end - end -end diff --git a/lib/open_food_network/reports/report.rb b/lib/open_food_network/reports/report.rb deleted file mode 100644 index 2c4e5900f2..0000000000 --- a/lib/open_food_network/reports/report.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'open_food_network/reports/row' -require 'open_food_network/reports/rule' - -module OpenFoodNetwork::Reports - class Report - class_attribute :_header, :_columns, :_rules_head - - # -- API - def header - _header - end - - def columns - _columns.to_a - end - - def rules - # Flatten linked list and return as hashes - rules = [] - - rule = _rules_head - while rule - rules << rule - rule = rule.next - end - - rules.map(&:to_h) - end - - # -- DSL - def self.header(*columns) - self._header = columns - end - end -end diff --git a/lib/open_food_network/reports/row.rb b/lib/open_food_network/reports/row.rb deleted file mode 100644 index 35b4bffe33..0000000000 --- a/lib/open_food_network/reports/row.rb +++ /dev/null @@ -1,15 +0,0 @@ -module OpenFoodNetwork::Reports - class Row - def initialize - @columns = [] - end - - def column(&block) - @columns << block - end - - def to_a - @columns - end - end -end diff --git a/lib/open_food_network/reports/rule.rb b/lib/open_food_network/reports/rule.rb deleted file mode 100644 index cfb8b7e67f..0000000000 --- a/lib/open_food_network/reports/rule.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'open_food_network/reports/row' - -module OpenFoodNetwork::Reports - class Rule - attr_reader :next - - def group(&block) - @group = block - end - - def sort(&block) - @sort = block - end - - def to_h - h = { group_by: @group, sort_by: @sort } - h[:summary_columns] = @summary_row.to_a if @summary_row - h - end - end -end diff --git a/lib/spree/authentication_helpers.rb b/lib/spree/authentication_helpers.rb index 49bd97542a..1f26c65f2c 100644 --- a/lib/spree/authentication_helpers.rb +++ b/lib/spree/authentication_helpers.rb @@ -11,7 +11,9 @@ module Spree current_spree_user end - delegate :login_path, to: :spree, prefix: true + def spree_login_path + main_app.login_path + end delegate :signup_path, to: :spree, prefix: true diff --git a/lib/spree/core.rb b/lib/spree/core.rb new file mode 100644 index 0000000000..5a7d98dbd2 --- /dev/null +++ b/lib/spree/core.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'rails/all' +require 'active_merchant' +require 'acts_as_list' +require 'awesome_nested_set' +require 'cancan' +require 'kaminari' +require 'mail' +require 'paperclip' +require 'paranoia' +require 'ransack' +require 'state_machine' + +module Spree + mattr_accessor :user_class + + def self.user_class + if @@user_class.is_a?(Class) + raise "Spree.user_class MUST be a String object, not a Class object." + end + + return unless @@user_class.is_a?(String) + + @@user_class.constantize + end + + # Used to configure Spree. + # + # Example: + # + # Spree.config do |config| + # config.site_name = "An awesome Spree site" + # end + # + # This method is defined within the core gem on purpose. + # Some people may only wish to use the Core part of Spree. + def self.config + yield(Spree::Config) + end +end + +require 'spree/core/version' +require 'spree/core/engine' + +require 'spree/i18n' +require 'spree/money' + +require 'spree/core/delegate_belongs_to' +require 'spree/core/ext/active_record' +require 'spree/core/permalinks' +require 'spree/core/token_resource' +require 'spree/core/calculated_adjustments' +require 'spree/core/product_duplicator' + +ActiveRecord::Base.class_eval do + include CollectiveIdea::Acts::NestedSet +end diff --git a/lib/spree/core/calculated_adjustments.rb b/lib/spree/core/calculated_adjustments.rb new file mode 100644 index 0000000000..c502c00099 --- /dev/null +++ b/lib/spree/core/calculated_adjustments.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module Spree + module Core + module CalculatedAdjustments + def self.included(klass) + klass.class_eval do + has_one :calculator, class_name: "Spree::Calculator", as: :calculable, dependent: :destroy + accepts_nested_attributes_for :calculator + validates :calculator, presence: true + + def self.calculators + spree_calculators.__send__(model_name_without_spree_namespace) + end + + def calculator_type + calculator.class.to_s if calculator + end + + def calculator_type=(calculator_type) + klass = calculator_type.constantize if calculator_type + self.calculator = klass.new if klass && !calculator.is_a?(klass) + end + + # Creates a new adjustment for the target object + # (which is any class that has_many :adjustments) and sets amount based on the + # calculator as applied to the given calculable (Order, LineItems[], Shipment, etc.) + # By default the adjustment will not be considered mandatory + def create_adjustment(label, target, calculable, mandatory = false, state = "closed") + # Adjustment calculations done on Spree::Shipment objects MUST + # be done on their to_package'd variants instead + # It's only the package that contains the correct information. + # See https://github.com/spree/spree_active_shipping/pull/96 et. al + old_calculable = calculable + calculable = calculable.to_package if calculable.is_a?(Spree::Shipment) + amount = compute_amount(calculable) + return if amount.zero? && !mandatory + + target.adjustments.create( + amount: amount, + source: old_calculable, + originator: self, + label: label, + mandatory: mandatory, + state: state + ) + end + + # Updates the amount of the adjustment using our Calculator and + # calling the +compute+ method with the +calculable+ + # referenced passed to the method. + def update_adjustment(adjustment, calculable) + # Adjustment calculations done on Spree::Shipment objects MUST + # be done on their to_package'd variants instead + # It's only the package that contains the correct information. + # See https://github.com/spree/spree_active_shipping/pull/96 et. al + calculable = calculable.to_package if calculable.is_a?(Spree::Shipment) + adjustment.update_column(:amount, compute_amount(calculable)) + end + + # Calculate the amount to be used when creating an adjustment + # NOTE: May be overriden by classes where this module is included into. + # Such as Spree::Promotion::Action::CreateAdjustment. + def compute_amount(calculable) + calculator.compute(calculable) + end + + def self.model_name_without_spree_namespace + to_s.tableize.gsub('/', '_').sub('spree_', '') + end + private_class_method :model_name_without_spree_namespace + + def self.spree_calculators + Rails.application.config.spree.calculators + end + private_class_method :spree_calculators + end + end + end + end +end diff --git a/lib/spree/core/controller_helpers.rb b/lib/spree/core/controller_helpers.rb new file mode 100644 index 0000000000..3df5251c9a --- /dev/null +++ b/lib/spree/core/controller_helpers.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Spree + module Core + module ControllerHelpers + def self.included(klass) + klass.class_eval do + include Spree::Core::ControllerHelpers::Common + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::RespondWith + include Spree::Core::ControllerHelpers::Order + end + end + end + end +end diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb new file mode 100644 index 0000000000..c6c18b9be1 --- /dev/null +++ b/lib/spree/core/controller_helpers/auth.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module Spree + module Core + module ControllerHelpers + module Auth + extend ActiveSupport::Concern + + included do + before_filter :ensure_api_key + + rescue_from CanCan::AccessDenied do + unauthorized + end + end + + # Needs to be overriden so that we use Spree's Ability rather than anyone else's. + def current_ability + @current_ability ||= Spree::Ability.new(spree_current_user) + end + + # Redirect as appropriate when an access request fails. The default action is to redirect + # to the login screen. Override this method in your controllers if you want to have + # special behavior in case the user is not authorized to access the requested action. + # For example, a popup window might simply close itself. + def unauthorized + if spree_current_user + flash[:error] = Spree.t(:authorization_failure) + redirect_to '/unauthorized' + else + store_location + redirect_to main_app.root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}") + end + end + + def store_location + # disallow return to login, logout, signup pages + authentication_routes = [:spree_signup_path, :spree_login_path, :spree_logout_path] + disallowed_urls = [] + authentication_routes.each do |route| + if respond_to?(route) + disallowed_urls << __send__(route) + end + end + + disallowed_urls.map!{ |url| url[/\/\w+$/] } + return if disallowed_urls.include?(request.fullpath) + + session['spree_user_return_to'] = request.fullpath.gsub('//', '/') + end + + def redirect_back_or_default(default) + redirect_to(session["spree_user_return_to"] || default) + session["spree_user_return_to"] = nil + end + + # Need to generate an API key for a user due to some actions potentially + # requiring authentication to the Spree API + def ensure_api_key + return unless (user = spree_current_user) + + return unless user.respond_to?(:spree_api_key) && user.spree_api_key.blank? + + user.generate_spree_api_key! + end + end + end + end +end diff --git a/lib/spree/core/controller_helpers/auth_decorator.rb b/lib/spree/core/controller_helpers/auth_decorator.rb deleted file mode 100644 index 7342450c74..0000000000 --- a/lib/spree/core/controller_helpers/auth_decorator.rb +++ /dev/null @@ -1,5 +0,0 @@ -Spree::Core::ControllerHelpers::Auth.class_eval do - def require_login_then_redirect_to(url) - redirect_to main_app.root_path(anchor: "login?after_login=#{url}") - end -end diff --git a/lib/spree/core/controller_helpers/common.rb b/lib/spree/core/controller_helpers/common.rb new file mode 100644 index 0000000000..e88920eaf6 --- /dev/null +++ b/lib/spree/core/controller_helpers/common.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +module Spree + module Core + module ControllerHelpers + module Common + extend ActiveSupport::Concern + included do + helper_method :title + helper_method :title= + helper_method :accurate_title + + layout :get_layout + + before_filter :set_user_language + + protected + + # Convenience method for firing instrumentation events with the default payload hash + def fire_event(name, extra_payload = {}) + ActiveSupport::Notifications.instrument(name, default_notification_payload. + merge(extra_payload)) + end + + # Creates the hash that is sent as the payload for all notifications. + # Specific notifications will add additional keys as appropriate. + # This method can be overriden to provide additional data when + # responding to a notification + def default_notification_payload + { user: spree_current_user, order: current_order } + end + + # This can be used in views as well as controllers. + # e.g. <% self.title = 'This is a custom title for this view' %> + attr_writer :title + + def title + title_string = @title.presence || accurate_title + if title_string.present? + if Spree::Config[:always_put_site_name_in_title] + [title_string, default_title].join(' - ') + else + title_string + end + else + default_title + end + end + + def default_title + Spree::Config[:site_name] + end + + # This is a hook for subclasses to provide title + def accurate_title + Spree::Config[:default_seo_title] + end + + def render_404(_exception = nil) + respond_to do |type| + type.html { + render status: :not_found, + file: "#{::Rails.root}/public/404", + formats: [:html], + layout: nil + } + type.all { render status: :not_found, nothing: true } + end + end + + private + + def set_user_language + locale = session[:locale] + locale ||= config_locale if respond_to?(:config_locale, true) + locale ||= Rails.application.config.i18n.default_locale + unless I18n.available_locales.map(&:to_s).include?(locale) + locale ||= I18n.default_locale + end + I18n.locale = locale + end + + # Returns which layout to render. + # The layout to render can be set inside Spree configuration with the +:layout+ option. + # Default layout is: +app/views/spree/layouts/spree_application+ + def get_layout + layout ||= Spree::Config[:layout] + end + end + end + end + end +end diff --git a/lib/spree/core/controller_helpers/order.rb b/lib/spree/core/controller_helpers/order.rb new file mode 100644 index 0000000000..e95499bef2 --- /dev/null +++ b/lib/spree/core/controller_helpers/order.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'open_food_network/scope_variant_to_hub' + +module Spree + module Core + module ControllerHelpers + module Order + def self.included(base) + base.class_eval do + helper_method :current_order + helper_method :current_currency + before_filter :set_current_order + end + end + + def current_order(create_order_if_necessary = false) + order = spree_current_order(create_order_if_necessary) + + if order + scoper = OpenFoodNetwork::ScopeVariantToHub.new(order.distributor) + order.line_items.each do |li| + scoper.scope(li.variant) + end + end + + order + end + + # The current incomplete session order used in cart and checkout + def spree_current_order(create_order_if_necessary = false) + return @current_order if @current_order + + if session[:order_id] + current_order = Spree::Order.includes(:adjustments) + .find_by(id: session[:order_id], currency: current_currency) + @current_order = current_order unless current_order.try(:completed?) + end + + if create_order_if_necessary && (@current_order.nil? || @current_order.completed?) + @current_order = Spree::Order.new(currency: current_currency) + @current_order.user ||= spree_current_user + # See https://github.com/spree/spree/issues/3346 for reasons why this line is here + @current_order.created_by ||= spree_current_user + @current_order.save! + + # Verify that the user has access to the order (if they are a guest) + if spree_current_user.nil? + session[:access_token] = @current_order.token + end + end + + return unless @current_order + + @current_order.last_ip_address = ip_address + session[:order_id] = @current_order.id + @current_order + end + + def associate_user + @order ||= current_order + if spree_current_user && @order + if @order.user.blank? || @order.email.blank? + @order.associate_user!(spree_current_user) + end + end + + session[:guest_token] = nil + end + + # Recover incomplete orders from other sessions after logging in. + def set_current_order + return unless (user = spree_current_user) + + last_incomplete_order = user.last_incomplete_spree_order + + if session[:order_id].nil? && last_incomplete_order + session[:order_id] = last_incomplete_order.id + end + + # Load current order and create a new one if necessary. + current_order(true) + end + + def current_currency + Spree::Config[:currency] + end + + def ip_address + request.env['HTTP_X_REAL_IP'] || request.env['REMOTE_ADDR'] + end + end + end + end +end diff --git a/lib/spree/core/controller_helpers/order_decorator.rb b/lib/spree/core/controller_helpers/order_decorator.rb deleted file mode 100644 index 6da1b42ee6..0000000000 --- a/lib/spree/core/controller_helpers/order_decorator.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'open_food_network/scope_variant_to_hub' - -Spree::Core::ControllerHelpers::Order.class_eval do - def current_order_with_scoped_variants(create_order_if_necessary = false) - order = current_order_without_scoped_variants(create_order_if_necessary) - - if order - scoper = OpenFoodNetwork::ScopeVariantToHub.new(order.distributor) - order.line_items.each do |li| - scoper.scope(li.variant) - end - end - - order - end - alias_method_chain :current_order, :scoped_variants - - # Override definition in Spree::Core::ControllerHelpers::Order - # Do not attempt to merge incomplete and current orders. Instead, destroy the incomplete orders. - def set_current_order - if user = try_spree_current_user - last_incomplete_order = user.last_incomplete_spree_order - - if session[:order_id].nil? && last_incomplete_order - session[:order_id] = last_incomplete_order.id - - elsif current_order && last_incomplete_order && current_order != last_incomplete_order - last_incomplete_order.destroy - end - end - end -end diff --git a/lib/spree/core/controller_helpers/respond_with.rb b/lib/spree/core/controller_helpers/respond_with.rb new file mode 100644 index 0000000000..6b3e7129ca --- /dev/null +++ b/lib/spree/core/controller_helpers/respond_with.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +module ActionController + class Base + def respond_with(*resources, &block) + if self.class.mimes_for_respond_to.empty? + raise "In order to use respond_with, first you need to declare the formats your " \ + "controller responds to in the class level" + end + + return unless (collector = retrieve_collector_from_mimes(&block)) + + options = resources.size == 1 ? {} : resources.extract_options! + + # Fix spree issues #3531 and #2210 (patch provided by leiyangyou) + if (defined_response = collector.response) && + !Spree::BaseController.spree_responders[self.class.to_s.to_sym].try(:[], + action_name.to_sym) + if action = options.delete(:action) + render action: action + else + defined_response.call + end + else + # The action name is needed for processing + options[:action_name] = action_name.to_sym + # If responder is not specified then pass in Spree::Responder + (options.delete(:responder) || Spree::Responder).call(self, resources, options) + end + end + end +end + +module Spree + module Core + module ControllerHelpers + module RespondWith + extend ActiveSupport::Concern + + included do + cattr_accessor :spree_responders + self.spree_responders = {} + end + + module ClassMethods + def clear_overrides! + self.spree_responders = {} + end + + def respond_override(options = {}) + return if options.blank? + + action_name = options.keys.first + action_value = options.values.first + + if action_name.blank? || action_value.blank? + raise ArgumentError, "invalid values supplied #{options.inspect}" + end + + format_name = action_value.keys.first + format_value = action_value.values.first + + if format_name.blank? || format_value.blank? + raise ArgumentError, "invalid values supplied #{options.inspect}" + end + + if format_value.is_a?(Proc) + options = { + action_name.to_sym => { format_name.to_sym => { success: format_value } } + } + end + + spree_responders.deep_merge!(name.to_sym => options) + end + end + end + end + end +end diff --git a/lib/spree/core/controller_helpers/respond_with_decorator.rb b/lib/spree/core/controller_helpers/respond_with_decorator.rb deleted file mode 100644 index 522247ea01..0000000000 --- a/lib/spree/core/controller_helpers/respond_with_decorator.rb +++ /dev/null @@ -1,28 +0,0 @@ -module ActionController - class Base - def respond_with(*resources, &block) - if self.class.mimes_for_respond_to.empty? - raise "In order to use respond_with, first you need to declare the formats your " \ - "controller responds to in the class level" - end - - if collector = retrieve_collector_from_mimes(&block) - options = resources.size == 1 ? {} : resources.extract_options! - - # Fix spree issues #3531 and #2210 (patch provided by leiyangyou) - if (defined_response = collector.response) && !Spree::BaseController.spree_responders[self.class.to_s.to_sym].try(:[], action_name.to_sym) - if action = options.delete(:action) - render action: action - else - defined_response.call - end - else - # The action name is needed for processing - options[:action_name] = action_name.to_sym - # If responder is not specified then pass in Spree::Responder - (options.delete(:responder) || Spree::Responder).call(self, resources, options) - end - end - end - end -end diff --git a/lib/spree/core/controller_helpers/ssl.rb b/lib/spree/core/controller_helpers/ssl.rb new file mode 100644 index 0000000000..6c923e4977 --- /dev/null +++ b/lib/spree/core/controller_helpers/ssl.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Spree + module Core + module ControllerHelpers + module SSL + extend ActiveSupport::Concern + + included do + before_filter :force_non_ssl_redirect, if: proc { Spree::Config[:redirect_https_to_http] } + + def self.ssl_allowed(*actions) + class_attribute :ssl_allowed_actions + self.ssl_allowed_actions = actions + end + + def self.ssl_required(*actions) + class_attribute :ssl_required_actions + self.ssl_required_actions = actions + return unless ssl_supported? + + if ssl_required_actions.empty? || Rails.application.config.force_ssl + force_ssl + else + force_ssl only: ssl_required_actions + end + end + + def self.ssl_supported? + return Spree::Config[:allow_ssl_in_production] if Rails.env.production? + return Spree::Config[:allow_ssl_in_staging] if Rails.env.staging? + return unless Rails.env.development? || Rails.env.test? + + Spree::Config[:allow_ssl_in_development_and_test] + end + + private + + # Redirect the existing request to use the HTTP protocol. + # + # ==== Parameters + # * host - Redirect to a different host name + def force_non_ssl_redirect(host = nil) + return true if defined?(ssl_allowed_actions) && + ssl_allowed_actions.include?(action_name.to_sym) + + return unless request.ssl? && + (!defined?(ssl_required_actions) || + !ssl_required_actions.include?(action_name.to_sym)) + + redirect_options = { protocol: 'http://', status: :moved_permanently } + redirect_options.merge!(host: host) if host + redirect_options.merge!(params: request.query_parameters) + flash.keep if respond_to?(:flash) + redirect_to redirect_options + end + end + end + end + end +end diff --git a/lib/spree/core/delegate_belongs_to.rb b/lib/spree/core/delegate_belongs_to.rb new file mode 100644 index 0000000000..bfbf0b1fc0 --- /dev/null +++ b/lib/spree/core/delegate_belongs_to.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +## +# Creates methods on object which delegate to an association proxy. +# see delegate_belongs_to for two uses +# +# Todo - integrate with ActiveRecord::Dirty to make sure changes to delegate object are noticed +# Should do +# class User < ActiveRecord::Base; delegate_belongs_to :contact, :firstname; end +# class Contact < ActiveRecord::Base; end +# u = User.first +# u.changed? # => false +# u.firstname = 'Bobby' +# u.changed? # => true +# +# Right now the second call to changed? would return false +# +# Todo - add has_one support. fairly straightforward addition +## +module DelegateBelongsTo + extend ActiveSupport::Concern + + module ClassMethods + @@default_rejected_delegate_columns = ['created_at', 'created_on', 'updated_at', + 'updated_on', 'lock_version', 'type', 'id', + 'position', 'parent_id', 'lft', 'rgt'] + mattr_accessor :default_rejected_delegate_columns + + ## + # Creates methods for accessing and setting attributes on an association. Uses same + # default list of attributes as delegates_to_association. + # delegate_belongs_to :contact + # delegate_belongs_to :contact, [:defaults] ## same as above, and useless + # delegate_belongs_to :contact, [:defaults, :address, :fullname], :class_name => 'VCard' + ## + def delegate_belongs_to(association, *attrs) + opts = attrs.extract_options! + initialize_association :belongs_to, association, opts + attrs = get_association_column_names(association) if attrs.empty? + attrs.concat get_association_column_names(association) if attrs.delete :defaults + attrs.each do |attr| + class_def attr do |*args| + if args.empty? + __send__(:delegator_for, association).__send__(attr) + else + __send__(:delegator_for, association).__send__(attr, *args) + end + end + class_def "#{attr}=" do |val| + __send__(:delegator_for, association).__send__("#{attr}=", val) + end + end + end + + protected + + def get_association_column_names(association, without_default_rejected_delegate_columns = true) + association_klass = reflect_on_association(association).klass + methods = association_klass.column_names + if without_default_rejected_delegate_columns + methods.reject!{ |x| default_rejected_delegate_columns.include?(x.to_s) } + end + methods + rescue + [] + end + + ## + # initialize_association :belongs_to, :contact + def initialize_association(type, association, opts = {}) + unless [:belongs_to].include?(type.to_s.to_sym) + raise 'Illegal or unimplemented association type.' + end + + __send__(type, association, opts) if reflect_on_association(association).nil? + end + + private + + def class_def(name, method = nil, &blk) + class_eval { method.nil? ? define_method(name, &blk) : define_method(name, method) } + end + end + + def delegator_for(association) + if __send__(association).nil? + __send__("#{association}=", self.class.reflect_on_association(association).klass.new) + end + __send__(association) + end + protected :delegator_for +end + +ActiveRecord::Base.include(DelegateBelongsTo) diff --git a/lib/spree/core/environment/calculators.rb b/lib/spree/core/environment/calculators.rb new file mode 100644 index 0000000000..a5f60555f7 --- /dev/null +++ b/lib/spree/core/environment/calculators.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Spree + module Core + class Environment + class Calculators + include EnvironmentExtension + + attr_accessor :shipping_methods, :tax_rates + end + end + end +end diff --git a/lib/spree/core/environment_extension.rb b/lib/spree/core/environment_extension.rb new file mode 100644 index 0000000000..7b05908752 --- /dev/null +++ b/lib/spree/core/environment_extension.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Spree + module Core + module EnvironmentExtension + extend ActiveSupport::Concern + + def add_class(name) + instance_variable_set "@#{name}", Set.new + + create_method( "#{name}=".to_sym ) { |val| + instance_variable_set( "@" + name, val) + } + + create_method(name.to_sym) do + instance_variable_get( "@" + name ) + end + end + + private + + def create_method(name, &block) + self.class.__send__(:define_method, name, &block) + end + end + end +end diff --git a/lib/spree/core/gateway_error.rb b/lib/spree/core/gateway_error.rb new file mode 100644 index 0000000000..f90310bc54 --- /dev/null +++ b/lib/spree/core/gateway_error.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Spree + module Core + class GatewayError < RuntimeError; end + end +end diff --git a/lib/spree/core/mail_interceptor.rb b/lib/spree/core/mail_interceptor.rb new file mode 100644 index 0000000000..87ae2e33ab --- /dev/null +++ b/lib/spree/core/mail_interceptor.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Allows us to intercept any outbound mail message and make last minute changes +# (such as specifying a "from" address or sending to a test email account) +# +# See http://railscasts.com/episodes/206-action-mailer-in-rails-3 for more details. +module Spree + module Core + class MailInterceptor + def self.delivering_email(message) + return unless MailSettings.override? + + if Config[:intercept_email].present? + message.subject = "#{message.to} #{message.subject}" + message.to = Config[:intercept_email] + end + + return if Config[:mail_bcc].blank? + + message.bcc ||= Config[:mail_bcc] + end + end + end +end diff --git a/lib/spree/core/mail_settings.rb b/lib/spree/core/mail_settings.rb new file mode 100644 index 0000000000..80664d1c64 --- /dev/null +++ b/lib/spree/core/mail_settings.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +module Spree + module Core + class MailSettings + MAIL_AUTH = ['None', 'plain', 'login', 'cram_md5'].freeze + SECURE_CONNECTION_TYPES = ['None', 'SSL', 'TLS'].freeze + + # Override the Rails application mail settings based on preferences + # This makes it possible to configure the mail settings through an admin + # interface instead of requiring changes to the Rails envrionment file + def self.init + new.override! if override? + end + + def self.override? + Config.override_actionmailer_config + end + + def override! + if Config.enable_mail_delivery + ActionMailer::Base.default_url_options[:host] ||= Config.site_url + ActionMailer::Base.smtp_settings = mail_server_settings + ActionMailer::Base.perform_deliveries = true + else + ActionMailer::Base.perform_deliveries = false + end + end + + private + + def mail_server_settings + settings = if need_authentication? + basic_settings.merge(user_credentials) + else + basic_settings + end + + settings.merge(enable_starttls_auto: secure_connection?) + end + + def user_credentials + { user_name: Config.smtp_username, + password: Config.smtp_password } + end + + def basic_settings + { address: Config.mail_host, + domain: Config.mail_domain, + port: Config.mail_port, + authentication: Config.mail_auth_type } + end + + def need_authentication? + Config.mail_auth_type != 'None' + end + + def secure_connection? + Config.secure_connection_type == 'TLS' + end + end + end +end diff --git a/lib/spree/core/permalinks.rb b/lib/spree/core/permalinks.rb new file mode 100644 index 0000000000..b9d8a83274 --- /dev/null +++ b/lib/spree/core/permalinks.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'stringex' + +module Spree + module Core + module Permalinks + extend ActiveSupport::Concern + + included do + class_attribute :permalink_options + end + + module ClassMethods + def make_permalink(options = {}) + options[:field] ||= :permalink + self.permalink_options = options + + return unless connected? && + table_exists? && + column_names.include?(permalink_options[:field].to_s) + + before_validation(on: :create) { save_permalink } + end + + def find_by_param(value, *args) + __send__("find_by_#{permalink_field}", value, *args) + end + + def find_by_param!(value, *args) + __send__("find_by_#{permalink_field}!", value, *args) + end + + def permalink_field + permalink_options[:field] + end + + def permalink_prefix + permalink_options[:prefix] || "" + end + + def permalink_order + order = permalink_options[:order] + "#{order} ASC," if order + end + end + + def generate_permalink + "#{self.class.permalink_prefix}#{Array.new(9) { rand(9) }.join}" + end + + def save_permalink(permalink_value = to_param) + with_lock do + permalink_value ||= generate_permalink + + field = self.class.permalink_field + + # Do other links exist with this permalink? + other = self.class. + where("#{self.class.table_name}.#{field} LIKE ?", "#{permalink_value}%") + if other.any? + # Find the existing permalink with the highest number, and increment that number. + # (If none of the existing permalinks have a number, this will evaluate to 1.) + number = other.map { |o| o.__send__(field)[/-(\d+)$/, 1].to_i }.max + 1 + permalink_value += "-#{number}" + end + write_attribute(field, permalink_value) + end + end + end + end +end + +ActiveRecord::Base.include(Spree::Core::Permalinks) +ActiveRecord::Relation.include(Spree::Core::Permalinks) diff --git a/lib/spree/core/s3_support.rb b/lib/spree/core/s3_support.rb new file mode 100644 index 0000000000..92229c15f5 --- /dev/null +++ b/lib/spree/core/s3_support.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Spree + module Core + # This module exists to reduce duplication in S3 settings between + # the Image and Taxon models in Spree + module S3Support + extend ActiveSupport::Concern + + included do + def self.supports_s3(field) + # Load user defined paperclip settings + config = Spree::Config + return unless config[:use_s3] + + s3_creds = { access_key_id: config[:s3_access_key], + secret_access_key: config[:s3_secret], + bucket: config[:s3_bucket] } + attachment_definitions[field][:storage] = :s3 + attachment_definitions[field][:s3_credentials] = s3_creds + attachment_definitions[field][:s3_headers] = ActiveSupport::JSON. + decode(config[:s3_headers]) + attachment_definitions[field][:bucket] = config[:s3_bucket] + if config[:s3_protocol].present? + attachment_definitions[field][:s3_protocol] = config[:s3_protocol].downcase + end + + return if config[:s3_host_alias].blank? + + attachment_definitions[field][:s3_host_alias] = config[:s3_host_alias] + end + end + end + end +end diff --git a/lib/spree/core/token_resource.rb b/lib/spree/core/token_resource.rb new file mode 100644 index 0000000000..8d4173d11b --- /dev/null +++ b/lib/spree/core/token_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Spree + module Core + module TokenResource + module ClassMethods + def token_resource + has_one :tokenized_permission, as: :permissable + delegate :token, to: :tokenized_permission, allow_nil: true + after_create :create_token + end + end + + def create_token + permission = build_tokenized_permission + permission.token = token = ::SecureRandom.hex(8) + permission.save! + token + end + + def self.included(receiver) + receiver.extend ClassMethods + end + end + end +end + +ActiveRecord::Base.class_eval { include Spree::Core::TokenResource } diff --git a/lib/spree/i18n.rb b/lib/spree/i18n.rb new file mode 100644 index 0000000000..7780bc3ad7 --- /dev/null +++ b/lib/spree/i18n.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'i18n' +require 'active_support/core_ext/array/extract_options' +require 'spree/i18n/base' + +module Spree + extend ActionView::Helpers::TranslationHelper + + class << self + # Add spree namespace and delegate to Rails TranslationHelper for some nice + # extra functionality. e.g return reasonable strings for missing translations + def translate(*args) + @virtual_path = virtual_path + + options = args.extract_options! + options[:scope] = [*options[:scope]].unshift(:spree) + args << options + super(*args) + end + + alias_method :t, :translate + + def context + Spree::ViewContext.context + end + + def virtual_path + return unless context + + path = context.instance_variable_get("@virtual_path") + + return unless path + + path.gsub(/spree/, '') + end + end +end diff --git a/lib/spree/i18n/base.rb b/lib/spree/i18n/base.rb new file mode 100644 index 0000000000..88c2d3106d --- /dev/null +++ b/lib/spree/i18n/base.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Spree + module ViewContext + def self.context=(context) + @context = context + end + + def self.context + @context + end + + def view_context + super.tap do |context| + Spree::ViewContext.context = context + end + end + end +end diff --git a/lib/spree/i18n/initializer.rb b/lib/spree/i18n/initializer.rb new file mode 100644 index 0000000000..64b649f708 --- /dev/null +++ b/lib/spree/i18n/initializer.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +Spree::BaseController.include(Spree::ViewContext) diff --git a/lib/spree/money.rb b/lib/spree/money.rb new file mode 100644 index 0000000000..413c2f0e8c --- /dev/null +++ b/lib/spree/money.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: false + +require 'money' + +module Spree + class Money + attr_reader :money + + delegate :cents, to: :money + + def initialize(amount, options = {}) + @money = ::Money.parse([amount, (options[:currency] || Spree::Config[:currency])].join) + @options = {} + @options[:with_currency] = Spree::Config[:display_currency] + @options[:symbol_position] = Spree::Config[:currency_symbol_position].to_sym + @options[:no_cents] = Spree::Config[:hide_cents] + @options[:decimal_mark] = Spree::Config[:currency_decimal_mark] + @options[:thousands_separator] = Spree::Config[:currency_thousands_separator] + @options.merge!(options) + # Must be a symbol because the Money gem doesn't do the conversion + @options[:symbol_position] = @options[:symbol_position].to_sym + end + + def to_s + @money.format(@options) + end + + def to_html(options = { html: true }) + output = @money.format(@options.merge(options)) + if options[:html] + # 1) prevent blank, breaking spaces + # 2) prevent escaping of HTML character entities + output = output.gsub(" ", " ").html_safe + end + output + end + + def ==(other) + @money == other.money + end + end +end diff --git a/lib/spree/product_duplicator.rb b/lib/spree/product_duplicator.rb new file mode 100644 index 0000000000..8866f85fa5 --- /dev/null +++ b/lib/spree/product_duplicator.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +module Spree + class ProductDuplicator + attr_accessor :product + + def initialize(product) + @product = product + end + + def duplicate + new_product = duplicate_product + + # don't dup the actual variants, just the characterising types + new_product.option_types = product.option_types if product.has_variants? + + # allow site to do some customization + new_product.__send__(:duplicate_extra, product) if new_product.respond_to?(:duplicate_extra) + new_product.save! + new_product + end + + protected + + def duplicate_product + product.dup.tap do |new_product| + new_product.name = "COPY OF #{product.name}" + new_product.taxons = product.taxons + new_product.created_at = nil + new_product.deleted_at = nil + new_product.updated_at = nil + new_product.product_properties = reset_properties + new_product.master = duplicate_master + end + end + + def duplicate_master + master = product.master + master.dup.tap do |new_master| + new_master.sku = "COPY OF #{master.sku}" + new_master.deleted_at = nil + new_master.images = master.images.map { |image| duplicate_image image } + new_master.price = master.price + new_master.currency = master.currency + end + end + + def duplicate_image(image) + new_image = image.dup + new_image.assign_attributes(attachment: image.attachment.clone) + new_image + end + + def reset_properties + product.product_properties.map do |prop| + prop.dup.tap do |new_prop| + new_prop.created_at = nil + new_prop.updated_at = nil + end + end + end + end +end diff --git a/lib/spree/responder.rb b/lib/spree/responder.rb new file mode 100644 index 0000000000..3c0e60aa5b --- /dev/null +++ b/lib/spree/responder.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Spree + class Responder < ::ActionController::Responder #:nodoc: + attr_accessor :on_success, :on_failure + + def initialize(controller, resources, options = {}) + super + + class_name = controller.class.name.to_sym + action_name = options.delete(:action_name) + + result = Spree::BaseController.spree_responders[class_name]. + try(:[], action_name). + try(:[], self.format.to_sym) + return unless result + + self.on_success = handler(controller, result, :success) + self.on_failure = handler(controller, result, :failure) + end + + def to_html + if !(on_success || on_failure) + super + return + end + + has_errors? ? controller.instance_exec(&on_failure) : controller.instance_exec(&on_success) + end + + def to_format + if !(on_success || on_failure) + super + return + end + + has_errors? ? controller.instance_exec(&on_failure) : controller.instance_exec(&on_success) + end + + private + + def handler(controller, result, status) + return result if result.respond_to? :call + + case result + when Hash + if result[status].is_a? Symbol + controller.method(result[status]) + else + result[status] + end + when Symbol + controller.method(result) + end + end + end +end diff --git a/lib/tasks/sample_data/order_factory.rb b/lib/tasks/sample_data/order_factory.rb index 29d4cf03c6..9614f685a0 100644 --- a/lib/tasks/sample_data/order_factory.rb +++ b/lib/tasks/sample_data/order_factory.rb @@ -45,7 +45,7 @@ class OrderFactory def create_complete_order order = create_cart_order - AdvanceOrderService.new(order).call + OrderWorkflow.new(order).complete order end diff --git a/spec/controllers/admin/bulk_line_items_controller_spec.rb b/spec/controllers/admin/bulk_line_items_controller_spec.rb index 941b44eb0c..da05149079 100644 --- a/spec/controllers/admin/bulk_line_items_controller_spec.rb +++ b/spec/controllers/admin/bulk_line_items_controller_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Admin::BulkLineItemsController, type: :controller do - include AuthenticationWorkflow - describe '#index' do render_views @@ -17,11 +15,11 @@ describe Admin::BulkLineItemsController, type: :controller do let!(:line_item4) { FactoryBot.create(:line_item_with_shipment, order: order3) } context "as a normal user" do - before { allow(controller).to receive_messages spree_current_user: create_enterprise_user } + before { allow(controller).to receive_messages spree_current_user: create(:user) } it "should deny me access to the index action" do spree_get :index, format: :json - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -94,7 +92,7 @@ describe Admin::BulkLineItemsController, type: :controller do end it "does not display line items for which my enterprise is a supplier" do - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -172,7 +170,7 @@ describe Admin::BulkLineItemsController, type: :controller do end it "does not allow access" do - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/column_preferences_controller_spec.rb b/spec/controllers/admin/column_preferences_controller_spec.rb index acc3c194a5..53f2d12fda 100644 --- a/spec/controllers/admin/column_preferences_controller_spec.rb +++ b/spec/controllers/admin/column_preferences_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Admin::ColumnPreferencesController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "bulk_update" do let!(:user1) { create(:user) } diff --git a/spec/controllers/admin/customers_controller_spec.rb b/spec/controllers/admin/customers_controller_spec.rb index b1503d89f7..b439cc7c9c 100644 --- a/spec/controllers/admin/customers_controller_spec.rb +++ b/spec/controllers/admin/customers_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Admin::CustomersController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "index" do let(:enterprise) { create(:distributor_enterprise) } @@ -90,7 +90,7 @@ describe Admin::CustomersController, type: :controller do it "prevents me from updating the customer" do spree_put :update, format: :json, id: customer.id, customer: { email: 'new.email@gmail.com' } - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path expect(assigns(:customer)).to eq nil expect(customer.email).to_not eq 'new.email@gmail.com' end @@ -166,7 +166,7 @@ describe Admin::CustomersController, type: :controller do it "prevents me from updating the customer" do spree_get :show, format: :json, id: customer.id - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end end diff --git a/spec/controllers/admin/enterprises_controller_spec.rb b/spec/controllers/admin/enterprises_controller_spec.rb index 78678e03e2..a51af80b36 100644 --- a/spec/controllers/admin/enterprises_controller_spec.rb +++ b/spec/controllers/admin/enterprises_controller_spec.rb @@ -2,8 +2,6 @@ require 'spec_helper' require 'open_food_network/order_cycle_permissions' describe Admin::EnterprisesController, type: :controller do - include AuthenticationWorkflow - let(:user) { create(:user) } let(:admin_user) { create(:admin_user) } let(:distributor_manager) { create(:user, enterprise_limit: 10, enterprises: [distributor]) } @@ -138,7 +136,7 @@ describe Admin::EnterprisesController, type: :controller do let!(:property) { create(:property, name: "A nice name") } before do - login_as_enterprise_user [producer] + controller_login_as_enterprise_user [producer] end context "when a submitted property does not already exist" do @@ -179,7 +177,7 @@ describe Admin::EnterprisesController, type: :controller do let!(:tag_rule) { create(:tag_rule, enterprise: enterprise) } before do - login_as_enterprise_user [enterprise] + controller_login_as_enterprise_user [enterprise] end context "discount order rules" do @@ -294,7 +292,7 @@ describe Admin::EnterprisesController, type: :controller do it "does not allow access" do spree_post :register, id: enterprise.id, sells: 'none' - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -306,7 +304,7 @@ describe Admin::EnterprisesController, type: :controller do it "does not allow access" do spree_post :register, id: enterprise.id, sells: 'none' - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -366,18 +364,8 @@ describe Admin::EnterprisesController, type: :controller do end describe "bulk updating enterprises" do - let!(:original_owner) do - user = create_enterprise_user - user.enterprise_limit = 2 - user.save! - user - end - let!(:new_owner) do - user = create_enterprise_user - user.enterprise_limit = 2 - user.save! - user - end + let!(:original_owner) { create(:user) } + let!(:new_owner) { create(:user) } let!(:profile_enterprise1) { create(:enterprise, sells: 'none', owner: original_owner ) } let!(:profile_enterprise2) { create(:enterprise, sells: 'none', owner: original_owner ) } @@ -441,7 +429,7 @@ describe Admin::EnterprisesController, type: :controller do end describe "for_order_cycle" do - let!(:user) { create_enterprise_user } + let!(:user) { create(:user) } let!(:enterprise) { create(:enterprise, sells: 'any', owner: user) } let(:permission_mock) { double(:permission) } @@ -487,7 +475,7 @@ describe Admin::EnterprisesController, type: :controller do end describe "visible" do - let!(:user) { create(:user, enterprise_limit: 10) } + let!(:user) { create(:user) } let!(:visible_enterprise) { create(:enterprise, sells: 'any', owner: user) } let!(:not_visible_enterprise) { create(:enterprise, sells: 'any') } @@ -508,10 +496,10 @@ describe Admin::EnterprisesController, type: :controller do describe "index" do context "as super admin" do let(:super_admin) { create(:admin_user) } - let!(:user) { create_enterprise_user(enterprise_limit: 10) } + let!(:user) { create(:user) } let!(:enterprise1) { create(:enterprise, sells: 'any', owner: user) } let!(:enterprise2) { create(:enterprise, sells: 'own', owner: user) } - let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create_enterprise_user ) } + let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create(:user) ) } before do allow(controller).to receive_messages spree_current_user: super_admin @@ -533,10 +521,10 @@ describe Admin::EnterprisesController, type: :controller do end context "as an enterprise user" do - let!(:user) { create_enterprise_user(enterprise_limit: 10) } + let!(:user) { create(:user) } let!(:enterprise1) { create(:enterprise, sells: 'any', owner: user) } let!(:enterprise2) { create(:enterprise, sells: 'own', owner: user) } - let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create_enterprise_user ) } + let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create(:user) ) } before do allow(controller).to receive_messages spree_current_user: user diff --git a/spec/controllers/admin/inventory_items_controller_spec.rb b/spec/controllers/admin/inventory_items_controller_spec.rb index 741f329663..6d3f30f41f 100644 --- a/spec/controllers/admin/inventory_items_controller_spec.rb +++ b/spec/controllers/admin/inventory_items_controller_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Admin::InventoryItemsController, type: :controller do - # include AuthenticationWorkflow - describe "create" do context "json" do let(:format) { :json } @@ -21,7 +19,7 @@ describe Admin::InventoryItemsController, type: :controller do it "redirects to unauthorized" do spree_post :create, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -33,7 +31,7 @@ describe Admin::InventoryItemsController, type: :controller do context "but the producer has not granted VO permission" do it "redirects to unauthorized" do spree_post :create, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -84,7 +82,7 @@ describe Admin::InventoryItemsController, type: :controller do it "redirects to unauthorized" do spree_put :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -96,7 +94,7 @@ describe Admin::InventoryItemsController, type: :controller do context "but the producer has not granted VO permission" do it "redirects to unauthorized" do spree_put :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index 2ba98c9f8e..6988fa4787 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -2,9 +2,7 @@ require 'spec_helper' module Admin describe OrderCyclesController, type: :controller do - include AuthenticationWorkflow - - let!(:distributor_owner) { create_enterprise_user enterprise_limit: 2 } + let!(:distributor_owner) { create(:user) } before do allow(controller).to receive_messages spree_current_user: distributor_owner @@ -104,7 +102,7 @@ module Admin let(:params) { { format: :json, order_cycle: {} } } before do - login_as_enterprise_user([shop]) + controller_login_as_enterprise_user([shop]) allow(OrderCycleForm).to receive(:new) { form_mock } end @@ -150,7 +148,7 @@ module Admin end context "as a manager of the coordinator" do - before { login_as_enterprise_user([coordinator]) } + before { controller_login_as_enterprise_user([coordinator]) } let(:params) { { format: :json, id: order_cycle.id, order_cycle: {} } } context "when updating succeeds" do @@ -178,10 +176,22 @@ module Admin it "returns an error message" do spree_put :update, params + json_response = JSON.parse(response.body) expect(json_response['errors']).to be end end + + it "can update preference product_selection_from_coordinator_inventory_only" do + expect(OrderCycleForm).to receive(:new). + with(order_cycle, + { "preferred_product_selection_from_coordinator_inventory_only" => true }, + anything) { form_mock } + allow(form_mock).to receive(:save) { true } + + spree_put :update, params. + merge(order_cycle: { preferred_product_selection_from_coordinator_inventory_only: true }) + end end end @@ -288,7 +298,7 @@ module Admin end describe "notifying producers" do - let(:user) { create_enterprise_user } + let(:user) { create(:user) } let(:admin_user) do user = create(:user) user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') diff --git a/spec/controllers/admin/proxy_orders_controller_spec.rb b/spec/controllers/admin/proxy_orders_controller_spec.rb index 1d612e2c57..ccd4a9bb02 100644 --- a/spec/controllers/admin/proxy_orders_controller_spec.rb +++ b/spec/controllers/admin/proxy_orders_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Admin::ProxyOrdersController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe 'cancel' do let!(:user) { create(:user, enterprise_limit: 10) } @@ -20,7 +20,7 @@ describe Admin::ProxyOrdersController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -31,7 +31,7 @@ describe Admin::ProxyOrdersController, type: :controller do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -77,7 +77,7 @@ describe Admin::ProxyOrdersController, type: :controller do before do # Processing order to completion allow(Spree::OrderMailer).to receive(:cancel_email) { double(:email, deliver: true) } - AdvanceOrderService.new(order).call! + OrderWorkflow.new(order).complete! proxy_order.reload proxy_order.cancel allow(controller).to receive(:spree_current_user) { user } @@ -89,7 +89,7 @@ describe Admin::ProxyOrdersController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :resume, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -100,7 +100,7 @@ describe Admin::ProxyOrdersController, type: :controller do it 'redirects to unauthorized' do spree_put :resume, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/schedules_controller_spec.rb b/spec/controllers/admin/schedules_controller_spec.rb index 99b73f4e03..0648574642 100644 --- a/spec/controllers/admin/schedules_controller_spec.rb +++ b/spec/controllers/admin/schedules_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Admin::SchedulesController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "index" do let!(:coordinated_order_cycle) { create(:simple_order_cycle) } @@ -106,7 +106,7 @@ describe Admin::SchedulesController, type: :controller do it "prevents me from updating the schedule" do spree_put :update, format: :json, id: coordinated_schedule.id, schedule: { name: "my awesome schedule" } - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path expect(assigns(:schedule)).to eq nil expect(coordinated_schedule.name).to_not eq "my awesome schedule" end diff --git a/spec/controllers/admin/stripe_accounts_controller_spec.rb b/spec/controllers/admin/stripe_accounts_controller_spec.rb index 9a6854ae85..c1b0890316 100644 --- a/spec/controllers/admin/stripe_accounts_controller_spec.rb +++ b/spec/controllers/admin/stripe_accounts_controller_spec.rb @@ -46,7 +46,7 @@ describe Admin::StripeAccountsController, type: :controller do it "redirects to unauthorized" do spree_delete :destroy, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -93,7 +93,7 @@ describe Admin::StripeAccountsController, type: :controller do it "redirects to unauthorized" do spree_get :status, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/stripe_connect_settings_controller_spec.rb b/spec/controllers/admin/stripe_connect_settings_controller_spec.rb index 11cebea66e..73331a151a 100644 --- a/spec/controllers/admin/stripe_connect_settings_controller_spec.rb +++ b/spec/controllers/admin/stripe_connect_settings_controller_spec.rb @@ -14,7 +14,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do it "does not allow access" do spree_get :edit - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -76,7 +76,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do it "does not allow access" do spree_get :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/subscription_line_items_controller_spec.rb b/spec/controllers/admin/subscription_line_items_controller_spec.rb index d60c581ab5..6df2a71f53 100644 --- a/spec/controllers/admin/subscription_line_items_controller_spec.rb +++ b/spec/controllers/admin/subscription_line_items_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Admin::SubscriptionLineItemsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "build" do let(:user) { create(:user) } diff --git a/spec/controllers/admin/subscriptions_controller_spec.rb b/spec/controllers/admin/subscriptions_controller_spec.rb index c7f0e207a4..1aeb87ddef 100644 --- a/spec/controllers/admin/subscriptions_controller_spec.rb +++ b/spec/controllers/admin/subscriptions_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Admin::SubscriptionsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper include OpenFoodNetwork::EmailHelper describe 'index' do @@ -18,7 +18,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_get :index, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -55,7 +55,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_get :index, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -120,7 +120,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_post :create, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -272,7 +272,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_post :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -390,7 +390,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -401,7 +401,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -489,7 +489,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :pause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -500,7 +500,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_put :pause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -588,7 +588,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :unpause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -599,7 +599,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_put :unpause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/tag_rules_controller_spec.rb b/spec/controllers/admin/tag_rules_controller_spec.rb index b4da011923..5d654958a4 100644 --- a/spec/controllers/admin/tag_rules_controller_spec.rb +++ b/spec/controllers/admin/tag_rules_controller_spec.rb @@ -19,7 +19,7 @@ describe Admin::TagRulesController, type: :controller do it "redirects to unauthorized" do spree_delete :destroy, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/variant_overrides_controller_spec.rb b/spec/controllers/admin/variant_overrides_controller_spec.rb index c75a265cd1..cc8add0156 100644 --- a/spec/controllers/admin/variant_overrides_controller_spec.rb +++ b/spec/controllers/admin/variant_overrides_controller_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Admin::VariantOverridesController, type: :controller do - # include AuthenticationWorkflow - describe "bulk_update" do context "json" do let(:format) { :json } @@ -22,7 +20,7 @@ describe Admin::VariantOverridesController, type: :controller do it "redirects to unauthorized" do spree_put :bulk_update, format: format, variant_overrides: variant_override_params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -34,7 +32,7 @@ describe Admin::VariantOverridesController, type: :controller do context "but the producer has not granted VO permission" do it "redirects to unauthorized" do spree_put :bulk_update, format: format, variant_overrides: variant_override_params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -78,7 +76,7 @@ describe Admin::VariantOverridesController, type: :controller do it "allows to update other variant overrides" do spree_put :bulk_update, format: format, variant_overrides: variant_override_params - expect(response).to_not redirect_to spree.unauthorized_path + expect(response).to_not redirect_to unauthorized_path variant_override.reload expect(variant_override.price).to eq 123.45 end @@ -111,7 +109,7 @@ describe Admin::VariantOverridesController, type: :controller do it "redirects to unauthorized" do spree_put :bulk_reset, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -123,7 +121,7 @@ describe Admin::VariantOverridesController, type: :controller do context "where the producer has not granted create_variant_overrides permission to the hub" do it "restricts access" do spree_put :bulk_reset, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/api/base_controller_spec.rb b/spec/controllers/api/base_controller_spec.rb index d501aa98fb..1ebd3eca15 100644 --- a/spec/controllers/api/base_controller_spec.rb +++ b/spec/controllers/api/base_controller_spec.rb @@ -14,7 +14,7 @@ describe Api::BaseController do context "signed in as a user using an authentication extension" do before do - allow(controller).to receive_messages try_spree_current_user: + allow(controller).to receive_messages spree_current_user: double(email: "ofn@example.com") end diff --git a/spec/controllers/api/customers_controller_spec.rb b/spec/controllers/api/customers_controller_spec.rb index cab5b2e1e1..25fc52cc09 100644 --- a/spec/controllers/api/customers_controller_spec.rb +++ b/spec/controllers/api/customers_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' module Api describe CustomersController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper render_views let(:user) { create(:user) } diff --git a/spec/controllers/api/enterprise_fees_controller_spec.rb b/spec/controllers/api/enterprise_fees_controller_spec.rb index 8991e5fcde..b32423fea2 100644 --- a/spec/controllers/api/enterprise_fees_controller_spec.rb +++ b/spec/controllers/api/enterprise_fees_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' module Api describe EnterpriseFeesController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper let!(:unreferenced_fee) { create(:enterprise_fee) } let!(:referenced_fee) { create(:enterprise_fee) } diff --git a/spec/controllers/api/enterprises_controller_spec.rb b/spec/controllers/api/enterprises_controller_spec.rb index b6e42967dc..0a2a185b72 100644 --- a/spec/controllers/api/enterprises_controller_spec.rb +++ b/spec/controllers/api/enterprises_controller_spec.rb @@ -1,13 +1,12 @@ require 'spec_helper' describe Api::EnterprisesController, type: :controller do - include AuthenticationWorkflow render_views let(:enterprise) { create(:distributor_enterprise) } context "as an enterprise owner" do - let(:enterprise_owner) { create_enterprise_user enterprise_limit: 10 } + let(:enterprise_owner) { create(:user) } let!(:enterprise) { create(:distributor_enterprise, owner: enterprise_owner) } before do @@ -52,7 +51,7 @@ describe Api::EnterprisesController, type: :controller do end context "as an enterprise manager" do - let(:enterprise_manager) { create_enterprise_user } + let(:enterprise_manager) { create(:user) } before do enterprise_manager.enterprise_roles.build(enterprise: enterprise).save @@ -74,7 +73,7 @@ describe Api::EnterprisesController, type: :controller do end context "as an non-managing user" do - let(:non_managing_user) { create_enterprise_user } + let(:non_managing_user) { create(:user) } before do allow(Enterprise) diff --git a/spec/controllers/api/exchange_products_controller_spec.rb b/spec/controllers/api/exchange_products_controller_spec.rb index f94089280c..3fa7248198 100644 --- a/spec/controllers/api/exchange_products_controller_spec.rb +++ b/spec/controllers/api/exchange_products_controller_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' module Api describe ExchangeProductsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper let(:order_cycle) { create(:order_cycle) } let(:exchange) { order_cycle.exchanges.incoming.first } diff --git a/spec/controllers/api/logos_controller_spec.rb b/spec/controllers/api/logos_controller_spec.rb index 213ac8bc6e..b4cee3e896 100644 --- a/spec/controllers/api/logos_controller_spec.rb +++ b/spec/controllers/api/logos_controller_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" module Api describe LogosController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper let(:admin_user) { create(:admin_user) } let(:enterprise_owner) { create(:user) } diff --git a/spec/controllers/api/orders_controller_spec.rb b/spec/controllers/api/orders_controller_spec.rb index 726756734d..b4d03951fc 100644 --- a/spec/controllers/api/orders_controller_spec.rb +++ b/spec/controllers/api/orders_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' module Api describe OrdersController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper render_views let!(:regular_user) { create(:user) } diff --git a/spec/controllers/api/product_images_controller_spec.rb b/spec/controllers/api/product_images_controller_spec.rb index 5015d41b00..44fb239e38 100644 --- a/spec/controllers/api/product_images_controller_spec.rb +++ b/spec/controllers/api/product_images_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' module Api describe ProductImagesController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper render_views describe "uploading an image" do diff --git a/spec/controllers/api/promo_images_controller_spec.rb b/spec/controllers/api/promo_images_controller_spec.rb index cce6d08f5f..ac73a1d94b 100644 --- a/spec/controllers/api/promo_images_controller_spec.rb +++ b/spec/controllers/api/promo_images_controller_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" module Api describe PromoImagesController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper let(:admin_user) { create(:admin_user) } let(:enterprise_owner) { create(:user) } diff --git a/spec/controllers/api/shops_controller_spec.rb b/spec/controllers/api/shops_controller_spec.rb index a90f606f57..08040feea8 100644 --- a/spec/controllers/api/shops_controller_spec.rb +++ b/spec/controllers/api/shops_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Api::ShopsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper render_views context "as a non-authenticated user" do diff --git a/spec/controllers/base_controller_spec.rb b/spec/controllers/base_controller_spec.rb index ee7dcb4bcc..fb1d399335 100644 --- a/spec/controllers/base_controller_spec.rb +++ b/spec/controllers/base_controller_spec.rb @@ -9,6 +9,90 @@ describe BaseController, type: :controller do end end + describe "#current_order" do + let(:user) { create(:user) } + + it "doesn't change anything without a user" do + expect { + get :index + }.to_not change { Spree::Order.count } + end + + it "creates a new order" do + allow(controller).to receive(:spree_current_user).and_return(user) + + expect { + get :index + }.to change { Spree::Order.count }.by(1) + + expect(user.orders.count).to eq 1 + end + + it "uses the last incomplete order" do + last_cart = create(:order, user: user, created_by: user, state: "cart", completed_at: nil) + allow(controller).to receive(:spree_current_user).and_return(user) + + expect { + get :index + }.to_not change { Spree::Order.count } + + expect(session[:order_id]).to eq last_cart.id + end + + it "ignores the last incomplete order" do + # Spree used to merge the last order with the current one. + # And we used to override that logic to delete old incomplete orders. + # Now we are checking here that none of that is happening. + + last_cart = create(:order, user: user, created_by: user, state: "cart", completed_at: nil) + last_cart.line_items << create(:line_item) + + current_cart = create( + :order, + user: user, + created_by: user, + state: "cart", + completed_at: nil, + created_at: 1.week.ago + ) + session[:order_id] = current_cart.id + + allow(controller).to receive(:spree_current_user).and_return(user) + + expect { + get :index + }.to_not change { Spree::Order.count } + + expect(current_cart.line_items.count).to eq 0 + end + + it "doesn't recover old orders after checkout, a new empty one is created" do + last_cart = create(:order, user: user, created_by: user, state: "cart", completed_at: nil) + last_cart.line_items << create(:line_item) + + just_completed_order = create( + :order, + user: user, + created_by: user, + state: "complete", + completed_at: Time.zone.now, + created_at: 1.week.ago + ) + expect(just_completed_order.completed_at).to be_present + session[:order_id] = just_completed_order.id + + allow(controller).to receive(:spree_current_user).and_return(user) + + expect { + get :index + }.to change { Spree::Order.count }.by(1) + + expect(session[:order_id]).to_not eq just_completed_order.id + expect(session[:order_id]).to_not eq last_cart.id + expect(controller.current_order.line_items.count).to eq 0 + end + end + it "redirects to home with message if order cycle is expired" do expect(controller).to receive(:current_order_cycle).and_return(oc).twice expect(controller).to receive(:current_order).and_return(order).twice diff --git a/spec/controllers/checkout_controller_concurrency_spec.rb b/spec/controllers/checkout_controller_concurrency_spec.rb index 51eefe98ae..266f9a4fbe 100644 --- a/spec/controllers/checkout_controller_concurrency_spec.rb +++ b/spec/controllers/checkout_controller_concurrency_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # This is the first example of testing concurrency in the Open Food Network. @@ -15,6 +17,20 @@ describe CheckoutController, concurrency: true, type: :controller do let(:payment_method) { create(:payment_method, distributors: [distributor]) } let(:breakpoint) { Mutex.new } + let(:address_params) { address.attributes.except("id") } + let(:order_params) { + { + "payments_attributes" => [ + { + "payment_method_id" => payment_method.id, + "amount" => order.total + } + ], + "bill_address_attributes" => address_params, + "ship_address_attributes" => address_params, + } + } + before do # Create a valid order ready for checkout: create(:shipping_method, distributors: [distributor]) @@ -26,7 +42,9 @@ describe CheckoutController, concurrency: true, type: :controller do allow(controller).to receive(:spree_current_user).and_return(order.user) allow(controller).to receive(:current_distributor).and_return(order.distributor) allow(controller).to receive(:current_order_cycle).and_return(order.order_cycle) + end + it "handles two concurrent orders successfully" do # New threads start running straight away. The breakpoint is after loading # the order and before advancing the order's state and making payments. breakpoint.lock @@ -36,21 +54,6 @@ describe CheckoutController, concurrency: true, type: :controller do # I did not find out how to call the original code otherwise. ActiveSupport::Notifications.instrument("spree.checkout.update") end - end - - it "waits for concurrent checkouts" do - # Basic data the user submits during checkout: - address_params = address.attributes.except("id") - order_params = { - "payments_attributes" => [ - { - "payment_method_id" => payment_method.id, - "amount" => order.total - } - ], - "bill_address_attributes" => address_params, - "ship_address_attributes" => address_params, - } # Starting two checkout threads. The controller code will determine if # these two threads are synchronised correctly or run into a race condition. diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index ecb18971db..0d285dab08 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -67,10 +67,31 @@ describe CheckoutController, type: :controller do allow(order).to receive_message_chain(:insufficient_stock_lines, :empty?).and_return true end - it "does not redirect" do - expect(order_cycle_distributed_variants).to receive(:distributes_order_variants?).with(order).and_return(true) - get :edit - expect(response).to be_success + describe "order variants are distributed in the OC" do + before do + expect(order_cycle_distributed_variants).to receive(:distributes_order_variants?).with(order).and_return(true) + end + + it "does not redirect" do + get :edit + expect(response).to be_success + end + + it "returns a specific flash message when Spree::Core::GatewayError occurs" do + order_checkout_restart = double(:order_checkout_restart) + allow(OrderCheckoutRestart).to receive(:new) { order_checkout_restart } + call_count = 0 + allow(order_checkout_restart).to receive(:call) do + call_count += 1 + raise Spree::Core::GatewayError.new("Gateway blow up") if call_count == 1 + end + + spree_post :edit + + expect(response.status).to eq(200) + flash_message = I18n.t(:spree_gateway_error_flash_for_checkout, error: "Gateway blow up") + expect(flash[:error]).to eq flash_message + end end describe "when the order is in payment state and a stripe payment intent is provided" do @@ -230,6 +251,15 @@ describe CheckoutController, type: :controller do expect(response.body).to eq({ errors: {}, flash: { error: I18n.t("checkout.failed") } }.to_json) end + it "returns a specific error on Spree::Core::GatewayError" do + allow(order).to receive(:update).and_raise(Spree::Core::GatewayError.new("Gateway blow up")) + spree_post :update, format: :json, order: {} + + expect(response.status).to eq(400) + flash_message = I18n.t(:spree_gateway_error_flash_for_checkout, error: "Gateway blow up") + expect(json_response["flash"]["error"]).to eq flash_message + end + describe "stale object handling" do it "retries when a stale object error is encountered" do allow(OrderCompletionReset).to receive(:new).with(controller, order) { reset_order_service } @@ -298,7 +328,7 @@ describe CheckoutController, type: :controller do end end - describe "#update_failed" do + describe "#action_failed" do let(:restart_checkout) { instance_double(OrderCheckoutRestart, call: true) } before do @@ -312,7 +342,7 @@ describe CheckoutController, type: :controller do expect(restart_checkout).to receive(:call) expect(controller).to receive(:respond_to) - controller.send(:update_failed) + controller.send(:action_failed) end end end diff --git a/spec/controllers/registration_controller_spec.rb b/spec/controllers/registration_controller_spec.rb index 31a1a91116..ea5f73c590 100644 --- a/spec/controllers/registration_controller_spec.rb +++ b/spec/controllers/registration_controller_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe RegistrationController, type: :controller do - include AuthenticationWorkflow describe "redirecting when user not logged in" do it "index" do get :index @@ -10,7 +9,7 @@ describe RegistrationController, type: :controller do end describe "redirecting when user has reached enterprise ownership limit" do - let!(:user) { create_enterprise_user( enterprise_limit: 1 ) } + let!(:user) { create(:user, enterprise_limit: 1 ) } let!(:enterprise) { create(:distributor_enterprise, owner: user) } before do @@ -24,7 +23,7 @@ describe RegistrationController, type: :controller do end describe "loading data when user is logged in" do - let!(:user) { create_enterprise_user } + let!(:user) { create(:user) } before do allow(controller).to receive_messages spree_current_user: user diff --git a/spec/controllers/spree/admin/adjustments_controller_spec.rb b/spec/controllers/spree/admin/adjustments_controller_spec.rb index 4ad02b73c7..7691bd6e72 100644 --- a/spec/controllers/spree/admin/adjustments_controller_spec.rb +++ b/spec/controllers/spree/admin/adjustments_controller_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' module Spree describe Admin::AdjustmentsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper - before { login_as_admin } + before { controller_login_as_admin } describe "setting included tax" do let(:order) { create(:order) } diff --git a/spec/controllers/spree/admin/countries_controller_spec.rb b/spec/controllers/spree/admin/countries_controller_spec.rb index 4146a506de..87a9356f1e 100644 --- a/spec/controllers/spree/admin/countries_controller_spec.rb +++ b/spec/controllers/spree/admin/countries_controller_spec.rb @@ -5,10 +5,10 @@ require 'spec_helper' module Spree module Admin describe CountriesController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "#update" do - before { login_as_admin } + before { controller_login_as_admin } it "updates the name of an existing country" do country = create(:country) diff --git a/spec/controllers/spree/admin/image_settings_controller_spec.rb b/spec/controllers/spree/admin/image_settings_controller_spec.rb index 89ccac822c..20bdd9dae0 100644 --- a/spec/controllers/spree/admin/image_settings_controller_spec.rb +++ b/spec/controllers/spree/admin/image_settings_controller_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Spree::Admin::ImageSettingsController do - include AuthenticationWorkflow + include AuthenticationHelper - before { login_as_admin } + before { controller_login_as_admin } context "updating image settings" do it "should be able to update paperclip settings" do diff --git a/spec/controllers/spree/admin/mail_methods_controller_spec.rb b/spec/controllers/spree/admin/mail_methods_controller_spec.rb index 422491660e..f7aa10959b 100644 --- a/spec/controllers/spree/admin/mail_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/mail_methods_controller_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Spree::Admin::MailMethodsController do - include AuthenticationWorkflow + include AuthenticationHelper - before { login_as_admin } + before { controller_login_as_admin } context "#update" do it "should reinitialize the mail settings" do @@ -18,8 +18,10 @@ describe Spree::Admin::MailMethodsController do spree_api_key: 'fake', id: nil, owned_groups: nil) - allow(user).to receive_messages(enterprises: [create(:enterprise)], has_spree_role?: true) - allow(controller).to receive_messages(try_spree_current_user: user) + allow(user).to receive_messages(enterprises: [create(:enterprise)], + has_spree_role?: true, + locale: nil) + allow(controller).to receive_messages(spree_current_user: user) Spree::Config[:enable_mail_delivery] = "1" ActionMailer::Base.perform_deliveries = true diff --git a/spec/controllers/spree/admin/orders/customer_details_controller_spec.rb b/spec/controllers/spree/admin/orders/customer_details_controller_spec.rb index c62d0a0f9c..bc0c135505 100644 --- a/spec/controllers/spree/admin/orders/customer_details_controller_spec.rb +++ b/spec/controllers/spree/admin/orders/customer_details_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Spree::Admin::Orders::CustomerDetailsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "#update" do context "adding customer details via newly created admin order" do @@ -37,7 +37,7 @@ describe Spree::Admin::Orders::CustomerDetailsController, type: :controller do } before do - login_as_enterprise_user [order.distributor] + controller_login_as_enterprise_user [order.distributor] end it "advances the order state" do diff --git a/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb b/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb index 6932efa236..8e78be69d8 100644 --- a/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb +++ b/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Spree::Admin::PaymentsController, type: :controller do @@ -10,7 +12,7 @@ describe Spree::Admin::PaymentsController, type: :controller do allow(controller).to receive(:spree_current_user) { user } end - context "#create" do + describe "#create" do let!(:payment_method) { create(:payment_method, distributors: [shop]) } let(:params) { { amount: order.total, payment_method_id: payment_method.id } } @@ -138,4 +140,92 @@ describe Spree::Admin::PaymentsController, type: :controller do end end end + + describe '#fire' do + let(:payment_method) do + create( + :stripe_sca_payment_method, + distributor_ids: [create(:distributor_enterprise).id], + preferred_enterprise_id: create(:enterprise).id + ) + end + let(:order) { create(:order, state: 'complete') } + let(:payment) do + create(:payment, order: order, payment_method: payment_method, amount: order.total) + end + + let(:successful_response) { ActiveMerchant::Billing::Response.new(true, "Yay!") } + + context 'on credit event' do + let(:params) { { e: 'credit', order_id: order.number, id: payment.id } } + + before do + allow(request).to receive(:referer) { 'http://foo.com' } + allow(Spree::Payment).to receive(:find).with(payment.id.to_s) { payment } + end + + it 'handles gateway errors' do + allow(payment.payment_method) + .to receive(:credit).and_raise(Spree::Core::GatewayError, 'error message') + + spree_put :fire, params + + expect(flash[:error]).to eq('error message') + expect(response).to redirect_to('http://foo.com') + end + + it 'handles validation errors' do + allow(payment).to receive(:credit!).and_raise(StandardError, 'validation error') + + spree_put :fire, params + + expect(flash[:error]).to eq('validation error') + expect(response).to redirect_to('http://foo.com') + end + + it 'displays a success message and redirects to the referer' do + allow(payment_method).to receive(:credit) { successful_response } + + spree_put :fire, params + + expect(flash[:success]).to eq(I18n.t(:payment_updated)) + end + end + + context 'on refund event' do + let(:params) { { e: 'refund', order_id: order.number, id: payment.id } } + + before do + allow(request).to receive(:referer) { 'http://foo.com' } + allow(Spree::Payment).to receive(:find).with(payment.id.to_s) { payment } + end + + it 'handles gateway errors' do + allow(payment.payment_method) + .to receive(:refund).and_raise(Spree::Core::GatewayError, 'error message') + + spree_put :fire, params + + expect(flash[:error]).to eq('error message') + expect(response).to redirect_to('http://foo.com') + end + + it 'handles validation errors' do + allow(payment).to receive(:refund!).and_raise(StandardError, 'validation error') + + spree_put :fire, params + + expect(flash[:error]).to eq('validation error') + expect(response).to redirect_to('http://foo.com') + end + + it 'displays a success message and redirects to the referer' do + allow(payment_method).to receive(:refund) { successful_response } + + spree_put :fire, params + + expect(flash[:success]).to eq(I18n.t(:payment_updated)) + end + end + end end diff --git a/spec/controllers/spree/admin/orders_controller_spec.rb b/spec/controllers/spree/admin/orders_controller_spec.rb index 8ab20c385a..0d10068f1e 100644 --- a/spec/controllers/spree/admin/orders_controller_spec.rb +++ b/spec/controllers/spree/admin/orders_controller_spec.rb @@ -1,13 +1,12 @@ require 'spec_helper' describe Spree::Admin::OrdersController, type: :controller do - include AuthenticationWorkflow include OpenFoodNetwork::EmailHelper describe "#edit" do let!(:order) { create(:order_with_totals_and_distribution, ship_address: create(:address)) } - before { login_as_admin } + before { controller_login_as_admin } it "advances the order state" do expect { @@ -41,7 +40,7 @@ describe Spree::Admin::OrdersController, type: :controller do order_cycle_id: order.order_cycle_id } } end - before { login_as_admin } + before { controller_login_as_admin } context "complete order" do let(:order) { create :completed_order_with_totals } @@ -109,11 +108,11 @@ describe Spree::Admin::OrdersController, type: :controller do describe "#index" do context "as a regular user" do - before { allow(controller).to receive(:spree_current_user) { create_enterprise_user } } + before { allow(controller).to receive(:spree_current_user) { create(:user) } } it "should deny me access to the index action" do spree_get :index - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -140,7 +139,7 @@ describe Spree::Admin::OrdersController, type: :controller do it "should prevent me from sending order invoices" do spree_get :invoice, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -150,7 +149,7 @@ describe Spree::Admin::OrdersController, type: :controller do it "should prevent me from sending order invoices" do spree_get :invoice, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -198,7 +197,7 @@ describe Spree::Admin::OrdersController, type: :controller do it "should prevent me from sending order invoices" do spree_get :print, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -207,7 +206,7 @@ describe Spree::Admin::OrdersController, type: :controller do before { allow(controller).to receive(:spree_current_user) { user } } it "should prevent me from sending order invoices" do spree_get :print, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/spree/admin/overview_controller_spec.rb b/spec/controllers/spree/admin/overview_controller_spec.rb index e445932555..3c610b62cc 100644 --- a/spec/controllers/spree/admin/overview_controller_spec.rb +++ b/spec/controllers/spree/admin/overview_controller_spec.rb @@ -1,15 +1,13 @@ require 'spec_helper' describe Spree::Admin::OverviewController, type: :controller do - include AuthenticationWorkflow - describe "#index" do before do allow(controller).to receive(:spree_current_user).and_return(user) end context "when user owns only one enterprise" do - let(:user) { create_enterprise_user } + let(:user) { create(:user) } let!(:enterprise) { create(:distributor_enterprise, owner: user) } context "when the referer is not an admin page" do @@ -48,7 +46,7 @@ describe Spree::Admin::OverviewController, type: :controller do end context "when user owns multiple enterprises" do - let(:user) { create_enterprise_user(enterprise_limit: 2) } + let(:user) { create(:user) } let!(:enterprise1) { create(:distributor_enterprise, owner: user) } before { create(:distributor_enterprise, owner: user) } diff --git a/spec/controllers/spree/admin/payment_methods_controller_spec.rb b/spec/controllers/spree/admin/payment_methods_controller_spec.rb index dfc7dd307e..3e752170c7 100644 --- a/spec/controllers/spree/admin/payment_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/payment_methods_controller_spec.rb @@ -39,6 +39,20 @@ module Spree expect(response).to redirect_to spree.edit_admin_payment_method_path(assigns(:payment_method)) end + it "can save Pin Payment payment method details" do + expect { + spree_post :create, payment_method: { + name: "Test Method", type: "Spree::Gateway::Pin", distributor_ids: [enterprise.id], + preferred_server: "test", preferred_api_key: "apikey123", preferred_test_mode: "1" + } + }.to change(Spree::PaymentMethod, :count).by(1) + + payment_method = Spree::PaymentMethod.last + expect(payment_method.preferences[:server]).to eq "test" + expect(payment_method.preferences[:api_key]).to eq "apikey123" + expect(payment_method.preferences[:test_mode]).to eq true + end + it "can not create a payment method of an invalid type" do expect { spree_post :create, payment_method: { name: "Invalid Payment Method", type: "Spree::InvalidType", distributor_ids: [enterprise.id] } diff --git a/spec/controllers/spree/admin/products_controller_spec.rb b/spec/controllers/spree/admin/products_controller_spec.rb index e8ae658e9e..b33198d14c 100644 --- a/spec/controllers/spree/admin/products_controller_spec.rb +++ b/spec/controllers/spree/admin/products_controller_spec.rb @@ -10,13 +10,13 @@ describe Spree::Admin::ProductsController, type: :controller do end before do - login_as_enterprise_user [s_managed] + controller_login_as_enterprise_user [s_managed] spree_post :bulk_update, "products" => [{ "id" => product.id, "name" => "Pine nuts" }] end it "denies access" do - expect(response).to redirect_to spree.unauthorized_url + expect(response).to redirect_to unauthorized_path end it "does not update any product" do @@ -38,7 +38,7 @@ describe Spree::Admin::ProductsController, type: :controller do ) end - before { login_as_enterprise_user([producer]) } + before { controller_login_as_enterprise_user([producer]) } it 'fails' do spree_post :bulk_update, @@ -92,7 +92,7 @@ describe Spree::Admin::ProductsController, type: :controller do ) end - before { login_as_enterprise_user([producer]) } + before { controller_login_as_enterprise_user([producer]) } it 'does not fail' do spree_post :bulk_update, @@ -134,7 +134,7 @@ describe Spree::Admin::ProductsController, type: :controller do } before do - login_as_admin + controller_login_as_admin create(:stock_location) end @@ -174,7 +174,7 @@ describe Spree::Admin::ProductsController, type: :controller do let!(:product) { create(:simple_product, supplier: producer) } before do - login_as_enterprise_user [producer] + controller_login_as_enterprise_user [producer] end describe "change product supplier" do diff --git a/spec/controllers/spree/admin/reports_controller_spec.rb b/spec/controllers/spree/admin/reports_controller_spec.rb index 8cfda5fe36..9b72b5418f 100644 --- a/spec/controllers/spree/admin/reports_controller_spec.rb +++ b/spec/controllers/spree/admin/reports_controller_spec.rb @@ -65,7 +65,7 @@ describe Spree::Admin::ReportsController, type: :controller do context "Coordinator Enterprise User" do let!(:present_objects) { [orderA1, orderA2, orderB1, orderB2] } - before { login_as_enterprise_user [coordinator1] } + before { controller_login_as_enterprise_user [coordinator1] } describe 'Orders & Fulfillment' do it "shows all orders in order cycles I coordinate" do @@ -79,7 +79,7 @@ describe Spree::Admin::ReportsController, type: :controller do # As a Distributor Enterprise user for distributor1 context "Distributor Enterprise User" do - before { login_as_enterprise_user [distributor1] } + before { controller_login_as_enterprise_user [distributor1] } describe 'Orders and Distributors' do let!(:present_objects) { [orderA1, orderA2, orderB1, orderB2] } @@ -132,7 +132,7 @@ describe Spree::Admin::ReportsController, type: :controller do # As a Supplier Enterprise user for supplier1 context "Supplier" do - before { login_as_enterprise_user [supplier1] } + before { controller_login_as_enterprise_user [supplier1] } describe 'index' do it "loads reports relevant to producers" do @@ -191,7 +191,7 @@ describe Spree::Admin::ReportsController, type: :controller do end context "Products & Inventory" do - before { login_as_admin } + before { controller_login_as_admin } context "with distributors and suppliers" do let(:distributors) { [coordinator1, distributor1, distributor2] } @@ -235,7 +235,7 @@ describe Spree::Admin::ReportsController, type: :controller do end context "My Customers" do - before { login_as_admin } + before { controller_login_as_admin } it "should have report types for customers" do expect(subject.report_types[:customers]).to eq([ @@ -286,7 +286,7 @@ describe Spree::Admin::ReportsController, type: :controller do end context "Admin" do - before { login_as_admin } + before { controller_login_as_admin } describe "users_and_enterprises" do let!(:present_objects) { [coordinator1] } diff --git a/spec/controllers/spree/admin/return_authorizations_controller_spec.rb b/spec/controllers/spree/admin/return_authorizations_controller_spec.rb index 6c28642da5..4cc170872b 100644 --- a/spec/controllers/spree/admin/return_authorizations_controller_spec.rb +++ b/spec/controllers/spree/admin/return_authorizations_controller_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' module Spree module Admin describe ReturnAuthorizationsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper let(:order) do create(:order, :with_line_item, :completed, @@ -13,7 +13,7 @@ module Spree end before do - login_as_admin + controller_login_as_admin # Pay the order order.payments.first.complete diff --git a/spec/controllers/spree/admin/search_controller_spec.rb b/spec/controllers/spree/admin/search_controller_spec.rb index 48fffbabcd..a6f8623b30 100644 --- a/spec/controllers/spree/admin/search_controller_spec.rb +++ b/spec/controllers/spree/admin/search_controller_spec.rb @@ -1,13 +1,12 @@ require 'spec_helper' describe Spree::Admin::SearchController, type: :controller do - include AuthenticationWorkflow context "Distributor Enterprise User" do - let!(:owner) { create_enterprise_user( email: "test1@email.com" ) } - let!(:manager) { create_enterprise_user( email: "test2@email.com" ) } - let!(:random) { create_enterprise_user( email: "test3@email.com" ) } + let!(:owner) { create(:user, email: "test1@email.com" ) } + let!(:manager) { create(:user, email: "test2@email.com" ) } + let!(:random) { create(:user, email: "test3@email.com" ) } let!(:enterprise) { create(:enterprise, owner: owner, users: [owner, manager]) } - before { login_as_enterprise_user [enterprise] } + before { controller_login_as_enterprise_user [enterprise] } describe 'searching for known users' do describe "when search query is not an exact match" do diff --git a/spec/controllers/spree/admin/shipping_categories_controller_spec.rb b/spec/controllers/spree/admin/shipping_categories_controller_spec.rb index 531b175072..05aefff048 100644 --- a/spec/controllers/spree/admin/shipping_categories_controller_spec.rb +++ b/spec/controllers/spree/admin/shipping_categories_controller_spec.rb @@ -5,10 +5,10 @@ require 'spec_helper' module Spree module Admin describe ShippingCategoriesController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "#create and #update" do - before { login_as_admin } + before { controller_login_as_admin } it "creates a shipping shipping category" do expect { diff --git a/spec/controllers/spree/admin/shipping_methods_controller_spec.rb b/spec/controllers/spree/admin/shipping_methods_controller_spec.rb index 105d55563c..f209e87a81 100644 --- a/spec/controllers/spree/admin/shipping_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/shipping_methods_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Spree::Admin::ShippingMethodsController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "#update" do let(:shipping_method) { create(:shipping_method) } @@ -16,7 +16,7 @@ describe Spree::Admin::ShippingMethodsController, type: :controller do } } - before { login_as_admin } + before { controller_login_as_admin } it "updates preferred_amount and preferred_currency of a FlatRate calculator" do shipping_method.calculator = create(:calculator_flat_rate, calculable: shipping_method) @@ -81,7 +81,7 @@ describe Spree::Admin::ShippingMethodsController, type: :controller do let(:shipping_method) { create(:shipping_method) } scenario "is soft deleted" do - login_as_admin + controller_login_as_admin expect(shipping_method.deleted_at).to be_nil spree_delete :destroy, "id" => shipping_method.id @@ -94,7 +94,7 @@ describe Spree::Admin::ShippingMethodsController, type: :controller do let(:order) { create(:order_with_line_items) } scenario "is not soft deleted" do - login_as_admin + controller_login_as_admin expect(order.shipping_method.deleted_at).to be_nil spree_delete :destroy, "id" => order.shipping_method.id diff --git a/spec/controllers/spree/admin/variants_controller_spec.rb b/spec/controllers/spree/admin/variants_controller_spec.rb index 7163f6f423..9af2be952a 100644 --- a/spec/controllers/spree/admin/variants_controller_spec.rb +++ b/spec/controllers/spree/admin/variants_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' module Spree module Admin describe VariantsController, type: :controller do - before { login_as_admin } + before { controller_login_as_admin } describe "#index" do describe "deleted variants" do diff --git a/spec/controllers/spree/credit_cards_controller_spec.rb b/spec/controllers/spree/credit_cards_controller_spec.rb index e8996433f3..fd15916f0f 100644 --- a/spec/controllers/spree/credit_cards_controller_spec.rb +++ b/spec/controllers/spree/credit_cards_controller_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' -require 'support/request/authentication_workflow' describe Spree::CreditCardsController, type: :controller do - include AuthenticationWorkflow - let(:user) { create_enterprise_user } + let(:user) { create(:user) } let(:token) { "tok_234bd2c22" } before do @@ -88,7 +86,7 @@ describe Spree::CreditCardsController, type: :controller do context "but the card is not owned by the user" do it "redirects to unauthorized" do spree_put :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -135,7 +133,7 @@ describe Spree::CreditCardsController, type: :controller do context "but the card is not owned by the user" do it "redirects to unauthorized" do spree_delete :destroy, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb index cee76bdc39..1f74a3915f 100644 --- a/spec/controllers/spree/orders_controller_spec.rb +++ b/spec/controllers/spree/orders_controller_spec.rb @@ -58,7 +58,7 @@ describe Spree::OrdersController, type: :controller do it "redirects to unauthorized" do spree_get :show, id: order.number - expect(response.status).to eq(401) + expect(response).to redirect_to unauthorized_path end end @@ -415,9 +415,11 @@ describe Spree::OrdersController, type: :controller do let(:params) { { id: order.number } } context "when the user does not have permission to cancel the order" do + before { allow(controller).to receive(:spree_current_user) { create(:user) } } + it "responds with unauthorized" do spree_put :cancel, params - expect(response).to render_template 'shared/unauthorized' + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/spree/store_controller_spec.rb b/spec/controllers/spree/store_controller_spec.rb deleted file mode 100644 index b04ac0167e..0000000000 --- a/spec/controllers/spree/store_controller_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'spec_helper' - -describe Spree::StoreController, type: :controller do - controller(Spree::StoreController) do - before_filter :unauthorized - def index - render text: "" - end - end - it "redirects to home when unauthorized" do - get :index - expect(response).to render_template("shared/unauthorized", layout: 'darkswarm') - end -end diff --git a/spec/controllers/spree/user_sessions_controller_spec.rb b/spec/controllers/spree/user_sessions_controller_spec.rb index 60cbbb7d03..d5bcff290c 100644 --- a/spec/controllers/spree/user_sessions_controller_spec.rb +++ b/spec/controllers/spree/user_sessions_controller_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' describe Spree::UserSessionsController, type: :controller do - include AuthenticationWorkflow - - let(:user) { create_enterprise_user } + let(:user) { create(:user) } before do @request.env["devise.mapping"] = Devise.mappings[:spree_user] diff --git a/spec/controllers/spree/users_controller_spec.rb b/spec/controllers/spree/users_controller_spec.rb index 50ac3ebf6f..5210c1717a 100644 --- a/spec/controllers/spree/users_controller_spec.rb +++ b/spec/controllers/spree/users_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Spree::UsersController, type: :controller do - include AuthenticationWorkflow + include AuthenticationHelper describe "show" do let!(:u1) { create(:user) } diff --git a/spec/controllers/stripe/callbacks_controller_spec.rb b/spec/controllers/stripe/callbacks_controller_spec.rb index 33f7bd5b76..50c5433767 100644 --- a/spec/controllers/stripe/callbacks_controller_spec.rb +++ b/spec/controllers/stripe/callbacks_controller_spec.rb @@ -30,7 +30,7 @@ describe Stripe::CallbacksController, type: :controller do it "redirects to unauthorized" do spree_get :index, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/user_confirmations_controller_spec.rb b/spec/controllers/user_confirmations_controller_spec.rb index 9920330161..82ec5c2cc3 100644 --- a/spec/controllers/user_confirmations_controller_spec.rb +++ b/spec/controllers/user_confirmations_controller_spec.rb @@ -1,17 +1,16 @@ require 'spec_helper' describe UserConfirmationsController, type: :controller do - include AuthenticationWorkflow include OpenFoodNetwork::EmailHelper - let!(:user) { create_enterprise_user } - let!(:confirmed_user) { create_enterprise_user(confirmed_at: nil) } - let!(:unconfirmed_user) { create_enterprise_user(confirmed_at: nil) } + let!(:user) { create(:user) } + let!(:confirmed_user) { create(:user, confirmed_at: nil) } + let!(:unconfirmed_user) { create(:user, confirmed_at: nil) } let!(:confirmed_token) { confirmed_user.confirmation_token } before do @request.env["devise.mapping"] = Devise.mappings[:spree_user] - confirmed_user.confirm! + confirmed_user.confirm end context "confirming a user" do @@ -52,7 +51,8 @@ describe UserConfirmationsController, type: :controller do unconfirmed_user.reset_password_token = Devise.friendly_token unconfirmed_user.save! spree_get :show, confirmation_token: unconfirmed_user.confirmation_token - expect(response).to redirect_to spree.edit_spree_user_password_path(reset_password_token: unconfirmed_user.reset_password_token) + expect(response).to be_redirect + expect(response.body).to include spree.edit_spree_user_password_path end end end diff --git a/spec/factories.rb b/spec/factories.rb index ad3c804c92..455fc9b9a4 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -15,6 +15,7 @@ require 'spree/testing_support/factories' # * order_with_inventory_unit_shipped # * completed_order_with_totals # + FactoryBot.define do factory :classification, class: Spree::Classification do end diff --git a/spec/features/admin/adjustments_spec.rb b/spec/features/admin/adjustments_spec.rb index fcd0a0bb39..5911e602c5 100644 --- a/spec/features/admin/adjustments_spec.rb +++ b/spec/features/admin/adjustments_spec.rb @@ -4,7 +4,7 @@ feature ' As an administrator I want to manage adjustments on orders ', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let!(:user) { create(:user) } @@ -21,8 +21,7 @@ feature ' scenario "adding taxed adjustments to an order" do # When I go to the adjustments page for the order - login_to_admin_section - visit spree.admin_orders_path + login_as_admin_and_visit spree.admin_orders_path page.find('td.actions a.icon-edit').click click_link 'Adjustments' @@ -44,8 +43,7 @@ feature ' adjustment = create(:adjustment, label: "Extra Adjustment", adjustable: order, amount: 110, included_tax: 10) # When I go to the adjustments page for the order - login_to_admin_section - visit spree.admin_orders_path + login_as_admin_and_visit spree.admin_orders_path page.find('td.actions a.icon-edit').click click_link 'Adjustments' page.find('tr', text: 'Extra Adjustment').find('a.icon-edit').click @@ -68,8 +66,7 @@ feature ' adjustment = create(:adjustment, label: "Extra Adjustment", adjustable: order, amount: 110, included_tax: 0) # When I go to the adjustments page for the order - login_to_admin_section - visit spree.admin_orders_path + login_as_admin_and_visit spree.admin_orders_path page.find('td.actions a.icon-edit').click click_link 'Adjustments' page.find('tr', text: 'Extra Adjustment').find('a.icon-edit').click diff --git a/spec/features/admin/authentication_spec.rb b/spec/features/admin/authentication_spec.rb index 6ff46d15a4..f9401ad192 100644 --- a/spec/features/admin/authentication_spec.rb +++ b/spec/features/admin/authentication_spec.rb @@ -2,24 +2,21 @@ require 'spec_helper' feature "Authentication", js: true do include UIComponentHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let(:user) { create(:user, password: "password", password_confirmation: "password") } let!(:enterprise) { create(:enterprise, owner: user) } # Required for access to admin scenario "logging into admin redirects home, then back to admin" do - # This is the first admin spec, so give a little extra load time for slow systems - Capybara.using_wait_time(120) do - visit spree.admin_dashboard_path + visit spree.admin_dashboard_path - fill_in "Email", with: user.email - fill_in "Password", with: user.password - click_login_button - expect(page).to have_content "DASHBOARD" - expect(page).to have_current_path spree.admin_dashboard_path - expect(page).to have_no_content "CONFIGURATION" - end + fill_in "Email", with: user.email + fill_in "Password", with: user.password + click_login_button + expect(page).to have_content "DASHBOARD" + expect(page).to have_current_path spree.admin_dashboard_path + expect(page).to have_no_content "CONFIGURATION" end scenario "viewing my account" do diff --git a/spec/features/admin/bulk_order_management_spec.rb b/spec/features/admin/bulk_order_management_spec.rb index a92afed022..efe3a3ed7e 100644 --- a/spec/features/admin/bulk_order_management_spec.rb +++ b/spec/features/admin/bulk_order_management_spec.rb @@ -5,12 +5,12 @@ feature ' I want to be able to manage orders in bulk ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper context "listing orders" do before :each do - quick_login_as_admin + login_as_admin end it "displays a message when number of line items is zero" do @@ -121,7 +121,7 @@ feature ' context "altering line item properties" do before :each do - quick_login_as_admin + login_as_admin end context "tracking changes" do @@ -177,7 +177,7 @@ feature ' context "using page controls" do before :each do - quick_login_as_admin + login_as_admin end let!(:p1) { create(:product_with_option_types, group_buy: true, group_buy_unit_size: 5000, variant_unit: "weight", variants: [create(:variant, unit_value: 1000)] ) } @@ -719,11 +719,11 @@ feature ' let!(:line_item_not_distributed) { create(:line_item_with_shipment, order: o2, product: create(:product, supplier: s1) ) } before(:each) do - @enterprise_user = create_enterprise_user + @enterprise_user = create(:user) @enterprise_user.enterprise_roles.build(enterprise: s1).save @enterprise_user.enterprise_roles.build(enterprise: d1).save - quick_login_as @enterprise_user + login_as @enterprise_user end it "displays a Bulk Management Tab under the Orders item" do diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index c0b55ed224..553e2182aa 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -5,12 +5,12 @@ feature ' I want to be able to manage products in bulk ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper describe "listing products" do before do - quick_login_as_admin + login_as_admin end it "displays a list of products" do @@ -101,7 +101,7 @@ feature ' describe "listing variants" do before do - quick_login_as_admin + login_as_admin end it "displays a list of variants for each product" do @@ -176,8 +176,7 @@ feature ' shipping_category = create(:shipping_category) taxon = create(:taxon) - quick_login_as_admin - visit spree.admin_products_path + login_as_admin_and_visit spree.admin_products_path find("a", text: "NEW PRODUCT").click expect(page).to have_content 'NEW PRODUCT' @@ -199,7 +198,7 @@ feature ' scenario "creating new variants" do # Given a product without variants or a unit p = FactoryBot.create(:product, variant_unit: 'weight', variant_unit_scale: 1000) - quick_login_as_admin + login_as_admin visit spree.admin_products_path # I should see an add variant button @@ -250,7 +249,7 @@ feature ' t2 = FactoryBot.create(:taxon) p = FactoryBot.create(:product, supplier: s1, available_on: Date.current, variant_unit: 'volume', variant_unit_scale: 1, primary_taxon: t2, sku: "OLD SKU") - quick_login_as_admin + login_as_admin visit spree.admin_products_path toggle_columns "Available On", /^Category?/, "Inherits Properties?", "SKU" @@ -290,7 +289,7 @@ feature ' scenario "updating a product with a variant unit of 'items'" do p = FactoryBot.create(:product, variant_unit: 'weight', variant_unit_scale: 1000) - quick_login_as_admin + login_as_admin visit spree.admin_products_path expect(page).to have_select "variant_unit_with_scale", selected: "Weight (kg)" @@ -317,7 +316,7 @@ feature ' v.update_attribute(:on_demand, false) v.update_attribute(:on_hand, 9) - quick_login_as_admin + login_as_admin visit spree.admin_products_path expect(page).to have_selector "a.view-variants", count: 1 find("a.view-variants").click @@ -353,7 +352,7 @@ feature ' p = FactoryBot.create(:product) v = FactoryBot.create(:variant, product: p, price: 3.0) - quick_login_as_admin + login_as_admin visit spree.admin_products_path expect(page).to have_selector "a.view-variants", count: 1 find("a.view-variants").click @@ -376,7 +375,7 @@ feature ' scenario "updating a product mutiple times without refresh" do p = FactoryBot.create(:product, name: 'original name') - quick_login_as_admin + login_as_admin visit spree.admin_products_path @@ -409,7 +408,7 @@ feature ' scenario "updating a product after cloning a product" do p = FactoryBot.create(:product, name: "product 1") - quick_login_as_admin + login_as_admin visit spree.admin_products_path @@ -435,7 +434,7 @@ feature ' s2 = create(:supplier_enterprise) p1 = FactoryBot.create(:simple_product, name: "product1", supplier: s1) p2 = FactoryBot.create(:simple_product, name: "product2", supplier: s2) - quick_login_as_admin + login_as_admin visit spree.admin_products_path @@ -463,7 +462,7 @@ feature ' let!(:v3) { FactoryBot.create(:variant, product: p2 ) } before do - quick_login_as_admin + login_as_admin visit spree.admin_products_path end @@ -512,8 +511,7 @@ feature ' let!(:v2) { p2.variants.first } before do - quick_login_as_admin - visit spree.admin_products_path + login_as_admin_and_visit spree.admin_products_path end it "shows an edit button for products, which takes the user to the standard edit page for that product in a new window" do @@ -555,9 +553,8 @@ feature ' p1 = FactoryBot.create(:product, name: "P1") p2 = FactoryBot.create(:product, name: "P2") p3 = FactoryBot.create(:product, name: "P3") - quick_login_as_admin - visit spree.admin_products_path + login_as_admin_and_visit spree.admin_products_path expect(page).to have_selector "a.clone-product", count: 3 @@ -581,9 +578,7 @@ feature ' describe "using column display dropdown" do it "shows a column display dropdown, which shows a list of columns when clicked" do FactoryBot.create(:simple_product) - quick_login_as_admin - - visit spree.admin_products_path + login_as_admin_and_visit spree.admin_products_path toggle_columns "Available On" @@ -609,9 +604,8 @@ feature ' s2 = create(:supplier_enterprise) p1 = FactoryBot.create(:simple_product, name: "product1", supplier: s1) p2 = FactoryBot.create(:simple_product, name: "product2", supplier: s2) - quick_login_as_admin - visit spree.admin_products_path + login_as_admin_and_visit spree.admin_products_path # Page shows the filter controls expect(page).to have_select "producer_filter", visible: false @@ -658,7 +652,7 @@ feature ' end before do - @enterprise_user = create_enterprise_user + @enterprise_user = create(:user) @enterprise_user.enterprise_roles.build(enterprise: supplier_managed1).save @enterprise_user.enterprise_roles.build(enterprise: supplier_managed2).save @enterprise_user.enterprise_roles.build(enterprise: distributor_managed).save @@ -762,8 +756,7 @@ feature ' let!(:product) { create(:simple_product, name: "Carrots") } it "displays product images and image upload modal" do - quick_login_as_admin - visit spree.admin_products_path + login_as_admin_and_visit spree.admin_products_path within "table#listing_products tr#p_#{product.id}" do # Displays product images diff --git a/spec/features/admin/configuration/general_settings_spec.rb b/spec/features/admin/configuration/general_settings_spec.rb index 4dcc8ab63a..e676f32801 100644 --- a/spec/features/admin/configuration/general_settings_spec.rb +++ b/spec/features/admin/configuration/general_settings_spec.rb @@ -1,11 +1,10 @@ require 'spec_helper' describe "General Settings" do - include AuthenticationWorkflow + include AuthenticationHelper before(:each) do - quick_login_as_admin - visit spree.admin_dashboard_path + login_as_admin_and_visit spree.admin_dashboard_path click_link "Configuration" click_link "General Settings" end diff --git a/spec/features/admin/configuration/image_settings_spec.rb b/spec/features/admin/configuration/image_settings_spec.rb index 858f53c677..5c87e8e6ad 100644 --- a/spec/features/admin/configuration/image_settings_spec.rb +++ b/spec/features/admin/configuration/image_settings_spec.rb @@ -1,11 +1,10 @@ require 'spec_helper' describe "image settings" do - include AuthenticationWorkflow + include AuthenticationHelper before do - quick_login_as_admin - visit spree.admin_dashboard_path + login_as_admin_and_visit spree.admin_dashboard_path click_link "Configuration" click_link "Image Settings" end diff --git a/spec/features/admin/configuration/mail_methods_spec.rb b/spec/features/admin/configuration/mail_methods_spec.rb index d1e550db02..27d044d894 100644 --- a/spec/features/admin/configuration/mail_methods_spec.rb +++ b/spec/features/admin/configuration/mail_methods_spec.rb @@ -1,12 +1,10 @@ require 'spec_helper' describe "Mail Methods" do - include AuthenticationWorkflow + include AuthenticationHelper before(:each) do - quick_login_as_admin - visit spree.admin_dashboard_path - click_link "Configuration" + login_as_admin_and_visit spree.edit_admin_general_settings_path end context "edit" do diff --git a/spec/features/admin/configuration/states_spec.rb b/spec/features/admin/configuration/states_spec.rb index b762b33c84..e3a761088d 100755 --- a/spec/features/admin/configuration/states_spec.rb +++ b/spec/features/admin/configuration/states_spec.rb @@ -1,12 +1,12 @@ require 'spec_helper' describe "States" do - include AuthenticationWorkflow + include AuthenticationHelper let!(:country) { create(:country) } before(:each) do - quick_login_as_admin + login_as_admin @hungary = Spree::Country.create!(name: "Hungary", iso_name: "Hungary") Spree::Config[:default_country_id] = country.id end diff --git a/spec/features/admin/configuration/tax_categories_spec.rb b/spec/features/admin/configuration/tax_categories_spec.rb index 4248ff2596..9e5d2f3823 100644 --- a/spec/features/admin/configuration/tax_categories_spec.rb +++ b/spec/features/admin/configuration/tax_categories_spec.rb @@ -1,12 +1,10 @@ require 'spec_helper' describe "Tax Categories" do - include AuthenticationWorkflow + include AuthenticationHelper before(:each) do - quick_login_as_admin - visit spree.admin_dashboard_path - click_link "Configuration" + login_as_admin_and_visit spree.edit_admin_general_settings_path end context "admin visiting tax categories list" do diff --git a/spec/features/admin/configuration/tax_rates_spec.rb b/spec/features/admin/configuration/tax_rates_spec.rb index c4d11716c2..56ff8fac73 100644 --- a/spec/features/admin/configuration/tax_rates_spec.rb +++ b/spec/features/admin/configuration/tax_rates_spec.rb @@ -1,15 +1,13 @@ require 'spec_helper' describe "Tax Rates" do - include AuthenticationWorkflow + include AuthenticationHelper let!(:calculator) { create(:calculator_per_item, calculable: create(:order)) } let!(:tax_rate) { create(:tax_rate, calculator: calculator) } before do - quick_login_as_admin - visit spree.admin_dashboard_path - click_link "Configuration" + login_as_admin_and_visit spree.edit_admin_general_settings_path end # Regression test for #535 diff --git a/spec/features/admin/configuration/taxonomies_spec.rb b/spec/features/admin/configuration/taxonomies_spec.rb index 6e871e3529..f26b320be3 100644 --- a/spec/features/admin/configuration/taxonomies_spec.rb +++ b/spec/features/admin/configuration/taxonomies_spec.rb @@ -1,12 +1,10 @@ require 'spec_helper' describe "Taxonomies" do - include AuthenticationWorkflow + include AuthenticationHelper before(:each) do - quick_login_as_admin - visit spree.admin_dashboard_path - click_link "Configuration" + login_as_admin_and_visit spree.edit_admin_general_settings_path end context "show" do diff --git a/spec/features/admin/configuration/zones_spec.rb b/spec/features/admin/configuration/zones_spec.rb index 11b3f92649..1c03ff0941 100644 --- a/spec/features/admin/configuration/zones_spec.rb +++ b/spec/features/admin/configuration/zones_spec.rb @@ -1,19 +1,18 @@ require 'spec_helper' describe "Zones" do - include AuthenticationWorkflow + include AuthenticationHelper before do - quick_login_as_admin + login_as_admin Spree::Zone.delete_all end scenario "list existing zones" do - visit spree.admin_dashboard_path - click_link "Configuration" - + visit spree.edit_admin_general_settings_path create(:zone, name: "eastern", description: "zone is eastern") create(:zone, name: "western", description: "cool san fran") + click_link "Zones" within_row(1) { expect(page).to have_content("eastern") } diff --git a/spec/features/admin/content_spec.rb b/spec/features/admin/content_spec.rb index 75dd4ad656..cdc4971839 100644 --- a/spec/features/admin/content_spec.rb +++ b/spec/features/admin/content_spec.rb @@ -4,12 +4,11 @@ feature ' As a site administrator I want to configure the site content ' do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper before do - login_to_admin_section - click_link 'Configuration' + login_as_admin_and_visit spree.edit_admin_general_settings_path click_link 'Content' end diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index a78e5b70e4..4674504e2a 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' feature 'Customers' do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper context "as an enterprise user" do - let(:user) { create_enterprise_user(enterprise_limit: 10) } + let(:user) { create(:user, enterprise_limit: 10) } let(:managed_distributor1) { create(:distributor_enterprise, owner: user) } let(:managed_distributor2) { create(:distributor_enterprise, owner: user) } let(:unmanaged_distributor) { create(:distributor_enterprise) } @@ -18,7 +18,7 @@ feature 'Customers' do let!(:customer4) { create(:customer, enterprise: managed_distributor2) } before do - quick_login_as user + login_as user visit admin_customers_path end diff --git a/spec/features/admin/enterprise_fees_spec.rb b/spec/features/admin/enterprise_fees_spec.rb index a231f272e5..a525ae854a 100644 --- a/spec/features/admin/enterprise_fees_spec.rb +++ b/spec/features/admin/enterprise_fees_spec.rb @@ -4,8 +4,8 @@ feature ' As an administrator I want to manage enterprise fees ', js: true do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper let!(:tax_category_gst) { create(:tax_category, name: 'GST') } @@ -13,8 +13,7 @@ feature ' fee = create(:enterprise_fee, name: '$0.50 / kg', fee_type: 'packing', tax_category: tax_category_gst) amount = fee.calculator.preferred_amount - login_to_admin_section - click_link 'Configuration' + login_as_admin_and_visit spree.edit_admin_general_settings_path click_link 'Enterprise Fees' expect(page).to have_select "enterprise_fee_set_collection_attributes_0_enterprise_id" @@ -30,8 +29,7 @@ feature ' e = create(:supplier_enterprise, name: 'Feedme') # When I go to the enterprise fees page - quick_login_as_admin - visit admin_enterprise_fees_path + login_as_admin_and_visit admin_enterprise_fees_path # And I fill in the fields for a new enterprise fee and click update select 'Feedme', from: 'enterprise_fee_set_collection_attributes_0_enterprise_id' @@ -59,8 +57,7 @@ feature ' enterprise = create(:enterprise, name: 'Foo') # When I go to the enterprise fees page - quick_login_as_admin - visit admin_enterprise_fees_path + login_as_admin_and_visit admin_enterprise_fees_path # And I update the fields for the enterprise fee and click update select 'Foo', from: 'enterprise_fee_set_collection_attributes_0_enterprise_id' @@ -93,8 +90,7 @@ feature ' fee = create(:enterprise_fee) # When I go to the enterprise fees page - quick_login_as_admin - visit admin_enterprise_fees_path + login_as_admin_and_visit admin_enterprise_fees_path # And I click delete accept_alert do @@ -107,7 +103,7 @@ feature ' end context "as an enterprise manager" do - let(:enterprise_user) { create_enterprise_user } + let(:enterprise_user) { create(:user) } let(:distributor1) { create(:distributor_enterprise, name: 'First Distributor') } let(:distributor2) { create(:distributor_enterprise, name: 'Second Distributor') } let(:distributor3) { create(:distributor_enterprise, name: 'Third Distributor') } @@ -117,7 +113,7 @@ feature ' before(:each) do enterprise_user.enterprise_roles.build(enterprise: distributor1).save enterprise_user.enterprise_roles.build(enterprise: distributor2).save - quick_login_as enterprise_user + login_as enterprise_user end it "creates enterprise fees" do diff --git a/spec/features/admin/enterprise_groups_spec.rb b/spec/features/admin/enterprise_groups_spec.rb index c6fa57b055..ff19b44f17 100644 --- a/spec/features/admin/enterprise_groups_spec.rb +++ b/spec/features/admin/enterprise_groups_spec.rb @@ -4,8 +4,8 @@ feature ' As an administrator I want to manage enterprise groups ' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper before(:each) do login_to_admin_section @@ -107,12 +107,12 @@ feature ' end context "as an enterprise user" do - let(:user) { create_enterprise_user } + let(:user) { create(:user) } let!(:enterprise) { create(:distributor_enterprise, owner: user) } let!(:group) { create(:enterprise_group, name: 'My Group', owner: user) } it "lets me access enterprise groups" do - quick_login_as user + login_as user visit spree.admin_dashboard_path click_link 'Groups' expect(page).to have_content 'My Group' diff --git a/spec/features/admin/enterprise_relationships_spec.rb b/spec/features/admin/enterprise_relationships_spec.rb index 1926503045..3dd00acbae 100644 --- a/spec/features/admin/enterprise_relationships_spec.rb +++ b/spec/features/admin/enterprise_relationships_spec.rb @@ -4,11 +4,11 @@ feature ' As an Administrator I want to manage relationships between enterprises ', js: true do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper context "as a site administrator" do - before { quick_login_as_admin } + before { login_as_admin } scenario "listing relationships" do # Given some enterprises with relationships @@ -92,13 +92,13 @@ feature ' let!(:d1) { create(:distributor_enterprise) } let!(:d2) { create(:distributor_enterprise) } let!(:d3) { create(:distributor_enterprise) } - let(:enterprise_user) { create_enterprise_user( enterprises: [d1] ) } + let(:enterprise_user) { create(:user, enterprises: [d1] ) } let!(:er1) { create(:enterprise_relationship, parent: d1, child: d2) } let!(:er2) { create(:enterprise_relationship, parent: d2, child: d1) } let!(:er3) { create(:enterprise_relationship, parent: d2, child: d3) } - before { quick_login_as enterprise_user } + before { login_as enterprise_user } scenario "enterprise user can only see relationships involving their enterprises" do visit admin_enterprise_relationships_path diff --git a/spec/features/admin/enterprise_roles_spec.rb b/spec/features/admin/enterprise_roles_spec.rb index ff29207aeb..2e7c2775a1 100644 --- a/spec/features/admin/enterprise_roles_spec.rb +++ b/spec/features/admin/enterprise_roles_spec.rb @@ -4,7 +4,7 @@ feature ' As an Administrator I want to manage relationships between users and enterprises ', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include OpenFoodNetwork::EmailHelper diff --git a/spec/features/admin/enterprise_user_spec.rb b/spec/features/admin/enterprise_user_spec.rb index 6b4f4dd778..30b3907970 100644 --- a/spec/features/admin/enterprise_user_spec.rb +++ b/spec/features/admin/enterprise_user_spec.rb @@ -4,10 +4,10 @@ feature ' As a Super User I want to setup users to manage an enterprise ' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper - let!(:user) { create_enterprise_user } + let!(:user) { create(:user) } let!(:supplier1) { create(:supplier_enterprise, name: 'Supplier 1') } let!(:supplier2) { create(:supplier_enterprise, name: 'Supplier 2') } let(:supplier_profile) { create(:supplier_enterprise, name: 'Supplier profile', sells: 'none') } @@ -19,8 +19,7 @@ feature ' context "with a limitted number of owned enterprises" do scenario "setting the enterprise ownership limit" do expect(user.enterprise_limit).to eq 5 - login_to_admin_section - click_link 'Users' + login_as_admin_and_visit spree.admin_users_path click_link user.email fill_in "user_enterprise_limit", with: 2 @@ -35,7 +34,7 @@ feature ' describe "system management lockdown" do before do user.enterprise_roles.create!(enterprise: supplier1) - quick_login_as user + login_as user end scenario "should not be able to see system configuration" do diff --git a/spec/features/admin/enterprises/images_spec.rb b/spec/features/admin/enterprises/images_spec.rb index 110b8c2664..0d4644f8c7 100644 --- a/spec/features/admin/enterprises/images_spec.rb +++ b/spec/features/admin/enterprises/images_spec.rb @@ -1,17 +1,17 @@ require "spec_helper" feature "Managing enterprise images" do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper context "as an Enterprise user", js: true do - let(:enterprise_user) { create_enterprise_user(enterprise_limit: 1) } + let(:enterprise_user) { create(:user, enterprise_limit: 1) } let(:distributor) { create(:distributor_enterprise, name: "First Distributor") } before do enterprise_user.enterprise_roles.build(enterprise: distributor).save! - quick_login_as enterprise_user + login_as enterprise_user visit edit_admin_enterprise_path(distributor) end diff --git a/spec/features/admin/enterprises/index_spec.rb b/spec/features/admin/enterprises/index_spec.rb index b4897cbb11..550879d3c1 100644 --- a/spec/features/admin/enterprises/index_spec.rb +++ b/spec/features/admin/enterprises/index_spec.rb @@ -1,16 +1,15 @@ require 'spec_helper' feature 'Enterprises Index' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper context "as an admin user" do scenario "listing enterprises" do s = create(:supplier_enterprise) d = create(:distributor_enterprise) - login_to_admin_section - click_link 'Enterprises' + login_as_admin_and_visit admin_enterprises_path within("tr.enterprise-#{s.id}") do expect(page).to have_content s.name @@ -36,7 +35,7 @@ feature 'Enterprises Index' do context "editing enterprises in bulk" do let!(:s){ create(:supplier_enterprise) } let!(:d){ create(:distributor_enterprise, sells: 'none') } - let!(:d_manager) { create_enterprise_user(enterprise_limit: 1) } + let!(:d_manager) { create(:user, enterprise_limit: 1) } before do d_manager.enterprise_roles.build(enterprise: d).save @@ -45,8 +44,7 @@ feature 'Enterprises Index' do context "without violating rules" do before do - quick_login_as_admin - visit admin_enterprises_path + login_as_admin_and_visit admin_enterprises_path end it "updates the enterprises" do @@ -72,8 +70,7 @@ feature 'Enterprises Index' do d_manager.enterprise_roles.build(enterprise: second_distributor).save expect(d.owner).to_not eq d_manager - quick_login_as_admin - visit admin_enterprises_path + login_as_admin_and_visit admin_enterprises_path end def enterprise_row_index(enterprise_name) @@ -107,14 +104,14 @@ feature 'Enterprises Index' do let(:distributor1) { create(:distributor_enterprise, name: 'First Distributor') } let(:distributor2) { create(:distributor_enterprise, name: 'Another Distributor') } let(:distributor3) { create(:distributor_enterprise, name: 'Yet Another Distributor') } - let(:enterprise_manager) { create_enterprise_user } + let(:enterprise_manager) { create(:user) } let!(:er) { create(:enterprise_relationship, parent: distributor3, child: distributor1, permissions_list: [:edit_profile]) } before(:each) do enterprise_manager.enterprise_roles.build(enterprise: supplier1).save enterprise_manager.enterprise_roles.build(enterprise: distributor1).save - quick_login_as enterprise_manager + login_as enterprise_manager end context "listing enterprises", js: true do @@ -165,11 +162,11 @@ feature 'Enterprises Index' do end describe "as the owner of an enterprise" do - let!(:user) { create_enterprise_user } + let!(:user) { create(:user) } let!(:owned_distributor) { create(:distributor_enterprise, name: 'Owned Distributor', owner: user) } before do - quick_login_as user + login_as user end context "listing enterprises", js: true do diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index 4244e265e7..be7e9ddfa9 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -4,8 +4,8 @@ feature ' As an administrator I want to manage enterprises ' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper scenario "viewing an enterprise" do e = create(:enterprise) @@ -25,7 +25,7 @@ feature ' enterprise_fee = create(:enterprise_fee) # Navigating - admin = quick_login_as_admin + admin = login_as_admin visit '/admin/enterprises' click_link 'New Enterprise' @@ -66,7 +66,7 @@ feature ' enterprise_fee = create(:enterprise_fee, enterprise: @enterprise ) user = create(:user) - admin = quick_login_as_admin + admin = login_as_admin visit '/admin/enterprises' within "tr.enterprise-#{@enterprise.id}" do @@ -219,8 +219,7 @@ feature ' s = create(:supplier_enterprise) # When I go to its properties page - quick_login_as_admin - visit admin_enterprises_path + login_as_admin_and_visit admin_enterprises_path within(".enterprise-#{s.id}") { click_link 'Properties' } # And I create a property @@ -243,8 +242,7 @@ feature ' s.producer_properties.create! property_name: 'Certified Organic', value: 'NASAA 12345' # When I go to its properties page - quick_login_as_admin - visit main_app.admin_enterprise_producer_properties_path(s) + login_as_admin_and_visit main_app.admin_enterprise_producer_properties_path(s) # And I update the property fill_in 'enterprise_producer_properties_attributes_0_property_name', with: "Biodynamic" @@ -266,8 +264,7 @@ feature ' pp = s.producer_properties.create! property_name: 'Certified Organic', value: 'NASAA 12345' # When I go to its properties page - quick_login_as_admin - visit main_app.admin_enterprise_producer_properties_path(s) + login_as_admin_and_visit main_app.admin_enterprise_producer_properties_path(s) # And I remove the property expect(page).to have_field 'enterprise_producer_properties_attributes_0_property_name', with: 'Certified Organic' @@ -287,14 +284,14 @@ feature ' let(:distributor1) { create(:distributor_enterprise, name: 'First Distributor') } let(:distributor2) { create(:distributor_enterprise, name: 'Another Distributor') } let(:distributor3) { create(:distributor_enterprise, name: 'Yet Another Distributor') } - let(:enterprise_user) { create_enterprise_user(enterprise_limit: 1) } + let(:enterprise_user) { create(:user, enterprise_limit: 1) } let!(:er) { create(:enterprise_relationship, parent: distributor3, child: distributor1, permissions_list: [:edit_profile]) } before(:each) do enterprise_user.enterprise_roles.build(enterprise: supplier1).save enterprise_user.enterprise_roles.build(enterprise: distributor1).save - quick_login_as enterprise_user + login_as enterprise_user end context "when I have reached my enterprise ownership limit" do diff --git a/spec/features/admin/external_services_spec.rb b/spec/features/admin/external_services_spec.rb index 3a9a72610e..ceeef4c556 100644 --- a/spec/features/admin/external_services_spec.rb +++ b/spec/features/admin/external_services_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'External services' do - include AuthenticationWorkflow + include AuthenticationHelper describe "bugherd" do before do diff --git a/spec/features/admin/image_settings_spec.rb b/spec/features/admin/image_settings_spec.rb index 9ef2860cd4..83e584a0ce 100644 --- a/spec/features/admin/image_settings_spec.rb +++ b/spec/features/admin/image_settings_spec.rb @@ -4,7 +4,7 @@ feature ' As an admin I want to manage image formats ' do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper before(:all) do @@ -20,8 +20,7 @@ feature ' scenario "setting the image format for a paperclip style" do # When I go to the image settings page - login_to_admin_section - visit spree.edit_admin_image_settings_path + login_as_admin_and_visit spree.edit_admin_image_settings_path # All the styles should default to "Unchanged" expect(page).to have_select 'attachment_styles_format_mini', selected: 'Unchanged' diff --git a/spec/features/admin/multilingual_spec.rb b/spec/features/admin/multilingual_spec.rb index 90d21d1ecd..32e4684936 100644 --- a/spec/features/admin/multilingual_spec.rb +++ b/spec/features/admin/multilingual_spec.rb @@ -1,14 +1,14 @@ require 'spec_helper' feature 'Multilingual', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let(:admin_role) { Spree::Role.find_or_create_by!(name: 'admin') } let(:admin_user) { create(:user) } background do admin_user.spree_roles << admin_role - quick_login_as admin_user + login_as admin_user visit spree.admin_dashboard_path end diff --git a/spec/features/admin/order_cycles/complex_creating_specific_time_spec.rb b/spec/features/admin/order_cycles/complex_creating_specific_time_spec.rb index 39130fa434..237764eaae 100644 --- a/spec/features/admin/order_cycles/complex_creating_specific_time_spec.rb +++ b/spec/features/admin/order_cycles/complex_creating_specific_time_spec.rb @@ -7,7 +7,7 @@ feature ' I want to create/update complex order cycles with a specific time ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let(:order_cycle_opening_time) { Time.zone.local(2040, 11, 0o6, 0o6, 0o0, 0o0).strftime("%F %T %z") } @@ -33,8 +33,7 @@ feature ' distributor_fee = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee') # When I go to the new order cycle page - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path click_link 'New Order Cycle' # Select a coordinator since there are two available diff --git a/spec/features/admin/order_cycles/complex_editing_exchange_same_enterprise_spec.rb b/spec/features/admin/order_cycles/complex_editing_exchange_same_enterprise_spec.rb index 484dd21f40..ef0d1c5f95 100644 --- a/spec/features/admin/order_cycles/complex_editing_exchange_same_enterprise_spec.rb +++ b/spec/features/admin/order_cycles/complex_editing_exchange_same_enterprise_spec.rb @@ -7,7 +7,7 @@ feature ' I want to manage complex order cycles ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper scenario "editing an order cycle with an exchange between the same enterprise" do @@ -20,8 +20,7 @@ feature ' oc_outgoing = create(:simple_order_cycle, coordinator: c, distributors: [c]) # When I edit the first order cycle, the exchange should appear as incoming - quick_login_as_admin - visit admin_order_cycle_incoming_path(oc_incoming) + login_as_admin_and_visit admin_order_cycle_incoming_path(oc_incoming) expect(page).to have_selector 'table.exchanges tr.supplier' visit admin_order_cycle_outgoing_path(oc_incoming) expect(page).not_to have_selector 'table.exchanges tr.distributor' diff --git a/spec/features/admin/order_cycles/complex_editing_multiple_product_pages_spec.rb b/spec/features/admin/order_cycles/complex_editing_multiple_product_pages_spec.rb index 5ff181e7f5..c13e0dd8b1 100644 --- a/spec/features/admin/order_cycles/complex_editing_multiple_product_pages_spec.rb +++ b/spec/features/admin/order_cycles/complex_editing_multiple_product_pages_spec.rb @@ -7,7 +7,7 @@ feature ' I want to manage complex order cycles ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper describe "editing an order cycle with multiple pages of products", js: true do @@ -18,8 +18,7 @@ feature ' before do stub_const("#{Api::ExchangeProductsController}::DEFAULT_PER_PAGE", 1) - quick_login_as_admin - visit admin_order_cycle_incoming_path(order_cycle) + login_as_admin_and_visit admin_order_cycle_incoming_path(order_cycle) expect(page).to have_content "1 / 2 selected" page.find("tr.supplier-#{supplier_enterprise.id} td.products").click diff --git a/spec/features/admin/order_cycles/complex_editing_spec.rb b/spec/features/admin/order_cycles/complex_editing_spec.rb index 72eb521554..4b9aa275fc 100644 --- a/spec/features/admin/order_cycles/complex_editing_spec.rb +++ b/spec/features/admin/order_cycles/complex_editing_spec.rb @@ -7,7 +7,7 @@ feature ' I want to manage complex order cycles ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper scenario "editing an order cycle" do @@ -19,8 +19,7 @@ feature ' oc.distributors.last.update_attribute :name, 'ZZZZ' # When I edit it - quick_login_as_admin - visit edit_admin_order_cycle_path(oc) + login_as_admin_and_visit edit_admin_order_cycle_path(oc) wait_for_edit_form_to_load_order_cycle(oc) diff --git a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb index 2094a83f7e..dfa2946d97 100644 --- a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb +++ b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb @@ -7,7 +7,7 @@ feature ' I want to create/update complex order cycles with a specific time ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let(:order_cycle_opening_time) { Time.zone.local(2040, 11, 0o6, 0o6, 0o0, 0o0).strftime("%F %T %z") } @@ -40,8 +40,7 @@ feature ' distributor_fee2 = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee 2') # When I go to its edit page - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path within "tr.order-cycle-#{oc.id}" do find("a.edit-order-cycle").click end diff --git a/spec/features/admin/order_cycles/list_spec.rb b/spec/features/admin/order_cycles/list_spec.rb index d675984dd8..a7a4890511 100644 --- a/spec/features/admin/order_cycles/list_spec.rb +++ b/spec/features/admin/order_cycles/list_spec.rb @@ -7,7 +7,7 @@ feature ' I want to list and filter order cycles ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper scenario "listing and filtering order cycles" do @@ -30,8 +30,7 @@ feature ' create(:proxy_order, subscription: create(:subscription, schedule: schedule1), order_cycle: oc1) # When I go to the admin order cycles page - login_to_admin_section - click_link 'Order Cycles' + login_as_admin_and_visit admin_order_cycles_path # Then the order cycles should be ordered correctly expect(page).to have_selector "#listing_order_cycles tr td:first-child", count: 7 @@ -129,8 +128,7 @@ feature ' context 'using datepickers' do it "correctly opens the datepicker and changes the date field" do - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path within("tr.order-cycle-#{oc_pt.id}") do expect(find('input.datetimepicker', match: :first).value).to start_with '2012-01-01 00:00' diff --git a/spec/features/admin/order_cycles/simple_spec.rb b/spec/features/admin/order_cycles/simple_spec.rb index 0d6872c19c..1f22485f4c 100644 --- a/spec/features/admin/order_cycles/simple_spec.rb +++ b/spec/features/admin/order_cycles/simple_spec.rb @@ -7,7 +7,7 @@ feature ' I want to manage simple order cycles ', js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper scenario "updating many order cycle opening/closing times at once", js: true do @@ -19,8 +19,7 @@ feature ' orders_close_at: Time.zone.local(2041, 12, 12, 12, 12, 12)) # When I go to the order cycles page - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path # And I fill in some new opening/closing times and save them within("tr.order-cycle-#{oc1.id}") do @@ -77,8 +76,7 @@ feature ' oc = create(:simple_order_cycle) # When I clone it - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path within "tr.order-cycle-#{oc.id}" do find('a.clone-order-cycle').click end @@ -100,8 +98,7 @@ feature ' end it "displays a warning on the order cycles screen" do - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path expect(page).to have_content "The hub #{hub.name} is listed in an active order cycle, but does not have valid shipping and payment methods. Until you set these up, customers will not be able to shop at this hub." end end @@ -151,12 +148,12 @@ feature ' context "that is a manager of the coordinator" do before do - @new_user = create_enterprise_user + @new_user = create(:user) @new_user.enterprise_roles.build(enterprise: supplier_managed).save @new_user.enterprise_roles.build(enterprise: distributor_managed).save @new_user.enterprise_roles.build(enterprise: other_distributor_managed).save - quick_login_as @new_user + login_as @new_user end scenario "viewing a list of order cycles I am coordinating" do @@ -288,7 +285,7 @@ feature ' end context "that is a manager of a participating producer" do - let(:new_user) { create_enterprise_user } + let(:new_user) { create(:user) } before do new_user.enterprise_roles.build(enterprise: supplier_managed).save @@ -354,7 +351,7 @@ feature ' context "that is the manager of a participating hub" do let(:my_distributor) { create(:distributor_enterprise) } - let(:new_user) { create_enterprise_user } + let(:new_user) { create(:user) } before do create(:enterprise_relationship, parent: supplier_managed, child: my_distributor, permissions_list: [:add_to_order_cycle]) @@ -419,7 +416,7 @@ feature ' end describe "simplified interface for enterprise users selling only their own produce" do - let(:user) { create_enterprise_user } + let(:user) { create(:user) } let(:enterprise) { create(:enterprise, is_primary_producer: true, sells: 'own') } let!(:p1) { create(:simple_product, supplier: enterprise) } let!(:p2) { create(:simple_product, supplier: enterprise) } @@ -508,8 +505,7 @@ feature ' ex.update! pickup_time: 'pickup time', pickup_instructions: 'pickup instructions' # When I edit it - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path within "tr.order-cycle-#{oc.id}" do find("a.edit-order-cycle").click end @@ -541,8 +537,7 @@ feature ' ex.update! pickup_time: 'pickup time', pickup_instructions: 'pickup instructions' # When I edit it - quick_login_as_admin - visit edit_admin_order_cycle_path oc + login_as_admin_and_visit edit_admin_order_cycle_path oc wait_for_edit_form_to_load_order_cycle(oc) @@ -596,8 +591,7 @@ feature ' scenario "deleting an order cycle" do order_cycle = create(:simple_order_cycle, name: "Translusent Berries") - quick_login_as_admin - visit admin_order_cycles_path + login_as_admin_and_visit admin_order_cycles_path expect(page).to have_selector "tr.order-cycle-#{order_cycle.id}" accept_alert do first('a.delete-order-cycle').click diff --git a/spec/features/admin/order_cycles_complex_nav_check_spec.rb b/spec/features/admin/order_cycles_complex_nav_check_spec.rb index 4d89e16bb1..1814d9f5af 100644 --- a/spec/features/admin/order_cycles_complex_nav_check_spec.rb +++ b/spec/features/admin/order_cycles_complex_nav_check_spec.rb @@ -6,15 +6,14 @@ feature ' As an administrator I want to be alerted when I navigate away from a dirty order cycle form ', js: true do - include AuthenticationWorkflow + include AuthenticationHelper scenario "alert when navigating away from dirty form" do # Given a 'complex' order cycle form oc = create(:order_cycle) # When I edit the form - quick_login_as_admin - visit edit_admin_order_cycle_path(oc) + login_as_admin_and_visit edit_admin_order_cycle_path(oc) wait_for_edit_form_to_load_order_cycle(oc) diff --git a/spec/features/admin/order_print_ticket_spec.rb b/spec/features/admin/order_print_ticket_spec.rb index add2ef9e7d..15fd46692a 100644 --- a/spec/features/admin/order_print_ticket_spec.rb +++ b/spec/features/admin/order_print_ticket_spec.rb @@ -6,8 +6,8 @@ feature ' As an administrator I want to print a ticket for an order ', js: true do - include AuthenticationWorkflow include CheckoutHelper + include AuthenticationHelper include ActionView::Helpers::NumberHelper context "as an enterprise manager" do @@ -24,10 +24,10 @@ feature ' end before do - @enterprise_user = create_enterprise_user + @enterprise_user = create(:user) @enterprise_user.enterprise_roles.build(enterprise: distributor).save - quick_login_as @enterprise_user + login_as @enterprise_user Spree::Config[:enable_receipt_printing?] = true end diff --git a/spec/features/admin/order_spec.rb b/spec/features/admin/order_spec.rb index 009092686b..bfef4f6931 100644 --- a/spec/features/admin/order_spec.rb +++ b/spec/features/admin/order_spec.rb @@ -6,8 +6,8 @@ feature ' As an administrator I want to create and edit orders ', js: true do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper let(:user) { create(:user) } let(:product) { create(:simple_product) } @@ -43,8 +43,7 @@ feature ' distributor_disabled = create(:distributor_enterprise) create(:simple_order_cycle, name: 'Two') - quick_login_as_admin - visit spree.admin_orders_path + login_as_admin_and_visit spree.admin_orders_path click_link 'New Order' # Distributors without an order cycle should be shown as disabled @@ -79,8 +78,7 @@ feature ' end scenario "can add a product to an existing order" do - quick_login_as_admin - visit spree.edit_admin_order_path(order) + login_as_admin_and_visit spree.edit_admin_order_path(order) targetted_select2_search product.name, from: '#add_variant_id', dropdown_css: '.select2-drop' @@ -102,8 +100,7 @@ feature ' order.user = nil order.save - quick_login_as_admin - visit spree.edit_admin_order_path(order) + login_as_admin_and_visit spree.edit_admin_order_path(order) expect(page).to have_select2 "order_distributor_id", with_options: [d.name] select2_select d.name, from: 'order_distributor_id' @@ -117,15 +114,13 @@ feature ' scenario "can't add products to an order outside the order's hub and order cycle" do product = create(:simple_product) - quick_login_as_admin - visit spree.edit_admin_order_path(order) + login_as_admin_and_visit spree.edit_admin_order_path(order) expect(page).not_to have_select2 "add_variant_id", with_options: [product.name] end scenario "can't change distributor or order cycle once order has been finalized" do - quick_login_as_admin - visit spree.edit_admin_order_path(order) + login_as_admin_and_visit spree.edit_admin_order_path(order) expect(page).not_to have_select2 'order_distributor_id' expect(page).not_to have_select2 'order_order_cycle_id' @@ -149,7 +144,7 @@ feature ' order.shipping_method.update_attribute :require_ship_address, true # When I create a new order - quick_login_as user + login_as user new_order_with_distribution(distributor, order_cycle) targetted_select2_search product.name, from: '#add_variant_id', dropdown_css: '.select2-drop' find('button.add_variant').click @@ -187,12 +182,12 @@ feature ' let(:product) { order_cycle1.products.first } before(:each) do - @enterprise_user = create_enterprise_user + @enterprise_user = create(:user) @enterprise_user.enterprise_roles.build(enterprise: supplier1).save @enterprise_user.enterprise_roles.build(enterprise: coordinator1).save @enterprise_user.enterprise_roles.build(enterprise: distributor1).save - quick_login_as @enterprise_user + login_as @enterprise_user end feature "viewing the edit page" do diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index ea50ddb082..8510ff5943 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -6,7 +6,7 @@ feature ' As an administrator I want to manage orders ', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let(:user) { create(:user) } @@ -29,8 +29,7 @@ feature ' create(:simple_order_cycle, name: 'Four', orders_close_at: 4.weeks.from_now) create(:simple_order_cycle, name: 'Three', orders_close_at: 3.weeks.from_now) - quick_login_as_admin - visit 'admin/orders' + login_as_admin_and_visit 'admin/orders' open_select2('#s2id_q_order_cycle_id_in') @@ -50,8 +49,7 @@ feature ' order4 = create(:order_with_credit_payment, user: user, distributor: distributor, order_cycle: order_cycle4) - quick_login_as_admin - visit 'admin/orders' + login_as_admin_and_visit 'admin/orders' multi_select2_select 'Two', from: 'q_order_cycle_id_in' multi_select2_select 'Three', from: 'q_order_cycle_id_in' @@ -71,9 +69,7 @@ feature ' end scenario "capture payment" do - quick_login_as_admin - - visit spree.admin_orders_path + login_as_admin_and_visit spree.admin_orders_path expect(page).to have_current_path spree.admin_orders_path # click the 'capture' link for the order @@ -91,8 +87,7 @@ feature ' scenario "ship order from the orders index page" do order.payments.first.capture! - quick_login_as_admin - visit spree.admin_orders_path + login_as_admin_and_visit spree.admin_orders_path page.find("[data-powertip=Ship]").click @@ -106,9 +101,7 @@ feature ' scenario "can edit order" do incomplete_order = create(:order, distributor: distributor, order_cycle: order_cycle) - quick_login_as_admin - - visit spree.admin_orders_path + login_as_admin_and_visit spree.admin_orders_path uncheck 'Only show complete orders' page.find('a.icon-search').click diff --git a/spec/features/admin/overview_spec.rb b/spec/features/admin/overview_spec.rb index 3d472dac2f..3a4a3feb7d 100644 --- a/spec/features/admin/overview_spec.rb +++ b/spec/features/admin/overview_spec.rb @@ -4,15 +4,15 @@ feature ' As a backend user I want to be given information about the state of my enterprises, products and order cycles ', js: true do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper include ::Spree::TestingSupport::AuthorizationHelpers context "as an enterprise user" do before do - @enterprise_user = create_enterprise_user + @enterprise_user = create(:user) allow_any_instance_of(Spree::Admin::OverviewController).to receive(:spree_current_user).and_return @enterprise_user - quick_login_as @enterprise_user + login_as @enterprise_user end context "with an enterprise" do diff --git a/spec/features/admin/payment_method_spec.rb b/spec/features/admin/payment_method_spec.rb index 356c450611..851c1be1a0 100644 --- a/spec/features/admin/payment_method_spec.rb +++ b/spec/features/admin/payment_method_spec.rb @@ -4,8 +4,8 @@ feature ' As a Super Admin I want to be able to set a distributor on each payment method ' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper background do @distributors = (1..3).map { create(:distributor_enterprise) } @@ -13,9 +13,7 @@ feature ' describe "creating a payment method", js: true do scenario "assigning a distributor to the payment method" do - login_to_admin_section - - click_link 'Configuration' + login_as_admin_and_visit spree.edit_admin_general_settings_path click_link 'Payment Methods' click_link 'New Payment Method' @@ -47,7 +45,7 @@ feature ' end it "communicates the status of the stripe connection to the user" do - quick_login_as user + login_as user visit spree.new_admin_payment_method_path select2_select "Stripe", from: "payment_method_type" @@ -70,14 +68,12 @@ feature ' scenario "checking a single distributor is checked by default" do 2.times.each { Enterprise.last.destroy } - quick_login_as_admin - visit spree.new_admin_payment_method_path + login_as_admin_and_visit spree.new_admin_payment_method_path expect(page).to have_field "payment_method_distributor_ids_#{@distributors[0].id}", checked: true end scenario "checking more than a distributor displays no default choice" do - quick_login_as_admin - visit spree.new_admin_payment_method_path + login_as_admin_and_visit spree.new_admin_payment_method_path expect(page).to have_field "payment_method_distributor_ids_#{@distributors[0].id}", checked: false expect(page).to have_field "payment_method_distributor_ids_#{@distributors[1].id}", checked: false expect(page).to have_field "payment_method_distributor_ids_#{@distributors[2].id}", checked: false @@ -85,10 +81,9 @@ feature ' end scenario "updating a payment method", js: true do - payment_method = create(:payment_method, distributors: [@distributors[0]]) - quick_login_as_admin - - visit spree.edit_admin_payment_method_path payment_method + payment_method = create(:payment_method, distributors: [@distributors[0]], + calculator: build(:calculator_flat_rate)) + login_as_admin_and_visit spree.edit_admin_payment_method_path payment_method fill_in 'payment_method_name', with: 'New PM Name' find(:css, "tags-input .tags input").set "member\n" @@ -131,7 +126,7 @@ feature ' end context "as an enterprise user", js: true do - let(:enterprise_user) { create_enterprise_user } + let(:enterprise_user) { create(:user) } let(:distributor1) { create(:distributor_enterprise, name: 'First Distributor') } let(:distributor2) { create(:distributor_enterprise, name: 'Second Distributor') } let(:distributor3) { create(:distributor_enterprise, name: 'Third Distributor') } @@ -142,7 +137,7 @@ feature ' before(:each) do enterprise_user.enterprise_roles.build(enterprise: distributor1).save enterprise_user.enterprise_roles.build(enterprise: distributor2).save - quick_login_as enterprise_user + login_as enterprise_user end it "I can get to the new enterprise page" do diff --git a/spec/features/admin/payments_spec.rb b/spec/features/admin/payments_spec.rb index adce888db2..851843dc30 100644 --- a/spec/features/admin/payments_spec.rb +++ b/spec/features/admin/payments_spec.rb @@ -4,13 +4,12 @@ feature ' As an admin I want to manage payments ' do - include AuthenticationWorkflow + include AuthenticationHelper let(:order) { create(:completed_order_with_fees) } scenario "visiting the payment form" do - quick_login_as_admin - visit spree.new_admin_order_payment_path order + login_as_admin_and_visit spree.new_admin_order_payment_path order expect(page).to have_content "New Payment" end @@ -26,8 +25,7 @@ feature ' end scenario "visiting the payment form" do - quick_login_as_admin - visit spree.new_admin_order_payment_path order + login_as_admin_and_visit spree.new_admin_order_payment_path order expect(page).to have_content "New Payment" end @@ -40,8 +38,7 @@ feature ' end it "renders the payment details" do - quick_login_as_admin - visit spree.admin_order_payments_path order + login_as_admin_and_visit spree.admin_order_payments_path order page.click_link("StripeSCA") expect(page).to have_content order.payments.last.source.last_digits @@ -53,8 +50,7 @@ feature ' end it "renders the payment details" do - quick_login_as_admin - visit spree.admin_order_payments_path order + login_as_admin_and_visit spree.admin_order_payments_path order page.click_link("StripeSCA") expect(page).to have_content order.payments.last.amount diff --git a/spec/features/admin/product_import_spec.rb b/spec/features/admin/product_import_spec.rb index e12f2db82c..a4bae3794a 100644 --- a/spec/features/admin/product_import_spec.rb +++ b/spec/features/admin/product_import_spec.rb @@ -3,12 +3,12 @@ require 'open_food_network/permissions' feature "Product Import", js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let!(:admin) { create(:admin_user) } - let!(:user) { create_enterprise_user } - let!(:user2) { create_enterprise_user } + let!(:user) { create(:user) } + let!(:user2) { create(:user) } let!(:enterprise) { create(:supplier_enterprise, owner: user, name: "User Enterprise") } let!(:enterprise2) { create(:distributor_enterprise, owner: user2, name: "Another Enterprise") } let!(:relationship) { create(:enterprise_relationship, parent: enterprise, child: enterprise2, permissions_list: [:create_variant_overrides]) } @@ -31,7 +31,7 @@ feature "Product Import", js: true do let(:shipping_category_id_str) { Spree::ShippingCategory.all.first.id.to_s } describe "when importing products from uploaded file" do - before { quick_login_as_admin } + before { login_as_admin } after { File.delete('/tmp/test.csv') } it "validates entries and saves them if they are all valid and allows viewing new items in Bulk Products" do @@ -342,7 +342,7 @@ feature "Product Import", js: true do end describe "when dealing with uploaded files" do - before { quick_login_as_admin } + before { login_as_admin } it "checks filetype on upload" do File.write('/tmp/test.txt', "Wrong filetype!") @@ -408,7 +408,7 @@ feature "Product Import", js: true do end File.write('/tmp/test.csv', csv_data) - quick_login_as user + login_as user visit main_app.admin_product_import_path attach_file 'file', '/tmp/test.csv' @@ -432,7 +432,7 @@ feature "Product Import", js: true do let(:tmp_csv_path) { "/tmp/test.csv" } before do - quick_login_as admin + login_as admin visit main_app.admin_product_import_path end diff --git a/spec/features/admin/products_spec.rb b/spec/features/admin/products_spec.rb index b2ef204312..dd9bfafd2c 100644 --- a/spec/features/admin/products_spec.rb +++ b/spec/features/admin/products_spec.rb @@ -4,8 +4,8 @@ feature ' As an admin I want to set a supplier and distributor(s) for a product ' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper let!(:taxon) { create(:taxon) } let!(:stock_location) { create(:stock_location, backorderable_default: false) } @@ -67,8 +67,7 @@ feature ' end scenario "creating an on-demand product", js: true do - quick_login_as_admin - visit spree.admin_products_path + login_as_admin_and_visit spree.admin_products_path click_link 'New Product' @@ -97,7 +96,7 @@ feature ' let!(:tax_category) { create(:tax_category) } before do - @new_user = create_enterprise_user + @new_user = create(:user) @supplier2 = create(:supplier_enterprise, name: 'Another Supplier') @supplier_permitted = create(:supplier_enterprise, name: 'Permitted Supplier') @new_user.enterprise_roles.build(enterprise: @supplier2).save @@ -105,7 +104,7 @@ feature ' create(:enterprise_relationship, parent: @supplier_permitted, child: @supplier2, permissions_list: [:manage_products]) - quick_login_as @new_user + login_as @new_user end context "products do not require a tax category" do diff --git a/spec/features/admin/properties_spec.rb b/spec/features/admin/properties_spec.rb index 905810039e..634f3fd436 100644 --- a/spec/features/admin/properties_spec.rb +++ b/spec/features/admin/properties_spec.rb @@ -6,11 +6,10 @@ feature ' As an admin I want to manage product properties ' do - include AuthenticationWorkflow + include AuthenticationHelper scenario "creating and editing a property" do - login_to_admin_section - visit spree.admin_properties_path + login_as_admin_and_visit spree.admin_properties_path click_link 'New Property' fill_in 'property_name', with: 'New property!' diff --git a/spec/features/admin/reports/packing_report_spec.rb b/spec/features/admin/reports/packing_report_spec.rb index 9ab6ff1150..41035bada1 100644 --- a/spec/features/admin/reports/packing_report_spec.rb +++ b/spec/features/admin/reports/packing_report_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" feature "Packing Reports", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let(:distributor) { create(:distributor_enterprise) } @@ -13,7 +13,7 @@ feature "Packing Reports", js: true do before do order.line_items << li1 order.line_items << li2 - quick_login_as_admin + login_as_admin end describe "viewing a report" do diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index b8eb70f010..265d8cb97d 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -4,22 +4,22 @@ feature ' As an administrator I want numbers, all the numbers! ' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper context "Permissions for different reports" do context "As an enterprise user" do let(:user) do - create_enterprise_user(enterprises: [ - create(:distributor_enterprise) - ]) + create(:user, enterprises: [create(:distributor_enterprise)]) end + it "does not show super admin only report" do login_to_admin_as user click_link "Reports" expect(page).not_to have_content "Users & Enterprises" end end + context "As an admin user" do it "shows the super admin only report" do login_to_admin_section @@ -31,8 +31,7 @@ feature ' describe "Customers report" do before do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path end scenario "customers report" do @@ -63,8 +62,7 @@ feature ' describe "Order cycle management report" do before do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path end scenario "payment method report" do @@ -90,8 +88,7 @@ feature ' describe "Packing reports" do before do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path end let(:bill_address1) { create(:address, lastname: "Aman") } @@ -147,8 +144,7 @@ feature ' end scenario "orders and distributors report" do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link 'Orders And Distributors' click_button 'Search' @@ -156,8 +152,7 @@ feature ' end scenario "payments reports" do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link 'Payment Reports' click_button 'Search' @@ -167,8 +162,8 @@ feature ' describe "sales tax report" do let(:distributor1) { create(:distributor_enterprise, with_payment_and_shipping: true, charges_sales_tax: true) } let(:distributor2) { create(:distributor_enterprise, with_payment_and_shipping: true, charges_sales_tax: true) } - let(:user1) { create_enterprise_user enterprises: [distributor1] } - let(:user2) { create_enterprise_user enterprises: [distributor2] } + let(:user1) { create(:user, enterprises: [distributor1]) } + let(:user2) { create(:user, enterprises: [distributor2]) } let!(:shipping_method) { create(:shipping_method_with, :expensive_name, distributors: [distributor1]) } let(:enterprise_fee) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Calculator::FlatRate.new(preferred_amount: 120.0)) } let(:order_cycle) { create(:simple_order_cycle, coordinator: distributor1, coordinator_fees: [enterprise_fee], distributors: [distributor1], variants: [product1.master]) } @@ -191,8 +186,7 @@ feature ' order1.reload.update_distribution_charge! order1.finalize! - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link "Sales Tax" select("Tax types", from: "report_type") @@ -227,8 +221,7 @@ feature ' describe "orders & fulfilment reports" do it "loads the report page" do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link 'Orders & Fulfillment Reports' expect(page).to have_content 'Supplier' @@ -253,8 +246,7 @@ feature ' it "is precise to time of day, not just date" do # When I generate a customer report with a timeframe that includes one order but not the other - quick_login_as_admin - visit spree.orders_and_fulfillment_admin_reports_path + login_as_admin_and_visit spree.orders_and_fulfillment_admin_reports_path fill_in 'q_completed_at_gt', with: '2013-04-25 13:00:00' fill_in 'q_completed_at_lt', with: '2013-04-25 15:00:00' @@ -271,8 +263,7 @@ feature ' oc = create(:simple_order_cycle, name: "My Order Cycle", distributors: [distributor], orders_open_at: Time.zone.now, orders_close_at: nil) o = create(:order, order_cycle: oc, distributor: distributor) - quick_login_as_admin - visit spree.orders_and_fulfillment_admin_reports_path + login_as_admin_and_visit spree.orders_and_fulfillment_admin_reports_path expect(page).to have_content "My Order Cycle" end @@ -303,8 +294,7 @@ feature ' end it "shows products and inventory report" do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path expect(page).to have_content "All products" expect(page).to have_content "Inventory (on hand)" @@ -318,8 +308,7 @@ feature ' end it "shows the LettuceShare report" do - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link 'LettuceShare' click_button "Go" @@ -329,15 +318,14 @@ feature ' end describe "users and enterprises report" do - let!(:enterprise1) { create( :enterprise, owner: create_enterprise_user ) } - let!(:enterprise2) { create( :enterprise, owner: create_enterprise_user ) } - let!(:enterprise3) { create( :enterprise, owner: create_enterprise_user ) } + let!(:enterprise1) { create( :enterprise, owner: create(:user) ) } + let!(:enterprise2) { create( :enterprise, owner: create(:user) ) } + let!(:enterprise3) { create( :enterprise, owner: create(:user) ) } before do enterprise3.enterprise_roles.build( user: enterprise1.owner ).save - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link 'Users & Enterprises' end @@ -379,8 +367,8 @@ feature ' describe "Xero invoices report" do let(:distributor1) { create(:distributor_enterprise, with_payment_and_shipping: true, charges_sales_tax: true) } let(:distributor2) { create(:distributor_enterprise, with_payment_and_shipping: true, charges_sales_tax: true) } - let(:user1) { create_enterprise_user enterprises: [distributor1] } - let(:user2) { create_enterprise_user enterprises: [distributor2] } + let(:user1) { create(:user, enterprises: [distributor1]) } + let(:user2) { create(:user, enterprises: [distributor2]) } let(:shipping_method) { create(:shipping_method_with, :expensive_name) } let(:shipment) { create(:shipment_with, :shipping_method, shipping_method: shipping_method) } @@ -414,8 +402,7 @@ feature ' order1.update_attribute :email, 'customer@email.com' Timecop.travel(Time.zone.local(2015, 4, 25, 14, 0, 0)) { order1.finalize! } - quick_login_as_admin - visit spree.admin_reports_path + login_as_admin_and_visit spree.admin_reports_path click_link 'Xero Invoices' end diff --git a/spec/features/admin/schedules_spec.rb b/spec/features/admin/schedules_spec.rb index f017596e53..41c963e403 100644 --- a/spec/features/admin/schedules_spec.rb +++ b/spec/features/admin/schedules_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Schedules', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper context "as an enterprise user" do @@ -16,7 +16,7 @@ feature 'Schedules', js: true do let!(:oc5) { create(:simple_order_cycle, coordinator: managed_enterprise2, name: 'oc5') } let!(:weekly_schedule) { create(:schedule, name: 'Weekly', order_cycles: [oc1, oc2, oc3, oc4]) } - before { quick_login_as user } + before { login_as user } describe "Adding a new Schedule" do it "immediately shows the schedule in the order cycle list once created" do diff --git a/spec/features/admin/shipping_methods_spec.rb b/spec/features/admin/shipping_methods_spec.rb index 84de423581..560fe2f357 100644 --- a/spec/features/admin/shipping_methods_spec.rb +++ b/spec/features/admin/shipping_methods_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' feature 'shipping methods' do - include AuthenticationWorkflow include WebHelper + include AuthenticationHelper before :each do @shipping_method = create(:shipping_method) @@ -10,7 +10,7 @@ feature 'shipping methods' do context "as a site admin" do before(:each) do - quick_login_as_admin + login_as_admin end scenario "creating a shipping method owned by some distributors" do @@ -82,7 +82,7 @@ feature 'shipping methods' do end context "as an enterprise user", js: true do - let(:enterprise_user) { create_enterprise_user } + let(:enterprise_user) { create(:user) } let(:distributor1) { create(:distributor_enterprise, name: 'First Distributor') } let(:distributor2) { create(:distributor_enterprise, name: 'Second Distributor') } let(:distributor3) { create(:distributor_enterprise, name: 'Third Distributor') } @@ -94,7 +94,7 @@ feature 'shipping methods' do before(:each) do enterprise_user.enterprise_roles.build(enterprise: distributor1).save enterprise_user.enterprise_roles.build(enterprise: distributor2).save - quick_login_as enterprise_user + login_as enterprise_user end it "creating a shipping method" do diff --git a/spec/features/admin/subscriptions_spec.rb b/spec/features/admin/subscriptions_spec.rb index 61d5f59bcd..4278018aa2 100644 --- a/spec/features/admin/subscriptions_spec.rb +++ b/spec/features/admin/subscriptions_spec.rb @@ -2,16 +2,16 @@ require 'spec_helper' feature 'Subscriptions' do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper context "as an enterprise user", js: true do - let!(:user) { create_enterprise_user(enterprise_limit: 10) } + let!(:user) { create(:user) } let!(:shop) { create(:distributor_enterprise, owner: user, enable_subscriptions: true) } let!(:shop2) { create(:distributor_enterprise, owner: user, enable_subscriptions: true) } let!(:shop_unmanaged) { create(:distributor_enterprise, enable_subscriptions: true) } - before { quick_login_as user } + before { login_as user } context 'listing subscriptions' do let!(:subscription) { create(:subscription, shop: shop, with_items: true, with_proxy_orders: true) } diff --git a/spec/features/admin/tag_rules_spec.rb b/spec/features/admin/tag_rules_spec.rb index ca53fb68a9..0f3f035379 100644 --- a/spec/features/admin/tag_rules_spec.rb +++ b/spec/features/admin/tag_rules_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Tag Rules', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper let!(:enterprise) { create(:distributor_enterprise) } @@ -242,8 +242,7 @@ feature 'Tag Rules', js: true do end def visit_tag_rules - login_to_admin_section - visit main_app.edit_admin_enterprise_path(enterprise) + login_as_admin_and_visit main_app.edit_admin_enterprise_path(enterprise) expect(page).to have_content "PRIMARY DETAILS" click_link "Tag Rules" end diff --git a/spec/features/admin/tax_settings_spec.rb b/spec/features/admin/tax_settings_spec.rb index 830f45f692..5da7384c55 100644 --- a/spec/features/admin/tax_settings_spec.rb +++ b/spec/features/admin/tax_settings_spec.rb @@ -1,12 +1,10 @@ require 'spec_helper' feature 'Account and Billing Settings' do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper describe "updating" do - let!(:admin) { create(:admin_user) } - before do Spree::Config.set( products_require_tax_category: false, @@ -15,14 +13,9 @@ feature 'Account and Billing Settings' do ) end - before do - quick_login_as_admin - end - context "as an admin user" do it "loads the page" do - visit spree.admin_dashboard_path - click_link "Configuration" + login_as_admin_and_visit spree.edit_admin_general_settings_path click_link "Tax Settings" expect(page).to have_unchecked_field 'preferences_products_require_tax_category' @@ -31,7 +24,7 @@ feature 'Account and Billing Settings' do end it "attributes can be changed" do - visit spree.edit_admin_tax_settings_path + login_as_admin_and_visit spree.edit_admin_tax_settings_path check 'preferences_products_require_tax_category' check 'preferences_shipment_inc_vat' diff --git a/spec/features/admin/users_spec.rb b/spec/features/admin/users_spec.rb index b97089a0aa..94cb4b881f 100644 --- a/spec/features/admin/users_spec.rb +++ b/spec/features/admin/users_spec.rb @@ -1,13 +1,13 @@ require "spec_helper" feature "Managing users" do - include AuthenticationWorkflow + include AuthenticationHelper include OpenFoodNetwork::EmailHelper context "as super-admin" do before do setup_email - quick_login_as_admin + login_as_admin end context "from the index page" do diff --git a/spec/features/admin/variant_overrides_spec.rb b/spec/features/admin/variant_overrides_spec.rb index 1fb6e15981..7c4c6ff543 100644 --- a/spec/features/admin/variant_overrides_spec.rb +++ b/spec/features/admin/variant_overrides_spec.rb @@ -6,7 +6,7 @@ feature " Without affecting other hubs that share the same products ", js: true do include AdminHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper context "as the manager of a hub" do @@ -24,9 +24,9 @@ feature " create(:enterprise_relationship, parent: producer_related, child: hub, permissions_list: [:create_variant_overrides]) } - let(:user) { create_enterprise_user enterprises: [hub, producer_managed] } + let(:user) { create(:user, enterprises: [hub, producer_managed]) } - before { quick_login_as user } + before { login_as user } describe "selecting a hub" do let!(:er1) { @@ -401,9 +401,7 @@ feature " let(:product) { order_cycle.products.first } before do - login_to_admin_section - - visit 'admin/orders/new' + login_as_admin_and_visit spree.new_admin_order_path select2_select distributor.name, from: 'order_distributor_id' select2_select order_cycle.name, from: 'order_order_cycle_id' click_button 'Next' @@ -473,7 +471,7 @@ feature " last_variant = inventory_items.last.variant first_variant.product.update!(name: "A First Product") last_variant.product.update!(name: "Z Last Product") - quick_login_as supplier.users.first + login_as supplier.users.first visit admin_inventory_path expect(page).to have_text first_variant.name diff --git a/spec/features/admin/variants_spec.rb b/spec/features/admin/variants_spec.rb index 700c375954..2b5df3c0aa 100644 --- a/spec/features/admin/variants_spec.rb +++ b/spec/features/admin/variants_spec.rb @@ -4,7 +4,7 @@ feature ' As an admin I want to manage product variants ' do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper scenario "creating a new variant" do @@ -12,8 +12,7 @@ feature ' product = create(:simple_product, variant_unit: "weight", variant_unit_scale: "1") # When I create a variant on the product - login_to_admin_section - visit spree.admin_product_variants_path product + login_as_admin_and_visit spree.admin_product_variants_path product click_link 'New Variant' fill_in 'unit_value_human', with: '1' @@ -35,8 +34,7 @@ feature ' product.option_types << variant.option_values.first.option_type # When I view the variant - login_to_admin_section - visit spree.admin_product_variants_path product + login_as_admin_and_visit spree.admin_product_variants_path product page.find('table.index .icon-edit').click # Then I should not see a traditional option value field for the unit-related option value @@ -62,8 +60,7 @@ feature ' variant = product.variants.first variant.update(unit_description: 'foo') - login_to_admin_section - visit spree.edit_admin_product_variant_path(product, variant) + login_as_admin_and_visit spree.edit_admin_product_variant_path(product, variant) expect(page).to_not have_field "unit_value_human" expect(page).to have_field "variant_unit_description", with: "foo" @@ -120,8 +117,7 @@ feature ' product = create(:simple_product) variant = create(:variant, product: product) - login_to_admin_section - visit spree.admin_product_variants_path product + login_as_admin_and_visit spree.admin_product_variants_path product within "tr#spree_variant_#{variant.id}" do accept_alert do @@ -138,8 +134,7 @@ feature ' variant = product.variants.first # When I view the variant - login_to_admin_section - visit spree.admin_product_variants_path product + login_as_admin_and_visit spree.admin_product_variants_path product page.find('table.index .icon-edit').click # It should allow the display name to be changed diff --git a/spec/features/consumer/account/cards_spec.rb b/spec/features/consumer/account/cards_spec.rb index 2b2008b049..e364d8057f 100644 --- a/spec/features/consumer/account/cards_spec.rb +++ b/spec/features/consumer/account/cards_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "Credit Cards", js: true do - include AuthenticationWorkflow + include AuthenticationHelper describe "as a logged in user" do let(:user) { create(:user) } let!(:customer) { create(:customer, user: user) } @@ -9,7 +9,7 @@ feature "Credit Cards", js: true do let!(:non_default_card) { create(:credit_card, user_id: user.id, gateway_customer_profile_id: 'cus_FDTG') } before do - quick_login_as user + login_as user allow(Stripe).to receive(:api_key) { "sk_test_xxxx" } allow(Stripe).to receive(:publishable_key) { "some_token" } diff --git a/spec/features/consumer/account/settings_spec.rb b/spec/features/consumer/account/settings_spec.rb index 2edc45cab1..77012ee3d8 100644 --- a/spec/features/consumer/account/settings_spec.rb +++ b/spec/features/consumer/account/settings_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "Account Settings", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include OpenFoodNetwork::EmailHelper describe "as a logged in user" do @@ -14,7 +14,7 @@ feature "Account Settings", js: true do before do setup_email - quick_login_as user + login_as user visit "/account" click_link I18n.t('spree.users.show.tabs.settings') expect(page).to have_content I18n.t('spree.users.form.account_settings') diff --git a/spec/features/consumer/account_spec.rb b/spec/features/consumer/account_spec.rb index bdba76c971..401c8fbd33 100644 --- a/spec/features/consumer/account_spec.rb +++ b/spec/features/consumer/account_spec.rb @@ -6,7 +6,7 @@ feature ' and view any outstanding balance. ', js: true do include UIComponentHelper - include AuthenticationWorkflow + include AuthenticationHelper let(:user) { create(:user) } let!(:distributor1) { create(:distributor_enterprise) } diff --git a/spec/features/consumer/authentication_spec.rb b/spec/features/consumer/authentication_spec.rb index c172f40f38..790681cbd6 100644 --- a/spec/features/consumer/authentication_spec.rb +++ b/spec/features/consumer/authentication_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "Authentication", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include UIComponentHelper include OpenFoodNetwork::EmailHelper @@ -28,6 +28,7 @@ feature "Authentication", js: true do browse_as_large open_login_modal end + scenario "showing login" do expect(page).to have_login_modal end @@ -106,8 +107,31 @@ feature "Authentication", js: true do end.to enqueue_job Delayed::PerformableMethod expect(Delayed::Job.last.payload_object.method_name).to eq(:send_reset_password_instructions_without_delay) end + + context "user with unconfirmed email" do + let(:email) { "test@example.org" } + let!(:user) { Spree::User.create(email: email, unconfirmed_email: email, password: "secret") } + + scenario "cannot reset password before confirming email" do + fill_in "Your email", with: email + click_reset_password_button + expect(page).to have_content I18n.t('email_unconfirmed') + page.find("a", text: I18n.t('devise.confirmations.resend_confirmation_email')).click + expect(page).to have_content I18n.t('devise.confirmations.send_instructions') + + visit spree.spree_user_confirmation_path(confirmation_token: user.confirmation_token) + expect(user.reload.confirmed?).to be true + expect(page).to have_text I18n.t('devise.confirmations.confirmed') + + select_login_tab "Forgot Password?" + fill_in "Your email", with: email + click_reset_password_button + expect(page).to have_reset_password + end + end end end + describe "as medium" do before do browse_as_medium diff --git a/spec/features/consumer/confirm_invitation_spec.rb b/spec/features/consumer/confirm_invitation_spec.rb index bfdd4baddc..43645a9e31 100644 --- a/spec/features/consumer/confirm_invitation_spec.rb +++ b/spec/features/consumer/confirm_invitation_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" feature "Confirm invitation as manager" do - include UIComponentHelper # for be_logged_in_as + include UIComponentHelper include OpenFoodNetwork::EmailHelper describe "confirm email and set password" do @@ -15,8 +15,8 @@ feature "Confirm invitation as manager" do user.save! end - it "allows you to set a password" do - visit spree.spree_user_confirmation_url(confirmation_token: user.confirmation_token) + it "lets the user set a password" do + visit spree.spree_user_confirmation_path(confirmation_token: user.confirmation_token) expect(user.reload.confirmed?).to be true expect(page).to have_text I18n.t(:change_my_password) diff --git a/spec/features/consumer/groups_spec.rb b/spec/features/consumer/groups_spec.rb index dc9a3e4b75..3284b709c8 100644 --- a/spec/features/consumer/groups_spec.rb +++ b/spec/features/consumer/groups_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Groups', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include UIComponentHelper let(:enterprise) { create(:distributor_enterprise) } diff --git a/spec/features/consumer/multilingual_spec.rb b/spec/features/consumer/multilingual_spec.rb index 3e8a19f4d0..1a54a813d3 100644 --- a/spec/features/consumer/multilingual_spec.rb +++ b/spec/features/consumer/multilingual_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Multilingual', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include ShopWorkflow include UIComponentHelper @@ -77,14 +77,14 @@ feature 'Multilingual', js: true do expect_menu_and_cookie_in_es expect(user.locale).to be_nil - quick_login_as user + login_as user visit root_path expect_menu_and_cookie_in_es end it 'updates user locale and stays in cookie after logout' do - quick_login_as user + login_as user visit root_path(locale: 'es') user.reload diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb index cf49db00df..f9e03d5f87 100644 --- a/spec/features/consumer/producers_spec.rb +++ b/spec/features/consumer/producers_spec.rb @@ -5,7 +5,7 @@ feature ' I want to see a list of producers So that I can shop at hubs distributing their products ', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include UIComponentHelper diff --git a/spec/features/consumer/registration_spec.rb b/spec/features/consumer/registration_spec.rb index 0e9f1b221c..3d7cbb0a0f 100644 --- a/spec/features/consumer/registration_spec.rb +++ b/spec/features/consumer/registration_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "Registration", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper describe "Registering a Profile" do @@ -154,7 +154,7 @@ feature "Registration", js: true do let!(:user2) { create(:user) } before do - quick_login_as user2 + login_as user2 end context "if accepting Terms of Service is not required" do diff --git a/spec/features/consumer/shopping/cart_spec.rb b/spec/features/consumer/shopping/cart_spec.rb index 0bc4523a24..5339aa99f7 100644 --- a/spec/features/consumer/shopping/cart_spec.rb +++ b/spec/features/consumer/shopping/cart_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "full-page cart", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include ShopWorkflow include UIComponentHelper @@ -262,7 +262,7 @@ feature "full-page cart", js: true do order.distributor.allow_order_changes = true order.distributor.save add_product_to_cart order, product_with_tax - quick_login_as user + login_as user visit main_app.cart_path end diff --git a/spec/features/consumer/shopping/checkout_auth_spec.rb b/spec/features/consumer/shopping/checkout_auth_spec.rb index a4d9d8c1c3..acbbabd970 100644 --- a/spec/features/consumer/shopping/checkout_auth_spec.rb +++ b/spec/features/consumer/shopping/checkout_auth_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "As a consumer I want to check out my cart", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include ShopWorkflow include CheckoutWorkflow @@ -24,7 +24,7 @@ feature "As a consumer I want to check out my cart", js: true do end it "does not render the login form when logged in" do - quick_login_as user + login_as user visit checkout_path within "section[role='main']" do expect(page).to have_no_content "Login" diff --git a/spec/features/consumer/shopping/checkout_spec.rb b/spec/features/consumer/shopping/checkout_spec.rb index 342c699a43..dd79d95958 100644 --- a/spec/features/consumer/shopping/checkout_spec.rb +++ b/spec/features/consumer/shopping/checkout_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "As a consumer I want to check out my cart", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include ShopWorkflow include CheckoutWorkflow include WebHelper @@ -65,7 +65,7 @@ feature "As a consumer I want to check out my cart", js: true do let(:user) { create(:user) } before do - quick_login_as(user) + login_as(user) end context "with details filled out" do @@ -292,7 +292,7 @@ feature "As a consumer I want to check out my cart", js: true do expect(page).to have_content "Donkeys" expect(page).not_to have_content "Local" - quick_login_as(user) + login_as(user) visit checkout_path # Default rule in still effect, disallows access to 'Local' diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index 445a92186f..075209769e 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature "Using embedded shopfront functionality", js: true do include OpenFoodNetwork::EmbeddedPagesHelper - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include ShopWorkflow include CheckoutWorkflow diff --git a/spec/features/consumer/shopping/orders_spec.rb b/spec/features/consumer/shopping/orders_spec.rb index 4f2a379c12..f7b0a832c5 100644 --- a/spec/features/consumer/shopping/orders_spec.rb +++ b/spec/features/consumer/shopping/orders_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "Order Management", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include OpenFoodNetwork::EmailHelper describe "viewing a completed order" do @@ -109,7 +109,7 @@ feature "Order Management", js: true do order.save order.reload - quick_login_as user + login_as user end it 'shows the name of the shipping method' do diff --git a/spec/features/consumer/shopping/products_spec.rb b/spec/features/consumer/shopping/products_spec.rb index 0846845021..91393e3213 100644 --- a/spec/features/consumer/shopping/products_spec.rb +++ b/spec/features/consumer/shopping/products_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "As a consumer I want to view products", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include ShopWorkflow include UIComponentHelper diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index cf825ca475..f55c3aded5 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "As a consumer I want to shop with a distributor", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include ShopWorkflow include UIComponentHelper @@ -194,14 +194,16 @@ feature "As a consumer I want to shop with a distributor", js: true do end it "returns search results for products where the search term matches one of the product's variant names" do + pending "has been broken for a while" + visit shop_path fill_in "search", with: "Badg" # For variant with display_name "Badgers" within('div.pad-top') do - expect(page).to have_content product.name - expect(page).to have_content variant2.display_name expect(page).not_to have_content product2.name expect(page).not_to have_content variant3.display_name + expect(page).to have_content product.name + expect(page).to have_content variant2.display_name end end @@ -483,7 +485,7 @@ feature "As a consumer I want to shop with a distributor", js: true do let(:user) { create(:user, bill_address: address, ship_address: address) } before do - quick_login_as user + login_as user end context "as non-customer" do @@ -531,7 +533,7 @@ feature "As a consumer I want to shop with a distributor", js: true do let!(:returning_user) { create(:user, email: unregistered_customer.email) } before do - quick_login_as returning_user + login_as returning_user end it "shows the products without customer only message" do diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index 9c7ca0a5d1..d89990dc55 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "shopping with variant overrides defined", js: true do - include AuthenticationWorkflow + include AuthenticationHelper include WebHelper include ShopWorkflow include CheckoutWorkflow diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index a9c262817c..80483840fc 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Shops', js: true do - include AuthenticationWorkflow + include AuthenticationHelper include UIComponentHelper include WebHelper diff --git a/spec/javascripts/unit/darkswarm/services/checkout_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/checkout_spec.js.coffee index d7e23b457b..8caacdc531 100644 --- a/spec/javascripts/unit/darkswarm/services/checkout_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/checkout_spec.js.coffee @@ -1,4 +1,6 @@ describe 'Checkout service', -> + BugsnagMock = + notify: (arg) -> Checkout = null orderData = null $httpBackend = null @@ -48,6 +50,8 @@ describe 'Checkout service', -> ship_address: {test: "bar"} user_id: 901 + window.Bugsnag = BugsnagMock + module 'Darkswarm' module ($provide)-> $provide.value "RailsFlashLoader", FlashLoaderMock @@ -128,6 +132,7 @@ describe 'Checkout service', -> expect(Checkout.errors).toEqual {error: "frogs"} it "throws exception and sends generic flash message when there are errors but no flash message", -> + spyOn(BugsnagMock, "notify") $httpBackend.expectPUT("/checkout.json").respond 400, {errors: {error: "broken response"}} try Checkout.submit() @@ -136,9 +141,11 @@ describe 'Checkout service', -> expect(error.data.errors.error).toBe("broken response") expect(Checkout.errors).toEqual {} + expect(BugsnagMock.notify).toHaveBeenCalled() it "throws an exception and sends a flash message to the flash service when reponse doesnt contain errors nor a flash message", -> spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location + spyOn(BugsnagMock, "notify") $httpBackend.expectPUT("/checkout.json").respond 400, "broken response" try Checkout.submit() @@ -147,9 +154,11 @@ describe 'Checkout service', -> expect(error.data).toBe("broken response") expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith({ error: t("checkout.failed") }) + expect(BugsnagMock.notify).toHaveBeenCalled() it "throws an exception and sends a flash message to the flash service when an exception is thrown while handling the error", -> spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location + spyOn(BugsnagMock, "notify") navigationSpy.and.callFake(-> throw "unexpected error") $httpBackend.expectPUT("/checkout.json").respond 400, {path: 'path'} try @@ -159,6 +168,7 @@ describe 'Checkout service', -> expect(error).toBe("unexpected error") expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith({ error: t("checkout.failed") }) + expect(BugsnagMock.notify).toHaveBeenCalled() describe "when using the Stripe Connect gateway", -> beforeEach inject ($injector, StripeElements) -> diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index c95fbdf81b..088ea359e0 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -24,7 +24,7 @@ describe "Enterprises service", -> {id: 5, visible: true, name: 'e', category: "producer_hub", hubs: [{id: 1}]}, {id: 6, visible: true, name: 'f', category: "producer_shop", hubs: [{id: 2}]}, {id: 7, visible: true, name: 'g', category: "producer", hubs: [{id: 2}]} - {id: 8, visible: true, name: 'h', category: "producer", hubs: [{id: 2}]} + {id: 8, visible: true, name: 'h', category: "producer", hubs: [{id: 2}], latitude: 76.26, longitude: -42.66 } ] H1: 0 beforeEach -> @@ -142,4 +142,8 @@ describe "Enterprises service", -> it "resets the distance", -> Enterprises.resetDistance() for e in Enterprises.enterprises - expect(e.distance).toBeNull() \ No newline at end of file + expect(e.distance).toBeNull() + + describe "geocodedEnterprises", -> + it "only returns enterprises which have a latitude and longitude", -> + expect(Enterprises.geocodedEnterprises()).toEqual [Enterprises.enterprises[7]] diff --git a/spec/javascripts/unit/darkswarm/services/map_centre_calculator_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/map_centre_calculator_spec.js.coffee new file mode 100644 index 0000000000..0d18541442 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/services/map_centre_calculator_spec.js.coffee @@ -0,0 +1,86 @@ +describe 'MapCentreCalculator service', -> + MapCentreCalculator = null + Enterprises = null + defaultLongitude = null + defaultLatitude = null + + beforeEach -> + module 'Darkswarm' + defaultLongitude = -6 + defaultLatitude = 53 + angular.module('Darkswarm').value 'openStreetMapConfig', { + open_street_map_default_latitude: 76.26, + open_street_map_default_longitude: -42.66 + } + + inject (_MapCentreCalculator_, _Enterprises_)-> + MapCentreCalculator = _MapCentreCalculator_ + Enterprises = _Enterprises_ + + describe "initialLatitude", -> + it "calculates the center latitude of any present geocoded enterprises", -> + Enterprises.geocodedEnterprises = -> [ + { latitude: 53, longitude: defaultLongitude }, + { latitude: 54, longitude: defaultLongitude } + ] + + expect(MapCentreCalculator.initialLatitude()).toEqual 53.5 + + it "returns the default configured latitude when there are no geocoded enterprises present", -> + Enterprises.geocodedEnterprises = -> [] + + expect(MapCentreCalculator.initialLatitude()).toEqual 76.26 + + describe "initialLongitude", -> + it "calculates the center longitude of any present geocoded enterprises", -> + Enterprises.geocodedEnterprises = -> [ + { latitude: defaultLatitude, longitude: -6 }, + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator.initialLongitude()).toEqual -6.5 + + it "returns the default configured longitude when there are no geocoded enterprises present", -> + Enterprises.geocodedEnterprises = -> [] + + expect(MapCentreCalculator.initialLongitude()).toEqual -42.66 + + describe "_calculate", -> + it "calculates the average angle correctly when given a single angle", -> + coordinates = [ + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual -7 + + it "calculates the centre correctly when given a set of positive angles", -> + coordinates = [ + { latitude: 53, longitude: defaultLongitude }, + { latitude: 54, longitude: defaultLongitude } + ] + + expect(MapCentreCalculator._calculate("latitude", coordinates)).toEqual 53.5 + + it "calculates the centre correctly when given a set of negative angles", -> + coordinates = [ + { latitude: defaultLatitude, longitude: -6 }, + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual -6.5 + + it "calculates the centre correctly when given a mixture of positive and negative angles and the centre is positive", -> + coordinates = [ + { latitude: defaultLatitude, longitude: 7 }, + { latitude: defaultLatitude, longitude: -4 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual 1.5 + + it "calculates the centre correctly when given a mixture of positive and negative angles and the centre is negative", -> + coordinates = [ + { latitude: defaultLatitude, longitude: 4 }, + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual -1.5 diff --git a/spec/jobs/subscription_confirm_job_spec.rb b/spec/jobs/subscription_confirm_job_spec.rb index 603da10a10..87b3db0fd9 100644 --- a/spec/jobs/subscription_confirm_job_spec.rb +++ b/spec/jobs/subscription_confirm_job_spec.rb @@ -19,7 +19,7 @@ describe SubscriptionConfirmJob do let(:proxy_orders) { job.send(:unconfirmed_proxy_orders) } before do - AdvanceOrderService.new(order).call! + OrderWorkflow.new(order).complete! end it "returns proxy orders that meet all of the criteria" do @@ -126,7 +126,7 @@ describe SubscriptionConfirmJob do let(:order) { proxy_order.initialise_order! } before do - AdvanceOrderService.new(order).call! + OrderWorkflow.new(order).complete! allow(job).to receive(:send_confirmation_email).and_call_original setup_email expect(job).to receive(:record_order) @@ -216,7 +216,7 @@ describe SubscriptionConfirmJob do it "records and logs an error and sends the email" do expect(order).to receive(:update!) - expect(job).to receive(:record_and_log_error).with(:failed_payment, order).once + expect(job).to receive(:record_and_log_error).with(:failed_payment, order, nil).once job.send(:send_failed_payment_email, order) expect(SubscriptionMailer).to have_received(:failed_payment_email).with(order) expect(mail_mock).to have_received(:deliver) diff --git a/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb b/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb index a850e1ead9..94742455e3 100644 --- a/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb +++ b/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb @@ -4,9 +4,7 @@ require 'open_food_network/order_cycle_form_applicator' module OpenFoodNetwork describe OrderCycleFormApplicator do - include AuthenticationWorkflow - - let!(:user) { create_enterprise_user } + let!(:user) { create(:user) } context "unit specs" do it "creates new exchanges for incoming_exchanges" do diff --git a/spec/lib/open_food_network/order_cycle_management_report_spec.rb b/spec/lib/open_food_network/order_cycle_management_report_spec.rb index 8f65a80889..e0214b732a 100644 --- a/spec/lib/open_food_network/order_cycle_management_report_spec.rb +++ b/spec/lib/open_food_network/order_cycle_management_report_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' require 'open_food_network/order_cycle_management_report' -include AuthenticationWorkflow - module OpenFoodNetwork describe OrderCycleManagementReport do context "as a site admin" do @@ -37,7 +35,7 @@ module OpenFoodNetwork end context "as an enterprise user" do - let!(:user) { create_enterprise_user } + let!(:user) { create(:user) } subject { OrderCycleManagementReport.new user, {}, true } diff --git a/spec/lib/open_food_network/orders_and_fulfillments_report/customer_totals_report_spec.rb b/spec/lib/open_food_network/orders_and_fulfillments_report/customer_totals_report_spec.rb index 6bae6da8a1..4799c3e4ac 100644 --- a/spec/lib/open_food_network/orders_and_fulfillments_report/customer_totals_report_spec.rb +++ b/spec/lib/open_food_network/orders_and_fulfillments_report/customer_totals_report_spec.rb @@ -1,5 +1,7 @@ require "spec_helper" +require 'open_food_network/orders_and_fulfillments_report' require 'open_food_network/orders_and_fulfillments_report/customer_totals_report' +require 'open_food_network/order_grouper' RSpec.describe OpenFoodNetwork::OrdersAndFulfillmentsReport::CustomerTotalsReport do let!(:distributor) { create(:distributor_enterprise) } @@ -79,6 +81,27 @@ RSpec.describe OpenFoodNetwork::OrdersAndFulfillmentsReport::CustomerTotalsRepor end end + context "displaying payment fees" do + context "with both failed and completed payments present" do + let!(:order) { + create(:order_ready_to_ship, user: customer.user, + customer: customer, distributor: distributor) + } + let(:completed_payment) { order.payments.completed.first } + let!(:failed_payment) { create(:payment, order: order, state: "failed") } + + before do + completed_payment.adjustment.update amount: 123.00 + failed_payment.adjustment.update amount: 456.00, eligible: false, state: "finalized" + end + + it "shows the correct payment fee amount for the order" do + payment_fee_field = report_table.last[12] + expect(payment_fee_field).to eq completed_payment.adjustment.amount + end + end + end + context 'when a variant override applies' do let!(:order) do create(:completed_order_with_totals, line_items_count: 1, user: customer.user, diff --git a/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb b/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb index e646884e6e..f970c4b83a 100644 --- a/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb +++ b/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb @@ -1,8 +1,9 @@ require 'spec_helper' require 'open_food_network/orders_and_fulfillments_report' +require 'open_food_network/order_grouper' describe OpenFoodNetwork::OrdersAndFulfillmentsReport do - include AuthenticationWorkflow + include AuthenticationHelper let(:distributor) { create(:distributor_enterprise) } let(:order_cycle) { create(:simple_order_cycle) } diff --git a/spec/lib/open_food_network/packing_report_spec.rb b/spec/lib/open_food_network/packing_report_spec.rb index 197224d5d8..462baf0b58 100644 --- a/spec/lib/open_food_network/packing_report_spec.rb +++ b/spec/lib/open_food_network/packing_report_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'open_food_network/packing_report' -include AuthenticationWorkflow +include AuthenticationHelper module OpenFoodNetwork describe PackingReport do diff --git a/spec/lib/open_food_network/reports/report_spec.rb b/spec/lib/open_food_network/reports/report_spec.rb deleted file mode 100644 index 86e76bcec5..0000000000 --- a/spec/lib/open_food_network/reports/report_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'open_food_network/reports/report' - -module OpenFoodNetwork::Reports - class TestReport < Report - header 'One', 'Two', 'Three', 'Four' - end - - describe Report do - let(:report) { TestReport.new } - - it "returns the header" do - expect(report.header).to eq(%w(One Two Three Four)) - end - end -end diff --git a/spec/lib/open_food_network/reports/row_spec.rb b/spec/lib/open_food_network/reports/row_spec.rb deleted file mode 100644 index c541832edf..0000000000 --- a/spec/lib/open_food_network/reports/row_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'spec_helper' -require 'open_food_network/reports/row' - -module OpenFoodNetwork::Reports - describe Row do - let(:row) { Row.new } - # rubocop:disable Style/Proc - let(:proc) { Proc.new {} } - # rubocop:enable Style/Proc - - it "can define a number of columns and return them as an array" do - row.column(&proc) - row.column(&proc) - row.column(&proc) - - expect(row.to_a).to eq([proc, proc, proc]) - end - end -end diff --git a/spec/lib/open_food_network/reports/rule_spec.rb b/spec/lib/open_food_network/reports/rule_spec.rb deleted file mode 100644 index eae5b26045..0000000000 --- a/spec/lib/open_food_network/reports/rule_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'spec_helper' -require 'open_food_network/reports/rule' - -module OpenFoodNetwork::Reports - describe Rule do - let(:rule) { Rule.new } - # rubocop:disable Style/Proc - let(:proc) { Proc.new {} } - # rubocop:enable Style/Proc - - it "can define a group proc and return it in a hash" do - rule.group(&proc) - expect(rule.to_h).to eq(group_by: proc, sort_by: nil) - end - - it "can define a sort proc and return it in a hash" do - rule.sort(&proc) - expect(rule.to_h).to eq(group_by: nil, sort_by: proc) - end - end -end diff --git a/spec/lib/open_food_network/users_and_enterprises_report_spec.rb b/spec/lib/open_food_network/users_and_enterprises_report_spec.rb index 0587e7bbaa..f7503d992c 100644 --- a/spec/lib/open_food_network/users_and_enterprises_report_spec.rb +++ b/spec/lib/open_food_network/users_and_enterprises_report_spec.rb @@ -3,8 +3,6 @@ require 'open_food_network/users_and_enterprises_report' module OpenFoodNetwork describe UsersAndEnterprisesReport do - include AuthenticationWorkflow - describe "users_and_enterprises" do let!(:owners_and_enterprises) { double(:owners_and_enterprises) } let!(:managers_and_enterprises) { double(:managers_and_enterprises) } @@ -63,8 +61,8 @@ module OpenFoodNetwork end describe "filtering results" do - let!(:enterprise1) { create(:enterprise, owner: create_enterprise_user ) } - let!(:enterprise2) { create(:enterprise, owner: create_enterprise_user ) } + let!(:enterprise1) { create(:enterprise, owner: create(:user) ) } + let!(:enterprise2) { create(:enterprise, owner: create(:user) ) } describe "for owners and enterprises" do describe "by enterprise id" do @@ -103,8 +101,8 @@ module OpenFoodNetwork end describe "by user id" do - let!(:manager1) { create_enterprise_user } - let!(:manager2) { create_enterprise_user } + let!(:manager1) { create(:user) } + let!(:manager2) { create(:user) } let!(:params) { { user_id_in: [manager1.id.to_s] } } let!(:subject) { OpenFoodNetwork::UsersAndEnterprisesReport.new params, true } diff --git a/spec/lib/spree/core/calculated_adjustments_spec.rb b/spec/lib/spree/core/calculated_adjustments_spec.rb new file mode 100644 index 0000000000..b9210c4f29 --- /dev/null +++ b/spec/lib/spree/core/calculated_adjustments_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# Its pretty difficult to test this module in isolation b/c it needs to work in conjunction +# with an actual class that extends ActiveRecord::Base and has a corresponding table in the DB. +# So we'll just test it using Order and ShippingMethod. These classes are including the module. +describe Spree::Core::CalculatedAdjustments do + let(:calculator) { build(:calculator) } + let(:tax_rate) { Spree::TaxRate.new(calculator: calculator) } + + before do + allow(calculator).to receive(:compute) { 10 } + allow(calculator).to receive(:[]) { nil } + end + + it "should add has_one :calculator relationship" do + assert Spree::ShippingMethod. + reflect_on_all_associations(:has_one).map(&:name).include?(:calculator) + end + + context "#create_adjustment and its resulting adjustment" do + let(:order) { Spree::Order.create } + let(:target) { order } + + it "should be associated with the target" do + expect(target.adjustments).to receive(:create) + tax_rate.create_adjustment("foo", target, order) + end + + it "should have the correct originator and an amount derived from the calculator and supplied calculable" do + adjustment = tax_rate.create_adjustment("foo", target, order) + expect(adjustment).not_to be_nil + expect(adjustment.amount).to eq 10 + expect(adjustment.source).to eq order + expect(adjustment.originator).to eq tax_rate + end + + it "should be mandatory if true is supplied for that parameter" do + adjustment = tax_rate.create_adjustment("foo", target, order, true) + expect(adjustment).to be_mandatory + end + + context "when the calculator returns 0" do + before { allow(calculator).to receive_messages(compute: 0) } + + context "when adjustment is mandatory" do + before { tax_rate.create_adjustment("foo", target, order, true) } + + it "should create an adjustment" do + expect(Spree::Adjustment.count).to eq 1 + end + end + + context "when adjustment is not mandatory" do + before { tax_rate.create_adjustment("foo", target, order, false) } + + it "should not create an adjustment" do + expect(Spree::Adjustment.count).to eq 0 + end + end + end + end + + context "#update_adjustment" do + it "should update the adjustment using its calculator (and the specified source)" do + adjustment = double(:adjustment).as_null_object + calculable = double :calculable + expect(adjustment).to receive(:update_column).with(:amount, 10) + tax_rate.update_adjustment(adjustment, calculable) + end + end +end diff --git a/spec/lib/spree/core/environment_spec.rb b/spec/lib/spree/core/environment_spec.rb new file mode 100644 index 0000000000..7eec8dc329 --- /dev/null +++ b/spec/lib/spree/core/environment_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Spree::Core::Environment do + # Our version doesn't add any features we could test. + # So we just check that our file is loaded correctly. + let(:our_file) { Rails.root.join("lib/spree/core/environment.rb").to_s } + + it "is defined in our code" do + file = subject.method(:initialize).source_location.first + expect(file).to eq our_file + end + + it "used by Spree" do + file = Spree::Core::Engine.config.spree.method(:initialize).source_location.first + expect(file).to eq our_file + end +end diff --git a/spec/lib/spree/core/mail_interceptor_spec.rb b/spec/lib/spree/core/mail_interceptor_spec.rb new file mode 100644 index 0000000000..48a7f948bb --- /dev/null +++ b/spec/lib/spree/core/mail_interceptor_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# Here we use the OrderMailer as a way to test the mail interceptor. +describe Spree::OrderMailer do + let(:order) do + Spree::Order.new(distributor: create(:enterprise), + bill_address: create(:address)) + end + let(:message) { Spree::OrderMailer.confirm_email_for_shop(order) } + + before(:all) do + ActionMailer::Base.perform_deliveries = true + ActionMailer::Base.deliveries.clear + end + + context "#deliver" do + before do + ActionMailer::Base.delivery_method = :test + end + + after { ActionMailer::Base.deliveries.clear } + + it "should use the from address specified in the preference" do + Spree::Config[:mails_from] = "no-reply@foobar.com" + message.deliver + @email = ActionMailer::Base.deliveries.first + expect(@email.from).to eq ["no-reply@foobar.com"] + end + + it "should use the provided from address" do + Spree::Config[:mails_from] = "preference@foobar.com" + message.from = "override@foobar.com" + message.to = "test@test.com" + message.deliver + email = ActionMailer::Base.deliveries.first + expect(email.from).to eq ["override@foobar.com"] + expect(email.to).to eq ["test@test.com"] + end + + it "should add the bcc email when provided" do + Spree::Config[:mail_bcc] = "bcc-foo@foobar.com" + message.deliver + @email = ActionMailer::Base.deliveries.first + expect(@email.bcc).to eq ["bcc-foo@foobar.com"] + end + + context "when intercept_email is provided" do + it "should strip the bcc recipients" do + expect(message.bcc).to be_blank + end + + it "should strip the cc recipients" do + expect(message.cc).to be_blank + end + + it "should replace the receipient with the specified address" do + Spree::Config[:intercept_email] = "intercept@foobar.com" + message.deliver + @email = ActionMailer::Base.deliveries.first + expect(@email.to).to eq ["intercept@foobar.com"] + end + + it "should modify the subject to include the original email" do + Spree::Config[:intercept_email] = "intercept@foobar.com" + message.deliver + @email = ActionMailer::Base.deliveries.first + expect(@email.subject).to include order.distributor.contact.email + end + end + + context "when intercept_mode is not provided" do + it "should not modify the recipient" do + Spree::Config[:intercept_email] = "" + message.deliver + @email = ActionMailer::Base.deliveries.first + expect(@email.to).to eq [order.distributor.contact.email] + end + end + end +end diff --git a/spec/lib/spree/core/mail_settings_spec.rb b/spec/lib/spree/core/mail_settings_spec.rb new file mode 100644 index 0000000000..a8db4d5eed --- /dev/null +++ b/spec/lib/spree/core/mail_settings_spec.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require 'spec_helper' + +module Spree + module Core + describe MailSettings do + let!(:subject) { MailSettings.new } + + context "override option is true" do + before { Config.override_actionmailer_config = true } + + context "init" do + it "calls override!" do + expect(MailSettings).to receive(:new).and_return(subject) + expect(subject).to receive(:override!) + MailSettings.init + end + end + + context "enable delivery" do + before { Config.enable_mail_delivery = true } + + context "overrides appplication defaults" do + context "authentication method is none" do + before do + Config.mail_host = "smtp.example.com" + Config.mail_domain = "example.com" + Config.mail_port = 123 + Config.mail_auth_type = MailSettings::SECURE_CONNECTION_TYPES[0] + Config.smtp_username = "schof" + Config.smtp_password = "hellospree!" + Config.secure_connection_type = "TLS" + subject.override! + end + + it { expect(ActionMailer::Base.smtp_settings[:address]).to eq "smtp.example.com" } + it { expect(ActionMailer::Base.smtp_settings[:domain]).to eq "example.com" } + it { expect(ActionMailer::Base.smtp_settings[:port]).to eq 123 } + it { expect(ActionMailer::Base.smtp_settings[:authentication]).to eq "None" } + it { expect(ActionMailer::Base.smtp_settings[:enable_starttls_auto]).to be_truthy } + + it "doesnt touch user name config" do + expect(ActionMailer::Base.smtp_settings[:user_name]).to be_nil + end + + it "doesnt touch password config" do + expect(ActionMailer::Base.smtp_settings[:password]).to be_nil + end + end + end + + context "when mail_auth_type is other than none" do + before do + Config.mail_auth_type = "login" + Config.smtp_username = "schof" + Config.smtp_password = "hellospree!" + subject.override! + end + + context "overrides user credentials" do + it { expect(ActionMailer::Base.smtp_settings[:user_name]).to eq "schof" } + it { expect(ActionMailer::Base.smtp_settings[:password]).to eq "hellospree!" } + end + end + end + + context "do not enable delivery" do + before do + Config.enable_mail_delivery = false + subject.override! + end + + it { expect(ActionMailer::Base.perform_deliveries).to be_falsy } + end + end + + context "override option is false" do + before { Config.override_actionmailer_config = false } + + context "init" do + it "doesnt calls override!" do + expect(subject).not_to receive(:override!) + MailSettings.init + end + end + end + end + end +end diff --git a/spec/lib/spree/core/token_resource_spec.rb b/spec/lib/spree/core/token_resource_spec.rb new file mode 100644 index 0000000000..087c5b9350 --- /dev/null +++ b/spec/lib/spree/core/token_resource_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# Its pretty difficult to test this module in isolation b/c it needs to work in conjunction +# with an actual class that extends ActiveRecord::Base and has a corresponding table in the DB. +# So we'll just test it using Order instead since it included the module. +describe Spree::Core::TokenResource do + let(:order) { Spree::Order.new } + let(:permission) { double(Spree::TokenizedPermission) } + + it 'should add has_one :tokenized_permission relationship' do + assert Spree::Order. + reflect_on_all_associations(:has_one).map(&:name).include?(:tokenized_permission) + end + + context '#token' do + it 'should return the token of the associated permission' do + allow(order).to receive_messages tokenized_permission: permission + allow(permission).to receive_messages token: 'foo' + expect(order.token).to eq 'foo' + end + + it 'should return nil if there is no associated permission' do + expect(order.token).to be_nil + end + end + + context '#create_token' do + it 'should create a randomized 16 character token' do + token = order.create_token + expect(token.size).to eq 16 + end + end +end diff --git a/spec/lib/spree/i18n_spec.rb b/spec/lib/spree/i18n_spec.rb new file mode 100644 index 0000000000..386dd9d2ec --- /dev/null +++ b/spec/lib/spree/i18n_spec.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require 'rspec/expectations' +require 'spree/i18n' +require 'spree/testing_support/i18n' + +describe "i18n" do + before do + I18n.backend.store_translations( + :en, + { + spree: { + foo: "bar", + bar: { + foo: "bar within bar scope", + invalid: nil, + legacy_translation: "back in the day..." + }, + invalid: nil, + legacy_translation: "back in the day..." + } + } + ) + end + + it "translates within the spree scope" do + expect(Spree.normal_t(:foo)).to eql("bar") + expect(Spree.translate(:foo)).to eql("bar") + end + + it "translates within the spree scope using a path" do + allow(Spree).to receive(:virtual_path).and_return('bar') + + expect(Spree.normal_t('.legacy_translation')).to eql("back in the day...") + expect(Spree.translate('.legacy_translation')).to eql("back in the day...") + end + + it "raise error without any context when using a path" do + expect { + Spree.normal_t('.legacy_translation') + }.to raise_error + + expect { + Spree.translate('.legacy_translation') + }.to raise_error + end + + it "prepends a string scope" do + expect(Spree.normal_t(:foo, scope: "bar")).to eql("bar within bar scope") + end + + it "prepends to an array scope" do + expect(Spree.normal_t(:foo, scope: ["bar"])).to eql("bar within bar scope") + end + + it "returns two translations" do + expect(Spree.normal_t([:foo, 'bar.foo'])).to eql(["bar", "bar within bar scope"]) + end + + it "returns reasonable string for missing translations" do + expect(Spree.t(:missing_entry)).to include(" 'avs-code' }) + @fail_response = double('gateway_response', success?: false) + + @payment_gateway = create(:payment_method, + environment: 'test') + allow(@payment_gateway).to receive_messages :payment_profiles_supported? => true, + :authorize => @success_response, + :purchase => @success_response, + :capture => @success_response, + :void => @success_response, + :credit => @success_response + allow(@payment).to receive_messages payment_method: @payment_gateway + end + + context "#can_capture?" do + it "should be true if payment is pending" do + payment = create(:payment, created_at: Time.zone.now) + allow(payment).to receive(:pending?) { true } + expect(credit_card.can_capture?(payment)).to be_truthy + end + + it "should be true if payment is checkout" do + payment = create(:payment, created_at: Time.zone.now) + allow(payment).to receive_messages :pending? => false, + :checkout? => true + expect(credit_card.can_capture?(payment)).to be_truthy + end + end + + context "#can_void?" do + it "should be true if payment is not void" do + payment = create(:payment) + allow(payment).to receive(:void?) { false } + expect(credit_card.can_void?(payment)).to be_truthy + end + end + + context "#can_credit?" do + it "should be false if payment is not completed" do + payment = create(:payment) + allow(payment).to receive(:completed?) { false } + expect(credit_card.can_credit?(payment)).to be_falsy + end + + it "should be false when order payment_state is not 'credit_owed'" do + payment = create(:payment, + order: create(:order, payment_state: 'paid')) + allow(payment).to receive(:completed?) { true } + expect(credit_card.can_credit?(payment)).to be_falsy + end + + it "should be false when credit_allowed is zero" do + payment = create(:payment, + order: create(:order, payment_state: 'credit_owed')) + allow(payment).to receive_messages :completed? => true, + :credit_allowed => 0 + + expect(credit_card.can_credit?(payment)).to be_falsy + end + end + + context "#valid?" do + it "should validate presence of number" do + credit_card.attributes = valid_credit_card_attributes.except(:number) + expect(credit_card).to_not be_valid + expect(credit_card.errors[:number]).to eq ["can't be blank"] + end + + it "should validate presence of security code" do + credit_card.attributes = valid_credit_card_attributes.except(:verification_value) + expect(credit_card).to_not be_valid + expect(credit_card.errors[:verification_value]).to eq ["can't be blank"] + end + + it "should validate expiration is not in the past" do + credit_card.month = 1.month.ago.month + credit_card.year = 1.month.ago.year + expect(credit_card).to_not be_valid + expect(credit_card.errors[:base]).to eq ["has expired"] + end + + it "does not run expiration in the past validation if month is not set" do + credit_card.month = nil + credit_card.year = Time.zone.now.year + expect(credit_card).to_not be_valid + expect(credit_card.errors[:base]).to be_blank + end + + it "does not run expiration in the past validation if year is not set" do + credit_card.month = Time.zone.now.month + credit_card.year = nil + expect(credit_card).to_not be_valid + expect(credit_card.errors[:base]).to be_blank + end + + it "does not run expiration in the past validation if year and month are empty" do + credit_card.year = "" + credit_card.month = "" + expect(credit_card).to_not be_valid + expect(credit_card.errors[:card]).to be_blank + end + + it "should only validate on create" do + credit_card.attributes = valid_credit_card_attributes + credit_card.save + expect(credit_card).to be_valid + end + end + + context "#save" do + before do + credit_card.attributes = valid_credit_card_attributes + credit_card.save! + end + + let!(:persisted_card) { Spree::CreditCard.find(credit_card.id) } + + it "should not actually store the number" do + expect(persisted_card.number).to be_blank + end + + it "should not actually store the security code" do + expect(persisted_card.verification_value).to be_blank + end + end + + context "#number=" do + it "should strip non-numeric characters from card input" do + credit_card.number = "6011000990139424" + expect(credit_card.number).to eq "6011000990139424" + + credit_card.number = " 6011-0009-9013-9424 " + expect(credit_card.number).to eq "6011000990139424" + end + + it "should not raise an exception on non-string input" do + credit_card.number = ({}) + expect(credit_card.number).to be_nil + end + end + + context "#cc_type=" do + it "converts between the different types" do + credit_card.cc_type = 'mastercard' + expect(credit_card.cc_type).to eq 'master' + + credit_card.cc_type = 'maestro' + expect(credit_card.cc_type).to eq 'master' + + credit_card.cc_type = 'amex' + expect(credit_card.cc_type).to eq 'american_express' + + credit_card.cc_type = 'dinersclub' + expect(credit_card.cc_type).to eq 'diners_club' + + credit_card.cc_type = 'some_outlandish_cc_type' + expect(credit_card.cc_type).to eq 'some_outlandish_cc_type' + end + end + + context "#associations" do + it "should be able to access its payments" do + expect { credit_card.payments.to_a }.not_to raise_error + end + end + + context "#to_active_merchant" do + before do + credit_card.number = "4111111111111111" + credit_card.year = Time.zone.now.year + credit_card.month = Time.zone.now.month + credit_card.first_name = "Bob" + credit_card.last_name = "Boblaw" + credit_card.verification_value = 123 + end + + it "converts to an ActiveMerchant::Billing::CreditCard object" do + am_card = credit_card.to_active_merchant + expect(am_card.number).to eq "4111111111111111" + expect(am_card.year).to eq Time.zone.now.year + expect(am_card.month).to eq Time.zone.now.month + expect(am_card.first_name).to eq "Bob" + am_card.last_name = "Boblaw" + expect(am_card.verification_value).to eq 123 + end + end + end + describe "setting default credit card for a user" do let(:user) { create(:user) } let(:onetime_card_attrs) do diff --git a/spec/models/spree/gateway_spec.rb b/spec/models/spree/gateway_spec.rb new file mode 100644 index 0000000000..294073a559 --- /dev/null +++ b/spec/models/spree/gateway_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Spree::Gateway do + class Provider + def initialize(options); end + + def imaginary_method; end + end + + class TestGateway < Spree::Gateway + def provider_class + Provider + end + end + + it "passes through all arguments on a method_missing call" do + gateway = TestGateway.new + expect(gateway.provider).to receive(:imaginary_method).with('foo') + gateway.imaginary_method('foo') + end +end diff --git a/spec/models/spree/line_item_spec.rb b/spec/models/spree/line_item_spec.rb index bef32dc8d7..2836c2c51c 100644 --- a/spec/models/spree/line_item_spec.rb +++ b/spec/models/spree/line_item_spec.rb @@ -97,7 +97,7 @@ module Spree end it "caps at zero when stock is negative" do - v.update! on_hand: -2 + v.__send__(:stock_item).update_column(:count_on_hand, -2) li.cap_quantity_at_stock! expect(li.reload.quantity).to eq 0 end @@ -123,7 +123,7 @@ module Spree before { vo.update(count_on_hand: -3) } it "caps at zero" do - v.update(on_hand: -2) + v.__send__(:stock_item).update_column(:count_on_hand, -2) li.cap_quantity_at_stock! expect(li.reload.quantity).to eq 0 end diff --git a/spec/models/spree/order/checkout_spec.rb b/spec/models/spree/order/checkout_spec.rb index 8eed383c6a..5f49792aa2 100644 --- a/spec/models/spree/order/checkout_spec.rb +++ b/spec/models/spree/order/checkout_spec.rb @@ -1,6 +1,306 @@ require 'spec_helper' describe Spree::Order do + let(:order) { Spree::Order.new } + + context "with default state machine" do + let(:transitions) do + [ + { address: :delivery }, + { delivery: :payment }, + { payment: :complete }, + { delivery: :complete } + ] + end + + it "has the following transitions" do + transitions.each do |transition| + puts transition.keys.first + puts transition.values.first + transition = Spree::Order.find_transition(from: transition.keys.first, + to: transition.values.first) + expect(transition).to_not be_nil + end + end + + it "does not have a transition from delivery to confirm" do + transition = Spree::Order.find_transition(from: :delivery, to: :confirm) + expect(transition).to be_nil + end + + it '.find_transition when contract was broken' do + expect(Spree::Order.find_transition({ foo: :bar, baz: :dog })).to be_falsy + end + + it '.remove_transition' do + options = { from: transitions.first.keys.first, to: transitions.first.values.first } + allow(Spree::Order).to receive(:next_event_transition).and_return([options]) + expect(Spree::Order.remove_transition(options)).to be_truthy + end + + it '.remove_transition when contract was broken' do + expect(Spree::Order.remove_transition(nil)).to be_falsy + end + + context "#checkout_steps" do + context "when payment not required" do + before { allow(order).to receive_messages payment_required?: false } + specify do + expect(order.checkout_steps).to eq %w(address delivery complete) + end + end + + context "when payment required" do + before { allow(order).to receive_messages payment_required?: true } + specify do + expect(order.checkout_steps).to eq %w(address delivery payment complete) + end + end + end + + it "starts out at cart" do + expect(order.state).to eq "cart" + end + + it "transitions to address" do + order.line_items << FactoryGirl.create(:line_item) + order.email = "user@example.com" + order.next! + expect(order.state).to eq "address" + end + + it "cannot transition to address without any line items" do + expect(order.line_items).to be_blank + expect(lambda { order.next! }).to raise_error(StateMachine::InvalidTransition, + /#{Spree.t(:there_are_no_items_for_this_order)}/) + end + + context "from address" do + before do + order.state = 'address' + allow(order).to receive(:has_available_payment) + order.shipments << create(:shipment) + order.email = "user@example.com" + order.save! + end + + it "transitions to delivery" do + allow(order).to receive_messages(ensure_available_shipping_rates: true) + order.next! + expect(order.state).to eq "delivery" + end + + context "cannot transition to delivery" do + context "if there are no shipping rates for any shipment" do + specify do + transition = lambda { order.next! } + expect(transition).to raise_error(StateMachine::InvalidTransition, + /#{Spree.t(:items_cannot_be_shipped)}/) + end + end + end + end + + context "from delivery" do + before do + order.state = 'delivery' + end + + context "with payment required" do + before do + allow(order).to receive_messages payment_required?: true + end + + it "transitions to payment" do + order.next! + expect(order.state).to eq 'payment' + end + end + + context "without payment required" do + before do + allow(order).to receive_messages payment_required?: false + end + + it "transitions to complete" do + order.next! + expect(order.state).to eq "complete" + end + end + end + + context "from payment" do + before do + order.state = 'payment' + end + + context "when payment is required" do + before do + allow(order).to receive_messages confirmation_required?: false + allow(order).to receive_messages payment_required?: true + end + + it "transitions to complete" do + expect(order).to receive(:process_payments!).once.and_return true + order.next! + expect(order.state).to eq "complete" + end + end + + # Regression test for #2028 + context "when payment is not required" do + before do + allow(order).to receive_messages payment_required?: false + end + + it "does not call process payments" do + expect(order).to_not receive(:process_payments!) + order.next! + expect(order.state).to eq "complete" + end + end + end + end + + context "subclassed order" do + # This causes another test above to fail, but fixing this test should make + # the other test pass + class SubclassedOrder < Spree::Order + checkout_flow do + go_to_state :payment + go_to_state :complete + end + end + + it "should only call default transitions once when checkout_flow is redefined" do + order = SubclassedOrder.new + allow(order).to receive_messages payment_required?: true + expect(order).to receive(:process_payments!).once + order.state = "payment" + order.next! + expect(order.state).to eq "complete" + end + end + + context "re-define checkout flow" do + before do + @old_checkout_flow = Spree::Order.checkout_flow + Spree::Order.class_eval do + checkout_flow do + go_to_state :payment + go_to_state :complete + end + end + end + + after do + Spree::Order.checkout_flow(&@old_checkout_flow) + end + + it "should not keep old event transitions when checkout_flow is redefined" do + expect(Spree::Order.next_event_transitions).to eq [{ cart: :payment }, { payment: :complete }] + end + + it "should not keep old events when checkout_flow is redefined" do + state_machine = Spree::Order.state_machine + expect(state_machine.states.any? { |s| s.name == :address }).to be_falsy + known_states = state_machine.events[:next].branches.map(&:known_states).flatten + expect(known_states).to_not include(:address) + expect(known_states).to_not include(:delivery) + expect(known_states).to_not include(:confirm) + end + end + + # Regression test for #3665 + context "with only a complete step" do + before do + @old_checkout_flow = Spree::Order.checkout_flow + Spree::Order.class_eval do + checkout_flow do + go_to_state :complete + end + end + end + + after do + Spree::Order.checkout_flow(&@old_checkout_flow) + end + + it "does not attempt to process payments" do + allow(order).to receive_message_chain(:line_items, :present?).and_return(true) + expect(order).to_not receive(:payment_required?) + expect(order).to_not receive(:process_payments!) + order.next! + end + end + + context "insert checkout step" do + before do + @old_checkout_flow = Spree::Order.checkout_flow + Spree::Order.class_eval do + insert_checkout_step :new_step, before: :address + end + end + + after do + Spree::Order.checkout_flow(&@old_checkout_flow) + end + + it "should maintain removed transitions" do + transition = Spree::Order.find_transition(from: :delivery, to: :confirm) + expect(transition).to be_nil + end + + context "before" do + before do + Spree::Order.class_eval do + insert_checkout_step :before_address, before: :address + end + end + + specify do + order = Spree::Order.new + expect(order.checkout_steps).to eq %w(new_step before_address address delivery complete) + end + end + + context "after" do + before do + Spree::Order.class_eval do + insert_checkout_step :after_address, after: :address + end + end + + specify do + order = Spree::Order.new + expect(order.checkout_steps).to eq %w(new_step address after_address delivery complete) + end + end + end + + context "remove checkout step" do + before do + @old_checkout_flow = Spree::Order.checkout_flow + Spree::Order.class_eval do + remove_checkout_step :address + end + end + + after do + Spree::Order.checkout_flow(&@old_checkout_flow) + end + + it "should maintain removed transitions" do + transition = Spree::Order.find_transition(from: :delivery, to: :confirm) + expect(transition).to be_nil + end + + specify do + order = Spree::Order.new + expect(order.checkout_steps).to eq %w(delivery complete) + end + end + describe 'event :restart_checkout' do let(:order) { create(:order) } diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index 0c2c3d33e5..5c583a5252 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -855,12 +855,39 @@ describe Spree::Order do order.state = 'delivery' # payment's previous state allow(order).to receive(:payment_required?) { true } - allow(order).to receive(:charge_shipping_and_payment_fees!) end - it 'calls charge_shipping_and_payment_fees!' do + it 'calls charge_shipping_and_payment_fees! and updates totals' do + expect(order).to receive(:charge_shipping_and_payment_fees!) + expect(order).to receive(:update_totals).at_least(:once) + order.next - expect(order).to have_received(:charge_shipping_and_payment_fees!) + end + + context "payment's amount" do + let(:failed_payment) { create(:payment, order: order, state: 'failed', amount: 100) } + + before do + allow(order).to receive(:total) { 120 } + end + + it 'is not updated for failed payments' do + failed_payment + + order.next + + expect(failed_payment.reload.amount).to eq 100 + end + + it 'is updated only for pending payments' do + pending_payment = create(:payment, order: order, state: 'pending', amount: 80) + failed_payment + + order.next + + expect(failed_payment.reload.amount).to eq 100 + expect(pending_payment.reload.amount).to eq 120 + end end end end diff --git a/spec/models/spree/payment_method_spec.rb b/spec/models/spree/payment_method_spec.rb index 396b9f1ab0..3e0d99c5fa 100644 --- a/spec/models/spree/payment_method_spec.rb +++ b/spec/models/spree/payment_method_spec.rb @@ -1,7 +1,46 @@ require 'spec_helper' +class Spree::Gateway::Test < Spree::Gateway +end + module Spree describe PaymentMethod do + describe "#available" do + let(:enterprise) { create(:enterprise) } + + before do + Spree::PaymentMethod.delete_all + + [nil, 'both', 'front_end', 'back_end'].each do |display_on| + Spree::Gateway::Test.create( + name: 'Display Both', + display_on: display_on, + active: true, + environment: 'test', + description: 'foofah', + distributors: [enterprise] + ) + end + expect(Spree::PaymentMethod.all.size).to eq 4 + end + + it "should return all methods available to front-end/back-end when no parameter is passed" do + expect(Spree::PaymentMethod.available.size).to eq 2 + end + + it "should return all methods available to front-end/back-end when display_on = :both" do + expect(Spree::PaymentMethod.available(:both).size).to eq 2 + end + + it "should return all methods available to front-end when display_on = :front_end" do + expect(Spree::PaymentMethod.available(:front_end).size).to eq 2 + end + + it "should return all methods available to back-end when display_on = :back_end" do + expect(Spree::PaymentMethod.available(:back_end).size).to eq 2 + end + end + it "orders payment methods by name" do pm1 = create(:payment_method, name: 'ZZ') pm2 = create(:payment_method, name: 'AA') diff --git a/spec/models/spree/payment_spec.rb b/spec/models/spree/payment_spec.rb index 1ca723566c..200efab868 100644 --- a/spec/models/spree/payment_spec.rb +++ b/spec/models/spree/payment_spec.rb @@ -1,7 +1,687 @@ require 'spec_helper' -module Spree - describe Payment do +describe Spree::Payment do + context 'original specs from Spree' do + let(:order) { create(:order) } + let(:gateway) do + gateway = Spree::Gateway::Bogus.new(:environment => 'test', :active => true) + gateway.stub :source_required => true + gateway + end + + let(:card) { create(:credit_card) } + + before { allow(card).to receive(:has_payment_profile?).and_return(true) } + + let(:payment) do + payment = create(:payment) + payment.source = card + payment.order = order + payment.payment_method = gateway + payment + end + + let(:amount_in_cents) { payment.amount.to_f * 100 } + + let!(:success_response) do + double('success_response', :success? => true, + :authorization => '123', + :avs_result => { 'code' => 'avs-code' }, + :cvv_result => { 'code' => 'cvv-code', 'message' => "CVV Result"}) + end + + let(:failed_response) { double('gateway_response', :success? => false) } + + before(:each) do + # So it doesn't create log entries every time a processing method is called + allow(payment).to receive(:record_response) + end + + context "extends LocalizedNumber" do + it_behaves_like "a model using the LocalizedNumber module", [:amount] + end + + context 'validations' do + it "returns useful error messages when source is invalid" do + payment.source = Spree::CreditCard.new + expect(payment).not_to be_valid + cc_errors = payment.errors['Credit Card'] + expect(cc_errors).to include("Number can't be blank") + expect(cc_errors).to include("Month is not a number") + expect(cc_errors).to include("Year is not a number") + expect(cc_errors).to include("Verification Value can't be blank") + end + end + + # Regression test for https://github.com/spree/spree/pull/2224 + context 'failure' do + it 'should transition to failed from pending state' do + payment.state = 'pending' + payment.failure + expect(payment.state).to eql('failed') + end + + it 'should transition to failed from processing state' do + payment.state = 'processing' + payment.failure + expect(payment.state).to eql('failed') + end + + end + + context 'invalidate' do + it 'should transition from checkout to invalid' do + payment.state = 'checkout' + payment.invalidate + expect(payment.state).to eq('invalid') + end + end + + context "processing" do + before do + payment.stub(:update_order) + payment.stub(:create_payment_profile) + end + + context "#process!" do + it "should purchase if with auto_capture" do + payment.payment_method.should_receive(:auto_capture?).and_return(true) + payment.should_receive(:purchase!) + payment.process! + end + + it "should authorize without auto_capture" do + payment.payment_method.should_receive(:auto_capture?).and_return(false) + payment.should_receive(:authorize!) + payment.process! + end + + it "should make the state 'processing'" do + payment.should_receive(:started_processing!) + payment.process! + end + + it "should invalidate if payment method doesnt support source" do + payment.payment_method.should_receive(:supports?).with(payment.source).and_return(false) + expect { payment.process!}.to raise_error(Spree::Core::GatewayError) + expect(payment.state).to eq('invalid') + end + + end + + context "#authorize" do + it "should call authorize on the gateway with the payment amount" do + payment.payment_method.should_receive(:authorize).with(amount_in_cents, + card, + anything).and_return(success_response) + payment.authorize! + end + + it "should call authorize on the gateway with the currency code" do + payment.stub :currency => 'GBP' + payment.payment_method.should_receive(:authorize).with(amount_in_cents, + card, + hash_including({:currency => "GBP"})).and_return(success_response) + payment.authorize! + end + + it "should log the response" do + payment.authorize! + expect(payment).to have_received(:record_response) + end + + context "when gateway does not match the environment" do + it "should raise an exception" do + gateway.stub :environment => "foo" + expect { payment.authorize! }.to raise_error(Spree::Core::GatewayError) + end + end + + context "if successful" do + before do + payment.payment_method.should_receive(:authorize).with(amount_in_cents, + card, + anything).and_return(success_response) + end + + it "should store the response_code, avs_response and cvv_response fields" do + payment.authorize! + expect(payment.response_code).to eq('123') + expect(payment.avs_response).to eq('avs-code') + expect(payment.cvv_response_code).to eq('cvv-code') + expect(payment.cvv_response_message).to eq('CVV Result') + end + + it "should make payment pending" do + payment.should_receive(:pend!) + payment.authorize! + end + end + + context "if unsuccessful" do + it "should mark payment as failed" do + gateway.stub(:authorize).and_return(failed_response) + payment.should_receive(:failure) + payment.should_not_receive(:pend) + expect { + payment.authorize! + }.to raise_error(Spree::Core::GatewayError) + end + end + end + + context "purchase" do + it "should call purchase on the gateway with the payment amount" do + gateway.should_receive(:purchase).with(amount_in_cents, card, anything).and_return(success_response) + payment.purchase! + end + + it "should log the response" do + payment.purchase! + expect(payment).to have_received(:record_response) + end + + context "when gateway does not match the environment" do + it "should raise an exception" do + gateway.stub :environment => "foo" + expect { payment.purchase! }.to raise_error(Spree::Core::GatewayError) + end + end + + context "if successful" do + before do + payment.payment_method.should_receive(:purchase).with(amount_in_cents, + card, + anything).and_return(success_response) + end + + it "should store the response_code and avs_response" do + payment.purchase! + expect(payment.response_code).to eq('123') + expect(payment.avs_response).to eq('avs-code') + end + + it "should make payment complete" do + payment.should_receive(:complete!) + payment.purchase! + end + end + + context "if unsuccessful" do + it "should make payment failed" do + gateway.stub(:purchase).and_return(failed_response) + payment.should_receive(:failure) + payment.should_not_receive(:pend) + expect { payment.purchase! }.to raise_error(Spree::Core::GatewayError) + end + end + end + + context "#capture" do + before do + payment.stub(:complete).and_return(true) + end + + context "when payment is pending" do + before do + payment.state = 'pending' + end + + context "if successful" do + before do + payment.payment_method.should_receive(:capture).with(payment, card, anything).and_return(success_response) + end + + it "should make payment complete" do + payment.should_receive(:complete) + payment.capture! + end + + it "should store the response_code" do + gateway.stub :capture => success_response + payment.capture! + expect(payment.response_code).to eq('123') + end + end + + context "if unsuccessful" do + it "should not make payment complete" do + gateway.stub :capture => failed_response + payment.should_receive(:failure) + payment.should_not_receive(:complete) + expect { payment.capture! }.to raise_error(Spree::Core::GatewayError) + end + end + end + + # Regression test for #2119 + context "when payment is completed" do + before do + payment.state = 'completed' + end + + it "should do nothing" do + payment.should_not_receive(:complete) + payment.payment_method.should_not_receive(:capture) + payment.log_entries.should_not_receive(:create) + payment.capture! + end + end + end + + context "#void" do + before do + payment.response_code = '123' + payment.state = 'pending' + end + + context "when profiles are supported" do + it "should call payment_gateway.void with the payment's response_code" do + gateway.stub :payment_profiles_supported? => true + gateway.should_receive(:void).with('123', card, anything).and_return(success_response) + payment.void_transaction! + end + end + + context "when profiles are not supported" do + it "should call payment_gateway.void with the payment's response_code" do + gateway.stub :payment_profiles_supported? => false + gateway.should_receive(:void).with('123', anything).and_return(success_response) + payment.void_transaction! + end + end + + it "should log the response" do + payment.void_transaction! + expect(payment).to have_received(:record_response) + end + + context "when gateway does not match the environment" do + it "should raise an exception" do + gateway.stub :environment => "foo" + expect { payment.void_transaction! }.to raise_error(Spree::Core::GatewayError) + end + end + + context "if successful" do + it "should update the response_code with the authorization from the gateway" do + # Change it to something different + payment.response_code = 'abc' + payment.void_transaction! + expect(payment.response_code).to eq('12345') + end + end + + context "if unsuccessful" do + it "should not void the payment" do + gateway.stub :void => failed_response + payment.should_not_receive(:void) + expect { payment.void_transaction! }.to raise_error(Spree::Core::GatewayError) + end + end + + # Regression test for #2119 + context "if payment is already voided" do + before do + payment.state = 'void' + end + + it "should not void the payment" do + payment.payment_method.should_not_receive(:void) + payment.void_transaction! + end + end + end + + context "#credit" do + before do + payment.state = 'completed' + payment.response_code = '123' + end + + context "when outstanding_balance is less than payment amount" do + before do + payment.order.stub :outstanding_balance => 10 + payment.stub :credit_allowed => 1000 + end + + it "should call credit on the gateway with the credit amount and response_code" do + gateway.should_receive(:credit).with(1000, card, '123', anything).and_return(success_response) + payment.credit! + end + end + + context "when outstanding_balance is equal to payment amount" do + before do + payment.order.stub :outstanding_balance => payment.amount + end + + it "should call credit on the gateway with the credit amount and response_code" do + gateway.should_receive(:credit).with(amount_in_cents, card, '123', anything).and_return(success_response) + payment.credit! + end + end + + context "when outstanding_balance is greater than payment amount" do + before do + payment.order.stub :outstanding_balance => 101 + end + + it "should call credit on the gateway with the original payment amount and response_code" do + gateway.should_receive(:credit).with(amount_in_cents.to_f, card, '123', anything).and_return(success_response) + payment.credit! + end + end + + it "should log the response" do + payment.credit! + expect(payment).to have_received(:record_response) + end + + context "when gateway does not match the environment" do + it "should raise an exception" do + gateway.stub :environment => "foo" + expect { payment.credit! }.to raise_error(Spree::Core::GatewayError) + end + end + + context "when response is successful" do + it "should create an offsetting payment" do + expect(Spree::Payment).to receive(:create!) + payment.credit! + end + + it "resulting payment should have correct values" do + allow(payment.order).to receive(:outstanding_balance) { 100 } + allow(payment).to receive(:credit_allowed) { 10 } + + offsetting_payment = payment.credit! + expect(offsetting_payment.amount.to_f).to eq(-10) + expect(offsetting_payment).to be_completed + expect(offsetting_payment.response_code).to eq('12345') + expect(offsetting_payment.source).to eq(payment) + end + + context 'and the source payment card is expired' do + let(:card) do + Spree::CreditCard.new(month: 12, year: 1995, number: '4111111111111111') + end + + let(:successful_response) do + ActiveMerchant::Billing::Response.new(true, "Yay!") + end + + it 'lets the new payment to be saved' do + allow(payment.order).to receive(:outstanding_balance) { 100 } + allow(payment).to receive(:credit_allowed) { 10 } + + offsetting_payment = payment.credit! + + expect(offsetting_payment).to be_valid + end + end + end + end + end + + context "when response is unsuccessful" do + it "should not create a payment" do + gateway.stub :credit => failed_response + Spree::Payment.should_not_receive(:create) + expect { payment.credit! }.to raise_error(Spree::Core::GatewayError) + end + end + + context "when already processing" do + it "should return nil without trying to process the source" do + payment.state = 'processing' + + payment.should_not_receive(:authorize!) + payment.should_not_receive(:purchase!) + expect(payment.process!).to be_nil + end + end + + context "with source required" do + context "raises an error if no source is specified" do + before do + payment.source = nil + end + + specify do + expect { payment.process! }.to raise_error(Spree::Core::GatewayError, Spree.t(:payment_processing_failed)) + end + end + end + + context "with source optional" do + context "raises no error if source is not specified" do + before do + payment.source = nil + payment.payment_method.stub(:source_required? => false) + end + + specify do + expect { payment.process! }.not_to raise_error + end + end + end + + context "#credit_allowed" do + it "is the difference between offsets total and payment amount" do + payment.amount = 100 + payment.stub(:offsets_total).and_return(0) + expect(payment.credit_allowed).to eq(100) + payment.stub(:offsets_total).and_return(80) + expect(payment.credit_allowed).to eq(20) + end + end + + context "#can_credit?" do + it "is true if credit_allowed > 0" do + payment.stub(:credit_allowed).and_return(100) + expect(payment.can_credit?).to be true + end + it "is false if credit_allowed is 0" do + payment.stub(:credit_allowed).and_return(0) + expect(payment.can_credit?).to be false + end + end + + context "#credit" do + context "when amount <= credit_allowed" do + it "makes the state processing" do + payment.payment_method.name = 'Gateway' + payment.payment_method.distributors << create(:distributor_enterprise) + payment.payment_method.save! + + payment.order = create(:order) + + payment.state = 'completed' + payment.stub(:credit_allowed).and_return(10) + payment.partial_credit(10) + expect(payment).to be_processing + end + it "calls credit on the source with the payment and amount" do + payment.state = 'completed' + payment.stub(:credit_allowed).and_return(10) + payment.should_receive(:credit!).with(10) + payment.partial_credit(10) + end + end + context "when amount > credit_allowed" do + it "should not call credit on the source" do + payment.state = 'completed' + payment.stub(:credit_allowed).and_return(10) + payment.partial_credit(20) + expect(payment).to be_completed + end + end + end + + context "#save" do + it "should call order#update!" do + gateway.name = 'Gateway' + gateway.distributors << create(:distributor_enterprise) + gateway.save! + + order = create(:order) + payment = Spree::Payment.create(:amount => 100, :order => order, :payment_method => gateway) + order.should_receive(:update!) + payment.save + end + + context "when profiles are supported" do + before do + gateway.stub :payment_profiles_supported? => true + payment.source.stub :has_payment_profile? => false + end + + + context "when there is an error connecting to the gateway" do + it "should call gateway_error " do + pending '[Spree build] Failing spec' + message = double("gateway_error") + connection_error = ActiveMerchant::ConnectionError.new(message, nil) + expect(gateway).to receive(:create_profile).and_raise(connection_error) + expect do + Spree::Payment.create( + :amount => 100, + :order => order, + :source => card, + :payment_method => gateway + ) + end.should raise_error(Spree::Core::GatewayError) + end + end + + context "when successfully connecting to the gateway" do + it "should create a payment profile" do + gateway.name = 'Gateway' + gateway.distributors << create(:distributor_enterprise) + gateway.save! + + payment.payment_method = gateway + payment.source.save_requested_by_customer = true + + expect(gateway).to receive(:create_profile) + + Spree::Payment.create( + :amount => 100, + :order => create(:order), + :source => card, + :payment_method => gateway + ) + end + end + + + end + + context "when profiles are not supported" do + before { gateway.stub :payment_profiles_supported? => false } + + it "should not create a payment profile" do + gateway.name = 'Gateway' + gateway.distributors << create(:distributor_enterprise) + gateway.save! + + gateway.should_not_receive :create_profile + payment = Spree::Payment.create( + :amount => 100, + :order => create(:order), + :source => card, + :payment_method => gateway + ) + end + end + end + + context "#build_source" do + it "should build the payment's source" do + params = { :amount => 100, :payment_method => gateway, + :source_attributes => { + :expiry =>"1 / 99", + :number => '1234567890123', + :verification_value => '123' + } + } + + payment = Spree::Payment.new(params) + expect(payment).to be_valid + expect(payment.source).not_to be_nil + end + + it "errors when payment source not valid" do + params = { :amount => 100, :payment_method => gateway, + :source_attributes => {:expiry => "1 / 12" }} + + payment = Spree::Payment.new(params) + expect(payment).not_to be_valid + expect(payment.source).not_to be_nil + expect(payment.source.errors[:number]).not_to be_empty + expect(payment.source.errors[:verification_value]).not_to be_empty + end + end + + context "#currency" do + before { order.stub(:currency) { "ABC" } } + it "returns the order currency" do + expect(payment.currency).to eq("ABC") + end + end + + context "#display_amount" do + it "returns a Spree::Money for this amount" do + expect(payment.display_amount).to eq(Spree::Money.new(payment.amount)) + end + end + + # Regression test for #2216 + context "#gateway_options" do + before { order.stub(:last_ip_address => "192.168.1.1") } + + it "contains an IP" do + expect(payment.gateway_options[:ip]).to eq(order.last_ip_address) + end + end + + context "#set_unique_identifier" do + # Regression test for #1998 + it "sets a unique identifier on create" do + payment.run_callbacks(:save) + expect(payment.identifier).not_to be_blank + expect(payment.identifier.size).to eq(8) + expect(payment.identifier).to be_a(String) + end + + context "other payment exists" do + let(:other_payment) { + gateway.name = 'Gateway' + gateway.distributors << create(:distributor_enterprise) + gateway.save! + + payment = Spree::Payment.new + payment.source = card + payment.order = create(:order) + payment.payment_method = gateway + payment + } + + before { other_payment.save! } + + it "doesn't set duplicate identifier" do + payment.should_receive(:generate_identifier).and_return(other_payment.identifier) + payment.should_receive(:generate_identifier).and_call_original + + payment.run_callbacks(:save) + + expect(payment.identifier).not_to be_blank + expect(payment.identifier).not_to eq(other_payment.identifier) + end + end + end + describe "available actions" do context "for most gateways" do let(:payment) { create(:payment, source: create(:credit_card)) } @@ -24,7 +704,7 @@ module Spree context "for Pin Payments" do let(:d) { create(:distributor_enterprise) } - let(:pin) { Gateway::Pin.create! name: 'pin', distributor_ids: [d.id] } + let(:pin) { Spree::Gateway::Pin.create! name: 'pin', distributor_ids: [d.id] } let(:payment) { create(:payment, source: create(:credit_card), payment_method: pin) } it "does not void" do @@ -45,7 +725,7 @@ module Spree end end - describe "refunding" do + describe "refund!" do let(:payment) { create(:payment) } let(:success) { double(success?: true, authorization: 'abc123') } let(:failure) { double(success?: false) } @@ -105,9 +785,9 @@ module Spree expect do payment.refund! - end.to change(Payment, :count).by(1) + end.to change(Spree::Payment, :count).by(1) - p = Payment.last + p = Spree::Payment.last expect(p.order).to eq(payment.order) expect(p.source).to eq(payment) expect(p.payment_method).to eq(payment.payment_method) @@ -147,12 +827,23 @@ module Spree it "creates adjustment" do payment = create(:payment, order: order, payment_method: payment_method, - amount: order.total) + amount: order.total) expect(payment.adjustment).to be_present expect(payment.adjustment.amount).not_to eq(0) end end end + end + end + + context 'OFN specs from previously decorated model' do + describe "applying transaction fees" do + let!(:order) { create(:order) } + let!(:line_item) { create(:line_item, order: order, quantity: 3, price: 5.00) } + + before do + order.reload.update! + end context "to Stripe payments" do let(:shop) { create(:enterprise) } @@ -229,9 +920,5 @@ module Spree end end end - - context "extends LocalizedNumber" do - it_behaves_like "a model using the LocalizedNumber module", [:amount] - end end end diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb new file mode 100644 index 0000000000..9c9b233986 --- /dev/null +++ b/spec/models/spree/stock_item_spec.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Spree::StockItem do + let(:stock_location) { create(:stock_location_with_items) } + + subject { stock_location.stock_items.order(:id).first } + + describe "validation" do + let(:stock_item) { stock_location.stock_items.first } + + it "requires count_on_hand to be positive if not backorderable" do + stock_item.backorderable = false + + stock_item.__send__(:count_on_hand=, 1) + expect(stock_item.valid?).to eq(true) + + stock_item.__send__(:count_on_hand=, 0) + expect(stock_item.valid?).to eq(true) + + stock_item.__send__(:count_on_hand=, -1) + expect(stock_item.valid?).to eq(false) + end + + it "allows count_on_hand to be negative if backorderable" do + stock_item.backorderable = true + + stock_item.__send__(:count_on_hand=, 1) + expect(stock_item.valid?).to eq(true) + + stock_item.__send__(:count_on_hand=, -1) + expect(stock_item.valid?).to eq(true) + end + end + + it 'maintains the count on hand for a variant' do + expect(subject.count_on_hand).to eq 15 + end + + it "can return the stock item's variant's name" do + expect(subject.variant_name).to eq(subject.variant.name) + end + + context "available to be included in shipment" do + context "has stock" do + it { expect(subject).to be_available } + end + + context "backorderable" do + before { subject.backorderable = true } + it { expect(subject).to be_available } + end + + context "no stock and not backorderable" do + before do + subject.backorderable = false + allow(subject).to receive_messages(count_on_hand: 0) + end + + it { expect(subject).not_to be_available } + end + end + + context "adjust count_on_hand" do + let!(:current_on_hand) { subject.count_on_hand } + + it 'is updated pessimistically' do + copy = Spree::StockItem.find(subject.id) + + subject.adjust_count_on_hand(5) + expect(subject.count_on_hand).to eq(current_on_hand + 5) + + expect(copy.count_on_hand).to eq(current_on_hand) + copy.adjust_count_on_hand(5) + expect(copy.count_on_hand).to eq(current_on_hand + 10) + end + + context "item out of stock (by two items)" do + let(:inventory_unit) { double('InventoryUnit') } + let(:inventory_unit_2) { double('InventoryUnit2') } + + before do + allow(subject).to receive(:backorderable?).and_return(true) + subject.adjust_count_on_hand(- (current_on_hand + 2)) + end + + it "doesn't process backorders" do + expect(subject).not_to receive(:backordered_inventory_units) + subject.adjust_count_on_hand(1) + end + + context "adds new items" do + before { allow(subject).to receive_messages(backordered_inventory_units: [inventory_unit, inventory_unit_2]) } + + it "fills existing backorders" do + expect(inventory_unit).to receive(:fill_backorder) + expect(inventory_unit_2).to receive(:fill_backorder) + + subject.adjust_count_on_hand(3) + expect(subject.count_on_hand).to eq(1) + end + end + end + end +end diff --git a/spec/models/spree/user_spec.rb b/spec/models/spree/user_spec.rb index ba5b4cd488..fc89796e3c 100644 --- a/spec/models/spree/user_spec.rb +++ b/spec/models/spree/user_spec.rb @@ -109,7 +109,7 @@ describe Spree.user_class do setup_email expect do - create(:user, confirmed_at: nil).confirm! + create(:user, confirmed_at: nil).confirm end.to enqueue_job ConfirmSignupJob end end diff --git a/spec/requests/checkout/stripe_connect_spec.rb b/spec/requests/checkout/stripe_connect_spec.rb index 000b2250a8..4bc09fc74f 100644 --- a/spec/requests/checkout/stripe_connect_spec.rb +++ b/spec/requests/checkout/stripe_connect_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe "checking out an order with a Stripe Connect payment method", type: :request do include ShopWorkflow - include AuthenticationWorkflow + include AuthenticationHelper include OpenFoodNetwork::ApiHelper let!(:order_cycle) { create(:simple_order_cycle) } @@ -244,7 +244,7 @@ describe "checking out an order with a Stripe Connect payment method", type: :re before do params[:order][:existing_card_id] = credit_card.id - quick_login_as(order.user) + login_as(order.user) # Requests a token stub_request(:post, "https://api.stripe.com/v1/tokens") diff --git a/spec/requests/checkout/stripe_sca_spec.rb b/spec/requests/checkout/stripe_sca_spec.rb index d2734f66d4..ad03211b1a 100644 --- a/spec/requests/checkout/stripe_sca_spec.rb +++ b/spec/requests/checkout/stripe_sca_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' describe "checking out an order with a Stripe SCA payment method", type: :request do include ShopWorkflow - include AuthenticationWorkflow + include AuthenticationHelper include OpenFoodNetwork::ApiHelper let!(:order_cycle) { create(:simple_order_cycle) } @@ -289,7 +289,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques before do params[:order][:existing_card_id] = credit_card.id - quick_login_as(order.user) + login_as(order.user) end context "and the payment intent and payment method requests are accepted" do diff --git a/spec/requests/embedded_shopfronts_headers_spec.rb b/spec/requests/embedded_shopfronts_headers_spec.rb index 9e1dd4be4d..1a6f2a3a01 100644 --- a/spec/requests/embedded_shopfronts_headers_spec.rb +++ b/spec/requests/embedded_shopfronts_headers_spec.rb @@ -1,13 +1,13 @@ require 'spec_helper' describe "setting response headers for embedded shopfronts", type: :request do - include AuthenticationWorkflow + include AuthenticationHelper let(:enterprise) { create(:distributor_enterprise) } let(:user) { enterprise.owner } before do - quick_login_as(user) + login_as(user) end context "with embedded shopfront disabled" do diff --git a/spec/requests/home_controller_spec.rb b/spec/requests/home_controller_spec.rb new file mode 100644 index 0000000000..9400fedcd9 --- /dev/null +++ b/spec/requests/home_controller_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe HomeController, type: :request do + context "#unauthorized" do + it "renders the unauthorized template" do + get "/unauthorized" + + expect(response.status).to eq 401 + expect(response).to render_template("shared/unauthorized", layout: 'darkswarm') + end + end +end diff --git a/spec/serializers/api/admin/index_enterprise_serializer_spec.rb b/spec/serializers/api/admin/index_enterprise_serializer_spec.rb index f1d084b946..f0e0233ea2 100644 --- a/spec/serializers/api/admin/index_enterprise_serializer_spec.rb +++ b/spec/serializers/api/admin/index_enterprise_serializer_spec.rb @@ -1,11 +1,9 @@ require 'spec_helper' describe Api::Admin::IndexEnterpriseSerializer do - include AuthenticationWorkflow - let(:enterprise) { create(:distributor_enterprise) } context "when spree_current_user is a manager" do - let(:user) { create_enterprise_user } + let(:user) { create(:user) } before do user.enterprise_roles.create(enterprise: enterprise) end diff --git a/spec/services/checkout/form_data_adapter_spec.rb b/spec/services/checkout/form_data_adapter_spec.rb index be248a2af0..e2b3c38a94 100644 --- a/spec/services/checkout/form_data_adapter_spec.rb +++ b/spec/services/checkout/form_data_adapter_spec.rb @@ -36,6 +36,26 @@ describe Checkout::FormDataAdapter do end end + describe "and a credit card is provided" do + before do + params[:order][:payments_attributes].first[:source_attributes] = {number: "4444333322221111"} + end + + it "fills in missing credit card brand" do + expect(adapter.params[:order][:payments_attributes].first[:source_attributes][:cc_type]).to eq "visa" + end + + it "leaves an existing credit card brand" do + params[:order][:payments_attributes].first[:source_attributes][:cc_type] = "test" + expect(adapter.params[:order][:payments_attributes].first[:source_attributes][:cc_type]).to eq "test" + end + + it "doesn't touch the credit card brand without a number" do + params[:order][:payments_attributes].first[:source_attributes][:number] = "" + expect(adapter.params[:order][:payments_attributes].first[:source_attributes].key?(:cc_type)).to eq false + end + end + describe "and existing credit card is provided" do before { params[:order][:existing_card_id] = credit_card.id } diff --git a/spec/services/exchange_products_renderer_spec.rb b/spec/services/exchange_products_renderer_spec.rb index 67233906ad..b2eba1c6c3 100644 --- a/spec/services/exchange_products_renderer_spec.rb +++ b/spec/services/exchange_products_renderer_spec.rb @@ -7,8 +7,9 @@ describe ExchangeProductsRenderer do describe "#exchange_products" do describe "for an incoming exchange" do + let(:exchange) { order_cycle.exchanges.incoming.first } + it "loads products" do - exchange = order_cycle.exchanges.incoming.first products = renderer.exchange_products(true, exchange.sender) expect(products.first.supplier.name).to eq exchange.variants.first.product.supplier.name @@ -16,14 +17,34 @@ describe ExchangeProductsRenderer do end describe "for an outgoing exchange" do + let(:exchange) { order_cycle.exchanges.outgoing.first } + it "loads products" do - exchange = order_cycle.exchanges.outgoing.first products = renderer.exchange_products(false, exchange.receiver) suppliers = [exchange.variants[0].product.supplier.name, exchange.variants[1].product.supplier.name] expect(suppliers).to include products.first.supplier.name expect(suppliers).to include products.second.supplier.name end + + context "showing products from coordinator inventory only" do + before { order_cycle.update prefers_product_selection_from_coordinator_inventory_only: true } + + it "loads no products if there are no products from the coordinator inventory" do + products = renderer.exchange_products(false, exchange.receiver) + + expect(products).to be_empty + end + + it "loads products from the coordinator inventory" do + # Add variant already in the exchange to the coordinator's inventory + exchange.variants.first.inventory_items = [create(:inventory_item, enterprise: order_cycle.coordinator)] + + products = renderer.exchange_products(false, exchange.receiver) + + expect(products).to eq [exchange.variants.first.product] + end + end end end diff --git a/spec/services/order_factory_spec.rb b/spec/services/order_factory_spec.rb index c67cbaaf0e..394de7eaeb 100644 --- a/spec/services/order_factory_spec.rb +++ b/spec/services/order_factory_spec.rb @@ -47,7 +47,7 @@ describe OrderFactory do end it "retains address, delivery, and payment attributes until completion of the order" do - AdvanceOrderService.new(order).call + OrderWorkflow.new(order).complete order.reload diff --git a/spec/services/order_syncer_spec.rb b/spec/services/order_syncer_spec.rb index 9990425f6a..2cd6010736 100644 --- a/spec/services/order_syncer_spec.rb +++ b/spec/services/order_syncer_spec.rb @@ -409,7 +409,7 @@ describe OrderSyncer do context "when order is complete" do it "does not update the line_item quantities and adds the order to order_update_issues with insufficient stock" do - AdvanceOrderService.new(order).call + OrderWorkflow.new(order).complete expect(syncer.sync!).to be true @@ -423,7 +423,7 @@ describe OrderSyncer do it "does not update the line_item quantities and adds the order to order_update_issues with out of stock" do # this single item available is used when the order is completed below, making the item out of stock variant.update_attribute(:on_hand, 1) - AdvanceOrderService.new(order).call + OrderWorkflow.new(order).complete expect(syncer.sync!).to be true @@ -507,7 +507,7 @@ describe OrderSyncer do end context "when order is complete" do - before { AdvanceOrderService.new(order).call } + before { OrderWorkflow.new(order).complete } it "does not add line_item and adds the order to order_update_issues" do expect(syncer.sync!).to be true diff --git a/spec/services/advance_order_service_spec.rb b/spec/services/order_workflow_spec.rb similarity index 89% rename from spec/services/advance_order_service_spec.rb rename to spec/services/order_workflow_spec.rb index 58a2fcb03a..5b2b6f0bf5 100644 --- a/spec/services/advance_order_service_spec.rb +++ b/spec/services/order_workflow_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe AdvanceOrderService do +describe OrderWorkflow do let!(:distributor) { create(:distributor_enterprise) } let!(:order) do create(:order_with_totals_and_distribution, distributor: distributor, @@ -13,7 +13,7 @@ describe AdvanceOrderService do it "transitions the order multiple steps" do expect(order.state).to eq("cart") - service.call + service.complete order.reload expect(order.state).to eq("complete") end @@ -30,7 +30,7 @@ describe AdvanceOrderService do it "retains delivery method of the order" do order.select_shipping_method(shipping_method_b.id) - service.call + service.complete order.reload expect(order.shipping_method).to eq(shipping_method_b) end @@ -38,7 +38,7 @@ describe AdvanceOrderService do context "when raising on error" do it "transitions the order multiple steps" do - service.call! + service.complete! order.reload expect(order.state).to eq("complete") end @@ -49,7 +49,7 @@ describe AdvanceOrderService do end it "raises error" do - expect { service.call! }.to raise_error(StateMachine::InvalidTransition) + expect { service.complete! }.to raise_error(StateMachine::InvalidTransition) end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9ea40e8c66..d4130a9d2d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -181,6 +181,16 @@ RSpec.configure do |config| config.include JsonSpec::Helpers + # Suppress Selenium deprecation warnings. Stops a flood of pointless warnings filling the + # test output. We can remove this in the future after upgrading Rails, Rack, and Capybara. + if Rails::VERSION::MAJOR == 4 && Rails::VERSION::MINOR == 0 + Selenium::WebDriver.logger.level = :error + else + ActiveSupport::Deprecation.warn( + "Suppressing Selenium deprecation warnings is not needed any more." + ) + end + # Profiling # # This code shouldn't be run in normal circumstances. But if you want to know @@ -201,4 +211,5 @@ RSpec.configure do |config| # config.after :suite do # PerfTools::CpuProfiler.stop # end + config.infer_spec_type_from_file_location! end diff --git a/spec/support/controller_helper.rb b/spec/support/controller_helper.rb index b543555319..2d7ddf585d 100644 --- a/spec/support/controller_helper.rb +++ b/spec/support/controller_helper.rb @@ -1,6 +1,6 @@ module OpenFoodNetwork module ControllerHelper - def login_as_admin + def controller_login_as_admin @admin_user ||= begin user = create(:user) user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') @@ -10,7 +10,7 @@ module OpenFoodNetwork allow(controller).to receive_messages(spree_current_user: @admin_user) end - def login_as_enterprise_user(enterprises) + def controller_login_as_enterprise_user(enterprises) @enterprise_user ||= begin user = create(:user) user.spree_roles = [] diff --git a/spec/support/email_helper.rb b/spec/support/email_helper.rb index f622785425..4291844575 100644 --- a/spec/support/email_helper.rb +++ b/spec/support/email_helper.rb @@ -2,8 +2,6 @@ module OpenFoodNetwork module EmailHelper # Some specs trigger actions that send emails, for example creating an order. # But sending emails doesn't work out-of-the-box. This code sets it up. - # It's here in a single place to allow an easy upgrade to Spree 2 which - # needs a different implementation of this method. def setup_email Spree::Config[:mails_from] = "test@ofn.example.org" end diff --git a/spec/support/request/authentication_helper.rb b/spec/support/request/authentication_helper.rb new file mode 100644 index 0000000000..8c5e9e890a --- /dev/null +++ b/spec/support/request/authentication_helper.rb @@ -0,0 +1,34 @@ +module AuthenticationHelper + include Warden::Test::Helpers + + def login_as_admin + admin_user = create(:admin_user) + login_as admin_user + admin_user + end + + def login_as_admin_and_visit(path_visit) + login_as_admin + visit path_visit + end + + def login_to_admin_section + login_as_admin_and_visit(spree.admin_dashboard_path) + end + + def login_to_admin_as(user) + login_as user + visit spree.admin_dashboard_path + end + + def fill_in_and_submit_login_form(user) + fill_in "email", with: user.email + fill_in "password", with: user.password + click_button "Login" + end + + def expect_logged_in + # Ensure page has been reloaded after submitting login form + expect(page).to_not have_selector ".menu #login-link" + end +end diff --git a/spec/support/request/authentication_workflow.rb b/spec/support/request/authentication_workflow.rb deleted file mode 100644 index 8968c84da5..0000000000 --- a/spec/support/request/authentication_workflow.rb +++ /dev/null @@ -1,74 +0,0 @@ -module AuthenticationWorkflow - include Warden::Test::Helpers - - def quick_login_as(user) - login_as user - end - - def quick_login_as_admin - admin_role = Spree::Role.find_or_create_by!(name: 'admin') - admin_user = create(:user, - password: 'passw0rd', - password_confirmation: 'passw0rd', - remember_me: false, - persistence_token: 'pass', - login: 'admin@ofn.org') - - admin_user.spree_roles << admin_role - quick_login_as admin_user - admin_user - end - - def login_to_admin_section - quick_login_as_admin - visit spree.admin_dashboard_path - end - - # TODO: Should probably just rename this to create_user - def create_enterprise_user( attrs = {} ) - new_user = build(:user, attrs) - new_user.spree_roles = [Spree::Role.find_or_create_by!(name: 'user')] - new_user.save - if attrs.key? :enterprises - attrs[:enterprises].each do |enterprise| - enterprise.users << new_user - end - end - new_user - end - - def login_to_admin_as(user) - quick_login_as user - visit spree.admin_dashboard_path - # visit spree.admin_dashboard_path - # fill_in 'spree_user_email', :with => user.email - # fill_in 'spree_user_password', :with => user.password - # click_button 'Login' - end - - def fill_in_and_submit_login_form(user) - fill_in "email", with: user.email - fill_in "password", with: user.password - click_button "Login" - end - - def expect_logged_in - # Ensure page has been reloaded after submitting login form - expect(page).to_not have_selector ".menu #login-link" - end -end - -RSpec.configure do |config| - config.extend AuthenticationWorkflow, type: :feature - - # rspec-rails 3 will no longer automatically infer an example group's spec type - # from the file location. You can explicitly opt-in to the feature using this - # config option. - # To explicitly tag specs without using automatic inference, set the `:type` - # metadata manually: - # - # describe ThingsController, :type => :controller do - # # Equivalent to being in spec/controllers - # end - config.infer_spec_type_from_file_location! -end diff --git a/spec/views/spree/admin/orders/edit.html.haml_spec.rb b/spec/views/spree/admin/orders/edit.html.haml_spec.rb index b33cd187ef..e6b779df39 100644 --- a/spec/views/spree/admin/orders/edit.html.haml_spec.rb +++ b/spec/views/spree/admin/orders/edit.html.haml_spec.rb @@ -1,7 +1,6 @@ require "spec_helper" describe "spree/admin/orders/edit.html.haml" do - include AuthenticationWorkflow helper Spree::BaseHelper # required to make pretty_time work around do |example| @@ -17,7 +16,7 @@ describe "spree/admin/orders/edit.html.haml" do end end - allow(view).to receive_messages spree_current_user: create_enterprise_user + allow(view).to receive_messages spree_current_user: create(:user) order = create(:completed_order_with_fees) order.distributor = create(:distributor_enterprise) diff --git a/spec/views/spree/admin/orders/index.html.haml_spec.rb b/spec/views/spree/admin/orders/index.html.haml_spec.rb index 8cbbfeb90a..8379a77610 100644 --- a/spec/views/spree/admin/orders/index.html.haml_spec.rb +++ b/spec/views/spree/admin/orders/index.html.haml_spec.rb @@ -1,8 +1,6 @@ require "spec_helper" describe "spree/admin/orders/index.html.haml" do - include AuthenticationWorkflow - around do |example| original_config = Spree::Config[:enable_invoices?] example.run @@ -16,7 +14,7 @@ describe "spree/admin/orders/index.html.haml" do end end - allow(view).to receive_messages spree_current_user: create_enterprise_user + allow(view).to receive_messages spree_current_user: create(:user) end describe "print invoices button" do diff --git a/spec/views/spree/admin/shared/_order_links.html.haml_spec.rb b/spec/views/spree/admin/shared/_order_links.html.haml_spec.rb new file mode 100644 index 0000000000..027c188cab --- /dev/null +++ b/spec/views/spree/admin/shared/_order_links.html.haml_spec.rb @@ -0,0 +1,18 @@ +require "spec_helper" + +describe "spree/admin/shared/_order_links.html.haml" do + helper Spree::BaseHelper # required to make pretty_time work + + before do + order = create(:order) + assign(:order, order) + end + + describe "actions dropwdown" do + it "contains all the actions buttons" do + render + + expect(rendered).to have_content("links-dropdown") + end + end +end diff --git a/spec/views/spree/shared/_order_details.html.haml_spec.rb b/spec/views/spree/shared/_order_details.html.haml_spec.rb index ac6d788f24..60e95ac0f6 100644 --- a/spec/views/spree/shared/_order_details.html.haml_spec.rb +++ b/spec/views/spree/shared/_order_details.html.haml_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" describe "spree/shared/_order_details.html.haml" do - include AuthenticationWorkflow + include AuthenticationHelper helper Spree::BaseHelper let(:order) { create(:completed_order_with_fees) } diff --git a/vendor/assets/javascripts/leaflet-providers.js b/vendor/assets/javascripts/leaflet-providers.js index 208b6257d0..6d8349839b 100644 --- a/vendor/assets/javascripts/leaflet-providers.js +++ b/vendor/assets/javascripts/leaflet-providers.js @@ -219,66 +219,16 @@ } }, CyclOSM: { - url: 'https://dev.{s}.tile.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', + url: 'https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', options: { maxZoom: 20, attribution: 'CyclOSM | Map data: {attribution.OpenStreetMap}' } }, - OpenMapSurfer: { - url: 'https://maps.heigit.org/openmapsurfer/tiles/{variant}/webmercator/{z}/{x}/{y}.png', - options: { - maxZoom: 19, - variant: 'roads', - attribution: 'Imagery from GIScience Research Group @ University of Heidelberg | Map data ' - }, - variants: { - Roads: { - options: { - variant: 'roads', - attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}' - } - }, - Hybrid: { - options: { - variant: 'hybrid', - attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}' - } - }, - AdminBounds: { - options: { - variant: 'adminb', - maxZoom: 18, - attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}' - } - }, - ContourLines: { - options: { - variant: 'asterc', - maxZoom: 18, - minZoom: 13, - attribution: '{attribution.OpenMapSurfer} ASTER GDEM' - } - }, - Hillshade: { - options: { - variant: 'asterh', - maxZoom: 18, - attribution: '{attribution.OpenMapSurfer} ASTER GDEM, SRTM' - } - }, - ElementsAtRisk: { - options: { - variant: 'elements_at_risk', - attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}' - } - } - } - }, Hydda: { url: 'https://{s}.tile.openstreetmap.se/hydda/{variant}/{z}/{x}/{y}.png', options: { - maxZoom: 18, + maxZoom: 20, variant: 'full', attribution: 'Tiles courtesy of OpenStreetMap Sweden — Map data {attribution.OpenStreetMap}' }, @@ -288,18 +238,73 @@ RoadsAndLabels: 'roads_and_labels' } }, - MapBox: { - url: 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}{r}.png?access_token={accessToken}', + Jawg: { + url: 'https://{s}.tile.jawg.io/{variant}/{z}/{x}/{y}{r}.png?access-token={accessToken}', options: { attribution: - '© Mapbox ' + + '© JawgMaps ' + + '{attribution.OpenStreetMap}', + minZoom: 0, + maxZoom: 22, + subdomains: 'abcd', + variant: 'jawg-terrain', + // Get your own Jawg access token here : https://www.jawg.io/lab/ + // NB : this is a demonstration key that comes with no guarantee + accessToken: '', + }, + variants: { + Streets: 'jawg-streets', + Terrain: 'jawg-terrain', + Sunny: 'jawg-sunny', + Dark: 'jawg-dark', + Light: 'jawg-light', + Matrix: 'jawg-matrix' + } + }, + MapBox: { + url: 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}{r}?access_token={accessToken}', + options: { + attribution: + '© Mapbox ' + '{attribution.OpenStreetMap} ' + 'Improve this map', - subdomains: 'abcd', - id: 'mapbox.streets', + tileSize: 512, + maxZoom: 18, + zoomOffset: -1, + id: 'mapbox/streets-v11', accessToken: '', } }, + MapTiler: { + url: 'https://api.maptiler.com/maps/{variant}/{z}/{x}/{y}{r}.{ext}?key={key}', + options: { + attribution: + '© MapTiler © OpenStreetMap contributors', + variant: 'streets', + ext: 'png', + key: '', + tileSize: 512, + zoomOffset: -1, + minZoom: 0, + maxZoom: 21 + }, + variants: { + Streets: 'streets', + Basic: 'basic', + Bright: 'bright', + Pastel: 'pastel', + Positron: 'positron', + Hybrid: { + options: { + variant: 'hybrid', + ext: 'jpg' + } + }, + Toner: 'toner', + Topo: 'topo', + Voyager: 'voyager' + } + }, Stamen: { url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}{r}.{ext}', options: { @@ -719,11 +724,11 @@ } }, FreeMapSK: { - url: 'http://t{s}.freemap.sk/T/{z}/{x}/{y}.jpeg', + url: 'https://{s}.freemap.sk/T/{z}/{x}/{y}.jpeg', options: { minZoom: 8, maxZoom: 16, - subdomains: '1234', + subdomains: 'abcd', bounds: [[47.204642, 15.996093], [49.830896, 22.576904]], attribution: '{attribution.OpenStreetMap}, vizualization CC-By-SA 2.0 Freemap.sk'