Back to ER Diagram
Subcontractor Cycle

Subcontractor Cycle Logic

Complete subcontractor lifecycle — WO → DMB → RA Bill → Retention → Settlement

PostgreSQL
13 Tables
Schema: subcontractor
Retention Tracking

Overview

InfraTraq implements the full Subcontractor Management Lifecycle: WO → DMB → RA Bill → Payment → Settlement. 13 subcontractor tables manage work orders, measurement books, running account bills, retention, advances, security deposits, and final settlement. Designed for the Indian construction industry standard with retention, SD (Security Deposit), and LD (Liquidated Damages) provisions.


Empanelment

Work Order

Measurement

RA Bill

Payment

Settlement
Stage 1 — EMPANELMENT Subcontractor registration with trade and compliance details
Stage 2 — WORK ORDER Contract terms, retention, SD, LD provisions agreed
Stage 3 — MEASUREMENT Daily Measurement Book (DMB) in LBHQ format
Stage 4 — RA BILL Running Account Bill with deductions computed
Stage 5 — PAYMENT AP invoice, TDS deduction, bank transfer
Stage 6 — SETTLEMENT Final account after DLP expiry, retention & SD release
13
Subcontractor Tables
6
Lifecycle Stages
5
Deduction Types
LBHQ
Measurement Format

Status States

StatusDescriptionAllowed ActionsNext States
DraftWO/DMB/RA Bill created but not yet submittedEdit, Submit for Approval, DeletePending Approval
Pending ApprovalAwaiting PM/Contracts/Finance approvalApprove, Reject, ReturnApproved, Rejected
ApprovedWO approved and commitment created; DMB/RA Bill certifiedExecute, Amend, MeasureIn Progress, Amended
Under MeasurementActive WO with DMB recording in progressRecord DMB, Certify, Generate RA BillBill Generated
CertifiedDMB quantities verified and certified by engineerInclude in RA Bill, DisputeBilled
Bill GeneratedRA Bill compiled from certified DMBs with deductionsSubmit, Review, CorrectPending Approval
PaidRA Bill payment released via AP invoiceView, Audit, Generate Next BillSettled
SettledFinal settlement after DLP — retention & SD releasedView, Audit
CancelledWO cancelled; commitment released, balance restoredView, Audit
RejectedApproval denied; returned to originator for correctionEdit, Resubmit, DeleteDraft

Database Schema

subcontractor.subcontractor_master

  • sc_id — PK, empanelled subcontractor registry
  • sc_name — Subcontractor name
  • trade — Trade specialisation (civil, MEP, etc.)
  • gstin — GST identification number
  • pan — PAN for TDS compliance

subcontractor.work_order

  • wo_id — PK, work order header with contract terms
  • sc_id — FK → subcontractor.subcontractor_master
  • project_id — FK → project.project
  • wo_number — Auto-generated WO number
  • original_value, revised_value — Contract amounts
  • retention_percent, sd_percent, ld_rate — Deduction terms
  • status — draft, approved, in_progress, completed, cancelled

subcontractor.wo_item

  • id — PK, work order line items linked to BOQ
  • wo_id — FK → subcontractor.work_order
  • boq_item_id — FK → estimation.boq_item
  • description, uom — Scope description and unit
  • quantity, rate, amount — Agreed quantities and rates

subcontractor.dmb

  • dmb_id — PK, Daily Measurement Book header
  • wo_id — FK → subcontractor.work_order
  • dmb_number, dmb_date — Measurement identification
  • measured_by — FK → auth.user (site engineer)
  • total_value, status — Computed total and certification status

subcontractor.dmb_item

  • id — PK, measurement line items in LBHQ format
  • dmb_id — FK → subcontractor.dmb
  • wo_item_id — FK → subcontractor.wo_item
  • length, breadth, height, quantity — LBHQ dimensions
  • rate, amount — WO rate applied to measured quantity

subcontractor.ra_bill

  • bill_id — PK, Running Account Bill header
  • wo_id — FK → subcontractor.work_order
  • sc_id — FK → subcontractor.subcontractor_master
  • bill_number — Sequential RA bill number per WO
  • gross_amount, retention_amount, advance_recovery — Bill components
  • net_amount, cumulative_amount — Payable and running total
  • status — draft, certified, approved, paid

