feat(dimensions): voucher-level retro-tagging workbench — reversal pairs hidden by default (#874)
* feat(dimensions): voucher-level retro-tagging workbench, reversal pairs hidden by default UX rework of the BulkTagWorkbench (follow-up to #867): the verifikat is now the unit of work, matching how users think ('that invoice belongs to project X') and how every Swedish bookkeeping tool presents entries. - /api/dimensions/tagging/lines returns voucher-grouped results via a two-step query: filters select QUALIFYING vouchers (line-level predicates become 'voucher has such a line' through the inner join), then the complete line set for each — tagging a voucher always covers the whole verifikat, never the filtered subset of one - reversal pairs are EXCLUDED by default: an annulled entry and its storno net to zero in every dimension bucket as long as both sides carry the same tag, so retro-tagging them is a no-op with an asymmetry foot-gun attached; 'Visa annullerade' opts them back in, and the blocking motverifikat confirmation survives only in that view (correction rebooks remain taggable — only the original+storno pair is hidden) - voucher rows: label, description, date, line count, distinct tag chips + 'Delvis taggad' state, single total amount (no debit/credit columns); chevron expands to per-line rows (signed amount, per-line checkboxes) for the mixed case (a voucher split across projects) - selection stays line-id based under the hood (the retag RPC is per line); shift-click ranges operate on vouchers; apply groups by resulting map and now chunks to the apply route's 500-line cap; failed vouchers auto-expand with their Swedish RPC errors inline - 'endast otaggade' now means 'vouchers with at least one untagged line'; the cap counts vouchers (default 150, max 300) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: pull counter-vouchers into the annulled view even outside filters (review) Without this, a pair leg whose counter fell outside the date range would show no motverifikat warning at all — one-sided tagging would slip through silently, exactly the Srf U 14 skew the guard exists to prevent. Also scope the line fetch explicitly through the parent company filter (defense in depth). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
45438d4d64
commit
28827c2613
+10
-2
@@ -2202,9 +2202,17 @@ export const DimensionTaggingLinesQuerySchema = z.object({
|
||||
account_to: accountNumber.optional(),
|
||||
/** Free-text ilike filter on journal_entries.description. */
|
||||
text: z.string().trim().max(200).optional(),
|
||||
/** '1' → only lines whose dimensions map is empty ({}). */
|
||||
/** '1' → only vouchers with at least one untagged line ({} dimensions). */
|
||||
only_untagged: z.enum(['0', '1']).optional(),
|
||||
limit: z.coerce.number().int().min(1).max(500).default(200),
|
||||
/**
|
||||
* '1' → include reversal pairs (annulled entries + their stornos). Excluded
|
||||
* by default: a pair nets to zero in every dimension bucket when both sides
|
||||
* carry the same tag, so retro-tagging it is a no-op — and showing it
|
||||
* invites tagging one side only, which skews project P&L.
|
||||
*/
|
||||
include_annulled: z.enum(['0', '1']).optional(),
|
||||
/** Cap counts VOUCHERS since the voucher-level rework. */
|
||||
limit: z.coerce.number().int().min(1).max(300).default(150),
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user