From 9fa6b146e55748c9391a485e8be2fa5dbd64618e Mon Sep 17 00:00:00 2001 From: Eric Harding Date: Sat, 11 Jul 2026 20:42:37 -0400 Subject: [PATCH] Add 'orders' for customer button in the customers page. Fix bug in add line item --- public/css/style.css | 5 ++++ src/routes/orders.ts | 33 +++++++++++++++++++-------- src/server.ts | 1 + src/views/customers/list.njk | 6 +++-- src/views/invoice.njk | 5 ++-- src/views/orders/_line_item_added.njk | 2 -- src/views/orders/_totals.njk | 5 +++- src/views/orders/list.njk | 9 ++++++-- src/views/orders/new.njk | 4 ++++ 9 files changed, 51 insertions(+), 19 deletions(-) delete mode 100644 src/views/orders/_line_item_added.njk diff --git a/public/css/style.css b/public/css/style.css index 20126a6..9fcfe18 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -375,6 +375,11 @@ button.danger { color: #666; } +.invoice-terms-note { + font-weight: bold; + color: #111; +} + @media print { html { font-size: 100%; } /* keep the printed invoice at normal scale so it still fits one page */ .no-print { display: none !important; } diff --git a/src/routes/orders.ts b/src/routes/orders.ts index 5ef355e..d2ba254 100644 --- a/src/routes/orders.ts +++ b/src/routes/orders.ts @@ -59,7 +59,9 @@ export function getOrderDetail(id: string | number) { return { ...order, lineItems, workLog, totals }; } -router.get('/', (_req, res) => { +router.get('/', (req, res) => { + const customerId = req.query.customer_id ? Number(req.query.customer_id) : null; + const orders = db .prepare( `SELECT so.id, so.order_number, so.status, so.job_type, so.date_in, so.due_date, @@ -68,6 +70,7 @@ router.get('/', (_req, res) => { JOIN customers c ON c.id = so.customer_id LEFT JOIN order_totals ot ON ot.service_order_id = so.id WHERE so.deleted_at IS NULL + AND (? IS NULL OR so.customer_id = ?) ORDER BY CASE so.status WHEN 'OPEN' THEN 0 WHEN 'IN PROGRESS' THEN 1 @@ -78,9 +81,13 @@ router.get('/', (_req, res) => { so.date_in DESC, so.order_number DESC` ) - .all(); + .all(customerId, customerId); - res.render('orders/list.njk', { orders }); + const customerFilter = customerId + ? db.prepare('SELECT id, name FROM customers WHERE id = ?').get(customerId) + : null; + + res.render('orders/list.njk', { orders, customerFilter }); }); router.get('/orders/new', (_req, res) => { @@ -137,8 +144,8 @@ router.post('/orders', (req, res) => { const orderInfo = db .prepare( `INSERT INTO service_orders - (order_number, customer_id, clock_id, job_type, date_in, due_date, terms) - VALUES (?, ?, ?, ?, ?, ?, ?)` + (order_number, customer_id, clock_id, job_type, date_in, due_date, terms, internal_note) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)` ) .run( orderNumber, @@ -147,7 +154,8 @@ router.post('/orders', (req, res) => { b.job_type || null, b.date_in || todayStr(), b.due_date || null, - b.terms || null + b.terms || null, + b.internal_note || null ); return Number(orderInfo.lastInsertRowid); @@ -167,6 +175,11 @@ router.get('/orders/:id', (req, res) => { res.render('orders/detail.njk', { order, jobTypes: JOB_TYPES, statuses: STATUSES }); }); +router.get('/orders/:id/totals', (req, res) => { + const totals = db.prepare('SELECT * FROM order_totals WHERE service_order_id = ?').get(req.params.id); + res.render('orders/_totals.njk', { order: { id: req.params.id }, totals }); +}); + router.post('/orders/:id/line-items', (req, res) => { const orderId = req.params.id; const b = req.body as Record; @@ -187,9 +200,9 @@ router.post('/orders/:id/line-items', (req, res) => { .run(orderId, kind, b.stock_code || null, b.description || null, quantity, unitPrice, countRow.n); const line = db.prepare('SELECT * FROM line_items WHERE id = ?').get(info.lastInsertRowid); - const totals = db.prepare('SELECT * FROM order_totals WHERE service_order_id = ?').get(orderId); - res.render('orders/_line_item_added.njk', { line, order: { id: orderId }, totals, oob: true }); + res.set('HX-Trigger', 'line-items-changed'); + res.render('orders/_line_item_row.njk', { line, order: { id: orderId } }); }); router.delete('/orders/:id/line-items/:lineId', (req, res) => { @@ -197,8 +210,8 @@ router.delete('/orders/:id/line-items/:lineId', (req, res) => { req.params.lineId, req.params.id ); - const totals = db.prepare('SELECT * FROM order_totals WHERE service_order_id = ?').get(req.params.id); - res.render('orders/_totals.njk', { totals, oob: true }); + res.set('HX-Trigger', 'line-items-changed'); + res.send(''); }); router.post('/orders/:id/work-log', (req, res) => { diff --git a/src/server.ts b/src/server.ts index eae4c98..3bfa123 100644 --- a/src/server.ts +++ b/src/server.ts @@ -20,6 +20,7 @@ env.addFilter('money', (cents: number) => formatCents(cents)); env.addFilter('lineTotal', (unitPrice: number, quantity: number) => formatCents(Math.round((quantity ?? 1) * (unitPrice ?? 0))) ); +env.addFilter('tel', (phone: string) => (phone || '').replace(/[^\d+]/g, '')); app.use(express.urlencoded({ extended: true })); app.use(express.static(path.join(process.cwd(), 'public'))); diff --git a/src/views/customers/list.njk b/src/views/customers/list.njk index 0538b10..dbe2064 100644 --- a/src/views/customers/list.njk +++ b/src/views/customers/list.njk @@ -18,22 +18,24 @@ Phone Email Address + {% for c in customers %} {{ c.name }} - {{ c.phone or '' }} + {% if c.phone %}{{ c.phone }}{% endif %} {{ c.email or '' }} {%- if c.address_line1 -%} {{ c.address_line1 }}{% if c.city %}, {{ c.city }}{% endif %}{% if c.state %}, {{ c.state }}{% endif %} {{ c.zip or '' }} {%- endif -%} + Orders {% else %} - No customers found. + No customers found. {% endfor %} diff --git a/src/views/invoice.njk b/src/views/invoice.njk index b691e83..5ff04a4 100644 --- a/src/views/invoice.njk +++ b/src/views/invoice.njk @@ -14,8 +14,8 @@
-

Harding's Clocks

-

Clock Sales & Repair

+

Jim Harding

+

Clock Repair | Phone: 434 660 2030

Invoice #{{ order.order_number }}

@@ -81,6 +81,7 @@
+

Cash or check only.

Thank you for your business.

diff --git a/src/views/orders/_line_item_added.njk b/src/views/orders/_line_item_added.njk deleted file mode 100644 index a5d4006..0000000 --- a/src/views/orders/_line_item_added.njk +++ /dev/null @@ -1,2 +0,0 @@ -{% include "orders/_line_item_row.njk" %} -{% include "orders/_totals.njk" %} diff --git a/src/views/orders/_totals.njk b/src/views/orders/_totals.njk index 480b281..ced12ac 100644 --- a/src/views/orders/_totals.njk +++ b/src/views/orders/_totals.njk @@ -1,4 +1,7 @@ -
+
Parts
{{ totals.total_parts | money }}
Labor
{{ totals.total_labor | money }}
Sublet
{{ totals.total_sublet | money }}
diff --git a/src/views/orders/list.njk b/src/views/orders/list.njk index 90eaa4e..dcc0f21 100644 --- a/src/views/orders/list.njk +++ b/src/views/orders/list.njk @@ -2,8 +2,13 @@ {% block title %}Orders — Harding's Clocks{% endblock %} {% block content %} diff --git a/src/views/orders/new.njk b/src/views/orders/new.njk index cd42dd8..ba571b0 100644 --- a/src/views/orders/new.njk +++ b/src/views/orders/new.njk @@ -67,6 +67,10 @@ +