Class: Shipping::LtlShippingInsurance
- Inherits:
-
BaseService
- Object
- BaseService
- Shipping::LtlShippingInsurance
- Defined in:
- app/services/shipping/ltl_shipping_insurance.rb
Defined Under Namespace
Classes: Result
Constant Summary collapse
- LOADSURE_API_HASH =
LOADSURE_API_HASH = {
base_url: LOADSURE_API_BASE_URL,
partner_id: LOADSURE_API_PARTNER_ID,
user_id: LOADSURE_API_USER_ID,
additional_user_id: LOADSURE_API_ADDITIONAL_USER_ID,
token: LOADSURE_API_TOKEN
} {}
- INSURED_VALUE_MIN =
LOADSURE_API_HASH = Heatwave::Configuration.fetch(:loadsurance_api)
5000.0- INSURANCE_FEE_MAX_PERCENT =
0.05- INSURANCE_FEE_MAX_AMOUNT =
250.0- INSURANCE_DED_MAX_PERCENT =
0.2- INSURANCE_DED_MAX_AMOUNT =
1000.0- INSURANCE_FEE_MIN_AMOUNT =
5.0- LOADSURANCE_CARRIER_DATA_BY_CARRIER =
here we only populate parcel carriers that we know are covered by our Shipsurance contract
we do not cover freight carriers per Shipsurance contract
see: https://shipsurance-partner-api.readme.io/reference/extcarrierid-lookup { FedExFreight: { mode: 'ROAD', name: 'FedEx Freight', email: 'mark.lackinger@fedex.com', carrierId: { type: 'SCAC', value: 'FXFS' }, phone: '+12242422831', address: { address1: '5600 9TH ST', city: 'Zion', state: 'IL', postal: '60099', country: 'US' } }, Freightquote: { mode: 'ROAD', name: 'Freightquote.com Inc', email: 'brian.dougherty@freightquote.com', carrierId: { type: 'SCAC', value: 'FQCI' }, phone: '+18169496250', address: { address1: '901 West Carondelet Drive', city: 'Kansas City', state: 'MO', postal: '64114', country: 'US' } }, RlCarriers: { mode: 'ROAD', name: 'R&L Carriers', email: 'scott.brighton@rlcarriers.com', carrierId: { type: 'SCAC', value: 'RLCA' }, phone: '+18476953100', address: { address1: '375 Second Street', city: 'Elgin', state: 'IL', postal: '60123', country: 'US' } }, Roadrunner: { mode: 'ROAD', name: 'Roadrunner Freight', email: 'robert.provost@rrts.com', carrierId: { type: 'SCAC', value: 'RDFS' }, phone: '+18478007768', address: { address1: '4801 68th Avenue', city: 'Kenosha', state: 'WI', postal: '53144', country: 'US' } }, Saia: { mode: 'ROAD', name: 'Saia LTL Freight', email: 'ssanti@saia.com', carrierId: { type: 'SCAC', value: 'SAIA' }, phone: '+18474716588', address: { address1: '2260 Midlothian Road', city: 'Grayslake', state: 'IL', postal: '60030', country: 'US' } } }
- COVERAGE_LIMIT =
25_000.0
Instance Method Summary collapse
- #bill_shipping_to_customer_and_not_a_store_transfer?(delivery) ⇒ Boolean
- #book_shipping_insurance_for_delivery(delivery, options) ⇒ Object
- #carrier_present?(carrier) ⇒ Boolean
- #carrier_qualifies_for_rating?(carrier) ⇒ Boolean
- #cross_border_fedex_freight?(delivery) ⇒ Boolean
- #delivery_carrier_present?(delivery) ⇒ Boolean
- #get_shipping_insurance_cost_for_delivery(delivery) ⇒ Object
- #get_shipping_insurance_cost_for_shipment(shipment) ⇒ Object
- #get_shipping_insurance_insured_value_for_delivery(delivery) ⇒ Object
- #get_shipping_insurance_insured_value_for_shipment(shipment) ⇒ Object
- #get_shipping_insurance_link_for_shipment(shipment) ⇒ Object
- #process(delivery, options = {}) ⇒ Object
- #qualifies(delivery) ⇒ Object
- #qualifies_for_rating?(delivery) ⇒ Boolean
- #void_shipping_insurance_for_delivery(delivery) ⇒ Object
Methods inherited from BaseService
#initialize, #log_debug, #log_error, #log_info, #log_warning, #logger, #options, #tagged_logger
Constructor Details
This class inherits a constructor from BaseService
Instance Method Details
#bill_shipping_to_customer_and_not_a_store_transfer?(delivery) ⇒ Boolean
148 149 150 151 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 148 def bill_shipping_to_customer_and_not_a_store_transfer?(delivery) # if billing to customer, let them pay for declared value via carrier delivery.bill_shipping_to_customer && !delivery.order&.is_store_transfer? # this is to be readable to me, a human end |
#book_shipping_insurance_for_delivery(delivery, options) ⇒ Object
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 196 def book_shipping_insurance_for_delivery(delivery, ) status = :ok = '' insurance_result_hash = {} quote_hash = HTTP.use(logging: { logger: Rails.logger }).timeout(60).auth("Bearer #{LOADSURE_API_HASH[:token]}").post("#{LOADSURE_API_HASH[:base_url]}/quote", json: quote_data(delivery)).parse.with_indifferent_access if quote_hash[:success] == false msgs = (quote_hash[:errors] || []).map { |e| e.dig(:message) } status = :error = msgs.join('. ') else quote_cost = quote_hash.dig(:insuranceProduct, :premium).to_f + quote_hash.dig(:insuranceProduct, :serviceFee).to_f quote_deductible = quote_hash.dig(:insuranceProduct, :deductible).to_f threshhold_exceeded_hash = insurance_quote_exceeds_thresholds?(quote_cost, apply_carrier_coverage_limit(delivery), quote_deductible) quote_token = quote_hash.dig(:quoteToken) if threshhold_exceeded_hash[:status] != :ok status = threshhold_exceeded_hash[:status] = threshhold_exceeded_hash[:status_message] elsif quote_token.present? insurance_result_hash = HTTP.use(logging: { logger: Rails.logger }).timeout(60).auth("Bearer #{LOADSURE_API_HASH[:token]}").post("#{LOADSURE_API_HASH[:base_url]}/purchaseQuote", json: { quoteToken: quote_token, additionalAuthorizedUsers: [LOADSURE_API_HASH[:additional_user_id]] }).parse.with_indifferent_access if insurance_result_hash[:error].present? status = :error = insurance_result_hash[:error] end end end delivery.shipments.update_all(shipping_insurance_data: { shipping_insurance_record_id: insurance_result_hash[:certificateNumber] }.merge(insurance_result_hash)) if status == :ok Result.new(status: status, status_message: ) end |
#carrier_present?(carrier) ⇒ Boolean
158 159 160 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 158 def carrier_present?(carrier) LOADSURANCE_CARRIER_DATA_BY_CARRIER[(carrier || 'none').to_sym].present? end |
#carrier_qualifies_for_rating?(carrier) ⇒ Boolean
166 167 168 169 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 166 def (carrier) # here we want to return a simple TRUE/FALSE boolean, this is to see if we can use this carrier_present?(carrier) end |
#cross_border_fedex_freight?(delivery) ⇒ Boolean
153 154 155 156 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 153 def cross_border_fedex_freight?(delivery) # we do not ship insure cross border FedEx Freight via Loadsurance because we need to pass declared value delivery.carrier == 'FedExFreight' && delivery.is_cross_border? # this is to be readable to me, a human end |
#delivery_carrier_present?(delivery) ⇒ Boolean
162 163 164 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 162 def delivery_carrier_present?(delivery) carrier_present?(delivery.carrier) end |
#get_shipping_insurance_cost_for_delivery(delivery) ⇒ Object
244 245 246 247 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 244 def get_shipping_insurance_cost_for_delivery(delivery) delivery.shipments.first&.shipping_insurance_data&.dig('premium').to_f # cost = delivery.shipments.where("carrier IS NOT NULL").sum{|s| get_shipping_insurance_cost_for_shipment(s)} end |
#get_shipping_insurance_cost_for_shipment(shipment) ⇒ Object
249 250 251 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 249 def get_shipping_insurance_cost_for_shipment(shipment) (get_shipping_insurance_cost_for_delivery(shipment.delivery) / [shipment.delivery.shipments.size, 1].max).round(2) end |
#get_shipping_insurance_insured_value_for_delivery(delivery) ⇒ Object
253 254 255 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 253 def get_shipping_insurance_insured_value_for_delivery(delivery) delivery.calculate_declared_value.to_f.abs end |
#get_shipping_insurance_insured_value_for_shipment(shipment) ⇒ Object
257 258 259 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 257 def get_shipping_insurance_insured_value_for_shipment(shipment) (shipment.delivery.calculate_declared_value.to_f.abs / [shipment.delivery.shipments.size, 1].max).round(2) end |
#get_shipping_insurance_link_for_shipment(shipment) ⇒ Object
261 262 263 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 261 def get_shipping_insurance_link_for_shipment(shipment) %(<a href='https://portal.loadsure.net/certificates/details/?certificateNumber=#{shipment.shipping_insurance_record_id}' target='_blank' rel='noopener'>#{shipment.shipping_insurance_record_id}</a> <small>(file claim <a href='https://portal.loadsure.net/claims/file?id=#{shipment.shipping_insurance_record_id}' target='_blank' rel='noopener' onclick='return confirm("Are you sure you want to file a claim?")'>here</a>)</small>).html_safe end |
#process(delivery, options = {}) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 117 def process(delivery, = {}) status = :ok = 'WarmlyYours Self Insures all LTL Shipping' qualifies_res = qualifies(delivery) # 03/18/24 Here we have decided per Venu and Christian to discontinue our Shipping Insurance with Loadsure, and self-insure after seeing no record of any claims or losses for LTL shipments in our history. # So we want to qualify all LTL shipments i.e. return TRUE, so we don't pass declared value to the LTL carriers, but then do nothing when it is ship insurance time # if qualifies_res.status == :ok # r = book_shipping_insurance_for_delivery(delivery, options) # unless r.status == :ok # status = :error # status_message = "Shipping insurance for delivery #{delivery.name} cannot be booked: #{r.status_message}" # end # else # status = qualifies_res.status # status_message = qualifies_res.status_message # end Result.new(status: status, status_message: ) end |
#qualifies(delivery) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 171 def qualifies(delivery) # status = :ok # status_message = '' # any_labeled_shipments = delivery.shipments.label_complete.any? # all_labeled_shipments_have_tracking_number = delivery.shipments.label_complete.all?{|s| s.tracking_number.present?} # unless qualifies_for_rating?(delivery) && any_labeled_shipments && all_labeled_shipments_have_tracking_number # status = :error # status_message_arr = [] # status_message_arr << "Order #{delivery.order&.reference_number} does not qualify for Loadsurance shipping insurance" # status_message_arr << "Carrier #{delivery.carrier} is not one of our covered Loadsurance carriers" if !delivery_carrier_present?(delivery) # status_message_arr << "When customer pays for shipping we do not ship insure via Loadsurance" if bill_shipping_to_customer_and_not_a_store_transfer?(delivery) # status_message_arr << "When delivery value is less than $#{INSURED_VALUE_MIN.round(2)} we do not ship insure via Loadsurance" if delivery.calculate_declared_value.to_f.abs < INSURED_VALUE_MIN # status_message_arr << "When delivery is FedExFreight cross-border, we do not ship insure via Loadsurance" if cross_border_fedex_freight?(delivery) # status_message_arr << "Delivery does not have any labeled shipments" if !any_labeled_shipments # status_message_arr << "Not all shipments have tracking numbers" if !all_labeled_shipments_have_tracking_number # status_message = "#{status_message_arr.join('. ')}." # end ############################################################################ # Note that we are disabling LTL shipping insurance for all deliveries based on price increases, lack of claims and an executive decision by Christian Billen and Venu Adepu on 1/30/2025 ############################################################################ status = :error = 'LTL shipping insurance is now disabled.' Result.new(status: status, status_message: ) end |
#qualifies_for_rating?(delivery) ⇒ Boolean
136 137 138 139 140 141 142 143 144 145 146 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 136 def (delivery) # here we want to return a simple TRUE/FALSE boolean, this is to see if we can use this when the delivery, in quoting status, gets ship-labeled # return delivery.supported_shipping_carrier? && delivery_carrier_present?(delivery) && (delivery.calculate_declared_value.to_f.abs > INSURED_VALUE_MIN) && !cross_border_fedex_freight?(delivery) && !bill_shipping_to_customer_and_not_a_store_transfer?(delivery) ############################################################################ # Note that we are disabling LTL shipping insurance for all deliveries based on price increases, lack of claims and an executive decision by Christian Billen and Venu Adepu on 1/30/2025 ############################################################################ # return false # 03/18/24 Here we have decided per Venu and Christian to discontinue our Shipping Insurance with Loadsure, and self-insure after seeing no record of any claims or losses for LTL shipments in our history. # So we want to qualify all LTL shipments i.e. return TRUE, so we don't pass declared value to the LTL carriers, but then do nothing when it is ship insurance time true end |
#void_shipping_insurance_for_delivery(delivery) ⇒ Object
229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'app/services/shipping/ltl_shipping_insurance.rb', line 229 def void_shipping_insurance_for_delivery(delivery) status = :ok = '' void_result_hash = HTTP.use(logging: { logger: Rails.logger }).timeout(60).auth("Bearer #{LOADSURE_API_HASH[:token]}").post("#{LOADSURE_API_HASH[:base_url]}/cancelCertificate", json: void_data(delivery)).parse.with_indifferent_access if void_result_hash[:success] == false msgs = (void_result_hash[:errors] || []).map { |e| e.dig(:message) } status = :error = msgs.join('. ') end delivery.shipments.update_all(shipping_insurance_data: {}.merge(void_result_hash)) if status == :ok Result.new(status: status, status_message: ) end |