diff --git a/README.md b/README.md
index 3cdab14..e01f089 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ A Python tool that generates comprehensive vendor punchlist reports from Excel f
## Features
-- **Direct Excel Processing**: Reads Excel files directly using pandas (no LLM required)
+- **Direct Excel Processing**: Reads Excel files directly using pandas
- **Data Normalization**: Automatically normalizes vendor names, statuses, and priorities
- **24-Hour Updates**: Tracks items added, closed, or changed to monitor status in the last 24 hours (based on Baltimore/Eastern timezone)
- **Priority Tracking**: Groups items by priority levels (Very High, High, Medium, Low)
diff --git a/html_generator.py b/html_generator.py
index 0e662d2..290273d 100644
--- a/html_generator.py
+++ b/html_generator.py
@@ -510,8 +510,8 @@ def generate_html_content(report_data: Dict) -> str:
}}
.badge-danger {{
- background: #fee2e2;
- color: #991b1b;
+ background: #dc2626;
+ color: white;
}}
.badge-secondary {{
@@ -777,6 +777,10 @@ def generate_html_content(report_data: Dict) -> str:
{summary.get('total_open', 0)}
Open
+
+
{summary.get('total_incomplete', 0)}
+
Incomplete
+
@@ -1160,6 +1164,7 @@ def generate_vendor_section(vendor: Dict) -> str:
closed_count = vendor.get('closed_count', 0)
open_count = vendor.get('open_count', 0)
monitor_count = vendor.get('monitor_count', 0)
+ incomplete_count = vendor.get('incomplete_count', 0)
updates_24h = vendor.get('updates_24h', {})
oldest_unaddressed = vendor.get('oldest_unaddressed', [])
@@ -1171,6 +1176,7 @@ def generate_vendor_section(vendor: Dict) -> str:
closed_items = vendor.get('closed_items', [])
monitor_items = vendor.get('monitor_items', [])
open_items = vendor.get('open_items', [])
+ incomplete_items = vendor.get('incomplete_items', [])
# Convert to lists if needed (they should already be lists)
if not isinstance(closed_items, list):
@@ -1179,6 +1185,8 @@ def generate_vendor_section(vendor: Dict) -> str:
monitor_items = []
if not isinstance(open_items, list):
open_items = []
+ if not isinstance(incomplete_items, list):
+ incomplete_items = []
# Group all items by priority for the "All" tab
# Combine all items first
@@ -1206,6 +1214,13 @@ def generate_vendor_section(vendor: Dict) -> str:
seen_names.add(name)
all_items_combined.append(item)
+ # Add all incomplete items
+ for item in incomplete_items:
+ name = item.get('punchlist_name', '')
+ if name and name not in seen_names:
+ seen_names.add(name)
+ all_items_combined.append(item)
+
# Group items by priority level
very_high_all = []
high_all = []
@@ -1252,6 +1267,10 @@ def generate_vendor_section(vendor: Dict) -> str:
{open_count}
Open
+
+
{incomplete_count}
+
Incomplete
+
@@ -1263,6 +1282,7 @@ def generate_vendor_section(vendor: Dict) -> str:
+
@@ -1309,6 +1329,15 @@ def generate_vendor_section(vendor: Dict) -> str:
+
+
+
+
Incomplete Items ({len(incomplete_items)})
+
+ {''.join([generate_item_html(item) for item in incomplete_items]) if incomplete_items else '- No incomplete items
'}
+
+
+
"""
diff --git a/report_generator.py b/report_generator.py
index 1358926..ac5b36a 100644
--- a/report_generator.py
+++ b/report_generator.py
@@ -1,9 +1,8 @@
#!/usr/bin/env python3
"""
-Report Generator - Direct Generation (No LLM Required)
+Report Generator
Generates vendor reports directly from preprocessed Excel data.
-All requirements fulfilled programmatically - no AI needed!
"""
import json
@@ -38,7 +37,7 @@ def generate_report(
verbose: bool = True
) -> dict:
"""
- Generate vendor report directly from preprocessed data - NO LLM required!
+ Generate vendor report directly from preprocessed data.
Args:
reports_dir: Directory containing Excel files
@@ -50,7 +49,7 @@ def generate_report(
"""
if verbose:
print("=" * 70)
- print("DIRECT REPORT GENERATION (No LLM Required)")
+ print("REPORT GENERATION")
print("=" * 70)
print(f"Loading and preprocessing Excel files from '{reports_dir}'...")
@@ -115,9 +114,14 @@ def generate_report(
if item.get('status', '').lower() == 'complete' or item.get('is_closed', False)]
monitor_items = [convert_item_to_punchlist_item(item) for item in all_items
if item.get('status', '').lower() == 'monitor']
+ incomplete_items = [convert_item_to_punchlist_item(item) for item in all_items
+ if item.get('status', '').lower() == 'incomplete' and not item.get('is_closed', False)]
open_items = [convert_item_to_punchlist_item(item) for item in all_items
if item.get('status', '').lower() == 'incomplete' and not item.get('is_closed', False)]
+ # Calculate incomplete count
+ incomplete_count = len(incomplete_items)
+
# Create vendor metrics
vendor_metrics = VendorMetrics(
vendor_name=vendor_name,
@@ -137,6 +141,8 @@ def generate_report(
vendor_dict['closed_items'] = [item.model_dump() for item in closed_items]
vendor_dict['monitor_items'] = [item.model_dump() for item in monitor_items]
vendor_dict['open_items'] = [item.model_dump() for item in open_items]
+ vendor_dict['incomplete_items'] = [item.model_dump() for item in incomplete_items]
+ vendor_dict['incomplete_count'] = incomplete_count
vendors.append(vendor_dict)
@@ -149,7 +155,8 @@ def generate_report(
"total_items": sum(v.get('total_items', 0) if isinstance(v, dict) else v.total_items for v in vendors),
"total_closed": sum(v.get('closed_count', 0) if isinstance(v, dict) else v.closed_count for v in vendors),
"total_open": sum(v.get('open_count', 0) if isinstance(v, dict) else v.open_count for v in vendors),
- "total_monitor": sum(v.get('monitor_count', 0) if isinstance(v, dict) else v.monitor_count for v in vendors)
+ "total_monitor": sum(v.get('monitor_count', 0) if isinstance(v, dict) else v.monitor_count for v in vendors),
+ "total_incomplete": sum(v.get('incomplete_count', 0) if isinstance(v, dict) else 0 for v in vendors)
}
)
@@ -167,6 +174,10 @@ def generate_report(
report_data['vendors'][i]['monitor_items'] = vendor_dict['monitor_items']
if 'open_items' in vendor_dict:
report_data['vendors'][i]['open_items'] = vendor_dict['open_items']
+ if 'incomplete_items' in vendor_dict:
+ report_data['vendors'][i]['incomplete_items'] = vendor_dict['incomplete_items']
+ if 'incomplete_count' in vendor_dict:
+ report_data['vendors'][i]['incomplete_count'] = vendor_dict['incomplete_count']
# Save to file if specified
if output_file:
@@ -203,7 +214,7 @@ def generate_report(
if __name__ == "__main__":
import argparse
- parser = argparse.ArgumentParser(description="Generate vendor reports from Excel files (no LLM required)")
+ parser = argparse.ArgumentParser(description="Generate vendor reports from Excel files")
parser.add_argument(
"--reports-dir",
type=str,