Fix/m sprint fixes (#613)
* fix(dashboard): exclude ignored and already-triaged transactions from stale count The "Gamla transaktioner" widget counted transactions that had been ignored or already marked as is_business=true but not yet booked, so users saw a nag for a row they had already dealt with — and the /transactions inbox correctly hid it. Align the count with the inbox criterion (is_business IS NULL, is_ignored = false) so the widget clears when the row leaves the inbox. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(transactions): read entity_type from settings response wrapper The transactions page read entityRes.entity_type directly, but /api/settings returns { data: { entity_type, ... } }. The expression was always undefined, so setEntityType never fired and entityType stayed at its initial 'enskild_firma'. The template picker's entity_type filter then dropped every aktiebolag-tagged user template for AB customers — only entity_type='all' templates made it through. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * stale templates bank sync journal entry from transaction * fixed pr comments * fixed pr comment --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
fc7a46c3f2
commit
ea1bf01f1e
@@ -0,0 +1,87 @@
|
||||
import type { JournalEntryLine } from '@/types'
|
||||
|
||||
export interface CorrectionLineInput {
|
||||
account_number: string
|
||||
debit_amount: string | number
|
||||
credit_amount: string | number
|
||||
}
|
||||
|
||||
export interface AccountRow {
|
||||
account_number: string
|
||||
original: number
|
||||
storno: number
|
||||
correction: number
|
||||
delta: number
|
||||
}
|
||||
|
||||
function toNumber(v: string | number | null | undefined): number {
|
||||
if (v == null) return 0
|
||||
const n = typeof v === 'string' ? parseFloat(v) : v
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
|
||||
function round2(n: number): number {
|
||||
return Math.round(n * 100) / 100
|
||||
}
|
||||
|
||||
/**
|
||||
* Build per-account diff rows: original net, storno (= −original), proposed
|
||||
* correction net, and förändring (= storno + correction = correction − original).
|
||||
*
|
||||
* Net per row is debit − credit. Accounts appearing only on one side still get
|
||||
* a row, so the user sees account swaps clearly (old account drains to zero,
|
||||
* new account picks up the value).
|
||||
*
|
||||
* Corrected lines with account_number.length !== 4 are skipped — those are
|
||||
* incomplete user input mid-edit, not real proposals.
|
||||
*/
|
||||
export function buildCorrectionRows(
|
||||
original: JournalEntryLine[],
|
||||
corrected: CorrectionLineInput[]
|
||||
): AccountRow[] {
|
||||
const map = new Map<string, AccountRow>()
|
||||
|
||||
const ensure = (acc: string): AccountRow => {
|
||||
let row = map.get(acc)
|
||||
if (!row) {
|
||||
row = { account_number: acc, original: 0, storno: 0, correction: 0, delta: 0 }
|
||||
map.set(acc, row)
|
||||
}
|
||||
return row
|
||||
}
|
||||
|
||||
for (const line of original) {
|
||||
if (!line.account_number) continue
|
||||
const net = toNumber(line.debit_amount) - toNumber(line.credit_amount)
|
||||
const row = ensure(line.account_number)
|
||||
row.original += net
|
||||
row.storno -= net
|
||||
}
|
||||
|
||||
for (const line of corrected) {
|
||||
if (!line.account_number || line.account_number.length !== 4) continue
|
||||
const net = toNumber(line.debit_amount) - toNumber(line.credit_amount)
|
||||
const row = ensure(line.account_number)
|
||||
row.correction += net
|
||||
}
|
||||
|
||||
for (const row of map.values()) {
|
||||
row.original = round2(row.original)
|
||||
row.storno = round2(row.storno)
|
||||
row.correction = round2(row.correction)
|
||||
row.delta = round2(row.storno + row.correction)
|
||||
}
|
||||
|
||||
return Array.from(map.values()).sort((a, b) =>
|
||||
a.account_number.localeCompare(b.account_number)
|
||||
)
|
||||
}
|
||||
|
||||
export function formatSignedAmount(n: number): string {
|
||||
if (n === 0) return '–'
|
||||
const abs = Math.abs(n).toLocaleString('sv-SE', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})
|
||||
return n > 0 ? `+${abs}` : `−${abs}`
|
||||
}
|
||||
Reference in New Issue
Block a user