subcontractor.sc_retention

  • id — PK, retention tracking per WO
  • wo_id — FK → subcontractor.work_order
  • retention_amount — Cumulative retention deducted
  • released_amount — Retention released after DLP
  • balance — Unreleased retention balance

subcontractor.sc_settlement

  • id — PK, final account settlement after DLP expiry
  • wo_id — FK → subcontractor.work_order
  • total_billed, total_paid — Lifetime totals
  • retention_released, ld_applied — Settlement adjustments
  • net_settlement — Final payable/receivable amount

Process Flow


WO Issued
work_order approved
₹50,00,000

Site Work
SC mobilises
at site

Daily Measurement
dmb + dmb_item
LBHQ ₹8,40,000

DMB Certification
Engineer certifies
quantities

RA Bill Preparation
ra_bill cumulative
quantities

Deductions
Retention, SD, Adv,
LD, Material

Approval
PM → Finance
→ Management

Payment
AP invoice +
TDS deducted

DLP Tracking
12-month defect
liability period

Final Settlement
Retention + SD
released

Deduction Breakdown (Example RA Bill)

  • Gross Amount: ₹8,40,000
  • (-) Retention @ 5%: ₹42,000
  • (-) SD @ 2.5%: ₹21,000
  • (-) Advance Recovery (10% per bill): ₹84,000
  • (-) LD (if applicable): ₹0
  • (-) Material Recovery: ₹15,000
  • Net Payable: ₹6,78,000

Key Principle

  • Net RA Bill = Gross Amount − Retention − SD − Advance Recovery − LD − Material Recovery
  • Cumulative billing ensures no item exceeds WO quantity
  • Retention is released only after Defect Liability Period (DLP) expiry
  • Final settlement reconciles all deductions, recoveries, and balances

Step-by-Step Logic

1

Work Order Creation

Project team creates a Work Order against an empanelled subcontractor. WO items are linked to BOQ items with agreed rates. Contract terms specify retention_percent, sd_percent, ld_rate, advance amount, and payment terms. WO approval triggers a financial commitment in the commitment accounting system.

2

DMB Recording (LBHQ Format)

Site engineers record daily measurements in the dmb + dmb_item tables using the standard LBHQ format (Length × Breadth × Height × Quantity). Each measurement line references a wo_item_id to track against WO scope. Cumulative DMB quantities are checked against WO quantities to prevent over-measurement.

3

RA Bill Compilation

Running Account Bills are generated from certified DMBs. The system compiles cumulative quantities per WO item, computes gross_amount at WO rates, and subtracts the previous RA bill's cumulative to arrive at the current bill value. This ensures the running total never exceeds WO value.

4

Deduction Calculations

Five types of deductions are computed: Retention (% of gross as per WO terms), Security Deposit (% of gross), Advance Recovery (proportional recovery capped at % per bill), Liquidated Damages (per contract delay terms), and Material Recovery (for materials issued to SC from project stores).

5

Bill Certification

The certified RA bill goes through quantity verification by the site engineer, rate verification against WO terms, and deduction computation validation. The certifying officer confirms the net payable amount. Any disputed items are flagged for resolution before certification.

6

Approval Workflow

Certified RA bills follow a multi-level approval workflow: Site Engineer → Project Manager → Contracts Manager → Finance. Approval thresholds are configured per project. Bills above threshold require additional management approval. Each approval updates the bill status progressively.

7

Payment Processing

Approved RA bills generate an AP invoice in the finance module. Payment is processed with TDS deduction (as per Indian income tax provisions — typically 1% u/s 194C for SC payments). GST input credit is captured. Payment updates commitment.paid_amount in the commitment accounting system.

8

Retention Management

Retention deducted from each RA bill is tracked in sc_retention. The cumulative retention balance grows with each bill. Retention is released in two stages: 50% on completion certificate and 50% after DLP expiry. Partial releases are supported with full audit trail.

9

Defect Liability Period Tracking

On WO completion, the system starts a DLP timer (typically 12 months). During DLP, any defects reported are tracked against the SC. Rectification costs can be deducted from retained amounts. The system auto-notifies stakeholders 30 days before DLP expiry to initiate retention release.

10

Final Settlement

