AAuditPro Suite· Finance manual
Finance manual AR aging

The 4 aging buckets

BucketDays past dueColourAction
Currentnot yet dueGreenNone — invoice sent, payment within terms expected
1-30 days1-30Yellow1st reminder · friendly nudge
31-60 days31-60Orange2nd reminder · firmer · phone call
60+ days61+RedPartner escalation · legal review · payment plan or write-off

Where AR aging surfaces

Auto-overdue cron

InvoiceStateService::markOverdueDue() runs nightly at 02:00 Asia/Muscat. Logic:

FOR EACH invoice WHERE
    doc_type = 'tax_invoice' AND
    status IN ('sent', 'partially_paid') AND
    balance_due > 0 AND
    due_date < CURDATE() AND
    overdue_flagged_at IS NULL

  UPDATE status TO 'overdue'
  STAMP overdue_flagged_at = NOW()
  QUEUE M17 dunning email (template: invoice.payment_reminder)
  NOTIFY manager + accountant + partner
  AUDIT LOG entry

Dunning chain

The reminder cascade kicks in once an invoice goes overdue:

Days overdueEmail templateTone
1 (auto on flip)invoice.payment_reminderFriendly: "We notice payment is now past due..."
15invoice.payment_reminder.firmFirmer: "Payment remains outstanding. Please confirm a settlement date."
30invoice.payment_reminder.escalationEscalation: "Partner-level review pending. Settle within 7 days to avoid further action."
60+(manual partner letter)Legal review · payment plan · write-off discussion

Idempotent: each cron checks invoice.last_dunning_sent_at and skips if < 14 days ago. Configurable per firm via m11.dunning_intervals_days.

Collection workflow

Each overdue invoice gets a "Collection log" panel:

Roll-up across clients = the firm's collection pipeline.

Step-by-step — handling an overdue invoice

  1. Cron flips status to overdue

    2am Asia/Muscat run. Status auto-flips. Notification fires. M17 reminder queued.

  2. Accountant reviews next morning

    Reports → AR Aging Detail → 1-30 bucket. Click into each invoice.

  3. Contact client

    Pick method (phone preferred for first chase). Note the call's outcome in Collection log.

  4. Client commits to a date

    Set "Promised payment date" + notes ("Client confirmed payment by 15-Apr per call with their CFO").

  5. Track

    If date passes without payment → escalate. Re-contact. Update notes. Eventually escalate to partner.

  6. Resolution

    Either: payment arrives → allocate via normal flow → status auto-flips back to paid. Or: write-off after exhausting collection → reason captured + audit-logged.

Dashboard AR tile

Accounts Receivable
OMR 47,250.000
Current
28,500
1-30d
12,750
31-60d
4,500
60+d
1,500
14% of total in 31+ buckets — within firm threshold (target: < 20%)

The cashflow forecast (13-week)

Dashboard → 13-week cashflow forecast (Chart.js stacked bar):

Partner uses this for cashflow planning. If week 4 shows OMR 50k expected against OMR 70k operating costs, decisions get made (chase collections, defer expenses, draw credit line).

Try this

Open Reports → AR Aging Detail. Sort by days_overdue descending. The top 5 rows are your firm's risk concentration. Walk each one with the partner — for each, decide: chase / payment plan / write-off / legal. Every Friday morning. This is the single highest-leverage hour in the firm.

Watch out

The overdue cron only runs nightly. If you need same-day flagging (e.g. Monday morning after a Sunday deadline), run php bin/cron-m11-overdue.php manually. Idempotent — running twice doesn't double-flag. Useful when partners want fresh AR data before Monday partner meetings.

Tip — KPI watch

Healthy audit-firm AR: < 15% in 31-60 bucket, < 5% in 60+ bucket. Above those = pricing or collection issue. Track week-over-week. If 60+ creeps up 3 weeks in a row, it's now a collections crisis — escalate to partner, change collection cadence.