Fix initial balance journal entries and add investment account creation
- Fix account creation initial balance bug: the INSERT RETURNING result was not being unwrapped correctly from TypeORM's array response, causing account.id to be undefined and journal entry lines to have $0 amounts. Now uses findOne() after insert for reliable ID retrieval. - Add missing balancing equity entry line (debit/credit to account 3000/3100) so opening balance journal entries are proper double-entry - Fix account update to use findOne() instead of RETURNING * for consistent response format - Add investment account creation to Accounts page: account type dropdown now shows a separator followed by investment types (CD, Money Market, Treasury, Savings, Brokerage). Selecting an investment type expands the modal to show investment-specific fields (institution, principal, interest rate, purchase date, maturity date, account last 4, notes) and posts to /investment-accounts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -42,10 +42,10 @@ export class AccountsService {
|
||||
throw new BadRequestException(`Account number ${dto.accountNumber} already exists`);
|
||||
}
|
||||
|
||||
const rows = await this.tenant.query(
|
||||
const insertResult = await this.tenant.query(
|
||||
`INSERT INTO accounts (account_number, name, description, account_type, fund_type, parent_account_id, is_1099_reportable)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *`,
|
||||
RETURNING id`,
|
||||
[
|
||||
dto.accountNumber,
|
||||
dto.name,
|
||||
@@ -56,7 +56,8 @@ export class AccountsService {
|
||||
dto.is1099Reportable || false,
|
||||
],
|
||||
);
|
||||
const account = rows[0];
|
||||
const accountId = Array.isArray(insertResult[0]) ? insertResult[0][0].id : insertResult[0].id;
|
||||
const account = await this.findOne(accountId);
|
||||
|
||||
// Create opening balance journal entry if initialBalance is provided and non-zero
|
||||
if (dto.initialBalance && dto.initialBalance !== 0) {
|
||||
@@ -64,7 +65,7 @@ export class AccountsService {
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth() + 1;
|
||||
|
||||
// Find or use the current fiscal period
|
||||
// Find the current fiscal period
|
||||
const periods = await this.tenant.query(
|
||||
'SELECT id FROM fiscal_periods WHERE year = $1 AND month = $2',
|
||||
[year, month],
|
||||
@@ -75,11 +76,18 @@ export class AccountsService {
|
||||
|
||||
// Determine debit/credit based on account type
|
||||
const isDebitNormal = ['asset', 'expense'].includes(dto.accountType);
|
||||
const debit = isDebitNormal ? absAmount : 0;
|
||||
const credit = isDebitNormal ? 0 : absAmount;
|
||||
const acctDebit = isDebitNormal ? absAmount : 0;
|
||||
const acctCredit = isDebitNormal ? 0 : absAmount;
|
||||
|
||||
// Determine equity offset account based on fund type
|
||||
const equityAccountNumber = dto.fundType === 'reserve' ? 3100 : 3000;
|
||||
const equityRows = await this.tenant.query(
|
||||
'SELECT id FROM accounts WHERE account_number = $1',
|
||||
[equityAccountNumber],
|
||||
);
|
||||
|
||||
// Create the journal entry
|
||||
const jeRows = await this.tenant.query(
|
||||
const jeInsert = await this.tenant.query(
|
||||
`INSERT INTO journal_entries (entry_date, description, entry_type, fiscal_period_id, is_posted, posted_at, created_by)
|
||||
VALUES (CURRENT_DATE, $1, 'opening_balance', $2, true, NOW(), $3)
|
||||
RETURNING id`,
|
||||
@@ -89,12 +97,21 @@ export class AccountsService {
|
||||
'00000000-0000-0000-0000-000000000000',
|
||||
],
|
||||
);
|
||||
const jeId = Array.isArray(jeInsert[0]) ? jeInsert[0][0].id : jeInsert[0].id;
|
||||
|
||||
if (jeRows.length) {
|
||||
// Line 1: debit/credit the target account
|
||||
await this.tenant.query(
|
||||
`INSERT INTO journal_entry_lines (journal_entry_id, account_id, debit, credit, memo)
|
||||
VALUES ($1, $2, $3, $4, $5)`,
|
||||
[jeId, accountId, acctDebit, acctCredit, 'Opening balance'],
|
||||
);
|
||||
|
||||
// Line 2: balancing entry to equity offset account
|
||||
if (equityRows.length) {
|
||||
await this.tenant.query(
|
||||
`INSERT INTO journal_entry_lines (journal_entry_id, account_id, debit, credit, memo)
|
||||
VALUES ($1, $2, $3, $4, $5)`,
|
||||
[jeRows[0].id, account.id, debit, credit, 'Opening balance'],
|
||||
[jeId, equityRows[0].id, acctCredit, acctDebit, `Opening balance for ${dto.name}`],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -137,11 +154,11 @@ export class AccountsService {
|
||||
sets.push(`updated_at = NOW()`);
|
||||
params.push(id);
|
||||
|
||||
const rows = await this.tenant.query(
|
||||
`UPDATE accounts SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`,
|
||||
await this.tenant.query(
|
||||
`UPDATE accounts SET ${sets.join(', ')} WHERE id = $${idx}`,
|
||||
params,
|
||||
);
|
||||
return rows[0];
|
||||
return this.findOne(id);
|
||||
}
|
||||
|
||||
async setPrimary(id: string) {
|
||||
|
||||
Reference in New Issue
Block a user