Compare commits

..

37 Commits

Author SHA1 Message Date
dependabot[bot]
a3aebe5363 Bump valid_email2 from 5.2.3 to 7.0.15
Bumps [valid_email2](https://github.com/micke/valid_email2) from 5.2.3 to 7.0.15.
- [Release notes](https://github.com/micke/valid_email2/releases)
- [Changelog](https://github.com/micke/valid_email2/blob/main/CHANGELOG.md)
- [Commits](https://github.com/micke/valid_email2/compare/v5.2.3...v7.0.15)

---
updated-dependencies:
- dependency-name: valid_email2
  dependency-version: 7.0.15
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:43:46 +00:00
David Cook
b2e847b551 Merge pull request #13957 from openfoodfoundation/dependabot/bundler/i18n-1.14.8
Bump i18n from 1.14.7 to 1.14.8
2026-03-03 17:16:58 +11:00
Gaetan Craig-Riou
efdbf25f86 Merge pull request #13248 from drummer83/email_whitelabel
White labelling all customer facing emails
2026-03-03 09:40:47 +11:00
Konrad
498ed5a3ec Resolve conflicts 2026-03-02 22:05:29 +01:00
Rachel Arnould
c7d4c6f3c4 Merge pull request #13835 from prikeshsavla/13569-remove-v3-admin-styles
Refactor admin CSS: Promote v3 to canonical admin styles
2026-03-02 12:29:33 +01:00
dependabot[bot]
36e3e16ba0 Bump i18n from 1.14.7 to 1.14.8
Bumps [i18n](https://github.com/ruby-i18n/i18n) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/ruby-i18n/i18n/releases)
- [Changelog](https://github.com/ruby-i18n/i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ruby-i18n/i18n/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: i18n
  dependency-version: 1.14.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 02:36:18 +00:00
Gaetan Craig-Riou
0f047e2c25 Merge pull request #13977 from openfoodfoundation/dependabot/npm_and_yarn/minimatch-3.1.5
Bump minimatch from 3.1.2 to 3.1.5
2026-03-02 12:00:02 +11:00
dependabot[bot]
ef7bd083ed Bump minimatch from 3.1.2 to 3.1.5
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-28 03:02:06 +00:00
Rachel Arnould
c13785f2e3 Merge pull request #13943 from pavelk-lab/replace-brand-story-angular-with-details
Replace Angular expand/collapse with native HTML <details>/<summary> for brand story
2026-02-27 15:37:00 +01:00
Gaetan Craig-Riou
0c0304b1c1 Merge pull request #13976 from openfoodfoundation/revert-13973-fix-rubocop-violations
Revert "Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations"
2026-02-27 10:06:29 +11:00
David-OFN-CA
7922bf7b65 Revert "Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations" 2026-02-26 17:04:21 -05:00
David-OFN-CA
2d46676bb4 Merge pull request #13973 from David-OFN-CA/fix-rubocop-violations
Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations
2026-02-26 16:01:15 -05:00
David Thomas
2808a41f0d Safely autocorrect Rails/RedirectBackOrTo
Inspecting 1721 files
........................................W...................................................................W................W..W.......W................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

Offenses:

app/controllers/admin/order_cycles_controller.rb:212:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back(fallback_location: root_path)
        ^^^^^^^^^^^^^
app/controllers/locales_controller.rb:6:5: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
    redirect_back fallback_location: main_app.root_url
    ^^^^^^^^^^^^^
app/controllers/spree/admin/invoices_controller.rb:31:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back(fallback_location: spree.admin_dashboard_path)
        ^^^^^^^^^^^^^
app/controllers/spree/admin/orders_controller.rb:83:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back fallback_location: spree.admin_dashboard_path
        ^^^^^^^^^^^^^
app/controllers/spree/admin/orders_controller.rb:91:25: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
          format.html { redirect_back(fallback_location: spree.admin_dashboard_path) }
                        ^^^^^^^^^^^^^
app/controllers/spree/admin/return_authorizations_controller.rb:13:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back fallback_location: spree.admin_dashboard_path
        ^^^^^^^^^^^^^

1721 files inspected, 6 offenses detected, 6 offenses corrected
2026-02-26 15:35:55 -05:00
David Thomas
18869979db Safely autocorrect Rails/Presence
Inspecting 1721 files
...................................C.................................................................................................................................................................................................................................................................................................................................................C...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

Offenses:

app/controllers/admin/enterprises_controller.rb:180:7: C: [Corrected] Rails/Presence: Use @object.custom_tab.presence&.destroy instead of @object.custom_tab.destroy if @object.custom_tab.present?.
      @object.custom_tab.destroy if @object.custom_tab.present?
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/controllers/admin/enterprises_controller.rb:243:9: C: [Corrected] Rails/Presence: Use (enterprises.presence&.includes(supplied_products: [:variants, :image])) instead of if enterprises.present? ... end.
        if enterprises.present? ...
        ^^^^^^^^^^^^^^^^^^^^^^^
app/controllers/admin/enterprises_controller.rb:243:9: C: [Corrected] Style/RedundantParentheses: Don't use parentheses around a method call.
        (enterprises.presence&.includes(supplied_products: [:variants, :image]))
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/spree/product.rb:298:7: C: [Corrected] Rails/Presence: Use (first_variant.supplier.presence&.touch) instead of first_variant.supplier.touch if first_variant.supplier.present?.
      first_variant.supplier.touch if first_variant.supplier.present?
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/spree/product.rb:298:7: C: [Corrected] Style/RedundantParentheses: Don't use parentheses around a method call.
      (first_variant.supplier.presence&.touch)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1721 files inspected, 5 offenses detected, 5 offenses corrected
2026-02-26 15:34:45 -05:00
David Thomas
708dbb2270 Regenerate Rubocop's TODO file 2026-02-26 15:33:37 -05:00
Rachel Arnould
83ec97e720 Merge pull request #13944 from pavelk-lab/fix/rails-7-serialize-deprecation
Fix Rails 7.2 serialize deprecation warnings
2026-02-26 11:29:27 +01:00
Pavel
85c903cb7f Remove fixed serialize deprecation from allowed warnings
The "Passing the class as positional argument" warning was suppressed
while serialize calls were being updated to use the keyword argument
form. Now that the fix is applied, the suppression is no longer needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 23:30:48 +00:00
Pavel
98775bfdb8 Pass type as keyword argument in migration serialize call
Same fix as applied to Invoice and ReportRenderingOptions models in
the parent PR: Rails 7.2 requires the type class to be passed as a
keyword argument to serialize.

  serialize :options, Hash, coder: YAML
  ->
  serialize :options, type: Hash, coder: YAML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 23:23:12 +00:00
pavelk-lab
47ef21deb3 Merge branch 'master' into fix/rails-7-serialize-deprecation 2026-02-21 23:19:58 +00:00
Pavel
e98244fe63 Fix Rails 7.2 serialize deprecation warnings
Pass type as keyword argument in serialize calls, as required from Rails 7.2 onwards.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 21:55:13 +00:00
Pavel
b348536d12 Clean up dead code after Angular brand story removal
- Delete HomeCtrl controller file (nothing references it anymore)
- Remove misplaced .text-vbig class from <details> (was on the old <a> toggle; summary has no visible text)
- Remove redundant cursor: pointer on #brand-story-text (<summary> already sets it)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 21:39:32 +00:00
Pavel
b528bb47a0 Replace Angular expand/collapse with native HTML details/summary for brand story
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-19 21:23:09 +00:00
Prikesh Savla
5a9aa87831 Rename admin-style-v3 to admin-style and remove the admin_legacy styles folder that has no references 2026-01-25 21:15:40 +05:30
Prikesh Savla
8cfab08f9e Refactor admin CSS: Promote v3 to canonical admin styles
The Admin V3 styles are now the primary styles for the application. This change promotes the `admin_v3` directory to `admin` and archives the old styles.

Changes:
- Renamed `app/webpacker/css/admin_v3` to `app/webpacker/css/admin`.
- Renamed the previous `app/webpacker/css/admin` to `app/webpacker/css/admin_legacy`.
- Moved all files referenced by V3 styles from the legacy directory to the new `admin` directory.
- Updated imports in `all.scss` to distinct local files instead of relative paths.
- Cleaned up `admin_legacy` by removing files that are duplicates (by name or content) of the new admin styles.
- Updated `admin-style-v3` pack to point to the new location.
2026-01-25 21:05:38 +05:30
Konrad
e814fdd447 Remove test for active white labeling in test email as proposed by David 2025-12-29 12:36:50 +01:00
David Cook
4d6231105f Assign attribute directly instead of mocking
It's better to set a variable the same way the real code would

Co-authored-by: Maikel <maikel@email.org.au>
2025-12-29 12:18:55 +01:00
Konrad
3a75c3446e Update backorder mailer specs to check that these hub facing emails remain unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
29a76fd721 Update report mailer specs to check that this enterprise facing email remains unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
593bd89095 Update test mailer specs to check that this super admin facing email remains unaffected by white labelling (there are no user or customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
0079ed219b Update producer mailer specs to check that this producer facing email remains unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
5957d99812 Update enterprise mailer specs to check that enterprise facing emails remain unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
89453ec758 Update subscription mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples

Made the check for link to order page more general, because on my system a double quote was expected but a single quote was generated
2025-12-29 12:18:55 +01:00
Konrad
0de4f2f596 Update payment mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
183cbecef6 Update shipment mailer specs to check that customer facing emails are white labelled (there are no shop facing emails here)
Make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
ab6a49e568 Update order mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples

Including the invoice email was too tricky for me for now, sorry
2025-12-29 12:18:55 +01:00
Konrad
52ddb29dc7 Update user mailer specs to check that white labelling does not affect these emails
Move tests to separate file for reuse in other emails

Pass on :mail symbol and obtain the mail-object using public_send() to call it with different names
2025-12-29 12:18:54 +01:00
drummer83
5ce7905a33 White labelling ALL customer facing emails
White labelling added for Order: cancellation email, Order: invoice email, Shipment: shipped email, Subscriptions: authorize payment email, Subscriptions: placement email, Subscriptions: empty order email, Subscriptions: failed payment email

White labelling existed already for Order: confirmation email, Subscriptions: order confirmation email
2025-12-29 12:18:54 +01:00
76 changed files with 467 additions and 1773 deletions

View File

@@ -405,7 +405,7 @@ GEM
reline
htmlentities (4.4.2)
http_parser.rb (0.8.0)
i18n (1.14.7)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
i18n-js (3.9.2)
i18n (>= 0.6.6)
@@ -507,7 +507,8 @@ GEM
logger
mini_mime (1.1.5)
mini_portile2 (2.8.6)
minitest (6.0.1)
minitest (6.0.2)
drb (~> 2.0)
prism (~> 1.5)
monetize (1.13.0)
money (~> 6.12)
@@ -519,7 +520,7 @@ GEM
mutex_m (0.3.0)
net-http (0.9.1)
uri (>= 0.11.1)
net-imap (0.5.12)
net-imap (0.6.3)
date
net-protocol
net-pop (0.1.2)
@@ -924,8 +925,8 @@ GEM
unicode-emoji (4.2.0)
uniform_notifier (1.18.0)
uri (1.1.1)
valid_email2 (5.2.3)
activemodel (>= 3.2)
valid_email2 (7.0.15)
activemodel (>= 6.0)
mail (~> 2.5)
validate_url (1.0.15)
activemodel (>= 3.0.0)

View File

@@ -1,5 +0,0 @@
angular.module('Darkswarm').controller "HomeCtrl", ($scope) ->
$scope.brandStoryExpanded = false
$scope.toggleBrandStory = ->
$scope.brandStoryExpanded = !$scope.brandStoryExpanded

View File

@@ -6,6 +6,7 @@ class PaymentMailer < ApplicationMailer
def authorize_payment(payment)
@payment = payment
@order = @payment.order
@hide_ofn_navigation = @payment.order.distributor.hide_ofn_navigation
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject: default_i18n_subject(distributor: @order.distributor.name),

View File

@@ -11,6 +11,7 @@ module Spree
def cancel_email(order_or_order_id, resend = false)
@order = find_order(order_or_order_id)
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject: mail_subject(t('spree.order_mailer.cancel_email.subject'), resend),
@@ -51,6 +52,7 @@ module Spree
def invoice_email(order_or_order_id, options = {})
@order = find_order(order_or_order_id)
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
current_user = if options[:current_user_id].present?
find_user(options[:current_user_id])
end

View File

@@ -4,6 +4,7 @@ module Spree
class ShipmentMailer < ApplicationMailer
def shipped_email(shipment, delivery:)
@shipment = shipment.respond_to?(:id) ? shipment : Spree::Shipment.find(shipment)
@hide_ofn_navigation = @shipment.order.distributor.hide_ofn_navigation
@delivery = delivery
@order = @shipment.order
subject = base_subject

View File

@@ -19,6 +19,7 @@ class SubscriptionMailer < ApplicationMailer
@type = 'empty'
@changes = changes
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end
@@ -26,11 +27,13 @@ class SubscriptionMailer < ApplicationMailer
@type = 'placement'
@changes = changes
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end
def failed_payment_email(order)
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end

View File

@@ -4,7 +4,7 @@ class Invoice < ApplicationRecord
self.belongs_to_required_by_default = false
belongs_to :order, class_name: 'Spree::Order'
serialize :data, Hash, coder: YAML
serialize :data, type: Hash, coder: YAML
before_validation :serialize_order
after_create :cancel_previous_invoices
default_scope { order(created_at: :desc) }

View File

@@ -4,5 +4,5 @@ class ReportRenderingOptions < ApplicationRecord
self.belongs_to_required_by_default = false
belongs_to :user, class_name: "Spree::User"
serialize :options, Hash, coder: YAML
serialize :options, type: Hash, coder: YAML
end

View File

@@ -6,21 +6,21 @@
%p
= t :brandstory_intro
#brand-story-text.hide-show.slideable
%p
= t :brandstory_part1
%p
= t :brandstory_part2
%p
= t :brandstory_part3
%p
= t :brandstory_part4
%p
%strong
= t :brandstory_part5_strong
%p
= t :brandstory_part6
%a.text-vbig{"slide-toggle" => "#brand-story-text", "ng-click" => "toggleBrandStory()"}
%i.ofn-i_005-caret-down{"ng-hide" => "brandStoryExpanded"}
%i.ofn-i_006-caret-up{ "ng-show" => "brandStoryExpanded"}
%details#brand-story-text
%summary
%i.ofn-i_005-caret-down
%i.ofn-i_006-caret-up
.brand-story-content
%p
= t :brandstory_part1
%p
= t :brandstory_part2
%p
= t :brandstory_part3
%p
= t :brandstory_part4
%p
%strong
= t :brandstory_part5_strong
%p
= t :brandstory_part6

View File

@@ -5,7 +5,7 @@
- content_for :page_alert do
= render "shared/menu/alert"
%div{"ng-controller" => "HomeCtrl"}
%div
= render "home/tagline"
#panes

View File

@@ -14,7 +14,7 @@
= " - OFN #{t(:administration)}"
%link{:href => "https://fonts.googleapis.com/css?family=Open+Sans:400italic,600italic,400,600&subset=latin,cyrillic,greek,vietnamese", :rel => "stylesheet", :type => "text/css"}
= stylesheet_pack_tag 'admin-style-v3', media: "screen, print"
= stylesheet_pack_tag 'admin-style', media: "screen, print"
= render "layouts/bugsnag_js"
- if content_for? :minimal_js

View File

@@ -16,13 +16,13 @@
@import "flatpickr/dist/themes/material_blue";
@import "shortcut-buttons-flatpickr/dist/themes/light";
@import "../admin/globals/functions";
@import "globals/functions";
@import "globals/palette"; // admin_v3
@import "globals/variables"; // admin_v3
@import "../admin/globals/mixins";
@import "globals/mixins";
@import "mixins"; // admin_v3
@import "../admin/plugins/font-awesome";
@import "plugins/font-awesome";
@import "../shared/variables/layout";
@import "../shared/variables/variables";
@@ -32,7 +32,7 @@
@import "shared/icons"; // admin_v3
@import "shared/forms"; // admin_v3
@import "shared/layout"; // admin_v3
@import "../admin/shared/scroll_bar";
@import "shared/scroll_bar";
@import "../shared/trix";
@@ -40,96 +40,94 @@
@import "plugins/powertip"; // admin_v3
@import "sections/orders"; // admin_v3
@import "../admin/sections/products";
@import "sections/products";
@import "../admin/hacks/mozilla";
@import "../admin/hacks/opera";
@import "../admin/hacks/ie";
@import "hacks/mozilla";
@import "hacks/opera";
@import "hacks/ie";
@import "components/actions"; // admin_v3
@import "../admin/components/alert-box";
@import "../admin/components/alert_row";
@import "components/alert-box";
@import "components/alert_row";
@import "components/buttons"; // admin_v3
@import "components/date-picker"; // admin_v3
@import "../admin/components/dialogs";
@import "../admin/components/input";
@import "../admin/components/jquery_dialog";
@import "components/dialogs";
@import "components/input";
@import "components/jquery_dialog";
@import "components/messages"; // admin_v3
@import "components/navigation"; // admin_v3
@import "../admin/components/ng-cloak";
@import "../admin/components/page_actions";
@import "components/ng-cloak";
@import "components/page_actions";
@import "components/pagination"; // admin_v3
@import "../admin/components/per_page_controls";
@import "../admin/components/product_autocomplete";
@import "../admin/components/progress";
@import "../admin/components/save_bar";
@import "components/per_page_controls";
@import "components/product_autocomplete";
@import "components/progress";
@import "components/save_bar";
@import "components/sidebar"; // admin_v3
@import "../admin/components/simple_modal";
@import "../admin/components/states";
@import "../admin/components/stripe_connect_button";
@import "../admin/components/subscriptions_states";
@import "../admin/components/table-filter";
@import "../admin/components/table_loading";
@import "../admin/components/timepicker";
@import "../admin/components/todo";
@import "../admin/components/tooltip";
@import "../admin/components/wizard_progress";
@import "components/simple_modal";
@import "components/states";
@import "components/stripe_connect_button";
@import "components/subscriptions_states";
@import "components/table-filter";
@import "components/table_loading";
@import "components/timepicker";
@import "components/todo";
@import "components/tooltip";
@import "components/wizard_progress";
@import "../admin/pages/enterprise_form";
@import "../admin/pages/subscription_form";
@import "../admin/pages/subscription_line_items";
@import "../admin/pages/subscription_review";
@import "pages/enterprise_form";
@import "pages/subscription_form";
@import "pages/subscription_line_items";
@import "pages/subscription_review";
@import "../admin/advanced_settings";
@import "../admin/alert";
@import "../admin/animations";
@import "advanced_settings";
@import "alert";
@import "animations";
@import "pages/change_type_form"; // admin_v3
@import "../admin/connected_apps";
@import "../admin/customers";
@import "connected_apps";
@import "customers";
@import "dashboard/dashboard_item"; // admin_v3
@import "pages/dashboard-single-ent"; // admin_v3
@import "../admin/dialog";
@import "../admin/disabled";
@import "dialog";
@import "disabled";
@import "components/dropdown"; // admin_v3
@import "pages/edit_variant"; // admin_v3
@import "pages/enterprise_index_panels"; // admin_v3
@import "../admin/enterprises";
@import "../admin/filters_and_controls";
@import "../admin/grid";
@import "../admin/icons";
@import "../admin/index_panel_buttons";
@import "../admin/index_panels";
@import "../admin/modals";
@import "../admin/offsets";
@import "../admin/openfoodnetwork";
@import "../admin/order_cycles";
@import "../admin/orders";
@import "enterprises";
@import "filters_and_controls";
@import "grid";
@import "icons";
@import "index_panel_buttons";
@import "index_panels";
@import "modals";
@import "offsets";
@import "openfoodnetwork";
@import "order_cycles";
@import "orders";
@import "pages/product_import"; // admin_v3
@import "../admin/products";
@import "../admin/products_v3";
@import "../admin/question-mark-tooltip";
@import "../admin/relationships";
@import "../admin/reports";
@import "products";
@import "products_v3";
@import "question-mark-tooltip";
@import "relationships";
@import "reports";
@import "components/select2"; // admin_v3
@import "components/sidebar-item"; // admin_v3
@import "../admin/side_menu";
@import "../admin/tables";
@import "../admin/tag_rules";
@import "../admin/terms_of_service_files";
@import "../admin/validation";
@import "../admin/variant_overrides";
@import "../admin/welcome";
@import "side_menu";
@import "tables";
@import "tag_rules";
@import "terms_of_service_files";
@import "validation";
@import "variant_overrides";
@import "welcome";
@import "shared/question-mark-icon";
@import "../admin/question-mark-tooltip";
@import "tom-select/src/scss/tom-select.default";
@import "~tom-select/src/scss/tom-select.default";
@import "components/tom_select"; // admin_v3
@import "modal_component/modal_component";
@import "vertical_ellipsis_menu_component/vertical_ellipsis_menu_component"; // admin_v3 and only V3
@import "tag_list_input_component/tag_list_input_component";
@import "admin/trix";
@import "trix";
@import "terms_of_service_banner"; // admin_v3

View File

@@ -1,110 +0,0 @@
#change_type {
section {
margin: 2em 0 0 0;
&,
& * {
color: $spree-blue;
}
}
.description {
background-color: $spree-light-blue;
margin-top: -2em;
padding: 4em 2em 2em 1em;
@media all and (max-width: 786px) {
margin-bottom: 2em;
}
}
.admin-cta {
border: 1px solid $spree-blue;
@include border-radius(3px);
text-align: center;
padding: 1em;
}
.error {
display: block;
color: #f57e80;
border: 1px solid #f57e80;
background-color: #fde6e7;
@include border-radius(3px);
margin-bottom: 1em;
padding: 0.5em;
}
a.selector {
position: relative;
border: 2px solid black;
text-align: center;
width: 100%;
cursor: pointer;
&,
& * {
color: white;
}
&:after,
&:before {
top: 100%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
&:after {
border-color: rgba(136, 183, 213, 0);
border-top-color: $spree-blue;
border-width: 12px;
margin-left: -12px;
}
&:hover {
&:after {
border-top-color: $spree-green;
}
}
&:before {
border-color: rgba(84, 152, 218, 0);
border-top-color: black;
border-width: 15px;
margin-left: -15px;
}
.bottom {
background: repeating-linear-gradient(
60deg,
rgba(84, 152, 218, 0),
rgba(84, 152, 218, 0) 5px,
rgba(255, 255, 255, 0.25) 5px,
rgba(255, 255, 255, 0.25) 10px
);
margin-top: 1em;
margin-left: -15px;
margin-right: -15px;
padding: 5px;
text-transform: uppercase;
}
&.selected {
background-color: black;
&:after,
&:hover &:after {
border-top-color: black;
}
}
}
}

View File

@@ -1,21 +0,0 @@
.dashboard_item.single-ent {
.header {
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
height: auto !important;
}
.list {
.button.bottom {
width: 100%;
}
}
}
.button.big {
width: 100%;
font-size: 1rem;
@include border-radius(25px);
padding: 15px;
}

View File

@@ -1,244 +0,0 @@
div.dashboard_item {
margin-bottom: 30px;
.centered {
text-align: center;
}
.text-icon {
margin-top: 8px;
display: block;
font-size: 16px;
font-weight: bold;
color: #fff;
padding: 0px 6px;
border-radius: 10px;
&.green {
background-color: $spree-green;
}
&.warning {
background-color: $color-warning;
}
&.orange {
background-color: $color-warning;
}
}
div.header {
height: 50px;
border-radius: 6px 6px 0px 0px;
border: 1px solid $spree-blue;
position: relative;
a[ofn-with-tip] {
position: absolute;
right: 5px;
bottom: 5px;
}
&.warning {
border-color: $color-warning;
border-width: 3px;
h3 {
color: $color-warning;
}
}
&.orange {
border-color: $color-warning;
border-width: 3px;
h3 {
color: $color-warning;
}
}
h3.alpha {
height: 100%;
padding: 10px 5px 0px 3%;
}
a {
border-radius: 0px 4px 0px 0px;
height: 100%;
padding: 15px 2px 0px 2px;
}
}
.tabs {
height: 30px;
border: solid $spree-blue;
border-width: 0px 0px 1px 0px;
margin-top: 3px;
div.dashboard_tab {
cursor: pointer;
height: 30px;
color: #fff;
background-color: $spree-blue;
padding: 5px 5px 0px 5px;
text-align: center;
font-weight: bold;
border: solid $spree-blue;
border-width: 1px 1px 0px 1px;
&:hover {
background-color: $spree-green;
}
&.selected {
color: $spree-blue;
background-color: #fff;
}
}
}
.list {
max-height: 250px;
overflow-y: auto;
overflow-x: hidden;
&:focus {
outline: none;
}
}
.list-title {
border: solid $spree-blue;
border-width: 0px 1px 0px 1px;
span {
font-size: 105%;
padding: 10px 0px;
font-weight: bold;
}
span.alpha {
padding: 10px 2px 10px 5%;
}
}
.list-item {
border: solid $spree-blue;
border-width: 0px 1px 0px 1px;
height: 41px;
span.alpha {
font-weight: bold;
margin-left: -3px;
padding: 10px 2px 0px 5%;
}
span.omega {
padding-right: 13px;
margin-right: -3px;
text-align: right;
}
.icon-arrow-right {
padding-top: 6px;
font-size: 20px;
}
.icon-warning-sign {
color: $color-warning;
font-size: 30px;
}
.icon-remove-sign {
color: $color-warning;
font-size: 30px;
}
.icon-ok-sign {
color: $spree-green;
font-size: 30px;
}
&.orange {
color: $color-warning;
border: solid $color-warning;
}
&.warning {
color: $color-warning;
border: solid $color-warning;
}
&.orange,
&.warning {
border-width: 0px 3px 0px 3px;
}
&.even {
background-color: #fff;
}
&.odd {
background-color: $spree-light-blue;
}
&.even,
&.odd {
&:hover {
color: #ffffff;
background-color: $spree-green;
.icon-arrow-right {
color: #fff;
}
.icon-remove-sign {
color: #fff;
}
.icon-warning-sign {
color: #fff;
}
.icon-ok-sign {
color: #fff;
}
.text-icon {
&.green {
color: $spree-green;
background-color: #fff;
}
}
}
}
}
a.button {
color: #fff;
font-size: 110%;
font-weight: bold;
text-align: center;
&.orange {
background-color: $color-warning;
}
&.blue {
background-color: $spree-blue;
}
&.warning {
background-color: $color-warning;
}
&:hover {
background-color: $spree-green;
}
&.bottom {
border-radius: 0px 0px 6px 6px;
padding: 15px 15px;
}
}
}

View File

@@ -1,271 +0,0 @@
#content-header .ofn-drop-down {
border: none;
background-color: $spree-blue;
color: #fff;
float: none;
margin-left: 3px;
}
.ofn-drop-down {
.dropdown-content {
display: none;
}
.toggle-off {
display: none;
}
&:active:not(.disabled),
&:focus:not(.disabled) {
.dropdown-content {
display: inline-block;
}
}
}
.ofn-drop-down:hover,
.ofn-drop-down.expanded {
border: 1px solid #adadad;
color: #575757;
}
@mixin ofn-drop-down-style {
padding: 7px 15px;
border-radius: 3px;
border: 1px solid #d4d4d4;
background-color: #f5f5f5;
display: block;
color: #828282;
cursor: pointer;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
text-align: center;
margin-right: 10px;
&.disabled {
opacity: 0.5;
pointer-events: none;
&:hover {
cursor: default;
border-color: #d4d4d4;
color: #828282;
}
}
}
.ofn-drop-down-with-prepend {
display: flex;
&.right {
float: right;
}
.ofn-drop-down {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.ofn-drop-down-prepend {
@include ofn-drop-down-style;
border-right: none;
margin-left: 0;
margin-right: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
cursor: default;
}
}
.ofn-drop-down {
@include ofn-drop-down-style;
position: relative;
float: left;
&.right {
float: right;
margin-right: 0px;
margin-left: 10px;
}
&:hover,
&.expanded {
border: 1px solid #adadad;
color: #575757;
}
> span {
width: auto;
text-transform: uppercase;
font-size: 85%;
font-weight: 600;
}
.menu {
margin-top: 1px;
position: absolute;
float: none;
top: 100%;
left: 0px;
padding: 5px 0px;
border: 1px solid #adadad;
background-color: #ffffff;
box-shadow: 1px 3px 10px #888888;
z-index: 100;
white-space: nowrap;
.filter {
padding-left: 5px;
padding-right: 5px;
position: relative;
> input[type="text"] {
border: 1px solid rgba(18, 18, 18, 0.1);
width: 100%;
padding-left: 30px;
padding-top: 10px;
padding-bottom: 10px;
font-size: 13px;
color: #454545;
}
&:after {
content: "\f002";
font-family: FontAwesome;
position: absolute;
left: 15px;
top: 13px;
color: #454545;
}
}
.menu_item {
margin: 0px;
padding: 2px 10px;
color: #454545;
text-align: left;
display: block;
.check {
display: inline-block;
text-align: center;
width: 40px;
&:before {
content: "\00a0";
}
}
.name {
display: inline-block;
padding: 0px 15px 0px 0px;
}
&.selected {
.check:before {
content: "\2713";
}
}
&.hidden {
display: none;
}
}
.menu_item:hover {
background-color: #ededed;
}
}
> details {
// Override padding on ofn-drop-down-style
margin: -7px -15px;
padding: 7px 15px;
}
> details > summary {
display: inline-block;
list-style: none;
width: auto;
text-transform: uppercase;
font-size: 85%;
font-weight: 600;
// Override padding on ofn-drop-down-style to increase clickable area
margin: -8px -15px;
padding: 8px 15px;
}
> details > summary:after {
content: "\f0d7";
font-family: FontAwesome;
}
> details[open] > summary:after {
content: "\f0d8";
font-family: FontAwesome;
}
}
.ofn-drop-down-v2 {
border: 1px solid $pale-blue;
background-color: white;
padding: 0px;
&:hover {
border-color: $spree-blue;
}
.ofn-drop-down-label {
color: $color-3;
padding: 10px;
width: 235px;
display: flex;
justify-content: space-between;
&:hover {
color: $color-3;
}
.label {
padding-right: 10px;
}
.icon-caret-down,
.icon-caret-up {
padding-right: 0px;
}
}
.menu {
width: 100%;
}
.menu_items {
max-height: 200px;
overflow-y: scroll;
.menu_item {
margin-bottom: 5px;
color: #454545;
font-weight: 400;
cursor: pointer;
padding-top: 4px;
padding-bottom: 5px;
text-transform: uppercase;
font-size: 85%;
}
}
}
.ofn-drop-down.ofn-drop-down-v2 {
// Add very specific styling here for components that are in transition:
// ie. the ones using the two classes above
.ofn-drop-down-label {
padding-top: 7px;
padding-bottom: 7px;
}
}

View File

@@ -1,120 +0,0 @@
.enterprise_package_panel,
.enterprise_producer_panel {
.info {
p {
font-size: 1rem;
margin: 10px 0px;
}
}
a.selector {
display: block;
position: relative;
margin-bottom: 20px;
border: 2px solid black;
text-align: center;
// width: 100%;
cursor: pointer;
&,
& * {
color: white;
}
&:hover {
&:after {
border-top-color: $spree-green;
}
}
&.disabled {
background-color: #c1c1c1;
}
.bottom {
background: repeating-linear-gradient(
60deg,
rgba(84, 152, 218, 0),
rgba(84, 152, 218, 0) 5px,
rgba(255, 255, 255, 0.25) 5px,
rgba(255, 255, 255, 0.25) 10px
);
margin-top: 1em;
margin-left: -15px;
margin-right: -15px;
padding: 5px;
text-transform: uppercase;
}
&.selected {
background-color: #000000;
&:after {
top: 50%;
left: 0;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-right: 20px solid #000000;
margin-top: -20px;
margin-left: -20px;
}
}
}
}
.enterprise_status_panel {
.status-ok {
margin: 30px 0px;
i.icon-ok-sign {
color: $spree-green;
font-size: 1.5rem;
}
}
td.description {
font-size: 0.9rem;
}
td.severity {
text-align: center;
i {
font-size: 1.5rem;
&.issue {
color: $color-warning;
}
&.warning {
color: #ff9848;
}
}
}
}
tags-input .tags li.tag-item {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
margin: 2px 0 2px 3px;
background-image: none;
background-color: #5fa5e8;
border: none;
box-shadow: none;
color: white !important;
font-size: 85%;
height: 25px;
}
tags-input .tags .tag-item .remove-button {
color: white;
}
table th.actions .no-text[class*="icon-"],
table td.actions .no-text[class*="icon-"] {
cursor: pointer;
}

View File

@@ -1,20 +1,38 @@
// Basic color palette for admin
$spree-green: #9fc820;
$spree-blue: #5498da;
// Basic color palette for admin styles v3
$white: #ffffff !default; // White
$green: #9fc820 !default; // Green
$teal: #008397 !default; // Teal (Allports)
$orient: #006878 !default; // Orient (Cerulean)
$dark-blue: #004e5b !default; // Dark Blue (Sherpa)
$pale-blue: #cee1f4; // Pale blue
$red: #c85136 !default; // Red/Orange (Mojo)
$bright-orange: #ffa92e; // Bright orange
$yellow: #ff9300 !default; // Yellow
$mystic: #d9e8eb !default; // Mystic
$lighter-grey: #f8f9fa !default; // Lighter grey
$light-grey: #eff1f2 !default; // Light grey (Porcelain)
$medium-light-grey: #babdbe !default; // Silver Sand
$medium-grey: #919191 !default; // Medium grey
$dark-grey: #2e3132 !default; // Dark Grey
$near-black: #191c1d !default; // Near-black (Shark)
$fair-pink: #ffefeb !default; // Fair Pink
$roof-terracotta: #b83b1f !default; // Roof Terracotta
// Old colour variables for backwards compatibility
$spree-green: $green;
$spree-blue: $teal;
$spree-light-blue: #eff5fc;
$pale-blue: #cee1f4;
$bright-orange: #ffa92e;
$medium-grey: #919191;
$light-grey: #ccc;
$color-1: #ffffff !default; // White
$color-2: $spree-green !default; // Green
$color-3: $spree-blue !default; // Light Blue
$color-4: #6788a2 !default; // Dark Blue
$color-5: #c60f13 !default; // Red
$color-6: #ff9300 !default; // Yellow
$color-14: #f8f9fa !default; // Lighter grey
$dark-grey: #333;
$light-grey: #ddd;
$near-black: #222;
$color-1: $white;
$color-2: $green;
$color-3: $teal;
$color-4: $dark-blue;
$color-5: $red;
$color-6: $yellow;
$color-7: $light-grey;
$color-8: $near-black;
$color-9: $dark-grey;
$color-10: $orient;
$color-11: $mystic;
$color-12: $fair-pink;
$color-13: $roof-terracotta;
$color-14: $lighter-grey;

View File

@@ -1,189 +0,0 @@
.select2-container {
&:hover .select2-choice,
&.select2-container-active .select2-choice {
background-color: $color-sel-hover-bg !important;
border-color: $color-sel-hover-bg !important;
}
.select2-choice {
background-image: none !important;
background-color: $color-sel-bg;
border: none !important;
box-shadow: none !important;
@include border-radius($border-radius);
color: $color-1 !important;
font-size: 90%;
height: 31px;
line-height: inherit !important;
padding: 5px 15px 7px;
span {
display: block;
padding: 2px;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 100% !important;
@extend .icon-remove;
@extend [class^="icon-"], :before;
margin-top: 2px;
}
}
&.select2-container-active {
.select2-choice {
box-shadow: none !important;
}
&.select2-dropdown-open .select2-choice div b {
@extend .icon-caret-up;
}
}
}
.select2-drop {
border-color: $color-sel-hover-bg;
box-shadow: none !important;
z-index: 1000000;
&.select2-drop-above {
border-color: $color-sel-hover-bg;
}
}
.select2-search {
@extend .icon-search;
font-size: 100%;
color: darken($color-border, 15);
padding: 0 9px 0 0;
&:before {
@extend [class^="icon-"], :before;
position: absolute;
top: 13px;
left: 13px;
}
input {
@extend input, [type="text"];
padding: 6px 0 6px 25px;
margin: 5px 0 0 5px;
font-family: $base-font-family;
font-size: 90%;
box-shadow: none;
background-image: none;
}
}
.select2-container .select2-choice .select2-arrow {
background-image: none;
background: transparent;
border: 0;
b {
padding-top: 7px;
display: block;
width: 100%;
height: 100%;
background: none;
font-family: FontAwesome;
font-weight: 200 !important;
&:before {
content: "\f0d7";
}
}
}
.select2-results {
padding-left: 0 !important;
li {
font-size: 85% !important;
&.select2-highlighted {
.select2-result-label {
&,
h6 {
color: $color-1 !important;
}
}
}
.select2-result-label {
color: $color-body-text;
min-height: 22px;
clear: both;
overflow: auto;
}
&.select2-no-results,
&.select2-searching {
padding: 5px;
background-color: transparent;
color: $color-body-text;
text-align: center;
font-weight: $font-weight-bold;
text-transform: uppercase;
}
}
.select2-highlighted {
background-color: $color-sel-bg;
}
}
.select2-container-multi {
&.select2-container-active,
&.select2-dropdown-open {
.select2-choices {
border-color: $color-sel-hover-bg !important;
box-shadow: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
.select2-choices {
@extend input, [type="text"];
padding: 6px 3px 3px 3px;
box-shadow: none;
background-image: none !important;
.select2-search-choice {
@include border-radius($border-radius);
margin: 0 0 3px 3px;
background-image: none;
background-color: $color-sel-bg;
border: none;
box-shadow: none;
color: $color-1 !important;
font-size: 85%;
&:hover {
background-color: $color-sel-hover-bg;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 85% !important;
@extend .icon-remove;
@extend [class^="icon-"], :before;
margin-left: 2px;
color: $color-1;
}
}
}
}
label .select2-container {
margin-top: -6px;
.select2-choice {
span {
text-transform: none;
font-weight: normal;
}
}
}

View File

@@ -1,299 +0,0 @@
$pi-red: $color-warning;
$pi-green: lighten($spree-green, 10%);
$pi-orange: $bright-orange;
$pi-blue: lighten($spree-blue, 10%);
$pi-light-yellow: #faffaf;
// scss-lint:disable NestingDepth
div.panel-section {
.error {
color: $pi-red;
}
.warning {
color: $bright-orange;
}
.success {
color: $pi-green;
}
.info {
color: #68b7c0;
}
div.panel-header {
width: 100%;
clear: both;
float: left;
padding: 0.5em;
div {
font-size: 1.25em;
float: left;
}
div.header-caret {
width: 2em;
text-align: center;
min-height: 0.1em; //Empty div fix
}
div.header-icon {
width: 2.5em;
text-align: center;
padding-top: 0.18em;
i {
font-size: 1.5em;
line-height: 0.9em;
}
}
div.header-count {
min-width: 2em;
text-align: right;
padding-right: 0.5em;
}
div.header-description {
width: auto;
}
}
div.panel-header:hover {
cursor: pointer;
background-color: #f7f7f7;
}
div.panel-header.active {
background-color: #efefef;
text-shadow: 1px 1px 0px rgba(255, 255, 255, 0.75);
}
div.panel-content {
width: 100%;
clear: both;
margin-bottom: 0.5em;
background-color: #f9f9f9;
padding: 1.5em;
div.table-wrap {
width: 100%;
overflow: auto;
border-right: 1px solid #ceede3;
max-height: 23em;
}
table {
background-color: white;
margin-bottom: 0;
td,
th {
white-space: nowrap;
}
tr {
&.error {
color: #c84c4c;
}
&:hover td.invalid {
background-color: darken(#f05c51, 5%);
}
i {
display: block;
margin-bottom: -0.2em;
font-size: 1.4em !important;
}
}
td {
&.invalid {
background-color: #f05c51;
box-shadow: inset 0px 0px 1px red;
color: white;
}
}
}
div.import-errors {
margin-bottom: 0.85em;
p.line {
font-size: 1.15em;
margin-bottom: 0.2em;
color: #577084;
}
p.error {
color: #cb1b1b;
margin-bottom: 0.2em;
}
}
}
}
br.panels.clearfix {
clear: both;
}
.panel-section.import-settings {
.header-description {
padding-left: 1em;
}
span.header-error {
font-size: 0.85em;
color: $pi-red;
}
.select2-search {
display: none;
}
.select2-results {
margin: 0;
}
}
.post-save-results {
p {
font-size: 1.25em;
margin-bottom: 0.5em;
strong {
margin-right: 0.2em;
min-width: 1.8em;
display: inline-block;
text-align: right;
}
i {
font-size: 1.4em;
vertical-align: middle;
position: relative;
}
i.fa-check-circle {
color: $pi-green;
}
i.fa-info-circle {
color: $pi-blue;
}
}
p.save-error {
color: #ee4728;
font-size: 1.05em;
margin-top: 0.4em;
}
}
form.product-import,
div.post-save-results,
div.import-wrapper {
input[type="submit"] {
margin-right: 0.5em;
}
input[type="submit"],
button,
a.button {
min-width: 8em;
text-align: center;
}
}
div.import-wrapper {
.alert-box {
margin: 0 0 1.75em;
}
.ng-hide:not(.ng-hide-animate) {
// We have to use !important here to override angular's display properties
// scss-lint:disable ImportantRule
display: block !important;
position: absolute;
opacity: 0;
top: -9999px;
left: -9999px;
}
.ng-hide-add,
.ng-hide-remove,
.ng-hide-animate {
transition: all 0.4s ease-in-out;
}
form.product-import,
div.save-results {
transition: all 0.4s ease-in-out;
}
div.progress-interface {
text-align: center;
transition: all 0.4s ease-in-out;
button:disabled {
background: #ccc !important;
}
}
.post-save-results {
a.button {
float: left;
margin-right: 0.5em;
}
}
}
div.progress-bar {
height: 25px;
width: 30em;
max-width: 90%;
margin: 1em auto;
background: #f7f7f7;
padding: 3px;
border-radius: 0.3em;
border: 1px solid #eee;
span.progress-track {
display: block;
background: lighten($pi-green, 10%);
height: 100%;
border-radius: 0.3em;
box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.3);
transition: width 0.3s ease-in-out;
}
}
#upload-sidebar {
float: right;
background-color: lighten($spree-light-blue, 2.5%);
border: 1px solid lighten($pale-blue, 2.5%);
width: 50%;
padding: 0 1.5em 1.5em;
h4,
h5,
h6,
p {
margin: 1.25em 0 1em;
}
a.download {
display: block;
font-size: 1.05em;
margin-bottom: 0.5em;
i {
margin-right: 0.25em;
}
}
span.category {
display: inline-block;
background-color: $pi-blue;
color: white;
padding: 0.3em 0.6em;
margin: 0 0.4em 0.5em 0;
}
}

View File

@@ -1,6 +1,6 @@
// Customisations for the new Bulk Edit Products page only
// Scoped to containing div, because Turbo messes with body classes
@import "../admin_v3/pages/unit_popout";
@import "pages/unit_popout";
#products_v3_page {
#content > .row:first-child > .container:first-child {
@@ -59,6 +59,7 @@
overflow: visible;
background-color: white;
}
.form-actions-wrapper2 {
position: relative;
// Stretch to cover table side borders
@@ -157,6 +158,7 @@
tr:first-child td {
border-top: 4px solid $color-tbl-bg;
}
tr:last-child td {
border-bottom: 1px solid $color-tbl-cell-shadow;
}
@@ -187,6 +189,7 @@
$columns:
"image", "name", "sku", "unit_scale", "unit", "price", "on_hand", "producer", "category",
"tax_category", "tags", "inherits_properties";
@each $col in $columns {
&.hide-#{$col} {
.col-#{$col} {
@@ -237,6 +240,7 @@
align-items: center;
gap: 10px;
}
.per-page {
width: 9em;
}
@@ -286,6 +290,7 @@
.search-button {
position: relative;
> input {
padding-left: 30px;
}
@@ -295,6 +300,7 @@
// Blurred and non-clickable
$disabled-blur: 1.5px;
.disabled-section {
position: relative;
@@ -346,6 +352,7 @@
from {
transform: scaleY(1);
}
to {
transform: scaleY(0);
}
@@ -360,6 +367,7 @@
from {
transform: scaleY(0);
}
to {
transform: scaleY(1);
}

View File

@@ -1,63 +0,0 @@
.select2-container {
.select2-choice {
.select2-search-choice-close {
display: none !important;
}
.select2-arrow {
width: 22px;
border: none;
background-image: none;
background-color: transparent;
}
}
&.light {
.select2-choice {
background-color: #ffffff;
font-weight: normal;
color: $spree-blue !important;
border: 1px solid $color-border !important;
}
&:hover,
&.select2-container-active {
.select2-choice {
background-color: #ffffff !important;
border: 1px solid $spree-green !important;
.select2-arrow {
&:before {
color: $spree-blue;
}
}
}
}
}
&.select2-container-multi {
.select2-search-field {
max-height: 20px;
input {
padding: 0 !important;
margin: 0 0 0 5px !important;
}
}
.select2-search-choice {
display: flex;
align-items: center;
justify-content: center;
padding-left: 7px;
.select2-search-choice-close {
position: relative;
order: -1;
width: auto;
left: 0;
top: 0;
margin: 0;
padding: 0;
font-size: 100% !important;
}
}
}
}

View File

@@ -1,124 +0,0 @@
div.sidebar_item {
margin-bottom: 30px;
.centered {
text-align: center;
}
div.header {
font-size: 105%;
color: #fff;
padding: 10px 0px;
position: relative;
&.blue {
background-color: $spree-blue;
}
&.red {
background-color: $color-warning;
}
}
.list {
max-height: 400px;
overflow-y: auto;
overflow-x: hidden;
&.red {
color: $color-warning;
.list-item {
border: solid $color-warning;
border-width: 0px 3px 0px 3px;
a.alpha,
span.alpha {
margin-left: -3px;
}
&.odd {
background-color: #fcf6ef;
&:hover {
background-color: $spree-green;
}
}
}
a {
color: $color-warning;
}
}
}
.list-item {
.icon-arrow-right {
padding-top: 6px;
font-size: 20px;
}
border: solid $spree-blue;
border-width: 0px 1px 0px 1px;
a.alpha,
span.alpha {
font-weight: bold;
margin-left: -1px;
padding: 10px 2px 10px 5%;
overflow: hidden;
text-overflow: ellipsis;
}
span.omega {
padding: 8px 18px 8px 0px;
margin-right: -3px;
text-align: right;
}
.icon-remove-sign {
color: $color-warning;
font-size: 18px;
}
&.even {
background-color: #fff;
}
&.odd {
background-color: $spree-light-blue;
}
&.even,
&.odd {
&:hover {
color: #ffffff;
background-color: $spree-green;
a {
color: #ffffff;
}
}
}
}
a.button {
color: #fff;
padding: 15px 15px;
font-weight: bold;
text-align: center;
border-radius: 0px;
&.blue {
background-color: $spree-blue;
}
&.red {
background-color: $color-warning;
}
&:hover {
background-color: $spree-green;
}
}
}

View File

@@ -1,38 +0,0 @@
// Basic color palette for admin styles v3
$white: #ffffff !default; // White
$green: #9fc820 !default; // Green
$teal: #008397 !default; // Teal (Allports)
$orient: #006878 !default; // Orient (Cerulean)
$dark-blue: #004e5b !default; // Dark Blue (Sherpa)
$pale-blue: #cee1f4; // Pale blue
$red: #c85136 !default; // Red/Orange (Mojo)
$bright-orange: #ffa92e; // Bright orange
$yellow: #ff9300 !default; // Yellow
$mystic: #d9e8eb !default; // Mystic
$lighter-grey: #f8f9fa !default; // Lighter grey
$light-grey: #eff1f2 !default; // Light grey (Porcelain)
$medium-light-grey: #babdbe !default; // Silver Sand
$medium-grey: #919191 !default; // Medium grey
$dark-grey: #2e3132 !default; // Dark Grey
$near-black: #191c1d !default; // Near-black (Shark)
$fair-pink: #ffefeb !default; // Fair Pink
$roof-terracotta: #b83b1f !default; // Roof Terracotta
// Old colour variables for backwards compatibility
$spree-green: $green;
$spree-blue: $teal;
$spree-light-blue: #eff5fc;
$color-1: $white;
$color-2: $green;
$color-3: $teal;
$color-4: $dark-blue;
$color-5: $red;
$color-6: $yellow;
$color-7: $light-grey;
$color-8: $near-black;
$color-9: $dark-grey;
$color-10: $orient;
$color-11: $mystic;
$color-12: $fair-pink;
$color-13: $roof-terracotta;
$color-14: $lighter-grey;

View File

@@ -71,8 +71,50 @@
}
}
a.text-vbig i {
font-size: 75px;
#brand-story-text {
text-align: center;
margin-top: 1rem;
summary {
list-style: none;
cursor: pointer;
display: inline-block;
&::-webkit-details-marker {
display: none;
}
&::marker {
display: none;
}
i {
font-size: 75px;
}
.ofn-i_005-caret-down {
display: inline-block;
}
.ofn-i_006-caret-up {
display: none;
}
}
&[open] summary {
.ofn-i_005-caret-down {
display: none;
}
.ofn-i_006-caret-up {
display: inline-block;
}
}
.brand-story-content {
margin-top: 1rem;
text-align: left;
}
}
}

View File

@@ -1,5 +0,0 @@
@import "../css/admin_v3/all.scss";
@import "../css/admin_v3/components/spinner.scss";
@import "../../../node_modules/trix/dist/trix.css";

View File

@@ -0,0 +1,5 @@
@import "../css/admin/all.scss";
@import "../css/admin/components/spinner.scss";
@import "../../../node_modules/trix/dist/trix.css";

View File

@@ -74,8 +74,6 @@ Rails.application.configure do
allowed_warnings = [
# List strings here to allow matching deprecations.
#
"Passing the class as positional argument",
# Spree::CreditCard model aliases `cc_type` and has a method called `cc_type=` defined. Starting in Rails 7.2 `brand=` will not be calling `cc_type=` anymore. You may want to additionally define `brand=` to preserve the current behavior.
"model aliases",

View File

@@ -3,7 +3,7 @@ class UpdateItemNameToProductInOdReport < ActiveRecord::Migration[7.0]
self.belongs_to_required_by_default = false
belongs_to :user, class_name: "Spree::User"
serialize :options, Hash, coder: YAML
serialize :options, type: Hash, coder: YAML
end
# OD: Orders and Distributors

View File

@@ -1,19 +0,0 @@
describe "HomeCtrl", ->
ctrl = null
scope = null
beforeEach ->
module 'Darkswarm'
scope = {}
inject ($controller) ->
ctrl = $controller 'HomeCtrl', {$scope: scope}
it "starts with the brand story contracted", ->
expect(scope.brandStoryExpanded).toBe false
it "toggles the brand story", ->
scope.toggleBrandStory()
expect(scope.brandStoryExpanded).toBe true
scope.toggleBrandStory()
expect(scope.brandStoryExpanded).toBe false

View File

@@ -4,18 +4,30 @@ RSpec.describe BackorderMailer do
let(:order) { create(:completed_order_with_totals) }
describe "#backorder_failed" do
subject(:mail) { described_class.backorder_failed(order) }
it "notifies the owner" do
order.distributor.owner.email = "jane@example.net"
BackorderMailer.backorder_failed(order).deliver_now
mail = ActionMailer::Base.deliveries.first
expect(mail.to).to eq ["jane@example.net"]
expect(mail.subject).to eq "An automatic backorder failed"
first_mail = ActionMailer::Base.deliveries.first
expect(first_mail.to).to eq ["jane@example.net"]
expect(first_mail.subject).to eq "An automatic backorder failed"
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
end
describe "#backorder_incomplete" do
subject(:mail) {
described_class.backorder_incomplete(
user, distributor, order_cycle, order_id
)
}
let(:user) { build(:user, email: "jane@example.net") }
let(:distributor) { build(:enterprise) }
let(:order_cycle) { build(:order_cycle) }
@@ -24,9 +36,14 @@ RSpec.describe BackorderMailer do
it "notifies the owner" do
BackorderMailer.backorder_incomplete(user, distributor, order_cycle, order_id).deliver_now
mail = ActionMailer::Base.deliveries.first
expect(mail.to).to eq ["jane@example.net"]
expect(mail.subject).to eq "An automatic backorder failed to complete"
first_mail = ActionMailer::Base.deliveries.first
expect(first_mail.to).to eq ["jane@example.net"]
expect(first_mail.subject).to eq "An automatic backorder failed to complete"
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
end
end

View File

@@ -2,9 +2,10 @@
RSpec.describe EnterpriseMailer do
let(:enterprise) { build(:enterprise, name: "Fred's Farm") }
let(:order) { build(:order_with_distributor) }
describe "#welcome" do
subject(:mail) { EnterpriseMailer.welcome(enterprise) }
subject(:mail) { described_class.welcome(enterprise) }
it "sends a welcome email when given an enterprise" do
expect(mail.subject)
@@ -14,10 +15,15 @@ RSpec.describe EnterpriseMailer do
it "does not set a reply-to email" do
expect(mail.reply_to).to eq nil
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
end
describe "#manager_invitation" do
subject(:mail) { EnterpriseMailer.manager_invitation(enterprise, user) }
subject(:mail) { described_class.manager_invitation(enterprise, user) }
let(:user) { build(:user) }
it "should send a manager invitation email when given an enterprise and user" do
@@ -27,5 +33,10 @@ RSpec.describe EnterpriseMailer do
it "sets a reply-to of the enterprise email" do
expect(mail.reply_to).to eq([enterprise.contact.email])
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
end
end

View File

@@ -2,19 +2,24 @@
RSpec.describe Spree::OrderMailer do
describe '#confirm_email_for_customer' do
subject(:email) { described_class.confirm_email_for_customer(order) }
subject(:mail) { described_class.confirm_email_for_customer(order) }
let(:order) { build(:order_with_totals_and_distribution) }
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'customer facing email with active white labelling', :mail
end
it 'renders the shared/_payment.html.haml partial' do
expect(email.body).to include('Payment summary')
expect(mail.body).to include('Payment summary')
end
context 'when the order has outstanding balance' do
before { allow(order).to receive(:new_outstanding_balance) { 123 } }
it 'renders the amount as money' do
expect(email.body).to include('$123')
expect(mail.body).to include('$123')
end
end
@@ -22,18 +27,18 @@ RSpec.describe Spree::OrderMailer do
before { allow(order).to receive(:new_outstanding_balance) { 0 } }
it 'displays the payment status' do
expect(email.body).to include('NOT PAID')
expect(mail.body).to include('NOT PAID')
end
end
context "when :from is not set explicitly" do
it "falls back to spree config" do
expect(email.from).to eq [Spree::Config[:mails_from]]
expect(mail.from).to eq [Spree::Config[:mails_from]]
end
end
it "doesn't aggressively escape double quotes body" do
expect(email.body).not_to include("&quot;")
expect(mail.body).not_to include("&quot;")
end
it "accepts an order id as an alternative to an Order object" do
@@ -42,46 +47,37 @@ RSpec.describe Spree::OrderMailer do
described_class.confirm_email_for_customer(order.id).deliver_now
}.not_to raise_error
end
it "display the OFN header by default" do
expect(email.body).to include(ContentConfig.url_for(:logo))
end
context 'when hide OFN navigation is enabled for the distributor of the order' do
before do
allow(order.distributor).to receive(:hide_ofn_navigation).and_return(true)
end
it 'does not display the OFN navigation' do
expect(email.body).not_to include(ContentConfig.url_for(:logo))
end
end
end
describe '#confirm_email_for_shop' do
subject(:email) { described_class.confirm_email_for_shop(order) }
subject(:mail) { described_class.confirm_email_for_shop(order) }
let(:order) { build(:order_with_totals_and_distribution) }
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
it 'renders the shared/_payment.html.haml partial' do
expect(email.body).to include('Payment summary')
expect(mail.body).to include('Payment summary')
end
it "sets a reply-to of the customer email" do
expect(email.reply_to).to eq([order.email])
expect(mail.reply_to).to eq([order.email])
end
context 'when the order has outstanding balance' do
before { allow(order).to receive(:new_outstanding_balance) { 123 } }
it 'renders the amount as money' do
expect(email.body).to include('$123')
expect(mail.body).to include('$123')
end
end
context 'when the order has no outstanding balance' do
it 'displays the payment status' do
expect(email.body).to include('NOT PAID')
expect(mail.body).to include('NOT PAID')
end
end
end
@@ -149,6 +145,11 @@ RSpec.describe Spree::OrderMailer do
expect(mail.to).to eq([distributor.contact.email])
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
it "includes a link to the cancelled order in admin" do
expect(mail.body).to match /#{admin_order_link_href}/
end
@@ -167,6 +168,11 @@ RSpec.describe Spree::OrderMailer do
expect(mail.to).to eq([order.email])
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'customer facing email with active white labelling', :mail
end
it "displays the order number" do
expect(mail.body).to include(order.number.to_s)
end
@@ -176,7 +182,7 @@ RSpec.describe Spree::OrderMailer do
end
end
describe "order confimation" do
describe "order confirmation" do
let(:bill_address) { create(:address) }
let(:distributor_address) {
create(:address, address1: "distributor address", city: 'The Shire', zipcode: "1234")
@@ -242,7 +248,7 @@ RSpec.describe Spree::OrderMailer do
end
describe "#invoice_email" do
subject(:email) { described_class.invoice_email(order) }
subject(:mail) { described_class.invoice_email(order) }
let(:order) { create(:completed_order_with_totals) }
let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) }
let!(:invoice){
@@ -259,17 +265,17 @@ RSpec.describe Spree::OrderMailer do
allow(InvoiceRenderer).to receive(:new).and_return(renderer)
end
context "When invoices feature is not enabled" do
it "should call the invoice render with order as argument" do
it "should call the invoice renderer with order as argument" do
expect(generator).not_to receive(:generate_or_update_latest_invoice)
expect(order).not_to receive(:invoices)
expect(renderer).to receive(:render_to_string).with(order, nil).and_return("invoice")
expect {
email.deliver_now
mail.deliver_now
}.not_to raise_error
expect(deliveries.count).to eq(1)
expect(deliveries.first.attachments.count).to eq(1)
expect(deliveries.first.attachments.first.filename).to eq(attachment_filename)
expect(email.reply_to).to eq([order.distributor.contact.email])
expect(mail.reply_to).to eq([order.distributor.contact.email])
end
end
@@ -278,7 +284,7 @@ RSpec.describe Spree::OrderMailer do
expect(generator).to receive(:generate_or_update_latest_invoice)
expect(order).to receive(:invoices).and_return([invoice])
expect(renderer).to receive(:render_to_string).with(invoice.presenter, nil)
email.deliver_now
mail.deliver_now
end
end
end

View File

@@ -11,32 +11,42 @@ RSpec.describe PaymentMailer do
let(:order) { create(:completed_order_with_totals) }
context "authorize payment email" do
subject(:email) { described_class.authorize_payment(payment) }
subject(:mail) { described_class.authorize_payment(payment) }
it "includes the distributor's name in the subject" do
order.distributor.name = "Fennel Farmer"
expect(email.subject).to include("authorize your payment to Fennel Farmer")
expect(mail.subject).to include("authorize your payment to Fennel Farmer")
end
it "sets a reply-to of the customer email" do
expect(email.reply_to).to eq([order.distributor.contact.email])
expect(mail.reply_to).to eq([order.distributor.contact.email])
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'customer facing email with active white labelling', :mail
end
it "includes a link to authorize the payment" do
link = "http://test.host/payments/#{payment.id}/authorize"
expect(email.body).to have_link link, href: link
expect(mail.body).to have_link link, href: link
end
end
context "authorization required email" do
subject(:email) { described_class.authorization_required(payment) }
subject(:mail) { described_class.authorization_required(payment) }
it "includes the distributor's name in the subject" do
expect(email.subject).to include("A payment requires authorization from the customer")
expect(mail.subject).to include("A payment requires authorization from the customer")
end
it "sets a reply-to of the customer email" do
expect(email.reply_to).to eq([order.email])
expect(mail.reply_to).to eq([order.email])
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
end
end

View File

@@ -65,6 +65,11 @@ RSpec.describe ProducerMailer do
expect(mail.reply_to).to eq [order_cycle.coordinator.contact.email]
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
it "includes the pickup time for each distributor" do
expect(mail.body.encoded).to include "#{d1.name} (Tue, 23rd Dec)"
end

View File

@@ -2,25 +2,31 @@
RSpec.describe ReportMailer do
describe "#report_ready" do
subject(:email) {
subject(:mail) {
ReportMailer.with(
to: "current_user@example.net",
blob:,
).report_ready
}
let(:blob) { ReportBlob.create_locally!("customers.csv", "report content") }
let(:order) { build(:order_with_distributor) }
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
it "notifies about a report" do
expect(email.subject).to eq "Report ready"
expect(email.body).to have_content "Report ready for download"
expect(mail.subject).to eq "Report ready"
expect(mail.body).to have_content "Report ready for download"
end
it "notifies the user" do
expect(email.to).to eq ["current_user@example.net"]
expect(mail.to).to eq ["current_user@example.net"]
end
it "contains a download link" do
expect(email.body).to have_link(
expect(mail.body).to have_link(
"customers.csv",
href: %r"^http://test\.host/rails/active_storage/disk/.*/customers\.csv$"
)

View File

@@ -1,8 +1,9 @@
# frozen_string_literal: true
RSpec.describe Spree::ShipmentMailer do
let(:order) { build(:order_with_distributor) }
let(:shipment) do
order = build(:order_with_distributor)
product = build(:product, name: %{The "BEST" product})
variant = build(:variant, product:)
line_item = build(:line_item, variant:, order:, quantity: 1, price: 5)
@@ -11,18 +12,26 @@ RSpec.describe Spree::ShipmentMailer do
allow(shipment).to receive_messages(tracking_url: "TRACK_ME")
shipment
end
let(:shipment_email) { described_class.shipped_email(shipment, delivery: true) }
let(:picked_up_email) { described_class.shipped_email(shipment, delivery: false) }
let(:distributor) { shipment.order.distributor }
context ":from not set explicitly" do
it "falls back to spree config" do
message = Spree::ShipmentMailer.shipped_email(shipment, delivery: true)
expect(message.from).to eq [Spree::Config[:mails_from]]
expect(shipment_email.from).to eq [Spree::Config[:mails_from]]
end
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :shipment_email
it_behaves_like 'customer facing email with active white labelling', :shipment_email
it_behaves_like 'email with inactive white labelling', :picked_up_email
it_behaves_like 'customer facing email with active white labelling', :picked_up_email
end
# Regression test for #2196
it "doesn't include out of stock in the email body" do
shipment_email = Spree::ShipmentMailer.shipped_email(shipment, delivery: true)
expect(shipment_email.body).not_to include(%{Out of Stock})
end
@@ -34,33 +43,27 @@ RSpec.describe Spree::ShipmentMailer do
end
it "includes the distributor's name in the subject" do
shipment_email = Spree::ShipmentMailer.shipped_email(shipment, delivery: true)
expect(shipment_email.subject).to include("#{distributor.name} Shipment Notification")
end
it "includes the distributor's name in the body" do
shipment_email = Spree::ShipmentMailer.shipped_email(shipment, delivery: true)
expect(shipment_email.body).to include("Your order from #{distributor.name} has been shipped")
end
it "picked_up email includes different text in body" do
text = "Your order from #{distributor.name} has been picked-up"
picked_up_email = Spree::ShipmentMailer.shipped_email(shipment, delivery: false)
expect(picked_up_email.body).to include(text)
end
it "picked_up email has different subject" do
shipment_email = Spree::ShipmentMailer.shipped_email(shipment, delivery: false)
expect(shipment_email.subject).to include("#{distributor.name} Pick up Notification")
expect(picked_up_email.subject).to include("#{distributor.name} Pick up Notification")
end
it "picked_up email has as the reply to email as the distributor" do
shipment_email = Spree::ShipmentMailer.shipped_email(shipment, delivery: false)
expect(shipment_email.reply_to).to eq([distributor.contact.email])
expect(picked_up_email.reply_to).to eq([distributor.contact.email])
end
it "shipment_email email has as the reply to email as the distributor" do
shipment_email = Spree::ShipmentMailer.shipped_email(shipment, delivery: true)
it "shipment_email has as the reply to email as the distributor" do
expect(shipment_email.reply_to).to eq([distributor.contact.email])
end
end

View File

@@ -3,8 +3,8 @@
RSpec.describe SubscriptionMailer do
include ActionView::Helpers::SanitizeHelper
describe '#placement_email' do
subject(:email) { SubscriptionMailer.placement_email(order, changes) }
describe '#placement_email (customer)' do
subject(:mail) { described_class.placement_email(order, changes) }
let(:changes) { {} }
let(:shop) { create(:enterprise) }
@@ -13,11 +13,16 @@ RSpec.describe SubscriptionMailer do
let(:proxy_order) { create(:proxy_order, subscription:) }
let!(:order) { proxy_order.initialise_order! }
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'customer facing email with active white labelling', :mail
end
context "when changes have been made to the order" do
before { changes[order.line_items.first.id] = 2 }
it "sends the email, which notifies the customer of changes made" do
expect { email.deliver_now }.to change { SubscriptionMailer.deliveries.count }.by(1)
expect { mail.deliver_now }.to change { SubscriptionMailer.deliveries.count }.by(1)
body = SubscriptionMailer.deliveries.last.body.encoded
@@ -28,7 +33,7 @@ RSpec.describe SubscriptionMailer do
context "and changes have not been made to the order" do
it "sends the email" do
expect { email.deliver_now }.to change { SubscriptionMailer.deliveries.count }.by(1)
expect { mail.deliver_now }.to change { SubscriptionMailer.deliveries.count }.by(1)
body = SubscriptionMailer.deliveries.last.body.encoded
@@ -44,7 +49,7 @@ RSpec.describe SubscriptionMailer do
let(:content) { Capybara::Node::Simple.new(body) }
let(:body) { SubscriptionMailer.deliveries.last.body.encoded }
before { email.deliver_now }
before { mail.deliver_now }
context "when the customer has a user account" do
let(:customer) { create(:customer, enterprise: shop) }
@@ -85,7 +90,7 @@ RSpec.describe SubscriptionMailer do
before { allow(order).to receive(:new_outstanding_balance) { 123 } }
it 'renders the amount as money' do
expect(email.body).to include('$123')
expect(mail.body).to include('$123')
end
end
@@ -93,13 +98,13 @@ RSpec.describe SubscriptionMailer do
before { allow(order).to receive(:new_outstanding_balance) { 0 } }
it 'displays the payment status' do
expect(email.body).to include('NOT PAID')
expect(mail.body).to include('NOT PAID')
end
end
end
describe '#confirmation_email' do
subject(:email) { SubscriptionMailer.confirmation_email(order) }
describe '#confirmation_email (customer)' do
subject(:mail) { described_class.confirmation_email(order) }
let(:customer) { create(:customer) }
let(:subscription) { create(:subscription, customer:, with_items: true) }
@@ -108,14 +113,15 @@ RSpec.describe SubscriptionMailer do
let(:user) { order.user }
it "sends the email" do
expect { email.deliver_now }.to change{ SubscriptionMailer.deliveries.count }.by(1)
expect { mail.deliver_now }.to change{ SubscriptionMailer.deliveries.count }.by(1)
body = SubscriptionMailer.deliveries.last.body.encoded
expect(body).to include "This order was automatically placed for you"
end
it "display the OFN header by default" do
expect(email.body).to include(ContentConfig.url_for(:logo))
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'customer facing email with active white labelling', :mail
end
describe "linking to order page" do
@@ -125,7 +131,7 @@ RSpec.describe SubscriptionMailer do
let(:customer) { create(:customer) }
it "provides link to view details" do
expect(email.body.encoded).to include(order_url(order))
expect(mail.body.encoded).to include(order_url(order))
end
end
@@ -133,7 +139,7 @@ RSpec.describe SubscriptionMailer do
let(:customer) { create(:customer, user: nil) }
it "does not provide link" do
expect(email.body).not_to match /#{order_link_href}/
expect(mail.body).not_to match /#{order_link_href}/
end
end
end
@@ -142,7 +148,7 @@ RSpec.describe SubscriptionMailer do
before { allow(order).to receive(:new_outstanding_balance) { 123 } }
it 'renders the amount as money' do
expect(email.body).to include('$123')
expect(mail.body).to include('$123')
end
end
@@ -150,40 +156,36 @@ RSpec.describe SubscriptionMailer do
before { allow(order).to receive(:new_outstanding_balance) { 0 } }
it 'displays the payment status' do
expect(email.body).to include('NOT PAID')
end
end
context 'when hide OFN navigation is enabled for the distributor of the order' do
before do
allow(order.distributor).to receive(:hide_ofn_navigation).and_return(true)
end
it 'does not display the OFN navigation' do
expect(email.body).not_to include(ContentConfig.url_for(:logo))
expect(mail.body).to include('NOT PAID')
end
end
end
describe "empty order notification" do
describe "#empty_order_email (customer)" do
subject(:mail) { described_class.empty_email(order, {}) }
let(:subscription) { create(:subscription, with_items: true) }
let(:proxy_order) { create(:proxy_order, subscription:) }
let(:distributor) { create(:distributor_enterprise) }
let!(:order) { proxy_order.initialise_order! }
before do
expect do
SubscriptionMailer.empty_email(order, {}).deliver_now
end.to change{ SubscriptionMailer.deliveries.count }.by(1)
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'customer facing email with active white labelling', :mail
end
it "sends the email" do
expect { mail.deliver_now }.to change{ SubscriptionMailer.deliveries.count }.by(1)
body = SubscriptionMailer.deliveries.last.body.encoded
expect(body).to include "We tried to place a new order with"
expect(body).to include "Unfortunately, none of products that you ordered were available"
end
end
describe "failed payment notification" do
describe "#failed_payment_email (customer)" do
subject(:mail) { described_class.failed_payment_email(order) }
let(:customer) { create(:customer) }
let(:subscription) { create(:subscription, customer:, with_items: true) }
let(:proxy_order) { create(:proxy_order, subscription:) }
@@ -191,13 +193,16 @@ RSpec.describe SubscriptionMailer do
before do
order.errors.add(:base, "This is a payment failure error")
end
expect do
SubscriptionMailer.failed_payment_email(order).deliver_now
end.to change{ SubscriptionMailer.deliveries.count }.by(1)
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'customer facing email with active white labelling', :mail
end
it "sends the email" do
expect { mail.deliver_now }.to change{ SubscriptionMailer.deliveries.count }.by(1)
body = strip_tags(SubscriptionMailer.deliveries.last.body.encoded)
expect(body).to include 'We tried to process a payment, but had some problems...'
email_so_failed_payment_explainer_html = "The payment for your subscription with <strong>%s" \
@@ -212,10 +217,8 @@ RSpec.describe SubscriptionMailer do
end
describe "linking to order page" do
let(:order_link_href) { "href=\"#{order_url(order)}\"" }
let(:email) { SubscriptionMailer.deliveries.last }
let(:body) { email.body.encoded }
let(:order_link_href) { "href=['\"]#{order_url(order)}['\"]" }
let(:body) { mail.body.encoded }
context "when the customer has a user account" do
let(:customer) { create(:customer) }
@@ -235,28 +238,37 @@ RSpec.describe SubscriptionMailer do
end
end
describe "order placement summary" do
describe "#order_placement_summary_email (hub)" do
subject(:mail) { described_class.placement_summary_email(summary) }
let!(:shop) { create(:enterprise, :with_logo_image) }
let!(:summary) { double(:summary, shop_id: shop.id) }
let(:body) { strip_tags(SubscriptionMailer.deliveries.last.body.encoded) }
let(:scope) { "subscription_mailer" }
let(:order) { build(:order_with_distributor) }
before do
allow(summary).to receive(:unrecorded_ids) { [] }
allow(summary).to receive(:subscription_issues) { [] }
allow(summary).to receive(:order_count) { 37 }
allow(summary).to receive(:issue_count) { 0 }
allow(summary).to receive(:issues) { {} }
end
it "renders the shop's logo" do
mail.deliver_now
expect(SubscriptionMailer.deliveries.last.body).to include "logo.png"
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
context "when no issues were encountered while processing subscriptions" do
before do
allow(summary).to receive(:order_count) { 37 }
allow(summary).to receive(:issue_count) { 0 }
allow(summary).to receive(:issues) { {} }
end
it "sends the email, which notifies the enterprise that all orders " \
"were successfully processed" do
SubscriptionMailer.placement_summary_email(summary).deliver_now
mail.deliver_now
expect(body).to include("Below is a summary of the subscription orders " \
"that have just been placed for %s." % shop.name)
expect(body).to include("A total of %d subscriptions were marked " \
@@ -264,11 +276,6 @@ RSpec.describe SubscriptionMailer do
expect(body).to include 'All were processed successfully.'
expect(body).not_to include 'Details of the issues encountered are provided below.'
end
it "renders the shop's logo" do
SubscriptionMailer.placement_summary_email(summary).deliver_now
expect(SubscriptionMailer.deliveries.last.body).to include "logo.png"
end
end
context "when some issues were encountered while processing subscriptions" do
@@ -287,7 +294,7 @@ RSpec.describe SubscriptionMailer do
context "when no unrecorded issues are present" do
it "sends the email, which notifies the enterprise that some issues were encountered" do
SubscriptionMailer.placement_summary_email(summary).deliver_now
mail.deliver_now
expect(body).to include("Below is a summary of the subscription orders " \
"that have just been placed for %s." % shop.name)
expect(body).to include("A total of %d subscriptions were marked " \
@@ -318,7 +325,7 @@ RSpec.describe SubscriptionMailer do
it "sends the email, which notifies the enterprise that some issues were encountered" do
expect(summary).to receive(:orders_affected_by).with(:other) { [order3, order4] }
SubscriptionMailer.placement_summary_email(summary).deliver_now
mail.deliver_now
expect(body).to include("Error Encountered (%d orders)" % 2)
expect(body).to include 'Automatic processing of these orders failed due to an error. ' \
'The error has been listed where possible.'
@@ -344,7 +351,7 @@ RSpec.describe SubscriptionMailer do
allow(summary).to receive(:issue_count) { 2 }
allow(summary).to receive(:issues) { { changes: { 1 => nil, 2 => nil } } }
allow(summary).to receive(:orders_affected_by) { [order1, order2] }
SubscriptionMailer.placement_summary_email(summary).deliver_now
mail.deliver_now
end
it "sends the email, which notifies the enterprise that some issues were encountered" do
@@ -368,24 +375,29 @@ RSpec.describe SubscriptionMailer do
end
end
describe "order confirmation summary" do
describe "#order_confirmation_summary_email (hub)" do
subject(:mail) { SubscriptionMailer.confirmation_summary_email(summary) }
let!(:shop) { create(:enterprise) }
let!(:summary) { double(:summary, shop_id: shop.id) }
let(:body) { strip_tags(SubscriptionMailer.deliveries.last.body.encoded) }
let(:scope) { "subscription_mailer" }
let(:order) { build(:order_with_distributor) }
before do
allow(summary).to receive(:unrecorded_ids) { [] }
allow(summary).to receive(:subscription_issues) { [] }
allow(summary).to receive(:order_count) { 37 }
allow(summary).to receive(:issue_count) { 0 }
allow(summary).to receive(:issues) { {} }
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
context "when no issues were encountered while processing subscriptions" do
before do
allow(summary).to receive(:order_count) { 37 }
allow(summary).to receive(:issue_count) { 0 }
allow(summary).to receive(:issues) { {} }
SubscriptionMailer.confirmation_summary_email(summary).deliver_now
end
before { mail.deliver_now }
it "sends the email, which notifies the enterprise " \
"that all orders were successfully processed" do
@@ -414,7 +426,7 @@ RSpec.describe SubscriptionMailer do
context "when no unrecorded issues are present" do
it "sends the email, which notifies the enterprise that some issues were encountered" do
SubscriptionMailer.confirmation_summary_email(summary).deliver_now
mail.deliver_now
expect(body).to include("Below is a summary of the subscription orders " \
"that have just been finalised for %s." % shop.name)
expect(body).to include("A total of %d subscriptions were marked " \
@@ -445,7 +457,7 @@ RSpec.describe SubscriptionMailer do
it "sends the email, which notifies the enterprise that some issues were encountered" do
expect(summary).to receive(:orders_affected_by).with(:other) { [order3, order4] }
SubscriptionMailer.confirmation_summary_email(summary).deliver_now
mail.deliver_now
expect(body).to include("Failed Payment (%d orders)" % 2)
expect(body).to include 'Automatic processing of payment for these orders failed ' \
'due to an error. The error has been listed where possible.'
@@ -471,7 +483,7 @@ RSpec.describe SubscriptionMailer do
allow(summary).to receive(:issue_count) { 2 }
allow(summary).to receive(:issues) { { changes: { 1 => nil, 2 => nil } } }
allow(summary).to receive(:orders_affected_by) { [order1, order2] }
SubscriptionMailer.confirmation_summary_email(summary).deliver_now
mail.deliver_now
end
it "sends the email, which notifies the enterprise that some issues were encountered" do

View File

@@ -1,7 +1,9 @@
# frozen_string_literal: true
RSpec.describe Spree::TestMailer do
subject(:mail) { described_class.test_email(order) }
let(:user) { create(:user) }
let(:order) { build(:order_with_distributor) }
context ":from not set explicitly" do
it "falls back to spree config" do
@@ -16,4 +18,8 @@ RSpec.describe Spree::TestMailer do
Spree::TestMailer.test_email(user.id).deliver_now
}.not_to raise_error
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
end
end

View File

@@ -2,14 +2,19 @@
RSpec.describe Spree::UserMailer do
let(:user) { build(:user) }
let(:order) { build(:order_with_totals_and_distribution) }
before { ActionMailer::Base.deliveries.clear }
describe '#signup_confirmation' do
subject(:mail) { Spree::UserMailer.signup_confirmation(user) }
it "sends email when given a user" do
Spree::UserMailer.signup_confirmation(user).deliver_now
mail.deliver_now
expect(ActionMailer::Base.deliveries.count).to eq(1)
end
describe "user locale" do
context "user locale handling" do
around do |example|
original_default_locale = I18n.default_locale
I18n.default_locale = 'pt'
@@ -19,16 +24,21 @@ RSpec.describe Spree::UserMailer do
it "sends email in user locale when user locale is defined" do
user.locale = 'es'
Spree::UserMailer.signup_confirmation(user).deliver_now
mail.deliver_now
expect(ActionMailer::Base.deliveries.first.body).to include "Gracias por unirte"
end
it "sends email in default locale when user locale is not available" do
user.locale = 'cn'
Spree::UserMailer.signup_confirmation(user).deliver_now
mail.deliver_now
expect(ActionMailer::Base.deliveries.first.body).to include "Obrigada por juntar-se"
end
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
end
describe "#confirmation_instructions" do
@@ -42,7 +52,6 @@ RSpec.describe Spree::UserMailer do
context 'when the language is English' do
it 'sends an email with the translated subject' do
mail.deliver_now
expect(ActionMailer::Base.deliveries.first.subject).to include(
"Please confirm your OFN account"
)
@@ -54,19 +63,28 @@ RSpec.describe Spree::UserMailer do
it 'sends an email with the translated subject' do
mail.deliver_now
expect(ActionMailer::Base.deliveries.first.subject).to include(
"Por favor, confirma tu cuenta de OFN"
)
end
end
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
end
# adapted from https://github.com/spree/spree_auth_devise/blob/70737af/spec/mailers/user_mailer_spec.rb
describe '#reset_password_instructions' do
describe 'message contents' do
subject(:mail) { described_class.reset_password_instructions(user, nil).deliver_now }
subject(:mail) { described_class.reset_password_instructions(user, nil).deliver_now }
context "white labelling" do
it_behaves_like 'email with inactive white labelling', :mail
it_behaves_like 'non-customer facing email with active white labelling', :mail
end
describe 'message contents' do
context 'subject includes' do
it 'translated devise instructions' do
expect(mail.subject).to include "Reset password instructions"

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
RSpec.shared_examples 'email with inactive white labelling' do |mail|
it 'always displays the OFN header with logo' do
expect(public_send(mail).body).to include(ContentConfig.url_for(:logo))
end
end
RSpec.shared_examples 'non-customer facing email with active white labelling' do |mail|
context 'when hide OFN navigation is enabled for the distributor of the order' do
before do
order.distributor.hide_ofn_navigation = true
end
it 'still displays the OFN header with logo' do
expect(public_send(mail).body).to include(ContentConfig.url_for(:logo))
end
end
end
RSpec.shared_examples 'customer facing email with active white labelling' do |mail|
context 'when hide OFN navigation is enabled for the distributor of the order' do
before do
order.distributor.hide_ofn_navigation = true
end
it 'does not display the OFN header and logo' do
expect(public_send(mail).body).not_to include(ContentConfig.url_for(:logo))
end
end
end

View File

@@ -2763,7 +2763,7 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
brace-expansion@^2.0.1:
brace-expansion@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7"
integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==
@@ -5138,18 +5138,18 @@ minimalistic-assert@^1.0.0:
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
minimatch@^3.0.4, minimatch@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
version "3.1.5"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e"
integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==
dependencies:
brace-expansion "^1.1.7"
minimatch@^9.0.4:
version "9.0.5"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
version "9.0.9"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e"
integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==
dependencies:
brace-expansion "^2.0.1"
brace-expansion "^2.0.2"
minimist@^1.2.6:
version "1.2.8"