12 KiB
12 KiB
مشکلات و سناریوهای ثبت فاکتور
🔴 مشکلات شناسایی شده
1. عدم تطابق نام فیلد نوع فاکتور
- مشکل: در UI از
typeاستفاده میشود اما API ازinvoice_typeانتظار دارد - مکان:
new_invoice_page.dartخط 801 - وضعیت فعلی:
'type': _selectedInvoiceType!.value(مثل'sales','purchase') - وضعیت مورد انتظار:
'invoice_type': 'invoice_sales','invoice_purchase', و غیره
2. عدم تطابق فرمت نوع فاکتور
- مشکل: UI مقادیر ساده ارسال میکند (
'sales') اما API فرمت کامل میخواهد ('invoice_sales') - مکان: تبدیل از
InvoiceType.valueبه فرمت API - مثال:
'sales'باید به'invoice_sales'تبدیل شود
3. عدم استخراج person_id از customer/seller
- مشکل: API فقط
extra_info.person_idرا میخواند اما UIcustomer_idوseller_idرا ارسال میکند - مکان:
invoice_service.pyخط 393-399 (_person_id_from_header) - وضعیت فعلی:
customer_idوseller_idدر payload هستند اما API آنها را نمیخواند
4. عدم تطابق نام فیلد تاریخ
- مشکل: UI از
invoice_dateاستفاده میکند اما API ازdocument_dateانتظار دارد - مکان:
new_invoice_page.dartخط 804
5. عدم تطابق ساختار خطوط
- مشکل: UI از
line_itemsاستفاده میکند اما API ازlinesانتظار دارد - مکان:
new_invoice_page.dartخط 823
6. عدم وجود فیلد تامینکننده برای فاکتور خرید
- مشکل: برای فاکتورهای خرید و برگشت از خرید، باید تامینکننده (supplier) انتخاب شود نه مشتری
- مکان: UI فقط
CustomerPickerWidgetدارد که برای خرید مناسب نیست
7. عدم ارسال person_id در extra_info
- مشکل:
person_idباید درextra_infoارسال شود نه به صورت مستقیم - مکان:
new_invoice_page.dart- ساخت payload
📋 سناریوهای صحیح برای هر نوع فاکتور
✅ فاکتور فروش (Sales Invoice)
فیلدهای مورد نیاز:
- ✅ نوع فاکتور:
invoice_sales - ✅ مشتری (Customer): الزامی - باید به
person_idتبدیل شود - ✅ فروشنده/بازاریاب (Seller): اختیاری - فقط برای کارمزد
- ✅ تراکنشها: دریافت (Receipt) - اختیاری
- ✅ تاریخ فاکتور:
document_date - ✅ تاریخ سررسید:
due_date(اختیاری)
ساختار payload صحیح:
{
"invoice_type": "invoice_sales",
"document_date": "2024-01-15",
"due_date": "2024-02-15",
"currency_id": 1,
"is_proforma": false,
"description": "فروش محصولات",
"extra_info": {
"person_id": 123, // از customer_id استخراج شود
"seller_id": 456, // اختیاری
"commission": {
"type": "percentage",
"value": 5.5
},
"totals": {
"gross": 1000000,
"discount": 50000,
"tax": 95000,
"net": 1045000
}
},
"lines": [
{
"product_id": 1,
"quantity": 10,
"extra_info": {
"unit_price": 100000,
"line_discount": 5000,
"tax_amount": 9500,
"movement": "out"
}
}
],
"payments": [
{
"transaction_type": "cash",
"amount": 500000,
"transaction_date": "2024-01-15"
}
]
}
✅ فاکتور برگشت از فروش (Sales Return)
فیلدهای مورد نیاز:
- ✅ نوع فاکتور:
invoice_sales_return - ✅ مشتری (Customer): الزامی - همان مشتری فاکتور اصلی
- ✅ فروشنده/بازاریاب: اختیاری - همان فروشنده اصلی
- ✅ تراکنشها: پرداخت (Payment) - اختیاری
- ✅ تاریخ فاکتور:
document_date
ساختار payload صحیح:
{
"invoice_type": "invoice_sales_return",
"document_date": "2024-01-20",
"currency_id": 1,
"is_proforma": false,
"extra_info": {
"person_id": 123, // از customer_id استخراج شود
"totals": {
"gross": 500000,
"discount": 0,
"tax": 47500,
"net": 547500
}
},
"lines": [
{
"product_id": 1,
"quantity": 5,
"extra_info": {
"unit_price": 100000,
"movement": "in"
}
}
]
}
✅ فاکتور خرید (Purchase Invoice)
فیلدهای مورد نیاز:
- ✅ نوع فاکتور:
invoice_purchase - ✅ تامینکننده (Supplier): الزامی - باید
PersonPickerWidgetبا فیلترperson_types: ['تامینکننده', 'فروشنده']باشد - ✅ تراکنشها: پرداخت (Payment) - اختیاری
- ✅ تاریخ فاکتور:
document_date
مشکل فعلی: UI فقط CustomerPickerWidget دارد که برای خرید مناسب نیست!
ساختار payload صحیح:
{
"invoice_type": "invoice_purchase",
"document_date": "2024-01-15",
"currency_id": 1,
"is_proforma": false,
"extra_info": {
"person_id": 789, // از supplier_id استخراج شود
"totals": {
"gross": 2000000,
"discount": 100000,
"tax": 190000,
"net": 2090000
}
},
"lines": [
{
"product_id": 2,
"quantity": 20,
"extra_info": {
"unit_price": 100000,
"movement": "in"
}
}
],
"payments": [
{
"transaction_type": "cash",
"amount": 1000000,
"transaction_date": "2024-01-15"
}
]
}
✅ فاکتور برگشت از خرید (Purchase Return)
فیلدهای مورد نیاز:
- ✅ نوع فاکتور:
invoice_purchase_return - ✅ تامینکننده (Supplier): الزامی - همان تامینکننده فاکتور خرید اصلی
- ✅ تراکنشها: دریافت (Receipt) - اختیاری
- ✅ تاریخ فاکتور:
document_date
ساختار payload صحیح:
{
"invoice_type": "invoice_purchase_return",
"document_date": "2024-01-20",
"currency_id": 1,
"is_proforma": false,
"extra_info": {
"person_id": 789, // از supplier_id استخراج شود
"totals": {
"gross": 500000,
"discount": 0,
"tax": 47500,
"net": 547500
}
},
"lines": [
{
"product_id": 2,
"quantity": 5,
"extra_info": {
"unit_price": 100000,
"movement": "out"
}
}
]
}
✅ فاکتور مصرف مستقیم (Direct Consumption)
فیلدهای مورد نیاز:
- ✅ نوع فاکتور:
invoice_direct_consumption - ❌ مشتری/تامینکننده: نیاز ندارد
- ❌ تراکنشها: نیاز ندارد
- ✅ تاریخ فاکتور:
document_date
ساختار payload صحیح:
{
"invoice_type": "invoice_direct_consumption",
"document_date": "2024-01-15",
"currency_id": 1,
"is_proforma": false,
"extra_info": {
"totals": {
"gross": 0,
"discount": 0,
"tax": 0,
"net": 0
}
},
"lines": [
{
"product_id": 3,
"quantity": 5,
"extra_info": {
"movement": "out"
}
}
]
}
✅ فاکتور ضایعات (Waste)
فیلدهای مورد نیاز:
- ✅ نوع فاکتور:
invoice_waste - ❌ مشتری/تامینکننده: نیاز ندارد
- ❌ تراکنشها: نیاز ندارد
- ✅ تاریخ فاکتور:
document_date
ساختار payload صحیح:
{
"invoice_type": "invoice_waste",
"document_date": "2024-01-15",
"currency_id": 1,
"is_proforma": false,
"extra_info": {
"totals": {
"gross": 0,
"discount": 0,
"tax": 0,
"net": 0
}
},
"lines": [
{
"product_id": 4,
"quantity": 2,
"extra_info": {
"movement": "out"
}
}
]
}
✅ فاکتور تولید (Production)
فیلدهای مورد نیاز:
- ✅ نوع فاکتور:
invoice_production - ❌ مشتری/تامینکننده: نیاز ندارد
- ❌ تراکنشها: نیاز ندارد
- ✅ تاریخ فاکتور:
document_date - ✅ خطوط خروجی (مواد اولیه):
movement: "out" - ✅ خطوط ورودی (کالای ساخته شده):
movement: "in"
ساختار payload صحیح:
{
"invoice_type": "invoice_production",
"document_date": "2024-01-15",
"currency_id": 1,
"is_proforma": false,
"extra_info": {
"totals": {
"gross": 0,
"discount": 0,
"tax": 0,
"net": 0
}
},
"lines": [
{
"product_id": 5, // مواد اولیه
"quantity": 10,
"extra_info": {
"movement": "out"
}
},
{
"product_id": 6, // کالای ساخته شده
"quantity": 5,
"extra_info": {
"movement": "in"
}
}
]
}
🔧 راهحلهای پیشنهادی
1. تبدیل صحیح نوع فاکتور
String _convertInvoiceTypeToApi(InvoiceType type) {
return 'invoice_${type.value}';
}
2. استخراج person_id از customer/seller
// در ساخت payload:
if (_selectedInvoiceType == InvoiceType.sales ||
_selectedInvoiceType == InvoiceType.salesReturn) {
// برای فروش: person_id از customer
if (_selectedCustomer != null) {
extraInfo['person_id'] = _selectedCustomer!.id;
}
}
if (_selectedInvoiceType == InvoiceType.purchase ||
_selectedInvoiceType == InvoiceType.purchaseReturn) {
// برای خرید: person_id از supplier
if (_selectedSupplier != null) {
extraInfo['person_id'] = _selectedSupplier!.id;
}
}
3. افزودن PersonPickerWidget برای فاکتور خرید
// در _buildInvoiceInfoTab:
if (_selectedInvoiceType == InvoiceType.purchase ||
_selectedInvoiceType == InvoiceType.purchaseReturn) {
PersonPickerWidget(
personTypes: ['تامینکننده', 'فروشنده'],
selectedPerson: _selectedSupplier,
onChanged: (person) {
setState(() {
_selectedSupplier = person;
});
},
),
}
4. تبدیل نام فیلدها
final payload = <String, dynamic>{
'invoice_type': _convertInvoiceTypeToApi(_selectedInvoiceType!),
'document_date': _invoiceDate!.toIso8601String().split('T')[0],
// ...
'lines': _lineItems.map((e) => _serializeLineItem(e)).toList(),
'extra_info': {
if (_selectedInvoiceType == InvoiceType.sales ||
_selectedInvoiceType == InvoiceType.salesReturn)
if (_selectedCustomer != null)
'person_id': _selectedCustomer!.id,
if (_selectedInvoiceType == InvoiceType.purchase ||
_selectedInvoiceType == InvoiceType.purchaseReturn)
if (_selectedSupplier != null)
'person_id': _selectedSupplier!.id,
'totals': {
'gross': _sumSubtotal,
'discount': _sumDiscount,
'tax': _sumTax,
'net': _sumTotal,
},
},
};
📝 خلاصه
فاکتورهای نیازمند مشتری (Customer):
- ✅ فاکتور فروش
- ✅ فاکتور برگشت از فروش
فاکتورهای نیازمند تامینکننده (Supplier):
- ✅ فاکتور خرید
- ✅ فاکتور برگشت از خرید
فاکتورهای بدون person:
- ✅ فاکتور مصرف مستقیم
- ✅ فاکتور ضایعات
- ✅ فاکتور تولید
فاکتورهای نیازمند تراکنش:
- ✅ فاکتور فروش (Receipt)
- ✅ فاکتور برگشت از فروش (Payment)
- ✅ فاکتور خرید (Payment)
- ✅ فاکتور برگشت از خرید (Receipt)