From 40404a2947d7e6bfaa6a228116d063631ade1438 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 6 Feb 2026 07:47:17 +0000 Subject: [PATCH] Autosave: 20260206-074716 --- core/__pycache__/admin.cpython-311.pyc | Bin 7316 -> 7770 bytes core/__pycache__/forms.cpython-311.pyc | Bin 0 -> 1603 bytes core/__pycache__/models.cpython-311.pyc | Bin 42146 -> 45442 bytes core/__pycache__/urls.cpython-311.pyc | Bin 12281 -> 12847 bytes core/__pycache__/views.cpython-311.pyc | Bin 148418 -> 157098 bytes core/admin.py | 8 +- core/forms.py | 20 +++ ...vice_device_type_cashiercounterregistry.py | 34 ++++ core/migrations/0028_cashiersession.py | 30 ++++ ...ype_cashiercounterregistry.cpython-311.pyc | Bin 0 -> 2362 bytes .../0028_cashiersession.cpython-311.pyc | Bin 0 -> 2584 bytes core/models.py | 30 ++++ core/templates/base.html | 14 +- core/templates/core/cashier_registry.html | 119 +++++++++++++ core/templates/core/cashier_sessions.html | 55 ++++++ core/templates/core/index.html | 11 +- core/templates/core/pos.html | 5 + core/templates/core/session_close.html | 58 +++++++ core/templates/core/session_detail.html | 89 ++++++++++ core/templates/core/session_start.html | 33 ++++ core/templates/core/settings.html | 2 + core/urls.py | 7 + core/views.py | 160 +++++++++++++++++- 23 files changed, 667 insertions(+), 8 deletions(-) create mode 100644 core/__pycache__/forms.cpython-311.pyc create mode 100644 core/forms.py create mode 100644 core/migrations/0027_alter_device_device_type_cashiercounterregistry.py create mode 100644 core/migrations/0028_cashiersession.py create mode 100644 core/migrations/__pycache__/0027_alter_device_device_type_cashiercounterregistry.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0028_cashiersession.cpython-311.pyc create mode 100644 core/templates/core/cashier_registry.html create mode 100644 core/templates/core/cashier_sessions.html create mode 100644 core/templates/core/session_close.html create mode 100644 core/templates/core/session_detail.html create mode 100644 core/templates/core/session_start.html diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index c5c0f96bc06cbacee968befb2cd15041619e8026..6cacbdfe0a0c9cd2bd923a0523b5a654095d7cdd 100644 GIT binary patch literal 7770 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 F-Cv}3;8Oqq diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70c5bef3a7e031952e8ada454e83548ec4807099 GIT binary patch literal 1603 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 WdSX6;<-Q=RFqz!FL1(i3#$*77h`-+e diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index ae045be27491ce086e92c87c8302a0601d13d7f9..27570f7ef530a7aa002472981d46cf4bc2f9244a 100644 GIT binary patch delta 1520 zcmZ{kUu;uV9LM|TH%2$t4ut(_>AH1mZ(G`3%|vR4!jdr@lQBxhVz*iAc7@AoJMQgb zoWaf*ViSqka+S;n5_p+QFfzi6Jn;aDCM0k!9u=!G_~5^{YoZS(Mm^_u+h&P+n)~Um z-{1HAe&?KfZ~sVNoppZL)YM>MqyB?)@?_77v(5V5HNorB#;kR&dy@UM%#(b~l9i=a zm(HZqrog28T>6|zb2W)_=?f-hYtolY3V+3HEm|zky|9H$0f$Wv1Jf_s~Z}L_9!XK!*Ve0|sv0=-9lJ z{bcBQ0x2C*6jDafhZTA@^$)Et5=iKfppY;Em=0D7cvi=$_i++`mcXzM!xV-MbF-m} z!MnOZeSIWxn81h*BNRrAFjk0E41r4vRCt;Uo**!x!vxhH_5eHaAA0z?*9AHmgUCYx zpLq|S(8i+ewmnJh?LY_1u3`35FAo3LQ z9puMI9r+uwHN>3>Ps>ln-8)3exZ!rD~*%jgb!3fu1 zMwU>yg1n3THPU6Cz`QmWaXZe~@E{eNmJ{4tRr6Ot+lYAV3$~>8`fgt9BJw8k``x?; zL^%cI;VAcHk?*2%4N0SXZ@))7>#;@3u08B+w@3QZZiREb^(wYREJRtqsFx9c%fRvy?T)D5;yV$hIAOBFl3}n$BX}V?5kQbrsbuoBXTKoU{&xBLS;IYppJ^QUyP%5mB&N zlsZ%^Z^SM_oh(?ep`cyF#YK?j0=KA>P;ii9bSMZGe4qbSOvsOi_xZmcd2@MH{(Y|V zMIhjF@z>4jy{WhAc+eU; zW=VynRIsH&%Zt9x>F=Ab)Ml2(Eh*oW^0t(3`At?&$b6p$+)T*r$ak|`G9v6TSvslk zZV_Hi_VRiTE+=EW{)q8SjO^;CWCoVtm43=RLcIc;82JfzYqXl7(X8WeT2p!b1g^m^ zS|13p?l7E$58yIvz+W(wqU1q14)4O}@ICyNqJ2FBl+ed2_`$QtInN`vK2ilj`5+FIxV}d)8SjNJH0b;QecO(5%B^~jixDeCrznm z@ZG=E4JTFMskRLDHCTX`GBocYtV0{)Td*ff-9zwfmcHZ+T+H^x@zb6W@hn(gd7)y* z4y?ugKPwZW$u=;vV~|!EfJJx}GWZ&Pf`4Gl*tvuwY~6^6!;;C$1|9r9Tr%h&A5edX YfgEjM$JQeJ6sTLIh)y8DJorcP1z?IA}#tQNgEu z*rE+83Kd&yTI1GM`?G3Y6FN#9i-OgvZMC6l-R=K;&wI0ECQ$qP|39Dqe8}OxbI-l^ z+;h)4_uTvLd+&GG$N%)j_>>2dlM|xo_vF5v&RI|FP03N#BtAU+65(l@Uo&4s*`w^D zaY4-j`aiXCVbh|TMT|>pT->yzW(lX$8<#dMt69eBjK<|n)iu>dx$|nya}2j;a|-P!e&KaR}wZmfGzYBpHJwV0NRgTrP`Ft#j7bVFCy;(d;YaiH5XFekchmC z2s<M9r@5?Z&UdCmws)lfqn!6~^ z9)Z1^u#O1qPt=0=(xIJ{w=p8`fMYn}H$gUu_t>4}Mee2R&1z?Sre{k8^+C#OjKJPc z*ro{V1B7jkz#bxOO9b{XVOztoO3hDITSBJiLCTcjnKehq9l9d0582(+g`ZK0wuro+ z6LxC^_9$U5kH9|6Dsu(!sy8}c{6g&^PP&M;J%aX^guOBX`zyQI-qH9-Q+G{w)1x(y ziYTJm9zpdOVXun7K2BIq1onv`gx(Q>e$p;hMO9qgr6lGGF{EoqQjN&*WzDT~ZE`x~ z+?KXxw?m%q*ywb*DL> zQ^_@EOZ8{geD%kvS?YJ^S=1D3w))#Cmb8H+QBm6y)RQTT)LX12rbKs)CQgY=^{tXj zr6W;2X+2evv@vRXGX164)2@x`NSYTmr*F5oOSD-Rh`h1$qSkNNZtX~P=Nqlle;w8% z$@dG20q9TvwbOswQ#+D7)6}c;GL()~wcnnleUvDyTGb;WB}PPbr099k9hS}v5Scns z?OJP$7^=RImK+=35!VsZk)XZ$kjPRxlGRVsO0|nt2}_PWbAQ72H1`;POVoOlJ*y*4 zot3^?%uw%0zerT8e^1X~-7Z#YiUwYrV`RYe2IWV4eEctkUxJNL~WEczd1OQEPWLxP8JY!J;p= zp@p>J3b!j=JMe_a%9bmEH9MQ_jw|F=N*B|gYo}V5-8CU2|Msfm=@rM)D;{0hlU~uA zUgb@%+Oe!JtN3`<@MBrSd$UG(vqtPVuP?W>v%d4P&U$ZdMOQ`6dJ)r?KcX+UOx=}R zP@I`)iRq6buw&t8IZ;Vzd&+zAM;+SOn>fjvIH@Okl3b;Y^@!ZAQ@InO#XL2upf+tL zvG8F50lAPsMYOC^uP+!bW~)aF8bphlQD~b|OBp^>U1OtkfX>dB3+JzvTX5L`kO2Tu z%X$DFph;?DVMRqVUHg(-WsAM7!R@MTgk5xiW;;L&z>NSmslO>4l6f7H*8}VVxB;L| z{YPPTCW|iK*}T=!>~4|U3S- zmll)RUBHMVw~B02{E0A}XXp4^=qOzPHD8m^z|6%w(gn9g5wuKW2NJyWC%xZPMBiH?T_b zfT`6ohKLReUy9-URykZQXG^m$rmn&5-0C>2_@dif4(W?=x$E3*E?*j~vYy;yZ5GQ(wEHFwFZHtF^pPWp~%_v zzc1eDsx=xFa=*HN*vOpygs+H^P$*w~LmRn;CWmy%>(#f1<$8Q6I<>#H_T+{Z=@`@6 z;;P)_ZfdN^@WnK>*d2{7c?Xr3FaTZ8_n|uT2B&nneX*PBTy<`@lv99=y}V8~6Qe#+ zE3Kd(0n2hkKA>qqr9- zjH_%T;EE?;^Z#_`Vxm6CBZU6}2(BR~z9Z^nbXm`Uf1a|FnI+!Lk;gN~AIlv7XzY_o z&#&pp9N(LHp*QowSmQRlUipy~(S4l2@O|7_zUnH)FInV{}jQ==UsHyFJG( z#m6kgy_R9>{iQFb_T>%lPmYDZB0&Dis$N}|E>?BjQFfbMzcb;KIsATnx!PJ=8!2LNh4B@{pP4WAjQ|*E7bcP&>N~@8 z)yKzIsfR`ukVD*iGkN)wBO3)xkjqEs#OU0rTSku$5oN%epIM4#U5bgVb=zRA1DTai zqIoj`7MiYrss0Ys`pd}Q5Jfjg?K+#=@3VKK2sN|aH6RsYX1=6A#bIL*#Pb;Z5(R$+!1l+gGBncm z2*h((2RVE_LyQA`e?L4<0J2h}C^W(7Q0NtmVuw^BS$Ygn>m} z(NrEn*JW<;GhAyplV>QqhyGlb5!exBSf5(+a+zwGI9IGvUwyex9XV;3=vG%u8o7!& zz~HcWWGqtC2v9W8jP!E=7(w;1kQntts_mJN_EaaVpQs>Vqx}cHs8e8h@E?;zgi+!8!ZFsy`c*Up(+h(#F0Mi7Q z_C>quwmL%ekEJ{e*`4Z>v&MMdMY0M2toTe69m#B59>-<;{3{w9t!|oBE7EjJjHW2F zPQC;R7U8Q%1>~rU?vKC)<;U`7IVi17zG$c0(Io$j+7q2_b@S|DVx@ZP>|FELgnF;* zq1i9TT=Xm|coE9`8XqMVXNO5EA!6)Og9$*;&8v=`%%{M4M7Ir5{cur1fYvuUc&?BCcC5BWU2Cx#S zh$9iMrHi0CqkB59!Crk%I9D72*cX1fjb+r??X>|rGbAFTNKvNHpKG?z9^Ngoy53q` z3By1A02%&@yKh!~&-RLE)t$?R=^alF={OG^TRTQW{uAINKtBOr422&K5;ua2@Qy^7 z}heL-x6=E_`{+U=Y9C8NH-3V6J z6D`dKi9_yM-C5t0SkaqUq3*uuJerRGbkT##IWYSQGkYG{Non#%TiWC)O0iz*6SDjh zU6XIrJ%IXnO@W8`V7ah_Fh~?~Q}AB9+11j_4x=JFq=!MpccSh;0~`nF1js_Ksww45 zXlr)*9ra0M*#KBH99%cxax9{0jzlEOiw&8D)`;vT0u>1%(-@egDFEET6S^d9M<3N7 z_ZBC$?5u0_$1vQ7!4=P8&m<;|!Iwj*_S@;tHCH{oKf6m=Hzwr^$(iipShLx2 zzk+68Rkv&|To`cQzBs$n#akD;BR>Wj?ohy+`?4Ebw$(Mdx7D_`I1!LZhuz_5a@ghT zYVYO+=f0039|FK+52r{o#K|odAXNwuXi)Zn(gs|Sx^l}^A^>0B-{D_{T^d zboQT*0UP4xammAZ5~))F?+`d_*30m4b5<_eMHVfFXz}E*f2Dr3WoQg@oT^$I3&d;c zn8wlKXxIA2p<-nxQOW}#H(lo5rdK?JE)U1*Dip}qy(m;j2AVjm$n#KCaXDQICE(W8 z7n>%Cg|{_3J*x%pr2tD|KVv~hp+VRD@>KYxj zPP;FzzRl%qre!U6|L_d?5h`Ql{1~Z!L`9Vus}~!tS--Q9;+c!x0c-YyYD!D#h3FQo zq}!x)G&hhI&}y1BLHE7;P>ww(CXtZ1qYRgw0H*=ieoB$zY3CF5hL)v?pW^x)faB`h zEjG^>jL%qraRhvpK%=g0P4z8}@*HGMKvr~P%f=R;sZBQOs>b5mjGBTnWTj(O>p=!< z9uM_VTn2r@XLNZuhb(p$q5p-vpwTc@Se0BG*UQQqVlL`$TC?VJ6DF$0XZ2f7z{psK zKSvYn1fZF;Ri)dNu95O9!nty=eV0GP2)1|;XzQA1Fj90! ztw>d`z9Y{H)0TFy$BK~##mFqy6(iGy$jKiDT)wH!?W${Sl~)n@bxa1R2VjL5i&R+0*&RHHj7|V{ z8~;XX3IO+#y^obHIc_HGbI1zgiMh{V_F+e1akJXHKg)bI^}nF&@B5edW!<9dvnx>f4>dw0m z4b%2X}J^q2biZWxR>L2;#_+- zU->!hFm&BlY`+dv%xX;d=7J4b%rtXk(qp1P0T+BEwWaH_HNcO5OW_7;bvekp|}r*1;8(0tf{g)m`6vb%|L zmHOTN8)(pKU#3C3>VbDm<5=@CN%%raG`BU?(_;P=G|NiG^N)f{o4WVGat|vl%#FC_ zVZQ}z1ZSyRafyw9&^-kdKM8OO;2i=KFf;$GuACK!Ij}tqQ}QJRrRlUU(7m`P5Twb! zp)Ph{*1;VZ@@)VtPL?j)E}Jb+*bhQFq5GezudCR62QhtPm-yvnhQB**s+P~H%O5GN-HGnR zhIHqQ?#wXGfOUi!r{Tx~S|v5A`4?*MBWuYnu=U%$K3AD?CU3U)(b50aCNKr==)5mM zI^1nC%yY>*sp(J|fHD~_7E2SRm-~t23Am1HD3jKosrl-R$FB14LfrCVx`?@pa^yVq z5Tb3+ucO=KVWYg*i+Acxl;Y@ z6H5cm?c>L@)UThk@j~72;6{Mm@9*F`sfEED+yHJ27k7YYUjaAk!A;bAX(b1j939`2 zrfzvYUcL9%OK3Uy)T>KOTJ<9$MxFWew|dOUfeO38WTSIu@qcU%?D>pk9GlC%V3KVn zXol=ePNK7?01SV}-SL}_CuEVe8sQib`r-{H0^V*gXP5DPoE?ubi#yEYjRZp!9@wMg zCrGlz4(0(N1iM9z!3b=4)-bOj#!-kn`kG%YPhC{L_3Bh#>&IQ zKwPxC_W6SY9Ys63%8qv)Qr80PR2?ta7Q?)0|6~*}-#6@mHOe1R!BD@TzVbqr`9VTv zsvo{^(_qH`z)Qm~2^#NHR7s@q7olqQ-^EA`Zv4BD^%Q|Hkz}b4zmydtA0j4(s*7LV z88Gp~ugn}^-rU>oZ{9zr3I{XqtiX1$p(uulA0_(X(Zn7EN+zCF{!og#;Z<_pWZKK4 zb&LKBI`I+!tLiIA1@%?IWvCr@1Hr@i{q30f_S2)aiF;@rcptH71S}js^+q`kMcnuoQR52A zYEND6aJ1Jo+h#ZLRwkW^kYi9Mt8idDiQ>ks?~g7H>>t5@XC{OX z;GPEf9l$__m>Ibk8P5^$nHMZxHh+~oABYzK{s8bIz)Jugo`$BNeGVRj5o$7UV*z#p z@BoZQY61X{g1$&JdIRh$sPa_+9*-Ep>4CStNK1A(+-?%Dt9Gl?ak=azLUC=^Gao)^ z@{i07A1TT(9+^(mcK~2Nz%!_{3aPgNexm;TALllN35%I!4PsHAsZ++v*&AKi-{iw)$7PSq^xjOfgF`hqC z6%{FZD9wC^@gBy^Sx4n?Xtez~wL37{PIuUG7eYS(Vcctuk;jRF7uC-{dDP%qE2tDF zX`27(XJhJ_Ib$iz%$+IDm#h@8Q&j_-%=9~j0gcKxi12mDZH@ZPCpqe>f6eoc^TYqz zCnmA9jzVrh<%Z$Wj`Sed_91imP}CheM7F-Uk)X$8T+J3#V*@y=0{GWOgVY~7_ftK- zB-}ssZC^{vGT>doKm(|f|pzT3VVcF{f5 zL;tFe89bvlycN-+#ZZJmo2Q86Q)=>)YHm`ys$7go-m|nf(dJFG^+em~fF~dQdH=h5 zF)E-CblQpL3p(ba!n<(}maH3!@OoBy({SRtjY`=xnN0o-n zAFKfW!$I;dMDR6aw~uP4BWkfJ*IuROe_5bS5W;QfLig{4*dsE-ltJfL+h`KQbcT)X zLuNCK^??k1zi~$>G1#~VSpSe%H=Bv*C!xchuPulc8$-rk+hrER*0D&9H9vEB#?k+P zsvX#_fAj+_|BXnj)Utes62?$>7sZHCq5zZYhj9exJf_$}_h+*}0zd=0McWc9M$BYW zZXg=@Q-Ev&v_sX5Gzdd?_kD@3wv8Lex$q6vDML7 zVGWsQ25D5U{}dYe9L;?J@FhU79iExK0`6@(Fx+erWuDupz*jLPd_%Y*H{1ZWfc7+3 z0`LjIrvSY57A92-+AaVn1SkS{5TFMoz6R*WWvKh{(6trFWC9f#`jB)2aR8u$fG?JB zhCA*0nt(@_WqAq|XYVU@Gh&1g_Pa6&AfV6=Jt3?)dQg$b=UnvT+VVSMx1{@Vt9Tcu ztT8)xKbkJGVmv{c>_p|vCiBE&f}so1hLABwMvz&K2!o@;V=|a3Kx*wnSLjUH=%kOf zJWr(asL5|AufnEB0z4jJE+C9Q9vNnmhlf?R2wd?B;_MO)@>hit9+vA_hLvc7qZ+z{ z$ZM`|iE$pxh?!CkIE*2PB4fE2-sVP1&|)#A@L=qrIXx+3db=;l7gzbm#fU$&;{~E* zBh*(YV!7krZxkQ&ENosun4>o=|fkTu`pY)T6fp zax<|u*woXIrnkFI#uCLYh;+X{{;be0D(0@RioaGY?i1E<71wSUMl%kJHijywu;@C+ ze4bI~xGUf&(&$5bF(B}Ob`G2fjKG8Vw~*kr$potKHgw=nUtpaZN6vEZLV zCGERIqM$CwwxJQs_E|MT##1W;`S4Fj#t3ecNknoN7+DtxM;03jp(z9|v^z_!UF-yS=}U5Jy8pkxnptKcGsd1dJNwwDQ6+&-(_p>3NcEaFn_hG`;yt{YXFBs~?^ zi3+&)ftZ2}6la(86ViVMWvssIZTFd)TpQ&FDDsu|(TAcSpEt!V&L(UPQ3?GiFFBEz zc(&U%T}+G7cQXU6EchyUxs#s$Y2IkVd2Lttk(OvGxtdn2+_~duC{Q%yKB+}_2#v`9 z7~mfOJS5pjh0GwUam`amSZxrRzRegLa)+Q3*nkGUyA-CwSqH&;}5k6a{bjLt&$B`?OrM^^j+rQ4zyIzGM>~3Br`YnrTJ%zfyN})YXI>~3VJDQyidnG@^>5JJYTiRM( zzBoMW#{Iq)eC|ZOiL~Hug1*y<589}ltv#?#Tu)AG%zBZ3&NyPKLdf~lPD(5E&$bq0Bf|HE)i3f z&qI0vfr<+KjC>M3B}aX9NH8inJK$do-v!2ldzJ~fWL?{>S!+esWOn88z}^h71>hEd zM1Uj!2LWHKXb4dBo^&rb`!$g&s0= zG`Jo1T74+xYHnVecc~~A7ik+W6{Ga?H#NWmtn0q#Qn4dOpN|yvbZ3S(eWUn`zAl2J zSxvk2(Hk1;+%z)mcvu&CG~)HZkwwNV?k0L);?}xGdLCInz|KxAP>haOB2G3U-RB?% zCm2EDfx(P+V3Wu&w-Wv-?eR^bjh5?lwy8=9cTbS#>IHH#Y6&yapP>5x(kG2YnFyam zxC6)_+njnLfsARZxq*rx*;}ic0(9n-r-*$XAIK2 zHz|9yoQa&jp~3Ivc5I*w>mCi~ywGztc(#P7{sq88%`64D(NDi{_pnLB(}+HkoNA?+ z#7zvH>i)J>*o?b>d{l>TJMkTP$~JEIaVN39rma`(P#OpA>3NO1u$%XR(?_wJX!0Rt zKg<0*YtZp}!Y5Q4+UDM~v$!9Z;{e!D_aPNj*PtIZ9%W^LaBsFk=)v;^I`hmLAIM|b zkZTzh5RMU_CvR#Y_BkTKjrMI+%@^HOTg6(_{P}1c73rt-CL=Y800nhyJad3RlX%pL z&id=G1&~Wo>@@-`BJIRB+5r!Ckb49#rU$MZq;YNB5RYv&a=9xb(JAg3S4uOJF-{PP z-(ovJ1VQ+eO|F3k>r2~64seqr&FCUM#!P*@iVCD@JKM#n5C_w}<4R!@9yWh;T;E@# zuChyI5p#coT7xdq>RR`c+bUXQBUTM=>t`XTq92Hv;Q~1xEyXjG1i7lLovDD3f z``4F~wEkZlKg^`7Dyp6Cf&9fssJm4649gVA_OcjkZy*!%u-N1$nS~Hmu;dm0yR7 zp!#wV2!mCIZV#G;wt2UpCtkE&yG4Onr84WZ2X~A2$O!1}&d6vAAb-7AzX&VRO0rL zbkI80A7I#PXH_f;QJb{AoUmlUjn^{ zqOM^R9?|C~2&&0d4ORlg@*tR=uYGeDZD*nb^u$A$lb8&$dH`;WHG?%iD1|)a23;l( z^c3I*`c3~EEm$&P?EjJCAcGs`^>Zp7{z?n&w|9$NehJId-6!rAi;Oe1ecE@OWFXIK zLk@_N@!SdH9vky@CO1N{cr$o>PP^=Y$ShH>o0S}W{PHG1ah`@o`oO?uy zNuPYUFP*6806=gkUf22$i7f5ngCZv>G+#S?NMvfa9~6r`P>D!+2W1;tjOrfD9|wib z_J+kn$QGM1MGeLy2{}Vo%COChmixs}^AYOuU%U6-FKP`Le@Eh_{*0RPAaukKFDt;A z#2dC_tgSvQier98rQ_nXj>C{8y>}qD`yYqJ^C|j@gr_bDZnQHJpg?Gck<)5W07PJ`6N^P zD^HF*8=eCk56owj^2NJlU4x^(u3-zk?L*RYt+lj)KqvooYXxm8%JX8v8Pu1csxX7W z&V?z+1t@GnHD91LrO~ag8ZHE$2LQfD=Hv1r04zr2!`l8QLCrUglvU>&+qfZp7v%FYU zST`IXI{Un214#-2zo-2*5J4_jSbKom3qWm;*B=lH_q3GjOZA^K@gH|`$tS7X2fEGA zi_6I^kog|hR=*%7kZZW%1u z^CdBn>RI}dm@?q-Ez2OxX3#WwDOtTY9AEk8#yUQ7xNbK#bM8FM^Mu8v@AlWf)uHwRP@VeqBOsEvXe7 z*>qGeL#KU2+wr={n#ODkE=fCnkAUaJpz1~{4g!3PQte5rXye^xJl*(}C^>AF%e3Ct z#Z5WOK>Zxi9Oe@qSGcH56n3KB$Hh4!UpsVM3>mhHaCH8|w8gPa{sA?=05F?K=_K_% zsDYI7gX3aqtkE-Vc%KM;7$i*Bf_{x{y$&^`0*nCQfnw+3#N|=|W;5t>*uq&Rd@A`{ zkg(5zJm}phbkjhVPX+dVAWU`jE?t?8n;FbAt8ic_9DK$YOU{{d$a8t^EJJ%cPm2|!Cq!1%$Gz`DYC-;rMt0DgnQCpy^(1`3It6ep5W9kAVPMBL9d~gpTY& z7Wajv{5pt^1Nimji4Vl+ilBoUOkavohpsPL>W6epouMGi z@Jq-F42-TI+zIgS)9(FHq)mAfCI1BQ6sUvh(v8a#$ao9jZGdpyp*bMwuOi3%E@f7B zSNv6+fPTdOL#&Of4z?RZHPNoGiQXL99#^_{bZOJ*QoBBJvB9&g!_4*fas+Rr{0dD)Yp%yf;gD`5EYdF}1bMS=K8`|fjL&u9D@27LP$qHO4MG~m4E*b&t^ zyK}>Ri+AWlk4-PH_S6?*Y2gRdMm1~AVg2<8-1ERWFm1$_V!Zf+w*E^ohSp&>e<>CW z{V-5OeniOtE&B1X*8im_7cXczUvYs&Ux})Kr@7@TI_z~b$T%pPj8r`UI)b-xwl-1- zAbAIkJxfr_cp7Al8ioRS08Rk*Cx?;Z@PNY{b~)@G*l1b#V0Z{f<`|-9ufYf6tH|4&yzJ-v_mFRg!hJ=lfhz;lmE(43YfMUZ z;>kyMW0eVI`%%|3U^7PF1phZUz{_u?08jw-YaOx5 zxbSDzC!i<~ImgFSaLKIk@LF-1Ou)Yd$74Ha?L-vWi3DuL*&SQ)%CBf*qCdWSRGgA+ ztaRvc$#~_6GT~XY!s0(`_1weuA@jI8wfF06edoF57ek>RAsb;?G)#%S_hxi4j#x1#bbpwnl={2qKOYuvQOYl7R*ii(X7!9KI>=nc zP<0{AQESP@V%caffe3QxW}$0Ml=g9wlC9liQRb0S<0$eYR;5aaSF~BF%193zCkp}! z_+bXs4%2th2C9n!*qhNB3(JNSt3v})Ak?2;VI^-NwKCT7J~O?=mySf;Llgsf%y7{w zJQ_9y&YaWMdK~SorxCA(+CNj3{RV^Dp)}SoMuM1b zMr)`ybSlt0?%LMepvPIVkc!RLKF(1tFr;ogq0F9mKB|}pa4o=2?WcK4c~zMI=TL*( zPsFWf9xr42vj~!7BPISP^HCQyYS+gKAlX%iRFXgdybXfIxwP`j`-`T9y(Y7s6mJAhI1=+EB=a zR#)^=Fl|nOGTi<=;r$OASE9Z%E{G6s4p63Gd_6# zA|3L9)1b-8g7(6s@d0oFY3TP&nLYnTGxEXSAg(~KUrwalr!mqyiFSu}`zWPEbBtB$ zF`LlaW8)u<##_zlrR1teN!L=U#q+sz0Y}I`yLk(SKWY!1BkIsjRg0qAzP4JniwvXBK@PAyYkXx-~b!4d-I~=(`8m^p%A8js$y-I&MO`C%0P8Ceg_`0CNGh z5~*(QIMPI~!sU0U<5hw!(t_%4PoEulf4faOnp(D!nNVnCFyg0_(@3@9 zu{loXwE-qt{k&Tq&$i)3^f}k$OYj(#&_e>gID;>w^d?*tIr^^hItb=_9Apa%#o3g} z=8T7LCnCijY82{&0ef^?b|8lx6NeuubV(~P_B?#9Yzp;IP6a?;<+%XU3DD76$3}?{ z638lCCegsJv*uXh z(4NGheYv*%LyqTG9LudZG^#guvNw0~t|fyaPg>~J?eWPqV&7){{}Xv5ADVZxrYCP! zZ{93#-mE>bz$`f0-jg?{H*bzNZ_b`rdQWL;xz}2G+*)kL8a%w7fU}TyOrlyDmPFKJ2y9X-_5gq%Z4DU*=6;wrf>ivh~)Q z8*6S@w|m{Lb;b+kJ^Y6GnZ4yz-twy6H+8i)b@lPoHOErd^rqH$Q)_lC!CP3fc3*YeGVGXT*wNgl>^+uY zy_Th3%hDZ--b>HEefshAvSaCGM>BfT%X-r%dDAByPp>+bKBVfYgx>U}-t?tAmc2(q zL0{FF+?QqR%NWv^VN;hpkT(T;YGh>DbM-M^rGLd>6~17wphY%?XUuJEaXFBo_I{U@ z0RSLLa~5mI=o!6OOL$waoQe=4vmeEBVH9Dg&DagGlE;eAXkHrnYg~ zKX!;xb@%6n|G(*8k*H1^YaP2PDt^FcJ~qP_@Nc`Rc}htXO;uR<8o$kn>gmtVAK##? zjan6Tg=uZn<$`A5B!9L&-k7uY5BQ8u)aDd*_HVMy(H+s97VW@`qBxr7+Gut5kFyf& z3I1jDein# zJeT9y9__}G!T8bil1!iY2&vnivR{c%Buj`Q>CZ1{R6%>m+LpG!vE)tkK64wr-9i6= zhRqoGO8(|V`!J@I4x6XB#XVqdscYWmpI`K2(>#?ept}_@4J}PgPIvoI!)WyHe$b3W z(@=00YR~2g!>?zo2bq_m0^?U+x*NYhc^BkI4fw-x6#I@me|jq>KD9$^)2a8gMmJWH6Y8 zeE;ur#Aec`ILw77;;i1doPF5`i+YAF?k)B#@fI)Xja%xCTiO%1^n@jQpZNyQZck5K zL4QoNxu`Ea@Am25^zpmmcEx?suPEjsD!)5r&*cY2Pw}E&+hVV6ac|rbZ`_iexFskZ z+iS6TEw-LG#`e{-B7)| zdRO%c?ccYH{OS|w`TOSYt-8IcC#kqUnX3BC8f7i-wG8)KhVP0tyzzub-90PTcvoE7 zGpUaL^(NMP6YG1T>s_$Yrz?|YPm6kb+BtK^n$*+3&dT`af9p|PXYweER>7YHyhtGQ zKH|^*)96r+#D&F=rVdkQvf(JM?l7sB?a9jJj|UA1Ah#pBj;_^GKcOQfKiWfI zzM48TC513)fo7snRGU>mL9FgB(j(o)F!+Pb*jD2oeKCl9doWffM`CqnYrl1gA<^`? zq7nYj5oJ|UCxX68*_;)q!7{Lh?dA@1XSOz*K20XZslVNu$KMLeu%`xN`Bq_1+aBW{ zAE?~+pDNd0u22fJB^S__$8PuweM`(ePF<0f=Lrw8x5v7t`uQ?GDMl+DeBQ{Oy+1m_ z>*WmY^>V6P!knCK14YxuQy=UgXkRSO+3X=_M4zr$AQzEdkvqfOZf_srcW3(bKyT(t z@jEhOLk0_bij?QmfApSZ{vwc_?<{YmPXJ)G>`Qgin?oCG^$%dw(sLY5`aS8l_&^5V z;h0WzVSbVu*ZpL)T;g|1^5;a!cT4G&xnTi71G2*WW!N&8z2rPp1}`Z+OOfQIIqwrp z2C|-j{wVo;J4(2T%ZSJuw@3k!VT9%W`9OyA;4CXP1mXepOK2cb{zvIrU_FuJYp*LwrUy>)( zX(nY5Zr?=*>w1PS=q+35EnC=|w8)#Zs3&O=dD5OCqmE|(GOs6ndT%=U|LHwR)8SKR zuunaj(qpOWwN!a6RlA}oQch0Yz3g~W;jyH`Lz9n8f4;!GxV|T;us5l}o7AvleqUO) zHs-c52TM9V&Ar7Fy~PuI(5M>Z=Ouwnj&yI%A6GYDF9uXVb#I%NFFeTXBbFc(K2do!t&{%cLsdgE!!VCqndDcYT+o!%ibwA#%g zd$cLITSEl`lSD@}eTj~W2fxz>pQ)Z2OMWd^z4~*%$BY@^F=NSN<^?M+`j3^XD^d%v z^<&k_w!vlQYGY1{5qabzi~Ov!k4&VGz~KXMX8)JvJocnPoMm#Tvt+MD&!6A*@1NrklKl?f^WYZzF6T@hN3K940CVAIrqa|sn4dY3 zQrMY7FZE2B)SEKNn=)y~!hU=n#A_++v5Y%7<-X|$X5Kf`vt!YTBPm)%ClIxgzc)9^J_VO z6X$P&Nwz2wWG>}OP_-x>Aj5xzw6d96w{ywuL5rM7fv0Ycec3~_D{s4U@AliblVwhU zWlkArndLA|49KtLMv|j+67VGk52SC_YsN%SHWHvuZqPX(o`@#lGRbH_zk?2q@}&gZ#36V&MH_mK zlI=l=A%~II(0Ar;!{rfxdjNI;{087DfM)>y0Pr;ctuW~x4L}k=3IJYq%-;{uUyy$l zF0Tgo0l-dx8vu3#+$KmpqKO-Fv&r^MDHzwuHYMGCJ#ToUiLlBWRv0`MWg-vB-Xz-wVVG75cH0PsQ$ekldN5Q5*MAn{TH znFWvoFcDxXz%+m=0DhVh4=YM|2Z@K^`0*}&{z>AQBKZRVJT@coB#FeM9a06@?*YVd zc?qv94+G!~v&4a8iPM^Vc9G8=N*wu^+hGub!DLc)^C!V>mjsJyjeiFP6|7seB8yfXM1d;Ssx7tBRx0&7zjNQ2cQO;G{l4#c{&^k__dVw>=br7J zd*A!c6YnIydSi0NT7EGf5vpth* zrYxAkxOSdPYA#)HDVN)Orq)bbFpbMOp37>cFPLt$o3UVqtA{gpL)>H3`I8ud{}x&823zUuM)Rn2 zb|<)q+VzO3;UH{z47Q4}J!7!dgzcsMGCn)sNu}N~beFa_zN>99(fV%C4#nrp?H5yJ zDG~d}VBLfr5QAMt*nu(FYqg4mt^+(o8yrKcA?%PCY%O7jYIh{$wjUNltJe-BbnUa8 zYK(}XNy1(fgY{~5YwiFa(MHD58VEZo2D^f=qqPca?%Xjkv{ghK8-r~m?6??g6Jf{4 zV1J<|DYl(D840au1FO9*jC+yT1?Dg7OTke1j zM7u18wvn*YW3V?6c80dgmfP?07}`xltBApFVpp39R}-7Ho{3$>&00lb*Fm>X?Kv^E zZzb&980>A_#}()!@pdlHLwUj-RQt-9+IJFmehhXCVHd<;HLZVA?tots?dllXR>EEr zgT0He3$;Z_xpOOHXxoUkCT15!1NzwsGf+v+4=uTTeZam(^T<<+U$@7j0mp4NH@XYPH;YqEU( zLbc-JR>wK>R%dA)a^{GUT20Qp!n3J;s-?@}b2%#=zFlHFDTp+!v_uPDo+D^w2SUcrRPFz~MJGvk2*n9huL#adGPaS$NVW^y?oj6d? zV(Bi(-P1mt7_Bgf2AO`>vl#2jZ%tN$W?d9bjdJd-7%Q|O6wa;7Wag!t)Q3qBdYXEKpxJmoW z-YNHb6gL2D1h@e}YFWkkxh$4sckK#St*=ft%G-%Fw`F8;ibc%QE81HM#6?=g!1*~l z;~%q-ane8aw?_Dqv_nICvL9*Z=Jnx1e7rA>u({exCvy{=mYoUuZ4*Ujefl3nk)m5y zC+H`>7i9_F@kY%DvvUibR;P_>Cq5QWL(o6M~PLn4JAlJN&?y?|D{GD?HspPT z_Je+oz}h%1vHWPs=~Nr+l>pgm2HWelG25pcN*(-u>fnP3gXOH2#GZGH)OFNEt_RSy zCwtlb<}{o@!jaf4Wim>e0oXQgMu|DMG3UXwu$(HFd*!Vl-$o#qVdB|Bc_KEVsCn=- z)QmB0u~nPa`yMf?tg|ZEDZb_cqkmd)%ZHrGsQyjH)K{Re1c5EQfoE zV%fm=mWEfg$uqkVzytKpyF#nz-C65Bbc|NmuZ!U~EwlQ0gqWzk(!YaE%|biYe_(`& ztHI@kS+y$Zrq(+eYsf#ntvHoCF|?Hc3sadyc4$_Wp*Hf@RAUFKVlSuNHsEm*@X&#c zmSHRDSxy9)0APx`nI7lJEd+-7Du}wQQIMPxsJPp(HYuRHbhXF(JoX0c&6o7L(+xdkgTnq_gAq++cT_q z&h?tusV?g#ocfY$*g zYHyA2I}k$$ZH}6{hFYJ5kp$Ztc2im7@-3}%R@OQw`l%LZ_NLZjLjSJZEYVne8P5};HAEfa?$Hp;Zmw{fX-4bLusqlb7DXL`zVeE06W2W zS|4RT9^b@c@}yPOu6m!luC~0LGRFkUC>(MxYOokzK`AUtCBEMPXUdRe&a$x7*8~&X zK39!Ag5FczKJBB4WuihmH?hF_EulVa={V_K+q~z|!5)BjQ7e|*bmb$&y|@#v)DdGi3f9|6qQD>k+Y1W#K+R!iWVmb z1Tz}yIoC35Ne%;r)ha4w7Cn?Fu>j}E04PzMnsfS!sNN(3@ErW9fR*ELIxEA5ZpcIa zjq3Fj)L@*@KK{wxa^>_ga%g?|08yard+1he^4o{R^V*rq%hasXBWBHd+XPmi3i&wz zEL5H(5VSd69v8_vJPY|9XgrS?pZpV%qJ2`e4|8mjf2T?lwFfF5RspBws+m{B7f-}k zDP-us#nY!J<4rVuq&OFG1gI{NX`mGG@gg zG^L@|9SYR!7j{%<(eQ%kz+-=;l$>CwxcVC)c?m;R&TCJcqUo&*jV|CJpV&OzQmx`sbaXIhylZWMzLc!Ip;?m8R!%csqx| zUIO62`HFV5rf5nybO)21Zf`ZOaQji`RREsQYbZhF!F*3$qr>BCtgNqdBhQj9r^{92 za>_TfakY~#`VbXA27t@%$dLa;nMcefzGORq@PP6yP}>8SqwTNl?B`*_gQ=A3x2W?r zz&ik}f16~bV`+#9@xZY4-12T+XEBol{avUYzuecT>~bVJPE;lormG+d6O!Q}c39*LG_`o$UJDfv z)U}J34;CY|`sHr_EcBDA*k)l(MQc-H7)Qwo(g-FROH435v};h=2P~Uhl-Ha@ufyZ2 zbUTAdRSjNut;_4>`R^Ddd9`Ef{0!Y5kBjSO>{je}z6Ky4fCGMalsFXJt6e9%Ucs)> zuDU@=S8X+!flDe=P{H>EYIEp3iBf+62S7If7SSJ2Vh8Gq(&qqQXg|nlsi#mJ1n{PI zx!3M5fr3f_$_NBA!-IMoYpUuzvKvU{|MSS09Fgvit2J7sNC;+8!K$3w&uC72a*ov@d& z5r2hNe*%DM(n*DKEM=1Nn>g+0W_!m9kTO+puVl?S>ghCx=Kg5QKHtzBf1B=&PMKSn zT(s|*EWZkB1mAeffozdjO_sSRwsvfp2V8__UWPVsP1ymIHvCT(fKUj~5ug)55rCb* z99fKFIY3Ws|EA}QdZXAEpdW#-(_n}JgwUog?^^UR%}WkM9XOC2gwjxe5dc%P;O62? zNR9=?U~)^!&EMJ*E+e|W?=q3slD*~k38^f+VQ5pTeRo%{)QHJyJ@oPIA%~{qOVt{0 zFC}OGKwG2t>U50o<(=DbDDo%mHN8UIqvdX!GK4+K0Y2D|*pia)2vd`=dLy+~=4LQ* z=eA0bp#61QVHW&Z&I5bjP|4d)`)qS=iAp?jy-1fri~q`{4xiUiUoV$a_0BNUN-vb*)xVP%*tw{%pq8HuGoHJgwdFV4?rN&zZZS@x1^X2Tq{$SAbyvJV}l? zS@dY6$|_Ti;)%KM!0f|!qEcmTTyvh)NAu5Wxw?63C>L(o_s~K?DNoVEcE6X1`q=O)w1ULiG7K<^t5S%zFFH1GDV7RPYK?C=U*Is`3{sh>oGQfsMR)|~< z5)(1d1b}q_>$g1C!>?1RJXQ7pg3V|XO4R^W0LcKG0o(w5++;_IGe_ghDSdfE9qlA( z3)lKwB$ydN;1dK4=d}^A^Pg1Svx@kZ07JFsAA8v3U7ucLd791)O1GCdug9Rwtu6Yv zzz!1g%}m9sY$)8o8?VMw2AvgVsnSSgkvfi{I^L<;<--SRN4Iw}GuXpB1}@u8&Bp4Q{>dH}A;X3<7KrBs>uZzG|> zp)LF=m}W}T?VPNFxIdhp$xp!4F>sRAb`S&I4#47M>9PZ#0FKx2a+LA`m_;+9WhyoQ z5u|efJWF!5OD`~276;ENydbKW2ko*+nt&3hx?P3VjU=ecTW;Gm!%FUb?0+sD1NT;` zEAqwiWF=$n)RggC;AlUsSlqFhngv4}|^F}tqMZ*I|xu_A-!nP%Erk)?sM!h(nyaR7S zT6VoS{5(NTJGZCLe|5A=c{^qwOpz{MgN%w`@>Uu-`eZj9!4^9ct}k(z_7vjBdg_L@ zpV=L?9eb~%ZPAGXy@hQHggQZ+xi3$ve>o#!fBtVGkb|<3v-LYr(+HugT6;|4D;->ftMYk=)-T#2QMykJ7n?1a**6WpNW`vu$Zz%84LlLeg`u_P5 z?w8bkTM@1mD@KglN_F>v6-<`|)vol>sk;UqY^T}w&n9v8J~B04^N+P@x4M(Hjlch1 zrJS6sz`uj(#>6fV|JW5c@);XAb`>2wvcE9>0`ZP#6LK4W#P(_qQZg`+Y%mdyc5MZ_ zoSzfySidaosEF4K8u&ae&Pm%A6i))=14Ko@jED#r7L(-JawIUP%wk}t<{3uBKD>Dp z60F})4-4Ap1$u;jH|^X7~3F$S#hcX&w*^D$SE#fxfXz%A`G+|Dn zjW{BsF?=jh-cJmijn`g(=h0RXU?s+7eNI4W9l(0+(7Sd&{Fcr|dIJM!l$AkpMQ{QB_>eKkk1#rpWXe#>|TendmYN|^M1Bgf1o}p z0<=HaBf|T4(O9wGUknb|`%6$_PGh`(BS>f;CAhpOE<+LEA>uU?ysqZ_=9_~vOz+P< zJbKP<>MG>@EU%yM{SQ;uZFzs5R&+SeCLbYkq4t}@OWC`pCn%5pJ^0@Xz^2+(9uw)u zkE13l`se#G^A+;rILR*{4&&wQ9J!5nG7^>l(shf$2-^}XheZ|Tx_wZEouN(7haoeVz1q<+D^_ zkyd@;4Cg^qzoQQ=GKjs8xLp&K{@zV0C=X$!ty-(@SIf+;obTH{PpHWPyO2^4GT&4PCJ z>tQNkxf{=HQJ z>+<N^`^$)b(=l#&{8s^K`@-km%Fpu+zQoc>Sv>q)t^m4A%c=BDU_?Gso z9~>b~cRssK^kVrmV+7N@;d*q^9F5hE|EoluS)`~Oi`%l3*wMiS^&Z;iM0X1At<>7s z=TIq_24#oNzU4ux@gB7N6w%gd>wbJHq~uG^9f(wNbkADI@~*&~A9352(s1{iG1{48;a!TSS%U9o8&eKcdi2*Sm0@kC$f9G)<-%BY#9?S*o9i z7bX6UgrK}F$`6WB?ZUb>_D2yNQm;{K0c$mMEk_2a!ne@sHtKzC-0{SW4cBQm{@6ut zP7pprVu8L^afiq?-8iCu{fJGJDTa;1K4vqD^@s*E-p^C)N@A$B#Fb*htRJJU{sGn> z)IR!Yr2cH8SQ4S)RIuCBWj5|+>1%Hhg~M5@#?G9XJg+~0LOq*9>lMi&H}f;XS;#@; z@2Mcwx*oVSS@afNUZ#=0N+LkFNyN4E+LYgJ0+13H>K~?vo}*cB4yq&X0mvsn$44HN zQ8Du5J(%ikSh9q!qE_O~>{moh(Z{3;N~Ht4QpE(@gs4#3fKFBbKxEwA9Ca{ug4)WH z0G|VJ253Q@L;BEmqO1RNl-pWUuzL(W{DjOx9W3(YIZ7qwJaJ$UOyqaeZl_AvS-ULDpD|aOW}J)? z7IJcL4grcKcJ0*WtPU!or1IjbuF%Twh}+yiw;b^~ZoXnM4V2}JJe%KiLz7EpiARCv zB8(wIK^!V|`t4y-_}6EIMi&H2eXqQDA2KR;H~|iFRt-M)@zQ(FDof zhm3Kg{+q5m4Yu-e-NYjzuMI12>M}v!yIpkl^QCZkmij2qRMy9=M$N(Ghi3z(V!fYm zVLNG+Rx}X%<`O^;K_jhj__83oM)_~*a0BMBotB@j`tN#(8-lJTGa{JNFlM6@e0{i_q4AnLMuzfRq11{RmF2)sW1gff-Mt zzC^SBQh(86YW&)P!hR)doS8B-&P-ic!CugGkLHSB0s7BVW7ZvVbUP+Tzo{o-kN+onqz|RUq+xH1ho)Z$MiIlPZU-u5;2&I!Beu35-b_z`6;TlJ4dim@V~7mN}EM!pQn3HC4mWE-@#G<9YM z_XgC&LPLGE z(W0*(=Se{;-Kllg2je}iTDgP}^1{i3167bW1hb4grFAlNT=)TKH(@R~&7fH<{G2dbnxCOUq0Z4VGc#&j5}Cu$J;sidZZB zc;uAVhTq!}zp>Us#%S4$cjz^bG<2v;?^k{i)?6n|Go{0IYN@bF7kmY1%1t zs^XnMvsfE<+7_3TsW(3o_GH2;%0C(W_~p_XMg!mQ|G{haC4rir-$ODns$F;t~fAmns~~XVl$fZ=8>Hc zTgu62(?av)>+&C>ih0iaF{?dZk}Q~fp$;{<#m^! z<)r}A^zR*FxPKVRBM6k2%M(;5m`2}y(Y#%fKPX_bgYaszsG=Vp&5SVxk8E|D&_1hP zx)!^9)l2DRkq6wI{{>HKTwF(bsfYH}XqxC+RqbhTx{O6%f1^s2tE12lP$v@rvks=w zktLm-8M0w%u=+6%R)IP_;avounDRoD$DuQrgo(Aj7$aw(A?8ZCmEwWE>8!8!$`NBg z84tk2Ohk!!NM`ZUg-frJTc(%p&sXDPP$qcg6jW{2pQ;umVyb?yTJ%=8Yo-GaFe8xa z6l-m?m>#@N6zGpG6Q_ngk2%5<=Fs_k!eSC2Db4f@R#dW*1W8Y6PHxioUn}x13s zhhuaz8uOVa2QYRp9DGie1KXJ5dqkNd2Z8eQ1C|{_M9qvk zPcg+2^}arQ;V5w_tzP5=7kGsian;Bly=>btHj9H}48L(1035sX36$~y*tEYy=@bFF z}9Icr2`BdM6i_ma&?rFRdf?InjaXd#IZ~1-3Ve`SJdV zp^nrQJ$!S+*HtN-WNwB4fg$lt6J6|Axs}ALHNIXH7Ewx=4=-K&S%%-ZdtHAOVd^`812zH67x)$e`b}rZbnzkpvg2dcm{+>E_u*v z!D?Ud8o?($1#_gUnm+%o42zB@*IILuD=a9)pab*q}d7ObE zTkmmljN^>fW38Zi#femRl)h)J=%~x}qMQ1TDe&xi(c4nA2Q%6Vz~N~>%z@g($uTIs zpr6|y`WHsgnY0Q#H|kS1ieb_3$_Ao68wcC}Fg$($V6L`&HfW@-t$U|enw0sw`TJkK zpB}VU*Lf(T68to9S&%+&o&;C2%LH@p=kUSx5W8GRmpg+B8xQLy+HkfJQ&BXrA0WRb7Ac`)vi zQ?r}V5Upe07pKujxr^Pjqvf~Uw^J2Y;NV^2h=|B?UfL$Uvt&)cKtBMS1!&M;xmR@Y zuR?hpz@C~4C12Ee*(qmIQ{xm;SFZAmOg{a9IN7}5y|7Mif zVH_yYie+4d>d0FhPLO!=#usK=G27OoMSQ|&G9;;^Ha{n$Y*%rwq;ePacL%I|s=yBC zOp5x7Ftg-vX5i?3Vid&(t@n|Fz`zH@G0PRK;s)^eF2FPZe$&Ev#1484rZ{}`mT@UQ z(dVxYX3#6nwpyUF+=kgq)LjpWvTm3et(H+?WGJdF0^q@3)1Q7wbWoQy?gf^OAWF6cH^A}G%-C1-=!M|zp+6Nf+Z&QHj%Ad*?j|lP-o~;(b|P{D|nHUIKQW1bJ_%D7b_tXuJYsQ#b=Y+TuN8^}-HG=_?!p_0x}t z0_%Om$YDL>Q4zY48(8Fpv{Ket_6;)nUf zs(=^Sj_54189knCgMV`=W53;mDpde%#KtPt7JChGaXIR@K3cC{`bRrNXX}GB+fM># zcZkYXVji$lbf=I{bIQ}}c8a{=4^X|(J9TFHOdC8hXRXh=^_O;v65B)6`fQ^9#ZDF~ z{d_?|;L4}OTN!E>#B1X@^!E|~o4lDPQB(Cx0}&sJy$T##+iNIsT9iY6c7d<1-bBTN z0EYk$0~B!V{4I)a1H1$9JAf2))&ZbUe|4|uZtH|{k^Yyx^uFZ-sxc>GqcT?c7OS%} zS}z0m4B$9`8=yM?EAeiW*vEL1tVw=>^*IR4;z^Wv)wzhq4d#Tte)CC3t=Er}QabHW zE7n*rHVy#kyjl%eH{*e`1D6l*9RSOh)8F=>?g!44ATN!)0|{b z>ifT=cf9oJEu|T!OZ6Z2mehXz}=zI4=dBh5Z$X8F)m1=6$Yw#1a=D=Pjgf#5$JQ zLl;7fQ{?c*=5aE}_#}!`HzaDslX3$KUlA{+3<0yj46bBeu3JnC)V?EDB7l%HM=IBYQy+~^k{q`dAqqP(gvJSg0h zrP2pXuO;cXd@M3co6(G&G%QW^yH6a2=uHSI_~nm9K{Y$v#i%`!01X*a&8JS$3fSm^-rqM*3B1Fz&SQk@-q zX=Rm{gd0b8tRD-CK_XqxJ}Nqu%_1CKX^Fqq)hPF(=a&EmQ&o~2TOIK|^Qah+XiQ7L z^C)dgOrxs;C#JobVb1|VB|tVnPXN}!bd;6=Oa)*z&3MG#&obg$(0@S{j_8m_Fu_aj zJ7xC~z}^i+yrasi4BB{q!#uMYhxH)e!kkz)ztvZKA_iss8|`s(UInTI{e@3NQR<(7 zhM6I=$LpVL0Q3(B!4qnuLKAW+}Z$`_B>dL zF@f!9768f6I_i?v8Q+%Hvnq^VND66QcG`{RFA!+T3=?PZmpk%hefrm8M#p`qu^-@7 z0wHt2(68ywe=W)^$Tv`mF^Y{K@myG}zeT0D0gP$uW#9Zq11UitQ3lc* zxH5qM2LqAsfRpZ=)WbgH@9@k4&#(_>e=kU3H7WbxDPcC`i=m&Ns;qJ?rr%zZ2hhuV z0K3rAw4BHBco2j`0EYo!Mu~0MQTUyQX-6MYeS2Wbx8fM=sQx=KKPl{I2hWOvN?!HY z_u1{?@#^Pp*fJV0Ixj1Cf}jyF;z5OqCQUYu4yBS0*@%p+EgTo*9{rMk(M!fp^(Frj zPCMhw#3d=l>nkuJb^b2GvyzyBZ*F3Iy@gtY6RYrruxi|IlAH}qyqtt2! z+uIKHn++@(94yfmfWnaWqZml9px^jW^rK+j_eU|={z$T&h1~wb;dn`eCc3-hTy!!x{2Qg7ld*Zx5HDQdHua4;&;Cv^MzMbgkge z80AY~PZ1#V;*{-=KyW_I^bhbjkGgK-4FZvZ9egf*zs-_wJx#s68#rdOY>!twHtRR1 zSOyQc6CLaZZ#LPC@^={aZvfu|oB=?kroxG?74-W-eD6gY`$K}BoN7srJ`Nm=E_e;Q z7o}kU%p>bM3yR8)=rEmU7y63%i&*(ba$r`Lr7O}sn$r(zH{OYrpoxkOqyp<)X4yCSy)TO$Xx|V1#SyFBVuj zO*g}3Dlrk^(8eJNJM=fyuPFn1px+CuqnFx^wbhksV;YbaM(;UKaqm_^{!UOQCDce!ALHfK-mbr$=)fdt$sgIcN zBlY%OEZxVjk~e`~4NwJ;3}70=&3NQkY@GAvfVo?Ny-jcIV(FN}nP8HqzE1rvSsu~H z>f5_mZZ;KV{Dy;muE^49;q_>XRDXeSfKH6!p{yJlP z&W&FO&t33X1i+hSwsH3FgPjhvl@Dx5e^CeSBX_S=I|^ya#|{8y#-x zEBadOW4QC;u-x~7^cDb1n>m5->HWv!z(xyJ|DdmBNHJ`pypwuI#X{l6!_a`Q*L|n= z>SyWfXY*qP@`_agIt!9z$eftUXF;+|*i}l~8XdUL0Zsy7{ciQ1hGoWVLvY?cR)T!= ztj?YD=|dg*HBVn9B5O`~VWuyp+Gi8va#E&^QrCnBW zIo(CVuRGFZBm@OoV|WJ~C5Df{pqX3n^2hu}96?L)+lKe6{$&rMw!r&0QeSKJbNwu( z`hh`~s`Od(T>hL~AZUoI^-pJ7@iVj552hZ>Fi`l^NxG{z zp9p40*6WL3MOW7bJCMEcub-eX9RL&IUkX;6s^{?8GXLJJ{1%kI0sI}{Cjf!@ z;nzg?r}^YGl$Hbd09F930$2^;2iOR(3E*Y`eA+MZBN1{dz&!x>13U=u5P<&?z{dc# z1K>+q{%n)Kf8=in`O7~3PEH;H^#gz)z%hW&0KNjiw;l3(0Nmo|+wgpyT*g5jxEC#x z08#+b0D4;d1pA_h8-NnG;`llfUmTLSV7{|A*JLbLz? diff --git a/core/admin.py b/core/admin.py index bbd2353..48cfb9d 100644 --- a/core/admin.py +++ b/core/admin.py @@ -8,7 +8,8 @@ from .models import ( SaleReturn, SaleReturnItem, PurchaseReturn, PurchaseReturnItem, SystemSetting, PaymentMethod, HeldSale, - LoyaltyTier, LoyaltyTransaction + LoyaltyTier, LoyaltyTransaction, + CashierCounterRegistry ) @admin.register(Category) @@ -94,3 +95,8 @@ class DeviceAdmin(admin.ModelAdmin): list_display = ('name', 'device_type', 'connection_type', 'ip_address', 'is_active') list_filter = ('device_type', 'connection_type', 'is_active') search_fields = ('name', 'ip_address') + +@admin.register(CashierCounterRegistry) +class CashierCounterRegistryAdmin(admin.ModelAdmin): + list_display = ('cashier', 'counter', 'assigned_at') + search_fields = ('cashier__username', 'cashier__first_name', 'counter__name') \ No newline at end of file diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..0dce3c9 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,20 @@ +from django import forms +from .models import CashierSession + +class CashierSessionStartForm(forms.ModelForm): + class Meta: + model = CashierSession + fields = ['opening_balance', 'notes'] + widgets = { + 'opening_balance': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'}), + 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), + } + +class CashierSessionCloseForm(forms.ModelForm): + class Meta: + model = CashierSession + fields = ['closing_balance', 'notes'] + widgets = { + 'closing_balance': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'}), + 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), + } diff --git a/core/migrations/0027_alter_device_device_type_cashiercounterregistry.py b/core/migrations/0027_alter_device_device_type_cashiercounterregistry.py new file mode 100644 index 0000000..14f45c3 --- /dev/null +++ b/core/migrations/0027_alter_device_device_type_cashiercounterregistry.py @@ -0,0 +1,34 @@ +# Generated by Django 5.2.7 on 2026-02-06 06:36 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0026_purchaseorder_purchase_purchase_order_and_more'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name='device', + name='device_type', + field=models.CharField(choices=[('counter', 'POS Counter'), ('printer', 'Printer'), ('scanner', 'Scanner'), ('scale', 'Weight Scale'), ('display', 'Customer Display'), ('other', 'Other')], max_length=20, verbose_name='Device Type'), + ), + migrations.CreateModel( + name='CashierCounterRegistry', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('assigned_at', models.DateTimeField(auto_now_add=True, verbose_name='Assigned At')), + ('cashier', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='counter_assignment', to=settings.AUTH_USER_MODEL, verbose_name='Cashier')), + ('counter', models.ForeignKey(limit_choices_to={'device_type': 'counter'}, on_delete=django.db.models.deletion.CASCADE, related_name='assigned_cashiers', to='core.device', verbose_name='Counter')), + ], + options={ + 'verbose_name': 'Cashier Counter Registry', + 'verbose_name_plural': 'Cashier Counter Registries', + }, + ), + ] diff --git a/core/migrations/0028_cashiersession.py b/core/migrations/0028_cashiersession.py new file mode 100644 index 0000000..ee1242a --- /dev/null +++ b/core/migrations/0028_cashiersession.py @@ -0,0 +1,30 @@ +# Generated by Django 5.2.7 on 2026-02-06 07:28 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0027_alter_device_device_type_cashiercounterregistry'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='CashierSession', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_time', models.DateTimeField(auto_now_add=True, verbose_name='Start Time')), + ('end_time', models.DateTimeField(blank=True, null=True, verbose_name='End Time')), + ('opening_balance', models.DecimalField(decimal_places=3, default=0, max_digits=15, verbose_name='Opening Balance')), + ('closing_balance', models.DecimalField(blank=True, decimal_places=3, max_digits=15, null=True, verbose_name='Closing Balance')), + ('status', models.CharField(choices=[('active', 'Active'), ('closed', 'Closed')], default='active', max_length=20, verbose_name='Status')), + ('notes', models.TextField(blank=True, verbose_name='Notes')), + ('counter', models.ForeignKey(blank=True, limit_choices_to={'device_type': 'counter'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sessions', to='core.device', verbose_name='Counter')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sessions', to=settings.AUTH_USER_MODEL, verbose_name='Cashier')), + ], + ), + ] diff --git a/core/migrations/__pycache__/0027_alter_device_device_type_cashiercounterregistry.cpython-311.pyc b/core/migrations/__pycache__/0027_alter_device_device_type_cashiercounterregistry.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27d6ffbcf14b7ad102f921ddcdcb00b7c2979669 GIT binary patch literal 2362 zcmb6aO>YxNbU*C%cVg!QLrQ`{sKKbjQH!Xmpti{l$pzi3Z5?TY&t)ArA36SL0z7bfGEMM4s_PJ<^QUqD`qL@tnY2 z$Ql!nUm$b*m`QWK*jX#nw#2qEgdD zShv*RoVSby#Pf$dvk80l)C9x}92U1Dp(xxA-uTZxNFKoJKXsuN^JL>82MI_7PGZ}O z1mo7hhhKOUMN%*Js_nh_tF)&nHPnmIe|F|KK zj-wO3seP!EgRoY(EukJkZ=sWD`X`|`^J=sp_7mt7)$xU`hLU>nGF-`faYQDAKH!u5`NDO53u{CMJbNpTo|W zb_29T*VyuO0s`AjEqeA9s?07CtZJBGt_5|j+>>=|)a?dM?_#oPT39xeCKF0}b?;F$ z!gw^grC}Y>V->|}XqW`v+{SgyvPp*u8mcZ+;giK;gr=3YZOSUaij5IXfwxVCbmSe} zp$Q8UP0_V3Cda`xno=xFs~Z@}irr0>1ENs2!4+SPVeZKaLcVxR^>3$RL1<MH`X_{c2+2Q*l*run6u=b$2;q8H5tD9nVFc)Mr7UnEUv%1#QY&nRX z3~FXU13AY)kpbpT_jq7JnCwCrpYGIu>}VK9j_=&~(HzJvy-gIoD3U2qOeHV+7LA!L zZ!p~~PSUvS`6SCUDMKZqwvGW$%ktf}qO+XIGGX0LC#*fC)lxQLAK?}@5H{2fVZ)G) zmN%*^^2YkoZFzNVap?w44<*1dnk?&3r^_t!gtZqamgSXwWGXsu$XGQ!M+z{_D)|P0oW!x5@dGOGKgIFYy ze8vGdWMGiw5~rBrnSQSLXKvETpMS9H=FdNjJU;8xWXB**-g=U^+`Q#vZMfMfT>M#b z3l|@qbv8Dgg8HPOx&_tAqJD15IXVC1vU_s=;iW%5a2Kw-3sraFb7$vkuwqGA6~KTc z;R^vMU1+mqdRG9`0KyJH;Nr*oSyKjYYuJB`QL76W*7ueV&pQ2!Ibu@Z%#FhEx!j6!xLV+c!lm~{|eLV zDPIKaMf|egWgn6iAlc{KvH=W4p68(=_|pzo@c;b~Il?*TaBuhzq$yq+aIb?0NjH1; M8QVB~!>(u5KPFn7%K!iX literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0028_cashiersession.cpython-311.pyc b/core/migrations/__pycache__/0028_cashiersession.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2bff5d3436a3f3e5960edffee1f12fd176aa66d GIT binary patch literal 2584 zcmai0O>omj6qaOJ{)v;=kRRg2B!TebP+};g^uTm5`GG(j0uGtMbViZ28%IHwj3kF7 zQ#u^lnI5?{$DY!5;sb{sIOfQ4GoyoNPo3#0H#2bJ)VGrD0%4}I_1^03d!OF!``+5W zcXmcOxGwMfti6#q?jQEhx`NHYyG0oM${`N%I#=L93%XDa6aqZ61$40-ECkC^LE<@q zyTu{#Ck_R1a6Qxl+6{2r9^C#_2q8YtrKLmmxRB;)*v5{d86`U{&}dmJS&E~XhE1ii ziLh>~%{Wi>G#}nw7g$c%%cme9Uf^(GU2M6++hH~SwadfX;r6eRPzZUx;g$snC;*no zy0;U|ibVJXkyH!q0^(j9byYxN&$FW)E22m(x(m7N!R=q*)p5j2M6p`ur~3eYU7la8 z6^Xi093{}P+VLar?fJ}81m6T?*<0(|g*xrEYQ+I+zvtW8Mm>QBN&-rvK{QlL9YH?n zd3UwFMKoL+IkKWr&#U_*uTyALxq_iJ<=W>Ymbh%M(8veLuYDdcYzmsZEirm z=RU>$U&Iy%ICT2sI-~Qo^yjN9MQY=puBF5mdeH^o-&Zt}YjF*TC#t4}>D5b@zP=_a zx`Qnl;SEj2E#+)gu&gTfnuaaatQz29;gV)M))wuW^6hzS+rV5ZXlQAc3UkwGk;as& zW6G+96$c~QQL(hLVr|J!@D`2O*wPeT+r~7ufvuuxW7$y3m_}_!u^ida%6L1PXXBA2 z7(T*R_RBY1_!mCPEcc4p^O&Mt=&9R%{s&3jJfp2$D z`Gz)H&|+n?2ACLRqL&G81rjXRsj}{u6xGo-FqN{NW)=nv8z(V5jI5Iob;yvY1RKMm zL>f}pOsJG?C7IpJO~*#bS@Yq8hUq}^!3Cz$f}e-?;!v}Yw4+&TR%CV@d1bV>I~XS> z{5cw$@~fT>c?dMFYh}%mo9~t#(_0aZm&RY6_tCKI0m(9r$}${{RUN}PCd*H&iq4#6*;2pj5_#mY^)vk#YU%MbH259Hjv>6v*NYkO$0M;%ihPjl?twb+qDV>h)@ z78pFs(x9EwupUN5|1mc0^TU6NOsy$abGU>z9e)^|g+0_t#$6!1gw_?KWKsbYY1rE& z)-B=u%#ytDaDE>4B%7bgPS4ONaJBg>@F({U^58zqX4cFy&Qy!gdescx#42QEWuBSV z6T1TJ%&=Nz{`>XFKqr6OYS?B)Cn{SOJ9s?7&VPFd`2V8)X-HgTj<1K${StM<=l%%0 z=WiT@vu-%s2nKqj7xRr67a3-AC+msPzZ1QrfBfZ!+duwVd^1K0GBGUDZy)sAZof_9 zPCbz#!&i1T+~F(xJ!ENx3@Zo2iaV^3c(I-sB&o|g%WmrOYjOW7SzaM2MduV2}_Dk_A78 z;1eV{zH`=1j=$>JzeSSs2g!LiIZxubdLl`NF7C{_Ll<97zsZruh}^|QuR!2)SOcIu z=VyJD^VPDiWQJ`Bn@l|y?gT(R3KW@2sR2jybM- z<4!KPlgk8~#Q6a{t9*_@eJ^09lB;YPAYle1!zc-jf@ybcT~KLy795M MY~uYFX1%Qb1yGg1UH||9 literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index cc3eb67..ccc705e 100644 --- a/core/models.py +++ b/core/models.py @@ -412,6 +412,7 @@ class SystemSetting(models.Model): class Device(models.Model): DEVICE_TYPES = [ + ('counter', _('POS Counter')), ('printer', _('Printer')), ('scanner', _('Scanner')), ('scale', _('Weight Scale')), @@ -445,6 +446,35 @@ class UserProfile(models.Model): def __str__(self): return self.user.username +class CashierCounterRegistry(models.Model): + cashier = models.OneToOneField(User, on_delete=models.CASCADE, related_name="counter_assignment", verbose_name=_("Cashier")) + counter = models.ForeignKey(Device, on_delete=models.CASCADE, related_name="assigned_cashiers", verbose_name=_("Counter"), limit_choices_to={'device_type': 'counter'}) + assigned_at = models.DateTimeField(_("Assigned At"), auto_now_add=True) + + class Meta: + verbose_name = _("Cashier Counter Registry") + verbose_name_plural = _("Cashier Counter Registries") + + def __str__(self): + return f"{self.cashier.username} - {self.counter.name}" + +class CashierSession(models.Model): + STATUS_CHOICES = [ + ('active', _('Active')), + ('closed', _('Closed')), + ] + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sessions', verbose_name=_("Cashier")) + counter = models.ForeignKey(Device, on_delete=models.SET_NULL, null=True, blank=True, related_name='sessions', verbose_name=_("Counter"), limit_choices_to={'device_type': 'counter'}) + start_time = models.DateTimeField(_("Start Time"), auto_now_add=True) + end_time = models.DateTimeField(_("End Time"), null=True, blank=True) + opening_balance = models.DecimalField(_("Opening Balance"), max_digits=15, decimal_places=3, default=0) + closing_balance = models.DecimalField(_("Closing Balance"), max_digits=15, decimal_places=3, null=True, blank=True) + status = models.CharField(_("Status"), max_length=20, choices=STATUS_CHOICES, default='active') + notes = models.TextField(_("Notes"), blank=True) + + def __str__(self): + return f"{self.user.username} - {self.start_time.strftime('%Y-%m-%d %H:%M')}" + @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: diff --git a/core/templates/base.html b/core/templates/base.html index d566c76..b8c7d18 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -296,11 +296,11 @@