After DLP expiry and defect clearance, the final settlement is prepared in sc_settlement. It reconciles: total billed vs. total paid, retention released, LD applied, SD returned, and any pending material recoveries. The net settlement amount is processed as the final payment, closing the WO commitment.

Code Implementation

class SubcontractorService {

  /** Create a new work order for a subcontractor */
  async createWorkOrder(scId, projectId, scopeItems) {
    const sc = await SubcontractorMaster.findById(scId);
    if (!sc || sc.status !== 'empanelled') throw new Error('SC not empanelled');
    const totalValue = scopeItems.reduce((s, i) => s + i.quantity * i.rate, 0);
    await CommitmentService.checkBudgetAvailability(projectId, totalValue);
    const wo = await WorkOrder.create({
      sc_id: scId, project_id: projectId,
      wo_number: await generateWONumber(projectId),
      original_value: totalValue, revised_value: totalValue,
      retention_percent: 5, sd_percent: 2.5, ld_rate: 0.5,
      status: 'draft'
    });
    for (const item of scopeItems) {
      await WOItem.create({
        wo_id: wo.wo_id, boq_item_id: item.boqItemId,
        description: item.description, uom: item.uom,
        quantity: item.quantity, rate: item.rate, amount: item.quantity * item.rate
      });
    }
    return wo;
  }

  /** Record daily measurement in LBHQ format */
  async recordMeasurement(woId, items) {
    const wo = await WorkOrder.findById(woId);
    const dmb = await DMB.create({
      wo_id: woId, dmb_number: await generateDMBNumber(woId),
      dmb_date: new Date(), status: 'draft'
    });
    let total = 0;
    for (const m of items) {
      const woItem = await WOItem.findById(m.woItemId);
      const qty = m.length * m.breadth * m.height * m.nos;
      const cumQty = await DMBItem.sumQty(m.woItemId);
      if (cumQty + qty > woItem.quantity) throw new Error('Exceeds WO qty');
      const amount = qty * woItem.rate;
      await DMBItem.create({
        dmb_id: dmb.dmb_id, wo_item_id: m.woItemId,
        length: m.length, breadth: m.breadth, height: m.height,
        quantity: qty, rate: woItem.rate, amount
      });
      total += amount;
    }
    await dmb.update({ total_value: total });
    return dmb;
  }

  /** Generate RA Bill from certified DMBs for a given period */
  async generateRABill(woId, fromDate, toDate) {
    const wo = await WorkOrder.findById(woId);
    const certifiedDMBs = await DMB.findAll({
      wo_id: woId, status: 'certified',
      dmb_date: { between: [fromDate, toDate] }
    });
    const grossAmount = certifiedDMBs.reduce((s, d) => s + d.total_value, 0);
    const prevCumulative = await RABill.maxCumulative(woId);
    if (prevCumulative + grossAmount > wo.revised_value)
      throw new Error('Cumulative exceeds WO value');
    const bill = await RABill.create({
      wo_id: woId, sc_id: wo.sc_id,
      bill_number: await generateBillNumber(woId),
      gross_amount: grossAmount,
      cumulative_amount: prevCumulative + grossAmount,
      status: 'draft'
    });
    const deductions = await this.calculateDeductions(bill.bill_id);
    return { bill, deductions };
  }

  /** Calculate all deductions for an RA bill */
  async calculateDeductions(billId) {
    const bill = await RABill.findById(billId);
    const wo = await WorkOrder.findById(bill.wo_id);
    const retention = bill.gross_amount * wo.retention_percent / 100;
    const sd = bill.gross_amount * wo.sd_percent / 100;
    const advRecovery = Math.min(
      bill.gross_amount * 10 / 100,
      await AdvanceBalance.remaining(wo.wo_id)
    );
    const ld = await LDCalculator.compute(wo.wo_id);
    const materialRecovery = await MaterialIssue.unrecovered(wo.wo_id);
    const netAmount = bill.gross_amount - retention - sd - advRecovery - ld - materialRecovery;
    await bill.update({ retention_amount: retention, advance_recovery: advRecovery, net_amount: netAmount });
    await SCRetention.upsert({ wo_id: wo.wo_id, retention_amount: literal('retention_amount + ' + retention) });
    return { retention, sd, advRecovery, ld, materialRecovery, netAmount };
  }

