Skip to content

Bill of Quantities (BOQ)

The BOQ is the structured spec for what a project will deliver: every item the client is paying for, broken down into sections and line items, with quantities and rates. From there it drives the rest of the project lifecycle — procurement, allocation, delivery, installation, returns, invoicing, and close-out.

Accessing BOQ

  1. Go to Projects → [Project Name].
  2. Click the BOQ tab in the project detail page.

A project may have multiple BOQ versions. The version selector at the top of the BOQ page shows the active version; older versions are marked Archived.

BOQ statuses

Status What it means
Draft Being prepared. Items can be added, edited, deleted.
Pending Approval Submitted to the approval workflow. Edits are blocked while in this state.
Approved All approval levels passed. The BOQ is automatically locked at this point — edits and deletes require an admin to unlock first.
Locked Same as approved with an explicit lock applied. No edits allowed.
Completed Terminal positive state. Reached only after every item is fully invoiced or returned, every linked PO is closed, and any retention has been released.
Archived A prior version superseded by a newer revision.

Tabs

The BOQ page is organised into the following tabs:

Tab Purpose
Tree Hierarchical view of sections and items. Add / edit / move / approve / promote to inventory from the row dropdown.
List Flat tabular view across all items, with bulk selection and an action bar (e.g. create QC checklist from selected items).
Analytics Cost breakdown, variance, and progress charts. Visible only to users with cost-visibility permission.
Allocation Per-item view of required vs. reserved vs. available stock. Allocate, top up, or release reservations.
Delivery Delivery Challans (DCs) and Site Returns (SRs) tied to this BOQ.
Installation Material Issues (MIs) recording on-site consumption.
Invoices Billable summary, issued invoices, retention status, generate-invoice action.
Change Requests Internal revisions / additions / deletions / rate changes raised against the BOQ.
History Chronological audit trail of all lifecycle events — submission, approval, lock, dispatch, install, return, invoice, completion.
Compare Diff two versions of the BOQ.

A BOQ-level Approval Card appears above the tabs while status is Draft or Pending Approval. A Completion Card appears once the BOQ is Approved, Locked, or Completed.

Building the BOQ

Sections

Sections group items hierarchically (A, A.1, A.1.1, …). Add sections from the Tree tab. Each section has a code and a name; nested sections are supported.

Items

Each line item carries:

  • Item number (e.g. A.1.5) and a description.
  • Quantity + unit (bag, m², m³, nos, etc.).
  • Unit rate (which can be split into material / labor / equipment rates).
  • Wastage % to derive the adjusted quantity used for downstream caps.
  • Source type — how the item was added (see below).
  • Optional inventory link to a catalog SKU.

Source type

Each item carries a source-type badge:

Source Behaviour
Inventory Item was picked from the inventory catalog. Inventory link is set; downstream PO / DC flows can reference the SKU directly.
Custom (ad-hoc) Free-text item not yet in the catalog. Shown with an amber "Ad-hoc" hint in the item picker. Promoted to the inventory catalog when a PO or reservation is raised, or manually via Promote to Inventory in the row dropdown.
Template Imported from a BOQ template.
BOM Sourced from a Bill of Materials.
Import Loaded from an external file.
Change Request Added via an approved change request.

Ad-hoc items can be used freely in a draft BOQ. Promotion to the inventory catalog assigns them a SKU (ADHOC-{boq_number}-{item_number} by default, auto-disambiguated on collision) and links the BOQ item to the new inventory row with quantity_available = 0.

Inventory item picker

When adding an item, the picker searches the inventory catalog as you type. If your search matches a catalog row, selecting it links the BOQ item to that SKU. If you type free text that doesn't match anything, an "Ad-hoc — not in catalog" hint appears below the input; the item is saved as a custom entry and promoted later.

Versioning

Once a BOQ is approved (or otherwise locked), creating a new revision via the version selector copies all sections and items into a new draft version with version + 1. The prior version is marked Archived.

Each item in the new revision keeps a stable lineage link back to its parent in the prior revision, so the Compare tab can pair items even when they're renumbered or reordered between revisions.

Compare tab

Pick any two versions in the dropdowns. The diff shows:

  • Items added in the target.
  • Items removed from the target.
  • Items modified (description, quantity, rate, etc., grouped by field).
  • Items unchanged.
  • Cost impact summary at the top.

Toggle Group by Section to cluster changes per section, or flatten the list. Toggle Show / Hide Unchanged to focus on changes only.

Approval

