- 11 Sep, 2026 30 commits
-
-
DevPilot authored
١. قايمة المالية كانت ٤٥ بند في ليستة واحدة. اتقسمت لمجموعات: المحاسبة والدفتر العام / حسابات البنوك / الإيرادات والتحصيل / التقارير المحاسبية / القوائم المالية. «حسابات البنوك» جمّعت الحسابات البنكية والشيكات والأوراق التجارية وإقفال أوراق الدفع والقبض والودائع والمطابقة والقروض والاعتمادات. ٢. البحث جوه القوايم المنسدلة: مكوّن مشترك بيتفعّل لوحده على أي قائمة فيها أكتر من ١٢ خيار (زي دليل الحسابات في قيد اليومية)، وبيدوّر بالاسم أو بالرقم. البحث بيتجاهل الهمزات والتشكيل عشان يلاقي بالعربي. ٣. «إقفال أوراق القبض» — المقابل الناقص لإقفال أوراق الدفع: بيأكّد تحصيل الشيكات الواردة من كشف حساب البنك. ٤. سجل حركة الشيك بقى بيعمل القيد المحاسبي فعلًا. كان بيسجّل الحركة بس من غير ترحيل، وده كان بيخلي الشاشة الجديدة تخالف قاعدة إن أي حركة مالية لازم تنعكس على الدفتر. كل حركة دلوقتي متربوطة بقيدها.
-
DevPilot authored
- ٦ شاشات كانت بتقع بـ View not found: طلب عروض الأسعار، أنواع العمل الإضافي، سجل عهدة الأصل، تقرير حضور المرفق، مندوب المبيعات، وأسعار العملاء الخاصة. - مكوّن الترقيم المشترك بقى بيكمّل المفاتيح الناقصة لوحده، لأن ٢٠+ موديل بيبنوا مصفوفة الترقيم بإيدهم وبيبعتوا الأساسي بس. - شاشة الملاعب بترجّع 404 لما الملعب مش موجود بدل ما تقع على null. - تقرير الأبناء وسجل البوابة كانوا بيقروا مفاتيح مش موجودة.
-
DevPilot authored
اتنين أعطال بنيوية طلعوا من فحص الـ 830 شاشة: 1. الراوتر بيبعت بارامترات الـ URL كـ string، وفي ١٣ كنترولر معرّفينها int، ومع strict_types ده TypeError بيقع الشاشة. الراوتر دلوقتي بيقرا النوع المطلوب من الميثود نفسها ويحوّل ليه. 2. public/index.php كان لافف الـ dispatch والـ boot في try واحدة، فأي استثناء جوه الطلب بيطلّع «BOOT FAILURE» بـ 500 حتى لو كان 404 أو 403. الطلب دلوقتي ليه try لوحده بيسلّم لـ ExceptionHandler اللي بيحترم الكود.
-
DevPilot authored
كل رابط لسجل محذوف أو مش موجود كان بيطلّع صفحة 500 لأن findOrFail بيرمي RuntimeException من غير code، والـ ExceptionHandler بيعتبر أي code غير 401/403/404 عطل سيرفر. tools/route_smoke.py بيفتح كل GET route في النظام (٨٣٠ شاشة) ويبلّغ عن أي 500 برسالة الخطأ.
-
DevPilot authored
كمّلت باقي الأعمدة الغلط: payments (مفيهاش status/receipt_number/payable_*)، academy_contracts، facility_zone_schedules (جدول متكرر بيوم الأسبوع مش بتاريخ)، carnets، sa_attendance (المجموعة على الحجز)، وsubscriptions للسنة المالية. tools/sql_schema_check.py بيعدّي دلوقتي على app/ كلها من غير أي ملاحظة.
-
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 اتكتب من أول وجديد لأن الربط بالعضو على مستوى الصنف مش على مستوى القائمة.
-
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 تاني.
-
DevPilot authored
-
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.
-
DevPilot authored
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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. -
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
- 10 Sep, 2026 2 commits
-
-
DevPilot authored
Filters sidebar items/submenus live as the user types, normalizing Arabic orthographic variants (hamza forms, ta marbuta, alef maksura, Arabic-Indic digits) and doing typo-tolerant approximate matching against label_ar, label_en, and the route path. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
-
DevPilot authored
Controllers select suppliers.name_ar and members.full_name_ar, but the views referenced a nonexistent 'name' key, fataling the page.
-
- 08 Sep, 2026 2 commits
-
-
DevPilot authored
Four-pillar decomposition (membership/money, activities, events, gate/invitations) with data model, API spec, UX/motion system, and delivery plan.
-
DevPilot authored
I broke this. The page-actions block reads $gracePeriod to build the bulk-generate confirmation, but $gracePeriod was computed inside the content block — and page_actions renders first, so the variable did not exist yet. Production turns that notice into a fatal, so the contract page died outright. It had always been wrong; it was simply unreachable, because the guard above it requires status approved or active and until yesterday no contract could reach those states (the approve button was hidden on drafts). Making approval possible made the broken path reachable, and I shipped it without exercising the page in the state I had just unlocked. The shared variables now sit above both sections, which is where anything either section needs has to be. Why the test missed it: I was piping render output through `grep -v Warning:`, which filtered out the exact notice that is fatal in production. The check now installs an error handler that promotes every notice to an exception — the same thing ExceptionHandler does — and renders the contract page in all eight statuses and the invoice page in all three. All pass. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
- 07 Sep, 2026 6 commits
-
-
DevPilot authored
Asked how to make a contract live, and the honest answer was that you could not find out from the screen — so the screen now says it. The approve card was shown only when status was exactly 'pending_approval'. A contract created from the form lands on 'draft' (the controller even defaults to 'pending', which is not in the status list at all), so the one button that makes a contract live was invisible on precisely the contracts that needed it. It now appears for draft, pending and pending_approval. Added a four-step tracker across the top — العقد اتسجّل ← اعتماد العقد ← توليد الفواتير ← تحصيل الفاتورة — with the ticks reflecting real state and a line naming the single next action and where its button is. Underneath it, in words: which day of the month this contract's invoices fall due, read from the contract's own payment_due_day rather than assumed to be the 5th, that a short month pulls it back to the last day, and that the late fee is computed from the due date automatically. Invoice rows now carry a تحصيل button straight to the collection form when they are unpaid, instead of a عرض link that gave no hint the money is taken there. Verified rendered in draft, approved and active: the next-step line changes with state, the due day reads from the contract, and 11 unpaid rows show تحصيل while the paid one shows عرض. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
DevPilot authored
The rent could be invoiced but not collected. `payInvoice` required a `payment_id` that already existed, and the form asked the accountant to type "رقم الدفعة من النظام" — a number they had no way to obtain, because nothing on this screen created a payment. So a generated invoice could never be settled. `collectInvoice` takes the money properly: pick the treasury, the method and the date, and it writes the payment against that treasury, then settles the invoice through the same RentalInvoiceService::markPaid the old path used — so the late fee is still calculated from the due date and the journal entry is unchanged. payInvoice is left in place for the case it was built for: a cashier who already raised the receipt and has its number. Verified end to end on a production clone: contract approved, 12 monthly invoices generated on the contract's own payment_due_day, one collected into «الخزنة الرئيسية», and the entry posted Dr الصندوق / Cr إيجار محلات + ض.ق.م with the trial balance still at 0.00. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
DevPilot authored
Swept every link and form action in the financial modules against the real route patterns. The asset problem was not a one-off. **Screens you could reach but not use.** Three edit screens existed, worked, and had nothing linking to them: vendor invoices, return-to-vendor, and the legacy pricing configs. Buttons added on both the list and the detail page, gated on the same status the controller already enforces — draft only, since neither document should change once verified or submitted. **Links pointing at routes that do not exist.** - Asset custody was entirely unusable: both the transfer button and the transfer form posted to /inventory/assets/{id}/transfer, but the route is /inventory/assets/custody/{id}/transfer. Nobody could ever hand over an asset. - Pricing configs was broken at both ends — the list linked to /pricing/{id}/edit and the form posted to /pricing/{id}, while the routes are under /pricing/configs. The edit screen was unreachable and unsavable. - Quote comparison posted to /select-winner, which was never built; the endpoint is /procurement/quotes/evaluate. - The quotes list "عرض" pointed at a detail page that does not exist. It now opens the response screen, which is what a quote is actually for. - "تظلم" on a fine was an <a>, so it issued a GET against a POST-only route. It is a form now, with a confirmation, since it records something. **Buttons for things that were never built.** BOM edit had no route and no controller method — a guaranteed 404 in two places. Removed rather than faked; creating and viewing a BOM both work, and editing one is a feature nobody has written yet. Settlements had exactly one action and it opened a detail page that does not exist either; replaced with اعتماد, the action that does exist and the only thing a draft settlement is waiting on. Not changed, having checked: vouchers and budgets flagged in the sweep were artifacts of my own parser — PHP unescapes '\\d+' in single quotes, and the budgets links emit a query string from inside the PHP tag. Both resolve fine. Verified: 1503 routes resolve, 255 controllers instantiate, 243 services load, zero orphaned edit screens remain, and every screen touched renders. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
DevPilot authored
Two things I got wrong when I opened up direct asset registration. **There was nowhere to type what the asset IS.** The register carried a tag, a category and a serial — the name was borrowed from `inventory_items.name_ar`, which works only while every asset comes from stock. A building, a court or a transformer has no stock row, so the detail screen showed an empty cell and the form never asked. The register is meant to be read by someone doing a physical count: "أثاث ومعدات" tells them nothing, "مكيف سبليت ٣ حصان — قاعة الاجتماعات" tells them exactly what to look for. `asset_name` is now a required field, backfilled from the linked item where there is one and from the category otherwise, so no existing row loses the name it was already showing. It is also searchable. **The edit route had no button.** `/inventory/assets/{id}/edit` existed and worked; nothing linked to it, so once an asset was saved there was no way back in from the UI. Buttons on both the detail page and the register rows, hidden for disposed assets since those are history. Also corrected the labels that direct registration made wrong: the column header and search hint still said "الصنف", and the empty state still claimed assets are only created automatically when stock of type "أصل" is received. Verified on a production clone: name saves, displays on both screens, is findable by search, both edit buttons render, 1503 routes resolve. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
DevPilot authored
A bounce was one status change and one entry. It is actually four separate facts, and collapsing them is where the books go wrong. 1. The debt comes back. A cheque was never money, it was a promise; when it fails the drawer owes again. This part already worked. 2. The BANK charges the club. That charge leaves the club's account whoever ends up bearing it, so it posts Dr مصروفات بنكية / Cr البنك the moment it happens. Nothing recorded it before — which means the bank reconciliation could never have tied out on any month with a bounce in it. 3. Somebody bears that charge. Billing the drawer is a separate claim posted separately, so waiving it later does not touch the original debt. Saying the club bears it while also billing the drawer is now refused: it is a contradiction that quietly inflates income. 4. It has to end. Collected, replaced, re-presented and cleared, sent to legal, or written off. A bounce with no ending is a receivable nobody is chasing. Only the write-off posts here (Dr ديون معدومة / Cr شيكات مرتدة, for the cheque plus any fees billed on top, because both are being given up); the others are closed by events that already post on their own, and posting again would double them. The register now remembers what a bounce actually needs: the bank's reason code, how many times the cheque has been presented, how many times it came back, what the bank took, what was billed, who bore it, the protest number, and how it ended. Reasons that carry criminal liability in Egypt — insufficient funds, a closed account, a stop-payment on a valid cheque — are flagged, because the club's response differs even though the entry does not. The other half is delayed collection: a cheque past its due date that has NOT bounced. The bank has said nothing, so there is no accounting event and the screen posts nothing — but it is money the club is counting on and has not got, split by whether it never went to the bank or went and never came back. Also fixed: presentation_count only counted retries, so a cheque presented once and returned read as never presented. It now increments on every trip to the bank, in the transition itself rather than in the retry path. Verified on a production clone through the real EventBus: a 50,000 cheque deposited, bounced with a 75 bank charge and 100 billed to the drawer, produced four correct entries; re-presented and bounced again, totals accumulated to 150 and 200; written off for 50,200; and every guard fired — bouncing something not under collection, an unknown reason code, a negative charge, club-bears-plus-bill, resolving twice, and re-presenting after resolution. Trial balance diff 0.00. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
DevPilot authored
The trial balance showed a number with no way to ask where it came from. Every account row is now a link into that account's ledger, carrying the same date range and the same cost-centre/branch filters — so the movements you land on are exactly the ones that produced the figure you clicked. The ledger itself now reads newest first. The running balance is still accumulated in date order, because "the balance after this entry" only means anything with the earlier entries already in; the list is reversed after that accumulation, so the order flips and every balance still says what it says. The opening-balance row moved to the bottom accordingly — it is the oldest line on a newest-first list. Each entry number links to the full journal entry, so a line in one account opens the whole قيد with its other side. The reference type is shown under the reference number, which is usually what tells you which operation raised it. Verified against 779 movements on the cash account: order is newest first, the running balance on the top row equals the closing balance, and both screens render with 165 clickable rows and 779 entry links. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-