feat(assets): atomic asset disposal workflow (avyttring, utrangering, verksamhetsoverlatelse) (#1391)
* feat(assets): atomic asset disposal workflow (avyttring, utrangering, verksamhetsoverlatelse) Disposal books depreciation to the disposal date, clears cost and accumulated depreciation, books gain (3973) or loss (7973), applies output VAT on third-party sales, honors the ML 5 kap. 38 § verksamhetsoverlatelse exemption, and recalculates ML 15 kap. jamkning server-side from tax years and original input VAT. The voucher, the disposal-date depreciation schedule and the immutable register state commit in one dedicated commit_asset_disposal RPC transaction that delegates voucher numbering to commit_journal_entry. Fixes #325 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(assets): harden disposal per review and pg-real findings - commit_asset_disposal now uses the NULL-safe caller_is_company_member() guard (tenant-guard ratchet) and passes the allowed 'user_accept' commit_method instead of the unlisted 'asset_disposal' value - disposal metadata invariants validated in the RPC (non-negative proceeds/VAT, VAT requires a treatment, VAT <= gross, scrap carries no proceeds) since the RPC is independently callable - new FK and CHECK constraints added NOT VALID + VALIDATE CONSTRAINT so the migration never blocks writes on the hot journal_entries table - disposeAsset paginates fiscal periods and depreciation schedules with fetchAllRows; jamkning_remaining_years keeps a valid 0 (?? not ||) - engine imports shared AssetDisposalType/AssetJamkningDirection/ VatTreatment unions; post-commit reload retries once and logs before surfacing, so a transient read cannot masquerade as a failed disposal - dispose page parses Swedish-formatted amounts (125 000,50) and blocks submission on unparseable proceeds - assets pg tests write disposal attributes in the disposal transition itself and gain a regression test that the register is frozen after Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
1c9d378df8
commit
cb3ef45f14
+56
-1
@@ -836,7 +836,62 @@
|
||||
"category_vehicle": "Vehicle",
|
||||
"category_computer": "Computer",
|
||||
"category_other_tangible": "Other tangible",
|
||||
"count_footer": "{count, plural, one {1 asset} other {# assets}}"
|
||||
"count_footer": "{count, plural, one {1 asset} other {# assets}}",
|
||||
"disposal": {
|
||||
"title": "Dispose of asset",
|
||||
"load_failed_title": "Could not load the disposal",
|
||||
"try_again": "Please try again.",
|
||||
"submit_failed_title": "Disposal failed",
|
||||
"success_title": "Asset disposed",
|
||||
"success_description": "Depreciation, disposal, and the asset register were posted together.",
|
||||
"not_found": "The asset could not be found.",
|
||||
"already_disposed": "The asset was already disposed ({date}).",
|
||||
"back": "Back",
|
||||
"acquisition_cost": "Acquisition cost",
|
||||
"acquired": "Acquired",
|
||||
"bas_accounts": "Accounts (BAS)",
|
||||
"details_title": "Disposal details",
|
||||
"type_label": "Event",
|
||||
"type_sale": "Sale",
|
||||
"type_scrap": "Scrapping",
|
||||
"type_business_transfer": "Transfer of a business",
|
||||
"date_label": "Disposal date",
|
||||
"period_label": "Fiscal period",
|
||||
"period_placeholder": "Select period",
|
||||
"locked": "locked",
|
||||
"period_locked": "The selected period is locked or closed. Select an open period.",
|
||||
"proceeds_label": "Amount received including VAT",
|
||||
"consideration_label": "Consideration for the asset",
|
||||
"proceeds_account_label": "Receiving account",
|
||||
"vat_title": "VAT on the sale",
|
||||
"vat_treatment_label": "VAT treatment",
|
||||
"vat_standard_25": "Swedish VAT 25%",
|
||||
"vat_reverse_charge": "Reverse charge",
|
||||
"vat_export": "Export outside the EU",
|
||||
"vat_exempt": "VAT-exempt sale",
|
||||
"gross": "Gross",
|
||||
"vat": "Output VAT",
|
||||
"net": "Net",
|
||||
"adjustment_title": "Input VAT adjustment (ML chapter 15)",
|
||||
"within_adjustment_period": "Within the adjustment period: {years} years remain of {total}",
|
||||
"outside_adjustment_period": "Outside the adjustment period",
|
||||
"original_vat_label": "Total original input VAT",
|
||||
"original_vat_hint": "Enter the full VAT amount, not only the deducted part. Threshold: SEK {threshold}.",
|
||||
"original_percent_label": "Original deduction right (%)",
|
||||
"adjustment_direction": "Direction",
|
||||
"adjustment_amount": "Calculated adjustment",
|
||||
"direction_increase": "Increased deduction",
|
||||
"direction_decrease": "Decreased deduction",
|
||||
"direction_none": "No adjustment",
|
||||
"direction_transferred": "Transferred to the acquirer",
|
||||
"adjustment_capped": "The amount was capped at 25% of the sale price excluding VAT.",
|
||||
"business_transfer_confirm": "I confirm that the transfer covers an entire business or independent branch and meets the conditions in ML chapter 5, section 38.",
|
||||
"adjustment_document_confirm": "I confirm that an adjustment document is prepared for the acquirer.",
|
||||
"adjustment_data_required": "VAT basis data is required because the asset may be an investment good.",
|
||||
"cancel": "Cancel",
|
||||
"submit": "Post disposal",
|
||||
"write_required": "Only users with write access can dispose of assets."
|
||||
}
|
||||
},
|
||||
"employees": {
|
||||
"title": "Employees",
|
||||
|
||||
+56
-1
@@ -836,7 +836,62 @@
|
||||
"category_vehicle": "Fordon",
|
||||
"category_computer": "Dator",
|
||||
"category_other_tangible": "Övriga materiella",
|
||||
"count_footer": "{count, plural, one {1 tillgång} other {# tillgångar}}"
|
||||
"count_footer": "{count, plural, one {1 tillgång} other {# tillgångar}}",
|
||||
"disposal": {
|
||||
"title": "Avyttra tillgång",
|
||||
"load_failed_title": "Kunde inte ladda avyttringen",
|
||||
"try_again": "Försök igen.",
|
||||
"submit_failed_title": "Avyttringen misslyckades",
|
||||
"success_title": "Tillgången är avyttrad",
|
||||
"success_description": "Avskrivning, avyttring och tillgångsregister har bokförts tillsammans.",
|
||||
"not_found": "Tillgången kunde inte hittas.",
|
||||
"already_disposed": "Tillgången är redan avyttrad ({date}).",
|
||||
"back": "Tillbaka",
|
||||
"acquisition_cost": "Anskaffningsvärde",
|
||||
"acquired": "Anskaffad",
|
||||
"bas_accounts": "Konton (BAS)",
|
||||
"details_title": "Avyttringsuppgifter",
|
||||
"type_label": "Händelse",
|
||||
"type_sale": "Försäljning",
|
||||
"type_scrap": "Utrangering",
|
||||
"type_business_transfer": "Verksamhetsöverlåtelse",
|
||||
"date_label": "Avyttringsdatum",
|
||||
"period_label": "Räkenskapsperiod",
|
||||
"period_placeholder": "Välj period",
|
||||
"locked": "låst",
|
||||
"period_locked": "Vald period är låst eller stängd. Välj en öppen period.",
|
||||
"proceeds_label": "Erhållet belopp inklusive moms",
|
||||
"consideration_label": "Ersättning för tillgången",
|
||||
"proceeds_account_label": "Mottagarkonto",
|
||||
"vat_title": "Moms vid försäljning",
|
||||
"vat_treatment_label": "Momsbehandling",
|
||||
"vat_standard_25": "Svensk moms 25 %",
|
||||
"vat_reverse_charge": "Omvänd betalningsskyldighet",
|
||||
"vat_export": "Export utanför EU",
|
||||
"vat_exempt": "Momsfri försäljning",
|
||||
"gross": "Brutto",
|
||||
"vat": "Utgående moms",
|
||||
"net": "Netto",
|
||||
"adjustment_title": "Justering av ingående moms (ML 15 kap.)",
|
||||
"within_adjustment_period": "Inom justeringsperioden: {years} år kvar av {total}",
|
||||
"outside_adjustment_period": "Utanför justeringsperioden",
|
||||
"original_vat_label": "Total ursprunglig ingående moms",
|
||||
"original_vat_hint": "Ange hela momsbeloppet, inte bara avdragen del. Tröskel: {threshold} kr.",
|
||||
"original_percent_label": "Ursprunglig avdragsrätt (%)",
|
||||
"adjustment_direction": "Riktning",
|
||||
"adjustment_amount": "Beräknad justering",
|
||||
"direction_increase": "Ökat avdrag",
|
||||
"direction_decrease": "Minskat avdrag",
|
||||
"direction_none": "Ingen justering",
|
||||
"direction_transferred": "Överförs till förvärvaren",
|
||||
"adjustment_capped": "Beloppet har begränsats till 25 % av försäljningspriset exklusive moms.",
|
||||
"business_transfer_confirm": "Jag bekräftar att överlåtelsen omfattar en hel verksamhet eller självständig verksamhetsgren och uppfyller villkoren i ML 5 kap. 38 §.",
|
||||
"adjustment_document_confirm": "Jag bekräftar att en justeringshandling upprättas för förvärvaren.",
|
||||
"adjustment_data_required": "Momsunderlaget krävs eftersom tillgången kan vara en investeringsvara.",
|
||||
"cancel": "Avbryt",
|
||||
"submit": "Bokför avyttring",
|
||||
"write_required": "Endast användare med skrivrättigheter kan avyttra tillgångar."
|
||||
}
|
||||
},
|
||||
"employees": {
|
||||
"title": "Anställda",
|
||||
|
||||
Reference in New Issue
Block a user