From 14eac5b958cbbf5e596eacf86aa958d7acac4bdb Mon Sep 17 00:00:00 2001 From: pjpatil12 Date: Sun, 14 Dec 2025 18:04:03 +0530 Subject: [PATCH] upload client side MH and MH DC model commit --- ...ole_domestic_chamber_model.cpython-313.pyc | Bin 3486 -> 3486 bytes .../manhole_excavation_model.cpython-313.pyc | Bin 4592 -> 4592 bytes .../mh_dc_client_model.cpython-313.pyc | Bin 0 -> 2904 bytes .../mh_ex_client_model.cpython-313.pyc | Bin 4671 -> 5956 bytes app/models/mh_dc_client_model.py | 34 ++-- app/models/mh_ex_client_model.py | 29 ++- ...generate_comparison_report.cpython-313.pyc | Bin 6729 -> 6450 bytes app/routes/generate_comparison_report.py | 185 +++++++++++++----- .../__pycache__/file_service.cpython-313.pyc | Bin 11387 -> 15473 bytes app/services/file_service.py | 135 +++++++++---- 10 files changed, 266 insertions(+), 117 deletions(-) create mode 100644 app/models/__pycache__/mh_dc_client_model.cpython-313.pyc diff --git a/app/models/__pycache__/manhole_domestic_chamber_model.cpython-313.pyc b/app/models/__pycache__/manhole_domestic_chamber_model.cpython-313.pyc index 0482c1c068234035c177e6e52a930f3521ed0a60..81afb3c9f92a4c34445ef2edb5da5571aaec986e 100644 GIT binary patch delta 20 acmbOyJx`kZGcPX}0}%XMWw()gGA{r;R0Y=n delta 20 acmbOyJx`kZGcPX}0}wDf+iv8Z%nJZB2n2Kh diff --git a/app/models/__pycache__/manhole_excavation_model.cpython-313.pyc b/app/models/__pycache__/manhole_excavation_model.cpython-313.pyc index b222504a7de655315f7bd77b6f806063cf15e309..fcfaf273e0725db77882fe3b2b1db9c8c8d6877d 100644 GIT binary patch delta 20 acmeyM{6U%fGcPX}0}x!9Vz-g|sUQGIo(7=+ delta 20 acmeyM{6U%fGcPX}0}#wiw%W-3R1g3~#|AL~ diff --git a/app/models/__pycache__/mh_dc_client_model.cpython-313.pyc b/app/models/__pycache__/mh_dc_client_model.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c41e376828a3c55ecd02c5ef343c02297a3aac3 GIT binary patch literal 2904 zcmbVO%}*Og6rc4M#`pu9PrD(d1X8T3hyt$oh)^1caR8f$rEOF>nl8HoY+3KRvujn( z$)_H;&>~epasW=GTuM&qv3~-{7c^2NOTCmE63ww{XLfM~HA2m<yogO+lTBW;Ob(hXUhSP^oI2u~<7QjJsE3jy)xR-hz8(R3})4%(2%a!$ZSxQdF;!g^s*)Kmit zqM>2EPnMFb$*KiK5f&9h0{ms11gu~fi5ix4I*&djs!d#UTUr>VMu3!))wYA4~w*@|a1 zQD8P5yL6;1=`43AnVuNUeyQQrtRkYk0v}`T8zdTfc0$YL1uW|{z=ba>97?ZquX2a*x6h73$s=#_obCH( zkcr=AfmI=gXkZ^?=?V%P`yu?cASf3|2*M>9>xLq$NYyADfY4wivT)3fmUt#KrI1re z-6PdN%Lo&PED>K)!$@9MXHbzeUMV-Es2?N6JUD$t&Xd3uoOpNx%jz<2V!`V&^l)HC zBkrW42?p_}Q*dGKF`Rw)#lu#4j<$tO3~1 zEUGNa#0D&E(88!<*r3IuidjPzMwMlmydeuqSQu3dOISRrnDwcJQDs>P60TkvcyViV z;+>=)7Yp>`0-IOIQ!qqT`;PcTj3^*M!NBazO~r3aO^=w@-FxEtAz?ZsZs z|MK+U>CsrG{PEn;SMa#)>myflrMY!;ZewnD?pJu+oGzu$JfJbMUR*0~MRuakqq~DI zZkI#7rPN8Vaa~@Mw;Vh5&+B*Zya<+qAC{(0np!qTHb%DQcb;rNDL36M&7MS>H{%=e ztp_`)?Nm9^Q<|yuoOuDA72Sw#4eShW50}H;rRi%T)yA&zRBAle#QE=vW^3pCuQ)Zi zD(x}zG`jYC_j=3iA04?`D&eM!jg4)O9eQ7fUWJas_e;}nU7UN0v&zUSn2EcIllBJl zhFSj$cbc^ctG-ujPQ3T5`#X-uDVOyiy@QG~C&zJbK;#YR_|w(HO>w&e`@?&~Zvh*d Gx&8spi&dcj literal 0 HcmV?d00001 diff --git a/app/models/__pycache__/mh_ex_client_model.cpython-313.pyc b/app/models/__pycache__/mh_ex_client_model.cpython-313.pyc index 960c1b84f566a5ff3fd9514b29f2c042a653ef2f..1ea928a746a9ede7e3cff5711fd20ba08445cdf7 100644 GIT binary patch delta 1065 zcmaJ=O-mb56wSm@5_K~9?j%O7X&kk-RpZx874fTJTGN)qMWlrxt+5G>M#e;vE}AS{ zm4cYJNaALUo2bx6k>bKdTkr=&W)lVkp^L5xLfcL0qHiV<6+$1}Gxwcy-o1AoywA4d zd#axpRx5++Z+0YbT(_=Tm#^0CXTMd0zG~`VwMH)oqjC%QqL>lCNDug`7)0z6_Da|% zVZVd}5)Mj8Nk~h0A7TSYAV%;}p+$xyZdl}Qyb)VpU(ZKeZ`V(BxQdpuqi)LD=`S}N}p52ED^n}~$NfyGzM zq;Dzg7ZlJ|%4!{xOlY2g`vpNW8Ss`jWxIfnvAz=LUG#^7KEdMjvdjJerfE&KBgZi>z9m%DK9$*8?ccD@yvx3txv_R zmC9c#|$fWpan+!{t$68_4B##B>qYti|5N(prwl5Ik;8OcnLUlq2a#zu^2CKd)~~I4gKG zx|AttO4~UqL-870;^7%#=9C-CO>3?_+s+f61=IjO;0DS@=IAYY+m-k1c=%fb1@vaI zwJkThHM`B`qdQT)l`5dt3KaN*li)i}!_b2kbt}NsG>EH77`mbJ8rkhTdDE_G&wfbl zQ+&s80VRu_ck}cvz2`dg?0fjmkpkLYfdXf0Jvf53j?|>KxrK{u#J070Vu#?H?FG~V xe44h(Gzp>_9gK~xXYk1(FqRu3oL3 z1*J{AC@jin$y8(#%rC`IWEw0`WR@?ZipBC@y5ubZY(6u7oB{LDsPt426&q=+- z?^u+IA|O2Zqk!<_3jXNHulT1;{vc4GD(8_{loIb-T2z`FZy0YHpO}{tpO}7J83XC%$fn3-`|M7_cHhKLxth@kLv$w`tkjOJU+w74v&(%^Mt@&jRYCTZEp)gtDT zD@9Z%zYn9iprA@h?-B{Cn_ALs=hpOQRIrE^%W~CE~{Ex zU{QJ?uQ`q}^%*NOE~}VdU{NGa)nraFwaGGK uB9r^Y+I0Pa(aQ+L#nM3H12ZEd<6Q=!y9}~lSnL?hAin&{0AvLfocKsmD{=Cc>Kf(^yKzVeGUa zLYM`gAT|xNs4EsV2#J7%1Y{Gj>as{w^2jZAr-W9b6=G53D3K~57QBf)q!AKg#gl#C z{hWJ!-km#s-yit4U$d!JD*;^N?+vHIt;-qfbc z)(Cz0xQR7QA+3N^Of`{8Qsu|k=BegzpIB)3A_-DWYWh%8>qkkQ4Gh-9tmO*s)i3|> zwo@OXnd$UQVss%!U!}9DG~-1CbKS}Lk*g{K=3wxx`|Ri*+eN}0~I?}#<0-)^+rad-0*ox+u2(IC6lrk&Ey3s622s9JA3QjGskEt zv?V;X6OuGYrFj5lbdwQoTGeub(voJ<;zv=y=qXKDYK(-2JEbSBq>Z%uvF-N)z9-V7 zb^}Tqj&Z*$9X+rq2`LAbbWl3dNw)YK+QFn=@{=+Oka9oT&V55Th`|8n0!hT{nqc+Z z10s_%K^!X%krx&4GwIm&>#-;c1>F;A0f~As0ZqjPWsFVG*+e`_XIU{rXgoQSN-){z zZ(^!I)U8N5OV0=m|D5$YO<3M}GK6EOkqgl4~U zQ5Io)M;9O=S&E4#76fHxI+4gm8G1Gm;l9)`$iS*q`xSbSHH$wExke|>3V1XcPsOs) zD9p+xW-~A=OS9R`wN!Rmkg@4`CN9Y7xw!=QNN?rZ3@392wi)Kv&ZExEUyh}jEKA3- zX;#qf=+P`2g&c@j?Z7q57)#GyPBE|{Z2DTJ4rze8PY`AQ4t%>KyUNvi6i>O6Ndbr8 zXq?W{0v1cp2-sEFK0KbR73BUjI2sI)BIh(Ns^U-)jm)zK?o;D^+n?B+`I)jUuzJOm zL@;Z$n=3Xw&N-_NU~==u{-qI!bndwox*4iiowsZ^ZIG@-vlOfnb$8j($2 z>sZCud}DZdxX@NMdU&H}rLE|@Sn9g?z~rcO_vH^21_~W{S4rpHXavrFc-+pOm8msf zX>VXDc>Oh=Xs^n*tLAQo{%cupcm6;D%g^T>C7nkq+tF3*dTH%=seKsMo#crdoiL{!*4l`>*&^jf)R7B1Na=f8J09Z$?;dS`2QBAjjMQjBg#SQX3_oG&7$At+j( z{~AWDFJKVEszpscM>BCc!;V9P4RLv^Hz$tk7hn@gz{a2u@FAEwKa&_{S!jyaUq<}f zgWW)oM_}we7<&p1uY;rO;Mh7i4nI$U;TK?h2oxJ~(CjL@_J7@Z`whP7ToD-HlSWNt m#L6SqqOEtW>9%}LTZB3i+(1uZh

