From cc433c2fcb2b83a4d00fcedf04442182b97caf36 Mon Sep 17 00:00:00 2001 From: Ali Nabhan Aboobakuru <Ali3.Aboobakuru@live.uwe.ac.uk> Date: Mon, 24 Jun 2024 14:15:35 +0500 Subject: [PATCH] added Inventory graphs forecast and sales which work by filling forms to fill graph data --- .../__pycache__/admin.cpython-311.pyc | Bin 945 -> 1237 bytes .../__pycache__/forms.cpython-311.pyc | Bin 2416 -> 5984 bytes .../__pycache__/models.cpython-311.pyc | Bin 6888 -> 8702 bytes .../PROJECT1/__pycache__/urls.cpython-311.pyc | Bin 2015 -> 2381 bytes .../__pycache__/views.cpython-311.pyc | Bin 8723 -> 12704 bytes postgresTest/PROJECT1/admin.py | 6 +- postgresTest/PROJECT1/forms.py | 55 ++++- .../migrations/0014_account_forecast_sale.py | 39 ++++ ...0014_account_forecast_sale.cpython-311.pyc | Bin 0 -> 1809 bytes postgresTest/PROJECT1/models.py | 23 ++ .../PROJECT1/templates/add_account.html | 12 + .../PROJECT1/templates/add_forecast.html | 12 + postgresTest/PROJECT1/templates/add_sale.html | 11 + postgresTest/PROJECT1/templates/base.html | 8 +- .../PROJECT1/templates/dashboard.html | 4 +- .../PROJECT1/templates/inventory.html | 216 ++++++++++++++++++ postgresTest/PROJECT1/urls.py | 6 +- postgresTest/PROJECT1/views.py | 82 ++++++- 18 files changed, 460 insertions(+), 14 deletions(-) create mode 100644 postgresTest/PROJECT1/migrations/0014_account_forecast_sale.py create mode 100644 postgresTest/PROJECT1/migrations/__pycache__/0014_account_forecast_sale.cpython-311.pyc create mode 100644 postgresTest/PROJECT1/templates/add_account.html create mode 100644 postgresTest/PROJECT1/templates/add_forecast.html create mode 100644 postgresTest/PROJECT1/templates/add_sale.html create mode 100644 postgresTest/PROJECT1/templates/inventory.html diff --git a/postgresTest/PROJECT1/__pycache__/admin.cpython-311.pyc b/postgresTest/PROJECT1/__pycache__/admin.cpython-311.pyc index 2014e659ffaebb997f03b06e04cb540f83f513f9..cb12279806f9fe8d3d67ef23419fef86fe803a6c 100644 GIT binary patch delta 577 zcmdnUewCAVIWI340|NuYt(z5T=O*$>GCrB8uC9^G9>t!^5yg?q8O6!Skiw9{lEanD z9mUPakjj|F15yvd3wS4HX>ucT=b>^hp>QX&F{;<2Xa^aBj#Jr}F)}c$W`v2OTL}|K zrc*hH)uV;bmdc5ti6x5<Ccl7xvK6Dcj6e!|FoPz?OOUW8<1N<2l-$g`mmtS!vQMsM zR5QKB;g(;Nnw(f%a*HK6F(>sFyJK>4eraBbCgUxZ(Bjmh5KYEgJekGu#ia$QMWw~5 zMShxsllL<k@)U70FfbH>0>6lR@>@m)MxM!hOlPAc85kHq<`+vaGBA8#W@Kc%!Ju#f z72RM6xIj9ZtjwI_e1n0th3h(l@FfP}2_6?2WUnyDUSN<#7InGEAbEvB@&bb-vZ(t- X2AL}iG8Y(RZcLuQEXyL!z`y_iSP^&% delta 289 zcmcc0xsjcBIWI340|Ntt(ao~7go(V8j5ZV1)nynNQW#QLa@cb@qBs~CQW>*2L25vF z0oTMbO>SiFDpc-06z*gpMs;46EN+li5MIDD`4OW!BkyD`CMiai$*N3hGMbFHSVD_a zi$XLRZ}DUn#}}6tq!yJHrxy8X@=b1FGMs#XNtTgw@;#=r9%2j(42%p648=zn7#Kb< zGcq#XU{JV#if%AiTp)xdv$EtUJ>V6;!YhBBSM3t7+6I>kylNMDEwAueHgJJpkq83= F0{{eHMCt$l diff --git a/postgresTest/PROJECT1/__pycache__/forms.cpython-311.pyc b/postgresTest/PROJECT1/__pycache__/forms.cpython-311.pyc index cd7518955ad1908518336576a45fbde282a20a00..12e0e8753b7fd6ad66bb9362a9de828fadcda04a 100644 GIT binary patch literal 5984 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 A{{R30 delta 710 zcmaE$_d$qnIWI340|NuYR;lLHaF&UD5=^TYCTeIpGNdr(Fyt~uF)}iwu%xi&u;sEx zu`@C-F}O3Nu(dFxu%|LFV`gAj%?#2E!ciPxIgS>F6wXw}EY68_;{04-A+8pN6z){U zEbfVQ;_N&rJi!c_ypsbMt+*L)u{-DIl_VyYBu^9+oh-<IV)B1xRdrSd28LU#x%nxn zIYlfWHj8g+N#ZTGw9M3;l;V{PpF!6Bika-dA|~vZlNs-qn3R#27jI;2U}k7+XgYZs zi!pbR00RR<5jO(^1IJ`(0eyR65Emror^#Bx1LE+42tE)2vIC-C2*d>|6#=n0VFdf+ zP62N=umtDiy@HaHKMMrLYck#9%+1V;FH6iRO})jQnU`6TnV93J$%bw|D2Q(Hc;=O) zrl%IUfjn`Gqp&nFuOzdivIxyeF_4uYf_HMKpdQ3ZvCVr0XESnYGTvfMEGa1}o*XM| zBZcM%c91@P5Ft2uv#_xwnz10C7s)X&FbGcmFTBPI>=TffpC${sYeB;3u95*63?c+3 zUlDQT0c!_w{WN(etB8iWfCB0ki(7tCZV|}sw>W)4kq733l%W~-i^C>2KczG$)vm~x ufq{XMfq|j;4a4LIqV_5h7Z^~`4F>58sOSUB<O^b2j69QnizTvv90CB4U6$Jb diff --git a/postgresTest/PROJECT1/__pycache__/models.cpython-311.pyc b/postgresTest/PROJECT1/__pycache__/models.cpython-311.pyc index 6967190edda76ff050b1c856253ce6de18945554..4fc74ad33117e781e184ab01312693a87573ddae 100644 GIT binary patch delta 2723 zcmaE1`p=nfIWI340|Ns?$c>6LXa0$N5{%a-s!y4iFE#OW1S9KYJ;oR=CI)wg6wwxj z6tRhU(%iyeu6PSWiUf!&0_IA#Fr-LL%#&spO_2^}(3IIcfpHNd<FC!e%m$3cLJSNH zMWPH048@EL3=9fI;vl{R0|P@9Z$N2Ya)w@fd~r!pe7pciToOb`O`gUQEhx;uz;KJx zC9x#cEi*MIrATBl6RR^XNaIR|A}NqM@yS7~yBMV=^Rme?7ENyClb-C(rZjma8~@}Q zHhIky<`#x1t`wGF22Ivm9B%nVsmY1OB`=v77#LPE-r~wltccG^%}X!In8Yr|Xfm0D zS-C!isfHno2^1b6Jey%IYcRt~X1`yI3Ppkp3=Epgw^(!Y^GY&qu~eoe7TsbkOUx-v z#qKu&n1wL!fgE0}!oa}Lz;HuIY>L(ee#;B|mNQD`R6<xQLe|trL6{dfEWsZ1)8sCa z0eMswM96^%7I2_AXCxLu0>u!-=kd%dNlj0M3K@ZfxZHB`6H6d!j6oVf))#4jSdgFt zv9w?WD5#4g7!pB_YhZxD8$2={ZdZ6@Rxn=R(YnZ^b%jT(!Sx2WT!+~eZn=xx3Rk!l z8eDGh$buBfUgVL#!Xw|{`hkU!)#?KSCIR+Ok=EpgLXwzKC4&-GEWwF6sV_mXP^81a zz<@t?iu57z!d_UKSX7c)R0Q&U5!lCAlN=Aoa9ETmfD$DlN^~ypTVLR}ULdkW62e+h zvZe~cy1-#wR1XR`98pqa0t!lN5Mc@;z^*U@vA|Bj7Wft*Sr8!&azz9<VL(E@f#C+9 zTu0g!KDiZ&7x;88^66aR(`j&bASUo_K!J}=Kmy+a9QYx~`9y&o9P%8{Ov3J%oSa{p zSMpK><Tg;?PyWbcS6>9mnVL+uIFb`fQq%K`D)EFbKhy|V5UYbc2MRbys@J{1Z*YO% zV1dgLF9_=bhXL4iewv)vk~%0{>lun1K<>dGoVFk(AVL{rqX%km^2>LWUE!BsVRV6C z?;^k66@I-24{S--5EOdo1UuM)MYf>eo2<>Yg%zAEH@{_*U=$Mr<u&%A#FEUs^x|Sr znpIFJ5}z#1q0VS9*_p#b0pxW*O+H+HW0<^=L&LNPlxA+R78GSBr{3ZyD9SHLEh?!j z@&|bdEz3HA#6X1BWO2?`Hjwc}PMa5T7BF%nl@ya@x#bxnC);vMOQPuqrL!UsVLG{x zyNC;{AH+?bC@8v_iARM|%pGJyD2PDLK$C5FHR^pB7#Kc-%8CYt8~nmOwKGcQRLrTn z$gg{WLl+!KxO^%PG7ePm7J;%{ks^o-GN%aSlOnK<pdcv921(?A2sCG>fW){!BuH^_ z!Q?<8-N{mX?hp@v#6cdI+`u=NF?F&WzXVf}<zx$fRXwCI0hs_QJ&SNUMtO2Kzb<-! z<%9Hr2>;0!`I8{_fw*A%f&}g|rcO2xlwgdT>?!CgmI+dv1tL(wZjGRFeH2JE7es)< z+)q;gYm&g}HjtIKSo4cgQj4$#S`El#v_Pu_iGhd^28PLgLcNgGQaSmd(0xH?kQ^w7 zzvKti{zV0oFAD1!f!wdjSQG$~MD_uQ4=Tf|_?`3fN)nSxVA(rmvZ08u62wQi6M0d< z<TMdE+hA~J$xSUTPE1cN0_D?NT**bLi6yBi@rflxAPdlIsCtmiAR>11L6L4q=!3Z6 z(9ae<%I*bred=U$v3@sDin_&7TAW&xmzbLhNmgL5fJy`GwX~pDeo_!P_riRXJDEq^ z2wK#W7)NM{8Eh-q&um4hWtpkvSbYfcKoN*Y2bEjxkaBBsxRCl}DL%=`f5lySK%om( z;ioA!*-xS{3|wu4YK|gMc?U@jpgddz$_GWDlu`tW^&(I}fi<Fq>MstP-29Z%oK(A_ z2@DJjpjKINJkw-0$<BH<Myn4Dm_$cePt8Y=_!kfXQ6a#_Xai!Q6CGwfHXyY&Ahl3Q k0aixC4-A+@M_NzLN09gz5b=S56{Li3bH8LLBMZpe0CyHkl>h($ delta 1444 zcmez8{KAxPIWI340|NuY4!w%BJv<ZnBp6dBs!w5Lop>yL;zOy)wv4`PDWbs)nqr%o zm=-ZIR&8F&Y`|zN$iTo*B*MVJP|V1{z@Shh2I7k|Ffdf{29)L{XXwSp7nc;p#|wbO zB|wDaWDeG7K_LbPhFhF2i6yCSnW;G`MZ%LySe<!68dowDNrKdgO+Lc9i&1iNJ)7L* zV?0~<Rx;k=%1x|@&q>WoFUi<k&nv+wCJHizy(qCHGcUckm<i+pg(9)ZYx&d}B`06y z^H2ks<fqA3Bn>iA21Lk$2o{h&PUnooBCzd~ZTU6qZt-~Lm87PpLWFLy78GSBr{3Zy zD9SHLEh?!jvH)pR2N57cAs*EPaY2Oe<XQZ!Y+wn^&8h+gjNC{zPF^4=&*(DwfS|M_ znto@Heh?uy`HNr?7g#@tn><labaSha3Zs|-NQDE4Kn~=|`-L?aO((w)mPrTc!QsOq zIgmbP5FrmD6hH(h;EO;`E&>~E4-yLl5#b;L&3*nLF%V%eIa{O>;yw@;<i5$wqH`Go zCNC6~V0y_kdAF#l9+H<q`apq<+X+gO`NVYP(Cmu>=>rj<z%GuQTp*%5xlPOfVlhY@ zZ1GjGyHWw5805|`N=Yq>&n!vJE!Jcz;sNRQoP0*yS1bg?3<VJ=!KN>vTn`H0q6m-_ zB<KXNB@W!~2D#!EE7)SJ!I%Lu8O>X%ATbbO%fK-CqC_twp`=b;%Og3tR`Qsj7D!&3 zfq~&AKLZ0pNKy3U5GlQMkRLP|i>yGB$i4vaK^dir-#I_8Br&-JmdAWS*$|Y68yIfz z3-?rB;E(`kC0xnF5@eFq<d;%%PPU-nWY0}4E>28OEm8vUxRQ%f6H8K4;uA}XK-LwZ zc`6&E8$`H)tZkY+pI>=$j&w34u0Z18xOyjjl-(HYsesA5WcuAe$?q0NX>n>%USe)4 zBn^UnXb3V6t2YI`@{@wVSsdoku*v<hM)hPxA6m)>+Y0tPTTyCRW@<TBuYx>K1R_AG zuDG3nfuVt+VRD&>!{i1zS00c%z_Nat!jmt`6}p4%04Fn0UMT{lm?BW@7lA?rtP(9O me{tC4=BJeAq}mnLFfcHHO48!njFV@`cWz#)5X#5`vH<{vejzOY diff --git a/postgresTest/PROJECT1/__pycache__/urls.cpython-311.pyc b/postgresTest/PROJECT1/__pycache__/urls.cpython-311.pyc index e8524fe44dfc2d3a37edcf6b8a347eca74c19892..794fe9d18325708efec96aca472e5e970932c990 100644 GIT binary patch delta 479 zcmcc5e^y9iIWI340|NuYb@R%!*{lo<k3k$57K1WAt1xfWh+~@gfR$e*l{rfiD$J0g zI`M)izgjADmK0n_9VDcY%A6$)7t)+~K{Qe;l{rfWE~LGNa~U%O!)j)jNV*UcLn?bJ zYnCibB$YKw4#r-ivy6#>VKozsU&X+{5G9|Y8_b}oxA_2517m#^S7u&WYF<fxQKkMZ zPB^=YH!&q8J}ti}H94`kME@2KGPjBo#4AqBN!7o_0b^Eyl_Vx7=a=S{=-=W7i9>ms zjJJ4G@{>z*Q}asVi}LeJ{4^DAai?S@=A}=LW;r9x2e&r9EHkyd2oz35ppYq&o~+Dz zm|Ks5fq{{MfuY!mY4b<ceT?EaSU4J7I%Fo4UJ=*cpnZYG?jnob6&Ab6E7^=4<z|Rp zk<{8Cdx6FNB8&YM7W)sX!u(7h)EHQ~8{9f9u5in)h`6HbaDm0~B8%e{7RQh3!u(E* N4cs7Dq{G0#001r$e=q<5 delta 208 zcmX>rbe~^iIWI340|NsCn_NZOEEWca#~=<23qcv5r!Z~Qh-0!!=VM|>Wlv?zl7vby zq_Sp7!Psk5mN79ftY(7os~8v<qNGz)gBdi{HU}^_Fp6k0-r`NkPcF?(%`1s7%Fi$H z)0CO)!FqYJ72AGpO$G)AMg|6k;^&N;S=je68hnuD=V$sL$H2<n;MQSrg<Ez-#1&nK c3oMQoSsbshIDVAp=XYXk;0D1Wbp{3o0F?YJj{pDw diff --git a/postgresTest/PROJECT1/__pycache__/views.cpython-311.pyc b/postgresTest/PROJECT1/__pycache__/views.cpython-311.pyc index bd68d7ea23f14b2d271b5336493ae06a3275aa82..49b36fcdd7ad34d2192d3d0cf2122cd8ff0cd9fd 100644 GIT binary patch delta 4907 zcmbR2vLKmnIWI340|NuYT=UAbdWDI65{wNK)x+y^g`$LVg`<RXMWRF)8B$nN*mFd4 z#iGP=#iPV?C88v9C8H#BrJ|%58B!QhIC7+OWuj!j>Ns=wa%H1r!Qxywa=CI*a$q)h zj(n~{lmeK|lcSic6s5$-kiy%-5T%^L*TN8`lEUA@5T%+T0A|+<f;mDh3{h&S+$q8> z49gf87*>NE3dT|DsoW_d7@``f+$o|MqM9jUEeugwsoW{z7;@Sv5-ki-Iw_JZ3{kqN z+$mBJ6$VIF>7_`wFhuF6$h0s-8KlUzFhm)q$h9y;8Kua#Fhm)rC<HTTDo(Co%r|Ab z#q5=zbc@p~KPf1&Br`Al7Q1tPUP)qd$t@1I{G!z4#Nv`$EWwF6skhi2laupH^GY;X zCo?mtn%?4p$-Ctj<=)}|sR6UNq3S>!O~zZyj%DeZjJH?=O7oI4CR;L@%5pF;FfcPP zFnrcwVqlogP{WV~4j>S*fN^plw+Lg(WG!x0jVu<B5C|`0VqjR!1Y&`3EhDBDrWB^h z+T1Dv=z1n+b6be4VP3|_z_6MTq#1;3nM(vFmvd`tGhxWEln8-TKyVftgl1q^z%@CL zTe+UKL>wl<z>va{!iwfFHWYcb6m~Ru_8R6ImKxR)NrWjijHqrykz+!YtFK|JVNc<h z!(Pi#B8_AOLkedN$1-LHhSi{81xo}oXma`8;!T4_VSHt3V$m(G;>4WPVlaCp<1H4D zSmtwf28PTJAmToVc*V}ZpviuV6Q;5F7AsiOEsn(G<a$u_7Z=GgFfbI!F)%RP5{4-Q zn;Bn}n3tY<O8~3^Nu-J|Gp{T)uOz>yQZJ(<H%F827PGr+$Svmd)RH1lP~2k9%P%id z02#{<GL}6*DJwO(r1%zFT4qj3YEh8@NJ@|)nt|aKb7D@;Emnw4%$a#5MIbM0a^7Mu zN-Zo+EiOU0u1FE2O9@0Mg9sH6p$axXIX|x?wW6e$lYxOj0RkrLF!$9X92#GinOa_C z$iTqB%fP@;{DOgjp@HFsi1ZZi>Hd@a7x-_D*b=ibZcE%1Q;&-xo>xRX8+>mFN=%WS zE<Z_rfy~;9H8m^i*3@0mce*I(d_~Z?!Rx7j#1#RB>jLVR1k_i=UJy{fC}4d>z`DWn zE{{Nu&vhR8OFZ)R3!*OY$Y10!xWZ%5;Ch!|tf&4uztSasrHlM3SNK&LJf2F)FJM`a za#2eAij?*R7V*2{GBZLJm|PUsxFW7`fkos48-tkq4MDLRA~JU+WoE=)l+?Z=seM;W za)#E#{3-c2<c)5~=zQSk;Ai{5z`@Vf;Qm#Ffk$Y9`UPq272y}TIZdx{n_gfs{md{~ zQBacU6T@Ui8A(Q;$p?h|8I>ms2&=I$GL&#n4iJ`_yh~V75EL@t#Kyo-!;r$9!ZNu) zP_&-a?-omde{jexPI#>U;!R9Ri3cSMaQxq5Ny{(FUCDlnEjP6!BR{1`6cjTipqSyv zERHWr%*jl-#ZsJDmRbZV0l+c5lBq}!q{<u=8=#UvL7~V1tOI6rku3uQg9<}E14D5> zB(~W3TIyzqU1FENz%GB6Uwj7p9G;8(s#o|`J6LXT^Y`0!*>>9Z*nePP;?%ssBhc^J z<=N@o<K5wXS6F(6_eEiiE5aHVcr-q+GI45t<zNty=&b6g>R`FcEjU4ahW(1L4IwN1 zE^=F6;kLfOVqIj!z`&5q$iOgJLr{q9kShWOLXjy01H&&tkiTHr3mj}kAiry}7g>VB zK?FpARa=2r)*u2NSVcDIp~Qo1T9E?-0|O{DiwlqgDian`(lgxW_*~@Iyuz<ZUP#Gw z*7ejuL+XOG-UhK9A{+QFa@$|ww!gq)Ut~m4>H>$+Eq-|70;j9uA~R43fI_Iq0>nZO z0dVR76Ci0+kHh?pFNNqsQivTQiCmD;y(p}AMOg0wj~*zE=o67fKpto0nIt2{7zxf) z2B1u32g+2?e8j-Okit~Mh^Tl{m_Y?3M0O1eYIPFKkjGcTJh_lZLZp_l1XOZD)PZs% zYYH1UH?sRd!b=DdUa&+3DRAXMp=A#uK!K;pfj@cO;z`a)P0UM8iBCx^Nd)IijKl^` zUSPrroEsaE6B#V5@ujgKMo3^Ihqb|mk}KvOC&aFp2V4*iyeJ%aML6&RPar7ZgBU>} zk3G$CQ8UqjGiH?lC@UpGnnIZQQVbN5#OF(HB*Ti_85kIRKsgsBTV7(%f)rp<GtB4M zT;$id!mmMIwv_Iy?Wu)lOWh4@J6KlKUF5dA!fkhf#SUD8O-^L$vj-=PTdcYHc_kT| ztVN)fMv(@{U*G};Tupm1FfeFBi)4^gF;bB{c_*_Bt2YA!L-^!d%z83lbCW@}G&FTG z@W9%Czb31&Y~lqq2cc36SV7IK$-h_}m^m02Ca>p~n=H&Kv^kOWI3t@M$OZnB_1J^h zAWoRv#y&>?EQ)ZU|70T$t@<JzP|d&v_5ir00B&UzNq|hy1QA*wd5-*|l+>d5q{>^Y zX_-aE(3XTSq@ICT0a6RH;TCI2eoA6xQ3OaJ5=2CSh-i>8%*ly4w;*=KrzBPu7lnj_ zg+c25K`izHP|G*9xF{5)Ck#Y@R21ohqFNZy0)ezcASAeMEAj-X1raeIr7I@ea~82& z=aRlOc@w8L%XJCuOPlX;vNJLoZGOh}gNYZM(L;&?K$?Okzu|R<1(_wE3|l5hG-q-& zpRyl_sVM}>=OE7^MKH*{Xu(vJ0MeNVB0$abq8tz_8$^KX9I43{_+%YGl}QoUtR#>O z*rOmdw>a}s%j3cRF9x-xkvw;c6)ap-%)r3VxmlM#j*-!5@;*uD$>#+`Z9(Q0gPQBm zN}emVs3^ZEz92C@wWyqdfnfzGJU|Wg1_nrVY;%!Y;|jON1r`l(?Q&bU6e)qWgH$6W z&|91-iNzU7`H4j-MIE3%+GI_kL`HC}w0Vh80wbfzWL6PpEl7RK4GAcaW#9lVLe#ge zAit_JFfdGR6p=Orxf!el5)fS=OF<b1<Y#bn-r^`qP0uU_wP*Vn7#Q|XJ}a^w>}Scz z(?r+m^ny$SX(%cKX+`oqcTRqKerXA$Njiyvf#J;Ld@*aN)+1tj7)>TOid%St+XbLV zxW$%|nv+_RS~L-4B&e%ggxhdFh}w8)iB>d~fq~)DWEP1O7Ep_3aw3!1<R*z}@u13~ ziYqfOCA9)v=xMSRfwFNCI6G;B>;a`@aD|}B0?9(tL82gikdzMc8aynDCV(VC#BGpg zohHjmOHA&U)B}4e&>j?f7{R~}YPBaOmlVxpU|@I((gunYSPHPa$gOpSTk8Ug7B~e+ zPEMC9vjsUplLg(Spt1;7c!5+P7hXjm0Wk4$vXrzD*gejZCrAsaV|5dENosLPW^R67 zW@1j!90mr4cau*_%fN$f^M7eQMj3E*07?(HI0_Pri_7ziQZ$*0KmtYcCVR@NF;19V zAgj&>jz5#hb7iHR5Yd$f3Ma6Gp`i-V1`-8DbuntF_JG7e#HYzWW#_YlV$e_1Wb!;Y zM}heuDNs=hP8GN0CLfd&p3Ed~Q(pvXIKX;X3=FqeL5=g`B2d^Cf#Ve1)C4!tL6zGr zft0Moy!3p%lq9{}{FKz3;v!I=7*cA0+A6oWp$aleN(zdkKqVj#RHU>dGp86*+<<yk z;O1C8xTOHD`-(u72Bgpfl?vdT4$h!Op!`w<O8MaA2}wMlQ~-`BaJUzNe7%wZT-ktg z+b<5A-29Z%oK(A_RSXOapzKuK!^FVwftit!@dks#1t^-#uMi&La)E&abb}%K0&!^a zECsd6ClyRmKd^{0ntfn^6M7tsHXj(^ga`+t10#qJCq>|LU{zQZ*n@OH2{8sHfk}!X Nj5d=)6?cKt9{`5>v9tgH delta 2126 zcmZ3GJlTbBIWI340|Ns?f__EXd$Eap5{y0*)x+x<8B$nN*mHz(g`<RXMWRF)8B!Qh zIC4aD#iGQ(a-2DQx#CgcU~#S-i71H_h7|4`$y~`ONw64Cj#RF6lr)&ln<JAe8zsxg zkjkCH*TS%jfq`K)$WAbhl1t@I;YSm#XNZzd<xUYm6K04~ND*vdh*C`DP7%V8Q%VtT zVTe*r5ouwFQc2}b5yeoUnj+T15T%wP-og;2o+8o05T%hK*}@Q|nIhG~5T%vE70jS1 z{gQ!!Ve$sXY)0nEGE9<8noN@em{bKd8E-K=mZfVl-eL_X%}dVko4kt2bn-pHM%!B~ zm8pqEw^(!Y^GY%_S&Kv&7#MCb=jE3du`n<&6iI*xNd^W6O{QDyMX80Qsl_ElQVa|X z#Y`ZJT-o|2&li$rm1SUH;G4W(NRR0=!{qlul8lcga|&<b<phTjn8;$CJdsa)@@ruS zM$XCcN}`ilMFcm;i5zESQv_L|G+A3Lhz(-f<Yuus0$@>)W5Bi*DNWWF*V4PiT9lZV zo_dQ5>{>9pNEoDD2;^$^{G_bZ<dWiBY-yP}C8<S|>%=ANr9sjVb3rVSvA0-D@>3Ek zi?l%kIv_$9MCgIcU`|fVff^s5l2}<>qz)DZDOUoq*b6|xms(t;0n(xgBDBEb$@zID zsTC!~Am=C`fGmtzBm+__4kJLyiWg1RmndSqGI^<lHsh7eS0vaO8Ra(Lk^I5LcZ(&! zKR6_$NExJFb@D?QcUUm#$;z-ff<#>=2goW1ftZ>?x7c!1OEU6Pia_22M<F!SKng)& zQ)B{SnSuy25Md4?oIr#Nh;RmZfu%UHEVW2v@<CZy2XLr?4YL5rgFOpY#F>{`9uE$K zVm1Z_28i##e!ImA7B2E-U|?|AEGHMo$S5~?frj(s1M;G_AoGeDK^h=xxl)UY@{8gN z64O(Q0vQ+>Vn8Vh<j@9&yWD~k)MwaS<kq;tt#N@xqeyP@Lr%%b+6sqs{lV$52xM4M zB1i`)4Js%=jO0v7EY3*EPb^9)N@8GOh@UK_n8*m$yLqZ&0wbgS<ZnvO^|x5k@{4jc zxr^LE{^AD__8`x5WERJlCFW$N6nTKSJjpq!iFv6h@hOQViMN>3Q%j0K<;*Si;?m^g z)Z$`D=3oZ7hXvxEbdXWt5K95M43v35fdg?HM^S2eW^qYs5nE9XNOtmi<@Mmuk(^wi zvQ{S>q!*;4C;%jj6i(bZ`RVzkCGlmMspUll3=9knlLJ+)p<0)z?qRf_oUCTy4fYJk z@>^^vsX3`7sYUr9BSB6s!fiMoL~VRxa&mrYUP)0g0|P_b<Y#IrjB=CD2}({*QJ)qM z@>UgBW?o8ag<eKUZjL5v5f8{{P<pz>oS2hSBmm+fheRnz0Hm+T7UUa{zu+NJln0Uo z5&a-Jr^$?35|axx^uRs}v<F2nMi{VzvQ}bpNl^s@1H(*^Hspk2cadA`3b)n;7A<H( z@zgA{1vx>J1>w@7GLW@kM>0X83#0;Egh7)}5l8?`%$@v4(+KPy=gCD{Lh4xE#9fkF zT#}iapO=}KQ&i2sz_4iYYAqQ^xNUx@rN<}(N>xRmq;QL)AhEc(JijPKlL;(PR6AK) zM~yLWa*&QX8#w0dC)evpIUyp-4enZK;sTjdR0|RXMRGA}kfwpeLBz7jw{_;T$$=83 z_T)xgNA5b13<rqFpL|v~r2ZBwDDf8;fs;Kb-fjt`WF_XM=j){;>E-69q~;VC34)Y^ z0=P&Y!~&I5x45CIGD=DcibTNq11eHll9^KsDR4klKoPin1C;>aTn)~M;1mx|yY}D| z21x>-xC93`IP{7@&R@w;1adn#$Nb{3$<0qG%}KQ@>SSPG0Og2c{>eQ0Sti;S7;vH+ o3}zRwp~>g;)!6wPz;N;>eKY0<jQo>(4MG^rCO<OR#R9Sw0JdoCSpWb4 diff --git a/postgresTest/PROJECT1/admin.py b/postgresTest/PROJECT1/admin.py index ee1f6dfb..5acdc6d4 100644 --- a/postgresTest/PROJECT1/admin.py +++ b/postgresTest/PROJECT1/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import Job, CustomUser, JobRating, CartItem +from .models import Job, CustomUser, JobRating, CartItem,Forecast, Sale, Account from django.contrib.auth.models import User # Register your models here. @@ -7,5 +7,7 @@ admin.site.register(Job) admin.site.register(CustomUser) admin.site.register(JobRating) admin.site.register(CartItem) - +admin.site.register(Forecast) +admin.site.register(Sale) +admin.site.register(Account) superusers = CustomUser.objects.filter(is_superuser=True) diff --git a/postgresTest/PROJECT1/forms.py b/postgresTest/PROJECT1/forms.py index a7405668..f0d7e4c5 100644 --- a/postgresTest/PROJECT1/forms.py +++ b/postgresTest/PROJECT1/forms.py @@ -1,14 +1,61 @@ from django import forms from django.contrib.auth.forms import UserCreationForm from django.contrib.auth import get_user_model -from django import forms -from .models import Contact +from .models import Contact, Forecast, Sale, Account +import datetime + +class ForecastForm(forms.ModelForm): + MONTH_CHOICES = [ + ('Jan', 'January'), ('Feb', 'February'), ('Mar', 'March'), ('Apr', 'April'), + ('May', 'May'), ('Jun', 'June'), ('Jul', 'July'), ('Aug', 'August'), + ('Sep', 'September'), ('Oct', 'October'), ('Nov', 'November'), ('Dec', 'December') + ] + + month = forms.ChoiceField(choices=MONTH_CHOICES) + year = forms.IntegerField(min_value=datetime.datetime.now().year, initial=datetime.datetime.now().year) + + class Meta: + model = Forecast + fields = ['month', 'year', 'value'] + + def clean_year(self): + year = self.cleaned_data.get('year') + if year <= 2023: + raise forms.ValidationError("Year must be higher than 2023.") + return year + +class SaleForm(forms.ModelForm): + QUARTER_CHOICES = [ + ('Q1', 'First Quarter'), + ('Q2', 'Second Quarter'), + ('Q3', 'Third Quarter'), + ('Q4', 'Fourth Quarter'), + ] + + quarter = forms.ChoiceField(choices=QUARTER_CHOICES) + year = forms.IntegerField(min_value=2015, max_value=datetime.datetime.now().year) + value = forms.DecimalField(widget=forms.NumberInput(attrs={'step': '0.01'})) + + class Meta: + model = Sale + fields = ['quarter', 'year', 'value'] + + def clean_year(self): + year = self.cleaned_data.get('year') + current_year = datetime.datetime.now().year + if year < 2015 or year > current_year: + raise forms.ValidationError(f"Year must be between 2015 and {current_year}.") + return year + +class AccountForm(forms.ModelForm): + class Meta: + model = Account + fields = ['category', 'value'] class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = get_user_model() fields = UserCreationForm.Meta.fields - class AddToCartForm(forms.Form): quantity = forms.IntegerField(min_value=1, initial=0) @@ -22,4 +69,4 @@ class ContactForm(forms.ModelForm): 'phone': forms.TextInput(attrs={'placeholder': 'Phone Number', 'required': True, 'class': 'form-control'}), 'email': forms.EmailInput(attrs={'placeholder': 'Email', 'required': True, 'class': 'form-control'}), 'message': forms.Textarea(attrs={'placeholder': 'Message', 'required': True, 'class': 'form-control message-box'}), - } \ No newline at end of file + } diff --git a/postgresTest/PROJECT1/migrations/0014_account_forecast_sale.py b/postgresTest/PROJECT1/migrations/0014_account_forecast_sale.py new file mode 100644 index 00000000..41ecd26e --- /dev/null +++ b/postgresTest/PROJECT1/migrations/0014_account_forecast_sale.py @@ -0,0 +1,39 @@ +# Generated by Django 5.0.6 on 2024-06-24 02:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('PROJECT1', '0013_punch_total_time'), + ] + + operations = [ + migrations.CreateModel( + name='Account', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('category', models.CharField(max_length=20)), + ('value', models.FloatField()), + ], + ), + migrations.CreateModel( + name='Forecast', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('month', models.CharField(max_length=3)), + ('year', models.IntegerField()), + ('value', models.FloatField()), + ], + ), + migrations.CreateModel( + name='Sale', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quarter', models.CharField(max_length=2)), + ('year', models.IntegerField()), + ('value', models.FloatField()), + ], + ), + ] diff --git a/postgresTest/PROJECT1/migrations/__pycache__/0014_account_forecast_sale.cpython-311.pyc b/postgresTest/PROJECT1/migrations/__pycache__/0014_account_forecast_sale.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d269fe63ff467a70b84219159e8fcb126aa0c89 GIT binary patch literal 1809 zcmZ3^%ge>Uz`$U1vmz~$m4V?ghy%l{P{wB)1_p-d3@HpLj5!Rsj8TlaOi@gX3``8} z3@J=43@Oa1j9JW3wG7Lc85mZ>c~Q(MEWr$#tS>>*noPI2ax>G55=%1k^NMe=<>sfP z<`gG`q+pl_%J|H|1hO)fA&N1DA&M!5F`Y4rnTa8lB@5;#h7_h0kO*5AJ5&!t3QG!0 z3Tq168un!@3=FGTVB%>^DI81;sccysFp(6_HC)RW85mYG!bH-TQn<ltIAJ2o7#J8< z!#E6SOzF&Pc$P6SFsx>R38J}&mjw6lf$c)LhaZc31i)&*(F3v(-8}@|%R<1tf+V<C z2<#Swdxh!Y-gM?D?i7(=22IghoW8JhqserOBOu7%%hfr=@Rq27fuV7HL1|ucMtn(r zNn%cXNoH>9Eq2G`<owdSl3PrfDIspRm^@uHS#I$pmX_qlCl{qAmZYZK;w~u4%uOt+ zjL%N3yv13ZT9lcXlUbE|i>EBLC@H@<H9jvfH}w`ra$-qpdVW#mOA!VJ22I9WT)BxA z@j0n^=_MJrSj!S~N>eqNZn1#XvZZCF=A;zg;&96^N=;5IF1f{;o1a&b@e-67Zn0FR zCKlad2~NyOy~SQwnpjklTJ#c>lKeDzZgIqet&5Mp#T6f)o1apelNuj?izhz5urx6T zWH^YIl3I|Omy(*7oS9l&1U8e~8SEKfP&O(8rS@AqPMPVBr6u`pAgA2obk0aDf-t$< za`F>PAZ#Abypq)PRG3VDK`Jyyu4MQON@%}UI$Onr7N-^!gUJ||)Z*-t{DPRU%$%G= z=lq<U)b!Mt;L75X)LaFZ)Uwo^{DR!nyb^^_H)l8VU|nMaU85Ms;^NHoJg~4wh_8== zbAC!{jAKq_ykBBcMq*yPk+Ff9p|PQ9OhJBeNqSLgaY$-$NenDrV-Tf8jDdlnNqizC zKI7A%K^tG3n3JkkP+7#rz`y_|K#byPj0_A7aQK0Zfm81TGm{8ggU<&p22S}7t}7gJ zHw2{~2#Q`1*P2jvMO<qK%L$bWQSle@iY|y3UlcFCB3^t!pyY<2^aWYn8DUpsb$19| zkhQreYjZ``=7NCj4MB+uQra`ru1INLl+wK-rF%g@?*luF2;T=*c22I34D6g-UqHkM z0fcqZL|7+rK}ri`s@8_Y3sM#rr7W&USzHjXydfxlK~iUi*cC~gi;{X*B=s%`=wo#P zCo9Ma93UrffSka=$@M`9;RJCaoFH{UMrVfG6&al!j2C3AF3MP4k+HfUU`>$|RHcR3 z8oWTTNCOs8ewr+|I8(9`^V0M6Qj)+48Ju>(u~?)IQU+G5$-uzyi^B$z8|;d-85kHq yg>`Wl0|UbcW=2NF4{QvKnim)}FwqA#MMky{44A|Ot}6m6A3+jdKm?i+up0pxHqXxh literal 0 HcmV?d00001 diff --git a/postgresTest/PROJECT1/models.py b/postgresTest/PROJECT1/models.py index 5dbe3b22..fac442d2 100644 --- a/postgresTest/PROJECT1/models.py +++ b/postgresTest/PROJECT1/models.py @@ -16,6 +16,29 @@ class Punch(models.Model): def __str__(self): return f"{self.user} - {self.date}" +class Forecast(models.Model): + month = models.CharField(max_length=3) + year = models.IntegerField() + value = models.FloatField() + + def __str__(self): + return f"{self.month} {self.year} - {self.value}" + +class Sale(models.Model): + quarter = models.CharField(max_length=2) + year = models.IntegerField() + value = models.FloatField() + + def __str__(self): + return f"{self.quarter} {self.year} - {self.value}" + +class Account(models.Model): + category = models.CharField(max_length=20) + value = models.FloatField() + + def __str__(self): + return f"{self.category} - {self.value}" + class Job(models.Model): name = models.CharField(max_length=100) img = models.ImageField(upload_to='pics') diff --git a/postgresTest/PROJECT1/templates/add_account.html b/postgresTest/PROJECT1/templates/add_account.html new file mode 100644 index 00000000..32e22324 --- /dev/null +++ b/postgresTest/PROJECT1/templates/add_account.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} +<div class="container mt-4"> + <h2>Add Account</h2> + <form method="post"> + {% csrf_token %} + {{ form.as_p }} + <button type="submit" class="btn btn-primary">Add Account</button> + </form> +</div> +{% endblock %} diff --git a/postgresTest/PROJECT1/templates/add_forecast.html b/postgresTest/PROJECT1/templates/add_forecast.html new file mode 100644 index 00000000..14e246d4 --- /dev/null +++ b/postgresTest/PROJECT1/templates/add_forecast.html @@ -0,0 +1,12 @@ +<!-- add_forecast.html --> +{% extends 'base.html' %} +{% block content %} +<div class="container"> + <h2>Add Forecast</h2> + <form method="post"> + {% csrf_token %} + {{ form.as_p }} + <button type="submit" class="btn btn-primary">Add</button> + </form> +</div> +{% endblock %} \ No newline at end of file diff --git a/postgresTest/PROJECT1/templates/add_sale.html b/postgresTest/PROJECT1/templates/add_sale.html new file mode 100644 index 00000000..0338c23d --- /dev/null +++ b/postgresTest/PROJECT1/templates/add_sale.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% block content %} +<div class="container"> + <h2>Add Sale</h2> + <form method="post"> + {% csrf_token %} + {{ form.as_p }} + <button type="submit" class="btn btn-primary">Add Sale</button> + </form> +</div> +{% endblock %} diff --git a/postgresTest/PROJECT1/templates/base.html b/postgresTest/PROJECT1/templates/base.html index b1fa9979..5b19a8d7 100644 --- a/postgresTest/PROJECT1/templates/base.html +++ b/postgresTest/PROJECT1/templates/base.html @@ -94,7 +94,7 @@ </a> <a href="{% url 'redirect_to_current_month' %}" class="list-group-item list-group-item-action bg-light"> <i class="fa fa-calendar" aria-hidden="true"></i> Calendar - </a> + </a> <a href="{% url 'job' %}" class="list-group-item list-group-item-action bg-light"> <i class="fa fa-briefcase" aria-hidden="true"></i> Jobs </a> @@ -107,6 +107,12 @@ <a href="#" class="list-group-item list-group-item-action bg-light"> <i class="fa fa-file-text" aria-hidden="true"></i> Reports </a> + <a href="{% url 'inventory' %}" class="list-group-item list-group-item-action bg-light"> + <i class="fa fa-clipboard-list" aria-hidden="true"></i> Inventory + </a> + <a href="#" class="list-group-item list-group-item-action bg-light"> + <i class="fa fa-user" aria-hidden="true"></i> Employee + </a> </div> </div> diff --git a/postgresTest/PROJECT1/templates/dashboard.html b/postgresTest/PROJECT1/templates/dashboard.html index b74840b6..f57e92fe 100644 --- a/postgresTest/PROJECT1/templates/dashboard.html +++ b/postgresTest/PROJECT1/templates/dashboard.html @@ -1,5 +1,3 @@ -<!-- dashboard.html --> - {% extends 'base.html' %} {% block content %} @@ -93,4 +91,4 @@ }); }); </script> -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/postgresTest/PROJECT1/templates/inventory.html b/postgresTest/PROJECT1/templates/inventory.html new file mode 100644 index 00000000..480f7341 --- /dev/null +++ b/postgresTest/PROJECT1/templates/inventory.html @@ -0,0 +1,216 @@ +{% extends 'base.html' %} + +{% block content %} +<div class="container mt-4"> + <h2>Inventory Dashboard</h2> + <div class="row mb-4"> + <!-- Links to Add Data --> + <div class="col-md-4"> + <a href="{% url 'add_forecast' %}" class="btn btn-primary btn-block">Add Forecast</a> + </div> + <div class="col-md-4"> + <a href="{% url 'add_sale' %}" class="btn btn-primary btn-block">Add Sale</a> + </div> + <div class="col-md-4"> + <a href="{% url 'add_account' %}" class="btn btn-primary btn-block">Add Account</a> + </div> + </div> + <div class="row"> + <!-- Forecast Year Selector --> + <div class="col-md-6"> + <div class="form-group mt-4"> + <label for="forecast_year">Select Forecast Year</label> + <select class="form-control" id="forecast_year" name="forecast_year" onchange="updateForecastGraph()"> + {% for y in forecast_year_range %} + <option value="{{ y }}" {% if y == forecast_year %}selected{% endif %}>{{ y }}</option> + {% endfor %} + </select> + </div> + <!-- Forecast Graph --> + <div class="card mb-4"> + <div class="card-header"> + Forecast for {{ forecast_year }} + </div> + <div class="card-body"> + <canvas id="forecastChart"></canvas> + </div> + </div> + </div> + <!-- Sales Year Selector --> + <div class="col-md-6"> + <div class="form-group mt-4"> + <label for="sales_year">Select Sales Year</label> + <select class="form-control" id="sales_year" name="sales_year" onchange="updateSalesGraph()"> + {% for y in sales_year_range %} + <option value="{{ y }}" {% if y == sales_year %}selected{% endif %}>{{ y }}</option> + {% endfor %} + </select> + </div> + <!-- Sales Graph --> + <div class="card mb-4"> + <div class="card-header"> + Sales for {{ sales_year }} + </div> + <div class="card-body"> + <canvas id="salesChart"></canvas> + </div> + </div> + </div> + <!-- Account Graphs --> + <div class="col-md-6"> + <div class="card mb-4"> + <div class="card-header"> + Account Graphs + </div> + <div class="card-body"> + <canvas id="accountChart1"></canvas> + </div> + </div> + <div class="card mb-4"> + <div class="card-header"> + Account Graphs + </div> + <div class="card-body"> + <canvas id="accountChart2"></canvas> + </div> + </div> + </div> + <!-- Barcode Generator --> + <div class="col-md-6"> + <div class="card mb-4"> + <div class="card-header"> + Barcode Generator + </div> + <div class="card-body"> + <input type="text" id="barcodeValue" class="form-control" placeholder="Enter value for barcode"> + <button id="generateBarcode" class="btn btn-primary mt-2">Generate Barcode</button> + <svg id="barcode"></svg> + </div> + </div> + </div> + </div> +</div> + +<!-- Chart.js --> +<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> +<!-- JsBarcode --> +<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script> +<script> + document.addEventListener("DOMContentLoaded", function() { + // Initial data + var forecastLabels = {{ forecast_labels|safe }}; + var forecastData = {{ forecast_data|safe }}; + var salesLabels = {{ sales_labels|safe }}; + var salesData = {{ sales_data|safe }}; + var accountLabels = {{ account_labels|safe }}; + var accountData = {{ account_data|safe }}; + + // Forecast Chart + var forecastCtx = document.getElementById('forecastChart').getContext('2d'); + var forecastChart = new Chart(forecastCtx, { + type: 'line', + data: { + labels: forecastLabels, + datasets: [{ + label: 'Forecast', + data: forecastData, + backgroundColor: 'rgba(54, 162, 235, 0.2)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1 + }] + }, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + }); + + // Sales Chart + var salesCtx = document.getElementById('salesChart').getContext('2d'); + var salesChart = new Chart(salesCtx, { + type: 'bar', + data: { + labels: salesLabels, + datasets: [{ + label: 'Sales', + data: salesData, + backgroundColor: 'rgba(75, 192, 192, 0.2)', + borderColor: 'rgba(75, 192, 192, 1)', + borderWidth: 1 + }] + }, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + }); + + // Account Graph 1 + var accountCtx1 = document.getElementById('accountChart1').getContext('2d'); + var accountChart1 = new Chart(accountCtx1, { + type: 'pie', + data: { + labels: accountLabels.slice(0, 2), // Assume first two categories are for account 1 + datasets: [{ + label: 'Accounts', + data: accountData.slice(0, 2), + backgroundColor: ['rgba(255, 99, 132, 0.2)', 'rgba(255, 206, 86, 0.2)'], + borderColor: ['rgba(255, 99, 132, 1)', 'rgba(255, 206, 86, 1)'], + borderWidth: 1 + }] + }, + options: { + responsive: true + } + }); + + // Account Graph 2 + var accountCtx2 = document.getElementById('accountChart2').getContext('2d'); + var accountChart2 = new Chart(accountCtx2, { + type: 'doughnut', + data: { + labels: accountLabels.slice(2), // Assume remaining categories are for account 2 + datasets: [{ + label: 'Accounts', + data: accountData.slice(2), + backgroundColor: ['rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)'], + borderColor: ['rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)'], + borderWidth: 1 + }] + }, + options: { + responsive: true + } + }); + + // Barcode Generator + document.getElementById('generateBarcode').addEventListener('click', function() { + var value = document.getElementById('barcodeValue').value; + JsBarcode("#barcode", value, { + format: "CODE39", + lineColor: "#000", + width: 2, + height: 100, + displayValue: true + }); + }); + + // Functions to update the graphs + function updateForecastGraph() { + var selectedYear = document.getElementById('forecast_year').value; + window.location.href = '?forecast_year=' + selectedYear + '&sales_year=' + document.getElementById('sales_year').value; + } + + function updateSalesGraph() { + var selectedYear = document.getElementById('sales_year').value; + window.location.href = '?forecast_year=' + document.getElementById('forecast_year').value + '&sales_year=' + selectedYear; + } + }); +</script> +{% endblock %} diff --git a/postgresTest/PROJECT1/urls.py b/postgresTest/PROJECT1/urls.py index 052d2f77..77aece4f 100644 --- a/postgresTest/PROJECT1/urls.py +++ b/postgresTest/PROJECT1/urls.py @@ -19,7 +19,11 @@ urlpatterns = [ path('error/', views.error_page, name='error'), path('calendar/<int:year>/<int:month>/', views.calendar_view, name='calendar_view'), path('calendar/', views.redirect_to_current_month, name='redirect_to_current_month'), - path('punch/', views.punch, name='punch') + path('punch/', views.punch, name='punch'), + path('inventory/', views.inventory_view, name='inventory'), + path('add_forecast/', views.add_forecast, name='add_forecast'), + path('add_sale/', views.add_sale, name='add_sale'), + path('add_account/', views.add_account, name='add_account') ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/postgresTest/PROJECT1/views.py b/postgresTest/PROJECT1/views.py index 78f6b33d..d91a351b 100644 --- a/postgresTest/PROJECT1/views.py +++ b/postgresTest/PROJECT1/views.py @@ -2,15 +2,88 @@ from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout from django.contrib.auth.decorators import login_required from django.contrib import messages -from .models import Job, JobRating, Contact -from .forms import CustomUserCreationForm, ContactForm +from .models import Job, JobRating, Contact, Forecast, Sale, Account +from .forms import CustomUserCreationForm, ContactForm, ForecastForm, SaleForm, AccountForm from django.db.models import Avg from .models import Punch -import calendar from datetime import datetime from django.http import JsonResponse from django.utils import timezone +def inventory_view(request): + forecast_year = request.GET.get('forecast_year', datetime.now().year) + sales_year = request.GET.get('sales_year', datetime.now().year) + + forecasts = Forecast.objects.filter(year=forecast_year) + sales = Sale.objects.filter(year=sales_year) + accounts = Account.objects.all() + + forecast_year_range = range(2023, 2032) # Year range for forecasts + sales_year_range = range(2015, 2026) # Year range for sales + + context = { + 'forecasts': forecasts, + 'sales': sales, + 'accounts': accounts, + 'forecast_year': int(forecast_year), + 'sales_year': int(sales_year), + 'forecast_year_range': forecast_year_range, + 'sales_year_range': sales_year_range, + } + + return render(request, 'inventory.html', context) + +def add_sale(request): + if request.method == 'POST': + form = SaleForm(request.POST) + if form.is_valid(): + form.save() + return redirect('inventory') + else: + form = SaleForm() + return render(request, 'add_sale.html', {'form': form}) + +def add_forecast(request): + if request.method == 'POST': + form = ForecastForm(request.POST) + if form.is_valid(): + form.save() + return redirect('inventory') + else: + form = ForecastForm() + return render(request, 'add_forecast.html', {'form': form}) + +def add_sale(request): + if request.method == 'POST': + form = SaleForm(request.POST) + if form.is_valid(): + form.save() + return redirect('inventory_sales') + else: + form = SaleForm() + return render(request, 'add_sale.html', {'form': form}) + +def add_forecast(request): + if request.method == 'POST': + form = ForecastForm(request.POST) + if form.is_valid(): + form.save() + return redirect('inventory_forecast', year=form.cleaned_data['year']) + else: + form = ForecastForm() + return render(request, 'add_forecast.html', {'form': form}) + +def add_account(request): + if request.method == 'POST': + form = AccountForm(request.POST) + if form.is_valid(): + form.save() + return redirect('inventory') + else: + form = AccountForm() + return render(request, 'add_account.html', {'form': form}) + + @login_required def redirect_to_current_month(request): now = timezone.now() @@ -88,6 +161,9 @@ def punch(request): return JsonResponse({"error": "Invalid request"}, status=400) + + + #error.html page def error_page(request): return render(request, 'error.html') -- GitLab