suvradeepp commited on
Commit
03e7fda
Β·
verified Β·
1 Parent(s): d4fed95

Upload 63 files

Browse files
This view is limited to 50 files because it contains too many changes. Β  See raw diff
Files changed (50) hide show
  1. .gitattributes +8 -0
  2. .gitignore +4 -0
  3. README.md +857 -20
  4. __pycache__/app.cpython-311.pyc +0 -0
  5. __pycache__/data_loader.cpython-311.pyc +0 -0
  6. __pycache__/data_loader.cpython-312.pyc +0 -0
  7. app.py +634 -0
  8. data/activities.csv +151 -0
  9. data/boq.csv +541 -0
  10. data/daily_updates.csv +0 -0
  11. data/data.db +3 -0
  12. data/issues.csv +396 -0
  13. data/projects.csv +11 -0
  14. data/resources.csv +256 -0
  15. data_loader.py +207 -0
  16. dataset.py +439 -0
  17. engine/__init__.py +1 -0
  18. engine/__pycache__/__init__.cpython-311.pyc +0 -0
  19. engine/__pycache__/__init__.cpython-312.pyc +0 -0
  20. engine/__pycache__/dag_builder.cpython-311.pyc +0 -0
  21. engine/__pycache__/dag_builder.cpython-312.pyc +0 -0
  22. engine/__pycache__/ripple_engine.cpython-311.pyc +0 -0
  23. engine/__pycache__/ripple_engine.cpython-312.pyc +0 -0
  24. engine/__pycache__/whatif_scenarios.cpython-311.pyc +0 -0
  25. engine/__pycache__/whatif_scenarios.cpython-312.pyc +0 -0
  26. engine/dag_builder.py +87 -0
  27. engine/ripple_engine.py +195 -0
  28. engine/whatif_scenarios.py +204 -0
  29. features/__init__.py +1 -0
  30. features/__pycache__/__init__.cpython-311.pyc +0 -0
  31. features/__pycache__/__init__.cpython-312.pyc +0 -0
  32. features/__pycache__/feature_engineering.cpython-311.pyc +0 -0
  33. features/__pycache__/feature_engineering.cpython-312.pyc +0 -0
  34. features/feature_engineering.py +232 -0
  35. models/__init__.py +1 -0
  36. models/__pycache__/__init__.cpython-311.pyc +0 -0
  37. models/__pycache__/__init__.cpython-312.pyc +0 -0
  38. models/__pycache__/completion_predictor.cpython-311.pyc +0 -0
  39. models/__pycache__/completion_predictor.cpython-312.pyc +0 -0
  40. models/__pycache__/monte_carlo.cpython-311.pyc +0 -0
  41. models/__pycache__/monte_carlo.cpython-312.pyc +0 -0
  42. models/completion_predictor.py +277 -0
  43. models/monte_carlo.py +170 -0
  44. optimizer/__init__.py +1 -0
  45. optimizer/__pycache__/__init__.cpython-311.pyc +0 -0
  46. optimizer/__pycache__/__init__.cpython-312.pyc +0 -0
  47. optimizer/__pycache__/schedule_optimizer.cpython-311.pyc +0 -0
  48. optimizer/__pycache__/schedule_optimizer.cpython-312.pyc +0 -0
  49. optimizer/schedule_optimizer.py +326 -0
  50. 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
- title: Dynamic What If Scheduling
3
- emoji: πŸš€
4
- colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
- pinned: false
11
- short_description: Streamlit template space
12
- license: mit
13
- ---
14
-
15
- # Welcome to Streamlit!
16
-
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
-
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ![Overview](screenshots/overview.png)
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
+ ![Gantt Chart](screenshots/gantt.png)
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
+ ![Predictions](screenshots/predictions.png)
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
+ ![Ripple Analysis](screenshots/ripple.png)
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
+ ![What-if Scenarios](screenshots/whatif.png)
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
+ ![Optimization](screenshots/optimization.png)
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
+ ![DAG View](screenshots/dag.png)
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
- altair
2
- pandas
3
- streamlit
 
 
 
 
 
 
 
 
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