/plant and /plant/map import Fuel Logs CSVs by exact QR and show each vehicle's current and previous distinct site with the dates they were observed. - plant_site_observations is durable, QR-keyed history. It is never wiped and a previous site is never manufactured. - An older or repeated snapshot must not move a vehicle backwards; untimed conflicting sites on one day are held for review. - A manual site change shares the same history and the same lock. - Current/previous metadata and the sticker QR are captured BEFORE the asset rows are deleted in the seed, so a re-seed cannot wipe them. Explicit empty values are preserved too: clearing a site is a deliberate manual observation, not permission to restore an old sheet value. - Imports change location metadata only. They never touch income, cost or fuel measurements. - A new named site is created only for a matched Plant vehicle. Missing coordinates mean "awaiting a pin", never a headquarters fallback. Owner-confirmed 2026-11-04: TLB06's QR is 1089, not the old meter reading 4704. lib/plant-site-policy.json holds the confirmed aliases (Equestria Bastion Job -> Equestria 215, Cosmo City / Lion Park -> Cosmo City); no other identity is guessed.
28 lines
1.6 KiB
TypeScript
28 lines
1.6 KiB
TypeScript
type SiteHistory = {
|
|
site_label?: string;
|
|
previous_site_label?: string;
|
|
site_observed_on?: string;
|
|
previous_site_observed_on?: string;
|
|
site_source?: string;
|
|
};
|
|
|
|
export function siteSeenDate(value?: string) {
|
|
if (!value) return "Unknown";
|
|
const date = new Date(value.length === 10 ? `${value}T12:00:00Z` : value);
|
|
return Number.isNaN(date.getTime()) ? "Unknown" : date.toLocaleDateString("en-ZA", { day: "numeric", month: "short", year: "numeric", timeZone: "Africa/Johannesburg" });
|
|
}
|
|
|
|
export function VehicleSiteHistory({ asset, currentSite, previousSite }: {
|
|
asset: SiteHistory;
|
|
currentSite?: string | null;
|
|
previousSite?: string;
|
|
}) {
|
|
const source = asset.site_source === "fuel-log" ? "Fuel log" : asset.site_source === "manual" ? "Manual assignment" : "Source not recorded";
|
|
return (
|
|
<dl className="space-y-1.5 text-xs leading-relaxed text-gray-600 dark:text-gray-300">
|
|
<div><dt className="font-medium text-[#003D5B] dark:text-white">Current site</dt><dd className="break-words">{asset.site_label || currentSite || "Unassigned"}</dd></div>
|
|
<div><dt className="font-medium text-[#003D5B] dark:text-white">Previous site</dt><dd className="break-words">{asset.previous_site_label || previousSite || "Unknown — no earlier different site recorded"}{asset.previous_site_observed_on && <span className="block text-gray-500 dark:text-gray-400">{siteSeenDate(asset.previous_site_observed_on)}</span>}</dd></div>
|
|
<div><dt className="font-medium text-[#003D5B] dark:text-white">Last seen</dt><dd>{siteSeenDate(asset.site_observed_on)} · {source}</dd></div>
|
|
</dl>
|
|
);
|
|
}
|