fix(wizard): allow global materials without a canonical category

Quote creation was blocked for any new material whose typed name is not
one of the 8 canonical category names: api.materials.create threw
«دسته ... در سامانه تعریف نشده است» and the failed create cascaded a
bogus temp material_id into the quote payload (invalid-payload error).

v2.5+ model: materials are global (name UNIQUE) and the category
attaches via the supplier (first-link-wins). The backend already
accepts category_id=null (MaterialCreate schema + material_service).
This removes the frontend-only hard block: unknown category names now
create the material with category_id null, and the category is derived
automatically from the first linked supplier on quote save. The 8
canonical categories are still never auto-created (no rogue-category
regression).

Verified end-to-end through the real API: create «سیم» (category null)
→ supplier → quote via material_id → 201/201/201 with
material.category_id derived from the supplier; lint + build green.
This commit is contained in:
2026-09-06 15:39:09 +03:30
parent 93230d367c
commit c5bbbbbaaa
+6 -11
View File
@@ -959,17 +959,12 @@ export const api = {
},
create: async (m: Material): Promise<Material> => {
const lookup = await fetchLookup();
// v2.5: category_id اختیاری است — اگر نامِ تایپ‌شده یکی از ۸ دسته‌ی ثابت
// نباشد، متریال به‌صورت سراسری (بدون دسته) ساخته می‌شود و دسته‌اش بعداً
// از اولین تأمین‌کننده‌ی مرتبط استنتاج می‌شود (first-link-wins).
// دسته‌ی rogue دیگر هرگز ساخته نمی‌شود — فقط تطبیق با ۸ دسته‌ی موجود؛
// در صورت نبود تطبیق، خطا نمی‌دهیم و category_id را null می‌فرستیم.
const categoryId = m.category ? lookup.categoryNameToId.get(norm(m.category)) : undefined;
// دسته‌ها همان ۸ دسته‌ی ثابت سیستم‌اند و هرگز به‌صورت خودکار ساخته
// نمی‌شوند — قبلاً این‌جا برای هر نامِ ناشناخته یک رکورد material_categories
// می‌ساخت و باگ «پریز» (دسته‌ی rogue) را به وجود آورد.
if (!categoryId) {
throw new Error(
m.category
? `دسته «${m.category}» در سامانه تعریف نشده است — یکی از ۸ دسته‌ی موجود را انتخاب کنید`
: "دسته‌ی متریال مشخص نیست — یکی از ۸ دسته‌ی موجود را انتخاب کنید",
);
}
// واحد مرجع — اگر تعریف نشده، بساز (بک‌اند canonical_unit_id الزامی دارد)
const unitName = m.base_unit || "عدد";
const unitId = await unitIdByNameOrCreate(lookup, unitName);
@@ -988,7 +983,7 @@ export const api = {
if (defId) attrs.push({ attribute_definition_id: defId, value: spec });
}
const raw = await postData<RawMaterial>("/materials", {
category_id: categoryId,
category_id: categoryId ?? null,
name,
topic: m.topic || null,
canonical_unit_id: unitId,