From 2e623201671c6ed08c3913c37f36ba1806dae091 Mon Sep 17 00:00:00 2001 From: pjpatil12 Date: Thu, 11 Dec 2025 10:16:43 +0530 Subject: [PATCH] create project and create model and dashboard --- app/__init__.py | 47 ++++ app/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 1037 bytes app/__pycache__/app.cpython-313.pyc | Bin 0 -> 1959 bytes app/__pycache__/config.cpython-313.pyc | Bin 0 -> 655 bytes app/config.py | 24 +++ app/logs/app.log | 0 app/models/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 161 bytes .../subcontractor_model.cpython-313.pyc | Bin 0 -> 1867 bytes .../trench_excavation_model.cpython-313.pyc | Bin 0 -> 5390 bytes .../__pycache__/user_model.cpython-313.pyc | Bin 0 -> 593 bytes app/models/manhole_excavation_model.py | 0 app/models/subcontractor_model.py | 21 ++ app/models/trench_excavation_model.py | 73 +++++++ app/models/user_model.py | 21 ++ app/routes/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 161 bytes app/routes/__pycache__/auth.cpython-313.pyc | Bin 0 -> 1888 bytes .../__pycache__/dashboard.cpython-313.pyc | Bin 0 -> 609 bytes .../__pycache__/file_import.cpython-313.pyc | Bin 0 -> 1502 bytes .../subcontractor_routes.cpython-313.pyc | Bin 0 -> 4201 bytes app/routes/__pycache__/user.cpython-313.pyc | Bin 0 -> 702 bytes app/routes/auth.py | 31 +++ app/routes/dashboard.py | 8 + app/routes/file_import.py | 21 ++ app/routes/subcontractor_routes.py | 64 ++++++ app/routes/user.py | 9 + app/services/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 163 bytes .../__pycache__/db_service.cpython-313.pyc | Bin 0 -> 921 bytes .../__pycache__/file_service.cpython-313.pyc | Bin 0 -> 4990 bytes .../__pycache__/user_service.cpython-313.pyc | Bin 0 -> 1170 bytes app/services/db_service.py | 19 ++ app/services/file_service.py | 103 +++++++++ app/services/user_service.py | 47 ++++ app/static/css/subcontractor.css | 35 +++ app/static/uploads/sub_3/test_comparison.xlsx | Bin 0 -> 18270 bytes app/static/uploads/sub_4/testing11.xlsx | Bin 0 -> 8915 bytes app/templates/base.html | 64 ++++++ app/templates/dashboard.html | 10 + app/templates/file_import.html | 39 ++++ app/templates/list_user.html | 28 +++ app/templates/login.html | 17 ++ app/templates/register.html | 20 ++ app/templates/subcontractor/add.html | 40 ++++ app/templates/subcontractor/edit.html | 41 ++++ app/templates/subcontractor/list.html | 38 ++++ app/templates/users.htm | 28 +++ .../__pycache__/file_utils.cpython-313.pyc | Bin 0 -> 601 bytes app/utils/file_utils.py | 6 + app/utils/helpers.py | 2 + instance/comparisondb.db | Bin 0 -> 12288 bytes logs/app.log | 200 ++++++++++++++++++ requirements.txt | 7 + run.py | 9 + 55 files changed, 1072 insertions(+) create mode 100644 app/__init__.py create mode 100644 app/__pycache__/__init__.cpython-313.pyc create mode 100644 app/__pycache__/app.cpython-313.pyc create mode 100644 app/__pycache__/config.cpython-313.pyc create mode 100644 app/config.py create mode 100644 app/logs/app.log create mode 100644 app/models/__init__.py create mode 100644 app/models/__pycache__/__init__.cpython-313.pyc create mode 100644 app/models/__pycache__/subcontractor_model.cpython-313.pyc create mode 100644 app/models/__pycache__/trench_excavation_model.cpython-313.pyc create mode 100644 app/models/__pycache__/user_model.cpython-313.pyc create mode 100644 app/models/manhole_excavation_model.py create mode 100644 app/models/subcontractor_model.py create mode 100644 app/models/trench_excavation_model.py create mode 100644 app/models/user_model.py create mode 100644 app/routes/__init__.py create mode 100644 app/routes/__pycache__/__init__.cpython-313.pyc create mode 100644 app/routes/__pycache__/auth.cpython-313.pyc create mode 100644 app/routes/__pycache__/dashboard.cpython-313.pyc create mode 100644 app/routes/__pycache__/file_import.cpython-313.pyc create mode 100644 app/routes/__pycache__/subcontractor_routes.cpython-313.pyc create mode 100644 app/routes/__pycache__/user.cpython-313.pyc create mode 100644 app/routes/auth.py create mode 100644 app/routes/dashboard.py create mode 100644 app/routes/file_import.py create mode 100644 app/routes/subcontractor_routes.py create mode 100644 app/routes/user.py create mode 100644 app/services/__init__.py create mode 100644 app/services/__pycache__/__init__.cpython-313.pyc create mode 100644 app/services/__pycache__/db_service.cpython-313.pyc create mode 100644 app/services/__pycache__/file_service.cpython-313.pyc create mode 100644 app/services/__pycache__/user_service.cpython-313.pyc create mode 100644 app/services/db_service.py create mode 100644 app/services/file_service.py create mode 100644 app/services/user_service.py create mode 100644 app/static/css/subcontractor.css create mode 100644 app/static/uploads/sub_3/test_comparison.xlsx create mode 100644 app/static/uploads/sub_4/testing11.xlsx create mode 100644 app/templates/base.html create mode 100644 app/templates/dashboard.html create mode 100644 app/templates/file_import.html create mode 100644 app/templates/list_user.html create mode 100644 app/templates/login.html create mode 100644 app/templates/register.html create mode 100644 app/templates/subcontractor/add.html create mode 100644 app/templates/subcontractor/edit.html create mode 100644 app/templates/subcontractor/list.html create mode 100644 app/templates/users.htm create mode 100644 app/utils/__pycache__/file_utils.cpython-313.pyc create mode 100644 app/utils/file_utils.py create mode 100644 app/utils/helpers.py create mode 100644 instance/comparisondb.db create mode 100644 logs/app.log create mode 100644 requirements.txt create mode 100644 run.py diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..fb7cc38 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,47 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from app.config import Config + +db = SQLAlchemy() + +def create_app(): + app = Flask(__name__) + app.config.from_object(Config) + + db.init_app(app) + + # Register Blueprints + from app.routes.dashboard import dashboard_bp + from app.routes.file_import import file_import_bp + # from app.routes.user import user_bp + + app.register_blueprint(dashboard_bp) + app.register_blueprint(file_import_bp) + # app.register_blueprint(user_bp) + + from app.routes.subcontractor_routes import subcontractor_bp + app.register_blueprint(subcontractor_bp) + + return app + + + + + +# from flask import Flask +# from app.config import Config + +# def create_app(): +# app = Flask(__name__) +# app.config.from_object(Config) + +# # Register Blueprints +# from app.routes.dashboard import dashboard_bp +# from app.routes.file_import import file_import_bp +# from app.routes.user import user_bp + +# app.register_blueprint(dashboard_bp) +# app.register_blueprint(file_import_bp) +# app.register_blueprint(user_bp) + +# return app diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff00ddd9aee91801e67a69b6c48a73eb6449c6f7 GIT binary patch literal 1037 zcmZ`&PiqrF6rb6hO}1&%mQq_t5knC)RVoM-Dy2{Y9(JW@L-3G=VYAt!Yd5>=+s&c3 z6u}<6cu?@*7x3FC1eC#mq8D$4;K7@3c9W(S`e5I@_nY_s?Tm`W0zvwFyzRYWg#47s zgp{!`+CkwRsgW8ri9vyurL35Wp@N#qs>uuuv@)^Ob+R>fgItZ32;@6jCHGrm6)Lnx zz8xQ-P^dk9yyrWIZuc0qTr~{ZUdI`GriY4LexnsCvp0}u)R@#ow#HaM>f`{czf1@D z%LpM2eS%HA%cPOcK;j3*$?f#4pXb3|DfXQ=^nj+aYR(viKq<@ot5c7ORHxG%S6C=h z3yjUoIinchOs}w3r`C0HlT@^Qki)FW;>`&4`L^e~-0MamBpI?8_nJ-^ zBw#y92ojqIIbWf39@t%%bCJV)T!WZxL)hhE^SSFJph+90)fBoHcnP9R9B`O8_(ISz$s&yEH`_Dn(Yo~jvM*>352rr*s6xz$ObPCgYp=&FpR}{+6v!{jzz%%*G^p77hJ=5 zvWwV5)+gTz3vcz;_xjbZEPra87++ZFGb?>~FktJySnkw3G2f^Iw)`hYwEIK0b%v*& z*}UHwu-oW0)^-PMLt5?8bL`XFodLW1eRjTYj4&D5ujoQ+%g2!|Wigd`{KB`hR|2wG zQIONhwv;XgT7hHB{v*iA%`NR7&ZPtPaVoA-VoTTX<>p Ll@VK_3#sovwJ79^ literal 0 HcmV?d00001 diff --git a/app/__pycache__/app.cpython-313.pyc b/app/__pycache__/app.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1da547dd4bc0e1826a250e62708526defea3677 GIT binary patch literal 1959 zcmah}&rcgy5T55J;Pe+B;3?!F$7LYR5iZRWJ}nR-$#i^1OiM)au#l0{3Q;^P zX4G^a>GQCZ38gind05W$r^6)dVI?z=j*y6l)l8H`F`k+kB!hWw4DzvAu2TVt=i}K) zzpP-*z8zp64sni9KFjA9wIsnd{Y+8@SjzO_KRoE^_lr03!;FmBq7X zIye{24bE{%sHhcn6sDlpBb=c!pM=YpGYQKJ9}1VD%%x&~v12KLO1Gy<5+e*#Zh_Du9vL}BED2WsTfUnMK3fE_LmH2rC=MR)Y&U#t7>*((=iFcWhz$f zinH0znPTVK9Vy_#-qR9_r*OZcMVamL-BTdIx#Rra_E^#Y?n}N`j`!{3XSG70O^M4? z@$PArHnkbX%M9Mms&9s7dd#E*!a`D^V!8xBF7Q2^vJ~|C;?4XQHd)PAi)N#$e@^VL zka;J+XxADBu^hXe?CSDJ8+)f452$3-OXda{!Uz-iI&Y!afT6T2<~d)Pp!WEPs0)EJe@Yyb$O&nvQ1 zbBHA^dhI9dJ4lC^0vo$#6-{TlRM5MaD9jpRR$@0@v@tS>%Cr~GXnU-XK4wasF?pk7 z)fzT&3HutKi^fPM*d3q>5{wL2C~rILE^IDzoeCI<%AHcFRwi~$w+oCSluDRjT zP?4C1YwAX|N+s{gUQ4Jznsssk3-!n*30AVYP_s+Ts`(LN-$?u?f|EpfB5)k{8(iCm zYsWBh3=_w2}pFFm=gfZm65h6w=z4KJ^4@^V(#h@#GgaF9e%SN8hkSK%~V^v z@sA>M{K)`tVmJ2sAza36-QB}O7!P*mZES~O<-V4_t^X<|Sh_nqcfP*+N&uN9p_34Z{kxk7!f;zuT1(qYd*fS6&#_1W#EY-ucpAg~>+~a2 QKMcffC4?Unpv)&YXMCy~E6zX`zruB3S-q_*O;er%V>1&&hN{ zkPCznR_chNb+n1FdKY2sxtNeamA+EauOw~y5*IPo(e$yXTp(9;VnkJ}Pz|e8#~NM2 zI?doEy1b2W=2)Rwyi9ZbY$?Yx78xFe{VPq3o^1`r>?C>=kJG(u7?hBtEa7!Td@uS) zSYr5O5PLLaWY{~b@*E3%8YJ6KpPk+G;@Dt`mxR7CiX-Cnn6V?z<(khvbL})@To-Wq z6*WtFo&^|sg8+c%0S2TuiX^`Va5D0uxpE!gD5NZj!eKBZLcWc69n-Pi*^L9Jm|gRY ziEY^H)Ohhfq1!R7Iy739TD4}G-CC=Oc^=zV$L>PiKH!DDw$m~zP;EICyTeyZ$7$`` z6|g^a?Iup!R{>@(0WV2tcsNP|20-O6PQ^m}g;jR<2|acrKZqk}Q}QYB6Xsg~+}W7d zTw#mrr!GH<$5eiI3ep)?6z~O2itS7N-sHi>P{wB#AY&>+I)f&o-%5reCLr%KNa~h@vsFxZeo=Nz zPI78NPJBR7epYI7NpXyGer`cxQD$*|o&r=XCb6I(CO1DNHK#ZxK0Y%qvm`!Vub}c4 ehYe7$G$+-rh!toc$iiX}<0CU8BV!RWkOcss#VCXT literal 0 HcmV?d00001 diff --git a/app/models/__pycache__/subcontractor_model.cpython-313.pyc b/app/models/__pycache__/subcontractor_model.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8dc04278fb78bec6fe2be36d62f0a77048ae5ca GIT binary patch literal 1867 zcmb_c&2Jl35P!S=i0#B)+lkY-703-i#0R1(rJ_!v2oeZsqDClNgd(lJK$-x#J2sb#j;;)G11J;v}kPrtSDj~T&!#vwdYb+{R>XUY6-prfd z%$uEgop3mWVELqs{zydV5594iuP<~qK)8=&Bn#VUOQ1rE%i^}UB~mekX3#8>J(rQ} zRfJu?>-?18@bqNr&HK{+Hs7QLCg!q013A?pj$RhRGSA5tDuH?HR^z^b{9s`8X$Or)!!R2&(WQ?He z>vB5r0x-fOV}#uJE~k-^F~(hAms9BlU_?j8`1daIgdB!H8+#7I+;DFwle_c7+AdN; zj$B4`T9)Xgd^8T$@Yyg+ zhM{H+qCbX4Y%hYkJ;lj49L4{(=IEaiI5(Cf`)bK>w0^sS6(K%z{OimDf!P&4K)WFQ zcST^1uY2ZD+OzYyv@(!viV3TL9v{dSn`(i_^xDMOw|T%6+g@K%KD6jv#n4F6!0%J* zW1=~>vThZMD%EYvO!ak&S}ZCBD@P1l8HDXB7m8&Tz?hOE#h6VGWV7JvCn2Ui1Ehjl zu~dEP*Q+-hS8raVG7n=H((*-Mxx?@HBic#Na4?=PfQ2xI5G8}l6BvI|QjNYv!gyb& zwqxifF)c8MF?M*>dv?l;$o%V;Q7V{h?3U?}JfTd~bIdP0R5$aKXT-+TT#gdkX8yeG zVAEp$qH1y;ELd3`;({0;1ywgNxJGzSKuh2vp->;@w;k0f*(~r5JcoDSIi%ih*pj1} z)@LlFQ38e>RvkLc4GE07hpvGJlE{`EVnczFV57V?G{Fgfi@Suko&5;NSEw~LSGoOr zaQrZNkUUzfF5O!?f1?q+R#|H$uhf#K$@=0CneQ^^^7pF`-)$tLT?W-D>2x_7*HLTlyI^7-W1m(9dNWoHQY{G&$rO^6qp ztR|0>CyTY^Z3iWUWA>rk9nZ?x<9j5THkHnhP@IEmW>5g qdabfbuYoV`ar+98zdV8<{D$IxqL&_fC1K@gt-5({^9cg68|fc>%!8@Vx>32cEUx_1_wct zex0wW2CLUuLq&$t2yv1kzjT^|XN|=k>7p|53=>S|1A)YMj+o^mG$_Vcq~+kY`Ur&t}?0 zx1h}CGcr3GlC8BIwJWsz?-=G9Tf4&cGh#UF_wj-2#N@1)To)#1!{oX#xgJce7n8GN zaug=#z~uTcxqeJ;0FxWU*_OEn^7g8~f2 zk?Vy36WoOC`ul%T#`ht#aDSs=Q?Z2Dbtb`!!RqW;u0FS)a?zXba$3n1NEt1JN%df|kOip=a;fDX205|=7kd5)+2^79z zgJRsjAVgvee6WwSTB#X=E0 zX17>gHY2xHAy&Kl5(k}@hn(SR328QZFXq1`|)^cQ@5ZqL=*;Jj@ zvmD@*r>fI<+ElG(R~oIRFB&aslTz4qR4=8ex2&v07a3me)0otp2s~|6Q&)|YrUR#f z4r)wFPzHTin1HawR#Cg!kyGS=YH0|ntvC&;mPVjMHP;oQv8kP`?o?w_`&qSJ@UiIm zx*3;^tL1JrFQVTIR?+VTu>4eRN{GRz@SWTege)?k4v0|sXI$2BSEXv~rD!((77bRHyNAxK8fhgK8rIt#j)>qU^>h)CS#+w_5Gw)23se7ef zDw9knbJo0L-*MqScmhr`xfoym;EGZ2w)@$mjMcqRCbnm%y_wt^7kL0*gAbX4bgIVvMHy6l<_rp^E)dER1 zP?a40=KxDoU-@mA%Fpf3Nz~;6+0&pi=ksa+o==6U93IJ=4oruxbiCqTay$C0 zY0s1!`Pm{_E~UOyKlkA`VaYs{x?lS6S-rV?^VjCz+kb0+*LgSf@E=lVoUNQx<&ZAB zjj{m^80By4%F#D2DYHi92!DL6<>p(JS>QH&hFE2gi4UOVFN02}`-8ClK@9v&-q-17 QU&GAyo9%xHMK0(14=R2-umAu6 literal 0 HcmV?d00001 diff --git a/app/models/__pycache__/user_model.cpython-313.pyc b/app/models/__pycache__/user_model.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db855aabd370f5087c17836b438ed2fa07b8a9e9 GIT binary patch literal 593 zcmYLGzi-n(6n=1QEGiGBAV>p2X zCXlEXoGBn!1aX+RPRpuunh6_gNP$!W6eNnmB$xn2Nl3j#6!(1e)@l0jgwyifAgPts zA%D#?rZvnTTmHA0PwlQf%%9s%1i%7fHH$+Zm`fiO*;4zSUS`I|k&m3VSG33Vv@g_W zax!kp@UJh<(sw0&Ol__!i*Km>p!3?L7v-|b$hfkYc4ui;Rq3+4)Yhdd){R^HwEFD( zh^8<#q94kIPIvC1Op@DO!{%^wv%eXQZys!pCbxrz4TK-F$#e33A(j#*ukdB3W)L;MCbBs`0GO_KIh=wGStpSNOO(TD@G19!mmGgM0bIf>NqFJRgh`~^>=gLeP` literal 0 HcmV?d00001 diff --git a/app/models/manhole_excavation_model.py b/app/models/manhole_excavation_model.py new file mode 100644 index 0000000..e69de29 diff --git a/app/models/subcontractor_model.py b/app/models/subcontractor_model.py new file mode 100644 index 0000000..598e274 --- /dev/null +++ b/app/models/subcontractor_model.py @@ -0,0 +1,21 @@ +from app import db +# from app.services.db_service import db +from datetime import datetime + +class Subcontractor(db.Model): + __tablename__ = "subcontractors" + + id = db.Column(db.Integer, primary_key=True) + subcontractor_name = db.Column(db.String(255), nullable=False) + address = db.Column(db.String(500)) + gst_no = db.Column(db.String(50)) + pan_no = db.Column(db.String(50)) + mobile_no = db.Column(db.String(20)) + email_id = db.Column(db.String(150)) + contact_person = db.Column(db.String(150)) + status = db.Column(db.String(20), default="Active") + created_at = db.Column(db.DateTime, default=datetime.utcnow) + + def __repr__(self): + return f"" + diff --git a/app/models/trench_excavation_model.py b/app/models/trench_excavation_model.py new file mode 100644 index 0000000..6df15ff --- /dev/null +++ b/app/models/trench_excavation_model.py @@ -0,0 +1,73 @@ +from app import db +from datetime import datetime + +class TrenchExcavation(db.Model): + __tablename__ = "trench_excavation" + + id = db.Column(db.Integer, primary_key=True) + # Foreign Key to Subcontractor table + subcontractor_id = db.Column(db.Integer, db.ForeignKey("subcontractors.id"), nullable=False) + # Relationship for easy access (subcontractor.subcontractor_name) + subcontractor = db.relationship("Subcontractor", backref="trench_records") + + # Basic Fields + Location = db.Column(db.String(255)) + MH_NO = db.Column(db.String(100)) + CC_length = db.Column(db.Float) + Invert_Level = db.Column(db.Float) + MH_Top_Level = db.Column(db.Float) + Ground_Level = db.Column(db.Float) + ID_of_MH_m = db.Column(db.Float) + Actual_Trench_Length = db.Column(db.Float) + Pipe_Dia_mm = db.Column(db.Float) + + Width_0_to_2_5 = db.Column(db.Float) + Width_2_5_to_3_0 = db.Column(db.Float) + Width_3_0_to_4_5 = db.Column(db.Float) + Width_4_5_to_6_0 = db.Column(db.Float) + + Upto_IL_Depth = db.Column(db.Float) + Cutting_Depth = db.Column(db.Float) + Avg_Depth = db.Column(db.Float) + + # Excavation categories + Soft_Murum_0_to_1_5 = db.Column(db.Float) + Soft_Murum_1_5_to_3_0 = db.Column(db.Float) + Soft_Murum_3_0_to_4_5 = db.Column(db.Float) + + Hard_Murum_0_to_1_5 = db.Column(db.Float) + Hard_Murum_1_5_to_3_0 = db.Column(db.Float) + + Soft_Rock_0_to_1_5 = db.Column(db.Float) + Soft_Rock_1_5_to_3_0 = db.Column(db.Float) + + Hard_Rock_0_to_1_5 = db.Column(db.Float) + Hard_Rock_1_5_to_3_0 = db.Column(db.Float) + Hard_Rock_3_0_to_4_5 = db.Column(db.Float) + Hard_Rock_4_5_to_6_0 = db.Column(db.Float) + Hard_Rock_6_0_to_7_5 = db.Column(db.Float) + + # Totals + Soft_Murum_0_to_1_5_total = db.Column(db.Float) + Soft_Murum_1_5_to_3_0_total = db.Column(db.Float) + Soft_Murum_3_0_to_4_5_total = db.Column(db.Float) + + Hard_Murum_0_to_1_5_total = db.Column(db.Float) + Hard_Murum_1_5_and_above_total = db.Column(db.Float) + + Soft_Rock_0_to_1_5_total = db.Column(db.Float) + Soft_Rock_1_5_and_above_total = db.Column(db.Float) + + Hard_Rock_0_to_1_5_total = db.Column(db.Float) + Hard_Rock_1_5_and_above_total = db.Column(db.Float) + Hard_Rock_3_0_to_4_5_total = db.Column(db.Float) + Hard_Rock_4_5_to_6_0_total = db.Column(db.Float) + Hard_Rock_6_0_to_7_5_total = db.Column(db.Float) + + Remarks = db.Column(db.String(500)) + Total = db.Column(db.Float) + + created_at = db.Column(db.DateTime, default=datetime.utcnow) + + def __repr__(self): + return f"" diff --git a/app/models/user_model.py b/app/models/user_model.py new file mode 100644 index 0000000..63be6c1 --- /dev/null +++ b/app/models/user_model.py @@ -0,0 +1,21 @@ +# from app.services.db_service import db +# from werkzeug.security import generate_password_hash, check_password_hash + +# class User(db.Model): +# id = db.Column(db.Integer, primary_key=True) +# name = db.Column(db.String(120)) +# email = db.Column(db.String(120), unique=True) +# password_hash = db.Column(db.String(255)) + +# def set_password(self, password): +# self.password_hash = generate_password_hash(password) + +# def check_password(self, password): +# return check_password_hash(self.password_hash, password) + + +class User: + def __init__(self, id, name, email): + self.id = id + self.name = name + self.email = email diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/__pycache__/__init__.cpython-313.pyc b/app/routes/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..772ec629705d7bd68d72074214f37764db675a87 GIT binary patch literal 161 zcmey&%ge<81opekGePuY5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~h@vsFxZeo=Nz zPI78NPJBR7epYI7NpXyGer`cxQD$*|o&r=XCb6I(rYOI(B(*puK0Y%qvm`!Vub}c4 fhfQvNN@-52T@fqLK#+ySAjU^#Mn=XWW*`dysC6i% literal 0 HcmV?d00001 diff --git a/app/routes/__pycache__/auth.cpython-313.pyc b/app/routes/__pycache__/auth.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08144c09889774978c71da8112cc9d7116fb519b GIT binary patch literal 1888 zcmah}O>7fK6rTO_+G{&b>k=!5fJs7|J>ZmzP=#1M04?DBp)6^UY{^=@lVro%>&~tz zaV3;gl>$;FazS!$?x}F&$g$T-Jvcv7(8^WSp9?ofmU`}+U9T}xQC8ZSH}k%k_vU@? zy-qYLA@~mVKGpx?5c-=g{4dZII=_MN6e&nyW>J!06t_*;w0Z2*WRY_FM`RqVdoodg(x3Do%jynl*vJ>3%96MKTfT)u;lx{gqe z_cxb(-uw-iNBi#y_9?oe!cwz+w*C*pQOs1=i!xe96W!D5X#}e!HaL>QBXJnE~&cV1S_g#ePa^M5vxE(LDy>1 zqy{|QHC3Y3;y26pRYTWOMW7LvZCy1iC!ne2RZMD<%Sw99E*Y{!Xb7EvM+yni#ejPh zlAz$x$FG>A8srgt$=V`hL(@b z%w^~+G<-0-SqQV2Y19UM&{?31e9S0;i|ja(#RZ2it0hbZK}Trj&^od#brsi6(P~Wj zPGc=)Rf|Q?tyB$TEF2m!*S6a?e$Ek78*qNQ<%PLVHav)wedN1}wh-QZ|P+zVVM;v(O0!semxU_(HqJ60LedMcSXL!u^EJR{+Z z9Hgxg`8bPO+6rADroP*q7-oNNMxHD3TbZ~C!iZXt%S}Kvp(~;WN5p1rmHqVbgt>Jd zxb`0U$Gjeetmb=xgRRhS&!v0J2?Bo2$C z>o@v3stNC!Bf>axo$v(JTarG+sBO0$kK48=3{~yJKp07>fw=nYL;(vj5~FLL-{`pf zD^5zPMiG9O@LvOfe`M*QG<#mYX!c8$Uf~{!cQAbm(|>AxnEg9sKllC6+)C==mjao`HFe6K%(!N zEo5V(>5?=?%{s!WiyF46xrm4uebz#bOF{>x<{Zh8#6K`hq#*pcp(E-hmDav)HC?Rf zu7yebfJRlLVO!We39T@XE{e6VsoEGF7+;=k8_8yoAjk1c$^X6nc`)qB|b6zQ&0+prq8h7HGR=0wxmU~j+bbBDCzJB=C z!>4mSap598_xQo12mN%eo6bF->!tH;;Uc^EW9f%dKYO#Az1dm5-OIk)iM)O>oBjUI zlRN#{rS9y~^J;H)wH+PIT>th~Tl_t9qn}yrW>(LaewBNfokxkbIEW&Evx!v2s}2e##;|8KaDnWQ`(y-s+vl56zJg%N*F!MpUBO|Ks} zSiE7?k?9n!bXfH!{U%3LwW&3bs*=1}k8J8WJhd^p=TkW0|__ zeL9=e{LMoM{{W>PD7^ryFTmS>P0v4l=Pdur7v1U2)6}0Z-G@>aO5Ye~Z=TPcEp(vN TfyIBgB-G)M2i&?3y@UP*K@(j1 literal 0 HcmV?d00001 diff --git a/app/routes/__pycache__/subcontractor_routes.cpython-313.pyc b/app/routes/__pycache__/subcontractor_routes.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..55b182eb8fef427cfebafa763c5345b851b73b97 GIT binary patch literal 4201 zcmcgvPj3@f5Z_&|{}U&1Y#ay)P69X%!EPZb1OjSHi;y8M^(O5hR#(Pez_565}*sVdXPw8z`k+JbN_ z<)LG$e_Cdz39?q4Nh$Z0ps|-e;TGWb?vhZwRxU`kOG6A8m;O!1eCyIn49w^)gSYBv z8FvQ*hAlJgU@c>scn518Z?Tqri?vR3EyTKWnOZ_;=q;n?7<1I*_1MQaTBJ-3(KoH` zeRZ{&H(+hQIm@{@&rH*Ez#p*qUUMgaurI9zZBXKub0t9wU?@Q(@fCppIyG;pe7PtJ z{Bl|I2&G(6C3zBrDCW<#l zHFtCP_kcY{lVVY-#(e})Nt{45_DY$QG{;q;O3=Kp60{WIbPmv~x$@;wsaPe5MuO@4 z8BNgk62@+npwZx}5Ck2eGYS*CQ0@s32%XSqV`%Kr+{3y0&|zihusrp?I`ly!GID?Q z?rJ>}Qz9{W;)EKRZ3Oq+pSn9$4~{9pvB#&>V6xFacz@sBef9oPrGNDCq}qR^(YyP* z)o)kpz5A8k{f|9rZ+y$|3cJ?k{|r!0_wCfJ)a~@G^qtci>}Z2^;keF*6*j!VMqaXB z*>`09<_0_4@DIqLxayyj*-0~+(Kxo?MGNT}D+3+KSU`=Iv4Yp+P*et`JDLe00IwC$ z9K8s|ZI%I`IMOQ-8&Gur=*jLGtp#jTQk>P@ra2*LlbhflQPlGx8HY{n4r#{+kGCQ* zklBZF2Y`S>!ejODgc6>pho_YAlp0Q~r5l*vrhoiG@h`~if?<&=v=04=ApZq2T!A$heTo1rbWm>=xaWJFkdG8^gGi=nP4=gSTN9v z-in%VMI9Y*or3u>_@qNXbhy?-F(nkMhmIP2X<2QS)-&Va?q(y7>lGXdqdaT+3dMp_4K#x^N zK#z5Y9q6%Y3h2R1rnepFvFZ!xu`0?EW?Q{wFxz&t%uojdhGvjMJs37;ITyS^n@Ixr z`z^kwtxkB;-IM&dJ;@s|>qzqipT1--ka(Yw(lHW990^7z!NU>^`>y-wNuS`c37)Z) z=*c7urS`xH8E5DSodk$Ypy&@kx`ocmSmNpGlhu0cxDq=qpSY;T=GW#o*aMC6$)|Hq z=IZ0el<{No^hfIW$HkTiHrP|ICjY)W)JAiv|YL^Raf4l(jqjP6_eV&N1tM7YL-|1IFK<8w7K|?C{?|kQk3sOYq*rKyg@|BC5xg-$Z|a4{cxid& zKzU6R&JeT()?#TB$fkp)>7S`{KT+piP{9|}iC+fxJ>b``$!9rbU_qw(HeD1GtkV&N zjy!Ow^!_b|rf0St6cgRVUi-9r{m}ZLOh;t;=oYh!K8#YwHnF!k(o*79>F5^2(2F$A zk8bMSO`jzo4^F6b93?niViF}d+9omi{Iloh^_@;zJDus=NgkY3>BC!$+c?RT-qS7e E4|Og8761SM literal 0 HcmV?d00001 diff --git a/app/routes/__pycache__/user.cpython-313.pyc b/app/routes/__pycache__/user.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9351915ec9d9492a81c16489a3825035724295a GIT binary patch literal 702 zcmZ8fO>5LZ7@o<;ZZ^AX4+U2Xg;j(SkS!i+Sy?^UR?8NPG!zdFhPa*9*vTfmllalo zdQ$M>rO=QM12TQgIbf6=WhsU2u; zb&f1eQUcb#<b}aG1&&V8dMoe#)YR2Pt!?tZxejE`!J6fJq}$#i6-~ zLCx$8xSs&q3!kbc4@EjCHxvQY=<3PWl{+FkB@^lfF<0&3-Kd1NQJi&M@ayoh==X6=LJdPL7b&bc!<_Xo=F=um)K_%9x4_WlpB#B zjn=C>pBf9}#==R%8LfS;&mH&PWbbc}>#HA))m*(qHl3O@_jn)<08gTzC(o-r9fgkv zE;_i$FRO_p%lC&t#C%^?i{XPrnguOD25$-AZvai@q}7Y!-Hfvva8{KlSX@=^mrg1D vN-lpPSH9V^uWuc%ziW-{?x=c7trzpp=U+ZKp{?JVM%QSr6Ybn2EpYz;LK3R} literal 0 HcmV?d00001 diff --git a/app/routes/auth.py b/app/routes/auth.py new file mode 100644 index 0000000..cd0cb10 --- /dev/null +++ b/app/routes/auth.py @@ -0,0 +1,31 @@ +from flask import Blueprint, request, render_template, redirect, flash, session +from app.services.user_service import UserService + +auth_bp = Blueprint("auth", __name__, url_prefix="/auth") + +# LOGIN PAGE +@auth_bp.route("/login", methods=["GET", "POST"]) +def login(): + if request.method == "POST": + user = UserService.validate_login( + request.form["email"], + request.form["password"] + ) + if user: + session["user_id"] = user.id + return redirect("/dashboard") + flash("Invalid credentials", "danger") + return render_template("login.html") + +# REGISTER API ONLY +@auth_bp.route("/register", methods=["POST"]) +def register(): + data = request.json + UserService.register_user(data["name"], data["email"], data["password"]) + return {"message": "User registered successfully"}, 201 + +# LOGOUT +@auth_bp.route("/logout") +def logout(): + session.clear() + return redirect("/auth/login") diff --git a/app/routes/dashboard.py b/app/routes/dashboard.py new file mode 100644 index 0000000..fa4b6e9 --- /dev/null +++ b/app/routes/dashboard.py @@ -0,0 +1,8 @@ +from flask import Blueprint, render_template + +dashboard_bp = Blueprint("dashboard", __name__) + +@dashboard_bp.route("/") +@dashboard_bp.route("/dashboard") +def dashboard(): + return render_template("dashboard.html", title="Dashboard") diff --git a/app/routes/file_import.py b/app/routes/file_import.py new file mode 100644 index 0000000..88aae68 --- /dev/null +++ b/app/routes/file_import.py @@ -0,0 +1,21 @@ +from flask import Blueprint, render_template, request, flash +from app.services.file_service import FileService +from app.models.subcontractor_model import Subcontractor + +file_import_bp = Blueprint("file_import", __name__, url_prefix="/file") + +@file_import_bp.route("/import", methods=["GET", "POST"]) +def import_file(): + subcontractors = Subcontractor.query.all() + + if request.method == "POST": + file = request.files.get("file") + subcontractor_id = request.form.get("subcontractor_id") + file_type = request.form.get("file_type") + + service = FileService() + success, msg = service.handle_file_upload(file, subcontractor_id, file_type) + + flash(msg, "success" if success else "danger") + + return render_template("file_import.html", title="File Import", subcontractors=subcontractors) diff --git a/app/routes/subcontractor_routes.py b/app/routes/subcontractor_routes.py new file mode 100644 index 0000000..5fd3b71 --- /dev/null +++ b/app/routes/subcontractor_routes.py @@ -0,0 +1,64 @@ +from flask import Blueprint, render_template, request, redirect, flash +from app import db +from app.models.subcontractor_model import Subcontractor + +subcontractor_bp = Blueprint("subcontractor", __name__, url_prefix="/subcontractor") + +# ---------------- ADD ----------------- +@subcontractor_bp.route("/add") +def add_subcontractor(): + return render_template("subcontractor/add.html") + +@subcontractor_bp.route("/save", methods=["POST"]) +def save_subcontractor(): + subcontractor = Subcontractor( + subcontractor_name=request.form.get("subcontractor_name"), + contact_person=request.form.get("contact_person"), + mobile_no=request.form.get("mobile_no"), + email_id=request.form.get("email_id"), + gst_no=request.form.get("gst_no") + ) + db.session.add(subcontractor) + db.session.commit() + + flash("Subcontractor added successfully!", "success") + return redirect("/subcontractor/list") + +# ---------------- LIST ----------------- +@subcontractor_bp.route("/list") +def subcontractor_list(): + subcontractors = Subcontractor.query.all() + return render_template("subcontractor/list.html", subcontractors=subcontractors) + +# ---------------- EDIT ----------------- +@subcontractor_bp.route("/edit/") +def edit_subcontractor(id): + subcontractor = Subcontractor.query.get_or_404(id) + return render_template("subcontractor/edit.html", subcontractor=subcontractor) + +# ---------------- UPDATE ----------------- +@subcontractor_bp.route("/update/", methods=["POST"]) +def update_subcontractor(id): + subcontractor = Subcontractor.query.get_or_404(id) + + subcontractor.subcontractor_name = request.form.get("subcontractor_name") + subcontractor.contact_person = request.form.get("contact_person") + subcontractor.mobile_no = request.form.get("mobile_no") + subcontractor.email_id = request.form.get("email_id") + subcontractor.gst_no = request.form.get("gst_no") + + db.session.commit() + + flash("Subcontractor updated successfully!", "success") + return redirect("/subcontractor/list") + +# ---------------- DELETE ----------------- +@subcontractor_bp.route("/delete/") +def delete_subcontractor(id): + subcontractor = Subcontractor.query.get_or_404(id) + + db.session.delete(subcontractor) + db.session.commit() + + flash("Subcontractor deleted successfully!", "success") + return redirect("/subcontractor/list") diff --git a/app/routes/user.py b/app/routes/user.py new file mode 100644 index 0000000..12757bc --- /dev/null +++ b/app/routes/user.py @@ -0,0 +1,9 @@ +from flask import Blueprint, render_template +from app.services.user_service import UserService + +user_bp = Blueprint("user", __name__, url_prefix="/user") + +@user_bp.route("/list") +def list_users(): + users = UserService().get_all_users() + return render_template("users.html", users=users, title="Users") diff --git a/app/services/__init__.py b/app/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/services/__pycache__/__init__.cpython-313.pyc b/app/services/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be71a8111c0a7fc3d85f220dac817fe739772ccc GIT binary patch literal 163 zcmey&%ge<81dlJ7XM$-E0RxOs#%C5FV=6;BgC?WjN`@jPAn!9s>XwtURZMt(QFcsD za%w?Nd_YltR%&udag1|*Zb4#EW^sO=0#qy}v7jKPIJKxOGdZ<5CO$qhFS8^*Uaz3? g7Kcr4eoARhs$CH)&`6M##URE(^b literal 0 HcmV?d00001 diff --git a/app/services/__pycache__/db_service.cpython-313.pyc b/app/services/__pycache__/db_service.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea7c9aae8aaa7f3f576f0a0c31093d8f4795eb01 GIT binary patch literal 921 zcmZWn&ubGw6rRoQCYxz4R6g;?+0%!=^eg-}~l$Z)V=id(%QeM=*YTd+2_a5c)0_ z=};0fy$@uBFv8L{q7vB5cIKH(4v*Y(4P1ZqJUz z7~!61Oev4r1+er`Vo@DZ`w80T`iu zz<9KhOwzTmEp>Jk^Zjh5{gxyB}Wx`SUt}@CpuRWdz8VpQGPZWWfoi<7M+TfUq$MJ=~HCjs&D}bA=1H41y;^N1X4<{GJ)$`)&cwy;m z<#Z)A<>iZV?YvwYmzU2DP7fw|RH{voTG9dX`V{t~PtZeIt`Xu}eTNXP6VeYlLr?H| zLXL)(mncO-x-Mm*=lYHx5EAEBCWM7n=-R{zL+ZANp~FC1f}`n80gD1eZ$uz^jETN_ zkA5jxRgYtY482&43X#4spi~r|>+n6o2R$CuBR=f<1zcN?vwlMFz#dTnCL$)XBuUc} Sl9s-r+rJe}(tjd==+-|%a>%Oy literal 0 HcmV?d00001 diff --git a/app/services/__pycache__/file_service.cpython-313.pyc b/app/services/__pycache__/file_service.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43b0dd9b098cdba124f9732fec2c622ccad66176 GIT binary patch literal 4990 zcma)AYitzP6~42xvz~p}YkL8|?J*{VHFynvgka)0U~KRMgLYWrV2feAJ8LhjXEt|s zAy}#!^+#o@O4xbSrizM@s)nSM>i*+@8YQZby4!WM)-9x{MV0aoFjdp!PtTq4>>A_H zUfK6~?m73IbMN`i>{@ZL3qiRXJrr9hM(7`OU={m%XDtGq50QvOW(Z-kWv~s#wjp-V zj_m@SV~4mw2X+{J`%uv!k9nid4LJv0*k$w`L+(Kj_6VpF?L=ZxH4^zwn<)hsPcnYz zH*_%KXNXrf7#t~*j1j;a&6>ZfB+eH>?PP9Yq5II~l>F^g3 zcR!p%RPg0kSoy{SJHzY8Hn>qkvGBk46R5yYOo%xQy>4a?)U?PQ2ni^}1TE?2v{8$U zXtRtU+BldCQeK-%=lXceataDMHj%)PO5KJ0>vQ9BA~CL;R?^2QA8CCQNL(czIZlrNUV#Ntxxu1=jVmP}Rj2B{ zi&nkmb5qxTobygBz4~#_t)AufJ508z>&}5pQ+KYZH`COcZR)$bBR4RSfxo7SG(WKh z8&NoKBp6VO8qO(!`a=}5Sx$+7fhL&{`^?xDDmbkaQI}DMn~KPGje=9@etT$3cWu3| zbKU*VNaV)o35{YoSwLfX=LUIewa^CLg}&7rqqov1L2AKGMRbI0C8#}r(Ny~e383fZ zvJ-{uVv)!nvcXw=*6NG3Qn?L0|Ibs8_E}e7bpZG6mZU-(a#&UqP(2E9!HU9~)f1f- zjb&MR2SQ_&)_Sno>J?hhFwgna_6@YP1sbcjkyb4lYp~`;mn9dhl%EY11sg4jLTmYU zs~w`dFdJe;k8!)o;P#{5BLMD&Ju>hBJlZfk(( ztnx?rUF&U>iK1?{0Yw>q>4@LfKT~@;uE@F~!1ITPE$FFb0z~NVr*(2P%q2zSj1eSOPE1cq+NBwLAgo`WsdsgEcMBmSnkx~3#taBH%H^1HMSzu=dZ>Q5xJX&jzz9hx zfQ0SLOpU?E#0cQ3r@~=H*Q2R;{A!?o#s|@ij$`Vi5S2kYQ@Ee@R?K6T`n)PHLDSYMFv)AA)H62m&C0SL5|FDsy;8qu%BV52P& zAv{(9r$ANWGJ0@OB~G{mj;TpvpMphFl`zjEJ*NwC0{AHj1N)p9Tn{p+BS`5pK9ph+ z;-vEu^#XC2sAwo;MtegITO>*tMRx)h!77+OeNsLps}b03urRGg>Zu9W0Wt9WIz5Z- zhj8~U`lq*H)%WVx-pW;9$JbupTyo(@^FO+6%T_e6`dU`KzMNOcc!i~HAJ^Tg%XwQf z-quxL|3kiZg|B~D=3A(kuUM#^ul*>Rt8dHHw=GA~hlkQ#!|9Hb*|L#Y$35P4-TgE7 zT>sLUzwpfueLI&rKJLENo%J1<b6#-+kEH*L^hQj%kv1aR@4dR5y)bWkQJ{^+fLRa z;8kvMnvlm<^G-NaXZ9fy@k1?+>s(UPt)j_zUo6A-x9NLJqoakzS+oEzOf3q&>#r&E! zODMb&__}e6o)BmGPq&%xC5krTb1TU6{Eu@}Ona8Sh(go^?;#fc+=wS+1YdrXJg zA?pU-afVKWi>VRi9pXr8aY!);A4|g55NJn=res}CCNZWF6;mf;dihC_PLlu)6qF+o z;s|Tg)3GG>(Ad1kzoVEgo%4PW@HaiT!Vq3wiMP02W&ZA9Q7Oc4%JHh(jK_>lv( z9{BymPcLS-ANus-?XnNTi;eF`7vl5rU#Op4%xph2Yx}tih&($M%WqcSsLr~ZR_hv; zTsO|=>JDV;4rJ@vXOGU#TpIzJlG5vMU3+V>bM~!tapSBFW-6){2XEBps`h27_GPOA z%R86P{UMNRJDzDfewWR*4d>cUXWCBZ+RkR$&Su+2)8pqeZRaypQf9}6S@){98qxsx zGw|`mmo>S8bD4p2xdAydAZG`{=@XH3wUYKJX^-+?N5!oBk-g6O2D4f(+`M$-(yylH zU31)ndST8D2dS;U+4WJ^T<^V#`jv*(WgmcXwxV-YXu8EOa!-x*gTFku)Oqvu8?XOP zT;BfMbGer8OiOpRr6=7hXItdeU3(V$9_-z})SIo`^SBJv?tZ!rRX0CIY<2nSOP!Bc zXdmooe9S>R=XmNukfpfhT?-}iC5x9=N_Vf8)-1lADHYyxKi-QP_B{=tV(<0AYlAsY zUB*+l;(>IiB3%rukwH7UzI}R@L8Vn|$Oih|^OTqy8#11T z6;GpKox^vI+-Xl&_oRJ2UwL}If5cJB@APJH^!29Wy#2GihmIGcKkhl&0L>T0t`iRS zi;7(*81{?94D`QbIH++KkdOFz!b=kUc}0?lOOmFwNDA^iiFhRG?UWo}U-3$i`e8j8 zkEx2PNs^fb9{>*KP24U?dJ^JHSfbA;HjzpyI#5v&81evQURsLpm{#;dRi}ycPtg-Q z!-bhAjz+HIU&G9P?hVG=K*{_in1*BGNI>=}>&C+*CGZo*r5PnP8Av5#@%6mg1wT6k z;FAS@95T~z7ADL$ypt}0T1s3GJeNLGeU-TJ?8!DtXz&b}X|BN@@ZLQ0CS?f!nrW-o xu>>UWypZ7lNaYx2&4C!#Uy<)VYQB%^?xXVisOLWF{I_F_VcuY#Afqw#{4ev!GG71y literal 0 HcmV?d00001 diff --git a/app/services/__pycache__/user_service.cpython-313.pyc b/app/services/__pycache__/user_service.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70398f48bf12986b243e5b31609827353269bfb9 GIT binary patch literal 1170 zcmah|&1(}u6o0cjo33d#ZEe%qimVM&XP^n-U6cq8`O$;L5e6vXu>%j-}=Dqp7kD1@hG%YI&C}W=w23rk) zPs-^CZ5z$~Xsm(*4mk^F2q(6(wX@n8o$EGigE4UQ5pd|F*2>^?(I{rVD5pr|mJ`Pv zpWg^PA01j2KKEK-Elt`^a|Df5r~oGpaLplHceD}U)X}-INQ;K-R=Mp`Uq&(7>*T5u zCJr4(a}ZZoVeU6JsZf+zg>I4#7LhWU#q)0#hdA0H5@}^^wrev6c+5B`A1+a$?E|6p!|6OgMCZCY84leKWqN`fAT!$eUVv_}Au=M0Rjp3UpSe>NyORIl z#xCq<QRn2jlT#P%pgL|x?vg)l`%7*R+NWkOoVV-9 zw|D`?F0QDPU0xhTzL&_1SLY(;vdh2ad-cSZ=7OJiSKKh<>di>Q3uECIGm;8FT##CI zp6Ap$>;V}7j?dVVcrGd#YEy+mayUaGk~5OHL;*D7wU zR>7^QCnYMX5Nms-+HGkq`U%6Wu(X35E+gi&f=hovJF&O8j_Mw~vj!i`y|wJumc4F` zHMEVs{-?u_ho4s;4X^d>ZDc-}`IY=~er@RR8}rCUPhsWm^4;|wyFowh8DH<6cuAl4 zKN)zu{h9t``wQAI)_NyYMs7LxFu!4DSIlMeVfI7MKqL3_TQ~HT(qq4}3db{)tM50B zRGEw^{uz^5#+Kr0Jydp%vFmj=Y$H94Ed*R7VG#LI%orcUWLaQLByJLT%uNy=%;SX! z#8lxX4&Vi)6w|31MMJ2^d>_8koKfIAI>a%){)!kv^;IW?d_M}L^d5Hqpm|dG2B^}+Uzu12zW@LL literal 0 HcmV?d00001 diff --git a/app/services/db_service.py b/app/services/db_service.py new file mode 100644 index 0000000..f8adddc --- /dev/null +++ b/app/services/db_service.py @@ -0,0 +1,19 @@ +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate + +db = SQLAlchemy() +migrate = Migrate() + + +# import mysql.connector +# from app.config import Config + +# class DBService: + +# def connect(self): +# return mysql.connector.connect( +# host=Config.DB_HOST, +# user=Config.DB_USER, +# password=Config.DB_PASSWORD, +# database=Config.DB_NAME +# ) diff --git a/app/services/file_service.py b/app/services/file_service.py new file mode 100644 index 0000000..20d9929 --- /dev/null +++ b/app/services/file_service.py @@ -0,0 +1,103 @@ +# app/services/file_service.py + +import os +import pandas as pd +from werkzeug.utils import secure_filename +from app.config import Config +from app import db +from app.models.trench_excavation_model import TrenchExcavation +from app.utils.file_utils import ensure_upload_folder + + +class FileService: + + def allowed_file(self, filename): + return "." in filename and filename.rsplit(".", 1)[1].lower() in Config.ALLOWED_EXTENSIONS + + def handle_file_upload(self, file, subcontractor_id, file_type): + + if not subcontractor_id: + return False, "Please select subcontractor." + if not file_type: + return False, "Please select file type." + if not file or file.filename == "": + return False, "No file selected." + if not self.allowed_file(file.filename): + return False, "Invalid file type! Allowed: CSV, XLSX, XLS" + + ensure_upload_folder() + + folder = os.path.join(Config.UPLOAD_FOLDER, f"sub_{subcontractor_id}") + os.makedirs(folder, exist_ok=True) + + filename = secure_filename(file.filename) + filepath = os.path.join(folder, filename) + file.save(filepath) + + try: + df = pd.read_csv(filepath) if filename.endswith(".csv") else pd.read_excel(filepath) + + print("\n=== Uploaded File Preview ===") + print(df.head()) + print("=============================\n") + + if file_type == "trench_excavation": + return self.process_trench_excavation(df, subcontractor_id) + + return True, "File uploaded successfully." + + except Exception as e: + return False, f"Processing failed: {e}" + + + + # CLEAN & SAVE TRENCH EXCAVATION DATA + def process_trench_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()}" + + 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(TrenchExcavation, 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 = TrenchExcavation( + subcontractor_id=subcontractor_id, + **record_data + ) + + db.session.add(record) + saved_count += 1 + + db.session.commit() + return True, f"Trench Excavation data saved successfully. Total rows: {saved_count}" + + except Exception as e: + db.session.rollback() + return False, f"Trench Excavation Save Failed: {e}" diff --git a/app/services/user_service.py b/app/services/user_service.py new file mode 100644 index 0000000..88da95a --- /dev/null +++ b/app/services/user_service.py @@ -0,0 +1,47 @@ +# from app.models.user_model import User +# from app.services.db_service import db +# import logging + +# class UserService: + +# @staticmethod +# def register_user(name, email, password): +# user = User(name=name, email=email) +# user.set_password(password) +# db.session.add(user) +# db.session.commit() +# logging.info(f"New user registered: {email}") +# return user + +# @staticmethod +# def validate_login(email, password): +# user = User.query.filter_by(email=email).first() +# if user and user.check_password(password): +# logging.info(f"Login success: {email}") +# return user +# logging.warning(f"Login failed for: {email}") +# return None + +# @staticmethod +# def get_all_users(): +# return User.query.all() + + +from app.services.db_service import DBService +from app.models.user_model import User + +class UserService: + + def get_all_users(self): + db = DBService().connect() + cursor = db.cursor(dictionary=True) + + cursor.execute("SELECT id, name, email FROM users") + rows = cursor.fetchall() + + users = [User(**row) for row in rows] + + cursor.close() + db.close() + + return users diff --git a/app/static/css/subcontractor.css b/app/static/css/subcontractor.css new file mode 100644 index 0000000..26f4913 --- /dev/null +++ b/app/static/css/subcontractor.css @@ -0,0 +1,35 @@ +body { + background: #f5f7fa; + font-family: Arial; + padding: 40px; +} + +form { + width: 420px; + padding: 20px; + background: #fff; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +label { + margin-top: 10px; + display: block; + font-weight: bold; +} + +input, +textarea { + width: 100%; + padding: 8px; + margin-top: 4px; +} + +button { + margin-top: 20px; + padding: 10px 20px; + background: #0055ff; + color: #fff; + border: 0; + cursor: pointer; +} \ No newline at end of file diff --git a/app/static/uploads/sub_3/test_comparison.xlsx b/app/static/uploads/sub_3/test_comparison.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..61dde3731bb7354b9952f96bdd0f85d2706a5a43 GIT binary patch literal 18270 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 literal 0 HcmV?d00001 diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 0000000..2169bd2 --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1,64 @@ + + + + + + + {{ title if title else "IndustryBase" }} + + + + + + + + + +
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% for category, message in messages %} +
+ {{ message }} + +
+ {% endfor %} + {% endwith %} +
+ +
+ {% block content %}{% endblock %} +
+ + + + + + \ No newline at end of file diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html new file mode 100644 index 0000000..a14ea00 --- /dev/null +++ b/app/templates/dashboard.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

