From 82a5fde6bc587f33c20ed8ab9f94cee654990585 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 6 May 2026 13:51:55 +0000 Subject: [PATCH] update index --- assets/pasted-20260506-134907-6b1d58c7.png | Bin 0 -> 13855 bytes index.php | 19 +- pages/barcode_pos_script.php | 90 +-- tmp_barcode_pos_script_check.js | 843 +++++++++++++++++++++ 4 files changed, 905 insertions(+), 47 deletions(-) create mode 100644 assets/pasted-20260506-134907-6b1d58c7.png create mode 100644 tmp_barcode_pos_script_check.js diff --git a/assets/pasted-20260506-134907-6b1d58c7.png b/assets/pasted-20260506-134907-6b1d58c7.png new file mode 100644 index 0000000000000000000000000000000000000000..61911659179eb435a557fd94e5bfe7d87017df64 GIT binary patch literal 13855 zcmdVBXH-*fw=Wu0KtaHUU<6TV0#c+Z2nZ?=klsTFX+c1NfP^YV|4NhIq)87X)DQ?w zML_8-0YV8%2}$S>kkC$i-@Wg?U+x}ff4F0uv&Kj=*IG~3dS+Sk`OUK48|Z1Wu>e^B z000|E>xmHna3+dQr=Mk_e?KRLU!eam_!?=d1CRqeB>K)7S2bNV0H7v;_0WNlzJKne zmZdKMz~1rq!_e(r_8b6^s|P(%GkI;hIumBWIo`UyslUVR)At5%dr#!sD{&1iAzjc_`ew9w%^@0DG{*LwY|G!x( zu{x#BEdL3&ab}yie~D=JSAa96YF0+p^Xt-{<^EpGfPCMXOBY}pnQDr;PREr%(ljiD z=SP)UszA9Kvo`Qk_OK_gUhpKMZX=6l!l2+ZlAwbLAe5|y^?xy~K;o{N=eN)z*rnW< zVNtkOKd9v1m!`o>8I&r%VoVp|7tQdaZ*wsQoFMdf4&xJ)h=v8L`K232`*T^Q=9EBl zt6#yajrUSb0$!_q$<6?w&qP_TL>8_Yq}sXI?rXhT+lye?0?G*%gG~jY+7G7}8aQXl ziu63Tk7qA^Az_$2K{a+w5Cco+mFEo2;?2dlB;9Bsw7b|SFfh_u_?R5Oa zl^TsxA+oUSQ-TU%pj)k+LLkmn^fmLPNvqMroNUFV-7HXf7s@^J(v-9oCZE{+@M%N( z?aB&t82rV0KHFT$Jn)_0P@b5Um~sxDTbV4McGYUvfx|2U}i3H^Sl>dn-g!D z0e#ETRF{NFtcZ{S)SwDDgS+UB8k(HzkB<$p5gpf0mx&fwH-`T@{i*xndi}HaAtmjm zBX$)Ssi*#PWm8wK`ee6p2}CneM<&Vf>??pa7V!|h?AV3fiSApgd(NJdl16^hgR~Fu z9x?oW2|6!`7);5S$``*Dr%2&pPB`z*yKSPdj9>wArc-TE6aj+1u?FoMF;e1{je$7a zgV#5KzB{m9B!EnSlp^J?6nC=3@8OSwTh? z*6q93b1QP|3?H-+;D^$6k6$sqODg)F0%-qHh=ipZ1bd@E=IwOv}OF`-U6yb26O;TmZ? z;~-zwy|#|oz53Y4cuFr1e5(Tb1?nRKf*8H=lv)mbCY|uWbf0sT#}yV|hqZhCXL_*> z7Z(HV9BVyMh&&Q^R`Kog97;<8i)^xspMS+9;JMm>vHZ~dnDJF@3FjY?Z*W4LDqnp- zBKpWFj&hsK3)|TURL(oeyz<_+3Eq(o^?#rEa@)AP1f2H?Ng1f&M=Db5Ad)@cQPtUgJurcg9xLF?3>f+ zO&&u*@2;B~@D`z899cQ)wEL@F3+zW=b&iqAUyl{7W)>QUaN7_6^xfqAUcP!z&l_OF zzM$Y?sHZwJYBZZKE)q7Ll765a2*v&B(2Q>qgo3R$=?){n)i(j8 zuZ~vJ4IjHB(nd6nby9K<2h`^(sJOmkHcNosEJH8+*x7k#=6(|PC+!5Y)AZ}^$_Kh3 zS0ry5Yb2#)%nDFb$0oqST1J$h4P%Y$`cl@cqZc_X7|^>A!mSX~kL0R7Bl4A8^0Y7p zzSw-8R9yW*(oepqip40>&p-0oN;CfxMS_oWopP&RY1>dYQWX)B;ql03X!{)f!4gxd zE_miV`pLM-+Pt-I>ojg#XG9f5%dW_pYO|48-e()Rf(;DrPfl*hUW&|Jd=!fMR`LL^ z4T{b+*YXIuQ|^{oN-582$?*aAPI;WzH9y6S?HWM5tCEwM+)WKoH~QO6y;09pPj96D zb?zM}WfA!_T=LR!(hH|c=(f`S`vO|7%Dc|&*hN}85joNIILR-j?bhSG#?+>5zlY>= z;O+z={q^lHZ&^s!#{VGcYwCc9XY{<1+plBG-5n>d-ibR!Rni(Z@-k>82%6pDRlqXB zkWG1a`_1afQ^@woulGk`L)4Q=FfL!5u9NW}id_CjB+^4m&+eN(ymh=3ve}~fa%=T0 zjFPI61I>*@U#qC+lWAHyUyv4^=c~SxufTdC;P%}$cIVhvY5tBW{Kkyt&U5uIDRu3- z*BYqdH+U919Zhp;<$Qu5uRlH*BMkVr1ac$t1{?!s-12Ug3Ni40I&so) zRlh}k$(j%!?~oAhIL9`9A6UPrD>9#X47@MCLGG5yrPZ=O)5COZTDR6qm3wsVWHjQ9pj&Fjq$R-xQ}>3trN$8s8Tl#&6JMln6fVLHMT)$$`r+p zS*0c#2nRNPCT1$%CX47)rkYn3^41I18yXe-BKg!m*zTDep0gF@V0jVOXl1GHi8KkC zW)9EJ%QVH1F?-jR?hz4&o>dzKyn>v-+~Xz3=5M9Nz0tFHqKjOlz_a#jMN>vSo@+^V|B6~q(#B}F4TPd43r z3N8mnvkrUitSqDot_aDB*{tJXc~9V@!B=X7rNJ&#e*b|siATbDGLn$j(7R;~`lb*i z8=&W8>BnZi0A7*Z*-++i{e#+w82}QLy?tenIPP`sGH(CnRJf-{*ko$x7KSlOabdSh zx!ryGi!~unVYs*A7YprmT^RmSivx!M_+fvlcTO)wWv^|Of$P!WOWsI1uWnumGe2bE z{2G?chk?+UrTRs;a51=H-q-Q~gR#vK4kA^YJIlZe36dL%esdF$uhhg=4fcC@=XCgW z8`DtKfFA4Zn`iPL4`BDhuRjVyK2GVuVK?hJKY)`mj4b-!gDEUBX#L?ZvLWTz@Lv+=R0oxXSDIy z;_?4h0P|nh{%_-)|M9SCNA9=3?w%QXzr@5FqHNq$OihZA6LF94V#cG3-TNCHO+!WZ zXE@7AbxU_{iCTol&n*82EqeVN^WM^jYrFv}dX^Y1X^0i+b~cc8w(H%GvSFq5W|)xt zuJ429Jsg^M^3jEkzL9zh-ewwJZ?rx7#*?KaEzj{E@p3j>a4DRrntH>myBOUwnSz*( zG=&)DzwLT9oIvcNv{fmI`WM^CnnLUbG(3A0rcS~OjAfMqkwR}_!(|MB#&g&!USs%~ z)B(qLzqBo`l{ySK0{*bjgGCH^UKuPc18Q6?>(znz0BZR8&xIe*AZF9o_DP#mLbwV+bW9+-BlHc;2muJr9TOh@pOZZ7-q(%3Y>BU}(c6J<))Q zK$PfB72Wm^tmENd?Bgs`%DFVPjSxOQmE)tun8u5*3G5Hc6pKO@ldd461h#8VGigAE zTP%Eo0#mWam>~(^-ZJ%&2{dxlD~)pVt7ba$)`NzZ6+EK_k-*W$m6~BJfG_>sk`Ik8 z3u{`bCIa13Ie18-F}UwPF9L7+La5Co5bbLecU<;`!VJsa6l2HTyb{M^y?=%q&-tbr z&*q1a>aNJ#(wGlzG+Gb6Ti#^0j;!r*bQOUnIDMa(&M%xwbJwVBI(en~Y$U5i8mp5e znku8D!Ril&21wu<&)w5jo}g{el03oEVz}UysB19AkOWa~z$xXc47c)iG?t0X0e1v@ zI`ATxBB0pm+c&?o*?!22Sg$8@@r|DYX>zP7oP^#1Up^8=NqV5t?%I?Ht{;dv470S3 zt?_JYbB5UW8|GapzSjVCWQvU+xe0=(6me)Hl8;3z$d7mZ<{rgebJd-BVDW;96Jx}s z5H3-FTAyiPWY@S@R0;KX`$b)277%gK?os%)l@;ygJ0iH|q@uIBJVda8j?uc7@&)H( z@T;Qwqdo-y0EVHdi@%Q_9;NIpYo%ru`_k-l)4DZD%#%pe*(?)d)AA2+>5z}|#`*|J z90{&%$}?3`nyet|@v1U+prJ>PQ_N%bJmQtO>5z3vB`Fbh82ykl2R>H(7EB*mNFD4J zb#X7q5|FbgGieq3GCG$30j`a;2+JGDE%@;#wMW^)#pQx2?`Sh6Sylp;xtn=W5THy? zM&;`qat^Iw?tTTjES}=>3^FdY@u;(&E)@5+G7lwFOeM>AKko;G6J9Cr8N}vl_nLWm z<@$_Ej*c<^PQliyBpOFbgg73{uSj&m?iTzq6ZMId!0OPx2TO>kN2ZnBNxglf(Ko{| z_rZIqId^f_>-YuaNLpFG5NPr2(S406oexmA-n-lCzY6?{(^QLB1v?dU)1T{IHZPu? z^mLxf6~U6iUq+vQKVJ1g2imfb5nmOTCV*X7BF%K!_YX*7m)vp2&w5QJ%Z(60S|i0aIWIneu?=W;9q(?NPZG8U z(Lo?FB5&D$8k09&(u~POat_%2(HM(o2Iq^^Ac6!0GS%Mvfq-ohqMJ>M6YRj#7dD>H zC+H3<%Nv`r+Y`^Kc;~E#n58tn>FDq!x>F;xBlPwl+r5$P7+B|4aXbT!P=1+zinCJfaV3pm z6Smpu#>TQ?{^iS^)<5bk4@^s244&dlcmsX`cf_~RAKDdRRJe?y(-CY+H6!!(QhlAa z>3z6aij|y=FxjR&=K3Qpyqc@ZY(c40@{S&2LBXfyn9$XT>l|qwl2BJ)Z)g~6xb`yl zfvZiEK;v1!h9x4i`7!fUZBUTr@|0P1>6ViwGal4V8ZXK79vZF`h-(fg`}R%~vNK`P zKVh*_xnQVMvOaW{4W+!E{}mTg;e(Jon=eeyoca}(#Go)dJQZBNtfu~O6K6rCor+0* z6R?|J=Wu|gTSn0rrAokX&Ks8cfZfxl`p@%&Xwzo1pXD-4!WJ5>b~Q%V`>F4Xv}U+& ziTv@JnXy`$n`=}KDg+gGBQEc(vn!NxL5n5405)#Sydu3gj?c+dWa_ngW!E&O$tfpu zeCNzXvyCzfzDAt%M}eHNiyn7@Qo*mYm9`lGb7Ed~vrPaeCKMV4rvayroHz?KaPU(ak#LY_*ZYsZm>#?1m4o&R~4qu zZQRNwEfI42Nefj`-F;Z-JKbEzT<$!4N$j3YK$_c7Tc4+*IEaDYFAwFS)Bp7a;-{!t z97kzB$kvs;Y}IT_bYbGGcjgZ<0_F3O!N1n z0~-K9xLkhj-jeq&N{F&|_-+=NUSuDaP%pu4TRiexeLKDUCrm^|yMu|T zXFZmpp2(bs)-z;%A1mEmLY+c&$|2n(M!g#>&7qE;WlM_X!*hRM?U0I1YtOpww?mah zOqx~p=%1Ez>1@6-~pNN-M|La=-l2dQG2FZ!l>uwH1YLy?g6F-fUF-uC{Mhz=;7v(eY7 z{fX!9UYT05sK1LS6?G~Vr**pRplGQ-X8g}kLrpXtMQGc!>pmr_Bok~BwKLKyqY~ql z^b{19pB%e5FI+9FUovA%h#UX>bQ7~qS;H!ZXx$#geDfm9vN$&E1rx)edSPnqs@&cHZQ#D= zOg1tq=%{#!32P!(Mz_xQwv`ICybQU>u}-!xz5a7GY@l={MdTE;*rpLT#6p!BAEGrD z>;W?#QLP6KGiNkY+Ou$+|TImnsEi z%er@eK+@g$Pld%0HKglHjp}TQHLeNq)-NDRNWcs7UgglJdtguh3}Q5H03q*uo%*6S z(0q~OlY&OMR};q;@@^r{yzTo z;vVu+ht$9edB^qlQa1=-Co#XhZs@Sagz|PAS`w9J1M{xA_~3QQX5D9;bk$y%SKURW z*EKccQs+C$q~w(^IS90lWA;aaV&Z-B+t=6n*Q@JuTcptWCg$6*6P+<} z%j^kHIlD@_Z^!P^0= zF(EU>CL?R$)RKF_Axe4s?W>;+RXS6|WvoVQv)dVoJ1bZCR}%ZX?7$5x3c1a~-x`TOpMh_bGa2!De0yLG}b%ar3?M4inGSq7EBHoQ5$NuY+`JWUJftBVpCnYW* z+B4nVXefo1TIbveY<0}+vhz60+c-<3c|6K*KWzC?xp@G~XF5}#yosCAX9&rOmI!4z zdw#{fIWF)2Qy~{BC-;j*bz+ikXd6$8c)%pR6hj%_%KAWSnGSC zzA53{t*~kfiqKT)yM2%4A$xT58diZ3GP3hrm(Q~Tr=-4@@R8ix3wF`9p&lH*&c=Cp z41F&uo#vYgepWt66nXg-BFGL6J$;Pv9ya6j))@)ORq?wncGCpT-#Lv>twR8n{7ESIrrVrpkGimAFi?a(u+ASoCN{p`|q%CzeVbk;iHdjwjfh6ArtNoh@5z(M?k{*d6yZYDJV6L6g zoFM_xwz1UP1%(X;lyr&F2+MmPo+%e ze8sx$_qoQ_wE=;PUFKF!wZd&peDqE*2tV?IrCs)3B>5>#Dhm6gyZ;;!(2a{Ve(U1y zp<$iV5dFC}Q8=FHZ3k~CI54%+Fs((C5VQO;{s%U_Qjcl=kpQgiT#E5sR>=d)^} z!C?PhpYsPv??i+DSrwi{6`cn7&5$aK!36Ho^s9kq{U^rOEerBm`3h1vd71S;WdXAn zN_7JB}tG(Ip0o()irDb~b2s_0NpA zi?;VBi$W+e&~KT%W7Z|qUU|4XjitDrON)F89X^y+jCc#s+q9;Q-F=< z&Ory#>jc%K`^=2A@=V6Z%&u~5;^GHx74=_xT@c;(-TEAK+gMf;O{K>0dZBsuy8hG~ zrRG46CRGJyuHMw97u-(+@|71SVg56Wx^}2~LBo#1F7@KJ>c_W!l4h%XuW}a$ikUB) zSFMk4eoF*zZP(zZmd18GNVc9O2#Jy zbXDAUe(~Uiq*9qq{j7FIH{b_QB5f`_Wr-!*)9|6;ms2mhHX3<3K`&m;3}4TaueqHBWJZ z22P!i8#rj&CH5Qrv;BrHq(=#c<(2L({vRK#`5$}!D+$V5gU=&;{nPl+%DB*+@_ne2 zclb-N{!#G+fQ;_ifIROMPV~ zhF&$Y@_J58?B)@^GrY`$uTE_@rYlP6c8@nRM`ig7h&Vd5+A3xsNM1jMqQO$nkpq5L zpGgkl#+G?u&-I04s0wRCqaDen?LO@d_}nsjprw4Qg{ilHH=8lK{uv$nD2>0&p8*jODz&x~hfR>JmkP{NMz~`0* zSohlZe&TENFfTskSg6e8QKY5&PoiE+Zt3OzhTk-0{C=C?Nzom#RkG-wT`uAT)nXeX z-w=8hWts|R?-+P{Y#0ACH+$XB;I;lvKw6N=b9fhR2sQ*vpq2pW7mnd zTFDrImKhu@5HK(64+PrD^PqY9Q2RAaB8~0R8 zuYK`XJdk;56xK*gr!Cq%)6JsROvX^aHa#bPehSa+0iJEiVtG3#)32D`y zv(3bNPNNSh^!ojsaA^M6A7L}z*8a+CeJ=dFxo7#eCKX~6AduMYuvzcJJUR%fW=;bJ zsd`Q}2OOXe4r6ObHNWTpL&mE!ELaeK)~ba-hjEQNT|E3NHFP{O4WSDMpiHonSH?+8 z$eVI!-*_+ejY(2|7q4yA%O6{<$*pvHS%WBly(V(%L1{o8K?}%32Y^Id*aFc|V`A=( z6Ap9a@~~hjwq|ef^?WWJ&Ky$Y8nSS&UL3FCETTFR^E9tH>^-}ed$4+KK3F$ybNEM{ir(q-)@s2yi({VYuqNgz+wqkIJ4zdgVq%$?`#|H9CXC{2Ts7EBC6!#Gk)My~}-$=Xw;kjJ0-x zTQNRqYX=xhqeRZqSMJE`Joh^x+vT!x=`Epo^aZf1({pTS$BBkrXlT;N^?PXAI4|O~ z#&Ao=I0PXf$L#iHyfuhHLYK<}S{@M2bjI(nv0^4HW=RMeW+XXtqbxlBYTds(4i#Gd zrnQPZ{<+-P_?wa84OvQdcp^Wm#7Zfwt%M0XW{304Ssm1w*;Q$N(;a>xoZZ^X#AehL zgRRP=%`Q#fDc}D9JlQQ*p+K8y`+JFFWyaA@F@<^y{Ye{nemY*#+`K(uNeoh{f-p9x zd1z_n(_pZ0g@c_EcDlmCum8>H$3R%pJib=-78|~&wX0s6Tzc}S=a(Hh?0D;+E3_ya z;!_brI!mg2SRFan8Zicnm;GKb_Qx=H#LRPia*9UTU1EhdujWzbiB}=&AL~krH|u@I z+bR!hRakb?ArzY1pFU#Biy-<xTn!+1bL=;~e(O*sm*g4HOpMR9TlVoC4G>I!sIMk<}gW|2K@9xwRHf?=EekJ2YMRZ^x z%YYSU%Op{lp3n$1dd&60z>Fr=gHM5zLi|ZsaXzv(#rRk6$l`jTb(2RJV(^BZDekR# zN}EG+?NT&(uJ;5HPJH#uVLhk-o%r3f?691vX3LWXv~^rqsQ$_B);5jQ zn~gds?81?WtW z$yuY{RIy!0@Fg(JrRm**%wMPj`>Kay!PoVgs~kWLGQ#?So9&$$|OfDy-iLl zV3M_6UaLc0q707jaDw+j*J9Lwm%JobN^k9j8lzINnBQ2HsxtUi#2QfcN63fi{IhH) zpRHXhR-+q_k-ra?w|S4&&ACKN+7XpIdy2Ca?M%VCwrh08^zz{F!+Jel)pAjykfkvy zts!s5zke;GXzWuHkj_&_r_)X$2!n^{+x=-nPiow{5CXU z?apeUN^22bpXZuRl3%$QD#Y7+JBzl1F@?7l#n`Ua=|NE=s{@?>1kv40mP3T3jzTbB z9G|FDM-Wg-S&z{A9}FDHI&6C2(-g7Fb8fotKiCERKAZ* zQcIagz!^wS59N~@BfZpa8L|u|kH@>>cSDR_CQoh9z04dWgkRfO!)9o$Rk*)hhZWVl z8T6rv;Cr)M_vDy7zNMMZ#H0i9uNW@q8l)#rpetLPlS0LT3;impo?9Q^L{;^fhVk`d zMPKimriLC^ihE`Xxox@R&5n_VYMylpw}^@d>rP#b_xGY!BR^(}_?l8kJiR7|`h)JU z0XhfUSq+PoxY!=^_Lj=)K~iKe)5^F~G7De>>p_x9L%YN)@%EYot0&%AfwV7~hCOG> zVt<0!J<7rqR;$x-{u<37~AiTOqjRuR5vq*AaBvz`y0vu<43P*-b4aYmW(XGE{RXH-YGH%?F99hS+8Zb1L(|aP2okMpz&)hKF zJoMldUa|_Fv`~&ONz2UO?Y+GDOdx%{{dV_?t*T3|* zU&|pJWJJypN<-oVs+yn#J5Y-C_Huy^q1e3GVZnTW-j!_C#NH4i=6Li;e$ zRSKv50pWwSd)N4X%kuA3!6BEU&SB5%AAyH#FcpQN{l;M?!wtJO`U0@V)!>ic)TgY3 zFMR2b55MqIS6vSBEG(qjp-_eUq2)c7;6=QjPx`&1?dQ7NVfqw>)Uve?MZJqX`h&ye ziOI6R*io$&#_Q{M{I%^?CqI@GY%sUw?1r0GtH`K?wegg5W*Ua22PsU?GK$tiQwr-> z7cnDuZJJCz$Fi-Hc14oq4i#OW79a-N6TqvwcID=*Hg94ya(-AA)F&DAf7&KMgPd~6 z5}B%TX5aLQ2Rq1kC8AAN-}xLe$_!7#KaQV!hJcGMa+jG=UIdnXn|4K8R*IyjF{lw_ z`GW51TghndUoe1@o+>Wea3w6i+(Xl>Ae zsdfbdKY<+Fg+m*x&0hBITL2#E8yg>)D__{>wE{Jt!41X3$<} z&CKz#eIoy9_xh3`>pCP|Y+w4<=oOyxuD8N>u~+VnM|{2qMvq|Bw|@q~Zi#4yNE0`XGgnxN4-ygV8;s+#-2xan3!f2Wfw4VAmU9|X**FPMogrh*cs zjT9)6+e;$;gn!DlZ7-DG3K1;V3o@4+Dv5ce4HaLQvM!CxHX{?*ZKd>k4m8~G`eC0* zk)Arb0gd{`^O}J$YU--u@EuUdmHWFQt$*h4k%{*%gi{dn>+|&uLddbTg7-Zzmm=CH zLUBsoF@6>KT4I-E#k)Rwpon-_uc?3%wZK?Z@gAAzo~-&GB@4vyBAD54jI61IjjG!0 z3)kT-_D-%Tp-=cI>-CWXVE;n7`S#L9Ubhnva7Sb!P)8CP@IFfc%C^;zGS4Rmc3t#i$ zqi%Z(4=pUJRLPE!dOVL7S|+cw0mtVLHvan8eQBOSS*|aKBTNre(g1*> zFWn1;iip3oaXS+(dC|BlJli6#jhERAzdVZWu>aUH?aFsjrE)gh>_0C=QuIx98+YvK zmg#RU7`t-UnhhF6@8*(!Ub#E&9(C=JcNrAL-}*ZgWmQ{<{}^{^yNv zM!V^d|5uA1-SYpR7k@64#QsOG-v7z30A-wTlxSnm+50Kz{}mAEsooQ$x_!j|0{9sK AF8}}l literal 0 HcmV?d00001 diff --git a/index.php b/index.php index 0a12037..47d3759 100644 --- a/index.php +++ b/index.php @@ -5887,6 +5887,21 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]); .units-table tbody tr:last-child td { border-bottom: none; } + .items-list-heading { + font-size: calc(1.25rem + 1px); + font-weight: 800; + color: #1d4ed8; + letter-spacing: 0.01em; + } + .items-list-table thead th { + font-size: 0.82rem; + font-weight: 800; + color: #1d4ed8; + letter-spacing: 0.05em; + text-transform: uppercase; + background: rgba(29, 78, 216, 0.08); + border-bottom-color: rgba(29, 78, 216, 0.18); + } .units-name-stack { display: grid; gap: 0.2rem; @@ -7181,7 +7196,7 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
-
Stock Items ()
+
Stock Items ()
- +
diff --git a/pages/barcode_pos_script.php b/pages/barcode_pos_script.php index 7b4cf13..764941b 100644 --- a/pages/barcode_pos_script.php +++ b/pages/barcode_pos_script.php @@ -98,13 +98,13 @@ container.style.width = '100%'; container.style.maxWidth = '100%'; - container.style.lineHeight = '1.05'; + container.style.lineHeight = '1'; container.style.marginBottom = '0'; if (arabicLine) { arabicLine.style.display = 'block'; arabicLine.style.fontWeight = '700'; - arabicLine.style.fontSize = compact ? '0.98rem' : '1.10rem'; + arabicLine.style.fontSize = compact ? '1.04rem' : '1.16rem'; arabicLine.style.direction = 'rtl'; arabicLine.style.whiteSpace = 'nowrap'; arabicLine.style.overflow = 'hidden'; @@ -114,7 +114,7 @@ if (englishLine) { englishLine.style.display = 'block'; englishLine.style.fontWeight = '600'; - englishLine.style.fontSize = compact ? '0.84rem' : '0.95rem'; + englishLine.style.fontSize = compact ? '0.90rem' : '0.99rem'; englishLine.style.whiteSpace = 'nowrap'; englishLine.style.overflow = 'hidden'; englishLine.style.textOverflow = 'ellipsis'; @@ -127,21 +127,21 @@ } container.style.width = '100%'; - container.style.maxWidth = '240px'; + container.style.maxWidth = '260px'; container.style.direction = 'ltr'; container.style.textAlign = 'center'; - container.style.lineHeight = '1.05'; + container.style.lineHeight = '1'; container.style.fontWeight = '600'; - container.style.fontSize = compact ? '0.80rem' : '0.92rem'; + container.style.fontSize = compact ? '0.88rem' : '0.98rem'; container.style.marginTop = '0'; const row = container.querySelector('.label-date-row'); if (row) { - row.style.gap = compact ? '10px' : '14px'; + row.style.gap = compact ? '8px' : '12px'; } container.querySelectorAll('.label-date-item').forEach((item) => { - item.style.gap = compact ? '4px' : '6px'; + item.style.gap = compact ? '3px' : '5px'; }); } @@ -186,7 +186,7 @@ priceContainer.textContent = label.price ? 'OMR ' + label.price : ''; priceContainer.style.display = label.price ? 'block' : 'none'; priceContainer.style.fontWeight = '700'; - priceContainer.style.fontSize = compact ? '0.98rem' : '1.08rem'; + priceContainer.style.fontSize = compact ? '1.04rem' : '1.14rem'; priceContainer.style.lineHeight = '1'; priceContainer.style.marginTop = '0'; @@ -194,10 +194,10 @@ previewContainer.style.flexDirection = 'column'; previewContainer.style.alignItems = 'center'; previewContainer.style.justifyContent = 'center'; - previewContainer.style.gap = compact ? '4px' : '6px'; + previewContainer.style.gap = compact ? '3px' : '4px'; previewContainer.style.width = Math.min(Math.max(width * 3.8, 185), 310) + 'px'; previewContainer.style.maxWidth = '100%'; - previewContainer.style.padding = height <= 25 ? '10px 12px' : '12px 14px'; + previewContainer.style.padding = height <= 25 ? '9px 11px' : '11px 13px'; svg.innerHTML = ''; JsBarcode(svg, label.sku, getSingleBarcodeOptions(label.sku, width, height)); @@ -299,14 +299,14 @@ text-align: center; overflow: hidden; box-sizing: border-box; - padding: 1.1mm 1.8mm 1.2mm; - gap: 0.45mm; + padding: 0.9mm 1.55mm 1mm; + gap: 0.25mm; } .label-container:last-child { page-break-after: avoid; } .label-name { width: 100%; max-width: 100%; - line-height: 1.02; + line-height: 1; } .label-name-ar, .label-name-en { @@ -317,33 +317,33 @@ } .label-name-ar { font-weight: 700; - font-size: 12px; + font-size: 13.4px; direction: rtl; } .label-name-en { - font-size: 10px; + font-size: 11px; font-weight: 600; } .label-price { - font-size: 12px; + font-size: 13px; font-weight: 700; line-height: 1; white-space: nowrap; } .label-compact { - padding: 0.85mm 1.3mm 0.95mm; - gap: 0.35mm; + padding: 0.7mm 1.15mm 0.75mm; + gap: 0.2mm; } - .label-compact .label-name-ar { font-size: 10.5px; } - .label-compact .label-name-en { font-size: 8.75px; } - .label-compact .label-price { font-size: 10.5px; } + .label-compact .label-name-ar { font-size: 11.6px; } + .label-compact .label-name-en { font-size: 9.6px; } + .label-compact .label-price { font-size: 11.5px; } .barcode-wrap { width: 100%; display: flex; align-items: center; justify-content: center; - padding: 0 1mm; - margin: 0.15mm 0; + padding: 0 0.8mm; + margin: 0.1mm 0; overflow: visible; } .barcode-wrap svg { @@ -483,7 +483,7 @@ priceContainer.textContent = label.price ? 'OMR ' + label.price : ''; priceContainer.style.display = label.price ? 'block' : 'none'; priceContainer.style.fontWeight = '700'; - priceContainer.style.fontSize = compact ? '0.90rem' : '1.02rem'; + priceContainer.style.fontSize = compact ? '0.98rem' : '1.08rem'; priceContainer.style.lineHeight = '1'; priceContainer.style.marginTop = '0'; } @@ -492,10 +492,10 @@ previewContainer.style.flexDirection = 'column'; previewContainer.style.alignItems = 'center'; previewContainer.style.justifyContent = 'center'; - previewContainer.style.gap = compact ? '4px' : '5px'; + previewContainer.style.gap = compact ? '3px' : '4px'; previewContainer.style.width = Math.min(Math.max(width * 4.0, 190), 320) + 'px'; previewContainer.style.maxWidth = '100%'; - previewContainer.style.padding = height <= 30 ? '10px 11px' : '11px 13px'; + previewContainer.style.padding = height <= 30 ? '9px 10px' : '10px 12px'; svg.innerHTML = ''; JsBarcode(svg, label.sku, getDatedBarcodeOptions(label.sku, width, height)); @@ -625,13 +625,13 @@ } .label-container:last-child { page-break-after: avoid; } .dated-label { - padding: 0.95mm 1.45mm 1mm; - gap: 0.3mm; + padding: 0.78mm 1.25mm 0.8mm; + gap: 0.2mm; } .label-name { width: 100%; max-width: 100%; - line-height: 1.02; + line-height: 1; } .label-name-ar, .label-name-en { @@ -642,11 +642,11 @@ } .label-name-ar { font-weight: 700; - font-size: 11.5px; + font-size: 13px; direction: rtl; } .label-name-en { - font-size: 9.5px; + font-size: 10.6px; font-weight: 600; } .label-meta { @@ -655,8 +655,8 @@ flex-direction: column; align-items: center; justify-content: center; - gap: 0.25mm; - margin-top: 0.1mm; + gap: 0.15mm; + margin-top: 0; } .label-dates { --label-date-row-gap: 1.2mm; @@ -667,7 +667,7 @@ align-items: center; text-align: center; direction: ltr; - font-size: 9px; + font-size: 10.1px; font-weight: 600; line-height: 1; } @@ -687,31 +687,31 @@ font-weight: 700; } .label-price { - font-size: 10px; + font-size: 11.2px; font-weight: 700; line-height: 1; white-space: nowrap; } .label-compact { - padding: 0.75mm 1.05mm 0.8mm; - gap: 0.25mm; + padding: 0.58mm 0.95mm 0.6mm; + gap: 0.15mm; } - .label-compact .label-name-ar { font-size: 10px; } - .label-compact .label-name-en { font-size: 8.3px; } - .label-compact .label-meta { gap: 0.2mm; } + .label-compact .label-name-ar { font-size: 11.1px; } + .label-compact .label-name-en { font-size: 9.1px; } + .label-compact .label-meta { gap: 0.12mm; } .label-compact .label-dates { --label-date-row-gap: 0.85mm; --label-date-item-gap: 0.35mm; - font-size: 7.8px; + font-size: 8.7px; } - .label-compact .label-price { font-size: 8.8px; } + .label-compact .label-price { font-size: 9.7px; } .barcode-wrap { width: 100%; display: flex; align-items: center; justify-content: center; - padding: 0 0.7mm; - margin: 0.15mm 0; + padding: 0 0.55mm; + margin: 0.08mm 0; overflow: visible; } .barcode-wrap svg { diff --git a/tmp_barcode_pos_script_check.js b/tmp_barcode_pos_script_check.js new file mode 100644 index 0000000..5a3cb37 --- /dev/null +++ b/tmp_barcode_pos_script_check.js @@ -0,0 +1,843 @@ + function escapeBarcodeLabelHtml(value) { + return String(value || '') + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + function getSingleBarcodeLabelData() { + return window.currentSingleBarcodeLabel || null; + } + + function getSingleBarcodePrintDimensions() { + return { + width: Math.max(parseInt(document.getElementById('barcodeWidth').value, 10) || 50, 10), + height: Math.max(parseInt(document.getElementById('barcodeHeight').value, 10) || 30, 10) + }; + } + + function getSingleBarcodeScale(labelWidthMm, labelHeightMm) { + if (labelWidthMm <= 32 || labelHeightMm <= 20) { + return 0.96; + } + if (labelWidthMm <= 40 || labelHeightMm <= 25) { + return 0.92; + } + if (labelWidthMm <= 50 || labelHeightMm <= 30) { + return 0.88; + } + return 0.84; + } + + function getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm) { + const skuText = String(sku || ''); + const skuLength = skuText.length; + const compact = labelWidthMm <= 40 || labelHeightMm <= 25; + const extraCompact = labelWidthMm <= 32 || labelHeightMm <= 20; + const showValue = !extraCompact && labelHeightMm >= 24 && skuLength <= 18; + + let moduleWidth = 1.8; + if (skuLength >= 18 || labelWidthMm <= 35) { + moduleWidth = 1.1; + } else if (skuLength >= 14 || labelWidthMm <= 40) { + moduleWidth = 1.3; + } else if (labelWidthMm <= 50) { + moduleWidth = 1.6; + } + + let barcodeHeight = 56; + if (labelHeightMm <= 20) { + barcodeHeight = 30; + } else if (labelHeightMm <= 25) { + barcodeHeight = 38; + } else if (labelHeightMm <= 30) { + barcodeHeight = 46; + } else if (labelHeightMm <= 35) { + barcodeHeight = 56; + } else { + barcodeHeight = 64; + } + + const quietZone = extraCompact ? 4 : compact ? 6 : 10; + + return { + format: "CODE128", + lineColor: "#000", + width: moduleWidth, + height: barcodeHeight, + displayValue: showValue, + fontSize: compact ? 10 : 12, + textMargin: compact ? 2 : 4, + margin: quietZone, + marginTop: 0, + marginBottom: showValue ? 2 : 0, + fontOptions: "bold" + }; + } + + function buildSingleBarcodeNameHtml(nameAr, nameEn) { + const lines = []; + if (nameAr) { + lines.push('
' + escapeBarcodeLabelHtml(nameAr) + '
'); + } + if (nameEn) { + lines.push('
' + escapeBarcodeLabelHtml(nameEn) + '
'); + } + return lines.join(''); + } + + function applyBarcodePreviewNameStyles(container, compact) { + if (!container) { + return; + } + + const arabicLine = container.querySelector('.label-name-ar'); + const englishLine = container.querySelector('.label-name-en'); + + container.style.width = '100%'; + container.style.maxWidth = '100%'; + container.style.lineHeight = '1'; + container.style.marginBottom = '0'; + + if (arabicLine) { + arabicLine.style.display = 'block'; + arabicLine.style.fontWeight = '700'; + arabicLine.style.fontSize = compact ? '1.04rem' : '1.16rem'; + arabicLine.style.direction = 'rtl'; + arabicLine.style.whiteSpace = 'nowrap'; + arabicLine.style.overflow = 'hidden'; + arabicLine.style.textOverflow = 'ellipsis'; + } + + if (englishLine) { + englishLine.style.display = 'block'; + englishLine.style.fontWeight = '600'; + englishLine.style.fontSize = compact ? '0.90rem' : '0.99rem'; + englishLine.style.whiteSpace = 'nowrap'; + englishLine.style.overflow = 'hidden'; + englishLine.style.textOverflow = 'ellipsis'; + } + } + + function applyBarcodePreviewDateStyles(container, compact) { + if (!container) { + return; + } + + container.style.width = '100%'; + container.style.maxWidth = '260px'; + container.style.direction = 'ltr'; + container.style.textAlign = 'center'; + container.style.lineHeight = '1'; + container.style.fontWeight = '600'; + container.style.fontSize = compact ? '0.88rem' : '0.98rem'; + container.style.marginTop = '0'; + + const row = container.querySelector('.label-date-row'); + if (row) { + row.style.gap = compact ? '8px' : '12px'; + } + + container.querySelectorAll('.label-date-item').forEach((item) => { + item.style.gap = compact ? '3px' : '5px'; + }); + } + + function buildSingleBarcodeSvgMarkup(sku, labelWidthMm, labelHeightMm) { + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + const scale = getSingleBarcodeScale(labelWidthMm, labelHeightMm); + JsBarcode(svg, sku, getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm)); + svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); + svg.setAttribute('shape-rendering', 'crispEdges'); + svg.style.width = Math.round(scale * 100) + '%'; + svg.style.maxWidth = '100%'; + svg.style.height = 'auto'; + svg.style.display = 'block'; + svg.style.margin = '0 auto'; + svg.style.shapeRendering = 'crispEdges'; + return svg.outerHTML; + } + + function renderSingleBarcodePreview() { + const label = getSingleBarcodeLabelData(); + if (!label) { + return; + } + + const dimensions = getSingleBarcodePrintDimensions(); + const width = dimensions.width; + const height = dimensions.height; + const scale = getSingleBarcodeScale(width, height); + const compact = width <= 40 || height <= 25; + const nameContainer = document.getElementById('barcodeLabelName'); + const priceContainer = document.getElementById('barcodeLabelPrice'); + const previewContainer = document.getElementById('barcodeContainer'); + const svg = document.getElementById('barcodeSvg'); + + if (!nameContainer || !priceContainer || !previewContainer || !svg) { + return; + } + + nameContainer.innerHTML = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn); + applyBarcodePreviewNameStyles(nameContainer, compact); + + priceContainer.textContent = label.price ? 'OMR ' + label.price : ''; + priceContainer.style.display = label.price ? 'block' : 'none'; + priceContainer.style.fontWeight = '700'; + priceContainer.style.fontSize = compact ? '1.04rem' : '1.14rem'; + priceContainer.style.lineHeight = '1'; + priceContainer.style.marginTop = '0'; + + previewContainer.style.display = 'flex'; + previewContainer.style.flexDirection = 'column'; + previewContainer.style.alignItems = 'center'; + previewContainer.style.justifyContent = 'center'; + previewContainer.style.gap = compact ? '3px' : '4px'; + previewContainer.style.width = Math.min(Math.max(width * 3.8, 185), 310) + 'px'; + previewContainer.style.maxWidth = '100%'; + previewContainer.style.padding = height <= 25 ? '9px 11px' : '11px 13px'; + + svg.innerHTML = ''; + JsBarcode(svg, label.sku, getSingleBarcodeOptions(label.sku, width, height)); + svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); + svg.setAttribute('shape-rendering', 'crispEdges'); + svg.style.width = Math.round(scale * 100) + '%'; + svg.style.maxWidth = '100%'; + svg.style.height = 'auto'; + svg.style.display = 'block'; + svg.style.margin = '0 auto'; + svg.style.shapeRendering = 'crispEdges'; + } + + function initSingleBarcodePreviewControls() { + ['barcodeWidth', 'barcodeHeight'].forEach((id) => { + const input = document.getElementById(id); + if (!input || input.dataset.barcodePreviewBound === '1') { + return; + } + + input.dataset.barcodePreviewBound = '1'; + input.addEventListener('input', renderSingleBarcodePreview); + input.addEventListener('change', renderSingleBarcodePreview); + }); + } + + initSingleBarcodePreviewControls(); + + window.printItemBarcode = function(sku, nameAr, nameEn, price) { + if (!sku) { + Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error'); + return; + } + + window.currentSingleBarcodeLabel = { + sku: String(sku), + nameAr: nameAr || '', + nameEn: nameEn || '', + price: price || '' + }; + + renderSingleBarcodePreview(); + + const modal = new bootstrap.Modal(document.getElementById('barcodePrintModal')); + modal.show(); + }; + + window.executeBarcodePrint = function() { + const qty = Math.max(parseInt(document.getElementById('barcodeQty').value, 10) || 1, 1); + const dimensions = getSingleBarcodePrintDimensions(); + const width = dimensions.width; + const height = dimensions.height; + const label = getSingleBarcodeLabelData(); + + if (!label) { + return; + } + + const nameHtml = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn); + const price = label.price ? 'OMR ' + escapeBarcodeLabelHtml(label.price) : ''; + const svg = buildSingleBarcodeSvgMarkup(label.sku, width, height); + const compactClass = width <= 40 || height <= 25 ? 'label-compact' : ''; + + const iframe = document.createElement('iframe'); + iframe.style.position = 'absolute'; + iframe.style.width = '0px'; + iframe.style.height = '0px'; + iframe.style.border = 'none'; + document.body.appendChild(iframe); + + const doc = iframe.contentWindow.document; + + let labelsHtml = ''; + for (let i = 0; i < qty; i++) { + labelsHtml += ` +
+ ${nameHtml ? `
${nameHtml}
` : ''} +
${svg}
+ ${price ? `
${price}
` : ''} +
+ `; + } + + doc.open(); + doc.write(` + + + + + + ${labelsHtml} + + + `); + doc.close(); + + iframe.contentWindow.focus(); + setTimeout(() => { + iframe.contentWindow.print(); + setTimeout(() => { + document.body.removeChild(iframe); + }, 2000); + }, 500); + }; + + function formatBarcodeLabelDate(value) { + const dateText = String(value || '').trim(); + const match = dateText.match(/^(\d{4})-(\d{2})-(\d{2})$/); + if (match) { + return `${match[3]}/${match[2]}/${match[1]}`; + } + return ''; + } + + function buildDatedBarcodeDateRowsHtml(productionDate, expiryDate) { + const productionText = formatBarcodeLabelDate(productionDate) || '--/--/----'; + const expiryText = formatBarcodeLabelDate(expiryDate) || '--/--/----'; + + return ` +
+ P:${escapeBarcodeLabelHtml(productionText)} + E:${escapeBarcodeLabelHtml(expiryText)} +
+ `; + } + + function getDatedBarcodeLabelData() { + return window.currentDatedBarcodeLabel || null; + } + + function getDatedBarcodePrintDimensions() { + return { + width: Math.max(parseInt(document.getElementById('datedBarcodeWidth').value, 10) || 50, 10), + height: Math.max(parseInt(document.getElementById('datedBarcodeHeight').value, 10) || 35, 10) + }; + } + + function getDatedBarcodeScale(labelWidthMm, labelHeightMm) { + if (labelWidthMm <= 32 || labelHeightMm <= 24) { + return 0.96; + } + if (labelWidthMm <= 40 || labelHeightMm <= 30) { + return 0.95; + } + if (labelWidthMm <= 50 || labelHeightMm <= 35) { + return 0.94; + } + return 0.90; + } + + function getDatedBarcodeOptions(sku, labelWidthMm, labelHeightMm) { + const baseOptions = getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm); + const skuLength = String(sku || '').length; + const showValue = labelHeightMm >= 46 && labelWidthMm >= 50 && skuLength <= 16; + + return { + ...baseOptions, + displayValue: showValue, + fontSize: showValue ? 10 : 8, + textMargin: showValue ? 2 : 0, + height: Math.max(Math.round(baseOptions.height * (showValue ? 0.88 : 0.96)), 28), + margin: Math.max(baseOptions.margin, 6), + marginBottom: showValue ? 1 : 0 + }; + } + + function buildDatedBarcodeSvgMarkup(sku, labelWidthMm, labelHeightMm) { + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + const scale = getDatedBarcodeScale(labelWidthMm, labelHeightMm); + JsBarcode(svg, sku, getDatedBarcodeOptions(sku, labelWidthMm, labelHeightMm)); + svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); + svg.setAttribute('shape-rendering', 'crispEdges'); + svg.style.width = Math.round(scale * 100) + '%'; + svg.style.maxWidth = '100%'; + svg.style.height = 'auto'; + svg.style.display = 'block'; + svg.style.margin = '0 auto'; + svg.style.shapeRendering = 'crispEdges'; + return svg.outerHTML; + } + + function renderDatedBarcodePreview() { + const label = getDatedBarcodeLabelData(); + if (!label) { + return; + } + + const dimensions = getDatedBarcodePrintDimensions(); + const width = dimensions.width; + const height = dimensions.height; + const scale = getDatedBarcodeScale(width, height); + const compact = width <= 40 || height <= 30; + const nameContainer = document.getElementById('datedBarcodeLabelName'); + const datesContainer = document.getElementById('datedBarcodeLabelDates'); + const priceContainer = document.getElementById('datedBarcodeLabelPrice'); + const previewContainer = document.getElementById('datedBarcodeContainer'); + const svg = document.getElementById('datedBarcodeSvg'); + const productionInput = document.getElementById('datedBarcodeProductionDate'); + const expiryInput = document.getElementById('datedBarcodeExpiryDate'); + + if (!nameContainer || !datesContainer || !previewContainer || !svg) { + return; + } + + nameContainer.innerHTML = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn); + applyBarcodePreviewNameStyles(nameContainer, compact); + + datesContainer.innerHTML = buildDatedBarcodeDateRowsHtml( + productionInput ? productionInput.value : '', + expiryInput ? expiryInput.value : '' + ); + applyBarcodePreviewDateStyles(datesContainer, compact); + + if (priceContainer) { + priceContainer.textContent = label.price ? 'OMR ' + label.price : ''; + priceContainer.style.display = label.price ? 'block' : 'none'; + priceContainer.style.fontWeight = '700'; + priceContainer.style.fontSize = compact ? '0.98rem' : '1.08rem'; + priceContainer.style.lineHeight = '1'; + priceContainer.style.marginTop = '0'; + } + + previewContainer.style.display = 'flex'; + previewContainer.style.flexDirection = 'column'; + previewContainer.style.alignItems = 'center'; + previewContainer.style.justifyContent = 'center'; + previewContainer.style.gap = compact ? '3px' : '4px'; + previewContainer.style.width = Math.min(Math.max(width * 4.0, 190), 320) + 'px'; + previewContainer.style.maxWidth = '100%'; + previewContainer.style.padding = height <= 30 ? '9px 10px' : '10px 12px'; + + svg.innerHTML = ''; + JsBarcode(svg, label.sku, getDatedBarcodeOptions(label.sku, width, height)); + svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); + svg.setAttribute('shape-rendering', 'crispEdges'); + svg.style.width = Math.round(scale * 100) + '%'; + svg.style.maxWidth = '100%'; + svg.style.height = 'auto'; + svg.style.display = 'block'; + svg.style.margin = '0 auto'; + svg.style.shapeRendering = 'crispEdges'; + } + + function initDatedBarcodePreviewControls() { + ['datedBarcodeWidth', 'datedBarcodeHeight', 'datedBarcodeProductionDate', 'datedBarcodeExpiryDate'].forEach((id) => { + const input = document.getElementById(id); + if (!input || input.dataset.barcodePreviewBound === '1') { + return; + } + + input.dataset.barcodePreviewBound = '1'; + input.addEventListener('input', renderDatedBarcodePreview); + input.addEventListener('change', renderDatedBarcodePreview); + }); + } + + initDatedBarcodePreviewControls(); + + window.printItemBarcodeWithDates = function(sku, nameAr, nameEn, price, defaultExpiryDate) { + if (!sku) { + Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error'); + return; + } + + window.currentDatedBarcodeLabel = { + sku: String(sku), + nameAr: nameAr || '', + nameEn: nameEn || '', + price: price || '' + }; + + const productionInput = document.getElementById('datedBarcodeProductionDate'); + const expiryInput = document.getElementById('datedBarcodeExpiryDate'); + if (productionInput) { + productionInput.value = ''; + } + if (expiryInput) { + expiryInput.value = defaultExpiryDate || ''; + } + + renderDatedBarcodePreview(); + + const modal = new bootstrap.Modal(document.getElementById('datedBarcodePrintModal')); + modal.show(); + }; + + window.executeDatedBarcodePrint = function() { + const qty = Math.max(parseInt(document.getElementById('datedBarcodeQty').value, 10) || 1, 1); + const dimensions = getDatedBarcodePrintDimensions(); + const width = dimensions.width; + const height = dimensions.height; + const label = getDatedBarcodeLabelData(); + const productionDate = document.getElementById('datedBarcodeProductionDate').value || ''; + const expiryDate = document.getElementById('datedBarcodeExpiryDate').value || ''; + + if (!label) { + return; + } + + if (!productionDate || !expiryDate) { + Swal.fire('Missing dates', 'Please select both production and expiry dates before printing.', 'warning'); + return; + } + + if (expiryDate < productionDate) { + Swal.fire('Invalid dates', 'Expiry date must be the same as or later than the production date.', 'warning'); + return; + } + + const nameHtml = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn); + const dateHtml = buildDatedBarcodeDateRowsHtml(productionDate, expiryDate); + const priceHtml = label.price ? `
OMR ${escapeBarcodeLabelHtml(label.price)}
` : ''; + const svg = buildDatedBarcodeSvgMarkup(label.sku, width, height); + const compactClass = width <= 40 || height <= 30 ? 'label-compact' : ''; + + const iframe = document.createElement('iframe'); + iframe.style.position = 'absolute'; + iframe.style.width = '0px'; + iframe.style.height = '0px'; + iframe.style.border = 'none'; + document.body.appendChild(iframe); + + const doc = iframe.contentWindow.document; + + let labelsHtml = ''; + for (let i = 0; i < qty; i++) { + labelsHtml += ` +
+ ${nameHtml ? `
${nameHtml}
` : ''} +
${svg}
+
+
${dateHtml}
+ ${priceHtml} +
+
+ `; + } + + doc.open(); + doc.write(` + + + + + + ${labelsHtml} + + + `); + doc.close(); + + iframe.contentWindow.focus(); + setTimeout(() => { + iframe.contentWindow.print(); + setTimeout(() => { + document.body.removeChild(iframe); + }, 2000); + }, 500); + }; + + + window.printPosReceiptFromInvoice = function(inv) { + const container = document.getElementById('posReceiptContent'); + const itemsHtml = inv.items.map(item => { + const itemTotal = item.unit_price * item.quantity; + const vatRate = parseFloat(item.vat_rate !== undefined && item.vat_rate !== null ? item.vat_rate : 0); + const vatAmount = itemTotal * (vatRate / (100 + vatRate)); + return ` + + + + + + `; + }).join(''); + + const totalVat = inv.items.reduce((sum, item) => { + const itemTotal = item.unit_price * item.quantity; + const vatRate = parseFloat(item.vat_rate !== undefined && item.vat_rate !== null ? item.vat_rate : 0); + return sum + (itemTotal * (vatRate / (100 + vatRate))); + }, 0); + const subtotal = inv.items.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0); + + const companyName = ""; + const outletName = ""; + const companyPhone = ""; + const companyVat = ""; + const companyLogo = ""; + + container.innerHTML = ` +
+
+ ${companyLogo ? `Logo` : ''} +
${companyName}
+ ${inv.outlet_name ? `
${inv.outlet_name}
` : ''} + ${companyPhone ? `
Tel: ${companyPhone}
` : ''} + ${companyVat ? `
VAT: ${companyVat}
` : ''} +
+
TAX INVOICE / فاتورة ضريبية
+
Inv / رقم: INV-${inv.id.toString().padStart(5, '0')}
+
Date / التاريخ: ${inv.invoice_date}
+
+
+
+ Customer / العميل: ${inv.customer_name || 'Walk-in / عميل عابر'} +
+
+
${item.name_en} / ${item.name_ar}
${item.quantity} x ${parseFloat(item.unit_price).toFixed(3)}
${vatAmount.toFixed(2)}${itemTotal.toFixed(3)}
+ + + + + + + + + ${itemsHtml} + +
ITEM / الصنفVAT / الضريبةTOTAL / الإجمالي
+
+
+ Subtotal (Excl. VAT) / المجموع الفرعي (دون الضريبة) + ${(subtotal - totalVat).toFixed(3)} +
+
+ VAT / الضريبة + ${totalVat.toFixed(2)} +
+
+ TOTAL (Incl. VAT) / الإجمالي (شامل الضريبة) + ${subtotal.toFixed(3)} +
+
+ PAID / المدفوع + ${parseFloat(inv.paid_amount).toFixed(3)} +
+
+ BALANCE / الرصيد + ${(subtotal - inv.paid_amount).toFixed(3)} +
+
+
+

Thank You for your business! / شكراً لتعاملكم معنا!

+
+
+ `; + + const posModal = new bootstrap.Modal(document.getElementById('posReceiptModal')); + posModal.show(); + }; + + function printPosReceipt() { + const content = document.getElementById('posReceiptContent').innerHTML; + const printArea = document.getElementById('posPrintArea'); + printArea.innerHTML = `
${content}
`; + + document.body.classList.add('printing-receipt'); + window.print(); + document.body.classList.remove('printing-receipt'); + location.reload(); + } +