✓ Verified 📁 File Management ✓ Enhanced Data

Estimate Builder Qmohd

Build construction project estimates.

Rating
4.5 (385 reviews)
Downloads
1,867 downloads
Version
1.0.0

Overview

Build construction project estimates.

Complete Documentation

View Source →


name: "estimate-builder" description: "Build construction project estimates. Generate detailed cost breakdowns with labor, materials, equipment, and overhead." homepage: "https://datadrivenconstruction.io" metadata: {"openclaw":{"emoji":"📊","os":["darwin","linux","win32"],"homepage":"https://datadrivenconstruction.io","requires":{"bins":["python3"]}}}

Estimate Builder

Business Case

Problem Statement

Estimate creation challenges:
  • Complex cost structures
  • Multiple cost categories
  • Markup calculations
  • Format requirements vary

Solution

Structured estimate builder that creates professional construction estimates with proper cost categorization, markups, and export capabilities.

Technical Implementation

``python import pandas as pd from typing import Dict, Any, List, Optional from dataclasses import dataclass, field from datetime import date from enum import Enum class CostCategory(Enum): LABOR = "labor" MATERIAL = "material" EQUIPMENT = "equipment" SUBCONTRACTOR = "subcontractor" OTHER = "other" @dataclass class EstimateLineItem: line_number: int wbs_code: str description: str quantity: float unit: str unit_cost: float category: CostCategory notes: str = "" @property def total_cost(self) -> float: return round(self.quantity * self.unit_cost, 2) @dataclass class CostSummary: labor: float = 0 material: float = 0 equipment: float = 0 subcontractor: float = 0 other: float = 0 @property def direct_cost(self) -> float: return self.labor + self.material + self.equipment + self.subcontractor + self.other @dataclass class Markup: name: str rate: float # As decimal (0.10 = 10%) base: str = "direct" # "direct" or "subtotal" class EstimateBuilder: """Build construction project estimates.""" def __init__(self, project_name: str, project_number: str = ""): self.project_name = project_name self.project_number = project_number self.estimate_date = date.today() self.items: List[EstimateLineItem] = [] self.markups: List[Markup] = [] self._next_line = 1 def add_item(self, wbs_code: str, description: str, quantity: float, unit: str, unit_cost: float, category: CostCategory = CostCategory.OTHER, notes: str = "") -> EstimateLineItem: """Add line item to estimate.""" item = EstimateLineItem( line_number=self._next_line, wbs_code=wbs_code, description=description, quantity=quantity, unit=unit, unit_cost=unit_cost, category=category, notes=notes ) self.items.append(item) self._next_line += 1 return item def add_markup(self, name: str, rate: float, base: str = "direct"): """Add markup (overhead, profit, contingency, etc.).""" self.markups.append(Markup(name=name, rate=rate, base=base)) def set_standard_markups(self, overhead: float = 0.15, profit: float = 0.10, contingency: float = 0.05): """Set standard construction markups.""" self.markups = [ Markup("General Conditions / Overhead", overhead, "direct"), Markup("Profit", profit, "subtotal"), Markup("Contingency", contingency, "subtotal") ] def get_cost_summary(self) -> CostSummary: """Get cost summary by category.""" summary = CostSummary() for item in self.items: cost = item.total_cost if item.category == CostCategory.LABOR: summary.labor += cost elif item.category == CostCategory.MATERIAL: summary.material += cost elif item.category == CostCategory.EQUIPMENT: summary.equipment += cost elif item.category == CostCategory.SUBCONTRACTOR: summary.subcontractor += cost else: summary.other += cost return summary def calculate_total(self) -> Dict[str, Any]: """Calculate total estimate with markups.""" summary = self.get_cost_summary() direct_cost = summary.direct_cost markups_detail = [] subtotal = direct_cost for markup in self.markups: if markup.base == "direct": amount = direct_cost * markup.rate else: amount = subtotal * markup.rate markups_detail.append({ 'name': markup.name, 'rate': f"{markup.rate * 100:.1f}%", 'amount': round(amount, 2) }) subtotal += amount return { 'cost_summary': { 'labor': round(summary.labor, 2), 'material': round(summary.material, 2), 'equipment': round(summary.equipment, 2), 'subcontractor': round(summary.subcontractor, 2), 'other': round(summary.other, 2), 'direct_cost': round(direct_cost, 2) }, 'markups': markups_detail, 'total_markups': round(subtotal - direct_cost, 2), 'grand_total': round(subtotal, 2) } def get_items_by_wbs(self) -> Dict[str, List[EstimateLineItem]]: """Group items by WBS code prefix.""" by_wbs = {} for item in self.items: prefix = item.wbs_code.split('.')[0] if '.' in item.wbs_code else item.wbs_code if prefix not in by_wbs: by_wbs[prefix] = [] by_wbs[prefix].append(item) return by_wbs def import_from_df(self, df: pd.DataFrame): """Import line items from DataFrame.""" for _, row in df.iterrows(): self.add_item( wbs_code=str(row.get('wbs_code', '')), description=row['description'], quantity=float(row['quantity']), unit=row['unit'], unit_cost=float(row['unit_cost']), category=CostCategory(row.get('category', 'other').lower()), notes=row.get('notes', '') ) def export_to_df(self) -> pd.DataFrame: """Export estimate to DataFrame.""" data = [] for item in self.items: data.append({ 'Line': item.line_number, 'WBS': item.wbs_code, 'Description': item.description, 'Qty': item.quantity, 'Unit': item.unit, 'Unit Cost': item.unit_cost, 'Total': item.total_cost, 'Category': item.category.value, 'Notes': item.notes }) return pd.DataFrame(data) def export_to_excel(self, output_path: str) -> str: """Export estimate to Excel.""" totals = self.calculate_total() with pd.ExcelWriter(output_path, engine='openpyxl') as writer: # Cover sheet cover_df = pd.DataFrame([{ 'Project Name': self.project_name, 'Project Number': self.project_number, 'Estimate Date': self.estimate_date, 'Total Items': len(self.items), 'Direct Cost': totals['cost_summary']['direct_cost'], 'Grand Total': totals['grand_total'] }]) cover_df.to_excel(writer, sheet_name='Summary', index=False) # Line items items_df = self.export_to_df() items_df.to_excel(writer, sheet_name='Line Items', index=False) # Cost breakdown breakdown_df = pd.DataFrame([totals['cost_summary']]) breakdown_df.to_excel(writer, sheet_name='Cost Breakdown', index=False) # Markups if totals['markups']: markups_df = pd.DataFrame(totals['markups']) markups_df.to_excel(writer, sheet_name='Markups', index=False) return output_path def validate(self) -> List[str]: """Validate estimate for common issues.""" issues = [] if not self.items: issues.append("Estimate has no line items") for item in self.items: if item.quantity <= 0: issues.append(f"Line {item.line_number}: Invalid quantity") if item.unit_cost < 0: issues.append(f"Line {item.line_number}: Negative unit cost") if not item.description: issues.append(f"Line {item.line_number}: Missing description") if not self.markups: issues.append("No markups defined (overhead, profit)") return issues `

