mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-12 18:36:49 +00:00
Compare commits
221 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54a51a4995 | ||
|
|
37d113ed78 | ||
|
|
8f6e527f8a | ||
|
|
0d259b217e | ||
|
|
2e5b5eaac5 | ||
|
|
faaf391892 | ||
|
|
feed9376dd | ||
|
|
b829fea0c2 | ||
|
|
a2610279d9 | ||
|
|
25a8c44c22 | ||
|
|
7ebdc1d0da | ||
|
|
5c25d92354 | ||
|
|
0aa5ee081e | ||
|
|
82cf2afec9 | ||
|
|
8ea7614353 | ||
|
|
714bfafede | ||
|
|
8f98fb830a | ||
|
|
636da229ad | ||
|
|
560577827f | ||
|
|
9c1a7c13dc | ||
|
|
9cb7275250 | ||
|
|
3bf98e295d | ||
|
|
678e0be0a5 | ||
|
|
0ef4dec15e | ||
|
|
880ef9cf4f | ||
|
|
095633f21e | ||
|
|
3a894a1cdb | ||
|
|
ee862891c1 | ||
|
|
9dccb641c7 | ||
|
|
d1a87f7ba0 | ||
|
|
77eaebc2a7 | ||
|
|
3ececb04c5 | ||
|
|
0aa515101b | ||
|
|
c6139a975a | ||
|
|
212820b3da | ||
|
|
f1358dfa9a | ||
|
|
f061545a92 | ||
|
|
e99fdeb972 | ||
|
|
875eb292be | ||
|
|
08604ae8fd | ||
|
|
87d6a73e54 | ||
|
|
f566c2127d | ||
|
|
2573e3b7c5 | ||
|
|
7fe876266e | ||
|
|
8d5ed630d6 | ||
|
|
66d206ecb3 | ||
|
|
fd0a7971e9 | ||
|
|
ed3cb56c11 | ||
|
|
a367c3720c | ||
|
|
6eb43053e9 | ||
|
|
7006b0af4c | ||
|
|
d86b879972 | ||
|
|
fd339488e6 | ||
|
|
b6f5eab6e1 | ||
|
|
ced29c1f3d | ||
|
|
27ffe9edb2 | ||
|
|
0d7b5cd32c | ||
|
|
276fea6942 | ||
|
|
c45dcad975 | ||
|
|
f32d8e2678 | ||
|
|
a9a05debba | ||
|
|
9481876595 | ||
|
|
cdf4e88e21 | ||
|
|
7ddc53bb5b | ||
|
|
b9f6dc6de5 | ||
|
|
811985cf0f | ||
|
|
175b78b51f | ||
|
|
e82aa0c89a | ||
|
|
8be05e94bd | ||
|
|
7317347fd6 | ||
|
|
c5c542069f | ||
|
|
dc9e3aa1a0 | ||
|
|
a48b57f7a7 | ||
|
|
6f59158153 | ||
|
|
f501d48caa | ||
|
|
2429b186ce | ||
|
|
7df2759475 | ||
|
|
681cb34c48 | ||
|
|
94b903179e | ||
|
|
59070712d9 | ||
|
|
76aebf329e | ||
|
|
b2b5606f2e | ||
|
|
f890c4a31d | ||
|
|
b087f8da19 | ||
|
|
e3c1159c17 | ||
|
|
14054f0e70 | ||
|
|
d525ddfe14 | ||
|
|
df0b997258 | ||
|
|
ffbb0d26a4 | ||
|
|
5eb64f431a | ||
|
|
3da14233bf | ||
|
|
940c067b60 | ||
|
|
2297e20c78 | ||
|
|
d1331ac78a | ||
|
|
6e8fe080cb | ||
|
|
5521b4bb04 | ||
|
|
4183dda27e | ||
|
|
fcbb883244 | ||
|
|
c35b330d25 | ||
|
|
57e74a4980 | ||
|
|
a1b64fe27b | ||
|
|
49060892e8 | ||
|
|
9175504bc1 | ||
|
|
8867ec977c | ||
|
|
4931edc67c | ||
|
|
51ed9a6b78 | ||
|
|
e96428e7e2 | ||
|
|
b629a4f912 | ||
|
|
967380c542 | ||
|
|
ff0aa377a1 | ||
|
|
da683e3ecf | ||
|
|
aa46a4b5da | ||
|
|
61dad61ef7 | ||
|
|
71876ca23a | ||
|
|
07e5f8ed8d | ||
|
|
11684dae65 | ||
|
|
e44efd3db2 | ||
|
|
cb61c83688 | ||
|
|
e413920335 | ||
|
|
83ae13d7c7 | ||
|
|
9204687e4d | ||
|
|
c6741dda36 | ||
|
|
55f9fef2c3 | ||
|
|
4bc3101f4d | ||
|
|
404d7bbc43 | ||
|
|
55e448897f | ||
|
|
2fe9f4abc8 | ||
|
|
d7a8873ee9 | ||
|
|
a2993652c1 | ||
|
|
08e6e5a459 | ||
|
|
0018ef6eb4 | ||
|
|
9b9b6ded09 | ||
|
|
e5e7e12a32 | ||
|
|
2f216039ac | ||
|
|
e99799bca2 | ||
|
|
f5e300a5de | ||
|
|
ae0b76e610 | ||
|
|
cb09c935dc | ||
|
|
f28241cc5e | ||
|
|
ebf4175662 | ||
|
|
737fc699ed | ||
|
|
caf61e3a7e | ||
|
|
dfa00a770a | ||
|
|
cd940bd140 | ||
|
|
ffac38d934 | ||
|
|
5716ea8611 | ||
|
|
88d90a37e8 | ||
|
|
ed114f4c4c | ||
|
|
ffa0d202be | ||
|
|
41d797489d | ||
|
|
46623242f7 | ||
|
|
1a39a55009 | ||
|
|
56fb09c006 | ||
|
|
e4dee8a2fb | ||
|
|
04f9c5ec5e | ||
|
|
8c322c1a0f | ||
|
|
865a4b3063 | ||
|
|
b413f856a5 | ||
|
|
2f93a06dd5 | ||
|
|
c151195e3a | ||
|
|
7ec00cf40a | ||
|
|
208be3ede6 | ||
|
|
de061b4c54 | ||
|
|
c7a5dd65cf | ||
|
|
d9a228e5ec | ||
|
|
8a75fe777c | ||
|
|
66587ccc00 | ||
|
|
24cdd0c467 | ||
|
|
a3e9226878 | ||
|
|
0974c4b2ac | ||
|
|
5a10a2861e | ||
|
|
aedc12e0e3 | ||
|
|
fc4cc65e07 | ||
|
|
07cee32f04 | ||
|
|
42d5344179 | ||
|
|
12d18b2825 | ||
|
|
ad111e837e | ||
|
|
746533d3f6 | ||
|
|
4ef4a58532 | ||
|
|
685a5465f1 | ||
|
|
70e9ef93bb | ||
|
|
86ad31eb5c | ||
|
|
edfd0fd95c | ||
|
|
d1f5828d13 | ||
|
|
785f8ada4d | ||
|
|
b9511d4f07 | ||
|
|
16a475d8af | ||
|
|
1a734aacf8 | ||
|
|
cfdfd82d9a | ||
|
|
b872bf49c5 | ||
|
|
5d48da72c7 | ||
|
|
9d07295480 | ||
|
|
f435039061 | ||
|
|
6564ea7b00 | ||
|
|
f71013c514 | ||
|
|
44487af2c8 | ||
|
|
c3279941f5 | ||
|
|
7356d0fe77 | ||
|
|
bba683469b | ||
|
|
c6e1f458cc | ||
|
|
9bc928fd48 | ||
|
|
a6444e76a5 | ||
|
|
9b26ff2fa4 | ||
|
|
684ae2ca22 | ||
|
|
459708dbc8 | ||
|
|
f75aaf0b45 | ||
|
|
1a186affcf | ||
|
|
6e5c168d3b | ||
|
|
39564e612f | ||
|
|
97ae4def98 | ||
|
|
91501f05f2 | ||
|
|
93601ca556 | ||
|
|
2d3578bb30 | ||
|
|
02f50774bb | ||
|
|
ff8735d7a4 | ||
|
|
51a499d5c9 | ||
|
|
086c521a27 | ||
|
|
7cefdda579 | ||
|
|
ba859111de | ||
|
|
fd9479f720 | ||
|
|
0c7a0e3e96 |
3
.github/ISSUE_TEMPLATE/release.md
vendored
3
.github/ISSUE_TEMPLATE/release.md
vendored
@@ -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
|
||||
|
||||
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -38,6 +38,5 @@ Add the link or remove this section. -->
|
||||
|
||||
|
||||
#### Documentation updates
|
||||
<!-- Are their any wiki pages that need updating after merging this PR?
|
||||
<!-- Are there any wiki pages that need updating after merging this PR?
|
||||
List them here or remove this section. -->
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -19,7 +19,7 @@ RUN git clone --depth 1 --branch v1.1.2 https://github.com/rbenv/rbenv.git ${RBE
|
||||
echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh && \
|
||||
rbenv install $(cat .ruby-version) && \
|
||||
rbenv global $(cat .ruby-version) && \
|
||||
gem install bundler --version=1.17.2
|
||||
gem install bundler --version=1.17.3
|
||||
|
||||
# Install Postgres
|
||||
RUN sh -c "echo 'deb https://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main' > /etc/apt/sources.list.d/pgdg.list" && \
|
||||
|
||||
10
Gemfile.lock
10
Gemfile.lock
@@ -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)
|
||||
@@ -509,7 +509,7 @@ GEM
|
||||
pry-byebug (3.7.0)
|
||||
byebug (~> 11.0)
|
||||
pry (~> 0.10)
|
||||
public_suffix (4.0.5)
|
||||
public_suffix (4.0.6)
|
||||
rack (1.5.5)
|
||||
rack-mini-profiler (2.0.2)
|
||||
rack (>= 1.2.0)
|
||||
@@ -658,7 +658,7 @@ GEM
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.5.1)
|
||||
stripe (5.22.0)
|
||||
stripe (5.25.0)
|
||||
temple (0.8.2)
|
||||
test-unit (3.3.6)
|
||||
power_assert
|
||||
@@ -671,7 +671,7 @@ GEM
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.7.0)
|
||||
unicorn (5.6.0)
|
||||
unicorn (5.7.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
unicorn-rails (2.2.1)
|
||||
@@ -687,7 +687,7 @@ GEM
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (>= 1.3.0)
|
||||
selenium-webdriver (>= 3.0, < 4.0)
|
||||
webmock (3.8.3)
|
||||
webmock (3.9.1)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser) ->
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, $location, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser, ProductFiltersUrl) ->
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.columns = Columns.columns
|
||||
@@ -13,37 +13,29 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
{id: 100, name: t('js.admin.orders.index.per_page', results: 100)}
|
||||
]
|
||||
|
||||
$scope.filterableColumns = [
|
||||
{ name: t("label_producers"), db_column: "producer_name" },
|
||||
{ name: t("name"), db_column: "name" }
|
||||
]
|
||||
|
||||
$scope.filterTypes = [
|
||||
{ name: t("equals"), predicate: "eq" },
|
||||
{ name: t("contains"), predicate: "cont" }
|
||||
]
|
||||
|
||||
$scope.optionTabs =
|
||||
filters: { title: t("filter_products"), visible: false }
|
||||
$scope.q = {
|
||||
producerFilter: ""
|
||||
categoryFilter: ""
|
||||
importDateFilter: ""
|
||||
query: ""
|
||||
sorting: ""
|
||||
}
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.all
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.producerFilter = ""
|
||||
$scope.categoryFilter = ""
|
||||
$scope.importDateFilter = ""
|
||||
$scope.page = 1
|
||||
$scope.per_page = 15
|
||||
$scope.products = BulkProducts.products
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
$scope.sortOptions = SortOptions
|
||||
|
||||
$scope.initialise = ->
|
||||
$scope.q = ProductFiltersUrl.loadFromUrl($location.search())
|
||||
$scope.fetchProducts()
|
||||
|
||||
$scope.$watchCollection '[query, producerFilter, categoryFilter, importDateFilter, per_page]', ->
|
||||
$scope.$watchCollection '[q.query, q.producerFilter, q.categoryFilter, q.importDateFilter, per_page]', ->
|
||||
$scope.page = 1 # Reset page when changing filters for new search
|
||||
|
||||
$scope.changePage = (newPage) ->
|
||||
@@ -53,25 +45,27 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.fetchProducts = ->
|
||||
removeClearedValues()
|
||||
params = {
|
||||
'q[name_cont]': $scope.query,
|
||||
'q[supplier_id_eq]': $scope.producerFilter,
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter,
|
||||
'q[s]': $scope.sorting,
|
||||
import_date: $scope.importDateFilter,
|
||||
'q[name_cont]': $scope.q.query,
|
||||
'q[supplier_id_eq]': $scope.q.producerFilter,
|
||||
'q[primary_taxon_id_eq]': $scope.q.categoryFilter,
|
||||
'q[s]': $scope.q.sorting,
|
||||
import_date: $scope.q.importDateFilter,
|
||||
page: $scope.page,
|
||||
per_page: $scope.per_page
|
||||
}
|
||||
RequestMonitor.load(BulkProducts.fetch(params).$promise).then ->
|
||||
# update url with the filters used
|
||||
$location.search(ProductFiltersUrl.generate($scope.q))
|
||||
$scope.resetProducts()
|
||||
|
||||
removeClearedValues = ->
|
||||
delete $scope.producerFilter if $scope.producerFilter == "0"
|
||||
delete $scope.categoryFilter if $scope.categoryFilter == "0"
|
||||
delete $scope.importDateFilter if $scope.importDateFilter == "0"
|
||||
delete $scope.q.producerFilter if $scope.q.producerFilter == "0"
|
||||
delete $scope.q.categoryFilter if $scope.q.categoryFilter == "0"
|
||||
delete $scope.q.importDateFilter if $scope.q.importDateFilter == "0"
|
||||
|
||||
$timeout ->
|
||||
if $scope.showLatestImport
|
||||
$scope.importDateFilter = $scope.importDates[1].id
|
||||
$scope.q.importDateFilter = $scope.importDates[1].id
|
||||
|
||||
$scope.resetProducts = ->
|
||||
DirtyProducts.clear()
|
||||
@@ -101,10 +95,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.visibleTab = tab
|
||||
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.query = ""
|
||||
$scope.producerFilter = "0"
|
||||
$scope.categoryFilter = "0"
|
||||
$scope.importDateFilter = "0"
|
||||
$scope.q.query = ""
|
||||
$scope.q.producerFilter = "0"
|
||||
$scope.q.categoryFilter = "0"
|
||||
$scope.q.importDateFilter = "0"
|
||||
$scope.fetchProducts()
|
||||
|
||||
$scope.$watch 'sortOptions', (sort) ->
|
||||
@@ -122,8 +116,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
$scope.editWarn = (product, variant) ->
|
||||
if confirm_unsaved_changes()
|
||||
window.open(editProductUrl(product, variant), "_blank")
|
||||
|
||||
$window.location.href = ProductFiltersUrl.buildUrl(editProductUrl(product, variant), $scope.q)
|
||||
|
||||
$scope.toggleShowAllVariants = ->
|
||||
showVariants = !DisplayProperties.showVariants 0
|
||||
@@ -220,10 +213,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
data:
|
||||
products: productsToSubmit
|
||||
filters:
|
||||
'q[name_cont]': $scope.query
|
||||
'q[supplier_id_eq]': $scope.producerFilter
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter
|
||||
import_date: $scope.importDateFilter
|
||||
'q[name_cont]': $scope.q.query
|
||||
'q[supplier_id_eq]': $scope.q.producerFilter
|
||||
'q[primary_taxon_id_eq]': $scope.q.categoryFilter
|
||||
import_date: $scope.q.importDateFilter
|
||||
page: $scope.page
|
||||
per_page: $scope.per_page
|
||||
).success((data) ->
|
||||
|
||||
@@ -5,5 +5,10 @@ angular.module("ofn.admin").directive "ofnSelect2MinSearch", ->
|
||||
minimumResultsForSearch: attrs.ofnSelect2MinSearch
|
||||
|
||||
ngModel.$formatters.push (value) ->
|
||||
if (value)
|
||||
element.select2('val', value);
|
||||
# select2 populates options with a value like "number:3" or "string:category" but
|
||||
# select2('val', value) doesn't do the type conversion for us as one would expect
|
||||
if isNaN(value)
|
||||
element.select2('val', "string:#{value}")
|
||||
else
|
||||
element.select2('val', "number:#{value}")
|
||||
|
||||
|
||||
@@ -69,25 +69,24 @@ angular.module("admin.enterprises")
|
||||
$scope.newUser = $scope.invite_errors = $scope.invite_success = null
|
||||
|
||||
$scope.removeLogo = ->
|
||||
return unless confirm(t("admin.enterprises.remove_logo.immediate_removal_warning"))
|
||||
|
||||
Enterprises.removeLogo($scope.Enterprise).then (data) ->
|
||||
$scope.Enterprise = angular.copy(data)
|
||||
$scope.$emit("enterprise:updated", $scope.Enterprise)
|
||||
|
||||
StatusMessage.display("success", t("admin.enterprises.remove_logo.removed_successfully"))
|
||||
, (response) ->
|
||||
if response.data.error?
|
||||
StatusMessage.display("failure", response.data.error)
|
||||
$scope.performEnterpriseAction("removeLogo", "immediate_logo_removal_warning", "removed_logo_successfully")
|
||||
|
||||
$scope.removePromoImage = ->
|
||||
return unless confirm(t("admin.enterprises.remove_promo_image.immediate_removal_warning"))
|
||||
$scope.performEnterpriseAction("removePromoImage", "immediate_promo_image_removal_warning", "removed_promo_image_successfully")
|
||||
|
||||
Enterprises.removePromoImage($scope.Enterprise).then (data) ->
|
||||
$scope.removeTermsAndConditions = ->
|
||||
$scope.performEnterpriseAction("removeTermsAndConditions", "immediate_terms_and_conditions_removal_warning", "removed_terms_and_conditions_successfully")
|
||||
|
||||
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
|
||||
return unless confirm($scope.translation(warning_message_key))
|
||||
|
||||
Enterprises[enterpriseActionName]($scope.Enterprise).then (data) ->
|
||||
$scope.Enterprise = angular.copy(data)
|
||||
$scope.$emit("enterprise:updated", $scope.Enterprise)
|
||||
|
||||
StatusMessage.display("success", t("admin.enterprises.remove_promo_image.removed_successfully"))
|
||||
StatusMessage.display("success", $scope.translation(success_message_key))
|
||||
, (response) ->
|
||||
if response.data.error?
|
||||
StatusMessage.display("failure", response.data.error)
|
||||
|
||||
$scope.translation = (key) ->
|
||||
t('js.admin.enterprises.form.images.' + key)
|
||||
|
||||
@@ -9,22 +9,19 @@ angular.module('admin.orderCycles', ['ngTagsInput', 'admin.indexUtils', 'admin.e
|
||||
$timeout ->
|
||||
# using $parse instead of scope[attrs.datetimepicker] for cases
|
||||
# where attrs.datetimepicker is 'foo.bar.lol'
|
||||
$(element).datetimepicker
|
||||
dateFormat: 'yy-mm-dd'
|
||||
timeFormat: 'HH:mm'
|
||||
showOn: 'button'
|
||||
controlType: 'select'
|
||||
oneLine: true
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>"
|
||||
buttonImageOnly: true
|
||||
stepMinute: 15
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply(->
|
||||
element.val(dateText)
|
||||
parsed = $parse(attrs.datetimepicker)
|
||||
parsed.assign(scope, dateText)
|
||||
)
|
||||
|
||||
$(element).datetimepicker(
|
||||
Object.assign(
|
||||
window.JQUERY_UI_DATETIME_PICKER_DEFAULTS,
|
||||
{
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply(->
|
||||
element.val(dateText)
|
||||
parsed = $parse(attrs.datetimepicker)
|
||||
parsed.assign(scope, dateText)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
.directive 'ofnOnChange', ->
|
||||
(scope, element, attrs) ->
|
||||
|
||||
@@ -53,17 +53,18 @@ angular.module("admin.products").factory "OptionValueNamer", (VariantUnitManager
|
||||
[value, unit_name]
|
||||
|
||||
scale_for_unit_value: ->
|
||||
# Find the largest available unit where unit_value comes to >= 1 when expressed in it.
|
||||
# If there is none available where this is true, use the smallest available unit.
|
||||
unit = ([scale, unit_name] for scale, unit_name of VariantUnitManager.unitNames[@variant.product.variant_unit] when @variant.unit_value / scale >= 1).reduce (unit, [scale, unit_name]) ->
|
||||
if (unit && scale > unit[0]) || !unit?
|
||||
[scale, unit_name]
|
||||
else
|
||||
unit
|
||||
, null
|
||||
if !unit?
|
||||
unit = ([scale, unit_name] for scale, unit_name of VariantUnitManager.unitNames[@variant.product.variant_unit]).reduce (unit, [scale, unit_name]) ->
|
||||
if scale < unit[0] then [scale, unit_name] else unit
|
||||
, [Infinity,""]
|
||||
# Find the largest available and compatible unit where unit_value comes
|
||||
# to >= 1 when expressed in it.
|
||||
# If there is none available where this is true, use the smallest
|
||||
# available unit.
|
||||
product = @variant.product
|
||||
scales = VariantUnitManager.compatibleUnitScales(product.variant_unit_scale, product.variant_unit)
|
||||
variantUnitValue = @variant.unit_value
|
||||
|
||||
unit
|
||||
# sets largestScale = last element in filtered scales array
|
||||
[_, ..., largestScale] = (scales.filter (s) -> variantUnitValue / s >= 1)
|
||||
|
||||
if (largestScale)
|
||||
[largestScale, VariantUnitManager.getUnitName(largestScale, product.variant_unit)]
|
||||
else
|
||||
[scales[0], VariantUnitManager.getUnitName(scales[0], product.variant_unit)]
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
angular.module("admin.products").factory "VariantUnitManager", ->
|
||||
class VariantUnitManager
|
||||
@unitNames:
|
||||
@units:
|
||||
'weight':
|
||||
1.0: 'g'
|
||||
1000.0: 'kg'
|
||||
1000000.0: 'T'
|
||||
1.0:
|
||||
name: 'g'
|
||||
system: 'metric'
|
||||
1000.0:
|
||||
name: 'kg'
|
||||
system: 'metric'
|
||||
1000000.0:
|
||||
name: 'T'
|
||||
system: 'metric'
|
||||
453.6:
|
||||
name: 'lb'
|
||||
system: 'imperial'
|
||||
28.35:
|
||||
name: 'oz'
|
||||
system: 'imperial'
|
||||
'volume':
|
||||
0.001: 'mL'
|
||||
1.0: 'L'
|
||||
1000.0: 'kL'
|
||||
0.001:
|
||||
name: 'mL'
|
||||
system: 'metric'
|
||||
1.0:
|
||||
name: 'L'
|
||||
system: 'metric'
|
||||
1000.0:
|
||||
name: 'kL'
|
||||
system: 'metric'
|
||||
|
||||
@variantUnitOptions: ->
|
||||
options = for unit_type, scale_with_name of @unitNames
|
||||
options = for unit_type, _ of @units
|
||||
for scale in @unitScales(unit_type)
|
||||
name = @getUnitName(scale, unit_type)
|
||||
["#{I18n.t(unit_type)} (#{name})", "#{unit_type}_#{scale}"]
|
||||
@@ -30,7 +48,16 @@ angular.module("admin.products").factory "VariantUnitManager", ->
|
||||
unitScales[0]
|
||||
|
||||
@getUnitName: (scale, unitType) ->
|
||||
@unitNames[unitType][scale]
|
||||
if @units[unitType][scale]
|
||||
@units[unitType][scale]['name']
|
||||
else
|
||||
''
|
||||
|
||||
@unitScales: (unitType) ->
|
||||
(parseFloat(scale) for scale in Object.keys(@unitNames[unitType])).sort()
|
||||
(parseFloat(scale) for scale in Object.keys(@units[unitType])).sort (a, b) ->
|
||||
a - b
|
||||
|
||||
@compatibleUnitScales: (scale, unitType) ->
|
||||
scaleSystem = @units[unitType][scale]['system']
|
||||
(parseFloat(scale) for scale, scaleInfo of @units[unitType] when scaleInfo['system'] == scaleSystem).sort (a, b) ->
|
||||
a - b
|
||||
|
||||
@@ -14,4 +14,7 @@ angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
|
||||
'removePromoImage':
|
||||
url: '/api/enterprises/:id/promo_image.json'
|
||||
method: 'DELETE'
|
||||
'removeTermsAndConditions':
|
||||
url: '/api/enterprises/:id/terms_and_conditions.json'
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
@@ -52,3 +52,4 @@ angular.module("admin.resources").factory 'Enterprises', ($q, EnterpriseResource
|
||||
|
||||
removeLogo: performActionOnEnterpriseResource(EnterpriseResource.removeLogo)
|
||||
removePromoImage: performActionOnEnterpriseResource(EnterpriseResource.removePromoImage)
|
||||
removeTermsAndConditions: performActionOnEnterpriseResource(EnterpriseResource.removeTermsAndConditions)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
angular.module("ofn.admin").factory "ProductFiltersUrl", ($httpParamSerializer) ->
|
||||
new class ProductFiltersUrl
|
||||
productFilters: ['producerFilter', 'categoryFilter', 'query', 'sorting', 'importDateFilter']
|
||||
|
||||
loadFromUrl: (filters) ->
|
||||
loadedFilters = {}
|
||||
for filter in @productFilters
|
||||
loadedFilters[filter] = if filters[filter] then filters[filter] else ""
|
||||
|
||||
loadedFilters
|
||||
|
||||
generate: (ctrlFilters) ->
|
||||
filters = {}
|
||||
for filter in @productFilters
|
||||
filters[filter] = ctrlFilters[filter] if ctrlFilters[filter]
|
||||
|
||||
filters
|
||||
|
||||
buildUrl: (baseUrl, ctrlFilters) ->
|
||||
filterUrl = $httpParamSerializer(@generate(ctrlFilters))
|
||||
filterUrl = "?#{filterUrl}" if filterUrl isnt ""
|
||||
|
||||
"#{baseUrl}#{filterUrl}"
|
||||
@@ -1,27 +1,17 @@
|
||||
var update_state = function(region) {
|
||||
var country = $('span#' + region + 'country .select2').select2('val');
|
||||
|
||||
var state_select = $('span#' + region + 'state select.select2');
|
||||
var state_input = $('span#' + region + 'state input.state_name');
|
||||
|
||||
$.get(Spree.routes.states_search + "?country_id=" + country, function(data) {
|
||||
var states = data["states"]
|
||||
if (states.length > 0) {
|
||||
state_select.html('');
|
||||
var states_with_blank = [{name: '', id: ''}].concat(states);
|
||||
$.each(states_with_blank, function(pos,state) {
|
||||
var opt = $(document.createElement('option'))
|
||||
.attr('value', state.id)
|
||||
.html(state.name);
|
||||
state_select.append(opt);
|
||||
});
|
||||
state_select.prop("disabled", false).show();
|
||||
state_select.select2();
|
||||
state_input.hide().prop("disabled", true);
|
||||
|
||||
} else {
|
||||
state_input.prop("disabled", false).show();
|
||||
state_select.select2('destroy').hide();
|
||||
}
|
||||
$.get(Spree.routes.states_search + "?country_id=" + country, function(states) {
|
||||
state_select.html('');
|
||||
var states_with_blank = [{name: '', id: ''}].concat(states);
|
||||
$.each(states_with_blank, function(pos,state) {
|
||||
var opt = $(document.createElement('option'))
|
||||
.attr('value', state.id)
|
||||
.html(state.name);
|
||||
state_select.append(opt);
|
||||
});
|
||||
state_select.prop("disabled", false).show();
|
||||
state_select.select2();
|
||||
})
|
||||
};
|
||||
|
||||
17
app/assets/javascripts/admin/spree/orders/use_billing.js
Normal file
17
app/assets/javascripts/admin/spree/orders/use_billing.js
Normal file
@@ -0,0 +1,17 @@
|
||||
$(document).ready(function() {
|
||||
var order_use_billing_input = $('input#order_use_billing');
|
||||
|
||||
var order_use_billing = function () {
|
||||
if (!order_use_billing_input.is(':checked')) {
|
||||
$('#shipping').show();
|
||||
} else {
|
||||
$('#shipping').hide();
|
||||
}
|
||||
};
|
||||
|
||||
order_use_billing_input.click(function() {
|
||||
order_use_billing();
|
||||
});
|
||||
|
||||
order_use_billing();
|
||||
});
|
||||
@@ -1,22 +1,30 @@
|
||||
$(document).ready(function() {
|
||||
$('.datetimepicker').datetimepicker({
|
||||
dateFormat: 'yy-mm-dd',
|
||||
timeFormat: 'HH:mm',
|
||||
$(document).ready(function(){
|
||||
window.JQUERY_UI_DATE_PICKER_DEFAULTS = {
|
||||
dateFormat: Spree.translations.date_picker,
|
||||
dayNames: Spree.translations.abbr_day_names,
|
||||
dayNamesMin: Spree.translations.abbr_day_names,
|
||||
monthNames: Spree.translations.month_names,
|
||||
prevText: Spree.translations.previous,
|
||||
nextText: Spree.translations.next,
|
||||
showOn: 'button',
|
||||
controlType: 'select',
|
||||
oneLine: true,
|
||||
showOn: 'button',
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>",
|
||||
buttonImageOnly: true,
|
||||
stepMinute: 15
|
||||
});
|
||||
});
|
||||
buttonImageOnly: true
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
window.JQUERY_UI_DATETIME_PICKER_DEFAULTS = Object.assign(
|
||||
{},
|
||||
window.JQUERY_UI_DATE_PICKER_DEFAULTS,
|
||||
{
|
||||
currentText: Spree.translations.datetime_ui_current_text,
|
||||
closeText: Spree.translations.datetime_ui_close_text,
|
||||
timeText: Spree.translations.datetime_ui_time_text,
|
||||
timeFormat: 'HH:mm',
|
||||
controlType: 'select',
|
||||
stepMinute: 15
|
||||
}
|
||||
);
|
||||
$('.datetimepicker').datetimepicker(window.JQUERY_UI_DATETIME_PICKER_DEFAULTS);
|
||||
$('a.close').click(function(event){
|
||||
event.preventDefault();
|
||||
$(this).parent().slideUp(250);
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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: ->
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Darkswarm.factory "Loading", ->
|
||||
new class Loading
|
||||
message: null
|
||||
message: null
|
||||
clear: =>
|
||||
@message = null
|
||||
|
||||
17
app/assets/javascripts/darkswarm/services/messages.js.coffee
Normal file
17
app/assets/javascripts/darkswarm/services/messages.js.coffee
Normal 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()
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
@import "variables";
|
||||
@import "../variables";
|
||||
|
||||
span.unavailable, span.available {
|
||||
span.unavailable,
|
||||
span.available {
|
||||
font-weight: bold;
|
||||
|
||||
i {
|
||||
font-size: 150%;
|
||||
}
|
||||
@@ -13,4 +15,4 @@ span.available {
|
||||
|
||||
span.unavailable {
|
||||
color: $warning-red;
|
||||
}
|
||||
}
|
||||
@@ -132,3 +132,25 @@ dl {
|
||||
padding: 40px 0px;
|
||||
color: lighten($color-body-text, 15);
|
||||
}
|
||||
|
||||
.text-normal {
|
||||
font-size: 1rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-big {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-red {
|
||||
color: $warning-red;
|
||||
}
|
||||
|
||||
input.text-big {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.pad-top {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
@import "variables";
|
||||
|
||||
.text-normal {
|
||||
font-size: 1.0rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-big {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-red {
|
||||
color: $warning-red;
|
||||
}
|
||||
|
||||
|
||||
input.text-big {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ nav.top-bar {
|
||||
}
|
||||
|
||||
.off-canvas-wrap {
|
||||
overflow: inherit;
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.off-canvas-list li.language-switcher ul li {
|
||||
|
||||
@@ -33,12 +33,6 @@ module Api
|
||||
use_renderers :json
|
||||
check_authorization
|
||||
|
||||
# Temporary measure to help debugging strong_parameters
|
||||
rescue_from ActiveModel::ForbiddenAttributesError, with: :print_params
|
||||
def print_params
|
||||
raise ActiveModel::ForbiddenAttributesError, params.to_s
|
||||
end
|
||||
|
||||
def set_jsonp_format
|
||||
return unless params[:callback] && request.get?
|
||||
|
||||
|
||||
44
app/controllers/api/states_controller.rb
Normal file
44
app/controllers/api/states_controller.rb
Normal file
@@ -0,0 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
class StatesController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
def index
|
||||
render json: states, each_serializer: Api::StateSerializer, status: :ok
|
||||
end
|
||||
|
||||
def show
|
||||
@state = scope.find(params[:id])
|
||||
render json: @state, serializer: Api::StateSerializer, status: :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scope
|
||||
if params[:country_id]
|
||||
@country = Spree::Country.find(params[:country_id])
|
||||
@country.states
|
||||
else
|
||||
Spree::State.all
|
||||
end
|
||||
end
|
||||
|
||||
def states
|
||||
states = scope.ransack(params[:q]).result.
|
||||
includes(:country).order('name ASC')
|
||||
|
||||
if pagination?
|
||||
states = states.page(params[:page]).per(params[:per_page])
|
||||
end
|
||||
|
||||
states
|
||||
end
|
||||
|
||||
def pagination?
|
||||
params[:page] || params[:per_page]
|
||||
end
|
||||
end
|
||||
end
|
||||
18
app/controllers/api/terms_and_conditions_controller.rb
Normal file
18
app/controllers/api/terms_and_conditions_controller.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
class TermsAndConditionsController < Api::EnterpriseAttachmentController
|
||||
private
|
||||
|
||||
def attachment_name
|
||||
:terms_and_conditions
|
||||
end
|
||||
|
||||
def enterprise_authorize_action
|
||||
case action_name.to_sym
|
||||
when :destroy
|
||||
:remove_terms_and_conditions
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,12 +10,6 @@ class ApplicationController < ActionController::Base
|
||||
include EnterprisesHelper
|
||||
include Spree::AuthenticationHelpers
|
||||
|
||||
# Temporary measure to help debugging strong_parameters
|
||||
rescue_from ActiveModel::ForbiddenAttributesError, with: :print_params
|
||||
def print_params
|
||||
raise ActiveModel::ForbiddenAttributesError, params.to_s
|
||||
end
|
||||
|
||||
def redirect_to(options = {}, response_status = {})
|
||||
::Rails.logger.error("Redirected by #{begin
|
||||
caller(1).first
|
||||
|
||||
@@ -8,9 +8,55 @@ module Spree
|
||||
|
||||
before_action :load_data
|
||||
|
||||
create.before :set_viewable
|
||||
update.before :set_viewable
|
||||
destroy.before :destroy_before
|
||||
def index
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def new
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
render layout: !request.xhr?
|
||||
end
|
||||
|
||||
def create
|
||||
@url_filters = ::ProductFilters.new.extract(params)
|
||||
set_viewable
|
||||
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
redirect_to admin_product_images_url(params[:product_id], @url_filters)
|
||||
else
|
||||
respond_with(@object)
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(params)
|
||||
set_viewable
|
||||
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
redirect_to admin_product_images_url(params[:product_id], @url_filters)
|
||||
else
|
||||
respond_with(@object)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
destroy_before
|
||||
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
end
|
||||
|
||||
redirect_to admin_product_images_url(params[:product_id], @url_filters)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -5,6 +5,20 @@ module Spree
|
||||
before_action :find_properties
|
||||
before_action :setup_property, only: [:index]
|
||||
|
||||
def index
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
end
|
||||
# if destroy fails it won't show any errors to the user
|
||||
redirect_to admin_product_product_properties_url(params[:product_id], @url_filters)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_properties
|
||||
|
||||
@@ -10,35 +10,32 @@ module Spree
|
||||
include OrderCyclesHelper
|
||||
include EnterprisesHelper
|
||||
|
||||
create.before :create_before
|
||||
update.before :update_before
|
||||
|
||||
before_action :load_data
|
||||
before_action :load_form_data, only: [:index, :new, :create, :edit, :update]
|
||||
before_action :load_spree_api_key, only: [:index, :variant_overrides]
|
||||
before_action :strip_new_properties, only: [:create, :update]
|
||||
|
||||
respond_override create: { html: {
|
||||
success: lambda {
|
||||
if params[:button] == "add_another"
|
||||
redirect_to new_admin_product_path
|
||||
else
|
||||
redirect_to admin_products_path
|
||||
end
|
||||
},
|
||||
failure: lambda {
|
||||
render :new
|
||||
}
|
||||
} }
|
||||
|
||||
def new
|
||||
@object.shipping_category = DefaultShippingCategory.find_or_create
|
||||
super
|
||||
end
|
||||
|
||||
def create
|
||||
delete_stock_params_and_set_after do
|
||||
super
|
||||
if params[:product][:prototype_id].present?
|
||||
@prototype = Spree::Prototype.find(params[:product][:prototype_id])
|
||||
end
|
||||
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
if params[:button] == "add_another"
|
||||
redirect_to new_admin_product_path
|
||||
else
|
||||
redirect_to admin_products_path
|
||||
end
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
||||
invoke_callbacks(:create, :fails)
|
||||
@@ -56,14 +53,24 @@ module Spree
|
||||
@show_latest_import = params[:latest_import] || false
|
||||
end
|
||||
|
||||
def update
|
||||
original_supplier_id = @product.supplier_id
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(params)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
original_supplier_id = @product.supplier_id
|
||||
delete_stock_params_and_set_after do
|
||||
super
|
||||
if original_supplier_id != @product.supplier_id
|
||||
ExchangeVariantDeleter.new.delete(@product)
|
||||
params[:product] ||= {} if params[:clear_product_properties]
|
||||
if @object.update(permitted_resource_params)
|
||||
if original_supplier_id != @product.supplier_id
|
||||
ExchangeVariantDeleter.new.delete(@product)
|
||||
end
|
||||
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
end
|
||||
redirect_to edit_admin_product_url(@object, @url_filters)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,6 +100,14 @@ module Spree
|
||||
redirect_to edit_admin_product_url(@new)
|
||||
end
|
||||
|
||||
def group_buy_options
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def seo
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_resource
|
||||
@@ -135,19 +150,6 @@ module Spree
|
||||
@collection
|
||||
end
|
||||
|
||||
def create_before
|
||||
return if params[:product][:prototype_id].blank?
|
||||
|
||||
@prototype = Spree::Prototype.find(params[:product][:prototype_id])
|
||||
end
|
||||
|
||||
def update_before
|
||||
# We only reset the product properties if we're receiving a post from the form on that tab
|
||||
return unless params[:clear_product_properties]
|
||||
|
||||
params[:product] ||= {}
|
||||
end
|
||||
|
||||
def product_includes
|
||||
[{ variants: [:images, { option_values: :option_type }] },
|
||||
{ master: [:images, :default_price] }]
|
||||
|
||||
@@ -4,14 +4,46 @@ module Spree
|
||||
module Admin
|
||||
class VariantsController < ResourceController
|
||||
helper 'spree/products'
|
||||
|
||||
belongs_to 'spree/product', find_by: :permalink
|
||||
new_action.before :new_before
|
||||
|
||||
def index
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
redirect_to admin_product_variants_url(params[:product_id], @url_filters)
|
||||
else
|
||||
redirect_to edit_admin_product_variant_url(params[:product_id], @object, @url_filters)
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def create
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
on_demand = params[:variant].delete(:on_demand)
|
||||
on_hand = params[:variant].delete(:on_hand)
|
||||
|
||||
super
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
redirect_to admin_product_variants_url(params[:product_id], @url_filters)
|
||||
else
|
||||
redirect_to new_admin_product_variant_url(params[:product_id], @url_filters)
|
||||
end
|
||||
|
||||
return unless @object.present? && @object.valid?
|
||||
|
||||
@@ -26,6 +58,8 @@ module Spree
|
||||
end
|
||||
|
||||
def destroy
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
@variant = Spree::Variant.find(params[:id])
|
||||
flash[:success] = if VariantDeleter.new.delete(@variant)
|
||||
Spree.t('notice_messages.variant_deleted')
|
||||
@@ -33,9 +67,7 @@ module Spree
|
||||
Spree.t('notice_messages.variant_not_deleted')
|
||||
end
|
||||
|
||||
respond_with(@variant) do |format|
|
||||
format.html { redirect_to admin_product_variants_url(params[:product_id]) }
|
||||
end
|
||||
redirect_to admin_product_variants_url(params[:product_id], @url_filters)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
module BaseHelper
|
||||
# human readable list of variant options
|
||||
# Override: Do not show out of stock text
|
||||
def variant_options(variant, _options = {})
|
||||
variant.options_text
|
||||
end
|
||||
|
||||
# Overriden to eager-load :states
|
||||
def available_countries
|
||||
checkout_zone = Zone.find_by(name: Spree::Config[:checkout_zone])
|
||||
|
||||
@@ -21,5 +16,10 @@ module Spree
|
||||
country
|
||||
end.sort { |a, b| a.name <=> b.name }
|
||||
end
|
||||
|
||||
def pretty_time(time)
|
||||
[I18n.l(time.to_date, format: :long),
|
||||
time.strftime("%l:%M %p")].join(" ")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,14 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
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
|
||||
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'
|
||||
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
|
||||
@@ -12,10 +12,7 @@ class Enterprise < ActiveRecord::Base
|
||||
preference :shopfront_order_cycle_order, :string, default: "orders_close_at"
|
||||
preference :show_customer_names_to_suppliers, :boolean, default: false
|
||||
|
||||
# This is hopefully a temporary measure, pending the arrival of multiple named inventories
|
||||
# for shops. We need this here to allow hubs to restrict visible variants to only those in
|
||||
# their inventory if they so choose
|
||||
# TODO: delegate this to a separate model instead of abusing Preferences.
|
||||
# Allow hubs to restrict visible variants to only those in their inventory
|
||||
preference :product_selection_from_inventory_only, :boolean, default: false
|
||||
|
||||
has_paper_trail only: [:owner_id, :sells], on: [:update]
|
||||
@@ -78,10 +75,16 @@ class Enterprise < ActiveRecord::Base
|
||||
},
|
||||
url: '/images/enterprises/promo_images/:id/:style/:basename.:extension',
|
||||
path: 'public/images/enterprises/promo_images/:id/:style/:basename.:extension'
|
||||
|
||||
validates_attachment_content_type :logo, content_type: %r{\Aimage/.*\Z}
|
||||
validates_attachment_content_type :promo_image, content_type: %r{\Aimage/.*\Z}
|
||||
|
||||
has_attached_file :terms_and_conditions,
|
||||
url: '/files/enterprises/terms_and_conditions/:id/:basename.:extension',
|
||||
path: 'public/files/enterprises/terms_and_conditions/:id/:basename.:extension'
|
||||
validates_attachment_content_type :terms_and_conditions,
|
||||
content_type: "application/pdf",
|
||||
message: I18n.t(:enterprise_terms_and_conditions_type_error)
|
||||
|
||||
include Spree::Core::S3Support
|
||||
supports_s3 :logo
|
||||
supports_s3 :promo_image
|
||||
|
||||
@@ -159,7 +159,7 @@ module ProductImport
|
||||
end
|
||||
|
||||
def unit_fields_validation(entry)
|
||||
unit_types = ['g', 'kg', 't', 'ml', 'l', 'kl', '']
|
||||
unit_types = ['g', 'oz', 'lb', 'kg', 't', 'ml', 'l', 'kl', '']
|
||||
|
||||
unless entry.units&.present?
|
||||
mark_as_invalid(entry, attribute: 'units',
|
||||
|
||||
@@ -32,6 +32,8 @@ module ProductImport
|
||||
{
|
||||
'g' => { scale: 1, unit: 'weight' },
|
||||
'kg' => { scale: 1000, unit: 'weight' },
|
||||
'oz' => { scale: 28.35, unit: 'weight' },
|
||||
'lb' => { scale: 453.6, unit: 'weight' },
|
||||
't' => { scale: 1_000_000, unit: 'weight' },
|
||||
'ml' => { scale: 0.001, unit: 'volume' },
|
||||
'l' => { scale: 1, unit: 'volume' },
|
||||
|
||||
@@ -97,7 +97,9 @@ class AbilityDecorator
|
||||
end
|
||||
|
||||
can [:admin, :index, :create], Enterprise
|
||||
can [:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], Enterprise do |enterprise|
|
||||
can [:read, :edit, :update,
|
||||
:remove_logo, :remove_promo_image, :remove_terms_and_conditions,
|
||||
:bulk_update, :resend_confirmation], Enterprise do |enterprise|
|
||||
OpenFoodNetwork::Permissions.new(user).editable_enterprises.include? enterprise
|
||||
end
|
||||
can [:welcome, :register], Enterprise do |enterprise|
|
||||
|
||||
162
app/models/spree/address.rb
Normal file
162
app/models/spree/address.rb
Normal file
@@ -0,0 +1,162 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Address < ActiveRecord::Base
|
||||
include AddressDisplay
|
||||
|
||||
belongs_to :country, class_name: "Spree::Country"
|
||||
belongs_to :state, class_name: "Spree::State"
|
||||
|
||||
has_one :enterprise, dependent: :restrict_with_exception
|
||||
has_many :shipments
|
||||
|
||||
validates :firstname, :lastname, :address1, :city, :country, presence: true
|
||||
validates :zipcode, presence: true, if: :require_zipcode?
|
||||
validates :phone, presence: true, if: :require_phone?
|
||||
|
||||
validate :state_validate
|
||||
|
||||
after_save :touch_enterprise
|
||||
|
||||
alias_attribute :first_name, :firstname
|
||||
alias_attribute :last_name, :lastname
|
||||
delegate :name, to: :state, prefix: true, allow_nil: true
|
||||
|
||||
geocoded_by :geocode_address
|
||||
|
||||
def self.default
|
||||
country = begin
|
||||
Spree::Country.find(Spree::Config[:default_country_id])
|
||||
rescue StandardError
|
||||
Spree::Country.first
|
||||
end
|
||||
new(country: country)
|
||||
end
|
||||
|
||||
def full_name
|
||||
"#{firstname} #{lastname}".strip
|
||||
end
|
||||
|
||||
def state_text
|
||||
state.try(:abbr) || state.try(:name) || state_name
|
||||
end
|
||||
|
||||
def same_as?(other)
|
||||
return false if other.nil?
|
||||
|
||||
attributes.except('id', 'updated_at', 'created_at') ==
|
||||
other.attributes.except('id', 'updated_at', 'created_at')
|
||||
end
|
||||
|
||||
alias same_as same_as?
|
||||
|
||||
def to_s
|
||||
"#{full_name}: #{address1}"
|
||||
end
|
||||
|
||||
def clone
|
||||
self.class.new(attributes.except('id', 'updated_at', 'created_at'))
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self_attrs = attributes
|
||||
other_attrs = other.respond_to?(:attributes) ? other.attributes : {}
|
||||
|
||||
[self_attrs, other_attrs].each { |attrs|
|
||||
attrs.except!('id', 'created_at', 'updated_at', 'order_id')
|
||||
}
|
||||
|
||||
self_attrs == other_attrs
|
||||
end
|
||||
|
||||
def empty?
|
||||
attributes.except('id', 'created_at', 'updated_at', 'order_id', 'country_id').all? { |_, v|
|
||||
v.nil?
|
||||
}
|
||||
end
|
||||
|
||||
# Generates an ActiveMerchant compatible address hash
|
||||
def active_merchant_hash
|
||||
{
|
||||
name: full_name,
|
||||
address1: address1,
|
||||
address2: address2,
|
||||
city: city,
|
||||
state: state_text,
|
||||
zip: zipcode,
|
||||
country: country.try(:iso),
|
||||
phone: phone
|
||||
}
|
||||
end
|
||||
|
||||
def geocode_address
|
||||
render_address([address1, address2, zipcode, city, country.andand.name, state.andand.name])
|
||||
end
|
||||
|
||||
def full_address
|
||||
render_address([address1, address2, city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
def address_part1
|
||||
render_address([address1, address2])
|
||||
end
|
||||
|
||||
def address_part2
|
||||
render_address([city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_phone?
|
||||
true
|
||||
end
|
||||
|
||||
def require_zipcode?
|
||||
true
|
||||
end
|
||||
|
||||
def state_validate
|
||||
# Skip state validation without country (also required)
|
||||
# or when disabled by preference
|
||||
return if country.blank? || !Spree::Config[:address_requires_state]
|
||||
return unless country.states_required
|
||||
|
||||
# Ensure associated state belongs to country
|
||||
if state.present?
|
||||
if state.country == country
|
||||
self.state_name = nil # not required as we have a valid state and country combo
|
||||
elsif state_name.present?
|
||||
self.state = nil
|
||||
else
|
||||
errors.add(:state, :invalid)
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure state_name belongs to country without states,
|
||||
# or that it matches a predefined state name/abbr
|
||||
if state_name.present?
|
||||
if country.states.present?
|
||||
states = country.states.find_all_by_name_or_abbr(state_name)
|
||||
|
||||
if states.size == 1
|
||||
self.state = states.first
|
||||
self.state_name = nil
|
||||
else
|
||||
errors.add(:state, :invalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ensure at least one state field is populated
|
||||
errors.add :state, :blank if state.blank? && state_name.blank?
|
||||
end
|
||||
|
||||
def touch_enterprise
|
||||
enterprise.andand.touch
|
||||
end
|
||||
|
||||
def render_address(parts)
|
||||
parts.select(&:present?).join(', ')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,38 +0,0 @@
|
||||
Spree::Address.class_eval do
|
||||
include AddressDisplay
|
||||
|
||||
has_one :enterprise, dependent: :restrict_with_exception
|
||||
belongs_to :country, class_name: "Spree::Country"
|
||||
|
||||
after_save :touch_enterprise
|
||||
|
||||
geocoded_by :geocode_address
|
||||
|
||||
delegate :name, to: :state, prefix: true, allow_nil: true
|
||||
|
||||
def geocode_address
|
||||
render_address([address1, address2, zipcode, city, country.andand.name, state.andand.name])
|
||||
end
|
||||
|
||||
def full_address
|
||||
render_address([address1, address2, city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
def address_part1
|
||||
render_address([address1, address2])
|
||||
end
|
||||
|
||||
def address_part2
|
||||
render_address([city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def touch_enterprise
|
||||
enterprise.andand.touch
|
||||
end
|
||||
|
||||
def render_address(parts)
|
||||
parts.select(&:present?).join(', ')
|
||||
end
|
||||
end
|
||||
177
app/models/spree/adjustment.rb
Normal file
177
app/models/spree/adjustment.rb
Normal 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
|
||||
@@ -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
|
||||
56
app/models/spree/calculator.rb
Normal file
56
app/models/spree/calculator.rb
Normal 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
|
||||
@@ -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
|
||||
21
app/models/spree/classification.rb
Normal file
21
app/models/spree/classification.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Classification < ActiveRecord::Base
|
||||
self.table_name = 'spree_products_taxons'
|
||||
belongs_to :product, class_name: "Spree::Product", touch: true
|
||||
belongs_to :taxon, class_name: "Spree::Taxon", touch: true
|
||||
|
||||
before_destroy :dont_destroy_if_primary_taxon
|
||||
|
||||
private
|
||||
|
||||
def dont_destroy_if_primary_taxon
|
||||
return unless product.primary_taxon == taxon
|
||||
|
||||
errors.add :base, I18n.t(:spree_classification_primary_taxon_error, taxon: taxon.name,
|
||||
product: product.name)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,15 +0,0 @@
|
||||
Spree::Classification.class_eval do
|
||||
belongs_to :product, class_name: "Spree::Product", touch: true
|
||||
belongs_to :taxon, class_name: "Spree::Taxon", touch: true
|
||||
|
||||
before_destroy :dont_destroy_if_primary_taxon
|
||||
|
||||
private
|
||||
|
||||
def dont_destroy_if_primary_taxon
|
||||
if product.primary_taxon == taxon
|
||||
errors.add :base, I18n.t(:spree_classification_primary_taxon_error, taxon: taxon.name, product: product.name)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spree/concerns/payment_method_distributors'
|
||||
|
||||
module Spree
|
||||
class Gateway < PaymentMethod
|
||||
include Spree::PaymentMethodDistributors
|
||||
include PaymentMethodDistributors
|
||||
|
||||
delegate_belongs_to :provider, :authorize, :purchase, :capture, :void, :credit
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
require 'open_food_network/scope_variant_to_hub'
|
||||
require 'open_food_network/variant_and_line_item_naming'
|
||||
require 'variant_units/variant_and_line_item_naming'
|
||||
|
||||
Spree::LineItem.class_eval do
|
||||
include OpenFoodNetwork::VariantAndLineItemNaming
|
||||
include VariantUnits::VariantAndLineItemNaming
|
||||
include LineItemBasedAdjustmentHandling
|
||||
has_and_belongs_to_many :option_values, join_table: 'spree_option_values_line_items', class_name: 'Spree::OptionValue'
|
||||
|
||||
|
||||
18
app/models/spree/log_entry.rb
Normal file
18
app/models/spree/log_entry.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class LogEntry < ActiveRecord::Base
|
||||
belongs_to :source, polymorphic: true
|
||||
|
||||
# Fix for Spree #1767
|
||||
# If a payment fails, we want to make sure we keep the record of it failing
|
||||
after_rollback :save_anyway
|
||||
|
||||
def save_anyway
|
||||
log = Spree::LogEntry.new
|
||||
log.source = source
|
||||
log.details = details
|
||||
log.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -194,8 +194,6 @@ Spree::Order.class_eval do
|
||||
end
|
||||
|
||||
# After changing line items of a completed order
|
||||
# TODO: perhaps this should be triggered from a controller
|
||||
# rather than an after_save callback?
|
||||
def update_shipping_fees!
|
||||
shipments.each do |shipment|
|
||||
next if shipment.shipped?
|
||||
@@ -222,8 +220,6 @@ Spree::Order.class_eval do
|
||||
end
|
||||
|
||||
# After changing line items of a completed order
|
||||
# TODO: perhaps this should be triggered from a controller
|
||||
# rather than an after_save callback?
|
||||
def update_payment_fees!
|
||||
payments.each do |payment|
|
||||
next if payment.completed?
|
||||
|
||||
@@ -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) })
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spree/concerns/payment_method_distributors'
|
||||
|
||||
module Spree
|
||||
class PaymentMethod < ActiveRecord::Base
|
||||
include Spree::Core::CalculatedAdjustments
|
||||
include Spree::PaymentMethodDistributors
|
||||
include PaymentMethodDistributors
|
||||
|
||||
acts_as_taggable
|
||||
acts_as_paranoid
|
||||
|
||||
@@ -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
|
||||
|
||||
8
app/models/spree/role.rb
Normal file
8
app/models/spree/role.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Role < ActiveRecord::Base
|
||||
has_and_belongs_to_many :users, join_table: 'spree_roles_users',
|
||||
class_name: Spree.user_class.to_s
|
||||
end
|
||||
end
|
||||
@@ -90,7 +90,7 @@ module Spree
|
||||
end
|
||||
|
||||
def selected_shipping_rate
|
||||
shipping_rates.where(selected: true).first
|
||||
shipping_rates.find_by(selected: true)
|
||||
end
|
||||
|
||||
def selected_shipping_rate_id
|
||||
@@ -294,7 +294,7 @@ module Spree
|
||||
record = true
|
||||
while record
|
||||
random = "H#{Array.new(11) { rand(9) }.join}"
|
||||
record = self.class.where(number: random).first
|
||||
record = self.class.find_by(number: random)
|
||||
end
|
||||
self.number = random
|
||||
end
|
||||
|
||||
10
app/models/spree/shipping_category.rb
Normal file
10
app/models/spree/shipping_category.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingCategory < ActiveRecord::Base
|
||||
validates :name, presence: true
|
||||
has_many :products
|
||||
has_many :shipping_method_categories
|
||||
has_many :shipping_methods, through: :shipping_method_categories
|
||||
end
|
||||
end
|
||||
132
app/models/spree/shipping_method.rb
Normal file
132
app/models/spree/shipping_method.rb
Normal file
@@ -0,0 +1,132 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingMethod < ActiveRecord::Base
|
||||
include Spree::Core::CalculatedAdjustments
|
||||
DISPLAY = [:both, :front_end, :back_end].freeze
|
||||
|
||||
acts_as_taggable
|
||||
|
||||
default_scope -> { where(deleted_at: nil) }
|
||||
|
||||
has_many :shipments
|
||||
has_many :shipping_method_categories
|
||||
has_many :shipping_categories, through: :shipping_method_categories
|
||||
has_many :shipping_rates
|
||||
has_many :distributor_shipping_methods
|
||||
has_many :distributors, through: :distributor_shipping_methods,
|
||||
class_name: 'Enterprise',
|
||||
foreign_key: 'distributor_id'
|
||||
|
||||
has_and_belongs_to_many :zones, join_table: 'spree_shipping_methods_zones',
|
||||
class_name: 'Spree::Zone',
|
||||
foreign_key: 'shipping_method_id'
|
||||
|
||||
validates :name, presence: true
|
||||
validate :distributor_validation
|
||||
validate :at_least_one_shipping_category
|
||||
|
||||
after_save :touch_distributors
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
where(nil)
|
||||
else
|
||||
joins(:distributors).
|
||||
where('distributors_shipping_methods.distributor_id IN (?)',
|
||||
user.enterprises.select(&:id)).
|
||||
select('DISTINCT spree_shipping_methods.*')
|
||||
end
|
||||
}
|
||||
|
||||
scope :for_distributors, ->(distributors) {
|
||||
non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors })
|
||||
where(id: non_unique_matches.map(&:id))
|
||||
}
|
||||
scope :for_distributor, lambda { |distributor|
|
||||
joins(:distributors).
|
||||
where('enterprises.id = ?', distributor)
|
||||
}
|
||||
|
||||
scope :by_name, -> { order('spree_shipping_methods.name ASC') }
|
||||
scope :display_on_checkout, -> {
|
||||
where("spree_shipping_methods.display_on is null OR spree_shipping_methods.display_on = ''")
|
||||
}
|
||||
|
||||
def adjustment_label
|
||||
I18n.t('shipping')
|
||||
end
|
||||
|
||||
# Here we allow checkout with shipping methods without zones (see issue #3928 for details)
|
||||
# and also checkout with addresses outside of the zones of the selected shipping method
|
||||
# This method could be used, like in Spree, to validate shipping method zones on checkout.
|
||||
def include?(address)
|
||||
address.present?
|
||||
end
|
||||
|
||||
def build_tracking_url(tracking)
|
||||
tracking_url.gsub(/:tracking/, tracking) unless tracking.blank? || tracking_url.blank?
|
||||
end
|
||||
|
||||
def self.calculators
|
||||
spree_calculators.__send__ model_name_without_spree_namespace
|
||||
end
|
||||
|
||||
# Some shipping methods are only meant to be set via backend
|
||||
def frontend?
|
||||
display_on != "back_end"
|
||||
end
|
||||
|
||||
def has_distributor?(distributor)
|
||||
distributors.include?(distributor)
|
||||
end
|
||||
|
||||
# Checks whether the shipping method is of delivery type, meaning that it
|
||||
# requires the user to specify a ship address at checkout.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def delivery?
|
||||
require_ship_address
|
||||
end
|
||||
|
||||
# Return the services (pickup, delivery) that different distributors provide, in the format:
|
||||
# {distributor_id => {pickup: true, delivery: false}, ...}
|
||||
def self.services
|
||||
Hash[
|
||||
Spree::ShippingMethod.
|
||||
joins(:distributor_shipping_methods).
|
||||
group('distributor_id').
|
||||
select("distributor_id").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery").
|
||||
map { |sm| [sm.distributor_id.to_i, { pickup: sm.pickup, delivery: sm.delivery }] }
|
||||
]
|
||||
end
|
||||
|
||||
def self.on_backend_query
|
||||
"#{table_name}.display_on != 'front_end' OR #{table_name}.display_on IS NULL"
|
||||
end
|
||||
|
||||
def self.on_frontend_query
|
||||
"#{table_name}.display_on != 'back_end' OR #{table_name}.display_on IS NULL"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def at_least_one_shipping_category
|
||||
return unless shipping_categories.empty?
|
||||
|
||||
errors[:base] << "You need to select at least one shipping category"
|
||||
end
|
||||
|
||||
def touch_distributors
|
||||
distributors.each do |distributor|
|
||||
distributor.touch if distributor.persisted?
|
||||
end
|
||||
end
|
||||
|
||||
def distributor_validation
|
||||
validates_with DistributorsValidator
|
||||
end
|
||||
end
|
||||
end
|
||||
8
app/models/spree/shipping_method_category.rb
Normal file
8
app/models/spree/shipping_method_category.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingMethodCategory < ActiveRecord::Base
|
||||
belongs_to :shipping_method, class_name: 'Spree::ShippingMethod'
|
||||
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory'
|
||||
end
|
||||
end
|
||||
@@ -1,90 +0,0 @@
|
||||
Spree::ShippingMethod.class_eval do
|
||||
acts_as_taggable
|
||||
|
||||
has_many :distributor_shipping_methods
|
||||
has_many :distributors, through: :distributor_shipping_methods, class_name: 'Enterprise', foreign_key: 'distributor_id'
|
||||
|
||||
after_save :touch_distributors
|
||||
|
||||
validate :distributor_validation
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
where(nil)
|
||||
else
|
||||
joins(:distributors).
|
||||
where('distributors_shipping_methods.distributor_id IN (?)', user.enterprises.select(&:id)).
|
||||
select('DISTINCT spree_shipping_methods.*')
|
||||
end
|
||||
}
|
||||
|
||||
scope :for_distributors, ->(distributors) {
|
||||
non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors })
|
||||
where(id: non_unique_matches.map(&:id))
|
||||
}
|
||||
scope :for_distributor, lambda { |distributor|
|
||||
joins(:distributors).
|
||||
where('enterprises.id = ?', distributor)
|
||||
}
|
||||
|
||||
scope :by_name, -> { order('spree_shipping_methods.name ASC') }
|
||||
scope :display_on_checkout, -> { where("spree_shipping_methods.display_on is null OR spree_shipping_methods.display_on = ''") }
|
||||
|
||||
# Return the services (pickup, delivery) that different distributors provide, in the format:
|
||||
# {distributor_id => {pickup: true, delivery: false}, ...}
|
||||
def self.services
|
||||
Hash[
|
||||
Spree::ShippingMethod.
|
||||
joins(:distributor_shipping_methods).
|
||||
group('distributor_id').
|
||||
select("distributor_id").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery").
|
||||
map { |sm| [sm.distributor_id.to_i, { pickup: sm.pickup, delivery: sm.delivery }] }
|
||||
]
|
||||
end
|
||||
|
||||
# This method is overriden so that we can remove the restriction added in Spree
|
||||
# Spree restricts shipping method calculators to the ones that inherit from Spree::Shipping::ShippingCalculator
|
||||
# Spree::Shipping::ShippingCalculator makes sure that calculators are able to handle packages and not orders as input
|
||||
# This is not necessary in OFN because calculators in OFN are already customized to work with different types of input
|
||||
def self.calculators
|
||||
spree_calculators.send model_name_without_spree_namespace
|
||||
end
|
||||
|
||||
# This is bypassing the validation of shipping method zones on checkout
|
||||
# It allows checkout using shipping methods without zones (see issue #3928 for details)
|
||||
# and it allows checkout with addresses outside of the zones of the selected shipping method
|
||||
def include?(address)
|
||||
address.present?
|
||||
end
|
||||
|
||||
def has_distributor?(distributor)
|
||||
distributors.include?(distributor)
|
||||
end
|
||||
|
||||
def adjustment_label
|
||||
I18n.t('shipping')
|
||||
end
|
||||
|
||||
# Checks whether the shipping method is of delivery type, meaning that it
|
||||
# requires the user to specify a ship address at checkout. Note this is
|
||||
# a setting we added onto the +spree_shipping_methods+ table.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def delivery?
|
||||
require_ship_address
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def touch_distributors
|
||||
distributors.each do |distributor|
|
||||
distributor.touch if distributor.persisted?
|
||||
end
|
||||
end
|
||||
|
||||
def distributor_validation
|
||||
validates_with DistributorsValidator
|
||||
end
|
||||
end
|
||||
38
app/models/spree/shipping_rate.rb
Normal file
38
app/models/spree/shipping_rate.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingRate < ActiveRecord::Base
|
||||
belongs_to :shipment, class_name: 'Spree::Shipment'
|
||||
belongs_to :shipping_method, class_name: 'Spree::ShippingMethod'
|
||||
|
||||
scope :frontend,
|
||||
-> {
|
||||
includes(:shipping_method).
|
||||
where(ShippingMethod.on_frontend_query).
|
||||
references(:shipping_method).
|
||||
order("cost ASC")
|
||||
}
|
||||
scope :backend,
|
||||
-> {
|
||||
includes(:shipping_method).
|
||||
where(ShippingMethod.on_backend_query).
|
||||
references(:shipping_method).
|
||||
order("cost ASC")
|
||||
}
|
||||
|
||||
delegate :order, :currency, to: :shipment
|
||||
delegate :name, to: :shipping_method
|
||||
|
||||
def display_price
|
||||
price = if Spree::Config[:shipment_inc_vat]
|
||||
(1 + Spree::TaxRate.default) * cost
|
||||
else
|
||||
cost
|
||||
end
|
||||
|
||||
Spree::Money.new(price, { currency: currency })
|
||||
end
|
||||
|
||||
alias_method :display_cost, :display_price
|
||||
end
|
||||
end
|
||||
20
app/models/spree/tax_category.rb
Normal file
20
app/models/spree/tax_category.rb
Normal 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
|
||||
132
app/models/spree/tax_rate.rb
Normal file
132
app/models/spree/tax_rate.rb
Normal 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
|
||||
@@ -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
|
||||
113
app/models/spree/taxon.rb
Normal file
113
app/models/spree/taxon.rb
Normal file
@@ -0,0 +1,113 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Taxon < ActiveRecord::Base
|
||||
acts_as_nested_set dependent: :destroy
|
||||
|
||||
belongs_to :taxonomy, class_name: 'Spree::Taxonomy', touch: true
|
||||
has_many :classifications, dependent: :destroy
|
||||
has_many :products, through: :classifications
|
||||
|
||||
before_create :set_permalink
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
has_attached_file :icon,
|
||||
styles: { mini: '32x32>', normal: '128x128>' },
|
||||
default_style: :mini,
|
||||
url: '/spree/taxons/:id/:style/:basename.:extension',
|
||||
path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
|
||||
default_url: '/assets/default_taxon.png'
|
||||
|
||||
include Spree::Core::S3Support
|
||||
supports_s3 :icon
|
||||
|
||||
# Indicate which filters should be used for this taxon
|
||||
def applicable_filters
|
||||
[]
|
||||
end
|
||||
|
||||
# Return meta_title if set otherwise generates from root name and/or taxon name
|
||||
def seo_title
|
||||
if meta_title
|
||||
meta_title
|
||||
else
|
||||
root? ? name : "#{root.name} - #{name}"
|
||||
end
|
||||
end
|
||||
|
||||
# Creates permalink based on Stringex's .to_url method
|
||||
def set_permalink
|
||||
if parent.present?
|
||||
self.permalink = [parent.permalink, permalink_end].join('/')
|
||||
elsif permalink.blank?
|
||||
self.permalink = name.to_url
|
||||
end
|
||||
end
|
||||
|
||||
# For #2759
|
||||
def to_param
|
||||
permalink
|
||||
end
|
||||
|
||||
def active_products
|
||||
scope = products.active
|
||||
scope
|
||||
end
|
||||
|
||||
def pretty_name
|
||||
ancestor_chain = ancestors.inject("") do |name, ancestor|
|
||||
name += "#{ancestor.name} -> "
|
||||
end
|
||||
ancestor_chain + name.to_s
|
||||
end
|
||||
|
||||
# Find all the taxons of supplied products for each enterprise, indexed by enterprise.
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.supplied_taxons
|
||||
taxons = {}
|
||||
|
||||
Spree::Taxon.
|
||||
joins(products: :supplier).
|
||||
select('spree_taxons.*, enterprises.id AS enterprise_id').
|
||||
each do |t|
|
||||
taxons[t.enterprise_id.to_i] ||= Set.new
|
||||
taxons[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
|
||||
taxons
|
||||
end
|
||||
|
||||
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
|
||||
# May return :all taxons (distributed in open and closed order cycles),
|
||||
# or :current taxons (distributed in an open order cycle).
|
||||
#
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.distributed_taxons(which_taxons = :all)
|
||||
ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing)
|
||||
.select("DISTINCT variant_id, receiver_id AS enterprise_id")
|
||||
|
||||
ents_and_vars = ents_and_vars.merge(OrderCycle.active) if which_taxons == :current
|
||||
|
||||
taxons = Spree::Taxon
|
||||
.select("DISTINCT spree_taxons.id, ents_and_vars.enterprise_id")
|
||||
.joins(products: :variants_including_master)
|
||||
.joins("
|
||||
INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars
|
||||
ON spree_variants.id = ents_and_vars.variant_id")
|
||||
|
||||
taxons.each_with_object({}) do |t, ts|
|
||||
ts[t.enterprise_id.to_i] ||= Set.new
|
||||
ts[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def permalink_end
|
||||
return name.to_url if permalink.blank?
|
||||
|
||||
permalink.split('/').last
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,47 +0,0 @@
|
||||
Spree::Taxon.class_eval do
|
||||
has_many :classifications, dependent: :destroy
|
||||
|
||||
# Indicate which filters should be used for this taxon
|
||||
def applicable_filters
|
||||
fs = []
|
||||
# fs << Spree::ProductFilters.distributor_filter if Spree::ProductFilters.respond_to? :distributor_filter
|
||||
fs
|
||||
end
|
||||
|
||||
# Find all the taxons of supplied products for each enterprise, indexed by enterprise.
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.supplied_taxons
|
||||
taxons = {}
|
||||
|
||||
Spree::Taxon.
|
||||
joins(products: :supplier).
|
||||
select('spree_taxons.*, enterprises.id AS enterprise_id').
|
||||
each do |t|
|
||||
taxons[t.enterprise_id.to_i] ||= Set.new
|
||||
taxons[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
|
||||
taxons
|
||||
end
|
||||
|
||||
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
|
||||
# May return :all taxons (distributed in open and closed order cycles),
|
||||
# or :current taxons (distributed in an open order cycle).
|
||||
#
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.distributed_taxons(which_taxons = :all)
|
||||
ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing)
|
||||
.select("DISTINCT variant_id, receiver_id AS enterprise_id")
|
||||
|
||||
ents_and_vars = ents_and_vars.merge(OrderCycle.active) if which_taxons == :current
|
||||
|
||||
taxons = Spree::Taxon
|
||||
.select("DISTINCT spree_taxons.id, ents_and_vars.enterprise_id").joins(products: :variants_including_master)
|
||||
.joins("INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars ON spree_variants.id = ents_and_vars.variant_id")
|
||||
|
||||
taxons.each_with_object({}) do |t, ts|
|
||||
ts[t.enterprise_id.to_i] ||= Set.new
|
||||
ts[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
end
|
||||
end
|
||||
24
app/models/spree/taxonomy.rb
Normal file
24
app/models/spree/taxonomy.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Taxonomy < ActiveRecord::Base
|
||||
validates :name, presence: true
|
||||
|
||||
has_many :taxons
|
||||
has_one :root, -> { where parent_id: nil }, class_name: "Spree::Taxon", dependent: :destroy
|
||||
|
||||
after_save :set_name
|
||||
|
||||
default_scope -> { order("#{table_name}.position") }
|
||||
|
||||
private
|
||||
|
||||
def set_name
|
||||
if root
|
||||
root.update_column(:name, name)
|
||||
else
|
||||
self.root = Taxon.create!(taxonomy_id: id, name: name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,13 @@ module Spree
|
||||
belongs_to :ship_address, foreign_key: 'ship_address_id', class_name: 'Spree::Address'
|
||||
belongs_to :bill_address, foreign_key: 'bill_address_id', class_name: 'Spree::Address'
|
||||
|
||||
has_and_belongs_to_many :spree_roles,
|
||||
join_table: 'spree_roles_users',
|
||||
foreign_key: "user_id",
|
||||
class_name: "Spree::Role"
|
||||
|
||||
has_many :spree_orders, foreign_key: "user_id", class_name: "Spree::Order"
|
||||
|
||||
before_validation :set_login
|
||||
before_destroy :check_completed_orders
|
||||
|
||||
@@ -41,6 +48,12 @@ module Spree
|
||||
User.admin.count > 0
|
||||
end
|
||||
|
||||
# Whether a user has a role or not.
|
||||
def has_spree_role?(role_in_question)
|
||||
spree_roles.where(name: role_in_question.to_s).any?
|
||||
end
|
||||
|
||||
# Checks whether the specified user is a superadmin, with full control of the instance
|
||||
def admin?
|
||||
has_spree_role?('admin')
|
||||
end
|
||||
@@ -107,14 +120,6 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
# Checks whether the specified user is a superadmin, with full control of the
|
||||
# instance
|
||||
#
|
||||
# @return [Boolean]
|
||||
def superadmin?
|
||||
has_spree_role?('admin')
|
||||
end
|
||||
|
||||
def generate_spree_api_key!
|
||||
self.spree_api_key = SecureRandom.hex(24)
|
||||
save!
|
||||
@@ -125,6 +130,10 @@ module Spree
|
||||
save!
|
||||
end
|
||||
|
||||
def last_incomplete_spree_order
|
||||
spree_orders.incomplete.where(created_by_id: id).order('created_at DESC').first
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def password_required?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
require 'open_food_network/enterprise_fee_calculator'
|
||||
require 'open_food_network/variant_and_line_item_naming'
|
||||
require 'variant_units/variant_and_line_item_naming'
|
||||
require 'concerns/variant_stock'
|
||||
|
||||
Spree::Variant.class_eval do
|
||||
@@ -8,7 +8,7 @@ Spree::Variant.class_eval do
|
||||
# This file may be double-loaded in delayed job environment, so we check before
|
||||
# removing the Spree method to prevent error.
|
||||
remove_method :options_text if instance_methods(false).include? :options_text
|
||||
include OpenFoodNetwork::VariantAndLineItemNaming
|
||||
include VariantUnits::VariantAndLineItemNaming
|
||||
include VariantStock
|
||||
|
||||
has_many :exchange_variants
|
||||
|
||||
@@ -6,7 +6,7 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
:preferred_product_selection_from_inventory_only,
|
||||
:preferred_show_customer_names_to_suppliers, :owner, :contact, :users, :tag_groups,
|
||||
:default_tag_group, :require_login, :allow_guest_orders, :allow_order_changes,
|
||||
:logo, :promo_image
|
||||
:logo, :promo_image, :terms_and_conditions, :terms_and_conditions_file_name
|
||||
|
||||
has_one :owner, serializer: Api::Admin::UserSerializer
|
||||
has_many :users, serializer: Api::Admin::UserSerializer
|
||||
@@ -20,6 +20,12 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
attachment_urls(object.promo_image, [:thumb, :medium, :large])
|
||||
end
|
||||
|
||||
def terms_and_conditions
|
||||
return unless @object.terms_and_conditions.file?
|
||||
|
||||
@object.terms_and_conditions.url
|
||||
end
|
||||
|
||||
def tag_groups
|
||||
object.tag_rules.prioritised.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups|
|
||||
tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags.
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
class Api::StateSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :abbr
|
||||
attributes :id, :name, :abbr, :country_id
|
||||
end
|
||||
|
||||
@@ -32,7 +32,7 @@ class OrderTaxAdjustmentsFetcher
|
||||
end
|
||||
|
||||
def line_item_adjustments
|
||||
table[:adjustable_id].eq(order.line_item_ids.join(','))
|
||||
table[:adjustable_id].eq_any(order.line_item_ids)
|
||||
.and(table[:adjustable_type].eq('Spree::LineItem'))
|
||||
end
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ module PermittedAttributes
|
||||
[
|
||||
:id, :name, :visible, :permalink, :owner_id, :contact_name, :email_address, :phone,
|
||||
:is_primary_producer, :sells, :website, :facebook, :instagram, :linkedin, :twitter,
|
||||
:description, :long_description, :logo, :promo_image,
|
||||
:description, :long_description, :logo, :promo_image, :terms_and_conditions,
|
||||
:allow_guest_orders, :allow_order_changes, :require_login, :enable_subscriptions,
|
||||
:abn, :acn, :charges_sales_tax, :display_invoice_logo, :invoice_text,
|
||||
:preferred_product_selection_from_inventory_only, :preferred_shopfront_message,
|
||||
|
||||
11
app/services/product_filters.rb
Normal file
11
app/services/product_filters.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ProductFilters
|
||||
PRODUCT_FILTERS = [
|
||||
'query', 'producerFilter', 'categoryFilter', 'sorting', 'importDateFilter'
|
||||
].freeze
|
||||
|
||||
def extract(params)
|
||||
params.select { |key, _value| PRODUCT_FILTERS.include?(key) }
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
require "open_food_network/i18n_inflections"
|
||||
|
||||
module OpenFoodNetwork
|
||||
module VariantUnits
|
||||
class OptionValueNamer
|
||||
def initialize(variant = nil)
|
||||
@variant = variant
|
||||
@@ -39,7 +39,6 @@ module OpenFoodNetwork
|
||||
if @variant.unit_value.present?
|
||||
if %w(weight volume).include? @variant.product.variant_unit
|
||||
value, unit_name = option_value_value_unit_scaled
|
||||
|
||||
else
|
||||
value = @variant.unit_value
|
||||
unit_name = pluralize(@variant.product.variant_unit_name, value)
|
||||
@@ -63,21 +62,44 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def scale_for_unit_value
|
||||
units = { 'weight' => { 1.0 => 'g', 1000.0 => 'kg', 1_000_000.0 => 'T' },
|
||||
'volume' => { 0.001 => 'mL', 1.0 => 'L', 1000.0 => 'kL' } }
|
||||
units = {
|
||||
'weight' => {
|
||||
1.0 => { 'name' => 'g', 'system' => 'metric' },
|
||||
28.35 => { 'name' => 'oz', 'system' => 'imperial' },
|
||||
453.6 => { 'name' => 'lb', 'system' => 'imperial' },
|
||||
1000.0 => { 'name' => 'kg', 'system' => 'metric' },
|
||||
1_000_000.0 => { 'name' => 'T', 'system' => 'metric' }
|
||||
},
|
||||
'volume' => {
|
||||
0.001 => { 'name' => 'mL', 'system' => 'metric' },
|
||||
1.0 => { 'name' => 'L', 'system' => 'metric' },
|
||||
1000.0 => { 'name' => 'kL', 'system' => 'metric' }
|
||||
}
|
||||
}
|
||||
|
||||
# Find the largest available unit where unit_value comes to >= 1 when expressed in it.
|
||||
# If there is none available where this is true, use the smallest available unit.
|
||||
unit = units[@variant.product.variant_unit].select { |scale, _unit_name|
|
||||
@variant.unit_value / scale >= 1
|
||||
}.to_a.last
|
||||
unit = units[@variant.product.variant_unit].first if unit.nil?
|
||||
scales = units[@variant.product.variant_unit]
|
||||
product_scale = @variant.product.variant_unit_scale
|
||||
product_scale_system = scales[product_scale.to_f]['system']
|
||||
|
||||
unit
|
||||
largest_unit = find_largest_unit(scales, product_scale_system)
|
||||
[largest_unit[0], largest_unit[1]["name"]]
|
||||
end
|
||||
|
||||
# Find the largest available and compatible unit where unit_value comes
|
||||
# to >= 1 when expressed in it.
|
||||
# If there is none available where this is true, use the smallest available unit.
|
||||
def find_largest_unit(scales, product_scale_system)
|
||||
largest_unit = scales.select { |scale, unit_info|
|
||||
unit_info['system'] == product_scale_system &&
|
||||
@variant.unit_value / scale >= 1
|
||||
}.max
|
||||
return scales.first if largest_unit.nil?
|
||||
|
||||
largest_unit
|
||||
end
|
||||
|
||||
def pluralize(unit_name, count)
|
||||
I18nInflections.pluralize(unit_name, count)
|
||||
OpenFoodNetwork::I18nInflections.pluralize(unit_name, count)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,9 +2,9 @@
|
||||
# It contains all of our logic for creating and naming option values (which are associated
|
||||
# with both models) and methods for printing human readable "names" for instances of these models.
|
||||
|
||||
require 'open_food_network/option_value_namer'
|
||||
require 'variant_units/option_value_namer'
|
||||
|
||||
module OpenFoodNetwork
|
||||
module VariantUnits
|
||||
module VariantAndLineItemNaming
|
||||
# Copied and modified from Spree::Variant
|
||||
def options_text
|
||||
@@ -18,7 +18,24 @@ module OpenFoodNetwork
|
||||
order("#{Spree::OptionType.table_name}.position asc")
|
||||
end
|
||||
|
||||
values.map(&:presentation).to_sentence(words_connector: ", ", two_words_connector: ", ")
|
||||
values.map { |option_value|
|
||||
presentation(option_value)
|
||||
}.to_sentence(words_connector: ", ", two_words_connector: ", ")
|
||||
end
|
||||
|
||||
def presentation(option_value)
|
||||
return option_value.presentation unless option_value.option_type.name == "unit_weight"
|
||||
|
||||
return display_as if has_attribute?(:display_as) && display_as.present?
|
||||
|
||||
return variant.display_as if variant_display_as?
|
||||
|
||||
option_value.presentation
|
||||
end
|
||||
|
||||
def variant_display_as?
|
||||
respond_to?(:variant) && variant.present? &&
|
||||
variant.respond_to?(:display_as) && variant.display_as.present?
|
||||
end
|
||||
|
||||
def product_and_full_name
|
||||
@@ -48,9 +65,11 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def unit_to_display
|
||||
return options_text if !has_attribute?(:display_as) || display_as.blank?
|
||||
return display_as if has_attribute?(:display_as) && display_as.present?
|
||||
|
||||
display_as
|
||||
return variant.display_as if variant_display_as?
|
||||
|
||||
options_text
|
||||
end
|
||||
|
||||
def update_units
|
||||
@@ -84,7 +103,7 @@ module OpenFoodNetwork
|
||||
if has_attribute?(:display_as) && display_as.present?
|
||||
display_as
|
||||
else
|
||||
option_value_namer = OpenFoodNetwork::OptionValueNamer.new self
|
||||
option_value_namer = VariantUnits::OptionValueNamer.new self
|
||||
option_value_namer.name
|
||||
end
|
||||
end
|
||||
@@ -31,3 +31,16 @@
|
||||
= f.label :invoice_text, t('.invoice_text')
|
||||
.omega.eight.columns
|
||||
= f.text_area :invoice_text, style: "width: 100%; height: 100px;"
|
||||
|
||||
.row
|
||||
.alpha.three.columns
|
||||
= f.label :terms_and_conditions, t('.terms_and_conditions')
|
||||
|
||||
.omega.eight.columns
|
||||
%a{ href: '{{ Enterprise.terms_and_conditions }}', ng: { if: 'Enterprise.terms_and_conditions' } }
|
||||
= '{{ Enterprise.terms_and_conditions_file_name }}'
|
||||
.pad-top
|
||||
= f.file_field :terms_and_conditions
|
||||
.pad-top
|
||||
%a.button.red{ href: '', ng: {click: 'removeTermsAndConditions()', if: 'Enterprise.terms_and_conditions'} }
|
||||
= t('.remove_terms_and_conditions')
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
%img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.logo.medium }}', if: 'Enterprise.logo' } }
|
||||
= f.file_field :logo
|
||||
%a.button.red{ href: '', ng: {click: 'removeLogo()', if: 'Enterprise.logo'} }
|
||||
= t('admin.enterprises.remove_logo.remove')
|
||||
= t('.remove_logo')
|
||||
|
||||
.row.page-admin-enterprises-form__promo-image-field-group.image-field-group
|
||||
.alpha.three.columns
|
||||
@@ -23,4 +23,4 @@
|
||||
%img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.promo_image.large }}', if: 'Enterprise.promo_image' } }
|
||||
= f.file_field :promo_image
|
||||
%a.button.red{ href: '', ng: {click: 'removePromoImage()', if: 'Enterprise.promo_image'} }
|
||||
= t('admin.enterprises.remove_promo_image.remove')
|
||||
= t('.remove_promo_image')
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
= render "checkout/shipping", f: f
|
||||
= render "checkout/payment", f: f
|
||||
= render "checkout/already_ordered", f: f if show_bought_items?
|
||||
= render "checkout/terms_and_conditions", f: f
|
||||
%p
|
||||
%button.button.primary{type: :submit}
|
||||
= t :checkout_send
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
"ng-class" => "{valid: payment.$valid, open: accordion.payment}"}
|
||||
= render 'checkout/accordion_heading'
|
||||
|
||||
-# TODO render this in Angular instead of server-side
|
||||
-# The problem being how to render the partials
|
||||
.row
|
||||
.small-12.medium-12.large-6.columns
|
||||
- available_payment_methods.each do |method|
|
||||
|
||||
2
app/views/checkout/_terms_and_conditions.html.haml
Normal file
2
app/views/checkout/_terms_and_conditions.html.haml
Normal file
@@ -0,0 +1,2 @@
|
||||
%p.small
|
||||
= t('.message_html', terms_and_conditions_link: link_to( t( '.link_text' ), current_order.distributor.terms_and_conditions.url, target: '_blank')) if current_order.distributor.terms_and_conditions.file?
|
||||
@@ -2,7 +2,6 @@
|
||||
.row
|
||||
.small-12.text-center.columns
|
||||
%h1
|
||||
/ TODO: Rohan - logo asset & width is content manageable:
|
||||
%img{src: image_path("logo-white-notext.png"), title: Spree::Config.site_name}
|
||||
%br/
|
||||
%a.button.transparent{href: "/shops"}
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
:javascript
|
||||
$(document).ready(function() {
|
||||
var in_iframe = function(){
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
var isInIframe = function(){
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
function() {
|
||||
var inIframe = isInIframe();
|
||||
var embedded_styles_active = $('body.off-canvas').hasClass('embedded');
|
||||
|
||||
var set_shopfront_styles = function (state) {
|
||||
$.ajax({
|
||||
url: '/embedded_shopfront/' + state,
|
||||
type: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
if (inIframe && !embedded_styles_active){
|
||||
$('body.off-canvas').addClass('embedded');
|
||||
set_shopfront_styles('enable');
|
||||
}
|
||||
};
|
||||
|
||||
var embedded_styles_active = $('body.off-canvas').hasClass('embedded');
|
||||
|
||||
var set_shopfront_styles = function(state) {
|
||||
$.ajax({
|
||||
url: '/embedded_shopfront/'+state,
|
||||
type: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
if (in_iframe() && !embedded_styles_active){
|
||||
$('body.off-canvas').addClass('embedded');
|
||||
set_shopfront_styles('enable');
|
||||
}
|
||||
|
||||
if (!in_iframe() && embedded_styles_active) {
|
||||
$('body.off-canvas').removeClass('embedded');
|
||||
set_shopfront_styles('disable');
|
||||
}
|
||||
});
|
||||
if (!inIframe && embedded_styles_active) {
|
||||
$('body.off-canvas').removeClass('embedded');
|
||||
set_shopfront_styles('disable');
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
= stylesheet_link_tag "darkswarm/all"
|
||||
= csrf_meta_tags
|
||||
|
||||
%body{class: body_classes, "body-scroll" => true , ng: {app: "Darkswarm"}}
|
||||
%body{ class: body_classes, "body-scroll" => true , ng: { app: 'Darkswarm' }}
|
||||
/ [if lte IE 8]
|
||||
= render partial: "shared/ie_warning"
|
||||
= javascript_include_tag "iehack"
|
||||
|
||||
= render "layouts/shopfront_script" if @shopfront_layout
|
||||
|
||||
.off-canvas-wrap{offcanvas: true}
|
||||
.off-canvas-wrap{ offcanvas: true }
|
||||
.fixed.off-canvas-fixed
|
||||
= render "shared/menu/menu" unless @hide_menu
|
||||
= yield :page_alert
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
= render partial: 'spree/shared/error_messages', locals: { target: @image }
|
||||
|
||||
- content_for :page_actions do
|
||||
%li= button_link_to t('spree.back_to_images_list'), admin_product_images_url(@product), icon: 'icon-arrow-left'
|
||||
%li= button_link_to t('spree.back_to_images_list'), admin_product_images_url(@product, @url_filters), icon: 'icon-arrow-left'
|
||||
|
||||
= form_for [:admin, @product, @image], html: { multipart: true } do |f|
|
||||
= form_for [:admin, @product, @image], url: admin_product_image_path(@product, @image, @url_filters), html: { multipart: true } do |f|
|
||||
%fieldset
|
||||
%legend{align: "center"}= @image.attachment_file_name
|
||||
.field.alpha.three.columns.align-center
|
||||
@@ -18,4 +18,4 @@
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to t('spree.actions.cancel'), admin_product_images_url(@product), id: 'cancel_link', class: 'button icon-remove'
|
||||
= link_to t('spree.actions.cancel'), admin_product_images_url(@product, @url_filters), id: 'cancel_link', class: 'button icon-remove'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
= render partial: 'spree/admin/shared/product_tabs', locals: { current: 'Images'}
|
||||
|
||||
- content_for :page_actions do
|
||||
%li= link_to_with_icon('icon-plus', t('spree.new_image'), new_admin_product_image_url(@product), id: 'new_image_link', class: 'button')
|
||||
%li= link_to_with_icon('icon-plus', t('spree.new_image'), new_admin_product_image_url(@product, @url_filters), id: 'new_image_link', class: 'button')
|
||||
|
||||
#images
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
= t('spree.no_images_found')
|
||||
\.
|
||||
- else
|
||||
%table.index.sortable{ "data-sortable-link" => "#{update_positions_admin_product_images_url(@product)}" }
|
||||
%table.index.sortable{ "data-sortable-link" => "#{update_positions_admin_product_images_url(@product, @url_filters)}" }
|
||||
%colgroup
|
||||
%col{ style: "width: 5%" }/
|
||||
%col{ style: "width: 10%" }/
|
||||
@@ -36,5 +36,5 @@
|
||||
%td= options_text_for(image)
|
||||
%td= image.alt
|
||||
%td.actions
|
||||
= link_to_with_icon 'icon-edit', t('spree.edit'), edit_admin_product_image_url(@product, image), no_text: true, data: { action: 'edit'}
|
||||
= link_to_delete image, { url: admin_product_image_url(@product, image), no_text: true }
|
||||
= link_to_with_icon 'icon-edit', t('spree.edit'), edit_admin_product_image_url(@product, image, @url_filters), no_text: true, data: { action: 'edit'}
|
||||
= link_to_delete image, { url: admin_product_image_url(@product, image, @url_filters), no_text: true }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
= form_for [:admin, @product, @image], html: { multipart: true } do |f|
|
||||
= form_for [:admin, @product, @image], url: admin_product_images_path(@product, @image, @url_filters), html: { multipart: true } do |f|
|
||||
%fieldset
|
||||
%legend{ align: "center" }= t('spree.new_image')
|
||||
= render partial: 'form', locals: { f: f }
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to_with_icon 'icon-remove', t('spree.actions.cancel'), admin_product_images_url(@product), id: 'cancel_link', class: 'button'
|
||||
= link_to_with_icon 'icon-remove', t('spree.actions.cancel'), admin_product_images_url(@product, @url_filters), id: 'cancel_link', class: 'button'
|
||||
|
||||
= javascript_include_tag 'admin/spree/images/new.js'
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
- if use_billing
|
||||
.field{style: "position: absolute;margin-top: -15px;right: 0;"}
|
||||
%span
|
||||
= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address))
|
||||
= label_tag 'order[use_billing]', Spree.t(:use_billing_address)
|
||||
|
||||
- is_shipping_address = name == Spree.t(:shipping_address)
|
||||
- s_or_b = is_shipping_address ? 's' : 'b'
|
||||
|
||||
- display_style = (use_billing && (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address == @order.ship_address)) ? 'none' : 'block'
|
||||
|
||||
%div{id: "#{is_shipping_address ? 'shipping' : 'billing'}", style: "display: #{display_style}"}
|
||||
%div{class: "field"}
|
||||
= f.label :firstname, Spree.t(:first_name) + ':'
|
||||
= f.text_field :firstname, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :lastname, Spree.t(:last_name) + ':'
|
||||
= f.text_field :lastname, class: 'fullwidth'
|
||||
- if Spree::Config[:company]
|
||||
%div{class: "field"}
|
||||
= f.label :company, Spree.t(:company) + ':'
|
||||
= f.text_field :company, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :address1, Spree.t(:street_address) + ':'
|
||||
= f.text_field :address1, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :address2, Spree.t(:street_address_2) + ':'
|
||||
= f.text_field :address2, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :city, Spree.t(:city) + ':'
|
||||
= f.text_field :city, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :zipcode, Spree.t(:zip) + ':'
|
||||
= f.text_field :zipcode, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :country_id, Spree.t(:country) + ':'
|
||||
%span{id: "#{s_or_b}country"}
|
||||
= f.collection_select :country_id, available_countries, :id, :name, {}, {class: 'select2 fullwidth', onchange: "update_state('#{s_or_b}')"}
|
||||
%div{class: "field"}
|
||||
= f.label :state_id, Spree.t(:state) + ':'
|
||||
%span{id: "#{s_or_b}state"}
|
||||
= f.collection_select :state_id, f.object.country.states.sort, :id, :name, {include_blank: true}, {class: 'select2 fullwidth', disabled: f.object.country.states.empty?}
|
||||
%div{class: "field"}
|
||||
= f.label :phone, Spree.t(:phone) + ':'
|
||||
= f.phone_field :phone, class: 'fullwidth'
|
||||
@@ -11,13 +11,13 @@
|
||||
%fieldset.no-border-bottom
|
||||
%legend{:align => "center"}= Spree.t(:billing_address)
|
||||
= f.fields_for :bill_address do |ba_form|
|
||||
= render :partial => 'spree/admin/shared/address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false }
|
||||
= render :partial => 'address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false }
|
||||
|
||||
.omega.six.columns{"data-hook" => "ship_address_wrapper"}
|
||||
%fieldset.no-border-bottom
|
||||
%legend{:align => "center"}= Spree.t(:shipping_address)
|
||||
= f.fields_for :ship_address do |sa_form|
|
||||
= render :partial => 'spree/admin/shared/address_form', :locals => { :f => sa_form, :name => Spree.t(:shipping_address), :use_billing => true }
|
||||
= render :partial => 'address_form', :locals => { :f => sa_form, :name => Spree.t(:shipping_address), :use_billing => true }
|
||||
|
||||
.clear
|
||||
|
||||
@@ -26,3 +26,4 @@
|
||||
|
||||
- content_for :head do
|
||||
= javascript_include_tag 'admin/spree/orders/address_states.js'
|
||||
= javascript_include_tag 'admin/spree/orders/use_billing.js'
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
%col{style: "width: 13%"}
|
||||
%col{style: "width: 14%"}
|
||||
%col{style: "width: 32%"}
|
||||
%col{style: "width: 14%"}
|
||||
- if spree_current_user.admin?
|
||||
%col{style: "width: 14%"}
|
||||
%col{style: "width: 8%"}
|
||||
%col{style: "width: 8%"}
|
||||
%col{style: "width: 11%"}
|
||||
@@ -20,7 +21,8 @@
|
||||
%th= t('.name')
|
||||
%th= t('.products_distributor')
|
||||
%th= t('.provider')
|
||||
%th= t('.environment')
|
||||
- if spree_current_user.admin?
|
||||
%th= t('.environment')
|
||||
%th= t('.display')
|
||||
%th= t('.active')
|
||||
%th.actions
|
||||
@@ -33,7 +35,8 @@
|
||||
= distributor.name
|
||||
%br/
|
||||
%td= method.class.clean_name
|
||||
%td.align-center= method.environment.to_s.titleize
|
||||
- if spree_current_user.admin?
|
||||
%td.align-center= method.environment.to_s.titleize
|
||||
%td.align-center= method.display_on.blank? ? t('.both') : t('.' + method.display_on.to_s)
|
||||
%td.align-center= method.active ? t('.active_yes') : t('.active_no')
|
||||
%td.actions
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
= f.text_field :value, class: 'autocomplete'
|
||||
%td.actions
|
||||
- if f.object.persisted?
|
||||
= link_to_delete f.object, no_text: true
|
||||
= link_to_delete f.object, { url: admin_product_product_property_url(@product, f.object, @url_filters), no_text: true }
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
%li
|
||||
= link_to_add_fields t('.add_product_properties'), 'tbody#product_properties', class: 'icon-plus button'
|
||||
|
||||
= form_for @product, url: admin_product_url(@product), method: :put do |f|
|
||||
= form_for @product, url: admin_product_url(@product, @url_filters), method: :put do |f|
|
||||
%fieldset.no-border-top
|
||||
.add_product_properties
|
||||
= image_tag 'select2-spinner.gif', plugin: 'spree', style: 'display:none;', id: 'busy_indicator'
|
||||
@@ -46,7 +46,10 @@
|
||||
%td.actions
|
||||
|
||||
|
||||
= render partial: 'spree/admin/shared/edit_resource_links'
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to t('spree.actions.cancel'), admin_product_product_properties_url(@product, @url_filters), id: 'cancel_link', class: 'button icon-remove'
|
||||
|
||||
= hidden_field_tag 'clear_product_properties', 'true'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
- content_for :page_actions do
|
||||
%li= button_link_to t('admin.products.back_to_products_list'), admin_products_path, :icon => 'icon-arrow-left'
|
||||
%li= button_link_to t('admin.products.back_to_products_list'), "#{admin_products_path}#{(@url_filters.empty? ? "" : "#?#{@url_filters.to_query}")}", :icon => 'icon-arrow-left'
|
||||
%li#new_product_link
|
||||
= button_link_to t(:new_product), new_object_url, { :icon => 'icon-plus', :id => 'admin_new_product' }
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => 'Product Details' }
|
||||
= render :partial => 'spree/shared/error_messages', :locals => { :target => @product }
|
||||
|
||||
= form_for [:admin, @product], :method => :put, :html => { :multipart => true } do |f|
|
||||
= form_for [:admin, @product], :url => admin_product_path(@product, @url_filters), :method => :put, :html => { :multipart => true } do |f|
|
||||
%fieldset.no-border-top{'ng-app' => 'admin.products'}
|
||||
= render :partial => 'form', :locals => { :f => f }
|
||||
= render :partial => 'spree/admin/shared/edit_resource_links'
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t(:update), 'icon-refresh'
|
||||
%span.or= t(:or)
|
||||
= button_link_to t(:cancel), "#{collection_url}#{(@url_filters.empty? ? "" : "#?#{@url_filters.to_query}")}", icon: 'icon-remove'
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
= render partial: 'spree/admin/shared/product_sub_menu'
|
||||
= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => 'Group Buy Options' }
|
||||
= render :partial => 'spree/shared/error_messages', :locals => { :target => @product }
|
||||
= render partial: 'spree/admin/shared/product_tabs', locals: { :current => 'Group Buy Options' }
|
||||
= render partial: 'spree/shared/error_messages', locals: { :target => @product }
|
||||
|
||||
= form_for [:admin, @product], :method => :put, :html => { :multipart => true } do |f|
|
||||
= form_for [:admin, @product], url: admin_product_url(@product, @url_filters), method: :put, html: { :multipart => true } do |f|
|
||||
%fieldset.no-border-top
|
||||
= render :partial => 'group_buy_form', :locals => { :f => f }
|
||||
= render :partial => 'spree/admin/shared/edit_resource_links'
|
||||
= render partial: 'group_buy_form', locals: { f: f }
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to t('spree.actions.cancel'), edit_admin_product_url(@product, @url_filters), id: 'cancel_link', class: 'button icon-remove'
|
||||
|
||||
@@ -5,22 +5,20 @@
|
||||
.quick_search.three.columns.alpha
|
||||
%label{ for: 'quick_filter' }
|
||||
%br
|
||||
%input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress" => "$event.keyCode === 13 && fetchProducts()" }
|
||||
%input.quick-search.fullwidth{ ng: {model: 'q.query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress" => "$event.keyCode === 13 && fetchProducts()" }
|
||||
.one.columns
|
||||
.filter_select.three.columns
|
||||
%label{ for: 'producer_filter' }= t 'producer'
|
||||
%br
|
||||
%select.fullwidth{ id: 'producer_filter', 'ofn-select2-min-search' => 5, ng: {model: 'producerFilter', options: 'producer.id as producer.name for producer in producers'} }
|
||||
%select.fullwidth{ id: 'producer_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.producerFilter', options: 'producer.id as producer.name for producer in producers'} }
|
||||
.filter_select.three.columns
|
||||
%label{ for: 'category_filter' }= t 'category'
|
||||
%br
|
||||
%select.fullwidth{ id: 'category_filter', 'ofn-select2-min-search' => 5, ng: {model: 'categoryFilter', options: 'taxon.id as taxon.name for taxon in taxons'} }
|
||||
%select.fullwidth{ id: 'category_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.categoryFilter', options: 'taxon.id as taxon.name for taxon in taxons'} }
|
||||
.filter_select.three.columns
|
||||
%label{ for: 'import_filter' } Import Date
|
||||
%br
|
||||
%select.fullwidth{ id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'importDateFilter', init: "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}"}}
|
||||
%option{value: "{{date.id}}", ng: {repeat: "date in importDates" }}
|
||||
{{date.name}}
|
||||
%select.fullwidth{ id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.importDateFilter', init: "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}", options: 'date.id as date.name for date in importDates'} }
|
||||
|
||||
.filter_clear.three.columns.omega
|
||||
%label{ for: 'clear_all_filters' }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user