openclaw 网盘下载
OpenClaw

技能详情(站内镜像,无评论)

首页 > 技能库 > cost-estimation-resource

Agent skill by @datadrivenconstruction on ClawHub.

数据与表格

版本:v03.01.01

Package:datadrivenconstruction/cost-estimation-resource

安装(复制给龙虾 AI)

将下方整段复制到龙虾中文库对话中,由龙虾按 SKILL.md 完成安装。

请把本段交给龙虾中文库(龙虾 AI)执行:为本机安装 OpenClaw 技能「cost-estimation-resource」。简介:Agent skill by @datadrivenconstruction on ClawHub.。
请 fetch 以下地址读取 SKILL.md 并按文档完成安装:https://raw.githubusercontent.com/openclaw/skills/refs/heads/main/skills/datadrivenconstruction/cost-estimation-resource/SKILL.md
(来源:yingzhi8.cn 技能库)

SKILL.md

打开原始 SKILL.md(GitHub raw)

---
name: "cost-estimation-resource"
description: "Calculate construction costs using resource-based method. Estimate project costs from work items, physical resource norms, and current prices."
homepage: "https://datadrivenconstruction.io"
metadata: {"openclaw":{"emoji":"🧮","os":["darwin","linux","win32"],"homepage":"https://datadrivenconstruction.io","requires":{"bins":["python3"]}}}
---

# Cost Estimation - Resource Method

## Business Case

### Problem Statement
Traditional costing challenges:
- Fixed unit prices become outdated
- No visibility into cost components
- Difficult to adjust for conditions
- Limited cost analysis capability

### Solution
Resource-based costing separates physical resource consumption (norms) from prices, enabling accurate, adjustable, and transparent cost estimation.

## Technical Implementation

