98 lines
3.4 KiB
JavaScript
98 lines
3.4 KiB
JavaScript
import { randomUUID } from "node:crypto";
|
|
import { getPool, withClient } from "../db/pool";
|
|
function nowIso() {
|
|
return new Date().toISOString();
|
|
}
|
|
function mapBinding(row) {
|
|
return {
|
|
id: row.id,
|
|
device_id: row.device_id,
|
|
merchant_id: row.merchant_id,
|
|
outlet_id: row.outlet_id,
|
|
terminal_id: row.terminal_id,
|
|
active_flag: row.active_flag,
|
|
bound_at: row.bound_at,
|
|
unbound_at: row.unbound_at || undefined
|
|
};
|
|
}
|
|
export async function getActiveBindingByDevice(deviceId) {
|
|
const { rows } = await getPool().query(`SELECT * FROM device_bindings
|
|
WHERE device_id = $1 AND active_flag = TRUE
|
|
ORDER BY bound_at DESC
|
|
LIMIT 1`, [deviceId]);
|
|
return rows[0] ? mapBinding(rows[0]) : null;
|
|
}
|
|
export async function getActiveBindingByTerminal(terminalId) {
|
|
const { rows } = await getPool().query(`SELECT * FROM device_bindings
|
|
WHERE terminal_id = $1 AND active_flag = TRUE
|
|
ORDER BY bound_at DESC
|
|
LIMIT 1`, [terminalId]);
|
|
return rows[0] ? mapBinding(rows[0]) : null;
|
|
}
|
|
export async function getBindingsByDeviceId(deviceId) {
|
|
const { rows } = await getPool().query(`SELECT * FROM device_bindings
|
|
WHERE device_id = $1
|
|
ORDER BY bound_at DESC`, [deviceId]);
|
|
return rows.map(mapBinding);
|
|
}
|
|
export async function bindDevice(payload) {
|
|
const now = nowIso();
|
|
const result = await withClient(async (client) => {
|
|
const existing = await client.query(`SELECT * FROM device_bindings
|
|
WHERE device_id = $1 AND active_flag = TRUE
|
|
ORDER BY bound_at DESC
|
|
LIMIT 1`, [payload.device_id]);
|
|
const same = existing.rows[0]
|
|
? mapBinding(existing.rows[0])
|
|
: null;
|
|
if (same &&
|
|
same.merchant_id === payload.merchant_id &&
|
|
same.outlet_id === payload.outlet_id &&
|
|
same.terminal_id === payload.terminal_id) {
|
|
return same;
|
|
}
|
|
await client.query("BEGIN");
|
|
try {
|
|
if (existing.rows[0]) {
|
|
await client.query(`UPDATE device_bindings
|
|
SET active_flag = FALSE, unbound_at = $2
|
|
WHERE id = $1`, [same.id, now]);
|
|
}
|
|
const id = randomUUID();
|
|
const inserted = await client.query(`INSERT INTO device_bindings (
|
|
id,
|
|
device_id,
|
|
merchant_id,
|
|
outlet_id,
|
|
terminal_id,
|
|
active_flag,
|
|
bound_at
|
|
) VALUES ($1,$2,$3,$4,$5,TRUE,$6)
|
|
RETURNING *`, [id, payload.device_id, payload.merchant_id, payload.outlet_id, payload.terminal_id, now]);
|
|
await client.query("COMMIT");
|
|
return mapBinding(inserted.rows[0]);
|
|
}
|
|
catch (error) {
|
|
await client.query("ROLLBACK");
|
|
throw error;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
export async function unbindDevice(deviceId) {
|
|
const now = nowIso();
|
|
const { rows } = await getPool().query(`UPDATE device_bindings
|
|
SET active_flag = FALSE,
|
|
unbound_at = $2
|
|
WHERE device_id = $1 AND active_flag = TRUE
|
|
RETURNING *`, [deviceId, now]);
|
|
return rows[0] ? mapBinding(rows[0]) : null;
|
|
}
|
|
export async function getBindingById(id) {
|
|
const { rows } = await getPool().query("SELECT * FROM device_bindings WHERE id = $1", [id]);
|
|
return rows[0] ? mapBinding(rows[0]) : null;
|
|
}
|
|
export function toBindingPayload(binding) {
|
|
return { ...binding };
|
|
}
|