Class: Edi::Walmart::ShipCodeMapper
- Inherits:
-
Object
- Object
- Edi::Walmart::ShipCodeMapper
- Defined in:
- app/services/edi/walmart/ship_code_mapper.rb
Constant Summary collapse
- CARRIER_MAP =
Maps internal carrier names to Walmart carrier codes
Official list: https://developer.walmart.com/us-marketplace/docs/supported-carrier-names
Parcel carriers: https://marketplacelearn.walmart.com/guides/Seller%20Fulfillment%20Services/Shipping%20methods/Shipping-methods:-parcel-shipping-carriersIMPORTANT: Use exact Walmart carrier names - incorrect values cause shipment update failures
{ # Primary carriers (Walmart preferred) 'UPS' => 'UPS', 'Ups' => 'UPS', 'ups' => 'UPS', 'USPS' => 'USPS', 'Usps' => 'USPS', 'usps' => 'USPS', 'FedEx' => 'FedEx', 'Fedex' => 'FedEx', 'FEDEX' => 'FedEx', 'fedex' => 'FedEx', # UPS variants 'UPSMI' => 'UPSMI', 'UPS Mail Innovations' => 'UPSMI', # FedEx variants 'FDX' => 'FDX', 'FEDEXSP' => 'FEDEXSP', 'FedEx SmartPost' => 'FEDEXSP', # DHL variants 'DHL' => 'DHL', 'dhl' => 'DHL', 'DHL Ecommerce' => 'DHL Ecommerce - US', 'DHL eCommerce' => 'DHL Ecommerce - US', # Regional US carriers 'OnTrac' => 'OnTrac', 'ONTRAC' => 'OnTrac', 'LSO' => 'LSO', 'Lone Star Overnight' => 'LSO', 'LS' => 'LS', 'LaserShip' => 'LS', 'Lasership' => 'LS', 'UDS' => 'UDS', 'United Delivery Service' => 'UDS', 'AxleHire' => 'AxleHire', 'Better Trucks' => 'Better Trucks', # Freight carriers 'SAIA' => 'SAIA', 'Saia' => 'SAIA', 'Estes' => 'Estes Express', 'ESTES' => 'Estes Express', 'Estes Express' => 'Estes Express', 'XPO' => 'XPO Logistics', 'XPO Logistics' => 'XPO Logistics', 'ABF' => 'ABF Freight System', 'ABF Freight' => 'ABF Freight System', 'RL Carriers' => 'RL Carriers', 'R+L Carriers' => 'RL Carriers', 'R+L' => 'RL Carriers', 'RlCarriers' => 'RL Carriers', 'CEVA' => 'CEVA', 'TForce' => 'TForce Freight', 'TForce Freight' => 'TForce Freight', 'AAA Cooper' => 'AAA Cooper', 'Southeastern' => 'Southeastern Freight Lines', 'Southeastern Freight' => 'Southeastern Freight Lines', 'PITT OHIO' => 'PITT OHIO', 'Roadrunner' => 'Roadrunner Freight', 'Meyer' => 'Meyer Distribution', 'RXO' => 'RXO', 'PILOT' => 'PILOT', 'AM Trucking' => 'AM Trucking', 'Yellow Freight' => 'Yellow Freight Sys', 'YRC' => 'Yellow Freight Sys', 'AIT' => 'AIT Worldwide Logistics', # Canadian carriers 'Canada Post' => 'Canada Post', 'Canadapost' => 'Canada Post', 'CanadaPost' => 'Canada Post', 'CANADA POST' => 'Canada Post', 'Purolator' => 'Purolator', 'PUROLATOR' => 'Purolator', 'Canpar' => 'Canpar', 'CANPAR' => 'Canpar', # International carriers 'Royal Mail' => 'Royal Mail', 'Deutsche Post' => 'Deutsche Post', 'Japan Post' => 'Japan Post', 'India Post' => 'India Post', 'China Post' => 'China Post', 'Correos de Mexico' => 'Correos de Mexico', 'PostNord' => 'PostNord Sweden', # International express 'SF Express' => 'SF Express', 'SFC' => 'SFC', 'YunExpress' => 'YunExpress', 'Yanwen' => 'Yanwen', '4PX' => '4PX', 'CNE' => 'CNE', 'Chukou1' => 'Chukou1', 'GLS' => 'GLS', 'Sunyou' => 'Sunyou', 'Sendle' => 'Sendle', 'JD Logistics' => 'JD Logistics', 'JCEX' => 'JCEX', 'YDH' => 'YDH', 'Equick' => 'Equick', 'Tusou' => 'Tusou', 'WanB' => 'WanB', 'Flyt' => 'Flyt', 'Asendia' => 'Asendia', 'UBI' => 'UBI', 'ePost Global' => 'ePost Global', 'YF Logistics' => 'YF Logistics', 'Shypmax' => 'Shypmax', 'Shiprocket' => 'Shiprocket', 'DTDC' => 'DTDC', 'PTS' => 'PTS', 'Whistl' => 'Whistl', 'WIN.IT America' => 'WIN.IT America', # Specialty carriers 'FDS Express' => 'FDS Express', 'Seko' => 'Seko Worldwide', 'Seko Worldwide' => 'Seko Worldwide', 'HIT Delivery' => 'HIT Delivery', 'OSM' => 'OSM Worldwide', 'OSM Worldwide' => 'OSM Worldwide', 'FIRST MILE' => 'FIRST MILE', 'Landmark Global' => 'Landmark Global', 'Metropolitan' => 'Metropolitan Warehouse & Delivery', # Legacy/alternate names 'Airborne' => 'Airborne', 'Forward Air' => 'Forward Air', 'Conway' => 'Conway', 'Spee-Dee' => 'Spee-Dee', 'A1' => 'A1', 'Averitt' => 'Averitt' }.freeze
- PRIMARY_CARRIER_PREFIXES =
Prefix matching for carrier strings that include service-level suffixes
e.g., "FedEx Ground Economy" → "FedEx", "UPS 2nd Day Air" → "UPS"
Only primary carriers need this — regional/specialty carriers rarely appear with suffixes { 'fedex' => 'FedEx', 'ups' => 'UPS', 'usps' => 'USPS', 'dhl' => 'DHL' }.freeze
- METHOD_MAP =
Walmart method codes for shipping service levels
Valid values: Standard, Express, TwoDay, NextDay, Value (case-sensitive)
See: https://developer.walmart.com/us-marketplace/docs/get-an-order { # Standard shipping (3-5 days) 'Ground' => 'Standard', 'Standard' => 'Standard', 'standard' => 'Standard', 'FedEx Ground' => 'Standard', 'UPS Ground' => 'Standard', # Express shipping (2-3 days) 'Express' => 'Express', 'express' => 'Express', 'Expedited' => 'Express', 'Priority' => 'Express', '3-Day' => 'Express', # Two-day shipping '2-Day' => 'TwoDay', '2Day' => 'TwoDay', 'TwoDay' => 'TwoDay', 'Two Day' => 'TwoDay', 'FedEx 2Day' => 'TwoDay', 'UPS 2nd Day Air' => 'TwoDay', # Next-day shipping 'Overnight' => 'NextDay', 'NextDay' => 'NextDay', 'Next Day' => 'NextDay', '1-Day' => 'NextDay', 'FedEx Priority Overnight' => 'NextDay', 'FedEx Standard Overnight' => 'NextDay', 'UPS Next Day Air' => 'NextDay', # Value shipping (5-8 days, economy) 'Value' => 'Value', 'value' => 'Value', 'Economy' => 'Value', 'Saver' => 'Value', # Freight (maps to Standard for now - verify with Walmart if freight-specific code exists) 'Freight' => 'Standard', 'LTL' => 'Standard', 'White Glove' => 'Standard' }.freeze
Instance Attribute Summary collapse
-
#orchestrator ⇒ Object
readonly
Returns the value of attribute orchestrator.
Instance Method Summary collapse
-
#carrier_code(carrier) ⇒ String
Map internal carrier name to Walmart carrier code.
-
#carrier_info(shipment) ⇒ Hash
Build the complete carrier info hash for ship confirmation Walmart API expects carrierName as: { "carrier": "UPS" } for known carriers { "otherCarrier": "Custom Carrier Name" } for unknown carriers.
-
#extract_method_from_delivery(description, carrier) ⇒ String
Extract method name from delivery's shipping cost description.
-
#initialize(orchestrator) ⇒ ShipCodeMapper
constructor
A new instance of ShipCodeMapper.
-
#known_carrier?(carrier) ⇒ Boolean
Check if a carrier is in Walmart's known carrier list.
-
#method_code(method) ⇒ String
Map internal shipping method to Walmart method code.
Constructor Details
#initialize(orchestrator) ⇒ ShipCodeMapper
Returns a new instance of ShipCodeMapper.
208 209 210 |
# File 'app/services/edi/walmart/ship_code_mapper.rb', line 208 def initialize(orchestrator) @orchestrator = orchestrator end |
Instance Attribute Details
#orchestrator ⇒ Object (readonly)
Returns the value of attribute orchestrator.
206 207 208 |
# File 'app/services/edi/walmart/ship_code_mapper.rb', line 206 def orchestrator @orchestrator end |
Instance Method Details
#carrier_code(carrier) ⇒ String
Map internal carrier name to Walmart carrier code
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'app/services/edi/walmart/ship_code_mapper.rb', line 215 def carrier_code(carrier) return nil if carrier.blank? carrier_str = carrier.to_s.strip # Try exact match first return CARRIER_MAP[carrier_str] if CARRIER_MAP.key?(carrier_str) # Try case-insensitive match CARRIER_MAP.each do |key, value| return value if key.casecmp?(carrier_str) end # Try prefix match for carriers with service-level suffixes # e.g., "FedEx Ground Economy" should match "FedEx" carrier_lower = carrier_str.downcase PRIMARY_CARRIER_PREFIXES.each do |prefix, walmart_code| return walmart_code if carrier_lower.start_with?(prefix) end # Not found - will use otherCarrier field nil end |
#carrier_info(shipment) ⇒ Hash
Build the complete carrier info hash for ship confirmation
Walmart API expects carrierName as:
{ "carrier": "UPS" } for known carriers
{ "otherCarrier": "Custom Carrier Name" } for unknown carriers
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'app/services/edi/walmart/ship_code_mapper.rb', line 272 def carrier_info(shipment) # For Ship with Walmart shipments, use the actual carrier from sww_metadata # shipment.carrier = "WalmartSeller" indicates SWW, actual carrier is in sww_carrier is_sww = shipment.carrier == 'WalmartSeller' actual_carrier = if is_sww && shipment.sww_carrier.present? shipment.sww_carrier else shipment.carrier end carrier = carrier_code(actual_carrier) carrier_name = if carrier { carrier: carrier } else { otherCarrier: actual_carrier.to_s } end # Build tracking URL using the actual carrier. # Shipment.tracking_link can return "#" when the carrier/tracking-number combo # isn't recognized — reject anything that isn't a real http(s) URL. tracking_url = if shipment.tracking_number.present? && actual_carrier.present? url = Shipment.tracking_link(actual_carrier, shipment.tracking_number) url.present? && url.start_with?('http') ? url : nil else nil end # For SWW shipments, extract method from delivery's selected_shipping_cost.description # e.g., "Ship with Walmart: FedEx Ground Economy" -> "Ground Economy" # For regular shipments, use the standard method_code mapping method = if is_sww extract_method_from_delivery(shipment.delivery&.selected_shipping_cost&.description, actual_carrier) else method_code(shipment.delivery&.shipping_method_friendly) end { carrierName: carrier_name, methodCode: method, trackingNumber: shipment.tracking_number, trackingURL: tracking_url }.compact end |
#extract_method_from_delivery(description, carrier) ⇒ String
Extract method name from delivery's shipping cost description
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'app/services/edi/walmart/ship_code_mapper.rb', line 320 def extract_method_from_delivery(description, carrier) return 'Standard' if description.blank? method_str = description.to_s # Strip "Ship with Walmart: " prefix if present method_str = method_str.sub(/^Ship with Walmart:\s*/i, '') # Strip carrier name prefix (e.g., "FedEx Ground Economy" -> "Ground Economy") if carrier.present? # Try exact carrier match first, then normalized method_str = method_str.sub(/^#{Regexp.escape(carrier)}\s+/i, '') end method_str.strip.presence || 'Standard' end |
#known_carrier?(carrier) ⇒ Boolean
Check if a carrier is in Walmart's known carrier list
340 341 342 |
# File 'app/services/edi/walmart/ship_code_mapper.rb', line 340 def known_carrier?(carrier) carrier_code(carrier).present? end |
#method_code(method) ⇒ String
Map internal shipping method to Walmart method code
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'app/services/edi/walmart/ship_code_mapper.rb', line 241 def method_code(method) return 'Standard' if method.blank? method_str = method.to_s.strip # Try exact match first return METHOD_MAP[method_str] if METHOD_MAP.key?(method_str) # Try case-insensitive match METHOD_MAP.each do |key, value| return value if key.casecmp?(method_str) end # Try keyword extraction for longer strings like "FedEx Ground Economy" method_lower = method_str.downcase return 'NextDay' if method_lower.match?(/overnight|next.?day|1.?day/) return 'TwoDay' if method_lower.match?(/2.?day|two.?day|2nd.?day/) return 'Express' if method_lower.match?(/express|expedit|priority|3.?day/) return 'Value' if method_lower.match?(/economy|saver|value/) return 'Standard' if method_lower.match?(/ground|standard|home.?delivery/) # Default to Standard 'Standard' end |