%0`wG8GuYSR&-?`;tRBAr delta 2507 zcmbtWU2NOd6~3hYC6fA=C|Z_fH*PE^jbkTHEyqn3+ihIivSTrH3fPUxN_47NA`MdR z7O#VfJ!vm%9j=JdJ;Vb7Bn39qZC>2&VSa3Z0wt#f5?BXKu?)kuJ~)kmv>gWQ(z50R zZjpzP;Nki1{qA?pJ@;OMANG8Dlz4#Sb^x!*=@Z$KZ1d zfVRxKX)A4u8${2nC%IoA@c2dBX$OsUp)?*xX@Ua1JKdu1f;r|~zW1j58zk+N~FBzKUc688SVvpRqh!zn8I`a2hUmNZi4W{Jt@@LkLB4bXDJRVC&Gh>Z5 z2Ikd^*3l!awjXS@@3zwRL#AG&J}wGo5)D1t0VBT9KtTSN)m9_`js0*Qum@+X&=QOd zS|?*Cz!Ced?rAjfPXHVMMwn=5CeJjy-FF*c3|=tpkkBq5pD5kA3VFv|ZWVT1*kl@}b5Vq3HDiPRbJP{X@%Twv*4$qTSPErD!96ei_m+;j^ajT`sLpQC=Sght_(;!nwZo92EmR3L^g<^hTdV1 zzEOQO``Xr$vq}aG4Za&^#%LO=Wqh!18G>1z!bDvn07Z zE6z)rIeUQ@MDA?NAd>n(Gbf6IC~1}~zmQ|ooMui7oS5cfh!}zWOTpBTkY8Zs7x9ih z%{lbH8Ks8V0vkg$QIDYe56j3 z{HABjsXR5TFlp7BQLxNCvR%IG@txZ;gQf#j>aa>3u2TIf)vt`tD$r6dS1DGd*b0>{ zIX40atAQRh&{GWzsDS}x;=BTFAXN>d)j+xu;7X27EAR(PwtG}_dA>>=zcuZhLk!-{ zPWey1yG8G282G5=lcnKJGr$8?EUaSTS~z+waWzqEYPr^bwSOb>)XEDtPgNp^HrhLH z9$W3MwD)e1&E?F>soxU!9p(tJ1&!7<*(+;sZD@9)3hT|J_yl%sM}WV zgWkSSE!0xBLa*3L)u>20uxT^8TOS(CIB}mvK-0k1>j(%nUBlkRKI*EpkAB>>I(6gX z^@|^MsqLc`a;$`J_ySkPFOPpPUuhluaDLT&qw{*_2lHy{V8u67vTb;LR}Nl2Sibb< zo`ULGELpyRH8_uyY&EODYNb>wwGv-_X}zEnbueDDy5AyxMU*eClIurHglZju#RxrJ zB@d|Nf!`0lpLj2^-l32O6mqOeCRH-2&}Sv(%o@eNgd zqpEN8lkSQyQL=4W0ZfIuOv&Mrxfa}44L+*|pH%{VN+0B&DP0bFpAS{BHWh1IIkxIo zhR!NFU}~7ZibYf`Qhxm=v-S%`_Y*bDTVJ2@^v&M2X+>YF;fEGL#5W1~nPBXs(lqeN zdDSti7-zrx<}?DH9z(vpGu>9D&CeXO{)ITo95>uPZlAVU zVt)CTL76nb<0Zns75EugVEGIyiK7sRQ}WNrSW(}$?|}!<0`WCyH0wZK$Smf#6XGI- z`rm~#1I?xZL69%O>D%D+9nkkTaPkiL$sOSNEAV~+Y+v~!O3UHZj`d5be@X!!xIa-} o6$zBP6hhN$bD2qke87M27tbZKw#66Sbzck3j=Lu1ONa4 diff --git a/app/routes/generate_comparison_report.py b/app/routes/generate_comparison_report.py index 254f83f..29c80cb 100644 --- a/app/routes/generate_comparison_report.py +++ b/app/routes/generate_comparison_report.py @@ -1,15 +1,18 @@ from flask import Blueprint, render_template, request, send_file, flash -from app.models.subcontractor_model import Subcontractor +from app.models.subcontractor_model import Subcontractor from app.models.trench_excavation_model import TrenchExcavation from app.models.tr_ex_client_model import TrenchExcavationClient +from app.models.manhole_excavation_model import ManholeExcavation +from app.models.mh_ex_client_model import ManholeExcavationClient + from app import db import pandas as pd import io -generate_report_bp = Blueprint("generate_report", __name__, url_prefix="/report") +generate_report_bp = Blueprint("generate_report", __name__, url_prefix="/report") @generate_report_bp.route("/comparison_report", methods=["GET", "POST"]) @@ -21,21 +24,26 @@ def comparison_report(): if not subcontractor_id: flash("Please select a subcontractor.", "danger") - return render_template("generate_comparison_report.html", subcontractors=subcontractors) + return render_template( + "generate_comparison_report.html", + subcontractors=subcontractors + ) subcontractor = Subcontractor.query.get_or_404(subcontractor_id) - # Fetch data - contractor_rows = TrenchExcavation.query.filter_by(subcontractor_id=subcontractor_id).all() - client_rows = TrenchExcavationClient.query.filter_by(subcontractor_id=subcontractor_id).all() + contractor_tr_ex = TrenchExcavation.query.filter_by( + subcontractor_id=subcontractor_id + ).all() - + client_tr_ex = TrenchExcavationClient.query.filter_by( + subcontractor_id=subcontractor_id + ).all() - diff_rows = [] + combined_rows_tr_ex = [] - for row1, row2 in zip(client_rows, contractor_rows): - - total1 = ( + for row1, row2 in zip(client_tr_ex, contractor_tr_ex): + # -------- Tr.Ex CLIENT TOTAL ---------- + client_total = ( (row1.Marshi_Muddy_Slushy_0_to_1_5_total or 0) + (row1.Marshi_Muddy_Slushy_1_5_to_3_0_total or 0) + (row1.Marshi_Muddy_Slushy_3_0_to_4_5_total or 0) + @@ -55,7 +63,8 @@ def comparison_report(): (row1.Hard_Rock_6_0_to_7_5_total or 0) ) - total2 = ( + # -------- SUBCONTRACTOR TOTAL ---------- + contractor_total = ( (row2.Soft_Murum_0_to_1_5_total or 0) + (row2.Soft_Murum_1_5_to_3_0_total or 0) + (row2.Soft_Murum_3_0_to_4_5_total or 0) + @@ -69,54 +78,132 @@ def comparison_report(): (row2.Hard_Rock_6_0_to_7_5_total or 0) ) - diff = total1 - total2 + diff = client_total - contractor_total - # ---- store for excel ---- - diff_rows.append({ + # -------- COMBINED ROW ---------- + row_data = { "Location": row1.Location, - "Node No": row1.MH_NO, - "Client Sum": round(total1, 2), - "Subcontractor Sum": round(total2, 2), - "Diff": round(diff, 2) - }) + "MH No": row1.MH_NO, + } - # optional console print + # Client columns + for col, val in row1.__dict__.items(): + if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + continue + row_data[f"Client_{col}"] = val + + row_data["Client_Total"] = round(client_total, 2) + + # Subcontractor columns + for col, val in row2.__dict__.items(): + if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + continue + row_data[f"Sub_{col}"] = val + + row_data["Sub_Total"] = round(contractor_total, 2) + row_data["Diff"] = round(diff, 2) + + combined_rows_tr_ex.append(row_data) + + # Console log print( - f"Location : {row1.Location} | " - f"MH_NO : {row1.MH_NO} | " - f"Client : {total1} | " - f"Sub : {total2} | " - f"Diff : {diff}" + f"{row1.Location} | {row1.MH_NO} | " + f"Client={client_total} | Sub={contractor_total} | Diff={diff}" ) + # -------- Tr.Ex model ---------- + df_tr_ex = pd.DataFrame(combined_rows_tr_ex) + + # manhole ex + # contractor_mh_ex = ManholeExcavation.query.filter_by( + # subcontractor_id=subcontractor_id + # ).all() + + # client_mh_ex = ManholeExcavationClient.query.filter_by( + # subcontractor_id=subcontractor_id + # ).all() + + # combined_rows_mh_ex = [] + + # for row1, row2 in zip(client_mh_ex, contractor_mh_ex): + # # -------- Tr.Ex CLIENT TOTAL ---------- + # client_total = ( + # (row1.Marshi_Muddy_Slushy_0_to_1_5_total or 0) + + # (row1.Marshi_Muddy_Slushy_1_5_to_3_0_total or 0) + + # (row1.Marshi_Muddy_Slushy_3_0_to_4_5_total or 0) + + # (row1.Soft_Murum_0_to_1_5_total or 0) + + # (row1.Soft_Murum_1_5_to_3_0_total or 0) + + # (row1.Soft_Murum_3_0_to_4_5_total or 0) + + # (row1.Hard_Murum_0_to_1_5_total or 0) + + # (row1.Hard_Murum_1_5_to_3_0_total or 0) + + # (row1.Hard_Murum_3_0_to_4_5_total or 0) + + # (row1.Soft_Rock_0_to_1_5_total or 0) + + # (row1.Soft_Rock_1_5_to_3_0_total or 0) + + # (row1.Soft_Rock_3_0_to_4_5_total or 0) + + # (row1.Hard_Rock_0_to_1_5_total or 0) + + # (row1.Hard_Rock_1_5_to_3_0_total or 0) + + # (row1.Hard_Rock_3_0_to_4_5_total or 0) + + # (row1.Hard_Rock_4_5_to_6_0_total or 0) + + # (row1.Hard_Rock_6_0_to_7_5_total or 0) + # ) + + # # -------- SUBCONTRACTOR TOTAL ---------- + # contractor_total = ( + # (row2.Soft_Murum_0_to_1_5_total or 0) + + # (row2.Soft_Murum_1_5_to_3_0_total or 0) + + # (row2.Soft_Murum_3_0_to_4_5_total or 0) + + # (row2.Hard_Murum_0_to_1_5_total or 0) + + # (row2.Hard_Murum_1_5_and_above_total or 0) + + # (row2.Soft_Rock_0_to_1_5_total or 0) + + # (row2.Soft_Rock_1_5_and_above_total or 0) + + # (row2.Hard_Rock_0_to_1_5_total or 0) + + # (row2.Hard_Rock_1_5_and_above_total or 0) + + # (row2.Hard_Rock_4_5_to_6_0_total or 0) + + # (row2.Hard_Rock_6_0_to_7_5_total or 0) + # ) + + # diff = client_total - contractor_total + + # # -------- COMBINED ROW ---------- + # row_data = { + # "Location": row1.Location, + # "MH No": row1.MH_NO, + # } + + # # Client columns + # for col, val in row1.__dict__.items(): + # if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + # continue + # row_data[f"Client_{col}"] = val + + # row_data["Client_Total"] = round(client_total, 2) + + # # Subcontractor columns + # for col, val in row2.__dict__.items(): + # if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + # continue + # row_data[f"Sub_{col}"] = val + + # row_data["Sub_Total"] = round(contractor_total, 2) + # row_data["Diff"] = round(diff, 2) + + # combined_rows_tr_ex.append(row_data) + + # # Console log + # print( + # f"{row1.Location} | {row1.MH_NO} | " + # f"Client={client_total} | Sub={contractor_total} | Diff={diff}" + # ) - # Convert to DataFrame - df_contractor = pd.DataFrame([r.__dict__ for r in contractor_rows]) - df_client = pd.DataFrame([r.__dict__ for r in client_rows]) - df_diff = pd.DataFrame(diff_rows, columns=["Location", "Node No", "Client Sum", "Subcontractor Sum", "Diff"]) - # Drop unwanted columns - drop_cols = ["id", "subcontractor_id", "created_at", "_sa_instance_state", "Remarks"] - df_contractor.drop(columns=drop_cols, errors="ignore", inplace=True) - df_client.drop(columns=drop_cols, errors="ignore", inplace=True) - # Convert to numeric - df_contractor = df_contractor.apply(pd.to_numeric, errors="coerce").fillna(0) - df_client = df_client.apply(pd.to_numeric, errors="coerce").fillna(0) - - - # EXPORT EXCEL output = io.BytesIO() file_name = f"{subcontractor.subcontractor_name}_Comparison_Report.xlsx" with pd.ExcelWriter(output, engine="xlsxwriter") as writer: - df_contractor.to_excel(writer, index=False, sheet_name="Contractor_Data") - df_client.to_excel(writer, index=False, sheet_name="Client_Data") - df_diff.to_excel(writer, index=False, sheet_name="Diff") - - + df_tr_ex.to_excel(writer, index=False, sheet_name="Tr.Ex") output.seek(0) @@ -127,7 +214,7 @@ def comparison_report(): mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) - return render_template("generate_comparison_report.html", subcontractors=subcontractors) - - - + return render_template( + "generate_comparison_report.html", + subcontractors=subcontractors + ) diff --git a/app/services/__pycache__/file_service.cpython-313.pyc b/app/services/__pycache__/file_service.cpython-313.pyc index 9e0afbb93239112bc866fae1eb68692837d8ee40..e46e567f373a363c2c258f7fdca42588d68264b0 100644 GIT binary patch delta 2031 zcmbW2OH3O_7{_N~yx=D`2CvsPWo;l}3?}7a6F&g+j6xs{hQ=*%(PFQ_ig{=a6s7MR znqDdu&83&BRn^Vo;+I~&Hk27?ySU*vLcx-+n8wBgS-o8D`Pp_p#0=A>1!^2mnVD5kfgn4$X! zbVW#F=ds7Q`Ry01b6i+jSk8z;%Zp-mHJuz>5Ekb|iOk?GJVZXi0hb*~+L(q?7t>1m zd7VdJ(2b-sVoa3Q(@F97s@yL)fpIkns^a)wj;InU)3hpP3dRu<%m_`RNiR9UxD4i} zB5gGCf_=Wqg=TyuNeGoI-Ipq2mRL2>mN(*>+_7>Wt|{mj7iPtc*<>ayF0CrHRFa&n z=r!0R7AC_1^yKr3-`rfO)9hktRx~XstP88@<)uPhsfnD{*o~Uujik5&VUI?#l1)uJ zX32M&dTb-NH30@j&3;AP+E1~Ye6Rhwhe0Op;qo2Dr^I8mnn2=M+2(u zqs(ZBYP%IfxkF8v%Q)K0h}Oj7TH-bZDHA4+3Bs(a$eX6CxQ+Ci>zq9_P^gfWGnqLd zdHzd-WQ88RfFOCp?84LJ6LSmhBmJCJXM=DDWHb_it0s@kW;~gztO_zMgU~bt7zWf* zj7XzUgxw>Z06czq)+R8gXx&pyGJM0p6f{i(UIv^6&|QF}azGnE4R{6cDqscx!liS7 z1ZZOvZJp#C=f!X5KHzR)JfBNDI?E2D>{{KW11YP3*B(?^$+a$;QfQ^FIZ0e&VlLBa z_9pp|`!V;k%kVr}N1CP&q*ZemttA(`Nqw^i|C$?b-hHC1_u%VG-#2xkiyu@D9zVXo z4{!L$ow}xa$A3b6OjsBB5rJL`sUR;MWJAD}bzs~5%7*aMltSZEH;?as&$<@VCCS5* z;4tAmyvDz!+GWFeHcT$rqxeN~%F;z1*&XiF@=G&2Z^>Ljwj^YI;;-TuM%Lh;_a-ns z@ORM>O_+RRsbK?K_)1o`hh$6WhCcLgUriexNTp4A{E&9GQyYb)6hD*%CmWpqRQZ&! zDm;gky2Dsmt5_KTE4|NJN$*CEIS%Iiq?i{WdoH&ov=!TBqj@$;^p-yCe`22N0rk)k$1r{OYdaI&N0?<6<0p)lpo0 zjXtJuagGKMa&R-DM=6!3#=-uaQg_RZG z;&MvNWPSA8luADSHq9zANk<-d?QMEGjG|1L=f9E*6=B+KEhF|y7ikyjHp&J_w3V;B Zjr#XcbPtW(XAt)P!Az=gq=MiOI!E_Bl^af4!vsBtAJ=|U4@T&Xq2g$tciOmt&{k4fg6nSahb^WV&wkF#H+ zhEICEmhdJG97xZ57Y%k;THG^lx06N^ksKtV^H<!r0Nzx1HMDkr_-cm6EU}RK?!nOPpVM1`Esv5{Cc{>jwDiSjil2u2H5fi(i z+70IX162z!gC?N2Q5&9RM@a0r=9NJ+IGadLpHEL^-5P3T7qwonvAfzPsAey;0nx%E zb92lfEkixKC#@d*PS4@|wb5#f^RglEJnO!_gkOm7ix3>@%%AQyW&qgmz-C2*b%o|+(ggMSg-kMeneJ+E{>V;s>5!Hz3u97lwV2+RWG6y zft62vtS?wIiJ{biC>I#k9Ys{~o^x?rCM5+Z6HpS{mHSH5;8ONNDGDBCACyk>VGKUU zxft3`f}gr=w22P|aXOZrjOD1zHiF;S`;aXqak-qm?C|HY1@->3Qy tjt>F=Y!S^CF&BwkBy~k%Dw3We=_``aBI)ImH^l!%JSRY?M3Cj2-vNSe^hp2! diff --git a/app/services/file_service.py b/app/services/file_service.py index 0a2e911..628e205 100644 --- a/app/services/file_service.py +++ b/app/services/file_service.py @@ -6,8 +6,11 @@ from app import db from app.models.trench_excavation_model import TrenchExcavation from app.models.manhole_excavation_model import ManholeExcavation from app.models.manhole_domestic_chamber_model import ManholeDomesticChamber + from app.models.tr_ex_client_model import TrenchExcavationClient from app.models.mh_ex_client_model import ManholeExcavationClient +from app.models.mh_dc_client_model import ManholeDomesticChamberClient + from app.utils.file_utils import ensure_upload_folder @@ -56,14 +59,17 @@ class FileService: if file_type == "manhole_domestic_chamber": return self.process_manhole_domestic_chamber(df, subcontractor_id) - # Trench Excavation save (client) + # Tr Ex save (client) if file_type =="tr_ex_client": return self.client_trench_excavation(df, subcontractor_id) - # Manhole Excavation save (client) - # if file_type =="mh_ex_client": - # return self.client_manhole_excavation(df, subcontractor_id) + # Mh Ex save (client) + if file_type =="mh_ex_client": + return self.client_manhole_excavation(df, subcontractor_id) + # Mh and Dc save (client) + if file_type == "mh_dc_client": + return self.client_manhole_domestic_chamber(df, subcontractor_id) return True, "File uploaded successfully." @@ -212,7 +218,7 @@ class FileService: # ---------------------- client ---------------------------------- - # Trench Excavation save method (TrenchExcavationClient model) + # Tr Ex save method (TrenchExcavationClient model) def client_trench_excavation(self, df, subcontractor_id): df.columns = [str(c).strip() for c in df.columns] # If the sheet has merged cells -> forward fill Location @@ -256,49 +262,96 @@ class FileService: return False, f"Clinnt Tr Ex Save Failed: {e}" - # Manhole Excavation save method (ManholeExcavationClient model) - # def client_manhole_excavation(self, df, subcontractor_id): - # # Clean column names (strip whitespace) - # df.columns = [str(c).strip() for c in df.columns] - # # If the sheet has merged cells -> forward fill Location - # if "Location" in df.columns: - # df["Location"] = df["Location"].ffill() + # Mh Ex save method (ManholeExcavationClient model) + def client_manhole_excavation(self, df, subcontractor_id): + # Clean column names (strip whitespace) + df.columns = [str(c).strip() for c in df.columns] + # If the sheet has merged cells -> forward fill Location + if "Location" in df.columns: + df["Location"] = df["Location"].ffill() - # # REMOVE empty rows - # df = df.dropna(how="all") - # # Identify missing location rows before insert - # missing_loc = df[df["Location"].isna() | (df["Location"].astype(str).str.strip() == "")] - # if not missing_loc.empty: - # return False, f"Error: Some rows have empty Location. Rows: {missing_loc.index.tolist()}" + # REMOVE empty rows + df = df.dropna(how="all") + # Identify missing location rows before insert + missing_loc = df[df["Location"].isna() | (df["Location"].astype(str).str.strip() == "")] + if not missing_loc.empty: + return False, f"Error: Some rows have empty Location. Rows: {missing_loc.index.tolist()}" - # saved_count = 0 + saved_count = 0 - # try: - # for index, row in df.iterrows(): - # record_data = {} - # # Insert only fields that exist in model - # for col in df.columns: - # if hasattr(ManholeExcavationClient, col): - # value = row[col] + try: + for index, row in df.iterrows(): + record_data = {} + # Insert only fields that exist in model + for col in df.columns: + if hasattr(ManholeExcavationClient, col): + value = row[col] - # # Normalize empty values - # if pd.isna(value) or str(value).strip() in ["", "-", "—", "nan", "NaN"]: - # value = None + # Normalize empty values + if pd.isna(value) or str(value).strip() in ["", "-", "—", "nan", "NaN"]: + value = None - # record_data[col] = value + record_data[col] = value - # record = ManholeExcavationClient( - # subcontractor_id=subcontractor_id, - # **record_data - # ) + record = ManholeExcavationClient( + subcontractor_id=subcontractor_id, + **record_data + ) - # db.session.add(record) - # saved_count += 1 + db.session.add(record) + saved_count += 1 - # db.session.commit() - # return True, f" Client Mh Ex. data saved successfully. Total rows: {saved_count}" + db.session.commit() + return True, f" Client Mh Ex. data saved successfully. Total rows: {saved_count}" - # except Exception as e: - # db.session.rollback() - # return False, f"Client Mh Ex. Save Failed: {e}" + except Exception as e: + db.session.rollback() + return False, f"Client Mh Ex. Save Failed: {e}" + + # Mh and Dc save method (ManholeDomesticChamberClient model) + def client_manhole_domestic_chamber(self, df, subcontractor_id): + # Clean column names (strip whitespace) + df.columns = [str(c).strip() for c in df.columns] + # If the sheet has merged cells -> forward fill Location + if "Location" in df.columns: + df["Location"] = df["Location"].ffill() + + # REMOVE empty rows + df = df.dropna(how="all") + # Identify missing location rows before insert + missing_loc = df[df["Location"].isna() | (df["Location"].astype(str).str.strip() == "")] + if not missing_loc.empty: + return False, f"Error: Some rows have empty Location. Rows: {missing_loc.index.tolist()}" + + saved_count = 0 + + try: + for index, row in df.iterrows(): + record_data = {} + + # Insert only fields that exist in model + for col in df.columns: + if hasattr(ManholeDomesticChamberClient, col): + value = row[col] + # Normalize empty values + if pd.isna(value) or str(value).strip() in ["", "-", "—", "nan", "NaN"]: + value = None + + record_data[col] = value + + record = ManholeDomesticChamberClient( + subcontractor_id=subcontractor_id, + **record_data + ) + + db.session.add(record) + saved_count += 1 + + db.session.commit() + return True, f"Mh and Dc data saved successfully. Total rows: {saved_count}" + + except Exception as e: + db.session.rollback() + return False, f"Mh and Dc data Save Failed: {e}" + \ No newline at end of file