Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/docs/SCENARIO_BOM_TO_INVOICE.md
2026-04-14 19:34:55 +03:30

20 KiB
Executable file
Raw Permalink Blame History

سناریو: تولید کالا از طریق فاکتور تولید با استفاده از فرمول تولید (BOM)

اصل طراحی

فرمول تولید (BOM) که منجر به تولید کالای جدید می‌شود، صرفاً از طریق فاکتور تولید انجام می‌شود.

این یعنی:

  • ✅ اجباری: هر فاکتور تولید باید از یک فرمول تولید استفاده کند
  • ✅ یکپارچه: تمام فرآیند تولید از تعریف فرمول تا صدور فاکتور در یک جریان یکپارچه انجام می‌شود
  • ✅ قابل ردیابی: هر فاکتور تولید به یک فرمول مشخص لینک می‌شود

وضعیت فعلی

1. مدیریت فرمول تولید (BOM) در بخش کالا

  • مکان: تب "فرمول تولید" در فرم ویرایش/ایجاد کالا (product_form_dialog.dart)
  • عملکرد فعلی:
    • کاربر می‌تواند فرمول‌های تولید را برای هر کالا تعریف کند
    • فرمول‌ها در جدول product_boms ذخیره می‌شوند و به کالا لینک می‌شوند (product_id)
    • هر فرمول می‌تواند چندین نسخه داشته باشد (version)
    • یک فرمول می‌تواند به عنوان پیش‌فرض تنظیم شود (is_default)
    • حذف شده: دکمه "انفجار فرمول" از این بخش حذف شده است

2. صدور فاکتور تولید

  • مکان: صفحه new_invoice_page.dart
  • نوع فاکتور: InvoiceType.production (مقدار API: invoice_production)
  • عملکرد فعلی:
    • کاربر می‌تواند فاکتور از نوع "تولید" را ایجاد کند
    • ویجت BomExplosionWidget برای استفاده از فرمول‌های تولید موجود است
    • اما استفاده از BOM اجباری نیست (مشکل)

مشکل فعلی

  1. ❌ استفاده از BOM اجباری نیست: کاربر می‌تواند فاکتور تولید بدون استفاده از فرمول تولید ایجاد کند
  2. ❌ movement تنظیم نمی‌شود: در BOM Explosion، مقدار movement در extra_info ردیف‌ها ذخیره نمی‌شود
  3. ❌ عدم ردیابی: فاکتور تولید به فرمول استفاده شده لینک نمی‌شود
  4. ❌ امکان خطا: کاربر می‌تواند به صورت دستی ردیف‌های نادرست اضافه کند

سناریو بازطراحی شده

اصول طراحی

  1. ✅ اجبار استفاده از BOM: هر فاکتور تولید باید حداقل از یک فرمول تولید استفاده کند
  2. ✅ مدیریت فرمول در بخش کالا: فرمول‌ها همچنان در تب "فرمول تولید" کالا تعریف و مدیریت می‌شوند
  3. ✅ انفجار در فاکتور: انفجار فرمول فقط در صفحه صدور فاکتور تولید انجام می‌شود
  4. ✅ ردیابی کامل: هر فاکتور تولید به فرمول(های) استفاده شده لینک می‌شود
  5. ✅ حرکت خودکار: مقدار movement در extra_info به صورت خودکار تنظیم می‌شود

تغییرات پیشنهادی

1. بخش کالا (Frontend - product_bom_section.dart)

تغییرات:

  • ✅ حفظ: مدیریت فرمول‌ها (ایجاد، ویرایش، حذف) همچنان در این بخش باقی می‌ماند
  • ❌ حذف: دکمه "انفجار فرمول" از این بخش حذف می‌شود
  • ❌ حذف: دیالوگ نمایش نتایج انفجار و ایجاد پیش‌نویس سند حذف می‌شود
  • ✅ افزودن: یک پیام راهنما یا لینک به کاربر که "برای استفاده از این فرمول، در فاکتور تولید از آن استفاده کنید"

