سجلاتنا المالية كانت لغزاً: كيف أنقذنا “محرك التسوية الآلي” من جحيم التناقضات الصامتة؟

يا جماعة الخير، السلام عليكم ورحمة الله.

بتذكر منيح هذيك الليلة في شتاء 2019. كنت قاعد في مكتب الشركة الناشئة اللي بشتغل معها، الساعة كانت داخلة على الوحدة بعد نص الليل. ما كنت بكتب كود ولا كنت بحل مشكلة في السيرفرات. كنت قاعد مع “أبو خليل”، رئيس قسم المالية، وحوالينا أكوام من الورق، شاشات مليانة جداول Excel، وأكواب شاي بالمرمية بلشت تبرد. كان أبو خليل، الزلمة الخمسيني اللي قضى عمره في الأرقام، ماسك راسه وبحكيلي بصوت تعبان: “يا أبو عمر، مش زابطة! في فرق 317 دولار و 42 سنت بين سجلاتنا وكشف حساب البنك، ومش قادر ألاقيها. صارلي أسبوع بدور على هاي الفروقات الصغيرة اللي زي الأشباح”.

في هذيك اللحظة، وأنا شايف الإرهاق على وجهه، ما شفت مجرد مشكلة محاسبية. شفت مشكلة بيانات ضخمة، مشكلة نظام. آلاف العمليات من بوابات الدفع، ومثلها في نظامنا الداخلي، ومثلها في كشف البنك. وكل نظام بحكي “لغة” مختلفة. هون كانت الشرارة. قلت لأبو خليل: “يا خال، هاي الشغلة ما بتنحل بالورقة والقلم. هاي بدها “ماكينة” تفهم على كل هاي الأنظمة وتحكيلنا وين الخلل بالضبط”. من هذيك الليلة، بلشت رحلة بناء “محرك التسوية الآلي” اللي غيّر طريقة شغلنا للأبد.

ما هي التسوية المالية (Financial Reconciliation) وليش هي كابوس؟

قبل ما نغوص في الحل، خلينا نفهم أصل المشكلة. ببساطة، التسوية المالية هي عملية مقارنة مجموعتين أو أكثر من السجلات المالية للتأكد من تطابقها. فكر فيها زي لما تراجع كشف حساب بطاقتك البنكية مع فواتير مشترياتك عشان تتأكد إنه كل شي تمام وما في أي عملية غريبة.

هلأ، لما يكون عندك 10 عمليات في الشهر، الشغلة سهلة. بس لما يكون عندك شركة بتعالج 10,000 عملية في اليوم، الموضوع بتحول لكابوس حقيقي. ليش؟

  • تعدد المصادر: عندك بيانات من نظام الفوترة الداخلي، وبيانات من بوابة الدفع (مثل Stripe أو PayPal)، وبيانات من كشف الحساب البنكي. كل مصدر له شكل بياناته الخاص (CSV, API JSON, PDF).
  • فروقات التوقيت (Timing Differences): ممكن العميل يشتري اليوم، والمبلغ يظهر في حساب بوابة الدفع فوراً، لكنه ما بوصل حسابك البنكي إلا بعد يومين أو ثلاثة (فترة التسوية أو Settlement).
  • الرسوم والعمولات: بوابة الدفع بتاخذ عمولتها، والبنك ممكن ياخذ رسوم تحويل. فالمبلغ اللي دفعه العميل (100 دولار) مش هو المبلغ اللي بوصلك (مثلاً 96.5 دولار). هاي الفروقات الصغيرة هي “التناقضات الصامتة” اللي بتقتل المحاسبين.
  • الخطأ البشري: سواء في إدخال البيانات يدوياً أو في عملية المطابقة نفسها.
  • تجميع العمليات (Batching): أحياناً البنك أو بوابة الدفع بجمعوا مئات العمليات الصغيرة في تحويل واحد كبير لحسابك. كيف بدك تعرف هاد التحويل الكبير لأي عمليات برجع بالضبط؟

هذا الكابوس هو اللي كان أبو خليل وفريقه عايشين فيه كل شهر.

ولادة “محرك التسوية الآلي”: من الفكرة إلى التصميم

كان الهدف واضح: بناء نظام آلي يقرأ البيانات من كل المصادر، يفهمها، يقارنها، ويطلع تقرير واضح بالأمور المتطابقة، وغير المتطابقة، والمحتمل تطابقها. قسمنا الشغل لمراحل.

المرحلة الأولى: فهم المشكلة وجمع البيانات (مرحلة “اسمع وتعلم”)