Dashboard

+ +
+
Welcome to Comparison Project
+

This is dashboard panel.

+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/file_import.html b/app/templates/file_import.html new file mode 100644 index 0000000..211d753 --- /dev/null +++ b/app/templates/file_import.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} + +{% block content %} +

File Import

+ +
+ +
+ + + + + + + + + + + + + + +
+ +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/list_user.html b/app/templates/list_user.html new file mode 100644 index 0000000..ae534d6 --- /dev/null +++ b/app/templates/list_user.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% block content %} +

Users List

+ +
+ + + + + + + + + + + {% for user in users %} + + + + + + {% endfor %} + +
IDNameEmail
{{ user.id }}{{ user.name }}{{ user.email }}
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..988bd47 --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block content %} +

Login

+ +
+
+ + + + + + + + +
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/register.html b/app/templates/register.html new file mode 100644 index 0000000..d09a31b --- /dev/null +++ b/app/templates/register.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% block content %} +

User Registration

+ +
+
+ + + + + + + + + + + +
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/subcontractor/add.html b/app/templates/subcontractor/add.html new file mode 100644 index 0000000..61d15fa --- /dev/null +++ b/app/templates/subcontractor/add.html @@ -0,0 +1,40 @@ +{% extends "base.html" %} +{% block content %} + +
+ +

