Compare commits

...

42 Commits

Author SHA1 Message Date
Maikel Linke
e6a1021d6e Update latest translations 2020-09-15 16:19:00 +10:00
Maikel Linke
e82aa0c89a Update translations 2020-09-11 15:25:52 +10:00
Maikel Linke
8be05e94bd Update release issue template 2020-09-11 15:25:24 +10:00
Maikel
7317347fd6 Merge pull request #6012 from openfoodfoundation/transifex
Transifex
2020-09-11 15:25:04 +10:00
Maikel
c5c542069f Merge pull request #5951 from mkllnk/5785-js-error-reporting
5785 Notify Bugsnag when sending card to Stripe fails during checkout
2020-09-11 15:12:47 +10:00
Maikel
dc9e3aa1a0 Merge pull request #6010 from mkllnk/fix-module-declaration
Fix module declaration
2020-09-11 09:12:08 +10:00
Luis Ramos
a48b57f7a7 Merge pull request #5883 from luisramos0/taxs
[Bye bye Spree] Bring models tax_rate, tax_categories, adjustments and calculator from spree_core
2020-09-10 23:10:26 +01:00
Transifex-Openfoodnetwork
f501d48caa Updating translations for config/locales/fr.yml 2020-09-11 01:54:06 +10:00
Pau Pérez Fabregat
2429b186ce Merge pull request #6008 from openfoodfoundation/dependabot/bundler/ddtrace-0.40.0
Bump ddtrace from 0.39.0 to 0.40.0
2020-09-10 17:10:56 +02:00
Pau Pérez Fabregat
7df2759475 Merge pull request #5907 from Matt-Yorkley/data-cleanup
Data cleanup
2020-09-10 17:06:20 +02:00
Pau Pérez Fabregat
681cb34c48 Merge pull request #6009 from openfoodfoundation/transifex
Transifex
2020-09-10 14:01:49 +02:00
Maikel Linke
94b903179e Fix module declaration
Running script/prepare_imported_db.rb failed because
Spree::PaymentMethodDistributors couldn't be found. This problem is
described in the Rubocop docs:
https://rubystyle.guide/#namespace-definition
2020-09-10 16:12:17 +10:00
Maikel Linke
59070712d9 Update rubocop todo list 2020-09-10 16:08:18 +10:00
Transifex-Openfoodnetwork
76aebf329e Updating translations for config/locales/ar.yml 2020-09-10 02:13:08 +10:00
dependabot-preview[bot]
b2b5606f2e Bump ddtrace from 0.39.0 to 0.40.0
Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 0.39.0 to 0.40.0.
- [Release notes](https://github.com/DataDog/dd-trace-rb/releases)
- [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/DataDog/dd-trace-rb/compare/v0.39.0...v0.40.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-09 15:32:14 +00:00
Pau Perez
f890c4a31d Fix LogEntry spec 2020-09-08 14:12:17 +02:00
Pau Pérez Fabregat
b087f8da19 Merge pull request #6001 from openfoodfoundation/transifex
Transifex
2020-09-08 13:19:28 +02:00
Pau Perez
e3c1159c17 Start with 6 months data retention
As discussed in code review.
2020-09-08 12:49:58 +02:00
Pau Perez
14054f0e70 Move retention period to constant
There's no need to reevaluate the date 3 times, potentially leading to
edge cases.
2020-09-08 12:48:30 +02:00
Pau Perez
d525ddfe14 Move missing statements to where + delete_all
And fix the specs
2020-09-08 12:47:42 +02:00
Pau Pérez Fabregat
df0b997258 Use where + delete_all to increase readability
Co-authored-by: Maikel <maikel@email.org.au>
2020-09-08 12:26:47 +02:00
Pau Pérez Fabregat
ffbb0d26a4 Unhardcode class name 2020-09-08 12:26:21 +02:00
Transifex-Openfoodnetwork
3da14233bf Updating translations for config/locales/en_US.yml 2020-09-08 02:55:31 +10:00
Pau Pérez Fabregat
940c067b60 Merge pull request #5992 from openfoodfoundation/transifex
Transifex
2020-09-07 18:46:48 +02:00
Luis Ramos
6e8fe080cb Fix easy rubocop issues 2020-09-05 18:39:56 +01:00
Luis Ramos
8867ec977c Bring missing factory from spree_core and use ofn's calculator 2020-09-05 16:38:37 +01:00
Luis Ramos
4931edc67c Remove code related to promotions, we dont have promotions in OFN 2020-09-05 16:38:37 +01:00
Luis Ramos
51ed9a6b78 Fix comment and point out that it's a fix to a spree issue 2020-09-05 16:38:36 +01:00
Luis Ramos
e96428e7e2 Transpec adjustment_spec 2020-09-05 16:38:36 +01:00
Luis Ramos
b629a4f912 Make new specs pass 2020-09-05 16:38:36 +01:00
Luis Ramos
967380c542 Fix easy rubocop issues 2020-09-05 16:38:36 +01:00
Luis Ramos
ff0aa377a1 Run rubocop autocorrect 2020-09-05 16:38:36 +01:00
Luis Ramos
da683e3ecf Merge decorators with original code from spree_core 2020-09-05 16:38:36 +01:00
Luis Ramos
aa46a4b5da Bring models related to taxes and adjustments from spree_core 2020-09-05 16:38:36 +01:00
Transifex-Openfoodnetwork
61dad61ef7 Updating translations for config/locales/en_GB.yml 2020-09-05 02:37:15 +10:00
Maikel Linke
cd940bd140 Rewrite error message for failed credit card sending 2020-09-02 15:22:23 +10:00
Maikel Linke
5d48da72c7 Notify Bugsnag on Stripe payment errors 2020-08-27 11:09:16 +10:00
Maikel Linke
9d07295480 DRY error reporting during payment 2020-08-27 11:03:13 +10:00
Maikel Linke
f435039061 Simplify using loading and flash messages together 2020-08-27 11:03:13 +10:00
Matt-Yorkley
97ae4def98 Schedule cleanup task to run once per month 2020-08-15 11:39:55 +01:00
Matt-Yorkley
91501f05f2 DRY date usage 2020-08-15 11:19:24 +01:00
Matt-Yorkley
93601ca556 Extract #remove_transient_data from TruncateData 2020-08-15 11:19:24 +01:00
44 changed files with 1179 additions and 495 deletions

View File

@@ -9,10 +9,11 @@ assignees: ''
Steps:
- [ ] Include translations
- [ ] Include translations: `tx pull --force`
- [ ] [Draft new release]
- [ ] Notify #instance-managers of user-facing changes.
- [ ] Test: https://semaphoreci.com/openfoodfoundation/openfoodnetwork-2/branches/master <!-- replace the URL -->
- [ ] Update translations if necessary
- [ ] Publish and notify #global-community
- [ ] Deploy and notify #instance-managers
- [ ] Nudge next release manager

View File

@@ -330,6 +330,13 @@ Layout/LineLength:
- spec/requests/api/orders_spec.rb
- spec/swagger_helper.rb
- spec/views/spree/admin/payment_methods/index.html.haml_spec.rb
- app/models/spree/image.rb
- app/models/spree/payment_method.rb
- spec/factories/line_item_factory.rb
- spec/factories/shipment_factory.rb
- spec/factories/stock_location_factory.rb
- spec/factories/user_factory.rb
- spec/lib/spree/core/calculated_adjustments_spec.rb
Metrics/AbcSize:
Max: 15
@@ -459,6 +466,13 @@ Metrics/AbcSize:
- 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
- app/models/spree/zone.rb
- lib/spree/core/calculated_adjustments.rb
- lib/spree/core/delegate_belongs_to.rb
- lib/spree/core/permalinks.rb
- lib/spree/core/s3_support.rb
- lib/spree/money.rb
- spec/support/i18n_translations_checker.rb
Metrics/BlockLength:
Max: 25
@@ -501,6 +515,9 @@ Metrics/BlockLength:
- app/models/spree/payment/processing.rb
- spec/requests/api/orders_spec.rb
- spec/swagger_helper.rb
- spec/factories/address_factory.rb
- spec/factories/payment_method_factory.rb
- spec/factories/shipment_factory.rb
Metrics/CyclomaticComplexity:
Max: 6
@@ -535,6 +552,9 @@ Metrics/CyclomaticComplexity:
- 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
- app/models/spree/payment_method.rb
- app/models/spree/zone.rb
- lib/spree/core/calculated_adjustments.rb
Metrics/PerceivedComplexity:
Max: 7
@@ -563,6 +583,8 @@ Metrics/PerceivedComplexity:
- 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
- app/models/spree/zone.rb
- lib/spree/core/calculated_adjustments.rb
Metrics/MethodLength:
Max: 10
@@ -675,6 +697,15 @@ Metrics/MethodLength:
- 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
- app/models/spree/credit_card.rb
- app/models/spree/payment_method.rb
- app/models/spree/zone.rb
- lib/spree/core/calculated_adjustments.rb
- lib/spree/core/delegate_belongs_to.rb
- lib/spree/core/permalinks.rb
- lib/spree/core/s3_support.rb
- lib/spree/responder.rb
- spec/support/i18n_translations_checker.rb
Metrics/ClassLength:
Max: 100
@@ -719,6 +750,8 @@ Metrics/ClassLength:
- 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
- app/models/spree/credit_card.rb
- app/models/spree/zone.rb
Metrics/ModuleLength:
Max: 100
@@ -764,6 +797,8 @@ Metrics/ModuleLength:
- spec/support/request/web_helper.rb
- app/models/spree/order/checkout.rb
- app/models/spree/payment/processing.rb
- spec/lib/open_food_network/packing_report_spec.rb
- spec/models/spree/credit_card_spec.rb
Metrics/ParameterLists:
Max: 5

View File

@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 1400`
# on 2020-08-13 16:05:53 +1000 using RuboCop version 0.81.0.
# on 2020-09-10 16:12:05 +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
@@ -28,13 +28,14 @@ Layout/EmptyLines:
Exclude:
- 'spec/models/spree/payment_spec.rb'
# Offense count: 3
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: empty_lines, no_empty_lines
Layout/EmptyLinesAroundBlockBody:
Exclude:
- 'spec/models/spree/payment_spec.rb'
- 'spec/models/spree/zone_spec.rb'
# Offense count: 3
# Cop supports --auto-correct.
@@ -61,7 +62,7 @@ Layout/FirstHashElementIndentation:
- 'spec/models/spree/payment_spec.rb'
- 'spec/swagger_helper.rb'
# Offense count: 5
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
# SupportedHashRocketStyles: key, separator, table
@@ -69,6 +70,7 @@ Layout/FirstHashElementIndentation:
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
Layout/HashAlignment:
Exclude:
- 'spec/lib/open_food_network/packing_report_spec.rb'
- 'spec/models/spree/payment_spec.rb'
# Offense count: 1
@@ -79,13 +81,6 @@ 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: 409
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
@@ -123,13 +118,22 @@ Layout/SpaceInsideHashLiteralBraces:
- 'spec/services/checkout/form_data_adapter_spec.rb'
- 'spec/services/user_locale_setter_spec.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: final_newline, final_blank_line
Layout/TrailingEmptyLines:
Exclude:
- 'spec/factories.rb'
- 'spec/factories/address_factory.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/lib/open_food_network/orders_and_fulfillments_report/customer_totals_report_spec.rb'
- 'spec/requests/api/orders_spec.rb'
# Offense count: 2
@@ -145,6 +149,13 @@ Lint/IneffectiveAccessModifier:
- 'app/services/mail_configuration.rb'
- 'lib/open_food_network/feature_toggle.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
Lint/UnusedBlockArgument:
Exclude:
- 'spec/factories/stock_location_factory.rb'
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods.
@@ -160,48 +171,6 @@ Lint/UselessAccessModifier:
- 'app/services/mail_configuration.rb'
- 'lib/open_food_network/feature_toggle.rb'
# 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: 102
# Offense count: 2
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 231
# Offense count: 3
# Configuration parameters: IgnoredMethods.
Metrics/CyclomaticComplexity:
Max: 23
# Offense count: 19
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/MethodLength:
Max: 140
# Offense count: 2
# Configuration parameters: CountComments.
Metrics/ModuleLength:
Max: 208
# Offense count: 2
# Configuration parameters: IgnoredMethods.
Metrics/PerceivedComplexity:
Max: 24
# Offense count: 9
Naming/AccessorMethodName:
Exclude:
@@ -227,7 +196,7 @@ Naming/MemoizedInstanceVariableName:
- 'app/mailers/producer_mailer.rb'
- 'lib/open_food_network/address_finder.rb'
# Offense count: 19
# Offense count: 20
# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros.
# NamePrefix: is_, has_, have_
# ForbiddenPrefixes: is_, has_, have_
@@ -241,9 +210,10 @@ Naming/PredicateName:
- 'app/models/order_cycle.rb'
- 'app/models/spree/ability_decorator.rb'
- 'app/models/spree/adjustment_decorator.rb'
- 'app/models/spree/credit_card.rb'
- 'app/models/spree/line_item_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/payment_method_decorator.rb'
- 'app/models/spree/payment_method.rb'
- 'app/models/spree/preferences/file_configuration.rb'
- 'app/models/spree/shipping_method_decorator.rb'
- 'lib/open_food_network/customers_report.rb'
@@ -252,6 +222,13 @@ Naming/PredicateName:
- 'lib/open_food_network/packing_report.rb'
- 'lib/tasks/data.rake'
# Offense count: 2
# Configuration parameters: EnforcedStyle.
# SupportedStyles: snake_case, normalcase, non_integer
Naming/VariableNumber:
Exclude:
- 'spec/factories/stock_location_factory.rb'
# Offense count: 7
# Cop supports --auto-correct.
Rails/ActiveRecordAliases:
@@ -261,12 +238,13 @@ Rails/ActiveRecordAliases:
- 'spec/features/consumer/shopping/orders_spec.rb'
- 'spec/requests/api/orders_spec.rb'
# Offense count: 1
# Offense count: 3
# Configuration parameters: EnforcedStyle.
# SupportedStyles: strict, flexible
Rails/Date:
Exclude:
- 'app/models/order_cycle.rb'
- 'app/models/spree/credit_card.rb'
# Offense count: 1
# Cop supports --auto-correct.
@@ -281,7 +259,7 @@ Rails/Delegate:
# Whitelist: find_by_sql
Rails/DynamicFindBy:
Exclude:
- 'app/controllers/spree/admin/orders/customer_details_controller.rb'
- 'spec/factories/state_factory.rb'
# Offense count: 16
# Configuration parameters: EnforcedStyle.
@@ -323,7 +301,7 @@ Rails/FindEach:
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/shipment.rb'
# Offense count: 5
# Offense count: 6
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasAndBelongsToMany:
@@ -332,8 +310,9 @@ Rails/HasAndBelongsToMany:
- 'app/models/enterprise_group.rb'
- 'app/models/spree/concerns/payment_method_distributors.rb'
- 'app/models/spree/line_item_decorator.rb'
- 'app/models/spree/zone.rb'
# Offense count: 26
# Offense count: 27
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasManyOrHasOneDependent:
@@ -342,8 +321,9 @@ Rails/HasManyOrHasOneDependent:
- 'app/models/enterprise.rb'
- 'app/models/order_cycle.rb'
- 'app/models/spree/adjustment_decorator.rb'
- 'app/models/spree/credit_card.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/payment_method_decorator.rb'
- 'app/models/spree/payment_method.rb'
- 'app/models/spree/property.rb'
- 'app/models/spree/shipment.rb'
- 'app/models/spree/shipping_method_decorator.rb'
@@ -392,7 +372,7 @@ Rails/LexicallyScopedActionFilter:
- 'app/controllers/spree/users_controller.rb'
- 'app/controllers/user_passwords_controller.rb'
# Offense count: 12
# Offense count: 13
Rails/OutputSafety:
Exclude:
- 'app/controllers/spree/admin/reports_controller.rb'
@@ -403,6 +383,7 @@ Rails/OutputSafety:
- 'app/helpers/spree/admin/zones_helper.rb'
- 'app/helpers/spree/reports_helper.rb'
- 'app/serializers/api/product_serializer.rb'
- 'lib/spree/money.rb'
- 'lib/spree/money_decorator.rb'
- 'spec/features/admin/order_print_ticket_spec.rb'
@@ -422,7 +403,7 @@ Rails/ReflectionClassName:
- 'app/models/enterprise_role.rb'
- 'app/models/subscription.rb'
# Offense count: 233
# Offense count: 241
# 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:
@@ -439,17 +420,19 @@ Rails/SkipsModelValidations:
- 'app/models/product_import/inventory_reset_strategy.rb'
- 'app/models/proxy_order.rb'
- 'app/models/spree/address_decorator.rb'
- 'app/models/spree/credit_card_decorator.rb'
- 'app/models/spree/credit_card.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/payment.rb'
- 'app/models/spree/shipment.rb'
- 'app/models/spree/shipping_method_decorator.rb'
- 'app/models/spree/zone.rb'
- 'app/models/subscription.rb'
- 'app/models/variant_override.rb'
- 'app/services/order_factory.rb'
- 'engines/order_management/spec/performance/order_management/subscriptions/proxy_order_syncer_spec.rb'
- 'engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_service_spec.rb'
- 'engines/order_management/spec/services/order_management/subscriptions/stripe_payment_setup_spec.rb'
- 'lib/spree/core/calculated_adjustments.rb'
- 'lib/tasks/data/anonymize_data.rake'
- 'lib/tasks/sample_data/product_factory.rb'
- 'lib/tasks/users.rake'
@@ -494,6 +477,7 @@ Rails/SkipsModelValidations:
- 'spec/models/enterprise_relationship_spec.rb'
- 'spec/models/exchange_spec.rb'
- 'spec/models/spree/adjustment_spec.rb'
- 'spec/models/spree/asset_spec.rb'
- 'spec/models/spree/line_item_spec.rb'
- 'spec/models/spree/order_spec.rb'
- 'spec/models/spree/variant_spec.rb'
@@ -510,7 +494,7 @@ Rails/SkipsModelValidations:
- 'spec/support/request/shop_workflow.rb'
- 'spec/views/spree/shared/_order_details.html.haml_spec.rb'
# Offense count: 3
# Offense count: 4
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/UniqueValidationWithoutIndex:
@@ -518,6 +502,7 @@ Rails/UniqueValidationWithoutIndex:
- 'app/models/customer.rb'
- 'app/models/exchange.rb'
- 'app/models/spree/stock_item.rb'
- 'app/models/spree/zone.rb'
# Offense count: 2
# Configuration parameters: Environments.
@@ -527,23 +512,29 @@ Rails/UnknownEnv:
- 'app/models/spree/app_configuration_decorator.rb'
- 'lib/spree/core/controller_helpers/ssl.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: percent_q, bare_percent
Style/BarePercentLiterals:
Exclude:
- 'spec/support/request/web_helper.rb'
# Offense count: 2
Style/CaseEquality:
Exclude:
- 'app/helpers/angular_form_helper.rb'
- 'spec/models/spree/payment_spec.rb'
# Offense count: 71
# Offense count: 64
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
Exclude:
- 'app/models/calculator/flat_percent_per_item.rb'
- 'app/models/spree/concerns/payment_method_distributors.rb'
- 'app/models/spree/gateway/migs.rb'
- 'app/models/spree/gateway/pin.rb'
- 'app/models/spree/preferences/file_configuration.rb'
- 'app/models/spree/product_set.rb'
- 'app/models/tag_rule/discount_order.rb'
- 'app/models/tag_rule/filter_order_cycles.rb'
@@ -601,11 +592,13 @@ Style/ClassAndModuleChildren:
- 'app/serializers/api/variant_serializer.rb'
- 'lib/open_food_network/locking.rb'
- 'spec/controllers/spree/admin/base_controller_spec.rb'
- 'spec/models/spree/payment_method_spec.rb'
# Offense count: 2
# Offense count: 3
Style/ClassVars:
Exclude:
- 'lib/open_food_network/rack_request_blocker.rb'
- 'lib/spree/core/delegate_belongs_to.rb'
# Offense count: 4
# Configuration parameters: EnforcedStyle.
@@ -615,7 +608,7 @@ Style/FormatStringToken:
- 'lib/open_food_network/sales_tax_report.rb'
- 'spec/features/admin/bulk_order_management_spec.rb'
# Offense count: 847
# Offense count: 829
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: always, always_true, never
@@ -710,10 +703,6 @@ Style/FrozenStringLiteralComment:
- 'app/controllers/spree/admin/zones_controller.rb'
- 'app/controllers/spree/credit_cards_controller.rb'
- 'app/controllers/spree/orders_controller.rb'
- 'app/controllers/spree/store_controller.rb'
- 'app/controllers/spree/user_passwords_controller.rb'
- 'app/controllers/spree/user_registrations_controller.rb'
- 'app/controllers/spree/user_sessions_controller.rb'
- 'app/controllers/spree/users_controller.rb'
- 'app/controllers/stripe/callbacks_controller.rb'
- 'app/controllers/stripe/webhooks_controller.rb'
@@ -781,11 +770,9 @@ Style/FrozenStringLiteralComment:
- 'app/models/coordinator_fee.rb'
- 'app/models/customer.rb'
- 'app/models/distributor_shipping_method.rb'
- 'app/models/enterprise.rb'
- 'app/models/enterprise_fee.rb'
- 'app/models/enterprise_fee_set.rb'
- 'app/models/enterprise_group.rb'
- 'app/models/enterprise_relationship.rb'
- 'app/models/enterprise_relationship_permission.rb'
- 'app/models/enterprise_role.rb'
- 'app/models/enterprise_set.rb'
@@ -796,7 +783,6 @@ Style/FrozenStringLiteralComment:
- 'app/models/model_set.rb'
- 'app/models/order_cycle.rb'
- 'app/models/order_cycle_set.rb'
- 'app/models/order_updater.rb'
- 'app/models/preference_sections/footer_and_external_links_section.rb'
- 'app/models/preference_sections/group_signup_page_section.rb'
- 'app/models/preference_sections/header_section.rb'
@@ -824,16 +810,12 @@ Style/FrozenStringLiteralComment:
- 'app/models/spree/calculator_decorator.rb'
- 'app/models/spree/classification_decorator.rb'
- 'app/models/spree/concerns/payment_method_distributors.rb'
- 'app/models/spree/credit_card_decorator.rb'
- 'app/models/spree/gateway/migs.rb'
- 'app/models/spree/gateway/pin.rb'
- 'app/models/spree/gateway/stripe_connect.rb'
- 'app/models/spree/gateway_decorator.rb'
- 'app/models/spree/image_decorator.rb'
- 'app/models/spree/line_item_decorator.rb'
- 'app/models/spree/option_type_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/payment_method_decorator.rb'
- 'app/models/spree/preferences/file_configuration.rb'
- 'app/models/spree/price_decorator.rb'
- 'app/models/spree/product_decorator.rb'
@@ -842,7 +824,6 @@ Style/FrozenStringLiteralComment:
- 'app/models/spree/product_set.rb'
- 'app/models/spree/property.rb'
- 'app/models/spree/shipping_method_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'
@@ -1125,7 +1106,6 @@ 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_spec.rb'
@@ -1169,6 +1149,8 @@ Style/FrozenStringLiteralComment:
- 'spec/factories/product_factory.rb'
- 'spec/factories/shipment_factory.rb'
- 'spec/factories/shipping_method_factory.rb'
- 'spec/factories/state_factory.rb'
- 'spec/factories/stock_movement_factory.rb'
- 'spec/factories/subscription_factory.rb'
- 'spec/factories/tag_rule_factory.rb'
- 'spec/factories/user_factory.rb'
@@ -1323,7 +1305,6 @@ Style/FrozenStringLiteralComment:
- 'spec/models/exchange_spec.rb'
- 'spec/models/model_set_spec.rb'
- 'spec/models/order_cycle_spec.rb'
- 'spec/models/order_updater_spec.rb'
- 'spec/models/product_import/entry_processor_spec.rb'
- 'spec/models/product_import/inventory_reset_strategy_spec.rb'
- 'spec/models/product_import/reset_absent_spec.rb'
@@ -1461,6 +1442,7 @@ Style/FrozenStringLiteralComment:
- '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'
- 'spec/views/spree/admin/shared/_order_links.html.haml_spec.rb'
# Offense count: 48
# Configuration parameters: MinBodyLength.
@@ -1491,18 +1473,21 @@ Style/GuardClause:
- 'spec/support/request/distribution_helper.rb'
- 'spec/support/request/shop_workflow.rb'
# Offense count: 54
# Offense count: 66
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
Style/HashSyntax:
Exclude:
- 'spec/factories/stock_location_factory.rb'
- 'spec/models/spree/credit_card_spec.rb'
- 'spec/models/spree/payment_spec.rb'
# Offense count: 1
# Offense count: 2
Style/MissingRespondToMissing:
Exclude:
- 'app/helpers/application_helper.rb'
- 'app/models/spree/gateway.rb'
# Offense count: 2
Style/MixinUsage:
@@ -1510,7 +1495,7 @@ Style/MixinUsage:
- 'lib/open_food_network/orders_and_fulfillments_report.rb'
- 'spec/lib/open_food_network/packing_report_spec.rb'
# Offense count: 39
# Offense count: 37
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
# SupportedStyles: predicate, comparison
@@ -1521,7 +1506,6 @@ Style/NumericPredicate:
- 'app/controllers/spree/orders_controller.rb'
- 'app/helpers/checkout_helper.rb'
- 'app/helpers/shared_helper.rb'
- 'app/models/order_updater.rb'
- 'app/models/product_import/product_importer.rb'
- 'app/models/product_import/spreadsheet_entry.rb'
- 'app/models/spree/adjustment_decorator.rb'
@@ -1548,6 +1532,18 @@ Style/RaiseArgs:
Exclude:
- 'spec/controllers/checkout_controller_spec.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/RandomWithOffset:
Exclude:
- 'spec/factories.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/RedundantPercentQ:
Exclude:
- 'spec/support/request/web_helper.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
@@ -1556,6 +1552,14 @@ Style/RegexpLiteral:
Exclude:
- 'lib/spree/core/controller_helpers/auth.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: implicit, explicit
Style/RescueStandardError:
Exclude:
- 'lib/spree/core/delegate_belongs_to.rb'
# Offense count: 231
Style/Send:
Exclude:

View File

@@ -204,7 +204,7 @@ GEM
activerecord (>= 3.2.0, < 5.0)
fog (~> 1.0)
rails (>= 3.2.0, < 5.0)
ddtrace (0.39.0)
ddtrace (0.40.0)
msgpack
debugger-linecache (1.2.0)
delayed_job (4.1.8)

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService, RailsFlashLoader) ->
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService, Messages) ->
# Handles syncing of current cart/order state to server
new class Cart
dirty: false
@@ -50,7 +50,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
@popQueue() if @update_enqueued
.error (response, status)=>
RailsFlashLoader.loadFlash({error: t('js.cart.add_to_cart_failed')})
Messages.flash({error: t('js.cart.add_to_cart_failed')})
@update_running = false
compareAndNotifyStockLevels: (stockLevels) =>

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeElements, PaymentMethods, $http, Navigation, CurrentHub, RailsFlashLoader, Loading)->
Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeElements, PaymentMethods, $http, Navigation, CurrentHub, Messages)->
new class Checkout
errors: {}
secrets: {}
@@ -13,7 +13,7 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeE
@submit()
submit: =>
Loading.message = t 'submitting_order'
Messages.loading(t 'submitting_order')
$http.put('/checkout.json', {order: @preprocess()})
.then (response) =>
Navigation.go response.data.path
@@ -39,8 +39,7 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeE
@loadFlash(response.data.flash)
loadFlash: (flash) =>
Loading.clear()
RailsFlashLoader.loadFlash(flash)
Messages.flash(flash)
# Rails wants our Spree::Address data to be provided with _attributes
preprocess: ->

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'CreditCard', ($injector, $rootScope, CreditCards, StripeElements, Navigation, $http, RailsFlashLoader, Loading)->
Darkswarm.factory 'CreditCard', ($injector, $rootScope, CreditCards, StripeElements, Navigation, $http, Messages)->
new class CreditCard
visible: false
errors: {}
@@ -12,16 +12,15 @@ Darkswarm.factory 'CreditCard', ($injector, $rootScope, CreditCards, StripeEleme
params = @process_params()
$http.put('/credit_cards/new_from_token', params )
.success (data, status) =>
Loading.clear()
Messages.clear()
@reset()
CreditCards.add(data)
.error (response, status) =>
if response.path
Navigation.go response.path
else
Loading.clear()
@errors = response.errors
RailsFlashLoader.loadFlash(response.flash)
Messages.flash(response.flash)
setFullName: ->
@secrets.name = "#{@secrets.first_name} #{@secrets.last_name}"

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'CreditCards', ($http, $filter, savedCreditCards, RailsFlashLoader)->
Darkswarm.factory 'CreditCards', ($http, $filter, savedCreditCards, Messages)->
new class CreditCard
saved: $filter('orderBy')(savedCreditCards,'-is_default')
@@ -10,6 +10,6 @@ Darkswarm.factory 'CreditCards', ($http, $filter, savedCreditCards, RailsFlashLo
for othercard in @saved when othercard != card
othercard.is_default = false
$http.put("/credit_cards/#{card.id}", is_default: true).then (data) ->
RailsFlashLoader.loadFlash({success: t('js.default_card_updated')})
Messages.success(t('js.default_card_updated'))
, (response) ->
RailsFlashLoader.loadFlash({error: response.data.flash.error})
Messages.flash(response.data.flash)

View File

@@ -1,4 +1,4 @@
angular.module("Darkswarm").factory 'Customer', ($resource, RailsFlashLoader) ->
angular.module("Darkswarm").factory 'Customer', ($resource, Messages) ->
Customer = $resource('/api/customers/:id/:action.json', {}, {
'index':
method: 'GET'
@@ -13,8 +13,8 @@ angular.module("Darkswarm").factory 'Customer', ($resource, RailsFlashLoader) ->
Customer.prototype.update = ->
@$update().then (response) =>
RailsFlashLoader.loadFlash({success: t('js.changes_saved')})
Messages.success(t('js.changes_saved'))
, (response) =>
RailsFlashLoader.loadFlash({error: response.data.error})
Messages.error(response.data.error)
Customer

View File

@@ -1,5 +1,5 @@
Darkswarm.factory "Loading", ->
new class Loading
message: null
message: null
clear: =>
@message = null

View File

@@ -0,0 +1,17 @@
Darkswarm.factory "Messages", (Loading, RailsFlashLoader)->
new class Messages
loading: (message) ->
Loading.message = message
success: (message) ->
@flash(success: message)
error: (message) ->
@flash(error: message)
flash: (flash) ->
@clear()
RailsFlashLoader.loadFlash(flash)
clear: ->
Loading.clear()

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
Darkswarm.factory 'StripeElements', ($rootScope, Messages) ->
new class StripeElements
# These are both set from the StripeElements directive
stripe: null
@@ -8,39 +8,49 @@ Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
requestToken: (secrets, submit, loading_message = t("processing_payment")) ->
return unless @stripe? && @card?
Loading.message = loading_message
Messages.loading loading_message
cardData = @makeCardData(secrets)
@stripe.createToken(@card, cardData).then (response) =>
if(response.error)
Loading.clear()
RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"})
@triggerAngularDigest()
console.error(JSON.stringify(response.error))
@reportError(response.error, t("error") + ": #{response.error.message}")
else
secrets.token = response.token.id
secrets.cc_type = @mapTokenApiCardBrand(response.token.card.brand)
secrets.card = response.token.card
submit()
.catch (response) =>
# Stripe handles errors in the response above. This code may never be
# reached. But if we get here, we want to know.
@reportError(response, t("js.stripe_elements.unknown_error_from_stripe"))
throw response
# Create Payment Method to be used with the Stripe Payment Intents API
createPaymentMethod: (secrets, submit, loading_message = t("processing_payment")) ->
return unless @stripe? && @card?
Loading.message = loading_message
Messages.loading loading_message
cardData = @makeCardData(secrets)
@stripe.createPaymentMethod({ type: 'card', card: @card }, @card, cardData).then (response) =>
if(response.error)
Loading.clear()
RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"})
@triggerAngularDigest()
console.error(JSON.stringify(response.error))
@reportError(response.error, t("error") + ": #{response.error.message}")
else
secrets.token = response.paymentMethod.id
secrets.cc_type = @mapPaymentMethodsApiCardBrand(response.paymentMethod.card.brand)
secrets.card = response.paymentMethod.card
submit()
.catch (response) =>
# Stripe handles errors in the response above. This code may never be
# reached. But if we get here, we want to know.
@reportError(response, t("js.stripe_elements.unknown_error_from_stripe"))
throw response
reportError: (error, messageForUser) ->
Messages.error(messageForUser)
@triggerAngularDigest()
console.error(error)
Bugsnag.notify(new Error(JSON.stringify(error)))
triggerAngularDigest: ->
# $evalAsync is improved way of triggering a digest without calling $apply

View File

@@ -0,0 +1,177 @@
# frozen_string_literal: true
require 'spree/localized_number'
require 'concerns/adjustment_scopes'
# Adjustments represent a change to the +item_total+ of an Order. Each adjustment
# has an +amount+ that can be either positive or negative.
#
# Adjustments can be open/closed/finalized
#
# Once an adjustment is finalized, it cannot be changed, but an adjustment can
# toggle between open/closed as needed
#
# Boolean attributes:
#
# +mandatory+
#
# If this flag is set to true then it means the the charge is required and will not
# be removed from the order, even if the amount is zero. In other words a record
# will be created even if the amount is zero. This is useful for representing things
# such as shipping and tax charges where you may want to make it explicitly clear
# that no charge was made for such things.
#
# +eligible?+
#
# This boolean attributes stores whether this adjustment is currently eligible
# for its order. Only eligible adjustments count towards the order's adjustment
# total. This allows an adjustment to be preserved if it becomes ineligible so
# it might be reinstated.
module Spree
class Adjustment < ActiveRecord::Base
extend Spree::LocalizedNumber
# Deletion of metadata is handled in the database.
# So we don't need the option `dependent: :destroy` as long as
# AdjustmentMetadata has no destroy logic itself.
has_one :metadata, class_name: 'AdjustmentMetadata'
belongs_to :adjustable, polymorphic: true
belongs_to :source, polymorphic: true
belongs_to :originator, polymorphic: true
belongs_to :tax_rate, -> { where spree_adjustments: { originator_type: 'Spree::TaxRate' } },
foreign_key: 'originator_id'
validates :label, presence: true
validates :amount, numericality: true
after_save :update_adjustable
after_destroy :update_adjustable
state_machine :state, initial: :open do
event :close do
transition from: :open, to: :closed
end
event :open do
transition from: :closed, to: :open
end
event :finalize do
transition from: [:open, :closed], to: :finalized
end
end
scope :tax, -> { where(originator_type: 'Spree::TaxRate', adjustable_type: 'Spree::Order') }
scope :price, -> { where(adjustable_type: 'Spree::LineItem') }
scope :optional, -> { where(mandatory: false) }
scope :charge, -> { where('amount >= 0') }
scope :credit, -> { where('amount < 0') }
scope :return_authorization, -> { where(source_type: "Spree::ReturnAuthorization") }
scope :enterprise_fee, -> { where(originator_type: 'EnterpriseFee') }
scope :admin, -> { where(source_type: nil, originator_type: nil) }
scope :included_tax, -> {
where(originator_type: 'Spree::TaxRate', adjustable_type: 'Spree::LineItem')
}
scope :with_tax, -> { where('spree_adjustments.included_tax <> 0') }
scope :without_tax, -> { where('spree_adjustments.included_tax = 0') }
scope :payment_fee, -> { where(AdjustmentScopes::PAYMENT_FEE_SCOPE) }
scope :shipping, -> { where(AdjustmentScopes::SHIPPING_SCOPE) }
scope :eligible, -> { where(AdjustmentScopes::ELIGIBLE_SCOPE) }
localize_number :amount
# Update the boolean _eligible_ attribute which determines which adjustments
# count towards the order's adjustment_total.
def set_eligibility
result = mandatory || (amount != 0 && eligible_for_originator?)
update_column(:eligible, result)
end
# Allow originator of the adjustment to perform an additional eligibility of the adjustment
# Should return _true_ if originator is absent or doesn't implement _eligible?_
def eligible_for_originator?
return true if originator.nil?
!originator.respond_to?(:eligible?) || originator.eligible?(source)
end
# Update both the eligibility and amount of the adjustment. Adjustments
# delegate updating of amount to their Originator when present, but only if
# +locked+ is false. Adjustments that are +locked+ will never change their amount.
#
# Adjustments delegate updating of amount to their Originator when present,
# but only if when they're in "open" state, closed or finalized adjustments
# are not recalculated.
#
# It receives +calculable+ as the updated source here so calculations can be
# performed on the current values of that source. If we used +source+ it
# could load the old record from db for the association. e.g. when updating
# more than on line items at once via accepted_nested_attributes the order
# object on the association would be in a old state and therefore the
# adjustment calculations would not performed on proper values
def update!(calculable = nil)
return if immutable?
# Fix for Spree issue #3381
# If we attempt to call 'source' before the reload, then source is currently
# the order object. After calling a reload, the source is the Shipment.
reload
originator.update_adjustment(self, calculable || source) if originator.present?
set_eligibility
end
def currency
adjustable ? adjustable.currency : Spree::Config[:currency]
end
def display_amount
Spree::Money.new(amount, currency: currency)
end
def immutable?
state != "open"
end
def set_included_tax!(rate)
tax = amount - (amount / (1 + rate))
set_absolute_included_tax! tax
end
def set_absolute_included_tax!(tax)
# This rubocop issue can now fixed by renaming Adjustment#update! to something else,
# then AR's update! can be used instead of update_attributes!
# rubocop:disable Rails/ActiveRecordAliases
update_attributes! included_tax: tax.round(2)
# rubocop:enable Rails/ActiveRecordAliases
end
def display_included_tax
Spree::Money.new(included_tax, currency: currency)
end
def has_tax?
included_tax.positive?
end
def self.without_callbacks
skip_callback :save, :after, :update_adjustable
skip_callback :destroy, :after, :update_adjustable
result = yield
ensure
set_callback :save, :after, :update_adjustable
set_callback :destroy, :after, :update_adjustable
result
end
private
def update_adjustable
adjustable.update! if adjustable.is_a? Order
end
end
end

View File

@@ -1,62 +0,0 @@
require 'spree/localized_number'
require 'concerns/adjustment_scopes'
module Spree
Adjustment.class_eval do
extend Spree::LocalizedNumber
# Deletion of metadata is handled in the database.
# So we don't need the option `dependent: :destroy` as long as
# AdjustmentMetadata has no destroy logic itself.
has_one :metadata, class_name: 'AdjustmentMetadata'
belongs_to :tax_rate, -> { where spree_adjustments: { originator_type: 'Spree::TaxRate' } },
foreign_key: 'originator_id'
scope :enterprise_fee, -> { where(originator_type: 'EnterpriseFee') }
scope :admin, -> { where(source_type: nil, originator_type: nil) }
scope :included_tax, -> {
where(originator_type: 'Spree::TaxRate', adjustable_type: 'Spree::LineItem')
}
scope :with_tax, -> { where('spree_adjustments.included_tax <> 0') }
scope :without_tax, -> { where('spree_adjustments.included_tax = 0') }
scope :payment_fee, -> { where(AdjustmentScopes::PAYMENT_FEE_SCOPE) }
scope :shipping, -> { where(AdjustmentScopes::SHIPPING_SCOPE) }
scope :eligible, -> { where(AdjustmentScopes::ELIGIBLE_SCOPE) }
localize_number :amount
def set_included_tax!(rate)
tax = amount - (amount / (1 + rate))
set_absolute_included_tax! tax
end
def set_absolute_included_tax!(tax)
# This rubocop issue can only be fixed when Adjustment#update! is brought from Spree to OFN
# and renamed to something else, then AR's update! can be used instead of update_attributes!
# rubocop:disable Rails/ActiveRecordAliases
update_attributes! included_tax: tax.round(2)
# rubocop:enable Rails/ActiveRecordAliases
end
def display_included_tax
Spree::Money.new(included_tax, currency: currency)
end
def has_tax?
included_tax > 0
end
def self.without_callbacks
skip_callback :save, :after, :update_adjustable
skip_callback :destroy, :after, :update_adjustable
result = yield
ensure
set_callback :save, :after, :update_adjustable
set_callback :destroy, :after, :update_adjustable
result
end
end
end

View File

@@ -0,0 +1,56 @@
# frozen_string_literal: true
module Spree
class Calculator < ActiveRecord::Base
belongs_to :calculable, polymorphic: true
# This method must be overriden in concrete calculator.
#
# It should return amount computed based on #calculable and/or optional parameter
def compute(_something = nil)
raise NotImplementedError, 'please use concrete calculator'
end
# overwrite to provide description for your calculators
def self.description
'Base Calculator'
end
###################################################################
def self.register(*klasses); end
# Returns all calculators applicable for kind of work
def self.calculators
Rails.application.config.spree.calculators
end
def to_s
self.class.name.titleize.gsub("Calculator\/", "")
end
def description
self.class.description
end
def available?(_object)
true
end
private
# Given an object which might be an Order or a LineItem (amongst
# others), return a collection of line items.
def line_items_for(object)
if object.is_a?(Spree::LineItem)
[object]
elsif object.respond_to? :line_items
object.line_items
elsif object.respond_to?(:order) && object.order.present?
object.order.line_items
else
[object]
end
end
end
end

View File

@@ -1,19 +0,0 @@
module Spree
Calculator.class_eval do
private
# Given an object which might be an Order or a LineItem (amongst
# others), return a collection of line items.
def line_items_for(object)
if object.is_a?(Spree::LineItem)
[object]
elsif object.respond_to? :line_items
object.line_items
elsif object.respond_to?(:order) && object.order.present?
object.order.line_items
else
[object]
end
end
end
end

View File

@@ -3,12 +3,14 @@ require 'active_support/concern'
# This concern is used to duplicate the associations distributors and distributor_ids
# across payment method and gateway
# this fixes the inheritance problem https://github.com/openfoodfoundation/openfoodnetwork/issues/2781
module Spree::PaymentMethodDistributors
extend ActiveSupport::Concern
module Spree
module PaymentMethodDistributors
extend ActiveSupport::Concern
def self.included(base)
base.class_eval do
has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', class_name: 'Enterprise', foreign_key: 'payment_method_id', association_foreign_key: 'distributor_id'
def self.included(base)
base.class_eval do
has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', class_name: 'Enterprise', foreign_key: 'payment_method_id', association_foreign_key: 'distributor_id'
end
end
end
end

View File

@@ -179,11 +179,11 @@ module Spree
# 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!(shipping: order.ship_total * 100,
tax: order.tax_total * 100,
subtotal: order.item_total * 100,
discount: 0,
currency: currency)
options.merge!({ billing_address: order.bill_address.try(:active_merchant_hash),
shipping_address: order.ship_address.try(:active_merchant_hash) })

View File

@@ -1,45 +1,47 @@
module Spree::Preferences
class FileConfiguration < Configuration
def self.preference(name, type, *args)
if type == :file
super "#{name}_file_name", :string, *args
super "#{name}_content_type", :string, *args
super "#{name}_file_size", :integer, *args
super "#{name}_updated_at", :string, *args
module Spree
module Preferences
class FileConfiguration < Configuration
def self.preference(name, type, *args)
if type == :file
super "#{name}_file_name", :string, *args
super "#{name}_content_type", :string, *args
super "#{name}_file_size", :integer, *args
super "#{name}_updated_at", :string, *args
else
super name, type, *args
else
super name, type, *args
end
end
end
def get_preference(key)
if !has_preference?(key) && has_attachment?(key)
public_send key
else
super key
def get_preference(key)
if !has_preference?(key) && has_attachment?(key)
public_send key
else
super key
end
end
end
alias :[] :get_preference
alias :[] :get_preference
def preference_type(name)
if has_attachment? name
:file
else
super name
def preference_type(name)
if has_attachment? name
:file
else
super name
end
end
end
# Spree's Configuration responds to preference methods via method_missing, but doesn't
# override respond_to?, which consequently reports those methods as unavailable. Paperclip
# errors if respond_to? isn't correct, so we override it here.
def respond_to?(method, include_all = false)
name = method.to_s.delete('=')
super(self.class.preference_getter_method(name), include_all) || super(method, include_all)
end
# Spree's Configuration responds to preference methods via method_missing, but doesn't
# override respond_to?, which consequently reports those methods as unavailable. Paperclip
# errors if respond_to? isn't correct, so we override it here.
def respond_to?(method, include_all = false)
name = method.to_s.delete('=')
super(self.class.preference_getter_method(name), include_all) || super(method, include_all)
end
def has_attachment?(name)
self.class.respond_to?(:attachment_definitions) &&
self.class.attachment_definitions.key?(name.to_sym)
def has_attachment?(name)
self.class.respond_to?(:attachment_definitions) &&
self.class.attachment_definitions.key?(name.to_sym)
end
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
module Spree
class TaxCategory < ActiveRecord::Base
acts_as_paranoid
validates :name, presence: true, uniqueness: { scope: :deleted_at }
has_many :tax_rates, dependent: :destroy
before_save :set_default_category
def set_default_category
# set existing default tax category to false if this one has been marked as default
return unless is_default && tax_category = self.class.find_by(is_default: true)
tax_category.update_column(:is_default, false) unless tax_category == self
end
end
end

View File

@@ -0,0 +1,132 @@
# frozen_string_literal: false
module Spree
class DefaultTaxZoneValidator < ActiveModel::Validator
def validate(record)
return unless record.included_in_price
return if Zone.default_tax
record.errors.add(:included_in_price, Spree.t(:included_price_validation))
end
end
end
module Spree
class TaxRate < ActiveRecord::Base
acts_as_paranoid
include Spree::Core::CalculatedAdjustments
belongs_to :zone, class_name: "Spree::Zone"
belongs_to :tax_category, class_name: "Spree::TaxCategory"
validates :amount, presence: true, numericality: true
validates :tax_category_id, presence: true
validates_with DefaultTaxZoneValidator
scope :by_zone, ->(zone) { where(zone_id: zone) }
# Gets the array of TaxRates appropriate for the specified order
def self.match(order)
return [] if order.distributor && !order.distributor.charges_sales_tax
return [] unless order.tax_zone
all.select do |rate|
rate.zone == order.tax_zone || rate.zone.contains?(order.tax_zone) || rate.zone.default_tax
end
end
def self.adjust(order)
order.adjustments.tax.destroy_all
order.line_item_adjustments.where(originator_type: 'Spree::TaxRate').destroy_all
match(order).each do |rate|
rate.adjust(order)
end
end
# For VAT, the default rate is the rate that is configured for the default category
# It is needed for every price calculation (as all customer facing prices include VAT)
# Here we return the actual amount, which may be 0 in case of wrong setup, but is never nil
def self.default
category = TaxCategory.includes(:tax_rates).find_by(is_default: true)
return 0 unless category
address ||= Address.new(country_id: Spree::Config[:default_country_id])
rate = category.tax_rates.detect { |tax_rate| tax_rate.zone.include? address }.try(:amount)
rate || 0
end
# Creates necessary tax adjustments for the order.
def adjust(order)
label = create_label
if included_in_price
if Zone.default_tax.contains? order.tax_zone
order.line_items.each { |line_item| create_adjustment(label, line_item, line_item) }
else
amount = -1 * calculator.compute(order)
label = Spree.t(:refund) + label
order.adjustments.create(
amount: amount,
source: order,
originator: self,
state: "closed",
label: label
)
end
else
create_adjustment(label, order, order)
end
order.adjustments(:reload)
order.line_items(:reload)
# TaxRate adjustments (order.adjustments.tax)
# and price adjustments (tax included on line items) consist of 100% tax
(order.adjustments.tax + order.price_adjustments).each do |adjustment|
adjustment.set_absolute_included_tax! adjustment.amount
end
end
# Manually apply a TaxRate to a particular amount. TaxRates normally compute against
# LineItems or Orders, so we mock out a line item here to fit the interface
# that our calculator (usually DefaultTax) expects.
def compute_tax(amount)
line_item = LineItem.new quantity: 1
line_item.tax_category = tax_category
line_item.define_singleton_method(:price) { amount }
# Tax on adjustments (represented by the included_tax field) is always inclusive of
# tax. However, there's nothing to stop an admin from setting one up with a tax rate
# that's marked as not inclusive of tax, and that would result in the DefaultTax
# calculator generating a slightly incorrect value. Therefore, we treat the tax
# rate as inclusive of tax for the calculations below, regardless of its original
# setting.
with_tax_included_in_price do
calculator.compute line_item
end
end
private
def create_label
label = ""
label << (name.presence || tax_category.name) + " "
label << (show_rate_in_label? ? "#{amount * 100}%" : "")
end
def with_tax_included_in_price
old_included_in_price = included_in_price
self.included_in_price = true
calculator.calculable.included_in_price = true
result = yield
ensure
self.included_in_price = old_included_in_price
calculator.calculable.included_in_price = old_included_in_price
result
end
end
end

View File

@@ -1,61 +0,0 @@
module Spree
TaxRate.class_eval do
class << self
def match(order)
return [] if order.distributor && !order.distributor.charges_sales_tax
return [] unless order.tax_zone
all.select do |rate|
rate.zone == order.tax_zone || rate.zone.contains?(order.tax_zone) || rate.zone.default_tax
end
end
end
def adjust_with_included_tax(order)
adjust_without_included_tax(order)
order.adjustments(:reload)
order.line_items(:reload)
# TaxRate adjustments (order.adjustments.tax) and price adjustments (tax included on line items) consist of 100% tax
(order.adjustments.tax + order.price_adjustments).each do |adjustment|
adjustment.set_absolute_included_tax! adjustment.amount
end
end
alias_method_chain :adjust, :included_tax
# Manually apply a TaxRate to a particular amount. TaxRates normally compute against
# LineItems or Orders, so we mock out a line item here to fit the interface
# that our calculator (usually DefaultTax) expects.
def compute_tax(amount)
line_item = LineItem.new quantity: 1
line_item.tax_category = tax_category
line_item.define_singleton_method(:price) { amount }
# Tax on adjustments (represented by the included_tax field) is always inclusive of
# tax. However, there's nothing to stop an admin from setting one up with a tax rate
# that's marked as not inclusive of tax, and that would result in the DefaultTax
# calculator generating a slightly incorrect value. Therefore, we treat the tax
# rate as inclusive of tax for the calculations below, regardless of its original
# setting.
with_tax_included_in_price do
calculator.compute line_item
end
end
private
def with_tax_included_in_price
old_included_in_price = included_in_price
self.included_in_price = true
calculator.calculable.included_in_price = true
result = yield
ensure
self.included_in_price = old_included_in_price
calculator.calculable.included_in_price = old_included_in_price
result
end
end
end

View File

@@ -990,7 +990,7 @@ ar:
resend_email: إعادة إرسال البريد الإلكتروني
has_no_payment_methods: "لا تحتوي %{enterprise} حاليًا على طريقة دفع"
has_no_shipping_methods: "%{enterprise} لا يوجد لديها حاليا طريقة شحن"
email_confirmation: "تأكيد البريد الإلكتروني معلق. لقد أرسلنا رسالة تأكيد بالبريد الإلكتروني إلى %{email}."
email_confirmation: "تأكيد البريد الإلكتروني معلق. لقد أرسلنا لك رسالة تأكيد على البريد الإلكتروني إلى %{email}."
not_visible: "%{enterprise} غير مرئي وبالتالي لا يمكن العثور عليه على الخريطة أو في عمليات البحث"
reports:
hidden: خفية
@@ -1056,7 +1056,7 @@ ar:
unpause_subscription: إلغاء الاشتراك المؤقت
cancel_subscription: إلغاء الاشتراك
filters:
query_placeholder: "البحث عن طريق البريد الإلكتروني ..."
query_placeholder: "ابحث عن طريق البريد الإلكتروني ..."
setup_explanation:
title: "الاشتراكات"
just_a_few_more_steps: 'فقط بضع خطوات أخرى قبل أن تبدأ:'
@@ -1182,7 +1182,7 @@ ar:
footer_secure: "آمن وموثوق به."
footer_secure_text: "تستخدم شبكة الغذاء المفتوح تشفير( SSL 2048 بت RSA) في كل مكان للحفاظ على خصوصية معلومات التسوق والدفع. لا تقوم خوادمنا بتخزين تفاصيل بطاقة الائتمان الخاصة بك ، وتتم معالجة المدفوعات بواسطة خدمات متوافقة مع PCI."
footer_contact_headline: "أبق على اتصال"
footer_contact_email: "ارسل لنا عبر البريد الإلكتروني"
footer_contact_email: "راسلنا عبر البريد الإلكتروني"
footer_nav_headline: "التنقل"
footer_join_headline: "انضم إلينا"
footer_join_body: "إنشاء قائمة أو متجر أو دليل المجموعة على شبكة الغذاء المفتوح."
@@ -2869,6 +2869,8 @@ ar:
adjustments: "التعديلات"
payments: "المدفوعات"
return_authorizations: "عودة التراخيص"
credit_owed: "الائتمان مدين"
new_adjustment: "تعديل جديد"
payment: "دفعة"
payment_method: "طريقة الدفع او السداد"
shipment: "الشحنة"
@@ -3074,6 +3076,7 @@ ar:
other: "منعت أخطاء %{count} حفظ هذا السجل:"
there_were_problems_with_the_following_fields: "كانت هناك مشاكل مع الحقول التالية"
payments_list:
date_time: "التاريخ / الوقت"
amount: "القيمة"
payment_method: "طريقة الدفع او السداد"
payment_state: "حالة الدفعة"
@@ -3580,3 +3583,12 @@ ar:
shipment:
cannot_ready: "لا يمكن تجهيز الشحنة"
invalid_taxonomy_id: "معرف التصنيف غير صالح."
activerecord:
models:
spree/payment:
zero: المدفوعات
one: دفع
two: المدفوعات
few: المدفوعات
many: المدفوعات
other: الدفعات

View File

@@ -2544,7 +2544,7 @@ ca:
paid: "pagat"
pending: "pendents"
processing: "processant"
void: "buit"
void: "pendent"
invalid: "invàlid"
resend_user_email_confirmation:
resend: "Reenviar"
@@ -2849,8 +2849,8 @@ ca:
continue: "Continua"
fill_in_customer_info: "Ompliu la informació de la consumidora"
new_payment: "Nou pagament"
capture: "Captura"
void: "Buit"
capture: "Pagat"
void: "Pendent"
login: "Inicia sessió"
password: "Contrasenya"
signature: "Signatura"
@@ -3067,7 +3067,7 @@ ca:
index:
listing_orders: "Llistat comandes"
new_order: "Nova comanda"
capture: "Captura"
capture: "Pagat"
ship: "Enviament"
edit: "Editar"
order_not_updated: "La comanda no s'ha pogut actualitzar"
@@ -3201,7 +3201,7 @@ ca:
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ó
no_payment_via_admin_backend: Els pagaments amb Paypal no es poden marcar com pagats 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:
@@ -3363,7 +3363,7 @@ ca:
paid: pagat
pending: pendents
processing: processant
void: buit
void: pendent
invalid: invàlid
order_mailer:
cancel_email:

View File

@@ -2771,6 +2771,11 @@ See the %{link} to find out more about %{sitename}'s features and to start using
signup_or_login: "Start By Signing Up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
stripe_elements:
unknown_error_from_stripe: |
There was a problem setting up your card in our payments gateway.
Please refresh the page and try again, if it fails a second time,
please contact us for support.
# Singular and plural forms of commonly used words.
# We use these entries to pluralize unit names in every language.

View File

@@ -2642,6 +2642,11 @@ en_CA:
signup_or_login: "Start By Signing Up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
stripe_elements:
unknown_error_from_stripe: |
There was a problem setting up your card in our payments gateway.
Please refresh the page and try again, if it fails a second time,
please contact us for support.
inflections:
each:
one: "each"
@@ -3301,7 +3306,7 @@ en_CA:
sortable_header:
name: "Name"
number: "Number"
state: "Province"
state: "State"
payment_state: "Payment State"
shipment_state: "Shipment State"
email: "Email"

View File

@@ -1244,11 +1244,11 @@ en_FR:
menu_4_title: "Groups"
menu_4_url: "/groups"
menu_5_title: "About"
menu_5_url: "https://apropos.openfoodfrance.org/"
menu_5_url: "https://apropos.coopcircuits.fr/"
menu_6_title: "Connect"
menu_6_url: "https://apropos.openfoodfrance.org/blog/"
menu_6_url: "https://apropos.coopcircuits.fr/blog/"
menu_7_title: "Learn"
menu_7_url: "https://apropos.openfoodfrance.org/support/"
menu_7_url: "https://apropos.coopcircuits.fr/ressources/"
logo: "Logo (640x130)"
logo_mobile: "Mobile logo (75x26)"
logo_mobile_svg: "Mobile logo (SVG)"
@@ -2643,6 +2643,11 @@ en_FR:
signup_or_login: "Start By Signing Up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
stripe_elements:
unknown_error_from_stripe: |
There was a problem setting up your card in our payments gateway.
Please refresh the page and try again, if it fails a second time,
please contact us for support.
inflections:
each:
one: "each"

View File

@@ -2649,6 +2649,11 @@ en_GB:
signup_or_login: "Start By signing up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
stripe_elements:
unknown_error_from_stripe: |
There was a problem setting up your card in our payments gateway.
Please refresh the page and try again, if it fails a second time,
please contact us for support.
inflections:
each:
one: "each"
@@ -2779,6 +2784,8 @@ en_GB:
adjustments: "Adjustments"
payments: "Payments"
return_authorizations: "Return Authorisations"
credit_owed: "Credit Owed"
new_adjustment: "New Adjustment"
payment: "Payment"
payment_method: "Payment Method"
shipment: "Shipment"
@@ -2980,6 +2987,7 @@ en_GB:
other: "%{count} errors prohibited this record from being saved:"
there_were_problems_with_the_following_fields: "There were problems with the following fields"
payments_list:
date_time: "Date/time"
amount: "Amount"
payment_method: "Payment Method"
payment_state: "Payment State"
@@ -3486,3 +3494,8 @@ en_GB:
shipment:
cannot_ready: "Cannot ready shipment."
invalid_taxonomy_id: "Invalid taxonomy id."
activerecord:
models:
spree/payment:
one: Payment
other: Payments

View File

@@ -2773,6 +2773,8 @@ en_US:
adjustments: "Adjustments"
payments: "Payments"
return_authorizations: "Return Authorizations"
credit_owed: "Credit Owed"
new_adjustment: "New Adjustment"
payment: "Payment"
payment_method: "Payment Method"
shipment: "Shipment"
@@ -2974,6 +2976,7 @@ en_US:
other: "%{count} errors prohibited this record from being saved:"
there_were_problems_with_the_following_fields: "There were problems with the following fields"
payments_list:
date_time: "Date/time"
amount: "Amount"
payment_method: "Payment Method"
payment_state: "Payment State"
@@ -3480,3 +3483,8 @@ en_US:
shipment:
cannot_ready: "Cannot ready shipment."
invalid_taxonomy_id: "Invalid taxonomy id."
activerecord:
models:
spree/payment:
one: Payment
other: Payments

View File

@@ -2544,7 +2544,7 @@ es:
paid: "pagado"
pending: "pendiente"
processing: "procesando"
void: "vacío"
void: "pendiente"
invalid: "inválido"
resend_user_email_confirmation:
resend: "Reenviar"
@@ -2849,8 +2849,8 @@ es:
continue: "Continuar"
fill_in_customer_info: "Por favor complete la información de la consumidora"
new_payment: "Nuevo pago"
capture: "Captura"
void: "Vacío"
capture: "Pagado"
void: "Pendiente"
login: "Iniciar sesión"
password: "Contraseña"
signature: "Firma"
@@ -3067,7 +3067,7 @@ es:
index:
listing_orders: "Pedidos de listado"
new_order: "Nuevo pedido"
capture: "Captura"
capture: "Pagado"
ship: "Envío"
edit: "Editar"
order_not_updated: "El pedido no se pudo actualizar"
@@ -3201,7 +3201,7 @@ es:
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
no_payment_via_admin_backend: Los pagos de PayPal no se pueden marcar como pagados 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:
@@ -3363,7 +3363,7 @@ es:
paid: pagado
pending: pendiente
processing: procesando
void: vacío
void: pendiente
invalid: inválido
order_mailer:
cancel_email:

View File

@@ -185,7 +185,7 @@ fr:
home: "OFF"
title: "Open Food France"
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 ..."
site_meta_description: "Le service proposé est basé sur le logiciel libre Open Food Network. Les organisateurs de circuits courts qui utilisent la plateforme décident ensemble des évolutions à apporter au logiciel, et gèrent conjointement lactivité de la coopérative CoopCircuits. Ils décident notamment du prix quils paieront pour utiliser cette plateforme."
search_by_name: Recherche par nom ou département...
producers_join: Les producteurs et autres hubs basés en France sont invités à rejoindre Open Food France.
charges_sales_tax: Soumis à la TVA?
@@ -1179,21 +1179,21 @@ fr:
mobile_menu:
cart: "Panier"
register_call:
selling_on_ofn: "Vous souhaitez proposer vos produits sur Open Food France?"
selling_on_ofn: "Vous souhaitez proposer vos produits sur CoopCircuits ?"
register: "Démarrez ici"
footer:
footer_secure: "Fiable et sécurisé."
footer_secure_text: "Open Food France utilise un certificat type SSL (2048 bit RSA) pour garantir la confidentialité de votre commandes et données bancaires. Nos serveurs ne conservent pas vos données bancaires et les paiements sont effectués conformément aux normes de sécurité PCI."
footer_contact_headline: "Restez en contact"
footer_secure_text: "CoopCircuits utilise un certificat type SSL (2048 bit RSA) pour garantir la confidentialité de vos commandes et données bancaires. Nos serveurs ne conservent pas vos données bancaires et les paiements sont effectués conformément aux normes de sécurité PCI."
footer_contact_headline: "Général"
footer_contact_email: "Nous écrire"
footer_nav_headline: "Naviguer"
footer_join_headline: "Nous rejoindre"
footer_join_body: "Créer un profil, une boutique ou un groupe sur Open Food France."
footer_nav_headline: "Naviguer sur la plateforme"
footer_join_headline: "S'inscrire"
footer_join_body: "Créer un profil, une boutique ou un groupe sur CoopCircuits."
footer_join_cta: "Je veux en savoir plus!"
footer_legal_call: "Lire nos"
footer_legal_tos: "Termes et conditions"
footer_legal_tos: "conditions générales d'utilisation"
footer_legal_visit: "Nous trouver sur"
footer_legal_text_html: "Open Food Network est une plateforme logicielle open source, libre et gratuite. Nos données sont protégées sous licence %{content_license} et notre code sous %{code_license}."
footer_legal_text_html: "CoopCircuits utilise pour délivrer son service le logiciel libre Open Food Network, dont le code est protégé sous licence %{code_license}. Les autres productions disponibles sur ce site sont protégées sous licence %{content_license}."
footer_data_text_with_privacy_policy_html: "Nous prenons soin de vos données. Voir notre %{privacy_policy} et %{cookies_policy}."
footer_data_text_without_privacy_policy_html: "Nous prenons soin de vos données. Voir notre %{cookies_policy}."
footer_data_privacy_policy: "politique de confidentialité"
@@ -1246,11 +1246,11 @@ fr:
menu_4_title: "Groupes"
menu_4_url: "/groups"
menu_5_title: "A propos"
menu_5_url: "https://apropos.openfoodfrance.org/"
menu_5_url: "https://openfoodfrance.org/sell"
menu_6_title: "Blog"
menu_6_url: "https://apropos.openfoodfrance.org/blog/"
menu_6_url: "https://apropos.coopcircuits.fr/"
menu_7_title: "Support"
menu_7_url: "https://apropos.openfoodfrance.org/support/"
menu_7_url: "https://apropos.coopcircuits.fr/ressources/"
logo: "Logo (640x130)"
logo_mobile: "Logo smartphone (75x26)"
logo_mobile_svg: "Logo smartphone (SVG)"
@@ -1383,24 +1383,24 @@ fr:
cookies_accept_button: "Accepter les cookies"
home_shop: Faire mes courses
brandstory_headline: "Des aliments porteurs de sens."
brandstory_intro: "Parfois, le meilleur moyen de réparer le système, c'est d'en inventer un autre..."
brandstory_part1: "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 véritablement changer le monde."
brandstory_part2: "Nous avons besoin d'un outil pour rendre tout ça réel. Un moyen de redonner le pouvoir à ceux qui cultivent, vendent et achètent la nourriture. Un moyen de raconter les histoires, de gérer la logistique. Un moyen de transformer chaque jour les transactions en actions porteuses de changement."
brandstory_part3: "C'est pour cela que nous construisons cette plateforme, ce \"marché en ligne\", afin de rééquilibrer les échanges et redistribuer le pouvoir. Elle est transparente, pour assurer des relations équitables et favoriser les prises de conscience. Elle est open source, donc possédée par tout le monde. Elle se déploie aux échelles régionales et nationales, et des gens lancent de multiples versions à travers le monde."
brandstory_part4: "Elle fonctionne partout. Elle change tout."
brandstory_part5_strong: "Cette plateforme s'appelle Open Food Network."
brandstory_part6: "Nous aimons notre nourriture. Maintenant nous pouvons aussi aimer notre système alimentaire."
brandstory_intro: "Votre plateforme Open Food France change de nom et devient CoopCircuits, une plateforme libre, cogérée et accessible à tous."
brandstory_part1: "Le service proposé est basé sur le logiciel libre Open Food Network. Les organisateurs de circuits courts qui utilisent la plateforme décident ensemble des évolutions à apporter au logiciel, et gèrent conjointement lactivité de la coopérative CoopCircuits. Ils décident notamment du prix quils paieront pour utiliser cette plateforme."
brandstory_part2: "Afin de permettre à tout type dinitiative de circuit court de fonctionner efficacement, les offres proposées sadaptent à la diversité des modèles économiques : que vous gériez un groupement dachat bénévolement, ou pilotiez une entreprise familiale de distribution, CoopCircuits vous accompagne :-)"
brandstory_part3: " "
brandstory_part4: " "
brandstory_part5_strong: " "
brandstory_part6: " "
learn_body: "Explorer les modèles, les histoires et les ressources disponibles pour vous aider à développer votre propre initiative de commerce/organisation oeuvrant pour un système alimentaire équitable et juste. Trouver des outils pour vous former, des événements et autres opportunités d'apprendre de vos pairs."
learn_cta: "Découvrir "
connect_body: "Rechercher dans le répertoire des producteurs, hubs et groupes pour trouver des commerçants éthiques à côté de chez vous. Inscrivez votre commerce ou organisation sur OFFrance pour que les acheteurs puissent vous trouver. Rejoignez la communauté pour recevoir du soutien et résoudre ensemble les problèmes."
connect_cta: "Explorer"
system_headline: "Faire mes courses - comment ça marche?"
system_headline: "Commander en ligne - comment ça marche?"
system_step1: "1. Recherche"
system_step1_text: "Recherchez des produits locaux, de saison, parmi nos multiples boutiques indépendantes. Filtrez par localisation ou catégorie de produits, livraison en point retrait ou à domicile."
system_step1_text: "Trouvez le circuit court qui vous convient parmi de multiples points dachat indépendants aux modèles variés."
system_step2: "2. Achat"
system_step2_text: "Transformez vos achats en choisissant des produits locaux et abordables, proposés par les divers producteurs et hubs. Découvrez les histoires et les personnes qui se cachent derrière les produits!"
system_step2_text: "Commandez en ligne des produits bios/locaux auprès du circuit court sélectionné, et découvrez les producteurs qui se cachent derrière les produits."
system_step3: "3. Retrait / Livraison"
system_step3_text: "Réceptionnez vos produits à domicile, ou rendez vous chez votre producteur ou hub pour rencontrer les gens qui se cachent derrière les produits. Au delà de la bio-diversité, nous cultivons l'éco-diversité: vivez des expériences d'achat de nourriture uniques et humaines."
system_step3_text: "Retirez votre panier au lieu et à lheure indiqués lors de votre commande, ou à domicile si le circuit sélectionné propose cette option."
cta_headline: "Des achats qui rendent le monde un peu meilleur."
cta_label: "Je vote avec mes achats"
stats_headline: "Nous créons un nouveau système alimentaire."
@@ -1600,8 +1600,8 @@ fr:
components_filters_nofilters: "Pas de filtre"
components_filters_clearfilters: "Vider les filtres"
groups_title: Groupes
groups_headline: Groupes / réseaux territoriaux
groups_text: "Chaque producteur est unique. Chaque entreprise peut offrir quelque chose de différent. Nos groupes sont des collectifs de producteurs, des plateformes et des distributeurs qui partagent une proximité géographique, un marché fermier ou des valeurs. C'est ce qui rend votre expérience d'achat plus simple. Explorez donc ces groupes sélectionnés."
groups_headline: Groupes
groups_text: "Un groupe sur CoopCircuits est une page permettant de communiquer sur un collectif particulier (de producteurs, réseau de distributeurs dun même projet et producteurs associés, etc.) Il comprend une présentation du groupe, une carte permettant de visualiser géographiquement les membres, ainsi que des onglets pour un accès rapide aux boutiques et producteurs du groupe."
groups_search: "Recherche par nom ou mot-clé"
groups_no_groups: "Aucun groupe trouvé"
groups_about: "A propos"
@@ -1614,23 +1614,23 @@ fr:
groups_contact_website: Visiter notre site web
groups_contact_facebook: Nous suivre sur Facebook
groups_signup_title: S'inscrire en tant que groupe
groups_signup_headline: Inscription groupe
groups_signup_intro: "Nous sommes une plate-forme très efficace pour le marketing collaboratif, une excellente manière pour vos membres et parties prenantes d'atteindre de nouveaux marchés. Nous sommes à but non lucratif, abordable et simple."
groups_signup_headline: 'Groupe : un outil marketing au service de votre réseau'
groups_signup_intro: "Rassemblez en un même espace tous les producteurs et boutiques de votre réseau pour renforcer la visibilité de vos membres."
groups_signup_email: Nous écrire
groups_signup_motivation1: Nous transformons les systèmes alimentaires pour remettre de l'équité dans les échanges.
groups_signup_motivation2: C'est pourquoi nous sortons du lit chaque matin. Nous sommes une organisation à but non lucratif, basée sur un code source ouvert. Nous opérons en toute transparence.
groups_signup_motivation3: Vous avez de belles idées, et nous voulons vous aider. Nous partageons nos connaissances, réseaux et ressources. Nous savons que l'isolement ne crée pas le changement, alors coopérons.
groups_signup_motivation4: Nous venons à votre rencontrer.
groups_signup_motivation5: Vous êtes un réseau de circuits de distribution alternatifs, de producteurs, de distributeurs, une administration liée à l'industrie alimentaire ou une autorité locale?
groups_signup_motivation6: Quel que soit votre rôle dans la relocalisation des systèmes alimentaires, nous sommes prêts à vous soutenir. Si vous vous demandez à quoi Open Food Network ressemble / pourrait ressembler dans votre coin du monde, contactez-nous.
groups_signup_motivation7: Nous contribuons à remettre du sens dans les systèmes alimentaires.
groups_signup_motivation8: Vous avez besoin de connecter et d'outiller vos réseaux, nous offrons une plate-forme pour la coopération et l'action. Vous souhaitez de l'engagement. Nous vous aidons à atteindre les acteurs, les parties-prenantes, les secteurs.
groups_signup_motivation9: Vous avez besoin de ressources. Nous mettons à votre service notre expérience. Vous avez besoin de coopération. Nous vous connectons à un large réseau d'acteurs et d'organisations soeurs partout dans le monde.
groups_signup_pricing: Compte groupe
groups_signup_studies: Etudes de cas
groups_signup_contact: Vous voulez discuter?
groups_signup_contact_text: "Prenez contact et découvrez ce qu'Open Food France peut faire pour vous:"
groups_signup_detail: "Plus de précisions."
groups_signup_motivation1: A quoi ça sert ?
groups_signup_motivation2: Le module “groupe” est un espace dédié comprenant une carte des acteurs de votre réseau, une page de présentation, et une liste des producteurs et des boutiques associées. La carte et les listes comprennent une fonction de recherche. Ce module est accessible via un lien internet (URL) unique et peut être intégré sur votre site web.
groups_signup_motivation3: ' '
groups_signup_motivation4: ' '
groups_signup_motivation5: ' '
groups_signup_motivation6: ' '
groups_signup_motivation7: ' '
groups_signup_motivation8: ' '
groups_signup_motivation9: ' '
groups_signup_pricing: Pour qui ?
groups_signup_studies: Histoires de réseaux
groups_signup_contact: Vous souhaitez créer votre module groupe ?
groups_signup_contact_text: "Cette fonctionnalité nest pas encore automatisée. Prenez contact avec nous pour créer votre groupe."
groups_signup_detail: "Les avantages CoopCircuits"
login_invalid: "Email ou mot de passe erroné"
producers_about: A propos
producers_buy: Acheter
@@ -1644,14 +1644,14 @@ fr:
producers_title: Producteurs
producers_headline: Trouvez un producteur local
producers_signup_title: S'inscrire en tant que producteur
producers_signup_headline: Des producteurs, indépendants
producers_signup_motivation: Vendez vos produits et racontez vos histoires pour toucher de nouveaux marchés. Gagnez du temps et de l'argent sur la gestion des opérations courantes. Vous pouvez innover sans prendre de risque. Nous nivellons le terrain de jeu pour des échanges plus équitables.
producers_signup_send: Rejoindre le réseau
producers_signup_enterprise: Comptes entreprises
producers_signup_studies: Les histoires de nos producteurs.
producers_signup_cta_headline: Rejoindre le réseau!
producers_signup_cta_action: Rejoindre le réseau
producers_signup_detail: Comment ça marche.
producers_signup_headline: 'Producteurs : gérez vos ventes directes'
producers_signup_motivation: Vendez vos produits en direct et en ligne via votre boutique producteur. Gagnez du temps sur la gestion de votre commercialisation grâce à CoopCircuits, votre partenaire coopératif et engagé !
producers_signup_send: S'inscrire
producers_signup_enterprise: CoopCircuits vous simplifie la vie
producers_signup_studies: Histoires de producteurs
producers_signup_cta_headline: Rejoindre le réseau
producers_signup_cta_action: S'inscrire
producers_signup_detail: Les avantages CoopCircuits
products_item: Produit
products_description: Description
products_variant: Variante
@@ -1661,31 +1661,31 @@ fr:
products_price: "Prix"
name_or_sku: "NOM OU REF PRODUIT"
register_title: S'inscrire
sell_title: "S'inscrire"
sell_headline: "Aller sur Open Food France!"
sell_motivation: "Mettez en avant vos beaux aliments."
sell_producers: "Producteurs"
sell_hubs: "Hubs"
sell_title: "En savoir plus"
sell_headline: "Gérez vos ventes en ligne avec CoopCircuits"
sell_motivation: "3 options pour interagir avec vos acheteurs"
sell_producers: "Boutique producteur"
sell_hubs: "Boutique multi-producteurs"
sell_groups: "Groupes"
sell_producers_detail: "Créer un profil pour votre entreprise sur OFFrance en quelques minutes. A tout moment vous pourrez créer une boutique en ligne pour vendre vos produits en direct aux acheteurs."
sell_hubs_detail: "Créer un profil pour votre entreprise de distribution ou organisation sur OFFrance. A tout moment vous pourrez créer une boutique multi-fournisseurs."
sell_groups_detail: "Créer un répertoire sur mesure (regroupant différents producteurs et hubs de distribution) pour votre région ou votre organisation."
sell_producers_detail: "Vous êtes producteur ? Créez votre profil pour rejoindre le réseau, et ouvrez votre boutique pour vendre en ligne vos produits."
sell_hubs_detail: "Vous organisez des distributions de produits en provenance de plusieurs producteurs (drive fermier, groupement dachat…) ? Créez le profil de votre initiative, et ouvrez votre boutique multi-producteurs."
sell_groups_detail: "Vous gérez un collectif et souhaitez communiquer sur lensemble des membres qui le composent ? Créez une page groupe."
sell_user_guide: "En savoir plus en explorant le guide utilisateur."
sell_listing_price: "L'inscription sur OFFrance est gratuite. Ouvrir et gérer une boutique sur OFFrance ou créer un groupe sur OFFrance pour votre organisation ou réseau régional, n'est pas gratuit. Il existe deux formules : soit la formule \"petit débrouillard\" où vous pouvez opter pour un montant libre à nous reverser (mais vous ne pouvez pas disposer de support personnalisé), soit vous nous reversez 1% du volume de vente réalisé sur la plateforme pour bénéfier de notre accompagnement. Ce pourcentage peut être dégressif à partir d'un certain montant. Veuillez nous contacter pour en savoir plus !"
sell_embed: "Nous pouvons aussi intégrer votre boutique OFFrance dans votre propre site web ou construire un site web d'alimentation locale sur mesure pour votre région."
sell_ask_services: "Nous consulter sur les services des partenaires OFFrance."
sell_listing_price: "Créez gratuitement votre profil sur CoopCircuits pour être visible auprès des visiteurs et membres du réseau. Lutilisation de CoopCircuits pour vendre en ligne (boutique) est payante après une période dessai de 3 mois. Voir le lien “nos offres” en bas de page pour en savoir plus."
sell_embed: "Nous pouvons aussi intégrer votre boutique CoopCircuits dans votre propre site web ou construire pour vous un site de vente en ligne sappuyant sur une boutique CoopCircuits."
sell_ask_services: "Nous consulter pour en savoir plus."
shops_title: Boutiques
shops_headline: Des achats qui transforment.
shops_text: Les aliments poussent selon des cycles naturels, les fermiers récoltent en cycles. Alors ici, nous achetons aussi en cycles. Si un cycle de vente est terminé, attendez le suivant ou demandez des infos au hub !
shops_headline: Je vote avec mes achats.
shops_text: Trouvez des circuits de distribution pour vous approvisionner près de chez vous en bio/local/éthique.
shops_signup_title: S'inscrire en tant que hub
shops_signup_headline: Des hubs divers et variés
shops_signup_motivation: Quel que soit votre modèle, vous pouvez vous appuyer sur Open Food France. Si vous voulez le faire évoluer, nous sommes là pour vous aider. Nous agissons selon des principes de non-lucrativité, d'indépendance, et de transparence. Et nous faisons tout notre possible pour répondre à vos besoins et vous accompagner en toute circonstance.
shops_signup_action: Rejoindre le réseau
shops_signup_pricing: Comptes entreprises
shops_signup_stories: Histoires de hubs.
shops_signup_help: Nous sommes là pour vous aider.
shops_signup_help_text: Vous avez besoin de pouvoir travailler de manière efficace. Vous avez besoin de nouveaux acheteurs et de partenaires logistiques. Vous souhaitez que votre histoire soit racontée tout au long du circuit, que l'acheteur final sache qui se trouve derrière les produits.
shops_signup_detail: Comment ça marche.
shops_signup_headline: Des circuits courts offrant une large gamme de produits
shops_signup_motivation: 'Que vous soyez vous-même producteur, ou que vous gériez un groupement dachat, un drive ou autre circuit court, proposez à la vente des produits venant de différents producteurs via votre boutique multi-producteurs. Gagnez du temps sur la gestion de votre commercialisation grâce à CoopCircuits, votre partenaire coopératif et engagé ! '
shops_signup_action: S'inscrire
shops_signup_pricing: CoopCircuits vous simplifie la vie
shops_signup_stories: Histoires de circuits courts
shops_signup_help: Rejoindre le réseau
shops_signup_help_text: Créez votre profil distributeur, et dès que vous êtes prêt, changez de formule pour ouvrir votre boutique en ligne.
shops_signup_detail: Les avantages CoopCircuits
orders: Commandes
orders_fees: Frais...
orders_edit_title: Panier
@@ -2673,6 +2673,11 @@ fr:
signup_or_login: "Commencez par vous inscrire (ou connexion)"
have_an_account: "Déjà inscrit?"
action_login: "Se connecter."
stripe_elements:
unknown_error_from_stripe: |
Il a eu un problème lors de la prise en compte de votre carte.
Merci de rafraîchir la page. Si cela ne fonctionne pas une seconde fois,
merci de nous contacter.
inflections:
each:
one: "chacun"
@@ -2748,7 +2753,7 @@ fr:
other: "sachets"
producers:
signup:
start_free_profile: "Commencez par créer votre profil entreprise, et changez de formule quand vous êtes prêt !"
start_free_profile: "Créez votre profil producteur, et dès que vous êtes prêt, changez de formule pour ouvrir votre boutique en ligne."
order_management:
reports:
enterprise_fee_summaries:

View File

@@ -721,6 +721,10 @@ pt_BR:
enable_subscriptions_tip: "Ativar funcionalidade de inscrições?"
enable_subscriptions_false: "Desativado"
enable_subscriptions_true: "ativado"
customer_names_in_reports: "Nomes dos Clientes nos Relatórios"
customer_names_tip: "Permitir que seus fornecedores vejam os nomes dos clientes nos relatórios"
customer_names_false: "Desativado"
customer_names_true: "Ativado"
shopfront_message: "Mensagem da loja virtual"
shopfront_message_placeholder: >
Uma mensagem opcional para dar as boas-vindas aos clientes e explicar
@@ -2771,6 +2775,8 @@ pt_BR:
adjustments: "Ajustes"
payments: "Pagamentos"
return_authorizations: "Autorizações de Retorno"
credit_owed: "Crédito Devido"
new_adjustment: "Novo Ajuste"
payment: "Pagamento"
payment_method: "Método de Pagamento"
shipment: "Envio"
@@ -2972,6 +2978,7 @@ pt_BR:
other: "%{count}erros não permitiram que esse registro fosse salvo:"
there_were_problems_with_the_following_fields: "Houve problemas com os seguintes campos"
payments_list:
date_time: "Data/hora"
amount: "Montante"
payment_method: "Método de Pagamento"
payment_state: "Estado de pagamento"
@@ -3189,6 +3196,8 @@ pt_BR:
stripe:
error_saving_payment: Erro ao salvar o pagamento
submitting_payment: Enviando pagamento ...
paypal:
no_payment_via_admin_backend: Pagamentos por Paypal não podem ser completados na Área Administrativa
products:
image_upload_error: "A imagem do produto não foi reconhecida. Faça o upload de uma imagem no formato PNG ou JPG."
new:
@@ -3242,6 +3251,8 @@ pt_BR:
bulk_coop_allocation: 'Atacado Cooperativa - Alocação'
bulk_coop_packing_sheets: 'Atacado Cooperativa - Folhas de Empacotamento'
bulk_coop_customer_payments: 'Atacado Cooperativa - Pagamentos de Cliente'
customer_names_message:
customer_names_tip: "Se os nomes dos clientes estiverem ocultos na lista, você pode entrar em contato com o seu distribuidor e perguntar se ele pode atualizar as preferências de modo que os fornecedores possam ver os nomes dos clientes."
users:
index:
listing_users: "Listando Usuários"
@@ -3474,3 +3485,8 @@ pt_BR:
shipment:
cannot_ready: "Não é possível completar a entrega."
invalid_taxonomy_id: "Id invalido de taxonomia"
activerecord:
models:
spree/payment:
one: Pagamentos
other: Pagamentos

View File

@@ -11,6 +11,9 @@ env "MAILTO", app_config["SCHEDULE_NOTIFICATIONS"] if app_config["SCHEDULE_NOTIF
job_type :run_file, "cd :path; :environment_variable=:environment bundle exec script/rails runner :task :output"
job_type :enqueue_job, "cd :path; :environment_variable=:environment bundle exec script/enqueue :task :priority :output"
every 1.month do
rake 'ofn:data:remove_transient_data'
end
every 1.day, at: '2:45am' do
rake 'db2fog:clean' if app_config['S3_BACKUPS_BUCKET']

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'highline'
require 'tasks/data/remove_transient_data'
namespace :ofn do
namespace :data do
desc 'Remove transient data'
task remove_transient_data: :environment do
RemoveTransientData.new.call
end
end
end

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
class RemoveTransientData
RETENTION_PERIOD = 6.months.ago.to_date
# This model lets us operate on the sessions DB table using ActiveRecord's
# methods within the scope of this service. This relies on the AR's
# convention where a Session model maps to a sessions table.
class Session < ActiveRecord::Base
end
def call
Rails.logger.info("#{self.class.name}: processing")
Spree::StateChange.where("created_at < ?", RETENTION_PERIOD).delete_all
Spree::LogEntry.where("created_at < ?", RETENTION_PERIOD).delete_all
Session.where("updated_at < ?", RETENTION_PERIOD).delete_all
end
end

View File

@@ -1,12 +1,6 @@
# frozen_string_literal: true
class TruncateData
# This model lets us operate on the sessions DB table using ActiveRecord's
# methods within the scope of this service. This relies on the AR's
# convention where a Session model maps to a sessions table.
class Session < ActiveRecord::Base
end
def initialize(months_to_keep = nil)
@date = (months_to_keep || 24).to_i.months.ago
end
@@ -25,8 +19,6 @@ class TruncateData
sql_delete_from "order_cycles #{where_ocs_to_delete}"
Spree::TokenizedPermission.where("created_at < '#{date}'").delete_all
remove_transient_data
end
end
@@ -47,12 +39,6 @@ class TruncateData
sql_delete_from "spree_return_authorizations #{where_order_id_in_orders_to_delete}"
end
def remove_transient_data
Spree::StateChange.delete_all("created_at < '#{1.month.ago.to_date}'")
Spree::LogEntry.delete_all("created_at < '#{1.month.ago.to_date}'")
Session.delete_all("created_at < '#{2.weeks.ago.to_date}'")
end
def truncate_subscriptions
sql_delete_from "order_cycle_schedules #{where_oc_id_in_ocs_to_delete}"
sql_delete_from "proxy_orders #{where_oc_id_in_ocs_to_delete}"

View File

@@ -0,0 +1,9 @@
FactoryBot.define do
factory :return_authorization, class: Spree::ReturnAuthorization do
number '100'
amount 100.00
association(:order, factory: :shipped_order)
reason 'no particular reason'
state 'received'
end
end

View File

@@ -1,5 +1,9 @@
describe 'CreditCard service', ->
CreditCard = null
CreditCards = null
$http = null
Loading = null
RailsFlashLoader = null
beforeEach ->
module 'Darkswarm'
@@ -8,19 +12,43 @@ describe 'CreditCard service', ->
$provide.value "railsFlash", null
null
inject (_CreditCard_)->
inject (_CreditCard_, _CreditCards_, _$httpBackend_, _Loading_, _RailsFlashLoader_)->
CreditCard = _CreditCard_
CreditCards = _CreditCards_
$http = _$httpBackend_
Loading = _Loading_
RailsFlashLoader = _RailsFlashLoader_
CreditCard.secrets =
card:
exp_month: "12"
exp_year: "2030"
last4: "1234"
cc_type: 'mastercard'
token: "token123"
describe "submit", ->
it "adds a credit card", ->
$http.expectPUT("/credit_cards/new_from_token").respond(200, {})
spyOn(CreditCards, "add")
CreditCard.submit()
$http.flush()
expect(CreditCards.add).toHaveBeenCalled()
it "reports errors", ->
$http.expectPUT("/credit_cards/new_from_token").respond(500, {})
spyOn(Loading, "clear")
spyOn(RailsFlashLoader, "loadFlash")
CreditCard.submit()
$http.flush()
expect(Loading.clear).toHaveBeenCalled()
expect(RailsFlashLoader.loadFlash).toHaveBeenCalled()
describe "process_params", ->
beforeEach ->
CreditCard.secrets =
card:
exp_month: "12"
exp_year: "2030"
last4: "1234"
cc_type: 'mastercard'
token: "token123"
it "uses cc_type, rather than fetching the brand from the card", ->
# This is important for processing the card with activemerchant
process_params = CreditCard.process_params()

View File

@@ -0,0 +1,41 @@
describe 'Messages service', ->
Messages = null
Loading = null
RailsFlashLoader = null
beforeEach ->
module 'Darkswarm'
module ($provide)->
$provide.value "railsFlash", null
null
inject (_Messages_, _Loading_, _RailsFlashLoader_)->
Messages = _Messages_
Loading = _Loading_
RailsFlashLoader = _RailsFlashLoader_
it "shows a loading message", ->
Messages.loading("Hang on...")
expect(Loading.message).toEqual "Hang on..."
it "shows a success message", ->
spyOn(RailsFlashLoader, "loadFlash")
Messages.success("Yay!")
expect(RailsFlashLoader.loadFlash).toHaveBeenCalledWith({success: "Yay!"})
it "shows a error message", ->
spyOn(RailsFlashLoader, "loadFlash")
Messages.error("Boo!")
expect(RailsFlashLoader.loadFlash).toHaveBeenCalledWith({error: "Boo!"})
it "shows a flash message", ->
data = {info: "thinking"}
spyOn(RailsFlashLoader, "loadFlash")
Messages.flash(data)
expect(RailsFlashLoader.loadFlash).toHaveBeenCalledWith(data)
it "clears a loading message", ->
Messages.loading("Hang on...")
Messages.success("Done.")
expect(Loading.message).toEqual null

View File

@@ -46,10 +46,12 @@ describe 'StripeElements Service', ->
it "doesn't submit the form, shows an error message instead", inject (Loading, RailsFlashLoader) ->
spyOn(Loading, "clear")
spyOn(RailsFlashLoader, "loadFlash")
spyOn(Bugsnag, "notify")
StripeElements.requestToken(secrets, submit).then (data) ->
expect(submit).not.toHaveBeenCalled()
expect(Loading.clear).toHaveBeenCalled()
expect(RailsFlashLoader.loadFlash).toHaveBeenCalledWith({error: "Error: There was a problem"})
expect(Bugsnag.notify).toHaveBeenCalled()
describe 'mapTokenApiCardBrand', ->
it "maps the brand returned by Stripe's tokenAPI to that required by activemerchant", ->

View File

@@ -0,0 +1,39 @@
# frozen_string_literal: true
require 'spec_helper'
require 'tasks/data/remove_transient_data'
describe RemoveTransientData do
describe '#call' do
let(:retention_period) { RemoveTransientData::RETENTION_PERIOD }
before do
allow(Spree::StateChange).to receive(:delete_all)
allow(Spree::LogEntry).to receive(:delete_all)
allow(RemoveTransientData::Session).to receive(:delete_all)
allow(Rails.logger).to receive(:info)
end
it 'deletes state changes older than rentention_period' do
Spree::StateChange.create(created_at: retention_period - 1.day)
RemoveTransientData.new.call
expect(Spree::StateChange.all).to be_empty
end
it 'deletes log entries older than retention_period' do
Spree::LogEntry.create(created_at: retention_period - 1.day)
expect { RemoveTransientData.new.call }
.to change(Spree::LogEntry, :count).by(-1)
end
it 'deletes sessions older than retention_period' do
RemoveTransientData::Session.create(session_id: 1, updated_at: retention_period - 1.day)
RemoveTransientData.new.call
expect(RemoveTransientData::Session.all).to be_empty
end
end
end

View File

@@ -7,9 +7,6 @@ describe TruncateData do
describe '#call' do
before do
allow(Spree::ReturnAuthorization).to receive(:delete_all)
allow(Spree::StateChange).to receive(:delete_all)
allow(Spree::LogEntry).to receive(:delete_all)
allow(TruncateData::Session).to receive(:delete_all)
allow(Rails.logger).to receive(:info)
end
@@ -24,30 +21,6 @@ describe TruncateData do
expect(OrderCycle.all).to be_empty
end
it 'deletes state changes older than a month' do
TruncateData.new.call
expect(Spree::StateChange)
.to have_received(:delete_all)
.with("created_at < '#{1.month.ago.to_date}'")
end
it 'deletes log entries older than a month' do
TruncateData.new.call
expect(Spree::LogEntry)
.to have_received(:delete_all)
.with("created_at < '#{1.month.ago.to_date}'")
end
it 'deletes sessions older than two weeks' do
TruncateData.new.call
expect(TruncateData::Session)
.to have_received(:delete_all)
.with("created_at < '#{2.weeks.ago.to_date}'")
end
end
context 'when months_to_keep is nil' do
@@ -61,30 +34,6 @@ describe TruncateData do
expect(OrderCycle.all).to be_empty
end
it 'deletes state changes older than a month' do
TruncateData.new.call
expect(Spree::StateChange)
.to have_received(:delete_all)
.with("created_at < '#{1.month.ago.to_date}'")
end
it 'deletes log entries older than a month' do
TruncateData.new.call
expect(Spree::LogEntry)
.to have_received(:delete_all)
.with("created_at < '#{1.month.ago.to_date}'")
end
it 'deletes sessions older than two weeks' do
TruncateData.new.call
expect(TruncateData::Session)
.to have_received(:delete_all)
.with("created_at < '#{2.weeks.ago.to_date}'")
end
end
context 'when months_to_keep is specified' do
@@ -102,30 +51,6 @@ describe TruncateData do
expect(OrderCycle.all).to contain_exactly(recent_order_cycle)
end
it 'deletes state changes older than a month' do
TruncateData.new.call
expect(Spree::StateChange)
.to have_received(:delete_all)
.with("created_at < '#{1.month.ago.to_date}'")
end
it 'deletes log entries older than a month' do
TruncateData.new.call
expect(Spree::LogEntry)
.to have_received(:delete_all)
.with("created_at < '#{1.month.ago.to_date}'")
end
it 'deletes sessions older than two weeks' do
TruncateData.new.call
expect(TruncateData::Session)
.to have_received(:delete_all)
.with("created_at < '#{2.weeks.ago.to_date}'")
end
end
end
end

View File

@@ -2,6 +2,212 @@ require 'spec_helper'
module Spree
describe Adjustment do
let(:order) { build(:order) }
let(:adjustment) { Spree::Adjustment.create(label: "Adjustment", amount: 5) }
describe "scopes" do
let!(:arbitrary_adjustment) { create(:adjustment, source: nil, label: "Arbitrary") }
let!(:return_authorization_adjustment) { create(:adjustment, source: create(:return_authorization)) }
it "returns return_authorization adjustments" do
expect(Spree::Adjustment.return_authorization.to_a).to eq [return_authorization_adjustment]
end
end
context "#update!" do
context "when originator present" do
let(:originator) { double("originator", update_adjustment: nil) }
before do
allow(originator).to receive_messages update_amount: true
allow(adjustment).to receive_messages originator: originator, label: 'adjustment', amount: 0
end
it "should do nothing when closed" do
adjustment.close
expect(originator).not_to receive(:update_adjustment)
adjustment.update!
end
it "should do nothing when finalized" do
adjustment.finalize
expect(originator).not_to receive(:update_adjustment)
adjustment.update!
end
it "should set the eligibility" do
expect(adjustment).to receive(:set_eligibility)
adjustment.update!
end
it "should ask the originator to update_adjustment" do
expect(originator).to receive(:update_adjustment)
adjustment.update!
end
end
it "should do nothing when originator is nil" do
allow(adjustment).to receive_messages originator: nil
expect(adjustment).not_to receive(:amount=)
adjustment.update!
end
end
context "#eligible? after #set_eligibility" do
context "when amount is 0" do
before { adjustment.amount = 0 }
it "should be eligible if mandatory?" do
adjustment.mandatory = true
adjustment.set_eligibility
expect(adjustment).to be_eligible
end
it "should not be eligible unless mandatory?" do
adjustment.mandatory = false
adjustment.set_eligibility
expect(adjustment).to_not be_eligible
end
end
context "when amount is greater than 0" do
before { adjustment.amount = 25.00 }
it "should be eligible if mandatory?" do
adjustment.mandatory = true
adjustment.set_eligibility
expect(adjustment).to be_eligible
end
it "should be eligible if not mandatory and eligible for the originator" do
adjustment.mandatory = false
allow(adjustment).to receive_messages(eligible_for_originator?: true)
adjustment.set_eligibility
expect(adjustment).to be_eligible
end
it "should not be eligible if not mandatory not eligible for the originator" do
adjustment.mandatory = false
allow(adjustment).to receive_messages(eligible_for_originator?: false)
adjustment.set_eligibility
expect(adjustment).to_not be_eligible
end
end
end
context "#save" do
it "should call order#update!" do
adjustment = Spree::Adjustment.new(
adjustable: order,
amount: 10,
label: "Foo"
)
expect(order).to receive(:update!)
adjustment.save
end
end
context "adjustment state" do
let(:adjustment) { create(:adjustment, state: 'open') }
context "#immutable?" do
it "is true when adjustment state isn't open" do
adjustment.state = "closed"
expect(adjustment).to be_immutable
adjustment.state = "finalized"
expect(adjustment).to be_immutable
end
it "is false when adjustment state is open" do
adjustment.state = "open"
expect(adjustment).to_not be_immutable
end
end
context "#finalized?" do
it "is true when adjustment state is finalized" do
adjustment.state = "finalized"
expect(adjustment).to be_finalized
end
it "is false when adjustment state isn't finalized" do
adjustment.state = "closed"
expect(adjustment).to_not be_finalized
adjustment.state = "open"
expect(adjustment).to_not be_finalized
end
end
end
context "#eligible_for_originator?" do
context "with no originator" do
specify { expect(adjustment).to be_eligible_for_originator }
end
context "with originator that doesn't have 'eligible?'" do
before { adjustment.originator = build(:tax_rate) }
specify { expect(adjustment).to be_eligible_for_originator }
end
context "with originator that has 'eligible?'" do
let(:originator) { Spree::TaxRate.new }
before { adjustment.originator = originator }
context "and originator is eligible for order" do
before { allow(originator).to receive_messages(eligible?: true) }
specify { expect(adjustment).to be_eligible_for_originator }
end
context "and originator is not eligible for order" do
before { allow(originator).to receive_messages(eligible?: false) }
specify { expect(adjustment).to_not be_eligible_for_originator }
end
end
end
context "#display_amount" do
before { adjustment.amount = 10.55 }
context "with display_currency set to true" do
before { Spree::Config[:display_currency] = true }
it "shows the currency" do
expect(adjustment.display_amount.to_s).to eq "$10.55 #{Spree::Config[:currency]}"
end
end
context "with display_currency set to false" do
before { Spree::Config[:display_currency] = false }
it "does not include the currency" do
expect(adjustment.display_amount.to_s).to eq "$10.55"
end
end
context "with currency set to JPY" do
context "when adjustable is set to an order" do
before do
allow(order).to receive(:currency) { 'JPY' }
adjustment.adjustable = order
end
it "displays in JPY" do
expect(adjustment.display_amount.to_s).to eq "¥11"
end
end
context "when adjustable is nil" do
it "displays in the default currency" do
expect(adjustment.display_amount.to_s).to eq "$10.55"
end
end
end
end
context '#currency' do
it 'returns the globally configured currency' do
expect(adjustment.currency).to eq Spree::Config[:currency]
end
end
it "has metadata" do
adjustment = create(:adjustment, metadata: create(:adjustment_metadata))
expect(adjustment.metadata).to be
@@ -39,7 +245,7 @@ module Spree
let!(:zone) { create(:zone_with_member) }
let!(:order) { create(:order, bill_address: create(:address)) }
let!(:line_item) { create(:line_item, order: order) }
let(:tax_rate) { create(:tax_rate, included_in_price: true, calculator: Calculator::FlatRate.new(preferred_amount: 0.1)) }
let(:tax_rate) { create(:tax_rate, included_in_price: true, calculator: ::Calculator::FlatRate.new(preferred_amount: 0.1)) }
let(:adjustment) { line_item.adjustments(:reload).first }
before do
@@ -205,8 +411,10 @@ module Spree
end
context "when enterprise fees inherit their tax_category from the product they are applied to" do
let(:product_tax_rate) { create(:tax_rate, included_in_price: true, calculator: ::Calculator::DefaultTax.new, zone: zone, amount: 0.2) }
let(:product_tax_category) { create(:tax_category, tax_rates: [product_tax_rate]) }
let(:product_tax_rate) {
create(:tax_rate, included_in_price: true, calculator: ::Calculator::DefaultTax.new, zone: zone, amount: 0.2)
}
let(:product_tax_category) { create(:tax_category, tax_rates: [product_tax_rate]) }
before do
variant.product.update_attribute(:tax_category_id, product_tax_category.id)

View File

@@ -0,0 +1,30 @@
# frozen_string_literal: true
require 'spec_helper'
describe Spree::TaxCategory do
context 'default tax category' do
let(:tax_category) { create(:tax_category) }
let(:new_tax_category) { create(:tax_category) }
before do
tax_category.update_column(:is_default, true)
end
it "should undefault the previous default tax category" do
new_tax_category.update({ is_default: true })
expect(new_tax_category.is_default).to be_truthy
tax_category.reload
expect(tax_category.is_default).to be_falsy
end
it "undefaults the previous default tax category
except when updating the existing default tax category" do
tax_category.update_column(:description, "Updated description")
tax_category.reload
expect(tax_category.is_default).to be_truthy
end
end
end