Approval is workflow-driven. Each tenant has a default BOQ approval workflow seeded out of the box; admins can configure additional ones in Settings → Workflow Engine → Approval Workflows. Workflows can have multiple levels and condition-based routing (e.g. "BOQs over ₹500,000 also need director approval").

Submitting

While the BOQ is in Draft:

  1. Open the Approval Card that appears above the tabs.
  2. Optionally add notes for approvers.
  3. Click Submit for Approval.
  4. The BOQ flips to Pending Approval and routes to level 1 of the matched workflow.

You cannot submit an empty BOQ — the system requires at least one item.

Approving / Rejecting

When the BOQ is at your approval level:

  1. The Approval Card shows a level-by-level progress stepper.
  2. You'll also see it in the global Approvals queue (/approvals).
  3. Approve advances to the next level (or finalises if you're the last level). Reject sends the BOQ back to Draft with the reason recorded.

A user cannot approve a BOQ they created or submitted.

Auto-lock on final approval

When the final level approves, the BOQ is automatically locked:

  • is_locked = true, locked_at = now, locked_by = approver.
  • Item-level edit / delete / move actions are disabled in the UI.
  • Section management is disabled.

To make changes after approval, an admin must unlock the BOQ from the actions menu (or raise a Change Request — see below).

Approval workflow page

Settings → Workflow Engine → Approval Workflows lets admins:

  • Create new workflows scoped to entity_type = "boq".
  • Add levels (each tied to a role).
  • Add condition rules so that high-value BOQs route through extra levels.

Change Requests

Once approved, structural changes go through Change Requests:

  • Addition — add a new item.
  • Modification — change description, quantity, rate, etc.
  • Deletion — remove an item.
  • Rate Change — bulk rate update (often produced by Refresh Rates; see below).

Each CR goes through draft → submitted → approved → implemented; on implementation, the underlying BOQ items are mutated.

Rate management

Refreshing rates from inventory

For projects whose execution lags behind the BOQ — and inventory unit_cost has drifted — use Refresh Rates in the BOQ header (visible on approved BOQs):

  1. Click Refresh Rates.
  2. The dialog shows every linked item with current_rate → proposed_rate, variance percentage, and per-line cost impact.
  3. Pre-checked rows are those with a non-zero variance. Adjust the selection if needed.
  4. Click Create Rate-Change CR.
  5. A rate_change Change Request is drafted; submit it from the Change Requests tab. Once approved + implemented, the BOQ rates are updated.

Inventory price changes are tracked in an audit table (inventory_price_history) that records every unit_cost / selling_price change with source (created, manual, import, etc.).

Escalation index

A BOQ can carry an optional escalation index percentage (e.g. 8.5 for +8.5%). When set, the Refresh Rates preview applies it on top of the current inventory cost — useful for contracts with index-linked clauses.

Rate freeze

When a refresh CR is created, the BOQ's rate_frozen_at timestamp is stamped. This is informational; the actual rate-flip happens when the CR is approved and implemented.

Allocation (reservation)

The Allocation tab is the materials desk's view: per-item required vs. reserved vs. available, with a shortfall column.

Reserving stock

For each item linked to inventory:

  • Click Allocate to reserve up to the BOQ item's required quantity.
  • If part of the requirement was already reserved, the button reads Top Up.
  • If you ask for more than is available, the system partial-reserves up to free stock and reports the shortfall — it never fails outright as long as some stock is free.

Reserving moves quantity from quantity_available to quantity_reserved on the inventory row; both columns are updated atomically under a row-level lock so concurrent reservers can't double-allocate the same stock.

Releasing (unallocating)

Click Details on a row to see the reservations it holds. Each active reservation has a Release button. Releasing returns the quantity to quantity_available.

Reservation lifecycle

Status Meaning
Active Stock is held aside; counts toward quantity_reserved.
Released Manually unallocated; quantity restored.
Consumed Drained by a Delivery Challan dispatch (the reservation has been used up).
Expired Auto-released by the cron sweep when the optional expires_at passes.

Reservations on a BOQ's items are auto-released when the BOQ is Completed.

Procurement (Purchase Requisitions)

The materials desk consolidates buy lists across projects via Purchase Requisitions.

Generating a Requisition from a BOQ

On an approved BOQ, click Generate Requisition in the BOQ header. The system snapshots every item with a shortfall (adjusted_quantity − quantity_ordered > 0) into a new draft PR:

  • The PR is project-scoped (linked to this BOQ).
  • Each PR line links back to its BOQ item.
  • The PR starts in Draft state.

The Purchase Requisitions page

Procurement → Purchase Requisitions lists all PRs:

  • Filter by project (or leave it unset to see the full tenant-wide buy list).
  • Filter by status (Draft, Pending Approval, Approved, Partially Ordered, Ordered, Cancelled).
  • Click into any PR for line detail.

PR lifecycle

Status Meaning
Draft Being filled in.
Pending Approval Submitted to the PR approval workflow.
Approved Ready for conversion to PO(s).
Partially Ordered Some lines have been turned into POs; others remain.
Ordered All lines fully sourced.
Cancelled Abandoned.

A default PR approval workflow is seeded per tenant (one level → project manager). Admins can configure more in the same Approval Workflows page.

Convert to PO

From an approved (or partially-ordered) PR, the Create PO per Vendor action lets you select a vendor + a subset of lines and convert them to a purchase order:

  • Multiple POs per PR are supported (run convert-to-PO once per vendor).
  • Ad-hoc BOQ lines auto-promote to the inventory catalog at this point so the resulting PO carries an inventory link.
  • BOQItem.quantity_ordered is incremented atomically for every line.
  • The PR's per-line quantity_ordered is also incremented; the PR status flips to Partially Ordered or Ordered based on remaining qty.

Direct PO from BOQ

For quick-buys that don't need the full PR cycle, Generate PO from BOQ remains available — it bypasses the PR layer and creates a PO directly. The BOQ-side quantity_ordered writeback still happens.

Delivery (Delivery Challans)

Physical shipments from inventory to the project site are recorded as Delivery Challans on the Delivery tab.

Creating a DC

  1. Click New Delivery Challan.
  2. Pick items + quantities from the dialog (only items with remaining deliverable qty are shown).
  3. Optionally enter vehicle no, driver, notes.
  4. Click Create Draft DC.

The DC is created in Draft; inventory is not yet mutated.

Dispatch caps

When you create a DC, two caps are validated:

  1. Against the BOQ total: this_dc_qty + already_delivered − already_returned ≤ adjusted_quantity.
  2. Against inventory headroom: this_dc_qty ≤ free_available + reservation_held_for_this_BOQ_item.

If either fails, the line is rejected up-front so you don't have to find out at dispatch time.

Dispatching

From the DC list, click Dispatch on a draft. The system:

  1. Drains the BOQ item's reservation first (oldest reservation, partial consumption allowed) before touching free stock.
  2. Decrements quantity_reserved and quantity_available accordingly.
  3. Increments BOQItem.quantity_delivered.
  4. Writes a stock-movement ledger entry (type=out, reference_type=delivery_challan).
  5. Writes a BOQ progress audit row.

Dispatch runs under a row-level lock per inventory item to keep concurrent DCs safe. If a line's combined reservation + available is insufficient, the whole dispatch transaction rolls back — partial dispatches don't sneak through.

Receiving

Once the truck arrives at site, click Mark Received on a dispatched DC. This is the site acknowledgement step:

  • Optional signature URL and photo URLs (uploaded via the standard presigned-URL flow).
  • Optional notes appended to the DC.
  • DC status flips to Received.

There are no further inventory side effects — that all happened at dispatch.

Cancelling

Only Draft DCs can be cancelled. Once dispatched, use a Site Return to reverse the inventory side.

Installation (Material Issues)

A Material Issue records on-site consumption of already-delivered stock. It drives BOQItem.quantity_installed but has no inventory side-effect — the stock left inventory at delivery.

Recording an installation

From the Installation tab:

  1. Click Record Installation.
  2. Pick items + quantities. The dialog only shows items with positive "headroom" (delivered − returned − installed > 0).
  3. Optionally pick a section / task to attribute the install to.
  4. Click Issue.

The MI is created and immediately issued — no separate review step. The system increments quantity_installed and writes a BOQProgress(installed) audit row.

Cap

new_installed_total + already_installed ≤ delivered − returned (i.e. you can only install what's actually on site and not been returned).

Cancelling an issued MI

Issued MIs can be cancelled — quantity_installed is decremented by the cancelled quantity, and a reversal audit row is written.

Site Returns

Stock coming back from a project site is recorded as a Site Return on the Delivery tab.

Per-line condition

Each line on an SR carries a condition:

Condition Behaviour on receive
Usable Quantity restocked into quantity_available; BOQItem.quantity_returned incremented.
Defective No inventory side-effect; quantity_returned still incremented (so the cap math stays consistent).
Scrap Same as defective — terminal write-off.

Cap

SR_qty ≤ delivered − already_returned − installed — you cannot return what is installed or already returned.

Lifecycle

  1. Draft — line items entered with their conditions.
  2. Received — terminal positive state. Usable lines have run through restock, all lines have bumped quantity_returned, audit rows written.
  3. Cancelled — only valid from Draft.

Invoicing

The Invoices tab drives client billing.

Billable summary

Top of the tab shows the BOQ-level monetary summary: invoiceable now, invoiced to date, paid, outstanding, credit notes, net billed.

The per-item table shows:

Column Meaning
Required adjusted_quantity (the contractual amount).
Invoiced quantity_invoiced to date.
Billable now Required − Invoiced. Zero means fully billed.
Rate The unit rate.
Billable value Billable now × Rate.

Generate Invoice

Click Generate Invoice to draft a milestone invoice. Default behaviour:

  • Pre-selects all items with Billable now > 0, qty defaulting to remaining.
  • Cap enforced: qty_invoiced + this_invoice_qty ≤ adjusted_quantity per item. The qty cap is unit-based; credit notes do not unlock additional quantity.
  • Creates an Invoice + line items.
  • Writes back BOQItem.quantity_invoiced.

Retention / holdback

If the BOQ has retention_percent set (typical 5–10% for construction contracts), every invoice generated against it holds back that percentage of the pre-tax subtotal:

  • retention_amount = subtotal × retention_percent / 100.
  • The invoice's amount_due is reduced by the retention amount (the client is billed net of retention).
  • retention_held_to_date snapshots the cumulative still-held value at issue time.

A retention banner appears at the top of the Invoices tab whenever retention_percent > 0 or any retention is currently held. It shows the percentage, the amount currently held, and the configured release terms (free text on the BOQ).

Releasing retention

When contractual conditions are met (practical completion, defects-liability expiry, etc.), click Release Retention:

  1. Optionally enter a partial amount (leaves blank = release everything held).
  2. Optionally add notes.
  3. Click Release.

A "release invoice" is drafted with a positive total_amount and a negative retention_amount so the running sum gives the current still-held value naturally. Issuing this invoice bills the client for the released portion.

Credit notes

Credit notes (created from the standard Invoice module) are netted at the invoice level (monetary). They reduce total_outstanding_value and net_billed_value in the summary but do not unlock additional invoiceable quantity on the BOQ — the qty cap stays Required − Invoiced.

Completion

A BOQ reaches Completed when:

  1. Every item is accounted for: invoiced + returned ≥ adjusted_quantity (within a 0.01 tolerance for decimal drift).
  2. All linked POs are closed: status is received or cancelled.
  3. Retention is released or zero: the running sum of Invoice.retention_amount is at most 0.01.

The Completion Card above the tabs reports readiness:

  • Not Yet Completable — lists each blocker with a description.
  • Ready to Complete — shows a green button that, on a two-click confirm, flips the BOQ to Completed.

On completion:

  • Status → Completed, completed_at and completed_by stamped.
  • Any active reservations on linked items are auto-released so they don't sit forever.
  • The BOQ stays locked.

Reopening

Admins can reopen a Completed BOQ from the same Completion Card. Status goes back to Approved and completed_* are cleared. This is for accounting corrections (e.g. issuing a credit note + new invoice for already-released retention) and should not be used routinely.

History

The History tab shows a chronological audit trail. Events captured include:

  • BOQ submitted / approved / rejected / locked.
  • Change request created / approved / implemented.
  • Delivery Challan dispatched / received / cancelled.
  • Material Issue issued / cancelled.
  • Site Return received.
  • Purchase Requisition converted to PO.
  • BOQ status changes (including completion).

Each entry shows actor, timestamp, and a descriptive note.

Permissions

Permission Grants
boq.read View BOQs and their tabs.
boq.create Create new BOQs and items.
boq.update Edit BOQs (only while not locked).
boq.delete Delete BOQs and items.
boq.approve Approve / reject BOQs and Change Requests.
boq.reserve Reserve / release inventory for BOQ items.
boq.dispatch Create / dispatch / cancel DCs and MIs.
boq.return Create / receive / cancel Site Returns.
boq.invoice Generate invoices and release retention.
boq.complete Mark BOQ complete; reopen completed BOQs.
purchase_requisition.read / .create / .update / .approve Purchase Requisition lifecycle.

Default role grants out of the box:

Role BOQ permissions
Admin / Super Admin All
Project Manager All
Store Supervisor read, reserve, dispatch, return; PR read/create/update
Accountant read, invoice, complete; PR read
Site Engineer read; PR read

Approval alerts

When BOQs need your attention:

  • Home Dashboard — A red Pending Approvals card appears.
  • Projects Dashboard — Replaces the Budget Utilization card when approvals are pending.
  • Project Detail — A red alert banner shows below the quick stats bar.
  • All alerts link to the Approvals page.