```python
import pandas as pd
from typing import Dict, Any, List, Optional
from dataclasses import dataclass, field
from enum import Enum


class ResourceType(Enum):
    LABOR = "labor"
    MATERIAL = "material"
    EQUIPMENT = "equipment"
    SUBCONTRACTOR = "subcontractor"


@dataclass
class Resource:
    code: str
    name: str
    resource_type: ResourceType
    unit: str
    unit_price: float
    currency: str = "USD"


@dataclass
class ResourceNorm:
    resource_code: str
    consumption: float  # Units per work item unit
    waste_factor: float = 1.0  # 1.1 = 10% waste


@dataclass
class WorkItem:
    code: str
    name: str
    unit: str
    resources: List[ResourceNorm] = field(default_factory=list)


@dataclass
class CostLineItem:
    work_item_code: str
    work_item_name: str
    quantity: float
    unit: str
    labor_cost: float
    material_cost: float
    equipment_cost: float
    subcontractor_cost: float
    total_cost: float


class ResourceBasedEstimator:
    """Calculate costs using resource-based method."""

    def __init__(self):
        self.resources: Dict[str, Resource] = {}
        self.work_items: Dict[str, WorkItem] = {}
        self.overhead_rate: float = 0.15
        self.profit_rate: float = 0.10

    def add_resource(self, resource: Resource):
        """Add resource to database."""
        self.resources[resource.code] = resource

    def add_work_item(self, work_item: WorkItem):
        """Add work item with resource norms."""
        self.work_items[work_item.code] = work_item

    def load_resources_from_df(self, df: pd.DataFrame):
        """Load resources from DataFrame."""

        for _, row in df.iterrows():
            resource = Resource(
                code=row['code'],
                name=row['name'],
                resource_type=ResourceType(row['type'].lower()),
                unit=row['unit'],
                unit_price=float(row['unit_price']),
                currency=row.get('currency', 'USD')
            )
            self.add_resource(resource)

    def load_work_items_from_df(self, items_df: pd.DataFrame, norms_df: pd.DataFrame):
        """Load work items and norms from DataFrames."""

        # Group norms by work item
        norms_grouped = norms_df.groupby('work_item_code')

        for _, row in items_df.iterrows():
            code = row['code']
            resources = []

            if code in norms_grouped.groups:
                item_norms = norms_grouped.get_group(code)
                for _, norm_row in item_norms.iterrows():
                    resources.append(ResourceNorm(
                        resource_code=norm_row['resource_code'],
                        consumption=float(norm_row['consumption']),
                        waste_factor=float(norm_row.get('waste_factor', 1.0))
                    ))

            work_item = WorkItem(
                code=code,
                name=row['name'],
                unit=row['unit'],
                resources=resources
            )
            self.add_work_item(work_item)

    def calculate_work_item_cost(self, work_item_code: str, quantity: float) -> CostLineItem:
        """Calculate cost for a work item quantity."""

        if work_item_code not in self.work_items:
            raise ValueError(f"Work item {work_item_code} not found")

        work_item = self.work_items[work_item_code]

        labor_cost = 0.0
        material_cost = 0.0
        equipment_cost = 0.0
        subcontractor_cost = 0.0

        for norm in work_item.resources:
            if norm.resource_code not in self.resources:
                continue

            resource = self.resources[norm.resource_code]
            resource_qty = quantity * norm.consumption * norm.waste_factor
            resource_cost = resource_qty * resource.unit_price

            if resource.resource_type == ResourceType.LABOR:
                labor_cost += resource_cost
            elif resource.resource_type == ResourceType.MATERIAL:
                material_cost += resource_cost
            elif resource.resource_type == ResourceType.EQUIPMENT:
                equipment_cost += resource_cost
            elif resource.resource_type == ResourceType.SUBCONTRACTOR:
                subcontractor_cost += resource_cost

        total = labor_cost + material_cost + equipment_cost + subcontractor_cost

        return CostLineItem(
            work_item_code=work_item_code,
            work_item_name=work_item.name,
            quantity=quantity,
            unit=work_item.unit,
            labor_cost=round(labor_cost, 2),
            material_cost=round(material_cost, 2),
            equipment_cost=round(equipment_cost, 2),
            subcontractor_cost=round(subcontractor_cost, 2),
            total_cost=round(total, 2)
        )

    def calculate_estimate(self, items: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Calculate full estimate from list of items."""

        line_items = []
        totals = {
            'labor': 0.0,
            'material': 0.0,
            'equipment': 0.0,
            'subcontractor': 0.0,
            'direct': 0.0
        }

        for item in items:
            code = item['work_item_code']
            qty = float(item['quantity'])

            line = self.calculate_work_item_cost(code, qty)
            line_items.append(line)

            totals['labor'] += line.labor_cost
            totals['material'] += line.material_cost
            totals['equipment'] += line.equipment_cost
            totals['subcontractor'] += line.subcontractor_cost
            totals['direct'] += line.total_cost

        # Calculate overhead and profit
        overhead = totals['direct'] * self.overhead_rate
        subtotal = totals['direct'] + overhead
        profit = subtotal * self.profit_rate
        grand_total = subtotal + profit

        return {
            'line_items': line_items,
            'totals': {
                'labor': round(totals['labor'], 2),
                'material': round(totals['material'], 2),
                'equipment': round(totals['equipment'], 2),
                'subcontractor': round(totals['subcontractor'], 2),
                'direct_cost': round(totals['direct'], 2),
                'overhead': round(overhead, 2),
                'overhead_rate': self.overhead_rate,
                'subtotal': round(subtotal, 2),
                'profit': round(profit, 2),
                'profit_rate': self.profit_rate,
                'grand_total': round(grand_total, 2)
            },
            'summary': {
                'item_count': len(line_items),
                'labor_pct': round(totals['labor'] / totals['direct'] * 100, 1) if totals['direct'] > 0 else 0,
                'material_pct': round(totals['material'] / totals['direct'] * 100, 1) if totals['direct'] > 0 else 0,
                'equipment_pct': round(totals['equipment'] / totals['direct'] * 100, 1) if totals['direct'] > 0 else 0
            }
        }

    def adjust_prices(self, factor: float, resource_type: ResourceType = None):
        """Adjust resource prices by factor."""

        for code, resource in self.resources.items():
            if resource_type is None or resource.resource_type == resource_type:
                resource.unit_price *= factor

    def apply_regional_factor(self, factor: float):
        """Apply regional cost factor to all resources."""
        self.adjust_prices(factor)

    def get_resource_breakdown(self, work_item_code: str, quantity: float) -> pd.DataFrame:
        """Get detailed resource breakdown for work item."""

        if work_item_code not in self.work_items:
            return pd.DataFrame()

        work_item = self.work_items[work_item_code]
        data = []

        for norm in work_item.resources:
            if norm.resource_code not in self.resources:
                continue

            resource = self.resources[norm.resource_code]
            resource_qty = quantity * norm.consumption * norm.waste_factor
            resource_cost = resource_qty * resource.unit_price

            data.append({
                'Resource Code': resource.code,
                'Resource Name': resource.name,
                'Type': resource.resource_type.value,
                'Unit': resource.unit,
                'Consumption': norm.consumption,
                'Waste Factor': norm.waste_factor,
                'Total Qty': round(resource_qty, 3),
                'Unit Price': resource.unit_price,
                'Total Cost': round(resource_cost, 2)
            })

        return pd.DataFrame(data)

    def export_to_excel(self, estimate: Dict[str, Any], output_path: str) -> str:
        """Export estimate to Excel."""

        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
            # Summary
            summary_df = pd.DataFrame([estimate['totals']])
            summary_df.to_excel(writer, sheet_name='Summary', index=False)

            # Line items
            items_data = [{
                'Code': item.work_item_code,
                'Description': item.work_item_name,
                'Quantity': item.quantity,
                'Unit': item.unit,
                'Labor': item.labor_cost,
                'Material': item.material_cost,
                'Equipment': item.equipment_cost,
                'Subcontractor': item.subcontractor_cost,
                'Total': item.total_cost
            } for item in estimate['line_items']]
            items_df = pd.DataFrame(items_data)
            items_df.to_excel(writer, sheet_name='Line Items', index=False)

        return output_path
```

