Class: Edi::MarketplaceLabelPurchaser
- Inherits:
-
Object
- Object
- Edi::MarketplaceLabelPurchaser
- Defined in:
- app/services/edi/marketplace_label_purchaser.rb
Overview
Base class for marketplace-specific shipping label purchasers
Each marketplace (Walmart, Amazon, Wayfair, etc.) that offers discounted
shipping labels through their platform should have a subclass that handles:
- Purchasing labels via the marketplace's API
- Downloading label PDFs
- Attaching labels to shipments
- Voiding/canceling labels
Direct Known Subclasses
Amazon::ShippingLabelPurchaser, Walmart::ShippingLabelPurchaser
Defined Under Namespace
Classes: PurchaseResult
Instance Attribute Summary collapse
-
#delivery ⇒ Object
readonly
Returns the value of attribute delivery.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#order ⇒ Object
readonly
Returns the value of attribute order.
-
#shipment ⇒ Object
readonly
Returns the value of attribute shipment.
Class Method Summary collapse
-
.for_delivery(delivery) ⇒ Class?
Factory method to get the appropriate purchaser class for a delivery.
-
.for_order(order) ⇒ Class?
Factory method to get the appropriate purchaser class for an order.
-
.for_shipment(shipment) ⇒ Class?
Factory method to get the appropriate purchaser class for a shipment.
-
.marketplace_carrier?(carrier) ⇒ Boolean
Check if the carrier is a marketplace-provided carrier.
-
.marketplace_name(order) ⇒ String?
Get the marketplace name for display.
-
.supports_marketplace_labels?(delivery) ⇒ Boolean
Check if a delivery supports marketplace label purchasing.
Instance Method Summary collapse
-
#attach_label_pdf(label_data, filename) ⇒ Upload?
protected
Download a label PDF and attach it to the shipment Uses 'ship_label_pdf' category since it's a carrier-generated label (purchased through marketplace API, but still a real carrier label).
-
#failure_result(error) ⇒ Object
protected
Create a failure result.
-
#initialize(shipment, options = {}) ⇒ MarketplaceLabelPurchaser
constructor
A new instance of MarketplaceLabelPurchaser.
-
#map_carrier_name(marketplace_carrier) ⇒ String
protected
Map marketplace carrier codes to internal carrier names Subclasses can override for marketplace-specific mappings.
-
#marketplace_name ⇒ String
Human-readable name of this marketplace.
-
#purchase_label(_rate) ⇒ PurchaseResult
Purchase a shipping label using a marketplace rate.
-
#success_result(label_id:, tracking_number:, carrier:, service_type:, label_upload: nil) ⇒ Object
protected
Create a successful result.
-
#update_shipment_tracking(tracking_number, carrier, label_id) ⇒ Object
protected
Update shipment with tracking information.
-
#validate_order! ⇒ Object
protected
Validate the order is appropriate for this purchaser Subclasses should override to add marketplace-specific validation.
-
#void_label ⇒ Hash
Void/discard a previously purchased label.
Constructor Details
#initialize(shipment, options = {}) ⇒ MarketplaceLabelPurchaser
Returns a new instance of MarketplaceLabelPurchaser.
105 106 107 108 109 110 111 112 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 105 def initialize(shipment, = {}) @shipment = shipment @delivery = shipment.delivery @order = delivery.order @logger = [:logger] || Rails.logger validate_order! end |
Instance Attribute Details
#delivery ⇒ Object (readonly)
Returns the value of attribute delivery.
27 28 29 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 27 def delivery @delivery end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
27 28 29 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 27 def logger @logger end |
#order ⇒ Object (readonly)
Returns the value of attribute order.
27 28 29 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 27 def order @order end |
#shipment ⇒ Object (readonly)
Returns the value of attribute shipment.
27 28 29 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 27 def shipment @shipment end |
Class Method Details
.for_delivery(delivery) ⇒ Class?
Factory method to get the appropriate purchaser class for a delivery
66 67 68 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 66 def self.for_delivery(delivery) for_order(delivery&.order) end |
.for_order(order) ⇒ Class?
Factory method to get the appropriate purchaser class for an order
49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 49 def self.for_order(order) return nil unless order&.edi_orchestrator_partner.present? # Map EDI partner prefixes to their label purchaser classes # Add new marketplaces here as they're implemented case order.edi_orchestrator_partner when /^walmart_seller/ then Edi::Walmart::ShippingLabelPurchaser when /^amazon_seller/ then Edi::Amazon::ShippingLabelPurchaser # Future marketplaces: # when /^wayfair/ then Edi::Wayfair::ShippingLabelPurchaser end end |
.for_shipment(shipment) ⇒ Class?
Factory method to get the appropriate purchaser class for a shipment
38 39 40 41 42 43 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 38 def self.for_shipment(shipment) order = shipment.delivery&.order return nil unless order for_order(order) end |
.marketplace_carrier?(carrier) ⇒ Boolean
Check if the carrier is a marketplace-provided carrier
88 89 90 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 88 def self.marketplace_carrier?(carrier) %w[WalmartSeller AmazonSeller WayfairShipping].include?(carrier) end |
.marketplace_name(order) ⇒ String?
Get the marketplace name for display
96 97 98 99 100 101 102 103 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 96 def self.marketplace_name(order) case order&.edi_orchestrator_partner when /^walmart_seller/ then 'Walmart' when /^amazon_seller/ then 'Amazon' when /^wayfair/ then 'Wayfair' else nil end end |
.supports_marketplace_labels?(delivery) ⇒ Boolean
Check if a delivery supports marketplace label purchasing
74 75 76 77 78 79 80 81 82 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 74 def self.supports_marketplace_labels?(delivery) return false unless delivery&.order # Must have a marketplace purchaser available return false unless for_delivery(delivery) # Must have a marketplace carrier selected marketplace_carrier?(delivery.carrier) end |
Instance Method Details
#attach_label_pdf(label_data, filename) ⇒ Upload? (protected)
Download a label PDF and attach it to the shipment
Uses 'ship_label_pdf' category since it's a carrier-generated label
(purchased through marketplace API, but still a real carrier label)
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 177 def attach_label_pdf(label_data, filename) upload = Upload.uploadify_from_data( file_name: filename, data: label_data, category: 'ship_label_pdf', resource: shipment ) if upload&.persisted? shipment.uploads << upload logger.info("[#{self.class.name}] Label attached as upload #{upload.id}") end upload rescue StandardError => e logger.error("[#{self.class.name}] Error attaching label: #{e.}") nil end |
#failure_result(error) ⇒ Object (protected)
Create a failure result
158 159 160 161 162 163 164 165 166 167 168 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 158 def failure_result(error) PurchaseResult.new( success: false, label_id: nil, tracking_number: nil, carrier: nil, service_type: nil, label_upload: nil, error: error ) end |
#map_carrier_name(marketplace_carrier) ⇒ String (protected)
Map marketplace carrier codes to internal carrier names
Subclasses can override for marketplace-specific mappings
216 217 218 219 220 221 222 223 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 216 def map_carrier_name(marketplace_carrier) case marketplace_carrier&.upcase when 'USPS' then 'USPS' when 'FEDEX', 'FEDEX_GROUND', 'FEDEX_EXPRESS' then 'FedEx' when 'UPS' then 'UPS' else marketplace_carrier end end |
#marketplace_name ⇒ String
Human-readable name of this marketplace
132 133 134 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 132 def marketplace_name raise NotImplementedError, "#{self.class.name} must implement #marketplace_name" end |
#purchase_label(_rate) ⇒ PurchaseResult
Purchase a shipping label using a marketplace rate
118 119 120 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 118 def purchase_label(_rate) raise NotImplementedError, "#{self.class.name} must implement #purchase_label" end |
#success_result(label_id:, tracking_number:, carrier:, service_type:, label_upload: nil) ⇒ Object (protected)
Create a successful result
145 146 147 148 149 150 151 152 153 154 155 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 145 def success_result(label_id:, tracking_number:, carrier:, service_type:, label_upload: nil) PurchaseResult.new( success: true, label_id: label_id, tracking_number: tracking_number, carrier: carrier, service_type: service_type, label_upload: label_upload, error: nil ) end |
#update_shipment_tracking(tracking_number, carrier, label_id) ⇒ Object (protected)
Update shipment with tracking information
201 202 203 204 205 206 207 208 209 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 201 def update_shipment_tracking(tracking_number, carrier, label_id) shipment.update!( tracking_number: tracking_number, carrier: map_carrier_name(carrier), marketplace_label_id: label_id ) logger.info("[#{self.class.name}] Updated shipment #{shipment.id} with tracking: #{tracking_number}") end |
#validate_order! ⇒ Object (protected)
Validate the order is appropriate for this purchaser
Subclasses should override to add marketplace-specific validation
140 141 142 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 140 def validate_order! raise ArgumentError, 'Shipment must have an order' unless order.present? end |
#void_label ⇒ Hash
Void/discard a previously purchased label
125 126 127 |
# File 'app/services/edi/marketplace_label_purchaser.rb', line 125 def void_label raise NotImplementedError, "#{self.class.name} must implement #void_label" end |