1. 11 Sep, 2026 38 commits
    • DevPilot's avatar
      docs: تحديث الدليل — ٨٧ صفحة، ١٦ فصل، ١٤٤ خطوة · 7783bd1e
      DevPilot authored
      الفصل الجديد بيغطي تنظيم قائمة المالية الجديد، كشوف الحسابات الموحّدة
      بالمطابقة، البحث والترتيب في الجداول، وفحص جاهزية الإقفال. وفصل البنوك
      اتشال منه لقطة القائمة القديمة بعد ما التنظيم اتغيّر.
      7783bd1e
    • DevPilot's avatar
      fix(accounting): use statement مكانش ينفع جوه if — واتضاف فحص صياغة شامل · b2c3414b
      DevPilot authored
      الـ view اتدفع وفيه خطأ صياغة لأن git commit ما بيلنتش. tools/php_lint.sh
      بيفحص الـ ٢٣٩٠ ملف PHP في ثواني، وده اللي كان لازم يتشغّل قبل الدفع.
      b2c3414b
    • DevPilot's avatar
      feat(accounting): فحص جاهزية قبل إقفال الشهر · d1cdb878
      DevPilot authored
      الإقفال كان بيتحقق من حاجة واحدة (القيود المسودة) وبعدين يقفل. أسوأ حاجة
      في الإقفال إن المحاسب يقفل ويطلّع القوائم وبعدين يكتشف ناقص ويضطر يفتح تاني.
      
      الشاشة دلوقتي بتعمل سبع فحوصات قبل الإقفال، كل واحد بلينك يوصّل للشاشة
      اللي تحلّه: القيود المسودة، توازن الميزان، الشهر السابق، العمليات غير
      المقيّدة، الفلوس الواقفة في حسابات وسيطة، الشيكات المستحقة، والمطابقة
      البنكية.
      
      المسودة وعدم التوازن موانع بتوقف الإقفال — الباقي تنبيهات والقرار للمحاسب.
      والفحص بيتعاد في الكنترولر مش بس في الشاشة عشان حد ما يعديه بـ POST مباشر.
      d1cdb878
    • DevPilot's avatar
    • DevPilot's avatar
      fix(accounting): المطابقة تقارن حساب الذمم مش إجمالي الدفتر · 9245247e
      DevPilot authored
      أول ما شغّلت الشاشة على عضو حقيقي طلّعت «فرق ٣٦٣ ألف» على عضو حسابه سليم.
      السبب: القيد بيتعلّم برقم العضو على الطرفين (مدين الصندوق / دائن الإيراد)،
      فجمع كل سطوره بيطلّع صفر دايمًا والفرق مالوش معنى.
      
      المطابقة الصح بتقارن رصيد العضو في حسابات الذمم (١٢٠٣/١٢٠٤ للعملاء،
      ٢٣٠٦ للموردين) بالحساب المساعد. والعضو اللي بيدفع نقدي وقت العملية
      مالوش حساب ذمم أصلًا، فبقت الشاشة بتقول كده صريح بدل تحذير غلط.
      9245247e
    • DevPilot's avatar
      feat(ui): بحث وترتيب تلقائي لأي جدول طويل · 7a6dba5d
      DevPilot authored
      ٣١٦ شاشة فيها جدول من غير أي خانة بحث، والمستخدم بيلف بعينه على الصفحة.
      بدل ما نضيف خانة في كل شاشة (شغل ما بيخلصش وبيتنسي في الجديد)، مكوّن
      واحد بيشتغل لوحده على أي جدول أكتر من ٨ صفوف:
      
      - خانة بحث بتفلتر وانت بتكتب، بنفس نواة التطبيع العربي بتاعة النظام.
      - ترتيب بالضغط على عنوان العمود، بيفهم الأرقام والفلوس والتواريخ فـ
        «1,200.00 ج.م» بتترتّب كرقم مش كنص.
      - عدّاد «كام من كام»، ورسالة واضحة لما مفيش نتيجة.
      - بيتخطى الشاشات اللي فيها بحث أصلًا، وبيتعطّل بـ data-no-filter.
      7a6dba5d
    • DevPilot's avatar
      feat(accounting): المحاسبة المالية — قائمة بثلاث مستويات وكشف حساب موحّد · 60962799
      DevPilot authored
      القائمة:
      - «المحاسبة والدفتر العام» بقت «المحاسبة المالية»، وتحتها مجموعات:
        المؤشرات المالية، حسابات البنوك، المراجعة الداخلية والإقفال،
        القوائم المالية، والإعدادات المالية.
      - مراكز التكلفة والموازنات خرجوا لقائمة «المحاسبة الإدارية» — دول أدوات
        قرار مش جزء من دورة القيد والترحيل.
      - الشريط الجانبي كان بيدعم مستويين بس، فاتعمل يدعم أي عمق: الترشيح
        بالصلاحيات، وحالة «مفتوح»، والبحث كلهم بيمشوا على الشجرة كلها.
      
      كشوف الحسابات:
      - «كشف حساب عضو» و«كشف حساب عميل» كانوا شاشتين على نفس العضو. اتوحّدوا
        مع كشف المورد في شاشة واحدة بتختار فيها نوع الطرف، وبتعرض دفتر الأستاذ
        والحساب المساعد جنب بعض وتقارن بينهم — لأن اختلافهم هو بالظبط اللي
        المحاسب محتاج يشوفه. الروابط القديمة بتحوّل عليها بنفس الطرف والفترة.
      
      البحث:
      - نواة واحدة (arabic-search.js) بتطبّع الهمزات والتشكيل والأرقام العربية
        وبتتحمّل الأخطاء المطبعية وبترتّب بالأقرب. كان في تلات تطبيقات مختلفة،
        واحدة منهم بتعمل indexOf عادي فـ«احمد» ما كانتش بتلاقي «أحمد».
      - أي قايمة فيها ١٢ خيار أو أكتر بتتحوّل لقايمة بحث تلقائيًا.
      
      tools/menu_link_check.py بيتأكد إن كل بند قائمة وكل لينك في الشاشات له
      route فعلي — ٢٨١ بند و٠ مكسور.
      60962799
    • DevPilot's avatar
      docs: rebuild the step-by-step tutorial with the bank group and cheque chapters · 2b4a3fba
      DevPilot authored
      ٨٠ صفحة، ١٥ فصل، ١٣٣ خطوة بلقطات حقيقية من النظام. الجديد فصلين:
      حسابات البنوك (التجميع في القائمة، البحث في دليل الحسابات، وإقفال أوراق
      القبض بالقيد اللي بيتولد منه) ودورة حياة الشيك بسجل حركته الكامل.
      2b4a3fba
    • DevPilot's avatar
      feat(accounting): bank group in the menu, searchable account lookup, notes receivable closing · 913bbb73
      DevPilot authored
      ١. قايمة المالية كانت ٤٥ بند في ليستة واحدة. اتقسمت لمجموعات:
         المحاسبة والدفتر العام / حسابات البنوك / الإيرادات والتحصيل /
         التقارير المحاسبية / القوائم المالية.
         «حسابات البنوك» جمّعت الحسابات البنكية والشيكات والأوراق التجارية
         وإقفال أوراق الدفع والقبض والودائع والمطابقة والقروض والاعتمادات.
      
      ٢. البحث جوه القوايم المنسدلة: مكوّن مشترك بيتفعّل لوحده على أي قائمة
         فيها أكتر من ١٢ خيار (زي دليل الحسابات في قيد اليومية)، وبيدوّر
         بالاسم أو بالرقم. البحث بيتجاهل الهمزات والتشكيل عشان يلاقي بالعربي.
      
      ٣. «إقفال أوراق القبض» — المقابل الناقص لإقفال أوراق الدفع: بيأكّد تحصيل
         الشيكات الواردة من كشف حساب البنك.
      
      ٤. سجل حركة الشيك بقى بيعمل القيد المحاسبي فعلًا. كان بيسجّل الحركة بس
         من غير ترحيل، وده كان بيخلي الشاشة الجديدة تخالف قاعدة إن أي حركة
         مالية لازم تنعكس على الدفتر. كل حركة دلوقتي متربوطة بقيدها.
      913bbb73
    • DevPilot's avatar
      fix: create 6 missing views and repair view-level crashes found by the smoke sweep · 31671ce5
      DevPilot authored
      - ٦ شاشات كانت بتقع بـ View not found: طلب عروض الأسعار، أنواع العمل الإضافي،
        سجل عهدة الأصل، تقرير حضور المرفق، مندوب المبيعات، وأسعار العملاء الخاصة.
      - مكوّن الترقيم المشترك بقى بيكمّل المفاتيح الناقصة لوحده، لأن ٢٠+ موديل
        بيبنوا مصفوفة الترقيم بإيدهم وبيبعتوا الأساسي بس.
      - شاشة الملاعب بترجّع 404 لما الملعب مش موجود بدل ما تقع على null.
      - تقرير الأبناء وسجل البوابة كانوا بيقروا مفاتيح مش موجودة.
      31671ce5
    • DevPilot's avatar
      fix(core): route params coerced to declared type, request errors no longer render as BOOT FAILURE · 49ccc60a
      DevPilot authored
      اتنين أعطال بنيوية طلعوا من فحص الـ 830 شاشة:
      
      1. الراوتر بيبعت بارامترات الـ URL كـ string، وفي ١٣ كنترولر معرّفينها int،
         ومع strict_types ده TypeError بيقع الشاشة. الراوتر دلوقتي بيقرا النوع
         المطلوب من الميثود نفسها ويحوّل ليه.
      
      2. public/index.php كان لافف الـ dispatch والـ boot في try واحدة، فأي
         استثناء جوه الطلب بيطلّع «BOOT FAILURE» بـ 500 حتى لو كان 404 أو 403.
         الطلب دلوقتي ليه try لوحده بيسلّم لـ ExceptionHandler اللي بيحترم الكود.
      49ccc60a
    • DevPilot's avatar
      fix(core): findOrFail returns 404 instead of 500, add route smoke tester · 2d5219ad
      DevPilot authored
      كل رابط لسجل محذوف أو مش موجود كان بيطلّع صفحة 500 لأن findOrFail
      بيرمي RuntimeException من غير code، والـ ExceptionHandler بيعتبر أي
      code غير 401/403/404 عطل سيرفر.
      
      tools/route_smoke.py بيفتح كل GET route في النظام (٨٣٠ شاشة) ويبلّغ
      عن أي 500 برسالة الخطأ.
      2d5219ad
    • DevPilot's avatar
      fix(sql): final pass — schema checker now clean across app/ · c9938287
      DevPilot authored
      كمّلت باقي الأعمدة الغلط: payments (مفيهاش status/receipt_number/payable_*)،
      academy_contracts، facility_zone_schedules (جدول متكرر بيوم الأسبوع مش بتاريخ)،
      carnets، sa_attendance (المجموعة على الحجز)، وsubscriptions للسنة المالية.
      
      tools/sql_schema_check.py بيعدّي دلوقتي على app/ كلها من غير أي ملاحظة.
      c9938287
    • DevPilot's avatar
      fix(sql): second pass on wrong columns and missing tables · b29e4e27
      DevPilot authored
      جداول ما كانتش موجودة أصلًا (sessions، group_players، training_group_players،
      facility_units، activities، membership_types) وكانت أي شاشة أو كرون بيلمسها بيقع.
      اتوجّهت للجداول الحقيقية (training_sessions، sa_group_players، sa_facility_units،
      sport_disciplines)، وتذكير تجديد العضوية اتعمل على السنة المالية لأن members
      مفيهاش تاريخ انتهاء أصلًا. وCustomerPricingService اتكتب من أول وجديد لأن
      الربط بالعضو على مستوى الصنف مش على مستوى القائمة.
      b29e4e27
    • DevPilot's avatar
      fix(sql): correct column names that crash screens at runtime, add a schema checker · 952aa695
      DevPilot authored
      كشف حساب العضو كان بيقع بـ Unknown column 'phone' — جدول members فيه
      phone_mobile/phone_home مش phone. ولما دورت على الغلط ده في باقي الكود
      لقيت نفس النوع في 20+ مكان تاني (coaches.name_ar، players.name_ar،
      members.member_number، hr_attendance.employee_id، وغيرهم).
      
      tools/sql_schema_check.py بيقارن كل SQL في app/ بالـ schema الحقيقي
      ويقع بـ exit 1 لو لقى عمود مش موجود، عشان النوع ده ما يوصلش للـ production تاني.
      952aa695
    • DevPilot's avatar
    • DevPilot's avatar
      fix(accounting): cheque register summary lost closed cheques and cards did not reconcile · 761ee72a
      DevPilot authored
      A cheque that was collected and then closed fell out of every bucket, so the
      five cards stopped summing to the total. 'closed' is archival and is reachable
      from collected/paid/endorsed/returned/replaced/cancelled, so resolve it back to
      the status it held before the close movement.
      
      Buckets are now defined once in bucketStatuses() and read by both the summary
      and the filter, and the cards link by bucket instead of a single status, so the
      number on a card equals what you get when you click it. 'open' is the remainder
      so the cards always reconcile. The summary ignores the selected status/bucket
      so you can still navigate between cards after clicking one.
      761ee72a
    • DevPilot's avatar
    • DevPilot's avatar
      feat(accounting): unified cheque register with full lifecycle history · 927edd62
      DevPilot authored
      The cheque data existed but the screen was a per-direction list and the
      status was overwritten in place — there was no record of who did what,
      when, or what the previous state was. Adds:
      
      - صادر ووارد شيكات بنكية: one screen for both directions, with the
        full filter set (date range on either the cheque date or the movement
        date, direction, number, party, bank, branch, status, amount range),
        a reset, and per-direction summary cards whose totals are clickable
        and drive the filters.
      - instrument_movements: every action is appended as an immutable row
        (action, from/to status, date, user, bank, reference, notes). Nothing
        is ever deleted, so each cheque carries a complete audit trail.
        Existing cheques get an opening "register" movement on migrate so the
        history starts from a known point.
      - The complete status sets for both directions — registered, ready,
        delivered, deposited, under collection, pending, collected, paid,
        bounced, endorsed, returned, replaced, cancelled, closed — with a
        direction-specific transition map that refuses illogical moves such
        as collecting a cancelled cheque.
      - Cheques with movements cannot be deleted; corrections are new
        actions, not edits.
      
      The older screens now funnel through the same service, and the bounce
      and resolve paths log movements too, so the trail stays complete no
      matter which screen the action came from.
      927edd62
    • DevPilot's avatar
      docs: add tax rules, scoped voucher lookup and gap drill-down to the tutorial · ec7ca512
      DevPilot authored
      Two new chapters bring the guide to 108 steps over 13 chapters:
      
      - قواعد الضرائب: entering and amending income-tax brackets from the new
        screen — including the simulator that proves the calculation before
        payroll runs, and the validation refusing a set with a gap between
        brackets — plus the revenue tax profiles screen.
      - The voucher account lookup now scoped per side, shown for both a
        صرف and a قبض voucher, and the "عرض التفاصيل" drill-down on the
        accounting gaps screen listing the real documents behind each count.
      ec7ca512
    • DevPilot's avatar
      fix(accounting): gap detail queries referenced columns that do not exist · fa94e5b8
      DevPilot authored
      The drill-down queries were written against assumed column names and
      every one of them failed, so "عرض التفاصيل" always answered "لا توجد
      تفاصيل متاحة". Corrected against the real schema: pool zone bookings
      have label/zone_row/zone_col and no zone table, player cards use
      valid_from/issued_at and card_number, pool bookings carry booker_name
      rather than a member join, and private match bookings store total_cost
      rather than total_amount.
      fa94e5b8
    • DevPilot's avatar
      feat(hr,accounting): tax bracket admin screen, scoped voucher account lookup, gap drill-down · b16d18aa
      DevPilot authored
      Three things that were asked for and were genuinely missing:
      
      1. ضريبة كسب العمل had no screen at all — the brackets lived only in
         hr_tax_brackets and could only be changed with SQL. Adds a proper
         admin screen: brackets are versioned as a set per effective_date,
         old sets are kept (never deleted) so past payroll stays explainable,
         and activating a set deactivates the others. The form validates that
         brackets are contiguous, that only the last one is open-ended, and
         auto-fills the next bracket's start. A built-in simulator shows the
         tax on any annual income so the accountant can verify the set before
         running payroll.
      
         Also hardens the live calculator: IncomeTaxService summed every row
         flagged active regardless of effective_date, so two overlapping
         active sets produced a silently wrong tax. It now uses the newest
         active set only.
      
      2. The voucher screen searched the entire chart of accounts for both
         sides, so you could pick a fixed-asset account as the cash side or a
         cash account as the expense side — the latter trips the "same as the
         cash account" guard and the voucher just refuses to save. The lookup
         is now scoped per side: cash/bank accounts for the counter side, and
         expense (صرف) or revenue (قبض) accounts for the line side depending
         on the voucher's direction.
      
      3. The accounting gaps screen showed only a count per gap. Each gap now
         has a "عرض التفاصيل" button that lists the actual documents behind
         that number — id, date, party, quantity, recorded amount and status
         — so the accountant can check the cases before choosing a rate.
      b16d18aa
    • DevPilot's avatar
      docs: replace the screen catalogue with a real step-by-step tutorial · 33dc1451
      DevPilot authored
      The previous PDF showed screens from the outside — long full-page dumps
      of lists, with no instruction. This one teaches the system by driving
      it: every step opens the screen, fills the form with real data, submits,
      shows the result, and then shows the journal entry that operation
      produced. Screenshots are top-of-screen crops only.
      
      93 steps across 11 chapters: manual journal entry; the full fixed-asset
      lifecycle (purchase, maintenance, monthly depreciation, disposal with
      gain/loss) with the auto-generated entry after each; the government
      procurement cycle from PR through tender, committees, technical
      evaluation, the 3-offer gate, re-tender, award by item and the
      resulting purchase orders; the auction cycle from lots and committees
      through bidding, award, collection and the disposal entry; payment and
      receipt vouchers with cheque tracking; asset custody; GL sync preview;
      and the five financial statements.
      
      The superseded catalogue PDF is removed — it remains in git history.
      33dc1451
    • DevPilot's avatar
      fix(inventory): custody transfer never recorded the new custodian · b77649e8
      DevPilot authored
      The transfer form posts new_employee_id / new_location, but
      storeTransfer() read to_employee_id / to_location. Both came back
      empty, so every transfer wrote NULL over custodian_employee_id and
      blanked the location — the asset ended up with no custodian at all,
      and asset_custody_history recorded the move with an empty recipient.
      
      Reads the names the form actually sends, keeping the old ones as a
      fallback.
      b77649e8
    • DevPilot's avatar
      feat(procurement): allow re-tendering after the 3-offer gate rejects a tender · 8353e628
      DevPilot authored
      When fewer than three offers pass technical evaluation the tender is
      flagged "تحتاج إعادة طرح" — but that status also hid the invite-vendors
      form, so there was no way to actually invite more vendors and the
      process dead-ended with no route forward.
      
      Adds a "إعادة طرح المناقصة" action next to the rejection reason that
      returns the tender to published and clears the reason, so additional
      vendors can be invited and their offers recorded.
      8353e628
    • DevPilot's avatar
      fix: optional date inputs posted as '' crashed saves across 17 controllers · 831a3e96
      DevPilot authored
      MySQL strict mode rejects '' for a DATE/DATETIME column, so any form
      with an untouched optional date aborted the whole insert with
      "Incorrect date value: ''". This was not one bug — quote responses,
      vouchers, bounced cheques, bank loans, documentary credits, letters of
      guarantee, settlements, tenders, auctions, committees, payments,
      overtime, permission requests and more all passed the raw post value
      straight through.
      
      Adds Request::postDate(), which returns NULL for an empty date field,
      and routes all 33 optional-date call sites through it. QuoteService
      also guards expiry_date directly since it is called from more than one
      path.
      831a3e96
    • DevPilot's avatar
      feat(accounting,procurement,auctions,inventory): reported fixes and committee dates/attachments · d75ca900
      DevPilot authored
      Four issues raised from the demo instance:
      
      1. GL sync preview kept listing rows that could never sync. The preview
         selected every non-voided payment while syncPayments() skips
         amount <= 0 in PHP, so zero-amount payments stayed "pending"
         forever — most visible right after a sync. Both queries now filter
         amount > 0, matching the dashboard count.
      
      2. The five financial statements (income statement, balance sheet,
         consolidated balance sheet, cash flow, changes in equity) moved out
         of the flat Accounting menu into their own "القوائم المالية" group
         inside the المالية section.
      
      3. Technical and financial committees — in both tenders and auctions —
         now carry تاريخ التشكيل / تاريخ الانعقاد / تاريخ البت on the
         formation screen, plus multi-file attachments per committee
         (new committee_attachments table + CommitteeAttachmentService,
         modelled on the existing Support attachment service). Dates and
         attachment links render on the tender and auction pages, with a
         permission-checked download route for each scope.
      
      4. Asset custody screens inner-joined inventory_items, so every asset
         without a stock item — buildings, courts, machines registered
         directly, which is most of the register — was invisible there. Now
         LEFT JOIN with the same name fallback the asset card already uses.
      d75ca900
    • DevPilot's avatar
      fix(procurement): add missing quote response form view · 55d6ac8e
      DevPilot authored
      QuoteController@recordResponse rendered
      Procurement.Views.quotes.response_form, which was never created — so
      /procurement/quotes/{id}/response returned a 500 and vendor prices
      could not be recorded at all. Without it the whole tender cycle is
      blocked: no quote totals, so no technical gate, no financial
      comparison, and no award.
      
      Fields match what storeResponse() reads: quote_item_ids[],
      quantities[], unit_prices[], delivery_days[], plus delivery/payment
      terms and expiry date.
      55d6ac8e
    • DevPilot's avatar
      fix(accounting): voucher save crashed when payment method is not a cheque · b4200e99
      DevPilot authored
      The cheque fields stay in the voucher form for every payment method, so
      check_date posts as '' when paying cash or by transfer. That went
      straight into a DATE column and MySQL rejected the row with
      "Incorrect date value: ''", so no non-cheque voucher could be saved at
      all. Send NULL instead; VoucherService already accepted null.
      
      Found by driving the voucher screen end-to-end while building the
      step-by-step accounting tutorial.
      b4200e99
    • DevPilot's avatar
      docs: add the comprehensive money/accounting guide with live screenshots · e0581a11
      DevPilot authored
      167-page Arabic guide covering every money-related screen in the
      system (139 screens across 20 modules): journal entries, chart of
      accounts, all financial statements, checks/bounced checks, bank
      reconciliation, treasury, procurement + tenders, purchase orders,
      fixed assets, auctions, rentals, sales/POS, payroll/tax/insurance,
      membership and sports-activity billing, pricing/discounts, and the
      reports catalog. Every screenshot is real, captured logged in as
      super admin against the live instance — not mockups.
      
      Building it surfaced and fixed three live bugs along the way (see
      previous commit): PO balance/purchase-volume reports referencing
      non-existent poi.quantity/qty_received columns, a missing
      price-deviation view, and HR insurance form2's wrong join.
      e0581a11
    • DevPilot's avatar
      fix(procurement,hr): fix crashing reports — wrong PO-item columns, missing view, wrong join · f5c65f90
      DevPilot authored
      PO balance and purchase-volume reports referenced poi.quantity /
      poi.qty_received, which don't exist — the real columns are
      quantity_ordered / quantity_received. Price-deviation report pointed
      at a view that was never created. HR insurance form2 joined
      hr_salary_adjustments through employees.id, but that table links
      straight to hr_employee_profiles via employee_profile_id (confirmed
      against the model and every other query on that table) — the extra
      employees join used a column, employee_id, that was never there.
      Found live via BOOT FAILURE pages while capturing screenshots for the
      accountant's tutorial PDF.
      f5c65f90
    • DevPilot's avatar
      docs: add Arabic accountant tutorial PDF for the new features · ea19e57b
      DevPilot authored
      Covers GL sync preview, Cash Flow Statement, Statement of Changes in
      Equity, asset maintenance/sale, the government procurement tender
      cycle, and the auctions module — step-by-step with exact menu paths
      and button labels for the club's accountant.
      ea19e57b
    • DevPilot's avatar
      fix(inventory): asset custody screens crashed on wrong employee name column · cf7b724f
      DevPilot authored
      Controller selects employees as full_name_ar; both custody_index and
      custody_transfer views were reading name_ar, which doesn't exist on
      that result set. Live crash: Undefined array key "name_ar" at
      custody_index.php:14. Pre-existing bug, unrelated to recent changes —
      just hadn't been hit until now. Confirmed via repo-wide grep this was
      the only place with the mismatch.
      cf7b724f
    • DevPilot's avatar
      feat(auctions): add asset-sale and facility-rental auction module · a22986b4
      DevPilot authored
      New Auctions module covering the full committee-driven auction cycle:
      one auction carries one booklet and many lots, each lot bundles one or
      more assets/facilities and snapshots their cost/depreciation/book value
      at lot-creation time, technical committee marks lots fit or not fit for
      disposal, every bid (including losing ones) stays on the lot, and the
      financial committee's award is per-lot so different lots can go to
      different winners. An asset only flips to disposed once its settlement
      is fully paid — not at award time — and disposal reuses the existing
      GL gain/loss posting path. A rental-type award creates a lease contract
      and marks the facility under lease instead of sold.
      a22986b4
    • DevPilot's avatar
      feat(procurement): government tender cycle — committees, technical/financial... · 1d760560
      DevPilot authored
      feat(procurement): government tender cycle — committees, technical/financial gate, multi-vendor award
      
      Adds the documented, auditable purchase cycle on top of the existing
      PR/quote infrastructure: a tender booklet (كراسة شروط) per PR, vendor
      invitations that open a quote record per vendor (rejected quotes stay
      on file with their reason, never deleted), technical committee
      evaluation with the 3-accepted-offer minimum before financial review
      (otherwise the tender is flagged for re-tender with a reason), a
      financial committee comparison scoped to technically-accepted quotes
      only, and item-level award that can split one PR across several
      vendors and therefore several purchase orders — replacing the old
      strict PR:PO 1:1 assumption. Every PO produced carries its tender and
      evaluation id back to the original PR.
      1d760560
    • DevPilot's avatar
      feat(inventory): add Asset Maintenance tracking with GL posting · afa29392
      DevPilot authored
      Closes the remaining gap in the fixed-asset lifecycle (acquisition,
      depreciation, disposal/sale already existed) by adding a maintenance
      log per asset with cost, vendor, and next-due tracking. Each category
      now carries its own maintenance expense account, mirroring how
      depreciation and disposal are already mapped, and maintenance cost
      posts Dr expense / Cr cash-bank-payable through the same operational
      posting pipeline.
      afa29392
    • DevPilot's avatar
      feat(accounting): add Cash Flow Statement and Statement of Changes in Equity · 89695e0e
      DevPilot authored
      Rounds out the القوائم المالية group alongside the existing income
      statement, balance sheet, and consolidated balance sheet. Cash flow uses
      the indirect method with a reconciling line so it always foots to the
      real cash-account movement; the equity statement ties exactly to the
      balance sheet's total_equity at both ends of the period.
      89695e0e
    • DevPilot's avatar
      feat(accounting): add GL sync preview before posting unsynced records · 5c5a5d2c
      DevPilot authored
      Lets a super admin review every unposted payment/fine/installment/sale/
      payroll/refund/rental-deposit row before committing the sync, instead of
      posting blind from the dashboard warning banner.
      5c5a5d2c
  2. 10 Sep, 2026 2 commits