Quick Start

`python

Create estimate

estimate = EstimateBuilder("Office Building A", "PRJ-2024-001")

Add line items

estimate.add_item("01.01", "Site Preparation", 5000, "SF", 2.50, CostCategory.OTHER) estimate.add_item("03.01", "Concrete Foundation", 200, "CY", 350, CostCategory.MATERIAL) estimate.add_item("03.02", "Foundation Formwork", 1500, "SF", 8.50, CostCategory.LABOR) estimate.add_item("05.01", "Structural Steel", 50, "TON", 4500, CostCategory.SUBCONTRACTOR)

Set markups

estimate.set_standard_markups(overhead=0.15, profit=0.10, contingency=0.05)

Calculate total

result = estimate.calculate_total() print(f"Direct Cost: ${result['cost_summary']['direct_cost']:,.2f}") print(f"Grand Total: ${result['grand_total']:,.2f}")
`

Common Use Cases

1. Cost by Category

`python summary = estimate.get_cost_summary() print(f"Labor: ${summary.labor:,.2f}") print(f"Material: ${summary.material:,.2f}") `

2. Export to Excel

`python estimate.export_to_excel("estimate_output.xlsx") `

3. Validate Estimate

`python issues = estimate.validate() for issue in issues: print(f"Warning: {issue}") ``

Resources

  • DDC Book: Chapter 3.1 - Cost Calculations and Estimates
  • Website: https://datadrivenconstruction.io

Installation

Terminal bash

openclaw install estimate-builder-qmohd
    
Copied!

Tags

#pdf_and-documents

Quick Info

Category File Management
Model Claude 3.5
Complexity One-Click
Author qmohd
Last Updated 3/10/2026
🚀
Optimized for
Claude 3.5
🧠

Ready to Install?

Get started with this skill in seconds

openclaw install estimate-builder-qmohd