Compare commits

..

2 Commits

Author SHA1 Message Date
Jean-Baptiste Bellet
e4ad6d736b Canceling an order: clicking on cancel btn or cancel action in dropdown 2023-04-20 13:53:37 +02:00
basilawwad
9f30471373 Use a shared_examples for the order cancellation tests 2023-04-20 12:28:27 +02:00
395 changed files with 5081 additions and 17439 deletions

View File

@@ -5,8 +5,6 @@
#
# cp .env.development .env.local
VERBOSE_QUERY_LOGS=true
SECRET_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
OFN_REDIS_URL="redis://localhost:6379/1"

View File

@@ -18,7 +18,7 @@ permissions:
jobs:
knapsack_rspec_controllers:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10
@@ -86,7 +86,7 @@ jobs:
bundle exec rake knapsack_pro:rspec
knapsack_rspec_models:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10
@@ -155,7 +155,7 @@ jobs:
bundle exec rake knapsack_pro:rspec
knapsack_rspec_system_admin:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10
@@ -233,7 +233,7 @@ jobs:
if-no-files-found: ignore
knapsack_rspec_system_consumer:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10
@@ -311,7 +311,7 @@ jobs:
if-no-files-found: ignore
knapsack_rspec_engines:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10
@@ -389,7 +389,7 @@ jobs:
if-no-files-found: ignore
knapsack_rspec_test_the_rest:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10
@@ -459,7 +459,7 @@ jobs:
bundle exec rake knapsack_pro:rspec
non_knapsack_jest_karma:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10

View File

@@ -1,5 +1,8 @@
# Basically, ignore everythings expect app/webpacker/controllers/*.js and app/webpacker/packs/*.js
*.css
*.scss
# Except v2
!/app/webpacker/css/admin/v2/**/*.scss
*.md
*.yml
*.yaml
@@ -9,10 +12,6 @@
babel.config.js
postcss.config.js
/app/webpacker/css/darkswarm/
/app/webpacker/css/mail/
/app/webpacker/css/shared/
/app/assets/
/config/
/coverage/

View File

@@ -1,3 +1 @@
{
"printWidth": 100
}
{}

View File

@@ -40,7 +40,6 @@ Metrics/BlockLength:
"resources",
"scenario",
"shared_examples",
"shared_examples_for",
"xdescribe",
]

View File

@@ -1,11 +1,41 @@
# This configuration was generated by
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 1400 --no-auto-gen-timestamp`
# using RuboCop version 1.50.2.
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 1400`
# on 2023-04-14 06:27:24 UTC using RuboCop version 1.50.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 4
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
# Include: **/*.gemfile, **/Gemfile, **/gems.rb
Bundler/OrderedGems:
Exclude:
- 'Gemfile'
# Offense count: 4
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Severity, Include.
# Include: **/*.gemspec
Gemspec/DeprecatedAttributeAssignment:
Exclude:
- 'engines/catalog/catalog.gemspec'
- 'engines/dfc_provider/dfc_provider.gemspec'
- 'engines/order_management/order_management.gemspec'
- 'engines/web/web.gemspec'
# Offense count: 4
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Severity, Include.
# Include: **/*.gemspec
Gemspec/RequireMFA:
Exclude:
- 'engines/catalog/catalog.gemspec'
- 'engines/dfc_provider/dfc_provider.gemspec'
- 'engines/order_management/order_management.gemspec'
- 'engines/web/web.gemspec'
# Offense count: 4
# Configuration parameters: Severity, Include.
# Include: **/*.gemspec
@@ -84,6 +114,13 @@ Layout/EmptyLinesAroundBlockBody:
- 'spec/requests/checkout/concurrency_spec.rb'
- 'spec/system/admin/order_cycles/list_spec.rb'
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
Layout/ExtraSpacing:
Exclude:
- 'spec/spec_helper.rb'
# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, IndentationWidth.
@@ -199,7 +236,7 @@ Layout/LineEndStringConcatenationIndentation:
- 'spec/system/consumer/cookies_spec.rb'
- 'spec/system/consumer/shopping/cart_spec.rb'
# Offense count: 615
# Offense count: 605
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
# URISchemes: http, https
@@ -412,7 +449,7 @@ Layout/TrailingEmptyLines:
Exclude:
- 'Rakefile'
# Offense count: 70
# Offense count: 67
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowInHeredoc.
Layout/TrailingWhitespace:
@@ -656,10 +693,8 @@ Metrics/BlockNesting:
Metrics/ClassLength:
Exclude:
- 'app/components/products_table_component.rb'
- 'app/controllers/admin/enterprise_fees_controller.rb'
- 'app/controllers/admin/enterprises_controller.rb'
- 'app/controllers/admin/order_cycles_controller.rb'
- 'app/controllers/admin/product_import_controller.rb'
- 'app/controllers/admin/resource_controller.rb'
- 'app/controllers/admin/schedules_controller.rb'
- 'app/controllers/admin/subscriptions_controller.rb'

View File

@@ -71,5 +71,5 @@ From here, your pull request will progress through the [Review, Test, Merge & De
[slack-dev]: https://openfoodnetwork.slack.com/messages/C2GQ45KNU
[ofn-transifex]: https://www.transifex.com/open-food-foundation/open-food-network/
[i18n]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Internationalisation-%28i18n%29
[welcome-dev]: https://github.com/orgs/openfoodfoundation/projects/5
[welcome-dev]: https://github.com/orgs/openfoodfoundation/projects/2
[ci]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Continuous-Integration

10
Gemfile
View File

@@ -14,11 +14,11 @@ gem "aws-sdk-s3", require: false
gem "image_processing"
gem 'activemerchant', '>= 1.78.0'
gem 'rexml'
gem 'angular-rails-templates', '>= 0.3.0'
gem 'awesome_nested_set'
gem 'ransack', '~> 2.6.0'
gem 'responders'
gem 'rexml'
gem 'webpacker', '~> 5'
gem 'i18n'
@@ -63,7 +63,6 @@ gem 'devise-token_authenticatable'
gem 'jwt', '~> 2.3'
gem 'oauth2', '~> 1.4.7' # Used for Stripe Connect
gem 'datafoodconsortium-connector'
gem 'jsonapi-serializer'
gem 'pagy', '~> 5.1'
@@ -71,8 +70,8 @@ gem 'rswag-api'
gem 'rswag-ui'
gem 'omniauth_openid_connect'
gem 'omniauth-rails_csrf_protection'
gem 'openid_connect', '~> 1.3'
gem 'omniauth-rails_csrf_protection'
gem 'angularjs-rails', '1.8.0'
gem 'bugsnag'
@@ -151,7 +150,6 @@ group :test, :development do
gem 'capybara'
gem 'cuprite'
gem 'database_cleaner', require: false
gem 'debug', '>= 1.0.0'
gem "factory_bot_rails", '6.2.0', require: false
gem 'fuubar', '~> 2.5.1'
gem 'json_spec', '~> 1.1.4'
@@ -162,6 +160,7 @@ group :test, :development do
gem 'rswag-specs'
gem 'shoulda-matchers'
gem 'timecop'
gem 'debug', '>= 1.0.0'
end
group :test do
@@ -176,11 +175,10 @@ end
group :development do
gem 'debugger-linecache'
gem 'rails-erd'
gem 'foreman'
gem 'listen'
gem 'pry', '~> 0.13.0'
gem 'query_count'
gem 'rails-erd'
gem 'rubocop'
gem 'rubocop-rails'
gem 'spring'

View File

@@ -137,7 +137,7 @@ GEM
activerecord (>= 6.0, < 7.1)
acts_as_list (1.0.4)
activerecord (>= 4.2)
addressable (2.8.4)
addressable (2.8.2)
public_suffix (>= 2.0.2, < 6.0)
aes_key_wrap (1.1.0)
afm (0.2.2)
@@ -157,16 +157,16 @@ GEM
awesome_nested_set (3.5.0)
activerecord (>= 4.0.0, < 7.1)
aws-eventstream (1.2.0)
aws-partitions (1.760.0)
aws-sdk-core (3.171.1)
aws-partitions (1.742.0)
aws-sdk-core (3.171.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.64.0)
aws-sdk-kms (1.63.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.122.0)
aws-sdk-s3 (1.120.1)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@@ -191,7 +191,7 @@ GEM
railties (>= 5.2)
thread-local (>= 1.1.0)
cancancan (1.15.0)
capybara (3.39.1)
capybara (3.39.0)
addressable
matrix
mini_mime (>= 0.1.3)
@@ -234,16 +234,14 @@ GEM
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
datafoodconsortium-connector (1.0.0.pre.alpha.6)
virtual_assembly-semantizer (~> 1.0, >= 1.0.4)
date (3.3.3)
ddtrace (1.11.1)
ddtrace (1.10.1)
debase-ruby_core_source (>= 0.10.16, <= 3.2.0)
libdatadog (~> 2.0.0.1.0)
libddwaf (~> 1.8.2.0.0)
libddwaf (~> 1.6.2.0.0)
msgpack
debase-ruby_core_source (3.2.0)
debug (1.8.0)
debug (1.7.2)
irb (>= 1.5.0)
reline (>= 0.3.1)
debugger-linecache (1.2.0)
@@ -340,7 +338,7 @@ GEM
hiredis (0.6.3)
htmlentities (4.3.4)
httpclient (2.8.3)
i18n (1.13.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
i18n-js (3.9.2)
i18n (>= 0.6.6)
@@ -351,7 +349,7 @@ GEM
activerecord (>= 3.0)
io-console (0.6.0)
ipaddress (0.8.3)
irb (1.6.4)
irb (1.6.3)
reline (>= 0.3.0)
jmespath (1.6.2)
jquery-rails (4.4.0)
@@ -361,20 +359,12 @@ GEM
jquery-ui-rails (4.2.1)
railties (>= 3.2.16)
json (2.6.3)
json-canonicalization (0.3.1)
json-jwt (1.16.3)
activesupport (>= 4.2)
aes_key_wrap
bindata
faraday (~> 2.0)
faraday-follow_redirects
json-ld (3.2.3)
htmlentities (~> 4.3)
json-canonicalization (~> 0.3)
link_header (~> 0.0, >= 0.0.8)
multi_json (~> 1.15)
rack (~> 2.2)
rdf (~> 3.2, >= 3.2.9)
json-schema (3.0.0)
addressable (>= 2.8)
json_spec (1.1.5)
@@ -383,23 +373,22 @@ GEM
jsonapi-serializer (2.2.0)
activesupport (>= 4.2)
jwt (2.7.0)
knapsack_pro (3.11.0)
knapsack_pro (3.9.0)
rake
launchy (2.5.0)
addressable (~> 2.7)
letter_opener (1.8.1)
launchy (>= 2.2, < 3)
libdatadog (2.0.0.1.0)
libddwaf (1.8.2.0.0)
libddwaf (1.6.2.0.0)
ffi (~> 1.0)
libv8-node (16.10.0.0)
link_header (0.0.8)
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.21.2)
loofah (2.20.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
nokogiri (>= 1.5.9)
mail (2.8.1)
mini_mime (>= 0.1.1)
net-imap
@@ -416,7 +405,7 @@ GEM
rake
mini_magick (4.11.0)
mini_mime (1.1.2)
mini_portile2 (2.8.2)
mini_portile2 (2.8.1)
mini_racer (0.6.3)
libv8-node (~> 16.10.0.0)
minitest (5.18.0)
@@ -424,7 +413,7 @@ GEM
money (~> 6.12)
money (6.16.0)
i18n (>= 0.6.4, <= 2)
msgpack (1.7.0)
msgpack (1.6.1)
multi_json (1.15.0)
multi_xml (0.6.0)
net-imap (0.3.4)
@@ -437,7 +426,7 @@ GEM
net-smtp (0.3.3)
net-protocol
nio4r (2.5.9)
nokogiri (1.14.4)
nokogiri (1.14.3)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
oauth2 (1.4.11)
@@ -473,10 +462,10 @@ GEM
paper_trail (12.3.0)
activerecord (>= 5.2)
request_store (~> 1.1)
parallel (1.23.0)
parallel (1.22.1)
paranoia (2.6.1)
activerecord (>= 5.1, < 7.1)
parser (3.2.2.1)
parser (3.2.2.0)
ast (~> 2.4.1)
paypal-sdk-core (0.3.4)
multi_json (~> 1.0)
@@ -490,7 +479,7 @@ GEM
ruby-rc4
ttfunk
pg (1.2.3)
power_assert (2.0.3)
power_assert (2.0.2)
private_address_check (0.5.0)
pry (0.13.1)
coderay (~> 1.1)
@@ -498,12 +487,9 @@ GEM
public_suffix (5.0.1)
puma (6.2.2)
nio4r (~> 2.0)
query_count (1.1.1)
activerecord (>= 4.2)
railties (>= 4.2)
raabro (1.4.0)
racc (1.6.2)
rack (2.2.7)
rack (2.2.6.4)
rack-mini-profiler (2.3.4)
rack (>= 1.2.0)
rack-oauth2 (1.21.3)
@@ -548,7 +534,7 @@ GEM
ruby-graphviz (~> 1.2)
rails-html-sanitizer (1.5.0)
loofah (~> 2.19, >= 2.19.1)
rails-i18n (7.0.7)
rails-i18n (7.0.6)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)
rails_safe_tasks (1.0.0)
@@ -568,8 +554,6 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rdf (3.2.9)
link_header (~> 0.0, >= 0.0.8)
redcarpet (3.6.0)
redis (4.8.1)
redis-client (0.14.1)
@@ -599,36 +583,36 @@ GEM
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.2)
rspec-core (3.12.1)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.3)
rspec-expectations (3.12.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.5)
rspec-mocks (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-rails (6.0.2)
rspec-rails (6.0.1)
actionpack (>= 6.1)
activesupport (>= 6.1)
railties (>= 6.1)
rspec-core (~> 3.12)
rspec-expectations (~> 3.12)
rspec-mocks (~> 3.12)
rspec-support (~> 3.12)
rspec-core (~> 3.11)
rspec-expectations (~> 3.11)
rspec-mocks (~> 3.11)
rspec-support (~> 3.11)
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-support (3.12.0)
rswag-api (2.9.0)
rswag-api (2.8.0)
railties (>= 3.1, < 7.1)
rswag-specs (2.9.0)
rswag-specs (2.8.0)
activesupport (>= 3.1, < 7.1)
json-schema (>= 2.2, < 4.0)
railties (>= 3.1, < 7.1)
rspec-core (>= 2.14)
rswag-ui (2.9.0)
rswag-ui (2.8.0)
actionpack (>= 3.1, < 7.1)
railties (>= 3.1, < 7.1)
rubocop (1.51.0)
rubocop (1.50.2)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.0.0)
@@ -638,7 +622,7 @@ GEM
rubocop-ast (>= 1.28.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.28.1)
rubocop-ast (1.28.0)
parser (>= 3.2.1.0)
rubocop-rails (2.19.1)
activesupport (>= 4.2.0)
@@ -668,11 +652,11 @@ GEM
semantic_range (3.0.0)
shoulda-matchers (5.3.0)
activesupport (>= 5.2.0)
sidekiq (7.1.0)
sidekiq (7.0.8)
concurrent-ruby (< 2)
connection_pool (>= 2.3.0)
rack (>= 2.2.4)
redis-client (>= 0.14.0)
redis-client (>= 0.11.0)
sidekiq-scheduler (5.0.2)
rufus-scheduler (~> 3.2)
sidekiq (>= 6, < 8)
@@ -713,16 +697,16 @@ GEM
rack (>= 2, < 4)
railties (>= 5.2, < 8)
redis (>= 4.0, < 6.0)
stringex (2.8.6)
stringex (2.8.5)
stripe (8.5.0)
swd (1.3.0)
activesupport (>= 3)
attr_required (>= 0.0.5)
httpclient (>= 2.4)
temple (0.8.2)
test-unit (3.5.8)
test-unit (3.5.7)
power_assert
thor (1.2.2)
thor (1.2.1)
thread-local (1.1.0)
tilt (2.1.0)
timecop (0.9.6)
@@ -742,7 +726,7 @@ GEM
activemodel (>= 3.0.0)
public_suffix
vcr (6.1.0)
view_component (3.0.0)
view_component (2.82.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
@@ -750,8 +734,6 @@ GEM
rails (>= 5.2, < 8.0)
stimulus_reflex (>= 3.5.0.pre2)
view_component (>= 2.28.0)
virtual_assembly-semantizer (1.0.4)
json-ld (~> 3.2, >= 3.2.3)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.0)
@@ -783,7 +765,7 @@ GEM
xml-simple (1.1.8)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.8)
zeitwerk (2.6.7)
PLATFORMS
ruby
@@ -817,7 +799,6 @@ DEPENDENCIES
combine_pdf
cuprite
database_cleaner
datafoodconsortium-connector
db2fog!
ddtrace
debug (>= 1.0.0)
@@ -876,7 +857,6 @@ DEPENDENCIES
private_address_check
pry (~> 0.13.0)
puma
query_count
rack-mini-profiler (< 3.0.0)
rack-rewrite
rack-timeout

