diff --git a/app/controllers/spree/admin/users_controller.rb b/app/controllers/spree/admin/users_controller.rb index 4591f1f5d5..00fd64e8a9 100644 --- a/app/controllers/spree/admin/users_controller.rb +++ b/app/controllers/spree/admin/users_controller.rb @@ -20,17 +20,9 @@ module Spree end def create - if params[:user] - roles = params[:user].delete("spree_role_ids") - end - @user = Spree::User.new(user_params) if @user.save - if roles - @user.spree_roles = roles.compact_blank.collect{ |r| Spree::Role.find(r) } - end - flash[:success] = Spree.t(:created_successfully) redirect_to edit_admin_user_path(@user) else @@ -39,15 +31,7 @@ module Spree end def update - if params[:user] - roles = params[:user].delete("spree_role_ids") - end - if @user.update(user_params) - if roles - @user.spree_roles = roles.compact_blank.collect{ |r| Spree::Role.find(r) } - end - flash[:success] = update_message redirect_to edit_admin_user_path(@user) else @@ -131,7 +115,7 @@ module Spree def user_params ::PermittedAttributes::User.new(params).call( - %i[enterprise_limit show_api_key_view] + %i[admin enterprise_limit show_api_key_view] ) end end diff --git a/app/models/spree/app_configuration.rb b/app/models/spree/app_configuration.rb index ca6e71f17d..a3069b3b02 100644 --- a/app/models/spree/app_configuration.rb +++ b/app/models/spree/app_configuration.rb @@ -37,7 +37,6 @@ module Spree preference :currency_symbol_position, :string, default: "before" preference :currency_thousands_separator, :string, default: "," preference :display_currency, :boolean, default: false - preference :default_country_id, :integer preference :default_meta_description, :string, default: 'OFN demo site' preference :default_meta_keywords, :string, default: 'ofn, demo' preference :default_seo_title, :string, default: '' diff --git a/app/models/spree/role.rb b/app/models/spree/role.rb deleted file mode 100644 index 9e34c4d8d2..0000000000 --- a/app/models/spree/role.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module Spree - class Role < ApplicationRecord - has_and_belongs_to_many :users, join_table: 'spree_roles_users', - class_name: "Spree::User" - - # The only role we have at the moment: - def self.admin - Spree::Role.find_or_create_by(name: 'admin') - end - end -end diff --git a/app/models/spree/tax_rate.rb b/app/models/spree/tax_rate.rb index 239a6d9072..bb200365e8 100644 --- a/app/models/spree/tax_rate.rb +++ b/app/models/spree/tax_rate.rb @@ -105,16 +105,7 @@ module Spree if default_zone_or_zone_match?(item.order) calculator.compute(item) else - # Tax refund should not be possible with the way our production server are configured - Alert.raise( - "Notice: Tax refund should not be possible, please check the default zone and " \ - "the tax rate zone configuration" - ) do |payload| - payload.add_metadata :order_tax_zone, item.order.tax_zone - payload.add_metadata :tax_rate_zone, zone - payload.add_metadata :default_zone, Zone.default_tax - end - # In this case, it's a refund. + # In this case, it's a refund (for instance offering a manual discount via an adjustment) calculator.compute(item) * - 1 end else diff --git a/app/models/spree/user.rb b/app/models/spree/user.rb index 371ab636f7..72f2a3c80a 100644 --- a/app/models/spree/user.rb +++ b/app/models/spree/user.rb @@ -18,15 +18,11 @@ module Spree belongs_to :ship_address, class_name: 'Spree::Address' belongs_to :bill_address, class_name: 'Spree::Address' - has_and_belongs_to_many :spree_roles, - join_table: 'spree_roles_users', - class_name: "Spree::Role" - before_validation :set_login after_create :associate_customers, :associate_orders before_destroy :check_completed_orders - scope :admin, lambda { includes(:spree_roles).where("spree_roles.name" => "admin") } + scope :admin, -> { where(admin: true) } has_many :enterprise_roles, dependent: :destroy has_many :enterprises, through: :enterprise_roles @@ -58,11 +54,6 @@ module Spree User.admin.count > 0 end - # Checks whether the specified user is a superadmin, with full control of the instance - def admin? - spree_roles.any? { |role| role.name == "admin" } - end - # Send devise-based user emails asyncronously via ActiveJob # See: https://github.com/heartcombo/devise/tree/v3.5.10#activejob-integration def send_devise_notification(notification, *args) diff --git a/app/models/spree/zone.rb b/app/models/spree/zone.rb index b310c2927f..a3deacda4f 100644 --- a/app/models/spree/zone.rb +++ b/app/models/spree/zone.rb @@ -7,6 +7,8 @@ module Spree has_and_belongs_to_many :shipping_methods, join_table: 'spree_shipping_methods_zones' validates :name, presence: true, uniqueness: true + validates :zone_members, presence: true + after_save :remove_defunct_members after_save :remove_previous_default diff --git a/app/views/spree/admin/users/_form.html.haml b/app/views/spree/admin/users/_form.html.haml index 4aac09f35f..2064cb4f74 100644 --- a/app/views/spree/admin/users/_form.html.haml +++ b/app/views/spree/admin/users/_form.html.haml @@ -5,13 +5,8 @@ = f.email_field :email, class: "fullwidth" = error_message_on :user, :email .field - = label_tag nil, t(".roles") - %ul - - [Spree::Role.admin].each do |role| - %li - = check_box_tag "user[spree_role_ids][]", role.id, @user.spree_roles.include?(role), id: "user_spree_role_#{role.name}" - = label_tag role.name - = hidden_field_tag "user[spree_role_ids][]", "" + = f.label :admin, t(".admin") + = f.check_box :admin = f.field_container :locale do = f.label :locale, t(".locale") = f.select :locale, locale_options, class: "fullwidth" diff --git a/app/views/spree/admin/zones/index.html.haml b/app/views/spree/admin/zones/index.html.haml index d46cde7a7d..deabffa5f9 100644 --- a/app/views/spree/admin/zones/index.html.haml +++ b/app/views/spree/admin/zones/index.html.haml @@ -22,7 +22,7 @@ %tr %th= sort_link [:spree, @search], :name, t("spree.name"), title: 'zones_order_by_name_title' %th - = sort_link [:spree, @search], :description, t("spree.description"), {}, {title: 'zones_order_by_description_title'} + = sort_link [:spree, @search], :description, t("spree.description"), {title: 'zones_order_by_description_title'} %th= t("spree.default_tax") %th.actions %tbody diff --git a/app/views/spree/admin/zones/new.html.haml b/app/views/spree/admin/zones/new.html.haml index b6bac9e73b..2f71b16d77 100644 --- a/app/views/spree/admin/zones/new.html.haml +++ b/app/views/spree/admin/zones/new.html.haml @@ -11,5 +11,7 @@ = form_for [:admin, @zone] do |zone_form| = render partial: 'form', locals: { zone_form: zone_form } + = render partial: 'member_type', locals: { type: 'country', zone_form: zone_form } + = render partial: 'member_type', locals: { type: 'state', zone_form: zone_form } .clear = render partial: 'spree/admin/shared/new_resource_links' diff --git a/config/initializers/rack_timeout.rb b/config/initializers/rack_timeout.rb new file mode 100644 index 0000000000..ced78fd762 --- /dev/null +++ b/config/initializers/rack_timeout.rb @@ -0,0 +1,7 @@ +# https://github.com/zombocom/rack-timeout/blob/main/doc/logging.md +# state changes into timed_out and expired are logged at the ERROR level + +# Log ready and completed messages in DEBUG mode only (instead of default INFO) +Rack::Timeout::StateChangeLoggingObserver::STATE_LOG_LEVEL[:ready] = :debug +Rack::Timeout::StateChangeLoggingObserver::STATE_LOG_LEVEL[:completed] = :debug + diff --git a/config/locales/el.yml b/config/locales/el.yml index 14e9c13e29..b4689848a6 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -61,7 +61,7 @@ el: order_cycle: orders_close_at: Ημερομηνία Κλεισίματος variant_override: - count_on_hand: "Στο χέρι" + count_on_hand: "Διαθέσιμο απόθεμα" spree/payment_method/calculator: preferred_flat_percent: "Υπολογιστής Σταθερού Ποσοστού:" preferred_amount: "Υπολογιστής Ποσού: " @@ -433,7 +433,7 @@ el: show_all_with_more: "Εμφάνιση όλων" cancel: Ακύρωση edit: Επεξεργασία - clone: Κλώνος + clone: Κλωνοποίηση distributors: Διανομείς distribution: Κατανομή order_cycles: Κύκλοι παραγγελιών @@ -488,8 +488,8 @@ el: back_to_payments_list: "Επιστροφή στη λίστα πληρωμών" maestro_or_solo_cards: "Κάρτα Maestro/Sola" backordered: "Σε εκκρεμότητα" - on_hand: "Στο χέρι" - on hand: "Στο χέρι" + on_hand: "Διαθέσιμο απόθεμα" + on hand: "Διαθέσιμο απόθεμα" ship: "Αποστολή" shipping_category: "Κατηγορία μεταφορικών" height: "Ύψος" @@ -534,26 +534,26 @@ el: producer: Παραγωγός category: Κατηγορία sku: SKU - on_hand: "Στο χέρι" + on_hand: "Διαθέσιμο απόθεμα" on_demand: "Κατά παραγγελία" tax_category: "Φορολογική Κατηγορία" inherits_properties: "Διατήρηση Ιδιοτήτων" import_date: "Ημερομηνία καταχώρησης" - actions: Δράση + actions: Ενέργειες columns_selector: unit: Μονάδα price: Τιμή producer: Παραγωγός category: Κατηγορία sku: SKU - on_hand: "Στο χέρι" + on_hand: "Διαθέσιμο απόθεμα" on_demand: "Κατά παραγγελία" tax_category: "Φορολογική Κατηγορία" inherits_properties: "Διατήρηση Ιδιοτήτων" import_date: "Ημερομηνία καταχώρησης" actions: edit: Επεξεργασία - clone: Κλώνος + clone: Κλωνοποίηση delete: Διαγραφή remove: Αφαίρεση image: @@ -574,7 +574,7 @@ el: name: Όνομα first_name: Όνομα last_name: Επίθετο - on_hand: Στο χέρι + on_hand: Διαθέσιμο απόθεμα on_demand: Κατά παραγγελία on_demand?: Κατά παραγγελία? order_cycle: Κύκλος Παραγγελειών @@ -615,7 +615,7 @@ el: please_select: Παρακαλώ επιλέξτε... column_save_as_default: Αποθήκευση ως πρότυπο columns: Στήλες - actions: Δράση + actions: Ενέργειες viewing: "Προβολή : %{current_view_name}" description: Περιγραφή whats_this: Τι είναι αυτό? @@ -725,7 +725,7 @@ el: index: title: "Τέλη επιχείρησης" enterprise: "Επιχείρηση" - fee_type: "Κατηγορίες αμοιβών" + fee_type: "Κατηγορίες τελών" name: "Όνομα" tax_category: "Φορολογική Κατηγορία" calculator: "Υπολογισμός" @@ -769,7 +769,7 @@ el: seo_tip: "Χρησιμοποιήστε λέξεις - κλειδιά για να βοηθήσετε στην αναζήτηση των προϊόντων σας στο διαδίκτυο. Χρησιμοποιήστε κενό για να διαχωρίσετε κάθε λέξη -κλειδί." search: "Αναζήτηση" properties: - property_name: "Όνομα Ιδιοκτησίας" + property_name: "Όνομα ιδιότητας" inherited_property: "Επίκτητη ιδιότητα" variants: infinity: "Άπειρο" @@ -962,7 +962,7 @@ el: unit_type: Τύπος μονάδας variant_unit_name: Όνομα μεταβλητής price: Τιμή - on_hand: Στο χέρι + on_hand: Διαθέσιμο απόθεμα on_demand: Κατά παραγγελία shipping_category: Κατηγορία μεταφορικών tax_category: Φορολογική Κατηγορία @@ -1089,12 +1089,12 @@ el: enterprise_fees: legend: "Τέλη επιχείρησης" name: Όνομα - fee_type: Κατηγορίες αμοιβών + fee_type: Κατηγορίες τελών manage_fees: Διαχείριση τελών επιχείρησης no_fees_yet: Δεν έχετε τέλη επιχείρησης ακόμα. create_button: Δημιούργησε έναν τώρα enterprise_permissions: - legend: "Δικαιώματα Επιχείρησης " + legend: "Άδειες επιχείρησης" enterprise_relationships: Σχέσεις Επιχειρήσεων images: legend: "Εικόνες" @@ -1341,7 +1341,7 @@ el: hub_shop_text: Πούλα προιόντα άλλων hub_shop_description_text: Η επιχείρησή σας είναι η ραχοκοκαλιά του τοπικού σας συστήματος τροφίμων. Συγκεντρώνετε προϊόντα από άλλες επιχειρήσεις και μπορείτε να τα πουλήσετε μέσω του καταστήματός σας στο Open Food Network. choose_option: Επιλέξτε μία από τις παραπάνω επιλογές. - change_now: Άλαξέ το τώρα + change_now: Εφαρμογή αλλαγής enterprise_user_index: loading_enterprises: ΦΌΡΤΩΣΕ ΤΙΣ ΕΠΙΧΕΙΡΉΣΕΙΣ no_enterprises_found: Δεν βρέθηκε επιχείρηση. @@ -1550,7 +1550,7 @@ el: shipping_methods: "Τρόποι αποστολής" payment_methods: "Τρόποι πληρωμής" enterprise_fees: "Τέλη επιχείρησης" - enterprise_permissions: "Δικαιώματα Επιχείρησης " + enterprise_permissions: "Άδειες επιχείρησης" inventory_settings: "Ρυθμίσεις Αποθεμάτων" tag_rules: "Κανόνες ετικετών" shop_preferences: "Επιλογές καταστήματος" @@ -1585,7 +1585,7 @@ el: totals_by_supplier: Παραγγείλετε συνολικά διανομέας κύκλου ανά προμηθευτή customer_totals: Σύνολο κύκλου παραγγελιών για τον πελάτη all_products: Ολα τα προϊόντα - inventory: Απογραφή (στο χέρι) + inventory: 'Απόθεμα (Διαθέσιμο) ' lettuce_share: Μαρούλι payment_methods: Αναφορά μεθόδων πληρωμής delivery: Αναφορά παράδοσης @@ -2307,7 +2307,7 @@ el: shopping_oc_last_closed: "Ο τελευταίος κύκλος έκλεισε %{distance_of_time} πριν" shopping_oc_next_open: "Ο επόμενος κύκλος ανοίγει σε %{distance_of_time}" shopping_oc_select: "Επιλέγω..." - shopping_tabs_home: "Home" + shopping_tabs_home: "Αρχική" shopping_tabs_shop: "Κατάστημα" shopping_tabs_about: "Σχετικά" shopping_tabs_producers: "Παραγωγοί" @@ -2336,7 +2336,7 @@ el: hubs_filter_by: "Φιλτράρισμα κατά" hubs_filter_type: "Τύπος" hubs_filter_delivery: "Διανομή" - hubs_filter_property: "Ιδιοκτησία" + hubs_filter_property: "Ιδιότητα" hubs_matches: "Εννοείς?" hubs_intro: Ψώνισε στην περιοχή σου hubs_distance: Πιο κοντά στο @@ -2418,7 +2418,7 @@ el: producers_buy_at_html: "Αγοράστε προϊόντα %{enterprise} στη διεύθυνση:" producers_filter: Φιλτράρισμα κατά producers_filter_type: Τύπος - producers_filter_property: Ιδιοκτησία + producers_filter_property: Ιδιότητα producers_title: Παραγωγοί producers_headline: Βρες τοπικούς παραγωγούς producers_signup_title: Εγγραφείτε ως παραγωγός @@ -2689,9 +2689,9 @@ el: text: "Έχετε συμπληρώσει το όριο για τον αριθμό των επιχειρήσεων που επιτρέπεται να έχετε στην ιδιοκτησία σας" action: "Επιστροφή στην αρχική σελίδα" finished: - headline: "Πεπερασμένος!" + headline: "Η διαδικασία ολοκληρώθηκε!" thanks: "Ευχαριστούμε για τη συμπλήρωση των στοιχείων για το %{enterprise}." - login: "Μπορείτε να αλλάξετε ή να ενημερώσετε την επιχείρησή σας σε οποιοδήποτε στάδιο, συνδεθείτε στο Open Food Network και μεταβείτε στον Διαχειριστή." + login: "Μπορείτε να αλλάξετε ή να ενημερώσετε την επιχείρησή σας σε οποιοδήποτε στάδιο, συνδεθείτε στο Open Food Network και μεταβείτε στον πίνακα διαχείρισης." action: "Μεταβείτε στον Πίνακα Επιχειρήσεων" back: "Πίσω" continue: "Συνέχεια" @@ -2779,7 +2779,7 @@ el: process_my_order: "Επεξεργασία της παραγγελίας μου" delivery_instructions: Οδηγίες παράδοσης delivery_method: Μέθοδος παράδοσης - fee_type: "Κατηγορίες αμοιβών" + fee_type: "Κατηγορίες τελών" tax_category: "Φορολογική κατηγορία" display: "Εμφάνιση" tags: "Ετικέτες" @@ -2802,7 +2802,7 @@ el: roles: "Ρόλοι" update: "Ανανέωση" delete: Διαγραφή - add_producer_property: "Προσθήκη ιδιοκτησίας παραγωγού" + add_producer_property: "Προσθήκη ιδιότητας παραγωγού" in_progress: "Σε εξέλιξη" started_at: "Ξεκίνησε στις" queued: "Ουρά" @@ -2832,7 +2832,7 @@ el: spree_admin_enterprises_create_new_product: "ΔΗΜΙΟΥΡΓΗΣΤΕ ΝΕΟ ΠΡΟDΟΝ" spree_admin_single_enterprise_alert_mail_confirmation: "Παρακαλώ επιβεβαιώστε τη διεύθυνση email για" spree_admin_single_enterprise_alert_mail_sent: "Έχουμε στείλει ένα email στο" - spree_admin_overview_action_required: "Απαιτείται δράση" + spree_admin_overview_action_required: "Απαιτείται Ενέργεια" spree_admin_overview_check_your_inbox: "Ελέγξτε τα εισερχόμενά σας για περισσότερες οδηγίες. Ευχαριστώ!" spree_admin_unit_value: Αξία μονάδας spree_admin_unit_description: Περιγραφή μονάδας @@ -2854,7 +2854,7 @@ el: spree_user_enterprise_limit_error: "^%{email} δεν επιτρέπεται να κατέχει άλλες επιχειρήσεις (το όριο είναι %{enterprise_limit})." spree_variant_product_error: πρέπει να έχει τουλάχιστον μία παραλλαγή your_profil_live: "Προφίλ καταστήματος" - see: "ΕΜΦΑΝΙΣΗ" + see: "Εμφάνιση" live: " " manage: "Διαχείριση" resend: "Ξαναστείλτε" @@ -2865,7 +2865,7 @@ el: edit_profile_details: "Επεξεργασία στοιχείων προφίλ" edit_profile_details_etc: "Αλλάξτε την περιγραφή του καταστήματός σας, εικόνες κ.λ.π." order_cycle: "Κύκλος Παραγγελειών" - enterprise_relationships: "Δικαιώματα επιχείρησης" + enterprise_relationships: "Άδειες επιχείρησης" first_name_begins_with: "Το όνομα αρχίζει με" last_name_begins_with: "Το επώνυμο αρχίζει με" shipping_method: "Μέθοδος αποστολής" @@ -3114,7 +3114,7 @@ el: payment_method_not_supported: "Αυτός ο τρόπος πληρωμής δεν υποστηρίζεται. Παρακαλώ επιλέξτε ένα άλλο." payment_updated: "Η πληρωμή ενημερώθηκε" cannot_perform_operation: "Δεν ήταν δυνατή η ενημέρωση της πληρωμής" - action_required: "Απαιτείται δράση" + action_required: "Απαιτείται Ενέργεια" tag_rules: "Κανόνες ετικετών" enterprise_fee_whole_order: Ολόκληρη παραγγελία enterprise_fee_by_name: "%{name} κρατήσεις απο %{role} %{enterprise_name}" @@ -3458,6 +3458,7 @@ el: add_to_cart: "Προσθήκη" in_cart: "στο καλάθι" quantity_in_cart: "%{quantity} στο καλάθι" + remaining_in_stock: "Έχουν απομείνει %{quantity}" bulk_buy_modal: min_quantity: "Ελάχιστη ποσότητα" max_quantity: "Μέγιστη ποσότητα" @@ -3648,7 +3649,7 @@ el: formats: csv: header: - fee_type: "Κατηγορίες αμοιβών" + fee_type: "Κατηγορίες τελών" enterprise_name: "Ιδιοκτήτης Επιχειρήσεων" fee_name: "Όνομα τέλους" customer_name: "Πελάτης" @@ -3658,7 +3659,7 @@ el: total_amount: "$ $ SUM" html: header: - fee_type: "Κατηγορίες αμοιβών" + fee_type: "Κατηγορίες τελών" enterprise_name: "Ιδιοκτήτης Επιχειρήσεων" fee_name: "Όνομα τέλους" customer_name: "Πελάτης" @@ -3767,7 +3768,7 @@ el: count_on_hand: "Μετρήστε στο χέρι" quantity: "Ποσότητα" on_demand: "Κατά παραγγελία" - on_hand: "Στο χέρι" + on_hand: "Διαθέσιμο απόθεμα" package_from: "πακέτο από" item_description: "περιγραφή αντικειμένου" price: "Τιμή" @@ -3861,7 +3862,7 @@ el: iso_name: "Όνομα ISO" states_required: "Απαιτούνται κράτη" editing_country: "Χώρα επεξεργασίας" - states: "Κρατών" + states: "Γεωγραφικά διαμερίσματα" abbreviation: "Συντομογραφία" new_state: "Νέα Πολιτεία" payment_methods: "τρόποι πληρωμής" @@ -3902,7 +3903,7 @@ el: new_image: "Νέα εικόνα" filename: "Ονομα αρχείου" alt_text: "Εναλλακτικό Κείμενο" - thumbnail: "Ονυξ του αντίχειρος" + thumbnail: "Μικρογραφία (Thumnail) " back_to_images_list: "Επιστροφή στη λίστα εικόνων" email: ΗΛΕΚΤΡΟΝΙΚΗ ΔΙΕΥΘΥΝΣΗ account_updated: "Ο λογαριασμός ενημερώθηκε!" @@ -4002,17 +4003,17 @@ el: properties: index: properties: "Ιδιότητες" - new_property: "Νέα ιδιοκτησία" + new_property: "Νέα ιδιότητα" name: "Όνομα" - presentation: "Παρουσίαση" + presentation: "Περιγραφή" new: - new_property: "Νέα ιδιοκτησία" + new_property: "Νέα ιδιότητα" edit: - editing_property: "Επεξεργασία ιδιοκτησίας" + editing_property: "Επεξεργασία ιδιότητας" back_to_properties_list: "Επιστροφή στη λίστα ιδιοτήτων" form: name: "Όνομα" - presentation: "Παρουσίαση" + presentation: "Περιγραφή" return_authorizations: index: new_return_authorization: "Νέα εξουσιοδότηση επιστροφής" @@ -4244,7 +4245,7 @@ el: price: "Τιμή" unit_price: "Τιμή Μονάδας" unit_price_legend: "Υπολογίζεται με βάση την τιμή του προϊόντος" - on_hand: "Στο χέρι" + on_hand: "Διαθέσιμο απόθεμα" on_demand: "Κατά παραγγελία" product_description: "περιγραφή προϊόντος" image: "Εικόνα" @@ -4274,7 +4275,7 @@ el: search_for_categories: "Αναζήτηση κατηγοριών" group_buy_form: group_buy: "Ομαδική αγορά;" - bulk_unit_size: Μέγεθος μονάδας χύδην + bulk_unit_size: Μέγεθος χονδρικής μονάδας display_as: display_as: Εμφάνιση ως clone: diff --git a/config/locales/en.yml b/config/locales/en.yml index 48ba87aee5..07a974d49a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -4660,7 +4660,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using form: disabled: "Disabled?" email: "Email" - roles: "Roles" + admin: "Super admin?" enterprise_limit: "Enterprise Limit" confirm_password: "Confirm Password" password: "Password" diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml index 570958030b..5728c220c5 100644 --- a/config/locales/en_CA.yml +++ b/config/locales/en_CA.yml @@ -3753,9 +3753,39 @@ en_CA: sack: one: "sack" other: "sacks" + bucket: + one: "bucket" + other: "buckets" + pail: + one: pail + other: pails + stem: + one: "stem" + other: "stems" + plug: + one: "plug" + other: "plugs" + plant: + one: "plant" + other: "plants" bundle: one: "bundle" other: "bundles" + bulb: + one: "bulb" + other: "bulbs" + root: + one: "root" + other: "roots" + tuber: + one: "tuber" + other: "tubers" + corm: + one: "corm" + other: "corms" + crate: + one: "crate" + other: "crates" producers: signup: start_free_profile: "Start with a free profile, and expand when you're ready!" diff --git a/config/locales/fr_CA.yml b/config/locales/fr_CA.yml index 11c014c2e1..ab6dce4cd0 100644 --- a/config/locales/fr_CA.yml +++ b/config/locales/fr_CA.yml @@ -3791,6 +3791,10 @@ fr_CA: one: "sachet" many: "sachets" other: "sachets" + bucket: + one: "bucket" + many: "buckets" + other: "buckets" bundle: one: "botte" many: "bottes" diff --git a/db/default/users.rb b/db/default/users.rb index 23ba8f549b..85fdd0379c 100644 --- a/db/default/users.rb +++ b/db/default/users.rb @@ -60,7 +60,6 @@ def create_admin_user ValidEmail2::Address.define_method(:valid_mx?) { true } if admin.save - admin.spree_roles << Spree::Role.admin say "New admin user persisted!" else say "There was some problems with persisting new admin user:" @@ -81,6 +80,7 @@ def read_user_attributes end { + admin: true, password:, password_confirmation: password, email:, diff --git a/db/default/zones.rb b/db/default/zones.rb index 2b2689b12c..c0357de2eb 100644 --- a/db/default/zones.rb +++ b/db/default/zones.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true unless Spree::Zone.find_by(name: "EU_VAT") - eu_vat = Spree::Zone.create!(name: "EU_VAT", - description: "Countries that make up the EU VAT zone.") + eu_vat = Spree::Zone.new( + name: "EU_VAT", description: "Countries that make up the EU VAT zone." + ) ["Poland", "Finland", "Portugal", "Romania", "Germany", "France", "Slovakia", "Hungary", "Slovenia", "Ireland", "Austria", "Spain", "Italy", "Belgium", "Sweden", "Latvia", "Bulgaria", "United Kingdom", "Lithuania", "Cyprus", "Luxembourg", "Malta", "Denmark", "Netherlands", "Estonia"].each do |name| - eu_vat.zone_members.create!(zoneable: Spree::Country.find_by!(name:)) + eu_vat.zone_members.new(zoneable: Spree::Country.find_by!(name:)) end + eu_vat.save! end unless Spree::Zone.find_by(name: "North America") - north_america = Spree::Zone.create!(name: "North America", description: "USA + Canada") + north_america = Spree::Zone.new(name: "North America", description: "USA + Canada") ["United States", "Canada"].each do |name| - north_america.zone_members.create!(zoneable: Spree::Country.find_by!(name:)) + north_america.zone_members.new(zoneable: Spree::Country.find_by!(name:)) end + north_america.save! end diff --git a/db/migrate/20250107013958_add_admin_to_spree_users.rb b/db/migrate/20250107013958_add_admin_to_spree_users.rb new file mode 100644 index 0000000000..057a43425f --- /dev/null +++ b/db/migrate/20250107013958_add_admin_to_spree_users.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# We'll replace our only role "admin" with a simple flag. +class AddAdminToSpreeUsers < ActiveRecord::Migration[7.0] + def change + add_column :spree_users, :admin, :boolean, default: false, null: false + end +end diff --git a/db/migrate/20250107014617_copy_admin_attribute_to_users.rb b/db/migrate/20250107014617_copy_admin_attribute_to_users.rb new file mode 100644 index 0000000000..869c20d11f --- /dev/null +++ b/db/migrate/20250107014617_copy_admin_attribute_to_users.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class CopyAdminAttributeToUsers < ActiveRecord::Migration[7.0] + def up + execute <<~SQL.squish + UPDATE spree_users SET admin = true WHERE id IN ( + SELECT user_id FROM spree_roles_users WHERE role_id IN ( + SELECT id FROM spree_roles WHERE name = 'admin' + ) + ) + SQL + end +end diff --git a/db/migrate/20250128031518_delete_default_country_id_preference.rb b/db/migrate/20250128031518_delete_default_country_id_preference.rb new file mode 100644 index 0000000000..fd1d80b581 --- /dev/null +++ b/db/migrate/20250128031518_delete_default_country_id_preference.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class DeleteDefaultCountryIdPreference < ActiveRecord::Migration[7.0] + def up + execute <<~SQL.squish + DELETE FROM spree_preferences + WHERE key = '/spree/app_configuration/default_country_id ' + SQL + end +end diff --git a/db/schema.rb b/db/schema.rb index d97d554f99..a20327a48a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2025_01_13_055412) do +ActiveRecord::Schema[7.0].define(version: 2025_01_28_031518) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" enable_extension "plpgsql" @@ -945,6 +945,7 @@ ActiveRecord::Schema[7.0].define(version: 2025_01_13_055412) do t.string "provider" t.string "uid" t.datetime "terms_of_service_accepted_at" + t.boolean "admin", default: false, null: false t.index ["confirmation_token"], name: "index_spree_users_on_confirmation_token", unique: true t.index ["email"], name: "email_idx_unique", unique: true t.index ["persistence_token"], name: "index_users_on_persistence_token" diff --git a/lib/tasks/sample_data/addressing.rb b/lib/tasks/sample_data/addressing.rb index 3db2753b71..1728933994 100644 --- a/lib/tasks/sample_data/addressing.rb +++ b/lib/tasks/sample_data/addressing.rb @@ -16,8 +16,10 @@ module Addressing end def zone - zone = Spree::Zone.find_or_create_by!(name: ENV.fetch('CHECKOUT_ZONE')) - zone.members.create!(zoneable: country) unless zone.zoneables.include?(country) + zone = Spree::Zone.find_or_create_by(name: ENV.fetch('CHECKOUT_ZONE')) + zone.members << Spree::ZoneMember.create(zoneable: country) unless + zone.zoneables.include?(country) + zone.save! zone end diff --git a/package.json b/package.json index eeaaa901cc..9798f25586 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "stimulus": "^3.2.2", "stimulus-flatpickr": "^1.4.0", "stimulus_reflex": "3.5.3", - "tom-select": "^2.4.1", + "tom-select": "^2.4.2", "trix": "^2.1.12", "turbo_power": "^0.7.0", "webpack": "~4" diff --git a/spec/base_spec_helper.rb b/spec/base_spec_helper.rb index c4cb929a7e..f8b326003a 100644 --- a/spec/base_spec_helper.rb +++ b/spec/base_spec_helper.rb @@ -234,12 +234,10 @@ RSpec.configure do |config| end end - default_country_id = DefaultCountry.id # Ensure we start with consistent config settings config.before(:each) do reset_spree_preferences do |spree_config| # These are all settings that differ from Spree's defaults - spree_config.default_country_id = default_country_id spree_config.shipping_instructions = true end CurrentConfig.clear_all diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index 59641c6e05..300b7aba89 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -431,11 +431,7 @@ module Admin describe "notifying producers" do let(:user) { create(:user) } - let(:admin_user) do - user = create(:user) - user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') - user - end + let(:admin_user) { create(:admin_user) } let(:order_cycle) { create(:simple_order_cycle) } before do diff --git a/spec/controllers/spree/admin/payment_methods_controller_spec.rb b/spec/controllers/spree/admin/payment_methods_controller_spec.rb index e6d3288603..7124e9fecd 100644 --- a/spec/controllers/spree/admin/payment_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/payment_methods_controller_spec.rb @@ -235,8 +235,6 @@ module Spree let(:user) do new_user = create(:user, email: 'enterprise@hub.com', password: 'blahblah', password_confirmation: 'blahblah', ) - # for some reason unbeknown to me, this new user gets admin permissions by default. - new_user.spree_roles = [] new_user.enterprise_roles.build(enterprise:).save new_user.save new_user diff --git a/spec/controllers/spree/admin/users_controller_spec.rb b/spec/controllers/spree/admin/users_controller_spec.rb index 97f0155f93..f040604cb6 100644 --- a/spec/controllers/spree/admin/users_controller_spec.rb +++ b/spec/controllers/spree/admin/users_controller_spec.rb @@ -3,37 +3,39 @@ require 'spec_helper' RSpec.describe Spree::Admin::UsersController do - context '#authorize_admin' do + describe '#authorize_admin' do let(:user) { create(:user) } - let(:test_user) { create(:user) } before do allow(controller).to receive_messages spree_current_user: user - allow(Spree::User).to receive(:find).with(test_user.id.to_s).and_return(test_user) - user.spree_roles.clear end - it 'should grant access to users with an admin role' do - user.spree_roles << Spree::Role.find_or_create_by(name: 'admin') - spree_post :index - expect(response).to render_template :index - end + context "as a super admin" do + let(:user) { create(:admin_user) } + let(:test_user) { create(:user) } - it "allows admins to update a user's show api key view" do - user.spree_roles << Spree::Role.find_or_create_by(name: 'admin') - spree_put :update, id: test_user.id, user: { show_api_key_view: true } - expect(response).to redirect_to spree.edit_admin_user_path(test_user) - end + before do + allow(Spree::User).to receive(:find).with(test_user.id.to_s).and_return(test_user) + end - it "re-renders the edit form if error" do - user.spree_roles << Spree::Role.find_or_create_by(name: 'admin') - spree_put :update, id: test_user.id, user: { password: "blah", password_confirmation: "" } + it 'should grant access to users with an admin role' do + spree_post :index + expect(response).to render_template :index + end - expect(response).to render_template :edit + it "allows admins to update a user's show api key view" do + spree_put :update, id: test_user.id, user: { show_api_key_view: true } + expect(response).to redirect_to spree.edit_admin_user_path(test_user) + end + + it "re-renders the edit form if error" do + spree_put :update, id: test_user.id, user: { password: "blah", password_confirmation: "" } + + expect(response).to render_template :edit + end end it 'should deny access to users without an admin role' do - allow(user).to receive_messages admin?: false spree_post :index expect(response).to redirect_to('/unauthorized') end diff --git a/spec/factories/user_factory.rb b/spec/factories/user_factory.rb index 5646f839ab..03d612bac4 100644 --- a/spec/factories/user_factory.rb +++ b/spec/factories/user_factory.rb @@ -35,7 +35,7 @@ FactoryBot.define do end factory :admin_user do - spree_roles { [Spree::Role.find_or_create_by!(name: 'admin')] } + admin { true } end factory :oidc_user do diff --git a/spec/factories/zone_factory.rb b/spec/factories/zone_factory.rb index 95c5ae8ddc..3cd2e67ffa 100644 --- a/spec/factories/zone_factory.rb +++ b/spec/factories/zone_factory.rb @@ -1,21 +1,18 @@ # frozen_string_literal: true FactoryBot.define do - factory :zone, class: Spree::Zone do + factory :zone, aliases: [:zone_with_member], class: Spree::Zone do sequence(:name) { |n| "#{generate(:random_string)}#{n}" } description { generate(:random_string) } - end + default_tax { true } + zone_members { [Spree::ZoneMember.new(zoneable: member)] } - factory :zone_with_member, parent: :zone do transient do member { Spree::Country.find_by(name: "Australia") } end - - default_tax { true } - zone_members { [Spree::ZoneMember.new(zoneable: member)] } end - factory :zone_with_state_member, parent: :zone_with_member do + factory :zone_with_state_member, parent: :zone do member { Spree::State.find_by(name: "Victoria") } end end diff --git a/spec/helpers/spree/base_helper_spec.rb b/spec/helpers/spree/base_helper_spec.rb index 050b1b61f2..4f57acecf8 100644 --- a/spec/helpers/spree/base_helper_spec.rb +++ b/spec/helpers/spree/base_helper_spec.rb @@ -26,9 +26,8 @@ RSpec.describe Spree::BaseHelper do context "with a checkout zone defined" do context "checkout zone is of type country" do before do - @country_zone = create(:zone, name: "CountryZone") - @country_zone.members.create(zoneable: country) - allow(ENV).to receive(:fetch).and_return(@country_zone.name) + country_zone = create(:zone, name: "CountryZone", member: country) + allow(ENV).to receive(:fetch).and_return(country_zone.name) end it "return only the countries defined by the checkout zone" do diff --git a/spec/lib/reports/customers_report_spec.rb b/spec/lib/reports/customers_report_spec.rb index 19f7283a78..9705260873 100644 --- a/spec/lib/reports/customers_report_spec.rb +++ b/spec/lib/reports/customers_report_spec.rb @@ -7,11 +7,7 @@ module Reporting module Customers RSpec.describe Base do context "as a site admin" do - let(:user) do - user = create(:user) - user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') - user - end + let(:user) { create(:admin_user) } subject { Base.new user, {} } describe "addresses report" do @@ -198,12 +194,7 @@ module Reporting end context "as an enterprise user" do - let(:user) do - user = create(:user) - user.spree_roles = [] - user.save! - user - end + let(:user) { create(:user) } subject { Base.new user, {} } diff --git a/spec/lib/reports/order_cycle_management_report_spec.rb b/spec/lib/reports/order_cycle_management_report_spec.rb index 17136d5942..a5883b8d27 100644 --- a/spec/lib/reports/order_cycle_management_report_spec.rb +++ b/spec/lib/reports/order_cycle_management_report_spec.rb @@ -10,11 +10,7 @@ module Reporting subject { Base.new(user, params) } let(:params) { {} } - let(:user) do - user = create(:user) - user.spree_roles << Spree::Role.find_or_create_by!(name: "admin") - user - end + let(:user) { create(:admin_user) } describe "fetching orders" do it 'calls the OutstandingBalanceQuery query object' do diff --git a/spec/lib/reports/products_and_inventory_report_spec.rb b/spec/lib/reports/products_and_inventory_report_spec.rb index 4962220a94..3eaca20d01 100644 --- a/spec/lib/reports/products_and_inventory_report_spec.rb +++ b/spec/lib/reports/products_and_inventory_report_spec.rb @@ -7,11 +7,7 @@ module Reporting module ProductsAndInventory RSpec.describe Base do context "As a site admin" do - let(:user) do - user = create(:user) - user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') - user - end + let(:user) { create(:admin_user) } subject do Base.new user, {} end @@ -72,7 +68,6 @@ module Reporting let(:enterprise_user) do user = create(:user) user.enterprise_roles.create(enterprise: supplier) - user.spree_roles = [] user.save! user end @@ -259,11 +254,7 @@ module Reporting end RSpec.describe AllProducts do - let(:user) do - user = create(:user) - user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') - user - end + let(:user) { create(:admin_user) } let(:report) do AllProducts.new user, { fields_to_hide: [] } end diff --git a/spec/models/enterprise_group_spec.rb b/spec/models/enterprise_group_spec.rb index 7e7c5fd95c..6ce1aa856f 100644 --- a/spec/models/enterprise_group_spec.rb +++ b/spec/models/enterprise_group_spec.rb @@ -77,7 +77,6 @@ RSpec.describe EnterpriseGroup do it "finds a user's enterprise groups" do user = create(:user) - user.spree_roles = [] eg1 = create(:enterprise_group, owner: user) eg2 = create(:enterprise_group) diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index de519e52e8..1d05f99bd6 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -651,7 +651,6 @@ RSpec.describe Enterprise do describe "managed_by" do it "shows only enterprises for given user" do user = create(:user) - user.spree_roles = [] e1 = create(:enterprise) e2 = create(:enterprise) e1.enterprise_roles.build(user:).save diff --git a/spec/models/exchange_spec.rb b/spec/models/exchange_spec.rb index b790d47356..2377e3618e 100644 --- a/spec/models/exchange_spec.rb +++ b/spec/models/exchange_spec.rb @@ -107,11 +107,7 @@ RSpec.describe Exchange do let(:oc) { create(:simple_order_cycle, coordinator:) } describe "finding exchanges managed by a particular user" do - let(:user) do - user = create(:user) - user.spree_roles = [] - user - end + let(:user) { create(:user) } before { Exchange.destroy_all } diff --git a/spec/models/invoice/data_presenter_spec.rb b/spec/models/invoice/data_presenter_spec.rb index 555aeeb952..4c76cb2e4e 100644 --- a/spec/models/invoice/data_presenter_spec.rb +++ b/spec/models/invoice/data_presenter_spec.rb @@ -61,9 +61,10 @@ RSpec.describe Invoice::DataPresenter do expect(presenter.display_line_item_tax_rate(taxable_line_item)).to eq "15.0%, 20.0%" end - context "one of the tax rate is appliable to a different tax zone" do + context "one of the tax rate is applicable to a different tax zone" do before do - order.line_items.last.tax_category.tax_rates.last.update!(zone: create(:zone)) + new_zone = create(:zone, default_tax: false, member: Spree::Country.last) + order.line_items.last.tax_category.tax_rates.last.update!(zone: new_zone) order.create_tax_charge! Orders::GenerateInvoiceService.new(order).generate_or_update_latest_invoice end diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb index 873f6730ad..395be0a985 100644 --- a/spec/models/order_cycle_spec.rb +++ b/spec/models/order_cycle_spec.rb @@ -62,8 +62,7 @@ RSpec.describe OrderCycle do it "finds order cycles accessible by a user" do e1 = create(:enterprise, is_primary_producer: true, sells: "any") e2 = create(:enterprise, is_primary_producer: true, sells: "any") - user = create(:user, enterprises: [e2], spree_roles: []) - user.spree_roles = [] + user = create(:user, enterprises: [e2]) oc_coordinated = create(:simple_order_cycle, coordinator: e2) oc_sent = create(:simple_order_cycle, suppliers: [e2]) diff --git a/spec/models/spree/ability_spec.rb b/spec/models/spree/ability_spec.rb index be228abfca..1339a39328 100644 --- a/spec/models/spree/ability_spec.rb +++ b/spec/models/spree/ability_spec.rb @@ -9,14 +9,6 @@ RSpec.describe Spree::Ability do let(:subject) { Spree::Ability.new(user) } let(:token) { nil } - before do - user.spree_roles.clear - end - - after(:each) { - user.spree_roles = [] - } - context 'for general resource' do let(:resource) { Object.new } @@ -42,8 +34,10 @@ RSpec.describe Spree::Ability do let(:fakedispatch_ability) { Spree::Ability.new(fakedispatch_user) } context 'with admin user' do + let(:user) { create(:admin_user) } + it 'should be able to admin' do - user.spree_roles << Spree::Role.find_or_create_by(name: 'admin') + user.update!(admin: true) expect(subject).to be_able_to :admin, resource expect(subject).to be_able_to :index, resource_order expect(subject).to be_able_to :show, resource_product @@ -303,7 +297,6 @@ RSpec.describe Spree::Ability do # create supplier_enterprise1 user without full admin access let(:user) do user = create(:user) - user.spree_roles = [] s1.enterprise_roles.build(user:).save user end @@ -487,7 +480,6 @@ RSpec.describe Spree::Ability do context "when is a distributor enterprise user" do let(:user) do user = create(:user) - user.spree_roles = [] d1.enterprise_roles.build(user:).save user end @@ -699,7 +691,6 @@ RSpec.describe Spree::Ability do context 'Order Cycle co-ordinator, distributor enterprise manager' do let(:user) do user = create(:user) - user.spree_roles = [] d1.enterprise_roles.build(user:).save user end @@ -738,7 +729,6 @@ RSpec.describe Spree::Ability do context 'enterprise manager' do let(:user) do user = create(:user) - user.spree_roles = [] s1.enterprise_roles.build(user:).save user end @@ -797,7 +787,7 @@ RSpec.describe Spree::Ability do let(:manage_actions) { [:admin, :index, :read, :update, :bulk_update, :bulk_reset] } describe "when admin" do - before { user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') } + let(:user) { create(:admin_user) } it "should have permission" do is_expected.to have_ability(manage_actions, for: variant_override) diff --git a/spec/models/spree/product_spec.rb b/spec/models/spree/product_spec.rb index 9f9937f897..59884d05e8 100644 --- a/spec/models/spree/product_spec.rb +++ b/spec/models/spree/product_spec.rb @@ -508,7 +508,6 @@ module Spree it "shows only products for given user" do user = create(:user) - user.spree_roles = [] e1.enterprise_roles.build(user:).save product = Product.managed_by user diff --git a/spec/models/spree/tax_rate_spec.rb b/spec/models/spree/tax_rate_spec.rb index ae12b8109d..2c3c8a6fbf 100644 --- a/spec/models/spree/tax_rate_spec.rb +++ b/spec/models/spree/tax_rate_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' module Spree RSpec.describe TaxRate do - describe "#match" do + describe ".match" do let!(:zone) { create(:zone_with_member) } let!(:order) { create(:order, distributor: hub, bill_address: create(:address)) } let!(:tax_rate) { @@ -44,7 +44,7 @@ module Spree let(:tax_category) { create(:tax_category) } let(:calculator) { ::Calculator::FlatRate.new } - it "should return an empty array when tax_zone is nil" do + it "returns an empty array when tax_zone is nil" do allow(order).to receive(:tax_zone) { nil } expect(Spree::TaxRate.match(order)).to eq [] end @@ -55,79 +55,70 @@ module Spree end context "when there is no default tax zone" do - before do - @zone = create(:zone, name: "Country Zone", default_tax: false, zone_members: []) - @zone.zone_members.create(zoneable: country) - end + let(:zone) { create( :zone, name: "Country Zone", default_tax: false, member: country) } - it "should return an empty array" do - allow(order).to receive(:tax_zone) { @zone } + it "returns an empty array" do + allow(order).to receive(:tax_zone).and_return(zone) expect(Spree::TaxRate.match(order)).to eq [] end - it "should return the rate that matches the rate zone" do + it "returns the rate that matches the rate zone" do rate = Spree::TaxRate.create( amount: 1, - zone: @zone, + zone:, tax_category:, calculator: ) - allow(order).to receive(:tax_zone) { @zone } + allow(order).to receive(:tax_zone).and_return(zone) expect(Spree::TaxRate.match(order)).to eq [rate] end - it "should return all rates that match the rate zone" do + it "returns all rates that match the rate zone" do rate1 = Spree::TaxRate.create( amount: 1, - zone: @zone, + zone:, tax_category:, calculator: ) rate2 = Spree::TaxRate.create( amount: 2, - zone: @zone, + zone:, tax_category:, calculator: ::Calculator::FlatRate.new ) - allow(order).to receive(:tax_zone) { @zone } + allow(order).to receive(:tax_zone).and_return(zone) expect(Spree::TaxRate.match(order)).to eq [rate1, rate2] end context "when the tax_zone is contained within a rate zone" do - before do - sub_zone = create(:zone, name: "State Zone", zone_members: []) - sub_zone.zone_members.create(zoneable: create(:state, country:)) - allow(order).to receive(:tax_zone) { sub_zone } + let(:sub_zone) { create(:zone, name: "State Zone", member: create(:state, country:)) } - @rate = Spree::TaxRate.create( + it "returns the rate zone" do + allow(order).to receive(:tax_zone).and_return(sub_zone) + + rate = Spree::TaxRate.create( amount: 1, - zone: @zone, + zone:, tax_category:, calculator: ) - end - it "should return the rate zone" do - expect(Spree::TaxRate.match(order)).to eq [@rate] + expect(Spree::TaxRate.match(order)).to eq [rate] end end end context "when there is a default tax zone" do - before do - @zone = create(:zone, name: "Country Zone", default_tax: true, zone_members: []) - @zone.zone_members.create(zoneable: country) - end - + let(:zone) { create(:zone, name: "Country Zone", default_tax: true, member: country) } let(:included_in_price) { false } let!(:rate) do Spree::TaxRate.create(amount: 1, - zone: @zone, + zone:, tax_category:, calculator:, included_in_price:) @@ -137,7 +128,7 @@ module Spree context "when the order has the same tax zone" do before do - allow(order).to receive(:tax_zone) { @zone } + allow(order).to receive(:tax_zone) { zone } allow(order).to receive(:billing_address) { tax_address } end @@ -149,12 +140,13 @@ module Spree context "when the tax is a VAT" do let(:included_in_price) { true } + it { is_expected.to eq [rate] } end end context "when the order has a different tax zone" do - let(:other_zone) { create(:zone, name: "Other Zone") } + let(:other_zone) { create(:zone, name: "Other Zone", default_tax: false) } before do allow(order).to receive(:tax_zone) { other_zone } @@ -200,47 +192,7 @@ module Spree end end - context "adjust" do - let(:order) { create(:order) } - let(:tax_category_1) { build_stubbed(:tax_category) } - let(:tax_category_2) { build_stubbed(:tax_category) } - let(:rate_1) { build_stubbed(:tax_rate, tax_category: tax_category_1) } - let(:rate_2) { build_stubbed(:tax_rate, tax_category: tax_category_2) } - let(:line_items) { [build_stubbed(:line_item)] } - - context "with line items" do - let(:line_item) { build_stubbed(:line_item, tax_category: tax_category_1) } - let(:line_items) { [line_item] } - - before do - allow(Spree::TaxRate).to receive(:match) { [rate_1, rate_2] } - end - - it "should apply adjustments for two tax rates to the order" do - expect(rate_1).to receive(:adjust) - expect(rate_2).not_to receive(:adjust) - Spree::TaxRate.adjust(order, line_items) - end - end - - context "with shipments" do - let(:shipment) { build_stubbed(:shipment, order:) } - let(:shipments) { [shipment] } - - before do - allow(shipment).to receive(:tax_category) { tax_category_1 } - allow(Spree::TaxRate).to receive(:match) { [rate_1, rate_2] } - end - - it "should apply adjustments for two tax rates to the order" do - expect(rate_1).to receive(:adjust) - expect(rate_2).not_to receive(:adjust) - Spree::TaxRate.adjust(order, shipments) - end - end - end - - context "default" do + describe ".default" do let(:tax_category) { create(:tax_category) } let(:country) { create(:country) } let(:calculator) { ::Calculator::FlatRate.new } @@ -248,7 +200,7 @@ module Spree context "when there is no default tax_category" do before { tax_category.is_default = false } - it "should return 0" do + it "returns 0" do expect(Spree::TaxRate.default).to eq 0 end end @@ -259,30 +211,29 @@ module Spree context "when the default category has tax rates in the default tax zone" do before(:each) do allow(DefaultCountry).to receive(:id) { country.id } - @zone = create(:zone, name: "Country Zone", default_tax: true) - @zone.zone_members.create(zoneable: country) + zone = create(:zone, name: "Country Zone", default_tax: true, member: country) rate = Spree::TaxRate.create( amount: 1, - zone: @zone, + zone:, tax_category:, calculator: ) end - it "should return the correct tax_rate" do + it "returns the correct tax_rate" do expect(Spree::TaxRate.default.to_f).to eq 1.0 end end context "when the default category has no tax rates in the default tax zone" do - it "should return 0" do + it "returns 0" do expect(Spree::TaxRate.default).to eq 0 end end end end - describe "#adjust" do + describe ".adjust" do let!(:country) { create(:country, name: "Default Country") } let!(:state) { create(:state, name: "Default State", country:) } let!(:zone) { create(:zone_with_member, default_tax: true, member: country ) } @@ -312,12 +263,12 @@ module Spree context "not taxable line item " do let!(:line_item) { order.contents.add(nontaxable, 1) } - it "should not create a tax adjustment" do + it "does not create a tax adjustment" do Spree::TaxRate.adjust(order, order.line_items) expect(line_item.adjustments.tax.charge.count).to eq 0 end - it "should not create a refund" do + it "does not create a refund" do Spree::TaxRate.adjust(order, order.line_items) expect(line_item.adjustments.credit.count).to eq 0 end @@ -331,14 +282,26 @@ module Spree rate2.update_column(:included_in_price, true) end + it "applies adjustments for the matching tax rates to the order" do + line_item = build_stubbed(:line_item, tax_category: category) + rate3 = create(:tax_rate, amount: 0.05, zone:) + + allow(Spree::TaxRate).to receive(:match) { [rate1, rate3] } + + expect(rate1).to receive(:adjust) + expect(rate3).not_to receive(:adjust) + + Spree::TaxRate.adjust(order, [line_item]) + end + context "when price includes tax" do context "when zone is contained by default tax zone" do - it "should create two adjustments, one for each tax rate" do + it "creates two adjustments, one for each tax rate" do Spree::TaxRate.adjust(order, order.line_items) expect(line_item.adjustments.count).to eq 2 end - it "should not create a tax refund" do + it "does not create a tax refund" do Spree::TaxRate.adjust(order, order.line_items) expect(line_item.adjustments.credit.count).to eq 0 end @@ -347,16 +310,17 @@ module Spree context "when order's zone is neither the default zone, or included " \ "in the default zone, but matches the rate's zone" do before do - # With no zone members, this zone will not contain anything - zone.zone_members.delete_all + # Create a new default zone, so the order's zone won't match this new one + create(:zone_with_member, default_tax: true) end - it "should create an adjustment" do + it "creates an adjustment" do Spree::TaxRate.adjust(order, order.line_items) + expect(line_item.adjustments.charge.count).to eq 2 end - it "should not create a tax refund for each tax rate" do + it "does not create a tax refund for each tax rate" do Spree::TaxRate.adjust(order, order.line_items) expect(line_item.adjustments.credit.count).to eq 0 end @@ -377,25 +341,15 @@ module Spree order.all_adjustments.delete_all end - it "should not create positive adjustments" do + it "does not create positive adjustments" do Spree::TaxRate.adjust(order, order.line_items) expect(line_item.adjustments.charge.count).to eq 0 end - it "should create a tax refund for each tax rate" do + it "creates a tax refund for each tax rate" do Spree::TaxRate.adjust(order, order.line_items) expect(line_item.adjustments.credit.count).to eq 2 end - - it "notifies bugsnag" do - # there are two tax rate - expect(Bugsnag).to receive(:notify).with( - "Notice: Tax refund should not be possible, please check the default zone and " \ - "the tax rate zone configuration" - ).twice.and_call_original - - Spree::TaxRate.adjust(order, order.line_items) - end end end @@ -409,21 +363,21 @@ module Spree Spree::TaxRate.adjust(order, order.line_items) end - it "should not delete adjustments for complete order when taxrate is deleted" do + it "does not delete adjustments for complete order when taxrate is deleted" do rate1.destroy! rate2.destroy! expect(line_item.adjustments.count).to eq 2 end - it "should create adjustments" do + it "creates adjustments" do expect(line_item.adjustments.count).to eq 2 end - it "should not create a tax refund" do + it "does not create a tax refund" do expect(line_item.adjustments.credit.count).to eq 0 end - it "should remove adjustments when tax_zone is removed" do + it "removes adjustments when tax_zone is removed" do expect(line_item.adjustments.count).to eq 2 allow(order).to receive(:tax_zone) { nil } Spree::TaxRate.adjust(order, order.line_items) @@ -431,6 +385,22 @@ module Spree end end end + + context "with shipments" do + let(:shipment) { build_stubbed(:shipment, order:) } + + it "applies adjustments for two tax rates to the order" do + rate3 = create(:tax_rate, amount: 0.05, zone:) + + allow(shipment).to receive(:tax_category) { category } + allow(Spree::TaxRate).to receive(:match) { [rate1, rate3] } + + expect(rate1).to receive(:adjust) + expect(rate3).not_to receive(:adjust) + + Spree::TaxRate.adjust(order, [shipment]) + end + end end end end diff --git a/spec/models/spree/user_spec.rb b/spec/models/spree/user_spec.rb index a2a0ab3897..ea9531f707 100644 --- a/spec/models/spree/user_spec.rb +++ b/spec/models/spree/user_spec.rb @@ -209,11 +209,11 @@ RSpec.describe Spree::User do end describe '#admin?' do - it 'returns true when the user has an admin spree role' do + it 'returns true when the user has an admin role' do expect(create(:admin_user).admin?).to be_truthy end - it 'returns false when the user does not have an admin spree role' do + it 'returns false when the user does not have an admin role' do expect(create(:user).admin?).to eq(false) end end diff --git a/spec/models/spree/zone_spec.rb b/spec/models/spree/zone_spec.rb index 9be11552ad..32f3a2dd53 100644 --- a/spec/models/spree/zone_spec.rb +++ b/spec/models/spree/zone_spec.rb @@ -3,7 +3,13 @@ require 'spec_helper' RSpec.describe Spree::Zone do - context "#match" do + describe "validations" do + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to validate_uniqueness_of(:name) } + it { is_expected.to validate_presence_of(:zone_members) } + end + + describe "#match" do let(:country_zone) { create(:zone, name: 'CountryZone') } let(:country) do country = create(:country) @@ -63,14 +69,12 @@ RSpec.describe Spree::Zone do end end - context "#countries" do + describe "#countries" do let(:state) { create(:state) } let(:country) { state.country } context "when zone consists of countries" do - let(:country_zone) { create(:zone, name: 'CountryZone') } - - before { country_zone.members.create(zoneable: country) } + let(:country_zone) { create(:zone, name: 'CountryZone', member: country) } it 'should return a list of countries' do expect(country_zone.countries).to eq [country] @@ -78,17 +82,15 @@ RSpec.describe Spree::Zone do end context "when zone consists of states" do - let(:state_zone) { create(:zone, name: 'StateZone') } - - before { state_zone.members.create(zoneable: state) } + let(:state_zone) { create(:zone, name: 'StateZone', member: state) } it 'should return a list of countries' do - expect(state_zone.countries).to eq [state.country] + expect(state_zone.countries).to eq [country] end end end - context "#contains_address?" do + describe "#contains_address?" do let(:state) { create(:state) } let(:country) { state.country } let(:address) { create(:address, country:, state:) } @@ -112,13 +114,13 @@ RSpec.describe Spree::Zone do end end - context ".default_tax" do + describe ".default_tax" do context "when there is a default tax zone specified" do - before { @foo_zone = create(:zone, name: 'whatever', default_tax: true) } + let!(:default_zone) { create(:zone, name: 'whatever', default_tax: true) } it "should be the correct zone" do - foo_zone = create(:zone, name: 'foo') - expect(Spree::Zone.default_tax).to eq @foo_zone + create(:zone, name: 'foo', default_tax: false) + expect(Spree::Zone.default_tax).to eq default_zone end end @@ -129,135 +131,122 @@ RSpec.describe Spree::Zone do end end - context "#contains?" do - let(:country1) { create(:country) } - let(:country2) { create(:country) } - let(:country3) { create(:country) } - - before do - @source = create(:zone, name: 'source', zone_members: []) - @target = create(:zone, name: 'target', zone_members: []) - end - - context "when the target has no members" do - before { @source.members.create(zoneable: country1) } - - it "should be false" do - expect(@source.contains?(@target)).to be_falsy - end - end - - context "when the source has no members" do - before { @target.members.create(zoneable: country1) } - - it "should be false" do - expect(@source.contains?(@target)).to be_falsy - end - end + describe "#contains?" do + let(:country_member1) { Spree::ZoneMember.create(zoneable: create(:country)) } + let(:country_member2) { Spree::ZoneMember.create(zoneable: create(:country)) } + let(:country_member3) { Spree::ZoneMember.create(zoneable: create(:country)) } + let(:source) { create(:zone, name: 'source') } + let(:target) { create(:zone, name: 'target') } context "when both zones are the same zone" do before do - @source.members.create(zoneable: country1) - @target = @source + source.zone_members = [country_member1] end it "should be true" do - expect(@source.contains?(@target)).to be_truthy + target = source + + expect(source.contains?(target)).to be_truthy end end context "when both zones are of the same type" do before do - @source.members.create(zoneable: country1) - @source.members.create(zoneable: country2) + source.zone_members = [country_member1, country_member2] end context "when all members are included in the zone we check against" do before do - @target.members.create(zoneable: country1) - @target.members.create(zoneable: country2) + target.zone_members = [country_member1, country_member2] end it "should be true" do - expect(@source.contains?(@target)).to be_truthy + expect(source.contains?(target)).to be_truthy end end context "when some members are included in the zone we check against" do before do - @target.members.create(zoneable: country1) - @target.members.create(zoneable: country2) - @target.members.create(zoneable: create(:country)) + target.zone_members = [ + country_member1, country_member2, Spree::ZoneMember.create(zoneable: create(:country)) + ] end it "should be false" do - expect(@source.contains?(@target)).to be_falsy + expect(source.contains?(target)).to be_falsy end end context "when none of the members are included in the zone we check against" do before do - @target.members.create(zoneable: create(:country)) - @target.members.create(zoneable: create(:country)) + target.zone_members = [ + Spree::ZoneMember.create(zoneable: create(:country)), + Spree::ZoneMember.create(zoneable: create(:country)) + ] end it "should be false" do - expect(@source.contains?(@target)).to be_falsy + expect(source.contains?(target)).to be_falsy end end end context "when checking country against state" do before do - @source.members.create(zoneable: create(:state)) - @target.members.create(zoneable: country1) + source.zone_members = [Spree::ZoneMember.create(zoneable: create(:state))] + target.zone_members = [country_member1] end it "should be false" do - expect(@source.contains?(@target)).to be_falsy + expect(source.contains?(target)).to be_falsy end end context "when checking state against country" do - before { @source.members.create(zoneable: country1) } + before { source.zone_members = [country_member1] } context "when all states contained in one of the countries we check against" do before do - state1 = create(:state, country: country1) - @target.members.create(zoneable: state1) + state1 = create(:state, country: country_member1.zoneable) + target.zone_members = [Spree::ZoneMember.create(zoneable: state1)] end it "should be true" do - expect(@source.contains?(@target)).to be_truthy + expect(source.contains?(target)).to be_truthy end end context "when some states contained in one of the countries we check against" do before do - state1 = create(:state, country: country1) - @target.members.create(zoneable: state1) - @target.members.create(zoneable: create(:state, country: country2)) + state1 = create(:state, country: country_member1.zoneable) + state2 = create(:state, country: country_member2.zoneable) + target.zone_members = [ + Spree::ZoneMember.create(zoneable: state1), + Spree::ZoneMember.create(zoneable: state2) + ] end it "should be false" do - expect(@source.contains?(@target)).to be_falsy + expect(source.contains?(target)).to be_falsy end end context "when none of the states contained in any of the countries we check against" do before do - @target.members.create(zoneable: create(:state, country: country2)) - @target.members.create(zoneable: create(:state, country: country2)) + target.zone_members = [ + Spree::ZoneMember.create(zoneable: create(:state, country: country_member2.zoneable)), + Spree::ZoneMember.create(zoneable: create(:state, country: country_member2.zoneable)) + ] end it "should be false" do - expect(@source.contains?(@target)).to be_falsy + expect(source.contains?(target)).to be_falsy end end end end - context "#save" do + describe "#save" do context "when default_tax is true" do it "should clear previous default tax zone" do zone1 = create(:zone, name: 'foo', default_tax: true) @@ -268,37 +257,32 @@ RSpec.describe Spree::Zone do context "when a zone member country is added to an existing zone consisting of state members" do it "should remove existing state members" do - zone = create(:zone, name: 'foo', zone_members: []) state = create(:state) + zone = create(:zone, name: 'foo', member: state) + country = create(:country) - zone.members.create(zoneable: state) country_member = zone.members.create(zoneable: country) zone.save + expect(zone.reload.members).to eq [country_member] end end end - context "#kind" do + describe "#kind" do context "when the zone consists of country zone members" do - before do - @zone = create(:zone, name: 'country', zone_members: []) - @zone.members.create(zoneable: create(:country)) - end + let!(:zone) { create(:zone, name: 'country', member: create(:country)) } it "should return the kind of zone member" do - expect(@zone.kind).to eq "country" + expect(zone.kind).to eq "country" end end context "when the zone consists of state zone members" do - before do - @zone = create(:zone, name: 'state', zone_members: []) - @zone.members.create(zoneable: create(:state)) - end + let!(:zone) { create(:zone, name: 'country', member: create(:state)) } it "should return the kind of zone member" do - expect(@zone.kind).to eq "state" + expect(zone.kind).to eq "state" end end end diff --git a/spec/support/controller_helper.rb b/spec/support/controller_helper.rb index c7cc66b6e2..f2f9b61bed 100644 --- a/spec/support/controller_helper.rb +++ b/spec/support/controller_helper.rb @@ -3,11 +3,7 @@ module OpenFoodNetwork module ControllerHelper def controller_login_as_admin - @admin_user ||= begin - user = create(:user) - user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin') - user - end + @admin_user ||= create(:admin_user) allow(controller).to receive_messages(spree_current_user: @admin_user) end @@ -15,7 +11,6 @@ module OpenFoodNetwork def controller_login_as_enterprise_user(enterprises) @enterprise_user ||= begin user = create(:user) - user.spree_roles = [] enterprises.each do |enterprise| enterprise.enterprise_roles.create!(user:) end diff --git a/spec/support/seeds.rb b/spec/support/seeds.rb index dc75402bcb..7f84dddf3b 100644 --- a/spec/support/seeds.rb +++ b/spec/support/seeds.rb @@ -22,8 +22,3 @@ if Spree::Country.where(name: "France").empty? Spree::State.create!({ "name" => "Alsace", "abbr" => "Als", :country => country }) Spree::State.create!({ "name" => "Aquitaine", "abbr" => "Aq", :country => country }) end - -# Since the country seeding differs from other environments, the default -# country id has to be updated here. This line can be removed as soon as the -# default country id is replaced by something database independent. -Spree::Config.default_country_id = Spree::Country.find_by(name: 'Australia').id diff --git a/spec/system/admin/adjustments_spec.rb b/spec/system/admin/adjustments_spec.rb index bc525c819e..64ce6a5ad0 100644 --- a/spec/system/admin/adjustments_spec.rb +++ b/spec/system/admin/adjustments_spec.rb @@ -25,7 +25,7 @@ RSpec.describe ' } let!(:tax_category_included) { create(:tax_category, name: 'TVA 20%', is_default: true) } - let!(:default_tax_zone) { create(:zone, default_tax: true) } + let!(:default_tax_zone) { create(:zone, default_tax: true, member: Spree::Country.last) } let!(:tax_rate2) { create(:tax_rate, name: "TVA 20%", amount: 0.2, zone: default_tax_zone, included_in_price: true, tax_category: tax_category_included, calculator: Calculator::DefaultTax.new ) diff --git a/spec/system/admin/configuration/shipping_categories_spec.rb b/spec/system/admin/configuration/shipping_categories_spec.rb index 7e884d0aeb..ea2fc73142 100644 --- a/spec/system/admin/configuration/shipping_categories_spec.rb +++ b/spec/system/admin/configuration/shipping_categories_spec.rb @@ -5,7 +5,6 @@ require 'system_helper' RSpec.describe "Shipping Categories" do include AuthenticationHelper include WebHelper - let(:admin_role) { Spree::Role.find_or_create_by!(name: 'admin') } let(:admin_user) { create(:user) } context 'user visits shipping categories page' do diff --git a/spec/system/admin/configuration/tax_rates_spec.rb b/spec/system/admin/configuration/tax_rates_spec.rb index 87c60b2392..6e26fddd03 100644 --- a/spec/system/admin/configuration/tax_rates_spec.rb +++ b/spec/system/admin/configuration/tax_rates_spec.rb @@ -6,8 +6,10 @@ RSpec.describe "Tax Rates" do include AuthenticationHelper let!(:calculator) { create(:calculator_per_item, calculable: create(:order)) } - let!(:tax_rate) { create(:tax_rate, name: "IVA", calculator:) } - let!(:zone) { create(:zone, name: "Ilhas") } + let!(:tax_rate) { + create(:tax_rate, name: "IVA", calculator:, zone: create(:zone, default_tax: false)) + } + let!(:zone) { create(:zone, name: "Ilhas", default_tax: false) } let!(:tax_category) { create(:tax_category, name: "Full") } before do diff --git a/spec/system/admin/configuration/zones_spec.rb b/spec/system/admin/configuration/zones_spec.rb index 134d4c14f7..f8d60bcf34 100644 --- a/spec/system/admin/configuration/zones_spec.rb +++ b/spec/system/admin/configuration/zones_spec.rb @@ -6,6 +6,10 @@ RSpec.describe "Zones" do include AuthenticationHelper include WebHelper + before do + Spree::Zone.delete_all + end + it "list existing zones" do login_as_admin visit spree.edit_admin_general_settings_path @@ -34,6 +38,11 @@ RSpec.describe "Zones" do fill_in "zone_name", with: "japan" fill_in "zone_description", with: "japanese time zone" + choose "Country Based" + + click_link "Add country" + find('.select2').find(:xpath, 'option[2]').select_option + click_button "Create" expect(page).to have_content("successfully created!") diff --git a/spec/system/admin/multilingual_spec.rb b/spec/system/admin/multilingual_spec.rb index e8de421d75..0f9f0900bd 100644 --- a/spec/system/admin/multilingual_spec.rb +++ b/spec/system/admin/multilingual_spec.rb @@ -5,11 +5,9 @@ require 'system_helper' RSpec.describe 'Multilingual' do include AuthenticationHelper include WebHelper - let(:admin_role) { Spree::Role.find_or_create_by!(name: 'admin') } - let(:admin_user) { create(:user) } + let(:admin_user) { create(:admin_user) } before do - admin_user.spree_roles << admin_role login_as admin_user visit spree.admin_dashboard_path end diff --git a/yarn.lock b/yarn.lock index c0f101beca..8afb190b71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8879,10 +8879,10 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tom-select@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tom-select/-/tom-select-2.4.1.tgz#6a0b6df8af3df7b09b22dd965eb75ce4d1c547bc" - integrity sha512-adI8H8+wk8RRzHYLQ3bXSk2Q+FAq/kzAATrcWlJ2fbIrEzb0VkwaXzKHTAlBwSJrhqbPJvhV/0eypFkED/nAug== +tom-select@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/tom-select/-/tom-select-2.4.2.tgz#9764faf6cba51f6571d03a79bb7c1cac1cac7a5a" + integrity sha512-2RWjkL3gMDz9E+u8w+tQy9JWsYq8gaSytEVeugKYDeMus6ZtxT1HttLPnXsfHCnBPlsNubVyj5gtUeN+S+bcpA== dependencies: "@orchidjs/sifter" "^1.1.0" "@orchidjs/unicode-variants" "^1.1.2"