أول وأهم خطوة ما كانت كتابة سطر كود واحد. كانت الجلوس مع أبو خليل وفريقه. قعدنا أيام نفهم طريقتهم اليدوية خطوة بخطوة. شو المصادر اللي بستخدموها؟ شو هو “المفتاح” اللي بدوروا عليه ليربطوا عملية في النظام الأول مع التاني؟ (رقم طلب، رقم عملية، تاريخ، مبلغ…).

نصيحة من أبو عمر: لا تفترض أبداً أنك تفهم مشكلة المستخدم. اجلس معه، راقبه وهو يعمل، واسأله “ليش بتعمل هيك؟”. التفاصيل الصغيرة اللي بيكشفها هي اللي بتصنع الفرق بين نظام فاشل ونظام عبقري. فريق المالية هم خبراء المجال، واحنا المبرمجين مجرد أدوات لتحويل خبرتهم إلى حل تقني.

اكتشفنا إنه ما في “مفتاح سحري” واحد. أحياناً بستخدموا رقم العملية، وأحياناً إذا فشل، بحاولوا يطابقوا المبلغ مع التاريخ، وأحياناً ببحثوا باسم العميل. هذا التعقيد أكد لنا أنه الحل لازم يكون مرن وقائم على عدة استراتيجيات.

المرحلة الثانية: تصميم بنية النظام (الخارطة المعمارية)

بعد ما فهمنا “شو” بدنا نعمل، صار وقت نفكر “كيف”. رسمنا بنية بسيطة لكن قوية للنظام، بتتكون من أربع أجزاء رئيسية:

  1. وحدات الإدخال (Input Adapters): لكل مصدر بيانات (كشف البنك، تقرير بوابة الدفع، قاعدة بياناتنا)، بنينا “محوّل” (Adapter) خاص فيه. مهمة هذا المحول هي قراءة البيانات من شكلها الأصلي (مثلاً ملف CSV) وتحويلها لصيغة موحدة ومتفق عليها داخل نظامنا.
  2. الكائن الموحّد للعملية (Standardized Transaction Object): هاي كانت خطوة جوهرية. عرفنا شكل بيانات موحد لكل العمليات بغض النظر عن مصدرها. هاد الشكل الموحد كان فيه كل الحقول اللي ممكن نحتاجها للمطابقة.
  3. محرك التسوية الأساسي (The Core Reconciliation Engine): هذا هو قلب النظام. هو اللي بستقبل البيانات الموحدة من كل المصادر وبطبق عليها استراتيجيات المطابقة المختلفة.
  4. وحدة التقارير (Reporting Module): بعد ما المحرك يخلص شغله، هاي الوحدة بتاخذ النتائج وبتعرضها بطريقة مفهومة للمستخدم:
    • قائمة بالعمليات المتطابقة 100%.
    • قائمة بالعمليات الموجودة في المصدر الأول وغير موجودة في الثاني (مثلاً عملية في نظامنا لم تصل البنك).
    • قائمة بالعمليات الموجودة في المصدر الثاني وغير موجودة في الأول (مثلاً إيداع بنكي بدون سجل في نظامنا).
    • قائمة “للاشتباهات” أو التطابقات المحتملة (مثلاً تطابق التاريخ ورقم الطلب ولكن المبلغ مختلف قليلاً بسبب العمولة).

الغوص في التفاصيل التقنية: كيف يعمل المحرك؟

هلأ خلينا نحكي لغة المبرمجين شوي. كيف ترجمنا التصميم السابق لكود حقيقي؟ استخدمنا لغة Python لسرعة التطوير ووفرة المكتبات لمعالجة البيانات.

الخطوة 1: تطبيع البيانات (Data Normalization)

هاي مهمة الـ Adapters. تخيل عندك بيانات من 3 مصادر مختلفة:

  • نظامنا الداخلي (DB): {'tx_id': 'abc-123', 'amount': 100.00, 'date': '2023-12-20T10:00:00Z'}
  • بوابة الدفع (CSV): "order-555,20/12/2023,97.50,abc-123"
  • البنك (TXT): "DEPOSIT REF:abc-123-settlement AMT:97.50 DATE:22-12-2023"

المحول لازم يقرأ كل سطر من هدول ويحولهم لشكل موحد. مثلاً:


class StandardTransaction:
    def __init__(self, source, unique_id, amount_in_cents, date, original_data):
        self.source = source  # 'internal', 'gateway', 'bank'
        self.unique_id = unique_id # The best possible unique ID we can extract
        self.amount_in_cents = amount_in_cents # Always store money as integers to avoid floating point issues
        self.date = date # A standard datetime object
        self.original_data = original_data # Keep the original record for auditing
        self.matched = False
        self.match_id = None

