/** * Allowlisted columns a user may read from their own payment orders. * Sensitive settlement material (epay_trade_no, raw_notify_payload_hash, * user_id, full snapshots) is deliberately excluded. */ export const PAYMENT_ORDERS_SELECT = [ "order_no", "product_code", "product_snapshot", "money_cents", "status", "grant_status", "created_at", "paid_at", ] as const; export type PaymentOrderRow = { order_no: string; product_code: string | null; product_snapshot: { name?: string } | null; money_cents: number; status: string; grant_status: string; created_at: Date | string; paid_at: Date | string | null; }; export type PaymentOrderSummary = { orderNo: string; product: string | null; name: string | null; price: number; status: string; grantStatus: string; createdAt: string; paidAt: string | null; }; function toIso(value: Date | string): string { return value instanceof Date ? value.toISOString() : value; } export function formatPaymentOrders( rows: readonly PaymentOrderRow[], ): PaymentOrderSummary[] { return rows.map((row) => ({ orderNo: row.order_no, product: row.product_code, name: row.product_snapshot?.name ?? row.product_code, price: row.money_cents, status: row.status, grantStatus: row.grant_status, createdAt: toIso(row.created_at), paidAt: row.paid_at ? toIso(row.paid_at) : null, })); }