feat(purchasing): show 'Supplier unknown' badge when OCR couldn't extract supplier

This commit is contained in:
DEls 2026-08-27 00:41:10 +02:00
parent e3c2e0396d
commit 9897f477b6
3 changed files with 53 additions and 6 deletions

View file

@ -23,7 +23,7 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { SlipPreview } from "@/components/slip-preview";
import { cn, formatCurrency, formatNumber } from "@/lib/utils";
import { cn, formatCurrency, formatNumber, isUnknownSupplier } from "@/lib/utils";
import type { DeliveryNoteProcessingStatus } from "@/lib/pb-types";
export interface PoDetailItem {
@ -152,7 +152,17 @@ export function PoDetailView({ detail }: { detail: PoDetail }) {
<h2 className="font-mono text-lg font-semibold tracking-tight">
{detail.poNumber}
</h2>
<span className="text-base font-medium">{detail.supplier || "—"}</span>
{isUnknownSupplier(detail.supplier) ? (
<Badge
variant="outline"
className="gap-1.5 border-amber-500/40 bg-amber-500/15 px-2 py-0.5 text-amber-700 dark:text-amber-300"
>
<AlertTriangle className="h-3.5 w-3.5" />
Supplier unknown
</Badge>
) : (
<span className="text-base font-medium">{detail.supplier}</span>
)}
<Badge variant="outline" className="font-mono text-xs">
{detail.projectCode || "—"}
</Badge>

View file

@ -26,7 +26,7 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Pagination } from "@/components/ui/pagination";
import { cn, formatCurrency, formatNumber } from "@/lib/utils";
import { cn, formatCurrency, formatNumber, isUnknownSupplier } from "@/lib/utils";
const PAGE_SIZE = 25;
const PO_BASE = "/dashboard/purchasing";
@ -331,9 +331,19 @@ function PoListItem({ po }: { po: PoRow }) {
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-baseline gap-x-3 gap-y-1">
<span className="font-mono text-sm font-semibold">{po.poNumber}</span>
<span className="truncate text-sm text-foreground">
{po.supplier || "—"}
</span>
{isUnknownSupplier(po.supplier) ? (
<Badge
variant="outline"
className="gap-1 border-amber-500/40 bg-amber-500/15 text-amber-700 dark:text-amber-300"
>
<AlertTriangle className="h-3 w-3" />
Supplier unknown
</Badge>
) : (
<span className="truncate text-sm text-foreground">
{po.supplier}
</span>
)}
<Badge variant="outline" className="font-mono text-xs">
{po.projectCode || "—"}
</Badge>

View file

@ -23,3 +23,30 @@ export function formatCurrency(n: number, currency = "ZAR") {
export function formatPercent(n: number, digits = 1) {
return `${n.toFixed(digits)}%`;
}
/**
* Strings that mean "OCR could not extract a real supplier" rather than
* a real vendor name. The OCR pipeline writes "Not specified in
* document" verbatim when the supplier line is missing; other placeholders
* ("Unknown", "N/A", "—") cover other pipelines. Anything in this set
* (case-insensitive, trimmed) renders as "Supplier unknown" in the UI
* instead of being displayed as if it were a real supplier.
*
* Kept as a Set literal rather than reading from config so it's easy to
* grep and extend — add more aliases here when OCR pipelines change.
*/
const UNKNOWN_SUPPLIER_ALIASES = new Set([
"",
"—",
"-",
"n/a",
"na",
"unknown",
"not specified",
"not specified in document",
]);
export function isUnknownSupplier(supplier: string | undefined | null): boolean {
if (!supplier) return true;
return UNKNOWN_SUPPLIER_ALIASES.has(supplier.trim().toLowerCase());
}