const BaseFinancialRepository = require('./BaseFinancialRepository'); const logger = require('../../../src/utils/logger'); /** * Unit Balance Repository * * Manages unit balance tracking for HOA financial management. * This is CRITICAL for the frontend - the useUnitBalance hook depends on this. */ class UnitBalanceRepository extends BaseFinancialRepository { constructor() { super('pg_fn_unit_balances'); } /** * Find balance for a specific unit * @param {string} unitId - Unit ID * @param {string} siteId - Site ID * @returns {Promise} Unit balance or null */ async findByUnitId(unitId, siteId) { try { return await this.findOne({ unit_id: unitId, site_id: siteId }); } catch (error) { logger.error('Error finding unit balance:', error); throw error; } } /** * Find balances for multiple units (batch lookup) * @param {Array} unitIds - Array of unit IDs * @param {string} siteId - Site ID * @returns {Promise} Object with unitId as key and balance as value */ async findByMultipleUnitIds(unitIds, siteId) { try { const balances = {}; const results = await this.findWhere({ unit_id: { in: unitIds }, site_id: { eq: siteId } }); // Convert array to object for easy lookup results.forEach(balance => { balances[balance.unit_id] = balance; }); return balances; } catch (error) { logger.error('Error finding multiple unit balances:', error); throw error; } } /** * Create or update unit balance * @param {Object} balanceData - Balance data * @returns {Promise} Created or updated balance */ async createOrUpdateUnitBalance(balanceData) { try { const { unit_id, site_id } = balanceData; const existing = await this.findByUnitId(unit_id, site_id); if (existing) { // Update existing balance return await this.updateById(existing.id, { ...balanceData, last_updated: new Date().toISOString() }); } else { // Create new balance const balance = { ...balanceData, created_at: new Date().toISOString() }; return await this.create(balance); } } catch (error) { logger.error('Error creating/updating unit balance:', error); throw error; } } /** * Update current balance for a unit * @param {string} unitId - Unit ID * @param {string} siteId - Site ID * @param {number} newBalance - New balance amount * @returns {Promise} Updated balance */ async updateCurrentBalance(unitId, siteId, newBalance) { try { const existing = await this.findByUnitId(unitId, siteId); if (!existing) { throw new Error('Unit balance not found'); } return await this.updateById(existing.id, { current_balance: newBalance, last_updated: new Date().toISOString() }); } catch (error) { logger.error('Error updating current balance:', error); throw error; } } /** * Calculate unit balance from invoices and payments * This will be called by the balances route to get REAL balance * @param {string} unitId - Unit ID * @param {string} siteId - Site ID * @returns {Promise} Balance breakdown */ async calculateUnitBalance(unitId, siteId) { try { const balanceRecord = await this.findByUnitId(unitId, siteId); // Balance is now calculated from transactions, not stored const currentBalance = balanceRecord ? parseFloat(balanceRecord.current_balance) : 0; return { unitId, siteId, currentBalance, lastUpdated: balanceRecord ? balanceRecord.last_updated : null }; } catch (error) { logger.error('Error calculating unit balance:', error); throw error; } } /** * Get all balances for a site * @param {string} siteId - Site ID * @returns {Promise} Array of unit balances */ async findBySiteId(siteId) { try { return await this.findAll({ site_id: siteId }, { orderBy: 'last_updated', orderDirection: 'desc' }); } catch (error) { logger.error('Error finding balances by site:', error); throw error; } } /** * Reset unit balance * @param {string} unitId - Unit ID * @param {string} siteId - Site ID * @returns {Promise} Reset balance */ async resetBalance(unitId, siteId) { try { return await this.createOrUpdateUnitBalance({ unit_id: unitId, site_id: siteId, current_balance: 0, created_by: 'system' // Will be set by route }); } catch (error) { logger.error('Error resetting balance:', error); throw error; } } } module.exports = UnitBalanceRepository;