فمثلاً، الـ Adapter الخاص بالبنك رح يستخدم Regular Expressions ليستخرج البيانات من النص، ويحول المبلغ من “97.50” إلى 9750 سنت، ويحول التاريخ من “22-12-2023” إلى كائن `datetime` قياسي.

الخطوة 2: استراتيجيات المطابقة (Matching Strategies)

هنا يكمن ذكاء المحرك. بدل ما يكون عنا منطق واحد للمطابقة، بنينا سلسلة من الاستراتيجيات اللي بتتنفذ بالترتيب.

  1. المطابقة الدقيقة (Exact Match):

    أول وأسرع استراتيجية. هل يوجد عملية في المصدر الأول لها نفس `unique_id` ونفس `amount_in_cents` في المصدر الثاني؟ إذا نعم، ممتاز! تم التطابق. هاي بتغطي 80% من الحالات.

  2. المطابقة مع فرق العمولة (Match with Tolerance):

    إذا فشلت المطابقة الدقيقة، بنجرب استراتيجية أذكى. هل يوجد عملية لها نفس `unique_id` ولكن المبلغ مختلف بنسبة بسيطة (مثلاً 2-3%)؟ هاي النسبة هي قيمة العمولة المتوقعة. إذا وجدنا تطابق زي هيك، بنعلمه كـ “تطابق محتمل” وبنسجل فرق العمولة.

  3. المطابقة المجمّعة (Many-to-One Match):

    هاي من أصعب الحالات. لما يكون عنا إيداع واحد كبير في البنك بقيمة 10,000 دولار. المحرك بحاول يلاقي مجموعة عمليات صغيرة من المصدر الثاني (بوابة الدفع مثلاً) مجموعها يساوي بالضبط 10,000 دولار. هاي المشكلة معروفة في علوم الحاسوب باسم (Subset Sum Problem) وهي معقدة حسابياً، لكن يمكن حلها بكفاءة للحالات العملية.

  4. المطابقة التقريبية (Fuzzy Matching):

    آخر حل. إذا كل شي فشل، بنلجأ للمطابقة التقريبية. مثلاً، هل في عمليتين الهم نفس المبلغ تقريباً، وبنفس اليوم، واسم العميل فيهم متشابه (بنستخدم خوارزميات مثل Levenshtein distance لقياس تشابه النصوص)؟ هاي النتائج بتنعرض للمستخدم كـ “اقتراحات” ليؤكدها يدوياً.

مثال بسيط جداً على دالة مطابقة بلغة بايثون:


def find_match(transaction_a, list_of_b_transactions):
    # Strategy 1: Exact Match on ID
    for transaction_b in list_of_b_transactions:
        if transaction_a.unique_id == transaction_b.unique_id:
            # We can also check amount for more certainty
            if transaction_a.amount_in_cents == transaction_b.amount_in_cents:
                return transaction_b, "Exact Match"

    # Strategy 2: Match with tolerance
    FEE_TOLERANCE = 0.03 # 3%
    for transaction_b in list_of_b_transactions:
        if transaction_a.unique_id == transaction_b.unique_id:
            amount_a = transaction_a.amount_in_cents
            amount_b = transaction_b.amount_in_cents
            if abs(amount_a - amount_b) / amount_a < FEE_TOLERANCE:
                 return transaction_b, "Match with Fee Tolerance"
    
    return None, "No Match Found"

نصائح من قلب الميدان (من خبرة أبو عمر)

بناء هذا النظام علمني دروس كثيرة، بحب أشارككم أهمها:

  • ابدأ بالبسيط ثم توسّع: لا تحاول بناء كل الاستراتيجيات المعقدة من أول يوم. ابدأ بأبسط حالة: مصدرين اثنين واستراتيجية المطابقة الدقيقة. لما تشتغل 100%، انتقل للاستراتيجية اللي بعدها.
  • البيانات هي الملك: “Garbage in, garbage out”. أو زي ما بنحكي “الزبالة اللي بتفوت، زبالة بتطلع”. نظافة ودقة البيانات المدخلة هي أهم عامل لنجاح النظام. استثمر وقتاً في كتابة وحدات إدخال (Adapters) قوية وموثوقة.
  • السجل والتدقيق (Logging and Auditing) أهم من الخوارزمية نفسها: يجب أن يسجل النظام كل قرار يتخذه. “لماذا تم مطابقة العملية A مع العملية B؟” “بناءً على استراتيجية المطابقة مع فرق العمولة بنسبة 2.5%”. هذا السجل يبني الثقة عند فريق المالية ويساعدك بشكل لا يصدق في تصحيح الأخطاء.
  • الهدف ليس أتمتة 100%: الهدف هو مساعدة الإنسان، وليس استبداله. حتى لو النظام أتمت 95% من الشغل، هذا إنجاز هائل. الـ 5% المتبقية هي الحالات الشاذة والمعقدة جداً اللي بتحتاج ذكاء وخبرة بشرية. النظام يحرر فريق المالية من العمل الممل ليركزوا على هاي الحالات الصعبة.

