recurring, tax exempt, badge

This commit is contained in:
2026-03-04 18:21:40 -06:00
parent e333628f1c
commit e9d88b1400
7 changed files with 323 additions and 70 deletions

View File

@@ -13,6 +13,16 @@ const { getBrowser, generatePdfFromHtml, getLogoHtml, renderInvoiceItems, format
const { exportInvoiceToQbo, syncInvoiceToQbo } = require('../services/qbo-service');
const { getOAuthClient, getQboBaseUrl, makeQboApiCall } = require('../config/qbo');
function calculateNextRecurringDate(invoiceDate, interval) {
const d = new Date(invoiceDate);
if (interval === 'monthly') {
d.setMonth(d.getMonth() + 1);
} else if (interval === 'yearly') {
d.setFullYear(d.getFullYear() + 1);
}
return d.toISOString().split('T')[0];
}
// GET all invoices
router.get('/', async (req, res) => {
try {
@@ -81,7 +91,7 @@ router.get('/:id', async (req, res) => {
// POST create invoice
router.post('/', async (req, res) => {
const { invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, items, scheduled_send_date, bill_to_name, created_from_quote_id } = req.body;
const { invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, items, scheduled_send_date, bill_to_name, created_from_quote_id, is_recurring, recurring_interval } = req.body;
const client = await pool.connect();
try {
@@ -112,11 +122,11 @@ router.post('/', async (req, res) => {
const tax_rate = 8.25;
const tax_amount = tax_exempt ? 0 : (subtotal * tax_rate / 100);
const total = subtotal + tax_amount;
const next_recurring_date = is_recurring ? calculateNextRecurringDate(invoice_date, recurring_interval) : null;
const invoiceResult = await client.query(
`INSERT INTO invoices (invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, tax_rate, subtotal, tax_amount, total, scheduled_send_date, bill_to_name, created_from_quote_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING *`,
[tempNumber, customer_id, invoice_date, terms, auth_code, tax_exempt, tax_rate, subtotal, tax_amount, total, scheduled_send_date || null, bill_to_name || null, created_from_quote_id]
`INSERT INTO invoices (invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, tax_rate, subtotal, tax_amount, total, scheduled_send_date, bill_to_name, created_from_quote_id, is_recurring, recurring_interval, next_recurring_date)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) RETURNING *`,
[tempNumber, customer_id, invoice_date, terms, auth_code, tax_exempt, tax_rate, subtotal, tax_amount, total, scheduled_send_date || null, bill_to_name || null, created_from_quote_id, is_recurring || false, recurring_interval || null, next_recurring_date]
);
const invoiceId = invoiceResult.rows[0].id;
@@ -158,7 +168,7 @@ router.post('/', async (req, res) => {
// PUT update invoice
router.put('/:id', async (req, res) => {
const { id } = req.params;
const { invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, items, scheduled_send_date, bill_to_name } = req.body;
const { invoice_number, customer_id, invoice_date, terms, auth_code, tax_exempt, items, scheduled_send_date, bill_to_name, is_recurring, recurring_interval } = req.body;
const client = await pool.connect();
try {
@@ -204,7 +214,11 @@ router.put('/:id', async (req, res) => {
[customer_id, invoice_date, terms, auth_code, tax_exempt, tax_rate, subtotal, tax_amount, total, scheduled_send_date || null, bill_to_name || null, id]
);
}
const next_recurring_date = is_recurring ? calculateNextRecurringDate(invoice_date, recurring_interval) : null;
await client.query(
'UPDATE invoices SET is_recurring = $1, recurring_interval = $2, next_recurring_date = $3 WHERE id = $4',
[is_recurring || false, recurring_interval || null, next_recurring_date, id]
);
// Delete and re-insert items
await client.query('DELETE FROM invoice_items WHERE invoice_id = $1', [id]);
for (let i = 0; i < items.length; i++) {