183 lines
5.3 KiB
JavaScript
183 lines
5.3 KiB
JavaScript
const BaseFinancialRepository = require('./BaseFinancialRepository');
|
|
const logger = require('../../../src/utils/logger');
|
|
|
|
/**
|
|
* Chart of Accounts Repository
|
|
*
|
|
* Manages financial chart of accounts for HOA operations.
|
|
* Supports multi-tenant sites with account hierarchy.
|
|
*/
|
|
class ChartOfAccountsRepository extends BaseFinancialRepository {
|
|
constructor() {
|
|
super('pg_fn_chart_of_accounts');
|
|
}
|
|
|
|
/**
|
|
* Find all accounts for a specific site
|
|
* @param {string} siteId - Site ID
|
|
* @param {Object} options - Query options (orderBy, orderDirection, limit)
|
|
* @returns {Promise<Array>} Array of accounts
|
|
*/
|
|
async findBySiteId(siteId, options = {}) {
|
|
try {
|
|
const defaultOptions = {
|
|
orderBy: 'account_code',
|
|
orderDirection: 'asc',
|
|
...options
|
|
};
|
|
return await this.findAll({ site_id: siteId }, defaultOptions);
|
|
} catch (error) {
|
|
logger.error('Error finding accounts by site ID:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find active accounts for a site
|
|
* @param {string} siteId - Site ID
|
|
* @returns {Promise<Array>} Array of active accounts
|
|
*/
|
|
async findActiveAccountsBySite(siteId) {
|
|
try {
|
|
return await this.findAll({ site_id: siteId, is_active: true }, { orderBy: 'account_code' });
|
|
} catch (error) {
|
|
logger.error('Error finding active accounts:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find accounts by type
|
|
* @param {string} siteId - Site ID
|
|
* @param {string} accountType - Account type (asset, liability, equity, revenue, expense)
|
|
* @returns {Promise<Array>} Array of accounts
|
|
*/
|
|
async findByType(siteId, accountType) {
|
|
try {
|
|
return await this.findAll({ site_id: siteId, account_type: accountType }, { orderBy: 'account_code' });
|
|
} catch (error) {
|
|
logger.error('Error finding accounts by type:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find account by code for a site
|
|
* @param {string} siteId - Site ID
|
|
* @param {string} accountCode - Account code
|
|
* @returns {Promise<Object|null>} Account or null
|
|
*/
|
|
async findByCode(siteId, accountCode) {
|
|
try {
|
|
return await this.findOne({ site_id: siteId, account_code: accountCode });
|
|
} catch (error) {
|
|
logger.error('Error finding account by code:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find child accounts (accounts with a parent)
|
|
* @param {string} parentAccountId - Parent account ID
|
|
* @returns {Promise<Array>} Array of child accounts
|
|
*/
|
|
async findChildren(parentAccountId) {
|
|
try {
|
|
return await this.findAll({ parent_account_id: parentAccountId }, { orderBy: 'account_code' });
|
|
} catch (error) {
|
|
logger.error('Error finding child accounts:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create account with validation
|
|
* @param {Object} accountData - Account data
|
|
* @returns {Promise<Object>} Created account
|
|
*/
|
|
async createAccount(accountData) {
|
|
try {
|
|
// Validate required fields
|
|
if (!accountData.site_id || !accountData.account_code || !accountData.account_name || !accountData.account_type) {
|
|
throw new Error('Missing required fields: site_id, account_code, account_name, account_type');
|
|
}
|
|
|
|
// Check if account code already exists for this site
|
|
const existingAccount = await this.findByCode(accountData.site_id, accountData.account_code);
|
|
if (existingAccount) {
|
|
throw new Error('Account with this code already exists for this site');
|
|
}
|
|
|
|
// Set defaults
|
|
const account = {
|
|
...accountData,
|
|
is_active: accountData.is_active !== undefined ? accountData.is_active : true,
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString()
|
|
};
|
|
|
|
return await this.create(account);
|
|
} catch (error) {
|
|
logger.error('Error creating account:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update account with validation
|
|
* @param {string} accountId - Account ID
|
|
* @param {Object} updateData - Update data
|
|
* @returns {Promise<Object>} Updated account
|
|
*/
|
|
async updateAccount(accountId, updateData) {
|
|
try {
|
|
const update = {
|
|
...updateData,
|
|
updated_at: new Date().toISOString()
|
|
};
|
|
|
|
return await this.updateById(accountId, update);
|
|
} catch (error) {
|
|
logger.error('Error updating account:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if account has transactions (used to prevent deletion)
|
|
* @param {string} accountId - Account ID
|
|
* @returns {Promise<boolean>} True if account has transactions
|
|
*/
|
|
async hasTransactions(accountId) {
|
|
try {
|
|
// This will be implemented when TransactionLineRepository is created
|
|
// For now, we'll need to check manually
|
|
// TODO: Add check using TransactionLineRepository when available
|
|
return false;
|
|
} catch (error) {
|
|
logger.error('Error checking account transactions:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deactivate account (soft delete)
|
|
* @param {string} accountId - Account ID
|
|
* @returns {Promise<Object>} Updated account
|
|
*/
|
|
async deactivate(accountId) {
|
|
try {
|
|
return await this.updateById(accountId, {
|
|
is_active: false,
|
|
updated_at: new Date().toISOString()
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error deactivating account:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = ChartOfAccountsRepository;
|
|
|
|
|