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

299 lines
No EOL
6.9 KiB
JavaScript

const express = require('express');
const router = express.Router();
const { invoiceRepository, paymentRepository } = require('../repositories');
/**
* GET /api/plugins/financials/invoices
* Get all invoices for a site or unit
*/
router.get('/', async (req, res) => {
try {
const { site_id, unit_id, status, invoice_type } = req.query;
if (!site_id) {
return res.status(400).json({
success: false,
error: 'site_id query parameter is required'
});
}
let invoices;
// Filter by unit_id if provided
if (unit_id) {
invoices = await invoiceRepository.findByUnitId(unit_id);
} else {
invoices = await invoiceRepository.findBySiteId(site_id);
}
// Filter by status if provided
if (status) {
invoices = invoices.filter(inv => inv.status === status);
}
// Filter by invoice_type if provided
if (invoice_type) {
invoices = invoices.filter(inv => inv.invoice_type === invoice_type);
}
res.json({
success: true,
data: invoices,
message: 'Invoices retrieved successfully'
});
} catch (error) {
console.error('Failed to get invoices:', error);
res.status(500).json({
success: false,
error: 'Failed to retrieve invoices',
message: error.message
});
}
});
/**
* GET /api/plugins/financials/invoices/:id
* Get invoice by ID
*/
router.get('/:id', async (req, res) => {
try {
const { id } = req.params;
const { site_id } = req.query;
if (!site_id) {
return res.status(400).json({
success: false,
error: 'site_id is required'
});
}
const invoice = await invoiceRepository.findById(id);
if (!invoice) {
return res.status(404).json({
success: false,
error: 'Invoice not found'
});
}
// Verify invoice belongs to site
if (invoice.site_id !== site_id) {
return res.status(403).json({
success: false,
error: 'Access denied'
});
}
res.json({
success: true,
data: invoice,
message: 'Invoice details retrieved successfully'
});
} catch (error) {
console.error('Failed to get invoice:', error);
res.status(500).json({
success: false,
error: 'Failed to retrieve invoice',
message: error.message
});
}
});
/**
* POST /api/plugins/financials/invoices
* Create a new invoice
*/
router.post('/', async (req, res) => {
try {
const { site_id, unit_id, invoice_number, invoice_type, description, amount, due_date, work_order_id, notes, created_by } = req.body;
if (!site_id || !unit_id || !invoice_type || !description || !amount || !due_date) {
return res.status(400).json({
success: false,
error: 'Missing required fields',
message: 'Site ID, unit ID, invoice type, description, amount, and due date are required'
});
}
const invoice = await invoiceRepository.createInvoice({
site_id,
unit_id,
invoice_number,
invoice_type,
description,
amount,
due_date,
work_order_id,
notes,
created_by: created_by || req.user?.id || 'system'
});
res.status(201).json({
success: true,
data: invoice,
message: 'Invoice created successfully'
});
} catch (error) {
console.error('Failed to create invoice:', error);
if (error.message.includes('already exists')) {
return res.status(409).json({
success: false,
error: 'Invoice number already exists',
message: error.message
});
}
res.status(500).json({
success: false,
error: 'Failed to create invoice',
message: error.message
});
}
});
/**
* PUT /api/plugins/financials/invoices/:id/pay
* Mark invoice as paid
*/
router.put('/:id/pay', async (req, res) => {
try {
const { id } = req.params;
const { payment_date, payment_method, payment_reference } = req.body;
const { site_id } = req.query;
if (!site_id) {
return res.status(400).json({
success: false,
error: 'site_id is required'
});
}
// Get invoice first to verify it exists
const invoice = await invoiceRepository.findById(id);
if (!invoice) {
return res.status(404).json({
success: false,
error: 'Invoice not found'
});
}
if (invoice.site_id !== site_id) {
return res.status(403).json({
success: false,
error: 'Access denied'
});
}
const updatedInvoice = await invoiceRepository.markAsPaid(id, {
payment_date,
payment_method,
payment_reference
});
res.json({
success: true,
data: updatedInvoice,
message: 'Invoice marked as paid successfully'
});
} catch (error) {
console.error('Failed to mark invoice as paid:', error);
res.status(500).json({
success: false,
error: 'Failed to mark invoice as paid',
message: error.message
});
}
});
/**
* PUT /api/plugins/financials/invoices/:id
* Update invoice
*/
router.put('/:id', async (req, res) => {
try {
const { id } = req.params;
const { site_id, description, amount, due_date, status, notes } = req.body;
if (!site_id) {
return res.status(400).json({
success: false,
error: 'site_id is required'
});
}
// Get invoice first
const invoice = await invoiceRepository.findById(id);
if (!invoice) {
return res.status(404).json({
success: false,
error: 'Invoice not found'
});
}
if (invoice.site_id !== site_id) {
return res.status(403).json({
success: false,
error: 'Access denied'
});
}
const updatedInvoice = await invoiceRepository.updateById(id, {
description,
amount,
due_date,
status,
notes,
updated_at: new Date().toISOString()
});
res.json({
success: true,
data: updatedInvoice,
message: 'Invoice updated successfully'
});
} catch (error) {
console.error('Failed to update invoice:', error);
res.status(500).json({
success: false,
error: 'Failed to update invoice',
message: error.message
});
}
});
/**
* GET /api/plugins/financials/invoices/overdue
* Get overdue invoices
*/
router.get('/overdue', async (req, res) => {
try {
const { site_id } = req.query;
if (!site_id) {
return res.status(400).json({
success: false,
error: 'site_id is required'
});
}
const overdueInvoices = await invoiceRepository.findOverdue(site_id);
res.json({
success: true,
data: overdueInvoices,
message: 'Overdue invoices retrieved successfully'
});
} catch (error) {
console.error('Failed to get overdue invoices:', error);
res.status(500).json({
success: false,
error: 'Failed to retrieve overdue invoices',
message: error.message
});
}
});
module.exports = router;