Class: ShippingCost
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- ShippingCost
- Defined in:
- app/models/shipping_cost.rb
Overview
== Schema Information
Table name: shipping_costs
Database name: primary
id :integer not null, primary key
cod :boolean default(FALSE)
cost :decimal(8, 2) default(0.0), not null
description_override :string
insured_value :decimal(8, 2)
is_free_ground_shipping :boolean default(FALSE)
rate_data :jsonb
saturday_delivery :boolean default(FALSE)
service_options_charges :decimal(8, 2) default(0.0), not null
signature_confirmation :boolean default(FALSE)
transportation_charges :decimal(8, 2) default(0.0), not null
created_at :datetime
updated_at :datetime
delivery_id :integer
shipping_account_number_id :integer
shipping_option_id :integer
Indexes
idx_delivery_id_shipping_option_id (delivery_id,shipping_option_id)
index_shipping_costs_on_delivery_id (delivery_id) USING hash
index_shipping_costs_on_shipping_option_id (shipping_option_id)
Foreign Keys
fk_rails_... (shipping_option_id => shipping_options.id) ON DELETE => cascade
shipping_costs_delivery_id_fk (delivery_id => deliveries.id) ON DELETE => cascade
Constant Summary
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #cost ⇒ Object readonly
Belongs to collapse
- #delivery ⇒ Delivery
- #shipping_account_number ⇒ ShippingAccountNumber
- #shipping_option ⇒ ShippingOption
Has many collapse
Delegated Instance Attributes collapse
-
#information ⇒ Object
Alias for Shipping_option#information.
-
#is_fedex_ca? ⇒ Object
Alias for Shipping_option#is_fedex_ca?.
-
#is_freightquote? ⇒ Object
Alias for Shipping_option#is_freightquote?.
-
#is_override? ⇒ Object
Alias for Shipping_option#is_override?.
-
#is_third_party_only? ⇒ Object
Alias for Shipping_option#is_third_party_only?.
-
#name ⇒ Object
Alias for Shipping_option#name.
-
#service_code ⇒ Object
Alias for Shipping_option#service_code.
Class Method Summary collapse
-
.amzbs_only ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are amzbs only.
-
.override_only ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are override only.
-
.skip_3rd_party ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip 3rd party.
-
.skip_canadapost ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip canadapost.
-
.skip_freight ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip freight.
-
.skip_override ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip override.
-
.supported ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are supported.
-
.sww_only ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are sww only.
Instance Method Summary collapse
-
#amzbs_delivery_date_from_window ⇒ Object
Extracts a delivery date from the AMZBS delivery window when transit_days fields are nil.
-
#calculated_cost ⇒ Object
Customer-facing shipping charge for this option.
-
#carrier_estimated_delivery_date ⇒ Object
Returns the estimated delivery date from any carrier (SWW, AMZBS, or ShipEngine).
- #days_commitment ⇒ Object
- #delivery_commitment ⇒ Object
- #description ⇒ Object
- #hide? ⇒ Boolean
-
#is_amzbs? ⇒ Boolean
Returns true if this is an Amazon Buy Shipping cost.
-
#is_amzbs_ptp? ⇒ Boolean
Returns true if this is an Amazon Buy Shipping pass-through (PTP) rate using the seller's own linked carrier account (UPS, FedEx, USPS).
- #is_beta? ⇒ Boolean
- #is_shipengine_ltl? ⇒ Boolean
-
#is_sww? ⇒ Boolean
Returns true if this is a Ship with Walmart shipping cost.
- #set_line_items_price ⇒ Object
-
#sww_estimated_delivery_date ⇒ Object
Returns the estimated delivery date for SWW rates.
-
#third_party_billed? ⇒ Boolean
Single source of truth, at this layer, for "is the carrier billed to the customer's own account (so we do NOT invoice them for shipping)?".
-
#to_partial_path ⇒ Object
Partial lives under
app/views/deliveries/, not the conventionalapp/views/shipping_costs/.
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#cost ⇒ Object (readonly)
51 |
# File 'app/models/shipping_cost.rb', line 51 validates :cost, numericality: true |
Class Method Details
.amzbs_only ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are amzbs only. Active Record Scope
95 |
# File 'app/models/shipping_cost.rb', line 95 scope :amzbs_only, -> { joins(:shipping_option).where(shipping_options: { carrier: 'AmazonSeller' }) } |
.override_only ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are override only. Active Record Scope
93 |
# File 'app/models/shipping_cost.rb', line 93 scope :override_only, -> { joins(:shipping_option).where(shipping_options: { name: 'override' }) } |
.skip_3rd_party ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip 3rd party. Active Record Scope
89 |
# File 'app/models/shipping_cost.rb', line 89 scope :skip_3rd_party, -> { joins(:shipping_option).where.not(shipping_options: { is_third_party_only: true }) } |
.skip_canadapost ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip canadapost. Active Record Scope
91 |
# File 'app/models/shipping_cost.rb', line 91 scope :skip_canadapost, -> { joins(:shipping_option).where("shipping_options.carrier IS NULL OR shipping_options.carrier <> 'Canadapost'") } |
.skip_freight ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip freight. Active Record Scope
90 |
# File 'app/models/shipping_cost.rb', line 90 scope :skip_freight, -> { joins(:shipping_option).where("shipping_options.carrier IS NULL OR shipping_options.carrier <> 'UPSFreight'") } |
.skip_override ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are skip override. Active Record Scope
88 |
# File 'app/models/shipping_cost.rb', line 88 scope :skip_override, -> { joins(:shipping_option).where.not(shipping_options: { name: 'override' }) } |
.supported ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are supported. Active Record Scope
92 |
# File 'app/models/shipping_cost.rb', line 92 scope :supported, -> { joins(:shipping_option).where.not(shipping_options: { is_third_party_only: true }).where.not(shipping_options: { carrier: nil }) } |
.sww_only ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are sww only. Active Record Scope
94 |
# File 'app/models/shipping_cost.rb', line 94 scope :sww_only, -> { joins(:shipping_option).where(shipping_options: { carrier: 'WalmartSeller' }) } |
Instance Method Details
#amzbs_delivery_date_from_window ⇒ Object
Extracts a delivery date from the AMZBS delivery window when transit_days
fields are nil. Amazon's Shipping V2 API returns delivery windows for FedEx/UPS
PTP rates instead of transit days.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'app/models/shipping_cost.rb', line 185 def amzbs_delivery_date_from_window return nil unless is_amzbs? window = rate_data&.dig('amz_delivery_window') || rate_data&.dig('raw', 'promise', 'deliveryWindow') # NOTE: `:'end'` quoted-symbol form rather than bare `:end` — the parser # gem used by Reek (parser-3.3.x via pronto-reek) trips on a bare `:end` # symbol literal followed by a closing paren ("unexpected token tRPAREN"). # Modern Ruby treats both forms identically; the quoted form is just # less ambiguous to the lookahead in legacy parser versions. end_date = window&.dig('end') || window&.dig(:end) return nil if end_date.blank? Time.zone.parse(end_date.to_s).to_date rescue StandardError nil end |
#calculated_cost ⇒ Object
Customer-facing shipping charge for this option. Zero when the
carrier is billed to the customer's own (attached) account, so we
don't also invoice them for shipping; otherwise the quoted cost.
238 239 240 241 242 |
# File 'app/models/shipping_cost.rb', line 238 def calculated_cost return 0.0 if third_party_billed? cost end |
#carrier_estimated_delivery_date ⇒ Object
Returns the estimated delivery date from any carrier (SWW, AMZBS, or ShipEngine)
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'app/models/shipping_cost.rb', line 151 def carrier_estimated_delivery_date return sww_estimated_delivery_date if is_sww? && sww_estimated_delivery.present? return estimated_delivery_date.to_date if estimated_delivery_date.present? transit_days = days_in_transit.presence || delivery_days.presence || sww_transit_days.presence || amz_transit_days.presence if transit_days.present? # transit_days counts BUSINESS days. Advance by working days — skipping # weekends AND the shipping company's holidays (via working_hours) — so a # Friday "+1" estimate doesn't land on a Saturday no carrier delivers. # ShipEngine rates already carry a real carrier date in # estimated_delivery_date (handled above); this is the fallback for rates # that only provide a transit-day count. company = delivery&.order&.company || Company.find_by(id: Company::USA) if company # Baseline ship date in the warehouse zone — prefer the order's # cutoff-aware `next_warehouse_ship_date` so an estimate quoted on # Saturday morning starts counting transit days from Monday, not # from "today". Falls back to today-in-warehouse-zone when there # is no order context (e.g. RMA rate quotes). baseline = delivery&.order&.next_warehouse_ship_date || Time.current.in_time_zone(company.working_hours_timezone).to_date return company.add_business_days(baseline, transit_days) end end amzbs_delivery_date_from_window rescue StandardError nil end |
#days_commitment ⇒ Object
107 108 109 |
# File 'app/models/shipping_cost.rb', line 107 def days_commitment days_in_transit.presence || sww_transit_days.presence || amz_transit_days.presence || shipping_option.days_commitment end |
#delivery ⇒ Delivery
46 |
# File 'app/models/shipping_cost.rb', line 46 belongs_to :delivery, optional: true |
#delivery_commitment ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 |
# File 'app/models/shipping_cost.rb', line 111 def delivery_commitment if days_in_transit.present? "#{days_in_transit} business days." elsif sww_transit_days.present? "#{sww_transit_days} business days via Walmart." elsif amz_transit_days.present? "#{amz_transit_days} business days via Amazon." else shipping_option.delivery_commitment end end |
#description ⇒ Object
97 98 99 100 101 102 103 104 105 |
# File 'app/models/shipping_cost.rb', line 97 def description return description_override || shipping_option.description || 'Override' if is_override? desc = [description_override || shipping_option.description] desc << 'Saturday' if saturday_delivery desc << 'Signature Required' if signature_confirmation # desc << "Cust. Acct. #: #{shipping_account_number.account_number}" if shipping_account_number desc.join(', ') end |
#hide? ⇒ Boolean
249 250 251 252 253 254 255 |
# File 'app/models/shipping_cost.rb', line 249 def hide? country_iso3_sym = shipping_option&.country_iso3&.to_sym Rails.logger.debug do "ShippingCost#hide? country_iso3_sym: #{country_iso3_sym}, shipping_option&.service_code: #{shipping_option&.service_code}, HIDE_SHIPPING_SERVICE_CODES[country_iso3_sym]: #{HIDE_SHIPPING_SERVICE_CODES[country_iso3_sym]}, HIDE_SHIPPING_SERVICE_CODES[country_iso3_sym]&.include?(shipping_option&.service_code): #{HIDE_SHIPPING_SERVICE_CODES[country_iso3_sym]&.include?(shipping_option&.service_code)}" end country_iso3_sym && HIDE_SHIPPING_SERVICE_CODES[country_iso3_sym]&.include?(shipping_option&.service_code) end |
#information ⇒ Object
Alias for Shipping_option#information
202 |
# File 'app/models/shipping_cost.rb', line 202 delegate :information, to: :shipping_option |
#is_amzbs? ⇒ Boolean
Returns true if this is an Amazon Buy Shipping cost
129 130 131 |
# File 'app/models/shipping_cost.rb', line 129 def is_amzbs? shipping_option&.carrier == 'AmazonSeller' || amz_carrier_id.present? end |
#is_amzbs_ptp? ⇒ Boolean
Returns true if this is an Amazon Buy Shipping pass-through (PTP) rate
using the seller's own linked carrier account (UPS, FedEx, USPS).
These rates provide A-to-Z Claims and OTDR protection.
136 137 138 |
# File 'app/models/shipping_cost.rb', line 136 def is_amzbs_ptp? is_amzbs? && amz_carrier_id.present? && amz_carrier_id != 'AMZN_US' end |
#is_beta? ⇒ Boolean
208 209 210 |
# File 'app/models/shipping_cost.rb', line 208 def is_beta? shipping_option&.is_beta? || false end |
#is_fedex_ca? ⇒ Object
Alias for Shipping_option#is_fedex_ca?
82 |
# File 'app/models/shipping_cost.rb', line 82 delegate :is_fedex_ca?, to: :shipping_option |
#is_freightquote? ⇒ Object
Alias for Shipping_option#is_freightquote?
83 |
# File 'app/models/shipping_cost.rb', line 83 delegate :is_freightquote?, to: :shipping_option |
#is_override? ⇒ Object
Alias for Shipping_option#is_override?
80 |
# File 'app/models/shipping_cost.rb', line 80 delegate :is_override?, to: :shipping_option |
#is_shipengine_ltl? ⇒ Boolean
204 205 206 |
# File 'app/models/shipping_cost.rb', line 204 def is_shipengine_ltl? shipping_option&.is_shipengine_ltl? || false end |
#is_sww? ⇒ Boolean
Returns true if this is a Ship with Walmart shipping cost
124 125 126 |
# File 'app/models/shipping_cost.rb', line 124 def is_sww? shipping_option&.carrier == 'WalmartSeller' || sww_carrier_id.present? end |
#is_third_party_only? ⇒ Object
Alias for Shipping_option#is_third_party_only?
81 |
# File 'app/models/shipping_cost.rb', line 81 delegate :is_third_party_only?, to: :shipping_option |
#line_items ⇒ ActiveRecord::Relation<LineItem>
49 |
# File 'app/models/shipping_cost.rb', line 49 has_many :line_items, dependent: :destroy |
#name ⇒ Object
Alias for Shipping_option#name
84 |
# File 'app/models/shipping_cost.rb', line 84 delegate :name, to: :shipping_option |
#service_code ⇒ Object
Alias for Shipping_option#service_code
85 |
# File 'app/models/shipping_cost.rb', line 85 delegate :service_code, to: :shipping_option |
#set_line_items_price ⇒ Object
244 245 246 247 |
# File 'app/models/shipping_cost.rb', line 244 def set_line_items_price Rails.logger.debug { "set_line_items_price: self.name: #{name}, self.calculated_cost: #{calculated_cost}, self.id: #{id}" } line_items.shipping_only.update_all(price: calculated_cost, discounted_price: calculated_cost) end |
#shipping_account_number ⇒ ShippingAccountNumber
47 |
# File 'app/models/shipping_cost.rb', line 47 belongs_to :shipping_account_number, optional: true |
#shipping_option ⇒ ShippingOption
45 |
# File 'app/models/shipping_cost.rb', line 45 belongs_to :shipping_option, optional: true |
#sww_estimated_delivery_date ⇒ Object
Returns the estimated delivery date for SWW rates
141 142 143 144 145 146 147 148 |
# File 'app/models/shipping_cost.rb', line 141 def sww_estimated_delivery_date return nil unless is_sww? return nil if sww_estimated_delivery.blank? sww_estimated_delivery.to_date rescue StandardError nil end |
#third_party_billed? ⇒ Boolean
Single source of truth, at this layer, for "is the carrier billed to
the customer's own account (so we do NOT invoice them for shipping)?"
The decision is whether a ShippingAccountNumber is ATTACHED to this
option — i.e. it was selected (auto, when the owner's
bill_shipping_to_customer is the default, OR manually from the
rate-shop dropdown even when it is not). Selecting the account IS the
instruction to bill it; the attached SAN carries the account number
to bill. The owner's flag only governs the default selection upstream
and is intentionally NOT re-consulted here.
The carrier label (WyShipping.classify_third_party_billing), the
customer's quoted shipping charge (#calculated_cost), the invoice
reconciliation (Delivery#adjusted_actual_shipping_cost), and the
on-screen account labels all gate on this one predicate, so they can
never drift apart (the drift — label on one axis, invoice on another
— is what leaked the cost to WarmlyYours: SO723955, SO725940).
231 232 233 |
# File 'app/models/shipping_cost.rb', line 231 def third_party_billed? shipping_account_number.present? end |
#to_partial_path ⇒ Object
Partial lives under app/views/deliveries/, not the conventional
app/views/shipping_costs/. Override so render shipping_cost
resolves correctly from any controller, not just the delivery views
that currently render it via the verbose render partial: ... form.
41 42 43 |
# File 'app/models/shipping_cost.rb', line 41 def to_partial_path 'deliveries/shipping_cost' end |