fiskaltrust / fiskaltrust/middleware
QueueES void validation refuses a correctly-negated void, and discards the field that would explain why
- Dominant language
- C#
- Stars
- 20
- Forks
- 11
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 13
Description
## Symptom
On the ES sandbox, voiding a demo-POS sale is refused by the middleware every time:
```
ftState 0x45532000eeeeeeee (0xEEEEEEEE failure marker, signature caption "FAILURE")
Validation error []: EEEE_Void does not match the original invoice '1-1788448309938'.
All articles from the original invoice must be properly voided with matching quantities and amounts.
```
Deterministic: 3 attempts across 2 tool sessions in run 33755682050 (queue items `21d4be51-f40f-4f2f-9299-4609e944eab8`, `e23ab372-4be8-4391-bfe5-b03a7a2e73e4`), and the same refusal on the two earlier ES runs.
The line sets are verbatim opposites:
| | original sale | void |
|---|---|---|
| Margherita Pizza | 1 × 0.85, VAT 21% | −1 × −0.85, VAT 21% |
| Pepperoni Pizza | 1 × 0.95, VAT 21% | −1 × −0.95, VAT 21% |
| Caesar Salad | 1 × 0.70, VAT 21% | −1 × −0.70, VAT 21% |
So the message's own claim — that the articles do not match in quantity and amount — is misleading about its cause. The articles match.
## The POS payload is not the problem
Read from the **deployed** bundle (`fiskaltrust.github.io/ft-posdemo/static/js/main.8052c939.js`), the void builds:
```js
cbReceiptReference: `Void(${e.cbReceiptReference})`,
cbPreviousReceiptReference: e.cbReceiptReference,
cbUser: "Admin",
cbArea: e.cbArea, cbCustomer: e.cbCustomer, cbSettlement: e.cbSettlement,
ftReceiptCaseData: e.ftReceiptCaseData,
ftReceiptCase: 0x00040000n | BigInt(e.ftReceiptCase),
cbChargeItems: e.cbChargeItems.map(e => ({ ...e, Amount: -e.Amount, VATAmount: -e.VATAmount, Quantity: -e.Quantity })),
```
Two things follow, and both contradict plausible-sounding theories:
1. It **clones the original line objects** (`{...e}`) and negates only Amount/VATAmount/Quantity. It does **not** rebuild them from the product grid, so no per-line identifier can be lost.
2. It carries `cbArea`, `cbCustomer`, `cbSettlement` and `ftReceiptCaseData` from the original — i.e. the earlier envelope fix (ft-posdemo PR #44) is present and live in the shipped bundle.
The only field that deliberately differs is `cbUser` (`"Admin"` on the void vs the sale's user) and, necessarily, `cbReceiptMoment` and `cbReceiptReference`.
## Why this cannot be diagnosed from the outside
**`QueueES/Validation/VoidValidator.cs` computes which comparison failed into a local and then discards it**, returning the bare `EEEE_VoidItemsMismatch(reference)` on every branch. `QueuePT`'s equivalent passes `ExtractDiffField(value, …)` and keeps it, so PT emits `(Field: cbArea)`-style suffixes and ES never can.
That discarded diagnostic is the blocker here. Everything visible in the payload matches; the one thing that would identify the mismatch is thrown away.
## Asks, in priority order
1. **Surface the field in ES** — mirror PT and include the computed mismatch in the returned message. This is small, it is the thing that unblocks every future ES void investigation, and it is arguably a defect in its own right.
2. With the field known, decide whether the ES rule or the POS payload is wrong. If ES compares `cbUser`, that is worth questioning: PT's validator explicitly ignores `cbUser`, `cbTerminalID`, `cbReceiptReference` and `cbReceiptMoment`, and a void is expected to be booked by a different operator than the sale.
## Evidence
- run https://github.com/fiskaltrust/service-portal-ui/actions/runs/33755682050 (ES developer-workshop; phases 01, 01-verify, 02, 02-pairing all passed; failed at `03-daily-operation-sales` step 4)
- original sale reference `1-1788448309938`, void reference `Void(1-1788448309938)`
- earlier ES runs with the identical refusal: 33624989791, 33697995831
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Contributor guide
Research direction
Start with QueueES/Validation/VoidValidator.cs and compare its void-mismatch handling with the equivalent QueuePT validator, which preserves ExtractDiffField(value, …). Trace where the computed comparison result is discarded, then ensure the ES validation message includes that field so future mismatches identify their cause.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100