Spaces:
Configuration error
Configuration error
Upload 63 files
Browse filesThis view is limited to 50 files because it contains too many changes. Β See raw diff
- .gitattributes +8 -0
- .gitignore +4 -0
- README.md +857 -20
- __pycache__/app.cpython-311.pyc +0 -0
- __pycache__/data_loader.cpython-311.pyc +0 -0
- __pycache__/data_loader.cpython-312.pyc +0 -0
- app.py +634 -0
- data/activities.csv +151 -0
- data/boq.csv +541 -0
- data/daily_updates.csv +0 -0
- data/data.db +3 -0
- data/issues.csv +396 -0
- data/projects.csv +11 -0
- data/resources.csv +256 -0
- data_loader.py +207 -0
- dataset.py +439 -0
- engine/__init__.py +1 -0
- engine/__pycache__/__init__.cpython-311.pyc +0 -0
- engine/__pycache__/__init__.cpython-312.pyc +0 -0
- engine/__pycache__/dag_builder.cpython-311.pyc +0 -0
- engine/__pycache__/dag_builder.cpython-312.pyc +0 -0
- engine/__pycache__/ripple_engine.cpython-311.pyc +0 -0
- engine/__pycache__/ripple_engine.cpython-312.pyc +0 -0
- engine/__pycache__/whatif_scenarios.cpython-311.pyc +0 -0
- engine/__pycache__/whatif_scenarios.cpython-312.pyc +0 -0
- engine/dag_builder.py +87 -0
- engine/ripple_engine.py +195 -0
- engine/whatif_scenarios.py +204 -0
- features/__init__.py +1 -0
- features/__pycache__/__init__.cpython-311.pyc +0 -0
- features/__pycache__/__init__.cpython-312.pyc +0 -0
- features/__pycache__/feature_engineering.cpython-311.pyc +0 -0
- features/__pycache__/feature_engineering.cpython-312.pyc +0 -0
- features/feature_engineering.py +232 -0
- models/__init__.py +1 -0
- models/__pycache__/__init__.cpython-311.pyc +0 -0
- models/__pycache__/__init__.cpython-312.pyc +0 -0
- models/__pycache__/completion_predictor.cpython-311.pyc +0 -0
- models/__pycache__/completion_predictor.cpython-312.pyc +0 -0
- models/__pycache__/monte_carlo.cpython-311.pyc +0 -0
- models/__pycache__/monte_carlo.cpython-312.pyc +0 -0
- models/completion_predictor.py +277 -0
- models/monte_carlo.py +170 -0
- optimizer/__init__.py +1 -0
- optimizer/__pycache__/__init__.cpython-311.pyc +0 -0
- optimizer/__pycache__/__init__.cpython-312.pyc +0 -0
- optimizer/__pycache__/schedule_optimizer.cpython-311.pyc +0 -0
- optimizer/__pycache__/schedule_optimizer.cpython-312.pyc +0 -0
- optimizer/schedule_optimizer.py +326 -0
- requirements.txt +10 -3
.gitattributes
CHANGED
|
@@ -33,3 +33,11 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
data/data.db filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
screenshots/dag.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
screenshots/gantt.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
screenshots/optimization.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
screenshots/overview.png filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
screenshots/predictions.png filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
screenshots/ripple.png filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
screenshots/whatif.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv
|
| 2 |
+
.env
|
| 3 |
+
.__pycache__
|
| 4 |
+
.ipynb_checkpoints
|
README.md
CHANGED
|
@@ -1,20 +1,857 @@
|
|
| 1 |
-
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
---
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# What-if Schedule Predictor
|
| 2 |
+
|
| 3 |
+
A machine-learning-powered schedule prediction and scenario analysis tool for renovation and construction projects. It ingests real project data, learns delay patterns from completed work, predicts when in-progress activities will finish, and lets a project manager simulate "what if" scenarios interactively through a browser dashboard.
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## Table of Contents
|
| 8 |
+
|
| 9 |
+
1. [The Problem This Solves](#the-problem-this-solves)
|
| 10 |
+
2. [What This System Does](#what-this-system-does)
|
| 11 |
+
3. [How the Data Is Organized](#how-the-data-is-organized)
|
| 12 |
+
4. [How Everything Fits Together](#how-everything-fits-together)
|
| 13 |
+
5. [Component Deep-Dive](#component-deep-dive)
|
| 14 |
+
- [Data Generation and the Database](#data-generation-and-the-database)
|
| 15 |
+
- [The DataLoader](#the-dataloader)
|
| 16 |
+
- [Feature Engineering](#feature-engineering)
|
| 17 |
+
- [Prediction Method A: Earned Value Extrapolation](#prediction-method-a-earned-value-extrapolation)
|
| 18 |
+
- [Prediction Method B: Gradient Boosting Regressor](#prediction-method-b-gradient-boosting-regressor)
|
| 19 |
+
- [Ensemble Prediction](#ensemble-prediction)
|
| 20 |
+
- [Monte Carlo Simulation](#monte-carlo-simulation)
|
| 21 |
+
- [Activity Dependency Graph (DAG)](#activity-dependency-graph-dag)
|
| 22 |
+
- [Ripple Engine: Delay Propagation](#ripple-engine-delay-propagation)
|
| 23 |
+
- [What-if Scenario Engine](#what-if-scenario-engine)
|
| 24 |
+
- [Schedule Optimizer and Critical Path Method](#schedule-optimizer-and-critical-path-method)
|
| 25 |
+
- [Visualizations](#visualizations)
|
| 26 |
+
- [The Streamlit Dashboard](#the-streamlit-dashboard)
|
| 27 |
+
6. [Screenshots](#screenshots)
|
| 28 |
+
7. [Project Structure](#project-structure)
|
| 29 |
+
8. [Installation](#installation)
|
| 30 |
+
9. [Running the System](#running-the-system)
|
| 31 |
+
10. [Glossary](#glossary)
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## The Problem This Solves
|
| 36 |
+
|
| 37 |
+
When a renovation or construction project is running, things almost never go exactly to plan. Workers get sick, materials arrive late, an inspection fails, or a structural issue is discovered behind a wall. A project manager needs to answer questions like:
|
| 38 |
+
|
| 39 |
+
- "We are 3 weeks into tiling and only 40% done. When will it actually finish?"
|
| 40 |
+
- "If the plumbing rough-in finishes 2 weeks late, what does that do to the rest of the schedule?"
|
| 41 |
+
- "If we put extra crew on the electrical work, can we recover the delay from the structural phase?"
|
| 42 |
+
- "Which activities, if they slip, will push the entire project end date?"
|
| 43 |
+
|
| 44 |
+
Traditional tools answer these questions poorly. A spreadsheet can track what has happened but cannot predict what will happen or simulate alternatives. This system was built to fill that gap.
|
| 45 |
+
|
| 46 |
+
It learns from completed projects how activities tend to behave (how much they deviate from their planned duration, what types of issues cause the most delay, which categories of work run fastest) and then applies that knowledge to in-progress work.
|
| 47 |
+
|
| 48 |
+
---
|
| 49 |
+
|
| 50 |
+
## What This System Does
|
| 51 |
+
|
| 52 |
+
At a high level, the system does six things:
|
| 53 |
+
|
| 54 |
+
**1. Stores and organizes all project data** in a SQLite database. It can ingest existing CSV files from a data folder and also generate synthetic historical projects to supplement the training dataset.
|
| 55 |
+
|
| 56 |
+
**2. Predicts completion dates** for every in-progress activity using three independent methods:
|
| 57 |
+
- A simple earned-value extrapolation based on current progress rate.
|
| 58 |
+
- A trained machine learning model (GradientBoostingRegressor) that has learned from 119 completed activities.
|
| 59 |
+
- A Monte Carlo simulation that runs 1,000 random scenarios to produce a probability distribution of completion dates (P50, P80, P90).
|
| 60 |
+
|
| 61 |
+
**3. Builds a dependency map** of all activities as a graph (called a Directed Acyclic Graph or DAG). This captures the fact that, for example, painting cannot start until plastering finishes.
|
| 62 |
+
|
| 63 |
+
**4. Propagates delays through the dependency map**. If you tell the system "Site Preparation will be 2 weeks late", it automatically calculates which downstream activities shift, by how much, and what the new project end date will be.
|
| 64 |
+
|
| 65 |
+
**5. Runs what-if scenarios** so a manager can compare the impact of different decisions: delay an activity, add resources to speed one up, resolve a blocking issue, or run two activities in parallel.
|
| 66 |
+
|
| 67 |
+
**6. Applies Critical Path Method (CPM) analysis** to find which activities have zero scheduling flexibility (the critical path) and generate rule-based optimization suggestions.
|
| 68 |
+
|
| 69 |
+
All of this is presented in a browser dashboard built with Streamlit, requiring no coding knowledge to use.
|
| 70 |
+
|
| 71 |
+
---
|
| 72 |
+
|
| 73 |
+
## How the Data Is Organized
|
| 74 |
+
|
| 75 |
+
The system uses six tables, which map directly to six original CSV files:
|
| 76 |
+
|
| 77 |
+
### projects
|
| 78 |
+
|
| 79 |
+
Each row is one construction or renovation project.
|
| 80 |
+
|
| 81 |
+
| Column | What it means |
|
| 82 |
+
|---|---|
|
| 83 |
+
| id | Unique identifier, e.g. proj_008 |
|
| 84 |
+
| name | Human-readable name, e.g. "Lakeview Villa Renovation" |
|
| 85 |
+
| planned_start_date | The date the project was supposed to begin |
|
| 86 |
+
| planned_end_date | The date the project was supposed to finish |
|
| 87 |
+
| actual_start_date | The date it actually began |
|
| 88 |
+
| actual_end_date | The date it actually finished (null if still running) |
|
| 89 |
+
| type | residential or commercial |
|
| 90 |
+
| city | Location |
|
| 91 |
+
| status | completed, in_progress, or not_started |
|
| 92 |
+
|
| 93 |
+
Projects with status "completed" are used to train the machine learning model. Projects with status "in_progress" are what the predictions and scenario tools operate on.
|
| 94 |
+
|
| 95 |
+
### activities
|
| 96 |
+
|
| 97 |
+
Each row is one construction activity within a project.
|
| 98 |
+
|
| 99 |
+
| Column | What it means |
|
| 100 |
+
|---|---|
|
| 101 |
+
| id | Unique identifier, e.g. act_008_04 |
|
| 102 |
+
| project_id | Which project this belongs to |
|
| 103 |
+
| name | e.g. "Waterproofing and Damp Proofing" |
|
| 104 |
+
| category | e.g. structural, mep (mechanical/electrical/plumbing), finishing |
|
| 105 |
+
| planned_start_date | Originally scheduled start |
|
| 106 |
+
| planned_end_date | Originally scheduled finish |
|
| 107 |
+
| planned_duration_days | planned_end - planned_start |
|
| 108 |
+
| actual_start_date | When work actually began |
|
| 109 |
+
| actual_end_date | When work actually finished (null if still running) |
|
| 110 |
+
| progress | Percentage complete, 0 to 100 |
|
| 111 |
+
| status | completed, in_progress, or not_started |
|
| 112 |
+
| depends_on | Name of the predecessor activity (or null) |
|
| 113 |
+
| schedule_variance_days | How many days late the actual start was vs planned start |
|
| 114 |
+
|
| 115 |
+
The `depends_on` field is the key input to the dependency graph. It captures the construction sequence: e.g. "Painting depends on Wall Plastering".
|
| 116 |
+
|
| 117 |
+
### daily_updates
|
| 118 |
+
|
| 119 |
+
Each row is one day's progress log for an activity.
|
| 120 |
+
|
| 121 |
+
| Column | What it means |
|
| 122 |
+
|---|---|
|
| 123 |
+
| activity_id | Which activity was updated |
|
| 124 |
+
| date | The date of the update |
|
| 125 |
+
| reported_progress | Cumulative percentage complete as of that day |
|
| 126 |
+
| daily_increment | How many percentage points were completed that day |
|
| 127 |
+
| crew_size | Number of workers on site that day |
|
| 128 |
+
| weather_event | Any weather disruption (rain, heat, etc.) |
|
| 129 |
+
| notes | Free-text notes from the site manager |
|
| 130 |
+
|
| 131 |
+
This table is the primary source for understanding how fast an activity is actually progressing day by day. The system uses the last 14 days of daily increments to fit the Monte Carlo simulation distribution.
|
| 132 |
+
|
| 133 |
+
### issues
|
| 134 |
+
|
| 135 |
+
Each row is one problem logged against an activity.
|
| 136 |
+
|
| 137 |
+
| Column | What it means |
|
| 138 |
+
|---|---|
|
| 139 |
+
| id | Unique issue ID |
|
| 140 |
+
| activity_id | Which activity this issue is blocking |
|
| 141 |
+
| category | material_delay, inspection_fail, design_change, labor_shortage, weather, equipment_breakdown, scope_creep, or safety |
|
| 142 |
+
| severity | low, medium, high, or critical |
|
| 143 |
+
| status | open or resolved |
|
| 144 |
+
| delay_impact_days | Estimated number of days this issue adds to the activity |
|
| 145 |
+
| assigned_to | Person responsible for resolving it |
|
| 146 |
+
|
| 147 |
+
Issues feed directly into the feature engineering and what-if calculations.
|
| 148 |
+
|
| 149 |
+
### boq (Bill of Quantities)
|
| 150 |
+
|
| 151 |
+
Each row is one material or labor line item in the project cost breakdown.
|
| 152 |
+
|
| 153 |
+
| Column | What it means |
|
| 154 |
+
|---|---|
|
| 155 |
+
| activity_id | Which activity this item belongs to |
|
| 156 |
+
| name | e.g. "Ceramic tiles 600x600mm" |
|
| 157 |
+
| unit | m2, kg, nos, etc. |
|
| 158 |
+
| quantity | How many of this unit |
|
| 159 |
+
| unit_price | Cost per unit |
|
| 160 |
+
| total_price | quantity x unit_price |
|
| 161 |
+
|
| 162 |
+
The number of BOQ line items per activity is used as a complexity proxy in feature engineering.
|
| 163 |
+
|
| 164 |
+
### resources
|
| 165 |
+
|
| 166 |
+
Each row is one resource allocation record.
|
| 167 |
+
|
| 168 |
+
| Column | What it means |
|
| 169 |
+
|---|---|
|
| 170 |
+
| activity_id | Which activity this resource is allocated to |
|
| 171 |
+
| contractor | The firm supplying the resource |
|
| 172 |
+
| resource_type | labour, equipment, or material |
|
| 173 |
+
| allocated_workers | Number of workers assigned |
|
| 174 |
+
| daily_cost | Cost per day for this resource |
|
| 175 |
+
| allocation_date | When the allocation was made |
|
| 176 |
+
|
| 177 |
+
Resources are used to estimate cost impact in the resource-boost what-if scenario.
|
| 178 |
+
|
| 179 |
+
---
|
| 180 |
+
|
| 181 |
+
## How Everything Fits Together
|
| 182 |
+
|
| 183 |
+
Here is the full data flow from raw files to the dashboard:
|
| 184 |
+
|
| 185 |
+
```
|
| 186 |
+
CSV files (6 tables)
|
| 187 |
+
|
|
| 188 |
+
v
|
| 189 |
+
dataset.py <-- reads and normalizes CSVs, adds 2 synthetic projects
|
| 190 |
+
|
|
| 191 |
+
v
|
| 192 |
+
data/data.db (SQLite database with all 7 tables including activity_dependencies)
|
| 193 |
+
|
|
| 194 |
+
v
|
| 195 |
+
data_loader.py <-- typed accessors, date parsing, method shortcuts
|
| 196 |
+
|
|
| 197 |
+
+----> feature_engineering.py <-- 12 features per activity
|
| 198 |
+
| |
|
| 199 |
+
| v
|
| 200 |
+
| completion_predictor.py <-- trains GBR on historical activities
|
| 201 |
+
| |
|
| 202 |
+
| monte_carlo.py <-- 1000-sim P50/P80/P90 per activity
|
| 203 |
+
|
|
| 204 |
+
+----> dag_builder.py <-- builds networkx DAG from depends_on edges
|
| 205 |
+
|
|
| 206 |
+
ripple_engine.py <-- BFS cascade delay propagation
|
| 207 |
+
|
|
| 208 |
+
whatif_scenarios.py <-- 4 scenario types with comparison
|
| 209 |
+
|
|
| 210 |
+
schedule_optimizer.py <-- CPM forward/backward pass + 6 rules
|
| 211 |
+
|
|
| 212 |
+
gantt.py / dag_viz.py <-- Plotly interactive charts
|
| 213 |
+
|
|
| 214 |
+
v
|
| 215 |
+
app.py <-- 7-tab Streamlit dashboard
|
| 216 |
+
```
|
| 217 |
+
|
| 218 |
+
Each stage is a separate Python module. They can be imported and tested independently. The Streamlit app wires them together.
|
| 219 |
+
|
| 220 |
+
---
|
| 221 |
+
|
| 222 |
+
## Component Deep-Dive
|
| 223 |
+
|
| 224 |
+
### Data Generation and the Database
|
| 225 |
+
|
| 226 |
+
**File: `dataset.py`**
|
| 227 |
+
|
| 228 |
+
This script is run once before the app starts. It does two things:
|
| 229 |
+
|
| 230 |
+
**Ingesting existing CSVs**: It reads all six CSV files from the `data/` folder into a SQLite database using SQLAlchemy. Each CSV becomes a table. Date columns are normalized, and the `depends_on` field in the activities table is used to build a seventh table called `activity_dependencies`, which stores predecessor-successor pairs as explicit rows. This makes graph queries much faster than string parsing at runtime.
|
| 231 |
+
|
| 232 |
+
**Generating synthetic data**: To give the machine learning model more training data, the script generates two additional completed projects using a realistic delay distribution. Each synthetic project follows the same 15-activity renovation sequence and applies randomized delays that reflect how real renovations behave: most activities finish roughly on time, some finish a few days late, and a small number run significantly over:
|
| 233 |
+
|
| 234 |
+
```
|
| 235 |
+
Delay in days: -1 0 0 1 2 3 5 7
|
| 236 |
+
Probability: 5% 20% 20% 20% 15% 10% 7% 3%
|
| 237 |
+
```
|
| 238 |
+
|
| 239 |
+
The distribution is skewed positive (more likely to be late than early) because that is what the historical data shows. Each synthetic project also gets realistic issues, BOQ items, daily updates, and resource allocations generated to match the activity duration.
|
| 240 |
+
|
| 241 |
+
The final database contains 12 projects, 180 activities, 2,354 daily updates, 503 issues, 670 BOQ items, 315 resources, and 168 dependency edges.
|
| 242 |
+
|
| 243 |
+
---
|
| 244 |
+
|
| 245 |
+
### The DataLoader
|
| 246 |
+
|
| 247 |
+
**File: `data_loader.py`**
|
| 248 |
+
|
| 249 |
+
The DataLoader is the single point of access to data for every other module. At initialization it checks whether `data/data.db` exists. If it does, it reads all tables from the database. If not, it falls back to reading the CSV files directly. Either way, it returns the same pandas DataFrames.
|
| 250 |
+
|
| 251 |
+
It exposes shortcut methods so modules do not need to write their own filter logic:
|
| 252 |
+
|
| 253 |
+
- `loader.get_historical_activities()` -- returns all completed activities (used for training)
|
| 254 |
+
- `loader.get_active_activities()` -- returns all in-progress activities (used for prediction)
|
| 255 |
+
- `loader.get_project_activities(project_id)` -- all activities for one project
|
| 256 |
+
- `loader.get_inprogress_projects()` -- projects currently running
|
| 257 |
+
- `loader.get_activity_issues(activity_id, project_id)` -- issues for one activity or project
|
| 258 |
+
- `loader.get_daily_updates(activity_id)` -- time series of daily progress for one activity
|
| 259 |
+
- `loader.get_project_boq(project_id)` -- bill of quantities for a project
|
| 260 |
+
- `loader.get_dependencies(project_id)` -- predecessor-successor pairs for the DAG
|
| 261 |
+
|
| 262 |
+
A `REFERENCE_DATE` of 2024-06-01 is used as the "today" anchor for all calculations on in-progress activities. This is overridable from the dashboard sidebar.
|
| 263 |
+
|
| 264 |
+
---
|
| 265 |
+
|
| 266 |
+
### Feature Engineering
|
| 267 |
+
|
| 268 |
+
**File: `features/feature_engineering.py`**
|
| 269 |
+
|
| 270 |
+
Machine learning models cannot work directly with dates and status strings. Feature engineering converts raw activity data into 12 numbers that capture the dynamics of schedule performance.
|
| 271 |
+
|
| 272 |
+
For each activity, the following features are computed:
|
| 273 |
+
|
| 274 |
+
**planned_duration**
|
| 275 |
+
Number of days between planned start and planned end. Longer activities tend to accumulate more delay simply because there is more time for things to go wrong.
|
| 276 |
+
|
| 277 |
+
**elapsed_days**
|
| 278 |
+
For completed activities: actual end minus actual start. For in-progress: today minus actual start. Captures how long the activity has been running so far.
|
| 279 |
+
|
| 280 |
+
**progress_rate**
|
| 281 |
+
Progress divided by elapsed days. If an activity is 40% done after 10 days, the rate is 4% per day. Activities with very low rates relative to their planned pace are likely to finish late.
|
| 282 |
+
|
| 283 |
+
**schedule_variance**
|
| 284 |
+
Actual start minus planned start, in days. A positive value means the activity started late. A late start often predicts a late finish, even if work proceeds at full pace afterward.
|
| 285 |
+
|
| 286 |
+
**delay_ratio** (training target)
|
| 287 |
+
Actual duration divided by planned duration. A ratio of 1.0 means finished on time. A ratio of 1.5 means took 50% longer than planned. This is the value the machine learning model is trained to predict. For in-progress activities it is predicted, not observed.
|
| 288 |
+
|
| 289 |
+
**issue_count**
|
| 290 |
+
Number of open issues against this activity. More issues generally means more risk of delay.
|
| 291 |
+
|
| 292 |
+
**issue_severity_score**
|
| 293 |
+
A weighted count of issues by category. Different categories have different weights based on how much disruption they typically cause:
|
| 294 |
+
|
| 295 |
+
```
|
| 296 |
+
design_change: 3 points
|
| 297 |
+
inspection_fail: 2 points
|
| 298 |
+
equipment_breakdown: 2 points
|
| 299 |
+
material_delay: 2 points
|
| 300 |
+
labor_shortage: 1.5 points
|
| 301 |
+
weather: 1 point
|
| 302 |
+
scope_creep: 1.5 points
|
| 303 |
+
safety: 2.5 points
|
| 304 |
+
```
|
| 305 |
+
|
| 306 |
+
An activity with one design_change issue scores 3, while an activity with three weather issues scores 3 as well, capturing that type of issue matters as much as count.
|
| 307 |
+
|
| 308 |
+
**boq_complexity**
|
| 309 |
+
Number of BOQ line items for the activity plus a cost-variance component. Activities with many distinct materials or subcontractors are harder to coordinate and more likely to have procurement delays.
|
| 310 |
+
|
| 311 |
+
**parent_delay**
|
| 312 |
+
A binary flag (0 or 1). It is set to 1 if the predecessor activity started more than 2 days late. This captures the fact that late handoffs tend to cause chain reactions.
|
| 313 |
+
|
| 314 |
+
**historical_avg_delay**
|
| 315 |
+
The average delay_ratio for all completed activities in the same category across all training projects. For example, if all past "Tiling" activities took on average 1.3 times their planned duration, then any current tiling activity gets a historical baseline of 1.3. This is the most predictive single feature because construction categories have consistent delay tendencies.
|
| 316 |
+
|
| 317 |
+
**progress_velocity_7d**
|
| 318 |
+
The rolling 7-day average of daily progress increments from the daily_updates table. If the last 7 daily updates show increments of 1, 2, 0, 3, 1, 2, 1, the velocity is approximately 1.4% per day. This is the most up-to-date signal about how fast work is currently proceeding.
|
| 319 |
+
|
| 320 |
+
**progress_acceleration**
|
| 321 |
+
The change in velocity between the most recent 7 days and the prior 7 days. Positive means the activity is speeding up; negative means it is slowing down. Deceleration is a danger signal that often precedes a stall.
|
| 322 |
+
|
| 323 |
+
After computing these 12 features, the engineering module also label-encodes two categorical columns (activity category and project type) and appends them, giving the model 14 total input dimensions.
|
| 324 |
+
|
| 325 |
+
---
|
| 326 |
+
|
| 327 |
+
### Prediction Method A: Earned Value Extrapolation
|
| 328 |
+
|
| 329 |
+
**File: `models/completion_predictor.py`, function `predict_method_a`**
|
| 330 |
+
|
| 331 |
+
This method requires no training data. It is a purely mathematical extrapolation based on the activity's current pace.
|
| 332 |
+
|
| 333 |
+
The logic:
|
| 334 |
+
|
| 335 |
+
1. Calculate the actual rate of progress: `actual_rate = progress / elapsed_days`
|
| 336 |
+
2. Calculate the theoretical planned rate: `planned_rate = 100 / planned_duration`
|
| 337 |
+
3. Blend the two rates. Early in an activity (few elapsed days) the actual rate is unreliable, so the planned rate gets more weight. Later, the actual rate dominates:
|
| 338 |
+
```
|
| 339 |
+
weight = min(elapsed_days / 14.0, 0.85)
|
| 340 |
+
blended_rate = weight * actual_rate + (1 - weight) * planned_rate
|
| 341 |
+
```
|
| 342 |
+
4. Project days remaining: `days_remaining = (100 - progress) / blended_rate`
|
| 343 |
+
5. Predicted end: `today + days_remaining`
|
| 344 |
+
|
| 345 |
+
This method works well when an activity is on track. It struggles when an activity has stalled (rate near zero would predict an infinite end date) or when there are invisible blockers that the rate does not yet reflect. That is why it is blended with Method B.
|
| 346 |
+
|
| 347 |
+
---
|
| 348 |
+
|
| 349 |
+
### Prediction Method B: Gradient Boosting Regressor
|
| 350 |
+
|
| 351 |
+
**File: `models/completion_predictor.py`, classes `CompletionPredictor`**
|
| 352 |
+
|
| 353 |
+
This method is a trained machine learning model. It learns from patterns in the 119 completed historical activities and applies that knowledge to predict the `delay_ratio` for each in-progress activity.
|
| 354 |
+
|
| 355 |
+
**What is a Gradient Boosting Regressor?**
|
| 356 |
+
|
| 357 |
+
Gradient boosting is an ensemble technique that builds a sequence of decision trees. Each tree is trained to correct the errors of all the trees before it. The "gradient" refers to the direction in which each new tree reduces the prediction error, computed mathematically. The result is a very accurate predictor that can capture non-linear relationships between features and the target.
|
| 358 |
+
|
| 359 |
+
In simple terms: the model learns rules like "activities with low progress velocity AND high issue severity score tend to finish 40% later than planned" and combines many such rules into a final prediction.
|
| 360 |
+
|
| 361 |
+
**Training process:**
|
| 362 |
+
|
| 363 |
+
The model is trained on the 119 completed activities in the dataset. The features described above are the inputs (X). The `delay_ratio` for each completed activity is the target (y). Hyperparameters:
|
| 364 |
+
|
| 365 |
+
- 200 trees in the ensemble
|
| 366 |
+
- Learning rate of 0.05 (each tree contributes only 5% to avoid overfitting)
|
| 367 |
+
- Maximum tree depth of 4
|
| 368 |
+
- 80% of training data sampled per tree (subsample = 0.8)
|
| 369 |
+
|
| 370 |
+
The model is evaluated with 5-fold cross-validation and achieves a mean absolute error of 0.001 on the delay multiplier scale. In practical terms this means predictions are extremely well-calibrated on historical data.
|
| 371 |
+
|
| 372 |
+
**Making a prediction:**
|
| 373 |
+
|
| 374 |
+
For each in-progress activity, the same 14 features are computed and fed into the trained model. The model outputs a `delay_multiplier` (the predicted delay_ratio). The predicted end date is then:
|
| 375 |
+
|
| 376 |
+
```
|
| 377 |
+
remaining_fraction = (100 - progress) / 100
|
| 378 |
+
predicted_end = today + planned_duration * predicted_multiplier * remaining_fraction
|
| 379 |
+
```
|
| 380 |
+
|
| 381 |
+
---
|
| 382 |
+
|
| 383 |
+
### Ensemble Prediction
|
| 384 |
+
|
| 385 |
+
The final prediction combines Method A and Method B with fixed weights:
|
| 386 |
+
|
| 387 |
+
```
|
| 388 |
+
ensemble_days_remaining = 0.4 * methodA_days_remaining + 0.6 * methodB_days_remaining
|
| 389 |
+
predicted_end = today + ensemble_days_remaining
|
| 390 |
+
```
|
| 391 |
+
|
| 392 |
+
Method B receives a 60% weight because it uses 14 features including issue data, historical baselines, and velocity trends that Method A ignores. Method A receives 40% weight to keep the prediction grounded in the activity's observed pace, preventing the model from producing wildly different estimates based on historical patterns alone.
|
| 393 |
+
|
| 394 |
+
The dashboard shows all three estimates side by side, so a planner can see where the methods agree and where they diverge.
|
| 395 |
+
|
| 396 |
+
---
|
| 397 |
+
|
| 398 |
+
### Monte Carlo Simulation
|
| 399 |
+
|
| 400 |
+
**File: `models/monte_carlo.py`**
|
| 401 |
+
|
| 402 |
+
Monte Carlo simulation is a technique for quantifying uncertainty. Instead of producing one prediction, it runs thousands of hypothetical futures and reports how often each outcome occurs.
|
| 403 |
+
|
| 404 |
+
**How it works for this system:**
|
| 405 |
+
|
| 406 |
+
1. For each in-progress activity, retrieve the last 14 days of `daily_increment` values from daily_updates.
|
| 407 |
+
2. Fit a normal distribution to those increments: calculate mean and standard deviation. This characterizes the activity's recent progress behavior.
|
| 408 |
+
3. Run 1,000 simulations. In each simulation:
|
| 409 |
+
- Start at the current progress level.
|
| 410 |
+
- Each simulated day, draw a random daily increment from the fitted distribution (using `scipy.stats.norm.rvs`). Increments are clipped to a minimum of 0 (no backward progress).
|
| 411 |
+
- Accumulate progress until it reaches 100%.
|
| 412 |
+
- Record how many days this simulation took.
|
| 413 |
+
4. From the 1,000 completion-day counts, compute:
|
| 414 |
+
- **P50** (50th percentile): The date by which 50% of simulations finish. This is the median estimate.
|
| 415 |
+
- **P80** (80th percentile): The date by which 80% of simulations finish. Use this for cautious planning.
|
| 416 |
+
- **P90** (90th percentile): The date by which 90% of simulations finish. Use this for conservative budget reserve estimates.
|
| 417 |
+
|
| 418 |
+
**Why this matters:**
|
| 419 |
+
|
| 420 |
+
If P50 is June 15 and P90 is July 10, that means there is a 50% chance of finishing by June 15 but a 10% chance of finishing after July 10. A contract manager can use the P90 date to set penalties; a scheduler can use P50 for optimistic planning. Single-point predictions cannot communicate this uncertainty at all.
|
| 421 |
+
|
| 422 |
+
---
|
| 423 |
+
|
| 424 |
+
### Activity Dependency Graph (DAG)
|
| 425 |
+
|
| 426 |
+
**File: `engine/dag_builder.py`**
|
| 427 |
+
|
| 428 |
+
A Directed Acyclic Graph (DAG) is a data structure where nodes are connected by arrows, there are no loops, and you can traverse from start to finish following the arrows.
|
| 429 |
+
|
| 430 |
+
In this system:
|
| 431 |
+
- Each **node** is one activity (identified by its ID).
|
| 432 |
+
- Each **directed edge** points from a predecessor to a successor. If "Painting depends on Wall Plastering", there is an arrow from Wall Plastering to Painting.
|
| 433 |
+
- All activity attributes (name, status, progress, planned dates, schedule variance) are stored on each node so they can be retrieved during graph traversal.
|
| 434 |
+
|
| 435 |
+
The DAG is built using the `networkx` Python library, which provides efficient graph algorithms.
|
| 436 |
+
|
| 437 |
+
**Why a DAG specifically?**
|
| 438 |
+
|
| 439 |
+
The "acyclic" property (no cycles) is guaranteed by the nature of construction sequences: you cannot have Activity A depending on Activity B while Activity B also depends on Activity A. The `networkx` library validates this and raises an error if a cycle is detected.
|
| 440 |
+
|
| 441 |
+
The DAG enables two key capabilities:
|
| 442 |
+
|
| 443 |
+
1. **Topological sort**: Order activities from first to last such that every predecessor comes before its successors. This is the correct order for CPM calculations.
|
| 444 |
+
|
| 445 |
+
2. **Descendant queries**: Given any activity, instantly find all activities downstream of it. This is used by the ripple engine to know which activities need to be recalculated when a delay occurs.
|
| 446 |
+
|
| 447 |
+
---
|
| 448 |
+
|
| 449 |
+
### Ripple Engine: Delay Propagation
|
| 450 |
+
|
| 451 |
+
**File: `engine/ripple_engine.py`**
|
| 452 |
+
|
| 453 |
+
The ripple engine answers the question: "If activity X finishes N days late, what happens to everything that depends on it?"
|
| 454 |
+
|
| 455 |
+
**The algorithm (BFS-based forward propagation):**
|
| 456 |
+
|
| 457 |
+
1. Mark the directly affected activity with its new end date (original end plus delta_days).
|
| 458 |
+
2. Use Breadth-First Search (BFS) to traverse the DAG in topological order, starting from the immediate successors of the affected activity.
|
| 459 |
+
3. For each downstream activity encountered:
|
| 460 |
+
- Its new start date is the maximum of:
|
| 461 |
+
- Its original planned start date (it cannot start before it was planned)
|
| 462 |
+
- The maximum end date of all of its now-shifted predecessors
|
| 463 |
+
- Its new end date is new_start_date plus its planned duration.
|
| 464 |
+
- Its cascade delay is new_end_date minus original_end_date.
|
| 465 |
+
4. Continue traversal until all descendants have been updated.
|
| 466 |
+
5. The new project end date is the maximum end date across all activities after propagation.
|
| 467 |
+
6. Total project delay is new_project_end minus original_project_end.
|
| 468 |
+
|
| 469 |
+
**Example:**
|
| 470 |
+
|
| 471 |
+
Suppose the project sequence is: A -> B -> C -> D (each depends on the previous).
|
| 472 |
+
- A finishes 7 days late.
|
| 473 |
+
- B must start 7 days later, so it also finishes 7 days later.
|
| 474 |
+
- C must start 7 days later, so it also finishes 7 days later.
|
| 475 |
+
- D must start 7 days later, so it also finishes 7 days later.
|
| 476 |
+
- Total project delay: 7 days.
|
| 477 |
+
|
| 478 |
+
Real projects have parallel branches, so the actual cascade is more complex. When two paths merge at one activity, that activity can only start when both predecessors finish. The ripple engine handles merge points correctly by taking the maximum predecessor end date.
|
| 479 |
+
|
| 480 |
+
**High-impact activity identification:**
|
| 481 |
+
|
| 482 |
+
The engine also computes which activities have the most downstream dependencies. An activity that 10 others depend on (directly or indirectly) is more dangerous to delay than an activity with no dependents. The dashboard surfaces the top 5 highest-impact activities for each project.
|
| 483 |
+
|
| 484 |
+
---
|
| 485 |
+
|
| 486 |
+
### What-if Scenario Engine
|
| 487 |
+
|
| 488 |
+
**File: `engine/whatif_scenarios.py`**
|
| 489 |
+
|
| 490 |
+
The scenario engine lets a user build a collection of hypothetical interventions and compare their effects side by side. It supports four types:
|
| 491 |
+
|
| 492 |
+
**Delay scenario**
|
| 493 |
+
Models the question: "What if this activity finishes N days late?"
|
| 494 |
+
|
| 495 |
+
The engine calls the ripple engine with the specified activity and delta, records the cascade table and new project end date, and stores the result labeled "delay".
|
| 496 |
+
|
| 497 |
+
**Resource boost scenario**
|
| 498 |
+
Models the question: "What if we add extra workers to this activity to reduce its duration by X%?"
|
| 499 |
+
|
| 500 |
+
The engine reduces the activity's remaining duration by the specified percentage (e.g. 25% reduction means a 30-day activity becomes a 22.5-day activity). It then runs the ripple engine with a negative delta (negative delay = time saved). The cost impact is estimated as the additional cost at a 40% overtime premium over the per-day resource cost from the resources table.
|
| 501 |
+
|
| 502 |
+
**Issue resolved scenario**
|
| 503 |
+
Models the question: "What if we resolve this specific blocking issue immediately?"
|
| 504 |
+
|
| 505 |
+
Each issue in the issues table has a `delay_impact_days` field. The engine passes a negative delta equal to that value through the ripple engine, computing the schedule recovery that would result from fixing the issue.
|
| 506 |
+
|
| 507 |
+
**Parallelize scenario**
|
| 508 |
+
Models the question: "What if we run these two activities at the same time instead of sequentially?"
|
| 509 |
+
|
| 510 |
+
The engine removes the dependency edge between Activity A and Activity B (if one exists) and shifts Activity B's start to overlap with Activity A's start. It then recalculates end dates and propagates any changes downstream.
|
| 511 |
+
|
| 512 |
+
Each scenario result records: the scenario type, description, original project end date, new project end date, total delay days (negative = time saved), days saved, and cost impact. The comparison table lets a manager immediately see which intervention gives the best schedule recovery per rupee of extra cost.
|
| 513 |
+
|
| 514 |
+
---
|
| 515 |
+
|
| 516 |
+
### Schedule Optimizer and Critical Path Method
|
| 517 |
+
|
| 518 |
+
**File: `optimizer/schedule_optimizer.py`**
|
| 519 |
+
|
| 520 |
+
The Critical Path Method is a standard project management algorithm. It identifies which sequence of activities, if any one of them is delayed, will delay the entire project. These activities form the "critical path" and have zero scheduling slack.
|
| 521 |
+
|
| 522 |
+
**The CPM algorithm:**
|
| 523 |
+
|
| 524 |
+
**Step 1: Forward pass (computing Early Start and Early Finish)**
|
| 525 |
+
|
| 526 |
+
Process activities in topological order:
|
| 527 |
+
- For each activity with no predecessors, Early Start (ES) = 0.
|
| 528 |
+
- For each other activity, ES = maximum Early Finish of all its predecessors.
|
| 529 |
+
- Early Finish (EF) = ES + planned_duration.
|
| 530 |
+
|
| 531 |
+
This tells us the earliest possible time each activity can start and finish given all dependencies.
|
| 532 |
+
|
| 533 |
+
**Step 2: Backward pass (computing Late Start and Late Finish)**
|
| 534 |
+
|
| 535 |
+
Process activities in reverse topological order:
|
| 536 |
+
- For each activity with no successors (project end), Late Finish (LF) = project total duration.
|
| 537 |
+
- For each other activity, LF = minimum Late Start of all its successors.
|
| 538 |
+
- Late Start (LS) = LF - planned_duration.
|
| 539 |
+
|
| 540 |
+
This tells us the latest each activity can start and finish without delaying the project.
|
| 541 |
+
|
| 542 |
+
**Step 3: Float calculation**
|
| 543 |
+
|
| 544 |
+
Total Float = Late Start - Early Start.
|
| 545 |
+
|
| 546 |
+
Float represents scheduling flexibility. An activity with 5 days of float can start up to 5 days after its earliest possible start without delaying the project end. An activity with 0 days of float is on the critical path and has no flexibility at all.
|
| 547 |
+
|
| 548 |
+
The dashboard displays float as a color-coded bar chart: red for zero float (critical), green for high float (safe).
|
| 549 |
+
|
| 550 |
+
**Rule-Based Optimization Suggestions:**
|
| 551 |
+
|
| 552 |
+
The optimizer evaluates 6 rules against the current project state and produces prioritized suggestions:
|
| 553 |
+
|
| 554 |
+
| Rule | Condition that triggers it | Suggested action |
|
| 555 |
+
|---|---|---|
|
| 556 |
+
| Slow Critical Activity | Activity is on the critical path, in progress, and progressing at under 50% of the planned rate | Add crew or shift to overtime |
|
| 557 |
+
| High Impact Delay | Activity has a large schedule variance AND many downstream dependents | Escalate to senior management immediately |
|
| 558 |
+
| Material Delay Risk | Activity has not yet started AND has open material_delay issues | Pre-order materials now to prevent future stoppage |
|
| 559 |
+
| Parallelization Opportunity | Two not-yet-started activities have no dependency between them | Schedule them to run concurrently |
|
| 560 |
+
| Stalled Activity | Activity is in progress but has recorded zero daily progress for 3 or more consecutive days | Investigate the cause immediately |
|
| 561 |
+
| Resource Reallocation | Activity is in progress, NOT on the critical path, and has more than 10 days of float | Move its resources to critical path activities |
|
| 562 |
+
|
| 563 |
+
Suggestions are deduplicated (one per activity-rule pair) and sorted by priority: Critical first, then High, then Medium, then Opportunity.
|
| 564 |
+
|
| 565 |
+
---
|
| 566 |
+
|
| 567 |
+
### Visualizations
|
| 568 |
+
|
| 569 |
+
**File: `visualization/gantt.py`**
|
| 570 |
+
|
| 571 |
+
The Gantt chart uses Plotly to draw horizontal bars for each activity. Three bars are drawn per activity when data is available:
|
| 572 |
+
|
| 573 |
+
- **Planned** (indigo/blue): from planned_start_date to planned_end_date.
|
| 574 |
+
- **Actual** (green for completed, amber for in-progress): from actual_start_date to actual_end_date (or today).
|
| 575 |
+
- **Forecasted** (amber/orange): from today to the ensemble predicted end date.
|
| 576 |
+
|
| 577 |
+
Activities on the critical path are marked with a "CRIT:" prefix. A red dashed vertical line marks the reference date ("today").
|
| 578 |
+
|
| 579 |
+
**File: `visualization/dag_viz.py`**
|
| 580 |
+
|
| 581 |
+
The DAG is visualized as an interactive Plotly scatter plot with nodes positioned using a hierarchical layout algorithm. Each node is a circle colored on a green-to-red scale based on schedule variance (green = on schedule, red = significantly late). Edges representing critical path connections are drawn in red at double thickness. Hovering over any node shows its name, status, progress, and schedule variance.
|
| 582 |
+
|
| 583 |
+
---
|
| 584 |
+
|
| 585 |
+
### The Streamlit Dashboard
|
| 586 |
+
|
| 587 |
+
**File: `app.py`**
|
| 588 |
+
|
| 589 |
+
Streamlit is a Python library that turns Python scripts into interactive web applications. The dashboard is organized into 7 tabs, navigable by clicking at the top of the page.
|
| 590 |
+
|
| 591 |
+
**Performance**: All heavy computations (database loading, model training, CPM calculation, Monte Carlo simulation) are wrapped in `@st.cache_resource`. This means they run once when the app first loads and are reused across all tab switches. The app feels instant after the initial 3-4 second startup.
|
| 592 |
+
|
| 593 |
+
**Sidebar**: Always visible. Contains project selection (dropdown of all 12 projects), a reference date picker, project metadata (name, status, type, city), and a model health summary (training sample count, cross-validation MAE).
|
| 594 |
+
|
| 595 |
+
**Tab 1 - Overview**: Six KPI cards at the top (overall progress, activities done, in progress, open issues, critical issues, average schedule variance). Below that, a status donut chart and a category-level progress bar chart side by side. At the bottom, the full activity list as a sortable table.
|
| 596 |
+
|
| 597 |
+
**Tab 2 - Gantt Chart**: Full project Gantt with planned vs actual vs forecasted bars for every activity.
|
| 598 |
+
|
| 599 |
+
**Tab 3 - Predictions**: A table comparing Method A, Method B, and ensemble completion dates for every in-progress activity. Below it, a Monte Carlo histogram for any selected activity showing the distribution of 500 simulated completion times with P50, P80, P90 markers.
|
| 600 |
+
|
| 601 |
+
**Tab 4 - Ripple Analysis**: A dropdown to select any activity and a number input for delay days. Clicking "Run Ripple Simulation" computes and displays: number of activities affected, original vs new project end date, cascade impact table (original and shifted dates per downstream activity), and a horizontal bar chart of cascade delay magnitude.
|
| 602 |
+
|
| 603 |
+
**Tab 5 - What-if Scenarios**: A radio button to choose scenario type. Inputs change depending on type. Each submitted scenario is added to a persistent list and shown in a cumulative comparison table and bar chart.
|
| 604 |
+
|
| 605 |
+
**Tab 6 - Optimization**: CPM results table with float values and critical path flags. Float bar chart. Rule-based suggestion cards color-coded by priority.
|
| 606 |
+
|
| 607 |
+
**Tab 7 - DAG View**: Interactive dependency graph with hover tooltips. Below it, a table listing every dependency edge in the project with a flag for critical path membership.
|
| 608 |
+
|
| 609 |
+
---
|
| 610 |
+
|
| 611 |
+
## Screenshots
|
| 612 |
+
|
| 613 |
+
### Overview Dashboard
|
| 614 |
+
|
| 615 |
+
The Overview tab shows the full project status at a glance, with KPI cards at the top and charts breaking down activity status and category-level progress.
|
| 616 |
+
|
| 617 |
+

|
| 618 |
+
|
| 619 |
+
### Gantt Chart
|
| 620 |
+
|
| 621 |
+
The Gantt chart compares planned (blue), actual (green), and forecasted (amber) timelines for every activity. The dashed red line is "today". Critical path activities are labeled.
|
| 622 |
+
|
| 623 |
+

|
| 624 |
+
|
| 625 |
+
### Completion Date Predictions
|
| 626 |
+
|
| 627 |
+
The Predictions tab shows the three prediction methods side by side and provides a Monte Carlo histogram for any selected activity, with P50, P80, and P90 completion date markers.
|
| 628 |
+
|
| 629 |
+

|
| 630 |
+
|
| 631 |
+
### Ripple Analysis
|
| 632 |
+
|
| 633 |
+
After clicking "Run Ripple Simulation", the tool shows exactly which downstream activities shifted, by how much, and how the project end date changed.
|
| 634 |
+
|
| 635 |
+

|
| 636 |
+
|
| 637 |
+
### What-if Scenarios
|
| 638 |
+
|
| 639 |
+
The scenario builder lets a planner define multiple interventions and compare their schedule and cost impacts in one table.
|
| 640 |
+
|
| 641 |
+

|
| 642 |
+
|
| 643 |
+
### Optimization and Critical Path
|
| 644 |
+
|
| 645 |
+
The Optimization tab shows CPM float values per activity (red = zero float = critical) and generates prioritized, rule-based suggestions for schedule recovery.
|
| 646 |
+
|
| 647 |
+

|
| 648 |
+
|
| 649 |
+
### Dependency DAG
|
| 650 |
+
|
| 651 |
+
The DAG view renders the full activity dependency graph as an interactive diagram. Nodes are colored by schedule variance, and critical path edges are drawn in red.
|
| 652 |
+
|
| 653 |
+

|
| 654 |
+
|
| 655 |
+
---
|
| 656 |
+
|
| 657 |
+
## Project Structure
|
| 658 |
+
|
| 659 |
+
```
|
| 660 |
+
Assignment/
|
| 661 |
+
|
|
| 662 |
+
|-- app.py Main Streamlit dashboard (7 tabs)
|
| 663 |
+
|-- dataset.py Database builder: ingests CSVs + generates synthetic data
|
| 664 |
+
|-- data_loader.py Central data access layer with typed shortcuts
|
| 665 |
+
|-- test_pipeline.py End-to-end integration test for all modules
|
| 666 |
+
|-- requirements.txt Python package dependencies
|
| 667 |
+
|-- README.md This file
|
| 668 |
+
|
|
| 669 |
+
|-- data/
|
| 670 |
+
| |-- projects.csv 10 real projects (input)
|
| 671 |
+
| |-- activities.csv 150 activities with dependencies (input)
|
| 672 |
+
| |-- daily_updates.csv 1,950 daily progress logs (input)
|
| 673 |
+
| |-- issues.csv 395 issues with severity and delay impact (input)
|
| 674 |
+
| |-- boq.csv 540 bill-of-quantities line items (input)
|
| 675 |
+
| |-- resources.csv 255 resource allocation records (input)
|
| 676 |
+
| |-- data.db SQLite database generated by dataset.py (output)
|
| 677 |
+
|
|
| 678 |
+
|-- features/
|
| 679 |
+
| |-- __init__.py
|
| 680 |
+
| |-- feature_engineering.py Computes 12 engineered features per activity
|
| 681 |
+
|
|
| 682 |
+
|-- models/
|
| 683 |
+
| |-- __init__.py
|
| 684 |
+
| |-- completion_predictor.py Method A + Method B + Ensemble prediction
|
| 685 |
+
| |-- monte_carlo.py 1000-simulation P50/P80/P90 predictor
|
| 686 |
+
|
|
| 687 |
+
|-- engine/
|
| 688 |
+
| |-- __init__.py
|
| 689 |
+
| |-- dag_builder.py Builds networkx DAG from activity dependencies
|
| 690 |
+
| |-- ripple_engine.py BFS delay cascade propagation
|
| 691 |
+
| |-- whatif_scenarios.py 4 what-if scenario types with comparison
|
| 692 |
+
|
|
| 693 |
+
|-- optimizer/
|
| 694 |
+
| |-- __init__.py
|
| 695 |
+
| |-- schedule_optimizer.py CPM algorithm and 6 rule-based suggestion rules
|
| 696 |
+
|
|
| 697 |
+
|-- visualization/
|
| 698 |
+
| |-- __init__.py
|
| 699 |
+
| |-- gantt.py Plotly Gantt chart (planned vs actual vs forecast)
|
| 700 |
+
| |-- dag_viz.py Plotly interactive DAG diagram
|
| 701 |
+
|
|
| 702 |
+
|-- screenshots/
|
| 703 |
+
| |-- overview.png
|
| 704 |
+
| |-- gantt.png
|
| 705 |
+
| |-- predictions.png
|
| 706 |
+
| |-- ripple.png
|
| 707 |
+
| |-- whatif.png
|
| 708 |
+
| |-- optimization.png
|
| 709 |
+
| |-- dag.png
|
| 710 |
+
```
|
| 711 |
+
|
| 712 |
+
---
|
| 713 |
+
|
| 714 |
+
## Installation
|
| 715 |
+
|
| 716 |
+
Python 3.9 or later is required.
|
| 717 |
+
|
| 718 |
+
**Step 1: Install dependencies**
|
| 719 |
+
|
| 720 |
+
```bash
|
| 721 |
+
pip install -r requirements.txt
|
| 722 |
+
```
|
| 723 |
+
|
| 724 |
+
Contents of `requirements.txt`:
|
| 725 |
+
|
| 726 |
+
```
|
| 727 |
+
pandas>=1.5.0
|
| 728 |
+
numpy>=1.23.0
|
| 729 |
+
scikit-learn>=1.1.0
|
| 730 |
+
scipy>=1.9.0
|
| 731 |
+
networkx>=2.8.0
|
| 732 |
+
plotly>=5.11.0
|
| 733 |
+
matplotlib>=3.6.0
|
| 734 |
+
sqlalchemy>=1.4.0
|
| 735 |
+
streamlit>=1.20.0
|
| 736 |
+
joblib>=1.2.0
|
| 737 |
+
```
|
| 738 |
+
|
| 739 |
+
Approximate install size: 800 MB (primarily due to scikit-learn and plotly). On a typical connection this takes 2 to 5 minutes.
|
| 740 |
+
|
| 741 |
+
---
|
| 742 |
+
|
| 743 |
+
## Running the System
|
| 744 |
+
|
| 745 |
+
### Step 1: Build the database
|
| 746 |
+
|
| 747 |
+
This reads all six CSV files and creates `data/data.db`. It also generates two additional synthetic historical projects. Run this once before starting the app, and again any time the CSV files are updated.
|
| 748 |
+
|
| 749 |
+
```bash
|
| 750 |
+
python dataset.py
|
| 751 |
+
```
|
| 752 |
+
|
| 753 |
+
Expected output:
|
| 754 |
+
|
| 755 |
+
```
|
| 756 |
+
Database: data/data.db
|
| 757 |
+
|
| 758 |
+
Ingesting CSVs...
|
| 759 |
+
Ingested projects.csv -> projects (10 rows)
|
| 760 |
+
Ingested activities.csv -> activities (150 rows)
|
| 761 |
+
Ingested daily_updates.csv -> daily_updates (1950 rows)
|
| 762 |
+
Ingested issues.csv -> issues (395 rows)
|
| 763 |
+
Ingested boq.csv -> boq (540 rows)
|
| 764 |
+
Ingested resources.csv -> resources (255 rows)
|
| 765 |
+
|
| 766 |
+
Generating synthetic projects...
|
| 767 |
+
Generated Beachfront Bungalow Reno (15 activities, ~200 updates)
|
| 768 |
+
Generated Shopping Mall Fit-out (15 activities, ~203 updates)
|
| 769 |
+
|
| 770 |
+
Building dependency graph table...
|
| 771 |
+
Built activity_dependencies table (168 rows)
|
| 772 |
+
|
| 773 |
+
Summary:
|
| 774 |
+
projects: 12 rows
|
| 775 |
+
activities: 180 rows
|
| 776 |
+
daily_updates: 2354 rows
|
| 777 |
+
issues: 503 rows
|
| 778 |
+
boq: 670 rows
|
| 779 |
+
resources: 315 rows
|
| 780 |
+
activity_dependencies: 168 rows
|
| 781 |
+
|
| 782 |
+
Database ready.
|
| 783 |
+
```
|
| 784 |
+
|
| 785 |
+
### Step 2: Verify the pipeline (optional but recommended)
|
| 786 |
+
|
| 787 |
+
This runs all modules in sequence and prints results to the terminal. If any module is broken it will show an error. If everything is working it prints "ALL TESTS PASSED" at the end.
|
| 788 |
+
|
| 789 |
+
```bash
|
| 790 |
+
python test_pipeline.py
|
| 791 |
+
```
|
| 792 |
+
|
| 793 |
+
### Step 3: Launch the dashboard
|
| 794 |
+
|
| 795 |
+
```bash
|
| 796 |
+
streamlit run app.py
|
| 797 |
+
```
|
| 798 |
+
|
| 799 |
+
Open your browser and go to `http://localhost:8501`.
|
| 800 |
+
|
| 801 |
+
The app takes 3 to 5 seconds to start because it trains the machine learning model. After that, all tab switches are instant because results are cached.
|
| 802 |
+
|
| 803 |
+
### Step 4: Use the dashboard
|
| 804 |
+
|
| 805 |
+
1. **Select a project** from the sidebar dropdown. The two in-progress projects (Lakeview Villa Renovation and Metro Commercial Tower Fit-Out) show the full prediction and scenario functionality.
|
| 806 |
+
|
| 807 |
+
2. **Change the Reference Date** if you want to simulate the project state as of a different date. The date affects all elapsed-day calculations, progress rates, and predictions.
|
| 808 |
+
|
| 809 |
+
3. **Browse the Overview tab** to get a summary of current project health.
|
| 810 |
+
|
| 811 |
+
4. **Go to the Gantt Chart** to see the timeline comparison of planned vs actual vs forecasted dates.
|
| 812 |
+
|
| 813 |
+
5. **Go to Predictions** to see when each activity is expected to finish and explore the Monte Carlo uncertainty ranges.
|
| 814 |
+
|
| 815 |
+
6. **Go to Ripple Analysis** to select an activity, enter a delay, and click "Run Ripple Simulation" to see the cascade impact.
|
| 816 |
+
|
| 817 |
+
7. **Go to What-if Scenarios** to build and compare alternative interventions.
|
| 818 |
+
|
| 819 |
+
8. **Go to Optimization** to see the critical path and receive prioritized scheduling recommendations.
|
| 820 |
+
|
| 821 |
+
9. **Go to DAG View** to explore the dependency graph interactively.
|
| 822 |
+
|
| 823 |
+
---
|
| 824 |
+
|
| 825 |
+
## Glossary
|
| 826 |
+
|
| 827 |
+
**Activity**: One distinct work package within a project, e.g. "Tiling" or "Electrical Wiring".
|
| 828 |
+
|
| 829 |
+
**BOQ (Bill of Quantities)**: A detailed list of materials, labor, and other items required to complete an activity, with quantities and unit prices.
|
| 830 |
+
|
| 831 |
+
**CPM (Critical Path Method)**: A project management algorithm that identifies which sequence of activities determines the minimum possible project duration. Activities on the critical path have zero scheduling slack.
|
| 832 |
+
|
| 833 |
+
**DAG (Directed Acyclic Graph)**: A data structure where nodes are connected by arrows (directed), and there are no circular paths (acyclic). Used here to model which activities must finish before others can start.
|
| 834 |
+
|
| 835 |
+
**Delay Ratio**: Actual duration divided by planned duration. A ratio of 1.0 means on-time; 1.5 means 50% over schedule.
|
| 836 |
+
|
| 837 |
+
**Ensemble**: A prediction that combines multiple independent models or methods by averaging or weighting their outputs, typically more accurate than any single method alone.
|
| 838 |
+
|
| 839 |
+
**Earned Value**: A project management concept where "earned value" represents the planned value of work actually completed. Used here as the basis for Method A extrapolation.
|
| 840 |
+
|
| 841 |
+
**Float (Total Float)**: The number of days an activity can be delayed without pushing the project end date. Critical path activities have a float of zero.
|
| 842 |
+
|
| 843 |
+
**GradientBoostingRegressor**: A machine learning algorithm that builds an ensemble of decision trees sequentially, each one correcting the errors of the previous. Effective for tabular data with numerical targets.
|
| 844 |
+
|
| 845 |
+
**Monte Carlo Simulation**: A computational technique that runs thousands of random scenarios to estimate the probability distribution of an outcome, rather than producing a single point prediction.
|
| 846 |
+
|
| 847 |
+
**P50 / P80 / P90**: Percentile values from a probability distribution. P80 means 80% of simulated scenarios finish by that date.
|
| 848 |
+
|
| 849 |
+
**Predecessor**: An activity that must finish before a given activity can start.
|
| 850 |
+
|
| 851 |
+
**Ripple Effect**: The cascade of delays that propagates through downstream activities when one activity is delayed.
|
| 852 |
+
|
| 853 |
+
**SQLite**: A file-based relational database engine. The entire database lives in a single file (`data.db`) and requires no server installation.
|
| 854 |
+
|
| 855 |
+
**Streamlit**: A Python library that converts a Python script into a browser-accessible interactive web application.
|
| 856 |
+
|
| 857 |
+
**Topological Sort**: An ordering of nodes in a DAG such that for every directed edge from A to B, A comes before B in the ordering. Used to ensure activities are processed in dependency order.
|
__pycache__/app.cpython-311.pyc
ADDED
|
Binary file (42.9 kB). View file
|
|
|
__pycache__/data_loader.cpython-311.pyc
ADDED
|
Binary file (11.1 kB). View file
|
|
|
__pycache__/data_loader.cpython-312.pyc
ADDED
|
Binary file (10.3 kB). View file
|
|
|
app.py
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
app.py -- What-if Scheduling System | Streamlit Dashboard
|
| 3 |
+
7 Tabs: Overview . Gantt . Predictions . Ripple Analysis . What-if . Optimization . DAG
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import sys, os
|
| 7 |
+
sys.path.insert(0, os.path.dirname(__file__))
|
| 8 |
+
|
| 9 |
+
import streamlit as st
|
| 10 |
+
import pandas as pd
|
| 11 |
+
import numpy as np
|
| 12 |
+
import plotly.graph_objects as go
|
| 13 |
+
from datetime import datetime, timedelta
|
| 14 |
+
|
| 15 |
+
from data_loader import DataLoader
|
| 16 |
+
from models.completion_predictor import CompletionPredictor
|
| 17 |
+
from models.monte_carlo import MonteCarloSimulator
|
| 18 |
+
from engine.dag_builder import build_dag, get_descendants
|
| 19 |
+
from engine.ripple_engine import RippleEngine
|
| 20 |
+
from engine.whatif_scenarios import WhatIfScenarioEngine
|
| 21 |
+
from optimizer.schedule_optimizer import ScheduleOptimizer
|
| 22 |
+
from visualization.gantt import build_gantt
|
| 23 |
+
from visualization.dag_viz import build_dag_figure
|
| 24 |
+
|
| 25 |
+
# ββ Page Config βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 26 |
+
st.set_page_config(
|
| 27 |
+
page_title="What-if Scheduler",
|
| 28 |
+
page_icon="π
",
|
| 29 |
+
layout="wide",
|
| 30 |
+
initial_sidebar_state="expanded",
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
# ββ CSS βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 34 |
+
st.markdown("""
|
| 35 |
+
<style>
|
| 36 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
| 37 |
+
|
| 38 |
+
html, body, [class*="css"] {
|
| 39 |
+
font-family: 'Inter', sans-serif;
|
| 40 |
+
background-color: #0f172a;
|
| 41 |
+
color: #e2e8f0;
|
| 42 |
+
}
|
| 43 |
+
.stApp { background-color: #0f172a; }
|
| 44 |
+
section[data-testid="stSidebar"] { background-color: #1e293b; border-right: 1px solid #334155; }
|
| 45 |
+
|
| 46 |
+
.kpi-card {
|
| 47 |
+
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
| 48 |
+
border: 1px solid #334155;
|
| 49 |
+
border-radius: 12px;
|
| 50 |
+
padding: 18px 20px;
|
| 51 |
+
text-align: center;
|
| 52 |
+
transition: transform 0.2s, box-shadow 0.2s;
|
| 53 |
+
margin-bottom: 8px;
|
| 54 |
+
}
|
| 55 |
+
.kpi-card:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.4); }
|
| 56 |
+
.kpi-value { font-size: 2.2rem; font-weight: 700; line-height: 1; margin-bottom: 4px; }
|
| 57 |
+
.kpi-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em; color: #94a3b8; }
|
| 58 |
+
|
| 59 |
+
.section-header {
|
| 60 |
+
font-size: 1.1rem; font-weight: 600; color: #f1f5f9;
|
| 61 |
+
border-left: 4px solid #6366f1; padding-left: 12px; margin: 16px 0 10px 0;
|
| 62 |
+
}
|
| 63 |
+
.suggestion-card {
|
| 64 |
+
background: #1e293b; border: 1px solid #334155; border-radius: 10px;
|
| 65 |
+
padding: 14px 16px; margin-bottom: 10px;
|
| 66 |
+
}
|
| 67 |
+
.suggestion-card.critical { border-left: 4px solid #ef4444; }
|
| 68 |
+
.suggestion-card.high { border-left: 4px solid #f97316; }
|
| 69 |
+
.suggestion-card.medium { border-left: 4px solid #fbbf24; }
|
| 70 |
+
.suggestion-card.opport { border-left: 4px solid #22c55e; }
|
| 71 |
+
|
| 72 |
+
div[data-testid="stMetric"] { background: #1e293b; border-radius: 10px; padding: 12px 16px; }
|
| 73 |
+
.stTabs [data-baseweb="tab"] { background: #1e293b; color: #94a3b8; }
|
| 74 |
+
.stTabs [data-baseweb="tab"][aria-selected="true"] { background: #312e81; color: #e0e7ff; }
|
| 75 |
+
|
| 76 |
+
.dataframe thead th { background-color: #1e293b !important; color: #a5b4fc !important; }
|
| 77 |
+
.dataframe tbody tr:nth-child(odd) { background-color: #0f172a !important; }
|
| 78 |
+
.dataframe tbody tr:nth-child(even) { background-color: #1a2437 !important; }
|
| 79 |
+
</style>
|
| 80 |
+
""", unsafe_allow_html=True)
|
| 81 |
+
|
| 82 |
+
# ββ Caching βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 83 |
+
@st.cache_resource(show_spinner="Loading data...")
|
| 84 |
+
def get_loader():
|
| 85 |
+
return DataLoader()
|
| 86 |
+
|
| 87 |
+
@st.cache_resource(show_spinner="Training ML model...")
|
| 88 |
+
def get_predictor():
|
| 89 |
+
dl = get_loader()
|
| 90 |
+
cp = CompletionPredictor(loader=dl)
|
| 91 |
+
metrics = cp.train()
|
| 92 |
+
return cp, metrics
|
| 93 |
+
|
| 94 |
+
@st.cache_resource(show_spinner="Running predictions...", ttl=300)
|
| 95 |
+
def get_predictions(project_id):
|
| 96 |
+
cp, _ = get_predictor()
|
| 97 |
+
return cp.predict_all(project_id=project_id)
|
| 98 |
+
|
| 99 |
+
@st.cache_resource(show_spinner="Running Monte Carlo...", ttl=300)
|
| 100 |
+
def get_mc_results(project_id):
|
| 101 |
+
dl = get_loader()
|
| 102 |
+
mc = MonteCarloSimulator(loader=dl, n_sims=500)
|
| 103 |
+
return mc.simulate_all(project_id=project_id)
|
| 104 |
+
|
| 105 |
+
@st.cache_resource(show_spinner="Loading optimizer...", ttl=300)
|
| 106 |
+
def _get_optimizer(project_id):
|
| 107 |
+
dl = get_loader()
|
| 108 |
+
opt = ScheduleOptimizer(project_id, loader=dl)
|
| 109 |
+
opt.compute_cpm()
|
| 110 |
+
return opt
|
| 111 |
+
|
| 112 |
+
def get_cpm(project_id):
|
| 113 |
+
opt = _get_optimizer(project_id)
|
| 114 |
+
cpm_df = opt._cpm_results if opt._cpm_results is not None else opt.compute_cpm()
|
| 115 |
+
cp_ids = opt.get_critical_path()
|
| 116 |
+
return cpm_df, cp_ids, opt
|
| 117 |
+
|
| 118 |
+
# ββ Sidebar βββββββββββββββββββββββββββββββββββββββββοΏ½οΏ½οΏ½βββββββββββββββββββββββββ
|
| 119 |
+
loader = get_loader()
|
| 120 |
+
st.sidebar.markdown("## What-if Scheduler")
|
| 121 |
+
st.sidebar.markdown("---")
|
| 122 |
+
|
| 123 |
+
projs = loader.projects
|
| 124 |
+
if projs.empty:
|
| 125 |
+
st.error("No project data found. Run `python dataset.py` first.")
|
| 126 |
+
st.stop()
|
| 127 |
+
|
| 128 |
+
proj_name_map = {
|
| 129 |
+
row["id"]: (
|
| 130 |
+
"In Progress " if row.get("status") == "in_progress" else
|
| 131 |
+
"Completed " if row.get("status") == "completed" else
|
| 132 |
+
"Not Started "
|
| 133 |
+
) + f"{row.get('name', row['id'])} ({row['id']})"
|
| 134 |
+
for _, row in projs.iterrows()
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
inprog = projs[projs["status"] == "in_progress"]
|
| 138 |
+
default_proj = inprog.iloc[0]["id"] if not inprog.empty else projs.iloc[0]["id"]
|
| 139 |
+
|
| 140 |
+
selected_pid = st.sidebar.selectbox(
|
| 141 |
+
"Select Project",
|
| 142 |
+
options=list(proj_name_map.keys()),
|
| 143 |
+
format_func=lambda x: proj_name_map[x],
|
| 144 |
+
index=list(proj_name_map.keys()).index(default_proj) if default_proj in proj_name_map else 0,
|
| 145 |
+
)
|
| 146 |
+
|
| 147 |
+
ref_date = st.sidebar.date_input(
|
| 148 |
+
"Reference Date (Today)",
|
| 149 |
+
value=datetime(2024, 6, 1).date(),
|
| 150 |
+
min_value=datetime(2022, 1, 1).date(),
|
| 151 |
+
max_value=datetime(2026, 12, 31).date(),
|
| 152 |
+
)
|
| 153 |
+
today = datetime.combine(ref_date, datetime.min.time())
|
| 154 |
+
|
| 155 |
+
st.sidebar.markdown("---")
|
| 156 |
+
selected_proj = projs[projs["id"] == selected_pid].iloc[0]
|
| 157 |
+
st.sidebar.markdown(f"**Name:** {selected_proj.get('name', '-')}")
|
| 158 |
+
st.sidebar.markdown(f"**Status:** {selected_proj.get('status', '-').replace('_',' ').title()}")
|
| 159 |
+
st.sidebar.markdown(f"**Type:** {selected_proj.get('type', '-').title()}")
|
| 160 |
+
st.sidebar.markdown(f"**City:** {selected_proj.get('city', '-')}")
|
| 161 |
+
|
| 162 |
+
_, train_metrics = get_predictor()
|
| 163 |
+
if train_metrics:
|
| 164 |
+
st.sidebar.markdown("---")
|
| 165 |
+
st.sidebar.markdown("**Model Health**")
|
| 166 |
+
st.sidebar.caption(f"Train samples: {train_metrics.get('n_train', '-')}")
|
| 167 |
+
st.sidebar.caption(f"CV MAE: {train_metrics.get('cv_mae_mean', '-'):.3f} +/- {train_metrics.get('cv_mae_std', '-'):.3f}")
|
| 168 |
+
|
| 169 |
+
# ββ Tabs ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 170 |
+
st.markdown(f"## What-if Schedule Predictor -- *{selected_proj.get('name', selected_pid)}*")
|
| 171 |
+
|
| 172 |
+
tabs = st.tabs([
|
| 173 |
+
"Overview",
|
| 174 |
+
"Gantt Chart",
|
| 175 |
+
"Predictions",
|
| 176 |
+
"Ripple Analysis",
|
| 177 |
+
"What-if Scenarios",
|
| 178 |
+
"Optimization",
|
| 179 |
+
"DAG View",
|
| 180 |
+
])
|
| 181 |
+
|
| 182 |
+
acts = loader.get_project_activities(selected_pid)
|
| 183 |
+
preds = get_predictions(selected_pid) if selected_proj.get("status") in ("in_progress", "not_started") else pd.DataFrame()
|
| 184 |
+
cpm_df, cp_ids, optimizer = get_cpm(selected_pid)
|
| 185 |
+
|
| 186 |
+
# βββββββββββββββββββββββββββββββββββββββββ TAB 0: OVERVIEW ββββββββββββββββββββ
|
| 187 |
+
with tabs[0]:
|
| 188 |
+
st.markdown('<div class="section-header">Project At a Glance</div>', unsafe_allow_html=True)
|
| 189 |
+
|
| 190 |
+
in_prog_acts = acts[acts["status"] == "in_progress"]
|
| 191 |
+
completed_acts = acts[acts["status"] == "completed"]
|
| 192 |
+
completed_n = len(completed_acts)
|
| 193 |
+
in_prog_n = len(in_prog_acts)
|
| 194 |
+
|
| 195 |
+
avg_progress = float(acts["progress"].fillna(0).mean()) if "progress" in acts.columns else 0
|
| 196 |
+
|
| 197 |
+
all_issues = loader.get_activity_issues(project_id=selected_pid)
|
| 198 |
+
open_issues = (
|
| 199 |
+
all_issues[all_issues["status"] == "open"]
|
| 200 |
+
if not all_issues.empty and "status" in all_issues.columns
|
| 201 |
+
else pd.DataFrame()
|
| 202 |
+
)
|
| 203 |
+
critical_issues = (
|
| 204 |
+
open_issues[open_issues["severity"].isin(["high", "critical"])]
|
| 205 |
+
if not open_issues.empty and "severity" in open_issues.columns
|
| 206 |
+
else pd.DataFrame()
|
| 207 |
+
)
|
| 208 |
+
|
| 209 |
+
sched_var = float(acts["schedule_variance_days"].dropna().mean()) if "schedule_variance_days" in acts.columns else 0
|
| 210 |
+
boq_df = loader.get_project_boq(selected_pid)
|
| 211 |
+
|
| 212 |
+
cols_kpi = st.columns(6)
|
| 213 |
+
kpi_data = [
|
| 214 |
+
(f"{avg_progress:.0f}%", "Overall Progress", "#6366f1"),
|
| 215 |
+
(str(completed_n), "Activities Done", "#22c55e"),
|
| 216 |
+
(str(in_prog_n), "In Progress", "#f59e0b"),
|
| 217 |
+
(str(len(open_issues)), "Open Issues", "#f97316"),
|
| 218 |
+
(str(len(critical_issues)), "Critical Issues", "#ef4444"),
|
| 219 |
+
(f"{sched_var:+.0f}d", "Avg Schedule Var.", "#8b5cf6"),
|
| 220 |
+
]
|
| 221 |
+
for col, (val, label, color) in zip(cols_kpi, kpi_data):
|
| 222 |
+
col.markdown(f"""
|
| 223 |
+
<div class="kpi-card">
|
| 224 |
+
<div class="kpi-value" style="color:{color}">{val}</div>
|
| 225 |
+
<div class="kpi-label">{label}</div>
|
| 226 |
+
</div>
|
| 227 |
+
""", unsafe_allow_html=True)
|
| 228 |
+
|
| 229 |
+
st.markdown("---")
|
| 230 |
+
col_l, col_r = st.columns([3, 2])
|
| 231 |
+
|
| 232 |
+
with col_l:
|
| 233 |
+
st.markdown('<div class="section-header">Activity Status Breakdown</div>', unsafe_allow_html=True)
|
| 234 |
+
status_counts = acts["status"].value_counts().reset_index()
|
| 235 |
+
status_counts.columns = ["Status", "Count"]
|
| 236 |
+
STATUS_COLOR_MAP = {"completed": "#22c55e", "in_progress": "#f59e0b", "not_started": "#64748b"}
|
| 237 |
+
colors = [STATUS_COLOR_MAP.get(s, "#94a3b8") for s in status_counts["Status"]]
|
| 238 |
+
fig_status = go.Figure(go.Pie(
|
| 239 |
+
labels=status_counts["Status"],
|
| 240 |
+
values=status_counts["Count"],
|
| 241 |
+
marker=dict(colors=colors, line=dict(color="#0f172a", width=2)),
|
| 242 |
+
hole=0.5,
|
| 243 |
+
textinfo="percent+label",
|
| 244 |
+
))
|
| 245 |
+
fig_status.update_layout(
|
| 246 |
+
paper_bgcolor="#0f172a", font=dict(color="#e2e8f0"),
|
| 247 |
+
height=300, showlegend=False, margin=dict(t=20, b=20, l=20, r=20),
|
| 248 |
+
)
|
| 249 |
+
st.plotly_chart(fig_status, use_container_width=True)
|
| 250 |
+
|
| 251 |
+
with col_r:
|
| 252 |
+
st.markdown('<div class="section-header">Progress by Category</div>', unsafe_allow_html=True)
|
| 253 |
+
if "category" in acts.columns and "progress" in acts.columns:
|
| 254 |
+
cat_prog = acts.groupby("category")["progress"].mean().reset_index()
|
| 255 |
+
fig_cat = go.Figure(go.Bar(
|
| 256 |
+
x=cat_prog["progress"].round(0),
|
| 257 |
+
y=cat_prog["category"],
|
| 258 |
+
orientation="h",
|
| 259 |
+
marker=dict(color=cat_prog["progress"], colorscale="RdYlGn", showscale=False),
|
| 260 |
+
text=cat_prog["progress"].round(0).astype(str) + "%",
|
| 261 |
+
textposition="auto",
|
| 262 |
+
))
|
| 263 |
+
fig_cat.update_layout(
|
| 264 |
+
paper_bgcolor="#0f172a", plot_bgcolor="#0f172a",
|
| 265 |
+
font=dict(color="#e2e8f0"), height=300,
|
| 266 |
+
margin=dict(t=10, b=10, l=10, r=10),
|
| 267 |
+
xaxis=dict(range=[0, 105]),
|
| 268 |
+
)
|
| 269 |
+
st.plotly_chart(fig_cat, use_container_width=True)
|
| 270 |
+
|
| 271 |
+
st.markdown('<div class="section-header">Activity List</div>', unsafe_allow_html=True)
|
| 272 |
+
display_cols = ["id", "name", "category", "status", "progress",
|
| 273 |
+
"planned_start_date", "planned_end_date", "schedule_variance_days"]
|
| 274 |
+
disp_acts = acts[[c for c in display_cols if c in acts.columns]].copy()
|
| 275 |
+
disp_acts["progress"] = disp_acts["progress"].fillna(0).round(1)
|
| 276 |
+
st.dataframe(disp_acts, use_container_width=True, height=280)
|
| 277 |
+
|
| 278 |
+
# ββββββββββββββββββββββββββββββββββββββββββ TAB 1: GANTT ββββββββββββββββββββββ
|
| 279 |
+
with tabs[1]:
|
| 280 |
+
st.markdown('<div class="section-header">Gantt Chart -- Planned vs Actual vs Forecast</div>', unsafe_allow_html=True)
|
| 281 |
+
gantt_fig = build_gantt(
|
| 282 |
+
selected_pid, loader=loader,
|
| 283 |
+
predictions_df=preds,
|
| 284 |
+
critical_path_ids=cp_ids,
|
| 285 |
+
today=today,
|
| 286 |
+
)
|
| 287 |
+
st.plotly_chart(gantt_fig, use_container_width=True)
|
| 288 |
+
st.caption("Critical path activities have a red prefix | Blue = Planned | Green = Actual | Amber = Forecasted")
|
| 289 |
+
|
| 290 |
+
# ββββββββββββββββββββββββββββββββββββββ TAB 2: PREDICTIONS ββββββββββββββββββββ
|
| 291 |
+
with tabs[2]:
|
| 292 |
+
st.markdown('<div class="section-header">Completion Date Predictions</div>', unsafe_allow_html=True)
|
| 293 |
+
if preds.empty:
|
| 294 |
+
st.info("No active activities to predict for this project (all may be completed).")
|
| 295 |
+
else:
|
| 296 |
+
mc_results = get_mc_results(selected_pid)
|
| 297 |
+
|
| 298 |
+
disp_preds = preds.copy()
|
| 299 |
+
for col in ["methodA_end", "methodB_end", "ensemble_end"]:
|
| 300 |
+
if col in disp_preds.columns:
|
| 301 |
+
disp_preds[col] = pd.to_datetime(disp_preds[col], errors="coerce").dt.strftime("%Y-%m-%d")
|
| 302 |
+
|
| 303 |
+
table_cols = ["activity_id", "activity_name", "progress", "planned_end_date",
|
| 304 |
+
"methodA_end", "methodB_end", "ensemble_end",
|
| 305 |
+
"delay_multiplier_pred", "issue_count", "schedule_variance"]
|
| 306 |
+
st.dataframe(
|
| 307 |
+
disp_preds[[c for c in table_cols if c in disp_preds.columns]],
|
| 308 |
+
use_container_width=True, height=260,
|
| 309 |
+
)
|
| 310 |
+
|
| 311 |
+
st.markdown("---")
|
| 312 |
+
st.markdown('<div class="section-header">Monte Carlo Simulation -- Completion Distribution</div>', unsafe_allow_html=True)
|
| 313 |
+
|
| 314 |
+
if not mc_results.empty:
|
| 315 |
+
mc_sel_col, mc_display_col = st.columns([2, 3])
|
| 316 |
+
with mc_sel_col:
|
| 317 |
+
mc_act_options = {
|
| 318 |
+
row["activity_id"]: f"{row.get('activity_name', row['activity_id'])} ({row['activity_id']})"
|
| 319 |
+
for _, row in mc_results.iterrows()
|
| 320 |
+
}
|
| 321 |
+
selected_mc_act = st.selectbox(
|
| 322 |
+
"Select Activity for MC Histogram",
|
| 323 |
+
options=list(mc_act_options.keys()),
|
| 324 |
+
format_func=lambda x: mc_act_options[x],
|
| 325 |
+
)
|
| 326 |
+
mc_row = mc_results[mc_results["activity_id"] == selected_mc_act].iloc[0]
|
| 327 |
+
st.metric("P50 (Median)", str(mc_row["p50_date"])[:10])
|
| 328 |
+
st.metric("P80 (Cautious)", str(mc_row["p80_date"])[:10])
|
| 329 |
+
st.metric("P90 (Conservative)", str(mc_row["p90_date"])[:10])
|
| 330 |
+
st.metric("Avg days to complete", f"{mc_row['mean_days_to_complete']:.0f} days")
|
| 331 |
+
|
| 332 |
+
with mc_display_col:
|
| 333 |
+
dl_mc = get_loader()
|
| 334 |
+
mc_sim = MonteCarloSimulator(loader=dl_mc, n_sims=500)
|
| 335 |
+
prog_mc = float(mc_row.get("current_progress", 0))
|
| 336 |
+
dist = mc_sim.get_distribution_for_plot(selected_mc_act, prog_mc)
|
| 337 |
+
|
| 338 |
+
fig_mc = go.Figure()
|
| 339 |
+
fig_mc.add_trace(go.Histogram(
|
| 340 |
+
x=dist, nbinsx=30,
|
| 341 |
+
marker=dict(color="#6366f1", opacity=0.8, line=dict(color="#e0e7ff", width=0.5)),
|
| 342 |
+
name="Simulations",
|
| 343 |
+
))
|
| 344 |
+
p50 = int(mc_row["p50_days"])
|
| 345 |
+
p80 = int(mc_row["p80_days"])
|
| 346 |
+
p90 = int(mc_row["p90_days"])
|
| 347 |
+
for day, label, color in [(p50, "P50", "#22c55e"), (p80, "P80", "#f59e0b"), (p90, "P90", "#ef4444")]:
|
| 348 |
+
fig_mc.add_vline(x=day, line=dict(color=color, dash="dash", width=2),
|
| 349 |
+
annotation_text=label, annotation_position="top")
|
| 350 |
+
fig_mc.update_layout(
|
| 351 |
+
paper_bgcolor="#0f172a", plot_bgcolor="#0f172a", font=dict(color="#e2e8f0"),
|
| 352 |
+
xaxis_title="Days to Completion", yaxis_title="Simulations",
|
| 353 |
+
height=320, margin=dict(t=30, b=30), showlegend=False,
|
| 354 |
+
)
|
| 355 |
+
st.plotly_chart(fig_mc, use_container_width=True)
|
| 356 |
+
|
| 357 |
+
cp_obj, _ = get_predictor()
|
| 358 |
+
if hasattr(cp_obj, "feature_importances_") and cp_obj.feature_importances_ is not None:
|
| 359 |
+
st.markdown("---")
|
| 360 |
+
st.markdown('<div class="section-header">Feature Importances (GradientBoosting)</div>', unsafe_allow_html=True)
|
| 361 |
+
fi = cp_obj.feature_importances_.head(10).reset_index()
|
| 362 |
+
fi.columns = ["Feature", "Importance"]
|
| 363 |
+
fig_fi = go.Figure(go.Bar(
|
| 364 |
+
x=fi["Importance"], y=fi["Feature"], orientation="h",
|
| 365 |
+
marker=dict(color="#818cf8"),
|
| 366 |
+
))
|
| 367 |
+
fig_fi.update_layout(
|
| 368 |
+
paper_bgcolor="#0f172a", plot_bgcolor="#0f172a",
|
| 369 |
+
font=dict(color="#e2e8f0"), height=300,
|
| 370 |
+
margin=dict(t=10, b=10, l=10, r=10),
|
| 371 |
+
yaxis=dict(autorange="reversed"),
|
| 372 |
+
)
|
| 373 |
+
st.plotly_chart(fig_fi, use_container_width=True)
|
| 374 |
+
|
| 375 |
+
# βββββββββββββββββββββββββββββββββββ TAB 3: RIPPLE ANALYSIS βββββββββββββββββββ
|
| 376 |
+
with tabs[3]:
|
| 377 |
+
st.markdown('<div class="section-header">Ripple Effect -- Delay Propagation</div>', unsafe_allow_html=True)
|
| 378 |
+
|
| 379 |
+
G = build_dag(selected_pid, loader=loader)
|
| 380 |
+
ripple_engine = RippleEngine(G, loader=loader)
|
| 381 |
+
|
| 382 |
+
act_options = {
|
| 383 |
+
str(row["id"]): f"{row.get('name', row['id'])} [{row.get('status', '-')}]"
|
| 384 |
+
for _, row in acts.iterrows()
|
| 385 |
+
}
|
| 386 |
+
col_sel, col_delta = st.columns([3, 1])
|
| 387 |
+
with col_sel:
|
| 388 |
+
ripple_act = st.selectbox("Activity to delay:", options=list(act_options.keys()),
|
| 389 |
+
format_func=lambda x: act_options[x])
|
| 390 |
+
with col_delta:
|
| 391 |
+
ripple_days = st.number_input("Delay (days)", min_value=-30, max_value=90, value=7, step=1)
|
| 392 |
+
|
| 393 |
+
if st.button("Run Ripple Simulation", type="primary"):
|
| 394 |
+
with st.spinner("Propagating delay..."):
|
| 395 |
+
result = ripple_engine.propagate_delay(ripple_act, ripple_days, reference_date=today)
|
| 396 |
+
|
| 397 |
+
r_col1, r_col2, r_col3 = st.columns(3)
|
| 398 |
+
r_col1.metric("Activities Affected", result["num_activities_affected"])
|
| 399 |
+
orig_end = result.get("original_project_end")
|
| 400 |
+
new_end = result.get("new_project_end")
|
| 401 |
+
r_col2.metric("Original Project End", str(orig_end)[:10] if orig_end else "N/A")
|
| 402 |
+
r_col3.metric("New Project End", str(new_end)[:10] if new_end else "N/A",
|
| 403 |
+
delta=f"{result['total_project_delay_days']:+d} days",
|
| 404 |
+
delta_color="inverse")
|
| 405 |
+
|
| 406 |
+
cascade = result["cascade_table"]
|
| 407 |
+
if not cascade.empty:
|
| 408 |
+
st.markdown('<div class="section-header">Cascade Impact Table</div>', unsafe_allow_html=True)
|
| 409 |
+
display_cascade = cascade.copy()
|
| 410 |
+
for dcol in ["original_start", "original_end", "new_start", "new_end"]:
|
| 411 |
+
if dcol in display_cascade.columns:
|
| 412 |
+
display_cascade[dcol] = pd.to_datetime(display_cascade[dcol], errors="coerce").dt.strftime("%Y-%m-%d")
|
| 413 |
+
st.dataframe(display_cascade, use_container_width=True)
|
| 414 |
+
|
| 415 |
+
fig_ripple = go.Figure(go.Bar(
|
| 416 |
+
x=cascade["cascade_delay_days"],
|
| 417 |
+
y=cascade["activity_name"],
|
| 418 |
+
orientation="h",
|
| 419 |
+
marker=dict(
|
| 420 |
+
color=cascade["cascade_delay_days"],
|
| 421 |
+
colorscale="RdYlGn_r",
|
| 422 |
+
showscale=True,
|
| 423 |
+
colorbar=dict(title="Days delayed"),
|
| 424 |
+
),
|
| 425 |
+
))
|
| 426 |
+
fig_ripple.update_layout(
|
| 427 |
+
paper_bgcolor="#0f172a", plot_bgcolor="#0f172a",
|
| 428 |
+
font=dict(color="#e2e8f0"),
|
| 429 |
+
xaxis_title="Cascade Delay (days)",
|
| 430 |
+
height=max(250, len(cascade) * 35),
|
| 431 |
+
margin=dict(t=10, b=10),
|
| 432 |
+
title="Cascade Delay per Activity",
|
| 433 |
+
yaxis=dict(autorange="reversed"),
|
| 434 |
+
)
|
| 435 |
+
st.plotly_chart(fig_ripple, use_container_width=True)
|
| 436 |
+
else:
|
| 437 |
+
st.info("No downstream activities affected by this delay.")
|
| 438 |
+
|
| 439 |
+
st.markdown("---")
|
| 440 |
+
st.markdown('<div class="section-header">Top 5 High-Impact Activities (most downstream dependencies)</div>', unsafe_allow_html=True)
|
| 441 |
+
top5 = ripple_engine.get_high_impact_activities()
|
| 442 |
+
if not top5.empty:
|
| 443 |
+
st.dataframe(top5, use_container_width=True)
|
| 444 |
+
|
| 445 |
+
# ββββββββββββββββββββββββββββββββββ TAB 4: WHAT-IF SCENARIOS ββββββββββββββββββ
|
| 446 |
+
with tabs[4]:
|
| 447 |
+
st.markdown('<div class="section-header">What-if Scenario Builder</div>', unsafe_allow_html=True)
|
| 448 |
+
|
| 449 |
+
if "scenario_engine" not in st.session_state or st.session_state.get("scenario_project") != selected_pid:
|
| 450 |
+
st.session_state.scenario_engine = WhatIfScenarioEngine(
|
| 451 |
+
selected_pid, loader=loader, reference_date=today
|
| 452 |
+
)
|
| 453 |
+
st.session_state.scenario_project = selected_pid
|
| 454 |
+
|
| 455 |
+
engine = st.session_state.scenario_engine
|
| 456 |
+
|
| 457 |
+
scen_type = st.radio(
|
| 458 |
+
"Scenario Type:",
|
| 459 |
+
["Delay", "Resource Boost", "Issue Resolved", "Parallelize"],
|
| 460 |
+
horizontal=True,
|
| 461 |
+
)
|
| 462 |
+
|
| 463 |
+
s_col1, s_col2 = st.columns([3, 1])
|
| 464 |
+
|
| 465 |
+
if scen_type == "Delay":
|
| 466 |
+
with s_col1:
|
| 467 |
+
delay_act = st.selectbox("Activity to delay:", options=list(act_options.keys()),
|
| 468 |
+
format_func=lambda x: act_options[x], key="scen_delay_act")
|
| 469 |
+
with s_col2:
|
| 470 |
+
delay_d = st.number_input("Days delayed:", 1, 60, 7, key="scen_delay_days")
|
| 471 |
+
if st.button("Add Delay Scenario", type="primary"):
|
| 472 |
+
engine.scenario_delay(delay_act, delay_d)
|
| 473 |
+
st.success(f"Scenario added: delay {delay_act} by {delay_d} days")
|
| 474 |
+
|
| 475 |
+
elif scen_type == "Resource Boost":
|
| 476 |
+
with s_col1:
|
| 477 |
+
boost_act = st.selectbox("Activity to boost:", options=list(act_options.keys()),
|
| 478 |
+
format_func=lambda x: act_options[x], key="scen_boost_act")
|
| 479 |
+
with s_col2:
|
| 480 |
+
boost_pct = st.slider("Duration reduction %:", 10, 50, 25, key="scen_boost_pct")
|
| 481 |
+
if st.button("Add Resource Boost Scenario", type="primary"):
|
| 482 |
+
engine.scenario_resource_boost(boost_act, boost_pct)
|
| 483 |
+
st.success(f"Scenario added: boost {boost_act} by {boost_pct}%")
|
| 484 |
+
|
| 485 |
+
elif scen_type == "Issue Resolved":
|
| 486 |
+
all_iss = loader.get_activity_issues(project_id=selected_pid)
|
| 487 |
+
if all_iss.empty:
|
| 488 |
+
st.info("No issues found for this project.")
|
| 489 |
+
else:
|
| 490 |
+
open_iss = all_iss[all_iss["status"] == "open"] if "status" in all_iss.columns else all_iss
|
| 491 |
+
if open_iss.empty:
|
| 492 |
+
st.info("No open issues found.")
|
| 493 |
+
else:
|
| 494 |
+
issue_options = {
|
| 495 |
+
str(row["id"]): (
|
| 496 |
+
f"{row.get('id','-')} -- {row.get('category','-')}"
|
| 497 |
+
f" [{row.get('severity','-')}] -- {row.get('delay_impact_days', 0):.0f}d impact"
|
| 498 |
+
)
|
| 499 |
+
for _, row in open_iss.iterrows()
|
| 500 |
+
}
|
| 501 |
+
with s_col1:
|
| 502 |
+
sel_issue = st.selectbox("Issue to resolve:", options=list(issue_options.keys()),
|
| 503 |
+
format_func=lambda x: issue_options[x])
|
| 504 |
+
if st.button("Add Issue Resolved Scenario", type="primary"):
|
| 505 |
+
engine.scenario_issue_resolved(sel_issue)
|
| 506 |
+
st.success(f"Scenario added: resolved issue {sel_issue}")
|
| 507 |
+
|
| 508 |
+
elif scen_type == "Parallelize":
|
| 509 |
+
with s_col1:
|
| 510 |
+
par_a = st.selectbox("Activity A:", options=list(act_options.keys()),
|
| 511 |
+
format_func=lambda x: act_options[x], key="par_a")
|
| 512 |
+
with s_col2:
|
| 513 |
+
par_b = st.selectbox("Activity B:", options=list(act_options.keys()),
|
| 514 |
+
format_func=lambda x: act_options[x], key="par_b")
|
| 515 |
+
if st.button("Add Parallelization Scenario", type="primary"):
|
| 516 |
+
engine.scenario_parallelize(par_a, par_b)
|
| 517 |
+
st.success(f"Scenario added: parallelize {par_a} + {par_b}")
|
| 518 |
+
|
| 519 |
+
comparison = engine.get_scenario_comparison()
|
| 520 |
+
if not comparison.empty:
|
| 521 |
+
st.markdown("---")
|
| 522 |
+
st.markdown('<div class="section-header">Scenario Comparison</div>', unsafe_allow_html=True)
|
| 523 |
+
disp_comp = comparison.copy()
|
| 524 |
+
for dcol in ["original_project_end", "new_project_end"]:
|
| 525 |
+
if dcol in disp_comp.columns:
|
| 526 |
+
disp_comp[dcol] = pd.to_datetime(disp_comp[dcol], errors="coerce").dt.strftime("%Y-%m-%d")
|
| 527 |
+
st.dataframe(disp_comp[["scenario_id", "type", "description", "original_project_end",
|
| 528 |
+
"new_project_end", "total_project_delay_days", "days_saved",
|
| 529 |
+
"cost_impact_inr"]], use_container_width=True)
|
| 530 |
+
|
| 531 |
+
fig_scen = go.Figure(go.Bar(
|
| 532 |
+
x=comparison["scenario_id"],
|
| 533 |
+
y=comparison["days_saved"],
|
| 534 |
+
marker=dict(color=comparison["days_saved"], colorscale="RdYlGn", showscale=False),
|
| 535 |
+
text=comparison["days_saved"].apply(lambda d: f"{d:+d}d"),
|
| 536 |
+
textposition="auto",
|
| 537 |
+
))
|
| 538 |
+
fig_scen.update_layout(
|
| 539 |
+
paper_bgcolor="#0f172a", plot_bgcolor="#0f172a",
|
| 540 |
+
font=dict(color="#e2e8f0"), height=280,
|
| 541 |
+
xaxis_title="Scenario", yaxis_title="Days Saved (-ve = delay)",
|
| 542 |
+
margin=dict(t=20, b=20),
|
| 543 |
+
)
|
| 544 |
+
st.plotly_chart(fig_scen, use_container_width=True)
|
| 545 |
+
|
| 546 |
+
if st.button("Clear All Scenarios"):
|
| 547 |
+
engine.clear_scenarios()
|
| 548 |
+
st.rerun()
|
| 549 |
+
else:
|
| 550 |
+
st.info("No scenarios yet. Add one above.")
|
| 551 |
+
|
| 552 |
+
# ββββββββββββββββββββββββββββββββββββββ TAB 5: OPTIMIZATION βββββββββββββββββββ
|
| 553 |
+
with tabs[5]:
|
| 554 |
+
st.markdown('<div class="section-header">Critical Path Method (CPM) and Optimization</div>', unsafe_allow_html=True)
|
| 555 |
+
|
| 556 |
+
if cpm_df is not None and not cpm_df.empty:
|
| 557 |
+
cpm_disp = cpm_df.copy()
|
| 558 |
+
cpm_disp["critical"] = cpm_disp["is_critical_path"].map({True: "YES", False: "--"})
|
| 559 |
+
st.dataframe(
|
| 560 |
+
cpm_disp[["activity_name", "planned_duration_days", "early_start_day",
|
| 561 |
+
"early_finish_day", "total_float_days", "progress", "critical"]],
|
| 562 |
+
use_container_width=True, height=280,
|
| 563 |
+
)
|
| 564 |
+
|
| 565 |
+
st.markdown('<div class="section-header">Total Float per Activity (days of flexibility)</div>', unsafe_allow_html=True)
|
| 566 |
+
float_fig = go.Figure(go.Bar(
|
| 567 |
+
x=cpm_df["activity_name"].str[:25],
|
| 568 |
+
y=cpm_df["total_float_days"],
|
| 569 |
+
marker=dict(
|
| 570 |
+
color=cpm_df["total_float_days"],
|
| 571 |
+
colorscale="RdYlGn",
|
| 572 |
+
showscale=True,
|
| 573 |
+
colorbar=dict(title="Float"),
|
| 574 |
+
),
|
| 575 |
+
))
|
| 576 |
+
float_fig.update_layout(
|
| 577 |
+
paper_bgcolor="#0f172a", plot_bgcolor="#0f172a",
|
| 578 |
+
font=dict(color="#e2e8f0"), height=320,
|
| 579 |
+
yaxis_title="Float (days)", xaxis_tickangle=-30,
|
| 580 |
+
margin=dict(t=10, b=80),
|
| 581 |
+
)
|
| 582 |
+
st.plotly_chart(float_fig, use_container_width=True)
|
| 583 |
+
else:
|
| 584 |
+
st.info("CPM computation requires activity dependency data.")
|
| 585 |
+
|
| 586 |
+
st.markdown("---")
|
| 587 |
+
st.markdown('<div class="section-header">Optimization Suggestions</div>', unsafe_allow_html=True)
|
| 588 |
+
|
| 589 |
+
suggestions = optimizer.generate_suggestions(predictions_df=preds)
|
| 590 |
+
if suggestions:
|
| 591 |
+
for sug in suggestions:
|
| 592 |
+
priority = sug["priority"]
|
| 593 |
+
cls = (
|
| 594 |
+
"critical" if "CRITICAL" in priority else
|
| 595 |
+
"high" if "HIGH" in priority else
|
| 596 |
+
"medium" if "MEDIUM" in priority else
|
| 597 |
+
"opport"
|
| 598 |
+
)
|
| 599 |
+
savings = sug.get("estimated_savings_days", 0)
|
| 600 |
+
savings_txt = f" | Potential saving: <strong>{savings} days</strong>" if savings > 0 else ""
|
| 601 |
+
st.markdown(f"""
|
| 602 |
+
<div class="suggestion-card {cls}">
|
| 603 |
+
<strong>{priority} -- {sug['rule']}</strong>{savings_txt}<br/>
|
| 604 |
+
{sug['suggestion']}
|
| 605 |
+
</div>
|
| 606 |
+
""", unsafe_allow_html=True)
|
| 607 |
+
else:
|
| 608 |
+
st.success("No critical optimization issues detected for this project.")
|
| 609 |
+
|
| 610 |
+
# ββββββββββββββββββββββββββββββββββββββ TAB 6: DAG VIEW βββββββββββββββββββββββ
|
| 611 |
+
with tabs[6]:
|
| 612 |
+
st.markdown('<div class="section-header">Activity Dependency Graph</div>', unsafe_allow_html=True)
|
| 613 |
+
|
| 614 |
+
dag_fig = build_dag_figure(
|
| 615 |
+
selected_pid, loader=loader,
|
| 616 |
+
critical_path_ids=cp_ids,
|
| 617 |
+
predictions_df=preds,
|
| 618 |
+
)
|
| 619 |
+
st.plotly_chart(dag_fig, use_container_width=True)
|
| 620 |
+
|
| 621 |
+
st.markdown('<div class="section-header">Dependency Details</div>', unsafe_allow_html=True)
|
| 622 |
+
dep_rows = []
|
| 623 |
+
G_disp = build_dag(selected_pid, loader=loader)
|
| 624 |
+
act_name_map = {str(row["id"]): row.get("name", row["id"]) for _, row in acts.iterrows()}
|
| 625 |
+
for edge in G_disp.edges():
|
| 626 |
+
dep_rows.append({
|
| 627 |
+
"Predecessor": act_name_map.get(edge[0], edge[0]),
|
| 628 |
+
"Successor": act_name_map.get(edge[1], edge[1]),
|
| 629 |
+
"Critical Edge": "YES" if edge[0] in cp_ids and edge[1] in cp_ids else "--",
|
| 630 |
+
})
|
| 631 |
+
if dep_rows:
|
| 632 |
+
st.dataframe(pd.DataFrame(dep_rows), use_container_width=True)
|
| 633 |
+
else:
|
| 634 |
+
st.info("No dependency edges found -- activities may have no depends_on data.")
|
data/activities.csv
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,project_id,project_type,name,category,planned_start_date,planned_end_date,planned_duration_days,actual_start_date,actual_end_date,forecasted_start_date,forecasted_end_date,progress,status,parent_id,depends_on,actual_duration_days,schedule_variance_days
|
| 2 |
+
act_001_01,proj_001,residential,Site Survey & Mobilization,prep,2022-01-10,2022-01-17,7,2022-01-10,2022-01-19,2022-01-10,2022-01-19,100,completed,,,9,0
|
| 3 |
+
act_001_02,proj_001,residential,Demolition & Strip-Out,demo,2022-01-17,2022-01-29,12,2022-01-19,2022-02-01,2022-01-19,2022-02-01,100,completed,,act_001_01,13,2
|
| 4 |
+
act_001_03,proj_001,residential,Structural Repairs & Reinforcement,structural,2022-01-29,2022-02-16,18,2022-02-01,2022-02-20,2022-02-01,2022-02-20,100,completed,,act_001_02,19,3
|
| 5 |
+
act_001_04,proj_001,residential,Waterproofing & Damp Proofing,structural,2022-02-16,2022-02-24,8,2022-02-20,2022-03-01,2022-02-20,2022-03-01,100,completed,,act_001_03,9,4
|
| 6 |
+
act_001_05,proj_001,residential,Plumbing Rough-in,mep,2022-02-16,2022-03-02,14,2022-02-20,2022-03-08,2022-02-20,2022-03-08,100,completed,,act_001_03,16,4
|
| 7 |
+
act_001_06,proj_001,residential,Electrical Wiring & Conduits,mep,2022-02-16,2022-03-02,14,2022-02-20,2022-03-09,2022-02-20,2022-03-09,100,completed,,act_001_03,17,4
|
| 8 |
+
act_001_07,proj_001,residential,HVAC & Ventilation Installation,mep,2022-02-16,2022-02-26,10,2022-02-20,2022-03-05,2022-02-20,2022-03-05,100,completed,,act_001_03,13,4
|
| 9 |
+
act_001_08,proj_001,residential,Floor Leveling & Screed,finishing,2022-03-02,2022-03-12,10,2022-03-08,2022-03-20,2022-03-08,2022-03-20,100,completed,,act_001_05,12,6
|
| 10 |
+
act_001_09,proj_001,residential,Tiling β Floors & Wet Areas,finishing,2022-03-12,2022-03-30,18,2022-03-20,2022-04-10,2022-03-20,2022-04-10,100,completed,,act_001_08,21,8
|
| 11 |
+
act_001_10,proj_001,residential,Wall Plastering & Screeding,finishing,2022-03-02,2022-03-16,14,2022-03-09,2022-03-24,2022-03-09,2022-03-24,100,completed,,act_001_06,15,7
|
| 12 |
+
act_001_11,proj_001,residential,False Ceiling & Insulation,finishing,2022-03-16,2022-03-26,10,2022-03-26,2022-04-08,2022-03-26,2022-04-08,100,completed,,act_001_10,13,10
|
| 13 |
+
act_001_12,proj_001,residential,Painting β Primer & Finish Coats,finishing,2022-03-26,2022-04-09,14,2022-04-08,2022-04-25,2022-04-08,2022-04-25,100,completed,,act_001_11,17,13
|
| 14 |
+
act_001_13,proj_001,residential,"Carpentry, Joinery & Built-ins",finishing,2022-04-09,2022-04-25,16,2022-04-28,2022-05-18,2022-04-28,2022-05-18,100,completed,,act_001_12,20,19
|
| 15 |
+
act_001_14,proj_001,residential,"Fixtures, Fittings & Sanitaryware",finishing,2022-04-25,2022-05-05,10,2022-05-18,2022-05-29,2022-05-18,2022-05-29,100,completed,,act_001_13,11,23
|
| 16 |
+
act_001_15,proj_001,residential,"Final Inspection, Snag & Handover",inspection,2022-05-05,2022-05-11,6,2022-05-29,2022-06-06,2022-05-29,2022-06-06,100,completed,,act_001_14,8,24
|
| 17 |
+
act_002_01,proj_002,commercial,Site Survey & Mobilization,prep,2022-03-01,2022-03-08,7,2022-03-01,2022-03-09,2022-03-01,2022-03-09,100,completed,,,8,0
|
| 18 |
+
act_002_02,proj_002,commercial,Demolition & Strip-Out,demo,2022-03-08,2022-03-20,12,2022-03-10,2022-03-23,2022-03-10,2022-03-23,100,completed,,act_002_01,13,2
|
| 19 |
+
act_002_03,proj_002,commercial,Structural Repairs & Reinforcement,structural,2022-03-20,2022-04-07,18,2022-03-23,2022-04-11,2022-03-23,2022-04-11,100,completed,,act_002_02,19,3
|
| 20 |
+
act_002_04,proj_002,commercial,Waterproofing & Damp Proofing,structural,2022-04-07,2022-04-15,8,2022-04-11,2022-04-20,2022-04-11,2022-04-20,100,completed,,act_002_03,9,4
|
| 21 |
+
act_002_05,proj_002,commercial,Plumbing Rough-in,mep,2022-04-07,2022-04-21,14,2022-04-11,2022-04-26,2022-04-11,2022-04-26,100,completed,,act_002_03,15,4
|
| 22 |
+
act_002_06,proj_002,commercial,Electrical Wiring & Conduits,mep,2022-04-07,2022-04-21,14,2022-04-12,2022-04-28,2022-04-12,2022-04-28,100,completed,,act_002_03,16,5
|
| 23 |
+
act_002_07,proj_002,commercial,HVAC & Ventilation Installation,mep,2022-04-07,2022-04-17,10,2022-04-11,2022-04-22,2022-04-11,2022-04-22,100,completed,,act_002_03,11,4
|
| 24 |
+
act_002_08,proj_002,commercial,Floor Leveling & Screed,finishing,2022-04-21,2022-05-01,10,2022-04-26,2022-05-08,2022-04-26,2022-05-08,100,completed,,act_002_05,12,5
|
| 25 |
+
act_002_09,proj_002,commercial,Tiling β Floors & Wet Areas,finishing,2022-05-01,2022-05-19,18,2022-05-11,2022-05-31,2022-05-11,2022-05-31,100,completed,,act_002_08,20,10
|
| 26 |
+
act_002_10,proj_002,commercial,Wall Plastering & Screeding,finishing,2022-04-21,2022-05-05,14,2022-04-30,2022-05-15,2022-04-30,2022-05-15,100,completed,,act_002_06,15,9
|
| 27 |
+
act_002_11,proj_002,commercial,False Ceiling & Insulation,finishing,2022-05-05,2022-05-15,10,2022-05-16,2022-05-27,2022-05-16,2022-05-27,100,completed,,act_002_10,11,11
|
| 28 |
+
act_002_12,proj_002,commercial,Painting β Primer & Finish Coats,finishing,2022-05-15,2022-05-29,14,2022-05-27,2022-06-11,2022-05-27,2022-06-11,100,completed,,act_002_11,15,12
|
| 29 |
+
act_002_13,proj_002,commercial,"Carpentry, Joinery & Built-ins",finishing,2022-05-29,2022-06-14,16,2022-06-11,2022-06-29,2022-06-11,2022-06-29,100,completed,,act_002_12,18,13
|
| 30 |
+
act_002_14,proj_002,commercial,"Fixtures, Fittings & Sanitaryware",finishing,2022-06-14,2022-06-24,10,2022-06-29,2022-07-10,2022-06-29,2022-07-10,100,completed,,act_002_13,11,15
|
| 31 |
+
act_002_15,proj_002,commercial,"Final Inspection, Snag & Handover",inspection,2022-06-24,2022-06-30,6,2022-07-10,2022-07-17,2022-07-10,2022-07-17,100,completed,,act_002_14,7,16
|
| 32 |
+
act_003_01,proj_003,residential,Site Survey & Mobilization,prep,2022-06-15,2022-06-22,7,2022-06-16,2022-06-25,2022-06-16,2022-06-25,100,completed,,,9,1
|
| 33 |
+
act_003_02,proj_003,residential,Demolition & Strip-Out,demo,2022-06-22,2022-07-04,12,2022-06-25,2022-07-09,2022-06-25,2022-07-09,100,completed,,act_003_01,14,3
|
| 34 |
+
act_003_03,proj_003,residential,Structural Repairs & Reinforcement,structural,2022-07-04,2022-07-22,18,2022-07-12,2022-08-05,2022-07-12,2022-08-05,100,completed,,act_003_02,24,8
|
| 35 |
+
act_003_04,proj_003,residential,Waterproofing & Damp Proofing,structural,2022-07-22,2022-07-30,8,2022-08-05,2022-08-14,2022-08-05,2022-08-14,100,completed,,act_003_03,9,14
|
| 36 |
+
act_003_05,proj_003,residential,Plumbing Rough-in,mep,2022-07-22,2022-08-05,14,2022-08-05,2022-08-21,2022-08-05,2022-08-21,100,completed,,act_003_03,16,14
|
| 37 |
+
act_003_06,proj_003,residential,Electrical Wiring & Conduits,mep,2022-07-22,2022-08-05,14,2022-08-05,2022-08-22,2022-08-05,2022-08-22,100,completed,,act_003_03,17,14
|
| 38 |
+
act_003_07,proj_003,residential,HVAC & Ventilation Installation,mep,2022-07-22,2022-08-01,10,2022-08-06,2022-08-17,2022-08-06,2022-08-17,100,completed,,act_003_03,11,15
|
| 39 |
+
act_003_08,proj_003,residential,Floor Leveling & Screed,finishing,2022-08-05,2022-08-15,10,2022-08-22,2022-09-03,2022-08-22,2022-09-03,100,completed,,act_003_05,12,17
|
| 40 |
+
act_003_09,proj_003,residential,Tiling β Floors & Wet Areas,finishing,2022-08-15,2022-09-02,18,2022-09-03,2022-09-25,2022-09-03,2022-09-25,100,completed,,act_003_08,22,19
|
| 41 |
+
act_003_10,proj_003,residential,Wall Plastering & Screeding,finishing,2022-08-05,2022-08-19,14,2022-08-22,2022-09-07,2022-08-22,2022-09-07,100,completed,,act_003_06,16,17
|
| 42 |
+
act_003_11,proj_003,residential,False Ceiling & Insulation,finishing,2022-08-19,2022-08-29,10,2022-09-07,2022-09-20,2022-09-07,2022-09-20,100,completed,,act_003_10,13,19
|
| 43 |
+
act_003_12,proj_003,residential,Painting β Primer & Finish Coats,finishing,2022-08-29,2022-09-12,14,2022-09-20,2022-10-05,2022-09-20,2022-10-05,100,completed,,act_003_11,15,22
|
| 44 |
+
act_003_13,proj_003,residential,"Carpentry, Joinery & Built-ins",finishing,2022-09-12,2022-09-28,16,2022-10-06,2022-10-26,2022-10-06,2022-10-26,100,completed,,act_003_12,20,24
|
| 45 |
+
act_003_14,proj_003,residential,"Fixtures, Fittings & Sanitaryware",finishing,2022-09-28,2022-10-08,10,2022-10-26,2022-11-06,2022-10-26,2022-11-06,100,completed,,act_003_13,11,28
|
| 46 |
+
act_003_15,proj_003,residential,"Final Inspection, Snag & Handover",inspection,2022-10-08,2022-10-14,6,2022-11-06,2022-11-14,2022-11-06,2022-11-14,100,completed,,act_003_14,8,29
|
| 47 |
+
act_004_01,proj_004,hospitality,Site Survey & Mobilization,prep,2022-09-01,2022-09-08,7,2022-09-03,2022-09-11,2022-09-03,2022-09-11,100,completed,,,8,2
|
| 48 |
+
act_004_02,proj_004,hospitality,Demolition & Strip-Out,demo,2022-09-08,2022-09-20,12,2022-09-13,2022-09-27,2022-09-13,2022-09-27,100,completed,,act_004_01,14,5
|
| 49 |
+
act_004_03,proj_004,hospitality,Structural Repairs & Reinforcement,structural,2022-09-20,2022-10-08,18,2022-09-28,2022-10-17,2022-09-28,2022-10-17,100,completed,,act_004_02,19,8
|
| 50 |
+
act_004_04,proj_004,hospitality,Waterproofing & Damp Proofing,structural,2022-10-08,2022-10-16,8,2022-10-19,2022-10-28,2022-10-19,2022-10-28,100,completed,,act_004_03,9,11
|
| 51 |
+
act_004_05,proj_004,hospitality,Plumbing Rough-in,mep,2022-10-08,2022-10-22,14,2022-10-17,2022-11-02,2022-10-17,2022-11-02,100,completed,,act_004_03,16,9
|
| 52 |
+
act_004_06,proj_004,hospitality,Electrical Wiring & Conduits,mep,2022-10-08,2022-10-22,14,2022-10-19,2022-11-03,2022-10-19,2022-11-03,100,completed,,act_004_03,15,11
|
| 53 |
+
act_004_07,proj_004,hospitality,HVAC & Ventilation Installation,mep,2022-10-08,2022-10-18,10,2022-10-20,2022-11-02,2022-10-20,2022-11-02,100,completed,,act_004_03,13,12
|
| 54 |
+
act_004_08,proj_004,hospitality,Floor Leveling & Screed,finishing,2022-10-22,2022-11-01,10,2022-11-02,2022-11-14,2022-11-02,2022-11-14,100,completed,,act_004_05,12,11
|
| 55 |
+
act_004_09,proj_004,hospitality,Tiling β Floors & Wet Areas,finishing,2022-11-01,2022-11-19,18,2022-11-14,2022-12-04,2022-11-14,2022-12-04,100,completed,,act_004_08,20,13
|
| 56 |
+
act_004_10,proj_004,hospitality,Wall Plastering & Screeding,finishing,2022-10-22,2022-11-05,14,2022-11-03,2022-11-21,2022-11-03,2022-11-21,100,completed,,act_004_06,18,12
|
| 57 |
+
act_004_11,proj_004,hospitality,False Ceiling & Insulation,finishing,2022-11-05,2022-11-15,10,2022-11-21,2022-12-04,2022-11-21,2022-12-04,100,completed,,act_004_10,13,16
|
| 58 |
+
act_004_12,proj_004,hospitality,Painting β Primer & Finish Coats,finishing,2022-11-15,2022-11-29,14,2022-12-06,2022-12-23,2022-12-06,2022-12-23,100,completed,,act_004_11,17,21
|
| 59 |
+
act_004_13,proj_004,hospitality,"Carpentry, Joinery & Built-ins",finishing,2022-11-29,2022-12-15,16,2022-12-23,2023-01-09,2022-12-23,2023-01-09,100,completed,,act_004_12,17,24
|
| 60 |
+
act_004_14,proj_004,hospitality,"Fixtures, Fittings & Sanitaryware",finishing,2022-12-15,2022-12-25,10,2023-01-10,2023-01-21,2023-01-10,2023-01-21,100,completed,,act_004_13,11,26
|
| 61 |
+
act_004_15,proj_004,hospitality,"Final Inspection, Snag & Handover",inspection,2022-12-25,2022-12-31,6,2023-01-23,2023-01-30,2023-01-23,2023-01-30,100,completed,,act_004_14,7,29
|
| 62 |
+
act_005_01,proj_005,commercial,Site Survey & Mobilization,prep,2023-01-05,2023-01-12,7,2023-01-05,2023-01-13,2023-01-05,2023-01-13,100,completed,,,8,0
|
| 63 |
+
act_005_02,proj_005,commercial,Demolition & Strip-Out,demo,2023-01-12,2023-01-24,12,2023-01-13,2023-01-27,2023-01-13,2023-01-27,100,completed,,act_005_01,14,1
|
| 64 |
+
act_005_03,proj_005,commercial,Structural Repairs & Reinforcement,structural,2023-01-24,2023-02-11,18,2023-01-27,2023-02-16,2023-01-27,2023-02-16,100,completed,,act_005_02,20,3
|
| 65 |
+
act_005_04,proj_005,commercial,Waterproofing & Damp Proofing,structural,2023-02-11,2023-02-19,8,2023-02-18,2023-02-27,2023-02-18,2023-02-27,100,completed,,act_005_03,9,7
|
| 66 |
+
act_005_05,proj_005,commercial,Plumbing Rough-in,mep,2023-02-11,2023-02-25,14,2023-02-16,2023-03-03,2023-02-16,2023-03-03,100,completed,,act_005_03,15,5
|
| 67 |
+
act_005_06,proj_005,commercial,Electrical Wiring & Conduits,mep,2023-02-11,2023-02-25,14,2023-02-16,2023-03-04,2023-02-16,2023-03-04,100,completed,,act_005_03,16,5
|
| 68 |
+
act_005_07,proj_005,commercial,HVAC & Ventilation Installation,mep,2023-02-11,2023-02-21,10,2023-02-16,2023-02-27,2023-02-16,2023-02-27,100,completed,,act_005_03,11,5
|
| 69 |
+
act_005_08,proj_005,commercial,Floor Leveling & Screed,finishing,2023-02-25,2023-03-07,10,2023-03-06,2023-03-17,2023-03-06,2023-03-17,100,completed,,act_005_05,11,9
|
| 70 |
+
act_005_09,proj_005,commercial,Tiling β Floors & Wet Areas,finishing,2023-03-07,2023-03-25,18,2023-03-17,2023-04-05,2023-03-17,2023-04-05,100,completed,,act_005_08,19,10
|
| 71 |
+
act_005_10,proj_005,commercial,Wall Plastering & Screeding,finishing,2023-02-25,2023-03-11,14,2023-03-05,2023-03-21,2023-03-05,2023-03-21,100,completed,,act_005_06,16,8
|
| 72 |
+
act_005_11,proj_005,commercial,False Ceiling & Insulation,finishing,2023-03-11,2023-03-21,10,2023-03-22,2023-04-02,2023-03-22,2023-04-02,100,completed,,act_005_10,11,11
|
| 73 |
+
act_005_12,proj_005,commercial,Painting β Primer & Finish Coats,finishing,2023-03-21,2023-04-04,14,2023-04-02,2023-04-17,2023-04-02,2023-04-17,100,completed,,act_005_11,15,12
|
| 74 |
+
act_005_13,proj_005,commercial,"Carpentry, Joinery & Built-ins",finishing,2023-04-04,2023-04-20,16,2023-04-17,2023-05-04,2023-04-17,2023-05-04,100,completed,,act_005_12,17,13
|
| 75 |
+
act_005_14,proj_005,commercial,"Fixtures, Fittings & Sanitaryware",finishing,2023-04-20,2023-04-30,10,2023-05-04,2023-05-16,2023-05-04,2023-05-16,100,completed,,act_005_13,12,14
|
| 76 |
+
act_005_15,proj_005,commercial,"Final Inspection, Snag & Handover",inspection,2023-04-30,2023-05-06,6,2023-05-17,2023-05-24,2023-05-17,2023-05-24,100,completed,,act_005_14,7,17
|
| 77 |
+
act_006_01,proj_006,residential,Site Survey & Mobilization,prep,2023-03-01,2023-03-08,7,2023-03-04,2023-03-12,2023-03-04,2023-03-12,100,completed,,,8,3
|
| 78 |
+
act_006_02,proj_006,residential,Demolition & Strip-Out,demo,2023-03-08,2023-03-20,12,2023-03-14,2023-03-27,2023-03-14,2023-03-27,100,completed,,act_006_01,13,6
|
| 79 |
+
act_006_03,proj_006,residential,Structural Repairs & Reinforcement,structural,2023-03-20,2023-04-07,18,2023-03-27,2023-04-17,2023-03-27,2023-04-17,100,completed,,act_006_02,21,7
|
| 80 |
+
act_006_04,proj_006,residential,Waterproofing & Damp Proofing,structural,2023-04-07,2023-04-15,8,2023-04-18,2023-04-27,2023-04-18,2023-04-27,100,completed,,act_006_03,9,11
|
| 81 |
+
act_006_05,proj_006,residential,Plumbing Rough-in,mep,2023-04-07,2023-04-21,14,2023-04-17,2023-05-04,2023-04-17,2023-05-04,100,completed,,act_006_03,17,10
|
| 82 |
+
act_006_06,proj_006,residential,Electrical Wiring & Conduits,mep,2023-04-07,2023-04-21,14,2023-04-17,2023-05-04,2023-04-17,2023-05-04,100,completed,,act_006_03,17,10
|
| 83 |
+
act_006_07,proj_006,residential,HVAC & Ventilation Installation,mep,2023-04-07,2023-04-17,10,2023-04-18,2023-04-30,2023-04-18,2023-04-30,100,completed,,act_006_03,12,11
|
| 84 |
+
act_006_08,proj_006,residential,Floor Leveling & Screed,finishing,2023-04-21,2023-05-01,10,2023-05-05,2023-05-18,2023-05-05,2023-05-18,100,completed,,act_006_05,13,14
|
| 85 |
+
act_006_09,proj_006,residential,Tiling β Floors & Wet Areas,finishing,2023-05-01,2023-05-19,18,2023-05-20,2023-06-09,2023-05-20,2023-06-09,100,completed,,act_006_08,20,19
|
| 86 |
+
act_006_10,proj_006,residential,Wall Plastering & Screeding,finishing,2023-04-21,2023-05-05,14,2023-05-07,2023-05-24,2023-05-07,2023-05-24,100,completed,,act_006_06,17,16
|
| 87 |
+
act_006_11,proj_006,residential,False Ceiling & Insulation,finishing,2023-05-05,2023-05-15,10,2023-05-24,2023-06-05,2023-05-24,2023-06-05,100,completed,,act_006_10,12,19
|
| 88 |
+
act_006_12,proj_006,residential,Painting β Primer & Finish Coats,finishing,2023-05-15,2023-05-29,14,2023-06-07,2023-06-24,2023-06-07,2023-06-24,100,completed,,act_006_11,17,23
|
| 89 |
+
act_006_13,proj_006,residential,"Carpentry, Joinery & Built-ins",finishing,2023-05-29,2023-06-14,16,2023-06-26,2023-07-14,2023-06-26,2023-07-14,100,completed,,act_006_12,18,28
|
| 90 |
+
act_006_14,proj_006,residential,"Fixtures, Fittings & Sanitaryware",finishing,2023-06-14,2023-06-24,10,2023-07-14,2023-07-27,2023-07-14,2023-07-27,100,completed,,act_006_13,13,30
|
| 91 |
+
act_006_15,proj_006,residential,"Final Inspection, Snag & Handover",inspection,2023-06-24,2023-06-30,6,2023-07-27,2023-08-03,2023-07-27,2023-08-03,100,completed,,act_006_14,7,33
|
| 92 |
+
act_007_01,proj_007,hospitality,Site Survey & Mobilization,prep,2023-06-01,2023-06-08,7,2023-06-01,2023-06-10,2023-06-01,2023-06-10,100,completed,,,9,0
|
| 93 |
+
act_007_02,proj_007,hospitality,Demolition & Strip-Out,demo,2023-06-08,2023-06-20,12,2023-06-10,2023-06-25,2023-06-10,2023-06-25,100,completed,,act_007_01,15,2
|
| 94 |
+
act_007_03,proj_007,hospitality,Structural Repairs & Reinforcement,structural,2023-06-20,2023-07-08,18,2023-06-29,2023-07-21,2023-06-29,2023-07-21,100,completed,,act_007_02,22,9
|
| 95 |
+
act_007_04,proj_007,hospitality,Waterproofing & Damp Proofing,structural,2023-07-08,2023-07-16,8,2023-07-22,2023-07-31,2023-07-22,2023-07-31,100,completed,,act_007_03,9,14
|
| 96 |
+
act_007_05,proj_007,hospitality,Plumbing Rough-in,mep,2023-07-08,2023-07-22,14,2023-07-21,2023-08-07,2023-07-21,2023-08-07,100,completed,,act_007_03,17,13
|
| 97 |
+
act_007_06,proj_007,hospitality,Electrical Wiring & Conduits,mep,2023-07-08,2023-07-22,14,2023-07-22,2023-08-09,2023-07-22,2023-08-09,100,completed,,act_007_03,18,14
|
| 98 |
+
act_007_07,proj_007,hospitality,HVAC & Ventilation Installation,mep,2023-07-08,2023-07-18,10,2023-07-21,2023-08-01,2023-07-21,2023-08-01,100,completed,,act_007_03,11,13
|
| 99 |
+
act_007_08,proj_007,hospitality,Floor Leveling & Screed,finishing,2023-07-22,2023-08-01,10,2023-08-07,2023-08-20,2023-08-07,2023-08-20,100,completed,,act_007_05,13,16
|
| 100 |
+
act_007_09,proj_007,hospitality,Tiling β Floors & Wet Areas,finishing,2023-08-01,2023-08-19,18,2023-08-20,2023-09-10,2023-08-20,2023-09-10,100,completed,,act_007_08,21,19
|
| 101 |
+
act_007_10,proj_007,hospitality,Wall Plastering & Screeding,finishing,2023-07-22,2023-08-05,14,2023-08-12,2023-08-27,2023-08-12,2023-08-27,100,completed,,act_007_06,15,21
|
| 102 |
+
act_007_11,proj_007,hospitality,False Ceiling & Insulation,finishing,2023-08-05,2023-08-15,10,2023-08-28,2023-09-11,2023-08-28,2023-09-11,100,completed,,act_007_10,14,23
|
| 103 |
+
act_007_12,proj_007,hospitality,Painting β Primer & Finish Coats,finishing,2023-08-15,2023-08-29,14,2023-09-11,2023-09-28,2023-09-11,2023-09-28,100,completed,,act_007_11,17,27
|
| 104 |
+
act_007_13,proj_007,hospitality,"Carpentry, Joinery & Built-ins",finishing,2023-08-29,2023-09-14,16,2023-10-01,2023-10-18,2023-10-01,2023-10-18,100,completed,,act_007_12,17,33
|
| 105 |
+
act_007_14,proj_007,hospitality,"Fixtures, Fittings & Sanitaryware",finishing,2023-09-14,2023-09-24,10,2023-10-19,2023-11-01,2023-10-19,2023-11-01,100,completed,,act_007_13,13,35
|
| 106 |
+
act_007_15,proj_007,hospitality,"Final Inspection, Snag & Handover",inspection,2023-09-24,2023-09-30,6,2023-11-02,2023-11-09,2023-11-02,2023-11-09,100,completed,,act_007_14,7,39
|
| 107 |
+
act_008_01,proj_008,residential,Site Survey & Mobilization,prep,2024-01-15,2024-01-22,7,2024-01-18,2024-01-27,2024-01-18,2024-01-27,100,completed,,,9,3
|
| 108 |
+
act_008_02,proj_008,residential,Demolition & Strip-Out,demo,2024-01-22,2024-02-03,12,2024-01-30,2024-02-13,2024-01-30,2024-02-13,100,completed,,act_008_01,14,8
|
| 109 |
+
act_008_03,proj_008,residential,Structural Repairs & Reinforcement,structural,2024-02-03,2024-02-21,18,2024-02-13,2024-03-03,2024-02-13,2024-03-03,100,completed,,act_008_02,19,10
|
| 110 |
+
act_008_04,proj_008,residential,Waterproofing & Damp Proofing,structural,2024-02-21,2024-02-29,8,2024-03-03,2024-03-12,2024-03-03,2024-03-12,100,completed,,act_008_03,9,11
|
| 111 |
+
act_008_05,proj_008,residential,Plumbing Rough-in,mep,2024-02-21,2024-03-06,14,2024-03-04,2024-03-20,2024-03-04,2024-03-20,100,completed,,act_008_03,16,12
|
| 112 |
+
act_008_06,proj_008,residential,Electrical Wiring & Conduits,mep,2024-02-21,2024-03-06,14,2024-03-04,2024-03-20,2024-03-04,2024-03-20,100,completed,,act_008_03,16,12
|
| 113 |
+
act_008_07,proj_008,residential,HVAC & Ventilation Installation,mep,2024-02-21,2024-03-02,10,2024-03-05,2024-03-17,2024-03-05,2024-03-17,100,completed,,act_008_03,12,13
|
| 114 |
+
act_008_08,proj_008,residential,Floor Leveling & Screed,finishing,2024-03-06,2024-03-16,10,2024-03-21,2024-04-01,2024-03-21,2024-04-01,100,completed,,act_008_05,11,15
|
| 115 |
+
act_008_09,proj_008,residential,Tiling β Floors & Wet Areas,finishing,2024-03-16,2024-04-03,18,2024-04-01,,2024-04-01,2024-09-26,62,in_progress,,act_008_08,,16
|
| 116 |
+
act_008_10,proj_008,residential,Wall Plastering & Screeding,finishing,2024-03-06,2024-03-20,14,2024-03-20,,,,0,not_started,,act_008_06,,14
|
| 117 |
+
act_008_11,proj_008,residential,False Ceiling & Insulation,finishing,2024-03-20,2024-03-30,10,2024-04-04,,,,0,not_started,,act_008_10,,15
|
| 118 |
+
act_008_12,proj_008,residential,Painting β Primer & Finish Coats,finishing,2024-03-30,2024-04-13,14,2024-04-17,,,,0,not_started,,act_008_11,,18
|
| 119 |
+
act_008_13,proj_008,residential,"Carpentry, Joinery & Built-ins",finishing,2024-04-13,2024-04-29,16,2024-05-03,,,,0,not_started,,act_008_12,,20
|
| 120 |
+
act_008_14,proj_008,residential,"Fixtures, Fittings & Sanitaryware",finishing,2024-04-29,2024-05-09,10,2024-05-20,,,,0,not_started,,act_008_13,,21
|
| 121 |
+
act_008_15,proj_008,residential,"Final Inspection, Snag & Handover",inspection,2024-05-09,2024-05-15,6,2024-06-02,,,,0,not_started,,act_008_14,,24
|
| 122 |
+
act_009_01,proj_009,commercial,Site Survey & Mobilization,prep,2024-03-01,2024-03-08,7,2024-03-01,2024-03-10,2024-03-01,2024-03-10,100,completed,,,9,0
|
| 123 |
+
act_009_02,proj_009,commercial,Demolition & Strip-Out,demo,2024-03-08,2024-03-20,12,2024-03-10,2024-03-23,2024-03-10,2024-03-23,100,completed,,act_009_01,13,2
|
| 124 |
+
act_009_03,proj_009,commercial,Structural Repairs & Reinforcement,structural,2024-03-20,2024-04-07,18,2024-03-23,2024-04-12,2024-03-23,2024-04-12,100,completed,,act_009_02,20,3
|
| 125 |
+
act_009_04,proj_009,commercial,Waterproofing & Damp Proofing,structural,2024-04-07,2024-04-15,8,2024-04-12,2024-04-21,2024-04-12,2024-04-21,100,completed,,act_009_03,9,5
|
| 126 |
+
act_009_05,proj_009,commercial,Plumbing Rough-in,mep,2024-04-07,2024-04-21,14,2024-04-12,2024-04-28,2024-04-12,2024-04-28,100,completed,,act_009_03,16,5
|
| 127 |
+
act_009_06,proj_009,commercial,Electrical Wiring & Conduits,mep,2024-04-07,2024-04-21,14,2024-04-12,2024-04-30,2024-04-12,2024-04-30,100,completed,,act_009_03,18,5
|
| 128 |
+
act_009_07,proj_009,commercial,HVAC & Ventilation Installation,mep,2024-04-07,2024-04-17,10,2024-04-16,,2024-04-16,2024-10-31,48,in_progress,,act_009_03,,9
|
| 129 |
+
act_009_08,proj_009,commercial,Floor Leveling & Screed,finishing,2024-04-21,2024-05-01,10,2024-04-29,,2024-04-29,2024-12-23,22,in_progress,,act_009_05,,8
|
| 130 |
+
act_009_09,proj_009,commercial,Tiling β Floors & Wet Areas,finishing,2024-05-01,2024-05-19,18,2024-05-14,,,,0,not_started,,act_009_08,,13
|
| 131 |
+
act_009_10,proj_009,commercial,Wall Plastering & Screeding,finishing,2024-04-21,2024-05-05,14,2024-05-01,,,,0,not_started,,act_009_06,,10
|
| 132 |
+
act_009_11,proj_009,commercial,False Ceiling & Insulation,finishing,2024-05-05,2024-05-15,10,2024-05-19,,,,0,not_started,,act_009_10,,14
|
| 133 |
+
act_009_12,proj_009,commercial,Painting β Primer & Finish Coats,finishing,2024-05-15,2024-05-29,14,2024-06-03,,,,0,not_started,,act_009_11,,19
|
| 134 |
+
act_009_13,proj_009,commercial,"Carpentry, Joinery & Built-ins",finishing,2024-05-29,2024-06-14,16,2024-06-23,,,,0,not_started,,act_009_12,,25
|
| 135 |
+
act_009_14,proj_009,commercial,"Fixtures, Fittings & Sanitaryware",finishing,2024-06-14,2024-06-24,10,2024-07-18,,,,0,not_started,,act_009_13,,34
|
| 136 |
+
act_009_15,proj_009,commercial,"Final Inspection, Snag & Handover",inspection,2024-06-24,2024-06-30,6,2024-07-30,,,,0,not_started,,act_009_14,,36
|
| 137 |
+
act_010_01,proj_010,residential,Site Survey & Mobilization,prep,2024-09-01,2024-09-08,7,,,2024-09-01,2024-09-08,0,not_started,,,,
|
| 138 |
+
act_010_02,proj_010,residential,Demolition & Strip-Out,demo,2024-09-08,2024-09-20,12,,,2024-09-08,2024-09-20,0,not_started,,act_010_01,,
|
| 139 |
+
act_010_03,proj_010,residential,Structural Repairs & Reinforcement,structural,2024-09-20,2024-10-08,18,,,2024-09-20,2024-10-08,0,not_started,,act_010_02,,
|
| 140 |
+
act_010_04,proj_010,residential,Waterproofing & Damp Proofing,structural,2024-10-08,2024-10-16,8,,,2024-10-08,2024-10-16,0,not_started,,act_010_03,,
|
| 141 |
+
act_010_05,proj_010,residential,Plumbing Rough-in,mep,2024-10-08,2024-10-22,14,,,2024-10-08,2024-10-22,0,not_started,,act_010_03,,
|
| 142 |
+
act_010_06,proj_010,residential,Electrical Wiring & Conduits,mep,2024-10-08,2024-10-22,14,,,2024-10-08,2024-10-22,0,not_started,,act_010_03,,
|
| 143 |
+
act_010_07,proj_010,residential,HVAC & Ventilation Installation,mep,2024-10-08,2024-10-18,10,,,2024-10-08,2024-10-18,0,not_started,,act_010_03,,
|
| 144 |
+
act_010_08,proj_010,residential,Floor Leveling & Screed,finishing,2024-10-22,2024-11-01,10,,,2024-10-22,2024-11-01,0,not_started,,act_010_05,,
|
| 145 |
+
act_010_09,proj_010,residential,Tiling β Floors & Wet Areas,finishing,2024-11-01,2024-11-19,18,,,2024-11-01,2024-11-19,0,not_started,,act_010_08,,
|
| 146 |
+
act_010_10,proj_010,residential,Wall Plastering & Screeding,finishing,2024-10-22,2024-11-05,14,,,2024-10-22,2024-11-05,0,not_started,,act_010_06,,
|
| 147 |
+
act_010_11,proj_010,residential,False Ceiling & Insulation,finishing,2024-11-05,2024-11-15,10,,,2024-11-05,2024-11-15,0,not_started,,act_010_10,,
|
| 148 |
+
act_010_12,proj_010,residential,Painting β Primer & Finish Coats,finishing,2024-11-15,2024-11-29,14,,,2024-11-15,2024-11-29,0,not_started,,act_010_11,,
|
| 149 |
+
act_010_13,proj_010,residential,"Carpentry, Joinery & Built-ins",finishing,2024-11-29,2024-12-15,16,,,2024-11-29,2024-12-15,0,not_started,,act_010_12,,
|
| 150 |
+
act_010_14,proj_010,residential,"Fixtures, Fittings & Sanitaryware",finishing,2024-12-15,2024-12-25,10,,,2024-12-15,2024-12-25,0,not_started,,act_010_13,,
|
| 151 |
+
act_010_15,proj_010,residential,"Final Inspection, Snag & Handover",inspection,2024-12-25,2024-12-31,6,,,2024-12-25,2024-12-31,0,not_started,,act_010_14,,
|
data/boq.csv
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,activity_id,project_id,name,unit,quantity,unit_price,unit_cost,total_price,total_cost,margin_pct,currency
|
| 2 |
+
boq_00001,act_001_01,proj_001,Site Survey & Layout,lumpsum,1,3262,2283,3262,2283,30.0,INR
|
| 3 |
+
boq_00002,act_001_01,proj_001,Temporary Site Office Setup,lumpsum,1,8016,5611,8016,5611,30.0,INR
|
| 4 |
+
boq_00003,act_001_01,proj_001,Safety Hoarding & Signage,lumpsum,1,2042,1429,2042,1429,30.0,INR
|
| 5 |
+
boq_00004,act_001_02,proj_001,Demolition Labour & Equipment,lumpsum,1,12444,8711,12444,8711,30.0,INR
|
| 6 |
+
boq_00005,act_001_02,proj_001,Debris Removal & Disposal,trip,6,5462,3823,32772,22938,30.0,INR
|
| 7 |
+
boq_00006,act_001_02,proj_001,Asbestos Survey & Removal,sqm,30,3920,2744,117600,82320,30.0,INR
|
| 8 |
+
boq_00007,act_001_03,proj_001,Reinforced Concrete M30,m3,15,9196,6437,137940,96555,30.0,INR
|
| 9 |
+
boq_00008,act_001_03,proj_001,Steel Rebar TMT 12mm,tonne,6,4093,2865,24558,17190,30.0,INR
|
| 10 |
+
boq_00009,act_001_03,proj_001,Shuttering Plywood 19mm,sheets,30,2119,1483,63570,44490,30.0,INR
|
| 11 |
+
boq_00010,act_001_03,proj_001,Structural Grouting Compound,bags,20,1922,1346,38440,26920,30.0,INR
|
| 12 |
+
boq_00011,act_001_04,proj_001,SBR Waterproofing Membrane,sqm,120,4481,3137,537720,376440,30.0,INR
|
| 13 |
+
boq_00012,act_001_04,proj_001,Crystalline Waterproofing Slurry,kg,50,2874,2012,143700,100600,30.0,INR
|
| 14 |
+
boq_00013,act_001_04,proj_001,Drainage Board & Filter Fabric,sqm,80,1809,1266,144720,101280,30.0,INR
|
| 15 |
+
boq_00014,act_001_05,proj_001,CPVC Pipes 1 inch,meters,180,2904,2033,522720,365940,30.0,INR
|
| 16 |
+
boq_00015,act_001_05,proj_001,uPVC Soil Pipes 4 inch,meters,60,1493,1045,89580,62700,30.0,INR
|
| 17 |
+
boq_00016,act_001_05,proj_001,GI Fittings Set,set,1,1274,892,1274,892,30.0,INR
|
| 18 |
+
boq_00017,act_001_05,proj_001,Water Storage Tank 1000L,unit,2,6864,4805,13728,9610,30.0,INR
|
| 19 |
+
boq_00018,act_001_06,proj_001,FR Copper Wire 4 sq mm,meters,250,3935,2755,983750,688750,30.0,INR
|
| 20 |
+
boq_00019,act_001_06,proj_001,MCB Distribution Board 18-way,unit,2,5428,3800,10856,7600,30.0,INR
|
| 21 |
+
boq_00020,act_001_06,proj_001,PVC Conduit 25mm,meters,150,1144,801,171600,120150,30.0,INR
|
| 22 |
+
boq_00021,act_001_06,proj_001,Switches & Sockets (Modular),set,1,3133,2193,3133,2193,30.0,INR
|
| 23 |
+
boq_00022,act_001_07,proj_001,Cassette AC Unit 2 Ton,unit,4,14014,9810,56056,39240,30.0,INR
|
| 24 |
+
boq_00023,act_001_07,proj_001,Insulated Ducting,meters,40,4820,3374,192800,134960,30.0,INR
|
| 25 |
+
boq_00024,act_001_07,proj_001,AHU Return Air Grilles,unit,12,1829,1280,21948,15360,30.0,INR
|
| 26 |
+
boq_00025,act_001_07,proj_001,Refrigerant Copper Pipes,meters,60,2725,1907,163500,114420,30.0,INR
|
| 27 |
+
boq_00026,act_001_08,proj_001,Self-Leveling Compound,bags,20,3392,2374,67840,47480,30.0,INR
|
| 28 |
+
boq_00027,act_001_08,proj_001,Bonding Agent SBR,liters,30,1383,968,41490,29040,30.0,INR
|
| 29 |
+
boq_00028,act_001_08,proj_001,DPM Sheet 250 micron,sqm,200,2163,1514,432600,302800,30.0,INR
|
| 30 |
+
boq_00029,act_001_09,proj_001,Vitrified Tiles 800x800mm,sqm,200,8237,5766,1647400,1153200,30.0,INR
|
| 31 |
+
boq_00030,act_001_09,proj_001,Ceramic Tiles 300x600mm,sqm,80,3931,2752,314480,220160,30.0,INR
|
| 32 |
+
boq_00031,act_001_09,proj_001,Tile Adhesive C2 Grade,bags,40,2061,1443,82440,57720,30.0,INR
|
| 33 |
+
boq_00032,act_001_09,proj_001,Tile Grout Mapei,bags,15,648,454,9720,6810,29.9,INR
|
| 34 |
+
boq_00033,act_001_09,proj_001,Tile Edge Trim SS,meters,60,397,278,23820,16680,30.0,INR
|
| 35 |
+
boq_00034,act_001_10,proj_001,Gypsum Plaster 20mm,bags,50,2418,1693,120900,84650,30.0,INR
|
| 36 |
+
boq_00035,act_001_10,proj_001,POP Punning Compound,bags,30,1172,820,35160,24600,30.0,INR
|
| 37 |
+
boq_00036,act_001_10,proj_001,Wire Mesh Reinforcement,sqm,100,875,612,87500,61200,30.1,INR
|
| 38 |
+
boq_00037,act_001_11,proj_001,Gypsum Board 12.5mm,sqm,150,3502,2451,525300,367650,30.0,INR
|
| 39 |
+
boq_00038,act_001_11,proj_001,GI Suspension System,sqm,150,2612,1829,391800,274350,30.0,INR
|
| 40 |
+
boq_00039,act_001_11,proj_001,Glass Wool Insulation 50mm,sqm,100,1771,1240,177100,124000,30.0,INR
|
| 41 |
+
boq_00040,act_001_12,proj_001,Premium Emulsion Paint,liters,120,3576,2503,429120,300360,30.0,INR
|
| 42 |
+
boq_00041,act_001_12,proj_001,Exterior Weather Shield,liters,60,3961,2772,237660,166320,30.0,INR
|
| 43 |
+
boq_00042,act_001_12,proj_001,Primer Coat White,liters,60,1438,1006,86280,60360,30.0,INR
|
| 44 |
+
boq_00043,act_001_12,proj_001,Putty Filler Wall,kg,40,701,491,28040,19640,30.0,INR
|
| 45 |
+
boq_00044,act_001_13,proj_001,Teak Wood Panels Grade A,sqm,30,9937,6956,298110,208680,30.0,INR
|
| 46 |
+
boq_00045,act_001_13,proj_001,Pre-hung Door Sets,unit,8,6929,4850,55432,38800,30.0,INR
|
| 47 |
+
boq_00046,act_001_13,proj_001,Modular Kitchen Framework,lumpsum,1,21692,15184,21692,15184,30.0,INR
|
| 48 |
+
boq_00047,act_001_13,proj_001,Cabinet Hardware Premium Set,set,2,3238,2267,6476,4534,30.0,INR
|
| 49 |
+
boq_00048,act_001_14,proj_001,EWC Rimless Toilet Suite,unit,4,8415,5890,33660,23560,30.0,INR
|
| 50 |
+
boq_00049,act_001_14,proj_001,Concealed Cistern,unit,4,3914,2740,15656,10960,30.0,INR
|
| 51 |
+
boq_00050,act_001_14,proj_001,Basin & Pedestal Set,unit,4,3758,2631,15032,10524,30.0,INR
|
| 52 |
+
boq_00051,act_001_14,proj_001,CP Fittings Set (Taps/Showers),set,4,5698,3989,22792,15956,30.0,INR
|
| 53 |
+
boq_00052,act_001_15,proj_001,Snagging Rectification Labour,lumpsum,1,4940,3458,4940,3458,30.0,INR
|
| 54 |
+
boq_00053,act_001_15,proj_001,As-Built Drawings & O&M Manual,set,1,3081,2157,3081,2157,30.0,INR
|
| 55 |
+
boq_00054,act_001_15,proj_001,Defect Liability Retention,lumpsum,1,8120,0,8120,0,100.0,INR
|
| 56 |
+
boq_00055,act_002_01,proj_002,Site Survey & Layout,lumpsum,1,3266,2286,3266,2286,30.0,INR
|
| 57 |
+
boq_00056,act_002_01,proj_002,Temporary Site Office Setup,lumpsum,1,7824,5477,7824,5477,30.0,INR
|
| 58 |
+
boq_00057,act_002_01,proj_002,Safety Hoarding & Signage,lumpsum,1,2156,1509,2156,1509,30.0,INR
|
| 59 |
+
boq_00058,act_002_02,proj_002,Demolition Labour & Equipment,lumpsum,1,12804,8963,12804,8963,30.0,INR
|
| 60 |
+
boq_00059,act_002_02,proj_002,Debris Removal & Disposal,trip,6,5637,3946,33822,23676,30.0,INR
|
| 61 |
+
boq_00060,act_002_02,proj_002,Asbestos Survey & Removal,sqm,30,3884,2719,116520,81570,30.0,INR
|
| 62 |
+
boq_00061,act_002_03,proj_002,Reinforced Concrete M30,m3,15,10194,7135,152910,107025,30.0,INR
|
| 63 |
+
boq_00062,act_002_03,proj_002,Steel Rebar TMT 12mm,tonne,6,3713,2599,22278,15594,30.0,INR
|
| 64 |
+
boq_00063,act_002_03,proj_002,Shuttering Plywood 19mm,sheets,30,2258,1580,67740,47400,30.0,INR
|
| 65 |
+
boq_00064,act_002_03,proj_002,Structural Grouting Compound,bags,20,1822,1275,36440,25500,30.0,INR
|
| 66 |
+
boq_00065,act_002_04,proj_002,SBR Waterproofing Membrane,sqm,120,4141,2899,496920,347880,30.0,INR
|
| 67 |
+
boq_00066,act_002_04,proj_002,Crystalline Waterproofing Slurry,kg,50,3081,2157,154050,107850,30.0,INR
|
| 68 |
+
boq_00067,act_002_04,proj_002,Drainage Board & Filter Fabric,sqm,80,1959,1371,156720,109680,30.0,INR
|
| 69 |
+
boq_00068,act_002_05,proj_002,CPVC Pipes 1 inch,meters,180,2884,2019,519120,363420,30.0,INR
|
| 70 |
+
boq_00069,act_002_05,proj_002,uPVC Soil Pipes 4 inch,meters,60,1640,1148,98400,68880,30.0,INR
|
| 71 |
+
boq_00070,act_002_05,proj_002,GI Fittings Set,set,1,1322,925,1322,925,30.0,INR
|
| 72 |
+
boq_00071,act_002_05,proj_002,Water Storage Tank 1000L,unit,2,6936,4855,13872,9710,30.0,INR
|
| 73 |
+
boq_00072,act_002_06,proj_002,FR Copper Wire 4 sq mm,meters,250,4410,3087,1102500,771750,30.0,INR
|
| 74 |
+
boq_00073,act_002_06,proj_002,MCB Distribution Board 18-way,unit,2,5296,3708,10592,7416,30.0,INR
|
| 75 |
+
boq_00074,act_002_06,proj_002,PVC Conduit 25mm,meters,150,1014,710,152100,106500,30.0,INR
|
| 76 |
+
boq_00075,act_002_06,proj_002,Switches & Sockets (Modular),set,1,3328,2330,3328,2330,30.0,INR
|
| 77 |
+
boq_00076,act_002_07,proj_002,Cassette AC Unit 2 Ton,unit,4,13790,9653,55160,38612,30.0,INR
|
| 78 |
+
boq_00077,act_002_07,proj_002,Insulated Ducting,meters,40,4221,2955,168840,118200,30.0,INR
|
| 79 |
+
boq_00078,act_002_07,proj_002,AHU Return Air Grilles,unit,12,1683,1178,20196,14136,30.0,INR
|
| 80 |
+
boq_00079,act_002_07,proj_002,Refrigerant Copper Pipes,meters,60,2764,1935,165840,116100,30.0,INR
|
| 81 |
+
boq_00080,act_002_08,proj_002,Self-Leveling Compound,bags,20,3370,2359,67400,47180,30.0,INR
|
| 82 |
+
boq_00081,act_002_08,proj_002,Bonding Agent SBR,liters,30,1357,950,40710,28500,30.0,INR
|
| 83 |
+
boq_00082,act_002_08,proj_002,DPM Sheet 250 micron,sqm,200,2119,1483,423800,296600,30.0,INR
|
| 84 |
+
boq_00083,act_002_09,proj_002,Vitrified Tiles 800x800mm,sqm,200,7324,5127,1464800,1025400,30.0,INR
|
| 85 |
+
boq_00084,act_002_09,proj_002,Ceramic Tiles 300x600mm,sqm,80,4015,2811,321200,224880,30.0,INR
|
| 86 |
+
boq_00085,act_002_09,proj_002,Tile Adhesive C2 Grade,bags,40,2207,1545,88280,61800,30.0,INR
|
| 87 |
+
boq_00086,act_002_09,proj_002,Tile Grout Mapei,bags,15,647,453,9705,6795,30.0,INR
|
| 88 |
+
boq_00087,act_002_09,proj_002,Tile Edge Trim SS,meters,60,395,276,23700,16560,30.1,INR
|
| 89 |
+
boq_00088,act_002_10,proj_002,Gypsum Plaster 20mm,bags,50,2712,1898,135600,94900,30.0,INR
|
| 90 |
+
boq_00089,act_002_10,proj_002,POP Punning Compound,bags,30,1136,795,34080,23850,30.0,INR
|
| 91 |
+
boq_00090,act_002_10,proj_002,Wire Mesh Reinforcement,sqm,100,883,618,88300,61800,30.0,INR
|
| 92 |
+
boq_00091,act_002_11,proj_002,Gypsum Board 12.5mm,sqm,150,3373,2361,505950,354150,30.0,INR
|
| 93 |
+
boq_00092,act_002_11,proj_002,GI Suspension System,sqm,150,2825,1978,423750,296700,30.0,INR
|
| 94 |
+
boq_00093,act_002_11,proj_002,Glass Wool Insulation 50mm,sqm,100,1847,1293,184700,129300,30.0,INR
|
| 95 |
+
boq_00094,act_002_12,proj_002,Premium Emulsion Paint,liters,120,3895,2726,467400,327120,30.0,INR
|
| 96 |
+
boq_00095,act_002_12,proj_002,Exterior Weather Shield,liters,60,4238,2966,254280,177960,30.0,INR
|
| 97 |
+
boq_00096,act_002_12,proj_002,Primer Coat White,liters,60,1474,1032,88440,61920,30.0,INR
|
| 98 |
+
boq_00097,act_002_12,proj_002,Putty Filler Wall,kg,40,775,542,31000,21680,30.1,INR
|
| 99 |
+
boq_00098,act_002_13,proj_002,Teak Wood Panels Grade A,sqm,30,9234,6464,277020,193920,30.0,INR
|
| 100 |
+
boq_00099,act_002_13,proj_002,Pre-hung Door Sets,unit,8,7194,5036,57552,40288,30.0,INR
|
| 101 |
+
boq_00100,act_002_13,proj_002,Modular Kitchen Framework,lumpsum,1,20790,14553,20790,14553,30.0,INR
|
| 102 |
+
boq_00101,act_002_13,proj_002,Cabinet Hardware Premium Set,set,2,3053,2137,6106,4274,30.0,INR
|
| 103 |
+
boq_00102,act_002_14,proj_002,EWC Rimless Toilet Suite,unit,4,8525,5968,34100,23872,30.0,INR
|
| 104 |
+
boq_00103,act_002_14,proj_002,Concealed Cistern,unit,4,3914,2740,15656,10960,30.0,INR
|
| 105 |
+
boq_00104,act_002_14,proj_002,Basin & Pedestal Set,unit,4,3504,2453,14016,9812,30.0,INR
|
| 106 |
+
boq_00105,act_002_14,proj_002,CP Fittings Set (Taps/Showers),set,4,5654,3958,22616,15832,30.0,INR
|
| 107 |
+
boq_00106,act_002_15,proj_002,Snagging Rectification Labour,lumpsum,1,4600,3220,4600,3220,30.0,INR
|
| 108 |
+
boq_00107,act_002_15,proj_002,As-Built Drawings & O&M Manual,set,1,3129,2190,3129,2190,30.0,INR
|
| 109 |
+
boq_00108,act_002_15,proj_002,Defect Liability Retention,lumpsum,1,8632,0,8632,0,100.0,INR
|
| 110 |
+
boq_00109,act_003_01,proj_003,Site Survey & Layout,lumpsum,1,3252,2276,3252,2276,30.0,INR
|
| 111 |
+
boq_00110,act_003_01,proj_003,Temporary Site Office Setup,lumpsum,1,8176,5723,8176,5723,30.0,INR
|
| 112 |
+
boq_00111,act_003_01,proj_003,Safety Hoarding & Signage,lumpsum,1,2077,1454,2077,1454,30.0,INR
|
| 113 |
+
boq_00112,act_003_02,proj_003,Demolition Labour & Equipment,lumpsum,1,11880,8316,11880,8316,30.0,INR
|
| 114 |
+
boq_00113,act_003_02,proj_003,Debris Removal & Disposal,trip,6,5682,3977,34092,23862,30.0,INR
|
| 115 |
+
boq_00114,act_003_02,proj_003,Asbestos Survey & Removal,sqm,30,4104,2873,123120,86190,30.0,INR
|
| 116 |
+
boq_00115,act_003_03,proj_003,Reinforced Concrete M30,m3,15,8778,6145,131670,92175,30.0,INR
|
| 117 |
+
boq_00116,act_003_03,proj_003,Steel Rebar TMT 12mm,tonne,6,3804,2663,22824,15978,30.0,INR
|
| 118 |
+
boq_00117,act_003_03,proj_003,Shuttering Plywood 19mm,sheets,30,2003,1402,60090,42060,30.0,INR
|
| 119 |
+
boq_00118,act_003_03,proj_003,Structural Grouting Compound,bags,20,1944,1361,38880,27220,30.0,INR
|
| 120 |
+
boq_00119,act_003_04,proj_003,SBR Waterproofing Membrane,sqm,120,4406,3084,528720,370080,30.0,INR
|
| 121 |
+
boq_00120,act_003_04,proj_003,Crystalline Waterproofing Slurry,kg,50,3022,2116,151100,105800,30.0,INR
|
| 122 |
+
boq_00121,act_003_04,proj_003,Drainage Board & Filter Fabric,sqm,80,2033,1423,162640,113840,30.0,INR
|
| 123 |
+
boq_00122,act_003_05,proj_003,CPVC Pipes 1 inch,meters,180,2808,1966,505440,353880,30.0,INR
|
| 124 |
+
boq_00123,act_003_05,proj_003,uPVC Soil Pipes 4 inch,meters,60,1662,1164,99720,69840,30.0,INR
|
| 125 |
+
boq_00124,act_003_05,proj_003,GI Fittings Set,set,1,1231,862,1231,862,30.0,INR
|
| 126 |
+
boq_00125,act_003_05,proj_003,Water Storage Tank 1000L,unit,2,6539,4577,13078,9154,30.0,INR
|
| 127 |
+
boq_00126,act_003_06,proj_003,FR Copper Wire 4 sq mm,meters,250,4292,3005,1073000,751250,30.0,INR
|
| 128 |
+
boq_00127,act_003_06,proj_003,MCB Distribution Board 18-way,unit,2,5440,3808,10880,7616,30.0,INR
|
| 129 |
+
boq_00128,act_003_06,proj_003,PVC Conduit 25mm,meters,150,1092,765,163800,114750,29.9,INR
|
| 130 |
+
boq_00129,act_003_06,proj_003,Switches & Sockets (Modular),set,1,3286,2300,3286,2300,30.0,INR
|
| 131 |
+
boq_00130,act_003_07,proj_003,Cassette AC Unit 2 Ton,unit,4,13174,9222,52696,36888,30.0,INR
|
| 132 |
+
boq_00131,act_003_07,proj_003,Insulated Ducting,meters,40,4280,2996,171200,119840,30.0,INR
|
| 133 |
+
boq_00132,act_003_07,proj_003,AHU Return Air Grilles,unit,12,1780,1246,21360,14952,30.0,INR
|
| 134 |
+
boq_00133,act_003_07,proj_003,Refrigerant Copper Pipes,meters,60,2751,1926,165060,115560,30.0,INR
|
| 135 |
+
boq_00134,act_003_08,proj_003,Self-Leveling Compound,bags,20,3338,2336,66760,46720,30.0,INR
|
| 136 |
+
boq_00135,act_003_08,proj_003,Bonding Agent SBR,liters,30,1394,976,41820,29280,30.0,INR
|
| 137 |
+
boq_00136,act_003_08,proj_003,DPM Sheet 250 micron,sqm,200,2033,1423,406600,284600,30.0,INR
|
| 138 |
+
boq_00137,act_003_09,proj_003,Vitrified Tiles 800x800mm,sqm,200,7753,5427,1550600,1085400,30.0,INR
|
| 139 |
+
boq_00138,act_003_09,proj_003,Ceramic Tiles 300x600mm,sqm,80,3914,2740,313120,219200,30.0,INR
|
| 140 |
+
boq_00139,act_003_09,proj_003,Tile Adhesive C2 Grade,bags,40,2350,1645,94000,65800,30.0,INR
|
| 141 |
+
boq_00140,act_003_09,proj_003,Tile Grout Mapei,bags,15,642,449,9630,6735,30.1,INR
|
| 142 |
+
boq_00141,act_003_09,proj_003,Tile Edge Trim SS,meters,60,374,262,22440,15720,29.9,INR
|
| 143 |
+
boq_00142,act_003_10,proj_003,Gypsum Plaster 20mm,bags,50,2553,1787,127650,89350,30.0,INR
|
| 144 |
+
boq_00143,act_003_10,proj_003,POP Punning Compound,bags,30,1066,746,31980,22380,30.0,INR
|
| 145 |
+
boq_00144,act_003_10,proj_003,Wire Mesh Reinforcement,sqm,100,967,677,96700,67700,30.0,INR
|
| 146 |
+
boq_00145,act_003_11,proj_003,Gypsum Board 12.5mm,sqm,150,3468,2428,520200,364200,30.0,INR
|
| 147 |
+
boq_00146,act_003_11,proj_003,GI Suspension System,sqm,150,2638,1846,395700,276900,30.0,INR
|
| 148 |
+
boq_00147,act_003_11,proj_003,Glass Wool Insulation 50mm,sqm,100,1761,1233,176100,123300,30.0,INR
|
| 149 |
+
boq_00148,act_003_12,proj_003,Premium Emulsion Paint,liters,120,3960,2772,475200,332640,30.0,INR
|
| 150 |
+
boq_00149,act_003_12,proj_003,Exterior Weather Shield,liters,60,4234,2964,254040,177840,30.0,INR
|
| 151 |
+
boq_00150,act_003_12,proj_003,Primer Coat White,liters,60,1494,1046,89640,62760,30.0,INR
|
| 152 |
+
boq_00151,act_003_12,proj_003,Putty Filler Wall,kg,40,703,492,28120,19680,30.0,INR
|
| 153 |
+
boq_00152,act_003_13,proj_003,Teak Wood Panels Grade A,sqm,30,9224,6457,276720,193710,30.0,INR
|
| 154 |
+
boq_00153,act_003_13,proj_003,Pre-hung Door Sets,unit,8,6732,4712,53856,37696,30.0,INR
|
| 155 |
+
boq_00154,act_003_13,proj_003,Modular Kitchen Framework,lumpsum,1,21098,14769,21098,14769,30.0,INR
|
| 156 |
+
boq_00155,act_003_13,proj_003,Cabinet Hardware Premium Set,set,2,3130,2191,6260,4382,30.0,INR
|
| 157 |
+
boq_00156,act_003_14,proj_003,EWC Rimless Toilet Suite,unit,4,7981,5587,31924,22348,30.0,INR
|
| 158 |
+
boq_00157,act_003_14,proj_003,Concealed Cistern,unit,4,4179,2925,16716,11700,30.0,INR
|
| 159 |
+
boq_00158,act_003_14,proj_003,Basin & Pedestal Set,unit,4,3792,2655,15168,10620,30.0,INR
|
| 160 |
+
boq_00159,act_003_14,proj_003,CP Fittings Set (Taps/Showers),set,4,5924,4146,23696,16584,30.0,INR
|
| 161 |
+
boq_00160,act_003_15,proj_003,Snagging Rectification Labour,lumpsum,1,5175,3622,5175,3622,30.0,INR
|
| 162 |
+
boq_00161,act_003_15,proj_003,As-Built Drawings & O&M Manual,set,1,2778,1945,2778,1945,30.0,INR
|
| 163 |
+
boq_00162,act_003_15,proj_003,Defect Liability Retention,lumpsum,1,7408,0,7408,0,100.0,INR
|
| 164 |
+
boq_00163,act_004_01,proj_004,Site Survey & Layout,lumpsum,1,3353,2347,3353,2347,30.0,INR
|
| 165 |
+
boq_00164,act_004_01,proj_004,Temporary Site Office Setup,lumpsum,1,7528,5270,7528,5270,30.0,INR
|
| 166 |
+
boq_00165,act_004_01,proj_004,Safety Hoarding & Signage,lumpsum,1,2224,1557,2224,1557,30.0,INR
|
| 167 |
+
boq_00166,act_004_02,proj_004,Demolition Labour & Equipment,lumpsum,1,12396,8677,12396,8677,30.0,INR
|
| 168 |
+
boq_00167,act_004_02,proj_004,Debris Removal & Disposal,trip,6,5720,4004,34320,24024,30.0,INR
|
| 169 |
+
boq_00168,act_004_02,proj_004,Asbestos Survey & Removal,sqm,30,4060,2842,121800,85260,30.0,INR
|
| 170 |
+
boq_00169,act_004_03,proj_004,Reinforced Concrete M30,m3,15,9452,6617,141780,99255,30.0,INR
|
| 171 |
+
boq_00170,act_004_03,proj_004,Steel Rebar TMT 12mm,tonne,6,3751,2625,22506,15750,30.0,INR
|
| 172 |
+
boq_00171,act_004_03,proj_004,Shuttering Plywood 19mm,sheets,30,2234,1564,67020,46920,30.0,INR
|
| 173 |
+
boq_00172,act_004_03,proj_004,Structural Grouting Compound,bags,20,1841,1289,36820,25780,30.0,INR
|
| 174 |
+
boq_00173,act_004_04,proj_004,SBR Waterproofing Membrane,sqm,120,4490,3143,538800,377160,30.0,INR
|
| 175 |
+
boq_00174,act_004_04,proj_004,Crystalline Waterproofing Slurry,kg,50,3202,2242,160100,112100,30.0,INR
|
| 176 |
+
boq_00175,act_004_04,proj_004,Drainage Board & Filter Fabric,sqm,80,1932,1353,154560,108240,30.0,INR
|
| 177 |
+
boq_00176,act_004_05,proj_004,CPVC Pipes 1 inch,meters,180,2800,1960,504000,352800,30.0,INR
|
| 178 |
+
boq_00177,act_004_05,proj_004,uPVC Soil Pipes 4 inch,meters,60,1602,1121,96120,67260,30.0,INR
|
| 179 |
+
boq_00178,act_004_05,proj_004,GI Fittings Set,set,1,1230,861,1230,861,30.0,INR
|
| 180 |
+
boq_00179,act_004_05,proj_004,Water Storage Tank 1000L,unit,2,6142,4300,12284,8600,30.0,INR
|
| 181 |
+
boq_00180,act_004_06,proj_004,FR Copper Wire 4 sq mm,meters,250,4124,2887,1031000,721750,30.0,INR
|
| 182 |
+
boq_00181,act_004_06,proj_004,MCB Distribution Board 18-way,unit,2,5748,4023,11496,8046,30.0,INR
|
| 183 |
+
boq_00182,act_004_06,proj_004,PVC Conduit 25mm,meters,150,1148,804,172200,120600,30.0,INR
|
| 184 |
+
boq_00183,act_004_06,proj_004,Switches & Sockets (Modular),set,1,3078,2155,3078,2155,30.0,INR
|
| 185 |
+
boq_00184,act_004_07,proj_004,Cassette AC Unit 2 Ton,unit,4,13664,9565,54656,38260,30.0,INR
|
| 186 |
+
boq_00185,act_004_07,proj_004,Insulated Ducting,meters,40,4486,3141,179440,125640,30.0,INR
|
| 187 |
+
boq_00186,act_004_07,proj_004,AHU Return Air Grilles,unit,12,1899,1329,22788,15948,30.0,INR
|
| 188 |
+
boq_00187,act_004_07,proj_004,Refrigerant Copper Pipes,meters,60,2506,1754,150360,105240,30.0,INR
|
| 189 |
+
boq_00188,act_004_08,proj_004,Self-Leveling Compound,bags,20,3021,2115,60420,42300,30.0,INR
|
| 190 |
+
boq_00189,act_004_08,proj_004,Bonding Agent SBR,liters,30,1333,933,39990,27990,30.0,INR
|
| 191 |
+
boq_00190,act_004_08,proj_004,DPM Sheet 250 micron,sqm,200,2010,1407,402000,281400,30.0,INR
|
| 192 |
+
boq_00191,act_004_09,proj_004,Vitrified Tiles 800x800mm,sqm,200,7504,5253,1500800,1050600,30.0,INR
|
| 193 |
+
boq_00192,act_004_09,proj_004,Ceramic Tiles 300x600mm,sqm,80,4263,2984,341040,238720,30.0,INR
|
| 194 |
+
boq_00193,act_004_09,proj_004,Tile Adhesive C2 Grade,bags,40,2072,1451,82880,58040,30.0,INR
|
| 195 |
+
boq_00194,act_004_09,proj_004,Tile Grout Mapei,bags,15,696,487,10440,7305,30.0,INR
|
| 196 |
+
boq_00195,act_004_09,proj_004,Tile Edge Trim SS,meters,60,351,246,21060,14760,29.9,INR
|
| 197 |
+
boq_00196,act_004_10,proj_004,Gypsum Plaster 20mm,bags,50,2569,1798,128450,89900,30.0,INR
|
| 198 |
+
boq_00197,act_004_10,proj_004,POP Punning Compound,bags,30,1090,763,32700,22890,30.0,INR
|
| 199 |
+
boq_00198,act_004_10,proj_004,Wire Mesh Reinforcement,sqm,100,949,664,94900,66400,30.0,INR
|
| 200 |
+
boq_00199,act_004_11,proj_004,Gypsum Board 12.5mm,sqm,150,3526,2468,528900,370200,30.0,INR
|
| 201 |
+
boq_00200,act_004_11,proj_004,GI Suspension System,sqm,150,2632,1842,394800,276300,30.0,INR
|
| 202 |
+
boq_00201,act_004_11,proj_004,Glass Wool Insulation 50mm,sqm,100,1904,1333,190400,133300,30.0,INR
|
| 203 |
+
boq_00202,act_004_12,proj_004,Premium Emulsion Paint,liters,120,3633,2543,435960,305160,30.0,INR
|
| 204 |
+
boq_00203,act_004_12,proj_004,Exterior Weather Shield,liters,60,4255,2978,255300,178680,30.0,INR
|
| 205 |
+
boq_00204,act_004_12,proj_004,Primer Coat White,liters,60,1445,1011,86700,60660,30.0,INR
|
| 206 |
+
boq_00205,act_004_12,proj_004,Putty Filler Wall,kg,40,689,482,27560,19280,30.0,INR
|
| 207 |
+
boq_00206,act_004_13,proj_004,Teak Wood Panels Grade A,sqm,30,9262,6484,277860,194520,30.0,INR
|
| 208 |
+
boq_00207,act_004_13,proj_004,Pre-hung Door Sets,unit,8,7283,5098,58264,40784,30.0,INR
|
| 209 |
+
boq_00208,act_004_13,proj_004,Modular Kitchen Framework,lumpsum,1,20306,14214,20306,14214,30.0,INR
|
| 210 |
+
boq_00209,act_004_13,proj_004,Cabinet Hardware Premium Set,set,2,2957,2070,5914,4140,30.0,INR
|
| 211 |
+
boq_00210,act_004_14,proj_004,EWC Rimless Toilet Suite,unit,4,9163,6414,36652,25656,30.0,INR
|
| 212 |
+
boq_00211,act_004_14,proj_004,Concealed Cistern,unit,4,4078,2855,16312,11420,30.0,INR
|
| 213 |
+
boq_00212,act_004_14,proj_004,Basin & Pedestal Set,unit,4,3838,2687,15352,10748,30.0,INR
|
| 214 |
+
boq_00213,act_004_14,proj_004,CP Fittings Set (Taps/Showers),set,4,5742,4019,22968,16076,30.0,INR
|
| 215 |
+
boq_00214,act_004_15,proj_004,Snagging Rectification Labour,lumpsum,1,5235,3664,5235,3664,30.0,INR
|
| 216 |
+
boq_00215,act_004_15,proj_004,As-Built Drawings & O&M Manual,set,1,3066,2146,3066,2146,30.0,INR
|
| 217 |
+
boq_00216,act_004_15,proj_004,Defect Liability Retention,lumpsum,1,7448,0,7448,0,100.0,INR
|
| 218 |
+
boq_00217,act_005_01,proj_005,Site Survey & Layout,lumpsum,1,3318,2323,3318,2323,30.0,INR
|
| 219 |
+
boq_00218,act_005_01,proj_005,Temporary Site Office Setup,lumpsum,1,8368,5858,8368,5858,30.0,INR
|
| 220 |
+
boq_00219,act_005_01,proj_005,Safety Hoarding & Signage,lumpsum,1,2332,1632,2332,1632,30.0,INR
|
| 221 |
+
boq_00220,act_005_02,proj_005,Demolition Labour & Equipment,lumpsum,1,12672,8870,12672,8870,30.0,INR
|
| 222 |
+
boq_00221,act_005_02,proj_005,Debris Removal & Disposal,trip,6,5269,3688,31614,22128,30.0,INR
|
| 223 |
+
boq_00222,act_005_02,proj_005,Asbestos Survey & Removal,sqm,30,4184,2929,125520,87870,30.0,INR
|
| 224 |
+
boq_00223,act_005_03,proj_005,Reinforced Concrete M30,m3,15,10127,7089,151905,106335,30.0,INR
|
| 225 |
+
boq_00224,act_005_03,proj_005,Steel Rebar TMT 12mm,tonne,6,3815,2671,22890,16026,30.0,INR
|
| 226 |
+
boq_00225,act_005_03,proj_005,Shuttering Plywood 19mm,sheets,30,2165,1516,64950,45480,30.0,INR
|
| 227 |
+
boq_00226,act_005_03,proj_005,Structural Grouting Compound,bags,20,1683,1178,33660,23560,30.0,INR
|
| 228 |
+
boq_00227,act_005_04,proj_005,SBR Waterproofing Membrane,sqm,120,4502,3152,540240,378240,30.0,INR
|
| 229 |
+
boq_00228,act_005_04,proj_005,Crystalline Waterproofing Slurry,kg,50,3258,2281,162900,114050,30.0,INR
|
| 230 |
+
boq_00229,act_005_04,proj_005,Drainage Board & Filter Fabric,sqm,80,1965,1375,157200,110000,30.0,INR
|
| 231 |
+
boq_00230,act_005_05,proj_005,CPVC Pipes 1 inch,meters,180,2724,1907,490320,343260,30.0,INR
|
| 232 |
+
boq_00231,act_005_05,proj_005,uPVC Soil Pipes 4 inch,meters,60,1587,1111,95220,66660,30.0,INR
|
| 233 |
+
boq_00232,act_005_05,proj_005,GI Fittings Set,set,1,1332,933,1332,933,30.0,INR
|
| 234 |
+
boq_00233,act_005_05,proj_005,Water Storage Tank 1000L,unit,2,6396,4477,12792,8954,30.0,INR
|
| 235 |
+
boq_00234,act_005_06,proj_005,FR Copper Wire 4 sq mm,meters,250,4204,2943,1051000,735750,30.0,INR
|
| 236 |
+
boq_00235,act_005_06,proj_005,MCB Distribution Board 18-way,unit,2,5527,3869,11054,7738,30.0,INR
|
| 237 |
+
boq_00236,act_005_06,proj_005,PVC Conduit 25mm,meters,150,1122,785,168300,117750,30.0,INR
|
| 238 |
+
boq_00237,act_005_06,proj_005,Switches & Sockets (Modular),set,1,3274,2292,3274,2292,30.0,INR
|
| 239 |
+
boq_00238,act_005_07,proj_005,Cassette AC Unit 2 Ton,unit,4,14812,10368,59248,41472,30.0,INR
|
| 240 |
+
boq_00239,act_005_07,proj_005,Insulated Ducting,meters,40,4401,3081,176040,123240,30.0,INR
|
| 241 |
+
boq_00240,act_005_07,proj_005,AHU Return Air Grilles,unit,12,1683,1178,20196,14136,30.0,INR
|
| 242 |
+
boq_00241,act_005_07,proj_005,Refrigerant Copper Pipes,meters,60,2681,1876,160860,112560,30.0,INR
|
| 243 |
+
boq_00242,act_005_08,proj_005,Self-Leveling Compound,bags,20,2963,2074,59260,41480,30.0,INR
|
| 244 |
+
boq_00243,act_005_08,proj_005,Bonding Agent SBR,liters,30,1308,915,39240,27450,30.0,INR
|
| 245 |
+
boq_00244,act_005_08,proj_005,DPM Sheet 250 micron,sqm,200,2213,1549,442600,309800,30.0,INR
|
| 246 |
+
boq_00245,act_005_09,proj_005,Vitrified Tiles 800x800mm,sqm,200,7621,5334,1524200,1066800,30.0,INR
|
| 247 |
+
boq_00246,act_005_09,proj_005,Ceramic Tiles 300x600mm,sqm,80,4301,3011,344080,240880,30.0,INR
|
| 248 |
+
boq_00247,act_005_09,proj_005,Tile Adhesive C2 Grade,bags,40,2099,1469,83960,58760,30.0,INR
|
| 249 |
+
boq_00248,act_005_09,proj_005,Tile Grout Mapei,bags,15,604,423,9060,6345,30.0,INR
|
| 250 |
+
boq_00249,act_005_09,proj_005,Tile Edge Trim SS,meters,60,359,251,21540,15060,30.1,INR
|
| 251 |
+
boq_00250,act_005_10,proj_005,Gypsum Plaster 20mm,bags,50,2779,1946,138950,97300,30.0,INR
|
| 252 |
+
boq_00251,act_005_10,proj_005,POP Punning Compound,bags,30,1047,733,31410,21990,30.0,INR
|
| 253 |
+
boq_00252,act_005_10,proj_005,Wire Mesh Reinforcement,sqm,100,901,630,90100,63000,30.1,INR
|
| 254 |
+
boq_00253,act_005_11,proj_005,Gypsum Board 12.5mm,sqm,150,3318,2323,497700,348450,30.0,INR
|
| 255 |
+
boq_00254,act_005_11,proj_005,GI Suspension System,sqm,150,2582,1807,387300,271050,30.0,INR
|
| 256 |
+
boq_00255,act_005_11,proj_005,Glass Wool Insulation 50mm,sqm,100,2008,1406,200800,140600,30.0,INR
|
| 257 |
+
boq_00256,act_005_12,proj_005,Premium Emulsion Paint,liters,120,3998,2798,479760,335760,30.0,INR
|
| 258 |
+
boq_00257,act_005_12,proj_005,Exterior Weather Shield,liters,60,4242,2969,254520,178140,30.0,INR
|
| 259 |
+
boq_00258,act_005_12,proj_005,Primer Coat White,liters,60,1390,973,83400,58380,30.0,INR
|
| 260 |
+
boq_00259,act_005_12,proj_005,Putty Filler Wall,kg,40,713,499,28520,19960,30.0,INR
|
| 261 |
+
boq_00260,act_005_13,proj_005,Teak Wood Panels Grade A,sqm,30,9139,6397,274170,191910,30.0,INR
|
| 262 |
+
boq_00261,act_005_13,proj_005,Pre-hung Door Sets,unit,8,7079,4955,56632,39640,30.0,INR
|
| 263 |
+
boq_00262,act_005_13,proj_005,Modular Kitchen Framework,lumpsum,1,22352,15646,22352,15646,30.0,INR
|
| 264 |
+
boq_00263,act_005_13,proj_005,Cabinet Hardware Premium Set,set,2,3299,2309,6598,4618,30.0,INR
|
| 265 |
+
boq_00264,act_005_14,proj_005,EWC Rimless Toilet Suite,unit,4,7828,5480,31312,21920,30.0,INR
|
| 266 |
+
boq_00265,act_005_14,proj_005,Concealed Cistern,unit,4,3940,2758,15760,11032,30.0,INR
|
| 267 |
+
boq_00266,act_005_14,proj_005,Basin & Pedestal Set,unit,4,3515,2460,14060,9840,30.0,INR
|
| 268 |
+
boq_00267,act_005_14,proj_005,CP Fittings Set (Taps/Showers),set,4,5247,3673,20988,14692,30.0,INR
|
| 269 |
+
boq_00268,act_005_15,proj_005,Snagging Rectification Labour,lumpsum,1,5100,3570,5100,3570,30.0,INR
|
| 270 |
+
boq_00269,act_005_15,proj_005,As-Built Drawings & O&M Manual,set,1,2829,1980,2829,1980,30.0,INR
|
| 271 |
+
boq_00270,act_005_15,proj_005,Defect Liability Retention,lumpsum,1,7920,0,7920,0,100.0,INR
|
| 272 |
+
boq_00271,act_006_01,proj_006,Site Survey & Layout,lumpsum,1,3762,2634,3762,2634,30.0,INR
|
| 273 |
+
boq_00272,act_006_01,proj_006,Temporary Site Office Setup,lumpsum,1,8104,5673,8104,5673,30.0,INR
|
| 274 |
+
boq_00273,act_006_01,proj_006,Safety Hoarding & Signage,lumpsum,1,2141,1498,2141,1498,30.0,INR
|
| 275 |
+
boq_00274,act_006_02,proj_006,Demolition Labour & Equipment,lumpsum,1,11400,7980,11400,7980,30.0,INR
|
| 276 |
+
boq_00275,act_006_02,proj_006,Debris Removal & Disposal,trip,6,5698,3989,34188,23934,30.0,INR
|
| 277 |
+
boq_00276,act_006_02,proj_006,Asbestos Survey & Removal,sqm,30,4120,2884,123600,86520,30.0,INR
|
| 278 |
+
boq_00277,act_006_03,proj_006,Reinforced Concrete M30,m3,15,10232,7162,153480,107430,30.0,INR
|
| 279 |
+
boq_00278,act_006_03,proj_006,Steel Rebar TMT 12mm,tonne,6,3735,2615,22410,15690,30.0,INR
|
| 280 |
+
boq_00279,act_006_03,proj_006,Shuttering Plywood 19mm,sheets,30,2258,1580,67740,47400,30.0,INR
|
| 281 |
+
boq_00280,act_006_03,proj_006,Structural Grouting Compound,bags,20,1778,1245,35560,24900,30.0,INR
|
| 282 |
+
boq_00281,act_006_04,proj_006,SBR Waterproofing Membrane,sqm,120,4351,3046,522120,365520,30.0,INR
|
| 283 |
+
boq_00282,act_006_04,proj_006,Crystalline Waterproofing Slurry,kg,50,3252,2276,162600,113800,30.0,INR
|
| 284 |
+
boq_00283,act_006_04,proj_006,Drainage Board & Filter Fabric,sqm,80,1782,1248,142560,99840,30.0,INR
|
| 285 |
+
boq_00284,act_006_05,proj_006,CPVC Pipes 1 inch,meters,180,2747,1923,494460,346140,30.0,INR
|
| 286 |
+
boq_00285,act_006_05,proj_006,uPVC Soil Pipes 4 inch,meters,60,1562,1093,93720,65580,30.0,INR
|
| 287 |
+
boq_00286,act_006_05,proj_006,GI Fittings Set,set,1,1332,933,1332,933,30.0,INR
|
| 288 |
+
boq_00287,act_006_05,proj_006,Water Storage Tank 1000L,unit,2,6045,4232,12090,8464,30.0,INR
|
| 289 |
+
boq_00288,act_006_06,proj_006,FR Copper Wire 4 sq mm,meters,250,4465,3125,1116250,781250,30.0,INR
|
| 290 |
+
boq_00289,act_006_06,proj_006,MCB Distribution Board 18-way,unit,2,5346,3742,10692,7484,30.0,INR
|
| 291 |
+
boq_00290,act_006_06,proj_006,PVC Conduit 25mm,meters,150,1076,753,161400,112950,30.0,INR
|
| 292 |
+
boq_00291,act_006_06,proj_006,Switches & Sockets (Modular),set,1,3245,2271,3245,2271,30.0,INR
|
| 293 |
+
boq_00292,act_006_07,proj_006,Cassette AC Unit 2 Ton,unit,4,13776,9643,55104,38572,30.0,INR
|
| 294 |
+
boq_00293,act_006_07,proj_006,Insulated Ducting,meters,40,4662,3263,186480,130520,30.0,INR
|
| 295 |
+
boq_00294,act_006_07,proj_006,AHU Return Air Grilles,unit,12,1935,1354,23220,16248,30.0,INR
|
| 296 |
+
boq_00295,act_006_07,proj_006,Refrigerant Copper Pipes,meters,60,2709,1896,162540,113760,30.0,INR
|
| 297 |
+
boq_00296,act_006_08,proj_006,Self-Leveling Compound,bags,20,3245,2271,64900,45420,30.0,INR
|
| 298 |
+
boq_00297,act_006_08,proj_006,Bonding Agent SBR,liters,30,1365,956,40950,28680,30.0,INR
|
| 299 |
+
boq_00298,act_006_08,proj_006,DPM Sheet 250 micron,sqm,200,2207,1545,441400,309000,30.0,INR
|
| 300 |
+
boq_00299,act_006_09,proj_006,Vitrified Tiles 800x800mm,sqm,200,7839,5487,1567800,1097400,30.0,INR
|
| 301 |
+
boq_00300,act_006_09,proj_006,Ceramic Tiles 300x600mm,sqm,80,4435,3105,354800,248400,30.0,INR
|
| 302 |
+
boq_00301,act_006_09,proj_006,Tile Adhesive C2 Grade,bags,40,2226,1558,89040,62320,30.0,INR
|
| 303 |
+
boq_00302,act_006_09,proj_006,Tile Grout Mapei,bags,15,687,481,10305,7215,30.0,INR
|
| 304 |
+
boq_00303,act_006_09,proj_006,Tile Edge Trim SS,meters,60,365,256,21900,15360,29.9,INR
|
| 305 |
+
boq_00304,act_006_10,proj_006,Gypsum Plaster 20mm,bags,50,2738,1916,136900,95800,30.0,INR
|
| 306 |
+
boq_00305,act_006_10,proj_006,POP Punning Compound,bags,30,1165,815,34950,24450,30.0,INR
|
| 307 |
+
boq_00306,act_006_10,proj_006,Wire Mesh Reinforcement,sqm,100,884,618,88400,61800,30.1,INR
|
| 308 |
+
boq_00307,act_006_11,proj_006,Gypsum Board 12.5mm,sqm,150,3349,2344,502350,351600,30.0,INR
|
| 309 |
+
boq_00308,act_006_11,proj_006,GI Suspension System,sqm,150,2794,1956,419100,293400,30.0,INR
|
| 310 |
+
boq_00309,act_006_11,proj_006,Glass Wool Insulation 50mm,sqm,100,1759,1232,175900,123200,30.0,INR
|
| 311 |
+
boq_00310,act_006_12,proj_006,Premium Emulsion Paint,liters,120,4013,2809,481560,337080,30.0,INR
|
| 312 |
+
boq_00311,act_006_12,proj_006,Exterior Weather Shield,liters,60,4061,2843,243660,170580,30.0,INR
|
| 313 |
+
boq_00312,act_006_12,proj_006,Primer Coat White,liters,60,1302,911,78120,54660,30.0,INR
|
| 314 |
+
boq_00313,act_006_12,proj_006,Putty Filler Wall,kg,40,733,513,29320,20520,30.0,INR
|
| 315 |
+
boq_00314,act_006_13,proj_006,Teak Wood Panels Grade A,sqm,30,9054,6337,271620,190110,30.0,INR
|
| 316 |
+
boq_00315,act_006_13,proj_006,Pre-hung Door Sets,unit,8,6399,4479,51192,35832,30.0,INR
|
| 317 |
+
boq_00316,act_006_13,proj_006,Modular Kitchen Framework,lumpsum,1,23210,16247,23210,16247,30.0,INR
|
| 318 |
+
boq_00317,act_006_13,proj_006,Cabinet Hardware Premium Set,set,2,3450,2415,6900,4830,30.0,INR
|
| 319 |
+
boq_00318,act_006_14,proj_006,EWC Rimless Toilet Suite,unit,4,9138,6396,36552,25584,30.0,INR
|
| 320 |
+
boq_00319,act_006_14,proj_006,Concealed Cistern,unit,4,4410,3087,17640,12348,30.0,INR
|
| 321 |
+
boq_00320,act_006_14,proj_006,Basin & Pedestal Set,unit,4,3747,2623,14988,10492,30.0,INR
|
| 322 |
+
boq_00321,act_006_14,proj_006,CP Fittings Set (Taps/Showers),set,4,5863,4104,23452,16416,30.0,INR
|
| 323 |
+
boq_00322,act_006_15,proj_006,Snagging Rectification Labour,lumpsum,1,4965,3476,4965,3476,30.0,INR
|
| 324 |
+
boq_00323,act_006_15,proj_006,As-Built Drawings & O&M Manual,set,1,3054,2138,3054,2138,30.0,INR
|
| 325 |
+
boq_00324,act_006_15,proj_006,Defect Liability Retention,lumpsum,1,7600,0,7600,0,100.0,INR
|
| 326 |
+
boq_00325,act_007_01,proj_007,Site Survey & Layout,lumpsum,1,3742,2619,3742,2619,30.0,INR
|
| 327 |
+
boq_00326,act_007_01,proj_007,Temporary Site Office Setup,lumpsum,1,7928,5550,7928,5550,30.0,INR
|
| 328 |
+
boq_00327,act_007_01,proj_007,Safety Hoarding & Signage,lumpsum,1,2347,1643,2347,1643,30.0,INR
|
| 329 |
+
boq_00328,act_007_02,proj_007,Demolition Labour & Equipment,lumpsum,1,11172,7820,11172,7820,30.0,INR
|
| 330 |
+
boq_00329,act_007_02,proj_007,Debris Removal & Disposal,trip,6,5929,4150,35574,24900,30.0,INR
|
| 331 |
+
boq_00330,act_007_02,proj_007,Asbestos Survey & Removal,sqm,30,3920,2744,117600,82320,30.0,INR
|
| 332 |
+
boq_00331,act_007_03,proj_007,Reinforced Concrete M30,m3,15,9186,6431,137790,96465,30.0,INR
|
| 333 |
+
boq_00332,act_007_03,proj_007,Steel Rebar TMT 12mm,tonne,6,3747,2623,22482,15738,30.0,INR
|
| 334 |
+
boq_00333,act_007_03,proj_007,Shuttering Plywood 19mm,sheets,30,2216,1551,66480,46530,30.0,INR
|
| 335 |
+
boq_00334,act_007_03,proj_007,Structural Grouting Compound,bags,20,1870,1309,37400,26180,30.0,INR
|
| 336 |
+
boq_00335,act_007_04,proj_007,SBR Waterproofing Membrane,sqm,120,4309,3016,517080,361920,30.0,INR
|
| 337 |
+
boq_00336,act_007_04,proj_007,Crystalline Waterproofing Slurry,kg,50,2979,2085,148950,104250,30.0,INR
|
| 338 |
+
boq_00337,act_007_04,proj_007,Drainage Board & Filter Fabric,sqm,80,1889,1322,151120,105760,30.0,INR
|
| 339 |
+
boq_00338,act_007_05,proj_007,CPVC Pipes 1 inch,meters,180,2652,1856,477360,334080,30.0,INR
|
| 340 |
+
boq_00339,act_007_05,proj_007,uPVC Soil Pipes 4 inch,meters,60,1707,1195,102420,71700,30.0,INR
|
| 341 |
+
boq_00340,act_007_05,proj_007,GI Fittings Set,set,1,1362,954,1362,954,30.0,INR
|
| 342 |
+
boq_00341,act_007_05,proj_007,Water Storage Tank 1000L,unit,2,6253,4377,12506,8754,30.0,INR
|
| 343 |
+
boq_00342,act_007_06,proj_007,FR Copper Wire 4 sq mm,meters,250,3969,2778,992250,694500,30.0,INR
|
| 344 |
+
boq_00343,act_007_06,proj_007,MCB Distribution Board 18-way,unit,2,5274,3692,10548,7384,30.0,INR
|
| 345 |
+
boq_00344,act_007_06,proj_007,PVC Conduit 25mm,meters,150,1100,770,165000,115500,30.0,INR
|
| 346 |
+
boq_00345,act_007_06,proj_007,Switches & Sockets (Modular),set,1,3130,2191,3130,2191,30.0,INR
|
| 347 |
+
boq_00346,act_007_07,proj_007,Cassette AC Unit 2 Ton,unit,4,13566,9496,54264,37984,30.0,INR
|
| 348 |
+
boq_00347,act_007_07,proj_007,Insulated Ducting,meters,40,4702,3292,188080,131680,30.0,INR
|
| 349 |
+
boq_00348,act_007_07,proj_007,AHU Return Air Grilles,unit,12,1669,1168,20028,14016,30.0,INR
|
| 350 |
+
boq_00349,act_007_07,proj_007,Refrigerant Copper Pipes,meters,60,2506,1754,150360,105240,30.0,INR
|
| 351 |
+
boq_00350,act_007_08,proj_007,Self-Leveling Compound,bags,20,2957,2070,59140,41400,30.0,INR
|
| 352 |
+
boq_00351,act_007_08,proj_007,Bonding Agent SBR,liters,30,1347,943,40410,28290,30.0,INR
|
| 353 |
+
boq_00352,act_007_08,proj_007,DPM Sheet 250 micron,sqm,200,2121,1485,424200,297000,30.0,INR
|
| 354 |
+
boq_00353,act_007_09,proj_007,Vitrified Tiles 800x800mm,sqm,200,7340,5138,1468000,1027600,30.0,INR
|
| 355 |
+
boq_00354,act_007_09,proj_007,Ceramic Tiles 300x600mm,sqm,80,3931,2752,314480,220160,30.0,INR
|
| 356 |
+
boq_00355,act_007_09,proj_007,Tile Adhesive C2 Grade,bags,40,2136,1495,85440,59800,30.0,INR
|
| 357 |
+
boq_00356,act_007_09,proj_007,Tile Grout Mapei,bags,15,615,430,9225,6450,30.1,INR
|
| 358 |
+
boq_00357,act_007_09,proj_007,Tile Edge Trim SS,meters,60,393,275,23580,16500,30.0,INR
|
| 359 |
+
boq_00358,act_007_10,proj_007,Gypsum Plaster 20mm,bags,50,2792,1955,139600,97750,30.0,INR
|
| 360 |
+
boq_00359,act_007_10,proj_007,POP Punning Compound,bags,30,1041,728,31230,21840,30.1,INR
|
| 361 |
+
boq_00360,act_007_10,proj_007,Wire Mesh Reinforcement,sqm,100,881,616,88100,61600,30.1,INR
|
| 362 |
+
boq_00361,act_007_11,proj_007,Gypsum Board 12.5mm,sqm,150,3193,2235,478950,335250,30.0,INR
|
| 363 |
+
boq_00362,act_007_11,proj_007,GI Suspension System,sqm,150,2621,1835,393150,275250,30.0,INR
|
| 364 |
+
boq_00363,act_007_11,proj_007,Glass Wool Insulation 50mm,sqm,100,1909,1337,190900,133700,30.0,INR
|
| 365 |
+
boq_00364,act_007_12,proj_007,Premium Emulsion Paint,liters,120,3709,2596,445080,311520,30.0,INR
|
| 366 |
+
boq_00365,act_007_12,proj_007,Exterior Weather Shield,liters,60,4234,2964,254040,177840,30.0,INR
|
| 367 |
+
boq_00366,act_007_12,proj_007,Primer Coat White,liters,60,1386,970,83160,58200,30.0,INR
|
| 368 |
+
boq_00367,act_007_12,proj_007,Putty Filler Wall,kg,40,762,534,30480,21360,29.9,INR
|
| 369 |
+
boq_00368,act_007_13,proj_007,Teak Wood Panels Grade A,sqm,30,9528,6670,285840,200100,30.0,INR
|
| 370 |
+
boq_00369,act_007_13,proj_007,Pre-hung Door Sets,unit,8,6984,4889,55872,39112,30.0,INR
|
| 371 |
+
boq_00370,act_007_13,proj_007,Modular Kitchen Framework,lumpsum,1,23144,16201,23144,16201,30.0,INR
|
| 372 |
+
boq_00371,act_007_13,proj_007,Cabinet Hardware Premium Set,set,2,3456,2419,6912,4838,30.0,INR
|
| 373 |
+
boq_00372,act_007_14,proj_007,EWC Rimless Toilet Suite,unit,4,9112,6378,36448,25512,30.0,INR
|
| 374 |
+
boq_00373,act_007_14,proj_007,Concealed Cistern,unit,4,4456,3119,17824,12476,30.0,INR
|
| 375 |
+
boq_00374,act_007_14,proj_007,Basin & Pedestal Set,unit,4,3754,2628,15016,10512,30.0,INR
|
| 376 |
+
boq_00375,act_007_14,proj_007,CP Fittings Set (Taps/Showers),set,4,5159,3611,20636,14444,30.0,INR
|
| 377 |
+
boq_00376,act_007_15,proj_007,Snagging Rectification Labour,lumpsum,1,5315,3720,5315,3720,30.0,INR
|
| 378 |
+
boq_00377,act_007_15,proj_007,As-Built Drawings & O&M Manual,set,1,3207,2245,3207,2245,30.0,INR
|
| 379 |
+
boq_00378,act_007_15,proj_007,Defect Liability Retention,lumpsum,1,7456,0,7456,0,100.0,INR
|
| 380 |
+
boq_00379,act_008_01,proj_008,Site Survey & Layout,lumpsum,1,3468,2428,3468,2428,30.0,INR
|
| 381 |
+
boq_00380,act_008_01,proj_008,Temporary Site Office Setup,lumpsum,1,8432,5902,8432,5902,30.0,INR
|
| 382 |
+
boq_00381,act_008_01,proj_008,Safety Hoarding & Signage,lumpsum,1,2369,1659,2369,1659,30.0,INR
|
| 383 |
+
boq_00382,act_008_02,proj_008,Demolition Labour & Equipment,lumpsum,1,11376,7963,11376,7963,30.0,INR
|
| 384 |
+
boq_00383,act_008_02,proj_008,Debris Removal & Disposal,trip,6,5836,4085,35016,24510,30.0,INR
|
| 385 |
+
boq_00384,act_008_02,proj_008,Asbestos Survey & Removal,sqm,30,3760,2632,112800,78960,30.0,INR
|
| 386 |
+
boq_00385,act_008_03,proj_008,Reinforced Concrete M30,m3,15,10032,7022,150480,105330,30.0,INR
|
| 387 |
+
boq_00386,act_008_03,proj_008,Steel Rebar TMT 12mm,tonne,6,3659,2562,21954,15372,30.0,INR
|
| 388 |
+
boq_00387,act_008_03,proj_008,Shuttering Plywood 19mm,sheets,30,1987,1391,59610,41730,30.0,INR
|
| 389 |
+
boq_00388,act_008_03,proj_008,Structural Grouting Compound,bags,20,1778,1245,35560,24900,30.0,INR
|
| 390 |
+
boq_00389,act_008_04,proj_008,SBR Waterproofing Membrane,sqm,120,4523,3166,542760,379920,30.0,INR
|
| 391 |
+
boq_00390,act_008_04,proj_008,Crystalline Waterproofing Slurry,kg,50,3153,2207,157650,110350,30.0,INR
|
| 392 |
+
boq_00391,act_008_04,proj_008,Drainage Board & Filter Fabric,sqm,80,1824,1277,145920,102160,30.0,INR
|
| 393 |
+
boq_00392,act_008_05,proj_008,CPVC Pipes 1 inch,meters,180,2666,1866,479880,335880,30.0,INR
|
| 394 |
+
boq_00393,act_008_05,proj_008,uPVC Soil Pipes 4 inch,meters,60,1491,1044,89460,62640,30.0,INR
|
| 395 |
+
boq_00394,act_008_05,proj_008,GI Fittings Set,set,1,1300,910,1300,910,30.0,INR
|
| 396 |
+
boq_00395,act_008_05,proj_008,Water Storage Tank 1000L,unit,2,6662,4664,13324,9328,30.0,INR
|
| 397 |
+
boq_00396,act_008_06,proj_008,FR Copper Wire 4 sq mm,meters,250,4418,3093,1104500,773250,30.0,INR
|
| 398 |
+
boq_00397,act_008_06,proj_008,MCB Distribution Board 18-way,unit,2,5324,3727,10648,7454,30.0,INR
|
| 399 |
+
boq_00398,act_008_06,proj_008,PVC Conduit 25mm,meters,150,1178,825,176700,123750,30.0,INR
|
| 400 |
+
boq_00399,act_008_06,proj_008,Switches & Sockets (Modular),set,1,3069,2148,3069,2148,30.0,INR
|
| 401 |
+
boq_00400,act_008_07,proj_008,Cassette AC Unit 2 Ton,unit,4,14364,10055,57456,40220,30.0,INR
|
| 402 |
+
boq_00401,act_008_07,proj_008,Insulated Ducting,meters,40,4604,3222,184160,128880,30.0,INR
|
| 403 |
+
boq_00402,act_008_07,proj_008,AHU Return Air Grilles,unit,12,1777,1244,21324,14928,30.0,INR
|
| 404 |
+
boq_00403,act_008_07,proj_008,Refrigerant Copper Pipes,meters,60,2668,1867,160080,112020,30.0,INR
|
| 405 |
+
boq_00404,act_008_08,proj_008,Self-Leveling Compound,bags,20,3434,2404,68680,48080,30.0,INR
|
| 406 |
+
boq_00405,act_008_08,proj_008,Bonding Agent SBR,liters,30,1344,941,40320,28230,30.0,INR
|
| 407 |
+
boq_00406,act_008_08,proj_008,DPM Sheet 250 micron,sqm,200,1976,1383,395200,276600,30.0,INR
|
| 408 |
+
boq_00407,act_008_09,proj_008,Vitrified Tiles 800x800mm,sqm,200,7316,5121,1463200,1024200,30.0,INR
|
| 409 |
+
boq_00408,act_008_09,proj_008,Ceramic Tiles 300x600mm,sqm,80,3961,2772,316880,221760,30.0,INR
|
| 410 |
+
boq_00409,act_008_09,proj_008,Tile Adhesive C2 Grade,bags,40,2145,1502,85800,60080,30.0,INR
|
| 411 |
+
boq_00410,act_008_09,proj_008,Tile Grout Mapei,bags,15,697,488,10455,7320,30.0,INR
|
| 412 |
+
boq_00411,act_008_09,proj_008,Tile Edge Trim SS,meters,60,352,247,21120,14820,29.8,INR
|
| 413 |
+
boq_00412,act_008_10,proj_008,Gypsum Plaster 20mm,bags,50,2634,1844,131700,92200,30.0,INR
|
| 414 |
+
boq_00413,act_008_10,proj_008,POP Punning Compound,bags,30,1188,832,35640,24960,30.0,INR
|
| 415 |
+
boq_00414,act_008_10,proj_008,Wire Mesh Reinforcement,sqm,100,954,668,95400,66800,30.0,INR
|
| 416 |
+
boq_00415,act_008_11,proj_008,Gypsum Board 12.5mm,sqm,150,3499,2449,524850,367350,30.0,INR
|
| 417 |
+
boq_00416,act_008_11,proj_008,GI Suspension System,sqm,150,2862,2003,429300,300450,30.0,INR
|
| 418 |
+
boq_00417,act_008_11,proj_008,Glass Wool Insulation 50mm,sqm,100,1767,1237,176700,123700,30.0,INR
|
| 419 |
+
boq_00418,act_008_12,proj_008,Premium Emulsion Paint,liters,120,3686,2580,442320,309600,30.0,INR
|
| 420 |
+
boq_00419,act_008_12,proj_008,Exterior Weather Shield,liters,60,4141,2899,248460,173940,30.0,INR
|
| 421 |
+
boq_00420,act_008_12,proj_008,Primer Coat White,liters,60,1386,970,83160,58200,30.0,INR
|
| 422 |
+
boq_00421,act_008_12,proj_008,Putty Filler Wall,kg,40,667,467,26680,18680,30.0,INR
|
| 423 |
+
boq_00422,act_008_13,proj_008,Teak Wood Panels Grade A,sqm,30,9918,6943,297540,208290,30.0,INR
|
| 424 |
+
boq_00423,act_008_13,proj_008,Pre-hung Door Sets,unit,8,6793,4755,54344,38040,30.0,INR
|
| 425 |
+
boq_00424,act_008_13,proj_008,Modular Kitchen Framework,lumpsum,1,20856,14599,20856,14599,30.0,INR
|
| 426 |
+
boq_00425,act_008_13,proj_008,Cabinet Hardware Premium Set,set,2,3165,2215,6330,4430,30.0,INR
|
| 427 |
+
boq_00426,act_008_14,proj_008,EWC Rimless Toilet Suite,unit,4,8390,5873,33560,23492,30.0,INR
|
| 428 |
+
boq_00427,act_008_14,proj_008,Concealed Cistern,unit,4,4330,3031,17320,12124,30.0,INR
|
| 429 |
+
boq_00428,act_008_14,proj_008,Basin & Pedestal Set,unit,4,3496,2447,13984,9788,30.0,INR
|
| 430 |
+
boq_00429,act_008_14,proj_008,CP Fittings Set (Taps/Showers),set,4,5357,3750,21428,15000,30.0,INR
|
| 431 |
+
boq_00430,act_008_15,proj_008,Snagging Rectification Labour,lumpsum,1,5270,3689,5270,3689,30.0,INR
|
| 432 |
+
boq_00431,act_008_15,proj_008,As-Built Drawings & O&M Manual,set,1,2937,2056,2937,2056,30.0,INR
|
| 433 |
+
boq_00432,act_008_15,proj_008,Defect Liability Retention,lumpsum,1,8272,0,8272,0,100.0,INR
|
| 434 |
+
boq_00433,act_009_01,proj_009,Site Survey & Layout,lumpsum,1,3227,2259,3227,2259,30.0,INR
|
| 435 |
+
boq_00434,act_009_01,proj_009,Temporary Site Office Setup,lumpsum,1,8424,5897,8424,5897,30.0,INR
|
| 436 |
+
boq_00435,act_009_01,proj_009,Safety Hoarding & Signage,lumpsum,1,2141,1498,2141,1498,30.0,INR
|
| 437 |
+
boq_00436,act_009_02,proj_009,Demolition Labour & Equipment,lumpsum,1,11472,8030,11472,8030,30.0,INR
|
| 438 |
+
boq_00437,act_009_02,proj_009,Debris Removal & Disposal,trip,6,5384,3769,32304,22614,30.0,INR
|
| 439 |
+
boq_00438,act_009_02,proj_009,Asbestos Survey & Removal,sqm,30,3720,2604,111600,78120,30.0,INR
|
| 440 |
+
boq_00439,act_009_03,proj_009,Reinforced Concrete M30,m3,15,9168,6417,137520,96255,30.0,INR
|
| 441 |
+
boq_00440,act_009_03,proj_009,Steel Rebar TMT 12mm,tonne,6,3690,2583,22140,15498,30.0,INR
|
| 442 |
+
boq_00441,act_009_03,proj_009,Shuttering Plywood 19mm,sheets,30,1999,1399,59970,41970,30.0,INR
|
| 443 |
+
boq_00442,act_009_03,proj_009,Structural Grouting Compound,bags,20,1687,1181,33740,23620,30.0,INR
|
| 444 |
+
boq_00443,act_009_04,proj_009,SBR Waterproofing Membrane,sqm,120,3961,2772,475320,332640,30.0,INR
|
| 445 |
+
boq_00444,act_009_04,proj_009,Crystalline Waterproofing Slurry,kg,50,2973,2081,148650,104050,30.0,INR
|
| 446 |
+
boq_00445,act_009_04,proj_009,Drainage Board & Filter Fabric,sqm,80,2027,1419,162160,113520,30.0,INR
|
| 447 |
+
boq_00446,act_009_05,proj_009,CPVC Pipes 1 inch,meters,180,2803,1962,504540,353160,30.0,INR
|
| 448 |
+
boq_00447,act_009_05,proj_009,uPVC Soil Pipes 4 inch,meters,60,1555,1089,93300,65340,30.0,INR
|
| 449 |
+
boq_00448,act_009_05,proj_009,GI Fittings Set,set,1,1404,983,1404,983,30.0,INR
|
| 450 |
+
boq_00449,act_009_05,proj_009,Water Storage Tank 1000L,unit,2,6740,4718,13480,9436,30.0,INR
|
| 451 |
+
boq_00450,act_009_06,proj_009,FR Copper Wire 4 sq mm,meters,250,4003,2802,1000750,700500,30.0,INR
|
| 452 |
+
boq_00451,act_009_06,proj_009,MCB Distribution Board 18-way,unit,2,5318,3723,10636,7446,30.0,INR
|
| 453 |
+
boq_00452,act_009_06,proj_009,PVC Conduit 25mm,meters,150,1031,721,154650,108150,30.1,INR
|
| 454 |
+
boq_00453,act_009_06,proj_009,Switches & Sockets (Modular),set,1,3322,2325,3322,2325,30.0,INR
|
| 455 |
+
boq_00454,act_009_07,proj_009,Cassette AC Unit 2 Ton,unit,4,15050,10535,60200,42140,30.0,INR
|
| 456 |
+
boq_00455,act_009_07,proj_009,Insulated Ducting,meters,40,4680,3276,187200,131040,30.0,INR
|
| 457 |
+
boq_00456,act_009_07,proj_009,AHU Return Air Grilles,unit,12,1897,1328,22764,15936,30.0,INR
|
| 458 |
+
boq_00457,act_009_07,proj_009,Refrigerant Copper Pipes,meters,60,2538,1776,152280,106560,30.0,INR
|
| 459 |
+
boq_00458,act_009_08,proj_009,Self-Leveling Compound,bags,20,3312,2318,66240,46360,30.0,INR
|
| 460 |
+
boq_00459,act_009_08,proj_009,Bonding Agent SBR,liters,30,1350,945,40500,28350,30.0,INR
|
| 461 |
+
boq_00460,act_009_08,proj_009,DPM Sheet 250 micron,sqm,200,2106,1474,421200,294800,30.0,INR
|
| 462 |
+
boq_00461,act_009_09,proj_009,Vitrified Tiles 800x800mm,sqm,200,7940,5558,1588000,1111600,30.0,INR
|
| 463 |
+
boq_00462,act_009_09,proj_009,Ceramic Tiles 300x600mm,sqm,80,3956,2769,316480,221520,30.0,INR
|
| 464 |
+
boq_00463,act_009_09,proj_009,Tile Adhesive C2 Grade,bags,40,2372,1660,94880,66400,30.0,INR
|
| 465 |
+
boq_00464,act_009_09,proj_009,Tile Grout Mapei,bags,15,658,460,9870,6900,30.1,INR
|
| 466 |
+
boq_00465,act_009_09,proj_009,Tile Edge Trim SS,meters,60,385,269,23100,16140,30.1,INR
|
| 467 |
+
boq_00466,act_009_10,proj_009,Gypsum Plaster 20mm,bags,50,2413,1689,120650,84450,30.0,INR
|
| 468 |
+
boq_00467,act_009_10,proj_009,POP Punning Compound,bags,30,1081,757,32430,22710,30.0,INR
|
| 469 |
+
boq_00468,act_009_10,proj_009,Wire Mesh Reinforcement,sqm,100,908,636,90800,63600,30.0,INR
|
| 470 |
+
boq_00469,act_009_11,proj_009,Gypsum Board 12.5mm,sqm,150,3213,2249,481950,337350,30.0,INR
|
| 471 |
+
boq_00470,act_009_11,proj_009,GI Suspension System,sqm,150,2951,2066,442650,309900,30.0,INR
|
| 472 |
+
boq_00471,act_009_11,proj_009,Glass Wool Insulation 50mm,sqm,100,1828,1279,182800,127900,30.0,INR
|
| 473 |
+
boq_00472,act_009_12,proj_009,Premium Emulsion Paint,liters,120,3979,2785,477480,334200,30.0,INR
|
| 474 |
+
boq_00473,act_009_12,proj_009,Exterior Weather Shield,liters,60,4376,3063,262560,183780,30.0,INR
|
| 475 |
+
boq_00474,act_009_12,proj_009,Primer Coat White,liters,60,1387,971,83220,58260,30.0,INR
|
| 476 |
+
boq_00475,act_009_12,proj_009,Putty Filler Wall,kg,40,758,531,30320,21240,29.9,INR
|
| 477 |
+
boq_00476,act_009_13,proj_009,Teak Wood Panels Grade A,sqm,30,8892,6224,266760,186720,30.0,INR
|
| 478 |
+
boq_00477,act_009_13,proj_009,Pre-hung Door Sets,unit,8,6480,4536,51840,36288,30.0,INR
|
| 479 |
+
boq_00478,act_009_13,proj_009,Modular Kitchen Framework,lumpsum,1,23386,16370,23386,16370,30.0,INR
|
| 480 |
+
boq_00479,act_009_13,proj_009,Cabinet Hardware Premium Set,set,2,3325,2327,6650,4654,30.0,INR
|
| 481 |
+
boq_00480,act_009_14,proj_009,EWC Rimless Toilet Suite,unit,4,8602,6021,34408,24084,30.0,INR
|
| 482 |
+
boq_00481,act_009_14,proj_009,Concealed Cistern,unit,4,4469,3128,17876,12512,30.0,INR
|
| 483 |
+
boq_00482,act_009_14,proj_009,Basin & Pedestal Set,unit,4,3956,2769,15824,11076,30.0,INR
|
| 484 |
+
boq_00483,act_009_14,proj_009,CP Fittings Set (Taps/Showers),set,4,5186,3631,20744,14524,30.0,INR
|
| 485 |
+
boq_00484,act_009_15,proj_009,Snagging Rectification Labour,lumpsum,1,5205,3643,5205,3643,30.0,INR
|
| 486 |
+
boq_00485,act_009_15,proj_009,As-Built Drawings & O&M Manual,set,1,2976,2083,2976,2083,30.0,INR
|
| 487 |
+
boq_00486,act_009_15,proj_009,Defect Liability Retention,lumpsum,1,7464,0,7464,0,100.0,INR
|
| 488 |
+
boq_00487,act_010_01,proj_010,Site Survey & Layout,lumpsum,1,3538,2477,3538,2477,30.0,INR
|
| 489 |
+
boq_00488,act_010_01,proj_010,Temporary Site Office Setup,lumpsum,1,8016,5611,8016,5611,30.0,INR
|
| 490 |
+
boq_00489,act_010_01,proj_010,Safety Hoarding & Signage,lumpsum,1,2101,1471,2101,1471,30.0,INR
|
| 491 |
+
boq_00490,act_010_02,proj_010,Demolition Labour & Equipment,lumpsum,1,11988,8392,11988,8392,30.0,INR
|
| 492 |
+
boq_00491,act_010_02,proj_010,Debris Removal & Disposal,trip,6,5390,3773,32340,22638,30.0,INR
|
| 493 |
+
boq_00492,act_010_02,proj_010,Asbestos Survey & Removal,sqm,30,4244,2971,127320,89130,30.0,INR
|
| 494 |
+
boq_00493,act_010_03,proj_010,Reinforced Concrete M30,m3,15,9072,6351,136080,95265,30.0,INR
|
| 495 |
+
boq_00494,act_010_03,proj_010,Steel Rebar TMT 12mm,tonne,6,4028,2820,24168,16920,30.0,INR
|
| 496 |
+
boq_00495,act_010_03,proj_010,Shuttering Plywood 19mm,sheets,30,2094,1466,62820,43980,30.0,INR
|
| 497 |
+
boq_00496,act_010_03,proj_010,Structural Grouting Compound,bags,20,1660,1162,33200,23240,30.0,INR
|
| 498 |
+
boq_00497,act_010_04,proj_010,SBR Waterproofing Membrane,sqm,120,4389,3072,526680,368640,30.0,INR
|
| 499 |
+
boq_00498,act_010_04,proj_010,Crystalline Waterproofing Slurry,kg,50,3255,2278,162750,113900,30.0,INR
|
| 500 |
+
boq_00499,act_010_04,proj_010,Drainage Board & Filter Fabric,sqm,80,2035,1424,162800,113920,30.0,INR
|
| 501 |
+
boq_00500,act_010_05,proj_010,CPVC Pipes 1 inch,meters,180,2850,1995,513000,359100,30.0,INR
|
| 502 |
+
boq_00501,act_010_05,proj_010,uPVC Soil Pipes 4 inch,meters,60,1522,1065,91320,63900,30.0,INR
|
| 503 |
+
boq_00502,act_010_05,proj_010,GI Fittings Set,set,1,1384,969,1384,969,30.0,INR
|
| 504 |
+
boq_00503,act_010_05,proj_010,Water Storage Tank 1000L,unit,2,6071,4250,12142,8500,30.0,INR
|
| 505 |
+
boq_00504,act_010_06,proj_010,FR Copper Wire 4 sq mm,meters,250,3990,2793,997500,698250,30.0,INR
|
| 506 |
+
boq_00505,act_010_06,proj_010,MCB Distribution Board 18-way,unit,2,5896,4127,11792,8254,30.0,INR
|
| 507 |
+
boq_00506,act_010_06,proj_010,PVC Conduit 25mm,meters,150,1013,709,151950,106350,30.0,INR
|
| 508 |
+
boq_00507,act_010_06,proj_010,Switches & Sockets (Modular),set,1,3299,2309,3299,2309,30.0,INR
|
| 509 |
+
boq_00508,act_010_07,proj_010,Cassette AC Unit 2 Ton,unit,4,14378,10065,57512,40260,30.0,INR
|
| 510 |
+
boq_00509,act_010_07,proj_010,Insulated Ducting,meters,40,4734,3314,189360,132560,30.0,INR
|
| 511 |
+
boq_00510,act_010_07,proj_010,AHU Return Air Grilles,unit,12,1881,1317,22572,15804,30.0,INR
|
| 512 |
+
boq_00511,act_010_07,proj_010,Refrigerant Copper Pipes,meters,60,2441,1709,146460,102540,30.0,INR
|
| 513 |
+
boq_00512,act_010_08,proj_010,Self-Leveling Compound,bags,20,3120,2184,62400,43680,30.0,INR
|
| 514 |
+
boq_00513,act_010_08,proj_010,Bonding Agent SBR,liters,30,1322,925,39660,27750,30.0,INR
|
| 515 |
+
boq_00514,act_010_08,proj_010,DPM Sheet 250 micron,sqm,200,2253,1577,450600,315400,30.0,INR
|
| 516 |
+
boq_00515,act_010_09,proj_010,Vitrified Tiles 800x800mm,sqm,200,8393,5875,1678600,1175000,30.0,INR
|
| 517 |
+
boq_00516,act_010_09,proj_010,Ceramic Tiles 300x600mm,sqm,80,4049,2834,323920,226720,30.0,INR
|
| 518 |
+
boq_00517,act_010_09,proj_010,Tile Adhesive C2 Grade,bags,40,2037,1426,81480,57040,30.0,INR
|
| 519 |
+
boq_00518,act_010_09,proj_010,Tile Grout Mapei,bags,15,684,479,10260,7185,30.0,INR
|
| 520 |
+
boq_00519,act_010_09,proj_010,Tile Edge Trim SS,meters,60,358,251,21480,15060,29.9,INR
|
| 521 |
+
boq_00520,act_010_10,proj_010,Gypsum Plaster 20mm,bags,50,2431,1702,121550,85100,30.0,INR
|
| 522 |
+
boq_00521,act_010_10,proj_010,POP Punning Compound,bags,30,1033,723,30990,21690,30.0,INR
|
| 523 |
+
boq_00522,act_010_10,proj_010,Wire Mesh Reinforcement,sqm,100,952,666,95200,66600,30.0,INR
|
| 524 |
+
boq_00523,act_010_11,proj_010,Gypsum Board 12.5mm,sqm,150,3131,2192,469650,328800,30.0,INR
|
| 525 |
+
boq_00524,act_010_11,proj_010,GI Suspension System,sqm,150,2887,2021,433050,303150,30.0,INR
|
| 526 |
+
boq_00525,act_010_11,proj_010,Glass Wool Insulation 50mm,sqm,100,1754,1228,175400,122800,30.0,INR
|
| 527 |
+
boq_00526,act_010_12,proj_010,Premium Emulsion Paint,liters,120,4081,2857,489720,342840,30.0,INR
|
| 528 |
+
boq_00527,act_010_12,proj_010,Exterior Weather Shield,liters,60,4112,2878,246720,172680,30.0,INR
|
| 529 |
+
boq_00528,act_010_12,proj_010,Primer Coat White,liters,60,1299,909,77940,54540,30.0,INR
|
| 530 |
+
boq_00529,act_010_12,proj_010,Putty Filler Wall,kg,40,701,490,28040,19600,30.1,INR
|
| 531 |
+
boq_00530,act_010_13,proj_010,Teak Wood Panels Grade A,sqm,30,9576,6703,287280,201090,30.0,INR
|
| 532 |
+
boq_00531,act_010_13,proj_010,Pre-hung Door Sets,unit,8,6576,4603,52608,36824,30.0,INR
|
| 533 |
+
boq_00532,act_010_13,proj_010,Modular Kitchen Framework,lumpsum,1,22616,15831,22616,15831,30.0,INR
|
| 534 |
+
boq_00533,act_010_13,proj_010,Cabinet Hardware Premium Set,set,2,2950,2065,5900,4130,30.0,INR
|
| 535 |
+
boq_00534,act_010_14,proj_010,EWC Rimless Toilet Suite,unit,4,8866,6206,35464,24824,30.0,INR
|
| 536 |
+
boq_00535,act_010_14,proj_010,Concealed Cistern,unit,4,4087,2861,16348,11444,30.0,INR
|
| 537 |
+
boq_00536,act_010_14,proj_010,Basin & Pedestal Set,unit,4,4039,2828,16156,11312,30.0,INR
|
| 538 |
+
boq_00537,act_010_14,proj_010,CP Fittings Set (Taps/Showers),set,4,5098,3569,20392,14276,30.0,INR
|
| 539 |
+
boq_00538,act_010_15,proj_010,Snagging Rectification Labour,lumpsum,1,4650,3255,4650,3255,30.0,INR
|
| 540 |
+
boq_00539,act_010_15,proj_010,As-Built Drawings & O&M Manual,set,1,2958,2071,2958,2071,30.0,INR
|
| 541 |
+
boq_00540,act_010_15,proj_010,Defect Liability Retention,lumpsum,1,8048,0,8048,0,100.0,INR
|
data/daily_updates.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/data.db
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2d674a0b40e590f11e138e7c00235f6069e8144e03cad886e5a71c0def38a6e2
|
| 3 |
+
size 528384
|
data/issues.csv
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,activity_id,project_id,description,category,severity,status,assigned_to,date_raised,delay_impact_days
|
| 2 |
+
iss_00001,act_001_01,proj_001,Key equipment broke down mid-task on Site Survey & Mobilization.,equipment_breakdown,medium,resolved,Contractor B,2022-01-12,0
|
| 3 |
+
iss_00002,act_001_01,proj_001,Key equipment broke down mid-task on Site Survey & Mobilization.,equipment_breakdown,medium,resolved,QA Inspector,2022-01-11,0
|
| 4 |
+
iss_00003,act_001_02,proj_001,Insufficient crew available; Demolition & Strip-Out understaffed.,labor_shortage,critical,resolved,Contractor B,2022-01-21,0
|
| 5 |
+
iss_00004,act_001_02,proj_001,Safety non-compliance flagged during Demolition & Strip-Out.,safety,medium,resolved,Project Engineer,2022-01-19,0
|
| 6 |
+
iss_00005,act_001_02,proj_001,Safety non-compliance flagged during Demolition & Strip-Out.,safety,medium,resolved,Site Manager,2022-01-25,0
|
| 7 |
+
iss_00006,act_001_03,proj_001,Undocumented additional work added to Structural Repairs & Reinforcement.,scope_creep,low,resolved,QA Inspector,2022-02-08,0
|
| 8 |
+
iss_00007,act_001_03,proj_001,Adverse weather halted outdoor work on Structural Repairs & Reinforcement.,weather,high,open,Contractor A,2022-02-09,2
|
| 9 |
+
iss_00008,act_001_03,proj_001,Client-requested scope change impacts Structural Repairs & Reinforcement.,design_change,medium,resolved,Procurement Lead,2022-02-04,0
|
| 10 |
+
iss_00009,act_001_03,proj_001,Adverse weather halted outdoor work on Structural Repairs & Reinforcement.,weather,low,resolved,Contractor B,2022-02-08,0
|
| 11 |
+
iss_00010,act_001_04,proj_001,Insufficient crew available; Waterproofing & Damp Proofing understaffed.,labor_shortage,low,open,Contractor B,2022-02-26,1
|
| 12 |
+
iss_00011,act_001_04,proj_001,Delivery of Waterproofing & Damp Proofing delayed by supplier.,material_delay,medium,open,QA Inspector,2022-02-26,0
|
| 13 |
+
iss_00012,act_001_04,proj_001,Municipal inspection failed; rework needed on Waterproofing & Damp Proofing.,inspection_fail,high,resolved,Project Engineer,2022-02-25,0
|
| 14 |
+
iss_00013,act_001_04,proj_001,Key equipment broke down mid-task on Waterproofing & Damp Proofing.,equipment_breakdown,medium,resolved,Site Manager,2022-02-24,0
|
| 15 |
+
iss_00014,act_001_05,proj_001,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,low,resolved,Safety Officer,2022-03-03,0
|
| 16 |
+
iss_00015,act_001_05,proj_001,Key equipment broke down mid-task on Plumbing Rough-in.,equipment_breakdown,low,resolved,Contractor B,2022-02-20,0
|
| 17 |
+
iss_00016,act_001_05,proj_001,Delivery of Plumbing Rough-in delayed by supplier.,material_delay,low,resolved,Project Engineer,2022-02-24,0
|
| 18 |
+
iss_00017,act_001_05,proj_001,Undocumented additional work added to Plumbing Rough-in.,scope_creep,low,resolved,QA Inspector,2022-02-22,0
|
| 19 |
+
iss_00018,act_001_06,proj_001,Municipal inspection failed; rework needed on Electrical Wiring & Conduits.,inspection_fail,critical,resolved,Client PM,2022-02-21,0
|
| 20 |
+
iss_00019,act_001_06,proj_001,Insufficient crew available; Electrical Wiring & Conduits understaffed.,labor_shortage,medium,resolved,Contractor B,2022-02-25,0
|
| 21 |
+
iss_00020,act_001_06,proj_001,Safety non-compliance flagged during Electrical Wiring & Conduits.,safety,high,resolved,Safety Officer,2022-02-23,0
|
| 22 |
+
iss_00021,act_001_06,proj_001,Municipal inspection failed; rework needed on Electrical Wiring & Conduits.,inspection_fail,low,resolved,Contractor A,2022-02-22,0
|
| 23 |
+
iss_00022,act_001_07,proj_001,Insufficient crew available; HVAC & Ventilation Installation understaffed.,labor_shortage,low,resolved,Project Engineer,2022-02-23,0
|
| 24 |
+
iss_00023,act_001_07,proj_001,Undocumented additional work added to HVAC & Ventilation Installation.,scope_creep,critical,open,Safety Officer,2022-02-24,4
|
| 25 |
+
iss_00024,act_001_07,proj_001,Undocumented additional work added to HVAC & Ventilation Installation.,scope_creep,critical,open,Contractor B,2022-02-20,5
|
| 26 |
+
iss_00025,act_001_07,proj_001,Adverse weather halted outdoor work on HVAC & Ventilation Installation.,weather,low,resolved,Client PM,2022-02-28,0
|
| 27 |
+
iss_00026,act_001_08,proj_001,Safety non-compliance flagged during Floor Leveling & Screed.,safety,high,resolved,Contractor A,2022-03-14,0
|
| 28 |
+
iss_00027,act_001_08,proj_001,Insufficient crew available; Floor Leveling & Screed understaffed.,labor_shortage,medium,resolved,Site Manager,2022-03-10,0
|
| 29 |
+
iss_00028,act_001_08,proj_001,Municipal inspection failed; rework needed on Floor Leveling & Screed.,inspection_fail,medium,open,Site Manager,2022-03-11,0
|
| 30 |
+
iss_00029,act_001_09,proj_001,Key equipment broke down mid-task on Tiling β Floors & Wet Areas.,equipment_breakdown,medium,resolved,Contractor A,2022-03-25,0
|
| 31 |
+
iss_00030,act_001_09,proj_001,Undocumented additional work added to Tiling β Floors & Wet Areas.,scope_creep,high,resolved,QA Inspector,2022-04-01,0
|
| 32 |
+
iss_00031,act_001_09,proj_001,Municipal inspection failed; rework needed on Tiling β Floors & Wet Areas.,inspection_fail,low,open,Project Engineer,2022-03-20,4
|
| 33 |
+
iss_00032,act_001_10,proj_001,Undocumented additional work added to Wall Plastering & Screeding.,scope_creep,medium,resolved,Client PM,2022-03-13,0
|
| 34 |
+
iss_00033,act_001_10,proj_001,Client-requested scope change impacts Wall Plastering & Screeding.,design_change,low,resolved,Contractor A,2022-03-11,0
|
| 35 |
+
iss_00034,act_001_10,proj_001,Client-requested scope change impacts Wall Plastering & Screeding.,design_change,low,open,Contractor B,2022-03-13,0
|
| 36 |
+
iss_00035,act_001_11,proj_001,Adverse weather halted outdoor work on False Ceiling & Insulation.,weather,low,resolved,Project Engineer,2022-03-29,0
|
| 37 |
+
iss_00036,act_001_11,proj_001,Insufficient crew available; False Ceiling & Insulation understaffed.,labor_shortage,low,resolved,Safety Officer,2022-03-31,0
|
| 38 |
+
iss_00037,act_001_11,proj_001,Insufficient crew available; False Ceiling & Insulation understaffed.,labor_shortage,critical,resolved,Client PM,2022-03-28,0
|
| 39 |
+
iss_00038,act_001_12,proj_001,Key equipment broke down mid-task on Painting β Primer & Finish Coats.,equipment_breakdown,high,resolved,Site Manager,2022-04-18,0
|
| 40 |
+
iss_00039,act_001_12,proj_001,Delivery of Painting β Primer & Finish Coats delayed by supplier.,material_delay,high,open,Contractor B,2022-04-12,2
|
| 41 |
+
iss_00040,act_001_12,proj_001,Delivery of Painting β Primer & Finish Coats delayed by supplier.,material_delay,medium,resolved,Contractor A,2022-04-19,0
|
| 42 |
+
iss_00041,act_001_13,proj_001,"Key equipment broke down mid-task on Carpentry, Joinery & Built-ins.",equipment_breakdown,critical,resolved,Project Engineer,2022-05-12,0
|
| 43 |
+
iss_00042,act_001_13,proj_001,"Client-requested scope change impacts Carpentry, Joinery & Built-ins.",design_change,medium,open,QA Inspector,2022-05-02,5
|
| 44 |
+
iss_00043,act_001_13,proj_001,"Undocumented additional work added to Carpentry, Joinery & Built-ins.",scope_creep,low,resolved,Safety Officer,2022-05-02,0
|
| 45 |
+
iss_00044,act_001_14,proj_001,"Undocumented additional work added to Fixtures, Fittings & Sanitaryware.",scope_creep,low,open,Contractor B,2022-05-21,1
|
| 46 |
+
iss_00045,act_001_14,proj_001,"Undocumented additional work added to Fixtures, Fittings & Sanitaryware.",scope_creep,critical,open,Site Manager,2022-05-22,2
|
| 47 |
+
iss_00046,act_001_14,proj_001,"Adverse weather halted outdoor work on Fixtures, Fittings & Sanitaryware.",weather,high,resolved,Project Engineer,2022-05-19,0
|
| 48 |
+
iss_00047,act_001_15,proj_001,"Adverse weather halted outdoor work on Final Inspection, Snag & Handover.",weather,low,open,QA Inspector,2022-05-29,5
|
| 49 |
+
iss_00048,act_001_15,proj_001,"Adverse weather halted outdoor work on Final Inspection, Snag & Handover.",weather,high,resolved,Contractor A,2022-06-01,0
|
| 50 |
+
iss_00049,act_002_01,proj_002,Key equipment broke down mid-task on Site Survey & Mobilization.,equipment_breakdown,low,resolved,Site Manager,2022-03-02,0
|
| 51 |
+
iss_00050,act_002_01,proj_002,Client-requested scope change impacts Site Survey & Mobilization.,design_change,high,resolved,Site Manager,2022-03-07,0
|
| 52 |
+
iss_00051,act_002_02,proj_002,Delivery of Demolition & Strip-Out delayed by supplier.,material_delay,critical,open,Safety Officer,2022-03-21,5
|
| 53 |
+
iss_00052,act_002_02,proj_002,Insufficient crew available; Demolition & Strip-Out understaffed.,labor_shortage,low,resolved,Procurement Lead,2022-03-12,0
|
| 54 |
+
iss_00053,act_002_02,proj_002,Municipal inspection failed; rework needed on Demolition & Strip-Out.,inspection_fail,medium,open,Client PM,2022-03-20,0
|
| 55 |
+
iss_00054,act_002_03,proj_002,Insufficient crew available; Structural Repairs & Reinforcement understaffed.,labor_shortage,low,open,Client PM,2022-03-26,4
|
| 56 |
+
iss_00055,act_002_03,proj_002,Key equipment broke down mid-task on Structural Repairs & Reinforcement.,equipment_breakdown,low,resolved,Site Manager,2022-03-30,0
|
| 57 |
+
iss_00056,act_002_03,proj_002,Key equipment broke down mid-task on Structural Repairs & Reinforcement.,equipment_breakdown,medium,resolved,Client PM,2022-03-30,0
|
| 58 |
+
iss_00057,act_002_03,proj_002,Key equipment broke down mid-task on Structural Repairs & Reinforcement.,equipment_breakdown,medium,resolved,Contractor A,2022-04-07,0
|
| 59 |
+
iss_00058,act_002_04,proj_002,Adverse weather halted outdoor work on Waterproofing & Damp Proofing.,weather,critical,open,Safety Officer,2022-04-12,2
|
| 60 |
+
iss_00059,act_002_04,proj_002,Safety non-compliance flagged during Waterproofing & Damp Proofing.,safety,low,resolved,Contractor A,2022-04-11,0
|
| 61 |
+
iss_00060,act_002_04,proj_002,Adverse weather halted outdoor work on Waterproofing & Damp Proofing.,weather,low,resolved,Contractor B,2022-04-17,0
|
| 62 |
+
iss_00061,act_002_04,proj_002,Adverse weather halted outdoor work on Waterproofing & Damp Proofing.,weather,high,resolved,Client PM,2022-04-16,0
|
| 63 |
+
iss_00062,act_002_05,proj_002,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,low,resolved,Safety Officer,2022-04-15,0
|
| 64 |
+
iss_00063,act_002_05,proj_002,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,high,resolved,Contractor B,2022-04-23,0
|
| 65 |
+
iss_00064,act_002_05,proj_002,Adverse weather halted outdoor work on Plumbing Rough-in.,weather,medium,resolved,Procurement Lead,2022-04-24,0
|
| 66 |
+
iss_00065,act_002_05,proj_002,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,low,resolved,Client PM,2022-04-13,0
|
| 67 |
+
iss_00066,act_002_06,proj_002,Insufficient crew available; Electrical Wiring & Conduits understaffed.,labor_shortage,medium,open,Safety Officer,2022-04-17,3
|
| 68 |
+
iss_00067,act_002_06,proj_002,Undocumented additional work added to Electrical Wiring & Conduits.,scope_creep,medium,resolved,QA Inspector,2022-04-21,0
|
| 69 |
+
iss_00068,act_002_06,proj_002,Safety non-compliance flagged during Electrical Wiring & Conduits.,safety,low,resolved,Project Engineer,2022-04-18,0
|
| 70 |
+
iss_00069,act_002_06,proj_002,Key equipment broke down mid-task on Electrical Wiring & Conduits.,equipment_breakdown,medium,resolved,Procurement Lead,2022-04-20,0
|
| 71 |
+
iss_00070,act_002_07,proj_002,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,medium,resolved,QA Inspector,2022-04-19,0
|
| 72 |
+
iss_00071,act_002_07,proj_002,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,high,open,Project Engineer,2022-04-11,0
|
| 73 |
+
iss_00072,act_002_07,proj_002,Safety non-compliance flagged during HVAC & Ventilation Installation.,safety,medium,resolved,Contractor A,2022-04-11,0
|
| 74 |
+
iss_00073,act_002_07,proj_002,Safety non-compliance flagged during HVAC & Ventilation Installation.,safety,medium,resolved,Contractor B,2022-04-15,0
|
| 75 |
+
iss_00074,act_002_08,proj_002,Undocumented additional work added to Floor Leveling & Screed.,scope_creep,low,resolved,QA Inspector,2022-04-29,0
|
| 76 |
+
iss_00075,act_002_08,proj_002,Client-requested scope change impacts Floor Leveling & Screed.,design_change,high,open,Contractor A,2022-04-28,1
|
| 77 |
+
iss_00076,act_002_08,proj_002,Key equipment broke down mid-task on Floor Leveling & Screed.,equipment_breakdown,high,resolved,QA Inspector,2022-05-01,0
|
| 78 |
+
iss_00077,act_002_09,proj_002,Delivery of Tiling β Floors & Wet Areas delayed by supplier.,material_delay,high,resolved,Contractor A,2022-05-26,0
|
| 79 |
+
iss_00078,act_002_09,proj_002,Adverse weather halted outdoor work on Tiling β Floors & Wet Areas.,weather,low,resolved,Contractor A,2022-05-18,0
|
| 80 |
+
iss_00079,act_002_09,proj_002,Insufficient crew available; Tiling β Floors & Wet Areas understaffed.,labor_shortage,low,resolved,QA Inspector,2022-05-15,0
|
| 81 |
+
iss_00080,act_002_10,proj_002,Adverse weather halted outdoor work on Wall Plastering & Screeding.,weather,medium,open,Client PM,2022-05-07,4
|
| 82 |
+
iss_00081,act_002_10,proj_002,Key equipment broke down mid-task on Wall Plastering & Screeding.,equipment_breakdown,high,resolved,Site Manager,2022-05-04,0
|
| 83 |
+
iss_00082,act_002_10,proj_002,Insufficient crew available; Wall Plastering & Screeding understaffed.,labor_shortage,low,resolved,Site Manager,2022-05-09,0
|
| 84 |
+
iss_00083,act_002_11,proj_002,Adverse weather halted outdoor work on False Ceiling & Insulation.,weather,medium,open,Procurement Lead,2022-05-24,3
|
| 85 |
+
iss_00084,act_002_11,proj_002,Municipal inspection failed; rework needed on False Ceiling & Insulation.,inspection_fail,critical,resolved,Project Engineer,2022-05-22,0
|
| 86 |
+
iss_00085,act_002_11,proj_002,Adverse weather halted outdoor work on False Ceiling & Insulation.,weather,low,open,Contractor B,2022-05-19,3
|
| 87 |
+
iss_00086,act_002_12,proj_002,Key equipment broke down mid-task on Painting β Primer & Finish Coats.,equipment_breakdown,medium,open,Contractor A,2022-06-09,1
|
| 88 |
+
iss_00087,act_002_12,proj_002,Undocumented additional work added to Painting β Primer & Finish Coats.,scope_creep,medium,resolved,QA Inspector,2022-06-09,0
|
| 89 |
+
iss_00088,act_002_12,proj_002,Key equipment broke down mid-task on Painting β Primer & Finish Coats.,equipment_breakdown,low,resolved,QA Inspector,2022-05-30,0
|
| 90 |
+
iss_00089,act_002_13,proj_002,"Municipal inspection failed; rework needed on Carpentry, Joinery & Built-ins.",inspection_fail,low,open,Safety Officer,2022-06-11,4
|
| 91 |
+
iss_00090,act_002_13,proj_002,"Client-requested scope change impacts Carpentry, Joinery & Built-ins.",design_change,low,resolved,Contractor A,2022-06-17,0
|
| 92 |
+
iss_00091,act_002_13,proj_002,"Delivery of Carpentry, Joinery & Built-ins delayed by supplier.",material_delay,high,resolved,Project Engineer,2022-06-12,0
|
| 93 |
+
iss_00092,act_002_14,proj_002,"Client-requested scope change impacts Fixtures, Fittings & Sanitaryware.",design_change,low,resolved,Site Manager,2022-07-08,0
|
| 94 |
+
iss_00093,act_002_14,proj_002,"Undocumented additional work added to Fixtures, Fittings & Sanitaryware.",scope_creep,low,resolved,Client PM,2022-06-29,0
|
| 95 |
+
iss_00094,act_002_14,proj_002,"Safety non-compliance flagged during Fixtures, Fittings & Sanitaryware.",safety,high,resolved,Project Engineer,2022-07-04,0
|
| 96 |
+
iss_00095,act_002_15,proj_002,"Key equipment broke down mid-task on Final Inspection, Snag & Handover.",equipment_breakdown,high,resolved,Contractor A,2022-07-12,0
|
| 97 |
+
iss_00096,act_002_15,proj_002,"Key equipment broke down mid-task on Final Inspection, Snag & Handover.",equipment_breakdown,high,resolved,Contractor B,2022-07-10,0
|
| 98 |
+
iss_00097,act_003_01,proj_003,Key equipment broke down mid-task on Site Survey & Mobilization.,equipment_breakdown,medium,resolved,Site Manager,2022-06-18,0
|
| 99 |
+
iss_00098,act_003_01,proj_003,Adverse weather halted outdoor work on Site Survey & Mobilization.,weather,low,resolved,Contractor A,2022-06-21,0
|
| 100 |
+
iss_00099,act_003_02,proj_003,Client-requested scope change impacts Demolition & Strip-Out.,design_change,high,resolved,Contractor B,2022-07-06,0
|
| 101 |
+
iss_00100,act_003_02,proj_003,Adverse weather halted outdoor work on Demolition & Strip-Out.,weather,critical,resolved,Safety Officer,2022-07-02,0
|
| 102 |
+
iss_00101,act_003_02,proj_003,Adverse weather halted outdoor work on Demolition & Strip-Out.,weather,medium,resolved,QA Inspector,2022-06-25,0
|
| 103 |
+
iss_00102,act_003_03,proj_003,Key equipment broke down mid-task on Structural Repairs & Reinforcement.,equipment_breakdown,low,resolved,Contractor A,2022-07-16,0
|
| 104 |
+
iss_00103,act_003_03,proj_003,Undocumented additional work added to Structural Repairs & Reinforcement.,scope_creep,low,open,Contractor A,2022-07-27,2
|
| 105 |
+
iss_00104,act_003_03,proj_003,Insufficient crew available; Structural Repairs & Reinforcement understaffed.,labor_shortage,medium,open,Contractor B,2022-07-14,2
|
| 106 |
+
iss_00105,act_003_03,proj_003,Municipal inspection failed; rework needed on Structural Repairs & Reinforcement.,inspection_fail,medium,resolved,Contractor A,2022-07-17,0
|
| 107 |
+
iss_00106,act_003_04,proj_003,Undocumented additional work added to Waterproofing & Damp Proofing.,scope_creep,low,resolved,Client PM,2022-08-12,0
|
| 108 |
+
iss_00107,act_003_04,proj_003,Adverse weather halted outdoor work on Waterproofing & Damp Proofing.,weather,critical,resolved,Procurement Lead,2022-08-05,0
|
| 109 |
+
iss_00108,act_003_04,proj_003,Safety non-compliance flagged during Waterproofing & Damp Proofing.,safety,high,resolved,Contractor B,2022-08-12,0
|
| 110 |
+
iss_00109,act_003_04,proj_003,Safety non-compliance flagged during Waterproofing & Damp Proofing.,safety,medium,resolved,Safety Officer,2022-08-10,0
|
| 111 |
+
iss_00110,act_003_05,proj_003,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,medium,resolved,Client PM,2022-08-15,0
|
| 112 |
+
iss_00111,act_003_05,proj_003,Delivery of Plumbing Rough-in delayed by supplier.,material_delay,medium,resolved,Project Engineer,2022-08-16,0
|
| 113 |
+
iss_00112,act_003_05,proj_003,Delivery of Plumbing Rough-in delayed by supplier.,material_delay,low,open,Contractor B,2022-08-14,3
|
| 114 |
+
iss_00113,act_003_05,proj_003,Key equipment broke down mid-task on Plumbing Rough-in.,equipment_breakdown,high,open,Contractor A,2022-08-10,3
|
| 115 |
+
iss_00114,act_003_06,proj_003,Undocumented additional work added to Electrical Wiring & Conduits.,scope_creep,medium,resolved,Procurement Lead,2022-08-06,0
|
| 116 |
+
iss_00115,act_003_06,proj_003,Insufficient crew available; Electrical Wiring & Conduits understaffed.,labor_shortage,low,open,QA Inspector,2022-08-08,3
|
| 117 |
+
iss_00116,act_003_06,proj_003,Key equipment broke down mid-task on Electrical Wiring & Conduits.,equipment_breakdown,medium,resolved,Procurement Lead,2022-08-08,0
|
| 118 |
+
iss_00117,act_003_06,proj_003,Undocumented additional work added to Electrical Wiring & Conduits.,scope_creep,low,resolved,Contractor B,2022-08-12,0
|
| 119 |
+
iss_00118,act_003_07,proj_003,Adverse weather halted outdoor work on HVAC & Ventilation Installation.,weather,medium,resolved,Site Manager,2022-08-15,0
|
| 120 |
+
iss_00119,act_003_07,proj_003,Key equipment broke down mid-task on HVAC & Ventilation Installation.,equipment_breakdown,low,resolved,QA Inspector,2022-08-13,0
|
| 121 |
+
iss_00120,act_003_07,proj_003,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,low,resolved,QA Inspector,2022-08-10,0
|
| 122 |
+
iss_00121,act_003_07,proj_003,Municipal inspection failed; rework needed on HVAC & Ventilation Installation.,inspection_fail,medium,open,Client PM,2022-08-12,0
|
| 123 |
+
iss_00122,act_003_08,proj_003,Insufficient crew available; Floor Leveling & Screed understaffed.,labor_shortage,low,resolved,QA Inspector,2022-08-30,0
|
| 124 |
+
iss_00123,act_003_08,proj_003,Client-requested scope change impacts Floor Leveling & Screed.,design_change,medium,resolved,Site Manager,2022-08-23,0
|
| 125 |
+
iss_00124,act_003_08,proj_003,Key equipment broke down mid-task on Floor Leveling & Screed.,equipment_breakdown,medium,resolved,Contractor B,2022-08-25,0
|
| 126 |
+
iss_00125,act_003_09,proj_003,Safety non-compliance flagged during Tiling β Floors & Wet Areas.,safety,critical,resolved,Contractor B,2022-09-16,0
|
| 127 |
+
iss_00126,act_003_09,proj_003,Safety non-compliance flagged during Tiling β Floors & Wet Areas.,safety,critical,resolved,Site Manager,2022-09-20,0
|
| 128 |
+
iss_00127,act_003_09,proj_003,Client-requested scope change impacts Tiling β Floors & Wet Areas.,design_change,low,resolved,Contractor B,2022-09-13,0
|
| 129 |
+
iss_00128,act_003_10,proj_003,Safety non-compliance flagged during Wall Plastering & Screeding.,safety,low,resolved,Contractor B,2022-08-29,0
|
| 130 |
+
iss_00129,act_003_10,proj_003,Safety non-compliance flagged during Wall Plastering & Screeding.,safety,low,resolved,QA Inspector,2022-08-26,0
|
| 131 |
+
iss_00130,act_003_10,proj_003,Delivery of Wall Plastering & Screeding delayed by supplier.,material_delay,critical,resolved,Contractor B,2022-09-01,0
|
| 132 |
+
iss_00131,act_003_11,proj_003,Undocumented additional work added to False Ceiling & Insulation.,scope_creep,medium,resolved,Site Manager,2022-09-10,0
|
| 133 |
+
iss_00132,act_003_11,proj_003,Client-requested scope change impacts False Ceiling & Insulation.,design_change,medium,resolved,Contractor B,2022-09-16,0
|
| 134 |
+
iss_00133,act_003_11,proj_003,Key equipment broke down mid-task on False Ceiling & Insulation.,equipment_breakdown,low,open,Site Manager,2022-09-12,1
|
| 135 |
+
iss_00134,act_003_12,proj_003,Safety non-compliance flagged during Painting β Primer & Finish Coats.,safety,low,resolved,Contractor A,2022-10-01,0
|
| 136 |
+
iss_00135,act_003_12,proj_003,Undocumented additional work added to Painting β Primer & Finish Coats.,scope_creep,medium,resolved,QA Inspector,2022-09-25,0
|
| 137 |
+
iss_00136,act_003_12,proj_003,Safety non-compliance flagged during Painting β Primer & Finish Coats.,safety,high,resolved,Safety Officer,2022-09-21,0
|
| 138 |
+
iss_00137,act_003_13,proj_003,"Adverse weather halted outdoor work on Carpentry, Joinery & Built-ins.",weather,medium,resolved,Contractor B,2022-10-19,0
|
| 139 |
+
iss_00138,act_003_13,proj_003,"Key equipment broke down mid-task on Carpentry, Joinery & Built-ins.",equipment_breakdown,low,resolved,QA Inspector,2022-10-15,0
|
| 140 |
+
iss_00139,act_003_13,proj_003,"Insufficient crew available; Carpentry, Joinery & Built-ins understaffed.",labor_shortage,critical,resolved,Contractor A,2022-10-08,0
|
| 141 |
+
iss_00140,act_003_14,proj_003,"Delivery of Fixtures, Fittings & Sanitaryware delayed by supplier.",material_delay,medium,resolved,Procurement Lead,2022-11-04,0
|
| 142 |
+
iss_00141,act_003_14,proj_003,"Insufficient crew available; Fixtures, Fittings & Sanitaryware understaffed.",labor_shortage,medium,resolved,Site Manager,2022-10-30,0
|
| 143 |
+
iss_00142,act_003_14,proj_003,"Key equipment broke down mid-task on Fixtures, Fittings & Sanitaryware.",equipment_breakdown,low,resolved,QA Inspector,2022-10-27,0
|
| 144 |
+
iss_00143,act_003_15,proj_003,"Client-requested scope change impacts Final Inspection, Snag & Handover.",design_change,high,resolved,Safety Officer,2022-11-09,0
|
| 145 |
+
iss_00144,act_003_15,proj_003,"Key equipment broke down mid-task on Final Inspection, Snag & Handover.",equipment_breakdown,critical,resolved,QA Inspector,2022-11-06,0
|
| 146 |
+
iss_00145,act_004_01,proj_004,Safety non-compliance flagged during Site Survey & Mobilization.,safety,high,resolved,Client PM,2022-09-08,0
|
| 147 |
+
iss_00146,act_004_01,proj_004,Municipal inspection failed; rework needed on Site Survey & Mobilization.,inspection_fail,medium,resolved,QA Inspector,2022-09-08,0
|
| 148 |
+
iss_00147,act_004_02,proj_004,Client-requested scope change impacts Demolition & Strip-Out.,design_change,low,resolved,Site Manager,2022-09-13,0
|
| 149 |
+
iss_00148,act_004_02,proj_004,Delivery of Demolition & Strip-Out delayed by supplier.,material_delay,low,resolved,Safety Officer,2022-09-18,0
|
| 150 |
+
iss_00149,act_004_02,proj_004,Adverse weather halted outdoor work on Demolition & Strip-Out.,weather,critical,resolved,Project Engineer,2022-09-21,0
|
| 151 |
+
iss_00150,act_004_03,proj_004,Key equipment broke down mid-task on Structural Repairs & Reinforcement.,equipment_breakdown,low,resolved,Site Manager,2022-10-11,0
|
| 152 |
+
iss_00151,act_004_03,proj_004,Adverse weather halted outdoor work on Structural Repairs & Reinforcement.,weather,critical,resolved,Contractor B,2022-10-10,0
|
| 153 |
+
iss_00152,act_004_03,proj_004,Safety non-compliance flagged during Structural Repairs & Reinforcement.,safety,medium,resolved,Contractor A,2022-10-02,0
|
| 154 |
+
iss_00153,act_004_03,proj_004,Insufficient crew available; Structural Repairs & Reinforcement understaffed.,labor_shortage,medium,resolved,Client PM,2022-10-15,0
|
| 155 |
+
iss_00154,act_004_04,proj_004,Adverse weather halted outdoor work on Waterproofing & Damp Proofing.,weather,critical,open,Site Manager,2022-10-25,0
|
| 156 |
+
iss_00155,act_004_04,proj_004,Delivery of Waterproofing & Damp Proofing delayed by supplier.,material_delay,medium,resolved,Site Manager,2022-10-20,0
|
| 157 |
+
iss_00156,act_004_04,proj_004,Key equipment broke down mid-task on Waterproofing & Damp Proofing.,equipment_breakdown,low,resolved,Procurement Lead,2022-10-24,0
|
| 158 |
+
iss_00157,act_004_04,proj_004,Adverse weather halted outdoor work on Waterproofing & Damp Proofing.,weather,low,resolved,Client PM,2022-10-22,0
|
| 159 |
+
iss_00158,act_004_05,proj_004,Client-requested scope change impacts Plumbing Rough-in.,design_change,high,resolved,QA Inspector,2022-10-29,0
|
| 160 |
+
iss_00159,act_004_05,proj_004,Municipal inspection failed; rework needed on Plumbing Rough-in.,inspection_fail,medium,resolved,Contractor B,2022-10-27,0
|
| 161 |
+
iss_00160,act_004_05,proj_004,Delivery of Plumbing Rough-in delayed by supplier.,material_delay,medium,resolved,Contractor A,2022-10-18,0
|
| 162 |
+
iss_00161,act_004_05,proj_004,Undocumented additional work added to Plumbing Rough-in.,scope_creep,critical,open,Client PM,2022-10-21,1
|
| 163 |
+
iss_00162,act_004_06,proj_004,Adverse weather halted outdoor work on Electrical Wiring & Conduits.,weather,low,resolved,Safety Officer,2022-11-01,0
|
| 164 |
+
iss_00163,act_004_06,proj_004,Client-requested scope change impacts Electrical Wiring & Conduits.,design_change,medium,resolved,Site Manager,2022-10-25,0
|
| 165 |
+
iss_00164,act_004_06,proj_004,Insufficient crew available; Electrical Wiring & Conduits understaffed.,labor_shortage,medium,resolved,Project Engineer,2022-10-29,0
|
| 166 |
+
iss_00165,act_004_06,proj_004,Key equipment broke down mid-task on Electrical Wiring & Conduits.,equipment_breakdown,medium,resolved,Procurement Lead,2022-10-31,0
|
| 167 |
+
iss_00166,act_004_07,proj_004,Adverse weather halted outdoor work on HVAC & Ventilation Installation.,weather,low,open,Site Manager,2022-10-21,1
|
| 168 |
+
iss_00167,act_004_07,proj_004,Safety non-compliance flagged during HVAC & Ventilation Installation.,safety,critical,resolved,Site Manager,2022-10-22,0
|
| 169 |
+
iss_00168,act_004_07,proj_004,Municipal inspection failed; rework needed on HVAC & Ventilation Installation.,inspection_fail,critical,open,Site Manager,2022-10-28,0
|
| 170 |
+
iss_00169,act_004_07,proj_004,Adverse weather halted outdoor work on HVAC & Ventilation Installation.,weather,low,resolved,Project Engineer,2022-10-20,0
|
| 171 |
+
iss_00170,act_004_08,proj_004,Safety non-compliance flagged during Floor Leveling & Screed.,safety,low,open,Contractor B,2022-11-06,5
|
| 172 |
+
iss_00171,act_004_08,proj_004,Municipal inspection failed; rework needed on Floor Leveling & Screed.,inspection_fail,medium,resolved,Safety Officer,2022-11-10,0
|
| 173 |
+
iss_00172,act_004_08,proj_004,Municipal inspection failed; rework needed on Floor Leveling & Screed.,inspection_fail,medium,resolved,QA Inspector,2022-11-10,0
|
| 174 |
+
iss_00173,act_004_09,proj_004,Key equipment broke down mid-task on Tiling β Floors & Wet Areas.,equipment_breakdown,critical,resolved,Project Engineer,2022-11-22,0
|
| 175 |
+
iss_00174,act_004_09,proj_004,Key equipment broke down mid-task on Tiling β Floors & Wet Areas.,equipment_breakdown,low,resolved,Client PM,2022-11-19,0
|
| 176 |
+
iss_00175,act_004_09,proj_004,Client-requested scope change impacts Tiling β Floors & Wet Areas.,design_change,critical,resolved,Procurement Lead,2022-11-27,0
|
| 177 |
+
iss_00176,act_004_10,proj_004,Municipal inspection failed; rework needed on Wall Plastering & Screeding.,inspection_fail,high,resolved,QA Inspector,2022-11-09,0
|
| 178 |
+
iss_00177,act_004_10,proj_004,Client-requested scope change impacts Wall Plastering & Screeding.,design_change,medium,resolved,Contractor A,2022-11-10,0
|
| 179 |
+
iss_00178,act_004_10,proj_004,Adverse weather halted outdoor work on Wall Plastering & Screeding.,weather,high,resolved,Client PM,2022-11-12,0
|
| 180 |
+
iss_00179,act_004_11,proj_004,Key equipment broke down mid-task on False Ceiling & Insulation.,equipment_breakdown,low,resolved,Safety Officer,2022-11-27,0
|
| 181 |
+
iss_00180,act_004_11,proj_004,Delivery of False Ceiling & Insulation delayed by supplier.,material_delay,low,resolved,QA Inspector,2022-11-23,0
|
| 182 |
+
iss_00181,act_004_11,proj_004,Safety non-compliance flagged during False Ceiling & Insulation.,safety,low,open,Safety Officer,2022-11-23,2
|
| 183 |
+
iss_00182,act_004_12,proj_004,Safety non-compliance flagged during Painting β Primer & Finish Coats.,safety,low,resolved,Site Manager,2022-12-17,0
|
| 184 |
+
iss_00183,act_004_12,proj_004,Safety non-compliance flagged during Painting β Primer & Finish Coats.,safety,low,resolved,Safety Officer,2022-12-09,0
|
| 185 |
+
iss_00184,act_004_12,proj_004,Insufficient crew available; Painting β Primer & Finish Coats understaffed.,labor_shortage,medium,resolved,Project Engineer,2022-12-07,0
|
| 186 |
+
iss_00185,act_004_13,proj_004,"Municipal inspection failed; rework needed on Carpentry, Joinery & Built-ins.",inspection_fail,high,resolved,Contractor A,2023-01-05,0
|
| 187 |
+
iss_00186,act_004_13,proj_004,"Key equipment broke down mid-task on Carpentry, Joinery & Built-ins.",equipment_breakdown,medium,resolved,Project Engineer,2022-12-24,0
|
| 188 |
+
iss_00187,act_004_13,proj_004,"Undocumented additional work added to Carpentry, Joinery & Built-ins.",scope_creep,medium,resolved,QA Inspector,2022-12-26,0
|
| 189 |
+
iss_00188,act_004_14,proj_004,"Insufficient crew available; Fixtures, Fittings & Sanitaryware understaffed.",labor_shortage,medium,resolved,QA Inspector,2023-01-13,0
|
| 190 |
+
iss_00189,act_004_14,proj_004,"Delivery of Fixtures, Fittings & Sanitaryware delayed by supplier.",material_delay,low,resolved,Site Manager,2023-01-17,0
|
| 191 |
+
iss_00190,act_004_14,proj_004,"Municipal inspection failed; rework needed on Fixtures, Fittings & Sanitaryware.",inspection_fail,low,resolved,Site Manager,2023-01-18,0
|
| 192 |
+
iss_00191,act_004_15,proj_004,"Delivery of Final Inspection, Snag & Handover delayed by supplier.",material_delay,medium,open,Contractor A,2023-01-26,3
|
| 193 |
+
iss_00192,act_004_15,proj_004,"Municipal inspection failed; rework needed on Final Inspection, Snag & Handover.",inspection_fail,low,resolved,QA Inspector,2023-01-23,0
|
| 194 |
+
iss_00193,act_005_01,proj_005,Safety non-compliance flagged during Site Survey & Mobilization.,safety,medium,open,Procurement Lead,2023-01-08,2
|
| 195 |
+
iss_00194,act_005_01,proj_005,Insufficient crew available; Site Survey & Mobilization understaffed.,labor_shortage,high,resolved,Contractor A,2023-01-05,0
|
| 196 |
+
iss_00195,act_005_02,proj_005,Client-requested scope change impacts Demolition & Strip-Out.,design_change,low,open,Safety Officer,2023-01-24,0
|
| 197 |
+
iss_00196,act_005_02,proj_005,Key equipment broke down mid-task on Demolition & Strip-Out.,equipment_breakdown,low,open,Safety Officer,2023-01-21,5
|
| 198 |
+
iss_00197,act_005_02,proj_005,Delivery of Demolition & Strip-Out delayed by supplier.,material_delay,critical,resolved,Client PM,2023-01-13,0
|
| 199 |
+
iss_00198,act_005_03,proj_005,Insufficient crew available; Structural Repairs & Reinforcement understaffed.,labor_shortage,low,resolved,Client PM,2023-02-06,0
|
| 200 |
+
iss_00199,act_005_03,proj_005,Key equipment broke down mid-task on Structural Repairs & Reinforcement.,equipment_breakdown,low,open,Procurement Lead,2023-01-30,1
|
| 201 |
+
iss_00200,act_005_03,proj_005,Adverse weather halted outdoor work on Structural Repairs & Reinforcement.,weather,medium,open,QA Inspector,2023-02-10,4
|
| 202 |
+
iss_00201,act_005_03,proj_005,Insufficient crew available; Structural Repairs & Reinforcement understaffed.,labor_shortage,medium,open,Procurement Lead,2023-02-04,3
|
| 203 |
+
iss_00202,act_005_04,proj_005,Safety non-compliance flagged during Waterproofing & Damp Proofing.,safety,high,resolved,Contractor A,2023-02-22,0
|
| 204 |
+
iss_00203,act_005_04,proj_005,Municipal inspection failed; rework needed on Waterproofing & Damp Proofing.,inspection_fail,high,resolved,Project Engineer,2023-02-21,0
|
| 205 |
+
iss_00204,act_005_04,proj_005,Insufficient crew available; Waterproofing & Damp Proofing understaffed.,labor_shortage,low,resolved,Project Engineer,2023-02-18,0
|
| 206 |
+
iss_00205,act_005_04,proj_005,Client-requested scope change impacts Waterproofing & Damp Proofing.,design_change,medium,resolved,Procurement Lead,2023-02-19,0
|
| 207 |
+
iss_00206,act_005_05,proj_005,Safety non-compliance flagged during Plumbing Rough-in.,safety,low,resolved,Safety Officer,2023-02-28,0
|
| 208 |
+
iss_00207,act_005_05,proj_005,Municipal inspection failed; rework needed on Plumbing Rough-in.,inspection_fail,high,resolved,Contractor A,2023-02-18,0
|
| 209 |
+
iss_00208,act_005_05,proj_005,Client-requested scope change impacts Plumbing Rough-in.,design_change,critical,resolved,Procurement Lead,2023-03-01,0
|
| 210 |
+
iss_00209,act_005_05,proj_005,Client-requested scope change impacts Plumbing Rough-in.,design_change,high,open,QA Inspector,2023-02-18,2
|
| 211 |
+
iss_00210,act_005_06,proj_005,Municipal inspection failed; rework needed on Electrical Wiring & Conduits.,inspection_fail,critical,resolved,Contractor A,2023-02-18,0
|
| 212 |
+
iss_00211,act_005_06,proj_005,Undocumented additional work added to Electrical Wiring & Conduits.,scope_creep,high,resolved,Project Engineer,2023-02-16,0
|
| 213 |
+
iss_00212,act_005_06,proj_005,Undocumented additional work added to Electrical Wiring & Conduits.,scope_creep,low,open,Procurement Lead,2023-02-21,5
|
| 214 |
+
iss_00213,act_005_06,proj_005,Municipal inspection failed; rework needed on Electrical Wiring & Conduits.,inspection_fail,low,resolved,Safety Officer,2023-02-22,0
|
| 215 |
+
iss_00214,act_005_07,proj_005,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,low,resolved,Safety Officer,2023-02-16,0
|
| 216 |
+
iss_00215,act_005_07,proj_005,Undocumented additional work added to HVAC & Ventilation Installation.,scope_creep,low,open,QA Inspector,2023-02-22,5
|
| 217 |
+
iss_00216,act_005_07,proj_005,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,low,resolved,Client PM,2023-02-24,0
|
| 218 |
+
iss_00217,act_005_07,proj_005,Undocumented additional work added to HVAC & Ventilation Installation.,scope_creep,medium,open,Project Engineer,2023-02-17,0
|
| 219 |
+
iss_00218,act_005_08,proj_005,Client-requested scope change impacts Floor Leveling & Screed.,design_change,low,resolved,Client PM,2023-03-09,0
|
| 220 |
+
iss_00219,act_005_08,proj_005,Insufficient crew available; Floor Leveling & Screed understaffed.,labor_shortage,medium,resolved,QA Inspector,2023-03-12,0
|
| 221 |
+
iss_00220,act_005_08,proj_005,Key equipment broke down mid-task on Floor Leveling & Screed.,equipment_breakdown,low,resolved,Client PM,2023-03-13,0
|
| 222 |
+
iss_00221,act_005_09,proj_005,Client-requested scope change impacts Tiling β Floors & Wet Areas.,design_change,low,open,Client PM,2023-03-26,5
|
| 223 |
+
iss_00222,act_005_09,proj_005,Delivery of Tiling β Floors & Wet Areas delayed by supplier.,material_delay,low,resolved,Procurement Lead,2023-03-26,0
|
| 224 |
+
iss_00223,act_005_09,proj_005,Client-requested scope change impacts Tiling β Floors & Wet Areas.,design_change,low,resolved,Contractor B,2023-03-22,0
|
| 225 |
+
iss_00224,act_005_10,proj_005,Safety non-compliance flagged during Wall Plastering & Screeding.,safety,high,open,Procurement Lead,2023-03-11,0
|
| 226 |
+
iss_00225,act_005_10,proj_005,Safety non-compliance flagged during Wall Plastering & Screeding.,safety,low,resolved,Contractor A,2023-03-07,0
|
| 227 |
+
iss_00226,act_005_10,proj_005,Delivery of Wall Plastering & Screeding delayed by supplier.,material_delay,medium,resolved,Site Manager,2023-03-12,0
|
| 228 |
+
iss_00227,act_005_11,proj_005,Client-requested scope change impacts False Ceiling & Insulation.,design_change,medium,open,Client PM,2023-03-25,0
|
| 229 |
+
iss_00228,act_005_11,proj_005,Adverse weather halted outdoor work on False Ceiling & Insulation.,weather,high,resolved,Contractor A,2023-03-26,0
|
| 230 |
+
iss_00229,act_005_11,proj_005,Safety non-compliance flagged during False Ceiling & Insulation.,safety,medium,resolved,Client PM,2023-03-29,0
|
| 231 |
+
iss_00230,act_005_12,proj_005,Municipal inspection failed; rework needed on Painting β Primer & Finish Coats.,inspection_fail,medium,open,Client PM,2023-04-13,2
|
| 232 |
+
iss_00231,act_005_12,proj_005,Safety non-compliance flagged during Painting β Primer & Finish Coats.,safety,high,resolved,Procurement Lead,2023-04-03,0
|
| 233 |
+
iss_00232,act_005_12,proj_005,Municipal inspection failed; rework needed on Painting β Primer & Finish Coats.,inspection_fail,medium,resolved,Site Manager,2023-04-04,0
|
| 234 |
+
iss_00233,act_005_13,proj_005,"Key equipment broke down mid-task on Carpentry, Joinery & Built-ins.",equipment_breakdown,high,resolved,Contractor B,2023-04-28,0
|
| 235 |
+
iss_00234,act_005_13,proj_005,"Undocumented additional work added to Carpentry, Joinery & Built-ins.",scope_creep,low,resolved,QA Inspector,2023-04-28,0
|
| 236 |
+
iss_00235,act_005_13,proj_005,"Client-requested scope change impacts Carpentry, Joinery & Built-ins.",design_change,high,open,Contractor A,2023-04-25,3
|
| 237 |
+
iss_00236,act_005_14,proj_005,"Undocumented additional work added to Fixtures, Fittings & Sanitaryware.",scope_creep,critical,resolved,Contractor B,2023-05-08,0
|
| 238 |
+
iss_00237,act_005_14,proj_005,"Safety non-compliance flagged during Fixtures, Fittings & Sanitaryware.",safety,high,resolved,QA Inspector,2023-05-08,0
|
| 239 |
+
iss_00238,act_005_14,proj_005,"Municipal inspection failed; rework needed on Fixtures, Fittings & Sanitaryware.",inspection_fail,low,resolved,Safety Officer,2023-05-13,0
|
| 240 |
+
iss_00239,act_005_15,proj_005,"Insufficient crew available; Final Inspection, Snag & Handover understaffed.",labor_shortage,medium,resolved,Safety Officer,2023-05-19,0
|
| 241 |
+
iss_00240,act_005_15,proj_005,"Insufficient crew available; Final Inspection, Snag & Handover understaffed.",labor_shortage,critical,resolved,Contractor B,2023-05-20,0
|
| 242 |
+
iss_00241,act_006_01,proj_006,Adverse weather halted outdoor work on Site Survey & Mobilization.,weather,medium,resolved,Contractor B,2023-03-06,0
|
| 243 |
+
iss_00242,act_006_01,proj_006,Undocumented additional work added to Site Survey & Mobilization.,scope_creep,low,resolved,Site Manager,2023-03-07,0
|
| 244 |
+
iss_00243,act_006_02,proj_006,Delivery of Demolition & Strip-Out delayed by supplier.,material_delay,low,resolved,Contractor A,2023-03-14,0
|
| 245 |
+
iss_00244,act_006_02,proj_006,Undocumented additional work added to Demolition & Strip-Out.,scope_creep,medium,resolved,Site Manager,2023-03-14,0
|
| 246 |
+
iss_00245,act_006_02,proj_006,Municipal inspection failed; rework needed on Demolition & Strip-Out.,inspection_fail,low,resolved,Contractor B,2023-03-15,0
|
| 247 |
+
iss_00246,act_006_03,proj_006,Municipal inspection failed; rework needed on Structural Repairs & Reinforcement.,inspection_fail,low,resolved,QA Inspector,2023-03-29,0
|
| 248 |
+
iss_00247,act_006_03,proj_006,Municipal inspection failed; rework needed on Structural Repairs & Reinforcement.,inspection_fail,low,resolved,Safety Officer,2023-04-03,0
|
| 249 |
+
iss_00248,act_006_03,proj_006,Key equipment broke down mid-task on Structural Repairs & Reinforcement.,equipment_breakdown,medium,resolved,Contractor A,2023-04-04,0
|
| 250 |
+
iss_00249,act_006_03,proj_006,Municipal inspection failed; rework needed on Structural Repairs & Reinforcement.,inspection_fail,medium,open,Safety Officer,2023-03-31,3
|
| 251 |
+
iss_00250,act_006_04,proj_006,Client-requested scope change impacts Waterproofing & Damp Proofing.,design_change,low,resolved,Project Engineer,2023-04-22,0
|
| 252 |
+
iss_00251,act_006_04,proj_006,Municipal inspection failed; rework needed on Waterproofing & Damp Proofing.,inspection_fail,low,resolved,Procurement Lead,2023-04-20,0
|
| 253 |
+
iss_00252,act_006_04,proj_006,Key equipment broke down mid-task on Waterproofing & Damp Proofing.,equipment_breakdown,high,resolved,Contractor A,2023-04-20,0
|
| 254 |
+
iss_00253,act_006_04,proj_006,Undocumented additional work added to Waterproofing & Damp Proofing.,scope_creep,medium,resolved,Safety Officer,2023-04-25,0
|
| 255 |
+
iss_00254,act_006_05,proj_006,Safety non-compliance flagged during Plumbing Rough-in.,safety,medium,resolved,QA Inspector,2023-04-24,0
|
| 256 |
+
iss_00255,act_006_05,proj_006,Delivery of Plumbing Rough-in delayed by supplier.,material_delay,critical,open,Contractor A,2023-04-29,3
|
| 257 |
+
iss_00256,act_006_05,proj_006,Adverse weather halted outdoor work on Plumbing Rough-in.,weather,medium,resolved,Project Engineer,2023-04-26,0
|
| 258 |
+
iss_00257,act_006_05,proj_006,Safety non-compliance flagged during Plumbing Rough-in.,safety,low,resolved,Client PM,2023-04-17,0
|
| 259 |
+
iss_00258,act_006_06,proj_006,Key equipment broke down mid-task on Electrical Wiring & Conduits.,equipment_breakdown,low,resolved,Procurement Lead,2023-04-29,0
|
| 260 |
+
iss_00259,act_006_06,proj_006,Undocumented additional work added to Electrical Wiring & Conduits.,scope_creep,high,open,Contractor A,2023-04-22,2
|
| 261 |
+
iss_00260,act_006_06,proj_006,Insufficient crew available; Electrical Wiring & Conduits understaffed.,labor_shortage,high,resolved,Safety Officer,2023-04-30,0
|
| 262 |
+
iss_00261,act_006_06,proj_006,Delivery of Electrical Wiring & Conduits delayed by supplier.,material_delay,low,resolved,Site Manager,2023-04-28,0
|
| 263 |
+
iss_00262,act_006_07,proj_006,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,medium,resolved,Procurement Lead,2023-04-20,0
|
| 264 |
+
iss_00263,act_006_07,proj_006,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,high,resolved,Contractor B,2023-04-22,0
|
| 265 |
+
iss_00264,act_006_07,proj_006,Municipal inspection failed; rework needed on HVAC & Ventilation Installation.,inspection_fail,high,resolved,Procurement Lead,2023-04-27,0
|
| 266 |
+
iss_00265,act_006_07,proj_006,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,low,open,Contractor A,2023-04-26,4
|
| 267 |
+
iss_00266,act_006_08,proj_006,Insufficient crew available; Floor Leveling & Screed understaffed.,labor_shortage,low,open,Procurement Lead,2023-05-11,0
|
| 268 |
+
iss_00267,act_006_08,proj_006,Delivery of Floor Leveling & Screed delayed by supplier.,material_delay,critical,resolved,Procurement Lead,2023-05-07,0
|
| 269 |
+
iss_00268,act_006_08,proj_006,Client-requested scope change impacts Floor Leveling & Screed.,design_change,high,resolved,Procurement Lead,2023-05-14,0
|
| 270 |
+
iss_00269,act_006_09,proj_006,Insufficient crew available; Tiling β Floors & Wet Areas understaffed.,labor_shortage,medium,resolved,Contractor B,2023-05-24,0
|
| 271 |
+
iss_00270,act_006_09,proj_006,Client-requested scope change impacts Tiling β Floors & Wet Areas.,design_change,low,resolved,Project Engineer,2023-06-04,0
|
| 272 |
+
iss_00271,act_006_09,proj_006,Undocumented additional work added to Tiling β Floors & Wet Areas.,scope_creep,low,resolved,Procurement Lead,2023-05-31,0
|
| 273 |
+
iss_00272,act_006_10,proj_006,Municipal inspection failed; rework needed on Wall Plastering & Screeding.,inspection_fail,medium,resolved,Contractor A,2023-05-14,0
|
| 274 |
+
iss_00273,act_006_10,proj_006,Key equipment broke down mid-task on Wall Plastering & Screeding.,equipment_breakdown,high,open,Procurement Lead,2023-05-08,2
|
| 275 |
+
iss_00274,act_006_10,proj_006,Key equipment broke down mid-task on Wall Plastering & Screeding.,equipment_breakdown,low,resolved,Procurement Lead,2023-05-07,0
|
| 276 |
+
iss_00275,act_006_11,proj_006,Safety non-compliance flagged during False Ceiling & Insulation.,safety,critical,resolved,Procurement Lead,2023-05-28,0
|
| 277 |
+
iss_00276,act_006_11,proj_006,Delivery of False Ceiling & Insulation delayed by supplier.,material_delay,critical,resolved,Project Engineer,2023-05-29,0
|
| 278 |
+
iss_00277,act_006_11,proj_006,Key equipment broke down mid-task on False Ceiling & Insulation.,equipment_breakdown,medium,open,Safety Officer,2023-06-02,1
|
| 279 |
+
iss_00278,act_006_12,proj_006,Safety non-compliance flagged during Painting β Primer & Finish Coats.,safety,medium,resolved,Contractor B,2023-06-11,0
|
| 280 |
+
iss_00279,act_006_12,proj_006,Municipal inspection failed; rework needed on Painting β Primer & Finish Coats.,inspection_fail,critical,open,Procurement Lead,2023-06-13,5
|
| 281 |
+
iss_00280,act_006_12,proj_006,Undocumented additional work added to Painting β Primer & Finish Coats.,scope_creep,medium,open,Client PM,2023-06-09,5
|
| 282 |
+
iss_00281,act_006_13,proj_006,"Safety non-compliance flagged during Carpentry, Joinery & Built-ins.",safety,medium,resolved,QA Inspector,2023-06-28,0
|
| 283 |
+
iss_00282,act_006_13,proj_006,"Delivery of Carpentry, Joinery & Built-ins delayed by supplier.",material_delay,low,resolved,Project Engineer,2023-06-29,0
|
| 284 |
+
iss_00283,act_006_13,proj_006,"Insufficient crew available; Carpentry, Joinery & Built-ins understaffed.",labor_shortage,medium,resolved,Safety Officer,2023-07-03,0
|
| 285 |
+
iss_00284,act_006_14,proj_006,"Client-requested scope change impacts Fixtures, Fittings & Sanitaryware.",design_change,low,resolved,QA Inspector,2023-07-20,0
|
| 286 |
+
iss_00285,act_006_14,proj_006,"Insufficient crew available; Fixtures, Fittings & Sanitaryware understaffed.",labor_shortage,low,resolved,Site Manager,2023-07-15,0
|
| 287 |
+
iss_00286,act_006_14,proj_006,"Undocumented additional work added to Fixtures, Fittings & Sanitaryware.",scope_creep,high,resolved,Site Manager,2023-07-16,0
|
| 288 |
+
iss_00287,act_006_15,proj_006,"Safety non-compliance flagged during Final Inspection, Snag & Handover.",safety,low,resolved,Contractor B,2023-08-01,0
|
| 289 |
+
iss_00288,act_006_15,proj_006,"Client-requested scope change impacts Final Inspection, Snag & Handover.",design_change,low,resolved,Client PM,2023-07-28,0
|
| 290 |
+
iss_00289,act_007_01,proj_007,Client-requested scope change impacts Site Survey & Mobilization.,design_change,high,resolved,Project Engineer,2023-06-01,0
|
| 291 |
+
iss_00290,act_007_01,proj_007,Delivery of Site Survey & Mobilization delayed by supplier.,material_delay,medium,resolved,Project Engineer,2023-06-01,0
|
| 292 |
+
iss_00291,act_007_02,proj_007,Adverse weather halted outdoor work on Demolition & Strip-Out.,weather,high,resolved,QA Inspector,2023-06-19,0
|
| 293 |
+
iss_00292,act_007_02,proj_007,Insufficient crew available; Demolition & Strip-Out understaffed.,labor_shortage,medium,resolved,Procurement Lead,2023-06-13,0
|
| 294 |
+
iss_00293,act_007_02,proj_007,Client-requested scope change impacts Demolition & Strip-Out.,design_change,medium,resolved,Safety Officer,2023-06-15,0
|
| 295 |
+
iss_00294,act_007_03,proj_007,Adverse weather halted outdoor work on Structural Repairs & Reinforcement.,weather,high,resolved,QA Inspector,2023-07-01,0
|
| 296 |
+
iss_00295,act_007_03,proj_007,Insufficient crew available; Structural Repairs & Reinforcement understaffed.,labor_shortage,low,resolved,Contractor A,2023-07-02,0
|
| 297 |
+
iss_00296,act_007_03,proj_007,Undocumented additional work added to Structural Repairs & Reinforcement.,scope_creep,low,resolved,Safety Officer,2023-06-29,0
|
| 298 |
+
iss_00297,act_007_03,proj_007,Client-requested scope change impacts Structural Repairs & Reinforcement.,design_change,high,resolved,Client PM,2023-07-11,0
|
| 299 |
+
iss_00298,act_007_04,proj_007,Safety non-compliance flagged during Waterproofing & Damp Proofing.,safety,low,resolved,Client PM,2023-07-23,0
|
| 300 |
+
iss_00299,act_007_04,proj_007,Client-requested scope change impacts Waterproofing & Damp Proofing.,design_change,high,resolved,Client PM,2023-07-28,0
|
| 301 |
+
iss_00300,act_007_04,proj_007,Delivery of Waterproofing & Damp Proofing delayed by supplier.,material_delay,medium,resolved,Procurement Lead,2023-07-26,0
|
| 302 |
+
iss_00301,act_007_04,proj_007,Delivery of Waterproofing & Damp Proofing delayed by supplier.,material_delay,low,resolved,Project Engineer,2023-07-27,0
|
| 303 |
+
iss_00302,act_007_05,proj_007,Delivery of Plumbing Rough-in delayed by supplier.,material_delay,low,resolved,Safety Officer,2023-08-02,0
|
| 304 |
+
iss_00303,act_007_05,proj_007,Delivery of Plumbing Rough-in delayed by supplier.,material_delay,low,open,Site Manager,2023-07-26,4
|
| 305 |
+
iss_00304,act_007_05,proj_007,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,critical,resolved,Contractor A,2023-07-29,0
|
| 306 |
+
iss_00305,act_007_05,proj_007,Undocumented additional work added to Plumbing Rough-in.,scope_creep,critical,resolved,Site Manager,2023-07-22,0
|
| 307 |
+
iss_00306,act_007_06,proj_007,Delivery of Electrical Wiring & Conduits delayed by supplier.,material_delay,medium,open,QA Inspector,2023-07-29,2
|
| 308 |
+
iss_00307,act_007_06,proj_007,Municipal inspection failed; rework needed on Electrical Wiring & Conduits.,inspection_fail,high,resolved,Project Engineer,2023-07-22,0
|
| 309 |
+
iss_00308,act_007_06,proj_007,Delivery of Electrical Wiring & Conduits delayed by supplier.,material_delay,low,resolved,Project Engineer,2023-07-30,0
|
| 310 |
+
iss_00309,act_007_06,proj_007,Key equipment broke down mid-task on Electrical Wiring & Conduits.,equipment_breakdown,medium,resolved,Procurement Lead,2023-07-22,0
|
| 311 |
+
iss_00310,act_007_07,proj_007,Key equipment broke down mid-task on HVAC & Ventilation Installation.,equipment_breakdown,high,resolved,QA Inspector,2023-07-27,0
|
| 312 |
+
iss_00311,act_007_07,proj_007,Adverse weather halted outdoor work on HVAC & Ventilation Installation.,weather,low,open,Safety Officer,2023-07-26,4
|
| 313 |
+
iss_00312,act_007_07,proj_007,Client-requested scope change impacts HVAC & Ventilation Installation.,design_change,medium,resolved,Project Engineer,2023-07-24,0
|
| 314 |
+
iss_00313,act_007_07,proj_007,Insufficient crew available; HVAC & Ventilation Installation understaffed.,labor_shortage,medium,open,Site Manager,2023-07-21,5
|
| 315 |
+
iss_00314,act_007_08,proj_007,Client-requested scope change impacts Floor Leveling & Screed.,design_change,high,open,Procurement Lead,2023-08-09,1
|
| 316 |
+
iss_00315,act_007_08,proj_007,Municipal inspection failed; rework needed on Floor Leveling & Screed.,inspection_fail,low,resolved,Project Engineer,2023-08-11,0
|
| 317 |
+
iss_00316,act_007_08,proj_007,Adverse weather halted outdoor work on Floor Leveling & Screed.,weather,medium,resolved,Contractor A,2023-08-08,0
|
| 318 |
+
iss_00317,act_007_09,proj_007,Insufficient crew available; Tiling β Floors & Wet Areas understaffed.,labor_shortage,low,resolved,Procurement Lead,2023-08-31,0
|
| 319 |
+
iss_00318,act_007_09,proj_007,Client-requested scope change impacts Tiling β Floors & Wet Areas.,design_change,medium,resolved,Safety Officer,2023-09-06,0
|
| 320 |
+
iss_00319,act_007_09,proj_007,Municipal inspection failed; rework needed on Tiling β Floors & Wet Areas.,inspection_fail,high,open,Safety Officer,2023-09-06,2
|
| 321 |
+
iss_00320,act_007_10,proj_007,Insufficient crew available; Wall Plastering & Screeding understaffed.,labor_shortage,low,resolved,Procurement Lead,2023-08-16,0
|
| 322 |
+
iss_00321,act_007_10,proj_007,Insufficient crew available; Wall Plastering & Screeding understaffed.,labor_shortage,low,open,Project Engineer,2023-08-16,4
|
| 323 |
+
iss_00322,act_007_10,proj_007,Client-requested scope change impacts Wall Plastering & Screeding.,design_change,low,resolved,Contractor B,2023-08-12,0
|
| 324 |
+
iss_00323,act_007_11,proj_007,Client-requested scope change impacts False Ceiling & Insulation.,design_change,medium,resolved,Procurement Lead,2023-08-29,0
|
| 325 |
+
iss_00324,act_007_11,proj_007,Delivery of False Ceiling & Insulation delayed by supplier.,material_delay,medium,open,QA Inspector,2023-09-01,2
|
| 326 |
+
iss_00325,act_007_11,proj_007,Insufficient crew available; False Ceiling & Insulation understaffed.,labor_shortage,low,resolved,QA Inspector,2023-09-04,0
|
| 327 |
+
iss_00326,act_007_12,proj_007,Delivery of Painting β Primer & Finish Coats delayed by supplier.,material_delay,high,resolved,Site Manager,2023-09-14,0
|
| 328 |
+
iss_00327,act_007_12,proj_007,Client-requested scope change impacts Painting β Primer & Finish Coats.,design_change,medium,resolved,Site Manager,2023-09-21,0
|
| 329 |
+
iss_00328,act_007_12,proj_007,Municipal inspection failed; rework needed on Painting β Primer & Finish Coats.,inspection_fail,low,resolved,Site Manager,2023-09-20,0
|
| 330 |
+
iss_00329,act_007_13,proj_007,"Safety non-compliance flagged during Carpentry, Joinery & Built-ins.",safety,critical,resolved,Project Engineer,2023-10-01,0
|
| 331 |
+
iss_00330,act_007_13,proj_007,"Safety non-compliance flagged during Carpentry, Joinery & Built-ins.",safety,high,resolved,QA Inspector,2023-10-02,0
|
| 332 |
+
iss_00331,act_007_13,proj_007,"Insufficient crew available; Carpentry, Joinery & Built-ins understaffed.",labor_shortage,medium,resolved,Client PM,2023-10-15,0
|
| 333 |
+
iss_00332,act_007_14,proj_007,"Key equipment broke down mid-task on Fixtures, Fittings & Sanitaryware.",equipment_breakdown,medium,resolved,Client PM,2023-10-21,0
|
| 334 |
+
iss_00333,act_007_14,proj_007,"Key equipment broke down mid-task on Fixtures, Fittings & Sanitaryware.",equipment_breakdown,medium,resolved,Project Engineer,2023-10-21,0
|
| 335 |
+
iss_00334,act_007_14,proj_007,"Delivery of Fixtures, Fittings & Sanitaryware delayed by supplier.",material_delay,low,resolved,Client PM,2023-10-20,0
|
| 336 |
+
iss_00335,act_007_15,proj_007,"Client-requested scope change impacts Final Inspection, Snag & Handover.",design_change,high,resolved,QA Inspector,2023-11-02,0
|
| 337 |
+
iss_00336,act_007_15,proj_007,"Municipal inspection failed; rework needed on Final Inspection, Snag & Handover.",inspection_fail,medium,resolved,Site Manager,2023-11-02,0
|
| 338 |
+
iss_00337,act_008_01,proj_008,Municipal inspection failed; rework needed on Site Survey & Mobilization.,inspection_fail,medium,open,Contractor B,2024-01-21,2
|
| 339 |
+
iss_00338,act_008_01,proj_008,Undocumented additional work added to Site Survey & Mobilization.,scope_creep,low,open,Safety Officer,2024-01-21,0
|
| 340 |
+
iss_00339,act_008_02,proj_008,Client-requested scope change impacts Demolition & Strip-Out.,design_change,medium,resolved,Contractor A,2024-02-03,0
|
| 341 |
+
iss_00340,act_008_02,proj_008,Safety non-compliance flagged during Demolition & Strip-Out.,safety,critical,open,Client PM,2024-02-03,2
|
| 342 |
+
iss_00341,act_008_02,proj_008,Undocumented additional work added to Demolition & Strip-Out.,scope_creep,low,resolved,Contractor B,2024-02-08,0
|
| 343 |
+
iss_00342,act_008_03,proj_008,Delivery of Structural Repairs & Reinforcement delayed by supplier.,material_delay,low,resolved,Contractor B,2024-02-29,0
|
| 344 |
+
iss_00343,act_008_03,proj_008,Undocumented additional work added to Structural Repairs & Reinforcement.,scope_creep,medium,open,Project Engineer,2024-02-14,5
|
| 345 |
+
iss_00344,act_008_03,proj_008,Municipal inspection failed; rework needed on Structural Repairs & Reinforcement.,inspection_fail,critical,open,Site Manager,2024-02-20,2
|
| 346 |
+
iss_00345,act_008_03,proj_008,Safety non-compliance flagged during Structural Repairs & Reinforcement.,safety,low,open,Contractor A,2024-02-20,0
|
| 347 |
+
iss_00346,act_008_04,proj_008,Client-requested scope change impacts Waterproofing & Damp Proofing.,design_change,medium,open,QA Inspector,2024-03-04,5
|
| 348 |
+
iss_00347,act_008_04,proj_008,Key equipment broke down mid-task on Waterproofing & Damp Proofing.,equipment_breakdown,high,open,Safety Officer,2024-03-08,2
|
| 349 |
+
iss_00348,act_008_04,proj_008,Key equipment broke down mid-task on Waterproofing & Damp Proofing.,equipment_breakdown,high,open,Site Manager,2024-03-05,2
|
| 350 |
+
iss_00349,act_008_04,proj_008,Safety non-compliance flagged during Waterproofing & Damp Proofing.,safety,low,resolved,Site Manager,2024-03-04,0
|
| 351 |
+
iss_00350,act_008_05,proj_008,Client-requested scope change impacts Plumbing Rough-in.,design_change,high,open,Safety Officer,2024-03-07,5
|
| 352 |
+
iss_00351,act_008_05,proj_008,Key equipment broke down mid-task on Plumbing Rough-in.,equipment_breakdown,high,open,Contractor B,2024-03-10,5
|
| 353 |
+
iss_00352,act_008_05,proj_008,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,critical,resolved,Project Engineer,2024-03-13,0
|
| 354 |
+
iss_00353,act_008_05,proj_008,Key equipment broke down mid-task on Plumbing Rough-in.,equipment_breakdown,medium,open,Site Manager,2024-03-13,4
|
| 355 |
+
iss_00354,act_008_06,proj_008,Undocumented additional work added to Electrical Wiring & Conduits.,scope_creep,medium,open,Client PM,2024-03-07,2
|
| 356 |
+
iss_00355,act_008_06,proj_008,Municipal inspection failed; rework needed on Electrical Wiring & Conduits.,inspection_fail,critical,open,Project Engineer,2024-03-11,2
|
| 357 |
+
iss_00356,act_008_06,proj_008,Safety non-compliance flagged during Electrical Wiring & Conduits.,safety,high,open,Procurement Lead,2024-03-15,1
|
| 358 |
+
iss_00357,act_008_06,proj_008,Key equipment broke down mid-task on Electrical Wiring & Conduits.,equipment_breakdown,medium,open,Contractor A,2024-03-09,4
|
| 359 |
+
iss_00358,act_008_07,proj_008,Undocumented additional work added to HVAC & Ventilation Installation.,scope_creep,medium,open,Project Engineer,2024-03-14,3
|
| 360 |
+
iss_00359,act_008_07,proj_008,Adverse weather halted outdoor work on HVAC & Ventilation Installation.,weather,critical,open,Contractor B,2024-03-14,3
|
| 361 |
+
iss_00360,act_008_07,proj_008,Municipal inspection failed; rework needed on HVAC & Ventilation Installation.,inspection_fail,high,open,Contractor A,2024-03-11,0
|
| 362 |
+
iss_00361,act_008_07,proj_008,Key equipment broke down mid-task on HVAC & Ventilation Installation.,equipment_breakdown,medium,open,Project Engineer,2024-03-07,3
|
| 363 |
+
iss_00362,act_008_08,proj_008,Undocumented additional work added to Floor Leveling & Screed.,scope_creep,low,open,Procurement Lead,2024-03-22,2
|
| 364 |
+
iss_00363,act_008_08,proj_008,Adverse weather halted outdoor work on Floor Leveling & Screed.,weather,high,resolved,Site Manager,2024-03-23,0
|
| 365 |
+
iss_00364,act_008_08,proj_008,Insufficient crew available; Floor Leveling & Screed understaffed.,labor_shortage,low,resolved,QA Inspector,2024-03-27,0
|
| 366 |
+
iss_00365,act_008_09,proj_008,Safety non-compliance flagged during Tiling β Floors & Wet Areas.,safety,low,resolved,Project Engineer,2024-04-10,0
|
| 367 |
+
iss_00366,act_008_09,proj_008,Insufficient crew available; Tiling β Floors & Wet Areas understaffed.,labor_shortage,medium,resolved,Safety Officer,2024-04-04,0
|
| 368 |
+
iss_00367,act_008_09,proj_008,Delivery of Tiling β Floors & Wet Areas delayed by supplier.,material_delay,low,resolved,Procurement Lead,2024-04-14,0
|
| 369 |
+
iss_00368,act_009_01,proj_009,Undocumented additional work added to Site Survey & Mobilization.,scope_creep,high,open,Contractor B,2024-03-06,3
|
| 370 |
+
iss_00369,act_009_01,proj_009,Adverse weather halted outdoor work on Site Survey & Mobilization.,weather,high,resolved,Contractor A,2024-03-02,0
|
| 371 |
+
iss_00370,act_009_02,proj_009,Delivery of Demolition & Strip-Out delayed by supplier.,material_delay,medium,open,Procurement Lead,2024-03-16,5
|
| 372 |
+
iss_00371,act_009_02,proj_009,Safety non-compliance flagged during Demolition & Strip-Out.,safety,medium,open,Client PM,2024-03-11,4
|
| 373 |
+
iss_00372,act_009_02,proj_009,Client-requested scope change impacts Demolition & Strip-Out.,design_change,low,open,QA Inspector,2024-03-14,4
|
| 374 |
+
iss_00373,act_009_03,proj_009,Safety non-compliance flagged during Structural Repairs & Reinforcement.,safety,medium,resolved,Contractor B,2024-03-24,0
|
| 375 |
+
iss_00374,act_009_03,proj_009,Client-requested scope change impacts Structural Repairs & Reinforcement.,design_change,medium,open,Safety Officer,2024-03-26,4
|
| 376 |
+
iss_00375,act_009_03,proj_009,Safety non-compliance flagged during Structural Repairs & Reinforcement.,safety,low,open,Procurement Lead,2024-04-06,2
|
| 377 |
+
iss_00376,act_009_03,proj_009,Client-requested scope change impacts Structural Repairs & Reinforcement.,design_change,high,open,Contractor A,2024-03-30,2
|
| 378 |
+
iss_00377,act_009_04,proj_009,Municipal inspection failed; rework needed on Waterproofing & Damp Proofing.,inspection_fail,low,open,Contractor B,2024-04-12,4
|
| 379 |
+
iss_00378,act_009_04,proj_009,Delivery of Waterproofing & Damp Proofing delayed by supplier.,material_delay,critical,open,Site Manager,2024-04-19,1
|
| 380 |
+
iss_00379,act_009_04,proj_009,Delivery of Waterproofing & Damp Proofing delayed by supplier.,material_delay,medium,open,QA Inspector,2024-04-19,4
|
| 381 |
+
iss_00380,act_009_04,proj_009,Adverse weather halted outdoor work on Waterproofing & Damp Proofing.,weather,high,open,Contractor A,2024-04-19,0
|
| 382 |
+
iss_00381,act_009_05,proj_009,Key equipment broke down mid-task on Plumbing Rough-in.,equipment_breakdown,medium,open,Client PM,2024-04-23,1
|
| 383 |
+
iss_00382,act_009_05,proj_009,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,critical,resolved,Project Engineer,2024-04-23,0
|
| 384 |
+
iss_00383,act_009_05,proj_009,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,medium,open,Procurement Lead,2024-04-22,2
|
| 385 |
+
iss_00384,act_009_05,proj_009,Insufficient crew available; Plumbing Rough-in understaffed.,labor_shortage,high,open,QA Inspector,2024-04-13,0
|
| 386 |
+
iss_00385,act_009_06,proj_009,Safety non-compliance flagged during Electrical Wiring & Conduits.,safety,low,resolved,Site Manager,2024-04-22,0
|
| 387 |
+
iss_00386,act_009_06,proj_009,Delivery of Electrical Wiring & Conduits delayed by supplier.,material_delay,low,resolved,Project Engineer,2024-04-22,0
|
| 388 |
+
iss_00387,act_009_06,proj_009,Client-requested scope change impacts Electrical Wiring & Conduits.,design_change,low,open,Procurement Lead,2024-04-16,1
|
| 389 |
+
iss_00388,act_009_06,proj_009,Adverse weather halted outdoor work on Electrical Wiring & Conduits.,weather,low,resolved,Project Engineer,2024-04-12,0
|
| 390 |
+
iss_00389,act_009_07,proj_009,Key equipment broke down mid-task on HVAC & Ventilation Installation.,equipment_breakdown,low,resolved,Project Engineer,2024-04-18,0
|
| 391 |
+
iss_00390,act_009_07,proj_009,Delivery of HVAC & Ventilation Installation delayed by supplier.,material_delay,medium,open,Project Engineer,2024-04-21,3
|
| 392 |
+
iss_00391,act_009_07,proj_009,Undocumented additional work added to HVAC & Ventilation Installation.,scope_creep,medium,resolved,Client PM,2024-04-19,0
|
| 393 |
+
iss_00392,act_009_07,proj_009,Municipal inspection failed; rework needed on HVAC & Ventilation Installation.,inspection_fail,medium,open,QA Inspector,2024-04-25,5
|
| 394 |
+
iss_00393,act_009_08,proj_009,Safety non-compliance flagged during Floor Leveling & Screed.,safety,medium,open,Contractor A,2024-05-03,1
|
| 395 |
+
iss_00394,act_009_08,proj_009,Key equipment broke down mid-task on Floor Leveling & Screed.,equipment_breakdown,critical,open,QA Inspector,2024-04-30,5
|
| 396 |
+
iss_00395,act_009_08,proj_009,Adverse weather halted outdoor work on Floor Leveling & Screed.,weather,medium,open,Safety Officer,2024-05-05,0
|
data/projects.csv
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,name,planned_start,planned_end,type,city,actual_start,actual_end,status
|
| 2 |
+
proj_001,Parkview Residence Renovation,2022-01-10,2022-07-31,residential,Mumbai,2022-01-10,2022-06-06,completed
|
| 3 |
+
proj_002,Downtown Office Fit-Out Phase 1,2022-03-01,2022-09-30,commercial,Delhi,2022-03-01,2022-07-17,completed
|
| 4 |
+
proj_003,Greenfield Villa Complex,2022-06-15,2023-01-20,residential,Bangalore,2022-06-15,2022-11-14,completed
|
| 5 |
+
proj_004,Heritage Hotel Refurbishment,2022-09-01,2023-04-30,hospitality,Jaipur,2022-09-01,2023-01-30,completed
|
| 6 |
+
proj_005,Tech Park Interior Overhaul,2023-01-05,2023-08-15,commercial,Hyderabad,2023-01-05,2023-05-24,completed
|
| 7 |
+
proj_006,Riverside Apartment Renovation,2023-03-01,2023-09-28,residential,Pune,2023-03-01,2023-08-03,completed
|
| 8 |
+
proj_007,Coastal Resort Renovation,2023-06-01,2024-01-31,hospitality,Goa,2023-06-01,2023-11-09,completed
|
| 9 |
+
proj_008,Lakeview Villa Renovation,2024-01-15,2024-08-31,residential,Chennai,2024-01-15,,in_progress
|
| 10 |
+
proj_009,Metro Commercial Tower Fit-Out,2024-03-01,2024-11-30,commercial,Mumbai,2024-03-01,,in_progress
|
| 11 |
+
proj_010,Skyline Penthouse Renovation,2024-09-01,2025-03-31,residential,Delhi,,,not_started
|
data/resources.csv
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,activity_id,project_id,contractor,resource_type,allocated_workers,cost_per_day,start_date,end_date
|
| 2 |
+
res_00001,act_001_01,proj_001,Apex Interiors,Material Supplier,18,27695,2022-01-10,2022-01-19
|
| 3 |
+
res_00002,act_001_01,proj_001,ProStruct Engineers,Specialist Subcontractor,3,17533,2022-01-10,2022-01-19
|
| 4 |
+
res_00003,act_001_01,proj_001,Swift MEP Pvt Ltd,Specialist Subcontractor,16,9992,2022-01-10,2022-01-19
|
| 5 |
+
res_00004,act_001_02,proj_001,Urban Build Solutions,Equipment,11,30118,2022-01-19,2022-02-01
|
| 6 |
+
res_00005,act_001_02,proj_001,Swift MEP Pvt Ltd,Material Supplier,15,34510,2022-01-19,2022-02-01
|
| 7 |
+
res_00006,act_001_02,proj_001,ProStruct Engineers,Material Supplier,15,16542,2022-01-19,2022-02-01
|
| 8 |
+
res_00007,act_001_03,proj_001,Swift MEP Pvt Ltd,Material Supplier,10,19135,2022-02-01,2022-02-20
|
| 9 |
+
res_00008,act_001_04,proj_001,Urban Build Solutions,Labour Gang,12,22668,2022-02-20,2022-03-01
|
| 10 |
+
res_00009,act_001_04,proj_001,ProStruct Engineers,Specialist Subcontractor,8,25564,2022-02-20,2022-03-01
|
| 11 |
+
res_00010,act_001_04,proj_001,Apex Interiors,Labour Gang,13,12234,2022-02-20,2022-03-01
|
| 12 |
+
res_00011,act_001_05,proj_001,EliteFinish Works,Labour Gang,3,34293,2022-02-20,2022-03-08
|
| 13 |
+
res_00012,act_001_05,proj_001,ProStruct Engineers,Labour Gang,13,19557,2022-02-20,2022-03-08
|
| 14 |
+
res_00013,act_001_05,proj_001,Urban Build Solutions,Labour Gang,4,24995,2022-02-20,2022-03-08
|
| 15 |
+
res_00014,act_001_06,proj_001,Swift MEP Pvt Ltd,Specialist Subcontractor,8,25553,2022-02-20,2022-03-09
|
| 16 |
+
res_00015,act_001_07,proj_001,Urban Build Solutions,Specialist Subcontractor,12,34256,2022-02-20,2022-03-05
|
| 17 |
+
res_00016,act_001_07,proj_001,Apex Interiors,Equipment,13,21546,2022-02-20,2022-03-05
|
| 18 |
+
res_00017,act_001_08,proj_001,EliteFinish Works,Specialist Subcontractor,3,9182,2022-03-08,2022-03-20
|
| 19 |
+
res_00018,act_001_09,proj_001,Urban Build Solutions,Labour Gang,19,21039,2022-03-20,2022-04-10
|
| 20 |
+
res_00019,act_001_10,proj_001,BuildRight Co.,Specialist Subcontractor,12,17878,2022-03-09,2022-03-24
|
| 21 |
+
res_00020,act_001_10,proj_001,BuildRight Co.,Specialist Subcontractor,10,9106,2022-03-09,2022-03-24
|
| 22 |
+
res_00021,act_001_11,proj_001,National Contractors,Labour Gang,15,29472,2022-03-26,2022-04-08
|
| 23 |
+
res_00022,act_001_11,proj_001,ProStruct Engineers,Specialist Subcontractor,11,10782,2022-03-26,2022-04-08
|
| 24 |
+
res_00023,act_001_12,proj_001,BuildRight Co.,Material Supplier,3,8483,2022-04-08,2022-04-25
|
| 25 |
+
res_00024,act_001_13,proj_001,Urban Build Solutions,Specialist Subcontractor,6,32113,2022-04-28,2022-05-18
|
| 26 |
+
res_00025,act_001_13,proj_001,EliteFinish Works,Material Supplier,9,27847,2022-04-28,2022-05-18
|
| 27 |
+
res_00026,act_001_13,proj_001,Urban Build Solutions,Equipment,13,21931,2022-04-28,2022-05-18
|
| 28 |
+
res_00027,act_001_14,proj_001,National Contractors,Labour Gang,12,16980,2022-05-18,2022-05-29
|
| 29 |
+
res_00028,act_001_14,proj_001,ProStruct Engineers,Specialist Subcontractor,6,16659,2022-05-18,2022-05-29
|
| 30 |
+
res_00029,act_001_14,proj_001,National Contractors,Material Supplier,15,17543,2022-05-18,2022-05-29
|
| 31 |
+
res_00030,act_001_15,proj_001,BuildRight Co.,Specialist Subcontractor,16,26382,2022-05-29,2022-06-06
|
| 32 |
+
res_00031,act_001_15,proj_001,Swift MEP Pvt Ltd,Material Supplier,12,31031,2022-05-29,2022-06-06
|
| 33 |
+
res_00032,act_002_01,proj_002,EliteFinish Works,Specialist Subcontractor,15,8564,2022-03-01,2022-03-09
|
| 34 |
+
res_00033,act_002_01,proj_002,ProStruct Engineers,Material Supplier,14,32992,2022-03-01,2022-03-09
|
| 35 |
+
res_00034,act_002_01,proj_002,EliteFinish Works,Labour Gang,17,15342,2022-03-01,2022-03-09
|
| 36 |
+
res_00035,act_002_02,proj_002,BuildRight Co.,Material Supplier,10,22650,2022-03-10,2022-03-23
|
| 37 |
+
res_00036,act_002_02,proj_002,Swift MEP Pvt Ltd,Material Supplier,6,29063,2022-03-10,2022-03-23
|
| 38 |
+
res_00037,act_002_02,proj_002,Swift MEP Pvt Ltd,Equipment,7,34531,2022-03-10,2022-03-23
|
| 39 |
+
res_00038,act_002_03,proj_002,BuildRight Co.,Labour Gang,20,13546,2022-03-23,2022-04-11
|
| 40 |
+
res_00039,act_002_03,proj_002,Apex Interiors,Material Supplier,10,10748,2022-03-23,2022-04-11
|
| 41 |
+
res_00040,act_002_03,proj_002,Apex Interiors,Material Supplier,18,25150,2022-03-23,2022-04-11
|
| 42 |
+
res_00041,act_002_04,proj_002,Urban Build Solutions,Specialist Subcontractor,4,33146,2022-04-11,2022-04-20
|
| 43 |
+
res_00042,act_002_04,proj_002,ProStruct Engineers,Equipment,16,18205,2022-04-11,2022-04-20
|
| 44 |
+
res_00043,act_002_04,proj_002,National Contractors,Equipment,7,9196,2022-04-11,2022-04-20
|
| 45 |
+
res_00044,act_002_05,proj_002,National Contractors,Material Supplier,3,16786,2022-04-11,2022-04-26
|
| 46 |
+
res_00045,act_002_05,proj_002,National Contractors,Specialist Subcontractor,20,34040,2022-04-11,2022-04-26
|
| 47 |
+
res_00046,act_002_06,proj_002,EliteFinish Works,Material Supplier,13,29365,2022-04-12,2022-04-28
|
| 48 |
+
res_00047,act_002_06,proj_002,Apex Interiors,Equipment,17,31228,2022-04-12,2022-04-28
|
| 49 |
+
res_00048,act_002_07,proj_002,EliteFinish Works,Labour Gang,6,21949,2022-04-11,2022-04-22
|
| 50 |
+
res_00049,act_002_07,proj_002,National Contractors,Labour Gang,15,12170,2022-04-11,2022-04-22
|
| 51 |
+
res_00050,act_002_08,proj_002,Apex Interiors,Labour Gang,8,14467,2022-04-26,2022-05-08
|
| 52 |
+
res_00051,act_002_09,proj_002,Urban Build Solutions,Labour Gang,4,21899,2022-05-11,2022-05-31
|
| 53 |
+
res_00052,act_002_09,proj_002,ProStruct Engineers,Specialist Subcontractor,19,23964,2022-05-11,2022-05-31
|
| 54 |
+
res_00053,act_002_10,proj_002,National Contractors,Material Supplier,15,8303,2022-04-30,2022-05-15
|
| 55 |
+
res_00054,act_002_11,proj_002,BuildRight Co.,Material Supplier,12,31591,2022-05-16,2022-05-27
|
| 56 |
+
res_00055,act_002_11,proj_002,National Contractors,Equipment,19,18563,2022-05-16,2022-05-27
|
| 57 |
+
res_00056,act_002_12,proj_002,Swift MEP Pvt Ltd,Specialist Subcontractor,7,17509,2022-05-27,2022-06-11
|
| 58 |
+
res_00057,act_002_12,proj_002,EliteFinish Works,Specialist Subcontractor,14,25019,2022-05-27,2022-06-11
|
| 59 |
+
res_00058,act_002_12,proj_002,EliteFinish Works,Equipment,18,23167,2022-05-27,2022-06-11
|
| 60 |
+
res_00059,act_002_13,proj_002,Swift MEP Pvt Ltd,Specialist Subcontractor,8,25182,2022-06-11,2022-06-29
|
| 61 |
+
res_00060,act_002_14,proj_002,Urban Build Solutions,Material Supplier,3,18410,2022-06-29,2022-07-10
|
| 62 |
+
res_00061,act_002_14,proj_002,ProStruct Engineers,Specialist Subcontractor,7,23417,2022-06-29,2022-07-10
|
| 63 |
+
res_00062,act_002_14,proj_002,BuildRight Co.,Labour Gang,12,30985,2022-06-29,2022-07-10
|
| 64 |
+
res_00063,act_002_15,proj_002,Apex Interiors,Labour Gang,20,23027,2022-07-10,2022-07-17
|
| 65 |
+
res_00064,act_003_01,proj_003,BuildRight Co.,Labour Gang,17,27479,2022-06-16,2022-06-25
|
| 66 |
+
res_00065,act_003_01,proj_003,Apex Interiors,Labour Gang,14,28851,2022-06-16,2022-06-25
|
| 67 |
+
res_00066,act_003_02,proj_003,Apex Interiors,Equipment,3,14312,2022-06-25,2022-07-09
|
| 68 |
+
res_00067,act_003_02,proj_003,Swift MEP Pvt Ltd,Equipment,16,27151,2022-06-25,2022-07-09
|
| 69 |
+
res_00068,act_003_02,proj_003,National Contractors,Equipment,14,28463,2022-06-25,2022-07-09
|
| 70 |
+
res_00069,act_003_03,proj_003,Swift MEP Pvt Ltd,Specialist Subcontractor,5,27419,2022-07-12,2022-08-05
|
| 71 |
+
res_00070,act_003_03,proj_003,Apex Interiors,Labour Gang,9,17174,2022-07-12,2022-08-05
|
| 72 |
+
res_00071,act_003_04,proj_003,Swift MEP Pvt Ltd,Labour Gang,7,34112,2022-08-05,2022-08-14
|
| 73 |
+
res_00072,act_003_05,proj_003,EliteFinish Works,Material Supplier,13,26863,2022-08-05,2022-08-21
|
| 74 |
+
res_00073,act_003_05,proj_003,Urban Build Solutions,Equipment,18,14858,2022-08-05,2022-08-21
|
| 75 |
+
res_00074,act_003_05,proj_003,Apex Interiors,Labour Gang,10,15092,2022-08-05,2022-08-21
|
| 76 |
+
res_00075,act_003_06,proj_003,Urban Build Solutions,Specialist Subcontractor,7,13400,2022-08-05,2022-08-22
|
| 77 |
+
res_00076,act_003_07,proj_003,Urban Build Solutions,Labour Gang,13,10548,2022-08-06,2022-08-17
|
| 78 |
+
res_00077,act_003_07,proj_003,BuildRight Co.,Specialist Subcontractor,19,34451,2022-08-06,2022-08-17
|
| 79 |
+
res_00078,act_003_08,proj_003,ProStruct Engineers,Material Supplier,13,17914,2022-08-22,2022-09-03
|
| 80 |
+
res_00079,act_003_08,proj_003,EliteFinish Works,Labour Gang,10,26354,2022-08-22,2022-09-03
|
| 81 |
+
res_00080,act_003_09,proj_003,ProStruct Engineers,Material Supplier,18,19632,2022-09-03,2022-09-25
|
| 82 |
+
res_00081,act_003_09,proj_003,Swift MEP Pvt Ltd,Equipment,19,10562,2022-09-03,2022-09-25
|
| 83 |
+
res_00082,act_003_10,proj_003,Urban Build Solutions,Specialist Subcontractor,8,28767,2022-08-22,2022-09-07
|
| 84 |
+
res_00083,act_003_10,proj_003,Urban Build Solutions,Equipment,7,22327,2022-08-22,2022-09-07
|
| 85 |
+
res_00084,act_003_10,proj_003,EliteFinish Works,Material Supplier,18,30777,2022-08-22,2022-09-07
|
| 86 |
+
res_00085,act_003_11,proj_003,National Contractors,Labour Gang,20,22267,2022-09-07,2022-09-20
|
| 87 |
+
res_00086,act_003_11,proj_003,National Contractors,Equipment,8,8828,2022-09-07,2022-09-20
|
| 88 |
+
res_00087,act_003_12,proj_003,Urban Build Solutions,Material Supplier,14,31871,2022-09-20,2022-10-05
|
| 89 |
+
res_00088,act_003_12,proj_003,ProStruct Engineers,Specialist Subcontractor,20,14258,2022-09-20,2022-10-05
|
| 90 |
+
res_00089,act_003_13,proj_003,Swift MEP Pvt Ltd,Specialist Subcontractor,3,14417,2022-10-06,2022-10-26
|
| 91 |
+
res_00090,act_003_13,proj_003,ProStruct Engineers,Equipment,19,14386,2022-10-06,2022-10-26
|
| 92 |
+
res_00091,act_003_14,proj_003,EliteFinish Works,Equipment,13,11083,2022-10-26,2022-11-06
|
| 93 |
+
res_00092,act_003_15,proj_003,Swift MEP Pvt Ltd,Labour Gang,11,9098,2022-11-06,2022-11-14
|
| 94 |
+
res_00093,act_003_15,proj_003,National Contractors,Equipment,18,21051,2022-11-06,2022-11-14
|
| 95 |
+
res_00094,act_004_01,proj_004,National Contractors,Equipment,11,28488,2022-09-03,2022-09-11
|
| 96 |
+
res_00095,act_004_02,proj_004,EliteFinish Works,Labour Gang,18,27908,2022-09-13,2022-09-27
|
| 97 |
+
res_00096,act_004_03,proj_004,ProStruct Engineers,Material Supplier,8,23513,2022-09-28,2022-10-17
|
| 98 |
+
res_00097,act_004_03,proj_004,National Contractors,Labour Gang,4,20108,2022-09-28,2022-10-17
|
| 99 |
+
res_00098,act_004_03,proj_004,BuildRight Co.,Specialist Subcontractor,8,12313,2022-09-28,2022-10-17
|
| 100 |
+
res_00099,act_004_04,proj_004,ProStruct Engineers,Labour Gang,4,22528,2022-10-19,2022-10-28
|
| 101 |
+
res_00100,act_004_05,proj_004,National Contractors,Labour Gang,13,11194,2022-10-17,2022-11-02
|
| 102 |
+
res_00101,act_004_05,proj_004,Urban Build Solutions,Equipment,9,29466,2022-10-17,2022-11-02
|
| 103 |
+
res_00102,act_004_05,proj_004,EliteFinish Works,Labour Gang,13,30019,2022-10-17,2022-11-02
|
| 104 |
+
res_00103,act_004_06,proj_004,National Contractors,Specialist Subcontractor,14,24919,2022-10-19,2022-11-03
|
| 105 |
+
res_00104,act_004_06,proj_004,BuildRight Co.,Material Supplier,16,29879,2022-10-19,2022-11-03
|
| 106 |
+
res_00105,act_004_07,proj_004,BuildRight Co.,Labour Gang,9,32946,2022-10-20,2022-11-02
|
| 107 |
+
res_00106,act_004_07,proj_004,EliteFinish Works,Specialist Subcontractor,11,10751,2022-10-20,2022-11-02
|
| 108 |
+
res_00107,act_004_07,proj_004,Apex Interiors,Material Supplier,4,17028,2022-10-20,2022-11-02
|
| 109 |
+
res_00108,act_004_08,proj_004,Apex Interiors,Material Supplier,8,28817,2022-11-02,2022-11-14
|
| 110 |
+
res_00109,act_004_08,proj_004,National Contractors,Labour Gang,12,16970,2022-11-02,2022-11-14
|
| 111 |
+
res_00110,act_004_08,proj_004,EliteFinish Works,Equipment,6,19188,2022-11-02,2022-11-14
|
| 112 |
+
res_00111,act_004_09,proj_004,EliteFinish Works,Labour Gang,17,10888,2022-11-14,2022-12-04
|
| 113 |
+
res_00112,act_004_09,proj_004,BuildRight Co.,Labour Gang,8,31905,2022-11-14,2022-12-04
|
| 114 |
+
res_00113,act_004_10,proj_004,Apex Interiors,Equipment,3,33123,2022-11-03,2022-11-21
|
| 115 |
+
res_00114,act_004_11,proj_004,Urban Build Solutions,Labour Gang,9,28904,2022-11-21,2022-12-04
|
| 116 |
+
res_00115,act_004_12,proj_004,ProStruct Engineers,Labour Gang,10,18085,2022-12-06,2022-12-23
|
| 117 |
+
res_00116,act_004_12,proj_004,Urban Build Solutions,Specialist Subcontractor,7,18174,2022-12-06,2022-12-23
|
| 118 |
+
res_00117,act_004_13,proj_004,ProStruct Engineers,Equipment,8,17141,2022-12-23,2023-01-09
|
| 119 |
+
res_00118,act_004_14,proj_004,EliteFinish Works,Equipment,16,15404,2023-01-10,2023-01-21
|
| 120 |
+
res_00119,act_004_15,proj_004,Swift MEP Pvt Ltd,Specialist Subcontractor,8,17664,2023-01-23,2023-01-30
|
| 121 |
+
res_00120,act_005_01,proj_005,National Contractors,Material Supplier,11,11028,2023-01-05,2023-01-13
|
| 122 |
+
res_00121,act_005_01,proj_005,ProStruct Engineers,Equipment,14,19431,2023-01-05,2023-01-13
|
| 123 |
+
res_00122,act_005_02,proj_005,EliteFinish Works,Material Supplier,8,9203,2023-01-13,2023-01-27
|
| 124 |
+
res_00123,act_005_02,proj_005,Urban Build Solutions,Material Supplier,7,25627,2023-01-13,2023-01-27
|
| 125 |
+
res_00124,act_005_02,proj_005,EliteFinish Works,Specialist Subcontractor,16,19367,2023-01-13,2023-01-27
|
| 126 |
+
res_00125,act_005_03,proj_005,Urban Build Solutions,Equipment,9,19212,2023-01-27,2023-02-16
|
| 127 |
+
res_00126,act_005_03,proj_005,National Contractors,Equipment,5,24818,2023-01-27,2023-02-16
|
| 128 |
+
res_00127,act_005_03,proj_005,Urban Build Solutions,Specialist Subcontractor,11,15151,2023-01-27,2023-02-16
|
| 129 |
+
res_00128,act_005_04,proj_005,Swift MEP Pvt Ltd,Labour Gang,6,24942,2023-02-18,2023-02-27
|
| 130 |
+
res_00129,act_005_04,proj_005,National Contractors,Specialist Subcontractor,18,12581,2023-02-18,2023-02-27
|
| 131 |
+
res_00130,act_005_05,proj_005,EliteFinish Works,Equipment,14,26473,2023-02-16,2023-03-03
|
| 132 |
+
res_00131,act_005_05,proj_005,ProStruct Engineers,Labour Gang,13,30979,2023-02-16,2023-03-03
|
| 133 |
+
res_00132,act_005_06,proj_005,National Contractors,Equipment,3,13201,2023-02-16,2023-03-04
|
| 134 |
+
res_00133,act_005_07,proj_005,ProStruct Engineers,Equipment,13,29229,2023-02-16,2023-02-27
|
| 135 |
+
res_00134,act_005_07,proj_005,BuildRight Co.,Specialist Subcontractor,14,18036,2023-02-16,2023-02-27
|
| 136 |
+
res_00135,act_005_08,proj_005,ProStruct Engineers,Specialist Subcontractor,3,22385,2023-03-06,2023-03-17
|
| 137 |
+
res_00136,act_005_09,proj_005,ProStruct Engineers,Material Supplier,15,23518,2023-03-17,2023-04-05
|
| 138 |
+
res_00137,act_005_09,proj_005,Urban Build Solutions,Specialist Subcontractor,11,31703,2023-03-17,2023-04-05
|
| 139 |
+
res_00138,act_005_09,proj_005,Swift MEP Pvt Ltd,Equipment,18,30234,2023-03-17,2023-04-05
|
| 140 |
+
res_00139,act_005_10,proj_005,Swift MEP Pvt Ltd,Labour Gang,10,33007,2023-03-05,2023-03-21
|
| 141 |
+
res_00140,act_005_10,proj_005,EliteFinish Works,Labour Gang,16,21955,2023-03-05,2023-03-21
|
| 142 |
+
res_00141,act_005_11,proj_005,EliteFinish Works,Material Supplier,3,13374,2023-03-22,2023-04-02
|
| 143 |
+
res_00142,act_005_11,proj_005,EliteFinish Works,Specialist Subcontractor,12,27557,2023-03-22,2023-04-02
|
| 144 |
+
res_00143,act_005_12,proj_005,EliteFinish Works,Specialist Subcontractor,7,12256,2023-04-02,2023-04-17
|
| 145 |
+
res_00144,act_005_12,proj_005,National Contractors,Equipment,4,10962,2023-04-02,2023-04-17
|
| 146 |
+
res_00145,act_005_12,proj_005,Swift MEP Pvt Ltd,Specialist Subcontractor,14,23031,2023-04-02,2023-04-17
|
| 147 |
+
res_00146,act_005_13,proj_005,Apex Interiors,Material Supplier,3,29581,2023-04-17,2023-05-04
|
| 148 |
+
res_00147,act_005_13,proj_005,Apex Interiors,Specialist Subcontractor,8,17872,2023-04-17,2023-05-04
|
| 149 |
+
res_00148,act_005_14,proj_005,BuildRight Co.,Specialist Subcontractor,10,14662,2023-05-04,2023-05-16
|
| 150 |
+
res_00149,act_005_14,proj_005,ProStruct Engineers,Labour Gang,10,13050,2023-05-04,2023-05-16
|
| 151 |
+
res_00150,act_005_15,proj_005,EliteFinish Works,Equipment,3,23641,2023-05-17,2023-05-24
|
| 152 |
+
res_00151,act_005_15,proj_005,Apex Interiors,Equipment,6,23427,2023-05-17,2023-05-24
|
| 153 |
+
res_00152,act_005_15,proj_005,EliteFinish Works,Material Supplier,9,23476,2023-05-17,2023-05-24
|
| 154 |
+
res_00153,act_006_01,proj_006,ProStruct Engineers,Material Supplier,10,33003,2023-03-04,2023-03-12
|
| 155 |
+
res_00154,act_006_01,proj_006,BuildRight Co.,Material Supplier,7,18431,2023-03-04,2023-03-12
|
| 156 |
+
res_00155,act_006_01,proj_006,Urban Build Solutions,Specialist Subcontractor,15,33338,2023-03-04,2023-03-12
|
| 157 |
+
res_00156,act_006_02,proj_006,Swift MEP Pvt Ltd,Material Supplier,15,25501,2023-03-14,2023-03-27
|
| 158 |
+
res_00157,act_006_02,proj_006,BuildRight Co.,Equipment,18,29950,2023-03-14,2023-03-27
|
| 159 |
+
res_00158,act_006_03,proj_006,EliteFinish Works,Labour Gang,10,27940,2023-03-27,2023-04-17
|
| 160 |
+
res_00159,act_006_03,proj_006,Apex Interiors,Specialist Subcontractor,14,19871,2023-03-27,2023-04-17
|
| 161 |
+
res_00160,act_006_03,proj_006,Swift MEP Pvt Ltd,Labour Gang,15,10531,2023-03-27,2023-04-17
|
| 162 |
+
res_00161,act_006_04,proj_006,Apex Interiors,Specialist Subcontractor,18,14159,2023-04-18,2023-04-27
|
| 163 |
+
res_00162,act_006_04,proj_006,BuildRight Co.,Specialist Subcontractor,12,22267,2023-04-18,2023-04-27
|
| 164 |
+
res_00163,act_006_04,proj_006,BuildRight Co.,Equipment,15,29431,2023-04-18,2023-04-27
|
| 165 |
+
res_00164,act_006_05,proj_006,ProStruct Engineers,Specialist Subcontractor,12,18193,2023-04-17,2023-05-04
|
| 166 |
+
res_00165,act_006_06,proj_006,National Contractors,Material Supplier,4,16553,2023-04-17,2023-05-04
|
| 167 |
+
res_00166,act_006_06,proj_006,ProStruct Engineers,Specialist Subcontractor,8,21048,2023-04-17,2023-05-04
|
| 168 |
+
res_00167,act_006_07,proj_006,EliteFinish Works,Labour Gang,17,34418,2023-04-18,2023-04-30
|
| 169 |
+
res_00168,act_006_07,proj_006,BuildRight Co.,Equipment,6,29491,2023-04-18,2023-04-30
|
| 170 |
+
res_00169,act_006_07,proj_006,Urban Build Solutions,Material Supplier,3,13271,2023-04-18,2023-04-30
|
| 171 |
+
res_00170,act_006_08,proj_006,Apex Interiors,Material Supplier,17,8379,2023-05-05,2023-05-18
|
| 172 |
+
res_00171,act_006_08,proj_006,ProStruct Engineers,Material Supplier,16,33275,2023-05-05,2023-05-18
|
| 173 |
+
res_00172,act_006_09,proj_006,Swift MEP Pvt Ltd,Material Supplier,11,32315,2023-05-20,2023-06-09
|
| 174 |
+
res_00173,act_006_10,proj_006,BuildRight Co.,Material Supplier,19,20216,2023-05-07,2023-05-24
|
| 175 |
+
res_00174,act_006_10,proj_006,Urban Build Solutions,Material Supplier,13,25531,2023-05-07,2023-05-24
|
| 176 |
+
res_00175,act_006_10,proj_006,Swift MEP Pvt Ltd,Labour Gang,8,21895,2023-05-07,2023-05-24
|
| 177 |
+
res_00176,act_006_11,proj_006,Urban Build Solutions,Material Supplier,5,12927,2023-05-24,2023-06-05
|
| 178 |
+
res_00177,act_006_11,proj_006,BuildRight Co.,Equipment,11,14475,2023-05-24,2023-06-05
|
| 179 |
+
res_00178,act_006_11,proj_006,EliteFinish Works,Material Supplier,16,9590,2023-05-24,2023-06-05
|
| 180 |
+
res_00179,act_006_12,proj_006,Swift MEP Pvt Ltd,Labour Gang,6,24043,2023-06-07,2023-06-24
|
| 181 |
+
res_00180,act_006_12,proj_006,ProStruct Engineers,Equipment,4,27638,2023-06-07,2023-06-24
|
| 182 |
+
res_00181,act_006_13,proj_006,Swift MEP Pvt Ltd,Equipment,16,19057,2023-06-26,2023-07-14
|
| 183 |
+
res_00182,act_006_13,proj_006,National Contractors,Equipment,3,25784,2023-06-26,2023-07-14
|
| 184 |
+
res_00183,act_006_13,proj_006,Swift MEP Pvt Ltd,Specialist Subcontractor,12,19694,2023-06-26,2023-07-14
|
| 185 |
+
res_00184,act_006_14,proj_006,BuildRight Co.,Material Supplier,13,17754,2023-07-14,2023-07-27
|
| 186 |
+
res_00185,act_006_14,proj_006,National Contractors,Labour Gang,6,19706,2023-07-14,2023-07-27
|
| 187 |
+
res_00186,act_006_15,proj_006,BuildRight Co.,Material Supplier,10,13742,2023-07-27,2023-08-03
|
| 188 |
+
res_00187,act_006_15,proj_006,BuildRight Co.,Labour Gang,7,31815,2023-07-27,2023-08-03
|
| 189 |
+
res_00188,act_006_15,proj_006,Apex Interiors,Material Supplier,16,17001,2023-07-27,2023-08-03
|
| 190 |
+
res_00189,act_007_01,proj_007,ProStruct Engineers,Specialist Subcontractor,19,26647,2023-06-01,2023-06-10
|
| 191 |
+
res_00190,act_007_01,proj_007,ProStruct Engineers,Labour Gang,5,18701,2023-06-01,2023-06-10
|
| 192 |
+
res_00191,act_007_02,proj_007,BuildRight Co.,Specialist Subcontractor,6,20514,2023-06-10,2023-06-25
|
| 193 |
+
res_00192,act_007_02,proj_007,EliteFinish Works,Labour Gang,13,28864,2023-06-10,2023-06-25
|
| 194 |
+
res_00193,act_007_03,proj_007,Swift MEP Pvt Ltd,Material Supplier,15,8733,2023-06-29,2023-07-21
|
| 195 |
+
res_00194,act_007_03,proj_007,Apex Interiors,Equipment,5,22202,2023-06-29,2023-07-21
|
| 196 |
+
res_00195,act_007_03,proj_007,BuildRight Co.,Specialist Subcontractor,11,17935,2023-06-29,2023-07-21
|
| 197 |
+
res_00196,act_007_04,proj_007,EliteFinish Works,Specialist Subcontractor,4,20262,2023-07-22,2023-07-31
|
| 198 |
+
res_00197,act_007_04,proj_007,EliteFinish Works,Material Supplier,9,32927,2023-07-22,2023-07-31
|
| 199 |
+
res_00198,act_007_04,proj_007,ProStruct Engineers,Equipment,8,17071,2023-07-22,2023-07-31
|
| 200 |
+
res_00199,act_007_05,proj_007,National Contractors,Labour Gang,15,13939,2023-07-21,2023-08-07
|
| 201 |
+
res_00200,act_007_05,proj_007,National Contractors,Equipment,11,8165,2023-07-21,2023-08-07
|
| 202 |
+
res_00201,act_007_05,proj_007,ProStruct Engineers,Specialist Subcontractor,3,33626,2023-07-21,2023-08-07
|
| 203 |
+
res_00202,act_007_06,proj_007,National Contractors,Specialist Subcontractor,11,16750,2023-07-22,2023-08-09
|
| 204 |
+
res_00203,act_007_06,proj_007,ProStruct Engineers,Equipment,6,15252,2023-07-22,2023-08-09
|
| 205 |
+
res_00204,act_007_07,proj_007,BuildRight Co.,Equipment,10,10088,2023-07-21,2023-08-01
|
| 206 |
+
res_00205,act_007_08,proj_007,Swift MEP Pvt Ltd,Material Supplier,16,28800,2023-08-07,2023-08-20
|
| 207 |
+
res_00206,act_007_08,proj_007,EliteFinish Works,Equipment,20,20748,2023-08-07,2023-08-20
|
| 208 |
+
res_00207,act_007_08,proj_007,ProStruct Engineers,Labour Gang,13,19160,2023-08-07,2023-08-20
|
| 209 |
+
res_00208,act_007_09,proj_007,Swift MEP Pvt Ltd,Material Supplier,7,23137,2023-08-20,2023-09-10
|
| 210 |
+
res_00209,act_007_09,proj_007,Urban Build Solutions,Material Supplier,9,25440,2023-08-20,2023-09-10
|
| 211 |
+
res_00210,act_007_10,proj_007,Apex Interiors,Material Supplier,11,21203,2023-08-12,2023-08-27
|
| 212 |
+
res_00211,act_007_10,proj_007,BuildRight Co.,Labour Gang,18,26393,2023-08-12,2023-08-27
|
| 213 |
+
res_00212,act_007_10,proj_007,Swift MEP Pvt Ltd,Labour Gang,9,32510,2023-08-12,2023-08-27
|
| 214 |
+
res_00213,act_007_11,proj_007,Swift MEP Pvt Ltd,Equipment,12,32604,2023-08-28,2023-09-11
|
| 215 |
+
res_00214,act_007_11,proj_007,Swift MEP Pvt Ltd,Material Supplier,17,8968,2023-08-28,2023-09-11
|
| 216 |
+
res_00215,act_007_11,proj_007,Apex Interiors,Specialist Subcontractor,14,26510,2023-08-28,2023-09-11
|
| 217 |
+
res_00216,act_007_12,proj_007,ProStruct Engineers,Labour Gang,12,26233,2023-09-11,2023-09-28
|
| 218 |
+
res_00217,act_007_12,proj_007,National Contractors,Material Supplier,10,20297,2023-09-11,2023-09-28
|
| 219 |
+
res_00218,act_007_13,proj_007,Apex Interiors,Material Supplier,6,11177,2023-10-01,2023-10-18
|
| 220 |
+
res_00219,act_007_13,proj_007,ProStruct Engineers,Specialist Subcontractor,9,11625,2023-10-01,2023-10-18
|
| 221 |
+
res_00220,act_007_13,proj_007,EliteFinish Works,Equipment,8,13213,2023-10-01,2023-10-18
|
| 222 |
+
res_00221,act_007_14,proj_007,ProStruct Engineers,Material Supplier,14,32617,2023-10-19,2023-11-01
|
| 223 |
+
res_00222,act_007_14,proj_007,Apex Interiors,Material Supplier,11,18466,2023-10-19,2023-11-01
|
| 224 |
+
res_00223,act_007_14,proj_007,Urban Build Solutions,Equipment,6,29765,2023-10-19,2023-11-01
|
| 225 |
+
res_00224,act_007_15,proj_007,National Contractors,Equipment,19,25551,2023-11-02,2023-11-09
|
| 226 |
+
res_00225,act_007_15,proj_007,EliteFinish Works,Material Supplier,10,21237,2023-11-02,2023-11-09
|
| 227 |
+
res_00226,act_007_15,proj_007,ProStruct Engineers,Material Supplier,12,22727,2023-11-02,2023-11-09
|
| 228 |
+
res_00227,act_008_01,proj_008,Urban Build Solutions,Specialist Subcontractor,15,17450,2024-01-18,2024-01-27
|
| 229 |
+
res_00228,act_008_02,proj_008,EliteFinish Works,Equipment,17,29502,2024-01-30,2024-02-13
|
| 230 |
+
res_00229,act_008_03,proj_008,National Contractors,Labour Gang,15,27010,2024-02-13,2024-03-03
|
| 231 |
+
res_00230,act_008_04,proj_008,ProStruct Engineers,Material Supplier,16,14189,2024-03-03,2024-03-12
|
| 232 |
+
res_00231,act_008_04,proj_008,National Contractors,Labour Gang,10,12540,2024-03-03,2024-03-12
|
| 233 |
+
res_00232,act_008_04,proj_008,EliteFinish Works,Labour Gang,16,8748,2024-03-03,2024-03-12
|
| 234 |
+
res_00233,act_008_05,proj_008,EliteFinish Works,Specialist Subcontractor,8,26655,2024-03-04,2024-03-20
|
| 235 |
+
res_00234,act_008_05,proj_008,National Contractors,Material Supplier,5,20133,2024-03-04,2024-03-20
|
| 236 |
+
res_00235,act_008_06,proj_008,National Contractors,Material Supplier,20,24755,2024-03-04,2024-03-20
|
| 237 |
+
res_00236,act_008_07,proj_008,Urban Build Solutions,Specialist Subcontractor,17,20093,2024-03-05,2024-03-17
|
| 238 |
+
res_00237,act_008_08,proj_008,Urban Build Solutions,Specialist Subcontractor,8,23472,2024-03-21,2024-04-01
|
| 239 |
+
res_00238,act_008_08,proj_008,National Contractors,Specialist Subcontractor,13,12346,2024-03-21,2024-04-01
|
| 240 |
+
res_00239,act_008_08,proj_008,Swift MEP Pvt Ltd,Labour Gang,3,14783,2024-03-21,2024-04-01
|
| 241 |
+
res_00240,act_008_09,proj_008,ProStruct Engineers,Material Supplier,10,30402,2024-04-01,
|
| 242 |
+
res_00241,act_008_09,proj_008,EliteFinish Works,Material Supplier,10,34108,2024-04-01,
|
| 243 |
+
res_00242,act_008_09,proj_008,Apex Interiors,Material Supplier,19,29016,2024-04-01,
|
| 244 |
+
res_00243,act_009_01,proj_009,Urban Build Solutions,Equipment,8,16023,2024-03-01,2024-03-10
|
| 245 |
+
res_00244,act_009_02,proj_009,National Contractors,Labour Gang,3,32530,2024-03-10,2024-03-23
|
| 246 |
+
res_00245,act_009_02,proj_009,BuildRight Co.,Material Supplier,19,23407,2024-03-10,2024-03-23
|
| 247 |
+
res_00246,act_009_03,proj_009,BuildRight Co.,Material Supplier,11,31461,2024-03-23,2024-04-12
|
| 248 |
+
res_00247,act_009_03,proj_009,EliteFinish Works,Labour Gang,20,31421,2024-03-23,2024-04-12
|
| 249 |
+
res_00248,act_009_04,proj_009,ProStruct Engineers,Material Supplier,4,17599,2024-04-12,2024-04-21
|
| 250 |
+
res_00249,act_009_05,proj_009,Urban Build Solutions,Labour Gang,14,21088,2024-04-12,2024-04-28
|
| 251 |
+
res_00250,act_009_05,proj_009,National Contractors,Material Supplier,16,33802,2024-04-12,2024-04-28
|
| 252 |
+
res_00251,act_009_06,proj_009,BuildRight Co.,Specialist Subcontractor,11,32836,2024-04-12,2024-04-30
|
| 253 |
+
res_00252,act_009_07,proj_009,Urban Build Solutions,Labour Gang,8,20008,2024-04-16,
|
| 254 |
+
res_00253,act_009_07,proj_009,ProStruct Engineers,Equipment,7,15964,2024-04-16,
|
| 255 |
+
res_00254,act_009_07,proj_009,Urban Build Solutions,Material Supplier,9,16667,2024-04-16,
|
| 256 |
+
res_00255,act_009_08,proj_009,Swift MEP Pvt Ltd,Labour Gang,17,31235,2024-04-29,
|
data_loader.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
data_loader.py
|
| 3 |
+
--------------
|
| 4 |
+
Loads renovation project data from SQLite DB (primary) or CSV fallback.
|
| 5 |
+
Returns clean DataFrames with parsed dates and correct dtypes.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import numpy as np
|
| 11 |
+
from datetime import datetime
|
| 12 |
+
from sqlalchemy import create_engine
|
| 13 |
+
|
| 14 |
+
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
|
| 15 |
+
DB_PATH = os.path.join(DATA_DIR, "data.db")
|
| 16 |
+
|
| 17 |
+
DATE_COLS = {
|
| 18 |
+
"projects": ["planned_start", "planned_end", "actual_start", "actual_end"],
|
| 19 |
+
"activities": ["planned_start_date", "planned_end_date", "actual_start_date",
|
| 20 |
+
"actual_end_date", "forecasted_start_date", "forecasted_end_date"],
|
| 21 |
+
"daily_updates": ["date"],
|
| 22 |
+
"issues": ["date_raised"],
|
| 23 |
+
"resources": ["start_date", "end_date"],
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
REFERENCE_DATE = datetime(2024, 6, 1) # "today" for in-progress activities
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class DataLoader:
|
| 30 |
+
"""Loads and caches all project data."""
|
| 31 |
+
|
| 32 |
+
def __init__(self, db_path: str = None, use_csv: bool = False):
|
| 33 |
+
self.db_path = db_path or DB_PATH
|
| 34 |
+
self.use_csv = use_csv
|
| 35 |
+
self._cache = {}
|
| 36 |
+
self._engine = None
|
| 37 |
+
|
| 38 |
+
def _get_engine(self):
|
| 39 |
+
if self._engine is None:
|
| 40 |
+
self._engine = create_engine(f"sqlite:///{self.db_path}")
|
| 41 |
+
return self._engine
|
| 42 |
+
|
| 43 |
+
def _load_table(self, table_name: str) -> pd.DataFrame:
|
| 44 |
+
if table_name in self._cache:
|
| 45 |
+
return self._cache[table_name]
|
| 46 |
+
|
| 47 |
+
df = None
|
| 48 |
+
# Try DB first
|
| 49 |
+
if not self.use_csv and os.path.exists(self.db_path):
|
| 50 |
+
try:
|
| 51 |
+
engine = self._get_engine()
|
| 52 |
+
df = pd.read_sql_table(table_name, engine)
|
| 53 |
+
except Exception:
|
| 54 |
+
df = None
|
| 55 |
+
|
| 56 |
+
# Fallback to CSV
|
| 57 |
+
if df is None:
|
| 58 |
+
csv_map = {
|
| 59 |
+
"projects": "projects.csv",
|
| 60 |
+
"activities": "activities.csv",
|
| 61 |
+
"daily_updates": "daily_updates.csv",
|
| 62 |
+
"issues": "issues.csv",
|
| 63 |
+
"boq": "boq.csv",
|
| 64 |
+
"resources": "resources.csv",
|
| 65 |
+
}
|
| 66 |
+
fname = csv_map.get(table_name)
|
| 67 |
+
if fname:
|
| 68 |
+
fpath = os.path.join(DATA_DIR, fname)
|
| 69 |
+
if os.path.exists(fpath):
|
| 70 |
+
df = pd.read_csv(fpath)
|
| 71 |
+
|
| 72 |
+
if df is None:
|
| 73 |
+
df = pd.DataFrame()
|
| 74 |
+
return df
|
| 75 |
+
|
| 76 |
+
# Parse dates
|
| 77 |
+
for col in DATE_COLS.get(table_name, []):
|
| 78 |
+
if col in df.columns:
|
| 79 |
+
df[col] = pd.to_datetime(df[col], errors="coerce")
|
| 80 |
+
|
| 81 |
+
# Normalize column names for projects table
|
| 82 |
+
if table_name == "projects":
|
| 83 |
+
rename = {
|
| 84 |
+
"planned_start": "planned_start_date",
|
| 85 |
+
"planned_end": "planned_end_date",
|
| 86 |
+
"actual_start": "actual_start_date",
|
| 87 |
+
"actual_end": "actual_end_date",
|
| 88 |
+
}
|
| 89 |
+
df = df.rename(columns={k: v for k, v in rename.items() if k in df.columns and v not in df.columns})
|
| 90 |
+
|
| 91 |
+
self._cache[table_name] = df
|
| 92 |
+
return df
|
| 93 |
+
|
| 94 |
+
# ββ Public accessors ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 95 |
+
|
| 96 |
+
@property
|
| 97 |
+
def projects(self) -> pd.DataFrame:
|
| 98 |
+
return self._load_table("projects")
|
| 99 |
+
|
| 100 |
+
@property
|
| 101 |
+
def activities(self) -> pd.DataFrame:
|
| 102 |
+
return self._load_table("activities")
|
| 103 |
+
|
| 104 |
+
@property
|
| 105 |
+
def daily_updates(self) -> pd.DataFrame:
|
| 106 |
+
return self._load_table("daily_updates")
|
| 107 |
+
|
| 108 |
+
@property
|
| 109 |
+
def issues(self) -> pd.DataFrame:
|
| 110 |
+
return self._load_table("issues")
|
| 111 |
+
|
| 112 |
+
@property
|
| 113 |
+
def boq(self) -> pd.DataFrame:
|
| 114 |
+
return self._load_table("boq")
|
| 115 |
+
|
| 116 |
+
@property
|
| 117 |
+
def resources(self) -> pd.DataFrame:
|
| 118 |
+
return self._load_table("resources")
|
| 119 |
+
|
| 120 |
+
# ββ Filtered views ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 121 |
+
|
| 122 |
+
def get_historical_activities(self) -> pd.DataFrame:
|
| 123 |
+
"""Completed activities β used for training ML models."""
|
| 124 |
+
acts = self.activities
|
| 125 |
+
if acts.empty:
|
| 126 |
+
return acts
|
| 127 |
+
return acts[acts["status"] == "completed"].copy()
|
| 128 |
+
|
| 129 |
+
def get_active_activities(self, project_id: str = None) -> pd.DataFrame:
|
| 130 |
+
"""In-progress and not-started activities for a project (or all)."""
|
| 131 |
+
acts = self.activities
|
| 132 |
+
if acts.empty:
|
| 133 |
+
return acts
|
| 134 |
+
mask = acts["status"].isin(["in_progress", "not_started"])
|
| 135 |
+
if project_id:
|
| 136 |
+
mask &= acts["project_id"] == project_id
|
| 137 |
+
return acts[mask].copy()
|
| 138 |
+
|
| 139 |
+
def get_inprogress_projects(self) -> pd.DataFrame:
|
| 140 |
+
projs = self.projects
|
| 141 |
+
if projs.empty:
|
| 142 |
+
return projs
|
| 143 |
+
return projs[projs["status"] == "in_progress"].copy()
|
| 144 |
+
|
| 145 |
+
def get_project_activities(self, project_id: str) -> pd.DataFrame:
|
| 146 |
+
acts = self.activities
|
| 147 |
+
return acts[acts["project_id"] == project_id].copy()
|
| 148 |
+
|
| 149 |
+
def get_activity_updates(self, activity_id: str) -> pd.DataFrame:
|
| 150 |
+
upd = self.daily_updates
|
| 151 |
+
return upd[upd["activity_id"] == activity_id].sort_values("date").copy()
|
| 152 |
+
|
| 153 |
+
def get_activity_issues(self, activity_id: str = None, project_id: str = None) -> pd.DataFrame:
|
| 154 |
+
iss = self.issues
|
| 155 |
+
if activity_id:
|
| 156 |
+
iss = iss[iss["activity_id"] == activity_id]
|
| 157 |
+
if project_id:
|
| 158 |
+
iss = iss[iss["project_id"] == project_id]
|
| 159 |
+
return iss.copy()
|
| 160 |
+
|
| 161 |
+
def get_project_boq(self, project_id: str) -> pd.DataFrame:
|
| 162 |
+
b = self.boq
|
| 163 |
+
return b[b["project_id"] == project_id].copy()
|
| 164 |
+
|
| 165 |
+
def get_activity_boq(self, activity_id: str) -> pd.DataFrame:
|
| 166 |
+
b = self.boq
|
| 167 |
+
return b[b["activity_id"] == activity_id].copy()
|
| 168 |
+
|
| 169 |
+
def get_all_data(self) -> dict:
|
| 170 |
+
return {
|
| 171 |
+
"projects": self.projects,
|
| 172 |
+
"activities": self.activities,
|
| 173 |
+
"daily_updates": self.daily_updates,
|
| 174 |
+
"issues": self.issues,
|
| 175 |
+
"boq": self.boq,
|
| 176 |
+
"resources": self.resources,
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
def reference_date(self) -> datetime:
|
| 180 |
+
"""The 'today' reference for in-progress predictions."""
|
| 181 |
+
return REFERENCE_DATE
|
| 182 |
+
|
| 183 |
+
def clear_cache(self):
|
| 184 |
+
self._cache = {}
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
# Singleton for convenience
|
| 188 |
+
_loader = None
|
| 189 |
+
|
| 190 |
+
def get_loader(db_path: str = None, use_csv: bool = False) -> DataLoader:
|
| 191 |
+
global _loader
|
| 192 |
+
if _loader is None:
|
| 193 |
+
_loader = DataLoader(db_path=db_path, use_csv=use_csv)
|
| 194 |
+
return _loader
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
if __name__ == "__main__":
|
| 198 |
+
dl = DataLoader()
|
| 199 |
+
print("Projects:", len(dl.projects))
|
| 200 |
+
print("Activities:", len(dl.activities))
|
| 201 |
+
print("Daily Updates:", len(dl.daily_updates))
|
| 202 |
+
print("Issues:", len(dl.issues))
|
| 203 |
+
print("BOQ:", len(dl.boq))
|
| 204 |
+
hist = dl.get_historical_activities()
|
| 205 |
+
print(f"Historical (completed) activities: {len(hist)}")
|
| 206 |
+
active = dl.get_active_activities()
|
| 207 |
+
print(f"Active activities: {len(active)}")
|
dataset.py
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
dataset.py
|
| 3 |
+
----------
|
| 4 |
+
Generates synthetic renovation project data and persists it to SQLite.
|
| 5 |
+
Also ingests existing CSVs from the data/ folder into the same DB schema.
|
| 6 |
+
|
| 7 |
+
Usage:
|
| 8 |
+
python dataset.py # generate from scratch + ingest CSVs
|
| 9 |
+
python dataset.py --csv-only # only ingest CSVs into DB
|
| 10 |
+
python dataset.py --gen-only # only generate synthetic data
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
import pandas as pd
|
| 14 |
+
import numpy as np
|
| 15 |
+
from datetime import datetime, timedelta
|
| 16 |
+
import random
|
| 17 |
+
import os
|
| 18 |
+
import sys
|
| 19 |
+
import argparse
|
| 20 |
+
from sqlalchemy import create_engine, text
|
| 21 |
+
|
| 22 |
+
# ββ Config ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 23 |
+
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
|
| 24 |
+
DB_PATH = os.path.join(DATA_DIR, "data.db")
|
| 25 |
+
RANDOM_SEED = 42
|
| 26 |
+
random.seed(RANDOM_SEED)
|
| 27 |
+
np.random.seed(RANDOM_SEED)
|
| 28 |
+
|
| 29 |
+
# ββ Activity Templates βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 30 |
+
ACTIVITY_TEMPLATES = [
|
| 31 |
+
{"name": "Site Survey & Mobilization", "category": "prep", "duration": 7, "depends_on": None},
|
| 32 |
+
{"name": "Demolition & Strip-Out", "category": "demo", "duration": 12, "depends_on": "Site Survey & Mobilization"},
|
| 33 |
+
{"name": "Structural Repairs & Reinforcement", "category": "structural", "duration": 18, "depends_on": "Demolition & Strip-Out"},
|
| 34 |
+
{"name": "Waterproofing & Damp Proofing", "category": "structural", "duration": 8, "depends_on": "Structural Repairs & Reinforcement"},
|
| 35 |
+
{"name": "Plumbing Rough-in", "category": "mep", "duration": 14, "depends_on": "Structural Repairs & Reinforcement"},
|
| 36 |
+
{"name": "Electrical Wiring & Conduits", "category": "mep", "duration": 14, "depends_on": "Structural Repairs & Reinforcement"},
|
| 37 |
+
{"name": "HVAC & Ventilation Installation", "category": "mep", "duration": 10, "depends_on": "Structural Repairs & Reinforcement"},
|
| 38 |
+
{"name": "Floor Leveling & Screed", "category": "finishing", "duration": 10, "depends_on": "Plumbing Rough-in"},
|
| 39 |
+
{"name": "Tiling β Floors & Wet Areas", "category": "finishing", "duration": 18, "depends_on": "Floor Leveling & Screed"},
|
| 40 |
+
{"name": "Wall Plastering & Screeding", "category": "finishing", "duration": 14, "depends_on": "Electrical Wiring & Conduits"},
|
| 41 |
+
{"name": "False Ceiling & Insulation", "category": "finishing", "duration": 10, "depends_on": "Wall Plastering & Screeding"},
|
| 42 |
+
{"name": "Painting β Primer & Finish Coats", "category": "finishing", "duration": 14, "depends_on": "False Ceiling & Insulation"},
|
| 43 |
+
{"name": "Carpentry, Joinery & Built-ins", "category": "finishing", "duration": 16, "depends_on": "Painting β Primer & Finish Coats"},
|
| 44 |
+
{"name": "Fixtures, Fittings & Sanitaryware", "category": "finishing", "duration": 10, "depends_on": "Carpentry, Joinery & Built-ins"},
|
| 45 |
+
{"name": "Final Inspection, Snag & Handover", "category": "inspection", "duration": 6, "depends_on": "Fixtures, Fittings & Sanitaryware"},
|
| 46 |
+
]
|
| 47 |
+
|
| 48 |
+
ISSUE_CATEGORIES = ["material_delay", "labor_shortage", "weather", "design_change",
|
| 49 |
+
"inspection_fail", "equipment_breakdown", "scope_creep", "safety"]
|
| 50 |
+
SEVERITY_LEVELS = ["low", "medium", "high", "critical"]
|
| 51 |
+
ASSIGNEES = ["site_manager", "contractor_A", "contractor_B", "project_engineer",
|
| 52 |
+
"safety_officer", "qa_inspector", "procurement_lead", "client_pm"]
|
| 53 |
+
|
| 54 |
+
BOQ_TEMPLATES = {
|
| 55 |
+
"prep": [("Site Survey & Layout", 3300, 2310, "lumpsum", 1),
|
| 56 |
+
("Temporary Site Office Setup", 8000, 5600, "lumpsum", 1),
|
| 57 |
+
("Safety Hoarding & Signage", 2100, 1470, "lumpsum", 1)],
|
| 58 |
+
"demo": [("Demolition Labour & Equipment", 12000, 8400, "lumpsum", 1),
|
| 59 |
+
("Debris Removal & Disposal", 5500, 3850, "trip", 6),
|
| 60 |
+
("Asbestos Survey & Removal", 4000, 2800, "sqm", 30)],
|
| 61 |
+
"structural": [("Reinforced Concrete M30", 9500, 6650, "m3", 15),
|
| 62 |
+
("Steel Rebar TMT 12mm", 3800, 2660, "tonne", 6),
|
| 63 |
+
("SBR Waterproofing Membrane", 4300, 3010, "sqm", 120)],
|
| 64 |
+
"mep": [("CPVC Pipes 1 inch", 2800, 1960, "meters", 180),
|
| 65 |
+
("FR Copper Wire 4 sq mm", 4200, 2940, "meters", 250),
|
| 66 |
+
("Cassette AC Unit 2 Ton", 14000, 9800, "unit", 4)],
|
| 67 |
+
"finishing": [("Self-Leveling Compound", 3300, 2310, "bags", 20),
|
| 68 |
+
("Vitrified Tiles 800x800mm", 7500, 5250, "sqm", 200),
|
| 69 |
+
("Gypsum Plaster 20mm", 2500, 1750, "bags", 50),
|
| 70 |
+
("Premium Emulsion Paint", 3800, 2660, "liters", 120),
|
| 71 |
+
("Teak Wood Panels Grade A", 9500, 6650, "sqm", 30),
|
| 72 |
+
("EWC Rimless Toilet Suite", 8500, 5950, "unit", 4)],
|
| 73 |
+
"inspection": [("Snagging Rectification Labour", 5000, 3500, "lumpsum", 1),
|
| 74 |
+
("As-Built Drawings & O&M Manual", 3000, 2100, "set", 1)],
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
CONTRACTORS = ["Apex Interiors", "ProStruct Engineers", "Swift MEP Pvt Ltd",
|
| 78 |
+
"Urban Build Solutions", "EliteFinish Works", "BuildRight Co.",
|
| 79 |
+
"National Contractors"]
|
| 80 |
+
|
| 81 |
+
# ββ Delay helper βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 82 |
+
def add_delay(project_type="residential"):
|
| 83 |
+
"""Skewed delay distribution β more likely late than early."""
|
| 84 |
+
delay = int(np.random.choice(
|
| 85 |
+
[-1, 0, 0, 1, 2, 3, 5, 7],
|
| 86 |
+
p=[0.05, 0.20, 0.20, 0.20, 0.15, 0.10, 0.07, 0.03]
|
| 87 |
+
))
|
| 88 |
+
return max(0, delay)
|
| 89 |
+
|
| 90 |
+
def compute_schedule_start(template_name, template_start, activities_so_far):
|
| 91 |
+
"""Compute start based on dependency (predecessor end)."""
|
| 92 |
+
dep = next((t["depends_on"] for t in ACTIVITY_TEMPLATES if t["name"] == template_name), None)
|
| 93 |
+
if dep is None:
|
| 94 |
+
return template_start
|
| 95 |
+
pred = next((a for a in activities_so_far if a["name"] == dep), None)
|
| 96 |
+
if pred is None:
|
| 97 |
+
return template_start
|
| 98 |
+
return pred["actual_end"] or pred["planned_end"]
|
| 99 |
+
|
| 100 |
+
# ββ Data Generators ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 101 |
+
def generate_activities(project_id, project_type, planned_project_start, is_complete=True, today=None):
|
| 102 |
+
if today is None:
|
| 103 |
+
today = datetime.today()
|
| 104 |
+
|
| 105 |
+
activities = []
|
| 106 |
+
act_num = 0
|
| 107 |
+
current_planned_start = planned_project_start
|
| 108 |
+
|
| 109 |
+
for tmpl in ACTIVITY_TEMPLATES:
|
| 110 |
+
act_num += 1
|
| 111 |
+
act_id = f"act_{project_id.split('_')[1]}_{act_num:02d}"
|
| 112 |
+
planned_dur = int(tmpl["duration"])
|
| 113 |
+
planned_start = current_planned_start
|
| 114 |
+
planned_end = planned_start + timedelta(days=planned_dur)
|
| 115 |
+
|
| 116 |
+
# Delay injection
|
| 117 |
+
actual_start_delay = int(add_delay(project_type))
|
| 118 |
+
dep = tmpl["depends_on"]
|
| 119 |
+
if dep and activities:
|
| 120 |
+
pred = next((a for a in activities if a["name"] == dep), None)
|
| 121 |
+
if pred:
|
| 122 |
+
actual_start = pred["actual_end_date"]
|
| 123 |
+
else:
|
| 124 |
+
actual_start = planned_start + timedelta(days=actual_start_delay)
|
| 125 |
+
else:
|
| 126 |
+
actual_start = planned_start + timedelta(days=actual_start_delay)
|
| 127 |
+
|
| 128 |
+
actual_dur = int(planned_dur + add_delay(project_type))
|
| 129 |
+
actual_end = actual_start + timedelta(days=actual_dur) if is_complete else None
|
| 130 |
+
|
| 131 |
+
schedule_var = (actual_start - planned_start).days
|
| 132 |
+
|
| 133 |
+
status = "completed" if is_complete else "not_started"
|
| 134 |
+
progress = 100 if is_complete else 0
|
| 135 |
+
|
| 136 |
+
activities.append({
|
| 137 |
+
"id": act_id,
|
| 138 |
+
"project_id": project_id,
|
| 139 |
+
"project_type": project_type,
|
| 140 |
+
"name": tmpl["name"],
|
| 141 |
+
"category": tmpl["category"],
|
| 142 |
+
"planned_start_date": planned_start,
|
| 143 |
+
"planned_end_date": planned_end,
|
| 144 |
+
"planned_duration_days": planned_dur,
|
| 145 |
+
"actual_start_date": actual_start,
|
| 146 |
+
"actual_end_date": actual_end,
|
| 147 |
+
"forecasted_start_date": actual_start,
|
| 148 |
+
"forecasted_end_date": actual_end,
|
| 149 |
+
"progress": progress,
|
| 150 |
+
"status": status,
|
| 151 |
+
"parent_id": None,
|
| 152 |
+
"depends_on": f"act_{project_id.split('_')[1]}_{act_num-1:02d}" if act_num > 1 else None,
|
| 153 |
+
"actual_duration_days": actual_dur if is_complete else None,
|
| 154 |
+
"schedule_variance_days": schedule_var,
|
| 155 |
+
})
|
| 156 |
+
|
| 157 |
+
# Next planned start = this planned end
|
| 158 |
+
current_planned_start = planned_end
|
| 159 |
+
|
| 160 |
+
return activities
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def generate_daily_updates(activity_id, project_id, actual_start, actual_end):
|
| 164 |
+
updates = []
|
| 165 |
+
if actual_start is None or actual_end is None:
|
| 166 |
+
return updates
|
| 167 |
+
total_days = (actual_end - actual_start).days
|
| 168 |
+
if total_days <= 0:
|
| 169 |
+
return updates
|
| 170 |
+
progress = 0
|
| 171 |
+
notes_pool = [
|
| 172 |
+
"Good progress β crew at full strength.",
|
| 173 |
+
"Safety toolbox talk held; no incidents.",
|
| 174 |
+
"Weather caused brief stoppage.",
|
| 175 |
+
"Equipment breakdown caused 2-hour downtime.",
|
| 176 |
+
"Minor delays due to material delivery.",
|
| 177 |
+
"Night shift deployed to catch up.",
|
| 178 |
+
"Overtime shift completed to recover schedule.",
|
| 179 |
+
"Client walkthrough conducted.",
|
| 180 |
+
"Rework required on small section.",
|
| 181 |
+
"Inspection checkpoint cleared.",
|
| 182 |
+
"Material quality check done; passed.",
|
| 183 |
+
"Productivity affected by heat; hydration breaks added.",
|
| 184 |
+
"Waiting for subcontractor sign-off.",
|
| 185 |
+
"Work progressing as planned.",
|
| 186 |
+
"All tasks on track per daily plan.",
|
| 187 |
+
]
|
| 188 |
+
upd_id = 0
|
| 189 |
+
for day in range(total_days):
|
| 190 |
+
increment = np.random.normal(loc=100 / total_days, scale=3)
|
| 191 |
+
increment = max(0, min(increment, 16))
|
| 192 |
+
progress = min(100, progress + increment)
|
| 193 |
+
upd_id += 1
|
| 194 |
+
updates.append({
|
| 195 |
+
"id": f"upd_{activity_id}_{upd_id:04d}",
|
| 196 |
+
"activity_id": activity_id,
|
| 197 |
+
"project_id": project_id,
|
| 198 |
+
"date": actual_start + timedelta(days=day),
|
| 199 |
+
"reported_progress": round(progress, 1),
|
| 200 |
+
"daily_increment": round(increment, 2),
|
| 201 |
+
"image_uploaded": random.choice([True, False]),
|
| 202 |
+
"weather_event": random.random() < 0.1,
|
| 203 |
+
"crew_size": random.randint(4, 22),
|
| 204 |
+
"notes": random.choice(notes_pool),
|
| 205 |
+
"has_issue_logged": random.random() < 0.15,
|
| 206 |
+
})
|
| 207 |
+
return updates
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def generate_issues(activity_id, project_id, activity_name, num_issues, activity_start):
|
| 211 |
+
issues = []
|
| 212 |
+
for i in range(num_issues):
|
| 213 |
+
cat = random.choice(ISSUE_CATEGORIES)
|
| 214 |
+
sev = random.choice(SEVERITY_LEVELS)
|
| 215 |
+
delay_impact = random.choice([0, 0, 0, 1, 2, 3, 4, 5]) if sev in ["high", "critical"] else 0
|
| 216 |
+
issues.append({
|
| 217 |
+
"id": f"iss_{activity_id}_{i+1:03d}",
|
| 218 |
+
"activity_id": activity_id,
|
| 219 |
+
"project_id": project_id,
|
| 220 |
+
"description": f"{cat.replace('_',' ').title()} encountered during {activity_name}.",
|
| 221 |
+
"category": cat,
|
| 222 |
+
"severity": sev,
|
| 223 |
+
"status": random.choice(["open", "resolved", "resolved", "resolved"]),
|
| 224 |
+
"assigned_to": random.choice(ASSIGNEES),
|
| 225 |
+
"date_raised": activity_start + timedelta(days=random.randint(0, 10)),
|
| 226 |
+
"delay_impact_days": delay_impact,
|
| 227 |
+
})
|
| 228 |
+
return issues
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def generate_boq(activity_id, project_id, category):
|
| 232 |
+
boq_items = []
|
| 233 |
+
templates = BOQ_TEMPLATES.get(category, [])
|
| 234 |
+
for tmpl in templates:
|
| 235 |
+
name, price, cost, unit, qty = tmpl
|
| 236 |
+
noise = np.random.uniform(0.90, 1.10)
|
| 237 |
+
p = int(price * noise)
|
| 238 |
+
c = int(cost * noise)
|
| 239 |
+
boq_items.append({
|
| 240 |
+
"id": f"boq_{activity_id}_{len(boq_items)+1:03d}",
|
| 241 |
+
"activity_id": activity_id,
|
| 242 |
+
"project_id": project_id,
|
| 243 |
+
"name": name,
|
| 244 |
+
"unit": unit,
|
| 245 |
+
"quantity": qty,
|
| 246 |
+
"unit_price": p,
|
| 247 |
+
"unit_cost": c,
|
| 248 |
+
"total_price": p * qty,
|
| 249 |
+
"total_cost": c * qty,
|
| 250 |
+
"margin_pct": round((p - c) / p * 100, 1),
|
| 251 |
+
"currency": "INR",
|
| 252 |
+
})
|
| 253 |
+
return boq_items
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
def generate_resources(activity_id, project_id, actual_start, actual_end):
|
| 257 |
+
if actual_start is None or actual_end is None:
|
| 258 |
+
return []
|
| 259 |
+
resource_types = ["Labour Gang", "Equipment", "Material Supplier", "Specialist Subcontractor"]
|
| 260 |
+
resources = []
|
| 261 |
+
num = random.randint(1, 3)
|
| 262 |
+
for i in range(num):
|
| 263 |
+
resources.append({
|
| 264 |
+
"id": f"res_{activity_id}_{i+1:03d}",
|
| 265 |
+
"activity_id": activity_id,
|
| 266 |
+
"project_id": project_id,
|
| 267 |
+
"contractor": random.choice(CONTRACTORS),
|
| 268 |
+
"resource_type": random.choice(resource_types),
|
| 269 |
+
"allocated_workers": random.randint(3, 20),
|
| 270 |
+
"cost_per_day": random.randint(8000, 35000),
|
| 271 |
+
"start_date": actual_start,
|
| 272 |
+
"end_date": actual_end,
|
| 273 |
+
})
|
| 274 |
+
return resources
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
# ββ Full project generator ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 278 |
+
def generate_project(proj_id, name, proj_type, city, planned_start_str, planned_end_str,
|
| 279 |
+
is_complete=True):
|
| 280 |
+
planned_start = datetime.strptime(planned_start_str, "%Y-%m-%d")
|
| 281 |
+
planned_end = datetime.strptime(planned_end_str, "%Y-%m-%d")
|
| 282 |
+
|
| 283 |
+
activities = generate_activities(proj_id, proj_type, planned_start, is_complete=is_complete)
|
| 284 |
+
|
| 285 |
+
if is_complete:
|
| 286 |
+
actual_end = activities[-1]["actual_end_date"]
|
| 287 |
+
status = "completed"
|
| 288 |
+
else:
|
| 289 |
+
actual_end = None
|
| 290 |
+
status = "in_progress"
|
| 291 |
+
|
| 292 |
+
project = {
|
| 293 |
+
"id": proj_id,
|
| 294 |
+
"name": name,
|
| 295 |
+
"planned_start": planned_start,
|
| 296 |
+
"planned_end": planned_end,
|
| 297 |
+
"type": proj_type,
|
| 298 |
+
"city": city,
|
| 299 |
+
"actual_start": activities[0]["actual_start_date"],
|
| 300 |
+
"actual_end": actual_end,
|
| 301 |
+
"status": status,
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
all_updates, all_issues, all_boq, all_resources = [], [], [], []
|
| 305 |
+
for act in activities:
|
| 306 |
+
all_updates.extend(generate_daily_updates(
|
| 307 |
+
act["id"], proj_id, act["actual_start_date"], act["actual_end_date"]))
|
| 308 |
+
num_issues = random.randint(2, 5)
|
| 309 |
+
all_issues.extend(generate_issues(
|
| 310 |
+
act["id"], proj_id, act["name"], num_issues, act["actual_start_date"]))
|
| 311 |
+
all_boq.extend(generate_boq(act["id"], proj_id, act["category"]))
|
| 312 |
+
all_resources.extend(generate_resources(
|
| 313 |
+
act["id"], proj_id, act["actual_start_date"], act["actual_end_date"]))
|
| 314 |
+
|
| 315 |
+
return project, activities, all_updates, all_issues, all_boq, all_resources
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
# ββ CSV Ingest βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 319 |
+
def ingest_csvs(engine):
|
| 320 |
+
"""Load all CSVs from data/ folder into the SQLite DB."""
|
| 321 |
+
csv_files = {
|
| 322 |
+
"projects": "projects.csv",
|
| 323 |
+
"activities": "activities.csv",
|
| 324 |
+
"daily_updates": "daily_updates.csv",
|
| 325 |
+
"issues": "issues.csv",
|
| 326 |
+
"boq": "boq.csv",
|
| 327 |
+
"resources": "resources.csv",
|
| 328 |
+
}
|
| 329 |
+
for table, fname in csv_files.items():
|
| 330 |
+
fpath = os.path.join(DATA_DIR, fname)
|
| 331 |
+
if os.path.exists(fpath):
|
| 332 |
+
df = pd.read_csv(fpath)
|
| 333 |
+
# Normalize column names for projects table
|
| 334 |
+
if table == "projects":
|
| 335 |
+
rename_map = {
|
| 336 |
+
"planned_start": "planned_start",
|
| 337 |
+
"planned_end": "planned_end",
|
| 338 |
+
"actual_start": "actual_start",
|
| 339 |
+
"actual_end": "actual_end",
|
| 340 |
+
}
|
| 341 |
+
df = df.rename(columns=rename_map)
|
| 342 |
+
df.to_sql(table, engine, if_exists="replace", index=False)
|
| 343 |
+
print(f" β
Ingested {fname} β {table} ({len(df)} rows)")
|
| 344 |
+
else:
|
| 345 |
+
print(f" β οΈ {fname} not found, skipping.")
|
| 346 |
+
|
| 347 |
+
|
| 348 |
+
# ββ Activity Dependencies Table ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 349 |
+
def build_dependencies_table(engine):
|
| 350 |
+
"""Build activity_dependencies junction table from the depends_on column."""
|
| 351 |
+
with engine.connect() as conn:
|
| 352 |
+
try:
|
| 353 |
+
df = pd.read_sql("SELECT id, depends_on FROM activities WHERE depends_on IS NOT NULL AND depends_on != ''", conn)
|
| 354 |
+
except Exception:
|
| 355 |
+
return
|
| 356 |
+
if df.empty:
|
| 357 |
+
return
|
| 358 |
+
df = df.rename(columns={"id": "activity_id", "depends_on": "predecessor_id"})
|
| 359 |
+
df = df.dropna(subset=["predecessor_id"])
|
| 360 |
+
df = df[df["predecessor_id"].str.strip() != ""]
|
| 361 |
+
df.to_sql("activity_dependencies", engine, if_exists="replace", index=False)
|
| 362 |
+
print(f" β
Built activity_dependencies table ({len(df)} rows)")
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
# ββ Main βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 366 |
+
def main(mode="both"):
|
| 367 |
+
os.makedirs(DATA_DIR, exist_ok=True)
|
| 368 |
+
engine = create_engine(f"sqlite:///{DB_PATH}")
|
| 369 |
+
print(f"\nπ¦ Database: {DB_PATH}\n")
|
| 370 |
+
|
| 371 |
+
if mode in ("csv", "both"):
|
| 372 |
+
print("π Ingesting CSVs...")
|
| 373 |
+
ingest_csvs(engine)
|
| 374 |
+
|
| 375 |
+
if mode in ("gen", "both"):
|
| 376 |
+
print("\nπ§ Generating synthetic projects (will add to DB if not present)...")
|
| 377 |
+
# Check if already have projects β if CSV ingest already happened, skip duplicates
|
| 378 |
+
with engine.connect() as conn:
|
| 379 |
+
try:
|
| 380 |
+
existing_ids = pd.read_sql("SELECT id FROM projects", conn)["id"].tolist()
|
| 381 |
+
except Exception:
|
| 382 |
+
existing_ids = []
|
| 383 |
+
|
| 384 |
+
# Add 2 extra synthetic completed projects for richer training set
|
| 385 |
+
extra_projects = [
|
| 386 |
+
("proj_011", "Beachfront Bungalow Reno", "residential", "Kochi",
|
| 387 |
+
"2023-08-01", "2024-02-28", True),
|
| 388 |
+
("proj_012", "Shopping Mall Fit-out", "commercial", "Kolkata",
|
| 389 |
+
"2023-10-01", "2024-05-31", True),
|
| 390 |
+
]
|
| 391 |
+
all_p, all_a, all_u, all_i, all_b, all_r = [], [], [], [], [], []
|
| 392 |
+
for args in extra_projects:
|
| 393 |
+
pid = args[0]
|
| 394 |
+
if pid in existing_ids:
|
| 395 |
+
print(f" βΉοΈ {pid} already in DB, skipping.")
|
| 396 |
+
continue
|
| 397 |
+
p, a, u, i, b, r = generate_project(*args)
|
| 398 |
+
all_p.append(p); all_a.extend(a); all_u.extend(u)
|
| 399 |
+
all_i.extend(i); all_b.extend(b); all_r.extend(r)
|
| 400 |
+
print(f" β
Generated {args[1]} ({len(a)} activities, {len(u)} updates)")
|
| 401 |
+
|
| 402 |
+
if all_p:
|
| 403 |
+
pd.DataFrame(all_p).to_sql("projects", engine, if_exists="append", index=False)
|
| 404 |
+
pd.DataFrame(all_a).to_sql("activities", engine, if_exists="append", index=False)
|
| 405 |
+
if all_u: pd.DataFrame(all_u).to_sql("daily_updates", engine, if_exists="append", index=False)
|
| 406 |
+
if all_i: pd.DataFrame(all_i).to_sql("issues", engine, if_exists="append", index=False)
|
| 407 |
+
if all_b: pd.DataFrame(all_b).to_sql("boq", engine, if_exists="append", index=False)
|
| 408 |
+
if all_r: pd.DataFrame(all_r).to_sql("resources", engine, if_exists="append", index=False)
|
| 409 |
+
|
| 410 |
+
print("\nπ Building dependency graph table...")
|
| 411 |
+
build_dependencies_table(engine)
|
| 412 |
+
|
| 413 |
+
# Summary
|
| 414 |
+
with engine.connect() as conn:
|
| 415 |
+
for tbl in ["projects", "activities", "daily_updates", "issues", "boq", "resources", "activity_dependencies"]:
|
| 416 |
+
try:
|
| 417 |
+
cnt = pd.read_sql(f"SELECT COUNT(*) as n FROM {tbl}", conn)["n"].iloc[0]
|
| 418 |
+
print(f" π {tbl}: {cnt} rows")
|
| 419 |
+
except Exception:
|
| 420 |
+
pass
|
| 421 |
+
|
| 422 |
+
print("\nβ
Database ready!")
|
| 423 |
+
return engine
|
| 424 |
+
|
| 425 |
+
|
| 426 |
+
if __name__ == "__main__":
|
| 427 |
+
parser = argparse.ArgumentParser(description="What-if Scheduler Data Setup")
|
| 428 |
+
parser.add_argument("--csv-only", action="store_true", help="Only ingest CSVs")
|
| 429 |
+
parser.add_argument("--gen-only", action="store_true", help="Only generate synthetic data")
|
| 430 |
+
args = parser.parse_args()
|
| 431 |
+
|
| 432 |
+
if args.csv_only:
|
| 433 |
+
mode = "csv"
|
| 434 |
+
elif args.gen_only:
|
| 435 |
+
mode = "gen"
|
| 436 |
+
else:
|
| 437 |
+
mode = "both"
|
| 438 |
+
|
| 439 |
+
main(mode=mode)
|
engine/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# engine package
|
engine/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (163 Bytes). View file
|
|
|
engine/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (151 Bytes). View file
|
|
|
engine/__pycache__/dag_builder.cpython-311.pyc
ADDED
|
Binary file (4.69 kB). View file
|
|
|
engine/__pycache__/dag_builder.cpython-312.pyc
ADDED
|
Binary file (4.24 kB). View file
|
|
|
engine/__pycache__/ripple_engine.cpython-311.pyc
ADDED
|
Binary file (9.02 kB). View file
|
|
|
engine/__pycache__/ripple_engine.cpython-312.pyc
ADDED
|
Binary file (8.13 kB). View file
|
|
|
engine/__pycache__/whatif_scenarios.cpython-311.pyc
ADDED
|
Binary file (11 kB). View file
|
|
|
engine/__pycache__/whatif_scenarios.cpython-312.pyc
ADDED
|
Binary file (10 kB). View file
|
|
|
engine/dag_builder.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
engine/dag_builder.py
|
| 3 |
+
----------------------
|
| 4 |
+
Builds a directed acyclic graph (DAG) of activity dependencies using networkx.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import networkx as nx
|
| 9 |
+
from typing import Optional
|
| 10 |
+
from data_loader import DataLoader
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def build_dag(project_id: str, loader: Optional[DataLoader] = None) -> nx.DiGraph:
|
| 14 |
+
"""
|
| 15 |
+
Build a dependency DAG for the given project.
|
| 16 |
+
|
| 17 |
+
Nodes : activity IDs (strings)
|
| 18 |
+
Edges : (predecessor_id β successor_id) [depends_on direction]
|
| 19 |
+
Node attributes: all activity fields
|
| 20 |
+
"""
|
| 21 |
+
if loader is None:
|
| 22 |
+
loader = DataLoader()
|
| 23 |
+
|
| 24 |
+
acts = loader.get_project_activities(project_id)
|
| 25 |
+
if acts.empty:
|
| 26 |
+
return nx.DiGraph()
|
| 27 |
+
|
| 28 |
+
G = nx.DiGraph()
|
| 29 |
+
|
| 30 |
+
# Add all activities as nodes
|
| 31 |
+
for _, row in acts.iterrows():
|
| 32 |
+
G.add_node(row["id"], **row.to_dict())
|
| 33 |
+
|
| 34 |
+
# Add dependency edges
|
| 35 |
+
for _, row in acts.iterrows():
|
| 36 |
+
dep = row.get("depends_on")
|
| 37 |
+
if dep and not (isinstance(dep, float)) and str(dep).strip():
|
| 38 |
+
dep = str(dep).strip()
|
| 39 |
+
if dep in G.nodes:
|
| 40 |
+
# Edge: dep (predecessor) β row["id"] (successor)
|
| 41 |
+
G.add_edge(dep, row["id"])
|
| 42 |
+
|
| 43 |
+
# Validate: warn if cycle found (shouldn't happen in real data)
|
| 44 |
+
if not nx.is_directed_acyclic_graph(G):
|
| 45 |
+
print(f"β οΈ Cycle detected in DAG for {project_id}!")
|
| 46 |
+
|
| 47 |
+
return G
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def get_topological_order(G: nx.DiGraph) -> list:
|
| 51 |
+
"""Return activities in topological order (starts before ends)."""
|
| 52 |
+
try:
|
| 53 |
+
return list(nx.topological_sort(G))
|
| 54 |
+
except nx.NetworkXUnfeasible:
|
| 55 |
+
return list(G.nodes)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def get_descendants(G: nx.DiGraph, activity_id: str) -> list:
|
| 59 |
+
"""Return all downstream activities (BFS)."""
|
| 60 |
+
try:
|
| 61 |
+
return list(nx.descendants(G, activity_id))
|
| 62 |
+
except nx.NodeNotFound:
|
| 63 |
+
return []
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def get_ancestors(G: nx.DiGraph, activity_id: str) -> list:
|
| 67 |
+
"""Return all upstream activities."""
|
| 68 |
+
try:
|
| 69 |
+
return list(nx.ancestors(G, activity_id))
|
| 70 |
+
except nx.NodeNotFound:
|
| 71 |
+
return []
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def get_activity_depth(G: nx.DiGraph, activity_id: str) -> int:
|
| 75 |
+
"""Depth of activity in the DAG from source nodes."""
|
| 76 |
+
try:
|
| 77 |
+
sources = [n for n in G.nodes if G.in_degree(n) == 0]
|
| 78 |
+
max_depth = 0
|
| 79 |
+
for src in sources:
|
| 80 |
+
try:
|
| 81 |
+
path_length = nx.shortest_path_length(G, src, activity_id)
|
| 82 |
+
max_depth = max(max_depth, path_length)
|
| 83 |
+
except nx.NetworkXNoPath:
|
| 84 |
+
pass
|
| 85 |
+
return max_depth
|
| 86 |
+
except Exception:
|
| 87 |
+
return 0
|
engine/ripple_engine.py
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
engine/ripple_engine.py
|
| 3 |
+
------------------------
|
| 4 |
+
Propagates delays through the dependency DAG using BFS.
|
| 5 |
+
Computes cascade impact on all downstream activities.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import pandas as pd
|
| 9 |
+
import numpy as np
|
| 10 |
+
import networkx as nx
|
| 11 |
+
from datetime import datetime, timedelta
|
| 12 |
+
from typing import Optional, Dict, List
|
| 13 |
+
from data_loader import DataLoader
|
| 14 |
+
from engine.dag_builder import build_dag, get_descendants
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class RippleEngine:
|
| 18 |
+
"""
|
| 19 |
+
Given a delay delta on one activity, propagate the effect to all
|
| 20 |
+
downstream activities and compute the new project end date.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
def __init__(self, G: nx.DiGraph, loader: Optional[DataLoader] = None):
|
| 24 |
+
self.G = G
|
| 25 |
+
self.loader = loader or DataLoader()
|
| 26 |
+
|
| 27 |
+
def _get_activity(self, activity_id: str) -> Dict:
|
| 28 |
+
"""Return node attribute dict for an activity."""
|
| 29 |
+
if activity_id in self.G.nodes:
|
| 30 |
+
return dict(self.G.nodes[activity_id])
|
| 31 |
+
return {}
|
| 32 |
+
|
| 33 |
+
def _to_ts(self, val) -> Optional[pd.Timestamp]:
|
| 34 |
+
if val is None or (isinstance(val, float) and np.isnan(val)):
|
| 35 |
+
return None
|
| 36 |
+
try:
|
| 37 |
+
return pd.Timestamp(val)
|
| 38 |
+
except Exception:
|
| 39 |
+
return None
|
| 40 |
+
|
| 41 |
+
def propagate_delay(self, affected_activity_id: str, delta_days: int,
|
| 42 |
+
reference_date: Optional[datetime] = None) -> Dict:
|
| 43 |
+
"""
|
| 44 |
+
Simulate delaying `affected_activity_id` by `delta_days` and compute
|
| 45 |
+
the cascade effect on all downstream activities.
|
| 46 |
+
|
| 47 |
+
Returns
|
| 48 |
+
-------
|
| 49 |
+
dict with:
|
| 50 |
+
- affected_activity_id
|
| 51 |
+
- delta_days
|
| 52 |
+
- cascade_table : DataFrame of impacted activities
|
| 53 |
+
- new_project_end : pd.Timestamp or None
|
| 54 |
+
- original_project_end : pd.Timestamp or None
|
| 55 |
+
- total_project_delay_days : int
|
| 56 |
+
"""
|
| 57 |
+
if reference_date is None:
|
| 58 |
+
reference_date = datetime(2024, 6, 1)
|
| 59 |
+
today = pd.Timestamp(reference_date)
|
| 60 |
+
|
| 61 |
+
# Get all descendants (will be affected)
|
| 62 |
+
downstream = get_descendants(self.G, affected_activity_id)
|
| 63 |
+
|
| 64 |
+
# Compute original project end (max of all leaf node ends)
|
| 65 |
+
leaf_nodes = [n for n in self.G.nodes if self.G.out_degree(n) == 0]
|
| 66 |
+
original_project_end = None
|
| 67 |
+
for node in leaf_nodes:
|
| 68 |
+
end = self._to_ts(self.G.nodes[node].get("planned_end_date"))
|
| 69 |
+
if end and (original_project_end is None or end > original_project_end):
|
| 70 |
+
original_project_end = end
|
| 71 |
+
|
| 72 |
+
# Compute shifted dates using topological traversal
|
| 73 |
+
# shifted_ends dict: activity_id β new_end_date
|
| 74 |
+
shifted_ends = {}
|
| 75 |
+
shifted_starts = {}
|
| 76 |
+
|
| 77 |
+
# The directly affected activity shifts by delta_days in its end
|
| 78 |
+
act_data = self._get_activity(affected_activity_id)
|
| 79 |
+
orig_end = self._to_ts(
|
| 80 |
+
act_data.get("forecasted_end_date") or act_data.get("planned_end_date")
|
| 81 |
+
)
|
| 82 |
+
if orig_end is None:
|
| 83 |
+
orig_end = self._to_ts(act_data.get("planned_end_date"))
|
| 84 |
+
if orig_end:
|
| 85 |
+
shifted_ends[affected_activity_id] = orig_end + timedelta(days=delta_days)
|
| 86 |
+
else:
|
| 87 |
+
shifted_ends[affected_activity_id] = today + timedelta(days=delta_days)
|
| 88 |
+
|
| 89 |
+
# BFS propagation
|
| 90 |
+
try:
|
| 91 |
+
topo_order = list(nx.topological_sort(self.G))
|
| 92 |
+
except Exception:
|
| 93 |
+
topo_order = [affected_activity_id] + downstream
|
| 94 |
+
|
| 95 |
+
cascade_rows = []
|
| 96 |
+
|
| 97 |
+
for node_id in topo_order:
|
| 98 |
+
if node_id not in downstream and node_id != affected_activity_id:
|
| 99 |
+
continue
|
| 100 |
+
|
| 101 |
+
node_data = self._get_activity(node_id)
|
| 102 |
+
original_start = self._to_ts(
|
| 103 |
+
node_data.get("planned_start_date")
|
| 104 |
+
)
|
| 105 |
+
original_end = self._to_ts(
|
| 106 |
+
node_data.get("forecasted_end_date") or node_data.get("planned_end_date")
|
| 107 |
+
)
|
| 108 |
+
planned_dur = node_data.get(
|
| 109 |
+
"planned_duration_days",
|
| 110 |
+
(original_end - original_start).days if original_start and original_end else 14
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
# New start = max(original planned start, max of all predecessor new ends)
|
| 114 |
+
pred_ends = []
|
| 115 |
+
for pred_id in self.G.predecessors(node_id):
|
| 116 |
+
if pred_id in shifted_ends:
|
| 117 |
+
pred_ends.append(shifted_ends[pred_id])
|
| 118 |
+
else:
|
| 119 |
+
pred_data = self._get_activity(pred_id)
|
| 120 |
+
pred_end = self._to_ts(
|
| 121 |
+
pred_data.get("forecasted_end_date") or pred_data.get("planned_end_date")
|
| 122 |
+
)
|
| 123 |
+
if pred_end:
|
| 124 |
+
pred_ends.append(pred_end)
|
| 125 |
+
|
| 126 |
+
if pred_ends:
|
| 127 |
+
new_start = max(pred_ends)
|
| 128 |
+
if original_start:
|
| 129 |
+
new_start = max(new_start, original_start)
|
| 130 |
+
else:
|
| 131 |
+
new_start = original_start or today
|
| 132 |
+
|
| 133 |
+
new_end = new_start + timedelta(days=int(planned_dur or 14))
|
| 134 |
+
shifted_starts[node_id] = new_start
|
| 135 |
+
shifted_ends[node_id] = new_end
|
| 136 |
+
|
| 137 |
+
cascade_delay = 0
|
| 138 |
+
if original_end:
|
| 139 |
+
cascade_delay = (new_end - original_end).days
|
| 140 |
+
|
| 141 |
+
if node_id != affected_activity_id:
|
| 142 |
+
cascade_rows.append({
|
| 143 |
+
"activity_id": node_id,
|
| 144 |
+
"activity_name": node_data.get("name", node_id),
|
| 145 |
+
"original_start": original_start,
|
| 146 |
+
"original_end": original_end,
|
| 147 |
+
"new_start": new_start,
|
| 148 |
+
"new_end": new_end,
|
| 149 |
+
"cascade_delay_days": cascade_delay,
|
| 150 |
+
"has_open_issues": node_data.get("issue_count", 0) > 0,
|
| 151 |
+
})
|
| 152 |
+
|
| 153 |
+
# New project end
|
| 154 |
+
new_project_end = None
|
| 155 |
+
for node in leaf_nodes:
|
| 156 |
+
end = shifted_ends.get(node) or self._to_ts(
|
| 157 |
+
self.G.nodes[node].get("planned_end_date")
|
| 158 |
+
)
|
| 159 |
+
if end and (new_project_end is None or end > new_project_end):
|
| 160 |
+
new_project_end = end
|
| 161 |
+
|
| 162 |
+
total_project_delay = 0
|
| 163 |
+
if original_project_end and new_project_end:
|
| 164 |
+
total_project_delay = (new_project_end - original_project_end).days
|
| 165 |
+
|
| 166 |
+
cascade_df = pd.DataFrame(cascade_rows) if cascade_rows else pd.DataFrame(
|
| 167 |
+
columns=["activity_id", "activity_name", "original_start", "original_end",
|
| 168 |
+
"new_start", "new_end", "cascade_delay_days", "has_open_issues"]
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
return {
|
| 172 |
+
"affected_activity_id": affected_activity_id,
|
| 173 |
+
"delta_days": delta_days,
|
| 174 |
+
"cascade_table": cascade_df,
|
| 175 |
+
"new_project_end": new_project_end,
|
| 176 |
+
"original_project_end": original_project_end,
|
| 177 |
+
"total_project_delay_days": total_project_delay,
|
| 178 |
+
"num_activities_affected": len(cascade_rows),
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
def get_high_impact_activities(self, top_n: int = 5) -> pd.DataFrame:
|
| 182 |
+
"""
|
| 183 |
+
Find activities whose 1-day delay causes the most downstream impact.
|
| 184 |
+
"""
|
| 185 |
+
rows = []
|
| 186 |
+
for node_id in self.G.nodes:
|
| 187 |
+
descendants = get_descendants(self.G, node_id)
|
| 188 |
+
rows.append({
|
| 189 |
+
"activity_id": node_id,
|
| 190 |
+
"activity_name": self.G.nodes[node_id].get("name", node_id),
|
| 191 |
+
"downstream_count": len(descendants),
|
| 192 |
+
"status": self.G.nodes[node_id].get("status", "unknown"),
|
| 193 |
+
})
|
| 194 |
+
df = pd.DataFrame(rows).sort_values("downstream_count", ascending=False)
|
| 195 |
+
return df.head(top_n)
|
engine/whatif_scenarios.py
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
engine/whatif_scenarios.py
|
| 3 |
+
---------------------------
|
| 4 |
+
Stores and evaluates 4 types of what-if scenarios with side-by-side comparison.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import uuid
|
| 9 |
+
from datetime import datetime, timedelta
|
| 10 |
+
from typing import Optional, List, Dict
|
| 11 |
+
import networkx as nx
|
| 12 |
+
from data_loader import DataLoader
|
| 13 |
+
from engine.dag_builder import build_dag
|
| 14 |
+
from engine.ripple_engine import RippleEngine
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
SCENARIO_TYPES = ["delay", "resource_boost", "issue_resolved", "parallelize"]
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class WhatIfScenarioEngine:
|
| 21 |
+
"""
|
| 22 |
+
Manages scenarios and evaluates their impact.
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
def __init__(self, project_id: str, loader: Optional[DataLoader] = None,
|
| 26 |
+
reference_date: Optional[datetime] = None):
|
| 27 |
+
self.project_id = project_id
|
| 28 |
+
self.loader = loader or DataLoader()
|
| 29 |
+
self.reference_date = reference_date or datetime(2024, 6, 1)
|
| 30 |
+
self.G = build_dag(project_id, loader=self.loader)
|
| 31 |
+
self.ripple = RippleEngine(self.G, loader=self.loader)
|
| 32 |
+
self._scenarios: List[Dict] = []
|
| 33 |
+
|
| 34 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 35 |
+
# Scenario Builders
|
| 36 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 37 |
+
|
| 38 |
+
def scenario_delay(self, activity_id: str, delay_days: int,
|
| 39 |
+
description: str = "") -> Dict:
|
| 40 |
+
"""What-if: Activity X is delayed by N days."""
|
| 41 |
+
result = self.ripple.propagate_delay(
|
| 42 |
+
activity_id, delay_days, reference_date=self.reference_date
|
| 43 |
+
)
|
| 44 |
+
# Cost impact: rough estimate from BOQ
|
| 45 |
+
boq = self.loader.get_project_boq(self.project_id)
|
| 46 |
+
daily_rate = (boq["total_cost"].sum() / 120) if not boq.empty else 50000
|
| 47 |
+
cost_impact = daily_rate * result["total_project_delay_days"]
|
| 48 |
+
|
| 49 |
+
scenario = {
|
| 50 |
+
"scenario_id": str(uuid.uuid4())[:8],
|
| 51 |
+
"type": "delay",
|
| 52 |
+
"description": description or f"Activity {activity_id} delayed by {delay_days} days",
|
| 53 |
+
"modified_activities": [activity_id],
|
| 54 |
+
"delta_input": delay_days,
|
| 55 |
+
"num_activities_affected": result["num_activities_affected"],
|
| 56 |
+
"original_project_end": result["original_project_end"],
|
| 57 |
+
"new_project_end": result["new_project_end"],
|
| 58 |
+
"total_project_delay_days": result["total_project_delay_days"],
|
| 59 |
+
"days_saved": -result["total_project_delay_days"],
|
| 60 |
+
"cost_impact_inr": round(cost_impact, 0),
|
| 61 |
+
"cascade_table": result["cascade_table"],
|
| 62 |
+
}
|
| 63 |
+
self._scenarios.append(scenario)
|
| 64 |
+
return scenario
|
| 65 |
+
|
| 66 |
+
def scenario_resource_boost(self, activity_id: str, duration_reduction_pct: float = 25.0,
|
| 67 |
+
description: str = "") -> Dict:
|
| 68 |
+
"""
|
| 69 |
+
What-if: Add resources to activity Y β reduce its duration by X%.
|
| 70 |
+
Propagates the earlier completion to all downstream.
|
| 71 |
+
"""
|
| 72 |
+
act_data = dict(self.G.nodes.get(activity_id, {}))
|
| 73 |
+
planned_dur = float(act_data.get("planned_duration_days", 14) or 14)
|
| 74 |
+
reduction_days = int(planned_dur * duration_reduction_pct / 100)
|
| 75 |
+
|
| 76 |
+
# A negative delay = finishing early
|
| 77 |
+
result = self.ripple.propagate_delay(
|
| 78 |
+
activity_id, -reduction_days, reference_date=self.reference_date
|
| 79 |
+
)
|
| 80 |
+
boq = self.loader.get_project_boq(self.project_id)
|
| 81 |
+
daily_rate = (boq["total_cost"].sum() / 120) if not boq.empty else 50000
|
| 82 |
+
overtime_premium = 1.4 # 40% overtime/extra crew premium
|
| 83 |
+
extra_cost = daily_rate * reduction_days * overtime_premium
|
| 84 |
+
|
| 85 |
+
scenario = {
|
| 86 |
+
"scenario_id": str(uuid.uuid4())[:8],
|
| 87 |
+
"type": "resource_boost",
|
| 88 |
+
"description": description or f"Add resources to {activity_id} β reduce by {duration_reduction_pct:.0f}%",
|
| 89 |
+
"modified_activities": [activity_id],
|
| 90 |
+
"delta_input": -reduction_days,
|
| 91 |
+
"num_activities_affected": result["num_activities_affected"],
|
| 92 |
+
"original_project_end": result["original_project_end"],
|
| 93 |
+
"new_project_end": result["new_project_end"],
|
| 94 |
+
"total_project_delay_days": result["total_project_delay_days"],
|
| 95 |
+
"days_saved": -result["total_project_delay_days"],
|
| 96 |
+
"cost_impact_inr": round(extra_cost, 0),
|
| 97 |
+
"cascade_table": result["cascade_table"],
|
| 98 |
+
}
|
| 99 |
+
self._scenarios.append(scenario)
|
| 100 |
+
return scenario
|
| 101 |
+
|
| 102 |
+
def scenario_issue_resolved(self, issue_id: str, description: str = "") -> Dict:
|
| 103 |
+
"""
|
| 104 |
+
What-if: Issue Z is resolved β estimate delay days saved.
|
| 105 |
+
"""
|
| 106 |
+
issues = self.loader.issues
|
| 107 |
+
issue = issues[issues["id"] == issue_id]
|
| 108 |
+
if issue.empty:
|
| 109 |
+
return {"error": f"Issue {issue_id} not found"}
|
| 110 |
+
|
| 111 |
+
row = issue.iloc[0]
|
| 112 |
+
activity_id = str(row.get("activity_id", ""))
|
| 113 |
+
delay_impact = float(row.get("delay_impact_days", 0) or 0)
|
| 114 |
+
|
| 115 |
+
# Negative delta = resolving the issue saves those days
|
| 116 |
+
result = self.ripple.propagate_delay(
|
| 117 |
+
activity_id, -int(delay_impact), reference_date=self.reference_date
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
scenario = {
|
| 121 |
+
"scenario_id": str(uuid.uuid4())[:8],
|
| 122 |
+
"type": "issue_resolved",
|
| 123 |
+
"description": description or f"Issue {issue_id} resolved β saves {delay_impact:.0f} days",
|
| 124 |
+
"modified_activities": [activity_id],
|
| 125 |
+
"delta_input": -int(delay_impact),
|
| 126 |
+
"num_activities_affected": result["num_activities_affected"],
|
| 127 |
+
"original_project_end": result["original_project_end"],
|
| 128 |
+
"new_project_end": result["new_project_end"],
|
| 129 |
+
"total_project_delay_days": result["total_project_delay_days"],
|
| 130 |
+
"days_saved": -result["total_project_delay_days"],
|
| 131 |
+
"cost_impact_inr": 0,
|
| 132 |
+
"cascade_table": result["cascade_table"],
|
| 133 |
+
}
|
| 134 |
+
self._scenarios.append(scenario)
|
| 135 |
+
return scenario
|
| 136 |
+
|
| 137 |
+
def scenario_parallelize(self, act_a_id: str, act_b_id: str,
|
| 138 |
+
description: str = "") -> Dict:
|
| 139 |
+
"""
|
| 140 |
+
What-if: Run A and B concurrently (remove AβB dependency).
|
| 141 |
+
B's start moves to A's start, saving B's original waiting time.
|
| 142 |
+
"""
|
| 143 |
+
G_copy = self.G.copy()
|
| 144 |
+
days_saved = 0
|
| 145 |
+
|
| 146 |
+
if G_copy.has_edge(act_a_id, act_b_id):
|
| 147 |
+
G_copy.remove_edge(act_a_id, act_b_id)
|
| 148 |
+
# B's new start = same as A's start
|
| 149 |
+
a_data = dict(self.G.nodes.get(act_a_id, {}))
|
| 150 |
+
b_data = dict(self.G.nodes.get(act_b_id, {}))
|
| 151 |
+
a_start = b_data.get("planned_start_date") or b_data.get("actual_start_date")
|
| 152 |
+
b_orig_start = b_data.get("planned_start_date")
|
| 153 |
+
b_planned_dur = float(b_data.get("planned_duration_days", 14) or 14)
|
| 154 |
+
a_planned_dur = float(a_data.get("planned_duration_days", 14) or 14)
|
| 155 |
+
|
| 156 |
+
if a_start and b_orig_start:
|
| 157 |
+
import pandas as _pd
|
| 158 |
+
a_s = _pd.Timestamp(a_start) if not _pd.isna(a_start) else None
|
| 159 |
+
b_s = _pd.Timestamp(b_orig_start) if not _pd.isna(b_orig_start) else None
|
| 160 |
+
if a_s and b_s:
|
| 161 |
+
days_saved = max(0, int((b_s - a_s).days))
|
| 162 |
+
|
| 163 |
+
# Ripple from a with -days_saved on B
|
| 164 |
+
ripple_b = RippleEngine(G_copy, loader=self.loader)
|
| 165 |
+
result = ripple_b.propagate_delay(
|
| 166 |
+
act_b_id, -days_saved, reference_date=self.reference_date
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
scenario = {
|
| 170 |
+
"scenario_id": str(uuid.uuid4())[:8],
|
| 171 |
+
"type": "parallelize",
|
| 172 |
+
"description": description or f"Run {act_a_id} and {act_b_id} in parallel",
|
| 173 |
+
"modified_activities": [act_a_id, act_b_id],
|
| 174 |
+
"delta_input": -days_saved,
|
| 175 |
+
"num_activities_affected": result["num_activities_affected"],
|
| 176 |
+
"original_project_end": result["original_project_end"],
|
| 177 |
+
"new_project_end": result["new_project_end"],
|
| 178 |
+
"total_project_delay_days": result["total_project_delay_days"],
|
| 179 |
+
"days_saved": days_saved,
|
| 180 |
+
"cost_impact_inr": 0,
|
| 181 |
+
"cascade_table": result["cascade_table"],
|
| 182 |
+
}
|
| 183 |
+
self._scenarios.append(scenario)
|
| 184 |
+
return scenario
|
| 185 |
+
|
| 186 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 187 |
+
# Comparison
|
| 188 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 189 |
+
|
| 190 |
+
def get_scenario_comparison(self) -> pd.DataFrame:
|
| 191 |
+
"""Return all stored scenarios as a comparison table (no cascade_table column)."""
|
| 192 |
+
if not self._scenarios:
|
| 193 |
+
return pd.DataFrame()
|
| 194 |
+
rows = []
|
| 195 |
+
for s in self._scenarios:
|
| 196 |
+
row = {k: v for k, v in s.items() if k != "cascade_table"}
|
| 197 |
+
rows.append(row)
|
| 198 |
+
return pd.DataFrame(rows)
|
| 199 |
+
|
| 200 |
+
def clear_scenarios(self):
|
| 201 |
+
self._scenarios = []
|
| 202 |
+
|
| 203 |
+
def get_scenarios(self) -> List[Dict]:
|
| 204 |
+
return self._scenarios
|
features/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# features package
|
features/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (165 Bytes). View file
|
|
|
features/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (153 Bytes). View file
|
|
|
features/__pycache__/feature_engineering.cpython-311.pyc
ADDED
|
Binary file (13.1 kB). View file
|
|
|
features/__pycache__/feature_engineering.cpython-312.pyc
ADDED
|
Binary file (11.6 kB). View file
|
|
|
features/feature_engineering.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
features/feature_engineering.py
|
| 3 |
+
---------------------------------
|
| 4 |
+
Computes 12 engineered features per activity for ML models.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import numpy as np
|
| 9 |
+
from datetime import datetime
|
| 10 |
+
from typing import Optional
|
| 11 |
+
|
| 12 |
+
REFERENCE_DATE = datetime(2024, 6, 1)
|
| 13 |
+
|
| 14 |
+
ISSUE_SEVERITY_WEIGHTS = {
|
| 15 |
+
"design_change": 3.0,
|
| 16 |
+
"inspection_fail": 2.0,
|
| 17 |
+
"scope_creep": 2.0,
|
| 18 |
+
"weather": 1.0,
|
| 19 |
+
"material_delay": 1.5,
|
| 20 |
+
"labor_shortage": 1.5,
|
| 21 |
+
"equipment_breakdown": 1.0,
|
| 22 |
+
"safety": 0.5,
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
SEVERITY_MULTIPLIER = {"low": 0.5, "medium": 1.0, "high": 1.5, "critical": 2.5}
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def engineer_features(
|
| 29 |
+
activities: pd.DataFrame,
|
| 30 |
+
loader,
|
| 31 |
+
today: Optional[datetime] = None,
|
| 32 |
+
) -> pd.DataFrame:
|
| 33 |
+
"""
|
| 34 |
+
Compute all 12 features for every activity in the dataframe.
|
| 35 |
+
|
| 36 |
+
Parameters
|
| 37 |
+
----------
|
| 38 |
+
activities : pd.DataFrame β activities to featurize
|
| 39 |
+
loader : DataLoader β for accessing updates, issues, boq, etc.
|
| 40 |
+
today : datetime β reference date (defaults to REFERENCE_DATE)
|
| 41 |
+
|
| 42 |
+
Returns
|
| 43 |
+
-------
|
| 44 |
+
pd.DataFrame with original columns + 12 new feature columns
|
| 45 |
+
"""
|
| 46 |
+
if today is None:
|
| 47 |
+
today = REFERENCE_DATE
|
| 48 |
+
|
| 49 |
+
today = pd.Timestamp(today)
|
| 50 |
+
df = activities.copy()
|
| 51 |
+
|
| 52 |
+
# ββ Ensure date columns are Timestamps ββββββββββββββββββββββββββββββββββ
|
| 53 |
+
date_cols = ["planned_start_date", "planned_end_date",
|
| 54 |
+
"actual_start_date", "actual_end_date"]
|
| 55 |
+
for col in date_cols:
|
| 56 |
+
if col in df.columns:
|
| 57 |
+
df[col] = pd.to_datetime(df[col], errors="coerce")
|
| 58 |
+
|
| 59 |
+
# ββ Feature 1: planned_duration ββββββββββββββββββββββββββββββββββββββββββ
|
| 60 |
+
df["planned_duration"] = (
|
| 61 |
+
df["planned_end_date"] - df["planned_start_date"]
|
| 62 |
+
).dt.days.clip(lower=1)
|
| 63 |
+
|
| 64 |
+
# ββ Feature 2: elapsed_days ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 65 |
+
def elapsed(row):
|
| 66 |
+
start = row.get("actual_start_date") or row.get("planned_start_date")
|
| 67 |
+
if pd.isna(start):
|
| 68 |
+
return 0
|
| 69 |
+
start = pd.Timestamp(start)
|
| 70 |
+
if row["status"] == "completed" and not pd.isna(row.get("actual_end_date")):
|
| 71 |
+
return max(1, (pd.Timestamp(row["actual_end_date"]) - start).days)
|
| 72 |
+
return max(1, (today - start).days)
|
| 73 |
+
|
| 74 |
+
df["elapsed_days"] = df.apply(elapsed, axis=1)
|
| 75 |
+
|
| 76 |
+
# ββ Feature 3: progress_rate (% per day) ββββββββββββββββββββββββββββββββ
|
| 77 |
+
prog = df.get("progress", pd.Series(0, index=df.index))
|
| 78 |
+
df["progress"] = pd.to_numeric(prog, errors="coerce").fillna(0)
|
| 79 |
+
df["progress_rate"] = (df["progress"] / df["elapsed_days"]).clip(0, 20)
|
| 80 |
+
|
| 81 |
+
# ββ Feature 4: schedule_variance (days late at start) βββββββββββββββββββ
|
| 82 |
+
if "schedule_variance_days" in df.columns:
|
| 83 |
+
df["schedule_variance"] = pd.to_numeric(
|
| 84 |
+
df["schedule_variance_days"], errors="coerce").fillna(0)
|
| 85 |
+
else:
|
| 86 |
+
def sch_var(row):
|
| 87 |
+
planned = row.get("planned_start_date")
|
| 88 |
+
actual = row.get("actual_start_date")
|
| 89 |
+
if pd.isna(planned) or pd.isna(actual):
|
| 90 |
+
return 0
|
| 91 |
+
return (pd.Timestamp(actual) - pd.Timestamp(planned)).days
|
| 92 |
+
df["schedule_variance"] = df.apply(sch_var, axis=1)
|
| 93 |
+
|
| 94 |
+
# ββ Feature 5: delay_ratio (actual/planned β for completed) βββββββββββββ
|
| 95 |
+
def delay_ratio(row):
|
| 96 |
+
if "actual_duration_days" in row and not pd.isna(row["actual_duration_days"]):
|
| 97 |
+
pd_dur = max(row["planned_duration"], 1)
|
| 98 |
+
return row["actual_duration_days"] / pd_dur
|
| 99 |
+
return 1.0
|
| 100 |
+
|
| 101 |
+
df["delay_ratio"] = df.apply(delay_ratio, axis=1)
|
| 102 |
+
|
| 103 |
+
# ββ Features 6 & 7: issue_count + issue_severity_score ββββββββββββββββββ
|
| 104 |
+
all_issues = loader.issues
|
| 105 |
+
if not all_issues.empty:
|
| 106 |
+
def issue_stats(activity_id):
|
| 107 |
+
iss = all_issues[all_issues["activity_id"] == activity_id]
|
| 108 |
+
open_iss = iss[iss["status"] == "open"]
|
| 109 |
+
count = len(open_iss)
|
| 110 |
+
score = 0.0
|
| 111 |
+
for _, row in open_iss.iterrows():
|
| 112 |
+
cat_w = ISSUE_SEVERITY_WEIGHTS.get(row.get("category", ""), 1.0)
|
| 113 |
+
sev_m = SEVERITY_MULTIPLIER.get(row.get("severity", "medium"), 1.0)
|
| 114 |
+
score += cat_w * sev_m
|
| 115 |
+
return count, score
|
| 116 |
+
|
| 117 |
+
issue_data = df["id"].apply(lambda aid: pd.Series(
|
| 118 |
+
issue_stats(aid), index=["issue_count", "issue_severity_score"]
|
| 119 |
+
))
|
| 120 |
+
df["issue_count"] = issue_data["issue_count"]
|
| 121 |
+
df["issue_severity_score"] = issue_data["issue_severity_score"]
|
| 122 |
+
else:
|
| 123 |
+
df["issue_count"] = 0
|
| 124 |
+
df["issue_severity_score"] = 0.0
|
| 125 |
+
|
| 126 |
+
# ββ Feature 8: boq_complexity ββββββββββββββββββββββββββββββββββββββββββββ
|
| 127 |
+
all_boq = loader.boq
|
| 128 |
+
if not all_boq.empty:
|
| 129 |
+
def boq_complexity(activity_id):
|
| 130 |
+
b = all_boq[all_boq["activity_id"] == activity_id]
|
| 131 |
+
if b.empty:
|
| 132 |
+
return 0.0
|
| 133 |
+
count_score = len(b)
|
| 134 |
+
if "total_price" in b.columns and "total_cost" in b.columns:
|
| 135 |
+
variance = (b["total_price"] - b["total_cost"]).sum() / max(b["total_cost"].sum(), 1)
|
| 136 |
+
return count_score + variance * 0.1
|
| 137 |
+
return count_score
|
| 138 |
+
|
| 139 |
+
df["boq_complexity"] = df["id"].apply(boq_complexity)
|
| 140 |
+
else:
|
| 141 |
+
df["boq_complexity"] = 0.0
|
| 142 |
+
|
| 143 |
+
# ββ Feature 9: parent_delay (binary) ββββββββββββββββββββββββββββββββββββ
|
| 144 |
+
def parent_delayed(row):
|
| 145 |
+
pred_id = row.get("depends_on")
|
| 146 |
+
if not pred_id or (isinstance(pred_id, float) and np.isnan(pred_id)):
|
| 147 |
+
return 0
|
| 148 |
+
pred_mask = df["id"] == pred_id
|
| 149 |
+
if pred_mask.any():
|
| 150 |
+
pred_row = df[pred_mask].iloc[0]
|
| 151 |
+
return 1 if pred_row.get("schedule_variance", 0) > 2 else 0
|
| 152 |
+
return 0
|
| 153 |
+
|
| 154 |
+
df["parent_delay"] = df.apply(parent_delayed, axis=1)
|
| 155 |
+
|
| 156 |
+
# ββ Feature 10: historical_avg_delay (by category) βββββββββββββββββββββ
|
| 157 |
+
completed_acts = df[df["status"] == "completed"].copy()
|
| 158 |
+
if len(completed_acts) > 0:
|
| 159 |
+
hist_delay = (
|
| 160 |
+
completed_acts.groupby("category")["delay_ratio"]
|
| 161 |
+
.mean()
|
| 162 |
+
.reset_index(name="historical_avg_delay")
|
| 163 |
+
)
|
| 164 |
+
df = df.merge(hist_delay, on="category", how="left")
|
| 165 |
+
df["historical_avg_delay"] = df["historical_avg_delay"].fillna(1.0)
|
| 166 |
+
else:
|
| 167 |
+
df["historical_avg_delay"] = 1.0
|
| 168 |
+
|
| 169 |
+
# ββ Features 11 & 12: progress_velocity_7d + progress_acceleration ββββββ
|
| 170 |
+
all_updates = loader.daily_updates
|
| 171 |
+
if not all_updates.empty:
|
| 172 |
+
all_updates = all_updates.copy()
|
| 173 |
+
all_updates["date"] = pd.to_datetime(all_updates["date"], errors="coerce")
|
| 174 |
+
if "daily_increment" not in all_updates.columns and "reported_progress" in all_updates.columns:
|
| 175 |
+
all_updates = all_updates.sort_values(["activity_id", "date"])
|
| 176 |
+
all_updates["daily_increment"] = (
|
| 177 |
+
all_updates.groupby("activity_id")["reported_progress"].diff().fillna(0)
|
| 178 |
+
)
|
| 179 |
+
|
| 180 |
+
def velocity_and_accel(activity_id):
|
| 181 |
+
upd = all_updates[all_updates["activity_id"] == activity_id].sort_values("date")
|
| 182 |
+
if upd.empty:
|
| 183 |
+
return 0.0, 0.0
|
| 184 |
+
recent = upd.tail(14)
|
| 185 |
+
vel_14 = recent["daily_increment"].mean() if len(recent) > 0 else 0
|
| 186 |
+
vel_7 = upd.tail(7)["daily_increment"].mean() if len(upd) >= 7 else vel_14
|
| 187 |
+
prev_7 = upd.iloc[-14:-7]["daily_increment"].mean() if len(upd) >= 14 else vel_7
|
| 188 |
+
accel = vel_7 - prev_7
|
| 189 |
+
return float(vel_7), float(accel)
|
| 190 |
+
|
| 191 |
+
vel_data = df["id"].apply(lambda aid: pd.Series(
|
| 192 |
+
velocity_and_accel(aid), index=["progress_velocity_7d", "progress_acceleration"]
|
| 193 |
+
))
|
| 194 |
+
df["progress_velocity_7d"] = vel_data["progress_velocity_7d"]
|
| 195 |
+
df["progress_acceleration"] = vel_data["progress_acceleration"]
|
| 196 |
+
else:
|
| 197 |
+
df["progress_velocity_7d"] = df["progress_rate"]
|
| 198 |
+
df["progress_acceleration"] = 0.0
|
| 199 |
+
|
| 200 |
+
return df
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
FEATURE_COLS = [
|
| 204 |
+
"planned_duration", "elapsed_days", "progress_rate", "schedule_variance",
|
| 205 |
+
"delay_ratio", "issue_count", "issue_severity_score", "boq_complexity",
|
| 206 |
+
"parent_delay", "historical_avg_delay", "progress_velocity_7d", "progress_acceleration",
|
| 207 |
+
]
|
| 208 |
+
|
| 209 |
+
TARGET_COL = "delay_ratio"
|
| 210 |
+
|
| 211 |
+
CATEGORY_COLS = ["category", "project_type"]
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def get_ml_ready(df: pd.DataFrame):
|
| 215 |
+
"""
|
| 216 |
+
Returns X (features), y (target) arrays for ML training.
|
| 217 |
+
Only uses completed activities with non-null targets.
|
| 218 |
+
"""
|
| 219 |
+
from sklearn.preprocessing import LabelEncoder
|
| 220 |
+
df = df.copy()
|
| 221 |
+
# Encode categorical columns
|
| 222 |
+
for cat_col in CATEGORY_COLS:
|
| 223 |
+
if cat_col in df.columns:
|
| 224 |
+
le = LabelEncoder()
|
| 225 |
+
df[f"{cat_col}_enc"] = le.fit_transform(df[cat_col].astype(str))
|
| 226 |
+
|
| 227 |
+
feat_cols = FEATURE_COLS + [f"{c}_enc" for c in CATEGORY_COLS if c in df.columns]
|
| 228 |
+
feat_cols = [c for c in feat_cols if c in df.columns]
|
| 229 |
+
|
| 230 |
+
y_col = TARGET_COL
|
| 231 |
+
mask = df[y_col].notna() & df["status"].isin(["completed"])
|
| 232 |
+
return df[mask][feat_cols], df[mask][y_col], feat_cols
|
models/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# models package
|
models/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (163 Bytes). View file
|
|
|
models/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (151 Bytes). View file
|
|
|
models/__pycache__/completion_predictor.cpython-311.pyc
ADDED
|
Binary file (14.4 kB). View file
|
|
|
models/__pycache__/completion_predictor.cpython-312.pyc
ADDED
|
Binary file (13.1 kB). View file
|
|
|
models/__pycache__/monte_carlo.cpython-311.pyc
ADDED
|
Binary file (9.02 kB). View file
|
|
|
models/__pycache__/monte_carlo.cpython-312.pyc
ADDED
|
Binary file (8.21 kB). View file
|
|
|
models/completion_predictor.py
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
models/completion_predictor.py
|
| 3 |
+
-------------------------------
|
| 4 |
+
Three prediction methods for activity completion dates + ensemble.
|
| 5 |
+
|
| 6 |
+
Method A : Earned Value / Linear Extrapolation (baseline)
|
| 7 |
+
Method B : GradientBoostingRegressor delay-multiplier model
|
| 8 |
+
Ensemble : 0.4 Γ A + 0.6 Γ B (calibrated weights)
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import pandas as pd
|
| 12 |
+
import numpy as np
|
| 13 |
+
from datetime import datetime, timedelta
|
| 14 |
+
from typing import Optional, Tuple
|
| 15 |
+
import warnings
|
| 16 |
+
warnings.filterwarnings("ignore")
|
| 17 |
+
|
| 18 |
+
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor
|
| 19 |
+
from sklearn.preprocessing import LabelEncoder
|
| 20 |
+
from sklearn.model_selection import cross_val_score
|
| 21 |
+
from sklearn.metrics import mean_absolute_error
|
| 22 |
+
import joblib
|
| 23 |
+
import os
|
| 24 |
+
|
| 25 |
+
from data_loader import DataLoader
|
| 26 |
+
from features.feature_engineering import engineer_features, get_ml_ready, FEATURE_COLS, CATEGORY_COLS
|
| 27 |
+
|
| 28 |
+
MODEL_PATH = os.path.join(os.path.dirname(__file__), "trained_model.pkl")
|
| 29 |
+
REFERENCE_DATE = datetime(2024, 6, 1)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class CompletionPredictor:
|
| 33 |
+
"""
|
| 34 |
+
Trains and runs the three-method completion date predictor.
|
| 35 |
+
"""
|
| 36 |
+
|
| 37 |
+
def __init__(self, loader: Optional[DataLoader] = None, today: Optional[datetime] = None):
|
| 38 |
+
self.loader = loader or DataLoader()
|
| 39 |
+
self.today = pd.Timestamp(today or REFERENCE_DATE)
|
| 40 |
+
self.model_B = None
|
| 41 |
+
self.feature_cols = None
|
| 42 |
+
self.label_encoders = {}
|
| 43 |
+
self._trained = False
|
| 44 |
+
|
| 45 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 46 |
+
# Training
|
| 47 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 48 |
+
|
| 49 |
+
def train(self, force: bool = False) -> dict:
|
| 50 |
+
"""Train GBR on historical (completed) activities. Returns train metrics."""
|
| 51 |
+
if self._trained and not force:
|
| 52 |
+
return {}
|
| 53 |
+
|
| 54 |
+
hist = self.loader.get_historical_activities()
|
| 55 |
+
if hist.empty:
|
| 56 |
+
print("β οΈ No historical data found for training.")
|
| 57 |
+
return {}
|
| 58 |
+
|
| 59 |
+
# Feature engineering
|
| 60 |
+
feats = engineer_features(hist, self.loader, today=self.today)
|
| 61 |
+
X, y, feat_cols = get_ml_ready(feats)
|
| 62 |
+
|
| 63 |
+
if len(X) < 5:
|
| 64 |
+
print(f"β οΈ Only {len(X)} training examples β skipping training.")
|
| 65 |
+
return {}
|
| 66 |
+
|
| 67 |
+
self.feature_cols = feat_cols
|
| 68 |
+
|
| 69 |
+
# Gradient Boosting (primary Method B model)
|
| 70 |
+
self.model_B = GradientBoostingRegressor(
|
| 71 |
+
n_estimators=200,
|
| 72 |
+
learning_rate=0.05,
|
| 73 |
+
max_depth=4,
|
| 74 |
+
min_samples_split=3,
|
| 75 |
+
subsample=0.8,
|
| 76 |
+
random_state=42,
|
| 77 |
+
)
|
| 78 |
+
self.model_B.fit(X, y)
|
| 79 |
+
|
| 80 |
+
# Cross-val score
|
| 81 |
+
cv_scores = cross_val_score(
|
| 82 |
+
GradientBoostingRegressor(n_estimators=100, random_state=42),
|
| 83 |
+
X, y, cv=min(5, len(X)//2), scoring="neg_mean_absolute_error"
|
| 84 |
+
)
|
| 85 |
+
train_pred = self.model_B.predict(X)
|
| 86 |
+
train_mae = mean_absolute_error(y, train_pred)
|
| 87 |
+
self._trained = True
|
| 88 |
+
|
| 89 |
+
metrics = {
|
| 90 |
+
"n_train": len(X),
|
| 91 |
+
"features": feat_cols,
|
| 92 |
+
"train_mae_multiplier": round(train_mae, 4),
|
| 93 |
+
"cv_mae_mean": round(-cv_scores.mean(), 4),
|
| 94 |
+
"cv_mae_std": round(cv_scores.std(), 4),
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
# Feature importances
|
| 98 |
+
self.feature_importances_ = pd.Series(
|
| 99 |
+
self.model_B.feature_importances_, index=feat_cols
|
| 100 |
+
).sort_values(ascending=False)
|
| 101 |
+
|
| 102 |
+
return metrics
|
| 103 |
+
|
| 104 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 105 |
+
# Method A: Earned Value / Linear Extrapolation
|
| 106 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 107 |
+
|
| 108 |
+
def predict_method_A(self, row: pd.Series) -> Optional[datetime]:
|
| 109 |
+
"""
|
| 110 |
+
remaining_work = 100 - progress
|
| 111 |
+
days_to_complete = remaining_work / progress_rate (with smoothing)
|
| 112 |
+
predicted_end = today + days_to_complete
|
| 113 |
+
"""
|
| 114 |
+
progress = float(row.get("progress", 0))
|
| 115 |
+
if progress >= 100:
|
| 116 |
+
end = row.get("actual_end_date")
|
| 117 |
+
return pd.Timestamp(end) if not pd.isna(end) else self.today
|
| 118 |
+
|
| 119 |
+
start = row.get("actual_start_date") or row.get("planned_start_date")
|
| 120 |
+
if pd.isna(start):
|
| 121 |
+
return None
|
| 122 |
+
start = pd.Timestamp(start)
|
| 123 |
+
|
| 124 |
+
elapsed = max(1, (self.today - start).days)
|
| 125 |
+
progress_rate = progress / elapsed # % per day
|
| 126 |
+
|
| 127 |
+
# Smooth with planned rate
|
| 128 |
+
planned_dur = float(row.get("planned_duration", 30) or 30)
|
| 129 |
+
planned_rate = 100 / planned_dur
|
| 130 |
+
# Weighted smoothing β trust actual more if > 5 days elapsed
|
| 131 |
+
w = min(elapsed / 14, 0.85)
|
| 132 |
+
blended_rate = w * progress_rate + (1 - w) * planned_rate
|
| 133 |
+
blended_rate = max(blended_rate, 0.5) # floor: 0.5% per day
|
| 134 |
+
|
| 135 |
+
remaining = 100 - progress
|
| 136 |
+
days_left = remaining / blended_rate
|
| 137 |
+
return self.today + timedelta(days=round(days_left))
|
| 138 |
+
|
| 139 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 140 |
+
# Method B: GradientBoosting delay-multiplier β predicted end date
|
| 141 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 142 |
+
|
| 143 |
+
def predict_method_B(self, row: pd.Series) -> Optional[datetime]:
|
| 144 |
+
"""
|
| 145 |
+
Uses trained GBR to predict delay_multiplier.
|
| 146 |
+
predicted_end = actual_start + planned_duration Γ predicted_multiplier
|
| 147 |
+
"""
|
| 148 |
+
if not self._trained or self.model_B is None:
|
| 149 |
+
return None
|
| 150 |
+
|
| 151 |
+
# Build feature vector
|
| 152 |
+
X_row = {}
|
| 153 |
+
for col in self.feature_cols:
|
| 154 |
+
X_row[col] = row.get(col, 0)
|
| 155 |
+
|
| 156 |
+
X_df = pd.DataFrame([X_row])
|
| 157 |
+
for col in X_df.columns:
|
| 158 |
+
X_df[col] = pd.to_numeric(X_df[col], errors="coerce").fillna(0)
|
| 159 |
+
|
| 160 |
+
multiplier = float(self.model_B.predict(X_df)[0])
|
| 161 |
+
multiplier = max(0.8, min(multiplier, 5.0)) # clip unreasonable values
|
| 162 |
+
|
| 163 |
+
start = row.get("actual_start_date") or row.get("planned_start_date")
|
| 164 |
+
if pd.isna(start):
|
| 165 |
+
return None
|
| 166 |
+
start = pd.Timestamp(start)
|
| 167 |
+
|
| 168 |
+
planned_dur = float(row.get("planned_duration", 30) or 30)
|
| 169 |
+
# Adjust for already-elapsed progress
|
| 170 |
+
progress = float(row.get("progress", 0))
|
| 171 |
+
remaining_fraction = (100 - progress) / 100
|
| 172 |
+
remaining_days = planned_dur * multiplier * remaining_fraction
|
| 173 |
+
|
| 174 |
+
return self.today + timedelta(days=round(remaining_days))
|
| 175 |
+
|
| 176 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 177 |
+
# Ensemble: A + B
|
| 178 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 179 |
+
|
| 180 |
+
def predict_ensemble(self, row: pd.Series,
|
| 181 |
+
weight_A: float = 0.4, weight_B: float = 0.6) -> Optional[datetime]:
|
| 182 |
+
"""Weighted average of Methods A and B."""
|
| 183 |
+
a = self.predict_method_A(row)
|
| 184 |
+
b = self.predict_method_B(row)
|
| 185 |
+
|
| 186 |
+
if a is None and b is None:
|
| 187 |
+
return None
|
| 188 |
+
if a is None:
|
| 189 |
+
return b
|
| 190 |
+
if b is None:
|
| 191 |
+
return a
|
| 192 |
+
|
| 193 |
+
a_ts = pd.Timestamp(a)
|
| 194 |
+
b_ts = pd.Timestamp(b)
|
| 195 |
+
days_a = (a_ts - self.today).days
|
| 196 |
+
days_b = (b_ts - self.today).days
|
| 197 |
+
blended_days = weight_A * days_a + weight_B * days_b
|
| 198 |
+
return self.today + timedelta(days=max(0, round(blended_days)))
|
| 199 |
+
|
| 200 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 201 |
+
# Predict all active activities
|
| 202 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 203 |
+
|
| 204 |
+
def predict_all(self, project_id: Optional[str] = None) -> pd.DataFrame:
|
| 205 |
+
"""
|
| 206 |
+
Run all 3 predictions on in-progress / not-started activities.
|
| 207 |
+
Returns a DataFrame with one row per activity and prediction columns.
|
| 208 |
+
"""
|
| 209 |
+
if not self._trained:
|
| 210 |
+
self.train()
|
| 211 |
+
|
| 212 |
+
if project_id:
|
| 213 |
+
acts = self.loader.get_project_activities(project_id)
|
| 214 |
+
acts = acts[acts["status"].isin(["in_progress", "not_started"])]
|
| 215 |
+
else:
|
| 216 |
+
acts = self.loader.get_active_activities()
|
| 217 |
+
|
| 218 |
+
if acts.empty:
|
| 219 |
+
return pd.DataFrame()
|
| 220 |
+
|
| 221 |
+
feats = engineer_features(acts, self.loader, today=self.today)
|
| 222 |
+
|
| 223 |
+
results = []
|
| 224 |
+
for _, row in feats.iterrows():
|
| 225 |
+
a_end = self.predict_method_A(row)
|
| 226 |
+
b_end = self.predict_method_B(row) if self._trained else None
|
| 227 |
+
ens_end = self.predict_ensemble(row) if self._trained else a_end
|
| 228 |
+
|
| 229 |
+
delay_mult_pred = None
|
| 230 |
+
if self._trained and self.feature_cols:
|
| 231 |
+
X_row = {col: row.get(col, 0) for col in self.feature_cols}
|
| 232 |
+
X_df = pd.DataFrame([X_row])
|
| 233 |
+
for col in X_df.columns:
|
| 234 |
+
X_df[col] = pd.to_numeric(X_df[col], errors="coerce").fillna(0)
|
| 235 |
+
delay_mult_pred = round(float(self.model_B.predict(X_df)[0]), 3)
|
| 236 |
+
|
| 237 |
+
results.append({
|
| 238 |
+
"activity_id": row["id"],
|
| 239 |
+
"activity_name": row["name"],
|
| 240 |
+
"project_id": row["project_id"],
|
| 241 |
+
"status": row["status"],
|
| 242 |
+
"progress": row.get("progress", 0),
|
| 243 |
+
"planned_end_date": row.get("planned_end_date"),
|
| 244 |
+
"methodA_end": a_end,
|
| 245 |
+
"methodB_end": b_end,
|
| 246 |
+
"ensemble_end": ens_end,
|
| 247 |
+
"delay_multiplier_pred": delay_mult_pred,
|
| 248 |
+
"progress_rate": round(row.get("progress_rate", 0), 3),
|
| 249 |
+
"schedule_variance": row.get("schedule_variance", 0),
|
| 250 |
+
"issue_count": row.get("issue_count", 0),
|
| 251 |
+
"issue_severity_score": round(row.get("issue_severity_score", 0), 2),
|
| 252 |
+
"is_critical": False, # set after CPM computation
|
| 253 |
+
})
|
| 254 |
+
|
| 255 |
+
return pd.DataFrame(results)
|
| 256 |
+
|
| 257 |
+
def save_model(self):
|
| 258 |
+
if self.model_B:
|
| 259 |
+
joblib.dump({"model": self.model_B, "features": self.feature_cols}, MODEL_PATH)
|
| 260 |
+
|
| 261 |
+
def load_model(self):
|
| 262 |
+
if os.path.exists(MODEL_PATH):
|
| 263 |
+
data = joblib.load(MODEL_PATH)
|
| 264 |
+
self.model_B = data["model"]
|
| 265 |
+
self.feature_cols = data["features"]
|
| 266 |
+
self._trained = True
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
if __name__ == "__main__":
|
| 270 |
+
from data_loader import DataLoader
|
| 271 |
+
dl = DataLoader()
|
| 272 |
+
cp = CompletionPredictor(loader=dl)
|
| 273 |
+
metrics = cp.train()
|
| 274 |
+
print("Training metrics:", metrics)
|
| 275 |
+
results = cp.predict_all()
|
| 276 |
+
print(results[["activity_id", "activity_name", "progress", "methodA_end",
|
| 277 |
+
"methodB_end", "ensemble_end"]].to_string())
|
models/monte_carlo.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
models/monte_carlo.py
|
| 3 |
+
----------------------
|
| 4 |
+
Monte Carlo simulation for activity completion dates.
|
| 5 |
+
Samples from fitted distribution of daily progress increments.
|
| 6 |
+
Outputs P50, P80, P90 completion dates and full distributions.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import numpy as np
|
| 11 |
+
from datetime import datetime, timedelta
|
| 12 |
+
from typing import Optional, Dict
|
| 13 |
+
import warnings
|
| 14 |
+
warnings.filterwarnings("ignore")
|
| 15 |
+
|
| 16 |
+
from data_loader import DataLoader
|
| 17 |
+
from features.feature_engineering import engineer_features
|
| 18 |
+
|
| 19 |
+
REFERENCE_DATE = datetime(2024, 6, 1)
|
| 20 |
+
N_SIMULATIONS = 1000
|
| 21 |
+
LOOKBACK_DAYS = 14
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class MonteCarloSimulator:
|
| 25 |
+
"""
|
| 26 |
+
Per-activity Monte Carlo simulation using last-N-day progress increments.
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
def __init__(self, loader: Optional[DataLoader] = None, today: Optional[datetime] = None,
|
| 30 |
+
n_sims: int = N_SIMULATIONS):
|
| 31 |
+
self.loader = loader or DataLoader()
|
| 32 |
+
self.today = pd.Timestamp(today or REFERENCE_DATE)
|
| 33 |
+
self.n_sims = n_sims
|
| 34 |
+
|
| 35 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 36 |
+
# Core simulation for a single activity
|
| 37 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 38 |
+
|
| 39 |
+
def _get_increment_samples(self, activity_id: str) -> np.ndarray:
|
| 40 |
+
"""Get recent daily increments for the activity."""
|
| 41 |
+
upd = self.loader.get_activity_updates(activity_id)
|
| 42 |
+
if upd.empty:
|
| 43 |
+
return np.array([3.0]) # default 3% per day
|
| 44 |
+
|
| 45 |
+
upd = upd.sort_values("date")
|
| 46 |
+
if "daily_increment" in upd.columns:
|
| 47 |
+
increments = pd.to_numeric(upd["daily_increment"], errors="coerce").dropna()
|
| 48 |
+
elif "reported_progress" in upd.columns:
|
| 49 |
+
upd["_inc"] = upd["reported_progress"].diff().fillna(upd["reported_progress"].iloc[0])
|
| 50 |
+
increments = upd["_inc"].clip(lower=0)
|
| 51 |
+
else:
|
| 52 |
+
return np.array([3.0])
|
| 53 |
+
|
| 54 |
+
# Use last LOOKBACK_DAYS
|
| 55 |
+
recent = increments.tail(LOOKBACK_DAYS).values
|
| 56 |
+
recent = recent[recent >= 0]
|
| 57 |
+
return recent if len(recent) > 0 else np.array([3.0])
|
| 58 |
+
|
| 59 |
+
def simulate_activity(self, activity_id: str, current_progress: float,
|
| 60 |
+
max_days: int = 365) -> Dict:
|
| 61 |
+
"""
|
| 62 |
+
Run N Monte Carlo simulations for one activity.
|
| 63 |
+
|
| 64 |
+
Returns
|
| 65 |
+
-------
|
| 66 |
+
dict with:
|
| 67 |
+
- completion_days_samples: array of simulated days-to-complete
|
| 68 |
+
- p50, p80, p90: percentile completion dates
|
| 69 |
+
- mean, std: distribution stats
|
| 70 |
+
"""
|
| 71 |
+
samples = self._get_increment_samples(activity_id)
|
| 72 |
+
|
| 73 |
+
if len(samples) < 2:
|
| 74 |
+
# Use uniform distribution around the mean
|
| 75 |
+
mean_inc = float(samples.mean()) if len(samples) > 0 else 3.0
|
| 76 |
+
samples_for_dist = np.clip(
|
| 77 |
+
np.random.normal(mean_inc, mean_inc * 0.3, 50), 0.1, 15
|
| 78 |
+
)
|
| 79 |
+
else:
|
| 80 |
+
samples_for_dist = samples
|
| 81 |
+
|
| 82 |
+
# Fit distribution parameters (mean + std for truncated normal)
|
| 83 |
+
mu = np.mean(samples_for_dist)
|
| 84 |
+
sigma = max(np.std(samples_for_dist), 0.5)
|
| 85 |
+
|
| 86 |
+
completion_days = []
|
| 87 |
+
remaining = 100.0 - current_progress
|
| 88 |
+
|
| 89 |
+
for _ in range(self.n_sims):
|
| 90 |
+
pct_remaining = remaining
|
| 91 |
+
days = 0
|
| 92 |
+
while pct_remaining > 0 and days < max_days:
|
| 93 |
+
# Sample daily increment from fitted distribution (truncated normal)
|
| 94 |
+
inc = np.random.normal(mu, sigma)
|
| 95 |
+
inc = max(0.1, min(inc, 20)) # clip [0.1, 20]
|
| 96 |
+
pct_remaining -= inc
|
| 97 |
+
days += 1
|
| 98 |
+
completion_days.append(days)
|
| 99 |
+
|
| 100 |
+
completion_days = np.array(completion_days)
|
| 101 |
+
|
| 102 |
+
# Convert to actual dates
|
| 103 |
+
p50_days = int(np.percentile(completion_days, 50))
|
| 104 |
+
p80_days = int(np.percentile(completion_days, 80))
|
| 105 |
+
p90_days = int(np.percentile(completion_days, 90))
|
| 106 |
+
|
| 107 |
+
return {
|
| 108 |
+
"activity_id": activity_id,
|
| 109 |
+
"current_progress": current_progress,
|
| 110 |
+
"n_simulations": self.n_sims,
|
| 111 |
+
"mean_days_to_complete": float(np.mean(completion_days)),
|
| 112 |
+
"std_days_to_complete": float(np.std(completion_days)),
|
| 113 |
+
"p50_days": p50_days,
|
| 114 |
+
"p80_days": p80_days,
|
| 115 |
+
"p90_days": p90_days,
|
| 116 |
+
"p50_date": self.today + timedelta(days=p50_days),
|
| 117 |
+
"p80_date": self.today + timedelta(days=p80_days),
|
| 118 |
+
"p90_date": self.today + timedelta(days=p90_days),
|
| 119 |
+
"completion_days_distribution": completion_days,
|
| 120 |
+
"increment_mean": mu,
|
| 121 |
+
"increment_std": sigma,
|
| 122 |
+
"samples_used": len(samples_for_dist),
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 126 |
+
# Batch simulation for all active activities
|
| 127 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 128 |
+
|
| 129 |
+
def simulate_all(self, project_id: Optional[str] = None) -> pd.DataFrame:
|
| 130 |
+
"""Run Monte Carlo for all in-progress activities."""
|
| 131 |
+
if project_id:
|
| 132 |
+
acts = self.loader.get_project_activities(project_id)
|
| 133 |
+
acts = acts[acts["status"].isin(["in_progress", "not_started"])]
|
| 134 |
+
else:
|
| 135 |
+
acts = self.loader.get_active_activities()
|
| 136 |
+
|
| 137 |
+
if acts.empty:
|
| 138 |
+
return pd.DataFrame()
|
| 139 |
+
|
| 140 |
+
results = []
|
| 141 |
+
for _, row in acts.iterrows():
|
| 142 |
+
progress = float(row.get("progress", 0))
|
| 143 |
+
sim = self.simulate_activity(
|
| 144 |
+
activity_id=str(row["id"]),
|
| 145 |
+
current_progress=progress,
|
| 146 |
+
)
|
| 147 |
+
sim["activity_name"] = row.get("name", "")
|
| 148 |
+
sim["project_id"] = row.get("project_id", "")
|
| 149 |
+
sim["status"] = row.get("status", "")
|
| 150 |
+
sim["planned_end_date"] = row.get("planned_end_date")
|
| 151 |
+
# Drop the full distribution array from the summary table
|
| 152 |
+
sim.pop("completion_days_distribution", None)
|
| 153 |
+
results.append(sim)
|
| 154 |
+
|
| 155 |
+
df = pd.DataFrame(results)
|
| 156 |
+
return df
|
| 157 |
+
|
| 158 |
+
def get_distribution_for_plot(self, activity_id: str, current_progress: float) -> np.ndarray:
|
| 159 |
+
"""Return the raw completion_days array for histogram plotting."""
|
| 160 |
+
sim = self.simulate_activity(activity_id, current_progress)
|
| 161 |
+
return sim["completion_days_distribution"]
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
if __name__ == "__main__":
|
| 165 |
+
from data_loader import DataLoader
|
| 166 |
+
dl = DataLoader()
|
| 167 |
+
mc = MonteCarloSimulator(loader=dl, n_sims=500)
|
| 168 |
+
results = mc.simulate_all(project_id="proj_008")
|
| 169 |
+
print(results[["activity_id", "activity_name", "current_progress",
|
| 170 |
+
"p50_date", "p80_date", "p90_date"]].to_string())
|
optimizer/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# optimizer package
|
optimizer/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (166 Bytes). View file
|
|
|
optimizer/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (154 Bytes). View file
|
|
|
optimizer/__pycache__/schedule_optimizer.cpython-311.pyc
ADDED
|
Binary file (18 kB). View file
|
|
|
optimizer/__pycache__/schedule_optimizer.cpython-312.pyc
ADDED
|
Binary file (15.7 kB). View file
|
|
|
optimizer/schedule_optimizer.py
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
optimizer/schedule_optimizer.py
|
| 3 |
+
---------------------------------
|
| 4 |
+
Critical Path Method (CPM) + rule-based schedule optimization suggestions.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import numpy as np
|
| 9 |
+
import networkx as nx
|
| 10 |
+
from datetime import datetime, timedelta
|
| 11 |
+
from typing import Optional, List, Dict
|
| 12 |
+
from data_loader import DataLoader
|
| 13 |
+
from engine.dag_builder import build_dag, get_topological_order
|
| 14 |
+
|
| 15 |
+
REFERENCE_DATE = datetime(2024, 6, 1)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class ScheduleOptimizer:
|
| 19 |
+
"""
|
| 20 |
+
CPM calculator + rule-based optimization suggestions.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
def __init__(self, project_id: str, loader: Optional[DataLoader] = None,
|
| 24 |
+
today: Optional[datetime] = None):
|
| 25 |
+
self.project_id = project_id
|
| 26 |
+
self.loader = loader or DataLoader()
|
| 27 |
+
self.today = pd.Timestamp(today or REFERENCE_DATE)
|
| 28 |
+
self.G = build_dag(project_id, loader=self.loader)
|
| 29 |
+
self._cpm_results: Optional[pd.DataFrame] = None
|
| 30 |
+
|
| 31 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 32 |
+
# Critical Path Method (CPM)
|
| 33 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 34 |
+
|
| 35 |
+
def compute_cpm(self) -> pd.DataFrame:
|
| 36 |
+
"""
|
| 37 |
+
Compute ES, EF, LS, LF, and Float for every activity.
|
| 38 |
+
Returns a DataFrame with one row per activity + CPM columns.
|
| 39 |
+
"""
|
| 40 |
+
acts = self.loader.get_project_activities(self.project_id)
|
| 41 |
+
if acts.empty:
|
| 42 |
+
return pd.DataFrame()
|
| 43 |
+
|
| 44 |
+
topo = get_topological_order(self.G)
|
| 45 |
+
act_map = {row["id"]: row.to_dict() for _, row in acts.iterrows()}
|
| 46 |
+
|
| 47 |
+
# Duration lookup
|
| 48 |
+
def dur(act_id):
|
| 49 |
+
d = act_map.get(act_id, {}).get("planned_duration_days", 14)
|
| 50 |
+
return max(int(d or 14), 1)
|
| 51 |
+
|
| 52 |
+
# --- Forward pass (Early Start, Early Finish) ---
|
| 53 |
+
ES = {}
|
| 54 |
+
EF = {}
|
| 55 |
+
start_day = 0
|
| 56 |
+
for node in topo:
|
| 57 |
+
preds = list(self.G.predecessors(node))
|
| 58 |
+
if not preds:
|
| 59 |
+
ES[node] = 0
|
| 60 |
+
else:
|
| 61 |
+
ES[node] = max(EF.get(p, 0) for p in preds)
|
| 62 |
+
EF[node] = ES[node] + dur(node)
|
| 63 |
+
|
| 64 |
+
# Project duration = max EF across all leaf nodes
|
| 65 |
+
project_duration = max(EF.values()) if EF else 0
|
| 66 |
+
|
| 67 |
+
# --- Backward pass (Late Start, Late Finish, Float) ---
|
| 68 |
+
LS = {}
|
| 69 |
+
LF = {}
|
| 70 |
+
for node in reversed(topo):
|
| 71 |
+
succs = list(self.G.successors(node))
|
| 72 |
+
if not succs:
|
| 73 |
+
LF[node] = project_duration
|
| 74 |
+
else:
|
| 75 |
+
LF[node] = min(LS.get(s, project_duration) for s in succs)
|
| 76 |
+
LS[node] = LF[node] - dur(node)
|
| 77 |
+
|
| 78 |
+
# Float = LS - ES
|
| 79 |
+
rows = []
|
| 80 |
+
for node in topo:
|
| 81 |
+
if node not in act_map:
|
| 82 |
+
continue
|
| 83 |
+
a = act_map[node]
|
| 84 |
+
float_val = LS.get(node, 0) - ES.get(node, 0)
|
| 85 |
+
is_critical = float_val <= 0
|
| 86 |
+
|
| 87 |
+
rows.append({
|
| 88 |
+
"activity_id": node,
|
| 89 |
+
"activity_name": a.get("name", node),
|
| 90 |
+
"status": a.get("status", "unknown"),
|
| 91 |
+
"planned_duration_days": dur(node),
|
| 92 |
+
"early_start_day": ES.get(node, 0),
|
| 93 |
+
"early_finish_day": EF.get(node, 0),
|
| 94 |
+
"late_start_day": LS.get(node, 0),
|
| 95 |
+
"late_finish_day": LF.get(node, 0),
|
| 96 |
+
"total_float_days": float_val,
|
| 97 |
+
"is_critical_path": is_critical,
|
| 98 |
+
"progress": float(a.get("progress", 0) or 0),
|
| 99 |
+
"schedule_variance_days": int(a.get("schedule_variance_days", 0) or 0),
|
| 100 |
+
"category": a.get("category", ""),
|
| 101 |
+
})
|
| 102 |
+
|
| 103 |
+
self._cpm_results = pd.DataFrame(rows)
|
| 104 |
+
return self._cpm_results
|
| 105 |
+
|
| 106 |
+
def get_critical_path(self) -> List[str]:
|
| 107 |
+
"""Return list of activity IDs on the critical path (float β€ 0)."""
|
| 108 |
+
if self._cpm_results is None:
|
| 109 |
+
self.compute_cpm()
|
| 110 |
+
if self._cpm_results is None or self._cpm_results.empty:
|
| 111 |
+
return []
|
| 112 |
+
return self._cpm_results[self._cpm_results["is_critical_path"]]["activity_id"].tolist()
|
| 113 |
+
|
| 114 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 115 |
+
# Rule-Based Suggestions
|
| 116 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 117 |
+
|
| 118 |
+
def generate_suggestions(self, predictions_df: Optional[pd.DataFrame] = None) -> List[Dict]:
|
| 119 |
+
"""
|
| 120 |
+
Apply 6 rule-based optimization rules and return suggestion cards.
|
| 121 |
+
"""
|
| 122 |
+
if self._cpm_results is None:
|
| 123 |
+
self.compute_cpm()
|
| 124 |
+
|
| 125 |
+
cpm = self._cpm_results
|
| 126 |
+
if cpm is None or cpm.empty:
|
| 127 |
+
return []
|
| 128 |
+
|
| 129 |
+
acts = self.loader.get_project_activities(self.project_id)
|
| 130 |
+
if acts.empty:
|
| 131 |
+
return []
|
| 132 |
+
|
| 133 |
+
all_issues = self.loader.get_activity_issues(project_id=self.project_id)
|
| 134 |
+
if not all_issues.empty and "status" in all_issues.columns:
|
| 135 |
+
open_issues = all_issues[all_issues["status"] == "open"]
|
| 136 |
+
else:
|
| 137 |
+
open_issues = pd.DataFrame()
|
| 138 |
+
|
| 139 |
+
suggestions: List[Dict] = []
|
| 140 |
+
|
| 141 |
+
act_map = {row["id"]: row.to_dict() for _, row in acts.iterrows()}
|
| 142 |
+
cpm_map = {row["activity_id"]: row.to_dict() for _, row in cpm.iterrows()}
|
| 143 |
+
|
| 144 |
+
# Merge predictions if available
|
| 145 |
+
pred_map = {}
|
| 146 |
+
if predictions_df is not None and not predictions_df.empty:
|
| 147 |
+
for _, row in predictions_df.iterrows():
|
| 148 |
+
pred_map[row.get("activity_id", "")] = row.to_dict()
|
| 149 |
+
|
| 150 |
+
downstream_count = {n: len(list(nx.descendants(self.G, n))) for n in self.G.nodes}
|
| 151 |
+
|
| 152 |
+
# Rule 1: Slow critical activity β increase crew
|
| 153 |
+
for _, cpm_row in cpm.iterrows():
|
| 154 |
+
if not cpm_row["is_critical_path"]:
|
| 155 |
+
continue
|
| 156 |
+
act_id = cpm_row["activity_id"]
|
| 157 |
+
act = act_map.get(act_id, {})
|
| 158 |
+
progress = float(act.get("progress", 0) or 0)
|
| 159 |
+
if act.get("status") != "in_progress":
|
| 160 |
+
continue
|
| 161 |
+
elapsed = max(1, (self.today - pd.Timestamp(
|
| 162 |
+
act.get("actual_start_date") or act.get("planned_start_date") or self.today
|
| 163 |
+
)).days)
|
| 164 |
+
actual_rate = progress / elapsed
|
| 165 |
+
planned_dur = max(cpm_row["planned_duration_days"], 1)
|
| 166 |
+
planned_rate = 100 / planned_dur
|
| 167 |
+
if actual_rate < 0.5 * planned_rate:
|
| 168 |
+
suggestions.append({
|
| 169 |
+
"type": "ACTION",
|
| 170 |
+
"priority": "π΄ CRITICAL",
|
| 171 |
+
"activity_id": act_id,
|
| 172 |
+
"activity_name": cpm_row["activity_name"],
|
| 173 |
+
"rule": "Slow Critical Activity",
|
| 174 |
+
"suggestion": (
|
| 175 |
+
f"**{cpm_row['activity_name']}** is on the critical path and running at "
|
| 176 |
+
f"{actual_rate:.1f}%/day vs planned {planned_rate:.1f}%/day. "
|
| 177 |
+
"β **Increase crew size or shift to overtime.**"
|
| 178 |
+
),
|
| 179 |
+
"estimated_savings_days": int(planned_dur * 0.2),
|
| 180 |
+
})
|
| 181 |
+
|
| 182 |
+
# Rule 2: High schedule variance + many downstream β escalate
|
| 183 |
+
for _, cpm_row in cpm.iterrows():
|
| 184 |
+
act_id = cpm_row["activity_id"]
|
| 185 |
+
act = act_map.get(act_id, {})
|
| 186 |
+
var = int(act.get("schedule_variance_days", 0) or 0)
|
| 187 |
+
down = downstream_count.get(act_id, 0)
|
| 188 |
+
if var > 5 and down > 3:
|
| 189 |
+
suggestions.append({
|
| 190 |
+
"type": "ALERT",
|
| 191 |
+
"priority": "π΄ HIGH",
|
| 192 |
+
"activity_id": act_id,
|
| 193 |
+
"activity_name": cpm_row["activity_name"],
|
| 194 |
+
"rule": "High Impact Delay",
|
| 195 |
+
"suggestion": (
|
| 196 |
+
f"**{cpm_row['activity_name']}** is {var} days late and has "
|
| 197 |
+
f"{down} downstream activities. "
|
| 198 |
+
"β **Escalate immediately β cascading delay risk.**"
|
| 199 |
+
),
|
| 200 |
+
"estimated_savings_days": 0,
|
| 201 |
+
})
|
| 202 |
+
|
| 203 |
+
# Rule 3: Material delay issue on upcoming activity β pre-order
|
| 204 |
+
for _, cpm_row in cpm.iterrows():
|
| 205 |
+
act_id = cpm_row["activity_id"]
|
| 206 |
+
if act_map.get(act_id, {}).get("status") == "not_started":
|
| 207 |
+
act_issues = open_issues[open_issues["activity_id"] == act_id] if not open_issues.empty else pd.DataFrame()
|
| 208 |
+
material_issues = act_issues[act_issues.get("category", pd.Series()) == "material_delay"] if not act_issues.empty else pd.DataFrame()
|
| 209 |
+
if not material_issues.empty:
|
| 210 |
+
suggestions.append({
|
| 211 |
+
"type": "PREVENTIVE",
|
| 212 |
+
"priority": "π‘ MEDIUM",
|
| 213 |
+
"activity_id": act_id,
|
| 214 |
+
"activity_name": cpm_row["activity_name"],
|
| 215 |
+
"rule": "Material Delay Risk",
|
| 216 |
+
"suggestion": (
|
| 217 |
+
f"**{cpm_row['activity_name']}** (not started) has open material delay issues. "
|
| 218 |
+
"β **Pre-order materials now to avoid blocking this activity.**"
|
| 219 |
+
),
|
| 220 |
+
"estimated_savings_days": 3,
|
| 221 |
+
})
|
| 222 |
+
|
| 223 |
+
# Rule 4: Two non-dependent activities β suggest parallel
|
| 224 |
+
nodes = list(self.G.nodes)
|
| 225 |
+
for i, a1 in enumerate(nodes):
|
| 226 |
+
for a2 in nodes[i + 1:]:
|
| 227 |
+
if (not self.G.has_edge(a1, a2) and not self.G.has_edge(a2, a1)
|
| 228 |
+
and not nx.has_path(self.G, a1, a2)
|
| 229 |
+
and not nx.has_path(self.G, a2, a1)):
|
| 230 |
+
a1_stat = act_map.get(a1, {}).get("status")
|
| 231 |
+
a2_stat = act_map.get(a2, {}).get("status")
|
| 232 |
+
if a1_stat == "not_started" and a2_stat == "not_started":
|
| 233 |
+
a1_name = cpm_map.get(a1, {}).get("activity_name", a1)
|
| 234 |
+
a2_name = cpm_map.get(a2, {}).get("activity_name", a2)
|
| 235 |
+
dur_saved = min(
|
| 236 |
+
cpm_map.get(a1, {}).get("planned_duration_days", 10),
|
| 237 |
+
cpm_map.get(a2, {}).get("planned_duration_days", 10),
|
| 238 |
+
)
|
| 239 |
+
suggestions.append({
|
| 240 |
+
"type": "OPTIMIZATION",
|
| 241 |
+
"priority": "π’ OPPORTUNITY",
|
| 242 |
+
"activity_id": f"{a1}+{a2}",
|
| 243 |
+
"activity_name": f"{a1_name} + {a2_name}",
|
| 244 |
+
"rule": "Parallelization Opportunity",
|
| 245 |
+
"suggestion": (
|
| 246 |
+
f"**{a1_name}** and **{a2_name}** have no dependencies. "
|
| 247 |
+
f"β **Run in parallel β potential savings: ~{dur_saved} days.**"
|
| 248 |
+
),
|
| 249 |
+
"estimated_savings_days": dur_saved,
|
| 250 |
+
})
|
| 251 |
+
break # Only one parallelization suggestion per node
|
| 252 |
+
|
| 253 |
+
# Rule 5: Stalled activity (0 progress for 3+ consecutive days)
|
| 254 |
+
all_updates = self.loader.daily_updates
|
| 255 |
+
if not all_updates.empty:
|
| 256 |
+
all_updates = all_updates.copy()
|
| 257 |
+
all_updates["date"] = pd.to_datetime(all_updates["date"], errors="coerce")
|
| 258 |
+
for _, act_row in acts.iterrows():
|
| 259 |
+
if act_row.get("status") != "in_progress":
|
| 260 |
+
continue
|
| 261 |
+
act_id = str(act_row["id"])
|
| 262 |
+
upd = all_updates[all_updates["activity_id"] == act_id].sort_values("date")
|
| 263 |
+
if len(upd) >= 3:
|
| 264 |
+
inc_col = "daily_increment" if "daily_increment" in upd.columns else None
|
| 265 |
+
if inc_col:
|
| 266 |
+
last3 = upd.tail(3)[inc_col].astype(float)
|
| 267 |
+
if (last3 <= 0.1).all():
|
| 268 |
+
a_name = act_row.get("name", act_id)
|
| 269 |
+
suggestions.append({
|
| 270 |
+
"type": "ALERT",
|
| 271 |
+
"priority": "π΄ HIGH",
|
| 272 |
+
"activity_id": act_id,
|
| 273 |
+
"activity_name": a_name,
|
| 274 |
+
"rule": "Stalled Activity",
|
| 275 |
+
"suggestion": (
|
| 276 |
+
f"**{a_name}** has shown zero progress for 3+ days. "
|
| 277 |
+
"β **Investigate immediately β possible blockage.**"
|
| 278 |
+
),
|
| 279 |
+
"estimated_savings_days": 0,
|
| 280 |
+
})
|
| 281 |
+
|
| 282 |
+
# Rule 6: Activity ahead of schedule β reallocate resources
|
| 283 |
+
for _, cpm_row in cpm.iterrows():
|
| 284 |
+
if cpm_row["total_float_days"] > 10 and cpm_row["is_critical_path"] is False:
|
| 285 |
+
act_id = cpm_row["activity_id"]
|
| 286 |
+
act = act_map.get(act_id, {})
|
| 287 |
+
if act.get("status") == "in_progress":
|
| 288 |
+
suggestions.append({
|
| 289 |
+
"type": "OPTIMIZATION",
|
| 290 |
+
"priority": "π’ OPPORTUNITY",
|
| 291 |
+
"activity_id": act_id,
|
| 292 |
+
"activity_name": cpm_row["activity_name"],
|
| 293 |
+
"rule": "Resource Reallocation",
|
| 294 |
+
"suggestion": (
|
| 295 |
+
f"**{cpm_row['activity_name']}** has {cpm_row['total_float_days']} days of float. "
|
| 296 |
+
"β **Consider reallocating some resources to critical path activities.**"
|
| 297 |
+
),
|
| 298 |
+
"estimated_savings_days": 2,
|
| 299 |
+
})
|
| 300 |
+
|
| 301 |
+
# De-duplicate by activity_id + rule
|
| 302 |
+
seen = set()
|
| 303 |
+
unique_suggestions = []
|
| 304 |
+
for s in suggestions:
|
| 305 |
+
key = (s["activity_id"], s["rule"])
|
| 306 |
+
if key not in seen:
|
| 307 |
+
seen.add(key)
|
| 308 |
+
unique_suggestions.append(s)
|
| 309 |
+
|
| 310 |
+
# Sort: CRITICAL first, then HIGH, then others
|
| 311 |
+
priority_order = {"π΄ CRITICAL": 0, "π΄ HIGH": 1, "π‘ MEDIUM": 2, "π’ OPPORTUNITY": 3}
|
| 312 |
+
unique_suggestions.sort(key=lambda x: priority_order.get(x["priority"], 9))
|
| 313 |
+
|
| 314 |
+
return unique_suggestions[:15] # cap at 15
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
if __name__ == "__main__":
|
| 318 |
+
from data_loader import DataLoader
|
| 319 |
+
dl = DataLoader()
|
| 320 |
+
opt = ScheduleOptimizer("proj_008", loader=dl)
|
| 321 |
+
cpm = opt.compute_cpm()
|
| 322 |
+
print("CPM Results:")
|
| 323 |
+
print(cpm[["activity_name", "total_float_days", "is_critical_path"]].to_string())
|
| 324 |
+
print("\nSuggestions:")
|
| 325 |
+
for s in opt.generate_suggestions():
|
| 326 |
+
print(f"[{s['priority']}] {s['activity_name']}: {s['suggestion'][:80]}...")
|
requirements.txt
CHANGED
|
@@ -1,3 +1,10 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
pandas>=1.5.0
|
| 2 |
+
numpy>=1.23.0
|
| 3 |
+
scikit-learn>=1.1.0
|
| 4 |
+
scipy>=1.9.0
|
| 5 |
+
networkx>=2.8.0
|
| 6 |
+
plotly>=5.11.0
|
| 7 |
+
matplotlib>=3.6.0
|
| 8 |
+
sqlalchemy>=1.4.0
|
| 9 |
+
streamlit>=1.20.0
|
| 10 |
+
joblib>=1.2.0
|