feat(skattekonto): bulk Bokför + inline single-row booking (fewer clicks) (#1535)
* feat(skattekonto): bulk Bokför and inline single-row booking
Booking a year of skattekonto events took 6 clicks per row (list, Bokför,
review page, Bokför, confirm, navigate back), even for a +1 kr
intäktsränta row.
- GET /skattekonto/transaktioner now attaches a deterministic
booking_suggestion per unbooked row (one hoisted skattekonto_rules +
entity_type fetch via the new attachBookingSuggestions), shown as muted
text on the inbox row ('Bokförs mot 8314 ...').
- New POST /skattekonto/transaktioner/bokfor-batch (Zod, max 200 ids):
sequential draft+commit per row server-side (no orphan drafts), per-row
results, never aborts on a row failure. Commit attribution: bulk_accept
for real batches, user_accept for the one-row inline flow. A failed
commit keeps the linked draft (degrades to the old review flow).
- Inbox: hover-reveal checkboxes on eligible SKV rows (suggestion
present, no duplicate hint, unbooked, genomförd), separate skvSelectedIds
set, bulkbar 'Bokför valda (N)' with ONE summary ConfirmationDialog
grouped by suggestion with per-group sums, chunked batchProgress, ONE
aggregate toast, local state patch with exit animation.
- Single-row: new SkattekontoBookDialog (dynamic import) replaces the
draft-then-window.location detour on both /transactions and /skattekonto;
'Öppna som utkast' keeps the old draft path via router.push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(skattekonto): batch booking guards for unsettled rows, double-post race and locked periods
- reject status != booked rows in the batch flow with NOT_SETTLED before
any draft exists (server no longer trusts client eligibility); the
single-row draft endpoint keeps its behaviour
- make the journal_entry_id backlink a conditional claim (update where
journal_entry_id is null, select affected rows): zero affected rows maps
to ALREADY_BOOKED and commitEntry only runs after a won claim, so two
concurrent submissions can no longer double-post the same row
- detect the period-lock trigger signature in the batch catch and map it
to PERIOD_LOCKED with Swedish text instead of UNKNOWN with raw DB output
- SkattekontoBookDialog: rows with no matched rule no longer get the
guaranteed-422 draft CTA; they route to the existing match flow and to
manual verifikat creation in /bookkeeping
- pass an explicit skv_book_dialog.commit_warning key for the
direct-commit warning instead of ConfirmationDialog's hardcoded default
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
Jakob Wennberg
parent
7cf0e34434
commit
dea5e31756
+43
-1
@@ -3227,7 +3227,27 @@
|
||||
"link_to_voucher": "Link to voucher",
|
||||
"book_anyway": "Post anyway",
|
||||
"book": "Post",
|
||||
"match_to_voucher": "Match to voucher"
|
||||
"match_to_voucher": "Match to voucher",
|
||||
"suggestion_line": "Posts to {account}",
|
||||
"select_row": "Select tax account event"
|
||||
},
|
||||
"skv_book_dialog": {
|
||||
"title": "Post tax account event",
|
||||
"event_label": "Event",
|
||||
"date_label": "Date",
|
||||
"amount_label": "Amount",
|
||||
"posting_label": "Posting",
|
||||
"posting_value": "1630 against {account}",
|
||||
"no_rule_matched": "No booking rule matched this event. Match it to an existing voucher, or create the voucher manually in Bookkeeping.",
|
||||
"confirm_book": "Post",
|
||||
"open_draft": "Open as draft",
|
||||
"match_cta": "Match to voucher",
|
||||
"manual_create_cta": "Create voucher manually",
|
||||
"commit_warning": "A voucher will be created and cannot be changed afterwards.",
|
||||
"draft_created_title": "Draft created",
|
||||
"draft_created_description": "Review and post the voucher in Bookkeeping.",
|
||||
"book_failed": "Could not post",
|
||||
"commit_failed_title": "Draft created but not posted"
|
||||
},
|
||||
"tx_form": {
|
||||
"date_required": "Date is required",
|
||||
@@ -5325,6 +5345,25 @@
|
||||
"batch_select_all": "Select all ({count})",
|
||||
"batch_clear": "Clear selection",
|
||||
"batch_progress": "Booking {done} of {total}…",
|
||||
"batch_skv_book": "Post selected ({count})",
|
||||
"skv_booked_title": "Posted",
|
||||
"skv_booked_description": "Voucher {voucher} was created.",
|
||||
"skv_booked_show": "Show voucher",
|
||||
"skv_bulk_title": "Post {count, plural, one {1 tax account event} other {# tax account events}}",
|
||||
"skv_bulk_confirm": "Post",
|
||||
"skv_bulk_warning": "{count, plural, one {One voucher will be created and cannot be changed afterwards.} other {# vouchers will be created and cannot be changed afterwards.}}",
|
||||
"skv_bulk_group": "{count} × {label} → {account}",
|
||||
"skv_bulk_total": "Total {count, plural, one {1 event} other {# events}}",
|
||||
"skv_bulk_done_title": "Done",
|
||||
"skv_bulk_done_description": "{count, plural, one {1 tax account event posted} other {# tax account events posted}}",
|
||||
"skv_bulk_partial_title": "Partially done",
|
||||
"skv_bulk_partial_ok": "{count} posted",
|
||||
"skv_err_period_locked": "locked period",
|
||||
"skv_err_no_counter_account": "no counter account",
|
||||
"skv_err_already_booked": "already posted",
|
||||
"skv_err_not_settled": "not settled yet",
|
||||
"skv_err_commit_failed": "draft created, not posted",
|
||||
"skv_err_other": "failed",
|
||||
"mode_all": "All",
|
||||
"footer_to_handle": "{count, plural, =0 {Nothing to handle} =1 {1 to handle} other {# to handle}}"
|
||||
},
|
||||
@@ -6902,6 +6941,9 @@
|
||||
"action_match": "Match",
|
||||
"action_book": "Book",
|
||||
"action_booking": "Booking…",
|
||||
"booked_toast_title": "Posted",
|
||||
"booked_toast_description": "Voucher {voucher} was created.",
|
||||
"booked_toast_show": "Show voucher",
|
||||
"payment_title": "Payment details",
|
||||
"payment_description": "The charge on {date} is {charge}.",
|
||||
"payment_bankgiro_label": "Bankgiro (Skatteverket)",
|
||||
|
||||
+43
-1
@@ -3227,7 +3227,27 @@
|
||||
"link_to_voucher": "Koppla till verifikat",
|
||||
"book_anyway": "Bokför ändå",
|
||||
"book": "Bokför",
|
||||
"match_to_voucher": "Matcha mot verifikat"
|
||||
"match_to_voucher": "Matcha mot verifikat",
|
||||
"suggestion_line": "Bokförs mot {account}",
|
||||
"select_row": "Välj skattekontohändelse"
|
||||
},
|
||||
"skv_book_dialog": {
|
||||
"title": "Bokför skattekontohändelse",
|
||||
"event_label": "Händelse",
|
||||
"date_label": "Datum",
|
||||
"amount_label": "Belopp",
|
||||
"posting_label": "Kontering",
|
||||
"posting_value": "1630 mot {account}",
|
||||
"no_rule_matched": "Ingen bokföringsregel matchade händelsen. Matcha den mot ett befintligt verifikat, eller skapa verifikatet manuellt i Bokföring.",
|
||||
"confirm_book": "Bokför",
|
||||
"open_draft": "Öppna som utkast",
|
||||
"match_cta": "Matcha mot verifikat",
|
||||
"manual_create_cta": "Skapa verifikat manuellt",
|
||||
"commit_warning": "En verifikation skapas och kan inte ändras efteråt.",
|
||||
"draft_created_title": "Utkast skapat",
|
||||
"draft_created_description": "Granska och bokför verifikatet i Bokföring.",
|
||||
"book_failed": "Kunde inte bokföra",
|
||||
"commit_failed_title": "Utkast skapat men inte bokfört"
|
||||
},
|
||||
"tx_form": {
|
||||
"date_required": "Datum krävs",
|
||||
@@ -5325,6 +5345,25 @@
|
||||
"batch_select_all": "Markera alla ({count})",
|
||||
"batch_clear": "Avmarkera",
|
||||
"batch_progress": "Bokför {done} av {total}…",
|
||||
"batch_skv_book": "Bokför valda ({count})",
|
||||
"skv_booked_title": "Bokförd",
|
||||
"skv_booked_description": "Verifikat {voucher} skapades.",
|
||||
"skv_booked_show": "Visa verifikat",
|
||||
"skv_bulk_title": "Bokför {count, plural, one {1 skattekontohändelse} other {# skattekontohändelser}}",
|
||||
"skv_bulk_confirm": "Bokför",
|
||||
"skv_bulk_warning": "{count, plural, one {En verifikation skapas och kan inte ändras efteråt.} other {# verifikationer skapas och kan inte ändras efteråt.}}",
|
||||
"skv_bulk_group": "{count} × {label} → {account}",
|
||||
"skv_bulk_total": "Totalt {count, plural, one {1 händelse} other {# händelser}}",
|
||||
"skv_bulk_done_title": "Klart",
|
||||
"skv_bulk_done_description": "{count, plural, one {1 skattekontohändelse bokförd} other {# skattekontohändelser bokförda}}",
|
||||
"skv_bulk_partial_title": "Delvis klart",
|
||||
"skv_bulk_partial_ok": "{count} bokförda",
|
||||
"skv_err_period_locked": "låst period",
|
||||
"skv_err_no_counter_account": "saknar motkonto",
|
||||
"skv_err_already_booked": "redan bokförd",
|
||||
"skv_err_not_settled": "ännu inte genomförd",
|
||||
"skv_err_commit_failed": "utkast skapat, ej bokfört",
|
||||
"skv_err_other": "misslyckades",
|
||||
"mode_all": "Alla",
|
||||
"footer_to_handle": "{count, plural, =0 {Inget att hantera} =1 {1 att hantera} other {# att hantera}}"
|
||||
},
|
||||
@@ -6902,6 +6941,9 @@
|
||||
"action_match": "Matcha",
|
||||
"action_book": "Bokför",
|
||||
"action_booking": "Bokför…",
|
||||
"booked_toast_title": "Bokförd",
|
||||
"booked_toast_description": "Verifikat {voucher} skapades.",
|
||||
"booked_toast_show": "Visa verifikat",
|
||||
"payment_title": "Betalningsuppgifter",
|
||||
"payment_description": "Dragningen {date} är {charge}.",
|
||||
"payment_bankgiro_label": "Bankgiro (Skatteverket)",
|
||||
|
||||
Reference in New Issue
Block a user