Class: Shipping::DeterminePackaging

Inherits:
BaseService show all
Defined in:
app/services/shipping/determine_packaging.rb

Overview

Resolves a Delivery into a Shipping::PackingSolution by walking a tiered
lookup against historical Packing records, then falling back to a 3D
bin-pack calculator (or per-item history, or a freight pallet calculator).

Lookup pipeline

  1. History match (#lookup_history) — direct, relevant, and nested
    JSONB matches against Packing.md5. The first hit wins.
  2. Multibox fallback (#apply_multibox_fallback) — per-item history
    coverage first; PackingCalculator second (parcel only).
  3. Single-box fallback (#apply_single_box_fallback) —
    PackingCalculator first; per-item history second when the calculator
    can't run; FreightPalletCalculator last for freight deliveries.

Memoization

Results are cached for the duration of a request via
CurrentScope.packing_solution_cache, keyed on
(delivery.id, is_freight, skip_calculator, dim_weight_divisor). Calculator
runs are no longer also persisted as from_calculator Packing records:
the audit found they were never re-read (1,978 rows, 0 reuse) so they were
pure write amplification.

Instance Attribute Summary

Attributes inherited from BaseService

#options

Instance Method Summary collapse

Methods inherited from BaseService

#initialize, #log_debug, #log_error, #log_info, #log_warning, #logger, #tagged_logger

Constructor Details

This class inherits a constructor from BaseService

Instance Method Details

#process(delivery:, md5_hash_override: nil, _store_id: nil, is_freight: false, skip_calculator: false, dim_weight_divisor: Shipping::PackingCalculator::DIM_WEIGHT_DIVISOR) ⇒ Shipping::PackingSolution

Parameters:

  • delivery (Delivery)
  • md5_hash_override (String) (defaults to: nil)

    override MD5 (test / admin use)

  • _store_id (Integer) (defaults to: nil)

    unused — kept for callers that still pass it

  • is_freight (Boolean) (defaults to: false)
  • skip_calculator (Boolean) (defaults to: false)

    bypass PackingCalculator and per-item history fallback (e.g. packed_or_pre_packed?)

  • dim_weight_divisor (Integer) (defaults to: Shipping::PackingCalculator::DIM_WEIGHT_DIVISOR)

    carrier-specific (default 139 = FedEx/UPS/Purolator Ground).
    Pass 115 for Purolator Express when the carrier is known.

Returns:



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
79
80
81
82
83
84
85
86
87
# File 'app/services/shipping/determine_packaging.rb', line 34

def process(delivery:, md5_hash_override: nil, _store_id: nil, is_freight: false, skip_calculator: false, dim_weight_divisor: Shipping::PackingCalculator::DIM_WEIGHT_DIVISOR)
  cache_key = "#{delivery.id}:#{is_freight}:#{skip_calculator}:#{dim_weight_divisor}"
  if (cached = CurrentScope.packing_solution_cache&.[](cache_key))
    logger.debug "Shipping::DeterminePackaging: returning cached solution for delivery #{delivery.id}"
    return cached
  end

  solution = Shipping::PackingSolution.new

  parent_lines = delivery.packable_active_parent_lines_only
  ActiveRecord::Associations::Preloader.new(records: parent_lines, associations: [:item, :direct_store_item, { catalog_item: :store_item }]).call

  multibox            = parent_lines.any? { |li| !li.item.ships_in_single_box? }
  line_items_to_pack, item_hash = pack_inputs(delivery, parent_lines, multibox: multibox)

  md5_result = Shipping::Md5HashItem.process(item_hash)
  solution.md5_line_items          = md5_hash_override || md5_result.md5
  solution.relevant_md5_line_items = md5_hash_override || md5_result.relevant_md5

  packing_query = is_freight ? Packing.freight_service : Packing.parcel_service

  packing, nested_md5 = lookup_history(packing_query,
                                       md5:          solution.md5_line_items,
                                       relevant_md5: solution.relevant_md5_line_items)

  if packing
    solution.packing_id            = packing.id
    solution.packages              = packing.to_packages(nested_md5)
    solution.equivalent_delivery_id = packing.delivery_id
    solution.source_type           = packing.origin&.to_sym || :unknown
  elsif multibox
    apply_multibox_fallback(solution,
                            item_hash:           item_hash,
                            line_items_to_pack:  line_items_to_pack,
                            packing_query:       packing_query,
                            delivery:            delivery,
                            is_freight:          is_freight,
                            skip_calculator:     skip_calculator,
                            dim_weight_divisor:  dim_weight_divisor)
  else
    apply_single_box_fallback(solution,
                              item_hash:           item_hash,
                              line_items_to_pack:  line_items_to_pack,
                              parent_lines:        parent_lines,
                              packing_query:       packing_query,
                              delivery:            delivery,
                              is_freight:          is_freight,
                              skip_calculator:     skip_calculator,
                              dim_weight_divisor:  dim_weight_divisor)
  end

  (CurrentScope.packing_solution_cache ||= {})[cache_key] = solution
  solution
end