Skip to content

Depreciation Completeness — reverse runs, reject dead methods, retire DRAFT

Date: 2026-06-27 Status: shipped Audit findings: #24, #25, #26 — depreciation run statuses and the units-of-production method were decorative or unreachable.

Problem / motivation

Three depreciation gaps:

  • #24 DepreciationRunStatus.REVERSED was never produced — there was no way to reverse a posted depreciation run.
  • #25 DepreciationMethod.UNITS_OF_PRODUCTION always computed 0, so an asset registered with it silently never depreciated.
  • #26 DepreciationRunStatus.DRAFT was vestigial — a zero-depreciation run was left as a misleading DRAFT that no calculation could see.

What shipped

  • Reverse a depreciation run (#24): new reverseDepreciationRun mutation → FixedAssetService.reverse_run. It reverses the run's GL entry (undoing the expense and accumulated depreciation), marks the run REVERSED, and returns any asset it had fully depreciated to ACTIVE. Because net book value and accumulated depreciation only count POSTED runs, the asset's book value is restored automatically. Reversing a non-posted run is rejected.
  • Reject units-of-production at registration (#25): register now raises a clear ValidationError for UNITS_OF_PRODUCTION instead of booking an asset that would never depreciate. (Implementing it needs per-period usage data the system doesn't capture — see Future additions.)
  • No more vestigial DRAFT (#26): run_period now always marks the run POSTED — even an empty period (no depreciable assets) — so the period is closed and the duplicate-run guard (audit #27) covers it.
  • Consistency fix: _accumulated_depreciation (used by disposal) now counts only POSTED runs, matching net-book-value, so a reversed run is fully undone for disposal too.

Files

GraphQL surface

  • New mutation reverseDepreciationRun(runId: UUID!): DepreciationRun — additive, gated by the existing FIXED_ASSETS permission.

Frontend impact

  • A new "reverse depreciation run" action is available. Registering an asset with the units-of-production method now returns a validation error (previously it succeeded but the asset never depreciated).

Future additions

  • Units-of-production depreciation: implement it once per-period usage/output is captured (a usage table + a per-period usage input on the run), then drop the registration guard.
  • Reversed-run book value across multiple runs: reverse_run re-activates a fully-depreciated asset whenever it had a line in the reversed run; a multi-run asset that is still fully depreciated by other runs would be a rare edge case to refine.