diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/DECISIONS.md | 16 | ||||
| -rw-r--r-- | docs/PAYROLL.md | 19 | ||||
| -rw-r--r-- | docs/PROTOCOL.md | 43 | ||||
| -rw-r--r-- | docs/STATE.md | 79 | ||||
| -rw-r--r-- | docs/TUI-GUIDELINES.md | 3 |
5 files changed, 133 insertions, 27 deletions
diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index b84e7fa..a108f48 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -186,6 +186,22 @@ kept verbatim from the STATE.md they were pruned from (2026-09-21). rules, attachments, bank, audit, templates, ib, bokslut, settings, invoices). Pure move: no key, string or scene-name changes; the registry keeps every name including the `yearinfo` alias. +24. **Payroll (2026-09-21)**: `docs/PAYROLL.md` is the chapter. Schema v10 + (v11 adds `employees.email`): `employees` with the personnummer encrypted + at rest (`secret_encrypt`, masked in every response; only `payroll.agi` + returns it in clear), `payroll_runs`/`payroll_run_lines`, and national + `tax_tables`/`tax_table_meta` without `org_id` (the one exception to the + tenant rule). Monthly runs post D salary (7210 default; 7010 for + kollektivanställda) / D 7510 / K 2710 / K 1930 / K 2731 with + `source:"payroll"`; `payroll.pay_tax` does D 2710 + D 2731 / K 1630. + Tax tables are fetched from Skatteverket's public fixed-width + `allmanna-tabeller-manad.txt` (one button, stale-year warning) and + over-80k % records are stored but refused until the rule is settled. + Lönebesked PDF + mail (wave 2). **User decisions**: only the owner is + employed now but everything is multi-employee; no semester accrual; + tax tables from day one; manual step-buttons (Bokför, Lönebesked, + AGI-underlag, Betala skatt & avgifter); bank phase 3 (`bank_rule.*`) is + dropped. ## Completed work formerly listed under "Pending decisions" diff --git a/docs/PAYROLL.md b/docs/PAYROLL.md index b821754..23e7fb1 100644 --- a/docs/PAYROLL.md +++ b/docs/PAYROLL.md @@ -5,7 +5,7 @@ Status: Design draft · 2026-09-21 · License: GPL-3.0-or-later Payroll for a small Swedish AB that runs monthly salaries from the books. Wave 1 is the engine and the mandatory steps; the employee is the owner but the schema and commands are multi-employee from the start. Wave 2 (the -lönebesked PDF and its delivery) is done; wave 3 is the TUI. +lönebesked PDF and its delivery) and wave 3 (the TUI) are done. ## 1. Scope @@ -227,12 +227,19 @@ the base is the gross. SMTP configuration `SMTP_NOT_CONFIGURED` and a failed delivery `SMTP_FAILED` (the stored attachment stays linked). `dry_run` validates, renders and stores nothing. See `PROTOCOL.md` §7.12. -- **TUI — Lön** (new section after Fakturering): `Lönekörningar` (list, - Ctrl+N for a new run), `Anställda` under Register, and a **Skattetabeller** - action/status that fetches and warns. +- **TUI — Lön** (done, `clients/screens_payroll.c`): `Lönekörningar` (list, + Ctrl+N for a new run) under Lön, `Anställda` under Företag, and a + **Skattetabeller** screen (System, since the tables are national) with + status, the Skatteverket fetch and the offline file import. - The run screen shows the preview (F5), posts with Ctrl+Enter after - confirmation, then offers the buttons **Lönebesked**, **AGI-underlag** and - **Betala skatt & avgifter** as manual steps. + confirmation, then offers the buttons **Lönebesked** (saves/opens the + PDF), **AGI-underlag** (`payroll.agi` in a pager, owner only) and + **Betala skatt & avgifter** (`payroll.pay_tax` with a date prompt) as + manual steps. Steps that do not apply yet are dimmed with the reason. + Posting and paying show the resulting voucher as `V-<n>`. +- The list title warns when the current year's tax tables are missing; a + new run is refused with a pointer to Anställda when nobody has a monthly + salary. ## 7. Testing diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md index ebce8bf..01f5dd1 100644 --- a/docs/PROTOCOL.md +++ b/docs/PROTOCOL.md @@ -925,6 +925,26 @@ commands. Implemented screens (0.1.0-dev): number, e-mail, your reference, payment days, notes). Ctrl+N creates, Enter edits (F5 validates with a dry run, Ctrl+Enter saves), `d` archives/reactivates. +- **Lönekörningar** — the monthly payroll runs (`payroll.run_list`, newest + period first) with status (`bokförd`/`betald`), gross and net. Ctrl+N + starts a new run (period YYYY-MM and pay date, defaulting into the + selected fiscal year) when an active employee with a monthly salary + exists, Enter opens an existing run. The run screen shows the status and + totals, `F5` previews (`payroll.run_preview` for a new run, the stored + lines for a posted one), `Ctrl+Enter` posts after confirmation + (`payroll.run_post`, showing the voucher), and the manual steps are the + action rows **Lönebesked** (PDF via `payroll.payslip`), **AGI-underlag** + (`payroll.agi`, owner only) and **Betala skatt & avgifter** + (`payroll.pay_tax`); a disabled step names its reason. The list title + warns when the current year's tax tables are missing. +- **Anställda** — the employee register (name, masked personnummer, salary, + tax table/column, e-mail). Ctrl+N creates, Enter edits (an empty + personnummer keeps the stored one), `d` archives/reactivates; F5 + validates with a dry run and Ctrl+Enter saves. +- **Skattetabeller** (System) — stored tax table years, the current year's + status, fetch time and source. Owners fetch Skatteverket's official + monthly table (`payroll.tax_tables_fetch`) or import a file offline + (`payroll.tax_tables_import`). - **Rapporter** — saldobalans, resultaträkning, balansräkning, moms, inkomstdeklaration (INK2/SRU), årsredovisning (K2 text draft) and kontolista (all accounts with type, moms treatment, SRU and status). @@ -939,18 +959,23 @@ commands. Implemented screens (0.1.0-dev): events, AGM and payment dates, proposed dividend, employees, other notes), edited per field; a new fiscal year inherits the stable fields. The årsredovisning draft reads them without prompting. -- **Företagsuppgifter** — the org record (name, org number, VAT number, - address, e-mail, phone, moms period, framework, fiscal-year start month), - plus the invoice bankgiro and "vår referens"; editable in place, only - owners can save, others see it read-only. The accounting accounts and the - SMTP transport live in **Inställningar**. -- **Revision** — chain verification and behandlingshistorik. +- **Bolaget** — the org record (name, org number, VAT number, address, + e-mail, phone, moms period, framework, fiscal-year start month), editable + in place by owners; others see it read-only. The sub-forms + **Fakturauppgifter…** (standardserie, fordringskonto, intäktskonto, + bankgiro, vår referens) and **E-post (SMTP)…** (host, port, user, sender, + reply-to, security, password) are `settings.set` and open to bookkeepers, + and **Styrelseledamöter** lists the board. +- **Systeminställningar** (System) — bilagornas mapp, the file browser's + start directory. +- **Revision** (System) — chain verification and behandlingshistorik. **Ctrl+N is the universal "add" key**: it starts a new verifikat from the dashboard, the voucher list and the voucher detail view; a new mall from the -Mallar menu; a new fiscal year from the year picker; and maps to the editor -in Ingående balans and to file upload in Underlag. F5 is the universal -refresh. Hints show the keys per screen. +Mallar menu; a new customer or employee from their registers; a new payroll +run from Lönekörningar; a new fiscal year from the year picker; and maps to +the editor in Ingående balans and to file upload in Underlag. F5 is the +universal refresh. Hints show the keys per screen. **Ctrl+R reloads the client in place** (for hot-reloading after a rebuild): it re-execs the installed binary with `--org`, `--fy` and `--screen NAME` diff --git a/docs/STATE.md b/docs/STATE.md index b7ed645..bd38963 100644 --- a/docs/STATE.md +++ b/docs/STATE.md @@ -6,10 +6,40 @@ Read with `AGENTS.md` (rules) and `docs/TUI-GUIDELINES.md` (UI conventions). ## Status Working self-hosted bookkeeping system, not production-proven. Backend ledger -core is complete; filing/year-end/payroll are not. TUI is usable and exercised -by `make test-pty` (golden screen-text scenarios); `make test` covers the -server/protocol/ledger, the TUI widget unit tests and the docs consistency -check. +core is complete, as are invoicing, the payroll engine and the payroll TUI; +filing/year-end work remains. TUI is usable and exercised by `make test-pty` +(golden screen-text scenarios, now including the payroll run and the +lönebesked); `make test` covers the server/protocol/ledger, the TUI widget +unit tests and the docs consistency check. + +## Resume here (2026-09-21) + +- **Deployed**: `v0.1.55`, healthy on `nas` (Alpine runtime, static aarch64 + binaries cross-compiled on this machine — ~20 s, the host only assembles + the image; image 33.7 MB, no `libssl3`). It brings the payroll server + waves (schema v11: employees, tax tables, lönebesked) and the payroll + TUI with the Företag/System menu; the live database migrated v9 → v11 on + startup with the automatic pre-migration snapshot in `var/db/backup/`. + `main` and the tag `v0.1.55` are pushed to `nas`. +- **Next tasks (payroll follow-ups)**: fold `payroll.settings_get/set` into + `settings.get/set` (cmd_settings.c was busy during wave 1); settle the + over-80k % rule (SKV 433 leaves it ambiguous — currently a clear + `INVALID_ARGS`); move `invoice.send` to the shared `src/mail.c`. The TUI + has no screen for the payroll account/rate settings yet (they are + defaults and can stay server-side until the fold). +- **Done in the TUI wave**: `clients/screens_payroll.c` with Lönekörningar + (list + Ctrl+N, run screen with F5 preview, Ctrl+Enter post after + confirmation and the action rows Lönebesked, AGI-underlag, Betala skatt & + avgifter), Anställda under Företag and the Skattetabeller + fetch/import/status screen under System. A pty scenario posts a run and + fetches its lönebesked, so the payslip PDF path is exercised end to end. +- **Menu (2026-09-21)**: the dashboard has the sections Bokföring (with + Mallar), Fakturering, Lön, Rapporter & bokslut, Företag (Anställda, + Kunder, Bolaget, Momsregler) and System (Skattetabeller, Revision, + Systeminställningar). Inställningar is gone: standardserie, + fordrings-/intäktskonto, bankgiro, vår referens and SMTP now live under + Bolaget (the Fakturauppgifter and E-post sub-forms) and bilagornas mapp + under System. `--screen settings` remains an alias for Bolaget. ## Open decisions @@ -27,25 +57,42 @@ None open. Completed items that used to be listed here are archived in 7. ~~Pre-migration `VACUUM INTO` snapshot~~ done. 8. ~~Docker image + compose~~ done (no registry, no systemd unit). 9. Password change, user disable, TOTP. -10. ~~Bank import/reconciliation (CSV first)~~ phase 1 done (SEB CSV + - matching, schema v8). Next: phase 2 prefill-from-transaction and - `bank_rule.*`, then PSD2; invoicing/reskontra and AGI/payroll if - employees. +10. ~~Bank import/reconciliation (CSV first)~~ phase 1 (SEB CSV + matching, + schema v8) and phase 2 (Ctrl+N prefills the voucher and auto-matches it, + `9b1021e`) done. Phase 3 (`bank_rule.*`) **dropped by the user + 2026-09-21**; PSD2 only if it ever hurts. 11a. Imported history years with source P&L closings: decided, no importer change (see DECISIONS.md). 11. ~~SIE import only into an empty fiscal year~~ chronological multi-year import works; each year must still target an empty fiscal year. 12. TUI polish: horizontal scrolling in long text fields, bracketed paste. +13. ~~Payroll TUI (wave 3)~~ done (`clients/screens_payroll.c`); the + remaining payroll follow-ups are listed under "Resume here". No + employee is registered yet in the real orgs. +14. Invoice follow-ups when needed: credit notes (`invoice.credit`), per-row + account in the invoice form, kundreskontra view. +15. `make test-pty` speed if it ever exceeds ~60 s: parallelise the + independent scenarios (each has its own rig) and add `--only` symmetry; + measure first. +16. Test fixtures (`t_fresh_org()`) + one test file per domain + (`tests/core_<domain>.c`) so `--only` stops cascading; pilot with one + domain. Original entries for the struck items are in `docs/DECISIONS.md`. ## Environment / how to run -- **Deployed**: `scripts/deploy.sh` (latest `v0.1.48`, healthy on nas). +- **Deployed**: `scripts/deploy.sh` (latest `v0.1.55`, healthy on nas). Live daemon `tls:bokf.makandra.eu:8788`, token `~/.config/bokf/migration-token` (scopes `read,write`; owner-only actions like closing years must be done by the human in the TUI). Git remote `origin` is `nas:/mnt/data/git-repos/bokf.git` (push `main` and tags). + `sh scripts/install-hooks.sh` once per checkout points `core.hooksPath` at + `.githooks/`, so every push runs `make gate` (clean `-Werror` build in + `build-gate/`, the suite and ASan); it is installed here. + `deploy/Dockerfile.cross` + `deploy/cross-build.sh` produce static aarch64 + `bokfd`/`bokfctl` in ~20 s when the host architecture differs; the image is + assembled on the host from `.prebuilt` (see docs/DEPLOY.md). - **Local test rig** (transient, `/tmp`): daemon `./build/bokfd --db /tmp/opencode/bokf-local/t.db --socket /tmp/opencode/bokf-local/sock`, org 1, login `admin`/`testpass123`. @@ -91,10 +138,11 @@ Original entries for the struck items are in `docs/DECISIONS.md`. - Never commit unless the human asks. - SQLite files must not be backed up live with restic; use `backup.snapshot` (`VACUUM INTO`) and point restic at the snapshots. -- Schema version is 9 (v3 moms rules; v4/v6 year info; v5 org +- Schema version is 11 (v3 moms rules; v4/v6 year info; v5 org description/shares + board members; v7 attachments append-only triggers; v8 bank reconciliation; v9 invoicing + widened `vouchers.source` with a - table rebuild); forward migrations are in `db.c`. + table rebuild; v10 payroll + `payroll`/`payroll_tax` sources, same + rebuild; v11 `employees.email`); forward migrations are in `db.c`. ## Makandra driftstatus (org 2) @@ -122,3 +170,12 @@ Original entries for the struck items are in `docs/DECISIONS.md`. över "Stäng"-verifikat i flerårsöversikten); utdelning bokförs vid stämman med mallen **Utdelning** (D 2099/K 2898); pappersoriginal finns i fysisk pärm (får refereras i efterhand, även i stängda år). +- **Lön (2026-09-21)**: bara ägaren är anställd, men schema och kommandon är + fleranvändarklara. Lönemotorn (schema v11: anställda, skattetabeller, + lönekörningar, lönebesked + mejl) och TUI-sektionen Lön är klara, men + **ingen anställd är registrerad än** (personnummer, lön, skattetabell och + kolumn fylls i under Register → Anställda). Konton enligt historiken: + 7210/7510/2710/2731/1630. Skattetabellerna hämtas med en knapp från + Skatteverket (varning när året är gammalt), personnumret är krypterat i + databasen. Ingen semesteruppbokning; arbetsgivardeklarationen (AGI) görs + manuellt med underlaget från `payroll.agi`. diff --git a/docs/TUI-GUIDELINES.md b/docs/TUI-GUIDELINES.md index 46982ed..7e0d404 100644 --- a/docs/TUI-GUIDELINES.md +++ b/docs/TUI-GUIDELINES.md @@ -43,7 +43,8 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width. - Rows are numbered `NN. text`, right-aligned so 2- and 3-digit numbers line up. - Verifikation ids are shown concatenated as `series+number` (`V-8`, `A8`), - using the org's `default_series` (Inställningar) for new vouchers. + using the org's `default_series` (Bolaget → Fakturauppgifter) for new + vouchers. - The last row may be an action (e.g. `+ Nytt verifikat (Ctrl+N)`); selecting it runs the action instead of opening a detail view. - Selection memory: lists remember the selected row by identity (voucher id), |
