AAuditPro Suite· Finance manual
Finance manual Billing policies

The 3 firm-wide toggles

1m11.auto_invoice_on_completion
Default ON

When job status flips to completed, system auto-drafts a tax invoice inheriting fee + lines. Saves 60 seconds per engagement; for firms with 100+ engagements/year, that's hours saved.

2m11.require_job_completion_for_invoice
Default OFF

If ON, blocks tax-invoice send action when linked job is not completed/archived. Forces "no work, no invoice" discipline.

3m11.notify_on_completion
Default ON

Internal notification fires to partner when a job hits completed. Includes auto-invoice link if drafted.

How auto-invoice-on-completion works

  1. Hook fires post-commit

    JobService::changeStatus($id, 'completed') commits the status change, then post-commit fires onJobCompleted($jobId) via EventDispatcher.

  2. Settings check

    Hook reads m11.auto_invoice_on_completion. If 0, exit. If 1, continue.

  3. Resolve fee source

    Priority: linked accepted quote > job.estimated_fee > firm default. Lines mirror the quote if available; else a single line "Audit fee FY {year}" at the estimated rate.

  4. Draft invoice

    doc_type=tax_invoice, status=draft, auto-numbered. Inherits client + job + currency + T&Cs. Saves to DB.

  5. Auto-allocate prior advances

    If client has advance balance > 0, system silently allocates against the new draft up to min(advance, total).

  6. Internal notification

    Per m11.notify_on_completion, partner gets notification with deep-link to draft invoice. Flash message on job dashboard: "Auto-drafted invoice INV/2026/0042 (clickable link)".

The completion gate

If m11.require_job_completion_for_invoice is ON:

Useful for firms that want strict "no premature billing" discipline. Default OFF because some firms invoice on retainer / phased basis.

Per-engagement overrides

Some jobs need to break the firm-wide policy. The job record carries:

The hook honours these in priority: per-job → firm setting → default.

Phased billing pattern

Audit firms often phase fees: 30% on engagement letter sign-off, 30% on planning complete, 40% on report issue. Configure:

  1. Set jobs.bill_method = 'phased'
  2. Set phased schedule: [{milestone: 'planning', percent: 30}, {milestone: 'fieldwork', percent: 30}, {milestone: 'reporting', percent: 40}]
  3. Each milestone task tick fires its phase invoice via the same auto-draft hook
  4. 3 separate invoices created over the engagement lifecycle

This is where the m11.require_job_completion_for_invoice gate must be OFF — phased billing intentionally bills before completion.

Job → Invoices roll-up

Job dashboard → Invoices tab shows:

One screen, all revenue context for the engagement.

Settings page walkthrough

  1. Open Settings → Company Profile → Billing Policy

    Three toggles + an explanation per setting.

  2. Read defaults

    auto_invoice ON · require_completion OFF · notify ON. Most firms keep these.

  3. Toggle as needed

    For firms enforcing strict invoicing discipline, flip require_completion ON. For firms with many phased engagements, leave OFF and rely on the per-job override.

  4. Save

    Changes apply immediately. New jobs use new policy; existing jobs unaffected unless their per-job override is null (in which case they inherit).

Try this

Set m11.auto_invoice_on_completion=1 + create a job from TPL-AA → walk it to status=completed. Within 2 seconds, a draft invoice appears in M11 with the right fee + client + lines. Check Activity log on the job — auto-invoice hook captured.

Watch out

If you flip require_job_completion_for_invoice ON mid-year and have phased-billing engagements running, those phased invoices will be blocked. Set the per-job override on each existing phased engagement BEFORE flipping the firm-wide setting.

Tip — discount tracking

If a firm wants discount governance (e.g. partner approval for discounts > 10%), add a job-level field discount_approved_by + reject invoice send until approver is set when discount exceeds threshold. Customisation, but trivial against the existing service hooks.