fix(articles): article ROT/RUT prefill was dead for every dashboard-created article (#1651)

* fix(articles): article ROT/RUT prefill was dead for every dashboard-created article

Follow-up to #1634. The user re-tested and picking a RUT article still left
the line on "Ingen": the article form has always stored the bare kind
('ROT'/'RUT'), while the prefill only recognised Skatteverket work-type codes
(BYGG, STAD, ...). On prod every dashboard-created ROT/RUT article holds the
bare kind, so the fix in #1634 never fired for a real user, and worse, since
the helper returned null for those values, picking such an article CLEARED a
deduction the user had set manually on the row.

- rot-rut-rules: parseArticleHouseworkType() understands both vocabularies
  (code -> kind + arbetstyp; bare ROT/RUT -> kind only), plus
  normalizeHouseworkType()/HOUSEWORK_TYPE_VALUES/workTypeLabel().
- InvoiceEditor.applyArticle: kind-only articles pre-fill the deduction and
  keep a same-kind arbetstyp already chosen on the row; "Spara som artikel"
  round-trips the code or, lacking one, the kind.
- ArticleForm: the ROT/RUT select now offers the real Skatteverket arbetstyper
  in ROT/RUT groups (its own hint always promised "förifyller arbetstyp");
  legacy kind-only values stay selectable as "RUT (arbetstyp ej vald)" so an
  edit never silently drops the flag. Article detail renders "RUT · Städning"
  instead of the raw code.
- API + MCP commit schemas normalize housework_type (case-insensitive code or
  ROT/RUT, '' clears) and reject anything else; the CSV article import
  normalizes the column the same way. Prod holds 178 articles with '0'/'1'
  from a boolean "Rot" column that the keyword detector mapped straight
  through; those now read as no flag everywhere and can no longer be created.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(articles): review follow-ups on #1651

- InvoiceEditor: switching a row's skattereduktion ROT<->RUT clears an
  arbetstyp from the other list, and Spara som artikel only round-trips a
  work type that belongs to the row's kind (CodeRabbit).
- MCP update_article: null / '' / whitespace now clear housework_type
  (commit drops only undefined keys, so the old undefined mapping made the
  flag un-clearable); create keeps treating them as unset. Tests.
- Article CSV import warns when a non-empty ROT/RUT value is dropped as
  not-an-arbetstyp instead of dropping it silently. Test.
- Hint wording: arbetstyp is pre-filled only when the article carries one.

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:
Jakob Wennberg
2026-08-17 19:47:29 +02:00
committed by GitHub
co-authored by Claude Fable 5 Jakob Wennberg
parent 1cd33d9d97
commit 79240cb2ed
15 changed files with 359 additions and 25 deletions
+2 -2
View File
@@ -4812,7 +4812,7 @@ export const tools: McpTool[] = [
revenue_account: { type: 'string', description: 'Optional BAS class-3 revenue account (e.g. 3041). Omit to derive from VAT.' },
cost_price: { type: 'number', description: 'Optional cost price (margin only; never booked).' },
ean: { type: 'string', description: 'Barcode / EAN.' },
housework_type: { type: 'string', description: 'ROT/RUT arbetstyp (services only).' },
housework_type: { type: 'string', description: 'ROT/RUT flag for service articles: a Skatteverket arbetstypskod (ROT: BYGG, EL, GLAS_PLAT, MARK_DRAN, MURNING, MALNING, VVS; RUT: STAD, KLAD, SNOSKOTTNING, TRADGARD, BARNPASS, PERSONLIG_OMS, FLYTT, IT, REPARATION, MOBLERING, TILLSYN, TRANSPORT, TVATT) or the bare kind ROT / RUT. Picking the article on an invoice line pre-fills the skattereduktion (and the arbetstyp when a code is given). Any other value is rejected.' },
name_en: { type: 'string', description: 'English name for English-language invoices.' },
notes: { type: 'string' },
article_number: { type: 'string', description: 'Optional manual number; omit to auto-generate.' },
@@ -4886,7 +4886,7 @@ export const tools: McpTool[] = [
revenue_account: { type: 'string', description: 'BAS class-3 revenue account, or omit to leave unchanged.' },
cost_price: { type: 'number' },
ean: { type: 'string' },
housework_type: { type: 'string' },
housework_type: { type: 'string', description: 'Skatteverket arbetstypskod (e.g. BYGG, STAD) or bare ROT / RUT; empty string clears. See gnubok_create_article.' },
name_en: { type: 'string' },
notes: { type: 'string' },
active: { type: 'boolean', description: 'Set false to deactivate (hide from pickers, keep history).' },