import { randomUUID } from "node:crypto"; import { getPool } from "../db/pool"; function nowIso() { return new Date().toISOString(); } function makeCode(id) { return `m_${id.slice(0, 6)}`; } function toPublic(entity) { return entity; } function mapRowToMerchant(row) { return { id: row.id, merchant_code: row.merchant_code, legal_name: row.legal_name, brand_name: row.brand_name || undefined, settlement_account_reference: row.settlement_account_reference || undefined, settlement_account_type: row.settlement_account_type || undefined, payout_mode: row.payout_mode, fee_profile_id: row.fee_profile_id || undefined, status: row.status, onboarding_status: row.onboarding_status, created_at: row.created_at, updated_at: row.updated_at }; } export async function createMerchant(payload) { const id = randomUUID(); const now = nowIso(); const payoutMode = payload.payout_mode || "merchant_direct"; const { rows } = await getPool().query(`INSERT INTO merchants ( id, merchant_code, legal_name, brand_name, settlement_account_reference, settlement_account_type, payout_mode, fee_profile_id, status, onboarding_status, created_at, updated_at ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12) RETURNING *`, [ id, makeCode(id), payload.legal_name, payload.brand_name, payload.settlement_account_reference, payload.settlement_account_type, payoutMode, payload.fee_profile_id, payload.status || "active", payload.onboarding_status || "pending", now, now ]); return toPublic(mapRowToMerchant(rows[0])); } export async function getMerchantById(id) { const { rows } = await getPool().query("SELECT * FROM merchants WHERE id = $1", [id]); if (rows.length === 0) { return null; } return mapRowToMerchant(rows[0]); } export async function listMerchants() { const { rows } = await getPool().query("SELECT * FROM merchants ORDER BY created_at DESC"); return rows.map(mapRowToMerchant); } export async function patchMerchant(id, patch) { const existing = await getMerchantById(id); if (!existing) { throw new Error("MERCHANT_NOT_FOUND"); } const merged = { ...existing, ...patch, updated_at: nowIso() }; const { rows } = await getPool().query(`UPDATE merchants SET legal_name = $2, brand_name = $3, settlement_account_reference = $4, settlement_account_type = $5, payout_mode = $6, fee_profile_id = $7, status = $8, onboarding_status = $9, updated_at = $10 WHERE id = $1 RETURNING *`, [ id, merged.legal_name, merged.brand_name, merged.settlement_account_reference, merged.settlement_account_type, merged.payout_mode, merged.fee_profile_id, merged.status, merged.onboarding_status, merged.updated_at ]); return mapRowToMerchant(rows[0]); } export function toMerchantPayload(m) { return { id: m.id, merchant_code: m.merchant_code, legal_name: m.legal_name, brand_name: m.brand_name, settlement_account_reference: m.settlement_account_reference, settlement_account_type: m.settlement_account_type, payout_mode: m.payout_mode, fee_profile_id: m.fee_profile_id, status: m.status, onboarding_status: m.onboarding_status, created_at: m.created_at, updated_at: m.updated_at }; }