feat(bokslut): IL 18 kap pooled tax depreciation with method election (#1393)

* feat(bokslut): IL 18 kap pooled tax depreciation with method election

Rakenskapsenlig (huvudregel 30 / kompletteringsregel 20) and restvarde 25
as a company-level annual pool separate from per-asset book depreciation.
Method election persisted with immutable snapshots and book-conformity
confirmation for rakenskapsenlig.

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

* chore(db): move tax depreciation migrations to coordinated versions

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

* fix(bokslut): keep tax depreciation view loadable when a saved election goes stale

A predecessor's changed closing value can push a saved elected deduction
above the new statutory maximum; the view now falls back to the statutory
recomputation so the snapshot is flagged stale instead of crashing.
Ratchet naive-ore-round baseline down by 3.

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

* fix(bokslut): resolve tax-depreciation period selects statically

The no-phantom-columns guard counts every select it cannot resolve
toward a hard ceiling, and the PERIOD_COLUMNS join pushed the repo
4 over (364 > 360). Inline the literal column list at the four call
sites so the guard verifies these columns instead of skipping them.

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

* fix(bokslut): address review findings on tax depreciation election

- DepreciationPanel: gate the saving flag on a dedicated save sequence
  so a successful save (which refreshes the view and bumps the request
  version) no longer leaves the card permanently busy
- computeTaxDepreciation: refuse kompletteringsregel_20 with a positive
  basis and no acquisition cohorts instead of degenerating to a full
  write-off the cohort evidence does not support (IL 18 kap. 17 §)
- migration 227000: judge the asset-method guards on NEW.disposed_at so
  reversing a disposal cannot reactivate a grandfathered non-linear row
- migration 227200: require snapshot column completeness in the CHECK;
  SQL NULL semantics let partially populated snapshots pass the pure
  arithmetic comparisons
- depreciation route: use the string issue code 'custom' like the rest
  of the codebase instead of the Zod 3 compat enum

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-08-04 11:43:58 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 00ae3540db
commit 5ca64bde30
25 changed files with 2863 additions and 657 deletions
+12 -2
View File
@@ -1623,6 +1623,13 @@ export interface FiscalPeriod {
closing_entry_id: string | null
opening_balance_entry_id: string | null
previous_period_id: string | null
tax_depreciation_method?: 'rakenskapsenlig' | 'restvarde' | null
tax_depreciation_rule?: 'huvudregel_30' | 'kompletteringsregel_20' | null
tax_depreciation_opening_value?: number | null
tax_depreciation_base?: number | null
tax_depreciation_deduction?: number | null
tax_depreciation_closing_value?: number | null
tax_depreciation_calculation?: Record<string, unknown> | null
created_at: string
updated_at: string
}
@@ -3334,12 +3341,15 @@ export type AssetCategory =
| 'computer'
| 'other_tangible'
/** Read type includes historical per-asset tax-method values retained on
* disposed rows. New and active assets may only be written as linear. */
export type DepreciationMethod =
| 'linear'
| 'declining_balance_30'
| 'declining_balance_20'
| 'restvardesavskrivning_25'
export type WritableDepreciationMethod = 'linear'
export type AssetDisposalType = 'sale' | 'scrap' | 'business_transfer'
export type AssetJamkningDirection = 'increase' | 'decrease' | 'none' | 'transferred'
@@ -3382,8 +3392,8 @@ export interface Asset {
bas_asset_account: string
bas_accumulated_account: string
bas_expense_account: string
/** Book-value floor for restvärdeavskrivning (IL 18 kap 13§ st.3). Required
* iff depreciation_method = 'restvardesavskrivning_25'; null otherwise. */
/** Deprecated legacy field. New tax depreciation is pooled per fiscal
* period and ordinary per-asset depreciation is linear. */
restvarde_target: number | null
disposed_at: string | null
disposed_proceeds: number | null