Change orders, EOT claims, variations, and arbitration management
InfraTraq implements a complete change management and claims lifecycle covering the full spectrum from variation requests through arbitration. The system manages variation requests, change orders, engineering change orders (ECOs), delay events, extension of time (EOT) claims, cost claims, and arbitration proceedings — all aligned with Indian construction contract standards (FIDIC / Indian Conditions of Contract).
| Status | Description | Allowed Actions | Next States |
|---|---|---|---|
| Draft | Variation request or claim created but not yet submitted | Edit, Submit, Delete | Submitted |
| Submitted | Variation request or claim submitted for evaluation | Evaluate, Return | Evaluated, Draft |
| Evaluated | Cost and time impact assessment completed | Create CO, Reject | Pending Approval |
| Pending Approval | Change order awaiting multi-level approval | Approve, Reject, Return | Approved, Rejected |
| Client Review | Change order sent to client for approval | Client Approve, Client Reject | Approved, Rejected |
| Approved | Change order or claim formally approved for execution | Execute, Measure, Bill | In Execution |
| In Execution | Changed work being executed on site | Measure, Update Progress | Measured |
| Measured | Completed work measured and verified | Bill, Close | Billed, Closed |
| Billed | Variation amount billed in running account | Track Payment, Close | Closed |
| Settled | Claim negotiation concluded with agreed settlement | Update Finance, Close | Closed |
| Closed | Change order or claim fully resolved and closed | View, Audit | — |
| Rejected | Change order or claim rejected at any approval stage | Edit, Resubmit, Archive | Draft |
co_id — PK, master change order recordproject_id — FK → project.projectcontract_id — FK → contracts.contractco_number, co_type — Classification (client-instructed, contractor-proposed, regulatory, design-driven)cost_impact, time_impact_days — Assessed impactstatus — draft, submitted, client_review, approved, rejectedvr_id — PK, initial variation request raised from siteproject_id — FK → project.projectvr_number — Auto-generated sequence per projectestimated_cost, estimated_time_impact — Preliminary impact estimatestatus — draft, evaluated, convertedeco_id — PK, engineering change order tracking design changesproject_id — FK → project.projecteco_number, design_discipline — Discipline classificationcost_impact, schedule_impact — Assessed impact on projectevent_id — PK, recorded delay eventproject_id — FK → project.projectevent_type, cause_category — Employer risk, contractor risk, neutral eventdelay_days — Duration of delay in calendar daysis_excusable, is_compensable — Entitlement classification flagsclaim_id — PK, Extension of Time claimproject_id — FK → project.projecttotal_delay_days, requested_eot_days — Delay quantumcost_impact — Prolongation and associated costsmethod_of_analysis — As-Planned vs As-Built, Time Impact, Windowsstatus — draft, submitted, negotiating, settled, arbitrationid — PK, cost breakdown per claimclaim_id — FK → claims.eot_claimcost_category — Prolongation, disruption, acceleration, direct costsclaimed_amount, approved_amount — Claimed vs settled amountsnotice_id — PK, contractual notice servedproject_id — FK → project.projectnotice_type — Delay, variation, claim, generalclause_reference — Contract clause (e.g., FIDIC Sub-Clause 20.1)response_due_date — Deadline for client responsearb_id — PK, arbitration proceedings recordproject_id — FK → project.projectclaim_amount — Total amount in disputearbitrator — Appointed arbitrator detailsaward_amount — Final arbitral awardstatus — initiated, arbitrator_appointed, hearing, award, enforcementSite team identifies a potential variation from the original contract scope. This may arise from client instruction, design changes, differing site conditions, or regulatory requirements. A variation_request is raised with preliminary description and estimated impacts.
The commercial team evaluates the variation request for cost impact (re-rate existing items or new rates per Indian Schedule of Rates), time impact (critical path analysis), and scope definition. The variation_request.estimated_cost and estimated_time_impact are updated with the assessment results.
Once assessed, a formal change_order is created linking to the variation request. The CO includes approved scope, cost breakdown, revised BOQ items, time impact in days, and contract clause references. The co_type classifies it (client-instructed, contractor-proposed, regulatory, design-driven).
Change orders route through approval workflows based on value thresholds: Site PM (up to ₹5L), Project Director (up to ₹25L), Regional Head (up to ₹1Cr), MD/Board (above ₹1Cr). Client-side approval is tracked separately. Status transitions: draft → submitted → client_review → approved/rejected.
When a delay occurs, the site team records it in claims.delay_event with contemporaneous evidence (photos, correspondence, weather data, labour records). Each event is classified by cause_category (employer risk, contractor risk, neutral event) and flagged as is_excusable and/or is_compensable.
Upon identifying a potential claim event, a formal claims.notice is served referencing the specific contract clause (e.g., FIDIC Sub-Clause 20.1). The system tracks response_due_date and auto-reminds if no response is received. Notice must be served within the contractual time bar (typically 28 days).
The system supports multiple delay analysis methodologies: As-Planned vs As-Built (simple comparison), Time Impact Analysis (prospective, event-by-event insertion into schedule), and Windows Analysis (retrospective, period-by-period). The eot_claim.method_of_analysis records the chosen approach.
Cost claims are built in claims.claim_cost with categories: prolongation costs (site overheads, staff, equipment), disruption costs (loss of productivity), acceleration costs (overtime, additional resources), and direct costs (material price escalation). Each line has claimed_amount supported by documentation.
After claim submission, the system tracks negotiation rounds. Each round records the client's position, contractor's counter, and agreed items. The claims.claim_cost.approved_amount is updated as items are agreed. If parties reach settlement, the claim status moves to settled and financial records are updated.
If negotiation fails, claims.arbitration is initiated. The system tracks arbitrator appointment, hearing dates, submissions, and the final award_amount. Status flow: initiated → arbitrator_appointed → hearing → award → enforcement. Legal team is auto-notified and all claim documentation is packaged for the proceedings.
class ChangeClaimService { /** Raise a new variation request from site */ async createVariationRequest(projectId, description, estimatedImpact) { const vr = await VariationRequest.create({ project_id: projectId, vr_number: await this.generateVRNumber(projectId), description, estimated_cost: estimatedImpact.cost, estimated_time_impact: estimatedImpact.days, status: 'draft' }); await NotificationService.notify('PM', 'COMMERCIAL', { type: 'variation_request_raised', vr_id: vr.vr_id }); return vr; } /** Evaluate a variation request for cost/time/scope impact */ async evaluateChangeOrder(vrId) { const vr = await VariationRequest.findById(vrId); const costAnalysis = await BOQService.priceVariation(vr); const scheduleImpact = await ScheduleService.assessTimeImpact(vr); const scopeDefinition = await ScopeService.defineChangedScope(vr); await vr.update({ estimated_cost: costAnalysis.totalCost, estimated_time_impact: scheduleImpact.criticalPathDays, status: 'evaluated' }); return { costAnalysis, scheduleImpact, scopeDefinition }; } /** Create formal change order from evaluated variation request */ async createChangeOrder(vrId, approvedScope) { const vr = await VariationRequest.findById(vrId); if (vr.status !== 'evaluated') throw new Error('VR must be evaluated first'); const co = await ChangeOrder.create({ project_id: vr.project_id, contract_id: approvedScope.contractId, co_number: await this.generateCONumber(vr.project_id), co_type: approvedScope.type, cost_impact: approvedScope.costImpact, time_impact_days: approvedScope.timeImpactDays, status: 'pending_approval' }); await ApprovalService.initiate('change_order', co.co_id, co.cost_impact); return co; } /** Record a delay event with contemporaneous evidence */ async recordDelayEvent(projectId, eventDetails) { const event = await DelayEvent.create({ project_id: projectId, event_type: eventDetails.type, cause_category: eventDetails.causeCategory, delay_days: eventDetails.delayDays, is_excusable: eventDetails.isExcusable, is_compensable: eventDetails.isCompensable, description: eventDetails.description, evidence_refs: eventDetails.evidenceDocIds }); // Check if notice is required under the contract const contract = await ContractService.getNoticeRequirements(projectId); if (contract.requiresNotice) { await this.promptNoticeServing(projectId, event.event_id, contract.noticePeriodDays); } return event; } /** Serve contractual notice referencing specific clause */ async serveNotice(projectId, noticeType, clauseRef) { const contract = await ContractService.getByProject(projectId); const responseDue = new Date(); responseDue.setDate(responseDue.getDate() + contract.response_period_days); const notice = await Notice.create({ project_id: projectId, notice_type: noticeType, clause_reference: clauseRef, response_due_date: responseDue, status: 'served' }); await DocumentService.generateNoticeLetter(notice); return notice; } /** Prepare an EOT claim linking delay events with analysis method */ async prepareEOTClaim(projectId, delayEventIds, analysisMethod) { const events = await DelayEvent.findByIds(delayEventIds); const totalDelay = events.reduce(function(sum, e) { return sum + e.delay_days; }, 0); const analysis = await DelayAnalysisService.run(analysisMethod, events); const claim = await EOTClaim.create({ project_id: projectId, total_delay_days: totalDelay, requested_eot_days: analysis.entitledDays, cost_impact: analysis.prolongationCost, method_of_analysis: analysisMethod, status: 'draft' }); return claim; } /** Submit a prepared claim for review */ async submitClaim(claimId) { const claim = await EOTClaim.findById(claimId); const costs = await ClaimCost.findByClaimId(claimId); if (!costs.length) throw new Error('Claim must have cost breakdown before submission'); await claim.update({ status: 'submitted', submitted_at: new Date() }); await ApprovalService.initiate('eot_claim', claimId, claim.cost_impact); return claim; } /** Track negotiation rounds between contractor and client */ async trackNegotiation(claimId, rounds) { for (const round of rounds) { await NegotiationRound.create({ claim_id: claimId, round_number: round.number, contractor_position: round.contractorAmount, client_position: round.clientAmount, agreed_items: round.agreedItems, notes: round.notes }); } const latestRound = rounds[rounds.length - 1]; if (latestRound.settled) { await EOTClaim.update(claimId, { status: 'settled' }); await FinanceService.updateRevisedBudget(claimId, latestRound.agreedAmount); } } /** Initiate arbitration when negotiation fails */ async initiateArbitration(projectId, disputeDetails) { const arb = await Arbitration.create({ project_id: projectId, claim_amount: disputeDetails.claimAmount, arbitrator: disputeDetails.proposedArbitrator, award_amount: null, status: 'initiated' }); await NotificationService.notify('LEGAL_TEAM', { type: 'arbitration_initiated', arb_id: arb.arb_id }); await DocumentService.packageClaimDocuments(projectId, arb.arb_id); return arb; } }
| Rule | Condition | Action |
|---|---|---|
| Notice Time Bar | Notice not served within contractual time limit (e.g., 28 days) | Block claim submission, warn of potential entitlement loss |
| Contemporaneous Records | Delay event created more than 7 days after occurrence | Flag as late recording, require justification |
| Contract Variation Limit | Change order cost exceeds contract variation limit % | Require additional approval level (Board/MD) |
| Claim Documentation | Claim amounts not supported by uploaded evidence | Block submission until supporting documents attached |
| ECO Drawing Reference | ECO does not reference affected drawings | Reject ECO, require drawing list |
| Duplicate Variation | Variation request already exists for same scope item | Show existing VR, prevent duplicate creation |
| Delay Classification | Delay event marked compensable but cause is contractor risk | Warn and require commercial team review |
| Event | Source Table | Auto Action |
|---|---|---|
| Variation Request Raised | change_order.variation_request | Notify PM and commercial team for evaluation |
| Change Order Approved | change_order.change_order | Update BOQ line items and commitment records |
| Delay Event Recorded | claims.delay_event | Check notice requirements, prompt notice serving if applicable |
| Notice Deadline Approaching | claims.notice | Auto-reminder at 7 days, 3 days, and 1 day before response_due_date |
| Claim Submitted | claims.eot_claim | Create approval workflow, notify client representative |
| Arbitration Initiated | claims.arbitration | Notify legal team, package all claim documentation |
| ECO Created | change_order.eco | Notify design team, flag affected drawings for revision |
| Claim Settled | claims.eot_claim | Update revised budget, adjust EVM baseline, close related notices |
claims.delay_event on (project_id, event_type, cause_category) for fast claim assembly queriesCHECK (approved_amount ≤ claimed_amount) on claim_costaudit.audit_trail for all change order and claim state transitions