require('dotenv').config(); const path = require('path'); const express = require('express'); const { savePayment, listPayments, countPayments } = require('./db'); const { createPaymentLink } = require('./payment-api'); const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); app.use(express.static(path.join(__dirname, 'public'))); function toNumber(v) { const n = parseFloat(v); return Number.isFinite(n) ? n : 0; } const ALLOWED_CURRENCIES = ['USD', 'AUD']; // --- Create payment link --------------------------------------------------- app.post('/api/payments', async (req, res) => { const { customerName, email, phone, address, currency, items } = req.body || {}; // All customer fields are required. const customerFields = { customerName, email, phone, address }; const CUSTOMER_LABELS = { customerName: 'Customer name', email: 'Email', phone: 'Phone number', address: 'Address', }; const missingCustomer = Object.keys(CUSTOMER_LABELS).filter( (k) => !customerFields[k] || !String(customerFields[k]).trim() ); if (missingCustomer.length) { return res.status(400).json({ error: `Missing required field(s): ${missingCustomer.map((k) => CUSTOMER_LABELS[k]).join(', ')}.`, }); } const cleanItems = Array.isArray(items) ? items : []; if (cleanItems.length === 0) { return res.status(400).json({ error: 'At least one item is required.' }); } const cleanCurrency = ALLOWED_CURRENCIES.includes(currency) ? currency : 'AUD'; const normItems = cleanItems.map((it) => ({ sku: (it.sku || '').trim(), name: (it.name || '').trim(), price: toNumber(it.price), quantity: toNumber(it.quantity), condition: (it.condition || '').trim(), })); // Each item requires SKU, a positive price, a positive quantity and a condition. for (let i = 0; i < normItems.length; i++) { const it = normItems[i]; const missing = []; if (!it.sku) missing.push('SKU'); if (!(it.price > 0)) missing.push('price'); if (!(it.quantity > 0)) missing.push('quantity'); if (!it.condition) missing.push('condition'); if (missing.length) { return res .status(400) .json({ error: `Item ${i + 1} is missing required field(s): ${missing.join(', ')}.` }); } } const total = normItems.reduce((sum, it) => sum + it.price * it.quantity, 0); // Sequential quote number based on how many payments already exist: // first ever -> QT000001, when history already has 9 -> QT000010. const quoteNumber = `QT${String(countPayments() + 1).padStart(6, '0')}`; try { const dataPayment = await createPaymentLink({ customerName, email, phone, address, currency: cleanCurrency, quoteNumber, items: normItems, total, }); const saved = savePayment({ customer_name: customerName, email: email || '', phone: phone || '', address: address || '', items_json: JSON.stringify(normItems), total, currency: cleanCurrency, payment_link: dataPayment.link, status: 'created', }); res.json({ ok: true, payment: saved, link: dataPayment.link, raw: dataPayment.raw }); } catch (err) { console.error('createPaymentLink error:', err); res.status(502).json({ error: err.message || 'Failed to create payment link.' }); } }); // --- History --------------------------------------------------------------- app.get('/api/payments', (_req, res) => { res.json({ ok: true, payments: listPayments() }); }); app.listen(PORT, () => { console.log(`Quick Payment server running: http://localhost:${PORT}`); });