تعديل الفواتير

A) إلغاء ثم إعادة ترحيل (الموصى به بعد الاعتماد)

  1. تحقق وصلاحيات: المستخدم، الفترة المحاسبية (غير مُقفلة)، حالة الفاتورة = completed.
  2. جلب الصورة الحالية: رأس الفاتورة + البنود + دفعات البنود + حركات المخزون + القيود المالية + حركة الخزنة + COGS.
  3. ابدأ معاملة واحدة (DB transaction) وقم بـ:
    • عكس المخزون:
      • لكل حركة sale سابقة تكتب حركة معاكسة (مثلاً sale_reversal أو adjustment_in) بنفس الكمية والتكلفة،
      • ترجِع كميات الدُفعات وأرصدة المستودع،
      • تُرجِع أثر الـ moving basis (تزيد الـ moving_qty_basis و moving_value_basis بالقيم التي كانت قد نُقصت).
    • عكس القيود المالية:
      • لكل قيد سابق تكتب قيدًا عكسيًا (نفس الحساب والمبلغ ولكن معكوس مدين/دائن)،
      • تُحدِّث أرصدة الحسابات وفق التسلسل.
    • عكس الخزينة (لو كانت نقدًا):
      • تكتب سندًا عكسيًا (صرف بدل قبض بنفس القيمة) لتعود الخزنة لوضعها قبل الفاتورة،
      • تنتبه لتسلسل أرصدة الخزائن بعد هذا التاريخ (انظر “إعادة توازن الأرصدة” بالأسفل).
    • تغيير حالة الفاتورة الأصلية إلى “revised” أو “voided” مع حفظ رقمها كسجل تاريخي (لا تحذفها).
  4. بناء النسخة الجديدة:
    • احسب البنود الجديدة والضرائب والمجاميع،
    • خصّص الدُفعات FEFO من المخزون الحالي،
    • احسب COGS وفق سياسة التكلفة الفعّالة.
  5. أعد الترحيل للنسخة الجديدة:
    • اكتب حركات مخزون sale الجديدة، وحدث أرصدة المستودع وmoving basis،
    • اكتب القيود المالية (إيراد/ضريبة/طرف مقابل نقدًا أو آجلاً)، وحدث أرصدة الحسابات،
    • اكتب حركة الخزينة (لو نقدًا)،
    • خزّن البنود/الدفعات الجديدة في جداولها.
  6. سجّل نشاط يوضح أن الفاتورة روجِعت، واربط الجديدة بالقديمة (reference_to=old_invoice_id).
  7. اعمل Commit.

لماذا هذا الأسلوب؟
لأنه يحافظ على أثر محاسبي نظيف لا يعبث بالماضي: كل ما حدث سابقًا يُعكس بحركات صريحة، ثم يُنشَر الجديد كوضع نهائي. التاريخ لا يُعاد كتابته؛ نضيف فقط سجلّات.