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 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 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 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} 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 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} 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} 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} 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} 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;