sdfsdf
This commit is contained in:
73
server.js
73
server.js
@@ -108,19 +108,15 @@ async function getNextQuoteNumber() {
|
||||
}
|
||||
|
||||
async function getNextInvoiceNumber() {
|
||||
const year = new Date().getFullYear();
|
||||
const result = await pool.query(
|
||||
'SELECT invoice_number FROM invoices WHERE invoice_number LIKE $1 ORDER BY invoice_number DESC LIMIT 1',
|
||||
[`${year}-%`]
|
||||
'SELECT MAX(CAST(invoice_number AS INTEGER)) as max_number FROM invoices WHERE invoice_number ~ \'^[0-9]+$\''
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return `${year}-001`;
|
||||
if (result.rows.length === 0 || result.rows[0].max_number === null) {
|
||||
return '110508';
|
||||
}
|
||||
|
||||
const lastNumber = parseInt(result.rows[0].invoice_number.split('-')[1]);
|
||||
const nextNumber = String(lastNumber + 1).padStart(3, '0');
|
||||
return `${year}-${nextNumber}`;
|
||||
return String(parseInt(result.rows[0].max_number) + 1);
|
||||
}
|
||||
|
||||
// Logo endpoints
|
||||
@@ -419,14 +415,40 @@ app.get('/api/invoices/:id', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// New endpoint to get next invoice number
|
||||
app.get('/api/invoices/next-number', async (req, res) => {
|
||||
try {
|
||||
const nextNumber = await getNextInvoiceNumber();
|
||||
res.json({ next_number: nextNumber });
|
||||
} catch (error) {
|
||||
console.error('Error getting next invoice number:', error);
|
||||
res.status(500).json({ error: 'Error getting next invoice number' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/invoices', async (req, res) => {
|
||||
const { customer_id, invoice_date, terms, auth_code, tax_exempt, items, created_from_quote_id } = req.body;
|
||||
const { invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, items, created_from_quote_id } = req.body;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
|
||||
const invoice_number = await getNextInvoiceNumber();
|
||||
// Validate invoice_number is provided and is numeric
|
||||
if (!invoice_number || !/^\d+$/.test(invoice_number)) {
|
||||
await client.query('ROLLBACK');
|
||||
return res.status(400).json({ error: 'Invalid invoice number. Must be a numeric value.' });
|
||||
}
|
||||
|
||||
// Check if invoice number already exists
|
||||
const existingInvoice = await client.query(
|
||||
'SELECT id FROM invoices WHERE invoice_number = $1',
|
||||
[invoice_number]
|
||||
);
|
||||
|
||||
if (existingInvoice.rows.length > 0) {
|
||||
await client.query('ROLLBACK');
|
||||
return res.status(400).json({ error: `Invoice number ${invoice_number} already exists.` });
|
||||
}
|
||||
|
||||
let subtotal = 0;
|
||||
|
||||
@@ -534,12 +556,29 @@ app.post('/api/quotes/:id/convert-to-invoice', async (req, res) => {
|
||||
|
||||
app.put('/api/invoices/:id', async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { customer_id, invoice_date, terms, auth_code, tax_exempt, items } = req.body;
|
||||
const { invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, items } = req.body;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
|
||||
// Validate invoice_number is provided and is numeric
|
||||
if (!invoice_number || !/^\d+$/.test(invoice_number)) {
|
||||
await client.query('ROLLBACK');
|
||||
return res.status(400).json({ error: 'Invalid invoice number. Must be a numeric value.' });
|
||||
}
|
||||
|
||||
// Check if invoice number already exists (excluding current invoice)
|
||||
const existingInvoice = await client.query(
|
||||
'SELECT id FROM invoices WHERE invoice_number = $1 AND id != $2',
|
||||
[invoice_number, id]
|
||||
);
|
||||
|
||||
if (existingInvoice.rows.length > 0) {
|
||||
await client.query('ROLLBACK');
|
||||
return res.status(400).json({ error: `Invoice number ${invoice_number} already exists.` });
|
||||
}
|
||||
|
||||
let subtotal = 0;
|
||||
|
||||
for (const item of items) {
|
||||
@@ -554,10 +593,10 @@ app.put('/api/invoices/:id', async (req, res) => {
|
||||
const total = subtotal + tax_amount;
|
||||
|
||||
await client.query(
|
||||
`UPDATE invoices SET customer_id = $1, invoice_date = $2, terms = $3, auth_code = $4, tax_exempt = $5,
|
||||
tax_rate = $6, subtotal = $7, tax_amount = $8, total = $9, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $10`,
|
||||
[customer_id, invoice_date, terms, auth_code, tax_exempt, tax_rate, subtotal, tax_amount, total, id]
|
||||
`UPDATE invoices SET invoice_number = $1, customer_id = $2, invoice_date = $3, terms = $4, auth_code = $5, tax_exempt = $6,
|
||||
tax_rate = $7, subtotal = $8, tax_amount = $9, total = $10, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $11`,
|
||||
[invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, tax_rate, subtotal, tax_amount, total, id]
|
||||
);
|
||||
|
||||
await client.query('DELETE FROM invoice_items WHERE invoice_id = $1', [id]);
|
||||
@@ -598,6 +637,8 @@ app.delete('/api/invoices/:id', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// PDF Generation code continues below...
|
||||
|
||||
// PDF Generation using templates and persistent browser
|
||||
app.get('/api/quotes/:id/pdf', async (req, res) => {
|
||||
const { id } = req.params;
|
||||
@@ -858,8 +899,6 @@ app.get('/api/invoices/:id/pdf', async (req, res) => {
|
||||
});
|
||||
|
||||
|
||||
// Nach den PDF-Endpoints, vor "Start server", einfügen:
|
||||
|
||||
// HTML Debug Endpoints
|
||||
app.get('/api/quotes/:id/html', async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
Reference in New Issue
Block a user