AFE Approval Workflow (Purchasing)
1. Overview
AFE stands for Authorization for Expenditure. It is a formal document the office prepares to justify and get sign-off on a Requisition (RQ) that is either out of the ordinary or exceeds the available budget. The AFE is typically sent to the site owner, signed (or approved by email), and returned to the office before the RQ can continue.
This release extends the existing AFE handling with a full approval workflow inside ZeeBORN Purchasing.
What changed compared to before:
-
Previously, an AFE was only required when the RQ had the Extraordinary Expenses flag set.
-
From this release on, an AFE is also required when the RQ pushes its cost account over the budget limit for the current period (the "red pie chart" under the RQ header).
-
The AFE approval itself now has a dedicated dialog (Manage Approval) with status, file attachment, remark, audit log and a controlled way to raise the budget limit.
-
The RQ approval is now blocked in a defined sequence: fill out AFE → attach signed AFE / approval email → mark as approved → optionally raise the budget → approve the RQ itself.
-
A new right 14105112 "Order without AFE Approval (Management Override)" lets management roles skip the AFE block if needed.
2. Prerequisites / Setup
Before using the workflow, make sure the following is in place:
-
Right 14105112 ("Order without AFE Approval (Management Override)") is granted to the management roles that are allowed to bypass the AFE.
-
The following configuration entries are set:
-
UseAuthorizationForExpenditure → enables the feature as a whole.
-
UseAuthorizationForExpenditureFormMandatory → makes the AFE mandatory when the triggers (see section 3) apply.
-
UseAuthorizationForExpenditureFormID → the ID of the AFE form template that the user will fill out.
-
-
The database migration in
docs/sql/2026-04-19_task4773_afe.sqlhas been applied. It is already on ALBERICH and victoriademo; bluesquared is updated through the regular setup pipeline. -
For each site that can trigger an AFE,
lm_sites.OwnerContactIDmust point to a contact inom_contacts, and that contact must have a business email entry inom_communication. Without this, the Send by Mail step cannot pre-fill a recipient.
3. When is an AFE required?
An AFE is required on an RQ if either of the following is true:
- Extraordinary Expenses is checked on the RQ.
- The RQ would push the cost account over the budget limit in the current period (the pie chart under the RQ header turns red).
In the RQ view, directly under the pie chart, an info block is shown in these cases:
- "AFE required (extraordinary expenses)"
- "AFE required (budget overrun)"
If neither trigger applies, no AFE is needed and the RQ can be approved as before.
4. Filling out the AFE form
The AFE form itself is the existing Expenses Form feature — it has not changed.
In the RQ, click the Fill Out button next to the AFE info block. A form based on the template configured in UseAuthorizationForExpenditureFormID opens. Fill in the questions as required and save.
For details on how to work with Expenses Forms, please refer to the existing ZeeBORN Expenses Forms documentation.
Once an AFE form has been filled out for the RQ, the approval workflow in the next section becomes available.
5. The AFE Approval dialog (Manage Approval)
The Manage Approval dialog is the central place to handle the AFE sign-off.
How to open it:
In the RQ view, click Manage Approval next to the AFE block. The dialog Purchase.AFEApproval opens.
Fields and areas:
- Status – shows the current approval status:
- Pending – AFE filled out but not yet signed off.
- Approved – signed AFE / approval mail attached and approver marked it done.
- Rejected – AFE was explicitly rejected.
- Attached file – the signed AFE PDF or the owner's approval email exported as PDF. Required before you can use Approve.
- Remark – free text, up to 500 characters. Use this for context the auditor or the next reviewer should see.
- Approver / Timestamp – automatically filled when Approve or Reject is used. Read-only.
Buttons:
- Approve
- Reject
- Reset to Pending
- Increase Budget
- Open attached file
- Export AFE
- Send by Mail
The individual actions are described in the following sections.
6. Attaching the signed AFE / approval email
Before the AFE can be set to Approved, a file must be attached. Accepted content:
- The signed AFE PDF returned by the owner, or
- The owner's approval email saved/exported as PDF.
Click the attach button in the dialog, pick the file, and it is stored with the AFE. Use Open attached file at any time to verify what was attached.
If Approve is clicked without an attachment, ZeeBORN blocks the action and asks for the file first.
7. Approving, Rejecting, Resetting to Pending
-
Approve – sets the AFE status to Approved. Requires an attached file. Stores the current user as approver and the current timestamp. Only now the RQ approval block due to the AFE is lifted (the budget check still applies, see section 10).
-
Reject – sets the status to Rejected. The RQ cannot be approved through the normal path while the AFE is rejected. Use the remark to state why.
-
Reset to Pending – sets the status back to Pending. The existing file, remark, approver name and timestamp are kept on purpose so the audit trail stays complete. If the attached file really must be removed, an administrator can delete it separately. Reset to Pending is only visible and usable for users who have the Management Override right 14105112.
8. Exporting the AFE form
Use Export AFE to save the filled-out AFE form to a file on your machine. The file is typically a PDF based on the AFE template.
Use this when you want to:
- Send the AFE to the owner through a channel other than the built-in Outlook draft.
- Keep a local copy before sending.
- Attach the AFE to an external system.
The export does not change any status on the RQ.
9. Sending the AFE to the owner by email
Send by Mail creates a new Outlook draft for the AFE, pre-filled as follows:
-
To: the business email of the contact set in
lm_sites.OwnerContactIDfor the RQ's site (looked up throughom_communication). -
Subject / Body: tabular layout in ZeeBORN branding, summarising the RQ and the AFE reason.
-
Attachment: the exported AFE file.
The draft opens in Outlook so the user can review, edit the text, add CCs, and hit Send manually. ZeeBORN does not send the mail for you.
Sent-to-Owner indicator in the RQ view:
-
Before Send by Mail has been used, a red "Not yet sent to Owner" box is shown.
-
After Send by Mail has been used, the box turns turquoise and reads "Sent to Owner on TT.MM.JJJJ HH:MM". The timestamp is stored in
pu_expensesforms.SentToOwnerAt.
Note: the indicator tracks the moment the draft was generated in ZeeBORN. It does not verify that the user actually clicked Send in Outlook.
10. Increasing the budget limit
If the AFE is triggered by a budget overrun, approving the AFE alone does not raise the budget. The limit on the cost account is still exceeded, and the RQ approval is still blocked with:
Budget is still exceeded by this RQ. Please increase the budget limit in the Manage Approval dialog before proceeding.
To raise the limit, click Increase Budget in the Manage Approval dialog. A small form opens with:
- New value – the new budget limit for this cost account / period.
- Reason – mandatory free-text reason.
- AFE file – optional, pre-filled with the attached AFE if available.
- RQ reference – optional, pre-filled with the current RQ.
On confirm, ZeeBORN calls UpdateBudgetLimit, which:
- Updates
bu_limits.Valueto the new limit. - Writes an entry to
bu_limits_changescontaining the old value, the new value, the reason, the user, the timestamp, and the AFE / RQ references.
From this point on, the pie chart uses the new limit, and – if the RQ now fits – the RQ approval is no longer blocked by the budget check.
11. Management override (right 14105112)
Users with the right 14105112 "Order without AFE Approval (Management Override)" can approve the RQ even if:
- No AFE has been filled out for the required reason,
- The AFE is still pending or rejected, or
- The budget is still exceeded.
The block messages from section 12 are still shown, but these users get an extra confirmation and can proceed. Use this right sparingly – every override is visible in the RQ approval history.
Users with this right are also the only ones who can use Reset to Pending (see section 7).
12. RQ approval block messages
When the user tries to approve the RQ, ZeeBORN checks the AFE state in sequence and can block with one of these messages:
-
"Please fill out AFE form (REASON) first." – AFE is required but has not been filled out yet. REASON is either extraordinary expenses or budget overrun.
-
"AFE for REASON is not yet approved. Please attach the signed AFE / approval mail and mark as approved first." – AFE is filled out, but the status in Manage Approval is not Approved.
-
"Budget is still exceeded by this RQ. Please increase the budget limit in the Manage Approval dialog before proceeding." – AFE approved, but the cost account is still over the limit. Use Increase Budget (section 10).
Each message tells the user the exact next step. Users with right 14105112 can override the block.
13. Approval history and audit trail
All changes relevant for audit are kept permanently:
- The AFE itself (filled-out answers) stays in
pu_expensesforms. - The attached signed AFE / approval email stays with the AFE.
- The approver name and timestamp stay on the AFE even after Reset to Pending.
- Every budget limit change is written to
bu_limits_changes, with old value, new value, mandatory reason, user, timestamp, and references to the AFE and RQ that triggered the change.
Nothing in the audit log is deleted automatically. If a wrong entry must be corrected, an administrator has to do it explicitly on the database.
14. Known limitations / notes
- Send by Mail creates an Outlook draft only. The user must click Send in Outlook. ZeeBORN does not verify that the mail was actually sent.
- The sent-to-owner timestamp reflects the draft generation, not the Outlook send.
- If
lm_sites.OwnerContactIDis missing or the contact has no business email inom_communication, the To field in the Outlook draft will be empty and the user has to fill it in manually. - The AFE form template is controlled by the configuration UseAuthorizationForExpenditureFormID. Changing the template affects new AFEs only; existing AFEs keep the template they were filled out with.
- Reset to Pending intentionally keeps the attached file and the approver trail. This is by design for audit reasons and is not a bug.
-
The Management Override right 14105112 bypasses the AFE block entirely. Grant it only to roles that are supposed to take that responsibility.
Accrual Report — "Also include POs already invoiced" option
1. Overview
The Accrual Report in ZeeBORN Purchasing (Purchasing → Reports → Open POs / Provision) computes the budget-side accrual by listing Purchase Orders that are not yet completely invoiced. The remaining (uninvoiced) part of each PO is what still has to be accrued against the budget for the selected period.
This release extends the report with an option for controlling use cases that need the period total — not just the remaining accrual. Specifically:
- A new option "Also include POs already invoiced in this period (for controlling)" in the Loading-Options dialog.
- A new grid column "Already Invoiced" that flags such rows.
- Two new controlling columns "Budgeted" and "Invoiced" (dynamic visibility).
- Two silent SQL bugs in the underlying query have been fixed as bycatch.
The report's default behaviour is unchanged. The new columns are only shown when the new option is active.
2. Running the report with the new option
- Open Purchasing → Reports → Provision / Open POs.
- In the Loading Options dialog, set the period (From / To) and the usual filters as before.
- In the sub-group Additional Options, tick the checkbox "Also include POs already invoiced in this period (for controlling)".
- Click Load.
When the checkbox is off (default), the report behaves exactly as before — only open POs that still have an uninvoiced portion are listed.
When the checkbox is on, the report additionally includes POs whose status is one of:
- Completely Paid
- Closed
- Closed Partially Paid
- Closed Completely Paid
i.e. POs that were already fully invoiced within the selected period. These rows typically have an OriginalPrice of 0 (because nothing is left to accrue), but they carry the budgeted and invoiced amounts for controlling.
3. Reading the report
The grid shows one row per PO / budget position. The relevant columns for this feature:
- Already Invoiced — a flag column. Set for rows where the PO was already fully invoiced in the selected period. These are the rows added by the new option.
- Budgeted — the amount originally booked into the budget for this position (see section 4).
- Invoiced — the amount that was actually invoiced, in original currency (see section 4).
All other columns (PO No., Supplier, Account, OriginalPrice, etc.) are unchanged.
When the new checkbox is off, the Already Invoiced flag column is still present but always empty, and Budgeted / Invoiced stay hidden — the report looks exactly like before.
4. The two controlling columns "Budgeted" and "Invoiced"
For rows flagged Already Invoiced, the accrual itself is correctly 0 — there is nothing left to accrue. The two controlling columns provide the additional context needed to reconcile period totals:
- Budgeted — what was originally booked into the budget for this position (
OV_Budget + OV_AdditionalCosts). - Invoiced — what was actually invoiced against this position, in the PO's original currency.
When these columns appear
The columns are hidden by default. They become visible automatically when both of the following are true:
- the "Also include POs already invoiced in this period" checkbox is active, and
- the current report contains at least one already-invoiced row.
If either condition is not met, the columns stay hidden to avoid cluttering the standard accrual view.
What they are for
Controlling often needs the full period picture in a single list — the open accrual plus what has already been posted. With Budgeted and Invoiced visible, the same list can be used to reconcile period totals (budget position vs. actual invoiced amount) without switching to a separate report.
5. Excel export
The Excel export follows the same rules as the on-screen grid:
- Already Invoiced is always exported.
- Budgeted and Invoiced are exported only when they are visible in the grid (i.e. checkbox on and at least one already-invoiced row present).
No separate option is needed — what you see on screen is what you get in Excel.
6. When to use this option vs. the default
- Leave the checkbox off when you want the classic accrual figure — the amount still to be accrued against the budget for open POs. This is the standard month-end accrual use case.
- Switch the checkbox on when you need the period total from a controlling perspective — budgeted vs. invoiced for every PO that was active in the period, including the ones that were fully invoiced during the period. Use this for period reconciliation, not for calculating the accrual itself.
Rule of thumb: accrual → off, period controlling → on.
7. Known issues fixed in this release
Two pre-existing bugs in the Accrual Report's underlying query were fixed as part of this change:
- POs with status "Partially Invoiced" or "Partially Paid" were silently dropped from the report due to a missing comma in the state-filter list. These POs now appear correctly in the standard (checkbox-off) accrual.
- An RfQ-text column was failing silently due to a wrong SQL alias (
r.wherep.was meant). The column now shows the expected text.
Both fixes apply regardless of the new checkbox.
8. Known limitations / notes
- The Invoiced column shows the invoiced amount in the PO's original currency. If your report mixes currencies, do not sum this column across rows without conversion.
- Budgeted reflects the budget booking at the time the PO was placed (
OV_Budget + OV_AdditionalCosts) and does not re-evaluate against later budget adjustments. - The Already Invoiced flag is based on PO status at report-load time. Re-run the report if statuses have changed since.
- Already-invoiced rows typically carry
OriginalPrice = 0. That is expected — the accrual has nothing left to post; the controlling value is in Budgeted / Invoiced.