Fix monthly actuals: allow negative values and fix save/reconcile error

- Remove min={0} from NumberInput to allow negative actuals (refunds/corrections)
- Fix post() in journal-entries service: use id param directly instead of
  RETURNING result which returns [rows, count] in TypeORM QueryRunner
- Handle negative amounts in saveActuals(): negative expense credits the
  expense account, negative income debits the income account

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 15:51:33 -05:00
parent 84822474f8
commit 32af961173
3 changed files with 23 additions and 20 deletions

View File

@@ -140,11 +140,11 @@ export class JournalEntriesService {
); );
} }
const result = await this.tenant.query( await this.tenant.query(
`UPDATE journal_entries SET is_posted = true, posted_by = $1, posted_at = NOW() WHERE id = $2 RETURNING *`, `UPDATE journal_entries SET is_posted = true, posted_by = $1, posted_at = NOW() WHERE id = $2`,
[userId, id], [userId, id],
); );
return this.findOne(result[0].id); return this.findOne(id);
} }
async void(id: string, userId: string, reason: string) { async void(id: string, userId: string, reason: string) {

View File

@@ -127,25 +127,28 @@ export class MonthlyActualsService {
for (const line of filteredLines) { for (const line of filteredLines) {
const acctType = accountTypeMap.get(line.accountId); const acctType = accountTypeMap.get(line.accountId);
if (!acctType) continue; if (!acctType) continue;
const abs = Math.abs(line.amount);
if (acctType === 'expense') { if (acctType === 'expense') {
// Expense: debit expense account, credit cash if (line.amount > 0) {
jeLines.push({ // Normal expense: debit expense, credit cash
accountId: line.accountId, jeLines.push({ accountId: line.accountId, debit: abs, credit: 0, memo: `${monthLabel} actual` });
debit: Math.abs(line.amount), totalCashCredit += abs;
credit: 0, } else {
memo: `${monthLabel} actual`, // Negative expense (refund/correction): credit expense, debit cash
}); jeLines.push({ accountId: line.accountId, debit: 0, credit: abs, memo: `${monthLabel} actual (correction)` });
totalCashCredit += Math.abs(line.amount); totalCashDebit += abs;
}
} else if (acctType === 'income') { } else if (acctType === 'income') {
// Income: credit income account, debit cash if (line.amount > 0) {
jeLines.push({ // Normal income: credit income, debit cash
accountId: line.accountId, jeLines.push({ accountId: line.accountId, debit: 0, credit: abs, memo: `${monthLabel} actual` });
debit: 0, totalCashDebit += abs;
credit: Math.abs(line.amount), } else {
memo: `${monthLabel} actual`, // Negative income (correction): debit income, credit cash
}); jeLines.push({ accountId: line.accountId, debit: abs, credit: 0, memo: `${monthLabel} actual (correction)` });
totalCashDebit += Math.abs(line.amount); totalCashCredit += abs;
}
} }
} }

View File

@@ -203,7 +203,7 @@ export function MonthlyActualsPage() {
size="xs" size="xs"
hideControls hideControls
decimalScale={2} decimalScale={2}
min={0} allowNegative
styles={{ input: { textAlign: 'right', fontFamily: 'monospace' } }} styles={{ input: { textAlign: 'right', fontFamily: 'monospace' } }}
/> />
</Table.Td> </Table.Td>