View File

@@ -12,6 +12,5 @@ angular.module("ofn.admin", [
"admin.orders"
]).config ($httpProvider, $locationProvider, $qProvider) ->
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
# for the next line, you should also probably check file: app/assets/javascripts/admin/utils/utils.js.coffee
$locationProvider.hashPrefix('')
$qProvider.errorOnUnhandledRejections(false)

View File

@@ -22,7 +22,6 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
"order_bill_address_phone",
"order_bill_address_firstname",
"order_bill_address_lastname",
"order_bill_address_full_name",
"variant_product_supplier_name",
"order_email",
"order_number",
@@ -122,16 +121,16 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
else
StatusMessage.display 'failure', t "unsaved_changes_error"
$scope.cancelOrder = (order, sendEmailCancellation, restock_items) ->
$scope.cancelOrder = (order, sendEmailCancellation) ->
return $http(
method: 'GET'
url: "/admin/orders/#{order.number}/fire?e=cancel&send_cancellation_email=#{sendEmailCancellation}&restock_items=#{restock_items}")
url: "/admin/orders/#{order.number}/fire?e=cancel&send_cancellation_email=#{sendEmailCancellation}")
$scope.deleteLineItem = (lineItem) ->
if lineItem.order.item_count == 1
ofnCancelOrderAlert((confirm, sendEmailCancellation, restock_items) ->
ofnCancelOrderAlert((confirm, sendEmailCancellation) ->
if confirm
$scope.cancelOrder(lineItem.order, sendEmailCancellation, restock_items).then(->
$scope.cancelOrder(lineItem.order, sendEmailCancellation).then(->
$scope.refreshData()
)
else
@@ -153,11 +152,11 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
willCancelOrders = true if (order.item_count == itemsPerOrder.get(order).length)
if willCancelOrders
ofnCancelOrderAlert((confirm, sendEmailCancellation, restock_items) ->
ofnCancelOrderAlert((confirm, sendEmailCancellation) ->
if confirm
itemsPerOrder.forEach (items, order) =>
if order.item_count == items.length
$scope.cancelOrder(order, sendEmailCancellation, restock_items).then(-> $scope.refreshData())
$scope.cancelOrder(order, sendEmailCancellation).then(-> $scope.refreshData())
else
Promise.all(LineItems.delete(item) for item in items).then(-> $scope.refreshData())
, "js.admin.deleting_item_will_cancel_order")

View File

@@ -15,7 +15,7 @@ $(document).ready(function() {
console.log(msg);
});
}
$('.admin-order-edit-form a.ship').click(handle_ship_click);
$('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click);
//handle shipping method edit click
$('a.edit-method').click(toggleMethodEdit);
@@ -37,7 +37,7 @@ $(document).ready(function() {
console.log(msg);
});
}
$('.admin-order-edit-form a.save-method').click(handle_shipping_method_save);
$('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save);
//handle tracking info edit/delete
@@ -64,8 +64,8 @@ $(document).ready(function() {
return Spree.url( Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipmentNumber + ".json");
}
$('.admin-order-edit-form a.save-tracking').click(saveTrackingInfo);
$('.admin-order-edit-form a.delete-tracking').click(deleteTrackingInfo);
$('[data-hook=admin_order_edit_form] a.save-tracking').click(saveTrackingInfo);
$('[data-hook=admin_order_edit_form] a.delete-tracking').click(deleteTrackingInfo);
// handle note edit/delete
@@ -96,8 +96,8 @@ $(document).ready(function() {
});
}
$('.admin-order-edit-form a.save-note').click(saveNote);
$('.admin-order-edit-form a.delete-note').click(deleteNote);
$('[data-hook=admin_order_edit_form] a.save-note').click(saveNote);
$('[data-hook=admin_order_edit_form] a.delete-note').click(deleteNote);
// Makes API call for notes/tracking info
makeApiCall = function(url, params) {

View File

@@ -100,7 +100,6 @@ adjustItems = function(shipment_number, variant_id, quantity, restock_item){
doAdjustItems(shipment_number, variant_id, quantity, inventory_units, restock_item, () => {
var redirectTo = new URL(Spree.routes.cancel_order.toString());
redirectTo.searchParams.append("send_cancellation_email", sendEmailCancellation);
redirectTo.searchParams.append("restock_item", restock_item);
window.location.href = redirectTo.toString();
});
}

View File

@@ -1,4 +1,3 @@
angular.module("admin.utils", ["templates", "ngSanitize"]).config ($httpProvider, $locationProvider) ->
# for the next line, you should also probably check file: app/assets/javascripts/admin/admin_ofn.js.coffee
$locationProvider.hashPrefix('')
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"

View File

@@ -1,10 +1,9 @@
# frozen_string_literal: true
class ConfirmModalComponent < ModalComponent
def initialize(id:, confirm_actions: nil, controllers: nil, message: nil, confirm_reflexes: nil)
def initialize(id:, confirm_actions: nil, controllers: nil, message: nil)
super(id: id, close_button: true)
@confirm_actions = confirm_actions
@confirm_reflexes = confirm_reflexes
@controllers = controllers
@message = message
end

View File

@@ -7,4 +7,4 @@
.modal-actions
%input{ class: "button icon-plus #{close_button_class}", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->modal#close" }
%input{ class: "button icon-plus primary", type: 'button', value: t('js.admin.modals.confirm'), "data-action": @confirm_actions, "data-reflex": @confirm_reflexes }
%input{ class: "button icon-plus primary", type: 'button', value: t('js.admin.modals.confirm'), "data-action": @confirm_actions }

View File

@@ -18,8 +18,6 @@ module Admin
end
end
ContentConfig.updated_at = Time.zone.now
flash[:success] =
t(:successfully_updated, resource: I18n.t('admin.contents.edit.your_content'))

View File

@@ -7,7 +7,6 @@ module Admin
before_action :load_enterprise_fee_set, only: :index
before_action :load_data
before_action :check_enterprise_fee_input, only: [:bulk_update]
before_action :check_calculators_compatibility_with_taxes, only: [:bulk_update]
def index
@include_calculators = params[:include_calculators].present?
@@ -120,17 +119,5 @@ module Admin
end
end
end
def check_calculators_compatibility_with_taxes
enterprise_fee_bulk_params['collection_attributes'].each do |_, enterprise_fee|
next unless enterprise_fee['inherits_tax_category'] == "true"
next unless EnterpriseFee::PER_ORDER_CALCULATORS.include?(enterprise_fee['calculator_type'])
flash[:error] = I18n.t(
'activerecord.errors.models.enterprise_fee.inherit_tax_requires_per_item_calculator'
)
return redirect_to redirect_path
end
end
end
end

View File

@@ -37,7 +37,7 @@ module Admin
end
def reset_absent_products
@importer = ProductImport::ProductImporter.new(File.new(file_path),
@importer = ProductImport::ProductImporter.new(File.new(params[:filepath]),
spree_current_user, import_into: params[:import_into], enterprises_to_reset: params[:enterprises_to_reset], updated_ids: params[:updated_ids], settings: params[:settings])
if params.key?(:enterprises_to_reset) && params.key?(:updated_ids)
@@ -56,7 +56,7 @@ module Admin
end
def process_data(method)
@importer = ProductImport::ProductImporter.new(File.new(file_path),
@importer = ProductImport::ProductImporter.new(File.new(params[:filepath]),
spree_current_user, start: params[:start], end: params[:end], settings: params[:settings])
begin
@@ -112,25 +112,5 @@ module Admin
def model_class
ProductImport::ProductImporter
end
def file_path
@file_path ||= validate_file_path(sanitize_file_path(params[:filepath]))
end
def sanitize_file_path(file_path)
FilePathSanitizer.new.sanitize(file_path, on_error: method(:raise_invalid_file_path))
end
def validate_file_path(file_path)
return file_path if file_path.to_s.match?(TEMP_FILE_PATH_REGEX)
raise_invalid_file_path
end
def raise_invalid_file_path
redirect_to '/admin/product_import', notice: I18n.t(:product_import_no_data_in_spreadsheet_notice)
raise 'Invalid File Path'
end
TEMP_FILE_PATH_REGEX = %r{^/tmp/product_import[A-Za-z0-9-]*/import\.csv$}
end
end

View File

@@ -77,7 +77,7 @@ module Admin
assign_view_data
if @blob
@error = ".report_taking_longer_html"
@error_url = @blob.expiring_service_url
@error_url = @blob.url
else
@error = ".report_taking_longer"
@error_url = ""

View File

@@ -116,7 +116,7 @@ module Api
def product_query_includes
[
master: { images: { attachment_attachment: :blob } },
master: [:images],
variants: [:default_price, :stock_locations, :stock_items, :variant_overrides,
{ option_values: :option_type }]
]

View File

@@ -30,8 +30,6 @@ module CheckoutCallbacks
@order.manual_shipping_selection = true
@order.checkout_processing = true
@voucher_adjustment = @order.voucher_adjustments.first
redirect_to(main_app.shop_path) && return if redirect_to_shop?
redirect_to_cart_path && return unless valid_order_line_items?
end

View File

@@ -5,15 +5,10 @@ module WhiteLabel
include EnterprisesHelper
def hide_ofn_navigation(distributor = current_distributor)
return false unless OpenFoodNetwork::FeatureToggle.enabled?(:white_label)
# if the distributor has the hide_ofn_navigation preference set to true
# then we should hide the OFN navigation
@hide_ofn_navigation = distributor.hide_ofn_navigation
# if the distributor has the hide_ofn_navigation preference
# set to false, there is no need to check the white_label_logo preference
return unless @hide_ofn_navigation
@white_label_logo = distributor.white_label_logo
@white_label_distributor = distributor
end
end

View File

@@ -30,8 +30,6 @@ class SplitCheckoutController < ::BaseController
end
def update
return process_voucher if params[:apply_voucher].present?
if confirm_order || update_order
return if performed?
@@ -61,27 +59,6 @@ class SplitCheckoutController < ::BaseController
replace("#flashes", partial("shared/flashes", locals: { flashes: flash }))
end
def render_voucher_section_or_redirect
respond_to do |format|
format.cable_ready { render_voucher_section }
format.html { redirect_to checkout_step_path(:payment) }
end
end
# Using the power of cable_car we replace only the #voucher_section instead of reloading the page
def render_voucher_section
render(
status: :ok,
cable_ready: cable_car.replace(
"#voucher-section",
partial(
"split_checkout/voucher_section",
locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
)
)
)
end
def order_error_messages
# Remove ship_address.* errors if no shipping method is not selected
remove_ship_address_errors if no_ship_address_needed?
@@ -202,47 +179,10 @@ class SplitCheckoutController < ::BaseController
selected_shipping_method.first.require_ship_address == false
end
def process_voucher
if add_voucher
render_voucher_section_or_redirect
elsif @order.errors.present?
render_error
end
end
def add_voucher
if params.dig(:order, :voucher_code).blank?
@order.errors.add(:voucher, I18n.t('split_checkout.errors.voucher_not_found'))
return false
end
# Fetch Voucher
voucher = Voucher.find_by(code: params[:order][:voucher_code], enterprise: @order.distributor)
if voucher.nil?
@order.errors.add(:voucher, I18n.t('split_checkout.errors.voucher_not_found'))
return false
end
adjustment = voucher.create_adjustment(voucher.code, @order)
if !adjustment.valid?
@order.errors.add(:voucher, I18n.t('split_checkout.errors.add_voucher_error'))
adjustment.errors.each { |error| @order.errors.import(error) }
return false
end
true
end
def summary_step?
params[:step] == "summary"
end
def payment_step?
params[:step] == "payment"
end
def advance_order_state
return if @order.complete?
@@ -312,14 +252,5 @@ class SplitCheckoutController < ::BaseController
def recalculate_tax
@order.create_tax_charge!
@order.update_order!
apply_voucher if @order.voucher_adjustments.present?
end
def apply_voucher
VoucherAdjustmentsService.calculate(@order)
# update order to take into account the voucher we applied
@order.update_order!
end
end

View File

@@ -65,7 +65,6 @@ module Spree
params.require(:order).permit(
:email,
:use_billing,
:customer_id,
bill_address_attributes: ::PermittedAttributes::Address.attributes,
ship_address_attributes: ::PermittedAttributes::Address.attributes
)

View File

@@ -9,9 +9,11 @@ module Spree
helper CheckoutHelper
before_action :load_order, only: [:edit, :update, :fire, :resend,
:invoice, :print, :distribution]
before_action :load_distribution_choices, only: [:new, :edit, :update, :distribution]
:invoice, :print]
before_action :load_distribution_choices, only: [:new, :edit, :update]
# Ensure that the distributor is set for an order when
before_action :ensure_distribution, only: :new
before_action :require_distributor_abn, only: :invoice
respond_to :html, :json
@@ -19,20 +21,8 @@ module Spree
def new
@order = Order.create
@order.created_by = spree_current_user
@order.generate_order_number
@order.save
redirect_to spree.distribution_admin_order_path(@order)
end
def distribution
return if order_params.blank?
on_update
@order.assign_attributes(order_params)
return unless @order.save(context: :set_distribution_step)
redirect_to spree.admin_order_customer_path(@order)
redirect_to spree.edit_admin_order_url(@order)
end
def edit
@@ -43,7 +33,12 @@ module Spree
end
def update
on_update
@order.recreate_all_fees!
unless @order.cart?
@order.create_tax_charge!
@order.update_order!
end
if params[:set_distribution_step] && @order.update(order_params)
return redirect_to spree.admin_order_customer_path(@order)
@@ -110,15 +105,6 @@ module Spree
private
def on_update
@order.recreate_all_fees!
return if @order.cart?
@order.create_tax_charge!
@order.update_order!
end
def order_params
return params[:order] if params[:order].blank?
@@ -156,6 +142,17 @@ module Spree
ocs.closed +
ocs.undated
end
def ensure_distribution
unless @order
@order = Spree::Order.new
@order.generate_order_number
@order.save!
end
return if @order.distribution_set?
render 'set_distribution', locals: { order: @order }
end
end
end
end

View File

@@ -7,6 +7,7 @@ module Spree
before_action :load_data
before_action :validate_payment_method_provider, only: [:create]
before_action :load_hubs, only: [:new, :edit, :update]
before_action :validate_calculator_preferred_value, only: [:update]
respond_to :html
@@ -16,10 +17,6 @@ module Spree
@payment_method = payment_method_class.constantize.new(base_params)
@object = @payment_method
if !base_params["calculator_type"] && gateway_params["calculator_type"]
@payment_method.calculator_type = gateway_params["calculator_type"]
end
load_hubs
if @payment_method.save
@@ -47,7 +44,6 @@ module Spree
redirect_to spree.edit_admin_payment_method_path(@payment_method)
else
respond_with(@payment_method)
clear_preference_cache
end
end
@@ -186,23 +182,33 @@ module Spree
end
end
# Ensure the calculator to be updated is the correct type
if params_for_update["calculator_type"] && params_for_update["calculator_attributes"]
add_type_to_calculator_attributes(params_for_update)
end
params_for_update
end
end
def clear_preference_cache
@payment_method.calculator.preferences.each_key do |key|
Rails.cache.delete(@payment_method.calculator.preference_cache_key(key))
def validate_calculator_preferred_value
return if calculator_preferred_values.all? do |value|
preferred_value_from_params = gateway_params.dig(:calculator_attributes, value)
preferred_value_from_params.nil? || Float(preferred_value_from_params,
exception: false)
end
flash[:error] = I18n.t(:calculator_preferred_value_error)
redirect_to spree.edit_admin_payment_method_path(@payment_method)
end
def add_type_to_calculator_attributes(hash)
hash["calculator_attributes"]["type"] = hash["calculator_type"]
def calculator_preferred_values
[
:preferred_amount,
:preferred_flat_percent,
:preferred_flat_percent,
:preferred_first_item,
:preferred_additional_item,
:preferred_max_items,
:preferred_normal_amount,
:preferred_discount_amount,
:preferred_minimal_amount
]
end
end
end

View File

@@ -1,32 +0,0 @@
# frozen_string_literal: true
class VoucherAdjustmentsController < BaseController
include CablecarResponses
def destroy
@order = current_order
@order.voucher_adjustments.find_by(id: params[:id])&.destroy
respond_to do |format|
format.cable_ready { render_voucher_section }
format.html { redirect_to checkout_step_path(:payment) }
end
end
private
# Using the power of cable_car we replace only the #voucher_section instead of reloading the page
def render_voucher_section
render(
status: :ok,
cable_ready: cable_car.replace(
"#voucher-section",
partial(
"split_checkout/voucher_section",
locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
)
)
)
end
end

View File

@@ -49,8 +49,13 @@ module Admin
{ name: 'tag_rules', icon_class: "icon-random", show: is_shop },
{ name: 'shop_preferences', icon_class: "icon-shopping-cart", show: is_shop },
{ name: 'users', icon_class: "icon-user", show: true },
{ name: 'white_label', icon_class: "icon-leaf", show: true },
]
] + [add_white_label_if_feature_activated].compact
end
def add_white_label_if_feature_activated
return nil unless OpenFoodNetwork::FeatureToggle.enabled?(:white_label)
{ name: 'white_label', icon_class: "icon-leaf", show: true }
end
end
end

View File

@@ -68,14 +68,4 @@ module ApplicationHelper
wicked_pdf_stylesheet_pack_tag(source)
end
end
def cache_with_locale(key = nil, options = {}, &block)
cache(cache_key_with_locale(key, I18n.locale), options) do
yield(block)
end
end
def cache_key_with_locale(key, locale)
Array.wrap(key) + [locale.to_s, I18nDigests.for_locale(locale)]
end
end

View File

@@ -87,10 +87,4 @@ module EnterprisesHelper
main_app.producers_url
end
end
def main_logo_link(enterprise)
return enterprise.white_label_logo_link if enterprise&.white_label_logo_link.present?
main_app.root_path
end
end

View File

@@ -29,8 +29,8 @@ module Spree
def preference_field_tag(name, value, options)
case options[:type]
when :integer, :decimal
number_field_tag(name, value, preference_field_options(options))
when :integer
text_field_tag(name, value, preference_field_options(options))
when :boolean
hidden_field_tag(name, 0) +
check_box_tag(name, 1, value, preference_field_options(options))
@@ -49,8 +49,8 @@ module Spree
def preference_field_for(form, field, options, object)
case options[:type]
when :integer, :decimal
form.number_field(field, preference_field_options(options))
when :integer
form.text_field(field, preference_field_options(options))
when :boolean
form.check_box(field, preference_field_options(options))
when :string
@@ -80,24 +80,26 @@ module Spree
end
def preference_field_options(options)
field_options =
case options[:type]
when :integer
{ size: 10, class: 'input_integer', step: 1 }
when :decimal
# Allow any number of decimal places
{ size: 10, class: 'input_integer', step: :any }
when :boolean
{}
when :string
{ size: 10, class: 'input_string fullwidth' }
when :password
{ size: 10, class: 'password_string fullwidth' }
when :text
{ rows: 15, cols: 85, class: 'fullwidth' }
else
{ size: 10, class: 'input_string fullwidth' }
end
field_options = case options[:type]
when :integer
{ size: 10,
class: 'input_integer' }
when :boolean
{}
when :string
{ size: 10,
class: 'input_string fullwidth' }
when :password
{ size: 10,
class: 'password_string fullwidth' }
when :text
{ rows: 15,
cols: 85,
class: 'fullwidth' }
else
{ size: 10,
class: 'input_string fullwidth' }
end
field_options.merge!(
readonly: options[:readonly],

View File

@@ -34,6 +34,7 @@ module Spree
link = link_to_with_icon(options[:icon], titleized_label, destination_url)
css_classes << 'tab-with-icon'
else
titleized_label = raw("<span class='text'>#{titleized_label}</span>")
link = link_to(titleized_label, destination_url)
end

View File

@@ -112,7 +112,7 @@ module Spree
event_label = I18n.t("cancel", scope: "actions")
button_link_to(event_label,
fire_admin_order_url(@order, e: "cancel"),
method: :put, icon: "icon-cancel", form_id: "cancel_order_form")
method: :put, icon: "icon-remove", form_id: "cancel_order_form")
end
def resume_event_link

View File

@@ -2,24 +2,9 @@
# Renders a report and stores it in a given blob.
class ReportJob < ApplicationJob
NOTIFICATION_TIME = 5.seconds
def perform(report_class, user, params, format, blob)
start_time = Time.zone.now
report = report_class.new(user, params, render: true)
result = report.render_as(format)
blob.store(result)
execution_time = Time.zone.now - start_time
email_result(user, blob) if execution_time > NOTIFICATION_TIME
end
def email_result(user, blob)
ReportMailer.with(
to: user.email,
blob: blob,
).report_ready.deliver_later
end
end

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
class ReportMailer < ApplicationMailer
def report_ready
# When we are in a background job then we don't have an HTTP request object
# and we need to tell ActiveStorage the hostname to generate URLs.
ActiveStorage::Current.url_options ||= url_options
@blob = params[:blob]
mail(params)
end
end

View File

@@ -1,11 +1,14 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class FlatPercentItemTotal < Spree::Calculator
extend Spree::LocalizedNumber
preference :flat_percent, :decimal, default: 0
validates :preferred_flat_percent,
numericality: true
localize_number :preferred_flat_percent
def self.description
Spree.t(:flat_percent)

View File

@@ -1,15 +1,18 @@
# frozen_string_literal: true
require 'spree/localized_number'
class Calculator::FlatPercentPerItem < Spree::Calculator
# Spree's FlatPercentItemTotal calculator sums all amounts, and then calculates a percentage
# on them.
# In the cart, we display line item individual amounts rounded, so to have consistent
# calculations we do the same internally. Here, we round adjustments at the individual
# item level first, then multiply by the item quantity.
extend Spree::LocalizedNumber
preference :flat_percent, :decimal, default: 0
validates :preferred_flat_percent,
numericality: true
localize_number :preferred_flat_percent
def self.description
I18n.t(:flat_percent_per_item)

View File

@@ -1,11 +1,14 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class FlatRate < Spree::Calculator
extend Spree::LocalizedNumber
preference :amount, :decimal, default: 0
validates :preferred_amount,
numericality: true
localize_number :preferred_amount
def self.description
I18n.t(:flat_rate_per_order)

View File

@@ -1,14 +1,17 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class FlexiRate < Spree::Calculator
extend Spree::LocalizedNumber
preference :first_item, :decimal, default: 0.0
preference :additional_item, :decimal, default: 0.0
preference :max_items, :integer, default: 0
validates :preferred_first_item,
:preferred_additional_item,
numericality: true
localize_number :preferred_first_item,
:preferred_additional_item
def self.description
I18n.t(:flexible_rate)

View File

@@ -1,11 +1,14 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class PerItem < Spree::Calculator
extend Spree::LocalizedNumber
preference :amount, :decimal, default: 0
validates :preferred_amount,
numericality: true
localize_number :preferred_amount
def self.description
I18n.t(:flat_rate_per_item)

View File

@@ -1,15 +1,18 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class PriceSack < Spree::Calculator
extend Spree::LocalizedNumber
preference :minimal_amount, :decimal, default: 0
preference :normal_amount, :decimal, default: 0
preference :discount_amount, :decimal, default: 0
validates :preferred_minimal_amount,
:preferred_normal_amount,
:preferred_discount_amount,
numericality: true
localize_number :preferred_minimal_amount,
:preferred_normal_amount,
:preferred_discount_amount
def self.description
I18n.t(:price_sack)

View File

@@ -1,10 +1,15 @@
# frozen_string_literal: true
require 'spree/localized_number'
module Calculator
class Weight < Spree::Calculator
extend Spree::LocalizedNumber
preference :unit_from_list, :string, default: "kg"
preference :per_unit, :decimal, default: 0.0
localize_number :preferred_per_unit
def self.description
I18n.t('spree.weight')
end

View File

@@ -83,19 +83,4 @@ class ContentConfiguration < Spree::Preferences::Configuration
# User Guide
preference :user_guide_link, :string, default: 'https://guide.openfoodnetwork.org/'
# ContentConfig Caching
preference :updated_at_timestamp, :integer, default: Time.zone.today.to_time.to_i
def updated_at
Time.zone.at updated_at_timestamp
end
def updated_at=(time)
self.updated_at_timestamp = time.to_i
end
def cache_key
"ContentConfig:#{updated_at_timestamp}"
end
end

View File

@@ -15,10 +15,6 @@ class Enterprise < ApplicationRecord
medium: { resize_to_fill: [720, 156] },
large: { resize_to_fill: [1200, 260] },
}.freeze
WHITE_LABEL_LOGO_SIZES = {
default: { gravity: "Center", resize_to_fill: [217, 44] },
mobile: { gravity: "Center", resize_to_fill: [75, 26] },
}.freeze
VALID_INSTAGRAM_REGEX = %r{\A[a-zA-Z0-9._]{1,30}([^/-]*)\z}
searchable_attributes :sells, :is_primary_producer, :name
@@ -88,7 +84,6 @@ class Enterprise < ApplicationRecord
has_one_attached :logo
has_one_attached :promo_image
has_one_attached :terms_and_conditions
has_one_attached :white_label_logo
validates :logo,
processable_image: true,
@@ -307,14 +302,6 @@ class Enterprise < ApplicationRecord
)
end
def white_label_logo_url(name = :default)
return unless white_label_logo.variable?
Rails.application.routes.url_helpers.url_for(
white_label_logo.variant(WHITE_LABEL_LOGO_SIZES[name])
)
end
def website
strip_url self[:website]
end

View File

@@ -58,12 +58,6 @@ class EnterpriseFee < ApplicationRecord
elsif inherits_tax_category_changed?
self.tax_category_id = nil if inherits_tax_category?
end
if inherits_tax_category? && PER_ORDER_CALCULATORS.include?(calculator_type)
errors.add(:base, :inherit_tax_requires_per_item_calculator)
throw :abort
end
true
end
end

View File

@@ -86,9 +86,9 @@ class Exchange < ApplicationRecord
exchange = dup
exchange.order_cycle = new_order_cycle
exchange.enterprise_fee_ids = enterprise_fee_ids
exchange.variant_ids = variant_ids
exchange.tag_ids = tag_ids
exchange.save!
clone_all_exchange_variants(exchange.id)
exchange
end
@@ -105,17 +105,4 @@ class Exchange < ApplicationRecord
receiver.touch_later
end
private
# An Order Cycle can have thousands of ExchangeVariants.
# It's a simple association without any callbacks on creation. So we can
# insert in bulk and improve the performance tenfold for large order cycles.
def clone_all_exchange_variants(exchange_id)
return unless variant_ids.any?
ExchangeVariant.insert_all( # rubocop:disable Rails/SkipsModelValidations
variant_ids.map{ |variant_id| { variant_id: variant_id, exchange_id: exchange_id } }
)
end
end

View File

@@ -2,9 +2,6 @@
# Stores a generated report.
class ReportBlob < ActiveStorage::Blob
# AWS S3 limits URL expiry to one week.
LIFETIME = 1.week
def self.create_for_upload_later!(filename)
# ActiveStorage discourages modifying a blob later but we need a blob
# before we know anything about the report file. It enables us to use the
@@ -15,7 +12,7 @@ class ReportBlob < ActiveStorage::Blob
checksum: "0",
content_type: content_type(filename),
).tap do |blob|
ActiveStorage::PurgeJob.set(wait: LIFETIME).perform_later(blob)
ActiveStorage::PurgeJob.set(wait: 1.month).perform_later(blob)
end
end
@@ -34,10 +31,6 @@ class ReportBlob < ActiveStorage::Blob
end
def result
@result ||= download.force_encoding(Encoding::UTF_8)
end
def expiring_service_url
url(expires_in: LIFETIME)
@result ||= download
end
end

View File

@@ -274,7 +274,7 @@ module Spree
# Enterprise User can access orders that are placed inside a OC they coordinate
order.order_cycle&.coordinated_by?(user)
end
can [:admin, :bulk_management, :managed, :distribution], Spree::Order do
can [:admin, :bulk_management, :managed], Spree::Order do
user.admin? || user.enterprises.any?(&:is_distributor)
end
can [:admin, :create, :show, :poll], :invoice

View File

@@ -4,7 +4,7 @@ module Spree
class Address < ApplicationRecord
include AddressDisplay
searchable_attributes :firstname, :lastname, :phone, :full_name
searchable_attributes :firstname, :lastname, :phone
searchable_associations :country, :state
belongs_to :country, class_name: "Spree::Country"
@@ -28,12 +28,6 @@ module Spree
alias_attribute :last_name, :lastname
delegate :name, to: :state, prefix: true, allow_nil: true
ransacker :full_name, formatter: proc { |value| value.to_s } do |parent|
Arel::Nodes::SqlLiteral.new(
"CONCAT(#{parent.table_name}.firstname, ' ', #{parent.table_name}.lastname)"
)
end
def self.default
new(country: DefaultCountry.country)
end

View File

@@ -42,6 +42,9 @@ module Spree
belongs_to :order, class_name: "Spree::Order"
belongs_to :tax_category, class_name: 'Spree::TaxCategory'
belongs_to :tax_rate, -> { where spree_adjustments: { originator_type: 'Spree::TaxRate' } },
foreign_key: 'originator_id'
validates :label, presence: true
validates :amount, numericality: true

View File

@@ -88,6 +88,7 @@ module Spree
# Default mail headers settings
preference :mails_from, :string, default: 'ofn@example.com'
preference :mail_bcc, :string, default: 'ofn@example.com'
preference :intercept_email, :string, default: nil
# Default smtp settings
preference :mail_host, :string, default: 'localhost'

View File

@@ -62,13 +62,6 @@ module Spree
has_many :line_item_adjustments, through: :line_items, source: :adjustments
has_many :shipment_adjustments, through: :shipments, source: :adjustments
has_many :all_adjustments, class_name: 'Spree::Adjustment', dependent: :destroy
has_many :voucher_adjustments,
-> {
where(originator_type: 'Voucher')
.order("#{Spree::Adjustment.table_name}.created_at ASC")
},
class_name: 'Spree::Adjustment',
dependent: :destroy
belongs_to :order_cycle
belongs_to :distributor, class_name: 'Enterprise'
@@ -104,8 +97,6 @@ module Spree
validates :email, presence: true,
format: /\A([\w.%+\-']+)@([\w\-]+\.)+(\w{2,})\z/i,
if: :require_email
validates :order_cycle, presence: true, on: :set_distribution_step
validates :distributor, presence: true, on: :set_distribution_step
make_permalink field: :number

View File

@@ -63,7 +63,7 @@ module Spree
# first unshipped that's leaving from a stock_location that stocks this variant
def determine_target_shipment(variant)
target_shipment = order.shipments.detect do |shipment|
(shipment.ready? || shipment.pending?) && shipment.contains?(variant)
(shipment.ready? || shipment.pending?) && shipment.include?(variant)
end
target_shipment || order.shipments.detect do |shipment|

View File

@@ -17,7 +17,6 @@ module Spree
validates :name, presence: true
validate :distributor_validation
validates_associated :calculator
after_initialize :init
@@ -41,8 +40,9 @@ module Spree
where(id: non_unique_matches.map(&:id))
}
scope :for_distributor, ->(distributor) {
joins(:distributors).where('enterprises.id = ?', distributor)
scope :for_distributor, lambda { |distributor|
joins(:distributors).
where('enterprises.id = ?', distributor)
}
scope :for_subscriptions, -> { where(type: Subscription::ALLOWED_PAYMENT_METHOD_TYPES) }

View File

@@ -22,8 +22,7 @@ module Spree
when :password
self[:value].to_s
when :decimal
BigDecimal(self[:value].to_s, exception: false)&.round(2, BigDecimal::ROUND_HALF_UP) ||
self[:value]
BigDecimal(self[:value].to_s).round(2, BigDecimal::ROUND_HALF_UP)
when :integer
self[:value].to_i
when :boolean

View File

@@ -117,7 +117,7 @@ module Spree
value.to_s
when :decimal
value = 0 if value.blank?
BigDecimal(value.to_s, exception: false)&.round(2, BigDecimal::ROUND_HALF_UP) || value
BigDecimal(value.to_s).round(2, BigDecimal::ROUND_HALF_UP)
when :integer
value.to_i
when :boolean

View File

@@ -246,7 +246,7 @@ module Spree
@tracking_url ||= shipping_method.build_tracking_url(tracking)
end
def contains?(variant)
def include?(variant)
inventory_units_for(variant).present?
end

View File

@@ -61,7 +61,7 @@ module Spree
# Here we allow checkout with shipping methods without zones (see issue #3928 for details)
# and also checkout with addresses outside of the zones of the selected shipping method
# This method could be used, like in Spree, to validate shipping method zones on checkout.
def delivers_to?(address)
def include?(address)
address.present?
end

View File

@@ -69,8 +69,7 @@ module Spree
return 0 unless category
address ||= Address.new(country_id: DefaultCountry.id)
rate = category.tax_rates
.detect { |tax_rate| tax_rate.zone.contains_address? address }.try(:amount)
rate = category.tax_rates.detect { |tax_rate| tax_rate.zone.include? address }.try(:amount)
rate || 0
end

View File

@@ -24,7 +24,7 @@ module Spree
# do nothing - just here to satisfy the form
end
def contains_address?(address)
def include?(address)
return false unless address
members.any? do |zone_member|
@@ -44,7 +44,7 @@ module Spree
def self.match(address)
return unless matches = includes(:zone_members).
order('zone_members_count', 'created_at').
select { |zone| zone.contains_address? address }
select { |zone| zone.include? address }
['state', 'country'].each do |zone_kind|
if match = matches.detect { |zone| zone_kind == zone.kind }

View File

@@ -1,15 +1,8 @@
# frozen_string_literal: false
class Voucher < ApplicationRecord
acts_as_paranoid
belongs_to :enterprise
has_many :adjustments,
as: :originator,
class_name: 'Spree::Adjustment',
dependent: :nullify
validates :code, presence: true, uniqueness: { scope: :enterprise_id }
def value
@@ -19,31 +12,4 @@ class Voucher < ApplicationRecord
def display_value
Spree::Money.new(value)
end
# Ideally we would use `include CalculatedAdjustments` to be consistent with other adjustments,
# but vouchers have complicated calculation so we can't easily use Spree::Calculator. We keep
# the same method to stay as consistent as possible.
#
# Creates a new voucher adjustment for the given order
def create_adjustment(label, order)
amount = compute_amount(order)
adjustment_attributes = {
amount: amount,
originator: self,
order: order,
label: label,
mandatory: false,
state: "open",
tax_category: nil
}
order.adjustments.create(adjustment_attributes)
end
# We limit adjustment to the maximum amount needed to cover the order, ie if the voucher
# covers more than the order.total we only need to create an adjustment covering the order.total
def compute_amount(order)
-value.clamp(0, order.total)
end
end

View File

@@ -2,7 +2,7 @@
class BulkActionsInOrdersListReflex < ApplicationReflex
def resend_confirmation_email(order_ids)
editable_orders.where(id: order_ids).find_each do |o|
orders(order_ids).find_each do |o|
Spree::OrderMailer.confirm_email_for_customer(o.id, true).deliver_later if can? :resend, o
end
@@ -11,7 +11,7 @@ class BulkActionsInOrdersListReflex < ApplicationReflex
def send_invoice(order_ids)
count = 0
editable_orders.where(id: order_ids).find_each do |o|
orders(order_ids).find_each do |o|
next unless o.distributor.can_invoice? && (o.resumed? || o.complete?)
Spree::OrderMailer.invoice_email(o.id).deliver_later
@@ -29,7 +29,7 @@ class BulkActionsInOrdersListReflex < ApplicationReflex
morph "#flashes", render(partial: "shared/flashes", locals: { flashes: flash })
end
def editable_orders
Permissions::Order.new(current_user).editable_orders
def orders(order_ids)
Spree::Order.where(id: order_ids)
end
end

View File

@@ -2,7 +2,7 @@
class CancelOrdersReflex < ApplicationReflex
def confirm(params)
OrdersBulkCancelService.new(params, current_user).call
OrdersBulkCancelService.new(params).call
cable_ready.dispatch_event(name: "modal:close")
# flash[:success] = Spree.t(:order_updated)
end

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
module EnterpriseConcern
extend ActiveSupport::Concern
included do
before_reflex do
@enterprise = Enterprise.find_by(permalink: params[:id])
authorize! :update, @enterprise
end
end
end

View File

@@ -1,26 +0,0 @@
# frozen_string_literal: true
class WhiteLabelReflex < ApplicationReflex
include EnterpriseConcern
delegate :view_context, to: :controller
def remove_logo
@enterprise.update!(white_label_logo: nil)
# delete the white_label_logo_link attribute as well since it has no meaning without the logo
@enterprise.update!(white_label_logo_link: "")
f = ActionView::Helpers::FormBuilder.new(:enterprise, @enterprise, view_context, {})
html = with_locale {
render(partial: "admin/enterprises/form/white_label",
locals: { f: f, enterprise: @enterprise })
}
morph "#white_label_panel", html
flash[:success] = with_locale {
I18n.t("admin.enterprises.form.white_label.remove_logo_success")
}
cable_ready.dispatch_event(name: "modal:close")
morph "#flashes", render(partial: "shared/flashes", locals: { flashes: flash })
end
end

View File

@@ -14,8 +14,7 @@ module Api
:logo, :promo_image, :terms_and_conditions,
:terms_and_conditions_file_name, :terms_and_conditions_updated_at,
:preferred_invoice_order_by_supplier, :preferred_product_low_stock_display,
:visible, :hide_ofn_navigation, :white_label_logo,
:white_label_logo_link
:visible, :hide_ofn_navigation
has_one :owner, serializer: Api::Admin::UserSerializer
has_many :users, serializer: Api::Admin::UserSerializer
@@ -30,10 +29,6 @@ module Api
attachment_urls(object.promo_image, Enterprise::PROMO_IMAGE_SIZES)
end
def white_label_logo
attachment_urls(object.white_label_logo, Enterprise::WHITE_LABEL_LOGO_SIZES)
end
def terms_and_conditions
return unless object.terms_and_conditions.attached?

View File

@@ -5,26 +5,12 @@ module Api
class ProductSerializer < ActiveModel::Serializer
attributes :id, :name, :sku, :variant_unit, :variant_unit_scale, :variant_unit_name,
:inherits_properties, :on_hand, :price, :available_on, :permalink_live,
:tax_category_id, :import_date, :image_url, :thumb_url, :variants, :master
:tax_category_id, :import_date, :image_url, :thumb_url
has_one :supplier, key: :producer_id, embed: :id
has_one :primary_taxon, key: :category_id, embed: :id
def variants
ActiveModel::ArraySerializer.new(
object.variants,
each_serializer: Api::Admin::VariantSerializer,
image: thumb_url,
stock_location: Spree::StockLocation.first
)
end
def master
Api::Admin::VariantSerializer.new(
object.master,
image: thumb_url
)
end
has_many :variants, key: :variants, serializer: Api::Admin::VariantSerializer
has_one :master, serializer: Api::Admin::VariantSerializer
def image_url
object.images.first&.url(:product) || "/noimage/product.png"

View File

@@ -33,7 +33,7 @@ module Api
end
def image
options[:image] || object.product.images.first&.url(:mini)
object.product.images.first&.url(:mini)
end
def in_stock
@@ -43,13 +43,13 @@ module Api
def stock_location_id
return if object.stock_items.empty?
options[:stock_location]&.id || object.stock_items.first.stock_location.id
object.stock_items.first.stock_location.id
end
def stock_location_name
return if object.stock_items.empty?
options[:stock_location]&.name || object.stock_items.first.stock_location.name
object.stock_items.first.stock_location.name
end
def variant_overrides_count

View File

@@ -10,7 +10,7 @@ module Api
:phone, :whatsapp_phone, :whatsapp_url, :visible, :email_address, :hash, :logo,
:promo_image, :path, :category, :active, :producers, :orders_close_at, :hubs,
:taxons, :supplied_taxons, :pickup, :delivery, :preferred_product_low_stock_display,
:hide_ofn_navigation, :white_label_logo, :white_label_logo_link
:hide_ofn_navigation
has_one :address, serializer: Api::AddressSerializer
has_many :supplied_properties, serializer: Api::PropertySerializer
@@ -49,10 +49,6 @@ module Api
enterprise.promo_image_url(:large)
end
def white_label_logo
enterprise.white_label_logo_url
end
def path
enterprise_shop_path(enterprise)
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
class FilePathSanitizer
def sanitize(file_path, on_error: nil)
pathname = Pathname.new(file_path)
return pathname.realpath if pathname.file?
on_error&.call
false
end
end

View File

@@ -22,6 +22,7 @@ class MailConfiguration
secure_connection_type: ENV.fetch('MAIL_SECURE_CONNECTION', 'None'),
mails_from: ENV.fetch('MAILS_FROM', "no-reply@#{ENV.fetch('MAIL_DOMAIN')}"),
mail_bcc: ENV.fetch('MAIL_BCC', ''),
intercept_email: ''
}
end

View File

@@ -1,24 +1,17 @@
# frozen_string_literal: true
class OrdersBulkCancelService
def initialize(params, current_user)
def initialize(params)
@order_ids = params[:order_ids]
@current_user = current_user
@send_cancellation_email = params[:send_cancellation_email]
@restock_items = params[:restock_items]
end
def call
editable_orders.where(id: @order_ids).find_each do |order|
Spree::Order.where(id: @order_ids).find_each do |order|
order.send_cancellation_email = @send_cancellation_email
order.restock_items = @restock_items
order.cancel
end
end
private
def editable_orders
Permissions::Order.new(@current_user).editable_orders
end
end

View File

@@ -31,7 +31,9 @@ module Permissions
end
def visible_line_items
editable_line_items.or(produced_line_items)
Spree::LineItem.where(id:
editable_line_items.select(:id) |
produced_line_items.select("spree_line_items.id"))
end
# Any line items that I can edit

View File

@@ -35,7 +35,7 @@ module PermittedAttributes
:show_customer_names_to_suppliers, :preferred_shopfront_product_sorting_method,
:preferred_invoice_order_by_supplier,
:preferred_product_low_stock_display,
:hide_ofn_navigation, :white_label_logo, :white_label_logo_link
:hide_ofn_navigation
]
end
end

View File

@@ -1,75 +0,0 @@
# frozen_string_literal: true
class VoucherAdjustmentsService
def self.calculate(order)
return if order.nil?
# Find open Voucher Adjustment
return if order.voucher_adjustments.empty?
# We only support one voucher per order right now, we could just loop on voucher_adjustments
adjustment = order.voucher_adjustments.first
# Recalculate value
amount = adjustment.originator.compute_amount(order)
# It is quite possible to have an order with both tax included in and tax excluded from price.
# We should be able to caculate the relevant amount apply the current calculation.
#
# For now we just assume it is either all tax included in price or all tax excluded from price.
if order.additional_tax_total.positive?
handle_tax_excluded_from_price(order, amount)
else
handle_tax_included_in_price(order, amount)
end
# Move to closed state
adjustment.close
end
def self.handle_tax_excluded_from_price(order, amount)
voucher_rate = amount / order.total
# Adding the voucher tax part
tax_amount = voucher_rate * order.additional_tax_total
adjustment = order.voucher_adjustments.first
adjustment_attributes = {
amount: tax_amount,
originator: adjustment.originator,
order: order,
label: "Tax #{adjustment.label}",
mandatory: false,
state: 'closed',
tax_category: nil,
included_tax: 0
}
order.adjustments.create(adjustment_attributes)
# Update the adjustment amount
amount = voucher_rate * (order.total - order.additional_tax_total)
adjustment.update_columns(
amount: amount,
updated_at: Time.zone.now
)
end
def self.handle_tax_included_in_price(order, amount)
voucher_rate = amount / order.total
included_tax = voucher_rate * order.included_tax_total
# Update Adjustment
adjustment = order.voucher_adjustments.first
return unless amount != adjustment.amount || included_tax != 0
adjustment.update_columns(
amount: amount,
included_tax: included_tax,
updated_at: Time.zone.now
)
end
private_class_method :handle_tax_included_in_price, :handle_tax_excluded_from_price
end

View File

@@ -8,6 +8,6 @@
- @preference_sections.each do |preference_section|
= render 'fieldset', name: preference_section[:name], preferences: preference_section[:preferences]
.form-buttons.filter-actions.actions
.form-buttons.filter-actions.actions{"data-hook" => "buttons"}
= button t(:update), 'icon-refresh'
= link_to_with_icon 'icon-remove', t(:cancel), main_app.edit_admin_contents_path, class: 'button'

View File

@@ -10,7 +10,7 @@
%col{style: "width: 18%;"}/
%col{style: "width: 25%;"}/
%thead
%tr
%tr{"data-hook" => "enterprises_header"}
%th= t('.name')
%th= t('.role')
- if spree_current_user.admin?
@@ -32,7 +32,7 @@
%td= enterprise_form.check_box :visible, {}, 'public', 'hidden'
- if spree_current_user.admin?
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
%td
%td{"data-hook" => "admin_users_index_row_actions"}
= render 'actions', enterprise: enterprise
- if @enterprises.empty?
%tr

View File

@@ -1,21 +1,22 @@
%form#add_manager_modal{ 'data-reflex': 'submit->InviteManager#invite', 'data-reflex-serialize-form': true }
.margin-bottom-30.text-center
.text-big
= t('js.admin.modals.invite_title')
%div#add_manager_modal
%form{ "data-reflex": "submit->InviteManager#invite", "data-reflex-serialize-form": true }
.margin-bottom-30.text-center
.text-big
= t('js.admin.modals.invite_title')
- if success
%p.alert-box.ok= t('user_invited', email: email)
- if error
%p.alert-box.error= error
= text_field_tag :email, nil, class: 'fullwidth margin-bottom-20'
= hidden_field_tag :enterprise_id, @enterprise&.id || enterprise.id
.modal-actions
- if success
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->help-modal#close" }
- else
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->help-modal#close" }
= submit_tag "#{t('js.admin.modals.invite')}"
%p.alert-box.ok= t('user_invited', email: email)
- if error
%p.alert-box.error= error
= text_field_tag :email, nil, class: 'fullwidth margin-bottom-20'
= hidden_field_tag :enterprise_id, @enterprise&.id || enterprise.id
.modal-actions
- if success
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->help-modal#close" }
- else
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->help-modal#close" }
= submit_tag "#{t('js.admin.modals.invite')}"

View File

@@ -1,31 +1,6 @@
- @object ||= enterprise
.row
.three.columns.alpha
= f.label :hide_ofn_navigation, t('.hide_ofn_navigation')
.three.columns
= f.check_box :hide_ofn_navigation, { "data-controller": "checkbox-display", "data-checkbox-display-target-id-value": "white_label_logo" }
= f.check_box :hide_ofn_navigation
%div{id: "white_label_logo"}
.row
.three.columns.alpha
= f.label :white_label_logo, t('.upload_logo')
.three.columns
= image_tag @object.white_label_logo_url if @object.white_label_logo.present?
= f.file_field :white_label_logo, accept: "image/*"
- if @object.white_label_logo.present?
%button.button.small{ type: "button", "data-controller": "modal-link", "data-action": "click->modal-link#open", "data-modal-link-target-value": "remove_logo" }
= t('.remove_logo')
- if @object.white_label_logo.present?
.row
.three.columns.alpha
= f.label :white_label_logo_link, t('.white_label_logo_link_label')
.three.columns
= f.text_field :white_label_logo_link
- if @object.white_label_logo.present?
= render ConfirmModalComponent.new(id: "remove_logo", confirm_reflexes: "click->WhiteLabel#remove_logo" ) do
.margin-bottom-30
= t('.remove_logo_confirm')

View File

@@ -20,5 +20,5 @@
= check_box_tag 'preferences[enterprise_number_required_on_invoices?]', '1', Spree::Config[:enterprise_number_required_on_invoices?]
= label_tag nil, t('.enterprise_number_required_on_invoices?')
.form-buttons
.form-buttons{"data-hook" => "buttons"}
= button t(:update), 'icon-refresh'

View File

@@ -23,5 +23,5 @@
= preference_field_tag("preferences[#{:matomo_tag_manager_url}]", Spree::Config[:matomo_tag_manager_url], type: Spree::Config.preference_type(:matomo_tag_manager_url))
.warning.note= t('.config_instructions_tag_manager_html')
.form-buttons
.form-buttons{"data-hook" => "buttons"}
= button t(:update), 'icon-refresh'

View File

@@ -3,4 +3,4 @@
{{ enterprise.name }}
= "{{ enterprise.issues_summary_#{type} ? '('+enterprise.issues_summary_#{type}+')' : '' }}"
= f.submit t(".add_#{type}"), 'ng-click' => "add#{type.capitalize}($event)", 'ng-disabled' => "!new_#{type}_id || !OrderCycle.novel#{type.capitalize}(new_#{type}_id)"
= f.submit t(".add_#{type}"), 'ng-click' => "add#{type.capitalize}($event)", 'ng-disabled' => "!new_#{type}_id || !OrderCycle.novel#{type.capitalize}(new_#{type}_id)", "class": "secondary"

View File

@@ -26,15 +26,16 @@
= f.submit t('.add_fee'), 'ng-click' => 'addExchangeFee($event, exchange)', 'ng-hide' => '!enterprises[exchange.enterprise_id].managed && !order_cycle.viewing_as_coordinator'
%td.actions
%a{'ng-click' => 'removeExchange($event, exchange)', :class => "icon-trash no-text remove-exchange"}
.flex
%a{'ng-click' => 'removeExchange($event, exchange)', :class => "icon-trash no-text remove-exchange"}
- if type == 'supplier'
%tr.panel-row{ object: "exchange",
panels: "{products: 'exchange_products_supplied'}",
locals: "$index,exchangeTotalVariants,order_cycle,exchange,enterprises,setExchangeVariants,selectAllVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
colspan: 4 }
colspan: if feature?(:admin_style_v2, spree_current_user) then 5 else 4 end }
- if type == 'distributor'
%tr.panel-row{ object: "exchange",
panels: "{products: 'exchange_products_distributed', tags: 'exchange_tags'}",
locals: "$index,exchangeTotalVariants,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
colspan: 5 }
colspan: if feature?(:admin_style_v2, spree_current_user) then 6 else 5 end }

