Module: ProblematicDeliveriesHelper

Defined in:
app/helpers/problematic_deliveries_helper.rb

Overview

View helper: problematic-delivery badges and tooltips — the warehouse
"Problematic Deliveries" tab plus the delivery-level icon badges shown
beside the tracking-status icons (warehouse rows, delivery show heading).

Constant Summary collapse

PROBLEMATIC_REASON_BADGES =

Presentation per ProblematicDeliverySweep reason: Font Awesome icon, the
short badge label, and the prose phrase used in tooltips and the digest.

Colour is deliberately NOT here — it comes from
ProblematicDeliverySweep.severity, because no_pickup_scan is yellow or
red depending on the parcel's age, not on the reason alone.

{
  exception: { icon: 'triangle-exclamation', label: 'Carrier exception',
               phrase: 'carrier exception with no delivered scan' },
  pickup_in_lieu: { icon: 'location-dot', label: 'Left at pickup point',
                    phrase: 'delivered to a pickup location instead of the address' },
  no_pickup_scan: { icon: 'truck-ramp-box', label: 'No pickup scan',
                    phrase: 'marked shipped but never scanned into carrier custody' },
  overdue_no_delivery: { icon: 'clock', label: 'Overdue',
                         phrase: 'past estimated delivery with no delivered scan' }
}.freeze
PROBLEMATIC_SEVERITY_BADGES =

Presentation per ProblematicDeliverySweep.severity. Bootstrap's
warning needs text-dark to clear contrast, per DESIGN.crm.md.

The word is not decoration: DESIGN.crm.md forbids conveying state with
colour alone, so every badge renders its severity as text beside the
colour and the icon.

{
  critical: { classes: 'bg-danger', word: 'Critical', icon: 'circle-exclamation' },
  warning: { classes: 'bg-warning text-dark', word: 'Warning', icon: 'triangle-exclamation' }
}.freeze

Instance Method Summary collapse

Instance Method Details

#problematic_delivery_badges(delivery, size: nil, events_by_number: nil) ⇒ ActiveSupport::SafeBuffer?

One icon badge per unique problematic reason across the delivery's
parcels, rendered with the same markup/tooltip machinery as the
tracking-status badges so they sit naturally beside them. Reasons come
from ProblematicDeliverySweep.badge_reason (the sweep/tab criteria),
so a badge disappears exactly when the row would leave the warehouse
Problematic Deliveries tab (delivered scan, dismissal, 30-day age-out).

Parameters:

Returns:

  • (ActiveSupport::SafeBuffer, nil)


115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'app/helpers/problematic_deliveries_helper.rb', line 115

def problematic_delivery_badges(delivery, size: nil, events_by_number: nil)
  return nil unless delivery

  by_reason = delivery.shipments
                      .select { |s| s.tracking_number.present? }
                      .group_by { |s| ProblematicDeliverySweep.badge_reason(s, events: events_by_number&.dig(s.tracking_number)) }
  by_reason.delete(nil)
  return nil if by_reason.empty?

  badges = by_reason.map do |reason, shipments|
    style = PROBLEMATIC_REASON_BADGES.fetch(reason)
    # Worst case wins the colour: one critical parcel among several makes
    # the delivery's badge red, rather than averaging down to yellow.
    severity = if shipments.any? { |s| ProblematicDeliverySweep.severity(s, reason) == :critical }
                 :critical
               else
                 :warning
               end
    badge = ShipmentEventStatusSummary::Badge.new(
      kind: :problematic,
      state: reason,
      color: severity == :critical ? :danger : :warning,
      icon: style[:icon],
      tooltip: problematic_reason_tooltip(reason, tracking_numbers: shipments.map(&:tracking_number)),
      event_time: nil
    )
    render_tracking_status_badge(badge, size: size)
  end
  safe_join(badges)
end

#problematic_reason_label(reason) ⇒ String

Returns short badge text, e.g. "No pickup scan".

