From 2c7297ef316c7d63d979ddbe39c73aeaf8f6527b Mon Sep 17 00:00:00 2001 From: user_2i Date: Mon, 23 Mar 2026 11:35:48 +0500 Subject: [PATCH] 23.03.2026 --- Categories_import.xlsx | Bin 0 -> 9970 bytes Clients_import.xlsx | Bin 0 -> 10956 bytes Materials_import.xlsx | Bin 0 -> 10973 bytes OrderItems_import.xlsx | Bin 0 -> 9726 bytes Orders_import.xlsx | Bin 0 -> 10625 bytes Products_import.xlsx | Bin 0 -> 9912 bytes README.md | 93 --- Resource/Categories_import.xlsx | Bin 0 -> 9970 bytes Resource/Clients_import.xlsx | Bin 0 -> 10956 bytes Resource/Materials_import.xlsx | Bin 0 -> 10973 bytes Resource/OfficeStyle.png | Bin 0 -> 4129 bytes Resource/OrderItems_import.xlsx | Bin 0 -> 9726 bytes Resource/Orders_import.xlsx | Bin 0 -> 10625 bytes Resource/Products_import.xlsx | Bin 0 -> 9912 bytes Resource/favicon.ico | Bin 0 -> 4129 bytes main.py | 653 ++++++++++++++++++ main_flask.py | 897 +++++++++++++++++++++++++ partners.db | Bin 0 -> 143360 bytes static/OfficeStyle.png | Bin 0 -> 4129 bytes static/css/style.css | 419 ++++++++++++ static/favicon.ico | Bin 0 -> 4129 bytes static/js/script.js | 37 + templates/about.html | 18 + templates/add_client.html | 378 +++++++++++ templates/add_product.html | 223 ++++++ templates/base.html | 620 +++++++++++++++++ templates/cart_new.html | 434 ++++++++++++ templates/catalog.html | 564 ++++++++++++++++ templates/components/header.html | 6 + templates/components/partner_card.html | 244 +++++++ templates/edit_client.html | 396 +++++++++++ templates/edit_product.html | 279 ++++++++ templates/home.html | 16 + templates/index.html | 238 +++++++ templates/materials.html | 266 ++++++++ templates/order_history.html | 465 +++++++++++++ templates/orders_list.html | 316 +++++++++ templates/product_detail.html | 427 ++++++++++++ 38 files changed, 6896 insertions(+), 93 deletions(-) create mode 100644 Categories_import.xlsx create mode 100644 Clients_import.xlsx create mode 100644 Materials_import.xlsx create mode 100644 OrderItems_import.xlsx create mode 100644 Orders_import.xlsx create mode 100644 Products_import.xlsx delete mode 100644 README.md create mode 100644 Resource/Categories_import.xlsx create mode 100644 Resource/Clients_import.xlsx create mode 100644 Resource/Materials_import.xlsx create mode 100644 Resource/OfficeStyle.png create mode 100644 Resource/OrderItems_import.xlsx create mode 100644 Resource/Orders_import.xlsx create mode 100644 Resource/Products_import.xlsx create mode 100644 Resource/favicon.ico create mode 100644 main.py create mode 100644 main_flask.py create mode 100644 partners.db create mode 100644 static/OfficeStyle.png create mode 100644 static/css/style.css create mode 100644 static/favicon.ico create mode 100644 static/js/script.js create mode 100644 templates/about.html create mode 100644 templates/add_client.html create mode 100644 templates/add_product.html create mode 100644 templates/base.html create mode 100644 templates/cart_new.html create mode 100644 templates/catalog.html create mode 100644 templates/components/header.html create mode 100644 templates/components/partner_card.html create mode 100644 templates/edit_client.html create mode 100644 templates/edit_product.html create mode 100644 templates/home.html create mode 100644 templates/index.html create mode 100644 templates/materials.html create mode 100644 templates/order_history.html create mode 100644 templates/orders_list.html create mode 100644 templates/product_detail.html diff --git a/Categories_import.xlsx b/Categories_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..317a00e98e4335c8a778a36f71504f9f63308313 GIT binary patch literal 9970 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 UVL1o@pu;|Nur#ir{_X1j073XV9smFU literal 0 HcmV?d00001 diff --git a/Clients_import.xlsx b/Clients_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..52b726515c6cd44e10e8b98473371b4a936063fe GIT binary patch literal 10956 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 bKm3@IEX?zE`PmDH1ektq1=#)BHV62BFateX literal 0 HcmV?d00001 diff --git a/Materials_import.xlsx b/Materials_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..31f0f4d25818693896bfc6c152eb2232f692d5de GIT binary patch literal 10973 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 literal 0 HcmV?d00001 diff --git a/OrderItems_import.xlsx b/OrderItems_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b9ef8e1c9a1b454e24597ec84520b2112adc23e3 GIT binary patch literal 9726 zcmeHtg;yNe_I2YB9D;=4?oMzB8lcg}9fE}50fM`02o~H4PUG%wY1}P=q#?Mw{d(rT z_svXZzQ5qTsq|M` z9qZ=@APUDXd`28(LJKmq=7bshNmQfDMx!QO$N)TGSDnaDj4SdH@6j`RdQcqOrmq&5 zHY_rRb9S230@}zi?9KPd0`fCFG1X$obJWm*i{B%~9ptEWo-W>RnjC6AAqeEFr>0K= z7Wp;(&<_h_nSN%g)WtG@<5VftdD`0Da1fFoAuIJlEiOxQkl4ur8Wwx%cDU7V8Yi0A z@m3LYX+G)$J|m~JDv3T|$2M*=Pkms&>GIn7nD)k>)GYWBf6r;B?6gY~XShonghJMg z#PG;{rZkuH__JL}SSE;Dsh4MP&5Z|*LLpNy+=1VAU>Y}m0avP^9!cbq4wyHXp-&*u z3HssoZ4dCZ-i?&Ione*%Hl-dP5df-x;bpxhC(RkGMG;0jbQmvtph1pRaZ@km6{N1R=cg zYxlhySzZ;1*%_j`*x)UX!h0%A)8JMSntb!_Jqk0u(8`!L0>jNps_$2XRyFeH>?Dk* z`^|qU+{P3S7gXGvN+lR_e*I<<>^)>lb$(5vsct3sw(513lMuCsvAJ#6sdRcL{=GMw za>fvdniubid;HZPUCz0mULEi8Xr@OWKU#0u(9v*U6h-kGOrriylI+I{76JqSpcDlF zz=n;CyDf*CgOkl`2M3$qgsWU*)jpl`X-9UQ+shSo+b6*}^qP!0n%1SIkfr@nr*2*? zI2yAw4NZ=Q`Gu%Gt|k5@uHXXQBBq_tt^u*Zuh(O-Ib6HH=?>tLoD?uwF$v>HI8z7sioVfY z%_kUUcSOQJ?04*~jS6+`1*bV=DJU zY3I2WRv+(=)fq;vpUdJ(h3G;?G{823B^HU?^3!o*{&dC@kkAU7ypq6BC}n-9)HjO{ z^H6X4xIqWc0P-918v@x6U^cx;0w9!B^0ilb zyGr8fSU_dik_b9*l4M)orRRe(Mr>{3;)F~}9KnW=z?ql9LW-LA!XG(Ql@-229 z!`ERy-6tMYRg^ME46u2wOnfMeKuRv7Tpn3MQ?@d`<}oW$E2

