Files
2026-09-28 23:15:47 +05:30

70 lines
2.3 KiB
TypeScript

import type { RowDataPacket } from "mysql2/promise";
import { getPool } from "./db";
import { normalizePhone } from "./phone";
import { sqlDateToIso } from "./time";
import { NO_BIKE, pickWorkshopJob, stageLabel, type BikeStatus, type StatusResult } from "./workshop";
export async function lookupBikes(rawPhone: string): Promise<StatusResult> {
const phone = normalizePhone(rawPhone);
if (!phone) return { message: NO_BIKE, error: null, bikes: [] };
const pool = getPool();
const [customers] = await pool.query<RowDataPacket[]>(
`SELECT id FROM customers WHERE phone = ? AND deleted_at IS NULL`,
[phone],
);
if (customers.length === 0) return { message: NO_BIKE, error: null, bikes: [] };
const customerIds = customers.map((row) => String(row.id));
const [vehicles] = await pool.query<RowDataPacket[]>(
`SELECT id, registration, make, model_name FROM vehicles
WHERE customer_id IN (${customerIds.map(() => "?").join(", ")}) AND deleted_at IS NULL
ORDER BY registration ASC, id ASC`,
customerIds,
);
if (vehicles.length === 0) return { message: NO_BIKE, error: null, bikes: [] };
const bikes: BikeStatus[] = [];
for (const vehicle of vehicles) {
const [jobs] = await pool.query<RowDataPacket[]>(
`SELECT id, stage, created_at FROM job_cards WHERE vehicle_id = ? AND deleted_at IS NULL`,
[vehicle.id],
);
const picked = pickWorkshopJob(
jobs.map((job) => ({
id: String(job.id),
stage: String(job.stage),
createdAt: sqlDateToIso(job.created_at) ?? "",
})),
);
const registration = String(vehicle.registration ?? "");
const make = String(vehicle.make ?? "");
const model = String(vehicle.model_name ?? "");
if (!picked) {
bikes.push({
registration,
make,
model,
inWorkshop: false,
stageLabel: null,
stageAt: null,
});
continue;
}
const [events] = await pool.query<RowDataPacket[]>(
"SELECT `at` FROM job_card_events WHERE job_card_id = ? AND deleted_at IS NULL ORDER BY `at` DESC, id DESC LIMIT 1",
[picked.id],
);
bikes.push({
registration,
make,
model,
inWorkshop: true,
stageLabel: stageLabel(picked.stage),
stageAt: events[0] ? sqlDateToIso(events[0].at) : null,
});
}
return { message: null, error: null, bikes };
}