feat(dashboard): owed-cash worklist buckets, prefilled partial dispense, resume cash-out (ADR-005 §5–§6)

Three buckets render first on the worklist — cash_owed, partial_pending,
dispense_unreported (awaiting_dispense older than the threshold) — the
only ones whose meaning is "a customer is owed money". partial_pending
rows open the partial-dispense dialog pre-filled from the machine's
report: the fraction from dispensed_fiat_cents / fiat_amount and the
dispenser's error in the note, so the operator confirms a number the
hardware produced rather than typing one.

Machine detail shows a held-cash-out banner (code, time, reason) with a
Resume button; POST /machines/{id}/resume-cash-out records a
resume_cash_out op and publishes the window. The machine clears the hold
on receipt and the banner clears on its next state report.
This commit is contained in:
Padreug 2026-10-10 21:51:52 +02:00
commit fdba2d363f
3 changed files with 179 additions and 12 deletions

View file

@ -661,6 +661,12 @@
@click="viewMachineFromWorklist(props.row)">
<q-tooltip>Open machine detail</q-tooltip>
</q-btn>
<q-btn v-if="bucket.key === 'partial_pending'"
flat dense size="sm" icon="call_split"
color="deep-orange"
@click="openPartialDispense(props.row)">
<q-tooltip>Record the resolution (pre-filled from the machine's report)</q-tooltip>
</q-btn>
<q-btn v-if="bucket.key === 'errored'"
flat dense size="sm" icon="restart_alt"
color="primary"
@ -1178,6 +1184,25 @@
<span v-text="machineDetail.cassettesError"></span>
</q-banner>
<q-banner v-if="machineDetail.machine
&& machineDetail.machine.cash_out_held_since"
class="bg-red-1 text-grey-9 q-mb-md">
<template v-slot:avatar>
<q-icon name="block" color="negative"></q-icon>
</template>
<b>Cash-out is held.</b>
The machine latched cash-out off after a terminal dispenser fault
(<span v-text="machineDetail.machine.cash_out_held_code || 'fault'"></span>
at <span v-text="formatTime(machineDetail.machine.cash_out_held_since)"></span>):
<span v-text="machineDetail.machine.cash_out_held_reason"></span>.
Clear the transport path, then either record a <b>Recount</b>
(which also fixes the count) or release it here.
<template v-slot:action>
<q-btn flat color="negative" label="Resume cash-out"
@click="confirmResumeCashOut(machineDetail.machine)"></q-btn>
</template>
</q-banner>
<q-banner v-if="machineDetail.machine
&& machineDetail.machine.counts_uncertain_since"
class="bg-orange-1 text-grey-9 q-mb-md">