fix(cassettes): decrement bays on an operator remediation dispense
recordTransaction only debited the cassette rows for type 'cash_out'. An operator remediation is recorded as 'manual_dispense', so HAL's in-memory bays went down while the persisted rows did not — and HAL re-seeds from those rows on the next boot, so the machine came back believing it still held bills a customer had already been handed. A remediation against a partly-dispensed original debits again on purpose: the original only ever debited what physically left, and this is a second lot of bills leaving the bay. Closes #76 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
ac27bc36e0
commit
5b22447dae
2 changed files with 113 additions and 18 deletions
|
|
@ -168,3 +168,95 @@ describe('state-store: recordTransaction cash_in cashbox', () => {
|
|||
expect(countsByPosition()).toEqual({ 1: 50, 2: 50, 3: 30 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('state-store: recordTransaction manual_dispense inventory (#76)', () => {
|
||||
it('decrements the bays an operator remediation actually emptied', () => {
|
||||
recordTransaction({
|
||||
...TX_BASE,
|
||||
txid: 'tx-manual',
|
||||
type: 'manual_dispense',
|
||||
status: 'complete',
|
||||
bills: [{ denomination: 20, count: 2 }],
|
||||
cassettes: [
|
||||
{
|
||||
name: 'cassette1',
|
||||
position: 1,
|
||||
denomination: 20,
|
||||
provisioned: 2,
|
||||
dispensed: 2,
|
||||
rejected: 0,
|
||||
},
|
||||
],
|
||||
})
|
||||
// Bills physically left bay 1; before #76 this row was untouched and the
|
||||
// inflated count became truth on the next boot.
|
||||
expect(countsByPosition()).toEqual({ 1: 48, 2: 50, 3: 30 })
|
||||
})
|
||||
|
||||
it('decrements again when remediating a partly-dispensed cash-out', () => {
|
||||
// Original cash-out managed 1 of the 2 notes it provisioned.
|
||||
recordTransaction({
|
||||
...TX_BASE,
|
||||
txid: 'tx-partial',
|
||||
type: 'cash_out',
|
||||
status: 'partial',
|
||||
bills: [{ denomination: 50, count: 1 }],
|
||||
cassettes: [
|
||||
{
|
||||
name: 'cassette3',
|
||||
position: 3,
|
||||
denomination: 50,
|
||||
provisioned: 2,
|
||||
dispensed: 1,
|
||||
rejected: 0,
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(countsByPosition()[3]).toBe(29)
|
||||
|
||||
// The operator dispenses the missing note by hand. That is a second lot of
|
||||
// bills leaving the bay, so it debits again — the original only ever
|
||||
// debited what physically left.
|
||||
recordTransaction({
|
||||
...TX_BASE,
|
||||
txid: 'tx-remediate',
|
||||
type: 'manual_dispense',
|
||||
status: 'complete',
|
||||
bills: [{ denomination: 50, count: 1 }],
|
||||
cassettes: [
|
||||
{
|
||||
name: 'cassette3',
|
||||
position: 3,
|
||||
denomination: 50,
|
||||
provisioned: 1,
|
||||
dispensed: 1,
|
||||
rejected: 0,
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(countsByPosition()[3]).toBe(28)
|
||||
})
|
||||
|
||||
it('leaves the cashbox alone (bills leave, they do not arrive)', () => {
|
||||
const before = getCashbox()
|
||||
recordTransaction({
|
||||
...TX_BASE,
|
||||
txid: 'tx-manual-cashbox',
|
||||
type: 'manual_dispense',
|
||||
status: 'complete',
|
||||
bills: [{ denomination: 20, count: 1 }],
|
||||
cassettes: [
|
||||
{
|
||||
name: 'cassette2',
|
||||
position: 2,
|
||||
denomination: 20,
|
||||
provisioned: 1,
|
||||
dispensed: 1,
|
||||
rejected: 0,
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(getCashbox()).toEqual(before)
|
||||
expect(countsByPosition()[2]).toBe(49)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue