feat: add customer cart with expiry, shipping addresses with USPS validation, and multi-item PayPal checkout
SonarQube Analysis / sonarqube (pull_request) Failing after 59s
Tests / backend-unit (pull_request) Successful in 34s
Tests / backend-integration (pull_request) Failing after 1m33s
Tests / frontend-e2e (pull_request) Failing after 1m5s

This commit is contained in:
2026-08-14 14:02:25 -05:00
parent 433d7e1db5
commit 9ab689e624
18 changed files with 1242 additions and 189 deletions
+104
View File
@@ -0,0 +1,104 @@
import { Router, Request, Response } from 'express';
import { pool } from '../db';
import { requireCustomer } from '../middleware/customerAuth';
import { validateAddress, uspsConfigured } from '../usps';
const router = Router();
router.get('/', requireCustomer, async (req: Request, res: Response) => {
const { rows } = await pool.query(
`SELECT * FROM shipping_addresses WHERE customer_id = $1 ORDER BY is_default DESC, created_at DESC`,
[req.customerId]
);
res.json(rows);
});
router.post('/', requireCustomer, async (req: Request, res: Response) => {
const { fullName, addressLine1, addressLine2, city, state, postalCode, country, isDefault } = req.body;
if (!fullName || !addressLine1 || !city || !state || !postalCode) {
return res.status(400).json({ error: 'fullName, addressLine1, city, state, and postalCode are required' });
}
let uspsResult = { validated: false, deliverable: null as boolean | null, standardized: null as Record<string, unknown> | null, reason: undefined as string | undefined };
if ((country || 'US') === 'US') {
uspsResult = await validateAddress({ addressLine1, addressLine2, city, state, postalCode });
}
const client = await pool.connect();
try {
await client.query('BEGIN');
if (isDefault) {
await client.query(`UPDATE shipping_addresses SET is_default = false WHERE customer_id = $1`, [req.customerId]);
}
const { rows } = await client.query(
`INSERT INTO shipping_addresses
(customer_id, full_name, address_line1, address_line2, city, state, postal_code, country, is_default, usps_validated, usps_standardized)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING *`,
[
req.customerId, fullName, addressLine1, addressLine2 || null, city, state, postalCode,
country || 'US', !!isDefault, uspsResult.deliverable === true, uspsResult.standardized
]
);
await client.query('COMMIT');
res.status(201).json({ address: rows[0], uspsCheck: uspsResult, uspsConfigured: uspsConfigured() });
} catch (err) {
await client.query('ROLLBACK');
console.error(err);
res.status(500).json({ error: 'internal error' });
} finally {
client.release();
}
});
router.put('/:id', requireCustomer, async (req: Request, res: Response) => {
const { fullName, addressLine1, addressLine2, city, state, postalCode, country, isDefault } = req.body;
const client = await pool.connect();
try {
await client.query('BEGIN');
if (isDefault) {
await client.query(`UPDATE shipping_addresses SET is_default = false WHERE customer_id = $1`, [req.customerId]);
}
const { rows } = await client.query(
`UPDATE shipping_addresses
SET full_name=$1, address_line1=$2, address_line2=$3, city=$4, state=$5, postal_code=$6, country=$7, is_default=$8,
usps_validated = false, usps_standardized = NULL
WHERE id=$9 AND customer_id=$10 RETURNING *`,
[fullName, addressLine1, addressLine2 || null, city, state, postalCode, country || 'US', !!isDefault, req.params.id, req.customerId]
);
if (!rows.length) { await client.query('ROLLBACK'); return res.status(404).json({ error: 'not found' }); }
await client.query('COMMIT');
res.json(rows[0]);
} catch (err) {
await client.query('ROLLBACK');
console.error(err);
res.status(500).json({ error: 'internal error' });
} finally {
client.release();
}
});
router.delete('/:id', requireCustomer, async (req: Request, res: Response) => {
await pool.query(`DELETE FROM shipping_addresses WHERE id = $1 AND customer_id = $2`, [req.params.id, req.customerId]);
res.status(204).end();
});
router.post('/:id/set-default', requireCustomer, async (req: Request, res: Response) => {
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query(`UPDATE shipping_addresses SET is_default = false WHERE customer_id = $1`, [req.customerId]);
const { rows } = await client.query(
`UPDATE shipping_addresses SET is_default = true WHERE id = $1 AND customer_id = $2 RETURNING *`,
[req.params.id, req.customerId]
);
await client.query('COMMIT');
res.json(rows[0]);
} catch (err) {
await client.query('ROLLBACK');
res.status(500).json({ error: 'internal error' });
} finally {
client.release();
}
});
export default router;