Class: ShippingCost

Inherits:
ApplicationRecord show all
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

Belongs to collapse

Has many collapse

Delegated Instance Attributes collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#costObject (readonly)



51
# File 'app/models/shipping_cost.rb', line 51

validates :cost, numericality: true

Class Method Details

.amzbs_onlyActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are amzbs only. Active Record Scope

Returns:

See Also:



95
# File 'app/models/shipping_cost.rb', line 95

scope :amzbs_only, -> { joins(:shipping_option).where(shipping_options: { carrier: 'AmazonSeller' }) }

.override_onlyActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are override only. Active Record Scope

Returns:

See Also:



93
# File 'app/models/shipping_cost.rb', line 93

scope :override_only, -> { joins(:shipping_option).where(shipping_options: { name: 'override' }) }

.skip_3rd_partyActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are skip 3rd party. Active Record Scope

Returns:

See Also:



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_canadapostActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are skip canadapost. Active Record Scope

Returns:

See Also:



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_freightActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are skip freight. Active Record Scope

Returns:

See Also:



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_overrideActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are skip override. Active Record Scope

Returns:

See Also:



88
# File 'app/models/shipping_cost.rb', line 88

scope :skip_override, -> { joins(:shipping_option).where.not(shipping_options: { name: 'override' }) }

.supportedActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are supported. Active Record Scope

Returns:

See Also:



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_onlyActiveRecord::Relation<ShippingCost>

A relation of ShippingCosts that are sww only. Active Record Scope

Returns:

See Also:



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_windowObject

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_costObject

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_dateObject

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_commitmentObject



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

#deliveryDelivery

Returns:

See Also:



46
# File 'app/models/shipping_cost.rb', line 46

belongs_to :delivery, optional: true

#delivery_commitmentObject



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

#descriptionObject



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

Returns:

  • (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

#informationObject

Alias for Shipping_option#information

Returns:

  • (Object)

    Shipping_option#information

See Also:



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

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


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

Returns:

  • (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?

Returns:

  • (Object)

    Shipping_option#is_fedex_ca?

See Also:



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?

Returns:

  • (Object)

    Shipping_option#is_freightquote?

See Also:



83
# File 'app/models/shipping_cost.rb', line 83

delegate :is_freightquote?, to: :shipping_option

#is_override?Object

Alias for Shipping_option#is_override?

Returns:

  • (Object)

    Shipping_option#is_override?

See Also:



80
# File 'app/models/shipping_cost.rb', line 80

delegate :is_override?, to: :shipping_option

#is_shipengine_ltl?Boolean

Returns:

  • (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

Returns:

  • (Boolean)


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?

Returns:

  • (Object)

    Shipping_option#is_third_party_only?

See Also:



81
# File 'app/models/shipping_cost.rb', line 81

delegate :is_third_party_only?, to: :shipping_option

#line_itemsActiveRecord::Relation<LineItem>

Returns:

See Also:



49
# File 'app/models/shipping_cost.rb', line 49

has_many :line_items, dependent: :destroy

#nameObject

Alias for Shipping_option#name

Returns:

  • (Object)

    Shipping_option#name

See Also:



84
# File 'app/models/shipping_cost.rb', line 84

delegate :name, to: :shipping_option

#service_codeObject

Alias for Shipping_option#service_code

Returns:

  • (Object)

    Shipping_option#service_code

See Also:



85
# File 'app/models/shipping_cost.rb', line 85

delegate :service_code, to: :shipping_option

#set_line_items_priceObject



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_numberShippingAccountNumber



47
# File 'app/models/shipping_cost.rb', line 47

belongs_to :shipping_account_number, optional: true

#shipping_optionShippingOption



45
# File 'app/models/shipping_cost.rb', line 45

belongs_to :shipping_option, optional: true

#sww_estimated_delivery_dateObject

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).

Returns:

  • (Boolean)


231
232
233
# File 'app/models/shipping_cost.rb', line 231

def third_party_billed?
  .present?
end

#to_partial_pathObject

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