diff --git a/activity.log b/activity.log index 5c1da1c..97c0f12 100644 --- a/activity.log +++ b/activity.log @@ -4506,6 +4506,7 @@ Timestamp: 2025-10-04 17:27:24 | User: Unknown | Action: Search contractor | Det Timestamp: 2025-10-04 17:27:24 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'a' Timestamp: 2025-10-04 17:27:24 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aad' Timestamp: 2025-10-04 17:27:25 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aad' +<<<<<<< HEAD Timestamp: 2025-10-06 13:03:06 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'd' Timestamp: 2025-10-06 13:03:06 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'da' Timestamp: 2025-10-06 13:03:06 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'day' @@ -4970,3 +4971,514 @@ Timestamp: 2025-11-15 18:42:49 | User: Unknown | Action: Check Block | Details: Timestamp: 2025-11-15 18:42:50 | User: Unknown | Action: Check Block | Details: Timestamp: 2025-11-15 18:42:52 | User: Unknown | Action: Check Block | Details: Timestamp: 2025-11-15 18:42:55 | User: Unknown | Action: Add Block | Details: +======= +Timestamp: 2025-10-31 11:24:34 | User: Unknown | Action: Login | Details: User admin logged in (static user) +Timestamp: 2025-10-31 11:25:19 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'a' +Timestamp: 2025-10-31 11:25:19 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aj' +Timestamp: 2025-10-31 11:25:19 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aja' +Timestamp: 2025-10-31 11:25:19 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'ajay' +Timestamp: 2025-10-31 11:25:21 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'ajay' +Timestamp: 2025-10-31 11:26:31 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 11:26:52 | User: Unknown | Action: Check State | Details: User admin Checked state 'U' +Timestamp: 2025-10-31 11:26:54 | User: Unknown | Action: Check State | Details: User admin Checked state 'Uttar Pradesh' +Timestamp: 2025-10-31 11:26:55 | User: Unknown | Action: Add State | Details: User admin added state 'Uttar Pradesh' +Timestamp: 2025-10-31 11:27:04 | User: Unknown | Action: Check District | Details: User admin Checked District 'Shamli' +Timestamp: 2025-10-31 11:27:04 | User: Unknown | Action: Check District | Details: User admin Checked District 'Shamli' +Timestamp: 2025-10-31 11:27:05 | User: Unknown | Action: Add District | Details: User admin Added District 'Shamli' +Timestamp: 2025-10-31 11:27:12 | User: Unknown | Action: Get District | Details: User admin Get District '5' +Timestamp: 2025-10-31 11:27:15 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Shamli' +Timestamp: 2025-10-31 11:27:15 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Shamli' +Timestamp: 2025-10-31 11:27:16 | User: Unknown | Action: Add Block | Details: User admin Added block 'Shamli' +Timestamp: 2025-10-31 11:27:37 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 11:27:41 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 11:27:41 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 11:27:41 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 11:27:41 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:33 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 12:00:38 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:38 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:38 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:38 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:38 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:38 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:38 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:00:54 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 12:00:56 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 12:05:17 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'a' +Timestamp: 2025-10-31 12:05:17 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aa' +Timestamp: 2025-10-31 12:05:17 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aar' +Timestamp: 2025-10-31 12:05:21 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aarh' +Timestamp: 2025-10-31 12:05:23 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aarh' +Timestamp: 2025-10-31 13:35:19 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 13:35:23 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:35:23 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:35:23 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:35:23 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:35:23 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:35:23 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:35:23 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:37:19 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 13:37:25 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:37:25 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:37:25 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:37:25 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:37:25 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:37:25 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 13:37:25 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:52:13 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 14:52:35 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 14:52:46 | User: Unknown | Action: Check State | Details: User admin Checked state 'm' +Timestamp: 2025-10-31 14:52:48 | User: Unknown | Action: Check State | Details: User admin Checked state 'Madhya Pradesh' +Timestamp: 2025-10-31 14:52:50 | User: Unknown | Action: Add State | Details: User admin added state 'Madhya Pradesh' +Timestamp: 2025-10-31 14:52:58 | User: Unknown | Action: Check District | Details: User admin Checked District 'Chhindawara' +Timestamp: 2025-10-31 14:52:58 | User: Unknown | Action: Check District | Details: User admin Checked District 'Chhindawara' +Timestamp: 2025-10-31 14:52:58 | User: Unknown | Action: Add District | Details: User admin Added District 'Chhindawara' +Timestamp: 2025-10-31 14:53:06 | User: Unknown | Action: Get District | Details: User admin Get District '7' +Timestamp: 2025-10-31 14:53:09 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Chhindawara' +Timestamp: 2025-10-31 14:53:09 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Chhindawara' +Timestamp: 2025-10-31 14:53:09 | User: Unknown | Action: Add Block | Details: User admin Added block 'Chhindawara' +Timestamp: 2025-10-31 14:53:25 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 14:53:38 | User: Unknown | Action: Check District | Details: User admin Checked District 'Chhindawara' +Timestamp: 2025-10-31 14:53:38 | User: Unknown | Action: Check District | Details: User admin Checked District 'Chhindawara' +Timestamp: 2025-10-31 14:53:43 | User: Unknown | Action: Check District | Details: User admin Checked District 'Chindawara' +Timestamp: 2025-10-31 14:53:44 | User: Unknown | Action: Check District | Details: User admin Checked District 'Chindawara' +Timestamp: 2025-10-31 14:53:45 | User: Unknown | Action: Add District | Details: User admin Added District 'Chindawara' +Timestamp: 2025-10-31 14:53:51 | User: Unknown | Action: Get District | Details: User admin Get District '7' +Timestamp: 2025-10-31 14:53:54 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Chhindawara' +Timestamp: 2025-10-31 14:53:54 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Chhindawara' +Timestamp: 2025-10-31 14:53:56 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Chindawara' +Timestamp: 2025-10-31 14:53:56 | User: Unknown | Action: Check Block | Details: User admin Checked block 'Chindawara' +Timestamp: 2025-10-31 14:53:57 | User: Unknown | Action: Add Block | Details: User admin Added block 'Chindawara' +Timestamp: 2025-10-31 14:54:07 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 14:54:11 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:54:11 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:54:11 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:54:11 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:54:11 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:54:18 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'b' +Timestamp: 2025-10-31 14:54:18 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'bg' +Timestamp: 2025-10-31 14:54:20 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'bg' +Timestamp: 2025-10-31 14:57:08 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 14:57:25 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:35 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:36 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:37 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 14:57:52 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'j' +Timestamp: 2025-10-31 14:57:52 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'ja' +Timestamp: 2025-10-31 14:57:54 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'ja' +Timestamp: 2025-10-31 16:17:29 | User: Unknown | Action: Upload Excel File | Details: User adminUpload Excel File'' +Timestamp: 2025-10-31 16:17:32 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 16:17:32 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 16:17:32 | User: Unknown | Action: Data saved | Details: User admin Data saved'None' +Timestamp: 2025-10-31 16:17:41 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'a' +Timestamp: 2025-10-31 16:17:41 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aj' +Timestamp: 2025-10-31 16:17:44 | User: Unknown | Action: Search contractor | Details: User admin Search contractor'aj' +Timestamp: 2025-11-03 11:03:32 | User: admin | Action: Logout | Details: User admin logged out +Timestamp: 2025-11-03 11:03:39 | User: admin | Action: Login | Details: Static admin logged in: admin +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 diff --git a/config.py b/config.py index 5d13397..3543388 100644 --- a/config.py +++ b/config.py @@ -5,7 +5,11 @@ import os # Get MySQL credentials from environment variables MYSQL_HOST = os.getenv("MYSQL_HOST", "127.0.0.1") MYSQL_USER = os.getenv("MYSQL_USER", "root") +<<<<<<< HEAD MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "root") +======= +MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "tiger") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 MYSQL_DB = os.getenv("MYSQL_DB", "test") # Connect to MySQL diff --git a/main.py b/main.py index 994beb5..13cb8c5 100644 --- a/main.py +++ b/main.py @@ -35,9 +35,49 @@ from openpyxl.utils import get_column_letter import logging import pandas as pd +<<<<<<< HEAD #import AppRoutes.StateRoute +======= +from openpyxl.styles import Font +from flask import Flask, render_template, request, redirect, url_for, flash, session +from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user +from ldap3 import Server, Connection, ALL +import logging +from logging.handlers import RotatingFileHandler +from flask import Flask, request, render_template +from ldap3 import Server, Connection, ALL, SUBTREE + + + + +from flask import request, session +0 +def log_action(action, details=""): + """Log user actions with timestamp, user, action, and details.""" + log_file = os.path.join(current_app.root_path, 'activity.log') + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # Prefer LDAP common name (cn), fallback to username, else Unknown + if hasattr(current_user, "cn") and current_user.cn: + user = current_user.cn + elif hasattr(current_user, "username") and current_user.username: + user = current_user.username + elif hasattr(current_user, "sAMAccountName") and current_user.sAMAccountName: + user = current_user.sAMAccountName + else: + user = "Unknown" + + with open(log_file, "a", encoding="utf-8") as f: + f.write( + f"Timestamp: {timestamp} | " + f"User: {user} | " + f"Action: {action} | " + f"Details: {details}\n" + ) + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # this is server @@ -46,11 +86,20 @@ login_manager = LoginManager() login_manager.init_app(app) login_manager.login_view = 'login' +<<<<<<< HEAD +======= +class User(UserMixin): + def __init__(self, id): + self.id = id +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @login_manager.user_loader def load_user(user_id): return User(user_id) +<<<<<<< HEAD #need to check and understand above function +======= +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 app.secret_key = '9f2a1b8c4d6e7f0123456789abcdef01' #Shouldnt be hardcoded @@ -65,6 +114,43 @@ def index(): return render_template('index.html') +<<<<<<< HEAD +======= +from ldap3 import Server, Connection, ALL +from ldap3.core.exceptions import LDAPBindError + + +# ---------------- LDAP SEARCH ---------------- +@app.route('/ldap_search', methods=['GET', 'POST']) +def ldap_search(): + results = [] + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + ldap_user_dn = f"uid={username},ou=users,dc=lcepl,dc=org" + + try: + # Connect to OpenLDAP using Docker service name + server = Server('openldap', port=389, get_info=ALL) + conn = Connection(server, user=ldap_user_dn, password=password, auto_bind=True) + + # Search for the user + conn.search( + 'dc=lcepl,dc=org', + f'(uid={username})', + search_scope=SUBTREE, + attributes=['cn', 'uid', 'mail'] + ) + + results = conn.entries + conn.unbind() + except LDAPBindError: + flash('Invalid LDAP credentials.', 'danger') + except Exception as e: + flash(f'LDAP error: {str(e)}', 'danger') + + return render_template('ldap_search.html', results=results) +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @@ -73,6 +159,7 @@ def index(): @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': +<<<<<<< HEAD loginData = LoginLDAP(request) # If bind successful → set session and log @@ -87,6 +174,39 @@ def login(): return redirect(url_for('index', login='success')) else: flash(loginData.errorMessage, 'danger') +======= + username = request.form['username'].strip() + password = request.form['password'] + + # Static fallback user + if username == 'admin' and password == 'admin123': + session['username'] = username + log_action('Login', f"User {username} logged in (static user)") + login_user(User(username)) + return redirect(url_for('index', login='success')) + + ldap_user_dn = f"uid={username},ou=users,dc=lcepl,dc=org" + + try: + # LDAP authentication + conn = Connection( + Server('ldap://localhost:389', get_info=ALL), + user=ldap_user_dn, + password=password, + auto_bind=True + ) + + # If bind successful → set session and log + session['username'] = username + log_action('Login', f"User {username} logged in (LDAP)") + login_user(User(username)) + return redirect(url_for('index', login='success')) + + except LDAPBindError: + flash('Invalid credentials.', 'danger') + except Exception as e: + flash(f'LDAP error: {str(e)}', 'danger') +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return render_template('login.html') @@ -96,11 +216,16 @@ def login(): @app.route('/logout') @login_required def logout(): +<<<<<<< HEAD LogHelper.log_action('Logout', f"User {current_user.id} logged out") # log the event +======= + log_action('Logout', f"User {current_user.id} logged out") # log the event +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 logout_user() flash('You have been logged out.', 'info') return redirect(url_for('login')) +<<<<<<< HEAD @@ -116,26 +241,140 @@ def activity_log(): logData = LogData() filtered_logs = logData.GetFilteredActivitiesLog(start_date,end_date,user_name) +======= +import os +from datetime import datetime +from flask import current_app +from flask_login import current_user + + + +import os +from flask import request, render_template, current_app +from datetime import datetime +from flask_login import login_required +from dateutil import parser # pip install python-dateutil + +@app.route('/activity_log', methods=['GET', 'POST']) +@login_required +def activity_log(): + logs = [] + log_file = os.path.join(current_app.root_path, 'activity.log') + + if os.path.exists(log_file): + with open(log_file, 'r') as f: + for line in f: + parts = line.strip().split(" | ") + if len(parts) == 4: + logs.append({ + "timestamp": parts[0].replace("Timestamp:", "").strip(), + "user": parts[1].replace("User:", "").strip(), + "action": parts[2].replace("Action:", "").strip(), + "details": parts[3].replace("Details:", "").strip() + }) + + # Filters (GET or POST) + start_date = request.values.get("start_date") + end_date = request.values.get("end_date") + username = request.values.get("username") + + filtered_logs = logs + + # Date filter + if start_date or end_date: + try: + start_dt = datetime.strptime(start_date, "%Y-%m-%d") if start_date else datetime.min + end_dt = datetime.strptime(end_date, "%Y-%m-%d") if end_date else datetime.max + end_dt = end_dt.replace(hour=23, minute=59, second=59) + + filtered_logs = [ + log for log in filtered_logs + if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt + ] + except Exception as e: + print("Date filter error:", e) + + # Username filter + if username: + filtered_logs = [log for log in filtered_logs if username.lower() in log["user"].lower()] + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return render_template( "activity_log.html", logs=filtered_logs, start_date=start_date, end_date=end_date, +<<<<<<< HEAD username=user_name ) +======= + username=username + ) + + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # ------------------------- State controller ------------------------------------------ @app.route('/add_state', methods=['GET', 'POST']) @login_required def add_state(): +<<<<<<< HEAD state = State() if request.method == 'POST': state.AddState(request=request) return state.resultMessage statedata = state.GetAllStates(request=request) +======= + connection = config.get_db_connection() + statedata = [] + + if connection: + cursor = connection.cursor() + if request.method == 'POST': + state_name = request.form['state_Name'].strip() + log_action("Add State", f"User {current_user.id} added state '{state_name}'") + + if not re.match(str_pattern_reg, state_name): + return json_response(ResponseHandler.invalid_name("state"), 400) + + try: + # cursor.execute("SELECT * FROM states WHERE State_Name = %s", (state_name,)) + # if cursor.fetchone(): + # return json_response(ResponseHandler.already_exists("state"), 409) + + cursor.callproc("CheckStateExists", (state_name,)) + for data in cursor.stored_results(): + existing_state = data.fetchone() + + if existing_state: + return json_response(ResponseHandler.already_exists("state"), 409) + + # cursor.execute("call SaveState (%s)", (state_name,)) + cursor.callproc("SaveState", (state_name,)) + connection.commit() + return json_response(ResponseHandler.add_success("state"), 200) + + except mysql.connector.Error as e: + print(f"Error inserting state: {e}") + return json_response(ResponseHandler.add_failure("state"), 500) + + try: + # cursor.execute("SELECT State_ID, State_Name FROM states") + # statedata = cursor.fetchall() + cursor.callproc("GetAllStates") + for res in cursor.stored_results(): + statedata = res.fetchall() + except mysql.connector.Error as e: + print(f"Error fetching states: {e}") + return ResponseHandler.fetch_failure("states"), 500 + finally: + cursor.close() + connection.close() + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return render_template('add_state.html', statedata=statedata) @@ -144,14 +383,47 @@ def add_state(): @app.route('/check_state', methods=['POST']) @login_required def check_state(): +<<<<<<< HEAD state = State() return state.CheckState(request=request) +======= + connection = config.get_db_connection() + + if connection: + cursor = connection.cursor() + state_name = request.json.get('state_Name', '').strip() + log_action("Check State", f"User {current_user.id} Checked state '{state_name}'") + if not re.match(str_pattern_reg, state_name): + return json_response(ResponseHandler.invalid_name("state"), 400) + + try: + # cursor.execute("SELECT * FROM states WHERE State_Name = %s", (state_name,)) + # existing_state = cursor.fetchone() + + cursor.callproc("CheckStateExists", (state_name,)) + for data in cursor.stored_results(): + existing_state = data.fetchone() + + if existing_state: + return json_response(ResponseHandler.already_exists("state"), 409) + else: + return json_response(ResponseHandler.is_available("state"), 200) + + except mysql.connector.Error as e: + print(f"Error checking state: {e}") + return json_response(ResponseHandler.add_failure("state"), 500) + finally: + cursor.close() + connection.close() + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # Delete State @app.route('/delete_state/', methods=['GET']) @login_required def deleteState(id): +<<<<<<< HEAD state = State() msg = state.DeleteState(request=request, id=id) @@ -159,6 +431,27 @@ def deleteState(id): return state.resultMessage else: return redirect(url_for('add_state')) +======= + connection = config.get_db_connection() + cursor = connection.cursor() + log_action("Delete State", f"User {current_user.id} Deleted state '{id}'") + try: + # cursor.execute("DELETE FROM states WHERE State_ID = %s", (id,)) + cursor.callproc('DeleteState', (id,)) + connection.commit() + # For API response + # return json_response(ResponseHandler.delete_success("state"), 200) + + except mysql.connector.Error as e: + print(f"Error deleting data: {e}") + return json_response(ResponseHandler.delete_failure("state"), 500) + + finally: + cursor.close() + connection.close() + + return redirect(url_for('add_state')) +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # Edit State @@ -172,6 +465,7 @@ def editState(id): statedata = [] if request.method == 'POST': +<<<<<<< HEAD state.EditState(request=request, id=id) if state.isSuccess: return redirect(url_for('add_state')) @@ -186,6 +480,12 @@ def editState(id): if statedata is None: statedata = [] +======= + state_name = request.form['state_Name'].strip() + log_action("Edit State", f"User {current_user.id} Edited state '{state_name}'") + if not re.match(str_pattern_reg, state_name): + return ResponseHandler.invalid_name("state"), 400 +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return render_template('edit_state.html', state=statedata) @@ -196,6 +496,7 @@ def editState(id): @app.route('/add_district', methods=['GET', 'POST']) @login_required def add_district(): +<<<<<<< HEAD district = District() if request.method == 'POST': @@ -206,6 +507,64 @@ def add_district(): districtdata = district.GetAllDistricts(request=request) +======= + connection = config.get_db_connection() + districtdata = [] + states = [] + + if connection: + cursor = connection.cursor() + + try: + # cursor.execute("SELECT State_ID, State_Name FROM states") + # states = cursor.fetchall() + cursor.callproc("GetAllStates") + for res in cursor.stored_results(): + states = res.fetchall() + + except mysql.connector.Error as e: + print(f"Error fetching states: {e}") + return ResponseHandler.fetch_failure("states"), 500 + + if request.method == 'POST': + district_name = request.form['district_Name'].strip() + state_id = request.form['state_Id'] + log_action("Add District", f"User {current_user.id} Added District '{district_name}'") + if not re.match(str_pattern_reg, district_name): + return json_response(ResponseHandler.invalid_name("district"), 400) + + try: + # cursor.execute("SELECT * FROM districts WHERE District_Name = %s AND State_Id = %s", + # (district_name, state_id)) + cursor.callproc("GetDistrictByNameAndState", (district_name, state_id)) + for data in cursor.stored_results(): + rs = data.fetchone() + if rs: + return json_response(ResponseHandler.already_exists("district"), 409) + + cursor.callproc('SaveDistrict', (district_name, state_id)) + connection.commit() + + return json_response(ResponseHandler.add_success("district"), 200) + + except mysql.connector.Error as e: + print(f"Error inserting district: {e}") + return json_response(ResponseHandler.add_failure("district"), 500) + + try: + # cursor.execute("SELECT d.District_id, d.District_Name, s.State_Name, s.State_Id FROM districts d JOIN states s ON d.State_Id = s.State_ID") + # districtdata = cursor.fetchall() + cursor.callproc("GetAllDistricts") + for dis in cursor.stored_results(): + districtdata = dis.fetchall() + except mysql.connector.Error as e: + print(f"Error fetching districts: {e}") + return ResponseHandler.fetch_failure("districts"), 500 + finally: + cursor.close() + connection.close() + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return render_template('add_district.html', districtdata=districtdata, states=states) @@ -217,17 +576,69 @@ def check_district(): return district.CheckDistrict(request=request) +<<<<<<< HEAD # Delete District @app.route('/delete_district/', methods=['GET']) +======= + if connection: + cursor = connection.cursor() + district_name = request.json.get('district_Name', '').strip() + state_id = request.json.get('state_Id', '') + log_action("Check District", f"User {current_user.id} Checked District '{district_name}'") + if not re.match(str_pattern_reg, district_name): + return json_response(ResponseHandler.invalid_name("district"), 400) + + try: + # cursor.execute("SELECT * FROM districts WHERE District_Name = %s AND State_Id = %s", + # (district_name, state_id)) + # existing_district = cursor.fetchone() + cursor.callproc("GetDistrictByNameAndState", (district_name, state_id,)) + for result in cursor.stored_results(): + existing_district = result.fetchone() + + if existing_district: + return json_response(ResponseHandler.already_exists("district"), 409) + else: + return json_response(ResponseHandler.is_available("district"), 200) + + except mysql.connector.Error as e: + print(f"Error checking district: {e}") + return json_response(ResponseHandler.add_failure("district"), 500) + finally: + cursor.close() + connection.close() + + +# this is delete District method by id.. +@app.route('/delete_district/', methods=['GET', 'POST']) +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @login_required def delete_district(district_id): district = District() district.DeleteDistrict(request=request, id=district_id) +<<<<<<< HEAD if not district.isSuccess: return district.resultMessage else: return redirect(url_for('add_district')) +======= + if connection: + cursor = connection.cursor() + try: + # cursor.execute("DELETE FROM districts WHERE District_id = %s", (district_id,)) + cursor.callproc("DeleteDistrict", (district_id,)) + connection.commit() + log_action("Delete District", f"User {current_user.id} Deleted District '{district_id}'") + except mysql.connector.Error as e: + print(f"Error deleting district: {e}") + return json_response(ResponseHandler.delete_failure("district"), 500) + finally: + cursor.close() + connection.close() + + return redirect('/add_district') +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # Edit District @@ -236,6 +647,7 @@ def delete_district(district_id): def edit_district(district_id): district = District() +<<<<<<< HEAD if request.method == 'POST': district.EditDistrict(request=request, id=district_id) if district.isSuccess: @@ -265,6 +677,47 @@ def edit_district(district_id): districtdata = [] if states is None: states = [] +======= + if connection: + cursor = connection.cursor() + + # Retrieve all states for dropdown + try: + + cursor.callproc("GetAllStates") + for res in cursor.stored_results(): + states = res.fetchall() + + except mysql.connector.Error as e: + print(f"Error fetching states: {e}") + return ResponseHandler.fetch_failure("states"), 500 + + # Retrieve district info + try: + + cursor.callproc("GetDistrictDataByID", (district_id,)) + for rs in cursor.stored_results(): + districtdata = rs.fetchone() + log_action("Edit District", f"User {current_user.id} Edited District '{district_id}'") + except mysql.connector.Error as e: + print(f"Error fetching district data: {e}") + return ResponseHandler.fetch_failure("district"), 500 + + # Handle update + if request.method == 'POST': + district_name = request.form['district_Name'] + state_id = request.form['state_Id'] + + try: + + + cursor.callproc("UpdateDistrict", (district_id, state_id, district_name,)) + connection.commit() + except mysql.connector.Error as e: + print(f"Error updating district: {e}") + return ResponseHandler.update_failure("district"), 500 + return redirect('/add_district') +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return render_template('edit_district.html', districtdata=districtdata, states=states) @@ -278,6 +731,7 @@ def add_block(): block = Block() district = District() +<<<<<<< HEAD # form submission if request.method == 'POST': block.AddBlock(request) @@ -287,6 +741,75 @@ def add_block(): connection = config.get_db_connection() cursor = connection.cursor() cursor.callproc("GetAllStates") +======= + if connection: + cursor = connection.cursor() + try: + + cursor.callproc("GetAllStates") + for res in cursor.stored_results(): + states = res.fetchall() + + except mysql.connector.Error as e: + print(f"Error fetching states: {e}") + return json_response(ResponseHandler.fetch_failure("states"), 500) + + if request.method == 'POST': + block_name = request.form['block_Name'].strip() + district_id = request.form['district_Id'] + log_action("Add Block", f"User {current_user.id} Added block '{block_name}'") + if not re.match(str_pattern_reg, block_name): + return json_response(ResponseHandler.invalid_name("block"), 400) + + try: + + cursor.callproc("GetBlockByNameAndDistrict", (block_name, district_id,)) + for rs in cursor.stored_results(): + existing_block = rs.fetchone() + + if existing_block: + return json_response(ResponseHandler.already_exists("block"), 409) + + cursor.callproc('SaveBlock', (block_name, district_id)) + connection.commit() + + return json_response(ResponseHandler.add_success("block"), 200) + + except mysql.connector.Error as e: + print(f"Error adding block: {e}") + return json_response(ResponseHandler.add_failure("block"), 500) + + # Fetch all blocks to display + try: + + cursor.callproc("GetAllBlocks") + for blocks in cursor.stored_results(): + block_data = blocks.fetchall() + + except mysql.connector.Error as e: + print(f"Error fetching blocks: {e}") + return json_response(ResponseHandler.fetch_failure("blocks"), 500) + finally: + cursor.close() + connection.close() + return render_template('add_block.html', block_data=block_data, states=states) + + +# check block +@app.route('/check_block', methods=['POST']) +@login_required +def check_block(): + connection = config.get_db_connection() + cursor = connection.cursor() + block_name = request.json.get('block_Name', '').strip() + district_id = request.json.get('district_Id', '') + log_action("Check Block", f"User {current_user.id} Checked block '{block_name}'") + if not re.match(str_pattern_reg, block_name): + return json_response(ResponseHandler.invalid_name("block"), 400) + + + cursor.callproc("GetBlockByNameAndDistrict", (block_name, district_id)) +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 for rs in cursor.stored_results(): states = rs.fetchall() @@ -296,11 +819,14 @@ def add_block(): return render_template('add_block.html', states=states, block_data=block_data) +<<<<<<< HEAD @app.route('/check_block', methods=['POST']) @login_required def check_block(): block = Block() return block.CheckBlock(request) +======= +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @app.route('/edit_block/', methods=['GET', 'POST']) @@ -318,6 +844,7 @@ def edit_block(block_id): for rs in cursor.stored_results(): states = rs.fetchall() +<<<<<<< HEAD # Load all districts cursor.callproc("GetAllDistrictsData") for rs in cursor.stored_results(): @@ -329,12 +856,81 @@ def edit_block(block_id): @app.route('/delete_block/') +======= + if connection: + cursor = connection.cursor() + # Retrieve all states + try: + + cursor.callproc("GetAllStates") + for rs in cursor.stored_results(): + states = rs.fetchall() + except mysql.connector.Error as e: + print(f"Error fetching states: {e}") + return "Failed to fetch states", 500 + + # Retrieve block data + try: + + cursor.callproc("GetBlockDataByID", (block_id,)) + for rs in cursor.stored_results(): + block_data = rs.fetchone() + log_action("Edit Block", f"User {current_user.id} Edited block '{block_id}'") + except mysql.connector.Error as e: + print(f"Error fetching block data: {e}") + return "Failed to fetch block data", 500 + + # Handle POST request + if request.method == 'POST': + block_name = request.form['block_Name'] + district_id = request.form['district_Id'] + try: + + cursor.callproc("UpdateBlockById", (block_name, district_id, block_id,)) + connection.commit() + flash("Block updated successfully!", "success") + return redirect(url_for('add_block', block_id=block_id)) + except mysql.connector.Error as e: + print(f"Error updating blocks: {e}") + return "Failed to update blocks", 500 + + # Retrieve districts for the dropdown + try: + + cursor.callproc("GetAllDistrictsData") + for rs in cursor.stored_results(): + districts = rs.fetchall() + except mysql.connector.Error as e: + print(f"Error fetching districts: {e}") + return "Failed to fetch districts", 500 + + return render_template('edit_block.html', block_data=block_data, states=states, districts=districts) + +# delete block by id +@app.route('/delete_block/', methods=['GET', 'POST']) +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @login_required def delete_block(block_id): block = Block() block.DeleteBlock(block_id) return redirect(url_for('add_block')) +<<<<<<< HEAD +======= + if connection: + cursor = connection.cursor() + try: + + cursor.callproc("DeleteBlock", (block_id,)) + log_action("Delete Block", f"User {current_user.id} Deleted block '{block_id}'") + connection.commit() + except mysql.connector.Error as e: + print(f"Error deleting block: {e}") + return json_response(ResponseHandler.add_failure("block"), 500) + finally: + cursor.close() + connection.close() +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @@ -348,13 +944,16 @@ def get_districts(state_id): if connection: cursor = connection.cursor() try: - # cursor.execute("SELECT District_id, District_Name FROM districts WHERE State_Id = %s", (state_id,)) - # districts = cursor.fetchall() + cursor.callproc("GetDistrictsByStateId", (state_id,)) for dis in cursor.stored_results(): districts = dis.fetchall() +<<<<<<< HEAD LogHelper.log_action("Get District", f"User {current_user.id} Get District '{state_id}'") +======= + log_action("Get District", f"User {current_user.id} Get District '{state_id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 except mysql.connector.Error as e: print(f"Error fetching districts: {e}") return HtmlHelper.json_response(ResponseHandler.fetch_failure("districts"), 500) @@ -376,11 +975,17 @@ def get_districts(state_id): def add_village(): village = Village() +<<<<<<< HEAD if request.method == 'POST': village.AddVillage(request=request) return village.resultMessage +======= + try: + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 +<<<<<<< HEAD state = State() # Use the State class to get states states = state.GetAllStates(request=request) @@ -397,11 +1002,155 @@ def check_village(): # Delete Village @app.route('/delete_village/', methods=['GET']) +======= + + cursor.callproc("GetAllVillages") + for result in cursor.stored_results(): + villages = result.fetchall() + + if request.method == 'POST': + block_id = request.form.get('block_Id') + village_name = request.form.get('Village_Name', '').strip() + log_action("Add Villages", f"User {current_user.id} Added Villages '{village_name}'") + if not block_id: + return json_response(ResponseHandler.add_failure("block"), 400) + + if not re.match(str_pattern_reg, village_name): + return json_response(ResponseHandler.invalid_name("village"), 400) + + + cursor.callproc("GetVillageByNameAndBlock", (village_name, block_id,)) + for rs in cursor.stored_results(): + existing_village = rs.fetchone() + if existing_village: + return json_response(ResponseHandler.already_exists("village"), 409) + + # Insert new village + cursor.callproc('SaveVillage', (village_name, block_id)) + connection.commit() + + return json_response(ResponseHandler.add_success("village"), 200) + + except mysql.connector.Error as e: + print(f"Database Error: {e}") + return json_response(ResponseHandler.add_failure("village"), 500) + finally: + cursor.close() + connection.close() + + return render_template('add_village.html', states=states, villages=villages) + + +# get block by district id +@app.route('/get_blocks/', methods=['GET']) +@login_required +def get_blocks(district_id): + connection = config.get_db_connection() + cursor = connection.cursor() + blocks = [] + + try: + + cursor.callproc("GetBlocksByDistrict", (district_id,)) + for rs in cursor.stored_results(): + blocks = rs.fetchall() + log_action("Get blocks", f"User {current_user.id} Get Blocks '{district_id}'") + except mysql.connector.Error as e: + print(f"Error fetching blocks: {e}") + return json_response({"error": "Failed to fetch blocks"}, 500) + finally: + cursor.close() + connection.close() + + return jsonify({"blocks": [{"Block_Id": block[0], "Block_Name": block[1]} for block in blocks]}) + + +# check village +@app.route('/check_village', methods=['POST']) +@login_required +def check_village(): + connection = config.get_db_connection() + cursor = connection.cursor() + + block_id = request.form.get('block_Id') + village_name = request.form.get('Village_Name', '').strip() + log_action("Check villages", f"User {current_user.id} Check villages '{village_name}'") + # Validate village name + if not re.match(str_pattern_reg, village_name): + return json_response(ResponseHandler.invalid_name("village"), 400) + + if not block_id or not village_name: + return json_response({'status': 'error', 'message': 'Block and Village Name are required!'}, 400) + + + cursor.callproc("GetVillageByNameAndBlocks", (village_name, block_id)) + for rs in cursor.stored_results(): + existing_village = rs.fetchone() + + cursor.close() + connection.close() + + if existing_village: + return json_response(ResponseHandler.already_exists("village"), 409) + else: + return json_response(ResponseHandler.is_available("village"), 200) + + + + +@app.route('/edit_village/', methods=['GET', 'POST']) +@login_required +def edit_village(village_id): + connection = config.get_db_connection() + village_data = None + blocks = [] + + try: + cursor = connection.cursor() + + cursor.callproc("GetVillageDetailsById", (village_id,)) + for rs in cursor.stored_results(): + village_data = rs.fetchone() + + cursor.callproc('GetAllBlocks') + for result in cursor.stored_results(): + blocks = result.fetchall() + + if request.method == 'POST': + village_name = request.form['Village_Name'] + block_id = request.form['block_Id'] + log_action("Edit villages", f"User {current_user.id} Edit villages '{village_name}'") + if not re.match("^[A-Za-z ]+$", village_name): + flash("Invalid village name! Only letters and spaces allowed.", "error") + return redirect(url_for('edit_village', village_id=village_id)) + + cursor.execute("UPDATE villages SET Village_Name = %s, Block_Id = %s WHERE Village_Id = %s", + (village_name, block_id, village_id)) + connection.commit() + flash("Village updated successfully!", "success") + return redirect(url_for('edit_village', village_id=village_id)) + + except mysql.connector.Error as e: + print(f"Error: {e}") + return "Failed to process request", 500 + finally: + if cursor: + cursor.close() + if connection: + connection.close() + + return render_template('edit_village.html', village_data=village_data, blocks=blocks) + + +# delete village +@app.route('/delete_village/', methods=['GET', 'POST']) +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @login_required def delete_village(village_id): village = Village() village.DeleteVillage(request=request, village_id=village_id) +<<<<<<< HEAD if not village.isSuccess: flash(village.resultMessage, "error") return redirect(url_for('add_village')) @@ -445,6 +1194,22 @@ def edit_village(village_id): blocks = [] return render_template('edit_village.html', village_data=village_data, blocks=blocks) +======= + try: + + cursor.callproc("DeleteVillage", (village_id,)) + log_action("Delete villages", f"User {current_user.id} Deletedvillages '{village_id}'") + connection.commit() + + except mysql.connector.Error as e: + print(f"Error: {e}") + return json_response(ResponseHandler.add_failure("village"), 500) + finally: + if cursor: + cursor.close() + if connection: + connection.close() +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @@ -468,9 +1233,7 @@ def add_invoice(): print("village name", village_name) - # Query the database to get the corresponding Village_Id based on the village name - # cursor.execute("SELECT Village_Id FROM villages WHERE Village_Name = %s", (village_name,)) - # village_result = cursor.fetchone() + cursor.callproc("GetVillageIdByName", (village_name,)) for rs in cursor.stored_results(): village_result = rs.fetchone() @@ -509,20 +1272,32 @@ def add_invoice(): final_amount = request.form.get('final_amount') final_amount=float(final_amount) if final_amount else 0.0 +<<<<<<< HEAD # invoice_id = cursor.lastrowid +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 cursor.callproc('InsertInvoice', [ pmc_no, village_id, work_type, invoice_details, invoice_date, invoice_no, basic_amount, debit_amount, after_debit_amount, amount, gst_amount, tds_amount, sd_amount, on_commission, hydro_testing, gst_sd_amount, final_amount]) +<<<<<<< HEAD LogHelper.log_action("Add invoice", f"User {current_user.id} Added invoice '{ pmc_no}'") +======= + log_action("Add invoice", f"User {current_user.id} Added invoice '{ pmc_no}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 for result in cursor.stored_results(): invoice_id = result.fetchone()['invoice_id'] connection.commit() print("This is the invocie id from the invoice table ", invoice_id) +<<<<<<< HEAD +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 subcontractor_id = request.form.get('subcontractor_id') cursor.callproc('AssignSubcontractor', [pmc_no, subcontractor_id, village_id]) connection.commit() @@ -533,8 +1308,7 @@ def add_invoice(): hold_count = 0 for hold_type, hold_amount in zip(hold_types, hold_amounts): - # cursor.execute("SELECT hold_type_id FROM hold_types WHERE hold_type = %s", (hold_type,)) - # hold_type_result = cursor.fetchone() + cursor.callproc('GetHoldTypeIdByName', [hold_type]) for result in cursor.stored_results(): hold_type_result = result.fetchone() @@ -542,14 +1316,7 @@ def add_invoice(): if not hold_type_result: return jsonify({"status": "error", "message": f"Invalid Hold Type: {hold_type}"}), 400 hold_type_id = hold_type_result['hold_type_id'] - # insert_hold_query = ''' - # INSERT INTO invoice_subcontractor_hold_join (Contractor_Id, Invoice_Id, hold_type_id, hold_amount) - # VALUES (%s, %s, %s, %s) - # ''' - # cursor.execute(insert_hold_query, (subcontractor_id, invoice_id, hold_type_id, hold_amount)) - # hold_count += 1 - - # connection.commit() + cursor.callproc('InsertInvoiceSubcontractorHold', [ subcontractor_id, invoice_id, hold_type_id, hold_amount ]) @@ -570,8 +1337,7 @@ def add_invoice(): # GET request: fetch and display all invoices (all fields) along with the form try: cursor = connection.cursor(dictionary=True) - # cursor.execute("SELECT * FROM view_invoice_details") - # invoices = cursor.fetchall() + cursor.callproc('GetAllInvoiceDetails') for result in cursor.stored_results(): invoices = result.fetchall() @@ -602,11 +1368,7 @@ def search_subcontractor(): sub_query = request.form.get("query") try: cursor = connection.cursor(dictionary=True) - # cursor.execute( - # "SELECT Contractor_Id, Contractor_Name FROM subcontractors WHERE Contractor_Name LIKE %s", - # (f"%{sub_query}%",) - # ) - # results = cursor.fetchall() + cursor.callproc('SearchContractorsByName', [sub_query]) for result in cursor.stored_results(): results = result.fetchall() @@ -637,17 +1399,20 @@ def get_hold_types(): connection = config.get_db_connection() try: cursor = connection.cursor(dictionary=True) - # cursor.execute("SELECT hold_type_id, hold_type FROM hold_types") - # hold_types = cursor.fetchall() + cursor.callproc("GetAllHoldTypes") for hold in cursor.stored_results(): hold_types = hold.fetchall() +<<<<<<< HEAD LogHelper.log_action("Get hold type", f"User {current_user.id} Get hold type'{ hold_types}'") +======= + log_action("Get hold type", f"User {current_user.id} Get hold type'{ hold_types}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return jsonify(hold_types) except mysql.connector.Error as e: return ResponseHandler.fetch_failure({str(e)}), 500 - # return jsonify({"status": "error", "message": f"Failed to fetch hold types: {str(e)}"}), 500 + finally: cursor.close() connection.close() @@ -671,8 +1436,7 @@ def edit_invoice(invoice_id): subcontractor_id = int(subcontractor_id) if subcontractor_id else None village_name = request.form.get('village') - # cursor.execute("SELECT Village_Id FROM villages WHERE Village_Name = %s", (village_name,)) - # village_result = cursor.fetchone() + cursor.callproc("GetVillageIdByName", (village_name,)) for rs in cursor.stored_results(): village_result = rs.fetchone() @@ -685,7 +1449,11 @@ def edit_invoice(invoice_id): invoice_details = request.form.get('invoice_details') invoice_date = request.form.get('invoice_date') invoice_no = request.form.get('invoice_no') +<<<<<<< HEAD LogHelper.log_action("Edit invoice", f"User {current_user.id} Edit invoice'{ invoice_id}'") +======= + log_action("Edit invoice", f"User {current_user.id} Edit invoice'{ invoice_id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # Convert numeric fields properly numeric_fields = { "basic_amount": request.form.get('basic_amount'), @@ -702,21 +1470,7 @@ def edit_invoice(invoice_id): } numeric_fields = {k: float(v) if v else 0 for k, v in numeric_fields.items()} - # # Update invoice - # update_invoice_query = ''' - # UPDATE invoice - # SET PMC_No=%s, Village_Id=%s, Work_Type=%s, Invoice_Details=%s, Invoice_Date=%s, - # Invoice_No=%s, Basic_Amount=%s, Debit_Amount=%s, After_Debit_Amount=%s, - # Amount=%s, GST_Amount=%s, TDS_Amount=%s, SD_Amount=%s, On_Commission=%s, - # Hydro_Testing=%s, GST_SD_Amount=%s, Final_Amount=%s - # WHERE Invoice_Id=%s - # ''' - # invoice_values = ( - # pmc_no, village_id, work_type, invoice_details, invoice_date, invoice_no, - # *numeric_fields.values(), invoice_id - # ) - # cursor.execute(update_invoice_query, invoice_values) - # connection.commit() + cursor.callproc('UpdateInvoice', [ pmc_no, village_id, work_type, invoice_details, invoice_date, invoice_no, *numeric_fields.values(), invoice_id @@ -731,19 +1485,12 @@ def edit_invoice(invoice_id): if not hold_type: continue # skip empty hold types - # Get or insert hold type - # cursor.execute("SELECT hold_type_id FROM hold_types WHERE hold_type = %s", (hold_type,)) - # hold_type_result = cursor.fetchone() + cursor.callproc('GetHoldTypeIdByName', [hold_type]) for result in cursor.stored_results(): hold_type_result = result.fetchone() - # if not hold_type_result: - # cursor.execute("INSERT INTO hold_types (hold_type) VALUES (%s)", (hold_type,)) - # connection.commit() - # hold_type_id = cursor.lastrowid - # else: - # hold_type_id = hold_type_result['hold_type_id'] + if not hold_type_result: # Call stored procedure to insert and return new ID @@ -759,30 +1506,18 @@ def edit_invoice(invoice_id): hold_amount = float(hold_amount) if hold_amount else 0 - # Check if join exists - # cursor.execute(""" - # SELECT join_id FROM invoice_subcontractor_hold_join - # WHERE Invoice_Id = %s AND Contractor_Id = %s AND hold_type_id = %s - # """, (invoice_id, subcontractor_id, hold_type_id)) - # join_result = cursor.fetchone() + cursor.callproc('GetHoldJoinId', [invoice_id, subcontractor_id, hold_type_id]) for result in cursor.stored_results(): join_result = result.fetchone() if join_result: - # cursor.execute(""" - # UPDATE invoice_subcontractor_hold_join - # SET hold_amount = %s - # WHERE join_id = %s - # """, (hold_amount, join_result['join_id'])) + cursor.callproc('UpdateHoldAmountByJoinId', [hold_amount, join_result['join_id']]) connection.commit() else: - # cursor.execute(""" - # INSERT INTO invoice_subcontractor_hold_join (Contractor_Id, Invoice_Id, hold_type_id, hold_amount) - # VALUES (%s, %s, %s, %s) - # """, (subcontractor_id, invoice_id, hold_type_id, hold_amount)) + cursor.callproc('InsertInvoiceSubcontractorHold', [ subcontractor_id, invoice_id, hold_type_id, hold_amount ]) @@ -801,16 +1536,7 @@ def edit_invoice(invoice_id): # ------------------ GET Request ------------------ try: - # Fetch invoice data - # cursor.execute( - # """SELECT i.*, s.Contractor_Name, v.Village_Name - # FROM invoice i - # LEFT JOIN assign_subcontractors a ON i.PMC_No = a.PMC_no AND i.Village_Id = a.Village_Id - # LEFT JOIN subcontractors s ON a.Contractor_Id = s.Contractor_Id - # LEFT JOIN villages v ON i.Village_Id = v.Village_Id - # WHERE i.Invoice_Id = %s""", (invoice_id,) - # ) - # invoice = cursor.fetchone() + cursor.callproc('GetInvoiceDetailsById', [invoice_id]) for result in cursor.stored_results(): invoice = result.fetchone() @@ -822,15 +1548,7 @@ def edit_invoice(invoice_id): while cursor.nextset(): pass - # Fetch hold amounts - # cursor.execute( - # """SELECT h.hold_type, ihj.hold_amount - # FROM invoice_subcontractor_hold_join ihj - # JOIN hold_types h ON ihj.hold_type_id = h.hold_type_id - # WHERE ihj.Invoice_Id = %s""", (invoice_id,) - # ) - # hold_amounts = cursor.fetchall() - # invoice["hold_amounts"] = hold_amounts + cursor.callproc('GetHoldAmountsByInvoiceId', [invoice_id]) for result in cursor.stored_results(): hold_amounts = result.fetchall() @@ -857,10 +1575,14 @@ def delete_invoice(invoice_id): try: cursor = connection.cursor() - # cursor.execute("DELETE FROM invoice WHERE Invoice_Id = %s", (invoice_id,)) + cursor.callproc("DeleteInvoice", (invoice_id,)) +<<<<<<< HEAD LogHelper.log_action("Delete invoice", f"User {current_user.id} Delete invoice'{ invoice_id}'") +======= + log_action("Delete invoice", f"User {current_user.id} Delete invoice'{ invoice_id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 connection.commit() # Check if the invoice was actually deleted @@ -878,9 +1600,9 @@ def delete_invoice(invoice_id): connection.close() -# ---------- end Invoice controller ------------------ +<<<<<<< HEAD # ----------------------------- Payment controller ------------------------------------------ # this is Payment Page to add data # @app.route('/add_payment', methods=['GET', 'POST']) @@ -933,6 +1655,8 @@ def delete_invoice(invoice_id): # # return render_template('add_payment.html', payments=payments) +======= +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @app.route('/add_payment', methods=['GET', 'POST']) @login_required def add_payment(): @@ -943,10 +1667,7 @@ def add_payment(): cursor = connection.cursor() try: - # cursor.execute( - # "SELECT Payment_Id, PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR FROM payment" - # ) - # payments = cursor.fetchall() + cursor.callproc('GetAllPayments') for result in cursor.stored_results(): payments = result.fetchall() @@ -964,13 +1685,14 @@ def add_payment(): tds_amount = request.form['TDS_Payment_Amount'] total_amount = request.form['total_amount'] utr = request.form['utr'] +<<<<<<< HEAD LogHelper.log_action("Add Payment", f"User {current_user.id} Add Payment'{ pmc_no}'") +======= + log_action("Add Payment", f"User {current_user.id} Add Payment'{ pmc_no}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 try: cursor = connection.cursor() - # cursor.execute('''INSERT INTO payment (PMC_No, invoice_no, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR) - # VALUES (%s, %s, %s, %s, %s, %s)''', - # (pmc_no, invoice_no, amount, tds_amount, total_amount, utr)) - # connection.commit() + cursor.callproc('InsertPayments', [ pmc_no, invoice_no, amount, tds_amount, total_amount, utr ]) @@ -994,15 +1716,7 @@ def get_pmc_nos_by_subcontractor(subcontractorId): connection = config.get_db_connection() cur = connection.cursor() print(subcontractorId) - # query = """ - # SELECT DISTINCT i.PMC_No - # FROM invoice i - # JOIN assign_subcontractors a ON i.PMC_No = a.PMC_no - # JOIN subcontractors s ON a.Contractor_Id = s.Contractor_Id - # WHERE s.Contractor_Id=%s; - # """ - # cur.execute(query, (subcontractorId,)) - # results = cur.fetchall() + cur.callproc('GetDistinctPMCNoByContractorId', [subcontractorId]) for result in cur.stored_results(): results = result.fetchall() @@ -1026,12 +1740,7 @@ def edit_payment(payment_id): try: cursor = connection.cursor() - # Fetch the existing payment data for the given payment_id - # cursor.execute( - # "SELECT Payment_Id, PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR FROM payment WHERE Payment_Id = %s", - # (payment_id,) - # ) - # payment_data = cursor.fetchone() + cursor.callproc("GetPaymentById", (payment_id,)) for result in cursor.stored_results(): @@ -1045,11 +1754,13 @@ def edit_payment(payment_id): tds_amount = request.form['TDS_Payment_Amount'] total_amount = request.form['total_amount'] utr = request.form['utr'] +<<<<<<< HEAD LogHelper.log_action("Edit Payment", f"User {current_user.id} Edit Payment'{ pmc_no}'") +======= + log_action("Edit Payment", f"User {current_user.id} Edit Payment'{ pmc_no}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 try: - # cursor.execute('''UPDATE payment SET PMC_No=%s, Invoice_No=%s, Payment_Amount=%s, TDS_Payment_Amount=%s, - # Total_Amount=%s, UTR=%s WHERE Payment_Id=%s''', - # (pmc_no, invoice_no, amount, tds_amount, total_amount, utr, payment_id)) + cursor.callproc("UpdatePayment", (payment_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr,)) @@ -1079,10 +1790,13 @@ def delete_payment(payment_id): return HtmlHelper.json_response(ResponseHandler.fetch_failure("payment"), 500) try: cursor = connection.cursor() - # cursor.execute("DELETE FROM payment WHERE Payment_Id = %s", (payment_id,)) - + cursor.callproc("DeletePayment", (payment_id,)) +<<<<<<< HEAD LogHelper.log_action("Delete Payment", f"User {current_user.id} Delete Payment'{ payment_id}'") +======= + log_action("Delete Payment", f"User {current_user.id} Delete Payment'{ payment_id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 connection.commit() # Check if any rows were deleted if cursor.rowcount == 0: @@ -1117,9 +1831,13 @@ def add_gst_release(): cursor.execute("SELECT GST_Release_Id, PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR FROM gst_release") gst_releases = cursor.fetchall() +<<<<<<< HEAD # cursor.callproc("GetAllGSTReleases") # for result in cursor.stored_results(): # gst_releases = result.fetchall() +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 if request.method == 'POST': pmc_no = request.form['PMC_No'] @@ -1129,11 +1847,16 @@ def add_gst_release(): total_amount = request.form['total_amount'] utr = request.form['utr'] contractor_id = request.form['subcontractor_id'] +<<<<<<< HEAD LogHelper.log_action("Add gst_release", f"User {current_user.id} Add gst_release'{ pmc_no}'") # cursor.callproc('SaveGSTRelease', ( # pmc_no, invoice_no, basic_amount, final_amount,total_amount, utr # )) # connection.commit() +======= + log_action("Add gst_release", f"User {current_user.id} Add gst_release'{ pmc_no}'") + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 cursor.execute(""" INSERT INTO gst_release (PMC_No, invoice_no, @@ -1188,9 +1911,12 @@ def edit_gst_release(gst_release_id): ) gst_release_data = cursor.fetchone() +<<<<<<< HEAD # cursor.callproc("GetGSTReleaseById", (gst_release_id,)) # for result in cursor.stored_results(): # gst_release_data = result.fetchone() +======= +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 if request.method == 'POST': pmc_no = request.form['PMC_No'] @@ -1199,7 +1925,11 @@ def edit_gst_release(gst_release_id): final_amount = request.form['final_amount'] total_amount = request.form['total_amount'] utr = request.form['utr'] +<<<<<<< HEAD LogHelper.log_action("Edit gst_release", f"User {current_user.id} Edit gst_release'{ pmc_no}'") +======= + log_action("Edit gst_release", f"User {current_user.id} Edit gst_release'{ pmc_no}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 try: cursor.execute(""" UPDATE gst_release @@ -1220,9 +1950,13 @@ def edit_gst_release(gst_release_id): gst_release_id )) +<<<<<<< HEAD # cursor.callproc("UpdateGSTRelease", (gst_release_id, pmc_id, invoice_no, basic_amount, final_amount)) # # connection.commit() +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return redirect(url_for('add_gst_release')) # Redirect to the page to view the updated list @@ -1250,9 +1984,13 @@ def delete_gst_release(gst_release_id): return HtmlHelper.json_response(ResponseHandler.fetch_failure("GST Release"), 500) try: cursor = connection.cursor() - # cursor.execute("DELETE FROM gst_release WHERE GST_Release_Id = %s", (gst_release_id,)) + cursor.callproc("DeleteGSTRelease", (gst_release_id,)) +<<<<<<< HEAD LogHelper.log_action("delete gst_release", f"User {current_user.id} delete gst_release'{ gst_release_id}'") +======= + log_action("delete gst_release", f"User {current_user.id} delete gst_release'{ gst_release_id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 connection.commit() # Check if any rows were deleted if cursor.rowcount == 0: @@ -1283,9 +2021,7 @@ def subcontract(): if request.method == 'GET': try: - # cursor.execute('SELECT * FROM subcontractors;') - # subcontractor = cursor.fetchall() # Fetch the current subcontractor list - # connection.commit() + cursor.callproc('GetAllSubcontractors') for result in cursor.stored_results(): subcontractor = result.fetchall() @@ -1321,9 +2057,7 @@ def subcontract(): )) connection.commit() - # Re-fetch subcontractors after inserting the new one - # cursor.execute('SELECT * FROM subcontractors') - # subcontractor = cursor.fetchall() + cursor.callproc('GetAllSubcontractors') for result in cursor.stored_results(): subcontractor = result.fetchall() @@ -1357,9 +2091,7 @@ def edit_subcontractor(id): cursor = connection.cursor() subcontractor = None - # Fetch existing subcontractor data by ID - # cursor.execute('SELECT * FROM subcontractors WHERE Contractor_Id = %s', (id,)) - # subcontractor = cursor.fetchone() + cursor.callproc("GetSubcontractorById", (id,)) for contractors in cursor.stored_results(): @@ -1381,19 +2113,13 @@ def edit_subcontractor(id): 'Contractor_password': request.form['Contractor_password'], 'id': id } +<<<<<<< HEAD LogHelper.log_action("Edit Subcontractor", f"User {current_user.id}Edit Subcontractor'{ id}'") +======= + log_action("Edit Subcontractor", f"User {current_user.id}Edit Subcontractor'{ id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 try: - # cursor.execute("""UPDATE subcontractors SET - # Contractor_Name=%(Contractor_Name)s, - # Address=%(Address)s, - # Mobile_No=%(Mobile_No)s, - # PAN_No=%(PAN_No)s, - # Email=%(Email)s, - # Gender=%(Gender)s, - # GST_Registration_Type=%(GST_Registration_Type)s, - # GST_No=%(GST_No)s, - # Contractor_password=%(Contractor_password)s - # WHERE Contractor_Id=%(id)s""", updated_data) + cursor.callproc("UpdateSubcontractor", ( id, @@ -1425,11 +2151,8 @@ def edit_subcontractor(id): return render_template('edit_subcontractor.html', subcontractor=subcontractor) -# delete Sub-Contractor methods by id .. -# @app.route('/deleteSubContractor/', methods=['GET', 'POST']) -# def deleteSubContractor(id): -# connection = config.get_db_connection() +<<<<<<< HEAD # if not connection: # return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor"), 500) @@ -1453,6 +2176,8 @@ def edit_subcontractor(id): # connection.close() # return redirect(url_for('subcontract')) +======= +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @app.route('/deleteSubContractor/', methods=['GET', 'POST']) @login_required def deleteSubContractor(id): @@ -1478,7 +2203,11 @@ def deleteSubContractor(id): for result in cursor.stored_results(): row = result.fetchone() affected_rows = row[0] if row else 0 +<<<<<<< HEAD LogHelper.log_action("Delete Subcontractor", f"User {current_user.id}Delete Subcontractor'{ id}'") +======= + log_action("Delete Subcontractor", f"User {current_user.id}Delete Subcontractor'{ id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 if affected_rows == 0: return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor not deleted"), 404) @@ -1510,188 +2239,16 @@ def upload(): if file and file.filename.endswith('.xlsx'): filepath = os.path.join(app.config['UPLOAD_FOLDER'], file.filename) file.save(filepath) +<<<<<<< HEAD LogHelper.log_action("Upload Excel File", f"User {current_user.id}Upload Excel File'{file}'") +======= + log_action("Upload Excel File", f"User {current_user.id}Upload Excel File'{file}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return redirect(url_for('show_table', filename=file.filename)) return render_template('uploadExcelFile.html') -# Show excel data in tables6 -# @app.route('/show_table/') -# def show_table(filename): -# global data -# data = [] -# -# filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) -# wb = openpyxl.load_workbook(filepath, data_only=True) -# sheet = wb.active -# -# # Extract key file information from the first 4 rows -# file_info = { -# "Subcontractor": sheet.cell(row=1, column=2).value, -# "State": sheet.cell(row=2, column=2).value, -# "District": sheet.cell(row=3, column=2).value, -# "Block": sheet.cell(row=4, column=2).value, -# } -# -# errors = [] -# subcontractor_data = None -# state_data = None -# district_data = None -# block_data = None -# -# # Database connection -# connection = config.get_db_connection() -# if connection: -# try: -# cursor = connection.cursor(dictionary=True) -# -# # Validate State -# # cursor.execute("SELECT State_ID, State_Name FROM states WHERE State_Name = %s", (file_info['State'],)) -# # state_data = cursor.fetchone() -# cursor.callproc('GetStateByName', [file_info['State']]) -# for result in cursor.stored_results(): -# state_data = result.fetchone() -# -# if not state_data: -# errors.append(f"State '{file_info['State']}' is not valid. Please add it.") -# -# # Validate District -# if state_data: -# # cursor.execute( -# # "SELECT District_ID, District_Name FROM districts WHERE District_Name = %s AND State_ID = %s", -# # (file_info['District'], state_data['State_ID']) -# # ) -# # district_data = cursor.fetchone() -# cursor.callproc('GetDistrictByNameAndStates', [file_info['District'], state_data['State_ID']]) -# for result in cursor.stored_results(): -# district_data = result.fetchone() -# -# if not district_data: -# errors.append( -# f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.") -# -# # Validate Block -# if district_data: -# # cursor.execute( -# # "SELECT Block_Id, Block_Name FROM blocks WHERE Block_Name = %s AND District_ID = %s", -# # (file_info['Block'], district_data['District_ID']) -# # ) -# # block_data = cursor.fetchone() -# cursor.callproc('GetBlockByNameAndDistricts', [file_info['Block'], district_data['District_ID']]) -# for result in cursor.stored_results(): -# block_data = result.fetchone() -# -# if not block_data: -# errors.append( -# f"Block '{file_info['Block']}' is not valid under district '{file_info['District']}'.") -# -# # old code -# # # Validate Subcontractor -# # cursor.execute("SELECT Contractor_Id, Contractor_Name FROM SubContractors WHERE Contractor_Name = %s", -# # (file_info['Subcontractor'],)) -# # subcontractor_data = cursor.fetchone() -# cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']]) -# for result in cursor.stored_results(): -# subcontractor_data = result.fetchone() -# -# if not subcontractor_data: -# # cursor.execute("INSERT INTO subcontractors (Contractor_Name) VALUES (%s)", -# # (file_info['Subcontractor'],)) -# # connection.commit() -# cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']]) -# connection.commit() -# -# # cursor.execute("SELECT Contractor_Id, Contractor_Name FROM SubContractors WHERE Contractor_Name = %s", -# # (file_info['Subcontractor'],)) -# # subcontractor_data = cursor.fetchone() -# cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']]) -# for result in cursor.stored_results(): -# subcontractor_data = result.fetchone() -# -# # new code -# # cursor.callproc('ValidateAndInsertSubcontractor', (file_info['Subcontractor'], 0, '')) -# # -# # for con in cursor.stored_results(): -# # subcontractor_data = con.fetchone() -# # print("subcon:",subcontractor_data) -# # -# # print("subcontractor_data",subcontractor_data) -# -# # Get hold types data from database (for faster lookup) -# # cursor.execute("SELECT hold_type_id, hold_type FROM hold_types") -# # hold_types_data = cursor.fetchall() -# -# cursor.callproc("GetAllHoldTypes") -# for ht in cursor.stored_results(): -# hold_types_data = ht.fetchall() -# -# hold_types_lookup = {row['hold_type'].lower(): row['hold_type_id'] for row in hold_types_data if -# row['hold_type']} -# -# cursor.close() -# except mysql.connector.Error as e: -# print(f"Database error: {e}") -# return "Database operation failed", 500 -# finally: -# connection.close() -# -# # Extract dynamic variable names from row 5 and detect "hold" columns -# variables = {} -# hold_columns = [] -# hold_counter = 0 -# -# for j in range(1, sheet.max_column + 1): -# col_value = sheet.cell(row=5, column=j).value -# if col_value: -# variables[col_value] = j # Store column name with its position -# -# # Check if the column header contains the word 'hold' -# if 'hold' in str(col_value).lower(): -# hold_counter += 1 -# # Lookup hold type id from database -# hold_type_key = str(col_value).lower().strip() -# hold_type_id = hold_types_lookup.get(hold_type_key, None) -# hold_columns.append({ -# 'column_name': col_value, -# 'column_number': j, -# 'hold_type_id': hold_type_id -# }) -# -# # Extract data dynamically based on row numbers -# for i in range(6, sheet.max_row + 1): -# row_data = {} -# if sheet.cell(row=i, column=1).value: -# row_data["Row Number"] = i # Store row number -# for var_name, col_num in variables.items(): -# row_data[var_name] = sheet.cell(row=i, column=col_num).value -# # Check if at least 4 non-empty cells exist in the row -# if sum(1 for value in row_data.values() if value) >= 4: -# data.append(row_data) -# -# # For debugging or console output, you can print the hold columns info -# for hold in hold_columns: -# if hold['hold_type_id']: -# print( -# f" if Column: {hold['column_name']}, Column Number: {hold['column_number']}, Hold Type ID: {hold['hold_type_id']}") -# else: -# errors.append( -# f"Hold Type not added ! Column name '{hold['column_name']}'.") -# print( -# f" else Column: {hold['column_name']}, Column Number: {hold['column_number']}, Hold Type ID: {hold['hold_type_id']}") -# -# return render_template( -# 'show_excel_file.html', -# file_info=file_info, -# variables=variables, -# data=data, -# subcontractor_data=subcontractor_data, -# state_data=state_data, -# district_data=district_data, -# block_data=block_data, -# errors=errors, -# hold_columns=hold_columns, -# hold_counter=hold_counter -# ) + @app.route('/show_table/') def show_table(filename): @@ -1823,166 +2380,7 @@ def show_table(filename): hold_counter=hold_counter ) -# Show excel data in tables6 -# @app.route('/show_table/') -# def show_table(filename): -# global data -# data = [] -# -# filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) -# wb = openpyxl.load_workbook(filepath, data_only=True) -# sheet = wb.active -# -# # Extract key file information from the first 4 rows -# file_info = { -# "Subcontractor": sheet.cell(row=1, column=2).value, -# "State": sheet.cell(row=2, column=2).value, -# "District": sheet.cell(row=3, column=2).value, -# "Block": sheet.cell(row=4, column=2).value, -# } -# -# errors = [] -# subcontractor_data = None -# state_data = None -# district_data = None -# block_data = None -# -# # Database connection -# connection = config.get_db_connection() -# if connection: -# try: -# cursor = connection.cursor(dictionary=True) -# -# # Validate State -# cursor.execute("SELECT State_ID, State_Name FROM states WHERE State_Name = %s", (file_info['State'],)) -# state_data = cursor.fetchone() -# if not state_data: -# errors.append(f"State '{file_info['State']}' is not valid. Please add it.") -# -# # Validate District -# if state_data: -# cursor.execute( -# "SELECT District_ID, District_Name FROM districts WHERE District_Name = %s AND State_ID = %s", -# (file_info['District'], state_data['State_ID']) -# ) -# district_data = cursor.fetchone() -# if not district_data: -# errors.append( -# f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.") -# -# # Validate Block -# if district_data: -# cursor.execute( -# "SELECT Block_Id, Block_Name FROM blocks WHERE Block_Name = %s AND District_ID = %s", -# (file_info['Block'], district_data['District_ID']) -# ) -# block_data = cursor.fetchone() -# if not block_data: -# errors.append( -# f"Block '{file_info['Block']}' is not valid under district '{file_info['District']}'.") -# -# -# # old code -# # # Validate Subcontractor -# cursor.execute("SELECT Contractor_Id, Contractor_Name FROM subcontractors WHERE Contractor_Name = %s", -# (file_info['Subcontractor'],)) -# subcontractor_data = cursor.fetchone() -# -# if not subcontractor_data: -# cursor.execute("INSERT INTO subcontractors (Contractor_Name) VALUES (%s)", -# (file_info['Subcontractor'],)) -# connection.commit() -# cursor.execute("SELECT Contractor_Id, Contractor_Name FROM subcontractors WHERE Contractor_Name = %s", -# (file_info['Subcontractor'],)) -# subcontractor_data = cursor.fetchone() -# -# # new code -# # cursor.callproc('ValidateAndInsertSubcontractor', (file_info['Subcontractor'], 0, '')) -# # -# # for con in cursor.stored_results(): -# # subcontractor_data = con.fetchone() -# # print("subcon:",subcontractor_data) -# # -# # print("subcontractor_data",subcontractor_data) -# -# # Get hold types data from database (for faster lookup) -# # cursor.execute("SELECT hold_type_id, hold_type FROM hold_types") -# # hold_types_data = cursor.fetchall() -# -# cursor.callproc("GetAllHoldTypes") -# for ht in cursor.stored_results(): -# hold_types_data = ht.fetchall() -# -# -# hold_types_lookup = {row['hold_type'].lower(): row['hold_type_id'] for row in hold_types_data if row['hold_type']} -# -# -# cursor.close() -# except mysql.connector.Error as e: -# print(f"Database error: {e}") -# -# # return "Database operation failed", 500 -# return f"{e}",500 -# finally: -# connection.close() -# -# # Extract dynamic variable names from row 5 and detect "hold" columns -# variables = {} -# hold_columns = [] -# hold_counter = 0 -# -# for j in range(1, sheet.max_column + 1): -# col_value = sheet.cell(row=5, column=j).value -# if col_value: -# variables[col_value] = j # Store column name with its position -# -# # Check if the column header contains the word 'hold' -# if 'hold' in str(col_value).lower(): -# hold_counter += 1 -# # Lookup hold type id from database -# hold_type_key = str(col_value).lower().strip() -# hold_type_id = hold_types_lookup.get(hold_type_key, None) -# hold_columns.append({ -# 'column_name': col_value, -# 'column_number': j, -# 'hold_type_id': hold_type_id -# }) -# -# # Extract data dynamically based on row numbers -# for i in range(6, sheet.max_row + 1): -# row_data = {} -# if sheet.cell(row=i, column=1).value: -# row_data["Row Number"] = i # Store row number -# for var_name, col_num in variables.items(): -# row_data[var_name] = sheet.cell(row=i, column=col_num).value -# # Check if at least 4 non-empty cells exist in the row -# if sum(1 for value in row_data.values() if value) >= 4: -# data.append(row_data) -# -# # For debugging or console output, you can print the hold columns info -# for hold in hold_columns: -# if hold['hold_type_id']: -# print( -# f" if Column: {hold['column_name']}, Column Number: {hold['column_number']}, Hold Type ID: {hold['hold_type_id']}") -# else: -# errors.append( -# f"Hold Type not added ! Column name '{hold['column_name']}'.") -# print( -# f" else Column: {hold['column_name']}, Column Number: {hold['column_number']}, Hold Type ID: {hold['hold_type_id']}") -# -# return render_template( -# 'show_excel_file.html', -# file_info=file_info, -# variables=variables, -# data=data, -# subcontractor_data=subcontractor_data, -# state_data=state_data, -# district_data=district_data, -# block_data=block_data, -# errors=errors, -# hold_columns=hold_columns, -# hold_counter=hold_counter -# ) + # save Excel data @app.route('/save_data', methods=['POST']) @@ -1997,13 +2395,13 @@ def save_data(): hold_columns = request.form.get("hold_columns") hold_counter = request.form.get("hold_counter") - # print("Info: ", subcontractor_id, state_id, district_id, block_id) + if not data: return jsonify({"error": "No data provided to save"}), 400 if data: - # print("Total number of entries in data:", len(data)) + connection = config.get_db_connection() cursor = connection.cursor() @@ -2037,7 +2435,11 @@ def save_data(): village_name, work_type = None, None village_id = 0 +<<<<<<< HEAD LogHelper.log_action("Data saved", f"User {current_user.id} Data saved'{ village_name}'") +======= + log_action("Data saved", f"User {current_user.id} Data saved'{ village_name}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 PMC_No = save_data.get('PMC_No') Invoice_Details = save_data.get('Invoice_Details') Invoice_Date = save_data.get('Invoice_Date') @@ -2075,8 +2477,7 @@ def save_data(): print("village_name ::", village_name, "|| work_type ::", work_type) if block_id and village_name: village_id = None - # cursor.execute("SELECT Village_Id FROM villages WHERE Block_Id = %s AND Village_Name = %s",(block_id, village_name)) - # result = cursor.fetchone() + cursor.callproc("GetVillageId", (block_id, village_name)) for result in cursor.stored_results(): result = result.fetchone() @@ -2086,8 +2487,7 @@ def save_data(): # cursor.execute("INSERT INTO villages (Village_Name, Block_Id) VALUES (%s, %s)", (village_name, block_id)) cursor.callproc("SaveVillage", (village_name, block_id)) - # cursor.execute("SELECT Village_Id FROM villages WHERE Block_Id = %s AND Village_Name = %s",(block_id, village_name)) - # result = cursor.fetchone() + cursor.callproc("GetVillageId", (block_id, village_name)) for result in cursor.stored_results(): result = result.fetchone() @@ -2098,16 +2498,7 @@ def save_data(): print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount, SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount) - # - # cursor.execute("SET @p_invoice_id = 0") - # cursor.callproc("SaveInvoice", ( - # PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, - # Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount, - # SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount, - # subcontractor_id, "@p_invoice_id" - # )) - # cursor.execute("SELECT @p_invoice_id") - # invoice_id = cursor.fetchone()[0] + args = ( PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, @@ -2115,12 +2506,15 @@ def save_data(): SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount, subcontractor_id, 0 ) +<<<<<<< HEAD # for result in cursor.stored_results(): # invoice_id = result.fetchone()['invoice_id'] +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 print("All invoice Details ",args) results = cursor.callproc('SaveInvoice', args) - # cursor.callproc("SaveInvoice",args) - # for re in cursor.stored_results(): + invoice_id = results[-1] print("invoice id from the excel ", invoice_id) @@ -2149,11 +2543,7 @@ def save_data(): "hold_amount": hold_amount } - # insert_hold_query = """INSERT INTO invoice_subcontractor_hold_join (Contractor_Id, Invoice_Id, hold_type_id, hold_amount) - # VALUES (%(Contractor_Id)s, %(Invoice_Id)s, %(hold_type_id)s, %(hold_amount)s); - # """ - # cursor.execute(insert_hold_query, hold_join_data) - # print(f"Inserted hold join data: {hold_join_data}") + cursor.callproc('InsertHoldJoinData', [ hold_join_data['Contractor_Id'], hold_join_data['Invoice_Id'], hold_join_data['hold_type_id'], hold_join_data['hold_amount'] @@ -2174,6 +2564,10 @@ def save_data(): """INSERT INTO credit_note (PMC_No, Invoice_Details, Basic_Amount, Debit_Amount, After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Contractor_Id, invoice_no) VALUES (%s,%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,%s)""", ( PMC_No, Invoice_Details, Basic_Amount, Debit_Amount, After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, subcontractor_id, Invoice_No)) #-----------------------------------------------Hold Amount---------------------------------------------------------------------- +<<<<<<< HEAD +======= + import re +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # Step 1: Normalize Invoice_Details: lowercase, trim, remove extra spaces normalized_details = re.sub(r'\s+', ' ', Invoice_Details.strip()).lower() @@ -2208,27 +2602,33 @@ def save_data(): elif Invoice_Details and any( keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']): print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id) +<<<<<<< HEAD #cursor.callproc("SaveGSTRelease", (PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR)) +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 cursor.execute( """INSERT INTO gst_release (PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, Contractor_Id) VALUES (%s,%s, %s, %s, %s, %s, %s)""", (PMC_No, Invoice_No, Basic_Amount, Final_Amount, Total_Amount, UTR, subcontractor_id)) - # insert_payment = """INSERT INTO payment (PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR) VALUES (%s, %s, %s, %s, %s, %s)""" - # cursor.execute(insert_payment, - # (PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR)) + if PMC_No and Total_Amount and UTR: print("Payment :", PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR ) +<<<<<<< HEAD # insert_payment = """INSERT INTO payment (PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR) VALUES (%s, %s, %s, %s, %s, %s)""" # cursor.execute(insert_payment, # (PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR)) +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 cursor.callproc("SavePayment", (PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR )) connection.commit() return jsonify({"success": "Data saved successfully!"}), 200 - # return render_template('uploadExcelFile.html') + except Exception as e: connection.rollback() return jsonify({"error": f"An unexpected error occurred: {e}"}), 500 @@ -2264,7 +2664,11 @@ def search_contractor(): conditions = [] params = [] +<<<<<<< HEAD LogHelper.log_action("Search contractor", f"User {current_user.id} Search contractor'{ subcontractor_name}'") +======= + log_action("Search contractor", f"User {current_user.id} Search contractor'{ subcontractor_name}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 if subcontractor_name: conditions.append("LOWER(s.Contractor_Name) LIKE LOWER(%s)") params.append(f"%{subcontractor_name}%") @@ -2291,21 +2695,7 @@ def search_contractor(): if not conditions: return jsonify({"error": "At least one field is required for search."}), 400 - # query = f""" - # SELECT DISTINCT s.Contractor_Id, s.Contractor_Name, i.PMC_No, st.State_Name, - # d.District_Name, b.Block_Name, v.Village_Name - # FROM subcontractors s - # INNER JOIN assign_subcontractors asg ON s.Contractor_Id = asg.Contractor_Id - # INNER JOIN villages v ON asg.Village_Id = v.Village_Id - # INNER JOIN invoice i ON i.Village_Id = asg.Village_Id AND i.PMC_No = asg.PMC_No - # LEFT JOIN blocks b ON v.Block_Id = b.Block_Id - # LEFT JOIN districts d ON b.District_id = d.District_id - # LEFT JOIN states st ON d.State_Id = st.State_Id - # WHERE {' AND '.join(conditions)} - # ORDER BY s.Contractor_Name ASC, i.PMC_No ASC - # """ - # cursor.execute(query, tuple(params)) - # data = cursor.fetchall() + cursor.callproc("search_contractor_info", [ subcontractor_name or None, pmc_no or None, @@ -2324,6 +2714,12 @@ def search_contractor(): +<<<<<<< HEAD +======= +from flask import render_template +from datetime import datetime +import config +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @app.route('/contractor_report/') def contractor_report(contractor_id): @@ -2467,6 +2863,10 @@ def contractor_report(contractor_id): current_date=current_date) +<<<<<<< HEAD +======= +from openpyxl import Workbook +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # # Download report by contractor id # # Download report by contractor id @@ -2475,23 +2875,71 @@ def contractor_report(contractor_id): class FilePathData: downloadReportFolder = "static/download" +<<<<<<< HEAD +======= + +from flask import send_from_directory +import os +import openpyxl +from openpyxl.styles import Font, PatternFill +from decimal import Decimal +from datetime import datetime + +from flask import send_from_directory +import os +import openpyxl +from openpyxl.styles import Font, PatternFill +from decimal import Decimal +from datetime import datetime + +from flask import send_from_directory +from decimal import Decimal +from datetime import datetime +import os +import openpyxl +from openpyxl.styles import Font, PatternFill +import config + + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @app.route('/download_report/') def download_report(contractor_id): connection = config.get_db_connection() cursor = connection.cursor(dictionary=True, buffered=True) +<<<<<<< HEAD output_folder = FilePathData.downloadReportFolder +======= + output_folder = "static/download" +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 os.makedirs(output_folder, exist_ok=True) output_file = os.path.join(output_folder, f"Contractor_Report_{contractor_id}.xlsx") try: # ---------------- Contractor Info ---------------- +<<<<<<< HEAD contractor = ContractorInfo(contractor_id) contInfo = contractor.contInfo if not contractor.contInfo: +======= + cursor.execute(""" + SELECT s.Contractor_Name, st.State_Name, d.District_Name, b.Block_Name, + s.Mobile_No, s.GST_Registration_Type, s.GST_No, s.PAN_No, + s.Email, s.Address + FROM subcontractors s + LEFT JOIN assign_subcontractors asg ON s.Contractor_Id = asg.Contractor_Id + LEFT JOIN villages v ON asg.Village_Id = v.Village_Id + LEFT JOIN blocks b ON v.Block_Id = b.Block_Id + LEFT JOIN districts d ON b.District_id = d.District_id + LEFT JOIN states st ON d.State_Id = st.State_Id + WHERE s.Contractor_Id = %s + """, (contractor_id,)) + contInfo = cursor.fetchone() + if not contInfo: +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return "No contractor found", 404 # ---------------- Hold Types ---------------- @@ -2645,8 +3093,22 @@ def download_report(contractor_id): for ht_id in hold_type_map: row.append(invoice_holds.get(ht_id, "")) +<<<<<<< HEAD # Payment values payment = payments_map.get(key, [None])[0] +======= + + + payment_list = payments_map.get(key, []) + + # Pop the first payment if available + payment = payment_list.pop(0) if payment_list else None + + # If the list becomes empty, remove the key + if not payment_list and key in payments_map: + del payments_map[key] + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 row += [ inv["Final_Amount"], payment["Payment_Amount"] if payment else "", @@ -2654,6 +3116,7 @@ def download_report(contractor_id): payment["Total_amount"] if payment else "", payment["utr"] if payment and payment.get("utr") else "" ] + sheet.append(row) # ---------------- Extra Payments for this PMC ---------------- @@ -2747,21 +3210,7 @@ def pmc_report(pmc_no): cursor = connection.cursor(dictionary=True, buffered=True) try: - # 1. Fetch PMC info using stored procedure - # cursor.execute(""" - # SELECT DISTINCT a.PMC_No, a.Village_Id, v.Village_Name, b.Block_Name, - # d.District_Name, s.State_Name, sc.Contractor_Id, sc.Contractor_Name, - # sc.Address, sc.Mobile_No, sc.PAN_No, sc.Email, sc.Gender, - # sc.GST_Registration_Type, sc.GST_No - # FROM assign_subcontractors a - # INNER JOIN villages v ON a.Village_Id = v.Village_Id - # INNER JOIN blocks b ON v.Block_Id = b.Block_Id - # INNER JOIN districts d ON b.District_id = d.District_id - # INNER JOIN states s ON d.State_Id = s.State_Id - # INNER JOIN subcontractors sc ON a.Contractor_Id = sc.Contractor_Id - # WHERE a.pmc_no = %s - # """, (pmc_no,)) - # pmc_info = cursor.fetchone() + cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,)) pmc_info = next(cursor.stored_results()).fetchone() @@ -2769,16 +3218,7 @@ def pmc_report(pmc_no): if not pmc_info: return "No PMC found with this number", 404 - # 2. Fetch hold types using stored procedure - # cursor.execute(""" - # SELECT DISTINCT ht.hold_type_id, ht.hold_type - # FROM invoice_subcontractor_hold_join h - # JOIN hold_types ht ON h.hold_type_id = ht.hold_type_id - # JOIN invoice i ON h.Invoice_Id = i.Invoice_Id - # JOIN assign_subcontractors a ON i.PMC_No = a.PMC_No - # WHERE a.PMC_No = %s AND a.Contractor_Id = %s - # """, (pmc_no, pmc_info["Contractor_Id"])) - # hold_types = cursor.fetchall() + cursor.callproc("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"])) hold_types = next(cursor.stored_results()).fetchall() hold_type_ids = [ht['hold_type_id'] for ht in hold_types] @@ -2837,13 +3277,7 @@ def pmc_report(pmc_no): ORDER BY invoice_no ASC """, (pmc_no,)) gst_rel = cursor.fetchall() - # gst_rel = cursor.fetchall() - # cursor.callproc('GetGSTReleaseByPMC', [pmc_no]) - # - # # Fetch results - # for result in cursor.stored_results(): - # gst_rel = result.fetchall() - + total_gst_basic = sum(row.get('basic_amount', 0) or 0 for row in gst_rel) total_gst_final = sum(row.get('final_amount', 0) or 0 for row in gst_rel) @@ -2866,10 +3300,7 @@ def pmc_report(pmc_no): ORDER BY invoice_no ASC """, (pmc_no,)) payments = cursor.fetchall() - # cursor.callproc('GetPaymentByPMC', [pmc_no]) - # - # for result in cursor.stored_results(): - # payments = result.fetchall() + total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments) total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments) @@ -2916,883 +3347,7 @@ def pmc_report(pmc_no): ) -# # Download report by PMC No -# @app.route('/download_pmc_report/') -# def download_pmc_report(pmc_no): -# connection = config.get_db_connection() -# output_folder = "static/download" -# output_file = os.path.join(output_folder, f"PMC_Report_{pmc_no}.xlsx") -# if not os.path.exists(output_folder): -# os.makedirs(output_folder) - -# cursor = connection.cursor(dictionary=True) - -# try: -# # # Fetch Contractor Details using PMC No -# # cursor.execute(""" -# # SELECT DISTINCT s.Contractor_Id, s.Contractor_Name, st.State_Name, d.District_Name, b.Block_Name, -# # s.Mobile_No, s.GST_Registration_Type, s.GST_No, s.PAN_No, s.Email, s.Address -# # FROM subcontractors s -# # LEFT JOIN assign_subcontractors asg ON s.Contractor_Id = asg.Contractor_Id -# # LEFT JOIN villages v ON asg.Village_Id = v.Village_Id -# # LEFT JOIN blocks b ON v.Block_Id = b.Block_Id -# # LEFT JOIN districts d ON b.District_id = d.District_id -# # LEFT JOIN states st ON d.State_Id = st.State_Id -# # WHERE asg.PMC_No = %s -# # """, (pmc_no,)) -# # contractor_info = cursor.fetchone() -# cursor.callproc('GetContractorDetailsByPMC', [pmc_no]) - -# # Now fetch the result: -# for result in cursor.stored_results(): -# contractor_info = result.fetchone() - -# if not contractor_info: -# return "No contractor found for this PMC No", 404 - -# # # Fetch distinct hold types present for the contractor -# # cursor.execute(""" -# # SELECT DISTINCT ht.hold_type_id, ht.hold_type -# # FROM invoice_subcontractor_hold_join h -# # JOIN hold_types ht ON h.hold_type_id = ht.hold_type_id -# # WHERE h.Contractor_Id = %s -# # """, (contractor_info["Contractor_Id"],)) -# # hold_types = cursor.fetchall() -# cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) - -# for result in cursor.stored_results(): -# hold_types = result.fetchall() - -# hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} - -# # # # Fetch Invoices & GST Releases -# # cursor.execute(""" -# # SELECT DISTINCT i.Invoice_Id, i.PMC_No, v.Village_Name, i.Work_Type, i.Invoice_Details, -# # i.Invoice_Date, i.Invoice_No, i.Basic_Amount, i.Debit_Amount, -# # i.After_Debit_Amount, i.GST_Amount, i.Amount, i.TDS_Amount, i.SD_Amount, -# # i.On_Commission, i.Hydro_Testing, i.GST_SD_Amount, i.Final_Amount, -# # g.pmc_no AS gst_pmc_no, g.invoice_no AS gst_invoice_no, -# # g.basic_amount AS gst_basic_amount, g.final_amount AS gst_final_amount -# # FROM invoice i -# # LEFT JOIN assign_subcontractors asg ON i.PMC_No = asg.PMC_No -# # LEFT JOIN villages v ON i.Village_Id = v.Village_Id -# # LEFT JOIN gst_release g ON i.PMC_No = g.pmc_no AND i.Invoice_No = g.invoice_no -# # WHERE asg.PMC_No = %s -# # ORDER BY i.Invoice_Date, i.Invoice_No -# # """, (pmc_no,)) -# # invoices = cursor.fetchall() - -# cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no]) - -# for result in cursor.stored_results(): -# invoices = result.fetchall() -# print("pmc_report invoice data:",invoices) - -# # cursor.callproc('GetInvoicesAndGSTReleasesByPMC', [pmc_no]) - -# # for result in cursor.stored_results(): -# # invoices = result.fetchall() - -# # # Fetch Hold Amounts separately -# # cursor.execute(""" -# # SELECT h.Invoice_Id, ht.hold_type_id, h.hold_amount -# # FROM invoice_subcontractor_hold_join h -# # JOIN hold_types ht ON h.hold_type_id = ht.hold_type_id -# # WHERE h.Contractor_Id = %s -# # """, (contractor_info["Contractor_Id"],)) -# # hold_amounts = cursor.fetchall() -# cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) - -# for result in cursor.stored_results(): -# hold_amounts = result.fetchall() - -# # Create a mapping of invoice_id to hold amounts by type -# hold_data = {} -# for h in hold_amounts: -# hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] - -# # # Fetch all Payments for the PMC number -# # cursor.execute(""" -# # SELECT pmc_no, invoice_no, Payment_Amount, TDS_Payment_Amount, Total_amount, UTR -# # FROM payment -# # WHERE pmc_no = %s -# # ORDER BY invoice_no -# # """, (pmc_no,)) -# # all_payments = cursor.fetchall() -# cursor.callproc('GetAllPaymentsByPMC', [pmc_no]) - -# for result in cursor.stored_results(): -# all_payments = result.fetchall() - -# # Organize payments by Invoice No (both regular and GST release notes) -# payments_map = {} -# extra_payments = [] -# for pay in all_payments: -# if pay['invoice_no']: -# key = pay['invoice_no'] -# if key not in payments_map: -# payments_map[key] = [] -# payments_map[key].append(pay) -# else: -# extra_payments.append(pay) - -# # Create Excel workbook -# workbook = openpyxl.Workbook() -# sheet = workbook.active -# sheet.title = "PMC Report" - -# # Write Contractor Details -# sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD.", "", ""]) -# sheet.append( -# ["Contractor Name", contractor_info["Contractor_Name"], " ", "GST No", contractor_info["GST_No"], " ", -# "GST Type", contractor_info["GST_Registration_Type"]]) -# sheet.append(["State", contractor_info["State_Name"], " ", "PAN No", contractor_info["PAN_No"], " ", "Address", -# contractor_info["Address"]]) -# sheet.append(["District", contractor_info["District_Name"], " ", "Mobile No", contractor_info["Mobile_No"]]) -# sheet.append(["Block", contractor_info["Block_Name"], " ", "Email", contractor_info["Email"]]) -# sheet.append([]) - -# # Table Headers - include all hold types as separate columns -# base_headers = ["PMC No", "Village", "Work Type", "Invoice Details", "Invoice Date", "Invoice No", -# "Basic Amount", "Debit", "After Debit Amount", "GST (18%)", "Amount", "TDS (1%)", -# "SD (5%)", "On Commission", "Hydro Testing", "GST SD Amount"] - -# hold_headers = [ht['hold_type'] for ht in hold_types] - -# payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"] - -# sheet.append(base_headers + hold_headers + payment_headers) - -# seen_invoices = set() -# seen_gst_notes = set() -# processed_payments = set() - -# # Process invoices -# for inv in invoices: -# invoice_no = inv["Invoice_No"] -# payments = payments_map.get(invoice_no, []) - -# # Process invoice row with first payment (if exists) -# if invoice_no not in seen_invoices: -# seen_invoices.add(invoice_no) -# first_payment = payments[0] if len(payments) > 0 else None - -# # Base invoice data -# row = [ -# pmc_no, inv["Village_Name"], inv["Work_Type"], inv["Invoice_Details"], -# inv["Invoice_Date"], invoice_no, inv["Basic_Amount"], inv["Debit_Amount"], -# inv["After_Debit_Amount"], inv["GST_Amount"], inv["Amount"], inv["TDS_Amount"], -# inv["SD_Amount"], inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"] -# ] - -# # Add hold amounts for each hold type -# invoice_holds = hold_data.get(inv["Invoice_Id"], {}) -# for ht_id in hold_type_map.keys(): -# row.append(invoice_holds.get(ht_id, "")) - -# # Add payment information -# row += [ -# inv["Final_Amount"], -# first_payment["Payment_Amount"] if first_payment else "", -# first_payment["TDS_Payment_Amount"] if first_payment else "", -# first_payment["Total_amount"] if first_payment else "", -# first_payment["UTR"] if first_payment else "" -# ] - -# sheet.append(row) - -# if first_payment: -# payment_id = f"{invoice_no}-{first_payment['Payment_Amount']}-{first_payment.get('UTR', '')}" -# processed_payments.add(payment_id) - -# # Process GST release if exists (only if we have a matching GST record) -# if inv["gst_pmc_no"] and inv["gst_invoice_no"] and inv["gst_invoice_no"] not in seen_gst_notes: -# seen_gst_notes.add(inv["gst_invoice_no"]) - -# # Find the payment that matches this GST release -# gst_payment = None -# for payment in payments[1:]: # Skip first payment (already used for invoice) -# if payment['invoice_no'] == inv["gst_invoice_no"]: -# gst_payment = payment -# break - -# # If no payment found in the invoice's payments, check all payments -# if not gst_payment: -# gst_payments = payments_map.get(inv["gst_invoice_no"], []) -# if gst_payments: -# gst_payment = gst_payments[0] - -# # GST release row -# row = [ -# pmc_no, "", "", "GST Release Note", "", inv["gst_invoice_no"], -# inv["gst_basic_amount"], "", "", "", "", "", "", "", "", "" # Empty GST SD Amount -# ] - -# # Empty holds for GST release -# row += ["" for _ in hold_headers] - -# # Add payment information -# row += [ -# inv["gst_final_amount"], -# gst_payment["Payment_Amount"] if gst_payment else "", -# gst_payment["TDS_Payment_Amount"] if gst_payment else "", -# gst_payment["Total_amount"] if gst_payment else "", -# gst_payment["UTR"] if gst_payment else "" -# ] - -# sheet.append(row) - -# if gst_payment: -# payment_id = f"{inv['gst_invoice_no']}-{gst_payment['Payment_Amount']}-{gst_payment.get('UTR', '')}" -# processed_payments.add(payment_id) - -# # Process remaining payments as extra payments -# for payment in payments[1:]: -# payment_id = f"{payment['invoice_no']}-{payment['Payment_Amount']}-{payment.get('UTR', '')}" -# if payment_id not in processed_payments: -# row = [ -# pmc_no, "", "", "", "", payment['invoice_no'], -# "", "", "", "", "", "", "", "", "", "" # Empty GST SD Amount -# ] - -# # Empty holds for extra payments -# row += ["" for _ in hold_headers] - -# # Add payment information -# row += [ -# "", -# payment["Payment_Amount"], -# payment["TDS_Payment_Amount"], -# payment["Total_amount"], -# payment["UTR"] -# ] - -# sheet.append(row) -# processed_payments.add(payment_id) - -# # Process extra payments (null invoice_no) -# for payment in extra_payments: -# payment_id = f"null-{payment['Payment_Amount']}-{payment.get('UTR', '')}" -# if payment_id not in processed_payments: -# row = [ -# pmc_no, "", "", "", "", "", -# "", "", "", "", "", "", "", "", "", "" # Empty GST SD Amount -# ] - -# # Empty holds for null invoice payments -# row += ["" for _ in hold_headers] - -# # Add payment information -# row += [ -# "", -# payment["Payment_Amount"], -# payment["TDS_Payment_Amount"], -# payment["Total_amount"], -# payment["UTR"] -# ] - -# sheet.append(row) -# processed_payments.add(payment_id) - -# # Calculate totals -# total_basic_amount = 0 -# total_tds_amount = 0 -# total_sd_amount = 0 -# total_on_commission = 0 -# total_hold_amount = 0 -# total_final_amount = 0 -# total_payment_amount = 0 -# total_tds_payment_amount = 0 -# total_total_paid = 0 - -# for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row, values_only=True): -# try: -# total_basic_amount += float(row[6] or 0) # Basic_Amount -# total_tds_amount += float(row[11] or 0) # TDS_Amount -# total_sd_amount += float(row[12] or 0) # SD_Amount -# total_on_commission += float(row[13] or 0) # On_Commission -# total_final_amount += float(row[-5] or 0) # Final_Amount -# total_payment_amount += float(row[-4] or 0) # Payment_Amount -# total_tds_payment_amount += float(row[-3] or 0) # TDS_Payment -# total_total_paid += float(row[-2] or 0) # Total_Paid - -# # Sum of hold amounts -# hold_start_col = len(base_headers) -# hold_end_col = hold_start_col + len(hold_headers) -# total_hold_amount += sum(float(row[i] or 0) for i in range(hold_start_col, hold_end_col)) -# except (ValueError, IndexError, TypeError): -# continue - -# # Append totals row -# totals_row = [ -# "TOTAL", "", "", "", "", "", -# total_basic_amount, "", "", "", "", total_tds_amount, total_sd_amount, -# total_on_commission, "", "", # Empty GST SD Amount -# ] - -# # Add hold totals -# totals_row += [total_hold_amount] + [""] * (len(hold_headers) - 1) - -# # Add payment totals -# totals_row += [ -# total_final_amount, -# total_payment_amount, -# total_tds_payment_amount, -# total_total_paid, -# "" # UTR column remains empty -# ] - -# sheet.append([]) -# sheet.append(totals_row) - -# # Make totals row bold -# for cell in sheet[sheet.max_row]: -# cell.font = Font(bold=True) - -# # Save Excel file -# workbook.save(output_file) -# workbook.close() - -# finally: -# cursor.close() -# connection.close() - -# return send_from_directory(output_folder, f"PMC_Report_{pmc_no}.xlsx", as_attachment=True) - - - -# @app.route('/download_pmc_report/') -# def download_pmc_report(pmc_no): -# connection = config.get_db_connection() -# output_folder = "static/download" -# output_file = os.path.join(output_folder, f"PMC_Report_{pmc_no}.xlsx") -# -# if not os.path.exists(output_folder): -# os.makedirs(output_folder) -# -# cursor = connection.cursor(dictionary=True) -# -# try: -# cursor.callproc('GetContractorDetailsByPMC', [pmc_no]) -# -# for result in cursor.stored_results(): -# contractor_info = result.fetchone() -# -# if not contractor_info: -# return "No contractor found for this PMC No", 404 -# -# cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) -# -# for result in cursor.stored_results(): -# hold_types = result.fetchall() -# -# hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} -# -# cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no]) -# -# for result in cursor.stored_results(): -# invoices = result.fetchall() -# total_tds=Decimal('0.00') -# final_amount=Decimal('0.00') -# # total_hold_amount=Decimal('0.00') -# for data in invoices: -# total_tds=total_tds+data.get('TDS_Amount',Decimal('0.00')) -# final_amount=final_amount+data.get('Final_Amount',Decimal('0.00')) -# -# cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) -# -# for result in cursor.stored_results(): -# hold_amounts = result.fetchall() -# -# hold_data = {} -# for h in hold_amounts: -# hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] -# -# cursor.callproc('GetAllPaymentsByPMC', [pmc_no]) -# -# for result in cursor.stored_results(): -# all_payments = result.fetchall() -# total_amount=Decimal('0.00') -# for d in all_payments: -# total_amount=total_amount+ d.get('Total_Amount',Decimal('0.00')) -# total_amount_paid= final_amount- total_amount; -# payments_map = {} -# extra_payments = [] -# for pay in all_payments: -# if pay['invoice_no']: -# key = pay['invoice_no'] -# if key not in payments_map: -# payments_map[key] = [] -# payments_map[key].append(pay) -# else: -# extra_payments.append(pay) -# -# workbook = openpyxl.Workbook() -# sheet = workbook.active -# sheet.title = "PMC Report" -# -# # Write Contractor Details -# sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD.", "", ""]) -# sheet.append( -# ["Contractor Name", contractor_info["Contractor_Name"], " ", "GST No", contractor_info["GST_No"], " ", -# "GST Type", contractor_info["GST_Registration_Type"]]) -# sheet.append(["State", contractor_info["State_Name"], " ", "PAN No", contractor_info["PAN_No"], " ", "Address", -# contractor_info["Address"]]) -# sheet.append(["District", contractor_info["District_Name"], " ", "Mobile No", contractor_info["Mobile_No"]]) -# sheet.append(["Block", contractor_info["Block_Name"], " ", "Email", contractor_info["Email"]]) -# sheet.append([]) -# -# # Table Headers - include all hold types as separate columns -# base_headers = ["PMC No", "Village", "Work Type", "Invoice Details", "Invoice Date", "Invoice No", -# "Basic Amount", "Debit", "After Debit Amount", "GST (18%)", "Amount", "TDS (1%)", -# "SD (5%)", "On Commission", "Hydro Testing", "GST SD Amount"] -# -# hold_headers = [ht['hold_type'] for ht in hold_types] -# -# payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"] -# -# sheet.append(base_headers + hold_headers + payment_headers) -# -# seen_invoices = set() -# seen_gst_notes = set() -# processed_payments = set() -# -# # Process invoices -# for inv in invoices: -# invoice_no = inv["Invoice_No"] -# payments = payments_map.get(invoice_no, []) -# -# # Process invoice row with first payment (if exists) -# if invoice_no not in seen_invoices: -# seen_invoices.add(invoice_no) -# first_payment = payments[0] if len(payments) > 0 else None -# -# # Base invoice data -# row = [ -# pmc_no, inv["Village_Name"], inv["Work_Type"], inv["Invoice_Details"], -# inv["Invoice_Date"], invoice_no, inv["Basic_Amount"], inv["Debit_Amount"], -# inv["After_Debit_Amount"], inv["GST_Amount"], inv["Amount"], inv["TDS_Amount"], -# inv["SD_Amount"], inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"] -# ] -# -# # Add hold amounts for each hold type -# invoice_holds = hold_data.get(inv["Invoice_Id"], {}) -# for ht_id in hold_type_map.keys(): -# row.append(invoice_holds.get(ht_id, "")) -# -# # Add payment information -# row += [ -# inv["Final_Amount"], -# first_payment["Payment_Amount"] if first_payment else "", -# first_payment["TDS_Payment_Amount"] if first_payment else "", -# first_payment["Total_amount"] if first_payment else "", -# first_payment["UTR"] if first_payment else "" -# ] -# -# sheet.append(row) -# -# if first_payment: -# payment_id = f"{invoice_no}-{first_payment['Payment_Amount']}-{first_payment.get('UTR', '')}" -# processed_payments.add(payment_id) -# -# # Process GST release if exists (only if we have a matching GST record) -# if inv["gst_pmc_no"] and inv["gst_invoice_no"] and inv["gst_invoice_no"] not in seen_gst_notes: -# seen_gst_notes.add(inv["gst_invoice_no"]) -# -# # Find the payment that matches this GST release -# gst_payment = None -# for payment in payments[1:]: # Skip first payment (already used for invoice) -# if payment['invoice_no'] == inv["gst_invoice_no"]: -# gst_payment = payment -# break -# -# # If no payment found in the invoice's payments, check all payments -# if not gst_payment: -# gst_payments = payments_map.get(inv["gst_invoice_no"], []) -# if gst_payments: -# gst_payment = gst_payments[0] -# -# # GST release row (this will be in the same row, after the invoice information) -# gst_row = [ -# pmc_no, "", "", "GST Release Note", "", inv["gst_invoice_no"], -# inv["gst_basic_amount"], "", "", "", "", "", "", "", "", "" # Empty GST SD Amount -# ] -# -# # Empty holds for GST release -# gst_row += ["" for _ in hold_headers] -# -# # Add GST payment information (same columns as invoice payment information) -# gst_row += [ -# inv["gst_final_amount"], -# gst_payment["Payment_Amount"] if gst_payment else "", -# gst_payment["TDS_Payment_Amount"] if gst_payment else "", -# gst_payment["Total_amount"] if gst_payment else "", -# gst_payment["UTR"] if gst_payment else "" -# ] -# -# sheet.append(gst_row) -# -# if gst_payment: -# payment_id = f"{inv['gst_invoice_no']}-{gst_payment['Payment_Amount']}-{gst_payment.get('UTR', '')}" -# processed_payments.add(payment_id) -# -# # Process remaining payments as extra payments (if any) -# for payment in payments[1:]: -# payment_id = f"{payment['invoice_no']}-{payment['Payment_Amount']}-{payment.get('UTR', '')}" -# if payment_id not in processed_payments: -# row = [ -# pmc_no, "", "", "", "", payment['invoice_no'], -# "", "", "", "", "", "", "", "", "", "" # Empty GST SD Amount -# ] -# -# # Empty holds for extra payments -# row += ["" for _ in hold_headers] -# -# # Add payment information -# row += [ -# "", -# payment["Payment_Amount"], -# payment["TDS_Payment_Amount"], -# payment["Total_amount"], -# payment["UTR"] -# ] -# -# sheet.append(row) -# processed_payments.add(payment_id) -# -# # Process extra payments (null invoice_no) -# for payment in extra_payments: -# payment_id = f"null-{payment['Payment_Amount']}-{payment.get('UTR', '')}" -# if payment_id not in processed_payments: -# row = [ -# pmc_no, "", "", "", "", "", -# "", "", "", "", "", "", "", "", "", "" # Empty GST SD Amount -# ] -# -# # Empty holds for null invoice payments -# row += ["" for _ in hold_headers] -# -# # Add payment information -# row += [ -# "", -# payment["Payment_Amount"], -# payment["TDS_Payment_Amount"], -# payment["Total_amount"], -# payment["UTR"] -# ] -# -# sheet.append(row) -# processed_payments.add(payment_id) -# -# # Calculate totals -# total_basic_amount = 0 -# total_tds_amount = 0 -# total_sd_amount = 0 -# total_on_commission = 0 -# total_hold_amount = 0 -# total_final_amount = 0 -# total_payment_amount = 0 -# total_tds_payment_amount = 0 -# total_total_paid = 0 -# -# for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row, values_only=True): -# try: -# total_basic_amount += float(row[6] or 0) # Basic_Amount -# total_tds_amount += float(row[11] or 0) # TDS_Amount -# total_sd_amount += float(row[12] or 0) # SD_Amount -# total_on_commission += float(row[13] or 0) # On_Commission -# total_final_amount += float(row[-5] or 0) # Final_Amount -# total_payment_amount += float(row[-4] or 0) # Payment_Amount -# total_tds_payment_amount += float(row[-3] or 0) # TDS_Payment -# total_total_paid += float(row[-2] or 0) # Total_Paid -# -# # Sum of hold amounts -# hold_start_col = len(base_headers) -# hold_end_col = hold_start_col + len(hold_headers) -# total_hold_amount += sum(float(row[i] or 0) for i in range(hold_start_col, hold_end_col)) -# except (ValueError, IndexError, TypeError): -# continue -# -# # Append totals row -# totals_row = [ -# "TOTAL", "", "", "", "", "", -# total_basic_amount, "", "", "", "", total_tds_amount, total_sd_amount, -# total_on_commission, "", "", # Empty GST SD Amount -# ] -# if hold_headers: -# totals_row += [total_hold_amount] + [""] * (len(hold_headers) - 1) -# -# # Add payment totals -# totals_row += [ -# total_final_amount, -# total_payment_amount, -# total_tds_payment_amount, -# total_total_paid, -# "" # UTR column remains empty -# ] -# -# sheet.append([]) -# sheet.append(totals_row) -# #new code added for small chart---summary -# total_hold_amount=Decimal('0.00') -# for d in invoices: -# total_hold_amount = total_hold_amount + d.get('SD_Amount', Decimal('0.00')) + d.get('On_Commission', -# Decimal( -# '0.00')) + d.get( -# 'Hydro_Testing', Decimal('0.00')) -# for data in hold_amounts: -# total_hold_amount = total_hold_amount + data.get('hold_amount', Decimal('0.00')) -# print("Total Hold Amount after adding the hold amount ", total_hold_amount) -# -# # Add payment information -# # Get today's date -# today_date = datetime.today().strftime('%A,%Y-%m-%d') -# # Add headers (optional) -# sheet.append(["Contractor Name", contractor_info["Contractor_Name"]]) -# sheet.append(["Date", today_date]) -# sheet.append(["Description", "Amount"]) -# # Add your values -# sheet.append(["Advance/Surplus", str(total_final_amount-total_payment_amount)]) -# sheet.append(["Total Hold Amount", str(total_hold_amount)]) -# sheet.append(["Amount With TDS", str(total_tds_payment_amount)]) -# # new coded ended here for summary chart -# # Make totals row bold -# for cell in sheet[sheet.max_row]: -# cell.font = Font(bold=True) -# -# # Save Excel file -# workbook.save(output_file) -# workbook.close() -# -# finally: -# cursor.close() -# connection.close() -# -# return send_from_directory(output_folder, f"PMC_Report_{pmc_no}.xlsx", as_attachment=True) - -# @app.route('/download_pmc_report/') -# def download_pmc_report(pmc_no): -# connection = config.get_db_connection() -# output_folder = "static/download" -# output_file = os.path.join(output_folder, f"PMC_Report_{pmc_no}.xlsx") -# -# if not os.path.exists(output_folder): -# os.makedirs(output_folder) -# -# cursor = connection.cursor(dictionary=True) -# -# try: -# cursor.callproc('GetContractorDetailsByPMC', [pmc_no]) -# contractor_info = next(cursor.stored_results()).fetchone() -# -# if not contractor_info: -# return "No contractor found for this PMC No", 404 -# -# cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) -# hold_types = next(cursor.stored_results()).fetchall() -# hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} -# -# cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no]) -# invoices = next(cursor.stored_results()).fetchall() -# -# cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) -# hold_amounts = next(cursor.stored_results()).fetchall() -# hold_data = {} -# for h in hold_amounts: -# hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] -# -# cursor.callproc('GetAllPaymentsByPMC', [pmc_no]) -# all_payments = next(cursor.stored_results()).fetchall() -# -# payments_map = {} -# extra_payments = [] -# for pay in all_payments: -# if pay['invoice_no']: -# payments_map.setdefault(pay['invoice_no'], []).append(pay) -# else: -# extra_payments.append(pay) -# -# workbook = openpyxl.Workbook() -# sheet = workbook.active -# sheet.title = "PMC Report" -# -# # Write contractor header -# sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."]) -# sheet.append(["Contractor Name", contractor_info["Contractor_Name"], "", "GST No", contractor_info["GST_No"], "", "GST Type", contractor_info["GST_Registration_Type"]]) -# sheet.append(["State", contractor_info["State_Name"], "", "PAN No", contractor_info["PAN_No"], "", "Address", contractor_info["Address"]]) -# sheet.append(["District", contractor_info["District_Name"], "", "Mobile No", contractor_info["Mobile_No"]]) -# sheet.append(["Block", contractor_info["Block_Name"], "", "Email", contractor_info["Email"]]) -# sheet.append([]) -# -# base_headers = ["PMC No", "Village", "Work Type", "Invoice Details", "Invoice Date", "Invoice No", -# "Basic Amount", "Debit", "After Debit Amount", "GST (18%)", "Amount", "TDS (1%)", -# "SD (5%)", "On Commission", "Hydro Testing", "GST SD Amount"] -# -# hold_headers = [ht['hold_type'] for ht in hold_types] -# payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"] -# sheet.append(base_headers + hold_headers + payment_headers) -# # Style the headers -# header_fill=PatternFill(start_color="ADD8E6",end_color="ADD8E6",fill_type="solid") -# header_font=Font(bold=True) -# for cell in sheet[sheet.max_row]: -# cell.font=header_font -# cell.fill=header_fill -# -# seen_invoices = set() -# seen_gst_notes = set() -# processed_payments = set() -# -# for inv in invoices: -# invoice_no = inv["Invoice_No"] -# payments = payments_map.get(invoice_no, []) -# -# if invoice_no not in seen_invoices: -# seen_invoices.add(invoice_no) -# first_payment = payments[0] if payments else None -# -# row = [ -# pmc_no, inv["Village_Name"], inv["Work_Type"], inv["Invoice_Details"], -# inv["Invoice_Date"], invoice_no, inv["Basic_Amount"], inv["Debit_Amount"], -# inv["After_Debit_Amount"], inv["GST_Amount"], inv["Amount"], inv["TDS_Amount"], -# inv["SD_Amount"], inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"] -# ] -# -# invoice_holds = hold_data.get(inv["Invoice_Id"], {}) -# for ht_id in hold_type_map.keys(): -# row.append(invoice_holds.get(ht_id, "")) -# -# row += [ -# inv["Final_Amount"], -# first_payment["Payment_Amount"] if first_payment else "", -# first_payment["TDS_Payment_Amount"] if first_payment else "", -# first_payment["Total_amount"] if first_payment else "", -# first_payment["UTR"] if first_payment else "" -# ] -# -# sheet.append(row) -# -# if first_payment: -# processed_payments.add(f"{invoice_no}-{first_payment['Payment_Amount']}-{first_payment.get('UTR', '')}") -# -# if inv["gst_pmc_no"] and inv["gst_invoice_no"] and inv["gst_invoice_no"] not in seen_gst_notes: -# seen_gst_notes.add(inv["gst_invoice_no"]) -# gst_payment = None -# for payment in payments[1:]: -# if payment['invoice_no'] == inv["gst_invoice_no"]: -# gst_payment = payment -# break -# if not gst_payment: -# gst_payment = payments_map.get(inv["gst_invoice_no"], [None])[0] -# -# gst_row = [ -# pmc_no, "", "", "GST Release Note", "", inv["gst_invoice_no"], -# inv["gst_basic_amount"], "", "", "", "", "", "", "", "", "" -# ] -# gst_row += ["" for _ in hold_headers] -# gst_row += [ -# inv["gst_final_amount"], -# gst_payment["Payment_Amount"] if gst_payment else "", -# gst_payment["TDS_Payment_Amount"] if gst_payment else "", -# gst_payment["Total_amount"] if gst_payment else "", -# gst_payment["UTR"] if gst_payment else "" -# ] -# sheet.append(gst_row) -# if gst_payment: -# processed_payments.add(f"{inv['gst_invoice_no']}-{gst_payment['Payment_Amount']}-{gst_payment.get('UTR', '')}") -# -# for payment in payments[1:]: -# payment_id = f"{payment['invoice_no']}-{payment['Payment_Amount']}-{payment.get('UTR', '')}" -# if payment_id not in processed_payments: -# row = [pmc_no, "", "", "", "", payment['invoice_no']] + [""] * 10 -# row += ["" for _ in hold_headers] -# row += [ -# "", payment["Payment_Amount"], payment["TDS_Payment_Amount"], -# payment["Total_amount"], payment["UTR"] -# ] -# sheet.append(row) -# processed_payments.add(payment_id) -# -# for payment in extra_payments: -# row = [pmc_no, "", "", "", "", ""] + [""] * 10 -# row += ["" for _ in hold_headers] -# row += [ -# "", payment["Payment_Amount"], payment["TDS_Payment_Amount"], -# payment["Total_amount"], payment["UTR"] -# ] -# sheet.append(row) -# -# # Totals -# total_basic_amount = Decimal('0.00') -# total_tds_amount = Decimal('0.00') -# total_sd_amount = Decimal('0.00') -# total_on_commission = Decimal('0.00') -# total_final_amount = Decimal('0.00') -# total_payment_amount = Decimal('0.00') -# total_tds_payment_amount = Decimal('0.00') -# total_total_paid = Decimal('0.00') -# total_hold_amount_dynamic = Decimal('0.00') -# -# for row in sheet.iter_rows(min_row=8, max_row=sheet.max_row, values_only=True): -# try: -# total_basic_amount += Decimal(str(row[6] or 0)) -# total_tds_amount += Decimal(str(row[11] or 0)) -# total_sd_amount += Decimal(str(row[12] or 0)) -# total_on_commission += Decimal(str(row[13] or 0)) -# total_final_amount += Decimal(str(row[-5] or 0)) -# total_payment_amount += Decimal(str(row[-4] or 0)) -# total_tds_payment_amount += Decimal(str(row[-3] or 0)) -# total_total_paid += Decimal(str(row[-2] or 0)) -# -# for i in range(len(base_headers), len(base_headers) + len(hold_headers)): -# total_hold_amount_dynamic += Decimal(str(row[i] or 0)) -# except: -# continue -# -# totals_row = [ -# "TOTAL", "", "", "", "", "", -# total_basic_amount, "", "", "", "", total_tds_amount, total_sd_amount, -# total_on_commission, "", "" -# ] -# totals_row += [total_hold_amount_dynamic] + [""] * (len(hold_headers) - 1) -# totals_row += [ -# total_final_amount, -# total_payment_amount, -# total_tds_payment_amount, -# total_total_paid, -# "" -# ] -# -# sheet.append([]) -# sheet.append(totals_row) -# -# # Summary -# summary_hold = Decimal('0.00') -# for d in invoices: -# summary_hold += Decimal(str(d.get('SD_Amount', 0.00))) + Decimal(str(d.get('On_Commission', 0.00))) + Decimal(str(d.get('Hydro_Testing', 0.00))) -# for h in hold_amounts: -# summary_hold += Decimal(str(h.get('hold_amount', 0.00))) -# -# sheet.append([]) -# today = datetime.today().strftime('%A, %Y-%m-%d') -# sheet.append(["Contractor Name", contractor_info["Contractor_Name"]]) -# sheet.append(["Date", today]) -# sheet.append(["Description", "Amount"]) -# sheet.append(["Advance/Surplus", str(total_final_amount - total_payment_amount)]) -# sheet.append(["Total Hold Amount", str(summary_hold)]) -# sheet.append(["Amount With TDS", str(total_payment_amount + total_tds_payment_amount)]) -# -# for cell in sheet[sheet.max_row]: -# cell.font = Font(bold=True) -# -# workbook.save(output_file) -# workbook.close() -# -# finally: -# cursor.close() -# connection.close() -# -# return send_from_directory(output_folder, f"PMC_Report_{pmc_no}.xlsx", as_attachment=True) @app.route('/download_pmc_report/') @@ -3881,7 +3436,11 @@ def download_pmc_report(pmc_no): for inv_no in invoice_nos: gst_release_map.setdefault(inv_no, []).append(gr) +<<<<<<< HEAD LogHelper.log_action("Download PMC Report", f"User {current_user.id} Download PMC Report'{ pmc_no}'") +======= + log_action("Download PMC Report", f"User {current_user.id} Download PMC Report'{ pmc_no}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 workbook = openpyxl.Workbook() sheet = workbook.active sheet.title = "PMC Report" @@ -3944,6 +3503,7 @@ def download_pmc_report(pmc_no): if first_payment: processed_payments.add(f"{invoice_no}-{first_payment['Payment_Amount']}-{first_payment.get('UTR', '')}") +<<<<<<< HEAD # if inv["gst_pmc_no"] and inv["gst_invoice_no"] and inv["gst_invoice_no"] not in seen_gst_notes: # seen_gst_notes.add(inv["gst_invoice_no"]) # gst_payment = None @@ -3967,6 +3527,9 @@ def download_pmc_report(pmc_no): # gst_payment["UTR"] if gst_payment else "" # ] # sheet.append(gst_row) +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # Add GST Release Note(s) for this invoice if any if invoice_no in gst_release_map: for gr in gst_release_map[invoice_no]: @@ -3986,8 +3549,12 @@ def download_pmc_report(pmc_no): sheet.append(gst_row) +<<<<<<< HEAD # if gst_payment: # processed_payments.add(f"{inv['gst_invoice_no']}-{gst_payment['Payment_Amount']}-{gst_payment.get('UTR', '')}") +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 for payment in payments[1:]: payment_id = f"{payment['invoice_no']}-{payment['Payment_Amount']}-{payment.get('UTR', '')}" @@ -4063,6 +3630,7 @@ def download_pmc_report(pmc_no): except: continue +<<<<<<< HEAD # totals_row = [ # "TOTAL", "", "", "", "", "", # total_basic_amount, "", "", "", "", total_tds_amount, total_sd_amount, @@ -4078,6 +3646,9 @@ def download_pmc_report(pmc_no): # "" # ] # Prepare empty totals_row with length of base_headers +======= + +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 totals_row = [""] * len(base_headers) # Fill in specific columns @@ -4105,12 +3676,7 @@ def download_pmc_report(pmc_no): sheet.append([]) sheet.append(totals_row) - # Summary - # summary_hold = Decimal('0.00') - # for d in invoices: - # summary_hold += Decimal(str(d.get('SD_Amount', 0))) + Decimal(str(d.get('On_Commission', 0))) + Decimal(str(d.get('Hydro_Testing', 0))) - # for h in hold_amounts: - # summary_hold += Decimal(str(h.get('hold_amount', 0))) + sheet.append([]) today = datetime.today().strftime('%A, %Y-%m-%d') @@ -4154,18 +3720,12 @@ def add_hold_type(): if not hold_type or not hold_type[0].isalpha(): return jsonify({"status": "error", "message": "Hold Type must start with a letter."}), 400 - # Validation: Check if it already exists (case-insensitive) - # cursor.execute("SELECT COUNT(*) AS count FROM hold_types WHERE LOWER(hold_type) = LOWER(%s)", (hold_type,)) - # if cursor.fetchone()['count'] > 0: - # return jsonify({"status": "error", "message": "This Hold Type already exists."}), 400 - # Call the procedure to check if the hold_type exists + cursor.callproc('CheckHoldTypeExists', [hold_type]) try: - # Insert new hold type into the database - # cursor.execute("INSERT INTO hold_types (hold_type) VALUES (%s)", (hold_type,)) - # connection.commit() + cursor.callproc('SaveHoldType', [hold_type]) connection.commit() @@ -4184,62 +3744,7 @@ def add_hold_type(): return render_template('add_hold_type.html', Hold_Types_data=hold_types) -# Route to Update Hold Type -# @app.route('/update_hold_type/', methods=['POST', 'GET']) -# def update_hold_type(id): -# # GET request: Show the form with the current hold type -# if request.method == 'GET': -# connection = config.get_db_connection() -# cursor = connection.cursor() -# # cursor.execute("SELECT * FROM hold_types WHERE hold_type_id = %s", (id,)) -# # hold_type = cursor.fetchone() -# -# cursor.callproc("GetHoldTypesById", (id,)) -# for hold in cursor.stored_results(): -# hold_type = hold.fetchone() -# -# cursor.close() -# connection.close() -# -# if not hold_type: -# return jsonify({'status': 'error', 'message': 'Hold Type not found.'}), 404 -# -# return render_template('edit_hold_type.html', hold_type=hold_type) -# -# # POST request: Update the hold type -# if request.method == 'POST': -# new_hold_type = request.form.get('hold_type').strip() -# -# # Validation: Must start with a letter -# if not new_hold_type or not new_hold_type[0].isalpha(): -# return jsonify(ResponseHandler.invalid_name('Hold Type')), 400 -# -# connection = config.get_db_connection() -# cursor = connection.cursor() -# -# try: -# # Check if the hold type exists before updating -# # cursor.execute("SELECT * FROM hold_types WHERE hold_type_id = %s", (id,)) -# # hold_type = cursor.fetchone() -# cursor.callproc("GetHoldTypesById", (id,)) -# for hold in cursor.stored_results(): -# hold_type = hold.fetchone() -# -# if not hold_type: -# return jsonify({'status': 'error', 'message': 'Hold Type not found.'}), 404 -# -# # Update the hold type -# # cursor.execute("UPDATE hold_types SET hold_type = %s WHERE hold_type_id = %s", (new_hold_type, id)) -# cursor.callproc("UpdateHoldTypeById", (id,new_hold_type)) -# connection.commit() -# return jsonify(ResponseHandler.update_success('Hold Type')) -# -# except mysql.connector.Error as e: -# connection.rollback() -# return jsonify(ResponseHandler.update_failure('Hold Type')), 500 -# finally: -# cursor.close() -# connection.close() + @app.route('/update_hold_type/', methods=['GET', 'POST']) @@ -4299,17 +3804,20 @@ def delete_hold_type(id): cursor = connection.cursor() try: - # cursor.execute("SELECT * FROM hold_types WHERE hold_type_id = %s", (id,)) - # hold_type = cursor.fetchone() + cursor.callproc("GetHoldTypesById", (id,)) for hold in cursor.stored_results(): hold_type = hold.fetchone() +<<<<<<< HEAD LogHelper.log_action("Delete hold type", f"User {current_user.id} Delete hold type'{ hold_type}'") +======= + log_action("Delete hold type", f"User {current_user.id} Delete hold type'{ hold_type}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 if not hold_type: return jsonify({'status': 'error', 'message': 'Hold Type not found.'}), 404 # Proceed with deletion - # cursor.execute("DELETE FROM hold_types WHERE hold_type_id = %s", (id,)) + cursor.callproc("DeleteHoldType", (id,)) connection.commit() return jsonify(ResponseHandler.delete_success('Hold Type')) @@ -4396,7 +3904,11 @@ def submit_work_order(): sd_against_gst = request.form['sd_against_gst'] final_total = request.form['final_total'] tds_of_gst = request.form['tds_of_gst'] +<<<<<<< HEAD LogHelper.log_action("Submit Work Order", f"User {current_user.id} Submit Work Order'{ work_order_type}'") +======= + log_action("Submit Work Order", f"User {current_user.id} Submit Work Order'{ work_order_type}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # print("Good Morning How are U") connection = config.get_db_connection() cursor = connection.cursor(dictionary=True) @@ -4434,7 +3946,11 @@ def delete_work_order(id): connection.commit() cursor.close() connection.close() +<<<<<<< HEAD LogHelper.log_action("delete Work Order", f"User {current_user.id} delete Work Order'{ id}'") +======= + log_action("delete Work Order", f"User {current_user.id} delete Work Order'{ id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return jsonify({'success': True}) @@ -4491,6 +4007,10 @@ def success(): return "Work Order Submitted Successfully!" +<<<<<<< HEAD +======= +import logging +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 logging.basicConfig(level=logging.DEBUG) @@ -4513,7 +4033,11 @@ def add_purchase_order(): GST_Amount = request.form.get('GST_Amount') TDS = request.form.get('TDS') final_amount = request.form.get('final_amount') +<<<<<<< HEAD LogHelper.log_action("Add purchase order", f"User {current_user.id} Added puirchase Order'{ purchase_order_no}'") +======= + log_action("Add purchase order", f"User {current_user.id} Added puirchase Order'{ purchase_order_no}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # Insert into database insert_query = """ INSERT INTO purchase_order ( @@ -4558,7 +4082,11 @@ def delete_purchase(id): connection.commit() cursor.close() connection.close() +<<<<<<< HEAD LogHelper.log_action("Delete purchase order", f"User {current_user.id} Deleted puirchase Order'{ id}'") +======= + log_action("Delete purchase order", f"User {current_user.id} Deleted puirchase Order'{ id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return render_template(('add_purchase_order.html')) @@ -4594,7 +4122,11 @@ def update_purchase(id): connection.commit() cursor.close() connection.close() +<<<<<<< HEAD LogHelper.log_action("Delete purchase order", f"User {current_user.id} Deleted puirchase Order'{ id}'") +======= + log_action("Delete purchase order", f"User {current_user.id} Deleted puirchase Order'{ id}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 return redirect(url_for('show_purchase_orders')) # Show edit form @@ -4709,6 +4241,13 @@ def work_order_report(): return render_template('work_order_report.html') +<<<<<<< HEAD +======= +from flask import request, jsonify, send_file +import pandas as pd +import os +import config # make sure your DB connection is imported correctly +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 # ✅ Vendor Name Search (for Select2) @@ -4771,6 +4310,15 @@ def get_work_order_data(): return jsonify(data) +<<<<<<< HEAD +======= +from flask import request, send_file +import pandas as pd +import os +from openpyxl import load_workbook +from openpyxl.styles import Font, Alignment +from openpyxl.utils import get_column_letter +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 @app.route('/download_work_order_report') @@ -4915,7 +4463,11 @@ def download_purchase_order_report(): if purchase_order_no == "null": purchase_order_no = None +<<<<<<< HEAD LogHelper.log_action("Download purchase order", f"User {current_user.id} Download puirchase Order'{ purchase_order_no}'") +======= + log_action("Download purchase order", f"User {current_user.id} Download puirchase Order'{ purchase_order_no}'") +>>>>>>> 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 query = "SELECT * FROM purchase_order WHERE 1=1" params = [] diff --git a/templates/base.html b/templates/base.html index bb52864..aa8b235 100644 --- a/templates/base.html +++ b/templates/base.html @@ -24,7 +24,7 @@ diff --git a/templates/index.html b/templates/index.html index b6e633b..dd31318 100644 --- a/templates/index.html +++ b/templates/index.html @@ -41,7 +41,7 @@ diff --git a/templates/uploadExcelFile.html b/templates/uploadExcelFile.html index 47c3a5b..b8569b9 100644 --- a/templates/uploadExcelFile.html +++ b/templates/uploadExcelFile.html @@ -11,7 +11,7 @@

Upload Excel File

-


diff --git a/uploads/Aiva Engineering Pvt. Ltd. Shamli _31.07.25.xlsx b/uploads/Aiva Engineering Pvt. Ltd. Shamli _31.07.25.xlsx new file mode 100644 index 0000000..683289c Binary files /dev/null and b/uploads/Aiva Engineering Pvt. Ltd. Shamli _31.07.25.xlsx differ diff --git a/uploads/Ajay Wankhede.xlsx b/uploads/Ajay Wankhede.xlsx new file mode 100644 index 0000000..935837b Binary files /dev/null and b/uploads/Ajay Wankhede.xlsx differ diff --git a/uploads/BG Construction.xlsx b/uploads/BG Construction.xlsx new file mode 100644 index 0000000..443f3e2 Binary files /dev/null and b/uploads/BG Construction.xlsx differ