Parameters:

  • reason (Symbol, String)

    a PROBLEMATIC_REASON_BADGES key

Returns:

  • (String)

    short badge text, e.g. "No pickup scan"



37
38
39
# File 'app/helpers/problematic_deliveries_helper.rb', line 37

def problematic_reason_label(reason)
  PROBLEMATIC_REASON_BADGES.dig(reason.to_sym, :label) || reason.to_s.humanize
end

#problematic_reason_tooltip(reason, tracking_numbers: []) ⇒ String

Tooltip text for a problematic-delivery reason badge.

Parameters:

  • reason (Symbol, String)

    a PROBLEMATIC_REASON_BADGES key

  • tracking_numbers (Array<String>) (defaults to: [])

    the affected parcel(s)

Returns:

  • (String)


46
47
48
49
50
51
# File 'app/helpers/problematic_deliveries_helper.rb', line 46

def problematic_reason_tooltip(reason, tracking_numbers: [])
  phrase = PROBLEMATIC_REASON_BADGES.dig(reason.to_sym, :phrase) || reason.to_s.humanize.downcase
  tooltip = "Problematic delivery: #{phrase}"
  tooltip += "#{tracking_numbers.join(', ')}" if tracking_numbers.present?
  tooltip
end

#problematic_severity_badge(shipment, reason) ⇒ ActiveSupport::SafeBuffer

The warehouse tab's Problem cell: one badge carrying severity colour,
severity word, and the reason, e.g. a red "Critical · Carrier exception".

Parameters:

  • shipment (Shipment)
  • reason (Symbol, String)

Returns:

  • (ActiveSupport::SafeBuffer)


59
60
61
62
63
64
65
66
67
# File 'app/helpers/problematic_deliveries_helper.rb', line 59

def problematic_severity_badge(shipment, reason)
  severity = ProblematicDeliverySweep.severity(shipment, reason)
  style = PROBLEMATIC_SEVERITY_BADGES.fetch(severity)

  tag.span(class: "badge #{style[:classes]} bs-tooltip", data: { placement: 'bottom' },
           title: problematic_reason_tooltip(reason, tracking_numbers: [shipment.tracking_number])) do
    safe_join([fa_icon(style[:icon]), " #{style[:word]} · #{problematic_reason_label(reason)}"])
  end
end

#rma_return_badge(delivery, size: nil) ⇒ ActiveSupport::SafeBuffer?

"Return" badge for the outbound return-label half of an Rma.

These deliveries sit in the same warehouse lists and the same
Problematic Deliveries tab as paid outbound orders, but they are a
different job with a different owner: a return label we issued that the
customer may legitimately never use (they shipped it themselves, used
another carrier, or no return was needed). Staff need to tell the two
apart at a glance rather than reading the missing order number — on
2026-07-30, 7 of the 8 aged no-scan Canada rows were RMA returns and
only DE794814 (SO728353) was a real sales order.

Rendered through the same ShipmentEventStatusSummary::Badge machinery
as the tracking-status and problematic badges so it sits naturally in
the same icon row.

Parameters:

  • delivery (Delivery, DeliveryPresenter, nil)
  • size (Symbol, String, nil) (defaults to: nil)

    optional Font Awesome size class

Returns:

  • (ActiveSupport::SafeBuffer, nil)

    nil unless this is an RMA return



87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'app/helpers/problematic_deliveries_helper.rb', line 87

def rma_return_badge(delivery, size: nil)
  return nil unless delivery&.is_rma_return?

  rma = delivery.rma_for_return
  badge = ShipmentEventStatusSummary::Badge.new(
    kind: :rma_return,
    state: :rma_return,
    color: :info,
    icon: 'arrow-rotate-left',
    tooltip: "RMA return label#{" — RMA##{rma.id}" if rma}: outbound return label, not a customer order",
    event_time: nil
  )
  render_tracking_status_badge(badge, size: size)
end