  /** Process final settlement after DLP expiry */
  async processSettlement(woId) {
    const wo = await WorkOrder.findById(woId);
    const totalBilled = await RABill.sumGross(woId);
    const totalPaid = await RABill.sumNet(woId);
    const retention = await SCRetention.findByWO(woId);
    const ldApplied = await LDCalculator.totalLD(woId);
    const settlement = await SCSettlement.create({
      wo_id: woId, total_billed: totalBilled, total_paid: totalPaid,
      retention_released: retention.balance, ld_applied: ldApplied,
      net_settlement: retention.balance - ldApplied
    });
    await this.releaseRetention(woId, retention.balance);
    await CommitmentService.closeCommitment(woId);
    return settlement;
  }

  /** Release retention amount after defect liability period */
  async releaseRetention(woId, amount) {
    const retention = await SCRetention.findByWO(woId);
    if (amount > retention.balance) throw new Error('Release exceeds balance');
    await retention.update({
      released_amount: literal('released_amount + ' + amount),
      balance: literal('balance - ' + amount)
    });
    // Create AP invoice for retention release payment
    await APService.createInvoice({
      vendor_id: (await WorkOrder.findById(woId)).sc_id,
      amount, type: 'retention_release', reference: 'WO-' + woId
    });
    return retention;
  }
}

Validation Rules

RuleConditionAction
DMB Quantity CeilingDMB cumulative quantity > WO item quantityBlock measurement entry, show remaining qty
RA Bill Cumulative CapRA bill cumulative amount > WO revised valueBlock bill generation, show WO balance
Retention % MatchRetention deducted ≠ WO retention_percent × grossAuto-correct to WO terms, flag discrepancy
LD CalculationLD applied per contract delay clauseCompute as ld_rate × delay days × WO value / 100
Advance Recovery CapRecovery per bill > configured % of grossCap recovery at max % per bill, carry forward balance
Material Recovery LinkRecovery amount must match issued material recordsBlock if unlinked, require store issue reference

Automated Actions & Triggers

EventSource TableAuto Action
WO Approvedsubcontractor.work_orderCreate commitment in finance.commitment + post JE
DMB Certifiedsubcontractor.dmbMark DMB items as available for billing
RA Bill Approvedsubcontractor.ra_billCreate AP invoice + update commitment invoiced_amount
Payment Releasedaccounts_payable.payment_voucherUpdate commitment.paid_amount + sc_retention balance
WO Completionsubcontractor.work_orderStart defect liability period timer
DLP Expirysubcontractor.work_orderNotify PM + Finance to release retention & SD

Integration Points

Upstream (Data Sources)

  • BOQ / Estimation — WO item rates sourced from BOQ line items
  • Procurement — Materials supplied to SC from project stores
  • Labour Module — SC worker attendance and tracking

Downstream (Consumers)

  • Finance — Commitment — WO value feeds commitment accounting
  • Accounts Payable — RA bill approval creates AP invoice for payment
  • Tax Module — GST input credit & TDS u/s 194C on SC payments
  • Analytics — SC performance scoring, cost tracking, delay analysis

Best Practices

Implementation Guidelines

  • DMB Recording — Record measurements daily at site, never backdate. Photograph key measurements. Have SC representative co-sign the DMB for dispute avoidance.
  • RA Bill Reconciliation — Reconcile cumulative quantities in every RA bill against WO scope. Flag items exceeding 90% utilisation for early WO amendment.
  • Retention Management — Maintain a retention register per WO. Auto-notify finance 30 days before DLP expiry. Track partial releases with reasons.
  • LD Application — Apply LD only after formal notice to SC. Document delay reasons and allow SC response before deduction. Ensure LD cap per contract is enforced.
  • Settlement Checklist — Verify: all DMBs certified, all RA bills paid, material recovery complete, no pending defects, DLP expired, retention balance correct, SD returned.

Common Pitfalls

  • Recording DMB after the fact without site verification — leads to inflated measurements
  • Not recovering advance proportionally — results in large outstanding at WO end
  • Releasing retention before DLP expiry — loses leverage for defect rectification
  • Ignoring material recovery — project absorbs cost of materials issued to SC
  • Not closing WO commitment after settlement — phantom obligations in budget reports