## Quick Start

```python
# Initialize estimator
estimator = ResourceBasedEstimator()

# Add resources
estimator.add_resource(Resource("L001", "Carpenter", ResourceType.LABOR, "MH", 55.00))
estimator.add_resource(Resource("L002", "Laborer", ResourceType.LABOR, "MH", 35.00))
estimator.add_resource(Resource("M001", "Concrete C30", ResourceType.MATERIAL, "CY", 150.00))
estimator.add_resource(Resource("M002", "Rebar #4", ResourceType.MATERIAL, "TON", 1200.00))
estimator.add_resource(Resource("E001", "Concrete Pump", ResourceType.EQUIPMENT, "HR", 250.00))

# Add work item with resource norms
estimator.add_work_item(WorkItem(
    code="03.01.01",
    name="Cast-in-place Concrete Foundation",
    unit="CY",
    resources=[
        ResourceNorm("L001", 1.5),      # 1.5 carpenter hours per CY
        ResourceNorm("L002", 2.0),      # 2.0 laborer hours per CY
        ResourceNorm("M001", 1.0, 1.05),# 1.0 CY concrete with 5% waste
        ResourceNorm("M002", 0.08),     # 0.08 ton rebar per CY
        ResourceNorm("E001", 0.25)      # 0.25 pump hours per CY
    ]
))

# Calculate estimate
estimate = estimator.calculate_estimate([
    {"work_item_code": "03.01.01", "quantity": 100}
])

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

## Common Use Cases

### 1. Resource Breakdown
```python
breakdown = estimator.get_resource_breakdown("03.01.01", quantity=100)
print(breakdown)
```

### 2. Regional Adjustment
```python
# Apply 15% regional factor
estimator.apply_regional_factor(1.15)
```

### 3. Labor Only Adjustment
```python
# Increase labor costs by 10%
estimator.adjust_prices(1.10, ResourceType.LABOR)
```

## Resources
- **DDC Book**: Chapter 3.1 - Resource-Based Costing
- **Website**: https://datadrivenconstruction.io