Phase 3: Optimize & clean up — unified projects, account enhancements, new tenant fix
- Unify reserve_components + capital_projects into single projects model with full CRUD backend and new Projects page frontend - Rewrite Capital Planning to read from unified projects/planning endpoint; add empty state directing users to Projects page when no planning items exist - Add default designation to assessment groups with auto-set on first creation; units now require an assessment group (pre-populated with default) - Add primary account designation (one per fund type) and balance adjustment via journal entries against equity offset accounts (3000/3100) - Add computed investment fields (interest earned, maturity value, days remaining) with PostgreSQL date arithmetic fix for DATE - DATE integer result - Restructure sidebar: investments in Accounts tab, Year-End under Reports, Planning section with Projects and Capital Planning - Fix new tenant creation seeding unwanted default chart of accounts — new tenants now start with a blank slate Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,30 @@ export class InvestmentsService {
|
||||
constructor(private tenant: TenantService) {}
|
||||
|
||||
async findAll() {
|
||||
return this.tenant.query('SELECT * FROM investment_accounts WHERE is_active = true ORDER BY name');
|
||||
return this.tenant.query(`
|
||||
SELECT ia.*,
|
||||
CASE
|
||||
WHEN ia.purchase_date IS NOT NULL AND ia.interest_rate IS NOT NULL AND ia.interest_rate > 0 THEN
|
||||
ROUND(ia.principal * (ia.interest_rate / 100.0) *
|
||||
(LEAST(COALESCE(ia.maturity_date, CURRENT_DATE), CURRENT_DATE) - ia.purchase_date)::numeric
|
||||
/ 365.0, 2)
|
||||
ELSE NULL
|
||||
END as interest_earned,
|
||||
CASE
|
||||
WHEN ia.purchase_date IS NOT NULL AND ia.maturity_date IS NOT NULL AND ia.interest_rate IS NOT NULL THEN
|
||||
ROUND(ia.principal * (1 + ia.interest_rate / 100.0 *
|
||||
(ia.maturity_date - ia.purchase_date)::numeric / 365.0), 2)
|
||||
ELSE NULL
|
||||
END as maturity_value,
|
||||
CASE
|
||||
WHEN ia.maturity_date IS NOT NULL THEN
|
||||
GREATEST(ia.maturity_date - CURRENT_DATE, 0)
|
||||
ELSE NULL
|
||||
END as days_remaining
|
||||
FROM investment_accounts ia
|
||||
WHERE ia.is_active = true
|
||||
ORDER BY ia.name
|
||||
`);
|
||||
}
|
||||
|
||||
async findOne(id: string) {
|
||||
|
||||
Reference in New Issue
Block a user