2. صفحه صدور فاکتور تولید (Frontend - new_invoice_page.dart)

تغییرات:

  • ✅ اجبار استفاده از BOM:
    • اگر نوع فاکتور "تولید" است، کاربر نمی‌تواند فاکتور را ذخیره کند مگر اینکه حداقل یک بار انفجار فرمول انجام داده باشد
    • یک پیام هشدار نمایش داده می‌شود: "برای فاکتور تولید، باید حداقل یک فرمول تولید را منفجر کنید"
  • ✅ ویجت انفجار فرمول (بهبود یافته):
    • انتخاب کالای تولیدی (از لیست کالاها)
    • نمایش فرمول‌های موجود برای آن کالا (اگر فرمول پیش‌فرض وجود دارد، به صورت پیش‌فرض انتخاب شود)
    • امکان انتخاب فرمول خاص (اگر چند فرمول وجود دارد)
    • ورود مقدار تولید
    • دکمه "انفجار و افزودن به فاکتور"
    • جدید: پس از انفجار، ID فرمول در extra_info فاکتور ذخیره می‌شود
  • ✅ پس از انفجار (بهبود یافته):
    • نتایج انفجار به صورت ردیف‌های فاکتور به _lineItems اضافه می‌شوند
    • اجباری: مواد اولیه (inputs) با movement: "out" در extra_info تنظیم می‌شوند
    • اجباری: خروجی‌ها (outputs) با movement: "in" در extra_info تنظیم می‌شوند
    • جدید: ID فرمول استفاده شده در extra_info هر ردیف ذخیره می‌شود (برای ردیابی)
    • کاربر می‌تواند قبل از ذخیره، ردیف‌ها را ویرایش کند (مقدار، قیمت، انبار)
    • جدید: امکان انفجار چند فرمول در یک فاکتور (برای محصولات مختلف)
  • ✅ اعتبارسنجی قبل از ذخیره:
    • بررسی می‌شود که حداقل یک ردیف با movement: "out" وجود دارد (مواد اولیه)
    • بررسی می‌شود که حداقل یک ردیف با movement: "in" وجود دارد (محصول نهایی)
    • بررسی می‌شود که تمام ردیف‌های فاکتور movement مشخص داشته باشند

3. Backend (تغییرات اعتبارسنجی)

  • ✅ API explode_bom همچنان موجود است و استفاده می‌شود
  • ✅ جدید: اعتبارسنجی در create_invoice:
    • اگر نوع فاکتور invoice_production است:
      • بررسی می‌شود که حداقل یک ردیف با movement: "out" وجود دارد
      • بررسی می‌شود که حداقل یک ردیف با movement: "in" وجود دارد
      • بررسی می‌شود که تمام ردیف‌ها movement مشخص داشته باشند
      • در صورت عدم وجود، خطا: "فاکتور تولید باید از فرمول تولید استفاده کند"
  • ✅ جدید: ذخیره اطلاعات فرمول:
    • در extra_info فاکتور، لیست ID فرمول‌های استفاده شده ذخیره می‌شود: {"bom_ids": [1, 2]}
    • در extra_info هر ردیف، ID فرمول استفاده شده ذخیره می‌شود: {"bom_id": 1}
  • ✅ ساختار دیتابیس بدون تغییر باقی می‌ماند

جریان کار طراحی شده

1. کاربر در بخش کالا (تعریف فرمول):
   └─> کالای تولیدی را ایجاد/ویرایش می‌کند
   └─> در تب "فرمول تولید"، فرمول‌های تولید را تعریف می‌کند:
       ├─ مواد اولیه (component products)
       ├─ خروجی‌ها (output products)
       └─ عملیات (operations)
   └─> فرمول را ذخیره می‌کند
   └─> (اختیاری) فرمولی را به عنوان پیش‌فرض تنظیم می‌کند

