diff --git a/server/src/routes/products.ts b/server/src/routes/products.ts
index 72730d9..2eea52e 100644
--- a/server/src/routes/products.ts
+++ b/server/src/routes/products.ts
@@ -91,6 +91,7 @@ productsRouter.post("/products", (req, res) => {
});
type UpdateBody = Partial<{
+ sku: string;
type: string;
kind: "bulk" | "discrete";
strainId: string | null;
@@ -105,13 +106,21 @@ productsRouter.patch("/products/:id", (req, res) => {
const existing = db
.prepare<
[string],
- { id: string; type: string; kind: string; strain_id: string; brand_id: string | null }
+ { id: string; sku: string; type: string; kind: string; strain_id: string; brand_id: string | null }
>(
- `SELECT id, type, kind, strain_id, brand_id FROM products WHERE id = ?`,
+ `SELECT id, sku, type, kind, strain_id, brand_id FROM products WHERE id = ?`,
)
.get(id);
if (!existing) return res.status(404).json({ error: "product not found" });
+ const nextSku = typeof body.sku === "string" && body.sku.trim() ? body.sku.trim() : existing.sku;
+ if (nextSku !== existing.sku) {
+ const duplicate = db
+ .prepare<[string, string], { id: string }>("SELECT id FROM products WHERE sku = ? AND id != ?")
+ .get(nextSku, id);
+ if (duplicate) return res.status(409).json({ error: "sku already exists" });
+ }
+
const nextType = typeof body.type === "string" && body.type ? body.type : existing.type;
const nextKind: "bulk" | "discrete" =
body.kind === "bulk" || body.kind === "discrete"
@@ -144,8 +153,8 @@ productsRouter.patch("/products/:id", (req, res) => {
}
db.prepare(
- `UPDATE products SET type = ?, kind = ?, strain_id = ?, brand_id = ? WHERE id = ?`,
- ).run(nextType, nextKind, nextStrainId, nextBrandId, id);
+ `UPDATE products SET sku = ?, type = ?, kind = ?, strain_id = ?, brand_id = ? WHERE id = ?`,
+ ).run(nextSku, nextType, nextKind, nextStrainId, nextBrandId, id);
res.json({ ok: true });
});
diff --git a/web/src/api.ts b/web/src/api.ts
index f73527b..cc59c0e 100644
--- a/web/src/api.ts
+++ b/web/src/api.ts
@@ -38,6 +38,7 @@ export const api = {
updateProduct: (
id: string,
body: Partial<{
+ sku: string;
type: string;
kind: "bulk" | "discrete";
strainId: string | null;
diff --git a/web/src/components/modals/SkuModals.tsx b/web/src/components/modals/SkuModals.tsx
index 92d9e0b..6535bf9 100644
--- a/web/src/components/modals/SkuModals.tsx
+++ b/web/src/components/modals/SkuModals.tsx
@@ -169,6 +169,7 @@ export function EditSkuModal({
const qc = useQueryClient();
const strain = data.strains.find((s) => s.id === product.strainId);
+ const [skuValue, setSkuValue] = useState(product.sku);
const [strainName, setStrainName] = useState(strain?.name ?? "");
const [brandId, setBrandId] = useState(product.brandId ?? "");
const [typeId, setTypeId] = useState(product.type);
@@ -188,6 +189,7 @@ export function EditSkuModal({
const updateProduct = useMutation({
mutationFn: async () => {
await api.updateProduct(product.id, {
+ sku: skuValue.trim(),
type: typeId,
kind: selectedType.kind,
strainName: strainName.trim(),
@@ -221,11 +223,18 @@ export function EditSkuModal({
boxShadow: "var(--shadow-lg)",
}}
>
-