View File

@@ -1,16 +1,16 @@
%colgroup
%col{ ng: { show: 'columns.name.visible' } }
%col{ ng: { show: 'columns.schedules.visible' } }
%col{ ng: { show: 'columns.open.visible' }, style: 'width: 20%;' }
%col{ ng: { show: 'columns.close.visible' }, style: 'width: 20%;' }
%col{ ng: { show: 'columns.open.visible' } }
%col{ ng: { show: 'columns.close.visible' } }
- unless simple_index
%col{ ng: { show: 'columns.producers.visible' } }
%col{ ng: { show: 'columns.coordinator.visible' } }
%col{ ng: { show: 'columns.shops.visible' } }
%col{ ng: { show: 'columns.products.visible' } }
%col{ style: 'width: 5%;' }
%col{ style: 'width: 5%;' }
%col{ style: 'width: 5%;' }
%col
%col
%col
%thead
%tr
@@ -32,5 +32,3 @@
%th{ ng: { show: 'columns.products.visible' } }
=t :products
%th.actions
%th.actions
%th.actions

View File

@@ -32,8 +32,9 @@
= t('.variants')
%td.actions
%a.edit-order-cycle.icon-edit.no-text{ ng: { href: '{{orderCycle.edit_path}}'}, 'ofn-with-tip' => t(:edit) }
%td.actions{ ng: { if: 'orderCycle.viewing_as_coordinator' } }
%a.clone-order-cycle.icon-copy.no-text{ ng: { href: '{{orderCycle.clone_path}}'}, 'ofn-with-tip' => t(:clone) }
%td.actions{ ng: { if: 'orderCycle.deletable && orderCycle.viewing_as_coordinator' }}
%a.delete-order-cycle.icon-trash.no-text{ ng: { href: '{{orderCycle.delete_path}}'}, data: { method: 'delete', confirm: t(:are_you_sure) }, 'ofn-with-tip' => t(:remove) }
.flex
%a.edit-order-cycle.icon-edit.no-text{ ng: { href: '{{orderCycle.edit_path}}'}, 'ofn-with-tip' => t(:edit) }
%div{ ng: { if: 'orderCycle.viewing_as_coordinator' } }
%a.clone-order-cycle.icon-copy.no-text{ ng: { href: '{{orderCycle.clone_path}}'}, 'ofn-with-tip' => t(:clone) }
%div{ ng: { if: 'orderCycle.deletable && orderCycle.viewing_as_coordinator' }}
%a.delete-order-cycle.icon-trash.no-text{ ng: { href: '{{orderCycle.delete_path}}'}, data: { method: 'delete', confirm: t(:are_you_sure) }, 'ofn-with-tip' => t(:remove) }