2. کاربر برای صدور فاکتور تولید:
   └─> به صفحه "صدور فاکتور جدید" می‌رود
   └─> نوع فاکتور را "تولید" انتخاب می‌کند
   └─> به تب "کالاها و خدمات" می‌رود
   └─> ⚠️ سیستم بررسی می‌کند که آیا فرمولی منفجر شده است؟
       ├─ خیر: نمایش پیام هشدار "برای فاکتور تولید، باید حداقل یک فرمول تولید را منفجر کنید"
       └─ بله: ادامه روند
   └─> دکمه "انفجار فرمول" را می‌زند
   └─> کالای تولیدی را انتخاب می‌کند
   └─> سیستم فرمول‌های موجود را نمایش می‌دهد:
       ├─ اگر فرمول پیش‌فرض وجود دارد، به صورت پیش‌فرض انتخاب می‌شود
       └─ در غیر این صورت، کاربر فرمول را انتخاب می‌کند
   └─> مقدار تولید را وارد می‌کند
   └─> دکمه "انفجار و افزودن" را می‌زند
   └─> ✅ ردیف‌های فاکتور به صورت خودکار پر می‌شوند:
       ├─ مواد اولیه (movement: "out" در extra_info)
       │   └─ extra_info.bom_id = [ID فرمول]
       └─ محصولات تولید شده (movement: "in" در extra_info)
           └─ extra_info.bom_id = [ID فرمول]
   └─> (اختیاری) امکان انفجار فرمول دیگر برای کالای دیگر
   └─> کاربر می‌تواند ردیف‌ها را ویرایش کند:
       ├─ مقدار (quantity)
       ├─ قیمت (unit_price)
       ├─ انبار (warehouse_id)
       └─ ⚠️ نمی‌تواند movement را تغییر دهد
   └─> هنگام ذخیره، اعتبارسنجی انجام می‌شود:
       ├─ ✅ حداقل یک ردیف با movement: "out" وجود دارد؟
       ├─ ✅ حداقل یک ردیف با movement: "in" وجود دارد؟
       └─ ✅ تمام ردیف‌ها movement مشخص دارند؟
   └─> ✅ فاکتور ذخیره می‌شود
   └─> ✅ حواله‌های انبار به صورت خودکار ایجاد می‌شوند:
       ├─ حواله issue (برای مواد اولیه - movement: "out")
       └─ حواله receipt (برای محصولات نهایی - movement: "in")
   └─> ✅ اسناد حسابداری در پست حواله‌ها ایجاد می‌شوند

جزئیات پیاده‌سازی

Frontend - ویجت انفجار فرمول در فاکتور (بهبود یافته)

فایل: hesabixUI/hesabix_ui/lib/widgets/invoice/bom_explosion_widget.dart

تغییرات لازم:

class BomExplosionWidget extends StatefulWidget {
  final int businessId;
  final Function(List<InvoiceLineItem>, int bomId) onExploded; // bomId اضافه شد
  
  // ...
}

// در _explodeAndAdd():
// پس از انفجار موفق:
final bomId = _selectedBom?.id;
if (bomId != null) {
  // اضافه کردن bom_id به extra_info هر ردیف
  for (var item in lineItems) {
    // باید InvoiceLineItem را گسترش دهیم یا از Map استفاده کنیم
  }
  widget.onExploded(lineItems, bomId);
}

عملکرد بهبود یافته:

  1. ✅ نمایش یک کارت برجسته در تب "کالاها و خدمات" (فقط برای InvoiceType.production)
  2. ✅ دیالوگ انتخاب کالا و فرمول
  3. ✅ ورود مقدار تولید با اعتبارسنجی
  4. ✅ فراخوانی API explode_bom
  5. ✅ تبدیل نتایج به InvoiceLineItem با تنظیم خودکار:
    • مواد اولیه: extra_info.movement = "out"
    • خروجی‌ها: extra_info.movement = "in"
    • همه: extra_info.bom_id = [bomId]
  6. ✅ افزودن به لیست و نمایش موفقیت
  7. ✅ جدید: ذخیره لیست bom_ids در extra_info فاکتور

