fix(suppliers): enforce Category → Supplier hierarchy, remove rogue-category bug

Domain model (v2.6): suppliers.category_id NOT NULL (1:N from the 8 fixed
categories), materials are global and link to suppliers via
supplier_materials. This fixes three regressions of the old inverted tree:

- remove the intermediate 'یک متریال را انتخاب کنید' screen: a category
  card now routes straight to that category's supplier list
  (/suppliers/category/:category); TopicPage is deleted and legacy
  /topics/:topic[/:category] URLs redirect to the new hierarchy
- kill the accidental-category bug: api.materials.create silently POSTed
  /material-categories for any unknown 'category' (a material name!), which
  is how the rogue «پریز» category (+ junk material) appeared. Unknown
  categories now fail loudly instead of creating catalog rows (DB cleaned:
  exactly the 8 canonical categories remain)
- fix inverted wording: supplier list is «تأمین‌کننده‌های این دسته» with
  category-first breadcrumbs; the legacy material multi-select on the
  add-supplier form is gone (a supplier gets the page's category)
- supplier details screen logic untouched — only its breadcrumb link
  targets were updated to the new routes
This commit is contained in:
ali_mohaghegh
2026-09-03 15:00:50 +03:30
parent b4ed18af71
commit f9ec68815e
7 changed files with 44 additions and 231 deletions
+9 -12
View File
@@ -959,19 +959,16 @@ export const api = {
},
create: async (m: Material): Promise<Material> => {
const lookup = await fetchLookup();
let categoryId = m.category ? lookup.categoryNameToId.get(norm(m.category)) : undefined;
// اگر دسته در بک‌اند نیست (مثلاً بعد از حذف seed) — بساز
if (!categoryId && m.category) {
const cat = await postData<RawMaterialCategory>("/material-categories", {
slug: norm(m.category) || "cat",
name: m.category,
is_active: true,
});
categoryId = cat.id;
lookup.categoryNameToId.set(norm(m.category), cat.id);
}
const categoryId = m.category ? lookup.categoryNameToId.get(norm(m.category)) : undefined;
// دسته‌ها همان ۸ دسته‌ی ثابت سیستم‌اند و هرگز به‌صورت خودکار ساخته
// نمی‌شوند — قبلاً این‌جا برای هر نامِ ناشناخته یک رکورد material_categories
// می‌ساخت و باگ «پریز» (دسته‌ی rogue) را به وجود آورد.
if (!categoryId) {
throw new Error(`متریال «${m.category}» در بک‌اند تعریف نشده است`);
throw new Error(
m.category
? `دسته «${m.category}» در سامانه تعریف نشده است — یکی از ۸ دسته‌ی موجود را انتخاب کنید`
: "دسته‌ی متریال مشخص نیست — یکی از ۸ دسته‌ی موجود را انتخاب کنید",
);
}
// واحد مرجع — اگر تعریف نشده، بساز (بک‌اند canonical_unit_id الزامی دارد)
const unitName = m.base_unit || "عدد";