View File

@@ -1,12 +1,12 @@
%fieldset.no-border-top
.add_producer_properties
.add_producer_properties{"data-hook" => "add_producer_properties"}
= image_pack_tag 'spinner.gif', :plugin => 'spree', :style => 'display:none;', :id => 'busy_indicator'
%table.index.sortable{"data-sortable-link" => main_app.update_positions_admin_enterprise_producer_properties_url(@enterprise)}
%table.index.sortable{"data-hook" => "", "data-sortable-link" => main_app.update_positions_admin_enterprise_producer_properties_url(@enterprise)}
%thead
%tr
%tr{"data-hook" => "producer_properties_header"}
%th{colspan: "2"}= t('admin.products.properties.property_name')
%th= t('admin.description')
%th.actions
%tbody#producer_properties
%tbody#producer_properties{"data-hook" => ""}
= f.fields_for :producer_properties do |pp_form|
= render 'admin/producer_properties/producer_property_fields', f: pp_form

View File

@@ -1,5 +1,5 @@
-# admin/admin.js.erb in spree requires id to start with "spree_" for sortable tables
%tr.product_property.fields{id: "spree_#{dom_id(f.object)}"}
%tr.product_property.fields{"data-hook" => "producer_property", id: "spree_#{dom_id(f.object)}"}
%td.no-border
%span.handle
= f.hidden_field :id

