mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-26 20:56:48 +00:00
Newer version of Rails have this option as default. We can slowly transition to opt in gradually, model by model. Once all models are covered, we can change the default and remove the setting from the models again. The style violation was added to the todo file because it's temporary. We have 60 models using `belongs_to`. And changing them all at once breaks some specs. So let's do it gradually.
146 lines
4.5 KiB
Ruby
146 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Spree
|
|
class ShippingMethod < ApplicationRecord
|
|
include CalculatedAdjustments
|
|
DISPLAY_ON_OPTIONS = {
|
|
both: "",
|
|
back_end: "back_end"
|
|
}.freeze
|
|
|
|
self.belongs_to_required_by_default = true
|
|
|
|
acts_as_paranoid
|
|
acts_as_taggable
|
|
|
|
default_scope -> { where(deleted_at: nil) }
|
|
|
|
has_many :shipping_rates, inverse_of: :shipping_method
|
|
has_many :shipments, through: :shipping_rates
|
|
has_many :shipping_method_categories
|
|
has_many :shipping_categories, through: :shipping_method_categories
|
|
has_many :distributor_shipping_methods
|
|
has_many :distributors, through: :distributor_shipping_methods,
|
|
class_name: 'Enterprise',
|
|
foreign_key: 'distributor_id'
|
|
|
|
has_and_belongs_to_many :zones, join_table: 'spree_shipping_methods_zones',
|
|
class_name: 'Spree::Zone'
|
|
|
|
belongs_to :tax_category, class_name: 'Spree::TaxCategory', optional: true
|
|
|
|
validates :name, presence: true
|
|
validate :distributor_validation
|
|
validate :at_least_one_shipping_category
|
|
validates :display_on, inclusion: { in: DISPLAY_ON_OPTIONS.values }, allow_nil: true
|
|
|
|
after_initialize :init
|
|
|
|
after_save :touch_distributors
|
|
|
|
scope :managed_by, lambda { |user|
|
|
if user.has_spree_role?('admin')
|
|
where(nil)
|
|
else
|
|
joins(:distributors).
|
|
where('distributors_shipping_methods.distributor_id IN (?)',
|
|
user.enterprises.select(&:id)).
|
|
select('DISTINCT spree_shipping_methods.*')
|
|
end
|
|
}
|
|
|
|
scope :for_distributors, ->(distributors) {
|
|
non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors })
|
|
where(id: non_unique_matches.map(&:id))
|
|
}
|
|
scope :for_distributor, lambda { |distributor|
|
|
joins(:distributors).
|
|
where('enterprises.id = ?', distributor)
|
|
}
|
|
|
|
scope :by_name, -> { order('spree_shipping_methods.name ASC') }
|
|
|
|
# Here we allow checkout with shipping methods without zones (see issue #3928 for details)
|
|
# and also checkout with addresses outside of the zones of the selected shipping method
|
|
# This method could be used, like in Spree, to validate shipping method zones on checkout.
|
|
def delivers_to?(address)
|
|
address.present?
|
|
end
|
|
|
|
def build_tracking_url(tracking)
|
|
tracking_url.gsub(/:tracking/, tracking) unless tracking.blank? || tracking_url.blank?
|
|
end
|
|
|
|
# Some shipping methods are only meant to be set via backend
|
|
def frontend?
|
|
display_on != "back_end"
|
|
end
|
|
|
|
def has_distributor?(distributor)
|
|
distributors.include?(distributor)
|
|
end
|
|
|
|
# Checks whether the shipping method is of delivery type, meaning that it
|
|
# requires the user to specify a ship address at checkout.
|
|
#
|
|
# @return [Boolean]
|
|
def delivery?
|
|
require_ship_address
|
|
end
|
|
|
|
# Return the services (pickup, delivery) that different distributors provide, in the format:
|
|
# {distributor_id => {pickup: true, delivery: false}, ...}
|
|
def self.services
|
|
Hash[
|
|
Spree::ShippingMethod.
|
|
joins(:distributor_shipping_methods).
|
|
group('distributor_id').
|
|
select("distributor_id").
|
|
select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup").
|
|
select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery").
|
|
map { |sm| [sm.distributor_id.to_i, { pickup: sm.pickup, delivery: sm.delivery }] }
|
|
]
|
|
end
|
|
|
|
def self.backend
|
|
where(display_on: DISPLAY_ON_OPTIONS[:back_end])
|
|
end
|
|
|
|
def self.frontend
|
|
where(display_on: [nil, ""])
|
|
end
|
|
|
|
def init
|
|
self.calculator ||= ::Calculator::None.new if new_record?
|
|
end
|
|
|
|
private
|
|
|
|
def no_active_or_upcoming_order_cycle_distributors_with_only_one_shipping_method?
|
|
return true if new_record?
|
|
|
|
distributors.
|
|
with_order_cycles_as_distributor_outer.
|
|
merge(OrderCycle.active.or(OrderCycle.upcoming)).none? do |distributor|
|
|
distributor.shipping_method_ids.one?
|
|
end
|
|
end
|
|
|
|
def at_least_one_shipping_category
|
|
return unless shipping_categories.empty?
|
|
|
|
errors.add(:base, "You need to select at least one shipping category")
|
|
end
|
|
|
|
def touch_distributors
|
|
distributors.each do |distributor|
|
|
distributor.touch if distributor.persisted?
|
|
end
|
|
end
|
|
|
|
def distributor_validation
|
|
validates_with DistributorsValidator
|
|
end
|
|
end
|
|
end
|