i+JWuxeE5-8z@^n zx16&p2i4Ek-knyp^Q~@oG8y?_3a+XNcC4r!|8x;bKPdLXgMceH43ik9DKqxK;)3GY z-kCDSp7@&-2-Xc~+GhHNmd5nojbZ%wJA(qm5|dA1EiEvaApxMm!5H)}rTH_D{-Zi@ zuqY75!~gEB9Ha#7yR%gC7_;flzrlc#mI292`9!@# zT`0qbUQzfl#XCduQd>0-*IguUN0>U7PgqCK4lRES56*sted)hXnO5RVc~WEm0FD#@ zAco!XZ>Q^QWntms%<=n)>o@P4p}YJcUjWC)`0XRy@fw^|{DHK*EWTXbY1Nc<@4oCj%!)@X_T*u}w4VE(r2N}%Cu~9YHNM$OA{rw)0QX!5?8*N4J`C;%|kDw1-|&eJQOvb2k~%H?+C zJx0MMf}b?wc#rCZJkBdd;-!R(o7@8q$J?ogE5VUf4*A2lFXw)Y(J7vq7ipvD3t>-uqvKOn&5(Sm zj!=Rihu!8arBI-+PV3{%)ghcO`t|xHMdrS^TdmL!#}H^~2D31Db^LWRw$%J``4aq% z@c7zJ_gCcvk;gd0nz~^Vymg@(vFy>4GM78}j~rp10}DR-*`1nWRKoNe$(xra`^l{0 zna@$V6Qrh2;7_}X)PGb-QL@RLbhw(zI9%rn2BnLqir(a+T7pkAW+7t9W`+ztCFwO+ zD4CpzPq_OjIrGrDvqd15)7R7A2lKyhJ-Iu``$8YvV;uZQ(WgFYJ&nttRHLg2O-CR= z?c3F-zO2<5TW2o7yJMZ4Lk5sB zOPkHL+ZwcZV4jVtyH;pHSei~HY&VPtuOAXmC(TMyi|fj{oVgeHk!(rYxSB+N!2x4g zcl6WKd9B<;w%z9}i3XuC+izIH-#KtuyO`GUxImSCR?m{w4wfn;^iwK| zfYDx%h4H*eAMzPsl6UsQA1B|ooEt6k6N=VUlq1hUz^fB=EN^} z)g9H6!{>|Lup3^l*bInilB^;D-6p5#p1YN)DkPuB5Gd55*Pgq`zqlaGm(}iq&@r(4 z0#j_)*xY$!$fy+C%!1#-jWT&nopDZA_{e3}%ix8?KaoNuP-cHa>wekPTQbpI;I;;r zYK9%8Q#O{aEf7#6!-w^*hADq6Q-P1gSNN!5H>1BeVKYfNM^&vtYK0QQY!eSv#ujD{>&4@w>hl?e9D7D1T!NJKxFW=_okSwlCQ&RVp$Whz!GUQXE1tGVwQ9nDP zMynFxF7~&>rC3R5ywr$8iWSbFH5jwjmQUAIY5I)a_hRfPqQ`kOJdnp~8~N38H}+W& z97h76al4Q^LcmTSZ!A09YfHISv@jtacRFmldDDWs%Qbd{b|dgYKYZG#0bNQLJL%&Z zpeIEF?mVz)deZ_g>#}YbhHjEiKg1VyQ}C)&PaIEc5(8~PcFp}O$Y>M3oeaqtaak1vw*=`UK>1W6r_^xithdJl1f>uduUO)K)#Y7ovmdT2Xd2WXw z#FO3+sJvJy|9+&h-g)?gs@nsia-Kqaw$-Ekh2WgAL8~52y-L+nR@ERX1 z7F~>g*nGSlZH2h~qoQ;Z;dCg&Lihp7-*QmDD~gMig`EY*@5kT8WKS0o^_>4{C((^K zhO^rp-}hL$wQu9L39Gc`nTe$J4SQ-@JlyeZ&+*~u1kXW?1)q~89YhnSULs(&pT(ll z)@@TvGC&q+DxkFKwhDT#m{G4D+KY-VvwS^IU5=;PQ#@a#p!dXoGVV}45zUBRNTHqn z0L zK6+5DhbEhFkd!QFErpQfGpK@?CjQDO@U^O!4>uLf9%hn)pI1qn$~sq^BxW?@SMAbj zy4>pTy)}~IAwNL}WK>HhrdeFVnTdqAU&_o#t6j*gXg>VdYuhZMQ~QUfk}l83qrd|_8(0#Rc~f$x35G=5sXsszNC+TE5AkS4uF68T5u_S{A+8ozHn{tlv8i+&5BfJhM@i zmUn6jWe=&hc57ZDFz@;K0e=l6NTNNSXKhZw&Wi zs7#>NG(|BAe(PJNn?}WR2*sl}Y0_ZARM5Pt6bpDLq={_cOo84!UrE-8Zb* zaL1A}%TLLXCF=EXw0#=ZDe8Cj^Sal#rn#OOXpcgtu6{5ZYy5bBPqb#-`Eayz%)dRu zaNN_^d3QaU-1&GcbY8WwLcr1Cb8@nsK=jq;d`l&kY-yR4EaiwQqWTEDZgxl?Wg38W zdkiO@*~cl_7ylCXr)%-S=n%Y-KIKl&`>Oq(Wm261q&AUGo5dE2<7V0qsg<(TNGoR1 zuEcIa-%8U)kB%I(6ju{YnnJ+8dz7m@11+%t*Y5LV@ln_0DRk zXtJ_asc`7LDEEe9Rm9l=PGwN|G@X=_2_1;NPU>~|XpaSD@X`rn&91Vy*k)GL+nmM} z_8y$R;U&<4Q7d+}J&>R@7av(il=%;CC%^7j^k5EJY0pTe(;G9^VBn@u*g1(r=M#+Y zShwVceJ|pHPCuubqlkIpL|qqRR7ISZ6yt~beCe^MWa8X{00*^oE?sjHW`h=S-h;) z!q99DH%5Jx#+Smnl1Rh${T;nH1NTzw1csiJ#cEeZq~f`TI}d%1SwYx)7J}@Fid*GV z_t=htCL=R0P7|9dT0U2MPpoE) zCHd6oO|a2os?MZ~&ZO#2a;~22JLnTmI|2fC=*2ggc4(Nyl0>K_Y2ua{K~Y_5TQvB| zSgNdN0#8XQoa$>19?Do3^~IKV9@g*QmbS|ju+c=j)W&d5aRw5tvkF5#-Rcgsq=wCK zt2DoEe(uDx6N8OwBSX#56hKd}KG7#^e_d~l+Q>}9YjchNlel-@9l4oiMxQ88y~*{N ze3t!{o9U-#L^Wa3i9!Ym$|J~JaVcJjeQd^Teo2_TlcafeEZY7!VtU`xUb0Z6zr%46 z9&+dIrgO01TpOcAiI4t9Jf?f*(vPP<6j(@qf++m0Z##gAK{qr<_1@*%=MD#&RE z!WEESMGyzQcH1x+v6^p-oDxj@KqC~T>YA5gp4Gz_0sbo*kEWB9{g|_t>pD2WG zPPXhX+)BD_%Ds`bwQ9?CJgle~Dl;#x?B2@?h#rF(#D_A!=)Hf*x~q_Rbu+TkHfxFE z79is3=qFGF`l%}EkW9mPGxdBZ@r6m$N`h_->en_w2DV3ECR>zMg$1@m64Oo`jUZ4i zZbMm!E3ww-eU-t^duHr!CUI&8Skt>Va0aFmGOlkc2j|%jzC+m{A-GXdipF1v>ep{J zIt&)Q-yPyoX5QA1CWfV-~H`FKcB1_Wyqm z`>DhHm;5@rc-UGv|MnMGrwOs2eu>jTbBtBi-fGkOPL6sxoVQ-1L{5$kZ$747S!*x0 zeoY!HoF}XU;jk+X;c%h@x3(dn$+{#bJW5nJ>)LWNeevC0OB}piYDu#e8kVwmbjry4 z?pfyU!%7~9KsCD(=HiJ+I`={AJ0YKIYVf{tRT-ZdAzW}Nep^FB8ZKzdhW@Qj9!udj zU`b2?;Rj2Zoe@sGnKAh%csCCzaw7x>IF{Ux_&D;AK_w_uPiy9cj%ejTk2Ts{tW}4} z?kDJFsS;U{Md`lgJKhQ<@BtuluO`$M&^A+t&Uvdx*u6Uca zmswT>FLkJ0vkisvcMywyzJWuclH&r)RMSIngT_lQ1jQ+VdCBMIxxkm8GBu5wv5n{_ z9lR^4Ng7VoyED1!bus(40!sT=P6 z3`RM&d#6$)N(CtT#oaT=(+x-tsJ^Q`XO#lrFn zpEJcaSv9{CWwjnbcsOiB7&<&Iz*-B}N?Nc`l@a%`1Akog5A;GLRgkb(#`nJ6zqnn6 ztj;fIyYV-Qe|vH9HWwO-J~~T73vitzeS2=GU9pVEwjO5HW#6sPf_rgu#MS-knvLa3 zHWa1I&AZGFJ?>lnims9&#@xav2^ghqa^MKjPb|ALjeV?kBK_(#f?voYjz4A-or5G3 zLKJ1Y6ZWu}+zq}7Q9S-Ehg&B9-#Zb$6{+k|%TL<9_4*6rru1M0$>ReGx*>7RIW z2%jT3@D}1baEryXu|DbPcjpz4t+D#(b@nA@GlBA_Yd%mcO_x3OoAuW+pRiCpD?HL{ z#-5}p*Fe%o{cVnaj6jh?O};9?$RP?#CO`c*1*}Y+EX>tioZi~M`JD;2@k;i+l(6zw zk|#=(&oviv`iLuGl4qc+9aTEL92_YRIBhxkh44|l1G&Q*##s@CTSW(i(C!G~bxPjI zl_2X}Hp?+aFYVi(cz9w}; zvaA55oEoe;DOZC8!KolVExR#~B1U_i4>B~2gdynpk=$Qedg$8W3T67z=vYU7XiVJr z7cstKuMp^CU8fN|`~Zzf#3-X~vBiSM7fFo%G$_UbrjC!(5@9suoR@ZgPE$6gQGKtnS+zXzw6Kc%RIs+Wi&`hpFGIt! zxp!%zG@jia8sihgO_U*YC&MAi)ZJB3qf+f=BqM_UcsG9#FwvXy%l+OEJ+Q(O*onSx zl|v9lC{#u4(ad-)5rxxoWzjoC$|M}*r6R2Ko!rYNX-M~;9KyPH>pMCBotW2en8M!g zYi!x(0G2M32}FS<09oHk>+YyPdquRvzeghr4wu-?u&p_ib6ryqyrUA-Lx4g+R(~Q_L&^V9#UL?Uoo+rJ~!nt2$$-7o8 zBNXqI*p!Z^aS%0iOvg|0kIsW4-7xA9*7DmV#`*IEHg$CT-~5FQ%)hsckAKuF887*s z$>FC>DSihU&j^9L%shBu;3K{JVR>6m(b=#VEybby(TTDgS~CR#cv{1| z)_bptv)dO8^_zb8lq`lK>e}x?LpW|4AC4c};Z4yg*lze`Y{cvI`F7v_`@?t>DUHeL*6z18XHyi{(wt33>;)0la?<`lGhsnbUy35>YH|GWJf^vbD}37tE?Z@{9IZ8 zuykU`v$GX(0rO-3@^WzSY%n$X=an}98I=E=|6$#YD)6rc{<TWX@S76 zz+cOxe?Z$|A>S`W(_g`Vtq}bIg>@3`ckutGUi7P-U&{u6SmMU`e=qU3BEqj$eoYnq zVI>&v9}`Ev8u&HX{lfqP$?pdK2z`Hr{u(6w0YxVJ7xdSV;a3ZPmAXIh06-u)0Pr{A l`xX9INAqX66xE;L|8_g7KqT1L1puDFc7K@iTG9M=^?!+M8EXIl literal 0 HcmV?d00001 diff --git a/Orders_import.xlsx b/Orders_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f789f339bd3c98fbdabc418a17b1d065ace878d2 GIT binary patch literal 10625 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 UVL1o@pu;|Nur#ir{_X1j073XV9smFU literal 0 HcmV?d00001 diff --git a/Resource/Clients_import.xlsx b/Resource/Clients_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..52b726515c6cd44e10e8b98473371b4a936063fe GIT binary patch literal 10956 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 bKm3@IEX?zE`PmDH1ektq1=#)BHV62BFateX literal 0 HcmV?d00001 diff --git a/Resource/Materials_import.xlsx b/Resource/Materials_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..31f0f4d25818693896bfc6c152eb2232f692d5de GIT binary patch literal 10973 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 literal 0 HcmV?d00001 diff --git a/Resource/OfficeStyle.png b/Resource/OfficeStyle.png new file mode 100644 index 0000000000000000000000000000000000000000..170e5cff71d4c7ab099fdd76baa0f0535ce5a7e0 GIT binary patch literal 4129 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

i+JWuxeE5-8z@^n zx16&p2i4Ek-knyp^Q~@oG8y?_3a+XNcC4r!|8x;bKPdLXgMceH43ik9DKqxK;)3GY z-kCDSp7@&-2-Xc~+GhHNmd5nojbZ%wJA(qm5|dA1EiEvaApxMm!5H)}rTH_D{-Zi@ zuqY75!~gEB9Ha#7yR%gC7_;flzrlc#mI292`9!@# zT`0qbUQzfl#XCduQd>0-*IguUN0>U7PgqCK4lRES56*sted)hXnO5RVc~WEm0FD#@ zAco!XZ>Q^QWntms%<=n)>o@P4p}YJcUjWC)`0XRy@fw^|{DHK*EWTXbY1Nc<@4oCj%!)@X_T*u}w4VE(r2N}%Cu~9YHNM$OA{rw)0QX!5?8*N4J`C;%|kDw1-|&eJQOvb2k~%H?+C zJx0MMf}b?wc#rCZJkBdd;-!R(o7@8q$J?ogE5VUf4*A2lFXw)Y(J7vq7ipvD3t>-uqvKOn&5(Sm zj!=Rihu!8arBI-+PV3{%)ghcO`t|xHMdrS^TdmL!#}H^~2D31Db^LWRw$%J``4aq% z@c7zJ_gCcvk;gd0nz~^Vymg@(vFy>4GM78}j~rp10}DR-*`1nWRKoNe$(xra`^l{0 zna@$V6Qrh2;7_}X)PGb-QL@RLbhw(zI9%rn2BnLqir(a+T7pkAW+7t9W`+ztCFwO+ zD4CpzPq_OjIrGrDvqd15)7R7A2lKyhJ-Iu``$8YvV;uZQ(WgFYJ&nttRHLg2O-CR= z?c3F-zO2<5TW2o7yJMZ4Lk5sB zOPkHL+ZwcZV4jVtyH;pHSei~HY&VPtuOAXmC(TMyi|fj{oVgeHk!(rYxSB+N!2x4g zcl6WKd9B<;w%z9}i3XuC+izIH-#KtuyO`GUxImSCR?m{w4wfn;^iwK| zfYDx%h4H*eAMzPsl6UsQA1B|ooEt6k6N=VUlq1hUz^fB=EN^} z)g9H6!{>|Lup3^l*bInilB^;D-6p5#p1YN)DkPuB5Gd55*Pgq`zqlaGm(}iq&@r(4 z0#j_)*xY$!$fy+C%!1#-jWT&nopDZA_{e3}%ix8?KaoNuP-cHa>wekPTQbpI;I;;r zYK9%8Q#O{aEf7#6!-w^*hADq6Q-P1gSNN!5H>1BeVKYfNM^&vtYK0QQY!eSv#ujD{>&4@w>hl?e9D7D1T!NJKxFW=_okSwlCQ&RVp$Whz!GUQXE1tGVwQ9nDP zMynFxF7~&>rC3R5ywr$8iWSbFH5jwjmQUAIY5I)a_hRfPqQ`kOJdnp~8~N38H}+W& z97h76al4Q^LcmTSZ!A09YfHISv@jtacRFmldDDWs%Qbd{b|dgYKYZG#0bNQLJL%&Z zpeIEF?mVz)deZ_g>#}YbhHjEiKg1VyQ}C)&PaIEc5(8~PcFp}O$Y>M3oeaqtaak1vw*=`UK>1W6r_^xithdJl1f>uduUO)K)#Y7ovmdT2Xd2WXw z#FO3+sJvJy|9+&h-g)?gs@nsia-Kqaw$-Ekh2WgAL8~52y-L+nR@ERX1 z7F~>g*nGSlZH2h~qoQ;Z;dCg&Lihp7-*QmDD~gMig`EY*@5kT8WKS0o^_>4{C((^K zhO^rp-}hL$wQu9L39Gc`nTe$J4SQ-@JlyeZ&+*~u1kXW?1)q~89YhnSULs(&pT(ll z)@@TvGC&q+DxkFKwhDT#m{G4D+KY-VvwS^IU5=;PQ#@a#p!dXoGVV}45zUBRNTHqn z0L zK6+5DhbEhFkd!QFErpQfGpK@?CjQDO@U^O!4>uLf9%hn)pI1qn$~sq^BxW?@SMAbj zy4>pTy)}~IAwNL}WK>HhrdeFVnTdqAU&_o#t6j*gXg>VdYuhZMQ~QUfk}l83qrd|_8(0#Rc~f$x35G=5sXsszNC+TE5AkS4uF68T5u_S{A+8ozHn{tlv8i+&5BfJhM@i zmUn6jWe=&hc57ZDFz@;K0e=l6NTNNSXKhZw&Wi zs7#>NG(|BAe(PJNn?}WR2*sl}Y0_ZARM5Pt6bpDLq={_cOo84!UrE-8Zb* zaL1A}%TLLXCF=EXw0#=ZDe8Cj^Sal#rn#OOXpcgtu6{5ZYy5bBPqb#-`Eayz%)dRu zaNN_^d3QaU-1&GcbY8WwLcr1Cb8@nsK=jq;d`l&kY-yR4EaiwQqWTEDZgxl?Wg38W zdkiO@*~cl_7ylCXr)%-S=n%Y-KIKl&`>Oq(Wm261q&AUGo5dE2<7V0qsg<(TNGoR1 zuEcIa-%8U)kB%I(6ju{YnnJ+8dz7m@11+%t*Y5LV@ln_0DRk zXtJ_asc`7LDEEe9Rm9l=PGwN|G@X=_2_1;NPU>~|XpaSD@X`rn&91Vy*k)GL+nmM} z_8y$R;U&<4Q7d+}J&>R@7av(il=%;CC%^7j^k5EJY0pTe(;G9^VBn@u*g1(r=M#+Y zShwVceJ|pHPCuubqlkIpL|qqRR7ISZ6yt~beCe^MWa8X{00*^oE?sjHW`h=S-h;) z!q99DH%5Jx#+Smnl1Rh${T;nH1NTzw1csiJ#cEeZq~f`TI}d%1SwYx)7J}@Fid*GV z_t=htCL=R0P7|9dT0U2MPpoE) zCHd6oO|a2os?MZ~&ZO#2a;~22JLnTmI|2fC=*2ggc4(Nyl0>K_Y2ua{K~Y_5TQvB| zSgNdN0#8XQoa$>19?Do3^~IKV9@g*QmbS|ju+c=j)W&d5aRw5tvkF5#-Rcgsq=wCK zt2DoEe(uDx6N8OwBSX#56hKd}KG7#^e_d~l+Q>}9YjchNlel-@9l4oiMxQ88y~*{N ze3t!{o9U-#L^Wa3i9!Ym$|J~JaVcJjeQd^Teo2_TlcafeEZY7!VtU`xUb0Z6zr%46 z9&+dIrgO01TpOcAiI4t9Jf?f*(vPP<6j(@qf++m0Z##gAK{qr<_1@*%=MD#&RE z!WEESMGyzQcH1x+v6^p-oDxj@KqC~T>YA5gp4Gz_0sbo*kEWB9{g|_t>pD2WG zPPXhX+)BD_%Ds`bwQ9?CJgle~Dl;#x?B2@?h#rF(#D_A!=)Hf*x~q_Rbu+TkHfxFE z79is3=qFGF`l%}EkW9mPGxdBZ@r6m$N`h_->en_w2DV3ECR>zMg$1@m64Oo`jUZ4i zZbMm!E3ww-eU-t^duHr!CUI&8Skt>Va0aFmGOlkc2j|%jzC+m{A-GXdipF1v>ep{J zIt&)Q-yPyoX5QA1CWfV-~H`FKcB1_Wyqm z`>DhHm;5@rc-UGv|MnMGrwOs2eu>jTbBtBi-fGkOPL6sxoVQ-1L{5$kZ$747S!*x0 zeoY!HoF}XU;jk+X;c%h@x3(dn$+{#bJW5nJ>)LWNeevC0OB}piYDu#e8kVwmbjry4 z?pfyU!%7~9KsCD(=HiJ+I`={AJ0YKIYVf{tRT-ZdAzW}Nep^FB8ZKzdhW@Qj9!udj zU`b2?;Rj2Zoe@sGnKAh%csCCzaw7x>IF{Ux_&D;AK_w_uPiy9cj%ejTk2Ts{tW}4} z?kDJFsS;U{Md`lgJKhQ<@BtuluO`$M&^A+t&Uvdx*u6Uca zmswT>FLkJ0vkisvcMywyzJWuclH&r)RMSIngT_lQ1jQ+VdCBMIxxkm8GBu5wv5n{_ z9lR^4Ng7VoyED1!bus(40!sT=P6 z3`RM&d#6$)N(CtT#oaT=(+x-tsJ^Q`XO#lrFn zpEJcaSv9{CWwjnbcsOiB7&<&Iz*-B}N?Nc`l@a%`1Akog5A;GLRgkb(#`nJ6zqnn6 ztj;fIyYV-Qe|vH9HWwO-J~~T73vitzeS2=GU9pVEwjO5HW#6sPf_rgu#MS-knvLa3 zHWa1I&AZGFJ?>lnims9&#@xav2^ghqa^MKjPb|ALjeV?kBK_(#f?voYjz4A-or5G3 zLKJ1Y6ZWu}+zq}7Q9S-Ehg&B9-#Zb$6{+k|%TL<9_4*6rru1M0$>ReGx*>7RIW z2%jT3@D}1baEryXu|DbPcjpz4t+D#(b@nA@GlBA_Yd%mcO_x3OoAuW+pRiCpD?HL{ z#-5}p*Fe%o{cVnaj6jh?O};9?$RP?#CO`c*1*}Y+EX>tioZi~M`JD;2@k;i+l(6zw zk|#=(&oviv`iLuGl4qc+9aTEL92_YRIBhxkh44|l1G&Q*##s@CTSW(i(C!G~bxPjI zl_2X}Hp?+aFYVi(cz9w}; zvaA55oEoe;DOZC8!KolVExR#~B1U_i4>B~2gdynpk=$Qedg$8W3T67z=vYU7XiVJr z7cstKuMp^CU8fN|`~Zzf#3-X~vBiSM7fFo%G$_UbrjC!(5@9suoR@ZgPE$6gQGKtnS+zXzw6Kc%RIs+Wi&`hpFGIt! zxp!%zG@jia8sihgO_U*YC&MAi)ZJB3qf+f=BqM_UcsG9#FwvXy%l+OEJ+Q(O*onSx zl|v9lC{#u4(ad-)5rxxoWzjoC$|M}*r6R2Ko!rYNX-M~;9KyPH>pMCBotW2en8M!g zYi!x(0G2M32}FS<09oHk>+YyPdquRvzeghr4wu-?u&p_ib6ryqyrUA-Lx4g+R(~Q_L&^V9#UL?Uoo+rJ~!nt2$$-7o8 zBNXqI*p!Z^aS%0iOvg|0kIsW4-7xA9*7DmV#`*IEHg$CT-~5FQ%)hsckAKuF887*s z$>FC>DSihU&j^9L%shBu;3K{JVR>6m(b=#VEybby(TTDgS~CR#cv{1| z)_bptv)dO8^_zb8lq`lK>e}x?LpW|4AC4c};Z4yg*lze`Y{cvI`F7v_`@?t>DUHeL*6z18XHyi{(wt33>;)0la?<`lGhsnbUy35>YH|GWJf^vbD}37tE?Z@{9IZ8 zuykU`v$GX(0rO-3@^WzSY%n$X=an}98I=E=|6$#YD)6rc{<TWX@S76 zz+cOxe?Z$|A>S`W(_g`Vtq}bIg>@3`ckutGUi7P-U&{u6SmMU`e=qU3BEqj$eoYnq zVI>&v9}`Ev8u&HX{lfqP$?pdK2z`Hr{u(6w0YxVJ7xdSV;a3ZPmAXIh06-u)0Pr{A l`xX9INAqX66xE;L|8_g7KqT1L1puDFc7K@iTG9M=^?!+M8EXIl literal 0 HcmV?d00001 diff --git a/Resource/Orders_import.xlsx b/Resource/Orders_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f789f339bd3c98fbdabc418a17b1d065ace878d2 GIT binary patch literal 10625 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 0), + price_at_moment DECIMAL(15,2) NOT NULL, + added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + -- Заказы + CREATE TABLE IF NOT EXISTS Orders ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + client_id INTEGER REFERENCES Clients(id), + order_date DATE NOT NULL, + total_amount DECIMAL(15,2) NOT NULL, + status VARCHAR(50) DEFAULT 'Новый', + production_days INTEGER DEFAULT 1, + production_start_date DATE, + production_end_date DATE, + production_status VARCHAR(50) DEFAULT 'Ожидает', + assembly_percent INTEGER DEFAULT 15, + delivery_percent INTEGER DEFAULT 10, + assembly_cost DECIMAL(15,2) DEFAULT 0, + delivery_cost DECIMAL(15,2) DEFAULT 0, + base_amount DECIMAL(15,2) DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + -- Состав заказа + CREATE TABLE IF NOT EXISTS OrderItems ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + order_id INTEGER NOT NULL REFERENCES Orders(id), + product_id INTEGER NOT NULL REFERENCES Catalog(id), + quantity INTEGER NOT NULL CHECK (quantity > 0), + price_at_moment DECIMAL(15,2) NOT NULL + ); + + -- Индексы для оптимизации + CREATE INDEX IF NOT EXISTS idx_client_type ON Clients(contractor_type_id); + CREATE INDEX IF NOT EXISTS idx_client_inn ON Clients(inn); + CREATE INDEX IF NOT EXISTS idx_catalog_category ON Catalog(category_id); + CREATE INDEX IF NOT EXISTS idx_catalog_material ON Catalog(material_id); + CREATE INDEX IF NOT EXISTS idx_catalog_article ON Catalog(article); + CREATE INDEX IF NOT EXISTS idx_material_name ON Materials(material_name); + CREATE INDEX IF NOT EXISTS idx_material_category ON Materials(category); + CREATE INDEX IF NOT EXISTS idx_material_supplier ON Materials(supplier); + CREATE INDEX IF NOT EXISTS idx_cart_client ON Cart(client_id); + CREATE INDEX IF NOT EXISTS idx_cart_status ON Cart(status); + CREATE INDEX IF NOT EXISTS idx_cart_items_cart ON CartItems(cart_id); + CREATE INDEX IF NOT EXISTS idx_order_client ON Orders(client_id); + CREATE INDEX IF NOT EXISTS idx_order_date ON Orders(order_date); + CREATE INDEX IF NOT EXISTS idx_order_status ON Orders(status); + CREATE INDEX IF NOT EXISTS idx_production_status ON Orders(production_status); + CREATE INDEX IF NOT EXISTS idx_orderitems_order ON OrderItems(order_id); + CREATE INDEX IF NOT EXISTS idx_orderitems_product ON OrderItems(product_id); + ''') + + db_connection.commit() + print("✅ Таблицы успешно созданы") + + +def calculate_discount(total_quantity): + """Рассчитывает скидку на основе общего количества заказанной продукции""" + if total_quantity >= 300000: + return 15, '15% (более 300000 ед.)' + elif total_quantity >= 50000: + return 10, '10% (50000-300000 ед.)' + elif total_quantity >= 10000: + return 5, '5% (10000-50000 ед.)' + else: + return 0, '0% (до 10000 ед.)' + + +def get_clients(db_path=DB_PATH, sort_by='rating', ascending=False): + """Получает данные о клиентах с возможностью сортировки""" + try: + conn = sqlite3.connect(db_path) + query = """ + SELECT + ct.type_name AS "Тип клиента", + c.name AS "Наименование клиента", + c.director AS "Директор", + c.email AS "Электронная почта", + c.phone AS "Телефон", + c.address AS "Адрес", + c.inn AS "ИНН", + c.rating AS "Рейтинг", + c.created_at AS "Дата создания", + COALESCE(SUM(oi.quantity), 0) as total_quantity, + COALESCE(SUM(o.total_amount), 0) as total_amount + FROM Clients c + JOIN ContractorType ct ON c.contractor_type_id = ct.id + LEFT JOIN Orders o ON c.id = o.client_id + LEFT JOIN OrderItems oi ON o.id = oi.order_id + GROUP BY c.id + """ + + if sort_by == 'discount': + query += " ORDER BY total_quantity" + elif sort_by == 'rating': + query += " ORDER BY c.rating" + elif sort_by == 'name': + query += " ORDER BY c.name" + elif sort_by == 'type': + query += " ORDER BY ct.type_name, c.name" + else: + query += " ORDER BY c.rating" + + query += " DESC" if not ascending else " ASC" + + df = pd.read_sql_query(query, conn) + conn.close() + + if not df.empty: + df['Скидка_процент'] = df['total_quantity'].apply(lambda x: calculate_discount(x)[0]) + df['Скидка_текст'] = df['total_quantity'].apply(lambda x: calculate_discount(x)[1]) + df['Общая_сумма'] = df['total_amount'].apply(lambda x: f"{x:,.2f} руб.") + + return df + + except Exception as e: + print(f"❌ Ошибка: {e}") + return None + + +def get_orders_history(db_path=DB_PATH, limit=50, sort_by='date_desc'): + """Получает историю заказов с разными вариантами сортировки""" + try: + conn = sqlite3.connect(db_path) + query = """ + SELECT + o.order_date AS "Дата заказа", + c.name AS "Клиент", + GROUP_CONCAT(cat.product_name || ' x' || oi.quantity, ', ') AS "Товары", + SUM(oi.quantity) AS "Количество", + o.total_amount AS "Сумма заказа", + o.status AS "Статус" + FROM Orders o + JOIN Clients c ON o.client_id = c.id + LEFT JOIN OrderItems oi ON o.id = oi.order_id + LEFT JOIN Catalog cat ON oi.product_id = cat.id + GROUP BY o.id + """ + + if sort_by == 'date_desc': + query += " ORDER BY o.order_date DESC, o.created_at DESC" + elif sort_by == 'date_asc': + query += " ORDER BY o.order_date ASC, o.created_at ASC" + elif sort_by == 'quantity_desc': + query += " ORDER BY SUM(oi.quantity) DESC" + elif sort_by == 'amount_desc': + query += " ORDER BY o.total_amount DESC" + elif sort_by == 'status': + query += " ORDER BY o.status, o.order_date DESC" + else: + query += " ORDER BY o.order_date DESC, o.created_at DESC" + + query += " LIMIT ?" + + df = pd.read_sql_query(query, conn, params=(limit,)) + conn.close() + return df + except Exception as e: + print(f"❌ Ошибка: {e}") + return None + + +def print_client_cards(clients_df): + """Выводит карточки клиентов в красивом формате""" + if clients_df is None or clients_df.empty: + print("📭 Нет данных о клиентах") + return + + for index, row in clients_df.iterrows(): + print("╔" + "═" * 79 + "╗") + print(f"║ {'КАРТОЧКА КЛИЕНТА':^77} ║") + print("╠" + "═" * 79 + "╣") + + type_text = f"Тип: {row['Тип клиента']}" + name_text = f"Наименование: {row['Наименование клиента']}" + director_text = f"Директор: {row['Директор']}" + rating_text = f"Рейтинг: {row['Рейтинг']}" + quantity_text = f"Заказано единиц: {row['total_quantity']:,}" + amount_text = f"На сумму: {row['total_amount']:,.2f} руб." + discount_text = f"Скидка: {row['Скидка_текст']}" + email_text = f"Email: {row['Электронная почта']}" + phone_text = f"Телефон: {row['Телефон']}" + inn_text = f"ИНН: {row['ИНН']}" + + address = row['Адрес'] if row['Адрес'] else 'Не указан' + if len(address) > 70: + address = address[:67] + "..." + address_text = f"Адрес: {address}" + + print(f"║ {type_text:<77} ║") + print(f"║ {name_text:<77} ║") + print(f"║ {director_text:<77} ║") + print(f"║ {rating_text:<77} ║") + print(f"║ {quantity_text:<77} ║") + print(f"║ {amount_text:<77} ║") + print(f"║ {discount_text:<77} ║") + print(f"║ {'':<77} ║") + print(f"║ {email_text:<77} ║") + print(f"║ {phone_text:<77} ║") + print(f"║ {inn_text:<77} ║") + print(f"║ {address_text:<77} ║") + print("╚" + "═" * 79 + "╝") + print() + + +def print_orders_cards(orders_df): + """Выводит карточки заказов в виде таблицы""" + if orders_df is None or orders_df.empty: + print("📭 Нет данных о заказах") + return + + print("╔" + "═" * 167 + "╗") + print(f"║ {'ИСТОРИЯ ЗАКАЗОВ':^165} ║") + print("╠" + "═" * 167 + "╣") + + headers = ["Дата", "Клиент", "Товары", "Кол-во", "Статус", "Сумма"] + print("║ {:<12} {:<25} {:<55} {:>12} {:<15} {:>15} ║".format( + headers[0], headers[1], headers[2], headers[3], headers[4], headers[5] + )) + print("╠" + "═" * 167 + "╣") + + for index, row in orders_df.iterrows(): + date = str(row['Дата заказа'])[:10] + client = str(row['Клиент'])[:25] if len(str(row['Клиент'])) > 25 else str(row['Клиент']) + products = str(row['Товары'])[:55] if len(str(row['Товары'])) > 55 else str(row['Товары']) + quantity = f"{int(row['Количество']):,}" + status = str(row['Статус'])[:15] if len(str(row['Статус'])) > 15 else str(row['Статус']) + amount = f"{float(row['Сумма заказа']):,.2f}" + + line = f"║ {date:<12} {client:<25} {products:<55} {quantity:>12} {status:<15} {amount:>15} ║" + print(line) + + print("╚" + "═" * 167 + "╝") + + total_quantity = orders_df['Количество'].sum() + total_amount = orders_df['Сумма заказа'].sum() + print(f"📊 ИТОГО: {len(orders_df)} заказов, {total_quantity:,.0f} единиц, общая сумма: {total_amount:,.2f} руб.") + + status_stats = orders_df['Статус'].value_counts() + print("📊 Статусы заказов:") + for status, count in status_stats.items(): + print(f" - {status}: {count}") + + +def simple_choice(options): + """Упрощенная функция выбора""" + print("\n" + "=" * 60) + print("ВЫБЕРИТЕ ОПЦИЮ:") + print("=" * 60) + for i, option in enumerate(options, 1): + print(f"{i}. {option}") + + while True: + try: + choice = input(f"\nВведите номер (1-{len(options)}): ").strip() + if choice.isdigit(): + choice_num = int(choice) + if 1 <= choice_num <= len(options): + return options[choice_num - 1] + print(f"❌ Пожалуйста, введите число от 1 до {len(options)}") + except KeyboardInterrupt: + print("\n👋 Программа прервана пользователем.") + sys.exit(0) + + +def safe_float(value, default=None): + """Безопасное преобразование в float""" + if pd.isna(value) or value == '-': + return default + try: + return float(value) + except (ValueError, TypeError): + return default + + +def safe_int(value, default=None): + """Безопасное преобразование в int""" + if pd.isna(value) or value == '-': + return default + try: + return int(float(value)) + except (ValueError, TypeError): + return default + + +def load_data_from_files(): + """Загружает данные из Excel файлов в базу данных""" + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + try: + print("\n📁 Введите имена файлов (или нажмите Enter для значений по умолчанию):") + clients_file = input("Файл с клиентами (Enter = Clients_import.xlsx): ").strip() or "Clients_import.xlsx" + categories_file = input("Файл с категориями (Enter = Categories_import.xlsx): ").strip() or "Categories_import.xlsx" + materials_file = input("Файл с материалами (Enter = Materials_import.xlsx): ").strip() or "Materials_import.xlsx" + catalog_file = input("Файл с каталогом (Enter = Products_import.xlsx): ").strip() or "Products_import.xlsx" + orders_file = input("Файл с заказами (Enter = Orders_import.xlsx): ").strip() or "Orders_import.xlsx" + orderitems_file = input("Файл с составом заказов (Enter = OrderItems_import.xlsx): ").strip() or "OrderItems_import.xlsx" + + # Формируем полные пути + clients_file = os.path.join(RESOURCE_DIR, os.path.basename(clients_file)) + categories_file = os.path.join(RESOURCE_DIR, os.path.basename(categories_file)) + materials_file = os.path.join(RESOURCE_DIR, os.path.basename(materials_file)) + catalog_file = os.path.join(RESOURCE_DIR, os.path.basename(catalog_file)) + orders_file = os.path.join(RESOURCE_DIR, os.path.basename(orders_file)) + orderitems_file = os.path.join(RESOURCE_DIR, os.path.basename(orderitems_file)) + + print(f"\n📂 Загружаем файлы из папки: {RESOURCE_DIR}") + + # 1. Загрузка типов контрагентов + print("\n1. 📊 Загрузка типов контрагентов...") + clients_df = pd.read_excel(clients_file) + + if 'Тип партнера' in clients_df.columns: + contractor_types = clients_df['Тип партнера'].unique() + for contractor_type in contractor_types: + cursor.execute("INSERT OR IGNORE INTO ContractorType (type_name) VALUES (?)", (contractor_type,)) + print(f" Загружено {len(contractor_types)} типов") + + # 2. Загрузка клиентов + print("2. 👥 Загрузка клиентов...") + loaded_clients = 0 + for _, row in clients_df.iterrows(): + type_value = row.get('Тип партнера', 'Клиент') + cursor.execute("SELECT id FROM ContractorType WHERE type_name = ?", (type_value,)) + result = cursor.fetchone() + contractor_type_id = result[0] if result else 1 + + cursor.execute("""INSERT OR IGNORE INTO Clients + (contractor_type_id, name, director, email, phone, address, inn, rating) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", + (contractor_type_id, + row.get('Наименование партнера', ''), + row.get('Директор', ''), + row.get('Электронная почта партнера', ''), + row.get('Телефон партнера', ''), + row.get('Юридический адрес партнера', ''), + row.get('ИНН', ''), + safe_float(row.get('Рейтинг', 0.0), 0.0)) + ) + loaded_clients += 1 + print(f" Загружено {loaded_clients} клиентов") + + # 3. Загрузка категорий + print("3. 📦 Загрузка категорий...") + categories_df = pd.read_excel(categories_file) + loaded_categories = 0 + for _, row in categories_df.iterrows(): + cursor.execute("INSERT OR IGNORE INTO Categories (category_name, coefficient) VALUES (?, ?)", + (row.get('Тип продукции', ''), + safe_float(row.get('Коэффициент типа продукции', 1.0), 1.0)) + ) + loaded_categories += 1 + print(f" Загружено {loaded_categories} категорий") + + # 4. Загрузка материалов + print("4. 📦 Загрузка материалов...") + materials_df = pd.read_excel(materials_file) + + loaded_materials = 0 + for _, row in materials_df.iterrows(): + cursor.execute(""" + INSERT OR IGNORE INTO Materials + (material_name, description, category, color, density, thickness, + supplier, country, wear_class, price_per_unit, unit, in_stock, + production_time_days, daily_capacity, markup_percent) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, ( + row.get('Наименование материала', ''), + row.get('Описание', ''), + row.get('Категория', ''), + row.get('Цвет', ''), + safe_float(row.get('Плотность', None)), + safe_float(row.get('Толщина', None)), + row.get('Поставщик', ''), + row.get('Страна', ''), + row.get('Класс износостойкости', ''), + safe_float(row.get('Цена за ед.', 0), 0), + row.get('Единица', 'шт'), + safe_int(row.get('В наличии', 0), 0), + 1, 10, 30 + )) + loaded_materials += 1 + print(f" ✅ Загружено {loaded_materials} материалов") + + # 5. Загрузка каталога + print("5. 🏷️ Загрузка каталога продукции...") + catalog_df = pd.read_excel(catalog_file) + + loaded_products = 0 + for index, row in catalog_df.iterrows(): + prod_days = 1 + if 'production_time_days' in catalog_df.columns: + val = row['production_time_days'] + if not pd.isna(val): + try: + prod_days = int(float(val)) + except: + prod_days = 1 + + cursor.execute(""" + INSERT OR IGNORE INTO Catalog + (category_id, material_id, product_name, article, description, min_price, quantity_in_stock, + production_time_days, daily_capacity) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + """, ( + safe_int(row.get('category_id', 1), 1), + safe_int(row.get('material_id', None)), + row.get('product_name', ''), + row.get('article', ''), + row.get('description', ''), + safe_float(row.get('min_price', 0), 0), + safe_int(row.get('quantity_in_stock', 0), 0), + prod_days, + 10 + )) + loaded_products += 1 + + print(f" ✅ Загружено {loaded_products} товаров") + + # 6. Загрузка заказов + print("6. 📝 Загрузка заказов...") + orders_df = pd.read_excel(orders_file) + loaded_orders = 0 + for _, row in orders_df.iterrows(): + # Преобразование дат + date_val = row.get('order_date') + if pd.isna(date_val): + order_date = datetime.now().strftime('%Y-%m-%d') + else: + if hasattr(date_val, 'strftime'): + order_date = date_val.strftime('%Y-%m-%d') + else: + order_date = str(date_val) + + prod_start = row.get('production_start_date') + if pd.isna(prod_start): + prod_start = None + else: + if hasattr(prod_start, 'strftime'): + prod_start = prod_start.strftime('%Y-%m-%d') + else: + prod_start = str(prod_start) + + prod_end = row.get('production_end_date') + if pd.isna(prod_end): + prod_end = None + else: + if hasattr(prod_end, 'strftime'): + prod_end = prod_end.strftime('%Y-%m-%d') + else: + prod_end = str(prod_end) + + cursor.execute(""" + INSERT INTO Orders + (id, client_id, order_date, total_amount, status, + production_days, production_start_date, production_end_date, production_status, + assembly_percent, delivery_percent, assembly_cost, delivery_cost, base_amount) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, ( + safe_int(row.get('id')), + safe_int(row.get('client_id')), + order_date, + safe_float(row.get('total_amount'), 0), + row.get('status', 'Новый'), + safe_int(row.get('production_days', 1)), + prod_start, + prod_end, + row.get('production_status', 'Ожидает'), + safe_int(row.get('assembly_percent', 15)), + safe_int(row.get('delivery_percent', 10)), + safe_float(row.get('assembly_cost', 0), 0), + safe_float(row.get('delivery_cost', 0), 0), + safe_float(row.get('base_amount', 0), 0) + )) + loaded_orders += 1 + print(f" ✅ Загружено {loaded_orders} заказов") + + # 7. Загрузка состава заказов (OrderItems) + print("7. 📦 Загрузка состава заказов...") + orderitems_df = pd.read_excel(orderitems_file) + loaded_items = 0 + for _, row in orderitems_df.iterrows(): + cursor.execute(""" + INSERT INTO OrderItems (order_id, product_id, quantity, price_at_moment) + VALUES (?, ?, ?, ?) + """, ( + safe_int(row.get('order_id')), + safe_int(row.get('product_id')), + safe_int(row.get('quantity'), 1), + safe_float(row.get('price_at_moment'), 0) + )) + loaded_items += 1 + print(f" ✅ Загружено {loaded_items} позиций") + + conn.commit() + print(f"✅ Данные успешно загружены!") + + except Exception as e: + print(f"❌ Ошибка при загрузке данных: {e}") + import traceback + traceback.print_exc() + conn.rollback() + finally: + conn.close() + + +def display_menu(): + """Главное меню программы""" + menu_options = [ + 'КАРТОЧКИ КЛИЕНТОВ (сортировка по рейтингу)', + 'КАРТОЧКИ КЛИЕНТОВ (сортировка по скидкам)', + 'ИСТОРИЯ ЗАКАЗОВ', + 'ЗАПОЛНЕНИЕ БД из файлов', + 'ВЫХОД' + ] + + while True: + choice = simple_choice(menu_options) + + if choice == 'КАРТОЧКИ КЛИЕНТОВ (сортировка по рейтингу)': + print("\n🎯 КАРТОЧКИ КЛИЕНТОВ (сортировка по рейтингу)") + print("═" * 80) + clients = get_clients(sort_by='rating', ascending=False) + print_client_cards(clients) + + elif choice == 'КАРТОЧКИ КЛИЕНТОВ (сортировка по скидкам)': + print("\n📊 КАРТОЧКИ КЛИЕНТОВ (сортировка по скидкам)") + print("═" * 80) + clients = get_clients(sort_by='discount', ascending=False) + print_client_cards(clients) + + elif choice == 'ИСТОРИЯ ЗАКАЗОВ': + print("\n📈 ИСТОРИЯ ЗАКАЗОВ") + print("═" * 80) + orders = get_orders_history(limit=50) + print_orders_cards(orders) + + elif choice == 'ЗАПОЛНЕНИЕ БД из файлов': + if os.path.exists(DB_PATH): + os.remove(DB_PATH) + print("🗑️ База данных удалена") + else: + print("ℹ️ Создаем новую базу") + + conn = sqlite3.connect(DB_PATH) + create_tables(conn) + conn.close() + load_data_from_files() + + elif choice == 'ВЫХОД': + print("\n👋 До свидания!") + break + + +if __name__ == "__main__": + display_menu() \ No newline at end of file diff --git a/main_flask.py b/main_flask.py new file mode 100644 index 0000000..9b65b46 --- /dev/null +++ b/main_flask.py @@ -0,0 +1,897 @@ +from flask import Flask, render_template, send_from_directory, request, redirect, url_for, flash, session +import sqlite3 +import os +from datetime import datetime, timedelta + +app = Flask(__name__) +app.secret_key = 'my_secret_key_12345' + +# ========== ФИЛЬТР ДЛЯ ФОРМАТИРОВАНИЯ ДАТ ========== +@app.template_filter('date_format') +def date_format(value): + """Преобразует дату из формата YYYY-MM-DD в ДД.ММ.ГГГГ""" + if not value: + return '-' + try: + # Если value уже строка, пробуем распарсить + if isinstance(value, str) and len(value) >= 10: + # Проверяем, что это похоже на дату в формате YYYY-MM-DD + if value[4] == '-' and value[7] == '-': + year, month, day = value[:10].split('-') + return f"{day}.{month}.{year}" + return value + except: + return value + +def get_db_connection(): + conn = sqlite3.connect('partners.db') + conn.row_factory = sqlite3.Row + return conn + +def dict_from_row(row): + """Преобразует sqlite3.Row в словарь""" + if row is None: + return None + return {key: row[key] for key in row.keys()} + +def list_from_rows(rows): + """Преобразует список sqlite3.Row в список словарей""" + return [dict_from_row(row) for row in rows] + +def calculate_discount(total_amount): + """Рассчитывает скидку на основе общей суммы заказов в рублях""" + return 0, '0%' + +def calculate_order_discount(order_amount): + """Рассчитывает скидку на текущий заказ в зависимости от его суммы""" + return 0 + +# ========== ГЛАВНАЯ СТРАНИЦА ========== + +@app.route('/') +def index(): + # Получаем параметры фильтрации из URL + search_query = request.args.get('search', '') + client_type = request.args.get('type', 'all') + min_rating = request.args.get('rating', '0') + sort_by = request.args.get('sort', 'name_asc') + + conn = get_db_connection() + + try: + # Получаем общее количество всех клиентов (без фильтров) + total_count = conn.execute('SELECT COUNT(*) as count FROM Clients').fetchone()['count'] + + # Базовый SQL запрос для клиентов + sql = ''' + SELECT c.*, ct.type_name as contractor_type_name, + COALESCE(SUM(o.total_amount), 0) as total_amount, + COALESCE(SUM(oi.quantity), 0) as total_quantity, + COUNT(DISTINCT o.id) as orders_count + FROM Clients c + LEFT JOIN ContractorType ct ON c.contractor_type_id = ct.id + LEFT JOIN Orders o ON c.id = o.client_id + LEFT JOIN OrderItems oi ON o.id = oi.order_id + WHERE 1=1 + ''' + params = [] + + # Поиск по названию или ИНН + if search_query: + sql += " AND (c.name LIKE ? OR c.inn LIKE ?)" + params.extend([f'%{search_query}%', f'%{search_query}%']) + + # Фильтр по типу клиента + if client_type != 'all': + sql += " AND ct.type_name = ?" + params.append(client_type) + + # Фильтр по минимальному рейтингу + if min_rating != '0': + sql += " AND c.rating >= ?" + params.append(float(min_rating)) + + # Группировка (обязательно после WHERE) + sql += " GROUP BY c.id" + + # Сортировка + if sort_by == 'name_asc': + sql += " ORDER BY c.name ASC" + elif sort_by == 'name_desc': + sql += " ORDER BY c.name DESC" + elif sort_by == 'rating_desc': + sql += " ORDER BY c.rating DESC" + elif sort_by == 'rating_asc': + sql += " ORDER BY c.rating ASC" + elif sort_by == 'discount_desc': + sql += " ORDER BY total_amount DESC" + elif sort_by == 'discount_asc': + sql += " ORDER BY total_amount ASC" + else: + sql += " ORDER BY c.name ASC" + + # Выполняем запрос и преобразуем в словари + rows = conn.execute(sql, params).fetchall() + clients = list_from_rows(rows) + + # Добавляем информацию о скидке на основе суммы + clients_with_discount = [] + for client in clients: + total_amount = client['total_amount'] or 0 + discount_percent, discount_text = calculate_discount(total_amount) + + client['total_sales'] = total_amount + client['discount_percent'] = discount_percent + client['discount'] = discount_percent + client['discount_text'] = discount_text + + clients_with_discount.append(client) + + conn.close() + + return render_template('index.html', + partners=clients_with_discount, + total_count=total_count) + + except Exception as e: + conn.close() + print(f"❌ ОШИБКА: {e}") + return render_template('index.html', + partners=[], + total_count=0, + error_message=f"Ошибка базы данных: {str(e)}") + +# ========== МАРШРУТЫ ДЛЯ КЛИЕНТОВ ========== + +@app.route('/add_client', methods=['GET', 'POST']) +def add_client(): + if request.method == 'POST': + try: + name = request.form['name'] + director = request.form.get('director', '') + email = request.form['email'] + phone = request.form.get('phone', '') + address = request.form.get('address', '') + inn = request.form.get('inn', '') + contractor_type_id = request.form['contractor_type_id'] + rating = request.form.get('rating', 0.0) + + conn = get_db_connection() + + # Проверяем уникальность ИНН + if inn: + existing = conn.execute('SELECT id FROM Clients WHERE inn = ?', (inn,)).fetchone() + if existing: + flash('Клиент с таким ИНН уже существует', 'error') + conn.close() + return redirect(url_for('add_client')) + + conn.execute(''' + INSERT INTO Clients (name, director, email, phone, address, inn, contractor_type_id, rating) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + ''', (name, director, email, phone, address, inn, contractor_type_id, rating)) + + conn.commit() + conn.close() + flash('Клиент успешно добавлен!', 'success') + return redirect(url_for('index')) + + except Exception as e: + flash(f'Ошибка: {str(e)}', 'error') + return redirect(url_for('add_client')) + + # GET запрос + conn = get_db_connection() + contractor_types = conn.execute('SELECT * FROM ContractorType ORDER BY type_name').fetchall() + conn.close() + return render_template('add_client.html', contractor_types=contractor_types) + +@app.route('/edit_client/', methods=['GET', 'POST']) +def edit_client(client_id): + conn = get_db_connection() + + if request.method == 'POST': + try: + name = request.form['name'] + director = request.form.get('director', '') + email = request.form['email'] + phone = request.form.get('phone', '') + address = request.form.get('address', '') + inn = request.form.get('inn', '') + contractor_type_id = request.form['contractor_type_id'] + rating = request.form.get('rating', 0.0) + + # Проверяем уникальность ИНН + if inn: + existing = conn.execute( + 'SELECT id FROM Clients WHERE inn = ? AND id != ?', + (inn, client_id) + ).fetchone() + if existing: + flash('Клиент с таким ИНН уже существует', 'error') + conn.close() + return redirect(url_for('edit_client', client_id=client_id)) + + conn.execute(''' + UPDATE Clients + SET name = ?, director = ?, email = ?, phone = ?, + address = ?, inn = ?, contractor_type_id = ?, rating = ? + WHERE id = ? + ''', (name, director, email, phone, address, inn, contractor_type_id, rating, client_id)) + + conn.commit() + conn.close() + flash('Данные обновлены!', 'success') + return redirect(url_for('index')) + + except Exception as e: + flash(f'Ошибка: {str(e)}', 'error') + conn.close() + return redirect(url_for('edit_client', client_id=client_id)) + + # GET запрос + client_row = conn.execute(''' + SELECT c.*, ct.type_name as contractor_type_name + FROM Clients c + LEFT JOIN ContractorType ct ON c.contractor_type_id = ct.id + WHERE c.id = ? + ''', (client_id,)).fetchone() + + client_dict = dict_from_row(client_row) + + contractor_types = conn.execute('SELECT * FROM ContractorType ORDER BY type_name').fetchall() + conn.close() + + if not client_dict: + flash('Клиент не найден', 'error') + return redirect(url_for('index')) + + return render_template('edit_client.html', client=client_dict, contractor_types=contractor_types) + +# ========== МАРШРУТЫ ДЛЯ ЗАКАЗОВ ========== + +@app.route('/order_history/') +def order_history(client_id): + conn = get_db_connection() + + client_row = conn.execute(''' + SELECT c.*, ct.type_name as contractor_type_name + FROM Clients c + LEFT JOIN ContractorType ct ON c.contractor_type_id = ct.id + WHERE c.id = ? + ''', (client_id,)).fetchone() + + client_dict = dict_from_row(client_row) + + # Получаем заказы клиента + orders_rows = conn.execute(''' + SELECT + o.* + FROM Orders o + WHERE o.client_id = ? + ORDER BY o.order_date DESC, o.id DESC + ''', (client_id,)).fetchall() + + # Получаем детальную информацию о товарах в каждом заказе + orders_with_items = [] + total_quantity_all = 0 + total_amount_all = 0 + completed_count = 0 + + for order_row in orders_rows: + order_dict = dict_from_row(order_row) + + # Получаем товары для этого заказа + items_rows = conn.execute(''' + SELECT oi.*, cat.product_name, cat.article, cat.min_price, cat2.category_name + FROM OrderItems oi + JOIN Catalog cat ON oi.product_id = cat.id + LEFT JOIN Categories cat2 ON cat.category_id = cat2.id + WHERE oi.order_id = ? + ''', (order_dict['id'],)).fetchall() + + items_list = list_from_rows(items_rows) + order_dict['items'] = items_list + + # Считаем общее количество для этого заказа + order_total_qty = sum(item['quantity'] for item in items_list) if items_list else 0 + order_dict['total_items'] = order_total_qty + + total_quantity_all += order_total_qty + total_amount_all += order_dict['total_amount'] + + if order_dict['status'] == 'Выполнен': + completed_count += 1 + + orders_with_items.append(order_dict) + + # Статистика + total_stats = { + 'total_orders': len(orders_with_items), + 'total_quantity': total_quantity_all, + 'total_amount': total_amount_all, + 'completed_orders': completed_count + } + + conn.close() + + if not client_dict: + flash('Клиент не найден', 'error') + return redirect(url_for('index')) + + return render_template('order_history.html', + client=client_dict, + orders=orders_with_items, + total_stats=total_stats) + +# ========== МАРШРУТ ДЛЯ ОБНОВЛЕНИЯ СТАТУСА ЗАКАЗА ========== +@app.route('/update_order_status/', methods=['POST']) +def update_order_status(order_id): + """Обновление статуса заказа""" + try: + new_status = request.form['status'] + + conn = get_db_connection() + conn.execute('UPDATE Orders SET status = ? WHERE id = ?', (new_status, order_id)) + conn.commit() + conn.close() + + flash(f'Статус заказа обновлен на "{new_status}"', 'success') + except Exception as e: + flash(f'Ошибка при обновлении статуса: {str(e)}', 'error') + + return redirect(request.referrer or url_for('orders_list')) + +# ========== МАРШРУТ ДЛЯ ОБНОВЛЕНИЯ СТАТУСА ПРОИЗВОДСТВА ========== +@app.route('/update_production_status/', methods=['POST']) +def update_production_status(order_id): + """Обновление статуса производства""" + try: + new_status = request.form['production_status'] + conn = get_db_connection() + conn.execute('UPDATE Orders SET production_status = ? WHERE id = ?', (new_status, order_id)) + conn.commit() + conn.close() + flash(f'Статус производства обновлен на "{new_status}"', 'success') + except Exception as e: + flash(f'Ошибка при обновлении статуса производства: {str(e)}', 'error') + return redirect(request.referrer) + +# ========== МАРШРУТЫ ДЛЯ ТОВАРОВ ========== + +@app.route('/add_product', methods=['GET', 'POST']) +def add_product(): + if request.method == 'POST': + try: + product_name = request.form['product_name'] + article = request.form['article'] + category_id = request.form['category_id'] + material_id = request.form.get('material_id') or None + description = request.form.get('description', '') + min_price = float(request.form['min_price']) + quantity_in_stock = int(request.form.get('quantity_in_stock', 0)) + production_time_days = int(request.form.get('production_time_days', 1)) + + conn = get_db_connection() + + existing = conn.execute('SELECT id FROM Catalog WHERE article = ?', (article,)).fetchone() + if existing: + flash('Товар с таким артикулом уже существует', 'error') + conn.close() + return redirect(url_for('add_product')) + + conn.execute(''' + INSERT INTO Catalog + (product_name, article, category_id, material_id, description, min_price, + quantity_in_stock, production_time_days) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + ''', (product_name, article, category_id, material_id, description, min_price, + quantity_in_stock, production_time_days)) + + conn.commit() + conn.close() + + flash('Товар успешно добавлен!', 'success') + return redirect(url_for('catalog')) + + except Exception as e: + flash(f'Ошибка: {str(e)}', 'error') + return redirect(url_for('add_product')) + + conn = get_db_connection() + categories = conn.execute('SELECT * FROM Categories ORDER BY category_name').fetchall() + materials = conn.execute('SELECT * FROM Materials ORDER BY material_name').fetchall() + conn.close() + + return render_template('add_product.html', categories=categories, materials=materials) + +@app.route('/edit_product/', methods=['GET', 'POST']) +def edit_product(product_id): + conn = get_db_connection() + + if request.method == 'POST': + try: + product_name = request.form['product_name'] + article = request.form['article'] + category_id = request.form['category_id'] + material_id = request.form.get('material_id') or None + description = request.form.get('description', '') + min_price = float(request.form['min_price']) + quantity_in_stock = int(request.form.get('quantity_in_stock', 0)) + production_time_days = int(request.form.get('production_time_days', 1)) + + existing = conn.execute( + 'SELECT id FROM Catalog WHERE article = ? AND id != ?', + (article, product_id) + ).fetchone() + if existing: + flash('Товар с таким артикулом уже существует', 'error') + conn.close() + return redirect(url_for('edit_product', product_id=product_id)) + + conn.execute(''' + UPDATE Catalog + SET product_name = ?, article = ?, category_id = ?, material_id = ?, + description = ?, min_price = ?, quantity_in_stock = ?, + production_time_days = ? + WHERE id = ? + ''', (product_name, article, category_id, material_id, description, min_price, + quantity_in_stock, production_time_days, product_id)) + + conn.commit() + conn.close() + + flash('Товар успешно обновлен!', 'success') + return redirect(url_for('catalog')) + + except Exception as e: + flash(f'Ошибка: {str(e)}', 'error') + return redirect(url_for('edit_product', product_id=product_id)) + + product_row = conn.execute(''' + SELECT cat.*, c.category_name, m.material_name + FROM Catalog cat + LEFT JOIN Categories c ON cat.category_id = c.id + LEFT JOIN Materials m ON cat.material_id = m.id + WHERE cat.id = ? + ''', (product_id,)).fetchone() + + product_dict = dict_from_row(product_row) + + categories = conn.execute('SELECT * FROM Categories ORDER BY category_name').fetchall() + materials = conn.execute('SELECT * FROM Materials ORDER BY material_name').fetchall() + conn.close() + + if not product_dict: + flash('Товар не найден', 'error') + return redirect(url_for('catalog')) + + return render_template('edit_product.html', + product=product_dict, + categories=categories, + materials=materials) + +@app.route('/delete_product/', methods=['POST']) +def delete_product(product_id): + try: + conn = get_db_connection() + + order_items = conn.execute('SELECT COUNT(*) as count FROM OrderItems WHERE product_id = ?', (product_id,)).fetchone() + if order_items['count'] > 0: + flash('Нельзя удалить товар, по которому есть заказы', 'error') + conn.close() + return redirect(url_for('catalog')) + + conn.execute('DELETE FROM Catalog WHERE id = ?', (product_id,)) + conn.commit() + conn.close() + + flash('Товар успешно удален', 'success') + except Exception as e: + flash(f'Ошибка при удалении: {str(e)}', 'error') + + return redirect(url_for('catalog')) + +@app.route('/catalog') +def catalog(): + conn = get_db_connection() + + categories = conn.execute('SELECT * FROM Categories ORDER BY category_name').fetchall() + # Получаем список всех клиентов для выпадающего списка + clients_rows = conn.execute('SELECT id, name FROM Clients ORDER BY name').fetchall() + clients = list_from_rows(clients_rows) + + search_query = request.args.get('search', '') + category_id = request.args.get('category', 'all') + sort_by = request.args.get('sort', 'name_asc') + + sql = ''' + SELECT cat.*, c.category_name, m.material_name, m.color, + m.production_time_days, m.daily_capacity + FROM Catalog cat + LEFT JOIN Categories c ON cat.category_id = c.id + LEFT JOIN Materials m ON cat.material_id = m.id + WHERE 1=1 + ''' + params = [] + + if search_query: + sql += " AND (cat.product_name LIKE ? OR cat.article LIKE ?)" + params.extend([f'%{search_query}%', f'%{search_query}%']) + + if category_id != 'all': + sql += " AND cat.category_id = ?" + params.append(category_id) + + if sort_by == 'name_asc': + sql += " ORDER BY cat.product_name ASC" + elif sort_by == 'name_desc': + sql += " ORDER BY cat.product_name DESC" + elif sort_by == 'price_asc': + sql += " ORDER BY cat.min_price ASC" + elif sort_by == 'price_desc': + sql += " ORDER BY cat.min_price DESC" + elif sort_by == 'stock_desc': + sql += " ORDER BY cat.quantity_in_stock DESC" + else: + sql += " ORDER BY cat.product_name ASC" + + products_rows = conn.execute(sql, params).fetchall() + products = list_from_rows(products_rows) + + cart = session.get('cart', {}) + cart_count = sum(item['quantity'] for item in cart.values()) if cart else 0 + + conn.close() + + return render_template('catalog.html', + products=products, + categories=categories, + clients=clients, + cart_count=cart_count) + +@app.route('/product/') +def product_detail(product_id): + conn = get_db_connection() + + product_row = conn.execute(''' + SELECT cat.*, c.category_name, m.material_name, + m.price_per_unit, m.unit, m.in_stock as material_stock, + m.daily_capacity as material_capacity, + m.production_time_days as material_production_time, + m.cost_price as material_cost_price + FROM Catalog cat + LEFT JOIN Categories c ON cat.category_id = c.id + LEFT JOIN Materials m ON cat.material_id = m.id + WHERE cat.id = ? + ''', (product_id,)).fetchone() + + product_dict = dict_from_row(product_row) + + material = None + if product_dict and product_dict.get('material_id'): + material_row = conn.execute('SELECT * FROM Materials WHERE id = ?', (product_dict['material_id'],)).fetchone() + material = dict_from_row(material_row) + + orders_stats_row = conn.execute(''' + SELECT + COUNT(DISTINCT oi.order_id) as total_orders, + SUM(oi.quantity) as total_sold, + AVG(oi.quantity) as avg_order_size + FROM OrderItems oi + WHERE oi.product_id = ? + ''', (product_id,)).fetchone() + + orders_stats_dict = dict_from_row(orders_stats_row) + + conn.close() + + if not product_dict: + flash('Товар не найден', 'error') + return redirect(url_for('catalog')) + + return render_template('product_detail.html', + product=product_dict, + material=material, + orders_stats=orders_stats_dict) + +# ========== МАРШРУТЫ ДЛЯ КОРЗИНЫ ========== + +@app.route('/cart') +def view_cart(): + cart = session.get('cart', {}) + cart_items = [] + total_amount = 0 + + conn = get_db_connection() + for key, item_data in cart.items(): + product_id = item_data['product_id'] + quantity = item_data['quantity'] + client_id = item_data['client_id'] + + # Получаем информацию о товаре + product_row = conn.execute(''' + SELECT cat.*, c.category_name, m.material_name, cat.quantity_in_stock + FROM Catalog cat + LEFT JOIN Categories c ON cat.category_id = c.id + LEFT JOIN Materials m ON cat.material_id = m.id + WHERE cat.id = ? + ''', (product_id,)).fetchone() + + # Получаем информацию о партнере + client_row = conn.execute('SELECT name FROM Clients WHERE id = ?', (client_id,)).fetchone() + client_name = client_row['name'] if client_row else 'Неизвестный' + + if product_row: + product = dict_from_row(product_row) + cart_items.append({ + 'id': key, + 'product_id': product_id, + 'product_name': product['product_name'], + 'article': product['article'], + 'category_name': product['category_name'], + 'material_name': product['material_name'], + 'client_id': client_id, + 'client_name': client_name, + 'price': product['min_price'], + 'quantity': quantity, + 'in_stock': product['quantity_in_stock'] or 0 + }) + total_amount += product['min_price'] * quantity + + conn.close() + + return render_template('cart_new.html', cart_items=cart_items, total_amount=total_amount) + +@app.route('/add_to_cart/', methods=['POST']) +def add_to_cart(product_id): + quantity = int(request.form.get('quantity', 1)) + client_id = request.form.get('client_id') + + if not client_id: + flash('Выберите партнера', 'error') + return redirect(url_for('catalog')) + + cart = session.get('cart', {}) + + # Проверяем, что все товары в корзине от одного партнера + if cart: + existing_client = next(iter(cart.values()))['client_id'] + if existing_client != int(client_id): + flash('Нельзя добавлять товары разных партнеров в одну корзину', 'error') + return redirect(url_for('catalog')) + + # Создаем уникальный ключ для комбинации товар + партнер + key = f"{product_id}_{client_id}" + + if key in cart: + cart[key]['quantity'] += quantity + else: + cart[key] = { + 'product_id': product_id, + 'client_id': int(client_id), + 'quantity': quantity + } + + session['cart'] = cart + flash('Товар добавлен в корзину', 'success') + return redirect(url_for('catalog')) + +@app.route('/update_cart/', methods=['POST']) +def update_cart(item_id): + quantity = int(request.form.get('quantity', 1)) + + cart = session.get('cart', {}) + + if quantity > 0 and item_id in cart: + cart[item_id]['quantity'] = quantity + elif quantity <= 0 and item_id in cart: + cart.pop(item_id, None) + + session['cart'] = cart + + return ('', 204) + +@app.route('/remove_from_cart/', methods=['POST']) +def remove_from_cart(item_id): + cart = session.get('cart', {}) + cart.pop(item_id, None) + session['cart'] = cart + + return redirect(url_for('view_cart')) + +# ========== МАРШРУТ ДЛЯ ОФОРМЛЕНИЯ ЗАКАЗА ========== + +@app.route('/checkout', methods=['POST']) +def checkout(): + cart = session.get('cart', {}) + if not cart: + flash('Корзина пуста', 'error') + return redirect(url_for('catalog')) + + conn = get_db_connection() + + # Проверяем, что все товары от одного партнера + client_ids = set(item_data['client_id'] for item_data in cart.values()) + + if len(client_ids) > 1: + flash('Ошибка: в корзине товары от разных партнеров', 'error') + conn.close() + return redirect(url_for('view_cart')) + + client_id = list(client_ids)[0] if client_ids else None + + # Собираем все товары + items = [] + subtotal = 0 + + for key, item_data in cart.items(): + product_id = item_data['product_id'] + quantity = item_data['quantity'] + + product_row = conn.execute('SELECT * FROM Catalog WHERE id = ?', (product_id,)).fetchone() + if not product_row: + flash(f'Товар с ID {product_id} не найден', 'error') + conn.close() + return redirect(url_for('view_cart')) + + product = dict_from_row(product_row) + + if product['quantity_in_stock'] < quantity: + flash(f'Недостаточно товара "{product["product_name"]}" на складе', 'error') + conn.close() + return redirect(url_for('view_cart')) + + items.append({ + 'product': product, + 'quantity': quantity + }) + subtotal += product['min_price'] * quantity + + try: + # Рассчитываем наценку 15% + 10% = 25% + assembly_percent = 15 + delivery_percent = 10 + assembly_cost = subtotal * assembly_percent / 100 + delivery_cost = subtotal * delivery_percent / 100 + total_amount = subtotal + assembly_cost + delivery_cost + + # Срок изготовления (максимальный из всех товаров) + production_days = max(item['product']['production_time_days'] or 1 for item in items) + today = datetime.now().strftime('%Y-%m-%d') + end_date = (datetime.now() + timedelta(days=production_days)).strftime('%Y-%m-%d') + + # Создаем ОДИН заказ + cursor = conn.execute(''' + INSERT INTO Orders ( + client_id, order_date, total_amount, status, + production_days, production_start_date, production_end_date, production_status, + assembly_percent, delivery_percent, assembly_cost, delivery_cost, base_amount + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ''', ( + client_id, today, total_amount, 'Новый', + production_days, today, end_date, 'Ожидает', + assembly_percent, delivery_percent, assembly_cost, delivery_cost, subtotal + )) + + order_id = cursor.lastrowid + + # Добавляем все товары в OrderItems + for item in items: + product = item['product'] + quantity = item['quantity'] + + conn.execute(''' + INSERT INTO OrderItems (order_id, product_id, quantity, price_at_moment) + VALUES (?, ?, ?, ?) + ''', (order_id, product['id'], quantity, product['min_price'])) + + conn.execute(''' + UPDATE Catalog + SET quantity_in_stock = quantity_in_stock - ? + WHERE id = ? + ''', (quantity, product['id'])) + + conn.commit() + session.pop('cart', None) + flash(f'✅ Заказ успешно оформлен! Сумма: {total_amount:.2f} руб.', 'success') + + except Exception as e: + conn.rollback() + flash(f'Ошибка при создании заказа: {str(e)}', 'error') + + conn.close() + return redirect(url_for('orders_list')) + +# ========== МАРШРУТ ДЛЯ СПИСКА ВСЕХ ЗАКАЗОВ ========== + +@app.route('/orders_list') +def orders_list(): + """Список всех заказов""" + conn = get_db_connection() + + clients_rows = conn.execute('SELECT id, name FROM Clients ORDER BY name').fetchall() + clients_list = list_from_rows(clients_rows) + + # Получаем заказы с основной информацией + orders_rows = conn.execute(''' + SELECT + o.*, + c.name as client_name, + c.inn as client_inn, + COUNT(oi.id) as items_count, + COALESCE(SUM(oi.quantity), 0) as total_items + FROM Orders o + LEFT JOIN Clients c ON o.client_id = c.id + LEFT JOIN OrderItems oi ON o.id = oi.order_id + GROUP BY o.id + ORDER BY o.order_date DESC, o.id DESC + LIMIT 100 + ''').fetchall() + + # Для каждого заказа получаем список товаров + orders_with_items = [] + for order_row in orders_rows: + order_dict = dict_from_row(order_row) + + # Получаем товары для этого заказа + items_rows = conn.execute(''' + SELECT oi.*, cat.product_name, cat.article, cat.min_price, cat.category_id, + cat2.category_name + FROM OrderItems oi + JOIN Catalog cat ON oi.product_id = cat.id + LEFT JOIN Categories cat2 ON cat.category_id = cat2.id + WHERE oi.order_id = ? + ''', (order_dict['id'],)).fetchall() + + order_dict['items'] = list_from_rows(items_rows) + orders_with_items.append(order_dict) + + # Считаем общую статистику + total_stats_row = conn.execute(''' + SELECT + COUNT(DISTINCT o.id) as total_orders, + COALESCE(SUM(oi.quantity), 0) as total_quantity, + COALESCE(SUM(o.total_amount), 0) as total_amount + FROM Orders o + LEFT JOIN OrderItems oi ON o.id = oi.order_id + ''').fetchone() + + total_stats = dict_from_row(total_stats_row) + + conn.close() + + return render_template('orders_list.html', + orders=orders_with_items, + total_stats=total_stats, + clients=clients_list) + +# ========== МАРШРУТ ДЛЯ МАТЕРИАЛОВ ========== + +@app.route('/materials') +def materials(): + conn = get_db_connection() + + materials_rows = conn.execute(''' + SELECT * FROM Materials + ORDER BY material_name + ''').fetchall() + + materials_list = list_from_rows(materials_rows) + conn.close() + + return render_template('materials.html', materials=materials_list) + +# ========== СЛУЖЕБНЫЕ МАРШРУТЫ ========== + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + +@app.route('/static/') +def static_files(filename): + return send_from_directory(app.root_path + '/static', filename) + +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file diff --git a/partners.db b/partners.db new file mode 100644 index 0000000000000000000000000000000000000000..0f810b9a637fb627988bce4018f891e5de351298 GIT binary patch literal 143360 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 E0u-3-fdBvi literal 0 HcmV?d00001 diff --git a/static/OfficeStyle.png b/static/OfficeStyle.png new file mode 100644 index 0000000000000000000000000000000000000000..170e5cff71d4c7ab099fdd76baa0f0535ce5a7e0 GIT binary patch literal 4129 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 { + btn.addEventListener('click', function() { + const partnerId = this.getAttribute('data-partner-id'); + // Переход на страницу редактирования + window.location.href = `/edit_partner/${partnerId}`; + }); + }); + + // Кнопка "Добавление продажи" + document.querySelectorAll('.btn-add').forEach(btn => { + btn.addEventListener('click', function() { + const partnerId = this.getAttribute('data-partner-id'); + // Переход на страницу добавления продажи + window.location.href = `/add_sale/${partnerId}`; + }); + }); + + // Кнопка "История реализации" + document.querySelectorAll('.btn-history').forEach(btn => { + btn.addEventListener('click', function() { + const partnerId = this.getAttribute('data-partner-id'); + // Переход на страницу истории реализации + window.location.href = `/sales_history/${partnerId}`; + }); + }); +}); \ No newline at end of file diff --git a/templates/about.html b/templates/about.html new file mode 100644 index 0000000..77fdb9f --- /dev/null +++ b/templates/about.html @@ -0,0 +1,18 @@ + + + + + About Flask + + + {% extends "template.html" %} + {% block content %} + +

About Flask

+

Flask is a micro web framework written in Python.

+

Applications that use the Flask framework include Pinterest, + LinkedIn, and the community web page for Flask itself.

+ + {% endblock %} + + \ No newline at end of file diff --git a/templates/add_client.html b/templates/add_client.html new file mode 100644 index 0000000..1470391 --- /dev/null +++ b/templates/add_client.html @@ -0,0 +1,378 @@ +{% extends "base.html" %} + +{% block title %}Добавление клиента{% endblock %} + +{% block content %} +
+
+
+
+
+

+ Добавление нового клиента +

+
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
+ {{ message }} + +
+ {% endfor %} + {% endif %} + {% endwith %} + +
+
+ +
+
Основная информация
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
От 0.0 до 5.0
+
+
+ + +
+
Контактная информация
+ +
+ + +
+ +
+ + +
+ +
+ + +
Только цифры, 10 или 12 цифр
+
+ +
+ + +
+
+
+ +
+
+
+ + Назад к списку + + +
+
+
+
+
+
+
+
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/templates/add_product.html b/templates/add_product.html new file mode 100644 index 0000000..b083f31 --- /dev/null +++ b/templates/add_product.html @@ -0,0 +1,223 @@ +{% extends "base.html" %} + +{% block title %}Добавление товара{% endblock %} + +{% block content %} +
+
+
+
+
+

+ Добавление товара +

+
+
+
+
+
+ + + Только буквы +
+ +
+ + + Генерируется автоматически +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + Сколько дней нужно на производство +
+ +
+ + +
+ +
+ + +
+
+ +
+
+
+ + Назад в каталог + + +
+
+
+
+
+
+
+
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..0884976 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,620 @@ + + + + + + {% block title %}OfficeStyle - Офисная мебель{% endblock %} + + + + + + + + + + + + + + + + + + + + +
+
+ {% block header %} + {% include 'components/header.html' %} + {% endblock %} + + + {% if request.endpoint in ['index', 'orders_list', 'catalog'] %} + + {% endif %} + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+ {% for category, message in messages %} + + {% endfor %} +
+ {% endif %} + {% endwith %} + + {% block content %} + {% endblock %} +
+
+ + + + + + + + + + + + + + {% block scripts %} + {% endblock %} + + \ No newline at end of file diff --git a/templates/cart_new.html b/templates/cart_new.html new file mode 100644 index 0000000..971c558 --- /dev/null +++ b/templates/cart_new.html @@ -0,0 +1,434 @@ +{% extends "base.html" %} + +{% block title %}Моя корзина{% endblock %} + +{% block content %} +
+
+

Моя корзина

+ + Продолжить покупки + +
+ + {% if cart_items %} + +
+ + + + + + + + + + + + + + + {% for item in cart_items %} + {% set item_total = item.price * item.quantity %} + + + + + + + + + + + {% endfor %} + +
ТоварАртикулКатегорияМатериалЦенаКоличествоСуммаДействия
{{ item.product_name }}{{ item.article }}{{ item.category_name }}{{ item.material_name or '-' }}{{ item.price|int }} руб. +
+ + + + +
+
{{ item_total|int }} руб. + +
+
+ + +
+
+
+
+
Итого по заказу
+
+
+ {% set ns = namespace(subtotal=0) %} + {% for item in cart_items %} + {% set ns.subtotal = ns.subtotal + (item.price * item.quantity) %} + {% endfor %} + + {% set assembly_percent = 15 %} + {% set delivery_percent = 10 %} + {% set assembly_amount = ns.subtotal * assembly_percent // 100 %} + {% set delivery_amount = ns.subtotal * delivery_percent // 100 %} + {% set total = ns.subtotal + assembly_amount + delivery_amount %} + +
+
Сумма без услуг:
+
{{ ns.subtotal|int }} руб.
+
+
+
Сборка ({{ assembly_percent }}%):
+
+{{ assembly_amount|int }} руб.
+
+
+
Доставка ({{ delivery_percent }}%):
+
+{{ delivery_amount|int }} руб.
+
+
+
+
ИТОГО:
+
{{ total|int }} руб.
+
+
+
+
+
+ + +
+
+ +
+
+ + {% else %} + +
+ +

Корзина пуста

+

Добавьте товары в корзину, чтобы оформить заказ

+ + Перейти в каталог + +
+ {% endif %} +
+ + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/catalog.html b/templates/catalog.html new file mode 100644 index 0000000..ab4ba6d --- /dev/null +++ b/templates/catalog.html @@ -0,0 +1,564 @@ +{% extends "base.html" %} + +{% block title %}Каталог товаров{% endblock %} + +{% block content %} + + + + +
+

Поиск и сортировка

+
+
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+ + + {% if products %} + {% for product in products %} +
+
+
+
+
{{ product.product_name }}
+ Артикул: {{ product.article }} +
+ + + +
+
+
+
+
+
+ Категория: + {{ product.category_name }} +
+ +
+ Материал: + + {% if product.material_name %} + {{ product.material_name }} + {% else %} + Не указан + {% endif %} + +
+ +
+ Время изготовления: + {{ product.production_time_days or 1 }} дн. +
+ + {% if product.description %} +
+ Описание: + {{ product.description }} +
+ {% endif %} +
+
+
+ В наличии: + + {% if product.quantity_in_stock and product.quantity_in_stock > 0 %} + {{ product.quantity_in_stock }} ед. + {% else %} + Нет в наличии + {% endif %} + +
+ +
+ Цена: + {{ product.min_price|int }} руб. +
+
+
+ + + +
+
+ {% endfor %} + + +
+
+

+ + Найдено товаров: {{ products|length }} + {% if request.args.get('search') %} + по запросу "{{ request.args.get('search') }}" + {% endif %} + {% if request.args.get('category') and request.args.get('category') != 'all' %} + {% for category in categories %} + {% if category.id == request.args.get('category')|int %} + , категория: {{ category.category_name }} + {% endif %} + {% endfor %} + {% endif %} +

+
+
+ + {% else %} +
+ + {% if request.args.get('search') or request.args.get('category') != 'all' %} + Ничего не найдено по вашему запросу. +
Сбросить все фильтры + {% else %} + В каталоге нет товаров. Добавьте первый товар. + {% endif %} +
+ {% endif %} + + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/components/header.html b/templates/components/header.html new file mode 100644 index 0000000..77c8b09 --- /dev/null +++ b/templates/components/header.html @@ -0,0 +1,6 @@ +
+
+ +

Офисная мебель

+
+
\ No newline at end of file diff --git a/templates/components/partner_card.html b/templates/components/partner_card.html new file mode 100644 index 0000000..849d8fc --- /dev/null +++ b/templates/components/partner_card.html @@ -0,0 +1,244 @@ +
+
+ +
+
+ + {% if partner.contractor_type_name %} + {{ partner.contractor_type_name }} + {% else %} + Тип не указан + {% endif %} + + | + {{ partner.name }} +
+ +
+ + {{ partner.total_quantity }} ед. + +
+
+ + +
+ Директор: + {{ partner.director or 'Не указан' }} +
+ +
+ Телефон: + + {% if partner.phone %} + {{ partner.phone }} + {% else %} + Не указан + {% endif %} + +
+ +
+ Рейтинг: + + + {{ partner.rating }} + + +
+ +
+ Общая сумма заказов: + + {{ "%.2f"|format(partner.total_sales) }} руб. + +
+ + + +
+
+ + \ No newline at end of file diff --git a/templates/edit_client.html b/templates/edit_client.html new file mode 100644 index 0000000..a342280 --- /dev/null +++ b/templates/edit_client.html @@ -0,0 +1,396 @@ +{% extends "base.html" %} + +{% block title %}Редактирование клиента{% endblock %} + +{% block content %} +
+
+
+
+
+

+ Редактирование клиента +

+
+
+ + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
+ {{ message }} + +
+ {% endfor %} + {% endif %} + {% endwith %} + +
+
+ +
+
Основная информация
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
От 0.0 до 5.0
+
+
+ + +
+
Контактная информация
+ +
+ + +
+ +
+ + +
+ +
+ + +
10 или 12 цифр
+
+ +
+ + +
+
+
+ +
+
+
+ + Назад к списку + +
+ + История заказов + + +
+
+
+
+
+
+
+
+
+
+ + + +{% block scripts %} + +{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/templates/edit_product.html b/templates/edit_product.html new file mode 100644 index 0000000..ccbeca2 --- /dev/null +++ b/templates/edit_product.html @@ -0,0 +1,279 @@ +{% extends "base.html" %} + +{% block title %}Редактирование товара{% endblock %} + +{% block content %} +
+
+
+
+
+

+ Редактирование товара +

+
+
+ + {% if client %} +
+ Редактирование товара партнера: + {{ client.name }} + +
+ {% endif %} + + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
+ {{ message }} + +
+ {% endfor %} + {% endif %} + {% endwith %} + +
+
+
+ + + Только буквы +
+ +
+ + + Не изменяется +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + + +
+ + + Сколько дней нужно на производство +
+ +
+ + +
+ +
+ + +
+
+ +
+
+
+ + Назад + + +
+
+
+
+
+
+
+
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/templates/home.html b/templates/home.html new file mode 100644 index 0000000..085f57c --- /dev/null +++ b/templates/home.html @@ -0,0 +1,16 @@ + + + + + Flask Tutorial + + + {% extends "template.html" %} + {% block content %} + +

My First Try Using Flask

+

Flask is Fun

+ + {% endblock %} + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..083953a --- /dev/null +++ b/templates/index.html @@ -0,0 +1,238 @@ +{% extends "base.html" %} + +{% block title %}Партнеры офисной мебели{% endblock %} + +{% block content %} + +
+

Партнеры офисной мебели

+ + Новый партнер + +
+ + +
+

Поиск и сортировка

+
+
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + + {% if partners %} +
+ {% for partner in partners %} + {% include 'components/partner_card.html' %} + {% endfor %} +
+ + +
+
+

+ + Найдено партнеров: {{ partners|length }} + {% if request.args.get('search') %} + по запросу "{{ request.args.get('search') }}" + {% endif %} + {% if request.args.get('type') and request.args.get('type') != 'all' %} + , тип: {{ request.args.get('type') }} + {% endif %} + {% if request.args.get('rating') and request.args.get('rating') != '0' %} + , рейтинг ≥ {{ request.args.get('rating') }} + {% endif %} +

+
+
+ {% else %} +
+ + {% if request.args.get('search') or request.args.get('type') != 'all' or request.args.get('rating') != '0' %} + Ничего не найдено по вашему запросу. +
Сбросить все фильтры + {% else %} + Нет данных о партнере. Добавьте первого партнера. + {% endif %} +
+ {% endif %} + + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/materials.html b/templates/materials.html new file mode 100644 index 0000000..f959b22 --- /dev/null +++ b/templates/materials.html @@ -0,0 +1,266 @@ +{% extends "base.html" %} + +{% block title %}Материалы{% endblock %} + +{% block content %} + +
+

Материалы

+ + Всего: {{ materials|length }} + +
+ + + {% if materials %} +
+ {% for material in materials %} +
+
+
+
+ {{ material.material_name }} +
+
+
+ {% if material.description %} +

{{ material.description }}

+ {% endif %} + +
+ {% if material.category %} +
+ Категория: + {{ material.category }} +
+ {% endif %} + + {% if material.color %} +
+ Цвет: + {{ material.color }} +
+ {% endif %} + + {% if material.density %} +
+ Плотность: + {{ material.density }} кг/м³ +
+ {% endif %} + + {% if material.thickness %} +
+ Толщина: + {{ material.thickness }} мм +
+ {% endif %} + + {% if material.supplier %} +
+ Поставщик: + {{ material.supplier }} +
+ {% endif %} + + {% if material.country %} +
+ Страна: + {{ material.country }} +
+ {% endif %} + + {% if material.wear_class %} +
+ Класс износа: + {{ material.wear_class }} +
+ {% endif %} +
+ +
+ {% if material.price_per_unit %} +
+ Цена: + {{ material.price_per_unit|int }} руб./{{ material.unit or 'шт' }} +
+ {% endif %} + +
+ В наличии: + + {{ material.in_stock or 0 }} {{ material.unit or 'шт' }} + +
+
+ + +
+
+
+ {% endfor %} +
+ {% else %} +
+ +

Нет материалов

+

В базе данных пока нет материалов. Добавьте материалы через импорт данных.

+
+ {% endif %} + + +{% endblock %} \ No newline at end of file diff --git a/templates/order_history.html b/templates/order_history.html new file mode 100644 index 0000000..87e99d1 --- /dev/null +++ b/templates/order_history.html @@ -0,0 +1,465 @@ +{% extends "base.html" %} + +{% block title %}История заказов - {{ client.name }}{% endblock %} + +{% block content %} +
+ +
+
+ + Назад + +

История заказов - {{ client.name }}

+
+
+ + +
+
+
+ + {% if client.contractor_type_name %} + {{ client.contractor_type_name }} + {% else %} + Тип не указан + {% endif %} + + | + {{ client.name }} +
+
+ +
+
+
+
+ Директор: + {{ client.director or 'Не указан' }} +
+
+ Телефон: + {{ client.phone or 'Не указан' }} +
+
+
+
+ Email: + {{ client.email or 'Не указан' }} +
+
+ ИНН: + {{ client.inn or 'Не указан' }} +
+
+
+
+
+ + +
+

Общая статистика

+
+
+
+
{{ total_stats.total_orders or 0 }}
+
Всего заказов
+
+
+
+
+
{{ total_stats.total_quantity or 0 }}
+
Общее количество
+
+
+
+
+
{{ "{:,.2f}".format(total_stats.total_amount or 0) }} руб.
+
Общая сумма
+
+
+
+
+
{{ total_stats.completed_orders or 0 }}
+
Выполненных
+
+
+
+
+ + +
+

Детализация заказов

+ + {% if orders %} +
+ {% for order in orders %} +
+

+ +

+
+
+ +
+
+

Дата заказа: {{ order.order_date[:10] }}

+

Срок изготовления: {{ order.production_days or 1 }} дн.

+
+
+

Дата готовности: {{ order.production_end_date[:10] if order.production_end_date else '-' }}

+
+
+ + +
Состав заказа:
+
+ + + + + + + + + + + + {% for item in order['items'] %} + {% set item_sum = item['price_at_moment'] * item['quantity'] %} + + + + + + + + {% endfor %} + +
ТоварАртикулКоличествоЦена за ед.Сумма
{{ item['product_name'] }}{{ item['article'] }}{{ "{:,}".format(item['quantity']) }} ед.{{ "{:,.2f}".format(item['price_at_moment']) }} руб.{{ "{:,.2f}".format(item_sum) }} руб.
+
+ + +
+
+
+
+ Базовая сумма товаров: + {{ "{:,.2f}".format(order.base_amount) }} руб. +
+
+ Сборка ({{ order.assembly_percent }}%): + +{{ "{:,.2f}".format(order.assembly_cost) }} руб. +
+
+ Доставка ({{ order.delivery_percent }}%): + +{{ "{:,.2f}".format(order.delivery_cost) }} руб. +
+
+ ИТОГОВАЯ СУММА ЗАКАЗА: + {{ "{:,.2f}".format(order.total_amount) }} руб. +
+
+
+
+ + +
+
+
+ + +
+
+
+
+
+
+ {% endfor %} +
+ {% else %} +
+ Нет данных о заказах +
+ {% endif %} +
+
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/orders_list.html b/templates/orders_list.html new file mode 100644 index 0000000..160687a --- /dev/null +++ b/templates/orders_list.html @@ -0,0 +1,316 @@ +{% extends "base.html" %} + +{% block title %}Список заказов{% endblock %} + +{% block content %} + +
+

Список заказов

+
+ + +
+
+
+
+
Всего заказов
+

{{ total_stats.total_orders or 0 }}

+
+
+
+
+
+
+
Всего единиц
+

{{ "{:,}".format(total_stats.total_quantity or 0) }}

+
+
+
+
+ +
+
+
Общая сумма
+

{{ "{:,.2f}".format(total_stats.total_amount or 0) }} руб.

+
+
+
+
+ + + {% if orders %} +
+ + + + + + + + + + + + + + + + {% for order in orders %} + {% set markup = order.assembly_cost + order.delivery_cost %} + + + + + + + + + + + + {% endfor %} + +
IDДатаКлиентИННСостав заказаВсего единицНаценка (25%)ИтогоСтатус
{{ order.id }}{{ order.order_date[:10] if order.order_date else '-' }} + {% if order.client_id %} + + {{ order.client_name or 'Неизвестный клиент' }} + + {% else %} + {{ order.client_name or 'Общий заказ' }} + {% endif %} + {{ order.client_inn or '-' }} + {% if order['items'] and order['items']|length > 0 %} + +
+
+ + + + + + + + + + + + {% for item in order['items'] %} + {% set item_sum = item.price_at_moment * item.quantity %} + + + + + + + + {% endfor %} + + + + + + + + + + + + + + + + + + + +
ТоварАртикулКол-воЦена за ед.Сумма
{{ item.product_name }}{{ item.article }}{{ "{:,}".format(item.quantity) }} ед.{{ "{:,.2f}".format(item.price_at_moment) }} руб.{{ "{:,.2f}".format(item_sum) }} руб.
Базовая сумма:{{ "{:,.2f}".format(order.base_amount) }} руб.
Сборка ({{ order.assembly_percent }}%):+{{ "{:,.2f}".format(order.assembly_cost) }} руб.
Доставка ({{ order.delivery_percent }}%):+{{ "{:,.2f}".format(order.delivery_cost) }} руб.
ИТОГО:{{ "{:,.2f}".format(order.total_amount) }} руб.
+
+
+ {% else %} + Нет товаров + {% endif %} +
{{ "{:,}".format(order.total_items or 0) }} ед.+{{ "{:,.2f}".format(markup) }} руб.{{ "{:,.2f}".format(order.total_amount) }} руб. + + {{ order.status }} + +
+
+ {% else %} +
+ + Нет данных о заказах. Вернуться на главную. +
+ {% endif %} + + +{% endblock %} \ No newline at end of file diff --git a/templates/product_detail.html b/templates/product_detail.html new file mode 100644 index 0000000..981d90b --- /dev/null +++ b/templates/product_detail.html @@ -0,0 +1,427 @@ +{% extends "base.html" %} + +{% block title %}{{ product.product_name }} - детальная информация{% endblock %} + +{% block content %} +
+ + + +
+ +
+
+
+
Основная информация
+
+
+ + + + + + + + + + + + + + {% if product.description %} + + + + + {% endif %} + + + + + + + + +
Артикул:{{ product.article }}
Категория:{{ product.category_name }}
Материал: + {% if product.material_name %} + {{ product.material_name }} + {% else %} + Не указан + {% endif %} +
Описание:{{ product.description }}
Базовая цена:{{ product.min_price|int }} руб.
В наличии: + {% if product.quantity_in_stock and product.quantity_in_stock > 0 %} + {{ product.quantity_in_stock }} шт. + {% else %} + Нет в наличии + {% endif %} +
+
+
+ + + {% if material %} +
+
+
Информация о материале
+
+
+ + + + + + {% if material.color %} + + + + + {% endif %} + {% if material.supplier %} + + + + + {% endif %} + + + + + + + + +
Материал:{{ material.material_name }}
Цвет:{{ material.color }}
Поставщик:{{ material.supplier }}
Цена за ед.:{{ material.price_per_unit|int }} руб./{{ material.unit }}
На складе: + {% if material.in_stock and material.in_stock > 0 %} + {{ material.in_stock }} {{ material.unit }} + {% else %} + Нет + {% endif %} +
+
+
+ {% endif %} +
+ + +
+ +
+
+
Производственные характеристики
+
+
+ + + + + + + + + + + + + + + + + +
Время изготовления: + {% if product.production_time_days %} + {{ product.production_time_days }} дн. + {% else %} + {{ material.production_time_days if material else 1 }} дн. (по умолчанию) + {% endif %} +
Производительность: + {% if product.daily_capacity %} + {{ product.daily_capacity }} шт/день + {% else %} + {{ material.daily_capacity if material else 10 }} шт/день (по умолчанию) + {% endif %} +
Себестоимость: + {% if product.cost_price %} + {{ product.cost_price|int }} руб. + {% elif material and material.price_per_unit %} + {{ (material.price_per_unit * 1.3)|int }} руб. (расчетная) + {% else %} + Не указана + {% endif %} +
Прибыль с единицы: + {% set cost = product.cost_price or (material.price_per_unit * 1.3 if material else 0) %} + {% if cost and cost > 0 %} + {{ (product.min_price - cost)|int }} руб. + ({{ ((product.min_price - cost) / product.min_price * 100)|round(1) }}%) + {% else %} + — + {% endif %} +
+
+
+ + +
+
+
Расчет стоимости со сборкой и доставкой
+
+
+
+
+ + +
+
+ + +
+ + + + + + + + + + + + + + + + + +
Базовая стоимость:0 руб.
Стоимость сборки (15%):0 руб.
Стоимость доставки (10%):0 руб.
ИТОГОВАЯ СТОИМОСТЬ:0 руб.
+
+
+
+ + +
+
+
Статистика продаж
+
+
+
+
+
+
{{ orders_stats.total_orders or 0 }}
+ Всего заказов +
+
+
+
+
{{ orders_stats.total_sold or 0 }}
+ Продано единиц +
+
+
+
+
{{ (orders_stats.avg_order_size or 0)|int }}
+ Средний заказ +
+
+
+
+
+
+
+
+ + + + + +{% endblock %} \ No newline at end of file