Complete documentation of budget allocation, commitment tracking from approved Purchase Orders, spending from invoices, and variance analysis for financial control and planning.
Budgets track financial allocations and spending across multiple dimensions. Each budget tracks three key amounts: allocated budget, committed (from approved POs), and spent (from paid invoices).
Day-to-day operating expenses. Typically monthly or quarterly budgets for recurring costs like supplies, services, and maintenance.
Capital expenditure budgets for assets, equipment, and infrastructure. Usually annual with special approval workflows.
Project-specific budgets tied to a defined scope and timeline. Tracks spending against project milestones.
id - UUID primary keycompany_id - Company scopefiscal_year - Budget yearbudget_type - OPERATIONAL, CAPITAL, PROJECTdepartment_id - Department allocationcost_center_id - Cost center allocationproject_id - Project allocationcategory_id - Item category allocationgl_account_id - GL account allocationbudget_amount - Total allocated budgetcommitted_amount - Amount from approved POsspent_amount - Amount from paid invoicesavailable_amount - Calculated remainingperiod_type - ANNUAL, QUARTERLY, MONTHLYperiod_number - Quarter/month numberstatus - DRAFT, APPROVEDid - UUID primary keybudget_id - Parent budget referencetransaction_type - COMMITMENT, RELEASE, SPEND, ADJUSTMENTtransaction_datereference_type - PR, PO, INVOICE, ADJUSTMENTreference_id - UUID of source documentreference_number - Document numberamount - Transaction amount (positive or negative)description - Transaction descriptionBudget change/revision requests
id - UUID primary keyrequest_number - Unique change request referencebudget_id - Target budget being modifiedrequested_by - User who initiated the changechange_type - INCREASE, DECREASE, REALLOCATION, SUPPLEMENTARYcurrent_amount - Budget amount before changerequested_amount - Proposed new budget amountchange_amount - Difference (positive or negative)justification - Business reason for the changestatus - DRAFT, SUBMITTED, APPROVED, REJECTED, CANCELLEDapproved_by - Approving authorityapproved_at - Approval timestampLine items in budget change requests
id - UUID primary keychange_request_id - Parent change request referencebudget_id - Specific budget line affectedcategory_id - Item category for the changegl_account_id - GL account affectedcurrent_amount - Current allocation for this lineproposed_amount - Proposed allocationchange_amount - Delta amountremarks - Line-level justificationBudget approval workflow
id - UUID primary keybudget_id - Budget being approvedchange_request_id - Optional link to change requestapproval_level - Sequential approval stage numberapprover_id - User designated as approverapproval_status - PENDING, APPROVED, REJECTED, ESCALATEDcomments - Approver remarksapproved_at - Timestamp of approval actiondelegated_from - Original approver if delegatedPO commitments against budgets
id - UUID primary keybudget_id - Budget being committed againstpo_id - Purchase Order creating the commitmentpo_number - PO reference numbercommitted_amount - Amount reserved from budgetreleased_amount - Amount released back (cancellation/invoice)spent_amount - Amount converted to actual spendstatus - ACTIVE, PARTIALLY_RELEASED, FULLY_RELEASED, CANCELLEDcommitted_at - Timestamp of commitment creationreleased_at - Timestamp of final releaseAnnual procurement planning
id - UUID primary keycompany_id - Company scopefiscal_year - Planning yeardepartment_id - Department submitting the plancategory_id - Procurement categoryitem_description - Description of planned procurementestimated_quantity - Planned quantityestimated_unit_price - Estimated unit costestimated_total - Total estimated spendplanned_quarter - Target quarter for procurementprocurement_method - OPEN_TENDER, LIMITED_TENDER, DIRECT, RATE_CONTRACTbudget_id - Linked budget allocationstatus - DRAFT, SUBMITTED, APPROVED, IN_PROGRESS, COMPLETEDcreated_by - Plan creator
Available Amount = budget_amount - committed_amount - spent_amount
Utilization % = (committed_amount + spent_amount) / budget_amount * 100
Spent % = spent_amount / budget_amount * 100
| Field | Updated By | Direction | Description |
|---|---|---|---|
budget_amount |
Budget approval | Set | Initial allocation from finance |
committed_amount |
PO approval | + Increase | Reserved when PO is approved |
committed_amount |
PO cancellation | - Decrease | Released when PO is cancelled |
spent_amount |
Invoice posting | + Increase | Actual spend recorded |
committed_amount |
Invoice posting | - Decrease | Commitment converted to spend |
| Transaction Type | Triggered By | Effect |
|---|---|---|
| COMMITMENT | PO Approval | Increases committed_amount, decreases available |
| RELEASE | PO Cancellation or Invoice | Decreases committed_amount, increases available |
| SPEND | Invoice Posting | Increases spent_amount, decreases available |
| ADJUSTMENT | Manual Adjustment | Budget reallocation or correction |
Budget validation occurs at PR submission and PO creation to prevent overspending:
-- Check budget availability before PO approval WITH budget_check AS ( SELECT b.id AS budget_id, b.budget_amount, b.committed_amount, b.spent_amount, b.budget_amount - b.committed_amount - b.spent_amount AS available, :po_amount AS requested_amount FROM planning.budgets b WHERE b.company_id = :company_id AND b.fiscal_year = :fiscal_year AND b.department_id = :department_id AND b.cost_center_id = :cost_center_id AND b.status = 'APPROVED' ) SELECT budget_id, available, requested_amount, CASE WHEN available >= requested_amount THEN 'SUFFICIENT' WHEN available > 0 THEN 'PARTIAL' ELSE 'INSUFFICIENT' END AS budget_status FROM budget_check;
When budget is insufficient, options include: (1) Request budget increase, (2) Obtain exception approval from finance, (3) Defer purchase to next period, (4) Reallocate from another budget.
-- Create commitment on PO approval BEGIN; -- Record commitment transaction INSERT INTO planning.budget_line_items ( budget_id, transaction_type, transaction_date, reference_type, reference_id, reference_number, amount, description ) VALUES ( :budget_id, 'COMMITMENT', CURRENT_DATE, 'PO', :po_id, :po_number, :po_amount, 'PO commitment for ' || :po_number ); -- Update budget committed amount UPDATE planning.budgets SET committed_amount = committed_amount + :po_amount, available_amount = budget_amount - committed_amount - :po_amount - spent_amount WHERE id = :budget_id; COMMIT;
-- Convert commitment to spend on invoice posting BEGIN; -- Release commitment INSERT INTO planning.budget_line_items ( budget_id, transaction_type, reference_type, reference_id, amount, description ) VALUES ( :budget_id, 'RELEASE', 'INVOICE', :invoice_id, -:committed_amount, 'Release commitment for invoice ' || :invoice_number ); -- Record spend INSERT INTO planning.budget_line_items ( budget_id, transaction_type, reference_type, reference_id, amount, description ) VALUES ( :budget_id, 'SPEND', 'INVOICE', :invoice_id, :invoice_amount, 'Invoice spend ' || :invoice_number ); -- Update budget amounts UPDATE planning.budgets SET committed_amount = committed_amount - :committed_amount, spent_amount = spent_amount + :invoice_amount, available_amount = budget_amount - committed_amount + :committed_amount - spent_amount - :invoice_amount WHERE id = :budget_id; COMMIT;
SELECT d.department_name, b.budget_type, b.fiscal_year, b.budget_amount, b.committed_amount, b.spent_amount, b.available_amount, ROUND((b.committed_amount + b.spent_amount) / b.budget_amount * 100, 2) AS utilization_pct, ROUND(b.spent_amount / b.budget_amount * 100, 2) AS spent_pct FROM planning.budgets b JOIN organization.departments d ON b.department_id = d.id WHERE b.company_id = :company_id AND b.fiscal_year = :fiscal_year AND b.status = 'APPROVED' ORDER BY utilization_pct DESC;
SELECT bt.transaction_date, bt.transaction_type, bt.reference_type, bt.reference_number, bt.amount, bt.description, SUM(bt.amount) OVER ( PARTITION BY bt.budget_id ORDER BY bt.transaction_date, bt.created_at ) AS running_balance FROM planning.budget_line_items bt WHERE bt.budget_id = :budget_id ORDER BY bt.transaction_date DESC, bt.created_at DESC;
SELECT d.department_name, cc.cost_center_name, b.budget_amount AS budgeted, b.spent_amount AS actual, b.budget_amount - b.spent_amount AS variance, CASE WHEN b.spent_amount > b.budget_amount THEN 'OVER' WHEN b.spent_amount < b.budget_amount * 0.9 THEN 'UNDER' ELSE 'ON_TRACK' END AS variance_status FROM planning.budgets b JOIN organization.departments d ON b.department_id = d.id LEFT JOIN organization.cost_centers cc ON b.cost_center_id = cc.id WHERE b.fiscal_year = :fiscal_year AND b.period_type = 'QUARTERLY' AND b.period_number = :quarter ORDER BY variance;
Review budget utilization weekly. Set up alerts for budgets approaching 80% utilization to allow time for adjustments.
Ensure commitments are recorded immediately upon PO approval. Delayed entries lead to inaccurate availability and potential overspending.
Investigate significant variances (>10%) between budget and actual. Understanding root causes improves future budget accuracy.