Class: Shipping::CreateSuggestedShipment
- Inherits:
-
BaseService
- Object
- BaseService
- Shipping::CreateSuggestedShipment
- Defined in:
- app/services/shipping/create_suggested_shipment.rb
Instance Method Summary collapse
-
#build_item_map_from_line_items(line_items) ⇒ Object
Returns a hash, item_id as key, mapping to array of line item id and quantities.
- #process(delivery) ⇒ Object
-
#synthesize_single_box_contents(package, line_items) ⇒ Object
For single-box solutions where the packing history has dims but no per-box item mapping, synthesize contents from the delivery's line items so the allocation loop can assign them to the one shipment.
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
#build_item_map_from_line_items(line_items) ⇒ Object
Returns a hash, item_id as key, mapping to array of line item id and quantities
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'app/services/shipping/create_suggested_shipment.rb', line 91 def build_item_map_from_line_items(line_items) item_map = {} # We will keep track of all line items to allocate line_items.each do |li| # Break kit items items = li.item.get_kit_items if li.item.is_kit? items ||= [li.item] items.each do |i| item_map[i.id] ||= {} item_map[i.id][li.id] = li.quantity.abs end end item_map end |
#process(delivery) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'app/services/shipping/create_suggested_shipment.rb', line 3 def process(delivery) # Shortcut return [] if delivery.is_service_only? suggested_shipments = [] Shipment.transaction do line_items_to_pack = delivery.packable_active_lines # Delete only fresh suggested shipments (container_code nil = never physically packed by warehouse). # Suggested shipments with a container_code were previously packed and measured by the warehouse # — they survive a CR Hold / shipping-method change so staff don't have to re-enter weights. delivery.shipments.suggested.where(container_code: [nil, '']).delete_all # If any non-voided shipments remain (packed, awaiting_label, label_complete, or # previously-measured suggested shipments) return them directly without rebuilding. remaining_shipments = delivery.shipments.non_voided return remaining_shipments if remaining_shipments.present? # Try to find a matching packaging from previous order or use legacy packing model packing_solution = Shipping::DeterminePackaging.new.process(delivery: delivery, is_freight: delivery.ships_ltl_freight?) item_map = {} if packing_solution.packages.all? { |p| p.contents.present? } item_map = build_item_map_from_line_items(line_items_to_pack) elsif packing_solution.packages.size == 1 && line_items_to_pack.any? item_map = build_item_map_from_line_items(line_items_to_pack) synthesize_single_box_contents(packing_solution.packages.first, line_items_to_pack) end packing_solution.packages.each do |p| suggested_shipment = delivery.shipments.create(weight: p.weight, length: p.length, width: p.width, height: p.height, is_legacy: false, is_manual: false, flat_rate_package_type: p.flat_rate_package_type, container_type: p.container_type || Shipment.container_types.keys.first, # 'carton' state: 'suggested') if !suggested_shipment.valid? || !suggested_shipment.persisted? logger.error "Could not create suggested shipment: #{suggested_shipment.errors_to_s}" else if item_map.present? && p.contents.present? # map shipment contents p.contents.each do |package_content| # this returns an array of [line item id, quantities] qty_remaining_to_allocate = package_content.quantity # Sometimes garbage data or mismatch can cause an item to be fully allocated already break if item_map[package_content.item_id].nil? item_map[package_content.item_id].each do |(line_item_id, line_quantity)| allocatable_qty = [qty_remaining_to_allocate,line_quantity].min sc = suggested_shipment.shipment_contents.where(line_item_id: line_item_id).first_or_initialize sc.quantity = allocatable_qty sc.save # Remove or reduce the quantity from this line item_map[package_content.item_id][line_item_id] -= allocatable_qty # If the line is fully allocated, we remove this entry if item_map[package_content.item_id][line_item_id] <= 0 item_map[package_content.item_id].delete(line_item_id) end # and remove the item id if its all allocated if item_map[package_content.item_id].empty? item_map.delete(package_content.item_id) end end # If we allocated everything in this package we move on break if qty_remaining_to_allocate == 0 end end suggested_shipments << suggested_shipment end end end suggested_shipments end |
#synthesize_single_box_contents(package, line_items) ⇒ Object
For single-box solutions where the packing history has dims but no per-box
item mapping, synthesize contents from the delivery's line items so the
allocation loop can assign them to the one shipment.
83 84 85 86 87 88 |
# File 'app/services/shipping/create_suggested_shipment.rb', line 83 def synthesize_single_box_contents(package, line_items) line_items.each do |li| items = li.item.is_kit? ? li.item.get_kit_items : [li.item] items.each { |i| package.add_content(i.id, li.quantity.abs) } end end |