Add New Subcontractor

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/subcontractor/edit.html b/app/templates/subcontractor/edit.html new file mode 100644 index 0000000..4c4c037 --- /dev/null +++ b/app/templates/subcontractor/edit.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} +{% block content %} + +
+

Edit Subcontractor

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + Back + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/subcontractor/list.html b/app/templates/subcontractor/list.html new file mode 100644 index 0000000..2ad86f0 --- /dev/null +++ b/app/templates/subcontractor/list.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} +{% block content %} + +
+

Subcontractor List

+ + + + + + + + + + + + + + + {% for s in subcontractors %} + + + + + + + + + {% endfor %} + +
IDNameMobileEmailGST NoAction
{{ s.id }}{{ s.subcontractor_name }}{{ s.mobile_no }}{{ s.email_id }}{{ s.gst_no }} + Edit + Delete +
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/users.htm b/app/templates/users.htm new file mode 100644 index 0000000..ae534d6 --- /dev/null +++ b/app/templates/users.htm @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% block content %} +

Users List

+ +
+ + + + + + + + + + + {% for user in users %} + + + + + + {% endfor %} + +
IDNameEmail
{{ user.id }}{{ user.name }}{{ user.email }}
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/utils/__pycache__/file_utils.cpython-313.pyc b/app/utils/__pycache__/file_utils.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..495d14e1819b66f1aefc3101dc3388b4fe3ae04a GIT binary patch literal 601 zcma)3&r1S96rS1LWOH5W;7KSXDBKPjK?o6oXdO~il<3fcEbeNXtFz1~)UB&sywt68 z(6#@>LkN={qD$R`{Rf(v*6P>{^S$qVydS(bfv!gZJ0EXZ_kr1W?ktWJl3<;YJJ0|P zSOS<^sRWNDEG0ohP5>--prL&7;EDlhq=5Qux6=xfg^?NZ7d$bz17||yP+#=;QJA*$ z#|i0KWTDm71^cyo@SCSX$=(Eidx!~tqdD6E|Erh;9d->^F(On#getx@IHwWk(j^0e z`AAehsg0^W({3;X6N!d=sAIlkAdVRYfN2E;6&o^N57 zpnfvcOw0Gp;lTBX*>*jrDQMciqH(8BhL{Pyhb+6gNmgV+w%Sel_=zHJ(1t>abhY_ q9P`DAFdXAS>Ol|LL(j?K73T7tlT`+D8AA91mS4eIph$3AWPAaPk8@`L literal 0 HcmV?d00001 diff --git a/app/utils/file_utils.py b/app/utils/file_utils.py new file mode 100644 index 0000000..8a79d69 --- /dev/null +++ b/app/utils/file_utils.py @@ -0,0 +1,6 @@ +import os +from app.config import Config + +def ensure_upload_folder(): + if not os.path.exists(Config.UPLOAD_FOLDER): + os.makedirs(Config.UPLOAD_FOLDER) diff --git a/app/utils/helpers.py b/app/utils/helpers.py new file mode 100644 index 0000000..2ab63b9 --- /dev/null +++ b/app/utils/helpers.py @@ -0,0 +1,2 @@ +def is_logged_in(session): + return session.get("user_id") is not None diff --git a/instance/comparisondb.db b/instance/comparisondb.db new file mode 100644 index 0000000000000000000000000000000000000000..3f771ffff950e676aba99681b3e4ac0431c6c488 GIT binary patch literal 12288 zcmeI#F-yZh6bJCTDry5I9W33-+e|=;t#oqGSPl)wXk#LD3MYv)khC>P(N#ykoL|S$ zT%axv-5kpQ;JxtPaUu81^d2ToQpWVW$TL~eDQh#%*#!|}j90N!#d@iFcU@FZRc~6H z^*;|=`ZsInJ*M~cuT2NA4*>{300Izz00bZa0SG_<0ucCrf%iV&?{+%;Cy7W*Oq4th9{>qes_nXQGMp#vu`bLN;hIkMiSM%z_llVAftYtshLNOz3y3uvt%B{ zZ^cVm&Gw;Om5aI#)t80?mDOB-pgdbDwN=7`00bZa0SG_<0uX=z1Rwwb2tZ(41vGUr f%>Uc^dvPxaKmY;|fB*y_009U<00IzzKrQeC^Xx`9 literal 0 HcmV?d00001 diff --git a/logs/app.log b/logs/app.log new file mode 100644 index 0000000..3b781b9 --- /dev/null +++ b/logs/app.log @@ -0,0 +1,200 @@ +2025-12-09 13:11:05,606 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:11:05,607 | INFO | Press CTRL+C to quit +2025-12-09 13:11:05,608 | INFO | * Restarting with stat +2025-12-09 13:11:06,239 | WARNING | * Debugger is active! +2025-12-09 13:11:06,240 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:11:48,880 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:11:48,881 | INFO | Press CTRL+C to quit +2025-12-09 13:11:48,882 | INFO | * Restarting with stat +2025-12-09 13:11:49,519 | WARNING | * Debugger is active! +2025-12-09 13:11:49,521 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:05,727 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\user_service.py', reloading +2025-12-09 13:12:05,826 | INFO | * Restarting with stat +2025-12-09 13:12:06,499 | WARNING | * Debugger is active! +2025-12-09 13:12:06,501 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:09,545 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:12:09,654 | INFO | * Restarting with stat +2025-12-09 13:12:10,286 | WARNING | * Debugger is active! +2025-12-09 13:12:10,288 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:12,311 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\routes\\auth.py', reloading +2025-12-09 13:12:12,407 | INFO | * Restarting with stat +2025-12-09 13:12:13,071 | WARNING | * Debugger is active! +2025-12-09 13:12:13,072 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:16,128 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:12:16,257 | INFO | * Restarting with stat +2025-12-09 13:12:16,898 | WARNING | * Debugger is active! +2025-12-09 13:12:16,900 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:20,944 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\routes\\user.py', reloading +2025-12-09 13:12:21,042 | INFO | * Restarting with stat +2025-12-09 13:12:21,719 | WARNING | * Debugger is active! +2025-12-09 13:12:21,721 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:23,762 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\routes\\file_import.py', reloading +2025-12-09 13:12:23,870 | INFO | * Restarting with stat +2025-12-09 13:12:24,505 | WARNING | * Debugger is active! +2025-12-09 13:12:24,507 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:27,561 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\__init__.py', reloading +2025-12-09 13:12:27,670 | INFO | * Restarting with stat +2025-12-09 13:12:28,294 | WARNING | * Debugger is active! +2025-12-09 13:12:28,296 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:31,336 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\db_service.py', reloading +2025-12-09 13:12:31,448 | INFO | * Restarting with stat +2025-12-09 13:12:32,097 | WARNING | * Debugger is active! +2025-12-09 13:12:32,099 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:13:05,662 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:13:05,773 | INFO | * Restarting with stat +2025-12-09 13:13:06,466 | WARNING | * Debugger is active! +2025-12-09 13:13:06,469 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:13:10,944 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:13:10,944 | INFO | Press CTRL+C to quit +2025-12-09 13:13:10,945 | INFO | * Restarting with stat +2025-12-09 13:13:11,623 | WARNING | * Debugger is active! +2025-12-09 13:13:11,625 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:14:11,295 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:14:11,393 | INFO | * Restarting with stat +2025-12-09 13:14:12,004 | WARNING | * Debugger is active! +2025-12-09 13:14:12,006 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:14:32,108 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:14:32,109 | INFO | Press CTRL+C to quit +2025-12-09 13:14:32,110 | INFO | * Restarting with stat +2025-12-09 13:14:32,699 | WARNING | * Debugger is active! +2025-12-09 13:14:32,701 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:15:58,632 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:15:58,733 | INFO | * Restarting with stat +2025-12-09 13:15:59,415 | WARNING | * Debugger is active! +2025-12-09 13:15:59,416 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:16:03,475 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:16:03,583 | INFO | * Restarting with stat +2025-12-09 13:16:04,204 | WARNING | * Debugger is active! +2025-12-09 13:16:04,206 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:16:33,504 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:16:33,605 | INFO | * Restarting with stat +2025-12-09 13:16:34,213 | WARNING | * Debugger is active! +2025-12-09 13:16:34,215 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:16:41,815 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:16:41,816 | INFO | Press CTRL+C to quit +2025-12-09 13:18:12,302 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:18:12,302 | INFO | Press CTRL+C to quit +2025-12-09 13:22:07,114 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:22:07,114 | INFO | Press CTRL+C to quit +2025-12-09 13:22:07,116 | INFO | * Restarting with stat +2025-12-09 13:22:07,935 | WARNING | * Debugger is active! +2025-12-09 13:22:07,937 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:23:21,204 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:23:21,305 | INFO | * Restarting with stat +2025-12-09 13:24:06,973 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:24:06,973 | INFO | Press CTRL+C to quit +2025-12-09 13:24:06,974 | INFO | * Restarting with stat +2025-12-09 13:24:07,689 | WARNING | * Debugger is active! +2025-12-09 13:24:07,691 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:24:36,315 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\app.py', reloading +2025-12-09 13:24:36,418 | INFO | * Restarting with stat +2025-12-09 13:24:37,074 | WARNING | * Debugger is active! +2025-12-09 13:24:37,076 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:26:54,442 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:26:54,543 | INFO | * Restarting with stat +2025-12-09 13:26:59,170 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:26:59,170 | INFO | Press CTRL+C to quit +2025-12-09 13:26:59,171 | INFO | * Restarting with stat +2025-12-09 13:26:59,827 | WARNING | * Debugger is active! +2025-12-09 13:26:59,829 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:47,631 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:28:47,747 | INFO | * Restarting with stat +2025-12-09 13:28:48,478 | WARNING | * Debugger is active! +2025-12-09 13:28:48,480 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:51,150 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:28:51,151 | INFO | Press CTRL+C to quit +2025-12-09 13:28:51,153 | INFO | * Restarting with stat +2025-12-09 13:28:51,788 | WARNING | * Debugger is active! +2025-12-09 13:28:51,790 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:54,904 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:28:55,010 | INFO | * Restarting with stat +2025-12-09 13:28:55,608 | WARNING | * Debugger is active! +2025-12-09 13:28:55,610 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:56,644 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:28:56,752 | INFO | * Restarting with stat +2025-12-09 13:29:04,454 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:29:04,454 | INFO | Press CTRL+C to quit +2025-12-09 13:29:04,455 | INFO | * Restarting with stat +2025-12-09 13:29:05,096 | WARNING | * Debugger is active! +2025-12-09 13:29:05,098 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:30:01,657 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:30:01,657 | INFO | Press CTRL+C to quit +2025-12-09 13:30:01,658 | INFO | * Restarting with stat +2025-12-09 13:30:02,278 | WARNING | * Debugger is active! +2025-12-09 13:30:02,280 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:30:27,872 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:30:27,872 | INFO | Press CTRL+C to quit +2025-12-09 13:30:27,873 | INFO | * Restarting with stat +2025-12-09 13:30:28,474 | WARNING | * Debugger is active! +2025-12-09 13:30:28,476 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:33:22,709 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:33:22,709 | INFO | Press CTRL+C to quit +2025-12-09 13:33:22,710 | INFO | * Restarting with stat +2025-12-09 13:33:23,778 | WARNING | * Debugger is active! +2025-12-09 13:33:23,781 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:33:29,939 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\db_service.py', reloading +2025-12-09 13:33:30,080 | INFO | * Restarting with stat +2025-12-09 13:33:44,462 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:33:44,462 | INFO | Press CTRL+C to quit +2025-12-09 13:33:44,464 | INFO | * Restarting with stat +2025-12-09 13:33:45,216 | WARNING | * Debugger is active! +2025-12-09 13:33:45,218 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:35:23,298 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:35:23,299 | INFO | Press CTRL+C to quit +2025-12-09 13:35:23,301 | INFO | * Restarting with stat +2025-12-09 13:35:24,098 | WARNING | * Debugger is active! +2025-12-09 13:35:24,100 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:25,991 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:38:26,126 | INFO | * Restarting with stat +2025-12-09 13:38:27,120 | WARNING | * Debugger is active! +2025-12-09 13:38:27,122 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:37,386 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:38:37,513 | INFO | * Restarting with stat +2025-12-09 13:38:38,297 | WARNING | * Debugger is active! +2025-12-09 13:38:38,300 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:45,485 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:38:45,605 | INFO | * Restarting with stat +2025-12-09 13:38:46,348 | WARNING | * Debugger is active! +2025-12-09 13:38:46,350 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:55,109 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:38:55,109 | INFO | Press CTRL+C to quit +2025-12-09 13:38:55,110 | INFO | * Restarting with stat +2025-12-09 13:38:55,959 | WARNING | * Debugger is active! +2025-12-09 13:38:55,961 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:39:27,813 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:39:27,937 | INFO | * Restarting with stat +2025-12-09 13:39:28,684 | WARNING | * Debugger is active! +2025-12-09 13:39:28,687 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:40:00,602 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:40:00,728 | INFO | * Restarting with stat +2025-12-09 13:40:01,428 | WARNING | * Debugger is active! +2025-12-09 13:40:01,430 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:40:21,531 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:40:21,531 | INFO | Press CTRL+C to quit +2025-12-09 13:40:21,533 | INFO | * Restarting with stat +2025-12-09 13:40:22,307 | WARNING | * Debugger is active! +2025-12-09 13:40:22,309 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 14:03:58,363 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 14:03:58,363 | INFO | Press CTRL+C to quit +2025-12-09 14:03:58,364 | INFO | * Restarting with stat +2025-12-09 14:03:59,038 | WARNING | * Debugger is active! +2025-12-09 14:03:59,041 | INFO | * Debugger PIN: 697-115-033 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..50eb16d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +Flask +pandas +openpyxl +xlrd +Werkzeug +python-dotenv +cryptography \ No newline at end of file diff --git a/run.py b/run.py new file mode 100644 index 0000000..ce951e0 --- /dev/null +++ b/run.py @@ -0,0 +1,9 @@ +from app import create_app, db + +app = create_app() + +with app.app_context(): + db.create_all() + +if __name__ == "__main__": + app.run(debug=True, port=5001)