View File

@@ -1,5 +1,5 @@
- content_for :sub_menu do
%ul#sub_nav.inline-menu
%ul#sub_nav.inline-menu{"data-hook" => "admin_enterprise_sub_tabs"}
= tab :enterprises, url: main_app.admin_enterprises_path
= tab :enterprise_relationships, url: main_app.admin_enterprise_relationships_path
- if ENV["OPENID_APP_ID"].present? && ENV["OPENID_APP_SECRET"].present?

View File

@@ -1,4 +1,4 @@
- content_for :sub_menu do
%ul#sub_nav.inline-menu
%ul#sub_nav.inline-menu{"data-hook" => "admin_user_sub_tabs"}
= tab :users, url: spree.admin_users_path
= tab :roles, url: main_app.admin_enterprise_roles_path, match_path: '/enterprise_roles'

View File

@@ -14,7 +14,7 @@
= f.label :stripe_connect_enabled, t('.stripe_connect_enabled')
= f.check_box :stripe_connect_enabled, disabled: disabled
.row
.twelve.columns.alpha.omega.form-buttons
.twelve.columns.alpha.omega.form-buttons{"data-hook" => "buttons"}
= button t(:update), 'icon-refresh', value: "update"
%fieldset.no-border-bottom

View File

@@ -77,7 +77,7 @@
%td.price.align-center {{ item.price_estimate | localizeCurrency }}
%td.quantity {{ item.quantity }}
%td.total.align-center {{ (item.price_estimate * item.quantity) | localizeCurrency }}
%tbody#subtotal.no-border-top
%tbody#subtotal.no-border-top{"data-hook" => "admin_order_form_subtotal"}
%tr#subtotal-row
%td{:colspan => "3"}
%b
@@ -85,7 +85,7 @@
\:
%td.total.align-center
%span {{ subscription.estimatedSubtotal() | localizeCurrency }}
%tbody#order-total.grand-total.no-border-top
%tbody#order-total.grand-total.no-border-top{"data-hook" => "admin_order_form_total"}
%tr
%td{:colspan => "3"}
%b

