diff --git a/backend/src/modules/investments/investments.service.ts b/backend/src/modules/investments/investments.service.ts
index 9379d75..7a97968 100644
--- a/backend/src/modules/investments/investments.service.ts
+++ b/backend/src/modules/investments/investments.service.ts
@@ -47,7 +47,57 @@ export class InvestmentsService {
dto.fund_type || 'reserve', dto.principal, dto.interest_rate || 0,
dto.maturity_date || null, dto.purchase_date || null, dto.current_value || dto.principal, dto.notes],
);
- return rows[0];
+ const investment = rows[0];
+
+ // If withdraw_from_primary is true, create a journal entry to debit the primary account
+ if (dto.withdraw_from_primary && dto.principal > 0) {
+ const fundType = dto.fund_type || 'reserve';
+ const primaryRows = await this.tenant.query(
+ `SELECT id, name FROM accounts WHERE is_primary = true AND fund_type = $1 AND is_active = true LIMIT 1`,
+ [fundType],
+ );
+ if (primaryRows.length) {
+ const primaryAccount = primaryRows[0];
+ const equityAccountNumber = fundType === 'reserve' ? 3100 : 3000;
+ const equityRows = await this.tenant.query(
+ 'SELECT id FROM accounts WHERE account_number = $1',
+ [equityAccountNumber],
+ );
+ if (equityRows.length) {
+ const now = new Date();
+ const year = now.getFullYear();
+ const month = now.getMonth() + 1;
+ const periods = await this.tenant.query(
+ 'SELECT id FROM fiscal_periods WHERE year = $1 AND month = $2',
+ [year, month],
+ );
+ if (periods.length) {
+ const memo = `Transfer to investment: ${dto.name}`;
+ const jeRows = 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, 'transfer', $2, true, NOW(), '00000000-0000-0000-0000-000000000000')
+ RETURNING *`,
+ [memo, periods[0].id],
+ );
+ const je = jeRows[0];
+ // Credit the primary asset account (reduces cash)
+ await this.tenant.query(
+ `INSERT INTO journal_entry_lines (journal_entry_id, account_id, debit, credit, memo)
+ VALUES ($1, $2, 0, $3, $4)`,
+ [je.id, primaryAccount.id, dto.principal, memo],
+ );
+ // Debit the equity offset account (reduces fund balance)
+ await this.tenant.query(
+ `INSERT INTO journal_entry_lines (journal_entry_id, account_id, debit, credit, memo)
+ VALUES ($1, $2, $3, 0, $4)`,
+ [je.id, equityRows[0].id, dto.principal, memo],
+ );
+ }
+ }
+ }
+ }
+
+ return investment;
}
async update(id: string, dto: any) {
diff --git a/frontend/src/pages/accounts/AccountsPage.tsx b/frontend/src/pages/accounts/AccountsPage.tsx
index 73647d3..9dfd23e 100644
--- a/frontend/src/pages/accounts/AccountsPage.tsx
+++ b/frontend/src/pages/accounts/AccountsPage.tsx
@@ -173,6 +173,7 @@ export function AccountsPage() {
maturityDate: null as Date | null,
purchaseDate: null as Date | null,
investmentNotes: '',
+ withdrawFromPrimary: true,
},
validate: {
accountNumber: (v, values) => isInvestmentType(values.accountType) ? null : (v > 0 ? null : 'Required'),
@@ -218,6 +219,7 @@ export function AccountsPage() {
purchase_date: values.purchaseDate ? values.purchaseDate.toISOString().split('T')[0] : null,
current_value: values.principal,
notes: values.investmentNotes || null,
+ withdraw_from_primary: values.withdrawFromPrimary,
});
}
return api.post('/accounts', values);
@@ -515,13 +517,21 @@ export function AccountsPage() {
- setPrimaryMutation.mutate(id)}
- onAdjustBalance={handleAdjustBalance}
- />
+
+ setPrimaryMutation.mutate(id)}
+ onAdjustBalance={handleAdjustBalance}
+ />
+ {investments.filter(i => i.is_active).length > 0 && (
+ <>
+
+ i.is_active)} onEdit={handleEditInvestment} />
+ >
+ )}
+
@@ -577,6 +587,7 @@ export function AccountsPage() {
onClose={close}
title={editing ? 'Edit Account' : isInvestmentType(form.values.accountType) ? 'New Investment Account' : 'New Account'}
size="md"
+ closeOnClickOutside={false}
>