Receber por email
← Voltar para o catálogo

punch-list-manager

Gerencie listas de pendências de construção para o encerramento do projeto. Acompanhe deficiências, atribua correções e monitore o status de conclusão.

190estrelas
Atualizado há 8 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/punch-list-manager-datadrivenconstruction/svg)](https://www.skillteca.com.br/skills/punch-list-manager-datadrivenconstruction)

Skills relacionadas

Ver todas de Documentos →

Alerta por categoria

Receba novas skills de Documentos toda segunda

1 email curto, só com as skills novas de Documentos. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Punch List Manager

Business Case

Problem Statement

Project closeout challenges:

  • Tracking hundreds of items
  • Assigning responsibility
  • Monitoring completion
  • Documentation for handover

Solution

Systematic punch list management to track deficiencies, assignments, and completion through project closeout.

Technical Implementation

import pandas as pd
from typing import Dict, Any, List, Optional
from dataclasses import dataclass, field
from datetime import date, timedelta
from enum import Enum


class PunchItemStatus(Enum):
    OPEN = "open"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    VERIFIED = "verified"
    REJECTED = "rejected"


class PunchItemPriority(Enum):
    CRITICAL = "critical"   # Life safety, code violation
    HIGH = "high"           # Functionality impaired
    MEDIUM = "medium"       # Cosmetic/minor
    LOW = "low"             # Nice to have


class PunchItemCategory(Enum):
    STRUCTURAL = "structural"
    ARCHITECTURAL = "architectural"
    MECHANICAL = "mechanical"
    ELECTRICAL = "electrical"
    PLUMBING = "plumbing"
    FIRE_PROTECTION = "fire_protection"
    EXTERIOR = "exterior"
    SITE = "site"
    GENERAL = "general"


@dataclass
class PunchItem:
    item_id: str
    location: str
    description: str
    category: PunchItemCategory
    priority: PunchItemPriority
    status: PunchItemStatus
    assigned_to: str
    created_date: date
    due_date: date
    completed_date: Optional[date] = None
    verified_date: Optional[date] = None
    verified_by: str = ""
    photos: List[str] = field(default_factory=list)
    notes: str = ""


@dataclass
class PunchListSummary:
    total_items: int
    open_items: int
    in_progress: int
    completed: int
    verified: int
    rejected: int
    completion_rate: float
    by_category: Dict[str, int]
    by_priority: Dict[str, int]
    by_assignee: Dict[str, int]
    overdue_count: int


class PunchListManager:
    """Manage construction punch lists."""

    def __init__(self, project_name: str, target_closeout_date: date):
        self.project_name = project_name
        self.target_date = target_closeout_date
        self.items: Dict[str, PunchItem] = {}
        self._next_id = 1

    def add_item(self,
                 location: str,
                 description: str,
                 category: PunchItemCategory,
                 priority: PunchItemPriority,
                 assigned_to: str,
                 due_date: date = None,
                 notes: str = "") -> PunchItem:
        """Add punch list item."""

        item_id = f"PL-{self._next_id:04d}"
        self._next_id += 1

        if due_date is None:
            # Default based on priority
            if priority == PunchItemPriority.CRITICAL:
                due_date = date.today() + timedelta(days=3)
            elif priority == PunchItemPriority.HIGH:
                due_date = date.today() + timedelta(days=7)
            else:
                due_date = date.today() + timedelta(days=14)

        item = PunchItem(
            item_id=item_id,
            location=location,
            description=description,
            category=category,
            priority=priority,
            status=PunchItemStatus.OPEN,
            assigned_to=assigned_to,
            created_date=date.today(),
            due_date=due_date,
            notes=notes
        )

        self.items[item_id] = item
        return item

    def update_status(self,
                      item_id: str,
                      status: PunchItemStatus,
                      verified_by: str = ""):
        """Update item status."""

        if item_id not in self.items:
            return

        item = self.items[item_id]
        item.status = status

        if status == PunchItemStatus.COMPLETED:
            item.completed_date = date.today()
        elif status == PunchItemStatus.VERIFIED:
            item.verified_date = date.today()
            item.verified_by = verified_by

    def reassign_item(self, item_id: str, new_assignee: str, new_due_date: date = None):
        """Reassign item to different contractor."""

        if item_id not in self.items:
            return

        item = self.items[item_id]
        item.assigned_to = new_assignee

        if new_due_date:
            item.due_date = new_due_date

        item.status = PunchItemStatus.OPEN

    def add_note(self, item_id: str, note: str):
        """Add note to item."""
        if item_id in self.items:
            self.items[item_id].notes += f"\n{date.today()}: {note}"

    def add_photo(self, item_id: str, photo_path: str):
        """Add photo reference to item."""
        if item_id in self.items:
            self.items[item_id].photos.append(photo_path)

    def get_summary(self) -> PunchListSummary:
        """Get punch list summary."""

        items = list(self.items.values())
        today = date.today()

        # Status counts
        open_items = sum(1 for i in items if i.status == PunchItemStatus.OPEN)
        in_progress = sum(1 for i in items if i.status == PunchItemStatus.IN_PROGRESS)
        completed = sum(1 for i in items if i.status == PunchItemStatus.COMPLETED)
        verified = sum(1 for i in items if i.status == PunchItemStatus.VERIFIED)
        rejected = sum(1 for i in items if i.status == PunchItemStatus.REJECTED)

        # Completion rate (verified / total)
        completion_rate = (verified / len(items) * 100) if items else 0

        # By category
        by_category = {}
        for cat in PunchItemCategory:
            count = sum(1 for i in items if i.category == cat and i.status != PunchItemStatus.VERIFIED)
            if count > 0:
                by_category[cat.value] = count

        # By priority
        by_priority = {}
        for pri in PunchItemPriority:
            count = sum(1 for i in items if i.priority == pri and i.status != PunchItemStatus.VERIFIED)
            if count > 0:
                by_priority[pri.value] = count

        # By assignee
        by_assignee = {}
        for item in items:
            if item.status not in [PunchItemStatus.VERIFIED, PunchItemStatus.COMPLETED]:
                if item.assigned_to not in by_assignee:
                    by_assignee[item.assigned_to] = 0
                by_assignee[item.assigned_to] += 1

        # Overdue
        overdue = sum(
            1 for i in items
            if i.due_date < today and i.status not in [PunchItemStatus.VERIFIED, PunchItemStatus.COMPLETED]
        )

        return PunchListSummary(
            total_items=len(items),
            open_items=open_items,
            in_progress=in_progress,
            completed=completed,
            verified=verified,
            rejected=rejected,
            completion_rate=round(completion_rate, 1),
            by_category=by_category,
            by_priority=by_priority,
            by_assignee=by_assignee,
            overdue_count=overdue
        )

    def get_items_by_status(self, status: PunchItemStatus) -> List[PunchItem]:
        """Get items by status."""
        return [i for i in self.items.values() if i.status == status]

    def get_items_by_assignee(self, assignee: str) -> List[PunchItem]:
        """Get items assigned to specific contractor."""
        return [i for i in self.items.values() if i.assigned_to == assignee]

    def get_overdue_items(self) -> List[PunchItem]:
        """Get overdue items."""
        today = date.today()
        return [
            i for i in self.items.values()
            if i.due_date < today and i.status not in [PunchItemStatus.VERIFIED, PunchItemStatus.COMPLETED]
        ]

    def get_critical_items(self) -> List[PunchItem]:
        """Get critical priority items."""
        return [
            i for i in self.items.values()
            if i.priority == PunchItemPriority.CRITICAL
            and i.status not in [PunchItemStatus.VERIFIED]
        ]

    def generate_contractor_report(self, assignee: str) -> pd.DataF
Compartilhar X LinkedIn