import { randomUUID } from "node:crypto"; import { getPool } from "../db/pool"; function nowIso() { return new Date().toISOString(); } function makeCode(prefix, id) { return `${prefix}_${id.slice(0, 6)}`; } function mapOutlet(row) { return { id: row.id, merchant_id: row.merchant_id, outlet_code: row.outlet_code, name: row.name, address: row.address || undefined, status: row.status, created_at: row.created_at, updated_at: row.updated_at }; } function mapTerminal(row) { return { id: row.id, outlet_id: row.outlet_id, terminal_code: row.terminal_code, qr_mode: row.qr_mode, partner_reference: row.partner_reference || undefined, status: row.status, created_at: row.created_at, updated_at: row.updated_at }; } export async function createOutlet(payload) { const id = randomUUID(); const now = nowIso(); const { rows } = await getPool().query(`INSERT INTO outlets (id, merchant_id, outlet_code, name, address, status, created_at, updated_at) VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING *`, [ id, payload.merchant_id, payload.outlet_code || makeCode("out", id), payload.name, payload.address, payload.status || "active", now, now ]); return mapOutlet(rows[0]); } export async function createTerminal(payload) { const id = randomUUID(); const now = nowIso(); const { rows } = await getPool().query(`INSERT INTO terminals (id, outlet_id, terminal_code, qr_mode, partner_reference, status, created_at, updated_at) VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING *`, [ id, payload.outlet_id, payload.terminal_code || makeCode("term", id), payload.qr_mode || "static", payload.partner_reference || null, payload.status || "active", now, now ]); return mapTerminal(rows[0]); } export async function listOutlets(filter) { const clauses = []; const params = []; let i = 1; if (filter?.merchant_id) { clauses.push(`merchant_id = $${i++}`); params.push(filter.merchant_id); } if (filter?.status) { clauses.push(`status = $${i++}`); params.push(filter.status); } if (filter?.q) { const value = `%${filter.q.toLowerCase()}%`; clauses.push(`(LOWER(name) LIKE $${i++} OR LOWER(outlet_code) LIKE $${i++})`); params.push(value, value); } const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : ""; const { rows } = await getPool().query(`SELECT * FROM outlets ${where} ORDER BY created_at DESC`, params); return rows.map(mapOutlet); } export async function listTerminals(filter) { const clauses = []; const params = []; let i = 1; if (filter?.outlet_id) { clauses.push(`outlet_id = $${i++}`); params.push(filter.outlet_id); } if (filter?.status) { clauses.push(`status = $${i++}`); params.push(filter.status); } if (filter?.q) { const value = `%${filter.q.toLowerCase()}%`; clauses.push(`(LOWER(terminal_code) LIKE $${i++} OR LOWER(COALESCE(partner_reference, '')) LIKE $${i++})`); params.push(value, value); } const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : ""; const { rows } = await getPool().query(`SELECT * FROM terminals ${where} ORDER BY created_at DESC`, params); return rows.map(mapTerminal); } export async function getOutletById(id) { const { rows } = await getPool().query("SELECT * FROM outlets WHERE id = $1", [id]); return rows[0] ? mapOutlet(rows[0]) : null; } export async function getTerminalById(id) { const { rows } = await getPool().query("SELECT * FROM terminals WHERE id = $1", [id]); return rows[0] ? mapTerminal(rows[0]) : null; } export async function patchOutlet(id, patch) { const existing = await getOutletById(id); if (!existing) { throw new Error("OUTLET_NOT_FOUND"); } const merged = { ...existing, ...patch, updated_at: nowIso() }; const { rows } = await getPool().query(`UPDATE outlets SET merchant_id = $2, outlet_code = $3, name = $4, address = $5, status = $6, updated_at = $7 WHERE id = $1 RETURNING *`, [ id, merged.merchant_id, merged.outlet_code, merged.name, merged.address || null, merged.status, merged.updated_at ]); return mapOutlet(rows[0]); } export async function patchTerminal(id, patch) { const existing = await getTerminalById(id); if (!existing) { throw new Error("TERMINAL_NOT_FOUND"); } const merged = { ...existing, ...patch, updated_at: nowIso() }; const { rows } = await getPool().query(`UPDATE terminals SET outlet_id = $2, terminal_code = $3, qr_mode = $4, partner_reference = $5, status = $6, updated_at = $7 WHERE id = $1 RETURNING *`, [ id, merged.outlet_id, merged.terminal_code, merged.qr_mode, merged.partner_reference || null, merged.status, merged.updated_at ]); return mapTerminal(rows[0]); } export function toOutletPayload(outlet) { return { ...outlet }; } export function toTerminalPayload(terminal) { return { ...terminal }; }