View File

@@ -25,7 +25,7 @@
%td.total.align-center {{ (item.price_estimate * item.quantity) | localizeCurrency }}
%td.actions
%a.delete-item.icon-trash.no-text{ ng: { click: 'removeSubscriptionLineItem(item)'}, :href => "javascript:void(0)" }
%tbody#subtotal.no-border-top
%tbody#subtotal.no-border-top{"data-hook" => "admin_order_form_subtotal"}
%tr#subtotal-row
%td{:colspan => "3"}
%b
@@ -43,7 +43,7 @@
%td.total.align-center
%span#order_fees {{ subscription.estimatedFees() | localizeCurrency }}
%td.actions
%tbody#order-total.grand-total.no-border-top
%tbody#order-total.grand-total.no-border-top{"data-hook" => "admin_order_form_total"}
%tr
%td{:colspan => "3"}
%b

View File

@@ -1,2 +1 @@
= cache do
%img.spinner{ src: image_pack_path("spinning-circles.svg"), style: "max-width: 100%" }
%img.spinner{ src: image_pack_path("spinning-circles.svg"), style: "max-width: 100%" }

View File

@@ -1,9 +1,8 @@
= cache_with_locale "sitename:#{Spree::Config.site_name}" do
#tagline
.row
.small-12.text-center.columns
%h1
%img{src: image_pack_path("logo-white-notext.png"), title: Spree::Config.site_name}
%br/
%a.button.transparent{href: "/shops"}
= t :home_shop
#tagline
.row
.small-12.text-center.columns
%h1
%img{src: image_pack_path("logo-white-notext.png"), title: Spree::Config.site_name}
%br/
%a.button.transparent{href: "/shops"}
= t :home_shop

