Flexible budget import with auto-account creation and text-based account numbers

Change account_number from INTEGER to VARCHAR(50) to support segmented codes
like 30-3001-0000 used by real HOA accounting systems. Budget CSV import now:
- Auto-creates income/expense accounts from CSV when they don't exist
- Infers account_type and fund_type from account number prefix conventions
- Parses currency-formatted values ($48,065.21, $(13,000.00), $-, etc.)
- Reports created accounts back to the user

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 14:24:00 -05:00
parent 1e40848222
commit 61e43212b9
14 changed files with 188 additions and 63 deletions

View File

@@ -92,7 +92,7 @@ export class AccountsService {
const acctCredit = isDebitNormal ? 0 : absAmount;
// Determine equity offset account based on fund type (auto-create if missing)
const equityAccountNumber = dto.fundType === 'reserve' ? 3100 : 3000;
const equityAccountNumber = dto.fundType === 'reserve' ? '3100' : '3000';
const equityName = dto.fundType === 'reserve' ? 'Reserve Fund Balance' : 'Operating Fund Balance';
let equityRows = await this.tenant.query(
'SELECT id FROM accounts WHERE account_number = $1',
@@ -247,7 +247,7 @@ export class AccountsService {
const fiscalPeriodId = periods[0].id;
// Determine the equity offset account based on fund_type
const equityAccountNumber = account.fund_type === 'reserve' ? 3100 : 3000;
const equityAccountNumber = account.fund_type === 'reserve' ? '3100' : '3000';
const equityRows = await this.tenant.query(
'SELECT id, account_type FROM accounts WHERE account_number = $1',
[equityAccountNumber],

View File

@@ -1,10 +1,10 @@
import { IsString, IsInt, IsOptional, IsBoolean, IsIn, IsUUID } from 'class-validator';
import { IsString, IsOptional, IsBoolean, IsIn, IsUUID } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateAccountDto {
@ApiProperty({ example: 6600 })
@IsInt()
accountNumber: number;
@ApiProperty({ example: '6600' })
@IsString()
accountNumber: string;
@ApiProperty({ example: 'Equipment Repairs' })
@IsString()

View File

@@ -1,4 +1,4 @@
import { IsString, IsOptional, IsBoolean, IsIn, IsInt } from 'class-validator';
import { IsString, IsOptional, IsBoolean, IsIn } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class UpdateAccountDto {
@@ -28,9 +28,9 @@ export class UpdateAccountDto {
isActive?: boolean;
@ApiProperty({ required: false })
@IsInt()
@IsString()
@IsOptional()
accountNumber?: number;
accountNumber?: string;
@ApiProperty({ required: false })
@IsIn(['operating', 'reserve'])