224 lines
6.5 KiB
JavaScript
224 lines
6.5 KiB
JavaScript
const BaseFinancialRepository = require('./BaseFinancialRepository');
|
|
const logger = require('../../../src/utils/logger');
|
|
|
|
/**
|
|
* Invoice Repository
|
|
*
|
|
* Manages invoice creation, tracking, and payments for units.
|
|
*/
|
|
class InvoiceRepository extends BaseFinancialRepository {
|
|
constructor() {
|
|
super('pg_fn_invoices');
|
|
}
|
|
|
|
/**
|
|
* Find invoices for a unit
|
|
* @param {string} unitId - Unit ID
|
|
* @param {Object} options - Query options
|
|
* @returns {Promise<Array>} Array of invoices
|
|
*/
|
|
async findByUnitId(unitId, options = {}) {
|
|
try {
|
|
return await this.findAll({ unit_id: unitId }, {
|
|
orderBy: 'issue_date',
|
|
orderDirection: 'desc',
|
|
...options
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error finding invoices by unit:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find invoices for a site
|
|
* @param {string} siteId - Site ID
|
|
* @param {Object} options - Query options
|
|
* @returns {Promise<Array>} Array of invoices
|
|
*/
|
|
async findBySiteId(siteId, options = {}) {
|
|
try {
|
|
return await this.findAll({ site_id: siteId }, {
|
|
orderBy: 'issue_date',
|
|
orderDirection: 'desc',
|
|
...options
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error finding invoices by site:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find invoices by status
|
|
* @param {string} siteId - Site ID
|
|
* @param {string} status - Invoice status (pending, paid, overdue, cancelled)
|
|
* @returns {Promise<Array>} Array of invoices
|
|
*/
|
|
async findByStatus(siteId, status) {
|
|
try {
|
|
return await this.findAll({ site_id: siteId, status }, { orderBy: 'due_date' });
|
|
} catch (error) {
|
|
logger.error('Error finding invoices by status:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find invoice by invoice number
|
|
* @param {string} siteId - Site ID
|
|
* @param {string} invoiceNumber - Invoice number
|
|
* @returns {Promise<Object|null>} Invoice or null
|
|
*/
|
|
async findByInvoiceNumber(siteId, invoiceNumber) {
|
|
try {
|
|
return await this.findOne({ site_id: siteId, invoice_number: invoiceNumber });
|
|
} catch (error) {
|
|
logger.error('Error finding invoice by number:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find overdue invoices
|
|
* @param {string} siteId - Site ID
|
|
* @returns {Promise<Array>} Array of overdue invoices
|
|
*/
|
|
async findOverdue(siteId) {
|
|
try {
|
|
const today = new Date().toISOString().split('T')[0];
|
|
return await this.findWhere({
|
|
site_id: { eq: siteId },
|
|
status: { eq: 'pending' },
|
|
due_date: { lt: today }
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error finding overdue invoices:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create invoice with validation
|
|
* @param {Object} invoiceData - Invoice data
|
|
* @returns {Promise<Object>} Created invoice
|
|
*/
|
|
async createInvoice(invoiceData) {
|
|
try {
|
|
// Validate required fields
|
|
if (!invoiceData.site_id || !invoiceData.unit_id || !invoiceData.invoice_number ||
|
|
!invoiceData.invoice_type || !invoiceData.description || !invoiceData.amount ||
|
|
!invoiceData.due_date) {
|
|
throw new Error('Missing required fields for invoice creation');
|
|
}
|
|
|
|
// Check if invoice number already exists for this site
|
|
const existingInvoice = await this.findByInvoiceNumber(invoiceData.site_id, invoiceData.invoice_number);
|
|
if (existingInvoice) {
|
|
throw new Error('Invoice with this number already exists for this site');
|
|
}
|
|
|
|
// Set defaults
|
|
const invoice = {
|
|
...invoiceData,
|
|
status: invoiceData.status || 'pending',
|
|
issue_date: invoiceData.issue_date || new Date().toISOString().split('T')[0],
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString()
|
|
};
|
|
|
|
return await this.create(invoice);
|
|
} catch (error) {
|
|
logger.error('Error creating invoice:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mark invoice as paid
|
|
* @param {string} invoiceId - Invoice ID
|
|
* @param {Object} paymentInfo - Payment information
|
|
* @returns {Promise<Object>} Updated invoice
|
|
*/
|
|
async markAsPaid(invoiceId, paymentInfo = {}) {
|
|
try {
|
|
const update = {
|
|
status: 'paid',
|
|
payment_date: paymentInfo.payment_date || new Date().toISOString().split('T')[0],
|
|
payment_method: paymentInfo.payment_method,
|
|
payment_reference: paymentInfo.payment_reference,
|
|
updated_at: new Date().toISOString()
|
|
};
|
|
|
|
return await this.updateById(invoiceId, update);
|
|
} catch (error) {
|
|
logger.error('Error marking invoice as paid:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mark invoice as overdue
|
|
* @param {string} invoiceId - Invoice ID
|
|
* @returns {Promise<Object>} Updated invoice
|
|
*/
|
|
async markAsOverdue(invoiceId) {
|
|
try {
|
|
return await this.updateById(invoiceId, {
|
|
status: 'overdue',
|
|
updated_at: new Date().toISOString()
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error marking invoice as overdue:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get invoice statistics for a unit
|
|
* @param {string} unitId - Unit ID
|
|
* @returns {Promise<Object>} Invoice statistics
|
|
*/
|
|
async getInvoiceStats(unitId) {
|
|
try {
|
|
const invoices = await this.findByUnitId(unitId);
|
|
|
|
const stats = {
|
|
total: invoices.length,
|
|
pending: invoices.filter(i => i.status === 'pending').length,
|
|
paid: invoices.filter(i => i.status === 'paid').length,
|
|
overdue: invoices.filter(i => i.status === 'overdue').length,
|
|
totalAmount: invoices.reduce((sum, inv) => sum + parseFloat(inv.amount), 0),
|
|
paidAmount: invoices
|
|
.filter(i => i.status === 'paid')
|
|
.reduce((sum, inv) => sum + parseFloat(inv.amount), 0),
|
|
pendingAmount: invoices
|
|
.filter(i => i.status === 'pending' || i.status === 'overdue')
|
|
.reduce((sum, inv) => sum + parseFloat(inv.amount), 0)
|
|
};
|
|
|
|
return stats;
|
|
} catch (error) {
|
|
logger.error('Error getting invoice stats:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find invoices for work order
|
|
* @param {string} workOrderId - Work order ID
|
|
* @returns {Promise<Array>} Array of invoices
|
|
*/
|
|
async findByWorkOrderId(workOrderId) {
|
|
try {
|
|
return await this.findAll({ work_order_id: workOrderId }, { orderBy: 'created_at' });
|
|
} catch (error) {
|
|
logger.error('Error finding invoices by work order:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = InvoiceRepository;
|
|
|
|
|