71 lines
2.9 KiB
JavaScript
71 lines
2.9 KiB
JavaScript
const { ChartOfAccountsRepository } = require('../repositories');
|
||
const logger = require('../../../src/utils/logger');
|
||
|
||
// Define the 7 default accounts to seed for every new HOA site
|
||
const DEFAULT_ACCOUNTS = [
|
||
{ code: '1000', name: 'Checking Account', type: 'asset', description: 'Holds all cash; receives monthly fees, pays all bills.' },
|
||
{ code: '1100', name: 'Accounts Receivable – Owners', type: 'asset', description: 'Tracks unpaid monthly service fees (who owes what).' },
|
||
{ code: '2000', name: 'Accounts Payable – Vendors', type: 'liability', description: 'Tracks unpaid bills (what the HOA owes).' },
|
||
{ code: '2100', name: 'Prepaid Assessments', type: 'liability', description: 'Records fees paid in advance (liability until earned).' },
|
||
{ code: '3100', name: 'HOA Fund Balance', type: 'equity', description: 'Starting/ending equity; required for balance sheet.' },
|
||
{ code: '4100', name: 'Monthly Service Fees', type: 'income', description: 'All regular income comes here.' },
|
||
{ code: '5100', name: 'Operating Expenses', type: 'expense', description: 'All spending (utilities, repairs, insurance, etc.).' }
|
||
];
|
||
|
||
/**
|
||
* Seed default financial accounts for a given site
|
||
* This function is idempotent per account code per site: it skips any that already exist.
|
||
* @param {string} siteId
|
||
* @param {string|null} createdByUserId
|
||
*/
|
||
async function seedDefaultAccounts(siteId, createdByUserId = null) {
|
||
const chartOfAccountsRepository = new ChartOfAccountsRepository();
|
||
|
||
const createdAccountIds = [];
|
||
try {
|
||
for (const acc of DEFAULT_ACCOUNTS) {
|
||
// Skip if exists
|
||
const exists = await chartOfAccountsRepository.findByCode(siteId, acc.code);
|
||
if (exists) {
|
||
continue;
|
||
}
|
||
|
||
const newAccount = await chartOfAccountsRepository.createAccount({
|
||
site_id: siteId,
|
||
account_code: acc.code,
|
||
account_name: acc.name,
|
||
account_type: acc.type,
|
||
description: acc.description,
|
||
is_active: true,
|
||
// created_by is optional in repository
|
||
...(createdByUserId ? { created_by: createdByUserId } : {})
|
||
});
|
||
|
||
if (newAccount && newAccount.id) {
|
||
createdAccountIds.push(newAccount.id);
|
||
}
|
||
}
|
||
|
||
logger.info(`Seeded default financial accounts for site ${siteId}: ${createdAccountIds.length} created`);
|
||
return { success: true, created: createdAccountIds.length };
|
||
} catch (error) {
|
||
// Best-effort rollback of any accounts created in this run
|
||
try {
|
||
for (const id of createdAccountIds) {
|
||
await chartOfAccountsRepository.deleteById(id);
|
||
}
|
||
logger.warn(`Rolled back ${createdAccountIds.length} seeded accounts for site ${siteId} due to error.`);
|
||
} catch (rollbackError) {
|
||
logger.error('Failed to rollback seeded accounts:', rollbackError);
|
||
}
|
||
logger.error('Failed to seed default accounts:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
seedDefaultAccounts,
|
||
DEFAULT_ACCOUNTS
|
||
};
|
||
|
||
|