4.7 KiB
کنترل موجودی دقیق در فروش سریع
مسئله
در فروش سریع، رابط کاربری موجودی فیزیکی انبار را میخواند و فقط وقتی مقدار درخواستی از موجودی بیشتر باشد خط را نامعتبر نمایش میدهد. بنابراین فروش یک عدد از کالایی با موجودی یک عدد باید مجاز باشد.
پیش از این، سمت API ردیفهای فاکتور را در invoice_item_lines ذخیره و flush
میکرد و سپس کنترل اولیه موجودی را اجرا میکرد. محاسبه موجودی، ردیف خروجی همان
فاکتور را نیز میدید؛ در نتیجه مقدار جاری یکبار از موجودی کسر و دوباره بهعنوان
نیاز فاکتور مقایسه میشد.
اگر موجودی پیش از فروش S و مقدار فروش Q باشد، کنترل معیوب عملاً این شرط را
اعمال میکرد:
S - Q >= Q
یعنی بهجای S >= Q، موجودی باید حداقل دو برابر فروش میبود. نمونهٔ آشکار آن
ردشدن فروش یک عدد از کالایی با موجودی دقیقاً یک عدد بود.
رفتار اصلاحشده
کنترل اولیهٔ _validate_outgoing_stock_before_invoice_commit اکنون شناسه سند
جاری را به _ensure_stock_sufficient میدهد. _iter_product_movements با
exclude_document_id فقط InvoiceItemLine و DocumentLineهای همان سند را از
موجودی تاریخی حذف میکند. سپس مقدار درخواستی فاکتور یکبار و فقط یکبار با
موجودی پیش از فاکتور مقایسه میشود.
این حذف به معنی نادیدهگرفتن سایر فاکتورها یا حوالهها نیست. تمام حرکات قطعی دیگر تا تاریخ سند همچنان در موجودی قابلاستفاده لحاظ میشوند.
ارتباط با حواله انبار
فروش سریع با گزینههای post_inventory=true و auto_post_warehouse=true دو
لایه کنترل دارد:
- کنترل اولیه پیش از تکمیل تراکنش فاکتور؛
- کنترل هنگام قطعیسازی حواله خروج مرتبط با فاکتور.
مسیر دوم از قبل سند مالی مبدأ را با source_document_id حذف میکرد. اصلاح حاضر
همان قاعده را در مسیر اول نیز برقرار میکند تا هر دو کنترل یک موجودی مبنا داشته
باشند. تراکنش همچنان اتمیک است و در صورت کسری واقعی، فاکتور و حواله با هم ثبت
نمیشوند.
حالتهای مرزی
- موجودی ۱ و فروش ۱: مجاز؛ موجودی نهایی صفر.
- موجودی صفر و فروش ۱: خطای
INSUFFICIENT_STOCK. - موجودی ۲ و فروش ۲: مجاز؛ موجودی نهایی صفر.
- چند خط از یک کالا و یک انبار: نیاز خطوط پیش از مقایسه تجمیع میشود.
- انبارهای متفاوت: موجودی و نیاز برای هر جفت کالا/انبار مستقل کنترل میشود.
- سیاست مجازبودن موجودی منفی برای کالای فله یا یونیک بدون تغییر باقی میماند.
- ایجاد و ویرایش فاکتور هر دو از همین تابع کنترل اولیه استفاده میکنند.
تست رگرسیون
فایل tests/test_invoice_stock_prevalidation.py دو قرارداد را تثبیت میکند:
- شناسه فاکتور جاری حتماً بهعنوان
exclude_document_idارسال شود؛ - برابر بودن موجودی قابلاستفاده و مقدار موردنیاز خطا محسوب نشود.
برای اجرای امن تستها باید از wrapper دیتابیس ایزولهٔ محیط توسعه استفاده شود؛ اجرای مستقیم pytest روی دیتابیس توسعه مجاز نیست.
ملاحظات عملیاتی
- تغییر schema یا migration لازم ندارد.
- قرارداد API و payload فروش سریع تغییر نکرده است.
- refresh یا hot reload برای اصلاح داده لازم نیست؛ پس از استقرار نسخه جدید API، ثبت فاکتورهای جدید از رفتار اصلاحشده استفاده میکند.
- فاکتور ناموفق قبلی در تراکنش ثبت نشده است و باید پس از استقرار دوباره ثبت شود.