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