plugin-financials/repositories/ChartOfAccountsRepository.js
2025-11-03 13:51:33 +02:00

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;