تغییرات در new_invoice_page.dart:

  • ✅ در متد _buildProductsTab():
    • ویجت BomExplosionWidget را نمایش بده (همیشه در بالای جدول)
    • پس از انفجار، ردیف‌ها را به _lineItems اضافه کن
    • bom_id را در extra_info فاکتور ذخیره کن
  • ✅ جدید: در متد _serializeLineItem():
    • بررسی کن که اگر نوع فاکتور production است:
      • اگر ردیف movement ندارد، خطا بده
  • ✅ جدید: در متد _validateAndBuildPayload():
    • اگر نوع فاکتور production است:
      • بررسی کن که حداقل یک ردیف با movement: "out" وجود دارد
      • بررسی کن که حداقل یک ردیف با movement: "in" وجود دارد
      • بررسی کن که تمام ردیف‌ها movement مشخص دارند
      • در صورت عدم وجود، خطا: "برای فاکتور تولید، باید حداقل یک فرمول تولید را منفجر کنید"

Frontend - حذف انفجار از بخش کالا

تغییرات در product_bom_section.dart:

  • حذف متد _explode()
  • حذف دکمه "انفجار فرمول" از ListTile
  • (اختیاری) افزودن یک InfoCard که راهنمایی می‌دهد: "برای استفاده از این فرمول، در فاکتور تولید از آن استفاده کنید"

مزایای این رویکرد

  1. ✅ یکپارچگی و کنترل:

    • تمام فرآیند تولید از یک مسیر انجام می‌شود
    • کاهش خطاهای انسانی (عدم وارد کردن دستی مواد اولیه)
    • تضمین صحت داده‌ها
  2. ✅ جداسازی مسئولیت‌ها:

    • مدیریت فرمول = بخش کالا (تعریف و نگهداری)
    • استفاده از فرمول = فاکتور تولید (اجرای عملیات)
  3. ✅ ردیابی کامل:

    • هر فاکتور تولید به فرمول(های) استفاده شده لینک می‌شود
    • امکان گزارش‌گیری دقیق از تولیدات بر اساس فرمول
    • امکان بازگشت و بررسی فرمول استفاده شده
  4. ✅ تجربه کاربری بهتر:

    • کاربر مستقیماً در فاکتور می‌تواند از فرمول استفاده کند
    • راهنمایی‌های واضح برای کاربر
    • جلوگیری از خطا با اعتبارسنجی‌های مناسب
  5. ✅ انعطاف‌پذیری کنترل شده:

    • کاربر می‌تواند پس از انفجار، ردیف‌ها را ویرایش کند (مقدار، قیمت، انبار)
    • کاربر نمی‌تواند movement را تغییر دهد (برای جلوگیری از خطا)
    • امکان انفجار چند فرمول در یک فاکتور (برای تولید چند محصول)
  6. ✅ سازگاری با Backend:

    • از API‌های موجود استفاده می‌کند
    • اعتبارسنجی‌های اضافی در Backend برای اطمینان از صحت داده‌ها

تصمیمات طراحی

  1. ✅ امکان ویرایش ردیف‌های انفجار شده: بله

    • کاربر می‌تواند مقدار، قیمت و انبار را تغییر دهد
    • کاربر نمی‌تواند movement را تغییر دهد (برای جلوگیری از خطا)
  2. ✅ امکان انفجار چندباره: بله

    • کاربر می‌تواند چند فرمول مختلف را در یک فاکتور منفجر کند
    • هر فرمول می‌تواند برای کالای متفاوتی باشد
  3. ✅ اجبار استفاده از BOM: بله

    • کاربر نمی‌تواند فاکتور تولید را بدون انفجار حداقل یک فرمول ذخیره کند
    • اعتبارسنجی در Frontend و Backend انجام می‌شود
  4. ✅ ذخیره اطلاعات فرمول: بله

    • bom_id در extra_info هر ردیف ذخیره می‌شود
    • لیست bom_ids در extra_info فاکتور ذخیره می‌شود
  5. ✅ حذف گروهی ردیف‌های انفجار شده: بله (در نسخه‌های بعدی)

    • امکان حذف تمام ردیف‌های مربوط به یک فرمول خاص
  6. ✅ حرکت خودکار: بله

    • movement: "out" برای مواد اولیه به صورت خودکار تنظیم می‌شود
    • movement: "in" برای محصولات نهایی به صورت خودکار تنظیم می‌شود