الخلاصة: من جحيم الجداول إلى راحة البال الآلية 🧘

بعد حوالي شهرين من التطوير والاختبار مع فريق المالية، أطلقنا النسخة الأولى من المحرك. أول تقرير شهري استغرقت معالجته حوالي 5 دقائق بدل أسبوع كامل. نظرة الرضا والدهشة على وجه أبو خليل في هذيك اللحظة كانت تساوي كل سطر كود كتبناه.

المحرك لم يوفر الوقت والجهد فقط، بل زاد من دقة سجلاتنا المالية بشكل كبير، وأعطانا ثقة في أرقامنا لاتخاذ قرارات عمل أفضل. تحول فريق المالية من فريق “إدخال بيانات ومطابقة” إلى فريق “تحليل مالي استراتيجي”.

نصيحتي الأخيرة لكل مطور أو مدير تقني يقرأ هذا الكلام: انظر حولك في شركتك. ابحث عن “أبو خليل” الخاص بك. ابحث عن تلك العمليات اليدوية المتكررة والمؤلمة التي يقوم بها زملاؤك. هناك تكمن أعظم الفرص لبناء حلول تقنية ذات قيمة حقيقية. التكنولوجيا في أسمى صورها هي أداة لتمكين الناس وتحريرهم من القيود. وهيك، بدل ما نقضي ليالينا نعد القروش ونشرب شاي، صرنا نخطط للمستقبل ونكبر البزنس.

والله ولي التوفيق.

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

صورة المقال
التوسع والأداء العالي والأحمال

خادمنا الوحيد كان على وشك الانفجار: كيف أنقذنا ‘موازن الأحمال’ من جحيم النقاط الفردية للفشل؟

في ليلة إطلاق صاخبة، كاد خادمنا الوحيد أن ينهار تحت الضغط. هذه قصة كيف أنقذنا موازن الأحمال (Load Balancer)، ولماذا يجب أن يكون صديقك المفضل...

21 أبريل، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

بنيتنا التحتية كانت قصراً من ورق: كيف أنقذتنا ‘البنية التحتية كشيفرة’ (IaC) من جحيم التغييرات اليدوية؟

أشارككم قصة حقيقية عن كارثة كادت أن تدمر مشروعنا، وكيف كانت "البنية التحتية كشيفرة" (Infrastructure as Code) طوق النجاة. سنتعلم معًا كيف نحول بنيتنا التحتية...

21 أبريل، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

اجتماعات ما بعد الكارثة: كيف أنقذتنا ثقافة “ما بعد الوفاة الخالية من اللوم” من جحيم الخوف؟

كنّا ندخل اجتماعات ما بعد الخطأ وكأننا في محاكم تفتيش، الكل خائف والكل يلقي باللوم. في هذه المقالة، أشارككم يا جماعة الخير كيف غيرت "ثقافة...

21 أبريل، 2026 قراءة المزيد
اختبارات الاداء والجودة

بيئة الإنتاج كانت حقل ألغام: كيف أنقذتنا ‘هندسة الفوضى’ من جحيم الأعطال غير المتوقعة؟

في إحدى الليالي، انهار نظامنا بالكامل بسبب عطل بسيط لم نتوقعه، مما دفعنا لتبني "هندسة الفوضى". هذه المقالة هي خلاصة تجربتي كـ "أبو عمر" في...

21 أبريل، 2026 قراءة المزيد
أتمتة العمليات

عملياتنا المعقدة كانت تموت بصمت: كيف أنقذنا ‘منسق سير العمل’ (Workflow Orchestrator) من جحيم الفشل غير المرئي؟

أشارككم قصة حقيقية عن معاناة فريقنا مع العمليات الخلفية التي كانت تفشل بصمت، وكيف كان الحل في تبني 'منسق سير العمل' (Workflow Orchestrator). اكتشفوا الفارق...

21 أبريل، 2026 قراءة المزيد
نصائح برمجية

إعادة المحاولة كانت كارثة: كيف أنقذتنا ‘العمليات عديمة الأثر’ (Idempotency) من جحيم الآثار الجانبية المزدوجة؟

تخيل أن تدفع فاتورة مرتين بسبب خطأ في الشبكة! في هذه المقالة، أشارككم قصة حقيقية من قلب المعركة البرمجية، وكيف أنقذنا مفهوم "العمليات عديمة الأثر"...

21 أبريل، 2026 قراءة المزيد
البودكاست