mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-15 19:06:50 +00:00
Compare commits
287 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26cd0f4a9d | ||
|
|
17c2f7b138 | ||
|
|
70643a84b2 | ||
|
|
62a00b17a2 | ||
|
|
c4f96a1dcf | ||
|
|
6f4f3d42cc | ||
|
|
e8692fec4c | ||
|
|
3b2c10526d | ||
|
|
b1a274ea27 | ||
|
|
00c7b9986b | ||
|
|
25b11f1f4b | ||
|
|
22384cb4da | ||
|
|
9dc18afef0 | ||
|
|
d2d3d767ac | ||
|
|
a4ff74272b | ||
|
|
1000dc52bf | ||
|
|
54b8d22e0d | ||
|
|
7e00f78a77 | ||
|
|
5a9b5660f1 | ||
|
|
1d42ce885b | ||
|
|
17751c448f | ||
|
|
4b8d9d18d7 | ||
|
|
a21ef19529 | ||
|
|
ea80ae3832 | ||
|
|
bf26a26743 | ||
|
|
e3f840f48c | ||
|
|
42ca7888c0 | ||
|
|
8aa892136e | ||
|
|
2d21341183 | ||
|
|
5cabf59015 | ||
|
|
289dff5b91 | ||
|
|
c4e4beb912 | ||
|
|
27d8951add | ||
|
|
f7720f1b1f | ||
|
|
c46ae4354d | ||
|
|
5f00323cbb | ||
|
|
c52f29706b | ||
|
|
2590745b2e | ||
|
|
6db0421347 | ||
|
|
b63c47cca2 | ||
|
|
2b9f57f4e0 | ||
|
|
8a1de72542 | ||
|
|
2cb3a0cd99 | ||
|
|
b0637a24ff | ||
|
|
d969b68c8c | ||
|
|
a89d4266d5 | ||
|
|
4b8ced5fc0 | ||
|
|
2678342122 | ||
|
|
b33c819863 | ||
|
|
97d7e27786 | ||
|
|
e73e43838c | ||
|
|
cdc40fbc38 | ||
|
|
3430cc617a | ||
|
|
ed6f042446 | ||
|
|
80a8c436d6 | ||
|
|
049a87e8a9 | ||
|
|
deb5b8e74c | ||
|
|
a5dd14d902 | ||
|
|
9a6859edc0 | ||
|
|
c0c53113d3 | ||
|
|
26688409a1 | ||
|
|
0893d14025 | ||
|
|
efd314e3b1 | ||
|
|
bd7549c57f | ||
|
|
45cf54408d | ||
|
|
15360740b1 | ||
|
|
5ce5072f26 | ||
|
|
35133f7ee8 | ||
|
|
5becbc2a11 | ||
|
|
390d80f0eb | ||
|
|
6da43850d1 | ||
|
|
a146bdacc8 | ||
|
|
43cadb00c4 | ||
|
|
2e616a9e31 | ||
|
|
1927e2883e | ||
|
|
a4b94cf39f | ||
|
|
a35f3c130e | ||
|
|
a93243a8b7 | ||
|
|
de4402457a | ||
|
|
bf9f7309f7 | ||
|
|
4b0e1610ec | ||
|
|
0c6fe20e82 | ||
|
|
0f2e23d225 | ||
|
|
129de8fd57 | ||
|
|
e24d858af9 | ||
|
|
d2cacf5330 | ||
|
|
af231d2ebe | ||
|
|
711a3debe7 | ||
|
|
d09b0849e4 | ||
|
|
c639821dc3 | ||
|
|
d9b643d795 | ||
|
|
6b8b3be524 | ||
|
|
1db8283e98 | ||
|
|
5fce40ee71 | ||
|
|
c64493ca77 | ||
|
|
5b942e6933 | ||
|
|
ffbb5934d7 | ||
|
|
bae9df8214 | ||
|
|
5da47b3f19 | ||
|
|
b14e4237cc | ||
|
|
3e7685193f | ||
|
|
8558000c22 | ||
|
|
6486e5f908 | ||
|
|
9244a95472 | ||
|
|
bd237ef257 | ||
|
|
bc06e10146 | ||
|
|
05eadac935 | ||
|
|
5a83b12c66 | ||
|
|
71576fd7db | ||
|
|
63a1d4145a | ||
|
|
1049525e50 | ||
|
|
bd32510837 | ||
|
|
f0b40eea1e | ||
|
|
ed790ab65d | ||
|
|
46e23b28fd | ||
|
|
bc904a7afa | ||
|
|
8ccc8dfaf6 | ||
|
|
55b32c828c | ||
|
|
25dfd8ad40 | ||
|
|
2a5311493f | ||
|
|
57ac28cfbd | ||
|
|
fb02043e6e | ||
|
|
30d7cc89fa | ||
|
|
d14b5eb46b | ||
|
|
8eb60388fd | ||
|
|
633f1bd7cf | ||
|
|
933b5f1606 | ||
|
|
4c7b8209b9 | ||
|
|
802ac647e3 | ||
|
|
c83bded763 | ||
|
|
03246d425d | ||
|
|
7585e3d1d6 | ||
|
|
bc1430c984 | ||
|
|
676d949972 | ||
|
|
e4bd7c4e30 | ||
|
|
50cdda7c63 | ||
|
|
d0af046e59 | ||
|
|
5811f3ead1 | ||
|
|
d7d3c9ea53 | ||
|
|
a02cc1de34 | ||
|
|
94783f44f9 | ||
|
|
2184c7c06b | ||
|
|
928bf0d9c7 | ||
|
|
0d02b2afcf | ||
|
|
1e76f3f744 | ||
|
|
7c3a0a292f | ||
|
|
c5ca0976a5 | ||
|
|
be7b3d5a12 | ||
|
|
d3f498f5b1 | ||
|
|
55941a1206 | ||
|
|
6304a085c0 | ||
|
|
7c708de937 | ||
|
|
5d51e5d393 | ||
|
|
464717dec5 | ||
|
|
7a06018c3e | ||
|
|
b8c76ff633 | ||
|
|
1ecc0bfe07 | ||
|
|
600d2d23c8 | ||
|
|
bf3211fd01 | ||
|
|
5fd0d9406d | ||
|
|
c78a6bea91 | ||
|
|
be9f33312b | ||
|
|
f23575302b | ||
|
|
0042ab2f28 | ||
|
|
53a63775fe | ||
|
|
461b1b26f3 | ||
|
|
f13d7d6845 | ||
|
|
e4d09b5404 | ||
|
|
415415273c | ||
|
|
d969190ca5 | ||
|
|
a180576c0a | ||
|
|
7fdaa0f0c7 | ||
|
|
ba750547a2 | ||
|
|
af8369ae1b | ||
|
|
829a73c58d | ||
|
|
a2691df64e | ||
|
|
6c8b175344 | ||
|
|
ad10053271 | ||
|
|
a508c55700 | ||
|
|
2712be3fa4 | ||
|
|
484326561f | ||
|
|
7ea96f88e8 | ||
|
|
de752b05a7 | ||
|
|
0b18344572 | ||
|
|
690474c01a | ||
|
|
777754f8a9 | ||
|
|
e4c5893c1e | ||
|
|
67aeae4a6d | ||
|
|
02008769e9 | ||
|
|
65dd9f51cf | ||
|
|
a224c53200 | ||
|
|
66f07c0d1c | ||
|
|
d5287026f8 | ||
|
|
6b80eb2c16 | ||
|
|
b54b981740 | ||
|
|
895032fe6a | ||
|
|
531c385aae | ||
|
|
d0a3ab68f3 | ||
|
|
b5038c5745 | ||
|
|
6877485c90 | ||
|
|
95c1b7f7a6 | ||
|
|
3fcf286516 | ||
|
|
e2cdb01a28 | ||
|
|
08e729673f | ||
|
|
c0bf09131f | ||
|
|
19042e0d37 | ||
|
|
4b3b4e00ff | ||
|
|
e3ffe8fe6b | ||
|
|
d91578ab80 | ||
|
|
873dcc373f | ||
|
|
1289c3f1a2 | ||
|
|
c37218fdc5 | ||
|
|
dad21a52b2 | ||
|
|
97a65d760f | ||
|
|
63e92197f5 | ||
|
|
fd534bf629 | ||
|
|
64d83bfc4d | ||
|
|
83065a798e | ||
|
|
b661b3ee40 | ||
|
|
b528903aa8 | ||
|
|
38215c2a88 | ||
|
|
4c3916a93d | ||
|
|
677f31ffa8 | ||
|
|
5848a46149 | ||
|
|
6b6cdf07fb | ||
|
|
8432dab142 | ||
|
|
0b0263a605 | ||
|
|
51dd55c5b9 | ||
|
|
17ea2cd510 | ||
|
|
325c427219 | ||
|
|
a3e87d893a | ||
|
|
480a629349 | ||
|
|
03fac6f285 | ||
|
|
2108a282c8 | ||
|
|
404e7c1f37 | ||
|
|
47916f823f | ||
|
|
ab4add1954 | ||
|
|
10fff31dca | ||
|
|
7fb85092ce | ||
|
|
7584e96759 | ||
|
|
f8ab64d71e | ||
|
|
ccb4c77d1f | ||
|
|
5ef1510fc7 | ||
|
|
1afd712ff4 | ||
|
|
699110258b | ||
|
|
3fb1df9bb3 | ||
|
|
14c03ead31 | ||
|
|
4480c2f0f0 | ||
|
|
b3ac5d8f41 | ||
|
|
6fb74c88cd | ||
|
|
38fd028a9f | ||
|
|
4e84310d63 | ||
|
|
66440f9e4c | ||
|
|
b8457ebece | ||
|
|
668fd1c7c0 | ||
|
|
aff934c814 | ||
|
|
6bb04f6cc6 | ||
|
|
0e815439b3 | ||
|
|
c7b01c37af | ||
|
|
ac8f3c811f | ||
|
|
1b820ea85c | ||
|
|
ec7b91bb68 | ||
|
|
c773cde191 | ||
|
|
db1065a69e | ||
|
|
9fa4bad0b4 | ||
|
|
a52c4b542c | ||
|
|
283abf9a88 | ||
|
|
f691d1aafd | ||
|
|
5724c3bb0a | ||
|
|
06200c9d3c | ||
|
|
2412658e51 | ||
|
|
03fa3e2269 | ||
|
|
11fbe7d5c9 | ||
|
|
799c1f08de | ||
|
|
6b66458bfd | ||
|
|
3e0a5bac6a | ||
|
|
2c2023df03 | ||
|
|
7306d379a5 | ||
|
|
e15c61d862 | ||
|
|
1eba17f048 | ||
|
|
00e57c8a55 | ||
|
|
2e74e64e22 | ||
|
|
fc5d623465 | ||
|
|
3b399b899c | ||
|
|
01d69c89aa | ||
|
|
a2801e40a2 | ||
|
|
abd4f0b923 |
@@ -386,7 +386,6 @@ Metrics/AbcSize:
|
||||
- app/helpers/spree/admin/base_helper.rb
|
||||
- app/helpers/spree/admin/zones_helper.rb
|
||||
- app/helpers/spree/orders_helper.rb
|
||||
- app/jobs/subscription_placement_job.rb
|
||||
- app/mailers/producer_mailer.rb
|
||||
- app/models/calculator/flat_percent_per_item.rb
|
||||
- app/models/column_preference.rb
|
||||
@@ -413,6 +412,8 @@ Metrics/AbcSize:
|
||||
- app/services/create_order_cycle.rb
|
||||
- app/services/order_syncer.rb
|
||||
- app/services/subscription_validator.rb
|
||||
- lib/active_merchant/billing/gateways/stripe_decorator.rb
|
||||
- lib/active_merchant/billing/gateways/stripe_payment_intents.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/customers_report.rb
|
||||
@@ -506,6 +507,7 @@ Metrics/CyclomaticComplexity:
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/variant_override_set.rb
|
||||
- app/services/cart_service.rb
|
||||
- lib/active_merchant/billing/gateways/stripe_payment_intents.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/enterprise_issue_validator.rb
|
||||
@@ -531,6 +533,7 @@ Metrics/PerceivedComplexity:
|
||||
- app/models/spree/ability_decorator.rb
|
||||
- app/models/spree/order_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- lib/active_merchant/billing/gateways/stripe_payment_intents.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/enterprise_issue_validator.rb
|
||||
@@ -600,6 +603,7 @@ Metrics/MethodLength:
|
||||
- app/serializers/api/cached_enterprise_serializer.rb
|
||||
- app/services/order_cycle_form.rb
|
||||
- engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb
|
||||
- lib/active_merchant/billing/gateways/stripe_payment_intents.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/column_preference_defaults.rb
|
||||
@@ -663,6 +667,7 @@ Metrics/ClassLength:
|
||||
- app/serializers/api/enterprise_shopfront_serializer.rb
|
||||
- app/services/cart_service.rb
|
||||
- engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb
|
||||
- lib/active_merchant/billing/gateways/stripe_payment_intents.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/enterprise_fee_calculator.rb
|
||||
- lib/open_food_network/order_cycle_form_applicator.rb
|
||||
|
||||
@@ -117,6 +117,15 @@ Style/FormatString:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styleformatstring
|
||||
|
||||
Style/HashEachMethods:
|
||||
Enabled: false
|
||||
|
||||
Style/HashTransformKeys:
|
||||
Enabled: false
|
||||
|
||||
Style/HashTransformValues:
|
||||
Enabled: false
|
||||
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styleifunlessmodifier
|
||||
|
||||
@@ -681,7 +681,6 @@ Style/FrozenStringLiteralComment:
|
||||
- 'app/models/product_import/entry_validator.rb'
|
||||
- 'app/models/product_import/inventory_reset_strategy.rb'
|
||||
- 'app/models/product_import/product_importer.rb'
|
||||
- 'app/models/product_import/products_reset_strategy.rb'
|
||||
- 'app/models/product_import/reset_absent.rb'
|
||||
- 'app/models/product_import/settings.rb'
|
||||
- 'app/models/product_import/spreadsheet_data.rb'
|
||||
@@ -1257,7 +1256,6 @@ Style/FrozenStringLiteralComment:
|
||||
- 'spec/models/producer_property_spec.rb'
|
||||
- 'spec/models/product_import/entry_processor_spec.rb'
|
||||
- 'spec/models/product_import/inventory_reset_strategy_spec.rb'
|
||||
- 'spec/models/product_import/products_reset_strategy_spec.rb'
|
||||
- 'spec/models/product_import/reset_absent_spec.rb'
|
||||
- 'spec/models/product_import/settings_spec.rb'
|
||||
- 'spec/models/product_importer_spec.rb'
|
||||
|
||||
5
Gemfile
5
Gemfile
@@ -12,6 +12,7 @@ gem "activerecord-import"
|
||||
# Patched version. See http://rubysec.com/advisories/CVE-2015-5312/.
|
||||
gem 'nokogiri', '>= 1.6.7.1'
|
||||
|
||||
gem "catalog", path: "./engines/catalog"
|
||||
gem "order_management", path: "./engines/order_management"
|
||||
gem 'web', path: './engines/web'
|
||||
|
||||
@@ -114,7 +115,7 @@ gem "foundation-rails"
|
||||
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
|
||||
|
||||
gem 'jquery-migrate-rails'
|
||||
gem 'jquery-rails', '3.0.4'
|
||||
gem 'jquery-rails', '3.1.5'
|
||||
gem 'jquery-ui-rails', '~> 4.0.0'
|
||||
gem 'select2-rails', '~> 3.4.7'
|
||||
|
||||
@@ -166,5 +167,5 @@ group :development do
|
||||
# greater than 1.0.9, so we just required the latest available version here.
|
||||
gem 'eventmachine', '>= 1.2.3'
|
||||
|
||||
gem 'rack-mini-profiler', '< 2.0.0'
|
||||
gem 'rack-mini-profiler', '< 3.0.0'
|
||||
end
|
||||
|
||||
42
Gemfile.lock
42
Gemfile.lock
@@ -75,6 +75,11 @@ GIT
|
||||
activemodel (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
|
||||
PATH
|
||||
remote: engines/catalog
|
||||
specs:
|
||||
catalog (0.0.1)
|
||||
|
||||
PATH
|
||||
remote: engines/order_management
|
||||
specs:
|
||||
@@ -211,7 +216,7 @@ GEM
|
||||
activerecord (>= 3.2.0, < 5.0)
|
||||
fog (~> 1.0)
|
||||
rails (>= 3.2.0, < 5.0)
|
||||
ddtrace (0.32.0)
|
||||
ddtrace (0.33.1)
|
||||
msgpack
|
||||
debugger-linecache (1.2.0)
|
||||
deface (1.0.2)
|
||||
@@ -419,7 +424,7 @@ GEM
|
||||
gmaps4rails (1.5.6)
|
||||
haml (4.0.7)
|
||||
tilt
|
||||
hashdiff (1.0.0)
|
||||
hashdiff (1.0.1)
|
||||
highline (1.6.18)
|
||||
hike (1.2.3)
|
||||
httparty (0.16.2)
|
||||
@@ -433,7 +438,7 @@ GEM
|
||||
jaro_winkler (1.5.4)
|
||||
journey (1.0.4)
|
||||
jquery-migrate-rails (1.2.1)
|
||||
jquery-rails (3.0.4)
|
||||
jquery-rails (3.1.5)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (4.0.5)
|
||||
@@ -467,7 +472,7 @@ GEM
|
||||
railties (>= 3.1)
|
||||
money (5.1.1)
|
||||
i18n (~> 0.6.0)
|
||||
msgpack (1.3.1)
|
||||
msgpack (1.3.3)
|
||||
multi_json (1.14.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
@@ -480,7 +485,7 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
oj (3.10.2)
|
||||
oj (3.10.5)
|
||||
orm_adapter (0.5.0)
|
||||
paper_trail (5.2.3)
|
||||
activerecord (>= 3.0, < 6.0)
|
||||
@@ -494,7 +499,7 @@ GEM
|
||||
parallel (1.19.1)
|
||||
paranoia (1.3.4)
|
||||
activerecord (~> 3.1)
|
||||
parser (2.7.0.2)
|
||||
parser (2.7.0.4)
|
||||
ast (~> 2.4.0)
|
||||
paypal-sdk-core (0.2.10)
|
||||
multi_json (~> 1.0)
|
||||
@@ -516,9 +521,9 @@ GEM
|
||||
rabl (0.8.4)
|
||||
activesupport (>= 2.3.14)
|
||||
rack (1.4.7)
|
||||
rack-cache (1.9.0)
|
||||
rack-cache (1.11.0)
|
||||
rack (>= 0.4)
|
||||
rack-mini-profiler (1.1.6)
|
||||
rack-mini-profiler (2.0.1)
|
||||
rack (>= 1.2.0)
|
||||
rack-protection (1.5.5)
|
||||
rack
|
||||
@@ -548,7 +553,7 @@ GEM
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.19.1)
|
||||
rake (13.0.0)
|
||||
rake (13.0.1)
|
||||
ransack (0.7.2)
|
||||
actionpack (~> 3.0)
|
||||
activerecord (~> 3.0)
|
||||
@@ -580,15 +585,15 @@ GEM
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-core (3.9.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-core (3.9.1)
|
||||
rspec-support (~> 3.9.1)
|
||||
rspec-expectations (3.9.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-mocks (3.9.0)
|
||||
rspec-mocks (3.9.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rails (3.9.0)
|
||||
rspec-rails (3.9.1)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
@@ -598,8 +603,8 @@ GEM
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.9.0)
|
||||
rubocop (0.80.0)
|
||||
rspec-support (3.9.2)
|
||||
rubocop (0.80.1)
|
||||
jaro_winkler (~> 1.5.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.0.1)
|
||||
@@ -679,7 +684,7 @@ GEM
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (>= 1.3.0)
|
||||
selenium-webdriver (>= 3.0, < 4.0)
|
||||
webmock (3.8.2)
|
||||
webmock (3.8.3)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
@@ -711,6 +716,7 @@ DEPENDENCIES
|
||||
bugsnag
|
||||
byebug (~> 9.0.0)
|
||||
capybara (>= 2.18.0)
|
||||
catalog!
|
||||
coffee-rails (~> 3.2.1)
|
||||
combine_pdf
|
||||
compass-rails
|
||||
@@ -742,7 +748,7 @@ DEPENDENCIES
|
||||
i18n-js (~> 3.6.0)
|
||||
immigrant
|
||||
jquery-migrate-rails
|
||||
jquery-rails (= 3.0.4)
|
||||
jquery-rails (= 3.1.5)
|
||||
jquery-ui-rails (~> 4.0.0)
|
||||
json_spec (~> 1.1.4)
|
||||
jwt (~> 2.2)
|
||||
@@ -762,7 +768,7 @@ DEPENDENCIES
|
||||
pg (~> 0.21.0)
|
||||
pry-byebug (>= 3.4.3)
|
||||
rabl
|
||||
rack-mini-profiler (< 2.0.0)
|
||||
rack-mini-profiler (< 3.0.0)
|
||||
rack-rewrite
|
||||
rack-ssl
|
||||
rails (~> 3.2.22)
|
||||
|
||||
23
app/assets/images/black-caret.svg
Normal file
23
app/assets/images/black-caret.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 6 3"
|
||||
viewBox="0 0 6 3"
|
||||
height="3px"
|
||||
width="24px"
|
||||
y="0px"
|
||||
x="12px"
|
||||
version="1.1"><metadata
|
||||
id="metadata10"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs8" /><polygon
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
id="polygon2"
|
||||
points="5.992,0 2.992,3 -0.008,0 " /></svg>
|
||||
|
After Width: | Height: | Size: 832 B |
23
app/assets/images/white-caret.svg
Normal file
23
app/assets/images/white-caret.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 6 3"
|
||||
viewBox="0 0 6 3"
|
||||
height="3px"
|
||||
width="24px"
|
||||
y="0px"
|
||||
x="12px"
|
||||
version="1.1"><metadata
|
||||
id="metadata10"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs8" /><polygon
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
id="polygon2"
|
||||
points="5.992,0 2.992,3 -0.008,0 " /></svg>
|
||||
|
After Width: | Height: | Size: 832 B |
@@ -20,7 +20,6 @@
|
||||
//= require angular
|
||||
//= require angular-resource
|
||||
//= require angular-animate
|
||||
//= require angular-sanitize
|
||||
//= require angularjs-file-upload
|
||||
//= require ../shared/ng-infinite-scroll.min.js
|
||||
//= require ../shared/ng-tags-input.min.js
|
||||
@@ -67,6 +66,8 @@
|
||||
|
||||
// text, dates and translations
|
||||
//= require textAngular-rangy.min.js
|
||||
// This replaces angular-sanitize. We should include only one.
|
||||
// https://github.com/textAngular/textAngular#where-to-get-it
|
||||
//= require textAngular-sanitize.min.js
|
||||
//= require textAngular.min.js
|
||||
//= require i18n/translations
|
||||
|
||||
@@ -21,7 +21,7 @@ angular.module('admin.payments').factory 'Payment', (AdminStripeElements, curren
|
||||
year: @form_data.card_year
|
||||
verification_value: @form_data.card_verification_value
|
||||
}
|
||||
when 'stripe'
|
||||
when 'stripe', 'stripe_sca'
|
||||
angular.extend munged_payment.payment, {
|
||||
source_attributes:
|
||||
gateway_payment_profile_id: @form_data.token
|
||||
@@ -35,6 +35,8 @@ angular.module('admin.payments').factory 'Payment', (AdminStripeElements, curren
|
||||
purchase: ->
|
||||
if @paymentMethodType() == 'stripe'
|
||||
AdminStripeElements.requestToken(@form_data, @submit)
|
||||
else if @paymentMethodType() == 'stripe_sca'
|
||||
AdminStripeElements.createPaymentMethod(@form_data, @submit)
|
||||
else
|
||||
@submit()
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ angular.module("admin.payments").factory 'AdminStripeElements', ($rootScope, Sta
|
||||
stripe: null
|
||||
card: null
|
||||
|
||||
# New Stripe Elements method
|
||||
# Create Token to be used with the Stripe Charges API
|
||||
requestToken: (secrets, submit) ->
|
||||
return unless @stripe? && @card?
|
||||
|
||||
@@ -20,6 +20,21 @@ angular.module("admin.payments").factory 'AdminStripeElements', ($rootScope, Sta
|
||||
secrets.card = response.token.card
|
||||
submit()
|
||||
|
||||
# Create Payment Method to be used with the Stripe Payment Intents API
|
||||
createPaymentMethod: (secrets, submit) ->
|
||||
return unless @stripe? && @card?
|
||||
|
||||
cardData = @makeCardData(secrets)
|
||||
|
||||
@stripe.createPaymentMethod({ type: 'card', card: @card }, @card, cardData).then (response) =>
|
||||
if(response.error)
|
||||
StatusMessage.display 'error', response.error.message
|
||||
else
|
||||
secrets.token = response.paymentMethod.id
|
||||
secrets.cc_type = response.paymentMethod.card.brand
|
||||
secrets.card = response.paymentMethod.card
|
||||
submit()
|
||||
|
||||
# Maps the brand returned by Stripe to that required by activemerchant
|
||||
mapCC: (ccType) ->
|
||||
switch ccType
|
||||
|
||||
@@ -16,7 +16,7 @@ angular.module("admin.subscriptions").controller "DetailsController", ($scope, $
|
||||
return if !newValue?
|
||||
paymentMethod = ($scope.paymentMethods.filter (pm) -> pm.id == newValue)[0]
|
||||
return unless paymentMethod?
|
||||
$scope.cardRequired = (paymentMethod.type == "Spree::Gateway::StripeConnect")
|
||||
$scope.cardRequired = (paymentMethod.type == "Spree::Gateway::StripeConnect" || paymentMethod.type == "Spree::Gateway::StripeSCA")
|
||||
$scope.loadCustomer() if $scope.cardRequired && !$scope.customer
|
||||
|
||||
$scope.loadCustomer = ->
|
||||
|
||||
@@ -2,4 +2,10 @@ angular.module("admin.utils").directive "textangularStrip", () ->
|
||||
restrict: 'CA'
|
||||
link: (scope, element, attrs) ->
|
||||
scope.stripFormatting = ($html) ->
|
||||
return String($html).replace(/<[^>]+>/gm, '')
|
||||
element = document.createElement("div")
|
||||
element.innerHTML = String($html)
|
||||
allTags = element.getElementsByTagName("*")
|
||||
for child in allTags
|
||||
child.removeAttribute("style")
|
||||
child.removeAttribute("class")
|
||||
return element.innerHTML
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
||||
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// the compiled file.
|
||||
//
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require_tree .
|
||||
@@ -0,0 +1,17 @@
|
||||
Darkswarm.controller "PageSelectionCtrl", ($scope, $location) ->
|
||||
$scope.selectedPage = ->
|
||||
# The path looks like `/contact` for the URL `https://ofn.org/shop#/contact`.
|
||||
# We remove the slash at the beginning.
|
||||
page = $location.path()[1..]
|
||||
|
||||
return $scope.whitelist[0] unless page
|
||||
|
||||
# If the path points to an unrelated path like `/login`, stay where we were.
|
||||
return $scope.lastPage unless page in $scope.whitelist
|
||||
|
||||
$scope.lastPage = page
|
||||
page
|
||||
|
||||
$scope.whitelistPages = (pages) ->
|
||||
$scope.whitelist = pages
|
||||
$scope.lastPage = pages[0]
|
||||
@@ -7,6 +7,8 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeE
|
||||
purchase: ->
|
||||
if @paymentMethod()?.method_type == 'stripe' && !@secrets.selected_card
|
||||
StripeElements.requestToken(@secrets, @submit)
|
||||
else if @paymentMethod()?.method_type == 'stripe_sca' && !@secrets.selected_card
|
||||
StripeElements.createPaymentMethod(@secrets, @submit)
|
||||
else
|
||||
@submit()
|
||||
|
||||
@@ -59,7 +61,7 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeE
|
||||
last_name: @order.bill_address.lastname
|
||||
}
|
||||
|
||||
if @paymentMethod()?.method_type == 'stripe'
|
||||
if @paymentMethod()?.method_type == 'stripe' || @paymentMethod()?.method_type == 'stripe_sca'
|
||||
if @secrets.selected_card
|
||||
angular.extend munged_order, {
|
||||
existing_card_id: @secrets.selected_card
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
|
||||
new class StripeElements
|
||||
# TODO: add locale here for translations of error messages etc. from Stripe
|
||||
|
||||
# These are both set from the StripeElements directive
|
||||
stripe: null
|
||||
card: null
|
||||
|
||||
# New Stripe Elements method
|
||||
# Create Token to be used with the Stripe Charges API
|
||||
requestToken: (secrets, submit, loading_message = t("processing_payment")) ->
|
||||
return unless @stripe? && @card?
|
||||
|
||||
@@ -23,6 +21,23 @@ Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
|
||||
secrets.card = response.token.card
|
||||
submit()
|
||||
|
||||
# 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
|
||||
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}"})
|
||||
else
|
||||
secrets.token = response.paymentMethod.id
|
||||
secrets.cc_type = response.paymentMethod.card.brand
|
||||
secrets.card = response.paymentMethod.card
|
||||
submit()
|
||||
|
||||
# Maps the brand returned by Stripe to that required by activemerchant
|
||||
mapCC: (ccType) ->
|
||||
switch ccType
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
/*
|
||||
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
||||
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||
*= require_self
|
||||
*= require_tree .
|
||||
*/
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.darkswarm navigation {
|
||||
display: block;
|
||||
background: #f7f7f7;
|
||||
background: $white;
|
||||
|
||||
distributor.details {
|
||||
box-sizing: border-box;
|
||||
@@ -10,9 +10,11 @@
|
||||
min-height: 150px;
|
||||
padding: 30px 0 20px 0;
|
||||
position: relative;
|
||||
|
||||
select {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
height: 100px;
|
||||
@@ -31,72 +33,158 @@
|
||||
|
||||
#distributor_title h3 {
|
||||
margin-top: 0;
|
||||
padding-top: 0.45em;
|
||||
|
||||
@media all and (max-width: 768px) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ordercycle {
|
||||
float: right;
|
||||
background: $teal-400;
|
||||
color: $white;
|
||||
width: 100%;
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
padding: 1em;
|
||||
margin-top: 3em;
|
||||
height: 7.6em;
|
||||
|
||||
&.requires-selection {
|
||||
background-color: $red-700;
|
||||
|
||||
ordercycle {
|
||||
text-align: right;
|
||||
float: right;
|
||||
p {
|
||||
max-width: 400px;
|
||||
.order-cycle-select {
|
||||
border: 1px solid $red-500;
|
||||
|
||||
.select-label {
|
||||
background-color: rgba($red-500, 0.5);
|
||||
}
|
||||
h4 i {
|
||||
margin-right: 0.3rem;
|
||||
|
||||
select {
|
||||
background-color: $white;
|
||||
background-image: url('/assets/black-caret.svg');
|
||||
color: $grey-500;
|
||||
font-style: italic;
|
||||
}
|
||||
@media all and (max-width: 640px) {
|
||||
float: left;
|
||||
clear: left;
|
||||
text-align: left;
|
||||
padding: 12px 10px;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
background: #e5e5e5;
|
||||
p {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
form.custom {
|
||||
text-align: right;
|
||||
& > strong {
|
||||
line-height: 2.5;
|
||||
font-size: 1.29em;
|
||||
padding-right: 14px;
|
||||
}
|
||||
select {
|
||||
width: inherit;
|
||||
display: inline-block;
|
||||
border: 1px #999;
|
||||
color: #666;
|
||||
font-size: 1em;
|
||||
margin-bottom: 0;
|
||||
padding: 8px 20px 8px 12px;
|
||||
@media all and (max-width: 768px) {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
@media screen and (-webkit-min-device-pixel-ratio: 0) {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
closing {
|
||||
@include headingFont;
|
||||
color: black;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
h4 i {
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
@media all and (max-width: 1024px) {
|
||||
float: none;
|
||||
padding: 0.5em 1em;
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
display: inline-block;
|
||||
border-radius: 0;
|
||||
position: relative;
|
||||
right: 0;
|
||||
height: auto;
|
||||
|
||||
p {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 768px) {
|
||||
padding: 0.5em 1em 0.75em;
|
||||
}
|
||||
|
||||
form.custom {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.order-cycle-select {
|
||||
border: 1px solid $teal-300;
|
||||
display: inline-block;
|
||||
font-size: 1em;
|
||||
border-radius: 0.25em;
|
||||
|
||||
.select-label {
|
||||
background-color: rgba($teal-300, 0.5);
|
||||
display: inline-block;
|
||||
border-radius: 0.25em 0 0 0.25em;
|
||||
float: left;
|
||||
font-size: 1em;
|
||||
line-height: 1.5em;
|
||||
padding: 0.5em 0.75em;
|
||||
height: 2.35em;
|
||||
|
||||
span {
|
||||
width: max-content;
|
||||
display: block;
|
||||
padding-bottom: 12px;
|
||||
@media all and (max-width: 768px) {
|
||||
font-size: 1.2em;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
span {
|
||||
@media all and (max-width: 768px) {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
width: inherit;
|
||||
display: inline-block;
|
||||
color: $white;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: 1em;
|
||||
line-height: 1.5em;
|
||||
padding: 0.5em 1.25em 0.5em 0.75em;
|
||||
height: 2.35em;
|
||||
background-image: url('/assets/white-caret.svg');
|
||||
background-size: 30px auto;
|
||||
border-radius: 0 0.25em 0.25em 0;
|
||||
min-width: 13em;
|
||||
|
||||
@media all and (max-width: 480px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 1024px) {
|
||||
float: none;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
@media all and (max-width: 768px) {
|
||||
float: none;
|
||||
}
|
||||
|
||||
@media all and (max-width: 480px) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
closing {
|
||||
@include headingFont;
|
||||
color: $white;
|
||||
font-size: 1.25rem;
|
||||
display: block;
|
||||
padding: 0 0 12px;
|
||||
|
||||
@media all and (max-width: 1024px) {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
padding: 0.2em 0 0;
|
||||
font-size: 1.2em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
@media all and (max-width: 768px) {
|
||||
float: none;
|
||||
padding: 0 0 10px;
|
||||
}
|
||||
|
||||
span {
|
||||
@media all and (max-width: 768px) {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,3 +38,25 @@ $light-grey: #ddd;
|
||||
$light-grey-transparency: rgba(0, 0, 0, .1);
|
||||
$black: #000;
|
||||
$white: #fff;
|
||||
|
||||
$grey-400: #bbb;
|
||||
$grey-500: #999;
|
||||
$grey-600: #777;
|
||||
$grey-700: #555;
|
||||
$grey-800: #333;
|
||||
|
||||
$teal-300: #80d3df;
|
||||
$teal-400: #4cb5c5;
|
||||
$teal-500: #0096ad;
|
||||
|
||||
$orange-400: #ff9466;
|
||||
$orange-500: #f27052;
|
||||
$orange-600: #d7583a;
|
||||
|
||||
$red-500: #e54e47;
|
||||
$red-700: #c1122b;
|
||||
|
||||
$social-facebook: #3b5998;
|
||||
$social-instagram: #e1306c;
|
||||
$social-linkedin: #0e76a8;
|
||||
$social-twitter: #00acee;
|
||||
|
||||
@@ -111,6 +111,22 @@
|
||||
|
||||
i {
|
||||
font-size: 2rem;
|
||||
|
||||
&.facebook {
|
||||
color: $social-facebook;
|
||||
}
|
||||
|
||||
&.twitter {
|
||||
color: $social-twitter;
|
||||
}
|
||||
|
||||
&.linkedin {
|
||||
color: $social-linkedin;
|
||||
}
|
||||
|
||||
&.instagram {
|
||||
color: $social-instagram;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
@@ -3,22 +3,27 @@
|
||||
@import "branding";
|
||||
|
||||
// Tabs styling
|
||||
.tabset-ctrl#shop-tabs {
|
||||
#shop-tabs {
|
||||
|
||||
.tab-buttons {
|
||||
background: url("/assets/gray_jean.png") top left repeat;
|
||||
|
||||
@include box-shadow(inset 0 2px 3px 0 rgba(0, 0, 0, 0.15));
|
||||
|
||||
color: $dark-grey;
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.05), 0 8px 6px -6px rgba(0, 0, 0, 0.2);
|
||||
|
||||
.row:first-child {
|
||||
.columns {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@media all and (max-width: 1024px) {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media all and (max-width: 480px) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
.page {
|
||||
text-align: center;
|
||||
border-top: 4px solid transparent;
|
||||
display: inline-block;
|
||||
@@ -27,8 +32,7 @@
|
||||
>a {
|
||||
outline: none;
|
||||
display: block;
|
||||
background-color: #efefef;
|
||||
color: #222;
|
||||
color: $grey-500;
|
||||
font-family: "Oswald", sans-serif;
|
||||
}
|
||||
|
||||
@@ -39,12 +43,11 @@
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
font-size: 0.875em;
|
||||
text-shadow: 0 -1px 1px #ffffff;
|
||||
padding: 1em 2em;
|
||||
border: none;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
color: $clr-brick-bright;
|
||||
&:hover, &:active {
|
||||
color: $teal-500;
|
||||
}
|
||||
|
||||
&, &:hover {
|
||||
@@ -53,29 +56,41 @@
|
||||
|
||||
@media all and (max-width: 640px) {
|
||||
padding: 0.35em 0 0.65em 0;
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-bottom: 4px solid $clr-brick;
|
||||
border-bottom: 4px solid $teal-500;
|
||||
|
||||
a {
|
||||
color: $clr-brick;
|
||||
color: $teal-500;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 1024px) {
|
||||
display: table-cell;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// content revealed in accordion
|
||||
|
||||
.tab-view {
|
||||
.page-view {
|
||||
margin-bottom: 5em;
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
.content {
|
||||
padding: 1.25em 0;
|
||||
background-color: $white;
|
||||
background-color: transparent;
|
||||
|
||||
a {
|
||||
color: $orange-500;
|
||||
|
||||
&:hover {
|
||||
color: $orange-600;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
margin: 0px 0px 0px 40px;
|
||||
@@ -83,6 +98,7 @@
|
||||
|
||||
h5 {
|
||||
margin-bottom: 1em;
|
||||
font-family: $body-font;
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -100,13 +116,9 @@
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
color: $dark-grey;
|
||||
border-bottom: 1px solid $disabled-dark;
|
||||
color: $grey-600;
|
||||
margin-top: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
|
||||
$headingFont: "Oswald";
|
||||
$bodyFont: "Roboto";
|
||||
$body-font: "Roboto", Arial, sans-serif;
|
||||
|
||||
body {
|
||||
@include bodyFont;
|
||||
@@ -43,7 +43,7 @@ small, .small {
|
||||
.text-small {
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-family: $bodyFont;
|
||||
font-family: $body-font;
|
||||
|
||||
&, & * {
|
||||
font-size: 0.875rem;
|
||||
@@ -52,12 +52,12 @@ small, .small {
|
||||
|
||||
.text-normal {
|
||||
font-weight: 400;
|
||||
font-family: $bodyFont;
|
||||
font-family: $body-font;
|
||||
}
|
||||
|
||||
.text-skinny {
|
||||
font-weight: 300;
|
||||
font-family: $bodyFont;
|
||||
font-family: $body-font;
|
||||
}
|
||||
|
||||
.word-wrap {
|
||||
@@ -114,9 +114,9 @@ ul.bullet-list, ul.check-list {
|
||||
}
|
||||
|
||||
li:before {
|
||||
content: "";
|
||||
content: "•";
|
||||
font-family: "OFN";
|
||||
margin-left: -1.25em;
|
||||
margin: 0 0.25em 0 -1.25em;
|
||||
display: inline-block;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@include border-radius(0.5em);
|
||||
|
||||
font-family: $bodyFont;
|
||||
font-family: $body-font;
|
||||
background-color: transparent;
|
||||
border: 2px solid rgba(200, 200, 200, 1);
|
||||
color: #999;
|
||||
@@ -63,7 +63,7 @@
|
||||
}
|
||||
|
||||
.button.primary, button.primary {
|
||||
font-family: $bodyFont;
|
||||
font-family: $body-font;
|
||||
background: $clr-brick;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ module Admin
|
||||
before_filter :setup_property, only: [:edit]
|
||||
|
||||
helper 'spree/products'
|
||||
include ActionView::Helpers::TextHelper
|
||||
include OrderCyclesHelper
|
||||
|
||||
def index
|
||||
@@ -77,19 +76,12 @@ module Admin
|
||||
|
||||
def bulk_update
|
||||
@enterprise_set = EnterpriseSet.new(collection, params[:enterprise_set])
|
||||
touched_enterprises = @enterprise_set.collection.select(&:changed?)
|
||||
if @enterprise_set.save
|
||||
flash[:success] = I18n.t(:enterprise_bulk_update_success_notice)
|
||||
|
||||
# 18-3-2015: It seems that the form for this action sometimes loads bogus values for
|
||||
# the 'sells' field, and submitting that form results in a bunch of enterprises with
|
||||
# values that have mysteriously changed. This statement is here to help debug that
|
||||
# issue, and should be removed (along with its display in index.html.haml) when the
|
||||
# issue has been resolved.
|
||||
flash[:action] = "#{I18n.t(:updated)} #{pluralize(touched_enterprises.count, 'enterprise')}: #{touched_enterprises.map(&:name).join(', ')}"
|
||||
|
||||
redirect_to main_app.admin_enterprises_path
|
||||
else
|
||||
touched_enterprises = @enterprise_set.collection.select(&:changed?)
|
||||
@enterprise_set.collection.select! { |e| touched_enterprises.include? e }
|
||||
flash[:error] = I18n.t(:enterprise_bulk_update_error)
|
||||
render :index
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
require 'open_food_network/referer_parser'
|
||||
require 'spree/authentication_helpers'
|
||||
require_dependency 'spree/authentication_helpers'
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
@@ -35,6 +35,8 @@ class CheckoutController < Spree::StoreController
|
||||
rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error
|
||||
|
||||
def edit
|
||||
return handle_redirect_from_stripe if valid_payment_intent_provided?
|
||||
|
||||
# This is only required because of spree_paypal_express. If we implement
|
||||
# a version of paypal that uses this controller, and more specifically
|
||||
# the #update_failed method, then we can remove this call
|
||||
@@ -151,6 +153,23 @@ class CheckoutController < Spree::StoreController
|
||||
end
|
||||
end
|
||||
|
||||
def valid_payment_intent_provided?
|
||||
params["payment_intent"]&.starts_with?("pi_") &&
|
||||
@order.state == "payment" &&
|
||||
@order.payments.last.state == "pending" &&
|
||||
@order.payments.last.response_code == params["payment_intent"]
|
||||
end
|
||||
|
||||
def handle_redirect_from_stripe
|
||||
if advance_order_state(@order) && order_complete?
|
||||
checkout_succeeded
|
||||
redirect_to(order_path(@order)) && return
|
||||
else
|
||||
flash[:error] = order_workflow_error
|
||||
checkout_failed
|
||||
end
|
||||
end
|
||||
|
||||
def checkout_workflow(shipping_method_id)
|
||||
while @order.state != "complete"
|
||||
if @order.state == "payment"
|
||||
@@ -165,11 +184,12 @@ class CheckoutController < Spree::StoreController
|
||||
return update_failed
|
||||
end
|
||||
|
||||
update_result
|
||||
update_response
|
||||
end
|
||||
|
||||
def redirect_to_payment_gateway
|
||||
redirect_path = Checkout::PaymentRedirect.new(params).path
|
||||
redirect_path = Checkout::PaypalRedirect.new(params).path
|
||||
redirect_path = Checkout::StripeRedirect.new(params, @order).path if redirect_path.blank?
|
||||
return if redirect_path.blank?
|
||||
|
||||
render json: { path: redirect_path }, status: :ok
|
||||
@@ -193,27 +213,27 @@ class CheckoutController < Spree::StoreController
|
||||
end
|
||||
end
|
||||
|
||||
def update_result
|
||||
if @order.state == "complete" || @order.completed?
|
||||
save_order_addresses_as_user_default
|
||||
ResetOrderService.new(self, current_order).call
|
||||
|
||||
update_succeeded
|
||||
def update_response
|
||||
if order_complete?
|
||||
checkout_succeeded
|
||||
update_succeeded_response
|
||||
else
|
||||
update_failed
|
||||
end
|
||||
end
|
||||
|
||||
def save_order_addresses_as_user_default
|
||||
user_default_address_setter = UserDefaultAddressSetter.new(@order, spree_current_user)
|
||||
user_default_address_setter.set_default_bill_address if params[:order][:default_bill_address]
|
||||
user_default_address_setter.set_default_ship_address if params[:order][:default_ship_address]
|
||||
def order_complete?
|
||||
@order.state == "complete" || @order.completed?
|
||||
end
|
||||
|
||||
def update_succeeded
|
||||
def checkout_succeeded
|
||||
Checkout::PostCheckoutActions.new(@order).success(self, params, spree_current_user)
|
||||
|
||||
session[:access_token] = current_order.token
|
||||
flash[:notice] = t(:order_processed_successfully)
|
||||
end
|
||||
|
||||
def update_succeeded_response
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
respond_with(@order, location: order_path(@order))
|
||||
@@ -225,9 +245,15 @@ class CheckoutController < Spree::StoreController
|
||||
end
|
||||
|
||||
def update_failed
|
||||
current_order.updater.shipping_address_from_distributor
|
||||
RestartCheckout.new(@order).call
|
||||
checkout_failed
|
||||
update_failed_response
|
||||
end
|
||||
|
||||
def checkout_failed
|
||||
Checkout::PostCheckoutActions.new(@order).failure
|
||||
end
|
||||
|
||||
def update_failed_response
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
render :edit
|
||||
|
||||
@@ -63,8 +63,6 @@ class EnterprisesController < BaseController
|
||||
end
|
||||
|
||||
def reset_order
|
||||
distributor = Enterprise.is_distributor.find_by_permalink(params[:id]) ||
|
||||
Enterprise.is_distributor.find(params[:id])
|
||||
order = current_order(true)
|
||||
|
||||
reset_distributor(order, distributor)
|
||||
@@ -74,6 +72,14 @@ class EnterprisesController < BaseController
|
||||
reset_order_cycle(order, distributor)
|
||||
|
||||
order.save!
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
flash[:error] = I18n.t(:enterprise_shop_show_error)
|
||||
redirect_to shops_path
|
||||
end
|
||||
|
||||
def distributor
|
||||
@distributor ||= Enterprise.is_distributor.find_by_permalink(params[:id]) ||
|
||||
Enterprise.is_distributor.find(params[:id])
|
||||
end
|
||||
|
||||
def reset_distributor(order, distributor)
|
||||
|
||||
@@ -110,7 +110,7 @@ module Spree
|
||||
else
|
||||
Gateway.providers.reject{ |p| p.name.include? "Bogus" }.sort_by(&:name)
|
||||
end
|
||||
@providers.reject!{ |p| p.name.ends_with? "StripeConnect" } unless show_stripe?
|
||||
@providers.reject!{ |provider| stripe_provider?(provider) } unless show_stripe?
|
||||
@calculators = PaymentMethod.calculators.sort_by(&:name)
|
||||
end
|
||||
|
||||
@@ -134,12 +134,12 @@ module Spree
|
||||
# current payment_method is already a Stripe method
|
||||
def show_stripe?
|
||||
Spree::Config.stripe_connect_enabled ||
|
||||
@payment_method.try(:type) == "Spree::Gateway::StripeConnect"
|
||||
stripe_payment_method?
|
||||
end
|
||||
|
||||
def restrict_stripe_account_change
|
||||
return unless @payment_method
|
||||
return unless @payment_method.type == "Spree::Gateway::StripeConnect"
|
||||
return unless stripe_payment_method?
|
||||
return unless @payment_method.preferred_enterprise_id.andand > 0
|
||||
|
||||
@stripe_account_holder = Enterprise.find(@payment_method.preferred_enterprise_id)
|
||||
@@ -147,6 +147,15 @@ module Spree
|
||||
|
||||
params[:payment_method][:preferred_enterprise_id] = @stripe_account_holder.id
|
||||
end
|
||||
|
||||
def stripe_payment_method?
|
||||
["Spree::Gateway::StripeConnect",
|
||||
"Spree::Gateway::StripeSCA"].include? @payment_method.try(:type)
|
||||
end
|
||||
|
||||
def stripe_provider?(provider)
|
||||
provider.name.ends_with?("StripeConnect", "StripeSCA")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -59,7 +59,7 @@ module Spree
|
||||
@collection ||= if @deleted.blank?
|
||||
super
|
||||
else
|
||||
Variant.where(product_id: parent.id).deleted
|
||||
Variant.unscoped.where(product_id: parent.id).deleted
|
||||
end
|
||||
@collection
|
||||
end
|
||||
|
||||
@@ -10,10 +10,14 @@ module Spree
|
||||
render json: @credit_card, serializer: ::Api::CreditCardSerializer, status: :ok
|
||||
else
|
||||
message = t(:card_could_not_be_saved)
|
||||
render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout, error: message) } }, status: :bad_request
|
||||
render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout,
|
||||
error: message) } },
|
||||
status: :bad_request
|
||||
end
|
||||
rescue Stripe::CardError => e
|
||||
render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout, error: e.message) } }, status: :bad_request
|
||||
render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout,
|
||||
error: e.message) } },
|
||||
status: :bad_request
|
||||
end
|
||||
|
||||
def update
|
||||
@@ -52,12 +56,20 @@ module Spree
|
||||
|
||||
private
|
||||
|
||||
# Currently can only destroy the whole customer object
|
||||
# It destroys the whole customer object
|
||||
def destroy_at_stripe
|
||||
stripe_customer = Stripe::Customer.retrieve(@credit_card.gateway_customer_profile_id)
|
||||
stripe_customer = Stripe::Customer.retrieve(@credit_card.gateway_customer_profile_id, {})
|
||||
|
||||
stripe_customer.delete if stripe_customer
|
||||
end
|
||||
|
||||
def stripe_account_id
|
||||
StripeAccount.
|
||||
find_by_enterprise_id(@credit_card.payment_method.preferred_enterprise_id).
|
||||
andand.
|
||||
stripe_user_id
|
||||
end
|
||||
|
||||
def create_customer(token)
|
||||
Stripe::Customer.create(email: spree_current_user.email, source: token)
|
||||
end
|
||||
|
||||
@@ -16,4 +16,8 @@ module SharedHelper
|
||||
def admin_user?
|
||||
spree_current_user.andand.has_spree_role? 'admin'
|
||||
end
|
||||
|
||||
def current_shop_products_path
|
||||
"#{main_app.enterprise_shop_path(current_distributor)}#/shop"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,6 +8,10 @@ module ShopHelper
|
||||
end
|
||||
end
|
||||
|
||||
def oc_select_options
|
||||
@order_cycles.map { |oc| { time: pickup_time(oc), id: oc.id } }
|
||||
end
|
||||
|
||||
def require_customer?
|
||||
current_distributor.require_login? && !user_is_related_to_distributor?
|
||||
end
|
||||
@@ -31,6 +35,10 @@ module ShopHelper
|
||||
].select{ |tab| tab[:show] }
|
||||
end
|
||||
|
||||
def shop_tab_names
|
||||
shop_tabs.map { |tab| tab[:name] }
|
||||
end
|
||||
|
||||
def show_home_tab?
|
||||
require_customer? || current_distributor.preferred_shopfront_message.present?
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ class SubscriptionConfirmJob
|
||||
ids = proxy_orders.pluck(:id)
|
||||
proxy_orders.update_all(confirmed_at: Time.zone.now)
|
||||
ProxyOrder.where(id: ids).each do |proxy_order|
|
||||
Rails.logger.info "Confirming Order for Proxy Order #{proxy_order.id}"
|
||||
@order = proxy_order.order
|
||||
process!
|
||||
end
|
||||
|
||||
@@ -5,8 +5,7 @@ class SubscriptionPlacementJob
|
||||
ids = proxy_orders.pluck(:id)
|
||||
proxy_orders.update_all(placed_at: Time.zone.now)
|
||||
ProxyOrder.where(id: ids).each do |proxy_order|
|
||||
proxy_order.initialise_order!
|
||||
process(proxy_order.order)
|
||||
place_order_for(proxy_order)
|
||||
end
|
||||
|
||||
send_placement_summary_emails
|
||||
@@ -28,16 +27,18 @@ class SubscriptionPlacementJob
|
||||
.joins(:subscription).merge(Subscription.not_canceled.not_paused)
|
||||
end
|
||||
|
||||
def process(order)
|
||||
def place_order_for(proxy_order)
|
||||
Rails.logger.info "Placing Order for Proxy Order #{proxy_order.id}"
|
||||
proxy_order.initialise_order!
|
||||
place_order(proxy_order.order)
|
||||
end
|
||||
|
||||
def place_order(order)
|
||||
record_order(order)
|
||||
return record_issue(:complete, order) if order.completed?
|
||||
|
||||
changes = cap_quantity_and_store_changes(order)
|
||||
if order.line_items.where('quantity > 0').empty?
|
||||
order.reload.adjustments.destroy_all
|
||||
order.update!
|
||||
return send_empty_email(order, changes)
|
||||
end
|
||||
return handle_empty_order(order, changes) if order.line_items.where('quantity > 0').empty?
|
||||
|
||||
move_to_completion(order)
|
||||
send_placement_email(order, changes)
|
||||
@@ -58,12 +59,18 @@ class SubscriptionPlacementJob
|
||||
changes
|
||||
end
|
||||
|
||||
def handle_empty_order(order, changes)
|
||||
order.reload.adjustments.destroy_all
|
||||
order.update!
|
||||
send_empty_email(order, changes)
|
||||
end
|
||||
|
||||
def move_to_completion(order)
|
||||
AdvanceOrderService.new(order).call!
|
||||
end
|
||||
|
||||
def unavailable_stock_lines_for(order)
|
||||
order.line_items.where('variant_id NOT IN (?)', available_variants_for(order))
|
||||
order.line_items.where('variant_id NOT IN (?)', available_variants_for(order).select(&:id))
|
||||
end
|
||||
|
||||
def available_variants_for(order)
|
||||
|
||||
@@ -321,7 +321,7 @@ class Enterprise < ActiveRecord::Base
|
||||
def distributed_taxons
|
||||
Spree::Taxon.
|
||||
joins(:products).
|
||||
where('spree_products.id IN (?)', Spree::Product.in_distributor(self)).
|
||||
where('spree_products.id IN (?)', Spree::Product.in_distributor(self).select(&:id)).
|
||||
select('DISTINCT spree_taxons.*')
|
||||
end
|
||||
|
||||
@@ -337,7 +337,7 @@ class Enterprise < ActiveRecord::Base
|
||||
def supplied_taxons
|
||||
Spree::Taxon.
|
||||
joins(:products).
|
||||
where('spree_products.id IN (?)', Spree::Product.in_supplier(self)).
|
||||
where('spree_products.id IN (?)', Spree::Product.in_supplier(self).select(&:id)).
|
||||
select('DISTINCT spree_taxons.*')
|
||||
end
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class EnterpriseFee < ActiveRecord::Base
|
||||
if user.has_spree_role?('admin')
|
||||
scoped
|
||||
else
|
||||
where('enterprise_id IN (?)', user.enterprises)
|
||||
where('enterprise_id IN (?)', user.enterprises.select(&:id))
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class EnterpriseRelationship < ActiveRecord::Base
|
||||
}
|
||||
|
||||
scope :involving_enterprises, ->(enterprises) {
|
||||
where('parent_id IN (?) OR child_id IN (?)', enterprises, enterprises)
|
||||
where('parent_id IN (?) OR child_id IN (?)', enterprises.select(&:id), enterprises.select(&:id))
|
||||
}
|
||||
|
||||
scope :permitting, ->(enterprise_ids) { where('child_id IN (?)', enterprise_ids) }
|
||||
|
||||
@@ -49,7 +49,7 @@ class Exchange < ActiveRecord::Base
|
||||
}
|
||||
scope :with_product, lambda { |product|
|
||||
joins(:exchange_variants).
|
||||
where('exchange_variants.variant_id IN (?)', product.variants_including_master)
|
||||
where('exchange_variants.variant_id IN (?)', product.variants_including_master.select(&:id))
|
||||
}
|
||||
scope :by_enterprise_name, -> {
|
||||
joins('INNER JOIN enterprises AS sender ON (sender.id = exchanges.sender_id)').
|
||||
|
||||
@@ -17,6 +17,7 @@ class OrderCycle < ActiveRecord::Base
|
||||
has_many :distributors, source: :receiver, through: :cached_outgoing_exchanges, uniq: true
|
||||
|
||||
has_and_belongs_to_many :schedules, join_table: 'order_cycle_schedules'
|
||||
has_paper_trail meta: { custom_data: :schedule_ids }
|
||||
|
||||
attr_accessor :incoming_exchanges, :outgoing_exchanges
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ module ProductImport
|
||||
if settings.importing_into_inventory?
|
||||
InventoryResetStrategy
|
||||
else
|
||||
ProductsResetStrategy
|
||||
Catalog::ProductImport::ProductsResetStrategy
|
||||
end
|
||||
end
|
||||
|
||||
@@ -122,7 +122,6 @@ module ProductImport
|
||||
|
||||
def save_new_inventory_item(entry)
|
||||
new_item = entry.product_object
|
||||
assign_defaults(new_item, entry)
|
||||
new_item.import_date = @import_time
|
||||
|
||||
if new_item.valid? && new_item.save
|
||||
@@ -136,7 +135,6 @@ module ProductImport
|
||||
|
||||
def save_existing_inventory_item(entry)
|
||||
existing_item = entry.product_object
|
||||
assign_defaults(existing_item, entry)
|
||||
existing_item.import_date = @import_time
|
||||
|
||||
if existing_item.valid? && existing_item.save
|
||||
@@ -164,7 +162,6 @@ module ProductImport
|
||||
product = Spree::Product.new
|
||||
product.assign_attributes(entry.attributes.except('id', 'on_hand', 'on_demand'))
|
||||
product.supplier_id = entry.producer_id
|
||||
assign_defaults(product, entry)
|
||||
|
||||
if product.save
|
||||
ensure_variant_updated(product, entry)
|
||||
@@ -179,7 +176,6 @@ module ProductImport
|
||||
|
||||
def save_variant(entry)
|
||||
variant = entry.product_object
|
||||
assign_defaults(variant, entry)
|
||||
variant.import_date = @import_time
|
||||
|
||||
if variant.valid? && variant.save
|
||||
@@ -199,37 +195,6 @@ module ProductImport
|
||||
)
|
||||
end
|
||||
|
||||
def assign_defaults(object, entry)
|
||||
# Assigns a default value for a specified field e.g. category='Vegetables', setting this value
|
||||
# either for all entries (overwrite_all), or only for those entries where the field was blank
|
||||
# in the spreadsheet (overwrite_empty), depending on selected import settings
|
||||
return unless settings.defaults(entry)
|
||||
|
||||
settings.defaults(entry).each do |attribute, setting|
|
||||
next unless setting['active']
|
||||
|
||||
case setting['mode']
|
||||
when 'overwrite_all'
|
||||
object.assign_attributes(attribute => setting['value'])
|
||||
# In case of new products, some attributes are saved on the variant.
|
||||
# We write them to the entry here to be copied to the variant later.
|
||||
if entry.respond_to? "#{attribute}="
|
||||
entry.public_send("#{attribute}=", setting['value'])
|
||||
end
|
||||
when 'overwrite_empty'
|
||||
if object.public_send(attribute).blank? ||
|
||||
((attribute == 'on_hand') &&
|
||||
entry.on_hand_nil)
|
||||
|
||||
object.assign_attributes(attribute => setting['value'])
|
||||
if entry.respond_to? "#{attribute}="
|
||||
entry.public_send("#{attribute}=", setting['value'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def display_in_inventory(variant_override, is_new = false)
|
||||
unless is_new
|
||||
existing_item = InventoryItem.where(
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
module ProductImport
|
||||
class ProductsResetStrategy
|
||||
def initialize(excluded_items_ids)
|
||||
@excluded_items_ids = excluded_items_ids
|
||||
end
|
||||
|
||||
def reset(enterprise_ids)
|
||||
@enterprise_ids = enterprise_ids
|
||||
|
||||
return 0 if enterprise_ids.blank?
|
||||
|
||||
reset_variants_on_hand(enterprise_variants_relation)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :excluded_items_ids, :enterprise_ids
|
||||
|
||||
def enterprise_variants_relation
|
||||
relation = Spree::Variant
|
||||
.joins(:product)
|
||||
.where(
|
||||
spree_products: { supplier_id: enterprise_ids },
|
||||
spree_variants: { is_master: false, deleted_at: nil }
|
||||
)
|
||||
|
||||
return relation if excluded_items_ids.blank?
|
||||
|
||||
relation.where('spree_variants.id NOT IN (?)', excluded_items_ids)
|
||||
end
|
||||
|
||||
def reset_variants_on_hand(variants)
|
||||
updated_records_count = 0
|
||||
variants.each do |variant|
|
||||
updated_records_count += 1 if reset_variant_on_hand(variant)
|
||||
end
|
||||
updated_records_count
|
||||
end
|
||||
|
||||
def reset_variant_on_hand(variant)
|
||||
variant.on_hand = 0
|
||||
variant.on_hand.zero?
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,7 @@
|
||||
class Schedule < ActiveRecord::Base
|
||||
has_and_belongs_to_many :order_cycles, join_table: 'order_cycle_schedules'
|
||||
has_paper_trail meta: { custom_data: :order_cycle_ids }
|
||||
|
||||
has_many :coordinators, uniq: true, through: :order_cycles
|
||||
|
||||
attr_accessible :name, :order_cycle_ids
|
||||
|
||||
@@ -13,14 +13,15 @@ module Spree
|
||||
def compute(object = nil)
|
||||
return 0 if object.nil?
|
||||
|
||||
preferred_amount * line_items_for(object).reduce(0) do |sum, value|
|
||||
value_to_add = if matching_products.blank? || matching_products.include?(value.product)
|
||||
value.quantity
|
||||
number_of_line_items = line_items_for(object).reduce(0) do |sum, line_item|
|
||||
value_to_add = if matching_products.blank? || matching_products.include?(line_item.product)
|
||||
line_item.quantity
|
||||
else
|
||||
0
|
||||
end
|
||||
sum + value_to_add
|
||||
end
|
||||
preferred_amount * number_of_line_items
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,12 +9,6 @@ module Spree
|
||||
|
||||
attr_accessible :preferred_enterprise_id
|
||||
|
||||
CARD_TYPE_MAPPING = {
|
||||
'American Express' => 'american_express',
|
||||
'Diners Club' => 'diners_club',
|
||||
'Visa' => 'visa'
|
||||
}.freeze
|
||||
|
||||
def method_type
|
||||
'stripe'
|
||||
end
|
||||
@@ -77,11 +71,6 @@ module Spree
|
||||
[money, creditcard, options]
|
||||
end
|
||||
|
||||
def update_source!(source)
|
||||
source.cc_type = CARD_TYPE_MAPPING[source.cc_type] if CARD_TYPE_MAPPING.include?(source.cc_type)
|
||||
source
|
||||
end
|
||||
|
||||
def token_from_card_profile_ids(creditcard)
|
||||
token_or_card_id = creditcard.gateway_payment_profile_id
|
||||
customer = creditcard.gateway_customer_profile_id
|
||||
|
||||
139
app/models/spree/gateway/stripe_sca.rb
Normal file
139
app/models/spree/gateway/stripe_sca.rb
Normal file
@@ -0,0 +1,139 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'stripe/profile_storer'
|
||||
require 'stripe/credit_card_cloner'
|
||||
require 'stripe/authorize_response_patcher'
|
||||
require 'stripe/payment_intent_validator'
|
||||
require 'active_merchant/billing/gateways/stripe_payment_intents'
|
||||
require 'active_merchant/billing/gateways/stripe_decorator'
|
||||
|
||||
module Spree
|
||||
class Gateway
|
||||
class StripeSCA < Gateway
|
||||
preference :enterprise_id, :integer
|
||||
|
||||
validate :ensure_enterprise_selected
|
||||
|
||||
attr_accessible :preferred_enterprise_id
|
||||
|
||||
def method_type
|
||||
'stripe_sca'
|
||||
end
|
||||
|
||||
def provider_class
|
||||
ActiveMerchant::Billing::StripePaymentIntentsGateway
|
||||
end
|
||||
|
||||
def payment_profiles_supported?
|
||||
true
|
||||
end
|
||||
|
||||
def stripe_account_id
|
||||
StripeAccount.find_by_enterprise_id(preferred_enterprise_id).andand.stripe_user_id
|
||||
end
|
||||
|
||||
# NOTE: the name of this method is determined by Spree::Payment::Processing
|
||||
def purchase(money, creditcard, gateway_options)
|
||||
begin
|
||||
payment_intent_id = fetch_payment_intent(creditcard, gateway_options)
|
||||
rescue Stripe::StripeError => e
|
||||
return failed_activemerchant_billing_response(e.message)
|
||||
end
|
||||
|
||||
options = basic_options(gateway_options)
|
||||
options[:customer] = creditcard.gateway_customer_profile_id
|
||||
provider.capture(money, payment_intent_id, options)
|
||||
rescue Stripe::StripeError => e
|
||||
failed_activemerchant_billing_response(e.message)
|
||||
end
|
||||
|
||||
# NOTE: the name of this method is determined by Spree::Payment::Processing
|
||||
def authorize(money, creditcard, gateway_options)
|
||||
authorize_response = provider.authorize(*options_for_authorize(money,
|
||||
creditcard,
|
||||
gateway_options))
|
||||
Stripe::AuthorizeResponsePatcher.new(authorize_response).call!
|
||||
rescue Stripe::StripeError => e
|
||||
failed_activemerchant_billing_response(e.message)
|
||||
end
|
||||
|
||||
# NOTE: the name of this method is determined by Spree::Payment::Processing
|
||||
def void(response_code, _creditcard, gateway_options)
|
||||
gateway_options[:stripe_account] = stripe_account_id
|
||||
provider.void(response_code, gateway_options)
|
||||
end
|
||||
|
||||
# NOTE: the name of this method is determined by Spree::Payment::Processing
|
||||
def credit(money, _creditcard, response_code, gateway_options)
|
||||
gateway_options[:stripe_account] = stripe_account_id
|
||||
provider.refund(money, response_code, gateway_options)
|
||||
end
|
||||
|
||||
def create_profile(payment)
|
||||
return unless payment.source.gateway_customer_profile_id.nil?
|
||||
|
||||
profile_storer = Stripe::ProfileStorer.new(payment, provider)
|
||||
profile_storer.create_customer_from_token
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# In this gateway, what we call 'secret_key' is the 'login'
|
||||
def options
|
||||
options = super
|
||||
options.merge(login: Stripe.api_key)
|
||||
end
|
||||
|
||||
def basic_options(gateway_options)
|
||||
options = {}
|
||||
options[:description] = "Spree Order ID: #{gateway_options[:order_id]}"
|
||||
options[:currency] = gateway_options[:currency]
|
||||
options[:stripe_account] = stripe_account_id
|
||||
options
|
||||
end
|
||||
|
||||
def options_for_authorize(money, creditcard, gateway_options)
|
||||
options = basic_options(gateway_options)
|
||||
options[:return_url] = full_checkout_path
|
||||
|
||||
customer_id, payment_method_id = Stripe::CreditCardCloner.new.clone(creditcard,
|
||||
stripe_account_id)
|
||||
options[:customer] = customer_id
|
||||
[money, payment_method_id, options]
|
||||
end
|
||||
|
||||
def fetch_payment_intent(creditcard, gateway_options)
|
||||
payment = fetch_payment(creditcard, gateway_options)
|
||||
raise Stripe::StripeError, I18n.t(:no_pending_payments) unless payment&.response_code
|
||||
|
||||
Stripe::PaymentIntentValidator.new.call(payment.response_code, stripe_account_id)
|
||||
end
|
||||
|
||||
def fetch_payment(creditcard, gateway_options)
|
||||
order_number = gateway_options[:order_id].split('-').first
|
||||
|
||||
Spree::Order.find_by_number(order_number).payments.merge(creditcard.payments).last
|
||||
end
|
||||
|
||||
def failed_activemerchant_billing_response(error_message)
|
||||
ActiveMerchant::Billing::Response.new(false, error_message)
|
||||
end
|
||||
|
||||
def ensure_enterprise_selected
|
||||
return if preferred_enterprise_id.andand.positive?
|
||||
|
||||
errors.add(:stripe_account_owner, I18n.t(:error_required))
|
||||
end
|
||||
|
||||
def full_checkout_path
|
||||
URI.join(url_helpers.root_url, url_helpers.checkout_path).to_s
|
||||
end
|
||||
|
||||
def url_helpers
|
||||
# This is how we can get the helpers with a usable root_url outside the controllers
|
||||
Rails.application.routes.default_url_options = ActionMailer::Base.default_url_options
|
||||
Rails.application.routes.url_helpers
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -56,7 +56,9 @@ Spree::Order.class_eval do
|
||||
# Find orders that are distributed by the user or have products supplied by the user
|
||||
# WARNING: This only filters orders, you'll need to filter line items separately using LineItem.managed_by
|
||||
with_line_items_variants_and_products_outer.
|
||||
where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)', user.enterprises, user.enterprises).
|
||||
where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)',
|
||||
user.enterprises.select(&:id),
|
||||
user.enterprises.select(&:id)).
|
||||
select('DISTINCT spree_orders.*')
|
||||
end
|
||||
}
|
||||
@@ -65,7 +67,7 @@ Spree::Order.class_eval do
|
||||
if user.has_spree_role?('admin')
|
||||
scoped
|
||||
else
|
||||
where('spree_orders.distributor_id IN (?)', user.enterprises)
|
||||
where('spree_orders.distributor_id IN (?)', user.enterprises.select(&:id))
|
||||
end
|
||||
}
|
||||
|
||||
@@ -115,6 +117,12 @@ Spree::Order.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
# "Checkout" is the initial state and, for card payments, "pending" is the state after authorization
|
||||
# These are both valid states to process the payment
|
||||
def pending_payments
|
||||
(payments.select(&:pending?) + payments.select(&:processing?) + payments.select(&:checkout?)).uniq
|
||||
end
|
||||
|
||||
def remove_variant(variant)
|
||||
line_items(:reload)
|
||||
current_item = find_line_item_by_variant(variant)
|
||||
|
||||
@@ -20,7 +20,7 @@ Spree::PaymentMethod.class_eval do
|
||||
scoped
|
||||
else
|
||||
joins(:distributors).
|
||||
where('distributors_payment_methods.distributor_id IN (?)', user.enterprises).
|
||||
where('distributors_payment_methods.distributor_id IN (?)', user.enterprises.select(&:id)).
|
||||
select('DISTINCT spree_payment_methods.*')
|
||||
end
|
||||
}
|
||||
@@ -68,6 +68,8 @@ Spree::PaymentMethod.class_eval do
|
||||
"Pin Payments"
|
||||
when "Spree::Gateway::StripeConnect"
|
||||
"Stripe"
|
||||
when "Spree::Gateway::StripeSCA"
|
||||
"Stripe SCA"
|
||||
when "Spree::Gateway::PayPalExpress"
|
||||
"PayPal Express"
|
||||
else
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Spree::ProductSet < ModelSet
|
||||
def initialize(attributes = {})
|
||||
super(Spree::Product, [], attributes, proc { |attrs| attrs[:product_id].blank? })
|
||||
super(Spree::Product, [], attributes)
|
||||
end
|
||||
|
||||
def save
|
||||
@@ -34,11 +34,9 @@ class Spree::ProductSet < ModelSet
|
||||
split_taxon_ids!(attributes)
|
||||
|
||||
product = find_model(@collection, attributes[:id])
|
||||
if product.nil?
|
||||
@klass.new(attributes).save unless @reject_if.andand.call(attributes)
|
||||
else
|
||||
update_product(product, attributes)
|
||||
end
|
||||
return if product.nil?
|
||||
|
||||
update_product(product, attributes)
|
||||
end
|
||||
|
||||
def split_taxon_ids!(attributes)
|
||||
|
||||
@@ -15,7 +15,7 @@ Spree::ShippingMethod.class_eval do
|
||||
scoped
|
||||
else
|
||||
joins(:distributors).
|
||||
where('distributors_shipping_methods.distributor_id IN (?)', user.enterprises).
|
||||
where('distributors_shipping_methods.distributor_id IN (?)', user.enterprises.select(&:id)).
|
||||
select('DISTINCT spree_shipping_methods.*')
|
||||
end
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
module Spree
|
||||
TaxRate.class_eval do
|
||||
class << self
|
||||
def match_with_sales_tax_registration(order)
|
||||
def match(order)
|
||||
return [] if order.distributor && !order.distributor.charges_sales_tax
|
||||
return [] unless order.tax_zone
|
||||
|
||||
match_without_sales_tax_registration(order)
|
||||
all.select do |rate|
|
||||
rate.zone == order.tax_zone || rate.zone.contains?(order.tax_zone) || rate.zone.default_tax
|
||||
end
|
||||
end
|
||||
alias_method_chain :match, :sales_tax_registration
|
||||
end
|
||||
|
||||
def adjust_with_included_tax(order)
|
||||
|
||||
@@ -49,7 +49,7 @@ Spree::Variant.class_eval do
|
||||
}
|
||||
|
||||
scope :for_distribution, lambda { |order_cycle, distributor|
|
||||
where('spree_variants.id IN (?)', order_cycle.variants_distributed_by(distributor))
|
||||
where('spree_variants.id IN (?)', order_cycle.variants_distributed_by(distributor).select(&:id))
|
||||
}
|
||||
|
||||
scope :visible_for, lambda { |enterprise|
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
class Subscription < ActiveRecord::Base
|
||||
ALLOWED_PAYMENT_METHOD_TYPES = ["Spree::PaymentMethod::Check", "Spree::Gateway::StripeConnect"].freeze
|
||||
ALLOWED_PAYMENT_METHOD_TYPES = ["Spree::PaymentMethod::Check",
|
||||
"Spree::Gateway::StripeConnect",
|
||||
"Spree::Gateway::StripeSCA"].freeze
|
||||
|
||||
belongs_to :shop, class_name: 'Enterprise'
|
||||
belongs_to :customer
|
||||
|
||||
@@ -4,7 +4,8 @@ module Api
|
||||
delegate :serializable_hash, to: :method_serializer
|
||||
|
||||
def method_serializer
|
||||
if object.type == 'Spree::Gateway::StripeConnect'
|
||||
if object.type == 'Spree::Gateway::StripeConnect' ||
|
||||
object.type == 'Spree::Gateway::StripeSCA'
|
||||
Api::Admin::PaymentMethod::StripeSerializer.new(object)
|
||||
else
|
||||
Api::Admin::PaymentMethod::BaseSerializer.new(object)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Provides the redirect path if a redirect to the payment gateway is needed
|
||||
module Checkout
|
||||
class PaymentRedirect
|
||||
class PaypalRedirect
|
||||
def initialize(params)
|
||||
@params = params
|
||||
end
|
||||
30
app/services/checkout/post_checkout_actions.rb
Normal file
30
app/services/checkout/post_checkout_actions.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Executes actions after checkout
|
||||
module Checkout
|
||||
class PostCheckoutActions
|
||||
def initialize(order)
|
||||
@order = order
|
||||
end
|
||||
|
||||
def success(controller, params, current_user)
|
||||
save_order_addresses_as_user_default(params, current_user)
|
||||
ResetOrderService.new(controller, @order).call
|
||||
end
|
||||
|
||||
def failure
|
||||
@order.updater.shipping_address_from_distributor
|
||||
RestartCheckout.new(@order).call
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def save_order_addresses_as_user_default(params, current_user)
|
||||
return unless params[:order]
|
||||
|
||||
user_default_address_setter = UserDefaultAddressSetter.new(@order, current_user)
|
||||
user_default_address_setter.set_default_bill_address if params[:order][:default_bill_address]
|
||||
user_default_address_setter.set_default_ship_address if params[:order][:default_ship_address]
|
||||
end
|
||||
end
|
||||
end
|
||||
46
app/services/checkout/stripe_redirect.rb
Normal file
46
app/services/checkout/stripe_redirect.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides the redirect path if a redirect to the payment gateway is needed
|
||||
module Checkout
|
||||
class StripeRedirect
|
||||
def initialize(params, order)
|
||||
@params = params
|
||||
@order = order
|
||||
end
|
||||
|
||||
# Returns the path to the authentication form if a redirect is needed
|
||||
def path
|
||||
return unless stripe_payment_method?
|
||||
|
||||
payment = @order.pending_payments.last
|
||||
return unless payment&.checkout?
|
||||
|
||||
payment.authorize!
|
||||
raise unless payment.pending?
|
||||
|
||||
field_with_url(payment) if url?(field_with_url(payment))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def stripe_payment_method?
|
||||
return unless @params[:order][:payments_attributes]
|
||||
|
||||
payment_method_id = @params[:order][:payments_attributes].first[:payment_method_id]
|
||||
payment_method = Spree::PaymentMethod.find(payment_method_id)
|
||||
payment_method.is_a?(Spree::Gateway::StripeSCA)
|
||||
end
|
||||
|
||||
def url?(string)
|
||||
return false if string.blank?
|
||||
|
||||
string.starts_with?("http")
|
||||
end
|
||||
|
||||
# Stripe::AuthorizeResponsePatcher patches the Stripe authorization response
|
||||
# so that this field stores the redirect URL
|
||||
def field_with_url(payment)
|
||||
payment.cvv_response_message
|
||||
end
|
||||
end
|
||||
end
|
||||
14
app/services/order_payment_finder.rb
Normal file
14
app/services/order_payment_finder.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module OrderPaymentFinder
|
||||
def self.last_payment_method(order)
|
||||
# `max_by` avoids additional database queries when payments are loaded
|
||||
# already. There is usually only one payment and this shouldn't cause
|
||||
# any overhead compared to `order(:created_at).last`. Using `last`
|
||||
# without order is not deterministic.
|
||||
#
|
||||
# We are not using `updated_at` because all payments are touched when the
|
||||
# order is updated and then all payments have the same `updated_at` value.
|
||||
order.payments.max_by(&:created_at)&.payment_method
|
||||
end
|
||||
end
|
||||
@@ -82,13 +82,18 @@ class SubscriptionValidator
|
||||
|
||||
def credit_card_ok?
|
||||
return unless customer && payment_method
|
||||
return unless payment_method.type == "Spree::Gateway::StripeConnect"
|
||||
return unless stripe_payment_method?(payment_method)
|
||||
return errors.add(:payment_method, :charges_not_allowed) unless customer.allow_charges
|
||||
return if customer.user.andand.default_card.present?
|
||||
|
||||
errors.add(:payment_method, :no_default_card)
|
||||
end
|
||||
|
||||
def stripe_payment_method?(payment_method)
|
||||
payment_method.type == "Spree::Gateway::StripeConnect" ||
|
||||
payment_method.type == "Spree::Gateway::StripeSCA"
|
||||
end
|
||||
|
||||
def subscription_line_items_present?
|
||||
return if subscription_line_items.reject(&:marked_for_destruction?).any?
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
-# For purposes of debugging bulk_update. See Admin/Enterprises#bulk_update.
|
||||
- if flash[:action]
|
||||
%p= flash[:action]
|
||||
|
||||
= form_for @enterprise_set, url: main_app.bulk_update_admin_enterprises_path do |f|
|
||||
%table#listing_enterprises.index
|
||||
%colgroup
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.three.columns.alpha
|
||||
= f.label "enterprise_preferred_shopfront_message", t('.shopfront_message')
|
||||
.eight.columns.omega
|
||||
%text-angular{'ng-model' => 'Enterprise.preferred_shopfront_message', 'id' => 'enterprise_preferred_shopfront_message', 'name' => 'enterprise[preferred_shopfront_message]', 'class' => 'text-angular', "textangular-links-target-blank" => true,
|
||||
%text-angular{'ng-model' => 'Enterprise.preferred_shopfront_message', 'id' => 'enterprise_preferred_shopfront_message', 'name' => 'enterprise[preferred_shopfront_message]', 'class' => 'text-angular textangular-strip', 'ta-paste' => "stripFormatting($html)", "textangular-links-target-blank" => true,
|
||||
'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]",
|
||||
'placeholder' => t('.shopfront_message_placeholder')}
|
||||
.row
|
||||
@@ -11,7 +11,7 @@
|
||||
.three.columns.alpha
|
||||
= f.label "enterprise_preferred_shopfront_closed_message", t('.shopfront_closed_message')
|
||||
.eight.columns.omega
|
||||
%text-angular{'ng-model' => 'Enterprise.preferred_shopfront_closed_message', 'id' => 'enterprise_preferred_shopfront_closed_message', 'name' => 'enterprise[preferred_shopfront_closed_message]', 'class' => 'text-angular', "textangular-links-target-blank" => true,
|
||||
%text-angular{'ng-model' => 'Enterprise.preferred_shopfront_closed_message', 'id' => 'enterprise_preferred_shopfront_closed_message', 'name' => 'enterprise[preferred_shopfront_closed_message]', 'class' => 'text-angular textangular-strip', 'ta-paste' => "stripFormatting($html)", "textangular-links-target-blank" => true,
|
||||
'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]",
|
||||
'placeholder' => t('.shopfront_closed_message_placeholder')}
|
||||
.row
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
{{ orderCycle.producers.length }}
|
||||
= t('.suppliers')
|
||||
%span{ ng: { hide: 'orderCycle.producers.length > 3', bind: 'orderCycle.producerNames' } }
|
||||
%td.coordinator{ ng: { show: 'columns.coordinator.visible' } }
|
||||
{{ orderCycle.coordinator.name }}
|
||||
%td.coordinator{ ng: { show: 'columns.coordinator.visible', bind: { html: 'orderCycle.coordinator.name'} } }
|
||||
%td.shops{ ng: { show: 'columns.shops.visible' } }
|
||||
%span{'ofn-with-tip' => '{{ orderCycle.shopNames }}', ng: { show: 'orderCycle.shops.length > 3' } }
|
||||
{{ orderCycle.shops.length }}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
%th.hide=t('admin.variant_overrides.index.hide')
|
||||
%tbody{ ng: { repeat: 'product in filteredProducts | limitTo:productLimit' } }
|
||||
%tr{ id: "v_{{variant.id}}", ng: { repeat: 'variant in product.variants | inventoryVariants:hub_id:views' } }
|
||||
%td.producer{ ng: { bind: '::producersByID[product.producer_id].name'} }
|
||||
%td.producer{ ng: { bind: { html: '::producersByID[product.producer_id].name'} } }
|
||||
%td.product{ ng: { bind: '::product.name'} }
|
||||
%td.variant
|
||||
%span{ ng: { bind: '::variant.display_name || ""'} }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
%tr.product.even
|
||||
%td.producer{ ng: { show: 'columns.producer.visible', bind: '::producersByID[product.producer_id].name'} }
|
||||
%td.producer{ ng: { show: 'columns.producer.visible', bind: { html: '::producersByID[product.producer_id].name'} } }
|
||||
%td.product{ ng: { show: 'columns.product.visible', bind: '::product.name'} }
|
||||
%td.sku{ ng: { show: 'columns.sku.visible' } }
|
||||
%td.price{ ng: { show: 'columns.price.visible' } }
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
- content_for :injection_data do
|
||||
- if Stripe.publishable_key
|
||||
:javascript
|
||||
angular.module('Darkswarm').value("stripeObject", Stripe("#{Stripe.publishable_key}"))
|
||||
|
||||
%fieldset#payment
|
||||
%ng-form{"ng-controller" => "PaymentCtrl", name: "payment"}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
%strong
|
||||
= pickup_time current_order_cycle
|
||||
|
||||
= render partial: "shopping_shared/header"
|
||||
= render partial: "shopping_shared/header", locals: { hide_oc_selector: true }
|
||||
|
||||
%accordion{"close-others" => "false"}
|
||||
%checkout.row{"ng-controller" => "CheckoutCtrl"}
|
||||
|
||||
@@ -19,22 +19,24 @@
|
||||
- content_for :order_cycle_form do
|
||||
|
||||
%div{"ng-controller" => "OrderCycleChangeCtrl", "ng-cloak" => true}
|
||||
%closing{"ng-if" => "OrderCycle.selected()"}
|
||||
= t :enterprises_next_closing
|
||||
%strong {{ OrderCycle.orders_close_at() | date_in_words }}
|
||||
%closing
|
||||
%div{"ng-if" => "OrderCycle.selected()"}
|
||||
= t :enterprises_next_closing
|
||||
%strong {{ OrderCycle.orders_close_at() | date_in_words }}
|
||||
%div{"ng-if" => "!OrderCycle.selected()"}
|
||||
= t :enterprises_choose
|
||||
|
||||
%span
|
||||
= t :enterprises_ready_for
|
||||
|
||||
/ Will this label should be a variable to reflect 'Ready for pickup / delivery' as appropriate
|
||||
|
||||
%select.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
|
||||
"ofn-change-order-cycle" => true,
|
||||
"disabled" => require_customer?,
|
||||
"ng-options" => "oc.id as oc.time for oc in #{@order_cycles.map {|oc| {time: pickup_time(oc), id: oc.id}}.to_json}",
|
||||
"popover-placement" => "left", "popover" => t(:enterprises_choose), "popover-trigger" => "openTrigger"}
|
||||
.order-cycle-select
|
||||
.select-label
|
||||
%span= t :enterprises_ready_for
|
||||
|
||||
%select.select2.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
|
||||
"ofn-change-order-cycle" => true,
|
||||
"disabled" => require_customer?,
|
||||
"ng-options" => "oc.id as oc.time for oc in #{oc_select_options.to_json}"}
|
||||
|
||||
- if oc_select_options.count > 1
|
||||
%option{value: "", disabled: "", selected: ""}= t :shopping_oc_select
|
||||
|
||||
= render partial: "shopping_shared/header"
|
||||
= render partial: "shopping_shared/tabs"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
.row
|
||||
.large-12.large-centered.columns
|
||||
%h2
|
||||
= t :label_login
|
||||
= form_for Spree::User.new, :remote => true, :html => {'data-type' => :json}, :as => :spree_user, :url => spree.spree_user_session_path do |f|
|
||||
#password-credentials
|
||||
#login-error-alert.alert-box.alert.hide
|
||||
= t :login_invalid
|
||||
%p
|
||||
= f.label :email, t(:email)
|
||||
= f.email_field :email, :class => 'title', :tabindex => 1, :id => "login_spree_user_email"
|
||||
%p
|
||||
= f.label :password, t(:password)
|
||||
= f.password_field :password, :class => 'title', :tabindex => 2, :id => "login_spree_user_password"
|
||||
%p
|
||||
%label
|
||||
= f.check_box :remember_me
|
||||
= f.label :remember_me, t(:remember_me)
|
||||
%p= f.submit t(:login), :class => 'button primary', :tabindex => 3, :id => "login_spree_user_remember_me"
|
||||
@@ -1,18 +0,0 @@
|
||||
.row
|
||||
.large-12.large-centered.columns
|
||||
%h2
|
||||
= t :label_signup
|
||||
= form_for Spree::User.new, :as => :spree_user, :url => spree.spree_user_registration_path(@spree_user) do |f|
|
||||
%p
|
||||
= f.label :email, t(:email)
|
||||
= f.email_field :email, :class => 'title', :id => "signup_spree_user_email"
|
||||
|
||||
#password-credentials
|
||||
%p
|
||||
= f.label :password, t(:password)
|
||||
= f.password_field :password, :class => 'title', :id => "signup_spree_user_password"
|
||||
%p
|
||||
= f.label :password_confirmation, t(:confirm_password)
|
||||
= f.password_field :password_confirmation, :class => 'title', :id => "signup_spree_user_password_confirmation"
|
||||
|
||||
= f.submit t(:create), :class => 'button'
|
||||
@@ -9,4 +9,4 @@
|
||||
%p= t(".login")
|
||||
.row
|
||||
.small-12.columns.text-center
|
||||
%a.button.primary{ type: "button", href: "/" }= "#{t(".action")} >"
|
||||
%a.button.primary{ type: "button", href: spree.admin_dashboard_path }= t(".action")
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
%navigation
|
||||
%distributor.details.row
|
||||
.small-12.medium-6.large-6.columns
|
||||
.small-12.medium-12.large-8.columns
|
||||
#distributor_title
|
||||
- if distributor.logo?
|
||||
%img.left{src: distributor.logo.url(:thumb)}
|
||||
%h3
|
||||
= distributor.name
|
||||
%location= distributor.address.city
|
||||
/ Will this needs to be a drop-down to choose either pick-up point or delivery once shipping methods are implemented
|
||||
|
||||
.small-12.medium-6.large-6.columns
|
||||
= render partial: "shopping_shared/order_cycles"
|
||||
- unless defined? hide_oc_selector
|
||||
.show-for-large-up.large-4.columns
|
||||
= render partial: "shopping_shared/order_cycles"
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
- if most_recently_closed = OrderCycle.most_recently_closed_for(@distributor)
|
||||
(
|
||||
= t :shopping_oc_last_closed, distance_of_time: distance_of_time_in_words_to_now(most_recently_closed.orders_close_at)
|
||||
)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
- if next_oc = OrderCycle.first_opening_for(@distributor)
|
||||
(
|
||||
= t :shopping_oc_next_open, distance_of_time: distance_of_time_in_words_to_now(next_oc.orders_open_at)
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
- content_for :injection_data do
|
||||
= inject_current_order_cycle
|
||||
|
||||
%ordercycle{"ng-controller" => "OrderCycleCtrl"}
|
||||
|
||||
- unless no_open_order_cycles?
|
||||
- unless no_open_order_cycles?
|
||||
%ordercycle{"ng-controller" => "OrderCycleCtrl", "ng-cloak" => true,
|
||||
"ng-class" => "{'requires-selection': !OrderCycle.selected()}"}
|
||||
%form.custom
|
||||
= yield :order_cycle_form
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
- shop_tabs.each do |tab|
|
||||
= render "shopping_shared/tabs/#{tab[:name]}"
|
||||
|
||||
.tabset-ctrl#shop-tabs{ navigate: 'true', alwaysopen: 'true', selected: shop_tabs.first[:name], prefix: 'shop', ng: { cloak: true } }
|
||||
#shop-tabs{ ng: { controller: "PageSelectionCtrl", init: "whitelistPages(#{shop_tab_names.to_json})", cloak: true } }
|
||||
.tab-buttons
|
||||
.row
|
||||
- shop_tabs.each do |tab|
|
||||
.tab{ id: "tab_#{tab[:name]}", name: tab[:name] }
|
||||
%a{ href: 'javascript:void(0)' }=tab[:title]
|
||||
.columns.small-12.large-8
|
||||
- shop_tabs.each do |tab|
|
||||
.page{ "ng-class" => "{ selected: selectedPage() == '#{tab[:name]}' }" }
|
||||
%a{ href: "##{tab[:name]}" }=tab[:title]
|
||||
|
||||
.tab-view
|
||||
.page-view{ ng: {include: "'shop/' + selectedPage() + '.html'" } }
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%div.center
|
||||
.header
|
||||
= t :shopping_contact_address
|
||||
%strong=current_distributor.name
|
||||
%span= current_distributor.name
|
||||
%p
|
||||
= current_distributor.address.address1
|
||||
- unless current_distributor.address.address2.blank?
|
||||
@@ -44,22 +44,19 @@
|
||||
- if current_distributor.twitter.present?
|
||||
%span
|
||||
%a{href: "http://twitter.com/#{current_distributor.twitter}", target: "_blank" }
|
||||
%i.ofn-i_041-twitter
|
||||
%i.twitter.ofn-i_041-twitter
|
||||
|
||||
- if current_distributor.facebook.present?
|
||||
%span
|
||||
%a{href: "http://#{current_distributor.facebook}", target: "_blank" }
|
||||
%i.ofn-i_044-facebook
|
||||
/ = current_distributor.facebook
|
||||
%i.facebook.ofn-i_044-facebook
|
||||
|
||||
- if current_distributor.linkedin.present?
|
||||
%span
|
||||
%a{href: "http://#{current_distributor.linkedin}", target: "_blank" }
|
||||
%i.ofn-i_042-linkedin
|
||||
/ = current_distributor.linkedin
|
||||
%i.linkedin.ofn-i_042-linkedin
|
||||
|
||||
- if current_distributor.instagram.present?
|
||||
%span
|
||||
%a{href: "http://instagram.com/#{current_distributor.instagram}", target: "_blank" }
|
||||
%i.ofn-i_043-instagram
|
||||
/ = current_distributor.instagram
|
||||
%i.instagram.ofn-i_043-instagram
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
%script{ type: "text/ng-template", id: "shop/groups.html" }
|
||||
.content
|
||||
.row
|
||||
.small-12.large-4.columns
|
||||
.small-12.columns
|
||||
- if current_distributor.groups.length > 0
|
||||
%h5
|
||||
=current_distributor.name
|
||||
= t :shopping_groups_part_of
|
||||
%ul.bullet-list
|
||||
%ul.bullet-list.small-block-grid-1.medium-block-grid-2.large-block-grid-3
|
||||
- for group in current_distributor.groups
|
||||
%li
|
||||
%a{href: main_app.groups_path + "/#{group.permalink}"}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
%script{ type: "text/ng-template", id: "shop/home.html" }
|
||||
.order-cycle-bar.hide-for-large-up
|
||||
= render partial: "shopping_shared/order_cycles"
|
||||
|
||||
.content
|
||||
= render partial: 'shop/messages'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.small-12.columns
|
||||
%h5
|
||||
= t :shopping_producers_of_hub, hub: '{{ shopfront.name }}'
|
||||
%ul.small-block-grid-2.large-block-grid-4
|
||||
%ul.small-block-grid-1.medium-block-grid-2.large-block-grid-3
|
||||
%li{"ng-repeat" => "enterprise in shopfront.producers"}
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
%script{ type: "text/ng-template", id: "shop/shop.html" }
|
||||
.order-cycle-bar.hide-for-large-up
|
||||
= render partial: "shopping_shared/order_cycles"
|
||||
|
||||
.row
|
||||
.small-12.columns
|
||||
- if no_open_order_cycles?
|
||||
@@ -8,10 +11,8 @@
|
||||
= t :shopping_oc_closed
|
||||
%small
|
||||
%em
|
||||
(
|
||||
= render partial: "shopping_shared/next_order_cycle"
|
||||
= render partial: "shopping_shared/last_order_cycle"
|
||||
)
|
||||
%p
|
||||
= t :shopping_oc_closed_description
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
%i.error.icon-remove-sign.with-tip{ng: {show: 'rowStatus[order.id] == "error"'}, 'ofn-with-tip' => t('.order_not_updated')}
|
||||
%a.icon_link.with-tip.icon-edit.no-text{'ng-href' => '{{order.edit_path}}', 'data-action' => 'edit', 'ofn-with-tip' => t('.edit')}
|
||||
%div{'ng-if' => 'order.ready_to_ship'}
|
||||
%button.icon-road.icon_link.with-tip.no-text{'ng-click' => 'shipOrder(order)', 'data-confirm' => t(:are_you_sure), rel: 'nofollow', 'ofn-with-tip' => t('.ship')}
|
||||
%button.icon-road.icon_link.with-tip.no-text{'ng-click' => 'shipOrder(order)', rel: 'nofollow', 'ofn-with-tip' => t('.ship')}
|
||||
%div{'ng-if' => 'order.ready_to_capture'}
|
||||
%button.icon-capture.icon_link.no-text{'ng-click' => 'capturePayment(order)', rel: 'nofollow', 'ofn-with-tip' => t('.capture')}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
%td{ :align => "right" }
|
||||
%h4= @order.order_cycle.andand.name
|
||||
%tr{ valign: "top" }
|
||||
%td{ :align => "left" }
|
||||
%td{ align: "left", colspan: 3 }
|
||||
%strong= "#{t('.from')}: #{@order.distributor.name}"
|
||||
- if @order.distributor.abn.present?
|
||||
%br
|
||||
@@ -26,31 +26,43 @@
|
||||
= @order.distributor.address.full_address
|
||||
%br
|
||||
= @order.distributor.contact.email
|
||||
%td{width: "10%" }
|
||||
%tr{ valign: "top" }
|
||||
%td{ colspan: 3 }
|
||||
|
||||
%td{ :align => "right" }
|
||||
%strong= "#{t('.to')}: #{@order.ship_address.full_name}"
|
||||
%tr{ valign: "top" }
|
||||
%td{ align: "left" }
|
||||
%strong= "#{t('.to')}:"
|
||||
%br
|
||||
= @order.bill_address.full_name
|
||||
- if @order.andand.customer.andand.code.present?
|
||||
%br
|
||||
= "#{t('.code')}: #{@order.customer.code}"
|
||||
%br
|
||||
= @order.ship_address.full_address
|
||||
= @order.bill_address.full_address
|
||||
%br
|
||||
- if @order.andand.customer.andand.email.present?
|
||||
= "#{@order.customer.email},"
|
||||
= "#{@order.bill_address.phone}"
|
||||
%td
|
||||
|
||||
%td{ align: "left", style: "border-left: .1em solid black; padding-left: 1em" }
|
||||
%strong= "#{t('.shipping')}: #{@order.shipping_method&.name}"
|
||||
- if @order.shipping_method&.require_ship_address
|
||||
%br
|
||||
= @order.ship_address.full_name
|
||||
%br
|
||||
= @order.ship_address.full_address
|
||||
%br
|
||||
= @order.ship_address.phone
|
||||
- if @order.special_instructions.present?
|
||||
%br
|
||||
%br
|
||||
%strong= t :customer_instructions
|
||||
= @order.special_instructions
|
||||
|
||||
|
||||
= render 'spree/admin/orders/invoice_table'
|
||||
|
||||
- if @order.special_instructions.present?
|
||||
%p.callout
|
||||
%strong
|
||||
= t :customer_instructions
|
||||
%p
|
||||
%em= @order.special_instructions
|
||||
%p
|
||||
|
||||
|
||||
- if @order.distributor.invoice_text.present?
|
||||
%p
|
||||
= @order.distributor.invoice_text
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
= @payment_method
|
||||
- case @payment_method
|
||||
- when Spree::Gateway::StripeConnect
|
||||
= render 'stripe_connect'
|
||||
- when Spree::Gateway::StripeSCA
|
||||
= render 'stripe_connect'
|
||||
- else
|
||||
- if @payment_method.preferences.present?
|
||||
%fieldset.alpha.eleven.columns.no-border-bottom#gateway_fields
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
.stripe
|
||||
%script{:src => "https://js.stripe.com/v3/", :type => "text/javascript"}
|
||||
- if Stripe.publishable_key
|
||||
:javascript
|
||||
angular.module('admin.payments').value("stripeObject", Stripe("#{Stripe.publishable_key}"))
|
||||
|
||||
.row
|
||||
.three.columns
|
||||
= label_tag :cardholder_name, t(:cardholder_name)
|
||||
.six.columns
|
||||
= text_field_tag :cardholder_name, nil, {size: 40, "ng-model" => 'form_data.name'}
|
||||
.row
|
||||
.three.columns
|
||||
= label_tag :card_details, t(:card_details)
|
||||
.six.columns
|
||||
%stripe-elements
|
||||
@@ -6,28 +6,28 @@
|
||||
%dt
|
||||
= Spree.t(:card_number)
|
||||
\:
|
||||
%dd= payment.source.display_number
|
||||
%dd= payment.source&.display_number
|
||||
%dt
|
||||
= Spree.t(:expiration)
|
||||
\:
|
||||
%dd
|
||||
= payment.source.month
|
||||
= payment.source&.month
|
||||
\/
|
||||
= payment.source.year
|
||||
= payment.source&.year
|
||||
%dt
|
||||
= Spree.t(:card_code)
|
||||
\:
|
||||
%dd= payment.source.verification_value
|
||||
%dd= payment.source&.verification_value
|
||||
.omega.six.columns
|
||||
%dl
|
||||
%dt
|
||||
= t(:maestro_or_solo_cards)
|
||||
\:
|
||||
%dd= payment.source.issue_number
|
||||
%dd= payment.source&.issue_number
|
||||
%dt
|
||||
= Spree.t(:start_date)
|
||||
\:
|
||||
%dd
|
||||
= payment.source.start_month
|
||||
= payment.source&.start_month
|
||||
\/
|
||||
= payment.source.start_year
|
||||
= payment.source&.start_year
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
= render "spree/admin/payments/source_views/gateway", payment: payment
|
||||
@@ -49,6 +49,6 @@
|
||||
- content_for :page_actions do
|
||||
%ul.inline-menu
|
||||
%li#new_var_link
|
||||
= link_to_with_icon('icon-plus', t('.new_variant'), new_admin_product_variant_url(@product), remote: true, 'data-update' => 'new_variant', class: 'button')
|
||||
= link_to_with_icon('icon-plus', t('.new_variant'), new_admin_product_variant_url(@product), class: 'button')
|
||||
|
||||
%li= link_to_with_icon('icon-filter', @deleted.blank? ? t('.show_deleted') : t('.show_active'), admin_product_variants_url(@product, deleted: @deleted.blank? ? "on" : "off"), class: 'button')
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
- content_for :injection_data do
|
||||
- if Stripe.publishable_key
|
||||
:javascript
|
||||
angular.module('Darkswarm').value("stripeObject", Stripe("#{Stripe.publishable_key}"))
|
||||
|
||||
.row{ "ng-show" => "savedCreditCards.length > 0" }
|
||||
.small-12.columns
|
||||
%h6= t('.used_saved_card')
|
||||
|
||||
22
app/views/spree/checkout/payment/_stripe_sca.html.haml
Normal file
22
app/views/spree/checkout/payment/_stripe_sca.html.haml
Normal file
@@ -0,0 +1,22 @@
|
||||
- content_for :injection_data do
|
||||
- if Stripe.publishable_key
|
||||
:javascript
|
||||
angular.module('Darkswarm').value("stripeObject", Stripe("#{Stripe.publishable_key}"))
|
||||
|
||||
.row{ "ng-show" => "savedCreditCards.length > 0" }
|
||||
.small-12.columns
|
||||
%h6= t('.used_saved_card')
|
||||
%select{ name: "selected_card", required: false, ng: { model: "secrets.selected_card", options: "card.id as card.formatted for card in savedCreditCards" } }
|
||||
%option{ value: "" }= "{{ secrets.selected_card ? '#{t('.enter_new_card')}' : '#{t('.choose_one')}' }}"
|
||||
|
||||
%h6{ ng: { if: '!secrets.selected_card' } }
|
||||
= t('.or_enter_new_card')
|
||||
|
||||
%div{ ng: { if: '!secrets.selected_card' } }
|
||||
%stripe-elements
|
||||
|
||||
- if spree_current_user
|
||||
.row
|
||||
.small-12.columns.text-right
|
||||
= check_box_tag 'secrets.save_requested_by_customer', '1', false, 'ng-model' => 'secrets.save_requested_by_customer'
|
||||
= label_tag 'secrets.save_requested_by_customer', t('.remember_this_card')
|
||||
@@ -8,7 +8,7 @@
|
||||
= t :email_payment_summary
|
||||
%h4
|
||||
= t :email_payment_method
|
||||
%strong= @order.payments.first.andand.payment_method.andand.name.andand.html_safe
|
||||
%strong= OrderPaymentFinder.last_payment_method(@order)&.name
|
||||
%p
|
||||
%em= @order.payments.first.andand.payment_method.andand.description.andand.html_safe
|
||||
%em= OrderPaymentFinder.last_payment_method(@order)&.description
|
||||
%p
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
- if @order.line_items.empty?
|
||||
%div.row{"data-hook" => "empty_cart"}
|
||||
%p= t(:your_cart_is_empty)
|
||||
%p= link_to t(:continue_shopping), main_app.shop_path, :class => 'button continue'
|
||||
%p= link_to t(:continue_shopping), current_shop_products_path, :class => 'button continue'
|
||||
|
||||
- else
|
||||
%div{"data-hook" => "outside_cart_form"}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.row.links{'data-hook' => "cart_buttons"}
|
||||
.columns.large-8{"data-hook" => ""}
|
||||
%a.button.large.secondary{href: main_app.shop_path}
|
||||
%a.button.large.secondary{href: current_shop_products_path}
|
||||
%i.ofn-i_008-caret-left
|
||||
= t :orders_edit_continue
|
||||
.columns.large-4.text-right
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
.row
|
||||
.columns.small-12.medium-3
|
||||
- if current_order.andand.distributor == @order.distributor
|
||||
- if current_order.line_items.present?
|
||||
- if current_order.nil? || current_order.distributor.nil? || current_order.distributor == @order.distributor
|
||||
- if current_order&.line_items.present?
|
||||
= link_to main_app.cart_path, :class => "button expand" do
|
||||
%i.ofn-i_008-caret-left
|
||||
= t(:order_back_to_cart)
|
||||
- else
|
||||
= link_to main_app.shop_path, :class => "button expand" do
|
||||
= link_to "#{main_app.enterprise_shop_path(@order.distributor)}#/shop", class: "button expand" do
|
||||
%i.ofn-i_008-caret-left
|
||||
= t(:order_back_to_store)
|
||||
- else
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
.pad
|
||||
.text-big
|
||||
= t :order_payment
|
||||
%strong= order.payments.first.andand.payment_method.andand.name.andand.html_safe
|
||||
%strong= OrderPaymentFinder.last_payment_method(order)&.name
|
||||
%p.text-small.text-skinny.pre-line
|
||||
%em= order.payments.first.andand.payment_method.andand.description.andand.html_safe
|
||||
%em= OrderPaymentFinder.last_payment_method(order)&.description
|
||||
|
||||
.order-summary.text-small
|
||||
%strong
|
||||
|
||||
@@ -92,6 +92,7 @@ module Openfoodnetwork
|
||||
app.config.spree.payment_methods << Spree::Gateway::Migs
|
||||
app.config.spree.payment_methods << Spree::Gateway::Pin
|
||||
app.config.spree.payment_methods << Spree::Gateway::StripeConnect
|
||||
app.config.spree.payment_methods << Spree::Gateway::StripeSCA
|
||||
end
|
||||
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
|
||||
@@ -33,11 +33,12 @@ Openfoodnetwork::Application.configure do
|
||||
# Use https in email links
|
||||
config.action_mailer.default_url_options = { protocol: 'https' }
|
||||
|
||||
# See everything in the log (default is :info)
|
||||
# Note: This config no longer works with our new logging strategy
|
||||
# config.log_level = :debug
|
||||
|
||||
# Configure logging for Rails 3.2:
|
||||
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(Rails.root.join("log", "#{Rails.env}.log")))
|
||||
config.logger.level = Logger::INFO
|
||||
config.logger.formatter = Logger::Formatter.new
|
||||
config.logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
||||
# Once we get to Rails 4.0, we can replace the above with:
|
||||
|
||||
@@ -33,11 +33,12 @@ Openfoodnetwork::Application.configure do
|
||||
# Use https in email links
|
||||
config.action_mailer.default_url_options = { protocol: 'https' }
|
||||
|
||||
# See everything in the log (default is :info)
|
||||
# Note: This config no longer works with our new logging strategy
|
||||
# config.log_level = :debug
|
||||
|
||||
# Configure logging for Rails 3.2:
|
||||
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(Rails.root.join("log", "#{Rails.env}.log")))
|
||||
config.logger.level = Logger::INFO
|
||||
config.logger.formatter = Logger::Formatter.new
|
||||
config.logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
||||
# Once we get to Rails 4.0, we can replace the above with:
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
PaperTrail.config.track_associations = false
|
||||
|
||||
module PaperTrail
|
||||
class Version < ActiveRecord::Base
|
||||
attr_accessible :custom_data
|
||||
end
|
||||
end
|
||||
|
||||
@@ -245,7 +245,7 @@ ar:
|
||||
allow_cookies: "السماح لملفات تعريف الارتباط"
|
||||
notes: ملاحظات
|
||||
error: خطأ
|
||||
processing_payment: معالجة الدفع...
|
||||
processing_payment: "معالجة الدفع..."
|
||||
filter_results: تصفية النتائج
|
||||
quantity: الكمية
|
||||
pick_up: النقل
|
||||
@@ -1864,7 +1864,6 @@ ar:
|
||||
headline: "تم الانتهاء !"
|
||||
thanks: "شكرًا لملء تفاصيل %{enterprise}."
|
||||
login: "يمكنك تغيير أو تحديث شركتك في أي مرحلة من خلال تسجيل الدخول إلى شبكة الغذاء المفتوح والذهاب إلى المسؤول."
|
||||
action: "بيت شبكة الغذاء المفتوح"
|
||||
back: "عودة"
|
||||
continue: "استمر"
|
||||
action_or: "أو"
|
||||
@@ -3155,6 +3154,12 @@ ar:
|
||||
used_saved_card: "استخدم بطاقة المحفوظة:"
|
||||
or_enter_new_card: "أو أدخل تفاصيل البطاقة الجديدة:"
|
||||
remember_this_card: تذكر هذه البطاقة؟
|
||||
stripe_sca:
|
||||
choose_one: اختيار واحد
|
||||
enter_new_card: أدخل تفاصيل البطاقة الجديدة
|
||||
used_saved_card: "استخدم بطاقة المحفوظة:"
|
||||
or_enter_new_card: "أو أدخل تفاصيل البطاقة الجديدة:"
|
||||
remember_this_card: تذكر هذه البطاقة؟
|
||||
date_picker:
|
||||
format: '٪ س-٪ م-%d'
|
||||
js_format: 'يوم-شهر-سنة'
|
||||
|
||||
@@ -245,7 +245,7 @@ ca:
|
||||
allow_cookies: "Permet les galetes"
|
||||
notes: Notes
|
||||
error: Error
|
||||
processing_payment: S'està processant el pagament...
|
||||
processing_payment: "S'està processant el pagament..."
|
||||
filter_results: Aplicar filtre
|
||||
quantity: Quantitat
|
||||
pick_up: Recollida
|
||||
@@ -1285,6 +1285,7 @@ ca:
|
||||
saving_credit_card: Desant la targeta de crèdit...
|
||||
card_has_been_removed: "S'ha eliminat la teva targeta (número: %{number})"
|
||||
card_could_not_be_removed: Ho sentim, no s'ha pogut eliminar la targeta
|
||||
invalid_credit_card: "Targeta de crèdit no vàlida"
|
||||
ie_warning_headline: "El vostre navegador no està actualitzat :-("
|
||||
ie_warning_text: "Per obtenir la millor experiència a Open Food Network et recomanem que actualitzis el teu navegador:"
|
||||
ie_warning_chrome: Descarrega Chrome
|
||||
@@ -1859,7 +1860,6 @@ ca:
|
||||
headline: "Acabat!"
|
||||
thanks: "Gràcies per omplir els detalls de%{enterprise}."
|
||||
login: "Pots canviar o actualitzar la teva organització en qualsevol moment accedint a Katuma i anant a Admin."
|
||||
action: "Inici"
|
||||
back: "Enrere"
|
||||
continue: "Continua"
|
||||
action_or: "O"
|
||||
@@ -2276,6 +2276,7 @@ ca:
|
||||
enterprise_register_success_notice: "Enhorabona! El registre de %{enterprise} s'ha completat!"
|
||||
enterprise_bulk_update_success_notice: "Les organitzacions s'han actualitzat correctament"
|
||||
enterprise_bulk_update_error: 'No s''ha pogut actualitzar'
|
||||
enterprise_shop_show_error: "La botiga que busqueu no existeix o està inactiva a OFN. Consulteu altres botigues."
|
||||
order_cycles_create_notice: 'S''ha creat el cicle de comanda.'
|
||||
order_cycles_update_notice: 'S''ha actualitzat el cicle de comanda.'
|
||||
order_cycles_bulk_update_notice: 'S''han actualitzat els cicles de comanda.'
|
||||
@@ -2430,6 +2431,12 @@ ca:
|
||||
severity: Severitat
|
||||
description: Descripció
|
||||
resolve: Resoldre
|
||||
exchange_products:
|
||||
load_more_variants: "Carregueu més variants"
|
||||
load_all_variants: "Carregueu totes les variants"
|
||||
select_all_variants: "Seleccioneu totes les %{total_number_of_variants} variants"
|
||||
variants_loaded: "%{num_of_variants_loaded} de %{total_number_of_variants} variants carregades"
|
||||
loading_variants: "Carregant variants"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Els mètodes d'enviament etiquetats"
|
||||
shipping_method_tagged_bottom: "son:"
|
||||
@@ -2588,6 +2595,73 @@ ca:
|
||||
signup_or_login: "Comenceu registrant-vos (o iniciant sessió)"
|
||||
have_an_account: "Ja tens un compte?"
|
||||
action_login: "Inicia la sessió ara."
|
||||
inflections:
|
||||
each:
|
||||
one: "cadascun"
|
||||
other: "cadascun"
|
||||
bunch:
|
||||
one: "munt"
|
||||
other: "grapats"
|
||||
pack:
|
||||
one: "paquet"
|
||||
other: "paquets"
|
||||
box:
|
||||
one: "Caixa"
|
||||
other: "caixes"
|
||||
bottle:
|
||||
one: "ampolla"
|
||||
other: "ampolles"
|
||||
jar:
|
||||
one: "gerro"
|
||||
other: "pots"
|
||||
head:
|
||||
one: "cap"
|
||||
other: "caps"
|
||||
bag:
|
||||
one: "bossa"
|
||||
other: "bosses"
|
||||
loaf:
|
||||
one: "pa"
|
||||
other: "barres"
|
||||
single:
|
||||
one: "solter"
|
||||
other: "únics"
|
||||
tub:
|
||||
one: "tina"
|
||||
other: "cubells"
|
||||
item:
|
||||
one: "article"
|
||||
other: "articles"
|
||||
dozen:
|
||||
one: "dotzena"
|
||||
other: "dotzenes"
|
||||
unit:
|
||||
one: "unitat"
|
||||
other: "unitats"
|
||||
serve:
|
||||
one: "servir"
|
||||
other: "porcions"
|
||||
tray:
|
||||
one: "safata"
|
||||
other: "safates"
|
||||
piece:
|
||||
one: "peça"
|
||||
other: "peces"
|
||||
pot:
|
||||
one: "pot"
|
||||
other: "pots"
|
||||
bundle:
|
||||
one: "paquet"
|
||||
other: "paquets"
|
||||
flask:
|
||||
one: "matràs"
|
||||
other: "ampolleta"
|
||||
basket:
|
||||
one: "cistella"
|
||||
other: "cistelles"
|
||||
sack:
|
||||
one: "sac"
|
||||
other: "sacs"
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Comença amb un perfil gratuït i amplia'l quan estiguis preparada."
|
||||
@@ -3139,6 +3213,12 @@ ca:
|
||||
used_saved_card: "Utilitza una targeta desada:"
|
||||
or_enter_new_card: "O bé introdueix els detalls d'una nova targeta:"
|
||||
remember_this_card: Recordar aquesta targeta?
|
||||
stripe_sca:
|
||||
choose_one: Escull-ne un
|
||||
enter_new_card: Introdueix els detalls d'una targeta nova
|
||||
used_saved_card: "Utilitza una targeta desada:"
|
||||
or_enter_new_card: "O bé introdueix els detalls d'una nova targeta:"
|
||||
remember_this_card: Recordar aquesta targeta?
|
||||
date_picker:
|
||||
format: '%d-% m-% Y'
|
||||
js_format: 'dd-mm-yy'
|
||||
|
||||
@@ -243,7 +243,7 @@ de_DE:
|
||||
allow_cookies: "Cookies erlauben"
|
||||
notes: Anmerkungen
|
||||
error: Fehler
|
||||
processing_payment: Bezahlung wird verarbeitet...
|
||||
processing_payment: "Bezahlung wird verarbeitet..."
|
||||
filter_results: Ergebnisse filtern
|
||||
quantity: Menge
|
||||
pick_up: Abholen
|
||||
@@ -1848,7 +1848,6 @@ de_DE:
|
||||
headline: "Fertig!"
|
||||
thanks: "Vielen Dank, dass Sie die Details für %{enterprise} ausgefüllt haben."
|
||||
login: "Sie können Ihr Unternehmen jederzeit ändern oder aktualisieren, indem Sie sich bei Open Food Network anmelden und zum Administrator wechseln."
|
||||
action: "Open Food Network nach Hause"
|
||||
back: "Zurück"
|
||||
continue: "Fortsetzen"
|
||||
action_or: "ODER"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user