View File

@@ -1,92 +1,91 @@
= cache_with_locale do
.row.active_table_row{"ng-if" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : open()}"}
.columns.small-12.fat.text-center{"ng-show" => "open() && shopfront_loading"}
%p.fullwidth
= render partial: "components/spinner"
.row.active_table_row{"ng-if" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : open()}"}
.columns.small-12.fat.text-center{"ng-show" => "open() && shopfront_loading"}
%p.fullwidth
= render partial: "components/spinner"
.columns.small-12.medium-7.large-7.fat{"ng-show" => "open() && !shopfront_loading"}
/ Will add in long description available once clean up HTML formatting producer.long_description
%div{"ng-if" => "::producer.description"}
%label
= t :producers_about
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
%p.text-small{ "ng-bind" => "::producer.description"}
%div.show-for-medium-up{"ng-if" => "::producer.description.length==0"}
%label &nbsp;
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
.columns.small-12.medium-7.large-7.fat{"ng-show" => "open() && !shopfront_loading"}
/ Will add in long description available once clean up HTML formatting producer.long_description
%div{"ng-if" => "::producer.description"}
%label
= t :producers_about
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
%p.text-small{ "ng-bind" => "::producer.description"}
%div.show-for-medium-up{"ng-if" => "::producer.description.length==0"}
%label &nbsp;
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
.columns.small-12.medium-5.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
.columns.small-12.medium-5.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::producer.supplied_taxons"}
%label
= t :producers_buy
%p.trans-sentence
%div
%span.fat-taxons{"ng-repeat" => "taxon in producer.supplied_taxons"}
%span{"ng-bind" => "::taxon.name"}
%div
%span.fat-properties{"ng-repeat" => "property in producer.supplied_properties"}
%span{"ng-bind" => "property.presentation"}
%div{"ng-if" => "::producer.supplied_taxons"}
%label
= t :producers_buy
%p.trans-sentence
%div
%span.fat-taxons{"ng-repeat" => "taxon in producer.supplied_taxons"}
%span{"ng-bind" => "::taxon.name"}
%div
%span.fat-properties{"ng-repeat" => "property in producer.supplied_properties"}
%span{"ng-bind" => "property.presentation"}
%div.show-for-medium-up{"ng-if" => "producer.supplied_taxons.length==0"}
&nbsp;
%div.show-for-medium-up{"ng-if" => "producer.supplied_taxons.length==0"}
&nbsp;
%div{"ng-if" => "::producer.email_address || producer.website || producer.phone"}
%label
= t :producers_contact
%div{"ng-if" => "::producer.email_address || producer.website || producer.phone"}
%label
= t :producers_contact
%p.word-wrap{"ng-if" => "::producer.phone"}
= t :producers_contact_phone
%span{"ng-bind" => "::producer.phone"}
%p.word-wrap{"ng-if" => "::producer.phone"}
= t :producers_contact_phone
%span{"ng-bind" => "::producer.phone"}
%p.word-wrap{"ng-if" => "::producer.whatsapp_phone"}
%a{"ng-href" => "{{::producer.whatsapp_url}}", target: "_blank"}
%img{ src: image_pack_path("social-logos/whatsapp.svg") }
%span{"ng-bind" => "::producer.whatsapp_phone"}
%p.word-wrap{"ng-if" => "::producer.whatsapp_phone"}
%a{"ng-href" => "{{::producer.whatsapp_url}}", target: "_blank"}
%img{ src: image_pack_path("social-logos/whatsapp.svg") }
%span{"ng-bind" => "::producer.whatsapp_phone"}
%p.word-wrap{"ng-if" => "::producer.email_address"}
%a{"ng-href" => "{{::producer.email_address | stripUrl}}", target: "_blank", mailto: true}
%span.obfuscatedEmail.email{"ng-bind" => "::producer.email_address | stripUrl"}
%p.word-wrap{"ng-if" => "::producer.email_address"}
%a{"ng-href" => "{{::producer.email_address | stripUrl}}", target: "_blank", mailto: true}
%span.obfuscatedEmail.email{"ng-bind" => "::producer.email_address | stripUrl"}
%p.word-wrap{"ng-if" => "::producer.website"}
%a{"ng-href" => "http://{{::producer.website | stripUrl}}", target: "_blank" }
%span{"ng-bind" => "::producer.website | stripUrl"}
%p.word-wrap{"ng-if" => "::producer.website"}
%a{"ng-href" => "http://{{::producer.website | stripUrl}}", target: "_blank" }
%span{"ng-bind" => "::producer.website | stripUrl"}
%div{"ng-if" => "::producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
%label
= t :producers_social
.follow-icons
%span{"ng-if" => "::producer.twitter"}
%a{"ng-href" => "http://twitter.com/{{::producer.twitter}}", target: "_blank"}
%i.ofn-i_041-twitter
%div{"ng-if" => "::producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
%label
= t :producers_social
.follow-icons
%span{"ng-if" => "::producer.twitter"}
%a{"ng-href" => "http://twitter.com/{{::producer.twitter}}", target: "_blank"}
%i.ofn-i_041-twitter
%span{"ng-if" => "::producer.facebook"}
%a{"ng-href" => "http://{{::producer.facebook | stripUrl}}", target: "_blank"}
%i.ofn-i_044-facebook
%span{"ng-if" => "::producer.facebook"}
%a{"ng-href" => "http://{{::producer.facebook | stripUrl}}", target: "_blank"}
%i.ofn-i_044-facebook
%span{"ng-if" => "::producer.linkedin"}
%a{"ng-href" => "http://{{::producer.linkedin | stripUrl}}", target: "_blank"}
%i.ofn-i_042-linkedin
%span{"ng-if" => "::producer.linkedin"}
%a{"ng-href" => "http://{{::producer.linkedin | stripUrl}}", target: "_blank"}
%i.ofn-i_042-linkedin
%span{"ng-if" => "::producer.instagram"}
%a{"ng-href" => "http://instagram.com/{{::producer.instagram}}", target: "_blank"}
%i.ofn-i_043-instagram
%span{"ng-if" => "::producer.instagram"}
%a{"ng-href" => "http://instagram.com/{{::producer.instagram}}", target: "_blank"}
%i.ofn-i_043-instagram
.row.active_table_row.pad-top{"ng-if" => "open() && producer.hubs && !shopfront_loading"}
.columns.small-12{"ng-if" => "producer.hubs.length > 0"}
.row
.columns.small-12.fat
%div{"ng-if" => "::producer.name"}
%label
= t :producers_buy_at_html, enterprise: '<span class="turquoise" ng-bind="::producer.name"></span>'.html_safe
%div.show-for-medium-up{"ng-if" => "::!producer.name"}
&nbsp;
.row.cta-container
.columns.small-12
%a.cta-hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'",
"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined }}",
"ng-class" => "::{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::hub.active"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::!hub.active"}
.hub-name{"ng-bind" => "::hub.name"}
.button-address{"ng-bind" => "::[hub.address.city, hub.address.state_name] | printArray"}
.row.active_table_row.pad-top{"ng-if" => "open() && producer.hubs && !shopfront_loading"}
.columns.small-12{"ng-if" => "producer.hubs.length > 0"}
.row
.columns.small-12.fat
%div{"ng-if" => "::producer.name"}
%label
= t :producers_buy_at_html, enterprise: '<span class="turquoise" ng-bind="::producer.name"></span>'.html_safe
%div.show-for-medium-up{"ng-if" => "::!producer.name"}
&nbsp;
.row.cta-container
.columns.small-12
%a.cta-hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'",
"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined }}",
"ng-class" => "::{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::hub.active"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::!hub.active"}
.hub-name{"ng-bind" => "::hub.name"}
.button-address{"ng-bind" => "::[hub.address.city, hub.address.state_name] | printArray"}

View File

@@ -1,5 +0,0 @@
%h3= t(".heading")
%p
= t(".intro")
%ul
%li= link_to(t(".link_label", name: @blob.filename), @blob.expiring_service_url)

View File

@@ -1,119 +1,115 @@
%footer
.footer-global
= cache_with_locale "global" do
.row
.small-12.columns.text-center
.logo
%img{src: image_pack_path("logo-white-notext.png") }
.row
.small-12.medium-8.medium-offset-2.columns.text-center
.alert-box
= render 'shared/register_call'
.row
.small-12.columns.text-center
.logo
%img{src: image_pack_path("logo-white-notext.png") }
.row
.small-12.medium-8.medium-offset-2.columns.text-center
.alert-box
= render 'shared/register_call'
.footer-local
= cache_with_locale "local" do
.row
.small-12.medium-2.medium-offset-2.columns.text-center
%p.secure-icon
%i.ofn-i_017-locked
.small-12.medium-6.columns.text-center
%p.text-big.secure-text
= t '.footer_secure'
%p.secure-text
= t '.footer_secure_text'
.small-12.medium-2.columns
.row
.small-12.medium-2.medium-offset-2.columns.text-center
%p.secure-icon
%i.ofn-i_017-locked
.small-12.medium-6.columns.text-center
%p.text-big.secure-text
= t '.footer_secure'
%p.secure-text
= t '.footer_secure_text'
.small-12.medium-2.columns
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
= cache_with_locale ContentConfig.cache_key do
.row
.small-6.medium-3.medium-offset-2.columns.text-left
// This is the instance-managed set of links:
%h4
= t '.footer_contact_headline'
- if show_social_icons?
%p.social-icons
- if ContentConfig.footer_facebook_url.present?
%a{href: ContentConfig.footer_facebook_url}
%i.ofn-i_044-facebook
- if ContentConfig.footer_twitter_url.present?
%a{href: ContentConfig.footer_twitter_url}
%i.ofn-i_041-twitter
- if ContentConfig.footer_instagram_url.present?
%a{href: ContentConfig.footer_instagram_url}
%i.ofn-i_043-instagram
- if ContentConfig.footer_linkedin_url.present?
%a{href: ContentConfig.footer_linkedin_url}
%i.ofn-i_042-linkedin
- if ContentConfig.footer_googleplus_url.present?
%a{href: ContentConfig.footer_googleplus_url}
%i.ofn-i_046-g
- if ContentConfig.footer_pinterest_url.present?
%a{href: ContentConfig.footer_pinterest_url}
%i.ofn-i_045-pintrest
- if ContentConfig.footer_email.present?
%p
%a{href: ContentConfig.footer_email.reverse, mailto: true, target: '_blank'}
= t '.footer_contact_email'
= render_markdown(ContentConfig.footer_links_md).html_safe
.small-6.medium-3.columns.text-left
%h4
= t '.footer_nav_headline'
.row
.small-6.medium-3.medium-offset-2.columns.text-left
// This is the instance-managed set of links:
%h4
= t '.footer_contact_headline'
- if show_social_icons?
%p.social-icons
- if ContentConfig.footer_facebook_url.present?
%a{href: ContentConfig.footer_facebook_url}
%i.ofn-i_044-facebook
- if ContentConfig.footer_twitter_url.present?
%a{href: ContentConfig.footer_twitter_url}
%i.ofn-i_041-twitter
- if ContentConfig.footer_instagram_url.present?
%a{href: ContentConfig.footer_instagram_url}
%i.ofn-i_043-instagram
- if ContentConfig.footer_linkedin_url.present?
%a{href: ContentConfig.footer_linkedin_url}
%i.ofn-i_042-linkedin
- if ContentConfig.footer_googleplus_url.present?
%a{href: ContentConfig.footer_googleplus_url}
%i.ofn-i_046-g
- if ContentConfig.footer_pinterest_url.present?
%a{href: ContentConfig.footer_pinterest_url}
%i.ofn-i_045-pintrest
- if ContentConfig.footer_email.present?
%p
%a{href: "/shops"}
= t :label_shops
%p
%a{href: "/map"}
= t :label_map
%p
%a{href: "/producers"}
= t :label_producers
%p
%a{href: "/groups"}
= t :label_groups
%p
%a{href: ContentConfig.footer_about_url}
= t :label_about
%a{href: ContentConfig.footer_email.reverse, mailto: true, target: '_blank'}
= t '.footer_contact_email'
= render_markdown(ContentConfig.footer_links_md).html_safe
.small-12.medium-2.columns.text-left
%h4
= t '.footer_join_headline'
%p
= t '.footer_join_body'
%a{href: "/sell"}
= t '.footer_join_cta'
.medium-2.columns.text-center
/ Placeholder
.small-6.medium-3.columns.text-left
%h4
= t '.footer_nav_headline'
%p
%a{href: "/shops"}
= t :label_shops
%p
%a{href: "/map"}
= t :label_map
%p
%a{href: "/producers"}
= t :label_producers
%p
%a{href: "/groups"}
= t :label_groups
%p
%a{href: ContentConfig.footer_about_url}
= t :label_about
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
.small-12.medium-2.columns.text-left
%h4
= t '.footer_join_headline'
%p
= t '.footer_join_body'
%a{href: "/sell"}
= t '.footer_join_cta'
= cache_with_locale [ContentConfig.cache_key, TermsOfServiceFile.current_url, Spree::Config.privacy_policy_url] do
.row.legal
.small-12.medium-3.medium-offset-2.columns.text-left
%a{href: main_app.root_path}
%img{src: ContentConfig.url_for(:footer_logo), width: "220"}
.small-12.medium-5.columns.text-left
%p.text-small
= t '.footer_legal_call'
= link_to_platform_terms
&#124;
= t '.footer_legal_visit'
%a{href:"https://github.com/openfoodfoundation/openfoodnetwork", target: "_blank"} GitHub
%p.text-small
= t('.footer_legal_text_html', content_license: link_to('CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/'), code_license: link_to('AGPL 3', 'https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)' ))
%p.text-small
- if Spree::Config.privacy_policy_url.present?
= t('.footer_data_text_with_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe, privacy_policy: privacy_policy_link.html_safe)
- else
= t('.footer_data_text_without_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe)
.medium-2.columns.text-center
/ Placeholder
.medium-2.columns.text-center
/ Placeholder
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
.row.legal
.small-12.medium-3.medium-offset-2.columns.text-left
%a{href: main_app.root_path}
%img{src: ContentConfig.url_for(:footer_logo), width: "220"}
.small-12.medium-5.columns.text-left
%p.text-small
= t '.footer_legal_call'
= link_to_platform_terms
&#124;
= t '.footer_legal_visit'
%a{href:"https://github.com/openfoodfoundation/openfoodnetwork", target: "_blank"} GitHub
%p.text-small
= t('.footer_legal_text_html', content_license: link_to('CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/'), code_license: link_to('AGPL 3', 'https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)' ))
%p.text-small
- if Spree::Config.privacy_policy_url.present?
= t('.footer_data_text_with_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe, privacy_policy: privacy_policy_link.html_safe)
- else
= t('.footer_data_text_without_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe)
.medium-2.columns.text-center
/ Placeholder

View File

@@ -1,13 +1,12 @@
= cache_with_locale do
.alert-cta
%h6
-# Please forgive the hard-coded link:
-# The more elegant 'registration_path' resolves to /signup due to spree_auth_device > config > routes.rb
-# This is one of several possible fixes. Long-term, we'd like to bring the accounts page into OFN.
-# View the discussion here: https://github.com/openfoodfoundation/openfoodnetwork/pull/3174
%a{href: "/register", target: "_blank"}
= t '.selling_on_ofn'
&nbsp;
%strong
= t '.register'
%i.ofn-i_054-point-right
.alert-cta
%h6
-# Please forgive the hard-coded link:
-# The more elegant 'registration_path' resolves to /signup due to spree_auth_device > config > routes.rb
-# This is one of several possible fixes. Long-term, we'd like to bring the accounts page into OFN.
-# View the discussion here: https://github.com/openfoodfoundation/openfoodnetwork/pull/3174
%a{href: "/register", target: "_blank"}
= t '.selling_on_ofn'
&nbsp;
%strong
= t '.register'
%i.ofn-i_054-point-right

View File

@@ -1,9 +1,8 @@
= cache_with_locale do
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
%a#cart.icon{"ng-click" => "toggleCartSidebar()"}
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
%a#cart.icon{"ng-click" => "toggleCartSidebar()"}
%span
= t '.cart'
%span.count
%img{ src: image_pack_path("menu/icn-cart.svg") }
%span
= t '.cart'
%span.count
%img{ src: image_pack_path("menu/icn-cart.svg") }
%span
{{ Cart.total_item_count() }}
{{ Cart.total_item_count() }}

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