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 Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #cost ⇒ BigDecimal 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 ⇒ void
- #delivery_commitment ⇒ void
- #description ⇒ void
- #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_curri? ⇒ Boolean
Returns true if this is a Curri same-day courier cost.
- #is_shipengine_ltl? ⇒ Boolean
-
#is_sww? ⇒ Boolean
Returns true if this is a Ship with Walmart shipping cost.
- #set_line_items_price ⇒ void
-
#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 Models::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#cost ⇒ BigDecimal (readonly)
Validations:
55 |
# File 'app/models/shipping_cost.rb', line 55 validates :cost, numericality: true |
Class Method Details
.amzbs_only ⇒ ActiveRecord::Relation<ShippingCost>
A relation of ShippingCosts that are amzbs only. Active Record Scope
99 |
# File 'app/models/shipping_cost.rb', line 99 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
97 |
# File 'app/models/shipping_cost.rb', line 97 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
93 |
# File 'app/models/shipping_cost.rb', line 93 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
95 |
# File 'app/models/shipping_cost.rb', line 95 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
94 |
# File 'app/models/shipping_cost.rb', line 94 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
92 |
# File 'app/models/shipping_cost.rb', line 92 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
96 |
# File 'app/models/shipping_cost.rb', line 96 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
98 |
# File 'app/models/shipping_cost.rb', line 98 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.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'app/models/shipping_cost.rb', line 201 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 # parser-3.3.x used by 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.
256 257 258 259 260 |
# File 'app/models/shipping_cost.rb', line 256 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)
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'app/models/shipping_cost.rb', line 167 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 ⇒ void
This method returns an undefined value.
113 114 115 |
# File 'app/models/shipping_cost.rb', line 113 def days_commitment days_in_transit.presence || sww_transit_days.presence || amz_transit_days.presence || shipping_option.days_commitment end |
#delivery ⇒ Delivery?
47 |
# File 'app/models/shipping_cost.rb', line 47 belongs_to :delivery, optional: true |
#delivery_commitment ⇒ void
This method returns an undefined value.
118 119 120 121 122 123 124 125 126 127 128 |
# File 'app/models/shipping_cost.rb', line 118 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 ⇒ void
This method returns an undefined value.
102 103 104 105 106 107 108 109 110 |
# File 'app/models/shipping_cost.rb', line 102 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
269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'app/models/shipping_cost.rb', line 269 def hide? # Deactivated options (is_inactive) drop out of pickers, auto-select, and # www freight selection. Callers keep an already-*selected* hidden cost # visible so historical/in-flight deliveries still show what they're on. return true if shipping_option&.is_inactive? 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
218 |
# File 'app/models/shipping_cost.rb', line 218 delegate :information, to: :shipping_option |
#is_amzbs? ⇒ Boolean
Returns true if this is an Amazon Buy Shipping cost
136 137 138 |
# File 'app/models/shipping_cost.rb', line 136 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.
152 153 154 |
# File 'app/models/shipping_cost.rb', line 152 def is_amzbs_ptp? is_amzbs? && amz_carrier_id.present? && amz_carrier_id != 'AMZN_US' end |
#is_beta? ⇒ Boolean
226 227 228 |
# File 'app/models/shipping_cost.rb', line 226 def is_beta? shipping_option&.is_beta? || false end |
#is_curri? ⇒ Boolean
Returns true if this is a Curri same-day courier cost. Drives the
admin-only selection lock in deliveries/_shipping_services during the
Curri beta (WyShipping::CURRI_ADMIN_ONLY) — deliberately carrier-scoped
rather than keyed on is_beta?, which 35 live ShipEngine LTL options also
carry and which ops select freely today.
145 146 147 |
# File 'app/models/shipping_cost.rb', line 145 def is_curri? shipping_option&.carrier == 'Curri' end |
#is_fedex_ca? ⇒ Object
Alias for Shipping_option#is_fedex_ca?
86 |
# File 'app/models/shipping_cost.rb', line 86 delegate :is_fedex_ca?, to: :shipping_option |
#is_freightquote? ⇒ Object
Alias for Shipping_option#is_freightquote?
87 |
# File 'app/models/shipping_cost.rb', line 87 delegate :is_freightquote?, to: :shipping_option |
#is_override? ⇒ Object
Alias for Shipping_option#is_override?
84 |
# File 'app/models/shipping_cost.rb', line 84 delegate :is_override?, to: :shipping_option |
#is_shipengine_ltl? ⇒ Boolean
221 222 223 |
# File 'app/models/shipping_cost.rb', line 221 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
131 132 133 |
# File 'app/models/shipping_cost.rb', line 131 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?
85 |
# File 'app/models/shipping_cost.rb', line 85 delegate :is_third_party_only?, to: :shipping_option |
#line_items ⇒ ActiveRecord::Relation<LineItem>
52 |
# File 'app/models/shipping_cost.rb', line 52 has_many :line_items, dependent: :destroy |
#name ⇒ Object
Alias for Shipping_option#name
88 |
# File 'app/models/shipping_cost.rb', line 88 delegate :name, to: :shipping_option |
#service_code ⇒ Object
Alias for Shipping_option#service_code
89 |
# File 'app/models/shipping_cost.rb', line 89 delegate :service_code, to: :shipping_option |
#set_line_items_price ⇒ void
This method returns an undefined value.
263 264 265 266 |
# File 'app/models/shipping_cost.rb', line 263 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?
49 |
# File 'app/models/shipping_cost.rb', line 49 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
157 158 159 160 161 162 163 164 |
# File 'app/models/shipping_cost.rb', line 157 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).
249 250 251 |
# File 'app/models/shipping_cost.rb', line 249 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.
40 41 42 |
# File 'app/models/shipping_cost.rb', line 40 def to_partial_path 'deliveries/shipping_cost' end |