لا تغيّر ولا تحذف سجلًّا ماليًا أبدًا. إذا كانت دفعة أو فاتورة أو حركة مخزون خاطئة، فصحّحها بإضافة قيد جديد يلغيها، ثم أضف القيد الصحيح.
هكذا يبقى تاريخك كاملًا. تصبح النزاعات قابلة للإثبات، والأخطاء سهلة التتبّع، والاحتيال الصامت أصعب بكثير.
يشرح هذا الدليل الفكرة بكلمات بسيطة، ويعرض نمط قاعدة البيانات بأمثلة SQL حقيقية. ويشرح أيضًا لماذا يهمّ هذا أكثر للمؤسسات في الجزائر.
لماذا لا يجب أن تعدّل سجلًّا ماليًا أبدًا؟
لأنّ زرّ التعديل على المال يمحو الشيء الوحيد الذي يجعل النظام المالي مفيدًا. وهو القدرة على الإجابة: ماذا حدث، ومتى، ومن فعله.
فكّر في كشف النقاط المدرسي. لو استطاع أستاذ أن يمحو علامة ويكتب غيرها دون أثر، لما وثق أحد في كشف نقاط بعد ذلك أبدًا.
لهذا تشطب المدارس وتوقّع، أو تُصدر تصحيحًا. وتبقى العلامة القديمة ظاهرة.
ومع ذلك يطلب الزبائن زرّ التعديل باستمرار، على الفواتير وحركات المخزون والمدفوعات. يبدو الطلب معقولًا: الرقم خاطئ، فلنصحّحه.
لكن في اللحظة التي يمكن فيها تغيير سطر مالي بصمت، تتوقّف قاعدة بياناتك عن كونها سجلًّا وتصبح رأيًا. لا تُظهر إلّا آخر ما كتبه أحدهم.
ما هو دفتر القيود غير القابل للتعديل؟
دفتر القيود غير القابل للتعديل جدول تُضاف فيه حركات المال فقط، ولا تُغيَّر ولا تُحذف أبدًا.
حلّت المحاسبة هذه المشكلة قبل الحواسيب بزمن طويل. في المحاسبة بالقيد المزدوج، تُكتب كل حركة مرّتين، مدينًا في حساب ودائنًا في آخر، ويجب أن يتوازنا.
وحين يكون هناك خطأ، لا تُعيد كتابة التاريخ. تكتب قيدًا جديدًا يلغي القديم، ثم تكتب القيد الصحيح.
وفي قاعدة البيانات يعمل الأمر بنفس الطريقة:
- الأسطر تُضاف فقط. لا تُعدَّل ولا تُحذف أبدًا.
- الرصيد ليس عمودًا مخزّنًا، بل يُحسب بجمع الحركات.
- الخطأ يُصحَّح بقيد عكسي (قيد جديد يلغي الخاطئ).
مثال: زبون اقتُطع منه 4.000 دج بدل 3.000 دج. لا تغيّر السطر إلى 3.000. تضيف قيدًا عكسيًا بـ 4.000، ثم تضيف القيد الصحيح بـ 3.000.
ومن يقرأ لاحقًا يرى الاقتطاع، والخطأ، والإلغاء، والتصحيح، كلٌّ بوقته وصاحبه.
ماذا يعطيك دفتر القيود ممّا لا يعطيه زرّ التعديل؟
| سطر قابل للتعديل (زرّ التعديل) | دفتر قيود لا يُعدَّل | |
|---|---|---|
| تصحيح خطأ | القيمة القديمة تُمحى | يُضاف قيد عكسي، ويبقى الاثنان ظاهرين |
| "ماذا كان مكتوبًا الأسبوع الماضي؟" | لا يمكن الإجابة | استعلام واحد بالتاريخ |
| من غيّره | مجهول | كل سطر يسجّل صاحبه |
| نفس الدفعة مرسلة مرّتين | تُقتطع مرّتين | تُرفض بمرجع فريد |
| شخصان يكتبان في نفس الوقت | تغيير يضيع بصمت | سطران، ولا شيء يضيع |
| الرصيد | رقم ينحرف مع الوقت | محسوب، ومتّسق دائمًا |
| نزاع مع زبون | كلمتك ضدّ كلمته | قائمة أحداث مؤرّخة |
| عامل يخفي مالًا | يعدّل الرقم ويمضي | يحتاج قيدًا عكسيًا ظاهرًا |
السطر الأخير هو الأهمّ عمليًا. جدول مالي قابل للتعديل يسمح لشخص غير نزيه بتغيير رقم دون أن يترك أثرًا.
لماذا يهمّ هذا أكثر في الجزائر؟
القانون يتوقّعه أصلًا في دفاتر التاجر. تنصّ المادة 11 من القانون التجاري الجزائري على أنّ دفتر اليومية ودفتر الجرد يُمسكان حسب التاريخ، "دون ترك بياض أو تغيير من أيّ نوع" (القانون التجاري، الكتاب الأول). والبرنامج الذي يسمح لأيّ أحد بإعادة كتابة المبالغ السابقة يعمل عكس هذا المبدأ.
المال يتحرّك بعيدًا عن خادمك. مع الدفع عند الاستلام، يتبادل الناس المال والسلعة عند الباب، عبر عون توصيل لا يعمل لديك. وبين "تسجيل الطلب" و"المال في اليد" أحداث كثيرة: لا ردّ، محاولة ثانية، رفض، إرجاع، دفعة أسبوعية من شركة التوصيل ناقص رسومها.
احفظ كل ذلك في سطر واحد بحالة تغيّرها باستمرار، وحين لا تطابق دفعة شركة التوصيل مجموعك، فلن يكون لديك ما تتحقّق منه.
الدفع الجزئي شائع. زبون يدفع 5.000 دج من طلب بـ 12.000 دج عند الباب، ثم 4.000 دج بعد أسبوع في المحلّ، والـ 3.000 دج الأخيرة لا تأتي أبدًا. في سطر قابل للتعديل، يكتب أحدهم 9.000 وتضيع القصّة. وفي دفتر القيود، لديك ثلاثة وصولات ورصيد متبقٍّ يحسب نفسه.
الكرّاس الورقي كان دفتر قيود أصلًا. في الكرّاس لا تستطيع المحو بنظافة. سطر مشطوب وبجانبه تصحيح هو دفتر قيود لا يُعدَّل مكتوب بالحبر. استبدل ذلك الكرّاس ببرنامج فيه زرّ تعديل، وستعطي صاحب المحلّ شيئًا أسوأ ممّا كان لديه.
كيف تبني دفتر قيود لا يُعدَّل في قاعدة بيانات؟
1. اعتبر المال أحداثًا، لا حالة. خزّن المبالغ أرقامًا صحيحة بالسنتيم، لأنّ الأرقام العشرية في البرمجة تسبّب أخطاء تقريب مع المال.
create table ledger_entries (
id uuid primary key default gen_random_uuid(),
account_id uuid not null references accounts(id),
amount_cents bigint not null check (amount_cents > 0),
direction text not null check (direction in ('credit', 'debit')),
currency char(3) not null default 'DZD',
reference_type text not null,
reference_id uuid not null,
external_ref text unique,
reverses_id uuid references ledger_entries(id),
actor_id uuid references profiles(id),
memo text,
created_at timestamptz not null default now()
);
create index on ledger_entries (account_id, created_at desc);
create index on ledger_entries (reference_type, reference_id);
2. امنع التعديل والحذف داخل قاعدة البيانات نفسها. لا تعتمد على حسن سلوك التطبيق. المشغّل (trigger، أي قاعدة تعمل تلقائيًا داخل قاعدة البيانات) يستطيع رفض كل تعديل وحذف (توثيق PostgreSQL).
create or replace function ledger_is_immutable() returns trigger as $$
begin
raise exception 'ledger_entries is append only: write a compensating entry instead';
end;
$$ language plpgsql;
create trigger ledger_no_update before update or delete on ledger_entries
for each row execute function ledger_is_immutable();
القاعدة التي تفرضها قاعدة البيانات قاعدة. والقاعدة التي يفرضها التطبيق وحده مجرّد اقتراح.
3. احسب الرصيد بدل أن تخزّنه.
select coalesce(sum(case when direction = 'credit' then amount_cents
else -amount_cents end), 0) as balance_cents
from ledger_entries
where account_id = $1;
إذا صار ذلك بطيئًا في جدول كبير، احفظ لقطة مع آخر قيد تغطّيه واجمع من بعدها. خزّن الرقم مؤقّتًا، لكن لا تجعل النسخة المؤقّتة هي الحقيقة.
هذا النمط قريب ممّا يسمّيه المهندسون "Event Sourcing"، أي تخزين كل تغيير كحدث، لا آخر حالة فقط (Martin Fowler).
4. أعطِ الزبون الزرّ الذي طلبه، واجعله آمنًا. لا تحاضره في المحاسبة. سمِّ الزرّ "تصحيح"، ودعه يكتب الرقم الصحيح، واجعله يكتب قيدًا عكسيًا وقيدًا جديدًا في الخلفية. يحصل على تصحيحه، وتحتفظ أنت بالتاريخ.
5. اعرض التاريخ على الشاشة. الفاتورة المصحَّحة يجب أن تُظهر بوضوح الأصل، والتصحيح، والوقت، والشخص. هذا الأثر هو ما يحسم النزاع لصالح زبونك.
ما الأخطاء الشائعة عند المطوّرين مع المال في البرامج؟
- تخزين الرصيد في عمود وتحديثه. تحديثان في نفس الوقت قد يُضيعان أحدهما بصمت.
- استعمال الأرقام العشرية للمال. استعمل أرقامًا صحيحة بالسنتيم.
- حماية دفتر القيود في التطبيق فقط. امنع التعديل والحذف في قاعدة البيانات.
- عدم وضع مرجع فريد للأحداث الخارجية. دفعة شركة توصيل مستوردة مرّتين تُحسب مرّتين.
- إخفاء التصحيحات عن المستخدمين. الأثر الظاهر هو الميزة التي تُنهي النزاعات.
ماذا تفعل هذا الأسبوع؟
- اليوم: ابحث في نظامك عن أيّ شاشة تسمح بتغيير دفعة أو فاتورة أو حركة مخزون سابقة.
- هذا الأسبوع: اكتب كل جدول يُخزَّن فيه رصيد بدل أن يُحسب.
- هذا الشهر: أضف جدول قيود لحركات المال الجديدة، مع المشغّل أعلاه.
- بعدها: حوّل كل "تعديل" على المال إلى "تصحيح" يكتب قيدًا عكسيًا وقيدًا جديدًا.
- أخيرًا: اعرض تاريخ التصحيحات على الفواتير وحسابات الزبائن.
لمثال حقيقي على أهمّية الأثر المكتوب في مشروع صغير، اقرأ لماذا تحتاج ورشات السيارات دفتر قيود لا يُعدَّل. وإذا كان مشروعك لا يزال يعمل بواتساب وExcel، فابدأ بـ متى يتوقّف واتساب وExcel عن خدمة مشروعك.