feat(barcode): admin barcode CRUD endpoints + UI; show extra barcodes publicly
CI / Python (ingestion) (pull_request) Successful in 10s
CI / Go (api) (pull_request) Failing after 15s
CI / Migrations (postgres) (pull_request) Failing after 11m35s

Wire the multi-barcode store layer to HTTP and the operator console:

- adminhandler: add POST /products/{id}/barcodes, DELETE
  /products/{id}/barcodes/{barcodeID}, and POST .../primary. A barcode
  owned by another product returns 409 with the conflicting product
  (gtin/product_id/product_name); an invalid GTIN returns 400.
- admin-frontend: BarcodesCard on the product detail page lists all
  barcodes (primary starred), adds with type/pack-level/region, sets
  primary, and deletes; audit labels for the new actions.
- public-frontend: product detail surfaces non-primary barcodes so a
  case/region code resolves and is visible to consumers.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
novaalphastrikeomegaz663
2026-06-20 07:06:07 +00:00
parent 1d5f775d33
commit 98b5f1575d
6 changed files with 286 additions and 0 deletions
+14
View File
@@ -86,6 +86,20 @@ export const api = {
request<{ status: string }>(`/products/${id}/msrp/${msrpId}`, {
method: "DELETE",
}),
addBarcode: (id: string, body: unknown) =>
request<import("./types").Barcode>(`/products/${id}/barcodes`, {
method: "POST",
body: JSON.stringify(body),
}),
deleteBarcode: (id: string, barcodeId: string) =>
request<{ status: string }>(`/products/${id}/barcodes/${barcodeId}`, {
method: "DELETE",
}),
setPrimaryBarcode: (id: string, barcodeId: string) =>
request<import("./types").Barcode>(
`/products/${id}/barcodes/${barcodeId}/primary`,
{ method: "POST" },
),
listBrands: () =>
request<{ items: import("./types").Brand[] }>("/brands"),
listCategories: () =>