خلاصه تغییرات فایل‌ها

فایل‌های جدید

  • ✅ hesabixUI/hesabix_ui/lib/widgets/invoice/bom_explosion_widget.dart - ویجت انفجار فرمول در فاکتور (موجود)

فایل‌های تغییر یافته (نیاز به اصلاح)

Frontend:

  1. hesabixUI/hesabix_ui/lib/widgets/invoice/bom_explosion_widget.dart:

    • ✅ افزودن movement به extra_info هر ردیف
    • ✅ افزودن bom_id به extra_info هر ردیف
    • ✅ برگرداندن bom_id به callback
  2. hesabixUI/hesabix_ui/lib/pages/business/new_invoice_page.dart:

    • ✅ ذخیره bom_ids در extra_info فاکتور
    • ✅ اعتبارسنجی قبل از ذخیره: بررسی وجود حداقل یک انفجار فرمول
    • ✅ اعتبارسنجی movement برای تمام ردیف‌ها
  3. hesabixUI/hesabix_ui/lib/models/invoice_line_item.dart (اختیاری):

    • بررسی نیاز به اضافه کردن فیلد bomId یا استفاده از extra_info

Backend:

  1. hesabixAPI/app/services/invoice_service.py:
    • ✅ اعتبارسنجی در create_invoice برای فاکتور تولید:
      • بررسی وجود حداقل یک ردیف با movement: "out"
      • بررسی وجود حداقل یک ردیف با movement: "in"
      • بررسی وجود movement در تمام ردیف‌ها

فایل‌های بدون تغییر

  • ✅ مدل‌های دیتابیس (نیاز به تغییر ندارند)
  • ✅ API endpoints موجود (نیاز به تغییر ندارند)
  • ✅ ساختار product_boms و جداول مرتبط

چک‌لیست پیاده‌سازی

مرحله 1: Frontend - ویجت انفجار

  • تنظیم movement: "out" برای مواد اولیه در BomExplosionWidget
  • تنظیم movement: "in" برای خروجی‌ها در BomExplosionWidget
  • اضافه کردن bom_id به extra_info هر ردیف
  • برگرداندن bom_id به callback

مرحله 2: Frontend - صفحه فاکتور

  • ذخیره لیست bom_ids در extra_info فاکتور
  • اعتبارسنجی قبل از ذخیره: بررسی انفجار حداقل یک فرمول
  • نمایش پیام هشدار در صورت عدم وجود انفجار فرمول
  • اعتبارسنجی movement برای تمام ردیف‌ها

مرحله 3: Backend - اعتبارسنجی

  • اعتبارسنجی در create_invoice برای فاکتور تولید
  • بررسی وجود movement در تمام ردیف‌ها
  • بررسی وجود حداقل یک ردیف با movement: "out"
  • بررسی وجود حداقل یک ردیف با movement: "in"

مرحله 4: تست

  • تست ایجاد فاکتور تولید با استفاده از BOM
  • تست عدم امکان ذخیره فاکتور تولید بدون BOM
  • تست انفجار چند فرمول در یک فاکتور
  • تست ویرایش ردیف‌های انفجار شده
  • تست ایجاد حواله‌های انبار

آماده برای پیاده‌سازی