From f9e3a958c4a853c9dfbe39d7ffa4df4b62c018ef Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 19 May 2019 10:44:09 +0200 Subject: [PATCH 001/317] NEW Module Intracomm report --- .tx/config | 6 + .../Intracommreport-ManuelDebXml.pdf | Bin 0 -> 225572 bytes .../Intracommreport-ManuelDesXML.pdf | Bin 0 -> 187033 bytes htdocs/core/boxes/intracommreport_box.php | 88 +++ htdocs/core/lib/intracommreport.lib.php | 52 ++ .../core/modules/modIntracommreport.class.php | 246 ++++++++ ...ommreport_intracommreporttrigger.class.php | 571 ++++++++++++++++++ htdocs/intracommreport/admin/index.html | 0 .../intracommreport/admin/intracommreport.php | 158 +++++ .../class/actions_intracommexport.class.php | 88 +++ .../class/deb_prodouane.class.php | 321 ++++++++++ htdocs/intracommreport/class/index.html | 0 htdocs/intracommreport/export.php | 214 +++++++ htdocs/intracommreport/index.html | 0 htdocs/langs/en_US/intracommreport.lang | 7 + .../theme/eldy/img/object_intracommreport.png | Bin 0 -> 1384 bytes .../theme/md/img/object_intracommreport.png | Bin 0 -> 1384 bytes 17 files changed, 1751 insertions(+) create mode 100644 dev/resources/iso-normes/Intracommreport-ManuelDebXml.pdf create mode 100644 dev/resources/iso-normes/Intracommreport-ManuelDesXML.pdf create mode 100644 htdocs/core/boxes/intracommreport_box.php create mode 100644 htdocs/core/lib/intracommreport.lib.php create mode 100644 htdocs/core/modules/modIntracommreport.class.php create mode 100644 htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php create mode 100644 htdocs/intracommreport/admin/index.html create mode 100644 htdocs/intracommreport/admin/intracommreport.php create mode 100644 htdocs/intracommreport/class/actions_intracommexport.class.php create mode 100644 htdocs/intracommreport/class/deb_prodouane.class.php create mode 100644 htdocs/intracommreport/class/index.html create mode 100644 htdocs/intracommreport/export.php create mode 100644 htdocs/intracommreport/index.html create mode 100644 htdocs/langs/en_US/intracommreport.lang create mode 100644 htdocs/theme/eldy/img/object_intracommreport.png create mode 100644 htdocs/theme/md/img/object_intracommreport.png diff --git a/.tx/config b/.tx/config index 0044fb91f49..028f2fdbefe 100644 --- a/.tx/config +++ b/.tx/config @@ -164,6 +164,12 @@ source_file = htdocs/langs/en_US/hrm.lang source_lang = en_US type = MOZILLAPROPERTIES +[dolibarr.intracommreport] +file_filter = htdocs/langs//intracommreport.lang +source_file = htdocs/langs/en_US/intracommreport.lang +source_lang = en_US +type = MOZILLAPROPERTIES + [dolibarr.install] file_filter = htdocs/langs//install.lang source_file = htdocs/langs/en_US/install.lang diff --git a/dev/resources/iso-normes/Intracommreport-ManuelDebXml.pdf b/dev/resources/iso-normes/Intracommreport-ManuelDebXml.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fef9f48f53e999ebf0239534d5ced7d68b1b1533 GIT binary patch literal 225572 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

K)#IHq1+HK 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�H>a4y93rXXnz{~q=3R*h+oHUl3n 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≤pHx@eBj7y#HlMO_gP$QM0upT|cre%*^E#^L+NQGrBw(xSU;tOpO`ozs3h!2~wBD9K13HrXs~P z`i2|4k|tzlWY$&!zePc3lc10*I^awa`Em#pQW-ZifD7Ftq$-*3=y>Q4=5xld8pjC> z`vZazZ+aFhPi)6}Hb+>}*4z5koRC)|qcRpgwWLgny>>{B(YzRs0*2C3$LuSJxJm1{ ziwFrr0eBaA9^qE9n1cTcML@d0{kIBkN7tpTW7z%wkbQ9_zh_yb=e*T@QrGr@>e%)y zKkKfN-*P&y8pD+g81OMJ1|zjF0-$&P>OPVHe@(1A(skLu0zfrr7U}jA)u}HVvco<4h$@ zm`!6KjjN=oG>!ZSrRZ4RcP0!_#OluwZqMKVNG|~m0*#+XOZG7MS>}0=hk53Oy-352 zGtcj1k%1?X{TO+5TFncP&mb13kRD%wFGQjueAYJAcCK)uZOK#{DnVR01(*7qY?Ey< zxZnVXPD$*nQ(X< z-=pR&8=6)y7X%r7$j{1QceCGiPS_Cg3vxsXNg#r#(D*+FYyuOAFsu$efv;r7nL}#U z?a?|M%nFamY9&{*8LnZy-e3|0W`%*K8hj+x@Q}Q&EGp0kMN!(82va0DabgmBGg)dA zj+Ki=NU6`^VFj15hm{NY2H>!^#zZ_4Dafw4R_n4kJ#KeC-_X>=-7jBr^27Yfm@AN2 zl4mZta+M^Q8g5nX_KK}iIu^sV>XuVaEDO1ub=ShEE}WTU?_{3@ z8Ri^z;U0#}n<|x5(!`QVy5jQlbupdM$gGIb?!=HO4~U@}?RI8G-c5?Y{qOgY4npLF z>LQ)Y)3W&@PeVRaH$F3=N_u#tE{}p-DxGUIsd}i?q}J4ss|~VD<1=rlK~l(M;uc*^9+Dl*2d+HzY}!n0QZ74he4@uFolo zU)^L3Y|k_HWlh*Fg^DAk$MgpbtX;9+gl@{;j_xwvRnXSh-K|1tq{Qh1i#3b2T~b$g zajROovqopI@Dd6y#65vH$4ZYES(TVe)udDPfe zm&!Cgi~Y!iOfwS)^hHzBSTvEo`&tWvsn^7)a2YVM5)C$+I8&QAKJ&JkG8UJLYsF0> zn-#Z;jQFLHfJu*YZE70>-5$)0WSC3=#%-MKR&AWIZX$y-12L30n@o+3Fz}~f2DB^k z&*F_JieluAmLiIUVk5E97^lXL$C!~AjtQht>{+G*P|r0pu{Tt7jpL1K(4Q^V^QxsN zfpRm#vjUHg^SGDCe8=35FHkTo4-F41OD0cDDgdi+qqI#aZ9?VvtPEIqV(M5~m>eoi z4o{Vb6kCy$QIzZ+ErF@MtO=uX|0K*6nXdX=#};*dVNM{TaWuCywJ=(}&Y)woa##v8 z+JdntAzO_jfb0%y$Q;1o$Q(^EfLe5o5-v0v?ExWxEn&E{YTE*cV2;qHUR(9f8b*G9teLSu7NQ*)s)9trbW zm&aL2Ysxox+#WZeFJLbqb+e14Cv5PH*5!mGX8u>AP3NrrVlegEC##l~VsR!Lk7dVp z-Ei)lfZgD+3MN+YiP`@98HDh zDYs3(dg~k~Z*FV3zw>Lj+~!RW6c>P!!=TQYW1L2F4+^0S(^JL#cvdBNoYIN}ZM8ar z%34ahv`DIP8%V0#C=oQb5&V}-1pg&k8dCqRQVJ)D#XrYsY5@)r-l_5Ejl&wqAGPHA`(QC7HHbO)WE4B(PnK-N{ zh%}~LK3tl#dy1v^;QjuCC_6Lp)cpC4S%Sy&l)A=&?2X)wn(f?3_Q~u-mRGYQSq5d@ zwJv3aW`%CKazD>6;IWi#Hq1AyG<<{me(mloKaoAIFcR<_`56#=jR0d^ZPHTdLg^C2 zmC_B;F0@PfA%Bp6rPdhNITEIJd(hG8s!6!p1Hqck5Ikn&(k?n`p)^jXL##1`jIv20 z=xcWkxJTSiy4jF>)Xlj6oa)s=Tc1kSHIne@`2}r9UB}icw^=edHCzU6Nq&Ue3`3V~ zo}%#S!62^QXat}Geg!-YppHOdxm>2G@SZY}Jv;#*SjB)E z*9h8;#t=IzfzU=&-l!ulQKJOx1zzIEco41zfRyj%IsRVmJKSE5C9mS4YXp1a1O=SV zP!Re_qR?AF71CP>EN+ryv4nyZ%m8jWQ9+d>hoPR;r4WB%&>ZbTUx-aMNRr{X1;!DXgRZ7e-Sgx-08T}yVLPK{r3#xy8Zew!%vw%GDl4( z3{Kq<9wYt;&kT`}jNK><+8D3pZ{nON=XQ~%I_yRJTGv+BF4y}m&gJs|hQly}NA^04 z9AO#`61=T0uouY~U*N}NM)+Uo+)01Y>c*SgTirX{towx1IikZk-KdVq>2~Pe*Rg_5 z)j>~mW4fa{t?q{w7l-a7aK)xod(NU-dMzxn2o}l09=Bi%X^9@j($W#^=&4{cFy$pv zLu~@E+%g1{z2s6x3 zKV{eCM|tEy#KYT+k)lb>6wPqz;O%>pMZOXcy0X__x${@@s&|IUouP84r+2DFUvvrH zqF1sN&2UokaTebMt-+!706}PK_7M8PQ2OC^#pHN`kPz*=c*BNmt8dGMTtENDBY*zu zfp5MtwGBU}5xnc0mfgzC`NcKYtiRrQ=N~YB=g*jb?T4*>(H8Y)korI2Tuedp1wfXf zY6aZ`TOsjHM&t4L&^Vsj&wiQla++~Q|CIc}_e4cG_r#JDQ|ESF-1#BOE}1O1k)gsk z;$RBX?}RVYd|~?gxSy=wcLUv61ah;CKivz^H!C?azAC#kRahrwqwbhh&kx9hG9yz; z04!6k0a=$)0*L(l0HFjm^@JG`LQpOps<6VthY0f9BV-7#uFW)}2tgu`d6k9`aq*^#`Ez?aYbNlWI!AUY!-(D+wJ!_Ms1_w zqxgHwlaZ(Ji}jzbkZ?G!i);;cXKB31E{1X9z?kRD+1< znG<9@Adkolk_B0kdu7tEQF*sKCQrymJia(1ZkPi@gY) zG|ImSnebB64ijU_3Y3x!pg}YWglz&HMS7CJpdViCyVb|^`tU9v_KjncYCo>UNGoV1 zZBDCdHQJ7F$3f<+h@!#p5KPtZ(9}@**wFAKC8wpy$ssDV9P^9MFdKT zUUf?aL#!T-+9rw&5ihi{r`fs@4t;L zJC?+=ao6ThaM48%fA3^R9kH&Q1FXpkvY88iwE|fOk!R*JwT6I`)1<{b){!XY2$W&1 z$plwWGyb-Zz!pUQw2ve~%nY%3B~;_@5s2On8oaSPx+rrS3)&s;$L2jo7o-yrHSrgH=zj zXTUS)8TIUjg1jje zMoqg-$4wg3UiaSbl4S*|w6xJhg;E<8g{TrU@@v=u6tLO>@u5_LVI)(WtL&1*?8*K9O4p!!~+vqcdy^RmPB60g=z>#6sjRs*TKS$Vq5O$U-WD)KjXF7Q_N8y1mcB zJc}p}^K4m~*p%3sU=vARG_gD?9frv+PYP3n!56FZO&Gp1Asl)|fk{7f#-v9`b#Zuh zlYXn7(L)8I7FtTD-9|-k(#C)6BljT!g=E4>Ssab5j}>rTC8fZwk}kQYmqG)3WX#*B8^H6k_2f?ng9Z+kp@zap4My0@=KdA477tz zyD&LCSq6z1lV()~;>uFY5U6(j*wr+P^Az9t$}$WA2*CO?L1OXMTbdU%MkA|Sc2_3n zFwdJit#pUI28}u53ndKL#XkAVUv{JuOMuEjapoRd8gDA3;J2{NH zwAJn8#<71daZ@QBo;q?kJ9(%&|L;u*uVj_V>PdCxy&e(l_&!n=)rtf6E=qaz@qp%A2j2L6RsL0U>-2O|HV#KPgI z349Ja3Y9}kQ%B0>3E{ACs7%QQAtKP?gUAdGXg3wt;3zZVf_vQik(b|9 zgYWbK^I2+MYg%jmRMcoimzWS)w@dW;SWGTX|8C5>a@E$dIfelOTOf^gzYgNxf4ErJ z#ZLb(kZ~M;qNXJPyt-`77$~9$V~*2AoxKh`;=sruIK~_kjw6nv4y|J#@c5lo`a;Ao za+FU1-c14k0R9oDEmCL# zm}|z1-g+yal;_$Kk&({2zS^%gU!C!!xEH5?(>?X${<*2-MeFlx*E5&O?#mX$FD80V z8(etcFh&$+7S8gRD9}gBW9(*1eate|FE(nkCAYWO^m_?Ca^NM%vpe5!Kt=tX-iJabmZY zAumOsUWa)H>E35*fIO+!MK%>Zf#_g#G`c%_JgSkRy-`LbmndOV4GoPnY-z28nOr4|#AvA2d3}vy zD(F}gHm8F2MG-mSZI^;_r^#z_j6zq62!&0&!)_QQWRWG}OGkkOs2 z#zJG0<7_^en5BxT+BtJ-Yuo00$y?t(-O*9!*YiPNAZfu)%{?Tet+sZ~v^*uPECwj= z#OuDEmb`=*GN=or?t{QPt*C}ERjFYB1R^TiP?6h2MQ)Qo7OYJ^jzA*GBoWm?5;+}k)one=C*^$PVLzEBQE@X_W}3I_*MO(ns@YC`yUN>fxgSV%5@vQTYsnZ9X}sZ z8wwm%mv@EmE3Q|4j2glVb+fIpb7bZeyRo#C!zzc5kZUhDzzuSv+!&|jJ^^9bSW->9 zK)^n&DU!8YqWdX5W65PbW4-6C-eU?b+!Nv!p1->9IkH-fI5H<-(#dAc|QR>4}m-?hXd?2dBS8Z6;#Nk0ze*vj(q8g&985L{f3P<{bE_+ig~+k zS@)&O=Ce;ewC%|+o*H@Nt{;8rzpiU9J#^#GrhmWtUryXTK=`f+A@+X(tmT>CR3Xh% zPzis{Q65@PuNIxv4eHsS)H-q(sfng^lyd5*+@_;)o6a32kGZMc$4ysE-LsOMd)9Q~ zCX!s76nCQ<`fv@csD@TilcJnGMLBz_!X|0tIISf$D-S~CAF6>okwO6`njpJ`vtiCjU2Cuo@?XjfjM^a^dIl!G&2j zA&WUG6V%fK?rgDJW4GL8aEm=boYG`H+?I>Nl zou$7J`P>bi2_@rbEksVan`EZ!l_g+x+ttm1ucsrHK|}^oVBQRk@`e! zdoEbt8929G<+kLvK44qJ7Dx?Q^0b)0UTc~14G@-@-gP^vdIkQz*J zBdO8USc*j{A;qNVGLO^Um>Ot&bSt65N>yr@s)Rs?i2wn8YqJ%LRZ2`~F`%Pe^s-tm z=4Cwr46=>J7XZD57)5Tr8E7>8iLOg91`{Ec8X>B}D-kQG@CsD=%*4;-**xxf_}-o? zCAY;`KW}=DL(Lnw_9fSCHd^X?rsp`j>#ZSQAYsK$g_(S*XJy-s(_2=BygNi+Mf*YHRVr`+()B=}rF!@DAZJm>geRcYss!qoKCrCq0%#JFq*R)Vv7YsH7#Y2Ngky!Lq z#hJg)iZe$mBDF|SQ;ZW@5F!b2xv`MQV3{M>DAPLR48`IMQISY$W)^KTv*Z9GpQu*y zc!t)O!4hX}HvqocD>#dia3)YAV6U}6HTFUiO4w@B9Kqo%(cC8~8lR29M44*R~TfdrZ0jxE&5UjPvtnrbS(H3s3WuoOs3#({xZ_7Z-AW2eN zu%rXw$W}qsOe&aI6gH%S0*FbeV7!8=g+yI@W3bSPr9=~=y#&d`W)lovF{&Rm;4uTX z8U_u!46hqF13}eT2FcO7P^LFCkQvNyBbm_*GnT<9BV;BrM>1Sypt*vk<^MUFI(-3+ zP8;*b0~&7t^Ew}2GmEGMQ;E?MaFybzt?B<3Q^~q0e_G0FK5IE*$);P{&mHtTEQXvq zJ=di+7}!u}uKw~xu44Ce>p2mp2-xb%TCiPn&(uXXbgjHV{o(XaR!JhoSK(aTdH;pk z#--DN3+qDBsKd~*l0Bzldm(-s=S+9A{|dZu4qAx%*$32H?C#zN;yasI7?m~5=Gx86 z7*wmR)1H5q#Fd(tuG!RlZG3Re4sM6$R?nBk9fj?4Z|&OAbNkY-d%iC2TsqDj)a>)@ z6JKq7wP#|@ku^ux9AD%2Nv^z5a5jb3Xuhvo)Ku~#H`^pH@*{7@=U#+*hr_AYjl{4$ zMi{Bx$*hPGY1wHikx(^)Ahav?WbB0)8ym+D?e9}YWGq8b)lACTcgau6FM#?{eTIhc zhzw;_adZ)0q(bTmBhj-shNKBQ4UiOHdnR8MM6jJbYd{ZC&y_n?pGigliEkVRJw*a(Gj2M{ZY+&56Wf zRN3{ohSc#Idu4OZ7Rnmt}fcj97tXh|2Mlx2BPXP%AsD6Ozc& zq>t=ntJge(uSYUA>;c_a`HWx(pw8s*6pc(O!^Z?==rekw3=?~XG9(-WRir#j6z7VW zW9ma<^e73F!=R*;%Mg(AP`KRDx9@fNeVHluE5j!y%aBY`V(-TwWtd>5&F-Pj2yoJ+ zo>{+y8+ul?c0~(;8jpxI@mNEBzP_=Z)wai%#_M9W@s+XV0UVeU44|IE5(&-2B?+CQ zDFsk(W=Q~@uPm2vr`R39D-x>$c;%{^RzDQ?&q0gp7fHBhQK3m?IwasZbGfzvJ~w+_ z04+wcyhB93opvD^2P$vM476d!-XE?scUJ;9N zyy|UGAs|j3!y`ta^s2VPPv ztX9KXmFrp#J<>Tp9g=f_!C#(J-gNncCttj+$7n0?Ya5j!b}ib_+1R`IqOSb(-?O>a z4bSa+Jm2`uKj3pyU+cf)kgCz@JwAg*yI^qSfHPin+9aN1HG1>l`9tgPUDePeim`e6 z^`ZJut-2Y?E{r|N!cf-sv z=1q`0>bb@$b|>=Gc9K`g+75&1dL^domDuX{=@KTAo{+6%0g~id3BELtd}}?gOIT&j zu4wQU4Zc!?HL)zlxR&=`7sTs>I2ex`XyQ4O3gsSE}*ado=h8%@;L{CRWRL2JwdAH9;mAvl}sK;onpr zK~<|Y-{8|(sJ@)AlOU1EH&lI<4pqWK1ar&e6b>CKmxM#quMQeT@HeGTd(({FUZ)z1 z>7=nJI{QtlqDH%7PNo;7m*&^zuTNc{zTNUz?95&oMz9 z!dcAVajfh`&()1%pK7ZWgWl)-L0`y+1)l^XM>4(7xk+Z&ZjVOHM$Vd`fhLH5it4hp z^$3wc^?k|f6^WtR>CTdYWqx7D*iHn2{~&T6>r{<{Ry<%Gw2oR?>o{&wy$PSUE(Ee% zdRGDuBnA^B306wv5=`P5;0_H~+S4;@C|WW(e1c-<6v4w88St=}1@ziGgCR;V^%&$& zmgt)4F=3KO7?@l-fJH|mk*L||G@FgvEOmsn5dUxSn%r179@tfvR*QjsQKN{E>eju_dV=DKT6(UIx2}w0(BiZO(>2F29mDZH| ziEv>{O5UPA=`CW_P-NirS4e`7uB97_b&!;%r@m+sg7%U{A{P)ufQrz-TZ~o+YorpG zAUNPCrbS1kE_IbK zd(JC%T{zlWTs8C!kJTaqn-3$zeW+QCf=EFv%uQ-;HCi3K6WtNKGr!aK?ZgwlClVj~ z{*?G**3^P-NNmY}vteick?0TeZ~NX(yqz>~t>erepR#UjY9-t^5N;%)`tL4JV_uch zaPbBk8`MY=F8-Rv&S+=sPTxEDt?0Y?4`MtQ#W8b(z`C@4pEKx=x|6P4T|-xNQR6Dy z=Utt+pRox@XkCF+`OnS4NmSKaQ;L`jZ(QiiI$@5aH z+S=Q?o>|WhXa=;v%5$5wSNpE^4+gJ^UY)oh`DN|x{@a5)@*}N3&%T@ebMzlkZ@+p0Qd$c%m`8$< zr%LUO!g~ z_s73dV`=KTpQiSKG!+rkVNf)Q%x9Izt@WW|>re2nkc`%05m9F$;=50HGjVw?4|M>e zt!FbI`)M%Q57K)Z;nEf5MIjaxfq3_m1=j2&RX^aYkcjHaKzp_^k`#lO_xZhkMyriS zV@xa`Pm1w8&hqtn90|trY$LAEvk8AHk8_&3Jc`wX^C;NB7V;P)&=}gzTwSlNkcA;U zJUonshfXiOBjWest}dJZ)AoV}sugHs6e*f24$QVHg3wh5cJEiZ*NwdY!PH28Ma)w} zHXSVb-un9=x^e1@v9-l}zjp3R&ur+uW@!KOD_`0%x6jY)3(mXXwu=w0h&4rq*(<*! zr(FX|e*vj*zTb5k+nET`=|97undhc>hL)POMkmIM=`%sL@Rr$O-LD%DSRmT^j zl%)R0r#&5{VATitnChV3$39xnXAh8a_SpqHd&ND0Mov&eq&-U9ls&{ZLX2sRl10?k zq%9y?6EUAGoa+oI`<`;RG+6=#5fsf&sy4{VVjA&PK4U3u6<-knS)IWs8AVGp=7Cx( zRT{C5F0dIYo-x!{M)FZV86S0?@ENF$$*$AICA$1AX)CVFaXVQ+BSq}9c1IGSD`|Fn zB3@lRBPJ(u5$HNSxlE9S{gQB4psQ)6_bT#z0Vl{(nv@{iZY;qy8k<9{(t^+eN#oNw zmIlQ{L|z(71e;%|2_U*|MqH6`S($ausdyUCTFC)u`GQ=vox@$Cz^=E-?oh%q{g=$< z8@rYar31|iaC?7AxvHnQn!Ru8&0W;L_@$9~{dbSxo$U>N9Gm*qNN>|(hCjENi2;l* zMTosYb2m~L-K<|mhI(XVs0}+q_t5yEaTYDsSyENNwOhyvv7G>=#ZJ{wN^dM$0)={j zLW3?E3wjW;rmVz0!>-k#Y-w^rm?#}S?UDsRH$nWd$Z?h(<{+}tXAp5-s7Yy~P?IiI zg*Cb~TlLN&&3Lva$u!bz(TGzWw&W{yg>kEYaE~d)Q$|!j5D9@#kI;f7F2UGh3!_GaIe*hqeO9f zYG9y|hOMoYuvDsq(Rv!H?tt7lYQaR^T5B1!OjwRsv=(pr8CJ{k6`#R!ML}8uvf2p> zX>AaESUy%UbGNlk4Y!r1Y{hbR*0K^yINkA>D;{$v11RB)25{8}o;bb(VWsi~StO~h z(KZq9j65+$<{PTAM#V)?t97~ZF8pX9Hh0<7d#U6+@7}$A`-d*;Yi$gA@{2;Dc%2&f zgk3!K=twvnjV3!UVpcC`yYu;LJ2Nf8f_#<3QNQu6c?$@gv>~L;fj+c~J#C}xr*yKP zLZ7GVM7CmaZg%xAN8GXql#&$HN;qClp{11i=I+^2-Ls`giYk**-R<++X}NZ4oouIe z$@az6?QHSvbBkv!8jEKuSWGOEUQ%|kfmE|tp^q!{aiy7B&PhVEKptx*JHU+Oxn@eY zo2fa46m4c`K11qgKFcePY}={wfLxUayi}<}s;%;fcU2=PDlyf3;2Ct^irbrQ=vqLG zq|*H5D^yY@y8>0SF` ziTKr3_(NYa;cq0lxx(mZ$xw&sKF&LA?#j^$(i2R-AE?(TfblcTJ}YhR4_Nrn)gN8Q^9VCsBvsdJO#@k58~g<(z~Er7?*C z{!~z{&8a#i+LCL=gUw^jOfyMyFIm+dUA#E7q<0B3vSf4#gO&(Om?c0x4mjP7O9uM- z$C=en$&YRo$MJ^SsIYgMQ=K3do@14ut>P_Sq8n;T^uJ`1u&=82S45|6KeN`KaMWZq z$0G5l2~;_YHEfBUY5f^SL>(jKq^Y@L{P}N8Kvh>mN>6y+^SQ6h>16&4+t67aICw9`uwB9(qd8OnIMWY_-zqoy{PAx1jD$_mGeiV(`&WE&m zwI?ONUBk4F7-R^SUCNXy=e71#>u`;(v*mDqHJlI^o`yyyqq+^21APR8iwvA9h} zbzI!r!o(S`4me{8eq@-1sUt@wgi~f^2WdUTzvv4@DA)?x+G$XOKH zRYh%Q+X^xD*QnHLHGxeM>9XjJ{x&9_H6u_mII}q z2`~F!mVQ>8Xn)iGru1LNvrDXJvvve|QloINMak(&}ZWj-?7QM=ThYd_M? zy^_J#WNysfrreq3I+T7>zs%|*-iUi{slCV7kv_NI?f*>L*e&neL6A}{&-8AAtKV$%P+rN4agvrsTISo_S8vPoROuh5Vi?ndkNu; zy#(youk}e#OCpo>CyJ$3e^G-uzs749{oZ(()S7Mfw`9VC5XKoN#+hu%ZXah}Rp&}s zC)qwH+Ym=DI9zOLNhIQo&+FA{HM&bnxTGK=07^KAFTevJ2#(VmmSXluwjF^gC9bwV1ZeT4%7QNY+ZWS#CN6p-3Yl z5+<=Q@jt&>;n!cELuImN10zHBfx-`iwss(kQ{n7fw%kuwO)ir+D4Vha?HpYY8CDS4 z5ujQxNnF;#)QWC%DI%DQ3}H78Q!yeMi*;~D7PyP?oSURi9B>!INjF(OKDyUkbds&5 z#-b?LNhaAbUCik0#js>AwvcrYYcWv?>|~FGm25H~fl>+PLa@hLJj?h)*K;c?8l)Ep zF4*n%0EQDvK}|C(u2^=eY0Vge&{2?G)PUn~R7zD+crEC0oj9`P+SOCfv<6&$J)iq< z`dG%^w0Js{kIfxifYs?wulmM%=IY)#xg&qAb(pMm3-BL`(WcesGygGt?!L8}SPUEW zF^9)vn~yJ;zOOaml4{vlOe6UE*5Lc_wq5Jtj;#yC=1;$h>zk4;m*BEtNV0m)y^KgO zVUS?{26&&tuc{weMQlMjkHu?Fg7{m@<#_u!_?&FNxCvh>UX|S&EgjC zHM#BRPVu(fPV_+T2k6n>CmMd|c}G0bFzNY|_$TkthR@JHJpU^fTYwjO zy0fcszh`Cka?kbNSHzcdZ;5Z^J`g|1St@H8QpoR(2aw6b=yf`Ta=AoOms^7nsru#0a<-NYyCbjgMe09>B`;$%QzseE1H^lJ zY~~mqWyg>adCoO_1!2%tCqPXV4rR~U&wUUz%$(X! zWY7i!p^kJ@w!tu`6|MfFp$Sb|bXttA1-WP!#QNoz<0$bgoF zit7+QZS6c#HFqjRGWe2V4l!L8g@wWz;Z7TOdm7J4m*(`O*Q77EU7o&Lx5c(4{bk)F z{KvZg(wlR0`ttpaS2l9$9Gum$$&}pz0<8D;u!HPLiJ*kMG!aCdj9p2xT%FK_NlO@> zw8<-48tOxaQ3Eqz7%@C)U=4qk7zbG_@k>%K*$g-$W3q{^g4!B+p!KDm*)0N<)ey3k zjrb1{pKH%)pKI1aRu$W*Bq?PJyjd4(jGN-QSb=YlaMlc$yuL}o^~So>8?}|HTM_XY zQ2P7XSl%_OmR3yviCIxG?>@tiNK+9w36fStN(TGl^LH%We!gB0({R8}*i}mTj1O-UVu3E*oWw!*6X_cjcGgnEcjOmo+o}@rC&yunf1cegk_^ ze@?V)o&MpbNNeA@mmK`{(7B?W!177rrs+jdFj*^Ob&o;4FZx?tht8)8bGC z3st~#^1rWs7C9ja7RDLQPpYC5c&2- zWs5-79kcSyi_gCgV4F3-5HQ1YZu{m}e*K-h9`Ai*rBxCGwHEBi@*4=g(M=ABP~zB`q!(pXN^4)LP~5CaznL+;h(kbUYmkE9sM1+q zoZ1TFE;k8WTFeKlYkd|XD$?&{SbUYGJ_4+kSyMDb{!TYzS~Sm8He;#+U!%1K?U9(M zP4(N2yrn|ZDhtn_Z^xXV)U-m-Cj7NTwfEN&$n)3Ib!4kAxKdzohAQ5YnCQ(gYGx$! zz2xo;m-FT1Qf-T}R8W1YytH$PPAauh=IYqh$sLXd91l1rGW;?J z4(lwbAfKr2$@GiXV2F+QQkZlr5~~q;UTg9DQ7B{~Br%IZz=)XvVEa#Ewz^LK=Xkx~ z>UA+MxL&8buBbWNDz>3~bj z9g%RtNj_*%F_;oJDze3@MIq)-<@3#*`HDYf^;;H*YT?an)#;LM@oi$S5c7+s8yqb) zPI1j03vc@scK%CoAl_QIHL;;Ixcj?T&$)no^5i9b4S`rpFcv`pzH;f`Ui%owBqaX^fQnrmZ^z;rr&eO&FVb^-XmUCj}gytR-GLku&X8` z*J^czTq7_bJRAk$Y<9& z$(8~eoD!T2`)_-Y7T!Ji$tR^Oyg&On1+5nidcRJu56keJ(MdN5I2~FWg;$$h%g_`C zYb6?yNIi#@&;Jz{z3h931^P`ERc~Kr=o8m?LG%J`$yf*zZGN4r;Pg6u5q;Po+a!Bb zl)RF!RbMo;+KCF#>RY5+sP8m%iCx}>zRPqE>UQeC?fa&GSNI3$G2J8j?|8rCd(8j5 zZomG3;ehzG_Zi=_{)zCL;%A1>#FM_vEbtMz$};yA8R z?Q0EKFhmWz3ps zZ77i7X;T5|CxC2@;};GHVLTG9j0Th<;Q_0oQ6^g)y@CRWd4jlGD!wW4Loa}&c)~YH z!eMc;vcZw0o+P5NGJB{!7d}pq+zyvfm(qQmz9k`!t05 zsF7@HJG$3VG?3*UgQKXE97R8zxS}}Yif0m0LaN$up{kh>WthhiqALSa!cPVgDc75C zd345bBUT!nk-+q`sp*66WXRUQ-WQ8Yk=(SFF}KuM^j2dm#@T}1r~blfnzDjk2V5e8 zkY)?$v~DD0R_!a-z0lEZw+Zw9SV_J)!ci<$8z-EO1{v@Nw`WEbp`J!e<#8UTpjAE36(h4c#%b4vv^ zf~5!^jO>majj$2{f3|U1;_NPg*UAYXqR1v7;(w6` zy^nsnE{SvaoEM*Xar)YS-MaE4+%WyiJfh zi#uxweVU69H%7iPkN&E*uEwjG)itYwSKup{D{8I?>auc4UMhb>^ML;`&7*#v!8JiQ z`IcW;AM#t}2rouZh!Lzhd7PP09eS)F)nh5ytx#PrdJ=JHoJp!aot}=So(`Ozj;22B zafg&3^@$@-pr8<38{8e_g3mBXySXz&V@sAw{1lkg2fns_-gx{3~NegnHFQ{zF^&9&K$td16*~=1dmHl^5W-WK@AMG1t>k zeNo*cQ`@FY?MkwmEO_O0whc|Xke`vmV#sfo!`_e|%Mln;n;fy*7zXP^FSXZr>377u z9C_3m)(`4NbVqgU3~`?9)eY#_wYmx25gn9}W3yg z;n6F7Pe^{%|GuB~FY7G~7Iqid0um@t3lyjY3e-Y47NsO2 zN)w}WKB5mb9zBS+p$hOS6&NM!Op_lP+I zLBgj1x0R4g3!&uLCKFRe-d2HOnTlU@gG+OsJuQV*2?qc=nL7LguDvGFsEx%e7W?@t zrr#2hEgxQeX>M+N^4gPs&gB%zPt*Rwp24Q7wWXW)ON)f#@J ze+I{p5kIUNbpO!cAHn?ph$TrH{P0tZ*JK{Yho6$kA`PaS?6zcpPuoveia)UGmVmx0H;$>Z_8y`##N;fnay>6?ltrWUl~?bDlE|C4=mIyqg7-@tDX zJ$(cspUi&g5_JZ!>6zH`lXbKcaLL>Y8DVO@$hErE(fLyJZ-g=&G+j30$Zm5?3hf|ZwXLmAJS8} zMnj=d30oyRAnlfpOROYO$#;C_Q=qYAy=!l+@++C_#HW5{RqdSMT?LSqoKPl*g~{^& z)!v)OM{!(<<5kt&b00mUV=m21&(U*eMl*vhkdRRe5C#O63>Xkb5fTUx26TgkO(dUy zkBG!)?8L~i@df@OB!dMwfjG9~B=(wYb`#qJLH*l~8h`}_R< z%t)`^>pHuutE=k0di9E__@t-VL#o$Z&oL_iXFKcZkeya8E3?Kji;!srnmmum?3VM) z-aPCvx#+GFJgLV3)1;1uFK^?&%xq;^AMCQ-{E=8iMJ&IfqW{&wYnM;)IbD_}pFNR# zX;1$E3(k*Kj7t~ResE@HAW&#jFO!#jlic+{jII7nOr)*QGRu90S?};N#57*K{SjT{tO_l#sUc#hD2vx8hMecDNF* zzmu``^_}0cYVBA!cBTO($EX33j)ttFtiYC28v@kI7tMA4#5;mnxDEv|QD$mANt`4} zF6q7B{B6%;=Etmu&Cgr)8V}C3;qBZFIoIdj&E1jvUG9G8e(o5jHE<@LxaV^9oRHLr zmY@rbV&M>RVSE&gay5sghlEHTheye&LzdW(h{aK^>d=63kC7NhxulZJ){^}QV_Yci zKVZRLOQnTaoJt6Xv=x#ao9$jZv9tc#K2KhgnZ41;+EvgiQ+rtFJD@ur>p0(V{@u#6 zAD%zU6pQJcfr<@tTq=WFc82t!Tv_GP79c|oI2wmgfOR%w!I#8_OuL0nGbry11CKSM z+0O?gsw`^_rnP0E&*p#b_0D+r(H(DZ-*WcBTYuW?T|0j6*!Y1XcO1r*-@j)d-|EVC z>V@mZi{3cAYy96%jgJ3$cgIuNho1V|(F;GrOODOW&2pt^&4WHOds^c?0nZj=ivdX1!=rb>Vn~RY$p*2yruq zIf+zh@oc0ZOx{8qfP{EFTS+Jat`ypYKA~UW1%fe;1Vtdb1zabrN{iQsBD4zx36emB zqhvAS@Sl`iWLBM2kw(>kinOWvR7AB>z5Hu1Owzp>6=yHdrA8pwazaDLS*K%c%xMQC zo;}MJU--#Y7)sD(%1+#ng>x|chxy_Q&DN%qM~&e=)Ug63n0oh+fn z3vf;X4F5h|j z5=T6!XphV<7DXAZ;70BBn`VXUYNdm?ss0`h&m3IU%$Gn_DTjC6j}A*)b>L}zm0T2M zVWf;s*3fR$qhmI@>GvNT94jvNr2~J**%3-@qSIdgxd&oXF`z_8_ZBb=rv}fq_p9VG zkFmapotPtIOKRlq_cM%KKx#>w^0H4OHAQ1eKyvMMS81WE*!D-H!rf5kPSW5#_viHE zcx~qM%b>X-=@m8enao~cnUCqI|HJ$M`B z7BjR=yX1PrwhrGFeW;BXB2N^o8pL>t)(+yto)t73wf&~;5$h;us_{~oCxm+5dJ~YO1BzH1&(OBPWfq(d$CY5{YNz}0kY$)8?+A31Y zju~;mRjqLeg_eqnkvy{GzflCPDVf(e#@gD#ea5qrn6wV!4UCKlwc{uJn{+G!<`XwM zB=Rh;xg~W6Sx{~q;SZM@v1w}3NXUjAhqBQKJvDRhd5a}{b3xt3jI3111=o~Z6+P4O zE)PRzxKThi1Y&~*trA4S4y>J^|M312mYDrxezR6qW}N;Aemw4qV5o1PS^-B0ZYka| zF3)3L1L81~0!&scb}bJ5uORVy6EKr!(cuw9c`RxQSaGk~#>oo!CU(3?)&VX(2rstk zwi!mM^}Hcx(UQ?IC+0LkigVQyX1$I-R-SX8`EDitOSf1mvr7#jMxcPO3x&>G;k*Ux z`aY%leo_@H-&3*(ow?2;h$7%^4~z3W|L|pQImq>k;#>~)Dw=skG6w7P=&K>1*Dj=9 zP9@Un$wnn?v{W_o(r!C_Q!e=4zc5afjcW+MsftgQKrr{I3z1kRFE{iZ(`nPo-GVJB z%gXBpwNxY)aif0d8Syz`h)Wdc0rSJkJRjBNgd2ran;ZRtHPaemMxyQo(Npvj{xNBc z?$?^2CMO?U-zD-jou}p zFB($W0`m?5_Kz2dEP%ic_9P!#D=p`MX|`6HAv9fqpV&FfhMPD1Hz-ZM0yGE_@el>m zZ+&n?156MRT787tg$j2}#aT&soJqc%pAS0W&U{J zXlc84&SXP>(zhB~J!swn*3A=XaClaBWB%4RBZ>VaxJt}V_ z1HW}J5g}bUw^K?(Ye!FSnAXNcR;@53q?)6F55mAHmhGKL4_C_Xyd#4jVv+o}7mAji5 z68P-wE_w9N2<85OIN|u&6Wl=)J*8~QqM$Hj4K!@HY=m1P*he%%tdmFpiZmR;{Q`NeFWUW_3#1+Oaxmgg^=qUPR7N+*yO%L3_Tg&(wN=zFX} zuuL?q{z7RKA9Xo1;!HU1VW)DmF>4)I6KY9l2D3j^LtR6rX0{xi@vyA9;^j~Vy(B(} zJfZc`?G;xt;iQF>Q2<7!BNA=`I(O!irx!rtU;8I(a$C z!oAvta+DX78{3oY3H>>8QvK77s8FI+}~ z$wJGbW!d=tMVW60te1kiRf)XB_vp4=s9S&*f7TqXcj*VNpQ<5^fd7w(FeK#sJCXD= zhoiNhyJ|-K5eBF-qG%S$)a{zZcNO;4*aWJEkCc2xq;cV0hZ7~qO?cov!;?C-neOfB zoiiU2d)FzbD`Er{+srBGtl?jacJd-=d>BE$Qw*@Mc2`J$YyJ%~@u!=3C?<;|G}nJl zb)FzE4*C&8@OF@)QAoRQ_jn;2#igfK5`{N8;+hX_@5>C4wMd5p#{48Gv+nlm(#zfJ zlnna1sLAy`HTn_B;`&JJ>k+zwzoA)d{VCW_V5G}gk^1G*9*Rk=?nNRMO^u)$8HRF< zx!oU)tsk?9Q39B5?@vUSWD>FvT>*Sb7X7Xi2!jAnsA-NsgTC?I`3WC6=fA8DUQ| zcD!*qGqGQ=9I5J1MsFCW&?xY|xS{lPI+czLHoM^bFU(srDao9_$gDe!mJ8u)c|QP^ zIM49ObZ&1ui0t&2gNik(%~jg#y3EB+_M4lTY+JbP2^SsCcBj?Dq1+fe4x3YzOD=Hl zRW0R~gMW2xHgwk8ou#aAUk?Dj6RRC(C7~^JnVQZ1Ymm6P{n?N;bvFe=+RZ9BpX}fbgYnTqEnj_6Z zT47ba8Q{&c%oD4tqEKiUGIyrQJ=SjJ4a}3N#nq)#4UD>>pjN*>U6+0bS!z$=IH?JW#fr{dVm;JJkB&07~V_S)y#bvksG z&(zMfz5`42=*(B1J6k!sbkxLN&s{q3gyApn?R4_Hz-7~Z7E%KVOVXlGPcQ2?lV9e+ zuHN=d2)Rg*aAr*@b<^Vz4;V5v2jPu}lD_<=tDPSJ=62GECXZ8}Kxjl`YhAZvmOEm@ zShxBO`KRvyduCU$-BD?3Q%m~*U1k^d0K?;)Cf z(kseu*NZmic_6(ZQ^BU#TvJimwt06MQM+Gb!G@*=r%0v_p!~{d#x#pb&Y;qs6~1NR zHR!Cp>BX!Jl$z*o;*nEUi|WqlxPdNqicH!;2*L1fy1xbeuNThI{|piIzc>ukI7e-( zd+eN@!j_bH86#yMkLfJ}?oD!qo6vy2ez=5I4#VDV7a&!tAbJznKBrSNSan+;U%2_m z*SL#);4|;ZfWZ~`XK#B()s`Z&P0(<0HqP(HqSB9?>DM|L1q#AP zt-~pa>I^HJ%;Fj#S(y4AlY5{r*T+Wge4aPF{>~r1!FZ`^2mNt;&hHz&?wB9WK<*k# zk+NsI`&NrL9ePLc$#I+8$HHh3dW)Ex!Cke&<;Ns%Aq4@|+zyS97*J)dzHG`X@jD*6 zVCwFzx?s8Z{>57-b^Q3aEXIv6^DGRqN(GjD!1mEpv)bp2@-xQ(;d+>>8XYB7(Qwg0 zx@BEY+p1o|KvGHMchNZ60)9M4+jI=F)v2ymP{n*^=w1UQPOIns#NRB|bN?HQO za6#C&`X}?ktHvU2M(73!<>C`Rz>fPdre~#OA3$`M)J$Qc={Kgd1^-OnW;)ICxb2## zma(zo=S!Z>*QQJDJi5%lesuCw#{svesbYxQ~#w*llu&J=+@k}zF@Ov zYVlm_x*UC4pr5>a#T&va(VXNqkiC^f3s*6WuU}Eyqj$jQkU9|(1!iz3wf(6f_Y-uQ zFxhJ?{;sIAHw;x*o_U#r-8bB)+&;baXZz2iCj$n1G%}b@cHvXbr02_d8uQi;);jaOH)f9{o9Y&)9|>6x zI0N7)&@)^xQZy zo>GL&ZA&RGtqr&OIpMxN{izR%HR3ZfuuQX0BOSY2ct0K)@3F3q^WsdL4?O138SwY? zJB7N3w)VG=H_pG+z3AVrr-br~Plyj(bH}>*n0%H4D&9(SbThY6`5AjCx{qHb-pc{$ zZ!EG}mNoWBwUG0YLN>7!vX*mgO>ORMsx={H+Sq!(v^keOCx}@;5|3NLR#RMHOO6<2 znuc3`$g&aP*LpI*MOE!l&YR4Hnb1?Pr>@D5;tcvKHkn8WKV_f-{1iz3;9p>o5m1wd zYfy5V?n%o^I_cs^l^`6e^{aO%2Bm+jN@d!lO4r#>`!@Zm(DcM5LtHF)UIx`l#Rhl3-oijb?k>{l* zZ^!^D+(C!(#~rr!S!q$A0HoD!rMjK~gg6~U(O(49*Dwp$J(b$6!w!AO{ zkNGi~;e-ADWT`Lyhs}2Hw=Y1q!_n&P*G-z(Pd`+3(p04f+rrSrJ^oN}t|CDV$ zey`(s*NeCJ=lw2rYeI3G?uygwb4Y@h!KGrQqrWm)L@YtJy;jyp6PUrd?#s!- z5*%jDxZ=|gONH_m$_-@ngVlR$ZGu-nOZQ@SO-H8z@*6HUsEvYry4%NM;hxeZ_XJuQZ0|%uh$vf)~mJKwy)tgDC?C^EmpRxvQoLXxvLHib(yYE zHMrt6{YTA}f7rUTujyU1PFIX^;uc&WiF$J}aj8j;2?NHaTvm;4hvZw~t5Y%>U* z+7v-|Oe07+8CD5eoao8BAaY4VTWt7yKX|?sS}N8`r;&n`d&|x3+E(#C7hnZpv(;)9 zg95vsJMKpAb90)Rb8^aYH`a5h({kk*Iy5bVQi|GJsCb^^sgF=2&d(D72%jfWufYP* zeh&xUoze3jU!D?)uurz10Vuws+>!evX0e@RL!C1*Q;Wqw@iY~9qEd)AaK_wZ$@`fH z+;~=j6ut76ROA5GLm?m4t{I`kM?HJn-$M<6LIO+0Y2ofbzCgZjP&4mYoDfat=(Bp} zEE!Al;7GOnYHwzD4-;vbscu(pRUQ;BHa@FBIfKCzGHc*#m*RhCI8fb3y99LKa&s$4 zMQrp1%xwGg_FPC-%{6LAp^;=^*SKZNQGeg+UbEQ5^^VT<6^<;N zHJ2}TQ@+I+ERE!!EthAinR^0nCd+}whsKwAC$*=xll*kv)H z#u2-!kZ>mk11eya5JoEh$<#OY;5C7atoCvO0Yx5fZw02e23mIgHGIk}+>-PwO>nLwVJVfM z^RfQhskhCw?bi|jvO|T!8=>^@dm-+5^7os^>G+~9cbVSERN?K+$?ZAshW|rzY6j$Sl&uh7e_|flckLR5&fz;w^(jr2}4(e_mq{(VXHt;PJuPCpoKU|JP z?=9|p4gr6p+^7S5vAxEhTyCmwGUE{gDtO3tV$7tSDw_#BwJmgeFPsknAR}~x_nYx! z0@i+DAZJS4SF@johzmx>Pcl`Z>;!^?L6rT1 zCPT_5$<6(-)h)p~2%TEJldyd10v9@(2G((b_DTq&ss)Fw(M{mCz3g%Hwy8~nzFl6B zTSUBSb%@uAxrkkIj7SsmzgqS>0$M@{V6FyZ6Da~9VPY^k(_hQ<3VO{%+g5&6A-Q!Z zj-ecu|M|OAL{HEf$CD-O3I&MAwI_;RHogOQ=&Iq-6(F+b#C$-3yGO^}kR>gcioG(X z-eB|Su#nd-)hRwIyVWlctNCyrECggmv@!0v93!Pw_m>veGdCN!XH=Kf&f@+q9- zJRofo)uYlBUlvnHwapp8TgqdrAYv~S{QTU&T`F)$GexkJ=ZsDIiT4-bp;#HCKL4I) zlUG<%k$E#CA$=(+eL6R|&F@cDJ_}Z%CqEwJW)J0IQwnFka|5SWRP?i=g3H<#Oo9&s#r61scs)E3c`$#uaiyRGAhz!~)+)biWD>258Wc|k=n@dgJ30>>+wVC3WMlNYPKS}cG{p2xOidY6-3;Ac zBfWG@L(Zd&X}8`ahrX(R|EKj0Mq=|z?xjAd(mVOQsFQ&3UJ+-JZ%QCWh>#onECh5< z2u-Gk1Se${ez4&<&ErBGGOfr((itbt*^r+XVkAOV&U#yB&rJeM92$$pq)nJZnNMr? z*Q+dfE`>TY^Fn^rt(6|lr;stM+ooZulw09AcBw|!)()?Q+G@I-FKTzKuOS1Qa;P`f z9q*91+IRrp_XU_Dgc7WBdTj1~-Yg6TyEDzIdevQr_%blap|Eh*8}CKk;JPwIIM$lF zkcN2SM}`lS3$;R<3%kG*#CK6UYGBner%P)>XZ%F^X&yxQ^EQV$(|T{p5F$0*(o|E1 z)qEL$?vApL`8s-^<1D_u>Nykwjr?DMV?AUh0#^6 zY+NV^MHlhr&8x5w5QGkROvgV6Tm4M$MA8{NfPN$fHqDddFlm6Ws3}`y!7|OSFge+s zPeK?m>NloN;8DhBcOfQm)Yer!#)4G(G)<@8Mgp%ZFpF@A6Agu!J;^1`n>5x-<0{UdSb5DXEjIoCc1ZCWu6b(~{WTuX3za74`$Y5rlgi89fF3}d=~#-QR!FqfR_tvyDQ!c*^j)g+VQ*4iDXBW&L9!ibZX6wXS2Gg%ClFHg zw;N6XJtAKmpQ`Tf*3V5aS32p>2k!fZzJ1eIWp(Lg-#*(hN2ajeSUx+I#tPbHhL&In z;@l0V9gTF5cndJ-LbpB%Cnhc#3EJ`wp3PcLnlo&cy2*MNDwS}zrmXi{4!2D9X?`Ll z_k!ahg+?S|v#No5&FfQvJ)4H0yF7>CK|9TQ4_FO^NqU1Q(ZQt6d6DH(zEs{p-pd}} zzr;9ABM6$)l$X57Y6xmo zAjt(R*t$SJ!^HzsLY!R1o54gl+kjdSDJR9s*mgy!Qy)!OMT$m^0lToQ!S5eKfaY7o zp>3R=L-t{Q&QAAbcD88TFRNvf-S*q&TVI^7Re*(bN;H4F& zcB3UR#-hmdm%?>!L&KzLSsfI?_g00XvNgs6JH9j< z{=GntA1I2}R+ho)JB~=bO@uqbXr{n1-RI`JlUZJkOz7?oMtS2(4b2_dok%~yNv`)v zsAy@0kKXVPD!{dqaU#cr-1ldV{eT%W$u;Im=`0Y%n@1xw1j3bPmJwg8s{lGTRunAB zHeDFIn zd;Ti!IjW(yT_iSe(mI^F;_9;WI=9@`X?Fp1=T2T*XQm_{?(HNqV0E@1KbrD;*uM{W z6JcFzX`aFcM;yxR%dm_wczq?t5Bn~(PvB1i)5mms>c!F$@U@mvZkW{ozIQLic$u}Pn|5b-B>l)u+9xe4z4AYv8MLF{0cTU&G3N{@$**&81e*i z1PMTLgvVyk1aN>&L6rouEPz0-1XMxUK(zkOwa#MeQ{DBm`UCz{FdHHHL`_(*-}OHl zNN^7nhED_Wg*J5m8VBjbVvNS{drJepjQ~0h%oXxalBqIzeu7&Aai2c66=c?`4PwM7 zG%Z~By?a$*@M zoNmOu(E=3qoSvZFk=&8+O-;)uS7a=1FFcqN%ygOA;b3Gg9=Y#vtAlgeXy*3sXe`IX)$u%l2^}u}5=P&MiRwHh@0hSDA()DxN1R{WHMpPSz6_v!Z^1=i((^K z_f08qXCzT2tfUpXCQT79U)+U@6JK~@mY5$DVwUE37Iq;aTnk#M`S}Q}9n3!$@{j!C z;GN4BP0Y%KtvQ5+@hoUqzOl_z|3Kg5Z#L(%e+(U&vs@mzLr#1i9=1coVmN7Ev|^c< z+T&&(IZ2~#bcN+!gBDiCPHd5mpoNZVeB7AX(7T zg@Lr6no(1x55A1;e$68Lx>VJ_wtX{9jMLS;vD11+N6emR$ss+k$zOsggG+!U%%C-5 zHGmjItj$;i*v~{SCrr_`oIzwZ$!~0pnUH@d1he(!2BG_Jb4hGRx34I}?x2Ttfp4(> zaD)!BHRwiehq+NfuY`ZkAf&+d#XIxQ${?If9cTC=P>|A<)J4#xr0bw@%tfa5=a$GX z7Z4?UR%yZ(S|{v;uMSoy_!9p7qHK{WpEIW~E)$N-&m#NU_iky3BlojWX|yDqB7cHg z_9y7-_+qd<^v&G6-luDmm^5K(5t^8k>qo8#_S6`+hzmgnq789+FlP&pwJllr{bclW znFBy;eA|)U6NFxOTqxU)^-gN$XYje^faBiE|9j9_qXGudd-&yiI zF19Z1dF7Sm{r2Ix1X zo5Z~=|2g)}>R3)^v^TWwN6~49&8tv#a~=D7iv7H7a*5|oMRpr<$2uK`rVSSXwj;>^ zz;=6fUP0eNQc|O#TU2AExvjdRrAstpacOmHX?0<9t(lWZ*?NPL&O*DTyF*H2VQz7* zt=L$`;MaLc3jJwCO7&bpvy4n8#-FP5)s+R#^zL`5zY64?UglD!7zb3zqza0~BYjJY z+1A?DmK}w<5x(v}(ZPsl^K5SW$aJSV{zzFQv~y=JHCb7lb^f-{e2XPGBmmcX&=ksE z&6d&BWUo!MSgx_w-Xunoi0sH@v$Z-6F3PUfw$9w2n_F7kw9cLjD4AlV%j_toG8PSf zwC0^FDbXn}trR`eL40m%h8N0cFM3LulBwR@q_ZqK(t$FMuc%d*1JBRCDClammYF`Y zDR*vca`rwydrU0`-)MJ#9LiyhYwD2Em|t7$MuIV0>x5AFBNVjw12#fdV$NvSI+OiL zGJdISp`kpzq&;c*Xmmx_U5fS<`*k9lPJ1)^#z~GU6%BEe;fOVRQ?Lk4^3-Nk#Imjt zO;UTl+4+8`xnvwRIMYUQ+v5Ak-1ItxsQ>!>=GHu2wfU+L4aQ!T?dr;BF-5@NqG<00 znF~k%X)K)lHXA>PH@@>RihgqLW7gB(sh(lnBi^~(2zEi-W0zmYU^}@ee!jnfJ~@E_ z--RA;@zm$$R5Opo*JS-`FCzR8div|o`RcFA`wb|24~Cv2-gngQke-Adkc|e0q&lp- z5AilF@GEqc$kS^NUi`jThp?`7->jp`((aA&|V4&ty%-Qz{69E6Xa^0XZGoxLUAeDEk8H2)4d*fm@jOsLt zd!xe!A(YtN!iNrldB#1~3B1X5;P)3V9Q9$gYC;tX;Xld|S2;LDa13Q83Kf%15mH(l z+>B=A0>1j?HxG0SJ;fmNF3+e*$i4X7u;)hvAy&l!#hf53LPrChL(>ez6 zVGJYy^2OMB+s)W}V_w#5#ZRf>4uov0(T`QFx)W#xiv!v5YsV<_%s;y-rUTKM*zB`5 zBEtjIf^t*D7IwBKcmiMHUgI-xL`4uvwh67+Mqq8hv#{abBRUxx^E@1m<92SdrtuJ4A%SW$d{(I0~q2Itp)9j3C8u$ci?W^ zTOkrnc7+mD75x1rA!VA4HKfoEyPdgY6>%J5Jw=F2^9^+LHRb|Vx$P9BQtoJ?C1+)F z8`gGUzdS3uK%haOMqoFaM?1z--ZAZ9HuE@xyQg@*?;{*2fCVcn-YK*KF8Ba)^FtUp zaFH+%9GaU2UkJzEdusld#8`$gvvu~PX8M1%JImPyYb|TyMoPE z!H>AlpwA*5OoeQ@Y^7|KY(?k<>S6^Y=L+Qt7v&y{77MxJV)5a4h+O@RBkhz?n$Ua#tfV491Ql^sM#s$+ zl?E+YIXHp)Dgm|&2W)9ZWl19F4M+6O z6)*>QFA+oQFF#2?HlQ3_pk=8X@NLt-&+1CBGf;#A5vJzPAT{hLVjs_SjFPi3d~F<~Bit1%-7Z6RmiIk*`l2T<=f*%qrMiU-#BZPbUp2D9|QP2Pq+ibW+- ztO_|Cc+C%qe{cgby(6+Mc>0E$Lb)q*y&YTZK;@WrWV9exA(gli;%_vOLm*{>e^dwk22qw_@;_!V@V z@9j4YtOE&vR`NIQjYU-55ZUL4I3)-;zb5Jl8S+J4tatLf;W_%+ly1L<8_vvM2o2ru zk~9QRVulHJc zWAHcJN)0S@JFR;b@lpZ>9^NkmBe=s4lEe>a1tWOE539ZB!_mw41pNV1>me)Z|Ge7^ zbKPRxivP5Q>g&G+u?8mFi5hUe&(aA?{p5Z;QivIl4C4_OJ*A0%@{r>H+$7IqYn1CM zX_vGm33IpNx{`@V76NjiQj_kHltjpSCBJuOx|c7wtn@u&C3G7 z(E3$P?J%n_g-T(DiTTO?;0f4WOjNAaAFdA2@PCd(U5mNM2ev!eVH17=J^ zN9a|pdZ*V3mg|Qc5gGZ$Bdf3~eToV_zYv#%=HmrPQFg)Wq4*8koP1Z<>%Mj4IfIz6 z&m6+69JuJuHK@CJvyoVFwI*;{?4OFhj~9VHzFc#WZurq)lgFay=Gt7fgs8yoi}GNz zVUXbJI)Z!ovw6HlEG)V?>A?Cd;}cc_w2eI2r+Ku(Nv+a_xLMS~L4kKl=$+RJb^^b* zfAc1&b28VM9_o2f{U*hO)DR>`m=(xc`O57{N&ku*aVt7yw^UJW0jp32uh0Zif!}O1 z?(#0{QBOdqd4Y$I3u&FHI9fcXva!H=mB}-Hn#t(3I@Oy$tA)~$3Csj(L@Zcblu9Ac zs&1OVw^7Kb0F`Mx7tcA#RK5>xaM7l0S#fu}o% zK7>|LnJh?eEwOnKgwIgtw=~9%{n3Tc9jZ*P`!S(a?+x+BQSx@7>xy@X1gH6`_7O+K z=r{r;5C~HNQ(^YQEBogN*w&GB+{gL6cTFLnTsjVFE2UQ&Rru*_X%*wEqrJVI>fvFa z_wuTqrN;(f<{fDna-`K|@FF)TC;AxIVBx~6n14F@ZbGLzu#aY|6xaM6Hr+ph7Y&j+ zC@06`rWyaaXO|-Slg&5Rx3_25x3{(cm?o7#h58A=f9J?MlVQjHUSZnE>pp3@47oi^~ z&w^f;*(cOa^?QTO4+8{>m}#3nqbhW7lmOnZ2Ji*qGL?@EV{BvO=;UCmZ~YIlHL!qz zVPa<_WF-6tvM_V7G5ue7rvJwC@GvO3+Zi*6+1faX7&{s|nAHfe+&Kh<8jNq<^dl+H2~{g4#J{}NYbT>{47i70|KTH zwE#kD7+Ftsj9r)1CVjQ?x||l*YPhs_y;!4qV|#j}l0GfI%wXDh8&(T_z^$=P<@lA^ zoU=Fbd9KMyx~k>ru~llv?UL%#Cf#s--}v^EZ$8y|KDWP=^o@&6->Sp%_0G^UW4Lsf z@g1gRM#em+O2r(7{+=(la#zY3HeI<3Kl8<&n^*TZ!55Y#Q$u z$(I3SiLd_$-bdHuyl&KKttI1!l+j*6PqwJ9e@~%rI2_&wcsj?o)Q?wBBjN{!s6zfb zq*qS>?8h<=;|Kc?lW!~Z$Fm*EKk6(2f{?H1kea~Ev zU*^y=yn&C@~}|5d?*>OtYd^S8X4#RP#V)yJa6DTCe82_k!O&z|?piS65rZhYxn z52NWTM%m+oD&P(9sYgKYVUIy@Kirn{+1(TpksY`sbp2(%+T;_pzftq#U&kjJ+N=$D zgU5OWR(^VepO1r?`TsN+mj4}1|Hm*G6rBy6{#l8VgR}8}utNHd#{Y)p|DS!BJ2*NC zo9R3J8}`!r{|&Qoz%Zzq8#$RdYO=Gl6S6Te68`+jLdeX@NXYtaGymZKl)q^#EZ_L= z{9pP<`xTJP{vW=7`M;$7U)KJ=GZ7&Z`@gA50fs@zR@uhzog^MnCFQvszexIqf@e9Z6i?@wcio{W)2I;4`Hd<(X z#0Y`7c%T4UYG`UGB|&hcrhvBqz5?gv6agU6W-{lNKj4-a>#vm6?pA-qE)@qY`12Y)VDsjW#g!l1Z@dH zWv142aM^8&`)&fCCPI}Pj(ak67@XeqQVMCX3T^o6y1axO`ch1mA|X!^E^iBe+7m?#Ugi;@bFJM`^*p2P{{Bbo;a?Gwtk|K>UMeW4G_h85;m740`OI%bu`ZS6yN zK{aK-XTX){upGii6k{2lYQam`;O_$=F!p?NH4%gXeL8Ak{h#p8L^v4{pRhPHd`i)L zfALNra77zugeikeh`F(2uLL}A5Bi2rARZ8O!gB&Ua)+2B3Qt=bZ-6tR+hG`bZ3!0w zu7nW{ND_7;&_iLbg<)0mFHb06;i>b$Pkd|`n&yJ(1ys>>1Yl>^-GIAWcSIFul21IG z_&rcRpy2m4Z+?uUdC1{u1S}b#HSaJV4fV~J#e1qcmfcA1f+6RB7S5cNl8(Bd@(DA) z!bZZ<=&`EF(RtO1#OC*(@Lmi!Plylh0IQlgV?x@E zyaGpUNZojY!*Ya`3XJprz24_%R%Ip-9GA^Ua>D)qP2EifcqEXqJFphAqax&EKFEcz zmE^gfI6Uyg=ws=^J@bhyC7zF(95LSGYYzG7n9+7dxg~|Pvlp1=>-Gp-=WX|SIqzTr z*bh8R{5sm|pmW%xRRkEC3n*rg9>|XBAkOR2AnoXE{Bo@OgaNSw;(bPZjX|r!n<^`E z0D2gZ>Vp~PR!6jUXlr4Hy!{i|lUg&dj@_xB8|j1EfDShdpI}_mBPQ5%PxbV!RPPw? zaNhp(*3>)OW7)p4d6$YAIKa`2Lle@F$B%A?!fitc&pHAP?9fsnsmL3Lcf3xV?ZBSU z+=0;Ba{$;Urf zGP(<9KQT zAD~9`e8vN_Fq&}>5%};z7;+}^1YY2J|Ko>(U_%DE`v!Z5a|d}xamPx+OfF`yC(Z4MniC0eY!SlO=RsKl)_U8bYdRZ3m9FCfdZ zbBc1@yP*v*V3Tp#2f+&R`AXB8e2?0Q&gDjgcI`vaia?JSJQ6?Hy}mH{9N>|)5edsK z(!z(Nd_sRE@`&^d{bTPdSc}5`3U_m3W5V>p`GoL@jsMabkZ*>;ZHsI&KHbvsrxd;}v_; zKb8^L3-iQ=h0C8$l%mI5gN>KV-^iUpeVDx;4)1RxY;B^*Zf)J!*SG&0enwr;%jrQD zdu-ltz9984)+xR4$wvGKHo{zjOW=wR7HmIOfFc_R&54v#&}bg`#jmvchm*{gUmJ@P zGJv00i1Vj%ah~X+hP^v)z?GCS*t2|jU;;?SqF-nqxS@Ke+q=H8_#z!M@9>3qvya1l@Du{{V-(r&EL4}D46Qu}Sk}co0o*qUoWVwH>^$xwc<$c= zC;J6jTbPd@RKW_6CtNf~&bEzfZE0?5Y^clB)>K!eD^nH8@de)Rc=g<+C-h7-&VUsfs{*IMDy|N#VdCUNCz;q`x~U+#Tp2QPMM% z^ll|>fOIejHw4<9D<%c{aZjMVzhm8so$Wo7pt=1z?ZoiJW!h8)+OO3?QU|GiN4R%C zcC=w7K^*PP`w3DT;Gz26;YscNuJ9!K1pQ33eetFJU9;!6Px1tV-KmOxJaK7wNk0lt z=ogYo6*N)#nSOp^ze@R;z)IR1bZcOL#n8^%21T@_C#k>p&Tq5OxOw9I?dM+gFgx3wD+4sUbLaLz|K8d2&%GL?VRtvQ0r!$N| zQaFj+?SY+h=7)p*Sx>lo@g(nlE82O%h5?rxaGif8Rk2?*6$f^|Q79$!hI13k&R$be zN_Co=cEQ<^#q^27Q-C1)14{$&B=f`2r$!nqYeYMjHbOP{bYr-y|5BKdmHnEDJv+r_ zT2Alp=b~abu=7g<6c8Ty^!$>=r4l|Weu-$3(#cs;gX?4I{$#ShyquDVY9h=jJY$=Z zuS->|8zhf}d&K}mFnp*B#&&Uca~g&}7^D+?>!6I5K&F4o?D@rf04?zxKyo_S-A{Vx zm7%dKwu|VMEn`>C-rf@iN+20 z*;5+ZX>-oY6|Xm*y;e%~TPDtDJfxH&9!9weM7i*6Wty3{?S_zu4 zKa6jgyGCS`(3qx{? zXwC#ea;Pgb6k@9&LGXX7RA-0}I|Dv36w(BILMSZ#r`vtT?~_#SG87=9phmqI<3U_5 zhtz^b(hyCXOLXFZv&*^L$v6X|gacBSv{~9MvC>goj-2EN1Hmij)2Ba`>uVL^Z#36> zDo1-j`+&ufPmws9OqLSWRk$w)Ia4?mi^sxYlhtmot+fT~YHJ$m8|v#!;gE_~g-x73 z5|}wDwrH7SVsmP=In@$z3%Vsc+U7Z8-1Ph%o7V)*-+Zzn6OTr1#*lM4Yj2)?FJ1$q zj}{jG&b-gO47zeFnJU|OQEXxZVpEOWIw^B&-Ce3Zbxa!_pvBYb4maWJRZpg#Z+#*4 zTI${4Z&UBqeU#GFsoGUjEmIv+>gGF^tM5U3>Ye~q=&)K}tHN8_9$+6#Jygx2wyw6N z_MW!2j(ctU@Dt6)@X0o<+TPW6bqmv}CN{H;w9sF9#nJS63$CeE14mC*lqD;o$%;g4 z?Q^v+)-r7ExY`-D*VTTv_L17}*Z!#X7q$OcJ5sCbt;Mx1R&`LlOnr@-CF&OSboEB{ z4)r7IC)IDLf2Y>y)E;%Onz5SIjMEU4lF(vedAg;O)ZB-1=`?Z5iDX7_O3p>jHO@zz z`<%y|st=r>I?uoiI%T7naS};IbV7wxk*>&AuoaUM6NRW0CDBh1N^7#3&6;BxHUJSp z8WCt<5Wgska@&?RBDeLlk+!F8*yf?VE9)xD7ChLKL=9pCX{h1ka5S@q`+_4?oXmA` zJsiuq#x-8#9K_Yzl0e(JzT}LNzEge4pX7j4PUUiITgB1b>ERs8X3b5>G+Y;3#Zx2V zh&Xy`SR64qnsR+>%``AIHDQyvsY!fOEw&n4TTw2F*Y4-(LOiH<`kVyix~r=uZjfsl zo4sMJ$go1x7Yjypv8I^OZ}KC3K;y@ua5K~3N21r@$J!7Cjckh_p(Kzb{BpARxdA?S zZC?(-AMQ({J}8Uw;ZUqDQy;C%#A1|4ZB{C>l}hVtYwVC!sJW)W!PDZni7(cwtszsM zyQOQ@Ag*)BW#h};-q@6u>_uzex^mkdhf!-axIO-w)swmwXg9RPgRWG~&ihu*TK(MZ zm#k_?_{>h5lq{=mpI+N}Q%B!~^851l$U!mcoH}vZJ-BJ|?D~evu!qupvM|hg00|r@ zj%Uk)xkHT{qJvvl*R6RYCQ&2=4&W>b9 zl8jMoZN<6b9J`~efs00B9=F#`cug!2jk2LQ_UT=IWH3rvNQe1Y9J>vEKMJb-@$=@m zoX+vY`EvL=u2<6=*c`c6{S^14`UO^fqk5Z$Y-TrWH%ptN_j30|c$`Chxo&KtQ%omZ znOZ=oOdJrb4x3!2VU!u!_U*7I!7#iYPE zx!m;8(T#m4Zh7GAo2u%Uu}{plcs(RK`gp!)bGT(n^YbTv+to~QJqc49f!P$%knA;Y zF*&k5X54Sa0*81cN}LF|#_J*y4-(6P$(IvJYK z(ZOx5qtQSrlTqS8Sc&DZ#gXaP;axh6bfS*vHc95a=6*AiHfPPd%tPjrX3k9OS7$Ob zKAft|m}U;aoF|jHzSFr}pR#i3>?(6c2OFjeLpcnQ-2n)%zhe5m929#{EW#%%=nKhyH%;wNd%+1D641cj{%GCusR%x>y1%T7}r za;HPt(4x@iAvP396i2y6p?9dS#C~%zj#Xu7EbH~g%n1>Tu3+QsP6Z3;fXx`q4bK#F zr;|yFj4*(R()uZ2{s4oyVJyDcrw}{PJySsh(&S0C^OKnDnpqr1uq+u8!c!Sv@dR5(ioaPxZ%X=xuehC{`P0# zs4bicw%{+1UVh=kdG6e<965u(%oPFWEaa4h$_7g{=Yus#J z=hz(XO>9ct?AV#Q-*BIOPsNk==PHg?7`F&JOoUEfu3N#zbP*fVC2UNWu#vXjjdDfk zaoD)Ju_-RHAqAPjbrxl!fdMIm(7^nXSEm~D*Gyj1F|cCJibE?Vu4vKdt0rupx;pBN zrZXu=+5DNX9N)Ua8Vs<(8F$ZZ+k4}W?)!XWW;}MUw)?#0qc`7fl^%L@|Fbd6PFN7L z3&Z4Butsahv+_b+l}*gDq9I`weF>Jg+O4leUyJ=t{6zexs7i>@@JEl=Ah#OS37dYhZknE#b+VqAYb3OXNEpMsX0fa@XCG0d(RPrX_n6aAkV*eN z>6Bc1Jd)c@7bjHN?Z)mwyju3V_SpY!HgmD0%IuGsb>`xtl+CsbzStZbESx;3vGNzu zgsjzA$weqA21!s^@;V_?%!Q0J-webf8L`nVWNHuwohU6ka zEdj;KaC0#gawp2h5Tgv!q^tq@EOXU1_9>)C*ZA;A4kF6?4ygkkF{`H49B_+Twg$86 zR$CYXdla(Jx1u=G4aC}adMzc?v0H-y7$K!A8fYVU3EWS6G5}2|F|?w@&=8FeoNX)F zJ)ERGT6ST%%n5_+H9;VHATT;0FxZO~y8(yj5BdFmA?qJ3{AoaMEyhrT#s{FfQchM8K0jn`3xRMt{$O%XuJ-9l*GP2&^I)&P#>X5Kz`Vy|Bp zvfw&6ajh#JNKLrsyVECoOlG^2`APmKx36f3cwC9sZ=E~y-mY?84er{ywWYkO zWAduT3zlBKFDeLO%HgLY#9ssJr-RItrO5=F&62G3H>d>*YDFEA1sFgFkLw#;5y?78 zetR&Kib!RUkgcKd5vesC5+af%9G2ra6p`YCnsB>>;f9Fsq+v#w)je;NvL@0N= zax zw=b0G8Gmv-**m^}{LpwN4Z(@=%y`%2&OvhFKyW6Ya&ji1^4cUQzPVP4$RI|H#ktm* z?aL;81ZeB$Cg~muv=gCgO z>m&M%Uhe#jj+@2JQqR=P(hYTTjbs)-OaC>`0z5;PiZI?u7otxY=mF7|pP{ z!F)hhrIU4xZmnjSQAe0TY?OVR?y%nN!7PgePT~kxZn4`oSgjTrP{~5+Q3QHSTZSwr zER4nFo_W!jCvJ%|E+z^w{jQZ>fD~>A29n_@CkKS2j>N zw;X~ncRA7_FZzRQ_ft7vFd;MYN+!`PdU;1gGAk0kAtIR+3Evr!yf5Oz9w%Je(% zE(carN5>}F-{mKgzsJAV-|uJB{;Yo&B!>Ja{k%^R{(;8Nll?`C;fex~9Z{B~q68#y z&9|zu<=-eRHh#gyvbb$mn#Lbd~v>I)N@urAR$Ob3x%S7z-=Tk!~vA5kO4gm z0;GRG2^HD7Ark_0OA;J8LLNj3L{~-~r7c#%uX7s_gPLT$Krlu`KoU&EAnrK4nZXRX z7Q~H71IWc*a0GuBDa0{jbQqU&L+9KLKq{Lx{N&a6EzIvQ`(< zHR-H+QBk!9LJ_K4{dvG6Ws)V`3F0jWq&g+*^B0Q+QHkZa)t(WP_+H)aB+CehE z0qupnhMdHKKTs^W!xU6278L%BpTZeHj?h6gh1UW4S!7*6Qw59O zrC+myQtp}Dj1dsy;0MoHei(HuUeeyacrnf>QG5Fm+Fk;X=riimgm%iQpxofiY6CtJ z3b_M5b138q_;4t!3;0Z-u-QZiR=Wj{DuG*WljchZ*V9`s)BNGQE*GJA2R&7b?}sw@r&QG|1skM9j0XT9J??bq;Or(R-zVV z2+3!oEz~k>)Y&ICrO2yAE3so@Q?z6jX1?>SiTKP`NJCFM5Mmo(y(S5J1Tge3hjdLE z9;Xz`*R;B>6y`XNkMhj#$ZwcmyBQl_$8`|qH~0e&F$+c%L`lgg2F2t);h3Pt9Aeu6w6>B-vI)@H$7fQv|92{16CC0p*84k`kx}q2w%}4+t`7 z27(OAf*^x(Bv5DzTF3OCWH;c^T52K5t)-UTF=^?45S0F1CVIJZ>-3ASwTd9}#OoZQ zIq9A|HC~sGm&Bh9Gbb;b*7R8Z?#t^`k%%hlT8j5x)f(KC*R5<+ohRnNU`_=d_5#qM z0R{0K+4;H~$Mx7ePi>4DFj6^UDves_li4vl2rI{u8G*&DJ6yzSC7N7}vPv}2G%iD9 zIZ~F)424gG2@1>Mo-j>va`=%j2@7V)Ow95L9oCg>RZ0v^)A%rGt2$Q*+Sqb1UPqPI zvB@i1O#0R;BX}C7iXw|LL9HW-xIGC6#VCnN{(ztGR*TI-cs}Owy1gzh!wUv;9D3>V zW4p%eM^2S5j!k-F9QzrgA6v8zKk{;pI4a4oitU7&XhGPnF2hZD3Z5cv&~v@~X8mTd z*R_S;rQaoPalJualeC*vy@p<4vvZefi(!kf%c;gWl_tGK^BKeWjlaBN*~Z_#GyL)K+9?jBuCp@bj~lG9sGE8D`oHXa{pQDT*~@R@Ex7+#(!&cC*h$F*92jW~-T}Pzc|71Vv!np9K7foQM#O-lH$qPtmhY`Ukzw zcn7`g=c>=tBqW1i5~P8^A&bO`7WM-bE~qdy--g3Qea;_|Lg6sSb6VFjjZO>r9s==| zM|^q7lV`ktZk{I7@5v1Dy1n92Gc56qJCk zLW2rIWFycWa*X zze-*Wzl%S?epW?><}zuWW}SAe|31s}mghm8KWaVfKN^13e>`eJ*k(bD z(R%`&1XMVIPh!GiE6jAzVspBjUzo7zug;iG73^enf)N{&xU_N=6RAf7Vj{+SaX;MQ z-WUBG7NOvkyu@3hD%GR$VL*fvDy$l_NvT|sk`+3cOP1`RipD)-c&%cA9_bTXO-)Uv zrd(eW=sTcmE6NYu3&CsqqKZ`+mQ};Kf?Ub8Tr@b=GqN<{)ip1kT)yeuJDzKAY?-0q z9S*4~l$kT7VOsV4zd66N0lQy2cE`Ru7c@4TQ`2^JNc2kZ86@73(U$h_Z`olz*WbI1L&m& zdh`(V$cz3WM{XfMAkQ;QTz?Nkw6MxC;ymWP_Jej}_Y#mIwK}zT5ceE5ryczupbz5E z0c=()dk}_D z6^(ntluXRZ0Od?DMy94QQpp8_b;w+oQKZ|FH3IM$2SMs>sAam&{0Xml_{K{fyeL}# z-tNnu?U}kP|2&RfKE6B@vExIya`(zxA2bXN_B=IZ+m0joL*`^V0^JWJRrYI@2XsG| zqWih=Mfg!vF#sK|JwhH(w7ufC@FA4RAS5R}2gN#ES3a1x?(YPk=&mcuyX@B>?^ffP z@`#;vX-J^9sCNCY)>;!Yx#h+ z-6q#|)ox%oEu+NvqAyI8+Y%fVt9HU6#O=dc8A2oN8VrsAj217J^-> zeX8TC4^+HB^%hl4?Y`u(BuOW;$yv!o$u-H%$z91ulIrA5qP^F?+s@eCaxJb!Mg6}m z7;x2$JESan1!I*ZKLZHEr0lP!Ta`WdG~Ih28EG9eujSy6TG>ke8)N<)rI-=9R?v!3 z4k!C^@KJ0dH88uTa3v`@chD?zjv%i91&Hz`7Z6hEx#4Ot7SqpIzSxp!p8ezhs)>&K z=JKLk&uKle2`P3>%(t?q@j*5}`tD=@G1`3f-L?4}dusyy2lKPX1pS4!u*DnAueocB z-wg9R%t~aNqUkrwdPD#mnX{Vy!OcJ`keGCkxt6%tL0s6sw5aKy8U;;X;XjJ1k8#*S zw&f4ay_)L!_~MfG&fj^+y!xsm1O_hr2WLjMY^aRpXd7_f2K!dRJF`g9+D1<5` zgBTJkc=JBvF(dI{WC0DKs4>JTvkz$^l0nfJf>dKz8ZL`S72z=Uz^%x+oK=N_L8H;2 zRV(^|)j}D!g~|XHkO3?p16ZgGV4*UAg~|XH%Kj}>5U@}gz@o?i7A#nBz;fI|L<_c1 z3BWv5iKWW^N|LVZtt6Eo2~?IOfy$C3P+4OAl_l0+S&|Ht4jTb9D^Zcvl$XWNss(YJ zjt|98#F=Idhj2SAbk!uQ8EmleJbk|zMozi9@+ zqGk{r(+rGqai65985k+j87a~ksb*mOSIwZfW4)GAGk}Qc|7<`#M>CkQrG5T&2@oh^ zH7>I`=_#9DAy``SF-0}trjLF&d*Y?r_vY_ft*8b;_cHwG)h)q>_Pp*=S4gcW2dkOG zifqB48Tk(84b$BeoLMm6?HmvW>g3MIgrFhe6cN*`idfqchO}PsfO7lI**4kS z)F#K`nKnu*ZL-aoscOUY@_^ZyX&Yo%*=Ds;4r%o@+^5(3(u9#=Hkm=jD+A6YtM5yz z+G9RJv2N?k#q9(wJZ+#8cXm3P2MZ^Z%~(S-Zmw~zRS~>aQsFd}MHpUAR7{}zTo4G^ z^aLzSkS34`ok5Wnib|n~1yK@-ILL6aHI}J@rbq@087V_Daxj*xpuZ!GSKb!*3l#Y zAYdW&NhrX6bzvRYMSKWN=$^P8b=B`=wtzD_WHOqrd>%MpEBZB7&=AkRA z%j#P$z3W1*B@vtu(*9_jX=E_F~##epwHAx3kOtg8roc3%|-w?VW}?Kb@tR zSIT7Vv+Q$uMrBk>D%OD=9;f6eY9*MHc)Mtm?1P0J@+tv&10JupLlCWkAYz0r5sZ*B zdW{&dycmGhEYdwty1`FGk3;Z?ARKdEQ1DbLp7$c1=PPkTl^_dU0wd&%pI|ELC>zTG zkd_HmrjBCjm*ONEvo$7iyRdLr?!hD*B@FrKNc4wcEwn@xN) zCh2&UQB2^3>~Wi`i&l*4k~as9JX+yQ#Bt0ILAg5>$7SB=S>KOj$-k^6B4;OO!Zg_I-0a^R+g!n3ZQbnZ z^?fJY8{eGVX1y(Zuk}9X1O5j>dm>L-p9wu1Ic)u5#5~D{6+IT(>y9d7)VbUyXsd5H z#~lskUD0Zb9%w4O&r#Je`d4Km1>aI#J7w-=&&SS5tZA6Lq&}Q!ipk5yFUmjO znQ=y=Bjz8zl7d0Ptj}HX*LkRWF4-R1T2hqe*e2p zYW+PmN)6SgMlkSnWsjw9%%4tGGFunb%;i_FRKfDr`;sm5E}cAg|W4)Nc?{XATNGaIe1MK44@@>Lc-V^3+d2s-oNG zrMQW9mJ>`K^SOSt((YO>UTQopyibGLDXA5UB5Ubyv<>&wc!t} zfw`l<%hp+Mxdp#-aMSv!<1*uTRxdhyak7(XA6{!yC-aWLiF*Tt+ zsPUQvn^vf*+qZrR#TO4kTpvi(9-tqcywJTxqs@eAAkrX7gUc){oR>u(ObnKBmzh>V z=04N?_Qx&!Qll#1L!pp5;4_B8-b%qpLUkSwQkzp=!6*5MuT5R0!d)P2Tvt(2eR6$@ zm^nj)im@mzr$N{aK^&A62$E2ijM_p`q&OcG zjh^&#!wqyMXttK_4xO{}0WyNwW;GI65sazi)Kza1sW#74&?oc1Z3j6NRkOZ({(ip2D)imj~9 z=`adwMbV@Z1d}8op9u6GNHu14+&pi)v%RKqx@? z@)#eD>dN9MY>@oeC?q*Z$2E~S4j3bToKRK#&#u$uyHW)RZ~E=EUDu@^4vFqrqr+{Dws6`RonAhnDc%;jc!}(eJbc{` z?kH@pZ@A){_Jxipjz+zelYu?m@aT$|W#VP|zx;MyOAX~2_mj7Y1$c%7O^{7rpXFNm zDInAqxt1B%3bN?T6kVfS&W#V2oJVFT{AQ<@|5>YSOg7$(WpwKl?BXUm=;vh1{W!o5m+Fawu ztjh{@o=yVbQs+f;6R7m*(P5xZ6D83swKZk4)Z}!E9(V$ce^~Ld0XhveW_`i7>^Pud zhHvr9u=2c3fd)U$`kMVrW3aj8^$cWLLQVR?LHoCE&$0OVp0P?8J;y7yzUc3V>x)K8 ziX`0ad8_%(IW5aFfv){m&FYn>teg9nO}W0`Y`A#4+_Gub9mmgXO8MdyiHJLuk>l~G zmt2NBQ+`iGbmPz8{K4cojy>1aw@=PIf5Xw+KDlvXXXnH(o^=MF{`i$UeYUzs3q!Z~ z9r+g;t#_}m`x-91l~P`?@FBC4TY-}3xGbpzhp-~KA-T=A&A!KSkNp|*llG$)UCNvF z5~~^y;(KHbod$wXP&ZzKdypCh$y+E!eu3Ob4GYU)$|#m%vkhYMi^H;!a~qI#kXQ}| zFy^#J@jXa~-G}`}!|@=aeZlk&N{9)PfV6B9KrM5p1V2y+$m4!j#W_~wWS@At52o_e z2q5+-%%RIY(u$nftb2s&(!(O1+8n6OMFTLVqQp7&U#jF%sTBo7XMHS7UY9t%cD}q} z!EH;Toqyc<-4`yp_?k`mpXc+>&uW^G4En^EFPge)h&&w*HeJ(t;rhD`Pd)woRnu;* zYkKPXU*&(>RF#`gNI#;4F5 zh>Lpb@p`o0yWV#*+V0)%d%*X!?-SqGK7DWF$wnfXC5vPgBVv>j%z{O*q6ms=>iKh> zA}X7Gu~3N%O3l7#D4Y)X>gew2E%HPl)&OX&WnPcf>-C`edW2Fwzt!jSBV6zEG7@&9 z`Z|J1Eb8-`O|Y^W8a+Tk?l$dl-3L0Nb2loh$?MN34+Oa_vc_i5H2S5ov|@oX(QB0_ zE6EVGIaazF8VB*5f#A4x&OuzUO>wGJoGL*1Nv;Lvps)rP3a7WEi9k-4?GK9r-I<@kIDjB^j};c)3J3@x+QpUb706S$X@RkTK2g3dmv zsbaLXm>&IybMy<&FfW&{GNxvh=?Gj*l5+eD=6c}DLFckFH-5{ZnUQaj>|1BrFLl&p zqfsnn(z=V81((&vqjU`!L25YybDqU_$gi8H7&^r%{;AS-{LgWGq9M^Z6<>yzS8fb! z3|^bQx8j+=3*<=PSnz1&(W;}_FUFfd{`0%47y)bIAl_pSE2a6WG_Lkb0b{ja2pF>> zXunyJH>!NR%kTENcE@o%UFM57Wt)9X9AWej2H~1Q>BmuFU62@Fv zQ7rRUTmAlOoW9M7(`^BxH2@7)rvrY`h}GQLRLnIVbPH}#(~n6Kx^^Qh?Ie;&QWjh; zxv4Q8BQ7V;spav5_}2r$U01+#mv1Zi$0{?bSh7!zo;szt&LYK*c~*&YLwsJDP}&5`!7`^d3#%kjyQ&hD87)~HFguIZiEfO~`gKv`KQp#R zSX5~nFtuDLT5ZuW+hL)a20g-{7%zAgvly?-&8i<=J*!e>Y<%r_t}1OCKl)X7?Zj)b zA^+4xdQYa3JQ`}QRJA|7>q@D49R7PtXTrUL@r?d@XA6ioe8g=w`Y*uI(W?@^8Xc4v z!j*U8PW;Vv#-LXf1)0Dut|*{=+v`1*ZXhmC)Oj7%O)?0vPXJZ9Vfi1YekcDppl=Ec z7XBeG)HThD;rpDY9j62T46)^EFT(nOPZbK`fR7J_4HP26o=P*S^m=)V8N_zA7{tN% zd+b~6kJuUe&U6gNJVgyLWuOWl=>naP=&y^$euxRM{&84^ioVfnODYT9uPL30D{j;% z)^BA8h8_`;!d7?jh)~!XOk>FnLC6+Kg;qI4qJ+jahNUONj`SQV6?p$}@k;D04KhV45 zn)R!HfI9|X!V8DmBI#N>BkhG@W&mh9guCQQBaby&m$nR*F|1W<^VqyhBR_?Ifn#(W zc6+p5)+a*fW3iiMnBs1G$cj+NER4B>4lWUp2z=(AZ;s<4| zV391u@}Ay62FV)(_-!?Mk?<&leE3V*EvviKd)18E9TDH&6)GO#3%SC@z4%kfwKIl6 z;205y#Zz?bbD)Wj7U71WCs!D{jl)o@3_~rZ3fkn020<1iAgIBXwyfEb(M5@&Dvb{m z&z-s*uFCJtpYqgm)ARZ5 zhDUCC`MS?3@&DiLVkc=}Bb=GAPebu^Md!6Vgr9aXiOsVffd}^e^s@a76jQ6Sh0be8(R;yGoqMu~|EQlQgZOYwWi7OE{ z2u8_BjBUQ+CTpAD?{lTBwu-U{0ZmqKFhs0IUlT2eqOxd&*wm@Y^H2_SfmW&pw4PG5 z*VYjwgO$B%5rj?Zm|xtnhWtn3M@psAF7%hVe~F7yOJ8X-TG@?`{ZH>2D2XRy8_~7# z1#4&N!(q!atK*J|O{sI8OWA7^#;dMqeT>bIzEi*DiqUyL*_2;=j&P!w67rjNZ1o7x z|LL&CUQ+yx;~>*(tPEamUuP#;$~kOiYo?ru*j~3WSv41OIwejMv;Bzt6k!m|5z^oX z55;04;-o>WJt!JN@978e9|w>-;T$Ay9unM=o4BcsAmgQ?2SiODHt+zM~y9mgN=Ypnly?BhmfBJjzCpku>aT{RP~vuS4GMR*O~jCWxU&nub|2eBv{&F&WJ z6$nKKrRqvo^B`{8KfmZ_Fif@LB;9SGZ$6+bg}&!N**R)L;-^%-8apkQD{-3Qexn>< zbc{fviCA)#Zl$nMw?Vi$u`PLz@VxFt-A{Et6%5q*k($f;aPHj0ZpE+7%9dR2={q*g zo_LGJE6F+9SOfEtF5&xd>+B``oYgVkd`Pnbs5o=k3pm#sqIJ;`W?C}?G`Hw}9 z4U78mfpL@%-9~cwgDR}u&i)WLBLmuqor)(trR5^|;xKd8kfOp( zRV%F*wN0MkfM%|r+&X^V!ur(3WBlzn;G-7ZE9;QP#Svbu(rC4V_&;Q!=qjegh|#F9 zT1EY*^yUCLMhGGzAp{uLVU0%3B0WDyekN-*ZvAe6z|*=fkKjA#^L#|j8B`9SHp=2| zot03oK`7TClxvW)tZ3L=WDwgGhB0Ov;&4!T$B89~@oLt{1Q`|^Tc zb9d!${KXsiS}F-=m1kLj?5GS4$sR4^X381ne$CUGLCqU_c9NQNggLcCisKg*6jS2| z2jX!=F-+DA95OiGMlR7sTok#?7I%60J>A=w0vL8B&H~se1;0uzYDEA$AHQncF^xGG zHN;F&`sN3po8hCefHAxT`9;?f9MeE5q?eXpw;6(nHhvCc2C>9st13*<`-+$|LXdm=U3r`w%nO^mDPCT6OvQnUT^H~ z-`^f^z5kP&KiG6jKL5mT^4E@#TY4`#{P4VlJ=yYP{;vRG|G&T4|MUK4pkFZ`Fi)Xo z@`^ky?t4HYZm-x(%uo4ov*FsRBh8H2Xq95pdUCJv!Rj~h2d!#RC8|Zbr{Hv`RTMZR zRhQ}u6{Aw|u1sAlDn@W5q8xG;vXS~QPi;P1EUxT>^+)STWeTT#e#wyb86`urfKs?w zP#M&c%H?xQu1G2>Me3Uyr23;gRy-?!O-jzN6q3Sq>5NoY={F*lSHiICk@WLvvM_yH z`iE&I?YmESzWImE%);i|n!gg5dBS$#k!Hr%Av9YBp*dCZDTeqB`DU{%^I-~KnA(zh zKJ`wDO<}X445S+l+i(=G#al7A!|<~7mBh@EZj$bjo|f3}8QwFTHZZs12LLCS-vJ<9 zVvwu`gVZdW!&w0f1|cmpv%r)MQd(+eo6{-DCm67rKbvyZ*G0m-%c_k z3xX-r>TtN}7#;Qt+2hdbqu2-%mH$9`x9>;Tk5XhkYC)}}V<7n7)QRKN$m!8jxujwu zN#@QPPZTP2H1+i*i{=vg=_~pT;KE6&LEu3er;4$)tQZS^B|e}pd6RVm-c$D?#nb{# zDB1tb-ts@0SpL=Ak}EkK$yT3JYs?5VFw($J15`TPqMV7oE}e6>w!Tkg>F=a-Nhc&h zbn7dcYTR|n_9R(_R_ZSEuc~|sKQBEWI3oSb@UcOQ>Cp*lxV6|F-`Z^AipB4&xuBte zDcWmP#rGRI91Z68pURnD2S@`E%jGc z*nC_xN+vI-?^o*tt~AIk1vxu{YH+7q#^_m#NpH2Z>sQ1!#8gq-;Fw#pp1p}|bv9&>@+%Kr^Z19a?YiReNt+(J?3Uv%Z0Wg6UGtr(H@4R;?ws;){td4qeDjn` zHaD)$y#zAHzQUjJ8RjLVgZZsFf?V|AiP@6jry!MnidiQxQ#2LFY}n>L)|90s3+!K&K7f&jkgk)Y?Ts#T6cy#UAGm(Wt;Xgs}S)|Bc&5GYk?HeFW z$RIpgKev)u^o(6$=%7ZQvBJ{tIk+N;vH9EM#<@Pl7e+bZ4SYdF56IRJ{;%KPkqe}6^O zzrUdAz}b`7%v1k%{u&|W)t8*<)9-DZ9A6}~eyMh;mG>(@_F-Me*t?bs|C#Sltx$QO zuBP<=2PpTcg86nd@9Zm?F*^U#%r{{#Hy2H15n9Mzg_5KRC7JJ{S%kj7`6@Jv@uAuL zvuHYb7RBINxpEEC5Kn`9wnM!IP$vO(J0L$5;w)U73F%t+tAVx?^bhVCF4dUzaR3nZcz1Ixc_xzWIse1h-X7tJESWio(^?a!86^alp!<) z?z2IhrN0Mp8vZ(=Y#(U?+A3H2TaS*B7AC|z%J#Co+*K-z`VoyyvtRRb%~#qtbv3#L zy5k0m;gs?3!egRN-1q;rclF^>RcHR(du}E(NhUK15TXI@O=gV44EbO}07FS;LV~to zAV8!j9kv)kIOyXymwyZeB( zg{&Wst5sm_s*hI7{?2*D4m&{ zwWX-1XsGBPXWv)6sd)UVm#;1@DJ~hC^VHne=Y2z6qg9nkr3cIQls)TmyT0Vw>dtY0 zRQ?awK78$K9*buORec!?;R?DKB4c+}u?=`=zeoNV%Mx!bvi1BeCa$pJwUsodqcx9O z0?W+G?lv)Jy=>UT3cf@5*u>&Z5x0pgY=QJ86KAuXQjdwPtXeu{VjKI0oNr>gyifk_ z#Qvzwsx-009Jt~eSY}FA!o*lh)=m>EY-ZLEO`OH@vc^noVMSU0X5wtNEbA2$TUoJX zu8D1Ig{7R`1CT6Fn<)Ij8T*XwnKQO++qP}nwt2?3ZQHhOsaWvozpLX86iZAQ4_7@BQRJqO5B4)QyO;I94l8qMW*%F0tb89nrWn z07=nIO_)h_W_-y=XKobryD5)n`b~vIc?IYk4t!nkvvN8E?Xh_=70u4lLMrlYeN8Gd zwdq*$=i3$?-C0h8k^TaY$=@)!?@W=OoyVE9KRe%<`q=a@pWq}T8;>#V>}PdSbqw@_ zUhgv?j>B3Huj%QI5_m*ebuJn{L?kO}&OS&XILM|jNl@&#i8uuoW_B6q%ui^KI29&_ zZ|5gtBt_TC!X4ST~lg#R7`l-L?)T=I$@tYp_d6VmhL@3@dM%>qz<2|pF z|0Jb7(upOKJSTVU8OZyN?QsMBUM4~L?8cWIF1#T}B(%{Z^GGzCm@Zr84;@-lg@fu3 zR*ih*lehF8EHwd9htU1YF^fwqOw7rb`QBM`KGO`cuRtkQNo$$PErmbP)@vEy!|`Zt z$#g-jKRB}-CK|=tx#Pv|u*taJ5Ekdu;veQI=3tFcF0^Fc^lK!bMQ#bi2Koyv0`KdC zBKkwkj&v9^pLDpX?y+JokEu~AgF-x8S~Q$|119>0c!l{P4E>u<Uozk*okmHL7YVO!OL#oc*!%)pUEvQs{PE-OWmNm7K_*xWz~^h$(6T0MXDDs!b( z7_0XJWFHPEUxdl$vCq7+lC&a7->Y_km$RZWlz6XJ(1aZ0ynMmGvvaNOBsp7AUISG+ z7?GoYGs$Z9a<`y~y+c9+b$x4f8SVVCi?-!Tfm@38oH-CtOmN`UA{K3sf=M3`%1zLs=EBPdHAjIG7DJUhrXiF zowisMI(w=B1&*{yM4{BSxycP6yJpFAzYMPf!h8U+_UfxD5#@5;`BAXlof-oQ^YZ-c z@_J}SQSv;RWWQ5%W_3AAP7c1UhyP7nsy&u-X_+I}E$_bZ=4n!Y!LXtW>Vm9T@WHzF zNRTy6T-WK(n9wPmC&3bZx*uscW$BHxT(2OKTDw8}o4Y|4D(PSWM^tGrBE}M?0Qt$6 zVh2y5Q;19Wp8q`JRg{mpkfXpVKWSMDfQ(CdYhsrEXFT?&jWmaKJo?{xFZQlpbul;j z`8p|_?hM>Rp8aY57)h3+-&d$`^g5g)p0{}Sg8>si1(h2-20OS=?<$VqUTu(d;C4jl z*?FGJmvIqInIv&(jyoV5;-3r_E&d%bXf}B^Z|$RnA5eDjN1K0~2h&JJEb$mOSp%Ga z)jLP9Tl45r>NIu{7O#e3nV(J`L`=)*P;nbimpvdfRMGD&Jk?U=!L_nA+{kOif!4tmdKjgH>KL0B|~ zIs17lNa2|(K-zjkY6D)~8a^&z*oO!v0#yXNGe}Jil?dmzZxJmomhiExVGsd?3BdAA z@lmFF0haqi3rq}(0G~Ga;$aC-5a2CZt@`Kptw36)XE)+Uy{jwFcracjwr_F?wlDbC>O>>~ z!WYb@9PhsL`C!-lT zGyDnME#O9l(wEBzGiQ3~2VQqT68t4G*Y?PL{MGGS0NV$GH-}ujCz!^s_3`FYZzYaC zT$J~??yTCw@Yl{t4wKiIJC;{wX2go+p7cug=sRv@5CjVJ$(4(*U0od9L3$B66l90Q z74JE~ue@m9k>@|S`a(C@`|YcgE5k2YZkppET7Gm>vzcHF=+ z$-Tn|U&k%c>Tp&0MgXyqIVF28Z*h-&rffurGeu-MAUa(PEnoGGo6mz7LY>=LdoiQ$ z5G`Q@hYn=I8R(q@eL|AyGs&nCfWHKq5C1y)7-K;}cSvCcs0izTf{A&c?^kUa5x zLt%JwC#dY;4$RsJFo1f|9Izfx3IbNbSeP1Q;9)&1Np|&Lv-a8K_3A9$TP);%fKq;f zmMy`&RnVv3Ka$8|xsP&wGXT{?56_RMO=K!Oz4_$TVe}wFm7Qjakg8;?bCn36c((3Vx|oD3;0M8jMlOtYX#Z1^ye) z{v8k1y;NQzpR|Bi8J8%MhHz-jaiStswO)0BHxYwIRiXl6f_o?=?~02 zKo8)SzSJ{!;T&&MT!8{OD{w{G6Apj>}_*&SL zS!eFjL&dR~u3>C_nyJBlh2t`A_MEDL1GO|tYL-k&H=e*ao`B{SZ=WNmi5Ci0&&Ah) zxRZsq1#$B$y{sCTUHT8eruYbm7FDb#zYCS!FO%_YkpZchcl=`fOeH=RUi}4m5P>gl zN8YWJR%bx#mpkrGtYy(u`u+)q2`u`w@~S5rNcICS@K!kdXZ%pp(pb=0b{>-J#f)Dr z)mA@pVrBo?!GeJa*wRcF~-;x}3bKk`yM3!wIx@*vc=_9G{JtTDi)zbn#ud z`mI#|&0o)xySmQgkpfYI9@PJS#wsH}JIcx~O{ z0AsM&+1zJ%x^=!FclzA6406xGMUQ$!$VCr#e0_x;GvWX z_7M8wRsa4tf|H7S61S}TbegS=U_)~+n|WPpUnj<;2=olgMMN<0D2ps93Afm1Ie)I> z8+P_s9rjnF00DwSBb=6IvOyunbx_1Q4eAx+KK30&St71_Ss;&yLMS#@%bXc?j;IoT z+EYHCkzWp|tr?@ieNzLrexqa~) zpZw#9XR4cf0eX>OEnSC)lf3ra!6}fcrR6diQnH~>C)81&bX@Q8( z?zhAriw}X%N{&O*Atn_>Xloq}>)rqGBY0~@>$SPhFpx{2dEwQGe`YTiZ>eyTAKfhD z`6wLl=C*eLpJg4kFM3-BDV}JU&vB?kc~~noy9?&6nlH3VU-t4h=}NNJ30*#1$#IyQ z4K=&#$SyC>VW<-{<5pqI}sZLhy>W`f{xeFe4?qVc?d3m%aBvh)0D7KyQvRp zsbcsO0VS=9)L)NmWo{;KhQ3cWt}Yv<7*CI9n^85eSH3QBT0}3JH>x6+TN){oOe5t~ z3V!?P77da`3L&WDUnB-4M{O_s_L%_LHZ3%{L1{JeGH?&8He!7LXnT;?kyu-EzaK&n zdy{Toh{rkCr^;x2ct6+5m!De8m{Y3~CevE!Q(wb~;FBJAi4m``%75w4K(kW`dl|Xx zmyAc*c)a|rr?T~U`Q)tJQ2)2(Z%x-uTauJQ39JGOi`D}wL4;SAgu27L&wQP?!CP(X zrCB$?@o`gg!Er>)AvfjELX?aQ*zxs1vu#(^vpA28&@{cpIgWrw_?mYhuSLrqVVqvQc!QXo4usf8g!wgpmGyu zH*L#2p|)kJQ?zqvfcTDgEtLOs{W~;TAa}0cA9u%;fE$P;8?LPj1SKY4eJWG?HJUPQ zVyiaStiLb%XF(IoDo@7~WqPygiRk_{GLRcrK)NCw=ON;Rk7rq4@h8dNvcPrF3mVrh zZb;-j;ul)>RgA#UZ6Hrf%pz_zZuPOj-~GRKwldf}Oy1!!N?6rs)jJXs=%I?2zl~X6 z7q2CrNKd<=X3fnux!(rTk$hDjgXoDy zcNIRn#&wKosC&P`lvw?D{zonQA7S|)UY?$wm5$-Rne5E}r7{1fqWxc}^MCR3g8w5g zPsMLzY50FL=9&I?W1gP*|EDoe&-8yW=2`xsr2h|Hn&rR#&wuFBj7+TmgDm~uEorTU z@v013_~2*Gpp@bW!kWpSsr>xn5Ta@ic|~3TK+@q00QMsUHag$;?Uf54C-qzgJ~&bH zN3N_>^U2*YmQQO&21^pLQ>CyA#JlI&^7Q9qVf>>z zR{vcCmyW<#x9|1zA{n89RFWS0rq?Cd@%!spyjJp}`LdJK-qCG$V;}vYC%X3&ci4YOWlsk6mE~ll*EL{RCfU8?h}lsZe->< zq{i*3t1_mlNgta%)2BpQ%old*7c!^QLr6?fcThl4_n=z(SJZ{r_it|YH=+PHp7C1irDjgTIthzc?x0_Pa=ybW*>tKd3&bIH^7zE^O4kA-R(uoBL*c;EH_K z#T|yI1vB=rKh1oYI6L4fX=0?@aW=UpudY2bQ;^l}K0(P;kG22DhR^z64dOo=`2PnJ z|Nm;||DzSp#PGjc@&Dnx|Kq3s(C%G5(wV{x9qOUorlP|Fix3cWV6)-upk-j{n1Z|EK%?A3gG)L=gX6d43XD{M&o~ zvGM;O-a8{59Ub$3@1qMHZk|X&Z?xJI0Jvg!Z+U ziVkHwrBJQG42fR~-DH#M_IZascln%-K+h93lP6bSB$M{kcg8^pUik`9HEV#v*b&<@ z=sQETsmtNA)G;`&9XW{swQjJJ4po)I<22SB@gafG_DFld!)P;B2T~k_%*k(osmI~i zpXfG!&+~SVUDJt;KiRGOl{cs%r}z8syLRC_DrIJu?%)7TaL-c?0{s{08m;H42#9RK zdf-0DEZ%6i98(%q`l7K5>n2Y1H0}tbaY!Fq+=eM7O?PfhiNx}rHF2TQAs4y3^3$1? z(_qq~drtY=(>agsPHwLX96Gz@OK5srzHkgWi#Pwz{KJ`V2HaivyS{Bw&X5jIXg7Fq zZ;#Xt@-dnI zEM|j~qUKAO5&KeB^b5|zoB`TM&5Z3}aFe++dw^yi=}fW|5k3%5*!5t1?Yt4Yn=XOM zwBvCH&l-3hd5?p2F$*Nb6@Z%U*TjxVU`XiZh3h*JJ^_vi{+r*DG_ZR%KdZ75pknW} zOD;p45g)Q!0#GJUKhu8#PdyAQrka|FmCPBgX&Yl?yBIQ~?Fi6Cb;9HbRNl9GFh5#9 z5)nS5>zZx+0JbqkytYhKcFNoT2RT=Kg#q^yv@@EP9CF zCMSSlddDXrW4Aq>qYqA0J7|KI+GT!LxLd@hms>MZWXG<+cY-v=0V?j7%LVMVnJIJR zbAat5jV%@~9y!|(*I;*#4t)LZ;&|g8QD`oI9D(jZ64yC+?LeDe-2LvjE<<{^z>lQ% znC;Q;Sz3_nH+4q1O+Rhk?;++5#F&BQ9W__tE#K=QxZV60*01yje1j3qJ7AUwiyiI# zYX56fZv>z68toRX4|Y0yJJwt8z3tKX19!&XCwedsU)~R_oU43}&|Z++2`AO6J;Ij3 zHsB$*s-B3RHbX8uq_?mgh%EhD(fi$dHa9UZIxj$cH^^Z*fnu8RL4#BQX3u{#~V7W_ZvblByK^|M-DG&xW{0339rN-`yVPF zDt$z|TDuZ*2*+XPgDAJS!8pMbFigR5!R-B7!N9?Ah3>gi+kZb#4yQO{Wb736{6+HF z3Ovrt^8$Qul$AcNWih|WIoEM_#>NGawaH^eM=a(HuY zA)WV`@32&W6>l(n3TXj@T193hG=a5)o)W&m$xsU>d58ON@9|KFc7A^#rU+u8!zwEF ze!^^qAH~baV&2>eKLBJ8O$)l@$#?wr3d#nl`U7tb4<$tEoiTC5g1})d9Jmc3qY~yo zN6I>*t~ty_`NhjEBr!v$&8K5a!+#wUm(rs5p{9qF4T4nzSt$ZD%4FI~>-SBV9mdKD zEA*;>x2bGT?1{Ei&Q~T0l;#Z3@(w@Z$Gt&odJAv}4bp}N^?Oh6g&W-79}F@bhLano zU;*q_oXn_c-J|_SpQ%VKm>1M`itfJnE^uLg450&pRSC}wKj)buR$fUS-jBu{XECVQ@)DH|b zEcNm;y^ZDXsiC4h9Sav7=Fl!R8puzwVTh5O^@lEl;fLAs>W;iJm+G->~ts zmrHph8p@IB2q6bTwq03gT8f?jWXhQ$RtqqY)#yWkrV%2;-$XzcLeljgr93I=O=VHr zu+xBG6xf*-Sb}oRdJcyfgU(j<{*K2i?2e#!v&+k1m%3nuHOeBFoyjAe;X*KBU!p=Z z?t~GN0(gpai&~YGM)mfibp-X2`1b3u;xBA7l9ZLQ!leF49@(O@P}V)i})k@XyW zTGxb91$Z2P;`=5Ayt9;{2Okm%+q*f^wgw^PioHQEm=nmYboN>#@;0CR#`c$l&0fiH zsfg{-7h}7Kgwfp1wR*Z3S2CNw>+7$S0f}Ir)Z&-uWumtq7i@#s!kw2k*FmSJOiCVC zIulck$3!w?ZaO>gJjWAVD7N%p{Csv{lzAK>P~acisVF#?6p`RYlIv98U8cdzT!s~z zyAf^5JRKA*ZIkG^a=YL$@ABb;1iws(KjSON7l^=WTWgD+c#}Z5(FY$=p8XV$X(h)m zWAC=8k6)Z1xXV}JWIxHWy+dMl4&`?kTNZIgnz2Xg;SNIz0 z_wdze>8F6ONN{B4&$;(e@N%~diEOo`XzVr_?qXapyyoz`Phb@Mz*>hAWGmg*ZKLC} z+RMK|M3n*g*6%?gE0jp@-X2Pg8M|?!a1sB&M)}hG?18cmsmzzJe9I zMLsUM!CQ3NOqx5I#F8_hIZ-P53J_2PcE@N9lVwyNP{3R#+MYVi8Bm)qzb6G21oNNY zB>pM}d}=2Wovevb@8Ub>y$8!v4Uc;u3@O1I5{Dq!a_=tkfiKduqm5^Vct{NL(B}6obq^) zTH#EQdv;hcsC_0dRTPcE5*yUb<42D03}J%(#6P!&4}WMP4hIQ#hi|88Bs*H2Z}WC3 zuDIK%Yr#~uJ|&;O`f*ykU#bQ?`tVJbX3l>P!}6qvUS!JGm5V%oZF71YZ3pq84VNeA z+yj1z*ASD7qIQZhj|OQcRM+$JiFk5I zO?@OEEKdsOvoga0Y)bq!>6|{sz3GbgS@EF!j+vUiFZ8CyDlo7r+&8YDEzF%Wa+A1A z2eeggIM3n=Z=PUkayZIBMM6pmz~l*-g`= z?e<0b6+XFm)IPC3Ay!{A*|Gi+kj7AsWOtN&&^(EhWE^ZLg*cq96i!)h`g4}Bb~dOE zUV*dUvHg4jX9GN;%RlcE;{i-4Q}d+w2>Lx4GuPukqO~G{+Txmy?h?^--x)bMfv0Na z0CuL^;sozPGtb60PbtiV8A#$;%afB5*bEv)Hit(VCRm#?qMXjml;rtM?u0(&Q| zm^-LAUk9I=a#;H!n}>$$6Ok%wF9DCldXJC$!aE2GY$X*m41fflIkIbBiAEyA7z62& z6{^^t7hz}Czc2blfF@0I(IKWhZMV3)DJL8U?>Ad{b_pkJvQ>j_EMsT$lp1bbsL2e~ zSz~kT1UdCDL%XC(b#0W`3#3q(V{*bY!_5|JZaS^5LY-Hggz-$nnZEXigDvVX?1f|c z#W*DJ#Pjds9|-4Q35wS_=@2QC%=cab^X8)xR-_|M;HQubQ-z-ZWok5FB?d?}m4qjN zmUeG+Z`Jh7n6BvW#NivRSew!}U_@gI3P{{}2*ZGeJB9-RcpHZP+94&OM&qT^&$SOA zfb*?yi;EBBEBHev+w~WX9*e*s7VLS2VLu*RuiyKsVM$nM^wdEKi3&iS0uZjSaBY3F zT@US}Bm>r~VgrMWrcqf{A`79s9|TyEaeJohyoyG>-Ff@#^U2lwCd_IrX+DQYfyJQz zF^q$`d7GnRM5OQ-e&-F(wiD54ceafK6C~4+QiXJ3)F5iUwYAUFtxe8e9-|n$5hyn% zPgdEN`ra}JvYU14{pG4jd+W-NyGgH$+b^z3Y)j6MtjVp5%+F|#{@BfaD<2=VDRtut zL#5NgFTw$YQlsG#W0r9XR~GsN-VH}@=NEfHs=jFcexY9Ebu*Z2z6J}ROsyQ#Y+P|O zv)oltzG>d@xLc5s6p7`XQU6kxX$57*ZW_HD^OSRvc`GPaa}DLXtQDHx4mAE4A?OfI zFn~aE+Fb;G&&-}a>n-RwIp^)JdOFA1UjLd5+%m@A?LCa62inMElQVDc=^675V(bfy zQmTDuWqe*R9k{h>=w>2Ytdc+>@yHo%AepoKj%{QuxXb0=ylXh`gcm@LuMY&~{RkZj zk7cRN4R8NQMUUuqt3zqdsZT|QsUa+7JMX=SfoXNq=f7$%UyoiUTu?~bAlXHHrb2ul zM>uh13R+F(Br%&)!H1gli(|gmPHEA_WGC?cih}K@fW3H|n9!+uGO?qBx=?OHDq(xh zA$3d?_AZD4^cB9PHHRO_fk+`9t_q@mIQUO1|`iGN*?QsC&j(FxE z-Pomyb^(|`no}K|dJ$Hvtod`jpCaNhW1&bY8pXW>+x9-%7C?9NFXh6|*~(}&UR9GM zjC$5#Q055`p&ISCKW#{(w_Isr+S(;KQ&+zENlGi!jv5|=IxM%iB{`?gL5|F3-}E~A zo!M^ot*w)0e`sm4?^xmb3fj|ap1I_CX3wiy~|wt*m}=6 z*l@CuwOFX+l$BPp;C|T;ZFt~r8uC1yHn)>-exJ=_7CVA*gBc$))x;wi_R)2QSoyO{ zc&Tnege#$q!7yzOJ20a`6ohB;$wp=Zmh%3-w(SVmcby6hHQ$5Tpg2G#^0RBwQh}fD z$3MXivcYH2M)@T)Jw~kna2go`$lAZ6G+I+W=TG67z&9P1h>p>J7)*u2&$eJ{pNL)o_cC=cw@CIm88gUAad=K7RJk ztfGn)eB03Zj+wmvR+t3cRx2@GFNNoGM8Mc(?P#?tg>4t8y@zEwGO|uADi&YDD3t=U zfiiXdNNS;l&;&U@wQ(PP1fblbccLApX$te$!k&+I7&&X4_9=9Kf#e|s!`)6i27`B+ zpC9AelHI7pvL%XuHWfe{92V5RjW4>^O>^%y5Wyb1_69FA28;R@GgMvg3I6A$K$eQf z``hpeDH~tR%Q40gM)6v;%hco2drAW4VBrvQGR$5;aOK*1HsXQ7t--ztijIg2>S&@w z`zYFIy5s@X>XK0CTpGH%Kxi9*hQCcwDkH2UB#Nv?TSiM2;3A!~;fJb*#j<7Meb3ku zc<4<>s#bp9dKsVw#z3tD&q|l$^{YyA1>9qur z4AJkf?MwF?qYu?RKisK3HP@-<`elU}W5%5+s1}EO@H1gqNRLVKJFxb-E`LW7gLdb} zpn$ws+=ev&I&nE+Iy+xIdTYO4!;?nC0Wy#k>4=bg4l+dhw0u_bG;{>pR%v4#_EqGp zNbt-QT4y#kS+)&jwN*Z3n)>L_wCK>%=uG1Uz0n)Xx32~m-w1bDtAgf26ZW)pyE@X& z2hX&O-cDP)HsCZKS+jbuDg!kbC{w$5`iZ{@g_j7Rfe!`8d7D9SChEJ zg%EuS;f#wSfs;b162D*v*(LJ7Leu%M5k3OGC^ysNBkJ-GWjbd}pJ|K#xZ%Bq!7|8> z35Aj)&;~4kA-}Zn{Fhz9Rd$_1*R+fE(Dt)7l3f>RNuEooCsWmSLy?gT*iI(o?f-yKB-9NZZyU3Sl(6MEKg;tn0uRvhYJ-N>fb*U0Ai+-p)ItM*LD{Q}#6gM}D#N6njQXhozrdFlzl~=D8KoDx&V~_!A9D z?KcK66v$r_fd$>hDx7YYJKC0LA)@k==90`>!t2vL#k6YG5UJ0vB3Fk#lv6|yYjV<$ zSq}WI{lzi-sNHjA`G{XDb=Nwd3Ilc*Lo)_-hf4Jq%yPkc`;5k%hCobpvOx&|sw{A} zyCg`11&O=1U-hqSh~XboxTxJSZ6zW~Se^0#Z5>VAe(Or1T5rg0vu2(bJ(np&fxZ-T z$(ef40VDOO_;e4;i=dq2umkAl&T2Ur7MB9nep?&imk1L!-{_>l#fV_{I(+`ekz<=lADs7+=1_s2=PSSR9gOeWX;5$?6e+3{l^{&-cEl#JrjK#sJjX6;v> zfep#mEBsf2b3gWewfaK!_e7|Nc*kDp>Aeq!)su(CMDup*Q943lp~Jn$wNBf?O5WhM zthm>2O2G8LEP3xvq|miQ=+L42X0#G<0m4M+Cuk;SP4xX}S7))m=@AA^_71zKhN{IY^-Neled4D(UszGQUl5v=SsN(i zKK1(=BDe!0V`+WW(_h9KwDb{a<985Z3-I`oe@O=JO~;t$;DU&tq_(E3^?7qOtM&x_ z$%!BzG-qkl?v!ei+RAGxGf^@St(5Cspcf~q3^%OkGwmTRFHchqsz+9X74sK}{{`=e zPrwR}VA!(Af)65g=LjJ~`kR66p2C7?uLx(!IknumZnD@^1j) zU49_K(O(WQ{@$tWSa3Tznaw|aA=`$1p~r_?D@T=To^p!CUxOcJT4RFUDgmW3X0Z40 zhxTboEs%|mPpu@C8+ugmkN3pK4bGW1c>5+6+DxVAO>2DF{xi4E7C**cy5qc@CG)<4 z?p|;pddLG63>r4i*QZC(gKZ}(Z#!LceqH*>ee0}G*mb%%d>-tqlhGo@YS<*jLwlVh z={Wl_1Uq&SNE;3F%tHEqKagey5&Eyf;Jyp3*MNmt2U%l?I% z1^>6ap*%!4osjOBk606@c0m)U)%i@^8cbU#H|=Hq63j9YC|N>tq2V~d##klyFnDm) z#4k2LB|A2W{6g`CeYUHibPbo~cFavrgh)bkje)&2YfNlw6k@}(Wh(jIQ|DSQMKa7& z-T8dMwofihdlshYsv?0aZOdM{#DuK(w!_rJ0%Eh>daA`_1eB@1Jt7obp;Y3Kv=l&h zVyOCkN=kL}+o1@Qka2U)+n1Y2c(Yu6Rf}#S!*dK??@Vr)0M+6&4#{ODv;6j6seo0= zKdE4MNr@?P{p(uV=0Ttm<(bY|7&|5jW%gd#~P?KbNSySBl$(K4y`_qsd#iH9nQ=|u(ZtMm!e@BQ&4Q9yhHjRJBco(nc zj`JYzYn^TxK@xHlB03@*fC)=YFcSoRw6q&E> zHojVM!T)-7UT=A>1hn2_->jb*nV_gG8R&F|wkVmZtRJTFDO^Ih{O{iH-}7`)Q%}~G znhsB&4l38)_DZL+A(Jg7MxU9h8Q7D%HahB0Qyb{>)~oR^Z~NOMx0Tr;%#53LcM!w- zhO1?z%@tahYu`r`o%19-YfLX|S(RZvS$=+LaUbHUkW1PqZ@S-#^rR6xlI}oqCa&~B z{3Qd7$Y|Df%7p3}jUZf<9X(tI>?2GWTa4Hu#r0olMojB<6>4gle^YI!pabi`(udfF zIELL!AROwg>o%=DQawgKY<0oB(=Teg4VwtT?#y5(hZTx_Y`lr{bE#jG(n0jLY~ac= zc}B+7C+wNRgJ_4kEL|vx^uomWMlmzl$qEB|ef8E@42D!!LxF(hgaHkLh7jFq`2Hju zBq!gPL4ge9L`BnVe+(gqZF{XIzswW1+ikOaMMk)HYrhS3a(pwJZKXZRd?v+S@o2tK zb?wIJ?A3Zmcdi?~bIFi+x4b6}uw-Z#a@NBB+C_- z=%YZR)RUjm$6t`#0Ddw~_I6;7mimaQ28}H~RUXY6)3wFHGP4cnvbeF$0ZK*zDsNI< zEe!$~|MC*%NGYT=tvU8+Ogt-bO*i+?VVLxJ8)me*vXinf!|wFNdG_mg0MuJ-gH zOhuK>$``&ki2{P%F3j%$X+le0>Ia#?SRIxGh246+-^w$&ti8JdL|`v8(fdw^ju%}! zIi!SvEWE%nJfXICm0s31=ux(_Od?=JpgrarqSE@-+|3x3M=h_W+$4myF!LNUcXv75!z22t@2$>?o7%%fB%Zne7ffqGOv!)(=TqmAJ`rl3+xql2J#Z?wTCu$=Jv!R_TL}4|=;1TQlff z-3h8ggG+p0tUjE7IN3v)TYU4oA9f?vc>v{+!B>d${nKaCJ>KC=NsIb+^Wp7F>4i2K<1e?(DWkhqujYzv{I`y ztI4kbY-;?49S`2p&Th^rt7mpWF;$~ia|<=5>B$BFlJ!P@iKE3zgEyW%ZJ4UD01Jao z!qeLZUy**U$gG3S8-n&6X%?iH${87;AV(bJ0vHe^5Aaf+hA0k6Q4a~QYtmyX_4_(K z&lZ3pAE(J=EWuZE=(v>b$_qkQ%z$DLCW%1hAD#!E8{#Z461azIl>=n+lZAjgDbIXn zcU?Z`=q*e6bblJ=UG8kboIhV_H0#mS?sssckbKQ~KU_EO;4ybTUwK@Ae{H(>+AsrL z<^V#s-H>lm+va6m%&0eX+v%)M+aF&N$Xxc3=a*Wx2IDS7dq}&*<8TwPO~9s5;rYJU zr6DD#F&(=*ibvxF0~l}zMZtJ>K9%C$eiv-elP{sn16%tFIKU z5>j2DdEjvyyvx%AhSE~rLfcG)eKp=-T^ZMoMZ?wnj9w>qUv7xosT3;BzR)FwrnV`0 zrJPgGl2gR%%d*Nvs0r2MY9M9c5-Q8p1gGovcu7hZ)i*AMHc}qGsIzdk9^Ai?nll!* z+Fs=fP2bjnIX~;rRv0S16V!bLyLnx?Revgtg#gFvIFRx^shTmW`>5l0keQP+JTgEW zM&I?g(hH*>qG6|s6+z4&mPWtvT0DjHi9Ahr>a2A;e(Zd;KaW=^td3f$I6H5s9G2a| z+)|Bf#ao?-+e>L_b&9r{fuGu7?4V(xRYx*RGJ27DAHIR)Fj%aNrbXrIe*)(Bh9jBy zGPsM=g{xD^NpV;YrYkisX<$}*GUrDqB7`QPk1xR*td2z*Q5Yzhe$ok{Dl-&9Sq!N* z$yYidOZZVY9d=o>8nc>-V!TLl)2)!@pc!&bBenajj)EGK&U@-hnaE&99_Xlz=!z<3 z8UJKQZ&og%7j%k*>pv_Nq^Xb6vW^XIad53Ue&{dfQKvud*EnxRxwe4oY%x4#;ILMI z8h9IK(Q!4$JYtTz5SZwO#%p@sdcBN8yv8oVI9KjjC1V!=h+z%&WDGfTOo@x#R1)qV zcQ2ikLuuaE9KDjS-8A|oWD|5NR9ICqES1(b%sMscI%#D9D1^& zDJNhbB8OkkF%CH{Gjq!y_qXtm{6&`k0mZ;Q=Hacu!oG>Uj zpa=+8gIN6*Csy}{U{uuC$K*@N$`V!Hp~{v!x@#gB4x#zV$X-J~0Va9#pRsRDb; zoa-**%c5UDk5@Yf%p~L<39TR=vS@?#c_T_r;@nad_*ME%C#!7doLk*l?a|=X(7vU8 z?H$P3$7SiR?y*)ZPEt)DGI4YSF0lYoBs^b#=Kbnhr=z5G=Kg3C$Z#y#G|^lE3KsWT zJ>HJLMt0U~&9}~{ncK!c_z8fc(c!u4V|f1-D9bViWAjFBXyKU zl_H{%y#`&T9vp9^b4}8odr~pY6n79+rIGYJBt@F&tMevf-T9NvquJ$gAZnVY(|Ib( zHS7J*fE9{@M!(MZ8S$%i`THs$X1fKX&@l}SI8*2*gYnrl+RP1uX!Kx`dp5+6JmRkS zb^cCgLnk;eCh#7AFPR@5P$O?WpXki_ePWhM+43;$ z;f{86@Fhx&25hi3>F|kct1@tu))-h-4I!Qh(X6)UOyQ63x#J?@CJ-}7duI2(y|*(P zkJN+O>EVZ@-s|d(fCa(efcMbAm!wldj`nnrs2Nds451{MpKQLtuNiVK(uh*ND0C`y zl3#-Nab`v(6S2vC0->tVm4Msj9?KZ4EoXQZf!r*vW(;0eO`U5Q(R! z)ZTcXCa*caKDtH2}+1e_6UfF(aZjMx~owT%rp&ss97a1 zvVCVET?>Aw!8)*hJ+}IwX=mQfsUfCr@N9zeiP-i`e0t=|wSqErjmnfB%?}U-Ivvw@ zi(fS~GJC(yAj6Yw8!e6yMaBAucmBuWM^m;_&WB62{!KJHj58BeBbplJFR)CD5?99IY>e7Z;)QSs+9rkmPfi z7$!0?&x{#Iq}OMTb+VWk*_hkGKZK7N zxyZVi2oCY$M!Bw&9q(?u_%@cMo_}|<3KPLRE8Vl_I@H^vL66qfb2icEf+U7&ZfQvD^V78`L#Zjmbk+UeprY~X#-$!)9i# z$y=}@d%yt~?}ImShdSIcZE9}W@38D94YX{ALG=BF;@RRVIYPMFqXB+#p-H?irkz|b|S zSJ(6h+y0vl+uo&s__7&Y%p5wX+a~C zN3&J^yR{a(V|=&CXo>f5v>lv{b*culZpS5^5$~r{2F;W&T_vc6DV*t&b*4sl*tFfj zLwt4e`(gBWT6VpBmx6Z2d&Or^9t&&2#gp5{W-yZ11>(REUOb>Z0{};Gw6Qd3sG;u$bgU3XfMxGkn7p>4lB>?2qk|}| zde4Q_v0D^6ok5LD?A@%3%}cH$WU4L8YtL&jnw-ndafyy>LG#9X%gbuy|Ozp5ci+^0i# zr}pBCz-;Xa(}@Ii`S80sNCKOmb=NSn^&OP8*G5hWTPXIE+5*=2nQc6>ZXNKbbL}$> zkPJd%(77f6H&o>qWdDn>cL1{V=N5k3)6>SZZQHhO+jdXewr$(CZQHh{job4-c)xS* z``uf$la>7>YbB{lvTNr_*6*QKBk&$#{7gb!Lexpj;3rw`pX}C=_&U^-6{tet)CePh zOWu&hrWxq~d#Z_}#+oZNeo8Gq&kMNn1U-80%$5!9T-6e^_^e_2%9BN_Owto{ zf$ySIEYGzwpvZhbEQ2QDdB#Fh6iaz;_uo0y;P*Rlj4ad^FmsLcluAJrU;=NMES7Sl zk>Mg^7o7&y?)6=@#9Y;)!@flI`jd}FRiz8vst=pem8mJBx7-hM;XU1ux47IEEf6cE z&hl0%j$1SbKO3ugXssV(m4>+oRX~oYGq$e7LP*rg$QGe zRO}_*Dl!=D)}K+#Fm(m=nQ_3l8*_2Hq`MUs+e}qV1sJ>77k=Td<^nOrDeX~?wvk)# znM#PB9bO%FuX#3hE4K+}9%LP46HF?ZSln+od{pMbVrIK@KY7A&Ub13wB8dlS!eiI$ zQ69US0Y8^FhOQ+Kb(;_|<}XgP0#U+ULilhqyE{Zvs46%XYMUuO!`;6LxV8Pdg{tfV z8;ReNE*#`IzgDbF=Z8K8pFaq%?Mz5m%L8xJ?*O&=KIBJvRBy+G?aL;)pE^-BIFZu( z9Y;XX&A+7t1*BLAz#4Ut8Y6?DrZ0@%8pBrH>`2J@Mu?R+W^;Iw`GUc~fNwA(FNzI= z?2s<#PNx)87yB=j4Bk~}7MJt{6}xXTSnS`jNl0%o-d0sDnIu!Y@3szxKN1>4R$HO7 z**o0z79*foCbK8uQ+1v-Y7TuWQ(!cglAosyU{k5(hszGAxjqT6FQG_sRB7Lk_# zNa;RIJ{*N?lF{|pzqZTjKhq53gFGwK}OIx{@F8DKpm zFscwDku}HEzSppNd7VN9Q@^R#l%hT|-rzQ7@=B9}*8Ai+Q1l^7Sm*&)c_ILOAz5)AH&a`(>^h&}FA-YHOv97hyLwnr+!+?A9SBZhHUrEv9J}hPu9H@|M-#?l*eN z(%a=-Hd-e9#{!QOn$hjftu5N1^MY|AWRyU^j(!FY$a>iZxY83919TF7<^;*Zr!Goz z#Cn3O;1gVxYS576PzkkwK3NLC<%d^bIfW>1idSgt**H%v%d?xEOA=X`#p%MwtT9Sy z{)8Zqkv!aj4?#>%Ozar4T`lw(@zbhGR1mH%JN0$%pug@BvShVaS(l>tygdjf8EK!U z)NcBHJf5;hdGV?p_Lftk&(jONchZk;%50ImpNG`=6xw*JE#oieWH*! zYH>d3c!QLlHK-aA^R=IfoZSiG2zT2~BKQp3MEQaX(&7WosR%Ep%i;t52_Xc9f_}gp z(~74Rf_t|*HFt48KIUIz^Vla0CGo{7)@UAV!+=x5 zi=A^mDLoke$$A?bQ#iNYR5;HtErVe^bM&{!q_RYmhIj{8%|L3g)B|LV6Z0JoG0#$T zOVti#VyG(=;6|<3xVbe8spc z>BvI>bGXyg(~@C-9{rN2I&{ajS=a*!J z2hvx-{E~{cgdquk@}_rN)ls}hDmp2Z=yI)Djy9ZF^TG#wH@+loO7ZatRA-+6nDxMu17XCJr6@(l63tr!zGF@ouC@8b5~8`f(ZczIb%kcX-`V9g4F#rA{@jG z63kA23AumR@DT5vwL#F~E6Aw&8yvrAUIcvAr|1?Fp=^M{MI1$0jcUI**KEUFQ>Y^- zv;O;q8f}P)YWq`1aVHmy#489cN^fLfF|FW5;Ujp~%uTS2`qy0+EpevOu;Uig6BCXA z#3wUW@NY;2c|!Pbtigy@$BTeHm*X^H<+*43Rv)>jM)};&tWkBcc1vISP-<|~JkOe; z(?)*(etTNYpgXS$)x05jN3@V)&|Kgxm6#Qm_Hjz!Z^gaDSr7A3KTco;EwPRj-jd2&F`r1%cJm^Qtdol{U*uQ@VfFXXF(|VuQ9#*Ik^s!yUKH;#uTbx?*W2iKb*&ug*yvV~1Zz%n(S4k53F@NkxBE*bf|? zU6!4R_kDsY&WJLsuEzn>MLccQun#$0j6t6eF+Ns-NvHuXJP(Uc#4t}N_JUXRDC9Kc zXL=s_v87NAFGML3gw{zxcQLA5oE9ZP%$ zJZ+MHB?WA;$u!+BAh1T7Mh7dCGxi&iWJ`TT^gt&whUPi_Ra~qs-6fdfq#F8^#xnBK zGG->Eiq(tJGRC=EW@Du?wkvU%Pe*r~7I}kuw2VYn5>2vm-!Ukxg}MP&D!6J;dQv9^ zzY+k_zC%4o?R1wD8W|_(UqVkGWOgiFANPoz2-`6p8PBe|&E?`WgbR;6JLMLLPNxt* z)aNgI6kzaCPN-$=E6SpcnDac?ma{nw_tX?YhlO5{?J@J3pc zhNzEb+f=WVj9XPw7uiOzoM29&N}{oc>2oN7De9prHe!7f6CVny?tiG>xVMB$apje& zEUTfY?W|py+Y@PZgtLAghgE&$j_|!I#rl^k!~%;YIc1iPlT18swt8A z7v^X6Ql>%6)t9{1iq#n+F#l3YG22Vv*1buz6)8WFKs7|yt{06Cr1 zyjnvLM6o%onS7d?$9Xzpy}g^E%7ZEO<$aItXZq9j*Gp0Gg#Yy}iPnmj%L=19x)Ca}0j_el%?Rz}Pfn$RVh+nxFDo8lZmoY>!$KH6(tA7AWOrtJ zfA4a7e*-bQxmQr%W#31fh2MogmhzEeFqy6@2oKM6>3K6njpJn&r#ZbHJomZwyG1Ee zSlB$iH_0j4fjZz*H;?26Eu<+`>ray0B=Q4c>wqqC9Y`rFjt1uB9Q5^=NRU<7g;PaA zPpGKH;gTdB6R@-={gA^eztkM!#u45tnAdyE>!B-F#&;wpwWlGpwG%&d&ZO2(H9){jzke$!~(De5!Fy1@=>)#|zL zEty=u7t%DJpUiG|zU&U$7#{^dfqmA+f4K2Y1a+<$5rQ@Wxyxww{z-5f{vyq4e&GWQ(!A|R+fo%J;x7Px}1jFI5|#3=E$P)Cuz@VGJ&;eoAMRj5S{PV=cAbdmUC)~DTFh~dD^o}KB9zig zp^qlT`SSHJ+i^oXco4lPe|uf#7#|*){lry>JU~`GN&WX}lKL@9!BVWE>G!~=ZG3!| z&kf>_S4Ku?0&fR}0mIB~pK)FYc-B`QbwtP%@}mNY)PN%?*izud8IKF_%_liO3;xo&?F!Zzsi%W1;YLbs( zcvnBLiHj=u0v4#^g?t0OXb56ktAfQt$MtrrsicwU+*SsGl$|e>yV)*u3ZSll_y=5? zai=|N_%{*y+6@=SiJQnCSj)7aHO`a)BkFvn=uXWI7vDx2+!heKOVr8@Cc}VP11Xo; z>eMXyMWj}=vp<8?*Q?5&J9@u>e@pxZi7gU=dO3#C6rp=7WvYsg_10n}LaY}vY6K63 zgdqFf7B8CCxfd44nwxeMVYFB1Z6CD=DWQso;@E!Xug?n$ZV2lP6s7ApEN+)tc7* z0s}!oN&gJhUg*w*5z0s^k`;z9?kkRI&kUG13dMHji0LDdQ$iBf0c5cfqbmSEKqXFA zDXhMgoye6{lTti;)3q{uTDbNYk2;STH+{H8kx<3wqfIO*VylA+k*sK?l^YPlV^WKC zW)UI-T2qzg%o;%05Y=K`Q>W26Y-;Uec(=3J(RArcO_v8lwH)3Kn7C{;)^;JfN49!9 z=qKBjJnlSLWK&JLH`*O#yX)4ugqnVE2|d!l4ur%E`znrTM5fni5KB@&Ma;LJtT<3rxUyj`kTj1h~&WtnhVU zf4~|p76EEy%FH9(zsXDd-s|&hVZU8>S0V9o19%e0boDV!HVvyPZ8-DS7{R26C9M#B zqQ-?}rH6tg01<(^{RydxYSD{TN_Mq|rpQ?VJy8udaaQ*l12nVz_O-5=z?xYcedh@K z^R#nZz%4nBUcyu(Bu7?I?iDU$olF^-rg)!~hi>jB_68n3WGLVJeE+2e**>s;)?T5s zwfh_YsN=$W<6O`J6MGBpKCKa*VNZCzAwz%k+_-`cA;0$z1X{pr9^OIXQCBA`QToxa z+peq!U&a9Jt{!Q0hkcHVY}FvZ2x0RXa^;bDg2lS^=w%VrOo%i1wV>CXi-Xg2pC+re zF#KH$b?}&7>+injNwe1FC20jcC#&N%v$IZUq~^xOS(M~PGpj|X;&sc^IxX}0qAi&v zISwtku|j)vBreNCBSMzA{`nUL4>Qu{JVnF#a{K$869^2526j>=` ztL=!=KK?_bUL^IDQCQ%wiW<{zCviUubr=&6Ld1n}$*~k7khn7!WI8M4PHW;5*hwly z&l6}%Eij4}7nx}JMzt>zA*_ad-FnoBOVNHW*chWJQs{gQH4Fs8e#JZ+^OoPUt1pD6DLWpNM| zLUz$+N+p`rl?6-^Tm%@B8XiZK9m!$WMcHLtJ1Vf!3{k|cE-YP z%4iRc(d$Te#>^B@gwZ0$^iKClIBg}S7Ti`VY{itJ*h)pNeA;9T$dg#X%!nSct35vK zEiRXU@_BRLP&oFn7E|0d_G3d`hyqkKQOEeqgY(0jl0DM~_!;J?KbQr)lu7qM{zZqu zW|y!(_dqQmj;F9_j%H%OjsUlWKr^L2n9aP@q2R%je)k?_4aap);XOJS>;Oc(v^7vi z>VW|9cFCV*%Z?*)<=!U^76K=SwCS9?yZ@T-kL$DgXq1(vH8sTg24R?AMV&Zo?Ewbz zCLaR|Oc*^_G;SKCv3STgAz-zaG)DRKds z{YL^!#G)Z6SP~}MDeOGnNJ6b9-)tvM)@i#)nm9Z*eP7PETIe<$fQf%^dpwHEf8bm5 zG}_Mcd0dj<>X+|&ckl{cAUCI zKuhQT{l6w@GLbzrK z4_U^eb&4Q9YGHOOKZ@|(i?z-Yo%x5`$Jjk(*WPB4#F`b=8?==*suN@;GrSpC&$w+0 zkutn7paFaYst;LrvZ1|Ah~aeBM**DLHy**46AuRQ;UDXMASXib@G)a~*$i^vK#k*Y zFuGnv*0MxgBVga5ybrWh_T#va&q}c}?o}Q}du1R^Vs(LF=3QB^JTaoLCEFGvjsKWZ zmuWmu-1(RegpEaendNYcoc6;?>)-wT_Q6?w3zNToa{RjuHYGZRt$BT)B$slNy^p)E z@{JfA@!)n%_1y4H@X2tRb=&3Z@+vsw2--e_$}}Of7Ov4AAn~+0&@0=OKKjJ|$QVSezO{_&$`e9H*zb)rfRGN_9<#m-vj zj3~hfaC_q;cp!U(!v)*xB65Jin>%%- z>x+u>mL=4iBx;xbVmmnUiMT6(nhWAxjDpp$!#sL2MQ%J!#Hp4g$`cwEFb1TI*f56o zRCJ){Bm1$7i#rToqou6Py{-88W5hk~w1YSr5P=^zl`sZ|821Q&WSkHIm(U-CAAuh6 z8P9{gs=SKkWCsppcN-_Ejh8xs#Kc*b#@)W<1E? z$K^-YSJ$?&eVMdMrdwv!6}ytt86ydrD}O}ZfJ0a>E@1(Ho+1QX10wJY-=bqt({@=( z4UqmJghDl$K7wSN+-ws8rR)mN((wz<#l5}L{j+sbuX|8KL(Ds~KSNy`T2-xz{1Mr;Sp_llV6;u6tSTTbkuBE<*vB4wav@nFmf9H*sW0 zquH5RCsS;bweR*BH?d8;5U*O%k5ZfapdTf~0N$-|6%0762yoKLw{L@W$Zpcri83v+ zE0L&Oab6Hkp=P=E1UbkG1WD$jHuHj$GEFl$+)vsyt+6}Q41jguHNMd&P?gJn^mOQv z-xn0q$C505E(V(|WUa0~D88u$`NBCmTgoWp0mT3y#3*eqEG)}m(LA&s>x%&LB+;EHN{Y zrlmXhx4ZFA9+JUi>!PbY^_h7`Er0cP#a6X-%uz{=I~$k)%0o-j^Gd%FK*=sKrW8?(~hI3LuWH1zvznQqE8f3Ok?=gr{hpVO|$ zQ}5get)2AKUquwb8|*G2G{$kBM|by(!#Gg5s~H(zh2~=mVA#^igVkKI@ zjfY@f|9xp-d6^E(d_8#QiDy?Dk9c=bVOp~tysxdFZ+wVtNCPjfh&ot^IcncMeDD1t zVFSjsvP&HGEmOtM4}7h5e|w9Q7s>?XIPNFP_rjv}MzUmMt#u}(Z%;)FwC*V5@OmME(_$u*NZsN6ZvvbToBwW=n1q zqoVPG*sGA3FotCI`;@;3+!r=3GA_`oFDgez<;?5q>u2gJtX;T)cRR=Uh<(d zd5e^o4pm2ri%q~so5IZ^jxY>QD9%(TH7}hTW`?ZMdaE^Y%LJle5ym>%q0MmAYl*rR zylS68tpq(EFSB2%{rs`!cmC^WOUv0~?{w7il<9DzHFla2#j}}4c!W9Y2E-wc*HmX9 zB)E&TB;`?v?>szclUAaXF2_*}z9#2sFj^y*WXb0NAoCW%6Mnz+A-lSZHnAUNZ=?KR zD7J}DGu#49M0r--(Jp)Uw2z{vyyomJ^VwJQF-%10t}x&_5j$B_^fea5k5?97urDrD zV9q+WEWt$YiW85vv!XY|mPxcC0Rk>>$!=~U+H!8mRrgK+Y4@A{v7b0POCej^_2(vd zxw^O<(OOP{a{I1h+54MAufX307P~lbELw`Y-R%LD8|B{;M25`lDt;y%TP5}bOk)) zIB+J#U?JnljJ4t-*e(SY$UR+Q{fVR78G1nO$#(M_= z@#g3?sX>o`kp5ka&VH$6`>Qb6gP37z;jDGjWvTaUc}cPpxpfw+y?TaVVt^Qy^l?L$w%JryKz0(+9;?d&kTC6Ld?=IW3F+TI2_mz*6!{e2~JB z%!`awHfuNi`{W5-?Mq8)tF!-OD11?K??%9L8lHw#2O=Ax+!%`0i?UnE2)RA7{&?-6UAutu2xl;DC)Qddnt@Zfm*8$W z!sG=Rl=sd2QrHfUfRlqCFH{~Ws*#$XHpMy?Ow2LH56}Ze{ady(@>OG{D0V>?eO|vu z$UF@=L5huIkMKpST2-Rp$)jW<7DAD}k}hIV_PqFH-kv6P)jt`?^{H#rg%BCi7>&4O z?cGfpw4MO?$WsXY-LghTSrP6B7&~;4v4drHS-?-M*0wW3dxK@8)H_I$_vwf}EpcIE!Sui^xGGAEZ81i#}P$o^zvKk?b^MII5c8i6ruosgg7C()4XSOFf7%~=wuTZ|% z7bf8}`Mc8gmij^f{XcpkbAhi8mw?d{iiyyxJm???ko(C z@-@8s`f&xBNAAlD4wpA3Pg0x1xKZwTD-BJ-U{s}RvN+@g6y`cpZC?6fT+Au)d}k4f zs0fO8iYJcnc`7-m!G&amAKVBy*RhUVDO$3}}658kMxN z0EDh262;m*I}QE%!k|$WXXQinx0@TacH$FLdziPWaW^<81P$8!A16`gA}0uMbfNx^ zw=VCHrhVqjG#V3KVHZ51vUTMBym|u#Fb1xU_`)W7G(eM16_pl`h-GV3GtnKit|Bge zSS`E|H38IS(PccU4R|*jD^m`AA=zcC&r^m5yNDe{@m$O^o{~tp7L1j_C{J_@)*wPH znT9MACX%F}N;rbd_RC&|14HR?`Uh2jFdV(>HvTA^QpP=s1XxMgVxEEuKUg_7$}(+$ zN(T~a@?f4?^fRW^4???cqDc5XWhyMP7iYG%Xv;IdnrEW0a%T`Z`s&x#O#peR()Kh0 zrvnimEYe&W-L~zwopHn@Dn;>$VXq6z&#kLDmSrg=C2!x#0@D)6x4Xf=;^>E$$tkC- z?*4$Mx1I-Zv~mQ#%?ND7o3cE)KfE18&xnxW6c)LI@Q@>yfp#giko@u5zV`I+vahY? zWZOxPXCI#5u^O>@po&ey43Agmq)L_OP@zycc7!O8``*WVYjSIP-IDekPBs=F6ua?& zHLMxdtegP9DZN_I&lTVKnXEYy8rZd92#8k4rqafH0*Y`~S7(VCdsioD&^A4&{97}W zNmOO8)t(53xfQ`8=9k?4X{4hT-(2FJC>`0up0C5DuAcm8 z&fD~4;jDGULFnq4!ttx!=-*ZAou~C*p5_Oh8Mjksh07o~W`DNPS3D-+J02<(S`1EJ zVzav&y$?Fu#nruofPq!JejiN2<6^&9@j0P8=JN-%AkI8hxm zQ-Jkse9FA<`i_+8_huV=zyel~En%Y{Yo5VlAwy1bGsZmUo(gG+uk`)mvo0h0CsZlO zycFjg@iSjp(mJK+TN_L~+`Dq>K#dg+)VG5>xZG`Gl+szrrics!*NL!LrN*in;fmu5 zptnag?8v&HSP!ltT;^#3E>f6jj`md2Nn={H{D-ErokXiA*GmfwpJ@pWU+8Kf!FUidG4b+tRXPA{ z*!+nHFd_}<-1|kNE0&@;=`7sS^g0KE-!-Ey3N(ik3OH`GilrkR!&EkZe=c}76!^tT zcSI*DmKWVTJg&0siL98xfk=7{I=nncID8e-&!TY|c%(@8bhjzOv$~TrrN%}+MFvP` z_Wh1@+%h3;ky*z5g*>AMi!E2*k`d-(SV10Bj9xTae^}nC(Za%J=kF25LF54D_Owbj z#J?;3>8ywHMIsjC%9+SBI`0(5V4LiSqz-e{o5Qw)S#2cYNge}hO#d~K!;l)(T`n!- zPk(=3EHTv3a7ug0FeWU9%$lVFf<`Fp<}3maZJpvYN<7~E3$jbcu@))x7>IR&N!7~chQ#bFY&*1Kl(da$X=W_>IAxeB3n6I-w z;Dddh$eRbmxrg|)rowa*)oOL?@|W-gyjmKG>*t&t*4sogHyA%NNIXNs2T=)gg$pYHU-<@Kf1wiwT4lEDM4IhRQ-~GE&yoxH{hNb zFC~45Vy4OKAU7xORsy#MX>zjxv|(*2dMJI;bJ*^o+gF@0o?&^hslm$&8GWwj#`A0; z3%Y;at@8UG0ehj(6alZ0a(R(;`7gSon1g-UtCQSZAM@}Q#w_c7qAdj52vIT8gtX(l zbNDtzEy>*FVdt=cJ9%lUBH%EC%&>>~Z^L{}=R{bF|8Ttw@NfgP$$g1snWcAwb~^W~ zY2|$*^Z`7fF#Qn2{e*v}u~(1;cw{z&hc6D^{Phkg%f$Sd$NDJ;|L_)wH9bb zjrSOu9GbtAIs7ORcPJ&Ar#H;BwyNVcby)4H>popMk7!Zf@VrWn*H9Q(XrBLMy7YJ* zjc~|%qSs)+8Rbki8ZCRGR`gp%`sRRaPu?DQ#5Ggf;BKdMvw6#WVszaBDc0oe6#0=r zW>b3Pm*lhV3?q^gzYh--6L->`j>okUX-Evtt_Q1WlBnXa>t#a-Wu80NIy;2HM+zun!XIr!~x`h+lBR3d>mUsL5-bD>n?y>)jX?Zdz9(IZTv5ZaHs9U=HV% zyN}$V`b;x|_6@8xu8rDF5OB7m?uVxANZiGTyf$nZxRHWlk;e{eK4ra;eYe5-fgRS* z4#Sxs`8Q&B!gL`Gbo`DsbN71$PWisG#kbE`Z)Q%G?RIkQc>0ahW$x{R(oHufEYPft zchk|Vjh-u^n&;b6uZ>zDZHr&*g4)q0ar@&{xr5QNCi-*?T+k)nnEM$}CrzNH4H=Ko zt_oX(bX~9un^{q{Cv0i@N#?RlQ$_7U7j=f!)RF)OC)Hhm`_(ikRdS2<>J)>-XAJ>B zsrbv~;NDwt?VNxEW{DTZ`KkTOxqC|2!FDqv^brOYa;cxmOaTM5AW!>A2deybe)zfp zw_x$A{cs^ExYV~>&hzS7!@X!XQi{x1>=MubmBF55C`hi(DUER;O9NBIJ6H%^!)yAn z=RQL|QfsQI&68jsp-w{!+GqK8#JtPY+}^uBF-;hnbk<`^zq>n7X^ zPulJ)0g?8@Nqw+|*MNln^G{A9r8b{RUCJUHe=8b4BCaJjMQQY)V_g$9NHfj}hocwS z3=2>Rf}0pa!9}pen7`D{Q$2@dYrXpMBDwN1E#x_1vwz@I-5oQX_M8V2_^E+YUc#kY zT8`J|ko}oaVKs0WZFqjEavf(M`&Zk8vvc$kzeH?_$TsVm_7Vkq&d_BAR3r|DS|^zZ z^(NS5+FX->*+&EcR>ib;G9sf8Nt*2TNYC9Ul z&SQBh(S*+rH>K!ykp?1ljlPNw!R~?=3#&_?n8=Dlu8Y%Wcdp#aymoBE-^C)o8mJo zl#xGcYfAvlT&{u%P5|wdt+5fPF_72NG0|A|+iCpJvhoa7RHBrf6(~;vdE<}KPGv83 zOp|AAuJ5cSS*R!194HwQsq<+KZ&=90E0p^A)aV4V-1w(b$xZpgcF>DdpV1QD>FjNd z+1XjAd_tqKte&exQW5!~;^IQN>cUcIbAAyyEoZ_8^2w>`cM}=p`fEE!j`r9AuaTOA zOm|(CRs0+d1o`fwY`GHGrXJBozT@`~cROxgWxK%X<#|AlbI4D>ZDe^jf6sIF{$1VR zI(tMyNOCP%W0pxEd{b;s%7*6Z;{0x|3SKVes-Un43c&ZNtH-KO7~Q(K5 z^`bwkG=929=U;uc7c$(zti5*WhBU?1nN$Fzc`#O+FXi<~lM-QSiny*W|15NVu)MfB zGdpid`Dvv-@9zoGQ1T-TsF`PD9Y>kn4}&z_*Vw71{7D~1$}ia*)?Iad#Q-3htcjOJ z6Bz53;c-oRfGQxWluP{q{%i+(@6rBi3=52P1ln%;-2wOWnD>3!_c)?U zt|RhKs>I;OEq)vIh{?Nqd?%YX?lg7ID&uF`^d8B5ZMbu=D6G`&=MX7_6IsKmwNVe_(j{ulpJG1uGkbU320s!CuSAcC%cbou#6$!%! z$pN?k)&ZwxP^shZp-8pewE&aB%uX#Ah6;0N0QLYd@BB1?Xkm5PdYFAK0limUau}TvWuLqRMTyrTz!(|{$KH>V{pDi|#wB=|;qTg2cNxrv ztrumBdR5Ef70?fiETWbvx%a)bBdC4H##TNUQ}3@VvijIYG4f^#+oJ~%)dAbh6UUQ> zF@iScU~2)`1dIvh0=)wX0L%v5{j~E$?TWHGVx|Zr3t5Ay%h99fLjxdakFLq#8eEl6 zo4nTu5YPc!mDvG3>4u?+;R;#PJfb1nxDBlcG6q9Gpp!?i<$)zOIsOj_)sFC36thqWXlHp65mNj?UYkAk3oO~MecQN;8b`35(WfUGWwJB1w(4@f;pq6})UWFUp`&hbul{$Ho@t;jR98FP@$fTAxM3u;~)1KTP~UY zm|$D3y;OiDpeaATJB#7ti%HA|jHOLtXb+AR4<`$gGoAAFYYh+2DN^N+78sUnZdA27 zyY7yqO4D1&S^F1XOF@*)IhT*z@Y6mAV1Cqf8^(8BZ2_#iaO+e77{T6^boiagVgs+c zGcb}reT3vfaa1`do*8KgLT&XQA3@GlQSTE@ne)dRUOPJ53%o@g#fwO&-4O@YIsg&p z9Z@)us^M4+y8o45l+^)Kmzh8%)Z2)FmUB3Ek`t21-k>(sCNVre%8JISP#t6 zet1xo61q4pS`&zS^b{6V5ghiL;%T4e=tx6gk^0vvMN`q=ve{&B)(_8~%Gd>;;gAc8S>M z?5(F*05^l={Cy4$paX!a>eK~*TOv}uhpk+T&^dR1g2V>VjrnX8Z^<-&Rr_|C?6A(c zk`#DsG*~YRDlQ$wQa6vsroUppgE6ktU5jgw8EZ+jE=#--((dHF-t!`91I0tT!*Nh4 z(Z?gC#`(aG$;+Jq>qP`ndtN$1AlHrQI%0h@4#p{gn`+g=(#sK0$+!r3?K&O2HO)x} zbW)rpu*H&y8vUcAJ2+$=6*o76oaCM}uhvijl24~4-*epS43D9fVgC{qKGvjmqVc7+HZZhF>G z<0_4Ufg7o;XO@DI;l{!gACYu)UAXGIHW6X>)n;qqw@b$0k#X4rwCW4L`t8si9fTKL z(Hci1uvoSe`9Av6ug$H6OGh!x6)Z9tFn!hjB-<*VT(wA5EQH@ooP0z=rsuWOr{^2} z3N>M75x&+cp|oNT=^i*nKZD)lQK)V`#bp8ZUaj#7a$q=1PscED`I-NH&4XcvFZzWc zKVDb2$Wb)5jHC3<82KO*V`^ z>qwP*=HQqi?Esv8$TW&bgjC8AjNsPAhj6@K)Rz5@76De;givBgRNOIcU0BT8fXL1z zVkm!Bb&AlG(!^)zEBX`ENc*{Hz%?f3mgr)zsa(v##0glqfHG?&NIawbRtBKd-1$Vo~>lw^4mFW?gxklhxhJ zbx_D?lUZH)SN+UDV&2tD&l!7C6bQ_cDcq&32z;t1tE!2q-B8v>&C{Q;Y zJJHS4$$1EFt5jqaZzYxk@umMG*DGOdMy>iIcn8+6?;~M1?Hu-F24{dtaIxuC7BzRs z^tNxv^iqjR%3TPaUuA|^s2o9$SV4f&OAs;x#8-(iW?%THnJP3i1G-b+_4e0it=5S@ zt|=z^fH^WuzAOXEq`9Wxj#5nt=vrGtp&7U#89Qe{TCOkN#c-}5wp$~jPSGvF+7U>= zo0H_Rkm^%oLJVPo?&t}QQIdCpf!+w*2ac}=YS+KRTKz*%`iJMn%*w*@FPGbR(jkkPPA!;^Ey-{2Q?ZBWZ&_q7&)Wwduq=wq|wbiMFY2Ver zlg{R>RBNH8-X5hU@d&XhT2-)Fw~5Cw+9voI7b#qoQuu}Oh8eTHO8vnyVKbs(tY$&7 zigv)oRi`}Z9PP1_;WSZZ$Z@3j@CK3U=ff*nvKt=uLwW7=X(ha9$M5_tR?!=&u_UOM^}9B z|BCv`GAG?V*ah{WVOFe@9~AV7&MeR!I5}fekm(iNma6DYH*Zs0CFNCN6pypLIcIab zX~q6^qw#8Su{>uZCy+kH^JqQ)lI(iILc4yD+&K4={Ia`T821vdb0m4Jvy|73;BaRU z9p&Z!%KBEs(aJb?>2nVJw4QB2W`lE&Sxwjq za!B1rwE(+&&BYdpC_H-2;vK_s_HQR0!@tJne^0Le50>2jYmWU}cpNLszu z`(OE2|G%Jf|GOUg|FrdA_WmjNt^dDl|9Aa=;d1}jU}eCiWBZSC|0kI4uO1yO9n(LB z{xe^cuI7W{`)_igBJn(13IFfslk|2FFHvww8{rfF#*{#N=oFtD-x zW9M%}|LfV`I{ppC?w=L&e^TuJS%d!9vh)`<`M)W4f0>%{|7L0WPtF}3F2i>p{|CkH zqSMtwQK*SkTj}??yZd%Br6)(GV-hi>STJ130T3P#Jb0bxj404gI8X%sl??bi{Bp<^ z0BZq3&|f0_eQ`b!C#>vIHdzrA?BNq3c~P!+M|2_LZQjLY9F$QE*-syzpKo48>21dg z_U3F(XA5jjZ!%ETPG1`GH&>3~vVEW1;dnZ8T%|vTX=H*QiU06+Sm}L)CD|P?km^8N;XBEF^bJk^zS#J2 zdk$A;V{WEB_Xs!^ipO|NIB8>M_5T1@K&ZcL8T#uHA3^*ALe{q-4a1jy41kI>P6ScX z$%@`!G?^_{o894bxjkNAQgTYFUk#)M(=$SuS=l+^LAiPP1%nHVBE>^WhNAy>KEe@{ z%))Mz%!g1iLb1~WA=(r>P4g%uUjnmI;vw{bZ8yYqv7a!>_YYEefa(z`tTrn2>k;8G=oohhp~cR#4ihl!hQXB#GZ`3 z01_EOgMlLxp`F?2F7z^b1N}Gp8(AG&jmDxW(DJWv3RZClIQ~BIl2v3C_YTT~(bht5 zm!ci06K3QHI*N_~Z+?$Xp--^`C*kpUHr|5&Mhv8Zyv04n9pK*OG5;*^JBTuXM{VdC zbO_e-Z_!&=fcgt?HNFKm<8Al}e2R3EugEvNj=zilp6?ez(NodyV-sV4M;_!u*P+|c zYT)fts2d$X|B2p1e?$L+&SMK6is$1eaVI{7zalb8Ba=uA*-D-vKj$WLTez3`Vty2V zEB{;mBVnzuNvfBk7k5P;jQ%|OyV&8_??84;P=5$j0!Qxvsdxsxgx-PLKSX~-f1&aN z^$*80@y*c661*Nigny2Ig@1>?gi#{)O(Vle1+>~sT7ge@k_X8{(E3~OJwZMqe1g~GMM6k(6BS9nD@E0&23VvG2> zbf>gN_aFT^{eOz0==^ABv>Rks2aK)n1kN{NBEfRi10%$L2qs`<+aukn32S^#2P9EnF z{uJ*)pMt!vKo8+t@e;Hb_u*mqc3gs2qj!mmn}XM%ve-_-V;PUbXA$%O-N84YoBy>I z#HHvD=!@vjcq9K)&`&*RE6nKg=wtjW`VI@RuRyzTppEK5%iII#!Mx6lE)qevy<2>v#77JZAp5RQOEjRH-2CfdaRjQ=E763c}Z2CEG1fps?@T?;Gb zQ;?El5T~)5V5KXdOA29CSEHGz0o@K-Z%eE*_IT{B*veQldJ|~B!-Md5xC2&14^Wh$ zU&Hr)^da5^>+stDyImmKfR3Xtu?J`1LRb%d!ZKmA@SJc!_=WIWaWHUu4SEbD`Y#~O z3XEV5`W^ZbeS>u{H(oRdMWDY!q3<)$0#d^rL!+?|wZNLq0zEz|F_I-v%bmcz$6-Am zgSBxM^u$f*7w9A=*bO6^1MTaeo+{w;EGWGTX7DcD4Ji$vwR6y4VcaG>l(a#68q~BE zwAOLx(;v`h!0j08*C5af6?i(-^$ofKH9!kPP&M8UGjIr%f@ZDY{sZ`(jxA^uPQywBcw65j$0mGfZjyU!klRQGN}R~ZRAv~e8e?n!-tg)Eh&x^6%H=Q&&wSY&dJWo z3}vJT(*mkLH6=O8=k>Tydw(Q655tt#wJ!aT`f^wh9*@y5<05*_!@&_XiD8JYNs3=6`a5EmO7Xk-^NaK z{mMX>&!_dqP9fhIb>q|-!9ZtuQn04JB6+_9ZM=SEw^viWSLfso+HbMO8N1(PP9O&3 zl}O{IJchC26sx-a5@#{(QE(gxM5j7Og`Ug^!kC8AN8?bman4XE2A>)XRGkelBTb$1 z=(>%TVKkl6cM2Jnpt|wz2qYlb_tn)Y^@$WQ!}51TQ7R{wL=Ex>@Xm0!Gbe|Nh%_4J z6#6)V#fx(XE$bmef-M#m0I&~L18?hVhUEkM0|7e0n|d@f8zP_tg|z%| zO(&_NImZWboYQDd`#{bm^12{M@&V>3I6HNrOaIIkmwn9qVV&6ZFR~ls`BhVbRg-7V zP{(YnOYpX8>Q%9L{?JQ#39QpTdIpz75*SJ1SS|?VO_vJO$P7a#p8@|wCe#g`90(;# zz-ncurEYBeS)&93|CFXj(p^E+6FW<(7`RN9=w;`y@YV6*SH-XDona#f{pCZXYU<35 z8v3{tnZ1n&km}V;Kp9Eo9y1$GNx`|LVIFIHYIgd-ctjEn2(2n zuo5(Ce-N*qykEoXr_7wuYXR?W{nQy<1e4KqqiXi2L*9&DFjX{`N-m|+m`Y=)3WK0` z5gp4)>eUcxXSqB}VDULU7_l_nKpIAKdPqFY!qVWA3uX+Rd;z{-6-a2*0fM8V)I-WO zI}-RPhZKpAV&v6{LX>bX;t-O-81^7f*mAzCziguAT-k*FGE@$@ zT9@>QuvIVktr-{*yDh_P(RnlXNm%NM9q*R)5$NJQn!P=M)j&aj1gtg{sg?o@vGkBl z-Rj^eo-lN+miBFerFQZ8@Zt%5tdr%ekEnJruC)gW-7c5S=>S_1zQF*t78RC^AjOeT zC^Hm%h@>2@yQ8Nrw`A^wyJkP#{|?Uj<4;S*&MGTgFlEF+;Yf1mmFSuOJa|{foT?l@ z|H{Q;lWqF1o_p@lT$>5SV&J!Z&SwhmkPz?{VF{S=IWT&#W+kW8vno;5NooRv5ovmp zHKOXX#)b)2dr2|M1}iiiu3fyim~xHP#g725Fd0A9i!8AVTBW}95&2Q$R?8k?w{lcI zYV7gpbPhb0Tq{;8lT!B>4~d6-uPeVcysw-zT#&vo8k5b*PAw@V;?$rmv-2hATTaeN zxoJ)JtledzQ`CL)yA|z0CtqOV>*%fb*S!NhWOa<)_X{ZBE^h%BPwGI?ZT~=)5USBiXct zC-hCU)Sj=M(02|dtq+#F=J04)j&hHdYKBLW1s=)P@-TdA%KIU|7ulc_P{Kw#1BDob zaujwA6g^kFn8Gk4K#*Z8rJe3_Q_$HhDP^2GUjz(&j~f)+Wy|*VtfDnwxA* zuG>8;z1zq(!)un;JRexz_k1CKq5H!Ah4X@FA8H@!9B&)%s`S(tnheq~TZya0!z~w< zo7V|z%^SRXY`a~(wnHx2#H1xDLg7K1BVsBt(iCrMgh8`4VmtzVm;&-*v+9usMUe*O zP|;?L@evGK1+rAPglQ@cpnM}mjB%k#k^&B|Z$?~qw@Z9wWq^j0O2se zxC&TYiv>C>qSHZVsDw^i8nV(^bMb?te>KgS)O7pmTdU_fu_Ju$w_im6id}uLd`iA5 zoHBLGbH^UPu{r-2uYlLYV+m*Mro4L)9?ye*m3DsH-8VmZ`8ZH9W`XKfSN4~3sTD9Z~53N5AjxdZwSrx&I_##J>Y%Nx69X?^t$iY zNd{3gI$fgIl__RBYrMbG zPSPt=Xg>>JnO~EFQHmv{Gv(V9J|$%kEG%Y}vN`NkvfadW<0Ds4{ zO@HixUtL$-Ts0NnJmkytk{K1(jVZF|$zSpweW+%`;b_l2cVCxW;?-4FcCDXzZ&h-J znml>T@aWsNLQiJd@acu2lJrL4$~xG3_ z7*tEPrYEEwcYvSkwU+ndWW-p$7&h5H3$+GdtF84;IE_41YN?iKEiI&45g3N5I^9#M zI*Y;R+OHH2twFT`uo9eOSIyS=ou`GzO|yR=7wvp8Gd~}AKG?nMe*PBMm`t) zZy2LL_Bq)iJOP^Nw^}xA_&BI!n}?akn`+FG*NHrw%Zc1Jy92vz#DP7WEGd$~(}S^Q zM(z%Gr<5kZ+camnV~1m( zgR672J2pE`IL6(WIV8_-I;SN9KE2?kTUxQr8E zSy;*jbd()*6prgDm`pE!2=md4-;d`*-+u%>ydHGcqadY5n8R(_*w679-8c4coc!zL zbAi~rf>$Ormg)BCt{TravR&M++h*vI-y^>l{vf|+I3t`9KQ~%->)s^)A^uYLnn75q z+aRvdaaNeWE=BLA)9BzON2%niOKM3XNu~h0YCBkbo|=Ju<$a+4LHXA%9z8>on=Er} zb6rgy9@m0Uf?XJ~flMN&0|nF4Lm6yqh_C1CH}*gN-#8L|w?ddXSd0<27m7|R zTbD(Jsl>_GM9-v8E*;kvrYm#PJGGBa@{`o(8;4e}>5BUK(BlV2&tLNsYNJktnWdJ! z86~65TCS}|tWj!g(_Pa&HObqhN8}5#+>+X!N``R}!!T#WJD#gBjCWReACYCc47&uq zkF7$zWCCeKiaXn63}LEr%x2`fKNY810$?J}D7#`Z%O>>omwgtO#lA};fjKociA_oq z%<5cEQ?giF69^P1wssq68}LmW?#r{v*GIn}xqs&2==afAy6(i@ep`OUZT0Kd%xhTp z_>DC<6YMY(_C7=`7h9gYZqYMOAAWKNbnqr_KfVvfE1(gYYpw8&Ktxct%LEPy9LB;q zf?J)l4)IR=ZXVPZc8yP%!4Ye7cNAH`v*_p(Ql34;3V!t_)0+W(Ur$O(OJYF#;TOR_ZgCNUZ zug`b?U_2Pax<^w`QF_4UEx07n=MpkaSLl|ymOEyH9n*zcF zJ`9y88YG>i>`=fvR%f-9u=H0h`e&b!0nM0ka0oUN* z&5u2Q@c#F(9{Ya&@WpFiJaS7}?|mk6*RxMN`Lky_p7^&v`)_~t3V*f$WWfTmkV9V4 zj*C_?sLOO)-NEg)?T&4k59i2|qtZcaM~%Iv*8`shFBs3KiP^?!#zy1A`faw|X}tz% zWKc`52+d1t2(7cNbF59fD_t%LjS(yL1o=aC59D_mCj|^OLNvc*W^6vd^qPo+JT_49pCT1$MZVr;pLs3`HA~N|sOAm#q4?t0ibae??82e6A%V)kR9xe3 zz)kM+Six?>`vPes%WgD~EZ;01^OafpY9IDh+NJXTTKGp*#6YNBoYafbVsBEd7U+q? zw4T_h?$mS|Kh^C|kH@_}7T1yhxz&h=q*bPEH$Ig1YTCPLVj#_67K|^L4l#pT!))7Kqh>`%FvPT~HEC^$Cc_v-q<-p+j(K zP_?VbtwFtR4JvhO#U&9p^-SGbMm9X4UbEZJoIu_^&8NY}X7=G~U(81mgI`SDJ@z>r zrqOfMDU3(s%!p^!#67#k@Tsk3ODa9~h9>K6<>oAS03W_OWGpo}45bw9GL!;`zTB@b zWy=NwJ!o8e2D9Qpae_YxLI>U;_=s*HzEqrGb@24<7&Y<>u+O$=&cc!mhjU!?`5RY# z^yx?MW<|fT&YIC&peBd#%QZ93ef?oS&JSNdEh{-+bvmq7Bc?yH@x}W#4IVMd?+T_m zljn}FTKmA;onWbzqXb?K7l`qf1^Gz#qKI6~xyc}@KV%DHQhRf!6PI8h0 z=RPNKIvv5Z44Yl2I_ME=Qf7P!EqU#EoAWyI zbZTBf9?5g0feU6YuoF8ybItwHGuLyqmycbo)Zu1~b;jDeQc9_k?($L4zTaL-X8;OO zyNK>&Fd0>ydhn*q%wJT8)=;~`9-vl*LzG;Ui{M-f@k84obgRk?1vzUV5eWsilJPI> zT{p9N*4oXrPc9oD{WNOCS+D#&=eirJ#t-`4bJ*4q9yLW<`5WO#%1w{Vn)iG-^TpK- z#}*rPgnupib3wl0+KOqi(BB(fAscEZj=Cv_S|x9Q%K8f*VjfnWmc$JO7k?-?*84a@ z#1K}60)Ytobidt8&&O-2vsZRL;cyH%MsLI&BhEd!THa9m zSUa&rxKd-OJ(5(xjWdq3S0sI#Bu^KoU$U#uOW!8xz+Lk(16rbXwC2+5EoPHDp!2nW z&1}s!nam-Jg&ETN7Ss+cc~i>c`x4Ag88`-((*urC+~gRr;i&B}SDbsL9ZhF|dF=F% z41_q7n$njog-uv2df}E{OrjTiXWTythUvO*?(93)&Y8C!T!rd}=%1qf(eu#{E2s5; z!S#0UeWH8!PHIaJ0$aBiq*p?%S}sm~jO$=Cjs< zvjYY=%+1Hq3H-g$iTo=UE_^=%dUX%X^#SHhH?y<6?!rh!NZ5cBYUK`h1PSzXuU$A5 zKh|pz&I)|H02V*tkdAO4g6Ysn{p#cBEFvl@U|u$l7V(3344fKVdCC{pO!S=Z9-PI_ z`7oM>-r=Y7?;<@Kt9f;tOoZ75oW>EZgv>5SlYjxb*`m@zc4`&@&z?l?Cmn<%Uc)7i z;~b3jG|I0%*I#?uQbvu#4C>+~zWBXpJLqGC?})B`2j7k*e0%h+=(o|kQ2c(OFa>y^ z$HTQJt$dO)nV+ffdxc%nUioSL@A12mc(;B#eu#Ti*d{$HKcwG-pXOvAc1l?|B-P;Q z(%sxfVWTWZ@NkKE6_w9dD){S^8a8*ZDV;6TGAl zS=39MPSo?9PC%H*0+MwcrxMvgAR_AZDiR#fJ5dl|?dfD$k3cS7JS=K>v+)Q0L;Fqm`>2pOI}p9Vdjs)kdOa7?h4dWHVGi`ACMOSzDC)4` z5t;TN0kx--^B@%-qO4Osk-t(v_bZB>B=Z*8uLQ{;UX}Bed1OA{DBq$iCoA};<>!=x z@)6~{{GH<3!Ecs#D6h$HC?AlM{QL5U${F%G|Ec_?Vq7k-Q0^l4@OR1gD4U5iL*Gbl z;pfTom1SflFIA8#zCx~2ZqVHz&rl?fl5dKTVSGd$u9TZ3ju?1RmK7)Q@org4*fM^? zbBZh&B&kp|843}5d!eh=86$f7V52nYjS-z@%8cmg1Ck!sEELh}I1E+-krbq(2N~sM zbR&;%(7=~caf^pK&N4VH-p1(61YP@$i0 zpHPi)@KV?Wz?=(*EoJ{@Df4+P{fqk-m-##vu&^P)a(Xdz-ohjedV95`F>|D<(>?{Z zOI_^Le!V)BZh`C*w_Z?qaV;nc5GuNeVISOrkAfvA;TNNQ(LY8%iT+7Aa?!(m{#_-1 z=l82<0GWCMH0?9O3rIlMXufKR>M5Sf5Ri@+d=lYQ9A6uBLl+14Uf$3rTB1}(P3TXk zsUmhp^aRc#r-T>2ANLL2!Ke-LBFL)~1<(cU&QkL@^9|B1`dbXo$-7M*!9%8#vLfn4 z#jSHGLrj&XN;7z>GPs-$v%@mPG{k(Zd8uioMvt&3=%d<>AJjdt?72l ztJs>bSJ>GTWlSM6PQXNQ+XGx42?niTq6}ClV3suh^}Y62Uaq_SmhR}!-fx|H^W3uE zzjsU7q_OD-&Im^){pQYRK1d$Ac5n1AxO{I-p#O1hV)~3x<8L%Do$xTs-&v}U(Pr%$ zoxn@F4AJHnaDlK73=cu(cshPX&d?*BBvx@`tOB}Q?^BHhM$O0>dHKo#8?Ln3n2QSg zWZAj0A2HcrF@VViYoQ%XHsLChjU50FE`X6c1Bvi3Uw-ima;jhDii9HzstR=|2rpV$XSLgW40sPwNzLtuN8EXU2?na zZg)1x0V$QTghzyJ@*CW*^g=nF1j2j0g#C8*L)fMF8bwHTj|=W0nVKP&Y4jX z+Nn+3CT!DfH*7cYIxLxVX33N3Ss^dCNz1J(oNM_Fx($Z4rn_w$9P6Fy-RnJTeFn*< zb4Wg?&FAoWoIc5(Ym~jY66ea?r(mR56jk9AYU`^7DOyThN=r(6N=J&QrkqV7DVEF* zgz0;|0x*RrQ<7Kx@)A>+rC+=F(y=;lVKG>VkrMhEtSG?>gdMg^Mq(P^egds7S zm1;kvFV?l|i`l@g@#RHyQ{W+RF0K%)LB5i^Ten%)q3hC}=EPUIw{#!rIF-xSMY!R* zNxBEP9l8!~pRSX8NvD_C(L+&jglO=PsO4bHFN_eCJ|ssmq-@jVKwgAQg$FBLnW{nz z9y%gP9>Te$K_pWePKu<7M3ZhJ(3Jej`!;c&Nq4Y;tqlAMx|7j81zWdcmCV5Q=m-7#VFSzM-ubSQd+}lgo&DLc3XZ`l zP{G5k9GY5{I$c_(TV}Xhx5jX{drguoy2T`$+m@7N&GKaVvQl+p^*8cU<(c|h_@D5% zdD?u3OouG58(*`0U^!zkamk{}PGS7MQa{uVniIQ{b4A%kRferkoW za|mPAI}4ICZPSTgRXO5Q(+bi^nm4mU!Dhv;6vWq2cVN|ytMmrjQO@-(1}Vrdi|Y?i zAAO)-%la3G%LX+PDE9j84bW$9#(G|oew1|_wx)@SY%$1W>wb301KZ`#1{PEs< z-^Ny4G${I!e{cIMpML&g?a|RB>6`wZnHyfl^WOOsH_RIM>2FFF+3yMmcd9DH%W&T+y^(OvvMGf&chA4w@AfFCCk@RKe(J)t`V z0Ag=+*=X#9X10|YRa>dTf|;g$u9*ywW-L`aG}ueSSAJ>|?uv7mGR#QNkE@h%#?fh& z!ClI;X$qej9P`dRG2 zZYg@we*5irjLRQ16nDP0^qv@cDf(sfef-DdE$dfKj*LsPHflp9og_;ZFt+7ub=S($4f1r$R?9Z)cIRWR z-Il|y51gNh=S98IV8Dn-8FtyASB-B`7YH`OG%cw*sV<3YNor3bYEnT`N7C^mJ_!>Q zsonzbaWChk+n(==ZI7M##rHgV*M_Yok1 zIIG}}lP|pe;VMT8ESJxY4V}4g-qshm@Wp8K!be+c>K~i7>O37E^)Pan_4|~TA@hR5 z5n0LLZTr9<wsO(Ubk)A@#pRMt)aG?&x0)V_F*R z#m`{+Tcq-XvQ955QV&kmlElaHQ1Db+aY#z1wioRwkGzI?%M!}&bblXxk$kS7IUw|1 zvOU1gL^Hwi3f_agIZJ1jOdCtqWA7Wc-P@wJCC{D~wkft{rRB;barck(;3=A!dsmi2A-^}1RPD>bw!~SqEpDIYXgPH`EjjHu z9XXg89a>{TiA-D)#j zZi(IG8nEG!)gg%)LlTy&lN$0Rq0ADOFnD46!qJ-P@aBEd7ovB-9yJbE;#I|2(Icg$ zrw$(c^PivBN@vzidEm&zyx%#3(of3qeRw{ehwqOrjz02>&5N|rzxYY?`-}Zx+B$~^ zo-L%(eQ)e@ehME#F7&wOzQH=rx>ew0(JPjbGHVs7vYsIld%JJt^)9419S%hn?T(Ps ziRj_3$;DpsyKu~fUH{_7h^)Kxl3$0<>agygzvPb}5C7n%NNxNoMJPlUv*Yr*<|Yn1 z)^zK0*I}>!`tq@@IoP{n+U%R3+e$j3o>Ps(CoMgVkAMFWNMLMdbTZz>&Q+aglQzL6 zg(THIL^`As+TEDr1>|%XEe4DH!&^zbQ=DbNmiuHgc7%up_I}^}^!^`q8;dOT&I@?l zN64)xKyKL&BVrQZop9O{zm=BIOSJ>nme>WXtL`q*1A3>`!A1vjoEX`?*jv19X-@sn z!H%FgTw;q~XxjY!_iygL*=#<`3mK6+xxdr-^T6OfgO%k%JsS9XIEPm)sQVV)Jas2mLW zYVc#SEcw=1R$`@B)Ql#3h&X1U4%cxPanZNivLWK~x>xj)rugN&@Z$I_w2QT6z>oOV zJbH`)fxZnZElk`(qqiFEMQqMG8l0lb5aA-ah$j-PAY*i6 zJQYC$_$Jv?>b%pi@T*=hJ)fkLudAh>{Hn$l%1bl4H++Gf1E95(|3I35N~Ih zf)wB-Uy6&}`H}*RPrPKYS~HW9lS7%{&x&SC$Y#}M7S~yEvlUx=NTp`>C52LwA+0$X z*MX-GX$LZ38=@~px)91tyq%>`8v^~#grb?+NC;&R(laBO+OTUP`I&EJew@jfGyR$E znHyxs9uhS_8y%Rf$jq}MqB@N~3U)LMJn>wqxQq+io z1ib@!^%*EfA3?+P>yVtVvK4GJu)6fJI|BB;j76lNa(aSW8fH#%l4jE*h1Y{0K?oKB zmrLp0aLtpP71100>?Dgff}3Db%9TmX;VRJdJSo-l<@_X`Dl;bSlpL z^)R<+vit@IqQJfWzZ@Ln%FQLIRKH;~3+?8w6F>~n&6-6Nuq3#JSptVu6W!pzV5dL! zC=ss}317nX;EkFrmVk;AMIK^nG`%L=sS@m!67O%yeBKFtK2JZD8&F{VObv&_U|D70 zV(|Vjf89kp*VjLq9NUc#{tb6WKZ%};ei`q{E`9UWWT6L` zW~6id!>@f@{*;2m*_4oCF<*I*nSAxj=S#o$Nu1hV{>=~AWU71M<#90RC6`ZTAI87O zrt4QdH+$Q}Ti$qi=e}j5ZysCRAslf9{lPm|Tz{{jC>v@UP<$m;n<1vp}gPUf$N zwPVMT1GX#y+bKsq26IH`GMXb2eTeiSxFC(h4;qF=Kq2x*y-BnXWEXimq5P!^z7Dpw z9=s2P-)zh`Wg*pB;H-0U^co(!M-hs!+j+L+)QFS52QB3^k2gZ!MD*ZHO(rZxfAIk^ z8!km!@{mZvw{pCixS<>d7a5*(4a8mKaCmX+1k1V8bYskquK@Pw-hz(AU~h_@-OpJt^NAA&#o$mGt>t!$-3t$!ryL~hY&S$G?1Ff_ zt{QuQ{`f>PaX~N(+0QRbI2^rzgV7D6Ge+OAx_a_N@2KM0H+x}$naJNRlHS_c*Q8nh zU|do|Wm|^bW+-sqfd8ls2K}WVktmWNCm|O}<*kBGa>%KQ)nKrNxv&`2mvW`zSZ=Ji zo!c(5U!iEr2VDz_O3(8GFY6WFkc51^OK`|u#c41EQ5K&mg;+wY0%%1iI7EQv4c5R(-8L{`?z8s_(f z5%rZ0=rv<04D&*lkvd8j4jD`Jnt`UA?K0353PkFs>uK!Nz=awnBJ>&p)xB|13BXFJ ziFRV^>xZ#<|C`tu-5dSe;R7HZV@VGU-+x5*_D=)Z*an(r4Lv1Bty;NG;6))rQgsEo zmvkTN_^(_s*<}U8UJL!hdys9Q zm4}mt{>SM%kY_IRZ=wFzG~C8d=L^{llIdD9n7g7R6N&CzupfxR3tar2ehFcxE6%jc zh|2Cwaabfi8F_VaJ$%~o87i-(7JF^kd9da#O~vJ#CewKQeT>Ik0VdICv;uR{e!6lD zz@0j_=Wo|GWl6v0$#$t1{{g=zoiz$N$;W%dEZC8T>c-+4{8PMCQbIT^4Z*{tN<3cL zuD>8&kmL+LB;_a(ewZ?vpQ!wj*IlPfy8wZnaZY0KDhM&^RuJi~Ox_mPrk$qN=DXO_4TOYdOwt$$pEkG7_iA6F1O|NU5 zWZYpqW#o(;O(sQpnru58zxo+>z8f#w5R2(Ofj%!dm+Z#C4=)Ua7Z02=#<2ls(_MP$ z@&GJzI>0V~D1KWY%zp3LO0NvG7GWm!n995Xua0iPH@x^79v|I~H$-=z{D=ez7yScH zkIMbO!{efdsa&lC@A09;{re~A{m~2BV0~#x(zQv%M(+&8Zw!4SiN*YI<8XU%(ipzV zSY;oR^pNz3tQbrfJgh745!v;6Gg1cb5m~Yc7cx^n(|~_?izt2z{~zuUu?xtfXJ~qQ zhbVr7NT4@}*zFcDZf%JxL{9sam+{wO@10$*M5Fz^H}2PLk#Q?)?^-jjajkHq|LjB2 zGtqCOXQLn8So1i^d1g|}j=hJTe1iUNc}nav-Ypyl4=f!OVB^68U5Y;v0&Sx$0OWP+ z>-GHTHEaKpPt4UT$A&U+Y+x$!`N6a~lXma^7~p!ZO7(xIE3~ij?O~$|HG4$bBdo)~v>38cCznX*9(r3jUMw^6*Len$lP3 zJ;^Q4IO*~Ze&>}du7{sroVY_ArdK+{7WRHN+*ivshFTiv&Rttto4CtJt+G(!7UICQ zIi6kkjtsf-iZ^!!j>j&X^XWUkJ9A6jZL6dGAN>06Czkcjnp9mkYvSZO-}0IpTH9*o zHFEB}C+nVm|NW=u?#LPZ;!oa;HvRPE^4Ia?sW;D>I%!s2|21uQ-o9+!?e|g1yfM0f zpACMY6{Vmjv=Unxi5Me}vgGlk!dT%LpR8-~;}jjN_!^-`xxqNyUgNIuO;6dS>`J~M zpErKvFj$c(iHat#cg96iGFwDXK<7=hWrOh)vRavF%J+i}<@3ic)StiNcH6lhTy6_5 zPF!zm5}K5`_9l0ecW#PUTZ644yAB`!1t`4_k0Y0V9?Fd?d3x5tr5iDK{FcYcK%1Vu zyJ7BzHTCrmL>Ca(wNuvbz!r?Kf98!(d{@aGcxuPa&V7%)!2To;edS`lY4h@}wpr$~ zzw5j@_LpjQeo}VnFObnw5plcl4zq0Vz@PF#NE#8Hh(=%j<32z5V>hKDBnhvhhxjFE zBn{*_bQIt;Qi>h~IF3s}>mbd~;-8@FA#4F00i24@pql_bK=A~90o1h>%D(|=n;;B= zviI=MqiMo)u(zH=TOjQTS_a||1FRQIQ4PTD0A~Y4kUk#ZgRGuXw3Oxp&Ap^FwiD|0 zNGWI)w4;YQXVF0Gfw&3E$xv<^Z42TCz}Eqs0`Nu{=Mc0P{SJRXbYvI#1NR9(jsH{_ zBD^35;rp2Qrc|XXmCKdC=(p;BX&7m^$8f@EGX96@ygA+czNOgmwspE~n(c!9pyN~L zH0MjsZ(Ogshq|BkqEWF#P@j8jmb^Phm$X)e3Dx4FYxbYoGwL0pj`qG2W>>@C_94xB9d>wfs$!k!$PA%(>#PLK|@C2$VSKtE03^zXa9o4^IoTAwFy z5qa=HJrbIYJqcU~TJ5$3E~Ab3xdd(`&ymO_nJDJ}l)ynG1bYG}h!;EwoI`_zOA|PcT+(WWi;yl#4<~RQ*`&u9E>XToKTqJmE9oG^b&zh5-bmm)$kKZZmnr|H zz61{Z*WHl7p&ng*0tf!oyPI(EaG2^_`_&H%;rkZv>lPXgyrsxe-tf%eT9OyJNTW0>J4Drv^@1kR&m<0OXD zpP$%_w^6FBt87$2__(jCU%CvYCA#;+OfqUBBI z1PslKd~E`!>1-?pHZSJ86F9VMz85_U_Fo}bfP*2ZXeyeI8Uao~&1eyXHnbA8u$0jd zYXzJ>>mj{~mB@pfk!S&YRdhY1%>(*2w1mYP0X9PEW$_}ypj--Z%7c{v zm$I2w*l+#u*0@}@=e)Jb#a zHqB{NbJgpcXE!ZUCpOKQ-@KrH$so15zOA)sPE)-)rGDw62I!nRxO8Y?P4iN9Vf{*V z>5@jZZ9epBZu6oxwXIogXj;;;05a+qHK;AEO^`STavA~FFHu_>TNgI9wKX=VvsVIH zqq+dvTtusY3|dDkOKoXwZdf{}O@)3epAQ|mq6L6Wi{>m?+5n7J2RhNbXu(P~t0`M; zTsRx*zM}M^f7v=K-atp++PH*{lCtM=1C;zyUBlUkvYMckw#J2&m#t0EYD4q#MGKni z8?I(TeSGMRttyPD8JdFU(zceRZE8c~GRkHsGrw^`%hepp1I5}1OOP(WHW2hHw~(uI z+R##L1QGq>sxp^T=d$H_WnMg`lF_$am6J&0)^o?WSGkwqx&O-itJ43y+5da9|MzD9 z@6G=I$<6+fj&1s<+Bcqa9l-ejmjOLZS$b93f6Tp>abU?+r3TU}L0c~X&2S#de*tM% zYv!x-256Qfw0QH6)_6I0I>W9k6Hgh-V$0Z`aCQFGIn_`H9raSC3n;HvURCW}Vvms2bMVLb7aDjLIsq0E(ems6|Q zDrf;tH~*l-rF3jXf8l~4&sXGMO1q9}37Y!9m7xD6m;TrF{VNGeoWY@3Ci(#V$Y=l5 z_K`;Jd9)7#K^Azb5IP`mNaLRGmW+j34?vrP!7f+0us3!bkYPnEJ@=u)_7}OmXcj7h z7K9iC4toC#jO7{hbs~j_UOm+<8))-SF{&i) zDWEdL(*mI#!afLZK@dxL7?R~b=zIE`n$T!Rz~-eu7XG$>9%+ZtAPtE5at@WMJR~;+$w;n z0OtTq0XUm$Kt|S2t=r8#2~-qE(}03z6(ov^2QccVf(JV@yF0ThiognpC?Fyd5fEWH z4D8~v2%c!-foP%v5xfCWj4?z_)Zm2&UKj)0U0q#W-Cf5+kuApW zUfi&>E0O47WxV}fL6KX@?5xYyFRvw^n_XG*I;30l9imq0<7Q!h)naSa{Fj8!!nG5x zkKQ)(+^OT|`F=bWq;Ox&f7!58CFiTGK zJ)T~d=&MW+NahzXTjT`d+QI%R$W3aQUt^-;E|t|+n1F8_7OIxq5Br`k3sh9q&XS(uHN0#ekU&2Z0?C^E;`6g^>5S9KEnUUD~^RFi3N6d16I9j zpLuIlmn^Spn-{hlm5n2(;%}l%nknNJkwwJmv&-J(V=4%>9!WN2g{JpS9pz-yuiCz$ z|Mf%jUwr&1?=WVU5gK6e>_4TwjOt8=n4}a8e)ef*>jOL~8JXe$ddH<5ff`N{`DLQp;9sg<=l}M!|N660=O^SV zVu~vri?A)&{;AyyqZX7;$*=YIoP1_puFFizppwWg!@XCHahZ+9SW=nhA#=SRo|$jm z#iqOKlV^{o2H6Y`wq9~Owm56fn(+J8O7TY~3x@@|2AM91`^gLP;b!gL!S4qnbi>nOSoLq8m2YAH+X8g6cDM1nVvKHtpz_wR-0cxo zS6#-NquY7=9Sie&qT9Oh0d3qRegPtZxxF~IVu4$PRZqVdmptRer}Sx4m+?kca64)* zSdedoZVSd+8Mzz#S>b}N_5rzm3*8h}gZ#F;rF!zyEyn5pLEETnpzcF>z)hlT5UmTcz$wZvlH=Rl8f48w2#r*k34iwOm>V(W3tuO zvwKCD8SnnYG+eT1X8Wu^Tcj&Ach?(0)xk=)?@Q@@a0lL4+drg=S% zTeN?R9ct@3?Ru~!n9Y7CC-+pX8Q|qqFz=Fg#xCDs{XhO*>Q&XJwo6#&#q;hutlr)) zGi~*w@qR;V=GRRzFaNI3(E%pq>Lp)gw*R4*@rdA#x7sg@`PupP@4cG>E#^D4dwT9z z{lnX<$>MG=$6o&W)u}Eo?)6yLM|?cBvzwQFV%wN)Z!PBCuS;IMI^_A?#NdHqy{RZq!f99G~eAuWysliuXSAOqy zgJa8hqd5nfJ~rALvUZk{@^M+yx2Xjm`^x8U%J3O?)B#rtzI*z@cj>gugH68}9S>RC zXY#OiJ(JW_m?wFPPtscMV)Na+!_k~-xCfR5D4DUAH@%K$e3*Cx(4SSU& z+;l8r+|#EoN7l3m&a?8ft^o&{l6Q=V{4T0~|Jx2t@hxGolPYfP zGhgggxjbOMSLRRlhi2Q}7pM=$C~q6B4gSyec-P-{{g!dE2e!A@?E<`FQ#Y5u<)Kxz zmQznu^eNnU*xN6zdzqQw;F$#`&0QLd-x)hSS$D+qtk2{(RAu#+n{VGZuPYd8IpE|A zC);Op=4Pv2+L>3>H*{*U{>E$WZ@WvvUJgxoGjy(COL+;gWKVi>gDCXjwTAd7);F@N z(%%K1JAK_Ga%fbGpfdTS^3Uw6G9cHeJSZcy2h{K40q)X75cKPndU$bo?TA@`LU@whalLer$W$nGt=R#})q+Klw^m zm0jm#-!3hZ*L}{~`VCk>BONU;z8B};9fBFHpUuNHS&uXsyJaAXolB~xm z^4aM-J|Dj6T<7uXXXMDfS@UN;yHxL0Tb4PwXy4rEM|B}{JT8s7l<3qY@!|KT&zIhK zRT^d*wln;}54R8AjUK*NQR?{ptkbr;O|6d5W1fD0?gI7O<+uAf?Mm)!wq=&_)aqe^ z1z&f&XlYh5u-oz6mD8qtl-{N&%_L#%EdPuj{i8zfUb32TaoL0GtG9Wra6PlEbc1zu zZ!?dMS$ntmd*y4sn4OltspxF_JO`T@7OTi?%N(=BM`;th1_YL49wwh`cKf;ir1VYU zDJ#z2%$d4}Hi~F2uh=(s*!D%g61IyjU)o5Ou6gt1?3N8Fy9;B-(_?+kIP9&nb#^Ph z(Jk-hKKDuc_iiUQh1+f^&cE?-4=1Nkanb%K^S6f1colNP?h1AIRJ$o9KE;R5_qae^ zT)TA2-cubD+nkqFPsb*;DW3j%UA5Zw-jBCl^!+O6$D_ez#s_m25>;j0=lx!Gx7nt5 z#g;Fo6|GOr9Pp}ZaZKag4CS&}X)%N7GIQ~<`i|o|q*RWdR+dDkH_)#pPMh5Jb%t_W zwo#Y1cjPBR#>d^PPuQN;So_$y13o(OOX{3HmsHp^KQ<&riy za9z=xo_1b^_AXcV%&YiyLyf<~*UKHJBrGXZ9gA`6AJgs;9_?SXb4vNqo!;Sxi#Hul z*iq4A%FvzfUUjNEwpqStR_{5LVP9R2uG1u(Kic3Oz3YIjcTQ3M32WaS=P zy5~s1lArQs1Uc`lTM=43>7?m{?^e2;UHL4qGHk?{)nE1)+tXx^&F0cM+ZR49Z+>X% zRdr%TY-1GG{rAk3>nq1nZC$qb_M%1~GP^V{`cj|W&Z9TD_?AAtQxKG6m2t|iTl&V* zNtdgK9PQfYsqxukue*IP?ivcTg@SJpGEzh#43rQMQc4FOK3w=d9@~e49lEiC9S(I< z#YO&E#6yyXh=();TGK{6B%~oiFHLw{Y=o;aI!=M%0->um$l>2aJR~5d+XRgwJ`j@v zjfYC9@raF6kQgCFal|;G#ppk3p^JDZrbHhIE9UGhNYtnm;qii$4I!E5ls9lo_xeVG z<7Id3xuXAq@T1S$Jj?HN%VYK_vW`RE+~R?JM>!G@4~YLd>&D|-?F8`w*Y+odo=u$-zb$`k@#)j?7S~QB*k+&0Z(4ig z*9UL>e1BICUo3QQ7%{U?-3j**?<#v=ZcN#{tvtc}#LgYl_WFlN3x|cRe-xZ(zBO`$ z-GNudo9)US?%!Hcf7&W*_1OvFTZpsOniH> z^oNOs-%h+=HE8$8HxGaI?X%;b+01HF7ik{a{+ij8%&iwX)Q{dc>4oi~0Z)&rj&Czj zS!Y)by(dXI{iZ{Tug8>0k)5`sn){ARZD%(w^`P11l2f0oYqpJ!ZFEYR-ngE|-;KC% z^;L2({?4W`_tDe)LmHi)=aqD^Yjmm#xqRzR?UH7TWTLpGrZBI>vk0zna>z)Y+NPa6 zRajiyvS(zyT{2zV(jlRCWbL$?Fz*e`fzvPDN+0-cL}OG<*p^9ank7x~b)GifsmmMT zeM9^vyH{nGZjBjUzH*K0`7X;=pIqPg(kfuiN@7HtSt(>oPSgDMska`8ea>XuQWb1} zbl`(JFa1L+-s|>X#2WmtihnTRpai0PPKu4x#3TmOtbl_kmL3zd51t~aj0qly(kT8O zy7cd)=siq;XwZdX@S)&r@!zJ8ilmLIWntD;`3lqVT9po+w2_ zis6U(O$sS(A?P<5q?jzwZv@0ogbVS4Qa}fnJ_U5ddpc5r5pcn80)$EeAzV6C5mX5- zeF|y?veu`dK+*dG#lR?By5Gbg6}a>%C|>-&crg?Y7yQN)2)XDp5#bp8Yl%b<98sSE z=o9?w;8M^%{X6KOo>oj@@UO*@5E%UH3XnkHM|}+>QcwgP5(P@9uM5Png?}wE4T`8| zf+jHd*TIp}>EET8wslbrXow`K=K=;CX3RlSm(m#gYl&qd4E}ZRQcR|20-{jDKfpmX zgnnvO!~}&VSm-y(Ll~e)(Lg5Q(F(ct;iY}Jg&3$2(CQSCu>pR7FZ2snqcFP!r7gu@ zk*G>iM<^1RNSlabO`xcItIpf&|yPJi+ABu-{StrnUcPZAWoUJJtIAPCGkc*-X0i`yI{gcg%FYb@fT> z5MarPy>e)!DVB_@PcVmU?S3cY_B#S^eT5=$u0|0=>zi_d;M#J6nJu)gq7x*uLSkt; zK_dI!%3Ntzq-?H4{{s_F?RuEa6*E4!vaG~BZD-cut<05n`OlUWd?2FL^@^FQpmo1~ z?m|dfe^4g0?h!Uu{{zz(f;WF57}rfJ>y_4J#FiB^F6y|FtCGM8BL+9UIuV>PGOZ74 zY&er(`iX%fhxy%r6c+}>YT^{bJ={G!;0sA&_`DLh0x8&epyY7DmrKwl1cl)6PK$Ku zQIG~a8o^~a?k7$DuX42gjW3f>Vz3?on(#58!8aSE8$GfE-2yPiSDMdJVW9QvshGv5nW z$1ZPhld-zHwpk2iD+2lG*_9)9fh`K;#>g93r)ap?GDh;Hv@nFrw1ciq-nRo(2gq=D z$d9SEzD-a*=mH`J7w8Z@!e#Ju;$nC}w5W~QWutcxA5$hgQT`O-MNfxl0M4WtkwRMZ zXJVy95=UrVUc>9e$~3%Q3wXAjJ?Z8XK$pROqHsM=I2eR~b~wA2u<9MYPnB#J~oCeUXs3BYc?& z7dsLmLRbBktZRfOR;2{5^F)6yblJyfGzp2rgu(>1$}v)v6s}Y_Myrx$I!3954#1HC zQ``~r|Hc$4C6LjR5RNn^me7m=lsJM5{I8h;o)ifQj*29;Dp3=zaa2Sw?+M}X5GJV9 zun)}RkXe92G*vWM+GymF*RFyELf-_1QY(pIt!go*Pni@KhcP!CG|x9l6Bnyw z{P+xxKsYvB8Eqe>9_r!mU?3M6OD=NQ5Z0*F`e6j@iQddGW`Z$A(7#~wAu=gKp~n;J z`X?H07<|AJqrQnujo#d#z6)^FS4GGqL0=aUkQY-VH0r2ujlzD^FcOEIAsImuumMMi z2jk>G93P09Qa|%aQ7fVZuzw_z3Lq=pA4W+e;0KGs7#I+PoxqsiFr^lT5@_!T{jp$D zmBJAK4opO#eJM5`(2CLS4jYCf zB;mm%GSq3=ctDG`JPlxA5oM?ov+OQG#w!*T%+Sy%&JU}!)F zkOQM}t_%PV&3QR^6t8Y1B}3MjjR*A*qn%SW3Xp-A6aTr+O^MD*$Pkchl^!k6ge=kBKG<2Rxo_mx$025e}Y&IU~WQ1)jxx{v`(0YhF z2Ef`x#4_0Eit%wyzve4Lx*z=@jwwcx&}OxyzyKL72(ms?2pGYfOx!!#C-n5IByJ< z!tq8c};EyjC&}Obq;xZ|}-DENxEeP59 zAv|8Y0Upo3pkaZd8^8-FJ~uxZZ$1eh`=z*ZB%qaX+ZXV_N*Lxx;3QPU5JnO(d~nJ| zc-(#jt7wYb2Z5I4mkYYa(QyKXJnno5XvO?;DKWR*U{(whPY%zpN={=&PK5 z1TZnz7Nh*oo&cK`R$U}IfyRNsY>x-yjSFykk8v;<(!zpoSur%Pv6r7j5HUgLojz7rZ`=YHtdqI?IdjZ zvGUWX!{Pk7T7b^~#m-iswYbn2<`+A5Zv9}-QC?Cf_rdxcMTrg-Q6AT&inT1)Au`PjPCD_ z-oGB-OR8qgnyVI>tdKA*BOMD2Szke4dtYN;HVhLX1EGz+ISe;9y`+(~iK8hYGw_N$ zy|9_3qmezmu%(`(k&uyrjiC`QFN}kuy^)?3jB7@cvRD}|J5uLl)zlJ$m6BPA@KoI= zxUY-&mp!}5pCnO2>EB;UzW=^$Utn%@YsaT;SWr=_MNP43`-o&sR?ZECmbzy!y19#4 zD`MZ*=}eCgLeY8iezS0CJ_q#fN`7$@-+yj%^8f*x*Zg?p)+pxCD7R~@JYTc)lB$ER zjcm9zD&^nMd=Sz+m49$_(EXLKnf*mIuc)l<*YBO6_vm&Ws2!sQ5Nb4gB#cw2w-SX8#J;LW+mgoC8g4^*gR7bl6!T^Iu&zsCVANow(ny5ita&1n=|#N- zg~occLZA|FXV2Cyo#*Qo&xbOoD8JC8!m~Pg2o`U8n20SD?1s`zI7XOey`AN`Mp?%a9G8i8CG#UcJ zXB@a263&)g7(qLc2#^-KN99CWrBekigfEau*W{?48=@#F)K(IvR)&6; z{RTrPEAw&Sp8c%Z02=CE0mw{^H5DiUIN-gMhw~WF6{!+_R4wuu8g1X5R_LCW9y+eI zwQ+s%;N-iQ3a|0PagcA9eKu*4qT{bR%Z;;JVdEjhCnB@>W@$+v(VEk1UFElbHo4Y( zaqul5G5hkFl9DI4iC_v#-ug*ih-)1)>w9U;URh|NEv@tu9Z#{KS{+N-&o6=;vR!$* zu9*Hsi2g_=jhaNbmOPLJYTw6;ETpV>R96l)lpSt9eQWL@i?%wnj@CXrPn#KN5{!v7}n;q;yvF9(_ zDpT4A?P9(xO3K+8?J(mT<%-J|s9VJ&9O7%4(9QM6t(=MWJJPw|FP9ODTkOw1A|E<% zDLUwmR7T-*d{$r+uU5Q`X-T^!;r@ur{;&Y#iU6YLxT0>H3DLa3knV{gXj? zO})9iLT(tV;xxDSil@7Q_l+7l4e7_}!_|h}e1OW9IO>Nla_~s?=X~!oJ6~5$e^&_@?VyRHmE?2i-bu*EH zC2#ohMINbaq$Vy0ea#fW`t=j-bNm;y2eYLpaF{4qg`+)3o=|MToUgiz*ov{e5OkJQ z@*RN4P9+C4O+j?}0>TW`@Y-c<8A3aQ;k(F^n_|1QUA#j)e2&^SxxL-PRNo% zQcKH0xZ5Vupk`^zEqnF5c{u|8RQLEQPLm7MC4^wcyHvF?SrIA$*l&7YmMns=$G+he zj~;)TS)JmP4J$qu=rw?-jGgm3U6_WsS3}X!sQrbn!%w~V`|_QnelX`9TD{CcYd=&1 z6_RebrV%VPJcN6z{%5Zvi#T->$buBkBL`>tm6|Qq;8ic>IFF{3rp2fy2?!W#S(#i` z11k5+6(eDkTcn_X{ZkJkHzQl#Inef{UT!5nDijDZ-^JW7~InzcyD}I3>P;JgLd3q zjyqmb8`=8?ovaqGbn?MYO?1AZkpaG^$>0Ez?~0O#)@u})MxG|nYaK`f{a4#_w00Wo z@Pf`|puE>ycGZM!P9S#r6F)s}Fymb_T>p(L{&BKD{>Q<{_MfiE@h`6U^?%@sXR4#6 zs|;{!lPZQyb;&(Ofzp1s~%xwKsXh4V?Uoz8Q23U~LQ z=*7p+dxB*-eadLFWEl!?u!ELrU$}VE!Ke#DQb*1WNi~dMsF6oS5KK!!ZJ0(cGIRQ8J3~=WeaC>pV;U@embEpXU3d zn$!jrzVbGRaQ$a>Ec)w3TVLsdbRG_xk;Y-1+ciR|Mv|523T3pf82M*5bQ^)KVWTH7 zw!Q%ZKh30M)WzU6_7X8|+}V(pzqOPLQ)4Ov9DkBsZoD{pEOdrnpy0EhFqh{KqOtH5>NbQ%5$akApChw#0~ZXNd8lp1Zy323^Gz0Zlb@&@CQa@a z10R`keo&--C)IS2IabwIl8<~-obS}xNp_?M@$gbsHW`ufON76~_&-S*X2n?qKlZkE zFFBZ%%AslyVMc-XqmZZ-OF3VO+zj&t7D^SAdu`||7~`Ix|1^Z4K&HlhY1C9=$S;7z zju@Kb#nX$1NtEmvGcHIq(EHsV5o{X|aL}*2h7OHx%4Xi4#(E0CT8@7Bb${lnp|X(- zi(>OtZ%Q0oYWv>f1Sue}CF5Ac(?ku% z$&z*$f#B91xcay+uEaE;I2N;xoN$J`-@U%D%__PYBLx|>m=97wNI)Yh`s_Bno8q=p zGKq8Wk8-HG75&uc&P!W8EfDt-<0M=WNn$IA(vsp~kv_m1$u)6JVa2rpADa#2fnO8< zaiRkwyS*EP|D%AsLyJUbAj5MNE8lcA>N(5qwHo2hnhGV#51cQ!=#bc8Ptm1c z!}Gt%%+Vu1KNtTS*!cq}e_)4^f%TshfRXWEfQRu<&hX!72vQM1K+-spGnBlmtfDyD(e!bma>^>gHW=` zJ(`<&IG(||3pq%W4zO{VEXtnS(gbN9ES`9fDw^1sT|uRsI)2@`$sqzDd=|8VuoB=h z#W82%@V45?hhjD@lpxfD!6HPn@bO)HcM6FBRsdQFz7kp{Lr@Y z-v{lm=Y$pHgBHXFNuVSy+aXAM%Au(bf54ml3Rj|6#--E2VhKcZLf(aQcr3zHE zN49laBxo(os3#3|!x|MhCTl6_4VI6JODdoqUq4#a-e~cJjTJcKWWN(iKIv3zs5cw%0G|C9Yt68qU*AYD=E% zy1P|RWVW!oR*~uj-LA;o@zc&>l@O0z)e~kfgd(AeD#&%Px#v(L5rii*&;z20Dxe1^ z!vHkmmsBm?#-oH#6RW%3wq(#^E2VJbt(}YAB5C^%1fkZXL$L+<)XX;85GZ5r4fBQ1 z(XJvRK|DW4e+<#_yIF)R7qz)0GFvP}G_Tf3S`^vtB#Y2!T2B9Nwd{_jSMInFybVL~ z9`*_!!hgXH2{e?aufL~z4ez{+SqU~eD$>r@JCWK6N85?l2L~B?Jd*I=mG$SH}3hD+x zt9$-o?f;#7{#5%%0)ObBJE*Qfi}l&~gx^{ke;3JKe4Bq5wjcB3ZI-;mJ^kVIQg@ZM zy|)X1TB?MGi%<`EqC0Ip0Wjz18(4)_rGd=}mUJc2-7=_^-as?Gq*AgkR*s?u> zW3?e-vB_=8lY&XFvw0C*r9zxB8^P-6kKt}1vVwWvY2BUbz8W>8EhKG(I_ahlD5$;y zur@Vh#8oqm8=i=Hu-)o|b;N;)gIp&>HBwlKB2-2E6zVTU5K7w$?TGB^e6@9L$K|zu z+>8N3@d(upzn@)jy+zW941E|L;M(@a>styCE+{2Y5>pT%o=k4E-k$POGoy+yKztUy z5RJ@h5P}VxKlJwCNl`fOgxVnJ;!8OBh7TZ zei79%J1t;dd;(gXdKRyOC5%}!%{oGM19DHZ%#Fe-4y;b$FMZ{3mwX8XbjhJEk8kyay-8ZxI5x& z3(Qx$B(k`gc5FF_#*12(>EBwL*l22U>kyBER>(U^%nrHP>B%C-v63!vx;@N?Xc6?T zHwcON_#t%{S1KnXmTrC{0Yp4%@agRJYbb|{+Qd$h;_eK0VAH#4+-wG=(Rt<)b8srw zj+aCePTLJ+Uv=$F)t*^=ClVt|KmykpN;r4|r?uACXo5v>CRVPTX-kc!PZU?HlR!h( zD%2$F2Ox8cK_QkE4+$bjsmZj-Qc)#T6@!DpYLXeu%fR8qWiaHVe3k2Vq#??CehZv? z66mfxK`d&RotaWW#9P>E2Dq3f3z!hj(SMpnpIPSLO8XM@`ukV+?EG9(FFov#F3)h} zA)@xMjS@7ZF@%-zcx`6jdDFEUG$dLH$;k{8^$y%s-K*?o0!!Zi~jZs~68qq!;u=X4C327#Q*mC)3+l_7iG2ZOH)2H?oQ4@AXD=0~i@0ZM4kL z3G}*LMA4~0QzJ6n!uSleGN)N{eBR9rFc$STRDuYGR2>dY>T#pNnUaY>yRtgWx zRdB0hUU6Cxn0HpPTak`un@}X15P_;jwvBZeb|U5v?jsEU7vi{H!$9|a(sf8LfTa6eE~3g5-j^x#gnF?jUI^|wr(#W z4Y>>S&N*yqEhN*S>H)4y0^51G7g>gWeT0=4bCRZV?P$LBN105E$pYr0{eY+3!%PHN z&Dzq&?!CiJ>&n;8&0ARBk_>ZCtvoL3?=rX-XKa~D##K?*x+>ilgPrb1+U3)1cpL>P*G^Lu_4O_O(~C!AY+l+&jj`E3zl32 zfX4!Ls3|X1H!jB4FNlI0ukfnrfdH}Tp%3y3|2>RPAZ8*0B-+bKB&L!qq}i7%)2M}* zAF|0aj>ri*~m=QB|6Bmk)1>!EvW?rqA=1 zZYw*-^SJ|L&kmFKQ`?K%N;U8I4C6je$gFYyFf@@M+&6+n-!1TiX&B`K=5#UBjXn5& znZp&;c@O`&Y1ke==a$+70iXh}TbELj15VMA+>}p~9L@E8bzpV6Nm5ww!}@T6=i`oO zJ7K&YPxWej$z3D_+*uS#6w9Fwlb1hQ3Y_2Om#17X<*C6Mx*Hk~j_;5yO#cnrBq6&E zjWUGwSLZo*73pyU(gi9h?lf0C$Y@BRbGmnID}08BAcVR%tFho38a9>w?DljoS`6OB zWyQpfCQC>CJGkt2v|7K54mF{n1D$$m90dSLs(704VO%;M*;qri*~g1cOxTv!mJeAl z?k7obkW+bmOqg|*-S0YQrR&z3ddX7)-(c26s-E`5lOMpU&b)Z1YF`HnY04&S1gd&^ zliURT@Hx1seiZcfdU8mueRliB>>x09ZyK)T&_uiER!(I(lyjAnt8!I*tFcv+;v+oZ zl~?}y9!VMf`_vd>gnO}wy%M04sIWynY)@+4%z`#ei)k2~d5S&b7prIlF|d#a1=%7h zrzQs7nR`IQT^(0GH|v;IKrP+ z1Ie@OeSr>8?w<@2HG)4FTGkyviE>6?e{Ioq@Ki--Suf7n3T8Bhc2Sx(7Ry(DY?6h- zQ$ezD{uD>q@=N{*p>eRq^wdx5BpiQJmw%={Om zYhQ%~+DGgVc@i|F*=xiN(ALDXDfLk|*r1Z0F9=n|vI;#NMhWF3je`AjI>hRk*!xc7 zWy^Y_iB*f%0-bW#y=AW4JKxIn)ZBD!UiXgI{8g{(?U(x%9UhTs6IXcpY56>LQ8*lW zkjPCLUTg311UrkNj`IWx`l?~92|Q(j{BRP5{3TA8o$2Pebw+EYXLz59HjqN?Ufm>7 zZ%Z`e`A0)5{G2Mh4fCc$Fh)Ika4mKUSwDt|xL3Lymt&)?ad;Zn>+X2ZTIU-ih%?n* z;_($9#nR(E`ir5?#Zm7!2^o0Uepx%?C7A`b$XLhuW-6^T`H_%LhbeTrxsh_K3h9l) zg=sP0P$S%mJFMAH;H>-zWus=Oi@*8Z#6=@vJ8#JT=6gJAj!>Vf->3;cM;}&J=oYM( zq}BA|n%QSRt?_A=*zR;)+_*Ezv7tR7QG=#)rfv7-tNS4G?EpTT_LI9cankB>D^tD1 zxI~Afr!BH+1*bk0ZIuNWn?7?(bLiM__AR3&3+cBrt@N+ z3k%5iBYJeENGqTq8~XPoTe#hcD}7l)7`xbCQZ+E!tGk#g zz;89w?qnm_NX;%k$qT}@?xf#H?`r_L%w%RPqDwo$ys?D2)f7Sj3LXANT1^Cnp zcY*O~iDqAQSynL1gly$22%(C+q|goTXl6vbngRsHDeE+{`%?lq8@OS1w;&Q5ipU-w<@m=AInTbi|NzhwErXjT*UhL-68y~JR(+@8th$qGyZL`SRU#8B6AUn zG6)CspkxjvWPD~A-STe-EA@SH{bh3vjGWAXeMaO&XOIyjv@H0YNZZ)c=tvZn^M0-< zNw6PdBYSgWv|R_%vtyYq@lV&E!rV7sky|A2Ol=6s5w=V^PNAtZDKpTgw|+0>r);@N z9TJoaz-TEePXNq$3L09znIUG5D{57+*uu-QIC9_ifrfvpQe65<1n-HKCxtYp^?lu4 zi=mvZ_{orhOc=aM7bOy2kv1nMC;FK*see#`?AJkHYhMB$XQPO<(*y~8lGFfltMq2- zrSca$BUUCOgvn+c|FrkC;`2c^_&uvIJc2NWQ>^)FTu8*Uu8Q_jm-xEj*9RpJrztT! ztwKgOo3W8ZC{9PsOp6sixtQDLR7fA}M<-$Y6NVNpZNteqw-8j5GIY#*p0l@4SM}2L zKhsJwZ+uH8Br`qJ{l0iI(A(KDW4kCkpS3NSEIf@nZ?|W%V1tTm?(mMBo~vzsYk50kP#PUy%`7d<_ zif*<>^r|xY=0*mN^a@V;j(^U@tn^Hb=vB-NffWdBY)tf`MrJ0aj)W|X%=7|gjt;U$ z_JTH6wl>yA){cZ6|0q>p`m0s}=HC=6&KPc(3mG|^85qfn2*CW;5{9$2 zD(gMb9EwdaOd2T7MZGpl;xkysO(UF=t?w1zVDlj)M5c4Tt4wouixa^o2L(o>{pKzp zAj~1q-C9bk9Z~L`DL2Z9(ue8Lwvq80T^c5cj@W1hEt{40^&zlUe{W<`y z!^i~+@ao^B*5yt&$Oh4^*Y~eV!2|K-RUg{4a50aZI$Pk=DKk4e2Xxmmjh~Q1BXn0< z>cR0!iQW)OuVtQDyNGWyK_YB$BkI0o&#WIJw$!%#n3S-ji1sJCV% zJiWuljI8X0xl2DQ6ZrDIU!@#YfI|{mgvsJ7x>kVOU?A+=zR*8hReC%wDdqmT6G86U zUi5bVcJ{RAChk83xtAO7&SR&CWx8;YH^k`b`RaApNlV`YGQ5@t{eF8#73}&3Uyls! zeJ|CBwb27?V#;YqHeyf52n2u0AlYNCajG}1gg;np+qA*u9?I)fwGb+Btje(iBy0ip zEW|x0OSC;8y6E|+o;CPd{=gQvICMm0VL~JDp9hn>GLiy2!xf3AynxE^V74v@1HdHg z0e0|f{3h@#xMH@z=c0uvH~`he&E8qdOjmrKpP^(nX`18sN zC%xuw7Gi+Kw8-;38Oh6iPY2Wzcz(JEp;{dxL6T(tNBH@36Jj%5vZBI!HG} z1qXzUmPaGMO7%TKE=5*=ixnt9gW15J0B5oj61^ukN%4^ngV~gUjMg zEwCKXnW4=Hr?b4?==S#~btwxMNWcUGL=140-A44`-k;Cz?su#{u1VY}fiodY*8%NXo3VFZJaxx031o3sZ) zut|X z#p-RL6b_I``=jlUf-zH-4A{Z|Drjv2Oacor^{B*?{Qb&|3dAzhrxl8xbY_5TX&AJ2 zw%A7+<-Ag7L&ZENDlABjXc?*NiQrinwD)zhW+<3!Bl^&0g+=P#yNi3sDgbB{HX9r2 z8qlLve3~Il4?5>3!0E>Q93|nd{Kx2L+oAF8Z{CJpMm(Xeb~cD`esfDIg{n~D{t8T$ zV*?N07Nb)4Ag^4HeA+Ew-I~z~p3-ep0Wr zF$%Vizs(!7!z2i3qmo)QJuxHfOY1)ELxjAqp2j@Se?a%Ie=s!H^d~S+K3WJ8wFNM- zy2E+71Bc)`a8d9g2)k=d!GJ(Z(K2Qp&#Qwq9oM&NO{AHJNc? z=DB%nt9MW-L~pV2Vez6@Q=xc%mvHQBaOV;x=o|ND@cg2yK>8Ri;yuc0vxT&0z3O#J z>%+iyUE=z9rgy7OIbx0KxyCM^+=+tWP%)wI1ouKP7Ujc0cUf|n(4~OFU0zW*A2fG8 zA74$yC3YFnaXfRAqEnbe)kf1JGQ6E4bF?eWiw;EYuN$jE<_ST9F8&{r8`>b6u z2`hB87e_qVS(+!ZW%ZG7E{iwjx%)g($zw*R1=mQ09L)U{dvZ z$|%Fvu=EaTpzq%_QUAXDIp+xeKf=el55ZRN1i34X>^OI4`w-F7oKMU9#>Yd2`W^j; zJArpFqX$+?cK`X=$0M#!$CIl{)zfp=dSFSzk*q^;S1Fs^+*=nEzRLvq8w0C0? z74$nWU_bZim>j&1dhtB+emq~89GuT+XnYH9I!d6g=! zz1pJ|8v6;3UuFAgG~gJQPN=Mv9cR~)01Yo!#ZGTAznNYzrWD*J^C)$+f=olO@d;Q? zV`Y(ll+`z%A$6JXgp{dA4sHZ@Wv(RpyO|--wZn64wfajXJds9)*CSt*medeEbS{6& zZ>52k*Da6lnu~WygjL{GB6CYRLk&zuH(0-_HnjT`???-^LmL?eQea^PK?j2v`(qk* zD@@#>mdurknHzsA<#;2NItvO9CB_ipF9a_}Nezt`or)F{jfK#Y+UdPUGu{?U%UsU! zVJW;zV5e;koo_jCI={qBp>ANbviV7Ug_FE|?&TdofcLVFq&Vg-Ddh!xymsNwxJ;+B zk|xt1@1oHtp7m=XdLf70wuwaUW$7Lyk5l&^~Z@3+@x$) zd}@uJqk(X$^-&6NBzv^GcDT$nxa7Ua^FYp|!KI7e3`;9w!7E~r{`le35#zG9V+CSx zSyv&s)V`EzAR^0#sVuR5cJjRWP+;5I9U7$Iy!&{=(|Q?2eE(%##Tk=fnhd0j<)1+9>5nHcie`3o+HN$B8q zX0lwScO*6EK4%_*&UtRrJ&TP{aiI)tQn=iO;Lr7SW(R=P;iPR6QEO}%N<{uBTbR_} zzZbi#v#C{5;sKhYA>XSf)VWk+R)r++D!s3g&kee`bH|ACCuui`g?VS0 zbwi7ZnDsbd{AOH2c z?*A||`bD<@n;5r=$#G;7^CXPoc?(JMFbP20ul57i+2azt`k-_7f)qL3>A~`>eP%p$ zqhovTxy1IBirWNoF1wKky_+vQoIvJycFZ#y3eIQ!60pS#NGI-D5Wn1ETIicEyX^D^?b+GdBhgd=6NrD zmQE{MOxfXi$n#NOn`;n*5y33ykHuQ&fp31etgKdHU+kSPCEnC#A`X7@?^CYGDzK2U zAb9+!zRFa8le9ADWXYmu|1sudZhU&5i0BIrIXruu+tN^izr?fSp&wjnA?sh|I%E*L zhk)7bT%MJJlYzh&@G`~K>5{ZLdS^(d=7^%(I=5q=K9lpfuHkRvIo8(j-YtaK#S>WK z^we)If@WdOT7#2cF-K<^!pLE%mZV^k?_in-j0xCXqLPz3&Qq(OTVd)EIws#ae}15mY zt1=Te(F|^}UJE3%VO}sTobydE5T!1KW{%z!Qr@B09TJ$vk~WEg3e+SbANJ%iG~ zb}z$J<;M3IgUbYuy9%DTO#qrrCAiP?GupgzRW_an#p4qDlD;Q_&w6ppi1*_Y(rUUT z;B=`OoX<_5g9-(=eg2aNgF75AT@NCB0Nce9kT~SH4sKQ(Y5DXyojxv1{`M&|vP2;J z50+b9e9O1>`-VW&tP&K4fwKqmWLgm=qnG95D8ABHnxfg~2^@xbq3v*msE2B@-)FhL zg?50$!bmYvB~?ZoLuR1YaVN5Q z^uK@3+ys=9@gSTLga#0M9Aa@#-%R73m-=KA0r{ogBFW*PF$a*w3@{8$D-P1t<_BBgwhkpo3 zwktIXpq81jXR=dd8uydSn|p2h-C2-(DzC*!m$)rJoM{xx6W9y5x3a+g^l%;@sSS04 z>Lx%nNL^%)hp_X>%ZCZ-t7T39^8CBw*|6^#gl~hC*ri>-d4iS4{E~Y4BoxmTZo7;R zKsTL^4T6tta8%2s`UQ=vjm@s__0$UhSnM3{1af#%AW!^%NHqUu{uG?2lglBvx+n{b zc^zIT_l;frZkj`(+Z1|yU~~R1@Qcv@_l>{hlW%$#+8>@3g$-?B45~{iX3r}t6yN;8 zT2@w^(&>I+2dKbRRfC4oCc3!FWczs;_2enA?(??xt&t(XlZ7Et3Lt8Z7goy zcV5Sh-=cKMZ7*dx&Y-8*{sY<5(v1zhl7;%Ny4n&=QI52++@S*=uS*(EKiM`6b zlKX*hOpl7prC=Y5l<42B8Qg?M!5!9GQaQ@R`IDs5z0?u)_^l>+C9Svom8-G|{h5Z5 zJ@;&3KFAF)XoOvBn}stiAf56c>G3PaBXw;N&R%t|KQl~w7zWey1*cB|2R5+>`0sx* z1Q_xjSaP5&Bg+6xaw#x#bm^`?IoN~1>=Wz!<8-BW#0$vna~l9$O+gXduuHuonOU0( z_S}{lQWdaedlh6Ljh3*OZWy&e32oD(T%ooCPWI-)()Y66q>WoO^pcl z=|&TkRtO2{N!b-$4ZW560JYf7Pw6R}cd55kL(%1ui5DLh*$8l@d|nnEd#V7-cyRi~ zLX>t^VvV5%3JVW%*VgxWs~IkYYCGUerHfw*Q6GszMD?`Y6Hkllqx#Y&0KdlA6B9Kw zr8RKO%90%rgCFp4#BTu~hO>XSy!suomZS$(d3OZ879bag>6X_kUCGGAuce3ScATN< z>)$erIX3c%G9|*Z=YQ#RF(=|R*AX>l7o*kg_fMr~zP1(wD1I>rE&S2WWa*_gx0o@_ zh9oq$9~LWItP|Q$J)pQ>K+jF zai_Sd-@8l(O={|?SU#8%mqGK582CI8I_K>Yw!nHHibo?&@}8MEIYa*#pjtv_39JuU zd1wNr-Fol9TwG>;-KPbSud1>#3#hh?moWh|_0}{fbZwv(%2vfWvwHuu_XJc*n;CA2 zEIITy$XvaYIEIJ15S=(I=30uS^`9eW7qUFDdQ)K(S`AQebIe-65mhd_Dmyl`1+%is z;UxsX`%gZuE?~V?Q80tYtgMK=382t}OG>MqR%ESGd_J!5F`Ym4|AzK{)W`-VBK9@l zh;Des`sN{EIL6x#dB>!MlcK~ueM{UcjL-;Ej#!jhGAELgK_(hUT~=Ozcc3nmH>oAE zsR|pNB|;)+S^OHWp`v;eMnZh23aZ0d=5qQ(1o%m+3xAj?B#(L(1gN z2>b{jR4mwxHd*5g1yeM+K>}ZNxJ*0t9oq4EeOVnaSa)BSnGp4?L{4TQD7igK0f$Th zex#|>bsm@wEw{;NU9BnUoiqY*&LA4sn-~0ne1!&nF6IfSj|i@Ch1*%(L@c%}($TL&4Q;eI|Q5{r(PA@DNgGz_x@m zC?4;y2BXtRPuuEge0(4oG@H3Rg}UtT666POz~hF5bmtg7+7i!8evifWr0+ z-uu&mz>q|gAiaT*Kfw=f(DBDket(m-tiR2|rlMf4jFble zna|4ckK3%7+$+zP7Q@QnMNwT~+(S|BDtO2~j$32ytc#AE25SHK~%|%Yn>u3m8mwDEyZZBlviK=kq;T&n4hya2`Mdotv zyJ$)#>DMb7#O;1bVCKynl*iET)~6XtrI4FL>MaaSQG(V>%*-NS-ar+j;HZL=#*RFpg7;$ zO)i+Lw{Zb<;npL-A$2Y0@dCQMJv!c8xqb%M8Mnw00`-&4UNG| zZ1<|3iIGX=s&+8fgw2-97cZeZe{-$}Xhvn*w^;#+K#--|lMe^kV(Txfh7qXo#`9Te_q<&OzREA&>(PUHT{;A|~)Aho=9V(aN+VB2@{ zoWjK%#F+&?Hj7$jwfkY;pE%Puuf}VRld6FfWNYF0 zt;T@FQ_$~`loQ-SB~2w=#mB{&4M<~0l$Gv)Diit3)`6g{O)ZFQK|Vz@6E&;!+R>n74xxa8eOZL|@&uq*1e-0X(HY@+S;AvvX2Yk$^m|}Uo zupx#A5ZUA&3G4ut-W?VYJs5hA8Nc-W=i;C0Y@ZFHg$oG4SqcNJyD-o+dS)cvyi=|4 ztB>+P@%%uxD%e{c}v`(>_tuQSQsbrHlz@07V%PiZo0NqY zOKe}?%S(31%o$+QV__iUd2#Li(EHsNLDJ>re#KN5l7Mb~aX%nLR{fdDxuVRTMgb1NYev2_ux7V(zQ zXrj`96VBbUpdZSQ{Q%T-6RgGlpJV zhxlwG5=^<-g+3a(^dpqFk}zZxtn+h#e@zJ;td<#0i%h>7^p&P$(=H-;53jxc79;VE zLZE;=frsB*48V_pIvKYwD%q==6~{J&DQ`peIj2~Gr^d7F*v-L~bYggjSfwja??*yx zEyH#qa&zokF-j;(id+QQx)^JWS(q;e_<-PN($Cehx?BTr-k*pN2u553`?~SoGgA)1 zaVL=EvgX_piVR5Ou=hq0pnW((%QN+VB2}0gzpC!@LJHINq~<{Q>!eI5IA{NgWjt6g zTpryWG9Ez8kuqE54_Ty~He8z9(--~zDK(VHUp9KpzkVwbEv#RWNp4*AcXW>Y)90W7 zrV<)~Ab*xbTBXs0VTZhI*OZr(aKOsM}8sWSUO{Ga>GIKcluDc}9siKY6;~xjud#m0Q66KkxsKN#E zQ|Src(>iq0o1Jmtdgf1cyfu&!gfw^>3FJY29K>gv{k|4#Il{Gj4+GuInk9j9UF-zu z7-6TFH(h7mT>ln*(mumkAg7!5)yi>x)8K&~mES+6@1E!rORWp^<=5MHcuJ2K= zO8kM_ZLpw|#)!b5eTiRD40z0K`p5k(D+`M45f2g zYIdjkR**+?Ft1nb6WERd-rOICkj5nOP7uD8kU#ViiaFPje-M{%=j6LU=|&VZdNh`3 zowS(BX z2DMQAI^;cxLKPx?=0y8rU?Ndh!lu&m2h}Jo9VV+UvugBI{g4+Aut2yjbK+i$#}pDjjasXwGx)s`&vkhlEKosW(Wc7-*6S$ScT zZ(Ci!#;@%ItCq7&(uXZym0#2e%HhZ8I_DZzb;V~vz5l*>QC1DMUe2aiz^*9NUTD1- zLi*|2xZyzJfdEA+Uh3Z=(?9mhGBR-db7u_GKPtEW3o`vrw#+uDja2TiA+`Uh(b9!a zM`Pzl+GHIDe3jHE3?VGC>?Wk|88hxe}$nvT!>gg99!RNL0t+N|C%<+RZ1p#qq47!CXUfm`3!?)>|~#DMskSw}_s-?w>mVL2Dc;jaZCdfPCee-ihPV zj)0V1_1EF>1<_=)8HBN9W?Sf6C;PFWDRu^j(_N`*_btUKv5pSZ7zP_I{|7(f)DD_+uwlYRAjwKv?YNbew9@pl>?4%ZT*6-X$?}0;9X3hyzkV_LY;j-f5#KcfG5Doidq_$Zy1|Se z)_jstp)m-uMlcb(_f$$YE<%*Pm+dMJ%obwK>mqldXzRXa8K3p+ODI-E<+pFg;4qk= z=*@BYEqS}xew zHOD^uidE`~d=70y1$A2CDACHUNPjqWdX+D}ICrj*bH(m4Wghyvj96=NUGn=U_{R)? z(z>xGM%K{GVIfg2LIn|RMOp1JdliY#?7`H9tC5^8f^m7Xhb^8JW296v=Bbp7@R}y1 zx{aR;_KBti(u3#MsZ-1ps2Y(~K#}`TN}15kx=Vi{rPQUaT9xVP*(kuHgIk!3R@;)n zs=XEBsL?ja!sKF!YN-2K&xh9&Dr_;U10HT`L#? zuDZ1|FJK%eklWdn={}wDWFh(d=ZBqGtfcfv;hZXjt+Owo zJl5GdPW8t{!v_Cj9qUltRUvIRGHKy>21AQ_-eXSmM#KbXPH2Bzw3}2J=>&>WFitXQ zlS@b2f+SsT?PpRz0%RjD;Q~T5@-(*1_5F8~?bdvK%bXj#H1Z9@%dP0I>bN68Ux)W^ z#RwQFTSRo@u87oV>J+Ctd5b7-ELyR&)l;eYvRr zSmyS#$)fbJa|uM4)$@yyDQjsZ4ikpNEr$ujjQd%X3Hmev^+B7FLi#ZWV?6^E-KCrg+egHk0Yq_@|NKEfS-uBzzowR>R$he zFbWy1kcI|Y<0Bv#knEW*`7n0Z6A zf|}kt+0q|rOziedf*w+W3Y>_-wc?NfY-;f~6`Ez2J7&6jn`gRl=Ok(BcF9ck@k+6W zh!;Orc-NRKr^`;rHMA6InV7YVZTFLKGSnm;>O>$6UlzBVn`u!BWdaCpIdauho6M-o ztuZ3PbF?&8`haJC8AdfB5YnbdX&lo<1YsZ9oj9|5S7{NBgS-Rn7Q30Ew5V>6Nts~J zf`fi}LngmafKCnTe+|*&Wms!}N)A{r{{Q zF^;-9+0$k1+RrcZh`+KPdXHJVYc+DXfF&T?(wu%!g~7NW#^byi)_(O9&(HO)cVj6s zV-FR=qm#5k&5z=f0ee49(2&7usd~C*JSBWic|+vHr?uO7g=%K~WSL8DZqwui4rBU*NrB{k>_%>c5-R zOZR~1Zh(Fbs9_&u(|cNAymeb!m!3Nc-yglW7Ru1Lu?NiD79T_A8?uo~&`?d<_WuE&xCnqPbcdm{{TUXHJS$zAG9dl7;O5BYb z8csk@NfF#NuJ7`yO%|2zPu+J!kVdNx&w>CiAT-WTWL=6l=GEYp=J7 zrmA(c5VGb<&5Q9B&}9wmKk@K}wbmu-a;+=G?htCmXl;1n_L`58*_) z*Fn|0Hg&1rZH`Albz@`oXzO5&U|}!PuP4y8czsMppD;EIR+dO)*0_ZYCm8)m%Eh_& zgt$kc^)cYBtaQB#(*0yGarR!1&4C7CkD~izf5xzIc&PiDB#3Uno9^!Gs7HDpu7W`x zUCJkCLj2J*s2Z!Xu~-VT`f9o)F`aZ$tS^Skf!_3z8elFlrjh`B6)7HQ5xt$w8? zeC8n;65N~4kz&-NzN-QrM#n!C2g$cdOXrp`)H9|~ape;()Wy^|;SS$u-ST^(w+ew$*f2o~?0+Wfe)&-6Nk2 zHx=S^Bn-t`)jxB~^9Q zEmH%qUbrz(c(DD;Ppno_omQnk8-|&B)4llWt|SScLXXMnQ#`jgK|*%%d;D1}~b zQkavInvRWFZ6pz7!s;9s3FPtm4Iu>NJ$4fQNtz!7WMk%gTkZi;M^%-UaHJ?`vi4hc z<}Y`5CnyjK$o1R;fDv>I+69P3(X)oS6E(K~$tVr`O+n3QXhw#C{nDpp4TimoMA1ZX z&AL`;uO<`9Q85&JLXhpCHcw-oDfr_W_}iSL8lR!1nO0qG%FoL>-QW*D`HI`0E9nxA ziD9+q@kJNlCjBhFRoz+e`xs}B;-W&tRM&#n`(co-p9F$Zd8IKA&p&)62_H)o-iZO1 zdJsve{F2>ZzNxWL7`iwBh?2E&rc+7jmb5xrGIoIYhZ6T%y`YurVY&Ys6ZgB_`Mur; zGwWXolZ=0cdH!;n7=NoV@b6Mv(v(C?c32SF?NWl%=hc;QT5an zaSfv)bFEUsxM^jah|;&hS@@Eju-~VtFKI+!tySS=@L8kq=SiUmwdK+TqYHKm7Zukg za-KL*uf_UNUS=|)_+3}gINGl*U1uncYC>M>x!$vHs`*ue6q#Rs2`+6;y*xU3HgieQ z4&%O%;}Iy-1<@cz@qfbP&FaxwMAbI(SrGL~|LW`=Q+Y`O7s_TXZd^qc(8uk)gAO`P zd2(3^l(=G(Eo75@Zkz!Bq|zReKsX-dg=#gx%~x{~w8iqs50v?C1;(W>jg-3&2lX|( zq8lpqq-Ty9rx*2Xv5E|R!pm!c{(%g^*jBa>=MLLh^NOL}VGOhq(?}=8b*Kw!l>atH ziK?bE7Izt{NM&E>hoBT^{VXL3QQo&(Zu@=Vdzdn%M*#L<2+oB$OmK{DP67-b8wmF) z=obadlhmXq!%|{MDr9yX}HIEXHQ|Ad8TUPg1g2X z7$F*4^ouAWx;M9|Zu%RqY;(r&gpzU6)gC4X^7IVTJt;o}k~PmLnFVC}Y@L{xckQd8 zMv+mamXuE(36uPaQ`Z_&5ep?jfIr;%ny9sz_tb{P)D-Py^OWsXqT4j=GIRBL;l3&q zfrm6crZ>$ym2@wpx$2JKhoVMFnso<%v+t?CH9X{#P+jpk9b52iakAmQ0BQtxu0lut z9C34Q{fY^l<%6l3-+i^SF+awN-g@#C?rGr%5($kATI+J((Xo1SC$}TuITR4C(uFzOK~PQ$t&Con1? z;pd_5*rgZqdh_L0vQ+kqF1A2ur*ihsDKKLG6mftAZsSK+B&Njy8c%RUW?xR>>iLKW zE$APL@oNM?bA4(c(zuYk7W7eIMGsCa@FLrJUP}241HcfF+(kmcI5<%= z_e=SV2Ec$a>)eooCqH;wSF%p~+_EE}FDaZ{VD)gqBGNnit*!_?onpwig&znZk&TJ@ zeI8D4uFnFL&_;h%$b5fY7+8&XLA%1kZ8rq|ouc})#tA(gJKJyfe^XjejQhXM@ zqZWS#SLqez&nlSulQ|S9YW4kQpPXMlTNdy(Rizo!ir~gol~1h0>6%1YhcsLG3;;AMgm-D077ZyeHS`xJD2G=YpKIsj52ogQ!M3qF#OHW$Qzb2aYRPqv<1 zS*!X6zxQLi4U5nF2uu&Wjt6v(#TVtEsQlQFj1u`$gBVBgfxQ@pFyV||bp${!j9v^n zy)L#4?hL58^JPr!aakMO$aZ?0c&k-JYQXMfawn;|aWxkMaMPs`@=JeySdblC`2*!^ z!=z4?40~z(f(&8Mp;b>BX))+B0|W3?>`^aURqZ8ptjF{LZ<_Jf+4d(z!zeaZh%@85 zUd`+vXgrUcbz#>;ZVqiqRP3~zbq7Ubah2DFG$#kkdpX>%^JJ) zNp|{*Th1PRtmV2a)@6{XKt^o{8;JL3_;3GjbGM=*-nP7cfI1k!U*{(ganLwfE#4Eyt!m6+}^dK!w2KWGYi z+Iy`X+=}prn@`v86Y3=y3Uv2mg?I)c7@_~5048THOE+BJS+k{{kKa^O*&a9BKD^4B zrMIV+^Qb?m38^W{^1ZIPwMN-Kl#u)(m$j$!R)P)`;%aX}jP>Q_sd(*N-y4}!>=}Tv zR}cGkdKwL;X6lNy$-YW+%-yntl+|)&d*|~R=EuPjOGqzdz=h`G0sv>&&2u*gyTEP7 z6tXy-MmfnO1Ledf_ll6wb~%_$|6HEc<@0b&pUVE#K#ATB%keF^RBDw`OutHgdo>}W zPLfnYaE)29OIluwm3_4I@3$V@Jm&2U z?`9Q~*ud4CYhW{x{s+Q^un(KGtF=~R<(H77oq&4y<`T;h!x*`i-tiV;Fe-Z#oX}>6 zdN^Be`HH>FLAcc#%_eQLJi1O_)_Mq9uA`Pl1~d!20^E&`x-ZX-W$3Ai2&RVgI*)cx zv)#ZlR=-^2TqU;ATJH3vVc6ituglU(?=>wC0G#{+7|CL6=0eu){P9rZr#tZ8uJ^a^ z9fBQ4t%%*lT+`kr=dDjPgYl%gCY>dqh4vtNo%KzFMH1P@vG?Qffv=b2Z{KiUtqD+G zFB{Z&J`QxO9Sn?=m{B)9-BN8A#eR2R9F`6<+i~pRd43sLbhp145LfAjdaZCFa<}ZL z-ZGMF*IrV*8hOk>X&*^K2ok-m)U0 zeAmK&H{uX zKg3VeGlEa_*Wffkc3Pq-%?b5TVO{cfls{(&&9ZOQhBD7oS>H!8aBr?R=cloI+6wmn{81?|?(zL0Ak zBdqW~U^^+U$C7o96WX9Nj=UC_w`=vPxg;fH=)3nHFoGkmbw%wZ7UXIrr|ewY_};ciaS%Rw_$1>R5t>409tE zV^Uz6Rpg4NRCKaMMYsCn(iXO2B%-^2T&d9AvJ=W2#{M&SR8mKOtBbq!o`Ujz!$TbB zwmO-X-;h9gezl7`5a*dfq9%1cGl{LHmb$m8#&&mT-OVrXYD>i|Q3nmS4fqB?n_nN< zfP?2w#n}3`H@biB&30~z;oMgs1;}xAcO5*CNOi0W?bw=Lz0!#{3ar7?-}*+j)#}eS z|ITciq#8%v_i)#s+-hyen?a$)`dLpk&bY{;XJ^yzlvjQ)sF8d+*{=OIuP0!0Tek{A z)fUgJLpu)jGBK5^?!GUPDLo;7 zM52}~2!9_>W_fq5Aj&4Zy!PeQu|CocUf&}WSQ7T)-|(WHZ}nOaHObd>rDtfgWSY;J z8g9pi07$35G7Pc9;oMBR^}V^52P(*&ft>@%=w!NBc%Kj!(dcBZSlDO_CRBz3_=oZQ?$@(v z-Oe*_wb=RsI7TC7nMt-p`wiu7-vpRZJKx`0znfp^2qlrl%CeYVj3;>tAfo74f`5ZY zNR9rFVGW({-VcbK=MmM7Y-aHW0;`Hg-?M7*kH>j3>V9Oe&WUb?x(7d76-O^EMa2&N zIuag#oKLdTT{f;e@Oa63I6KzZ3JhetE!sFJ^)c^a3y8~ef0&$bA6l=62ztLPpUUjT z0egmGN@7>P61FNSJ4$eQo-p#R_rk-XS zH`^5jj4?Xue!tvlF~a+kZ%jHXr}`+V?|Q-pGCG7zzGJli2keFYW(@Pz%qu?G^jqG9 zU6HT7S?e#3)kl&GW+u-q}| z91xa!n7!o5H`?F|M^!E%%&{}{z>3R}5wk)mi@#@C%BTlFv{~q+2n)KZ+-$6}Fie>= zW!H1uT4XQa>GU6E;h69GzQi&)Ry6lup{u#dE&#$}T4z-cdM)&~K<@8_>>a%3D5dV- z&*PynuR22*P8{RbyZ0<}bDV(MIGE$%+_b%Fq7(LPHETnIbrqH9yQ2@_g zGsr#*-9}sfWYet%l)}TSdgFu zl19g_j9BdtF!WWwSGMmy)r}B2%VIUvug_O1&?HOj0Rrzu>w?huWDXs&DUG{R4p1x_o(Y>H4~4 ziJ6y0SAZH$+D%lGOUjfZ?)!ksuY>Kb#}t@=b$1*k)FT$K!VPf+hGEV(j~k;Uboevh zbzP#V^s>1d#2OJ9*FNSM-S=YDKiqj5r5cEp`k1%`N}QDFICa!GPV%PeC|686+dbz@ zzq=jidpvK=H+h^2FzL+O0oTAcBt`L_ya_7o6hF^^P6 zR?tf1cMSuRo(9T@d7=OLulVGD+oi34!JD0RU;4Z7z@PLFMs}vZ>J~HpXZi=@e~11N zrz9S+%>wg#^8$R$s91eyIv9QIf&(xv39QV3?1FYLp@P0MgEtRy*6E<0^)rs4=5jvPEm}SuWMOYEk@LMKq=Y0~<@M?G5&gySg z@5OpX$X>CguZ56lXFrsFALIu?$47Q*wx}GH#17CK6ww?uj3xrrR#;0++;fkIMj>HL zfgwJboj_ts3Ias|y+CsM+${{8yfH8ONxDJ#=*ef@%528$?ZR&$!3&L;pP>+9x^PA2dUv9IqlF9jWU>Yrd6KSo>!Y80 zj;FazdSOi*!lQ584S7fg(yoa4-ORnbWTBtcy-7W?$nwuz8^6v6e4QWxfuct1L-g<2 zjENH4k$spOx;Hp*u#QVRuCFA!h(Db)1I?@Ah^!H7ZIhmLF5gu+X#=x%Ay<=_8IYx! z;DkjQA{Se4V#98UZChx;mcejE9+6F^JwY*db+`x*ZWhVupG4w3dFQUIl2smmgTWFo z8I4Pi*^58<2A~7R#`~r_T}$a!i=rrTR*77y^a-~LN#LY08jP>D%&9I#dRfAj?x)dH zRol#SgxbgvxLE*;!q_YMM^|MQTuu@cV(kT z9kFUqVM-Sg2Q1@dUC6r_TPVira*IFWp0nd{w%kab0@}Qwq*KT@+{z=@?mV&T9Xp-B z3Ztxh<%cdelThz)jNNc4DGuEh!{o<(kIxJXFFmNjUc4i_>p7SkwK=TK%{29PE}}tB zwjCSEiia&9~_0rbNmI$@VXw~&i(`z-upOo0KRfLXU8}T0_e`Qh$kaaFS+oo?h zs3xyc3l&q`zfQAVmLWcfO&dJlbK|Md`rgEL$doW-hx%OIoBqvj>&acDWue!eLC)R< z81~SNP3dhXJ6)}?V8Q2Jj2FDCQEAGX=Lx+8Cws15K^zgue(RP`KE1MIj*t0Bz<}v{!ZHgc!jl!5tXb*+=AN=}V>@_Hn#7tOz5n z^@!5Ji|~P(wTE4d^PgsF|Fxp`5@Wtmd5X^wu9IwCTBC)^LVE8t@r31J_Ep6KsiOWa zgx`sBX~{=5vbE*O^K7jC*7`??#lW!8L}lw)Q$=F%z$y< zba+RQOKEA4?~w0yH{0b0Kbni&2Ut-iqQ0lY6L_8jiwW1^U-W=AZw+8MkA}z^GM@lq z)JdqRy3@o;zwC{^Uy-=v1IAHgCP9#pPd+7+O8QVSt-!>!igdYwmK40$Vs%2e>g4rg zDP)BZB&MtilW{gKksijR!_HInpH{AJkkEcjBJmgLn#RZGZJ>V=(VTSZCVtncs0-^XPBE^cWa9D#f3F4~wN?_kdHa0_O zFy1LvU+ajgKw$g<76XCF+aKmLCZ7OAj1Po1n>U0$?}QhO*yp9!ZI3LapZw-T#&%nz z`^jUj6WDk4AN&`DCuB8Nf%2EoS%!Ard#_y$jweb23Y}^UD=cjl%|ZjGtqq=50a=Ef zUm1N2&wD*Bz~wlmJnkz5An1zU?p>zrXuS%vz4y|F)=X!e?X@SiUR=k+I&8Evv%OK9 z#9CuyP^hnI2$h0T!C<23jLWV9kxdQnHn?*n%Z&vfHcknu#cEyk4g-h8?&s*)tG%Yo zsf^{ZV@>qvI9fzk%c@@A8=pyotoy2+DvV7Zdc4r_MxoPRJI$P zfyj8xHTs#m;3z5BA(sWOw(6~IaLP{G@a>9nDYc}4VbhM?0SkI*)aci@D{CM=tK8&g zRimjTP7DTyj+pzD(>5&8^Rw6zV)&)^2~__`Y&>Md&4=Y0XG?*}CvGe+^t63Gfamco z;pHlWmb2pZdL-`od2e~Oq66<5FuiwuLI{97w7y#nVqb;n=ej!@UyeDKzR3*blOi^@ zqami%Xzz%{d3bPJwt|buz>{A4=84*}D&=9(0hi2zgmz9N0l%kE^Y&J7dn;dm-}zaU z*qGte!02thP2veyVk=16VK_!C6n?-L^rB+T4qxkQthVj$1y6Ly!>9D zeCj+Ex5L6Q{Y8@sp|*Wfp=pttJ^P=@JjSB22(`;CYF9>lx6AXP2V0dfn9ejYX~)v@ zw^K6l2}^5$S;X2(8NMqI$4%I!u19{N*yCnp^3 zNrthPlTY6!GgF6upr%1&a*W}~9v5LaP5Jd`(HEBKjKvziSwI_**~hA~VFDVQ5a$$B zOZ}y`ajhk4KV2Gkr#7=r>O~ceZ+U@b6I{cE!oi=(Az5ZJ9GUNGEoS%3fy@BI+fXDl zv&=8k&vFE@VM$V@J~IsKxcl=`e?2>%@zM~6m`Zw{p2-o+QvKKiFB)e5C_x#+>y9aO zGBpzhOHG`EG-+r-l4`DE$AigvkBr)jf5O90RAzMVdeD;fU%EUKw!-`qEZR3%nwOtc z2kG7yN7qg!D0=uGYsN>&r~a)`>+G7nf)pEquD9MNo|vc&jUnYOll{yhNX(qmSQMrs zGOcL0-$##$%s7jE57;o##qz_YwGJO}GgxBDY{LnEL+60LcI=;=#llFb>ZaLL^X`p1 zmisTYj1hLgVe_{3K=uSykg3g(IZtrZ<=7i)7=t-J!la#9pt{&QO$F?5tx>(^6BcAb znE0?*s~m7SI{Dn^5rLy8UPJc$N=M|MpkR6%L2&eU4M}*aL`v$6x;?XZrBv0IkHYnb zCwkWvw8K+Xh6*n}%rV$zMa0Ijh@~abnV`pn|FwSjf0Rcklxp}JO1}Jv`-j4=LUQ?2 zx02g1qBuytl3x|>u;*Vwva?}jPO(HN-WR{F0OfbNySJ~w4~5182u!23mO?F_jXXS@ z8Pft4#0CkOI{EgLs{Vasd;*ZNA0_v%W&7C0MI2gIH}|xY)7rV> z%H&W_aV1=B-eW9U%}$OwTH>4+aQ*5^u8chnEzNB$%tTR3#XYy}oZkNIQxKBz-qnY> zaXzFr$v7=Z?(uE3j9OCkr_7kPg7BsdX;SJ_qqw1(-OF+6Lbn<1-wwNe*g|3&nhFQs zO)n-uQZe_%hR&%BI*(W1wSfml=*ufPu(!Mda1P(CR!SA$^i7I}V*W>J+pd7(G+h+wEk-VzmXK{8^Q!u?Ha9sgi>|mEC>rNys;aGHzL3r zA-Mk*foW%_{88+)>bCM0;s@A8L5ijNFHAf7JVr?`b)VwE`2?iaXqimkO`@E|1H)%b zTiXtY!cTlX6emGS%k{TyB0`E8rypRMmEG%+m}azZ7NsVBhbo=%Cp>5KxM0>2fiQFd z#NQi$Uuw?lZSGv9&jEGUDPUsLkV5;7Lw?ItfE9P{O~Gip|#uMn#Ui;T-h@rMxB2%IsY{tdcWg!`SJ;ko8j-09exLPziogs zFfsjAUX$rRvv!#NJFJ~L74eAWch=6+d#k=qIHP++PysLMMIrF($T?nkA!&C|z6K%N zq4jf^fb7D6rnM7@kUYs?#;dWE>{-xc+7{_BQ)Ks=F5F5JSnQ>}tBe+{cC*)AqfZt1 zjkEjv9gh3U@9C(3Z2{L`W2X^&t0Nbfl!(eN$DCdkaW^C^@M?SC#-1i_;Wq{`~}OT&GZp2 zYPK${Y*>zCDV7nO#*`4*yNFsRk!hQeD_`kU!|IlHyBNvGFwSXl9$M&xY*Y!XC#Z1kC~Q^bu7uaB>5+u&LI35VAlL0_M*BBSaUXd zR0m+kBeWp z&0Vm*UKy#kwuO?ab|seXS|(F`fpBGfAgj9b8+at=Qu>@j{0-&$3}d#8-M6e)vK=dj zEP{lM0?M7@WqK`g1|}6*8@Dg(ro=js1jxQhioV*Owp&n?U;}OD6HAZkt9PlK)bw%U zpr^SVWabu4*PjrTxDg^KrphGtOS(V^tXGqM-bZFXSUy~zQ`M_s7S2W$Tg#A@2PNf)DmHu#NBpp9px$97R@}?e&~29A{L^DCR?+a)cXD zl1pVXhJSJm5FB zQzyeu8MoJ82AN-vm^W7vKryPL)sZu14hPBw8ER&2yqX6NVic6Wlbc_@W}s?Fi#fh$ z&xg8x;Jen0?0L zc6;)G*KzN4v*>7;h87s38D-x^?V#o0STarMc74J|$oY)YL0q8?W7k@8#)Wcs!b3n+ zJUM0S*do80d-^y=29EJnr?6`89gz!dhZ^0)_i%mtR`qjF1X9H6zVa6_Qb}X}^Yn8nqJEW@ zT^#U(%`Hry1V5i98E-CYk_3X00+@*Xyb)N^DiO#!=@(vP23KClPnL+h>m?}`6MkR} zB}n+|KKkBlB}jt3wAS7~@gtqUUfbP$_118WW?vZ3KH8-57MXCmS6I&V|4_kg7%4r| zl%!_UzvG71B0|`v!UqfPk6p zU+|ome(Q@N`@iHl#a2jx^C9$06C%Vda70Qvfl}DaroIaRn$@ap#$Eo-kx!<>+v`*OIh)4oTpP!2g+GGLl3PUe$uz6R~ow7V2$s zqbWkMDo7u8d42VnCw1?aJ4iOz9xoWPr?21#aIuC;s1JJ}9k`&LW7v)j** zm_FWXXOl2qj`~_Yk-pweY9xoY-j}*gwTtpa-|*&=CaSA%7aL2Y1ce(VgDhxSwac#U zg(lQM$#@X6_QP`H_H|MAu5s zGJc~OTvY`Z)N$q7=x|=n%#mbc5;RQjdmDYkzU{lrnK*Sh6=%7KACxPzgbAKx^AkrK zt2F#w)^b7qi|Yo=z!okVap4jwFV(8@Y&uh+vaMMPjOMxF0Uk<+9L1Sn)x0tk0%C{D zfmWe6y&NIIu$g3IKLw+s+!Q6QoSZDhO}3S(H118ji%+k`j{?xZtQ4EbsQfleT+_z7 zz+|h%l1;@uEd$pB#g|#j(Vho90gEyyl7eQ8g2F>zwD9I)kE}EeN~Tgu`FnTP**7E39#CQayCmJ)Skk zR(D4q-l*|&toNbC_&1}6N|q$j#pk$OGuoTMeoY-d*QigYlenjO=sgP~i2}>h2ThmI zOF3Li;`DG95eT-au@Soq6_FIDvjlPh?iH^lwt@LsU+H3lxisMGRQ-w&G^pE|k8Ghz z+rqe7zA#FGw`crh(rUM(*=Gb#o19uszd~4^)ZBIo)!GQJ+sCd$a!b24K>$XC@q*q9 zgPYWm^s*<=va`GXF%Q^e9m!gHQhz6ue{TCQvHnFBW&WoS>wh%4Xa4WBYj{V;Aw=(8 z?%&ZdcBN9D5wwI)1_3m?x$fXQp&gAX$@jND*0IGiruHL>%Z#}GNj62tFZZg^yAZt% zvuFfpDt7PK2THn#0f%czOdEKSyp| z&R3{Gwk?Uxwv^4hs9NP6z9_0b9z4>yU2|=$munH(MYec^N#90Y@kT^&ecu@nA)D(P z;e2Knw3YVW_XZKguH67}vG#FE!^4+0RC-w=iP_)O*_qA-5xVGtTx~tu74%KR5P*iR~`rYOp%Y+VW7d8i_|ys*(l_6*Lu*N%c9fD zs<@s+bcY$snEispT0KIr4}kW(nFl(6fgZ{Caf*VIMB^r7UChLu_7J!RykD)oU zaLcBGJ}U5wqTdVJvCJiN#L_2>!@0B@@t|O}C5#7(C3imn?E1{l3)Lsr#f4^V_4b1u zOW^_{u}&(nV^=T*{PHe~xeR?l@Li*BhKQuFSbtI|iXO9LhzTUYz>ihls<)X3<V$6m0UF5vCg8G*l?-BS<;|dA!Q`1Kj_75rY2+qs@WBwkvV@k zv7x(6h&lfZ>u4;ru^dd@x#V%gYZ*p#aX8_rOEE$_#mj&k@G+$lq^U`1m9w)fs@Qe| z(%Q@qF00$-B#b=2vUss{yOr>)2vob}BWHVwmZ}k8P2&(1={`exu!+q7i^}%CVts9y zj|)w(F7MpjcXz5aYR9fZ>`3Xpu#nP6SyZnD>;f`x6UrK>2A^5{R$L)ydy?R@!Z4yh z2l6ZvGESknI@b@XD1^5wH>?7b8xZOpII3M5i`T70wKV4jU+5_#)^u1yvdkh1mY`I( zzvU`&NYZaH|AL%Q5Kafna2if0BbWc!-0sMgu&tFQGQ5%=9b)OBo8+B@-OVPMDRc^j zF%L(U2s>&f6SyAeJF?SnB%siUwfw|jMHw^hZwfyf3YIJI5|+FIT6JU^Hq4-@z`(cr z320oy#B%OY+G9Dd^Zn#xFMvi0d%foXFe|r~m8%x6VI#z#SGip`Nw8X>-ex0Hi$S;< zgv(mM(RtoW?5+6~{cF0q1AaL19qNj#1@pR~l**46TVTet6Y$<%e+*2J`nv=b@|FdtAQl%C!Yr~iUk=hD zNwy`V*LgIgAELzS7vC#H#`O2bB&c*%C^aB57N97b%+T+r_!W3xeVL;_ezudZfy-rt zMySK5ulf<#@bOn|zA$KZGFX2Rp}0hy*r_OauI!VmH(j$iPyQ0vM(~<;F?nVig^N#7 zy%&YZK{z_{tz$w#^Clem=*o&H^qO>2k|}hetwW+Ilozd0K#@aKj%-RuD>A6E8URPm z0#qX$Q%>?HO*8#3q)A)@C8M{Pd+)e#BUIYM_Ntt3Byb2>t&KnH>FrOm^P`;PLJ@)4lxfJz`f}lK&@@q1N0mYBN3+}!Ts}khHq|{ogG@;&^Q~d5I}2okKqj6 zgjm^vY3H;NzWfT6G(cc5OpsD20&4SCd5OPZo6{L5tX%4>`uU%h0$z3HNgq`)u{$(k zq#nT}e`-E`I@|&FYTi091Wr|BDHcnWH)cOV41UEqvy&NbZi#Z=I*~Z>L^HMP_M_FN^(e?qa&!f_)q&@agrNkC)^wDqg6A!u;ta4o`NxS0D z`C?-5i_SiDyHpkk?266~GA;t~!a?F27z zMtPf)l09wiBaQjSqa)%>;m_CkIMlj54)Hn}G+%rwp#EtJzk_>#0_S2i{!Xm_gx1VV ze^ohQ{-?m-zjY4T|It>5h4o(v_5URYCO+#o-_Sqmvmi-5oIaAKml(E_JjuIjh>0A0 z4f);F2AygM<6A{15q<%;RKl6KwX->(P!h%eP7nb~?#)%?{E6xewSG z5@)!q$s4n$3;;t^v0M*bkG9ColS|=mBl``9ixR2(Xm(V9a>&bQfncy=NW`C7X+;E_ zqve_uiKc|!+F7MSFsbha_~*~pw|u#Q%v~}zlP(c5MEc3yFpO^>p+fX+I&RlFW#2Y6 z9OsE)`(J-(w)=GenWLz3i`7iL_xV*}@^!WZ>3!RX>=Eq?jU<2h>MG*(+e%`tD}NDO zlB~=?#)Wf=>?h=4OV3>^NR5gk;VlePt%_y&gT%ndK_A zj*o-c`M7WbQv{)c)2?4aR2tnmDuVE!4PVEU)>JIw!+hEIR78kqm3VE$i% z7I76)ALtSKl?V~Ys`hy`yP>TS2b^cfy}$X9U?B&uAVrq;=~NP%{b~h^@KSH5%QA6j zmULZxbJHSC(Bw>$@;n8U1ZRK!^t&@N(VXZCCK0rViPH;*sz5JIepmkworz9k-)(Q{mLPg7>4>oKm-$A;9 z0gZ!Gi>KX-}Xw@$33mmrLaI+rqkeGfQ|(`&5q*}KaZq5Uz(NZK+aI$)Y{$)M7bLHQ{yOW zay)E*a+x34&V)N6FBkT(BaY6@2bD*q@89Rc*-AR`-E?*a3l8}+FRIUa>3-`S&rSD^tO@>N=q5N-geX0a)+@(3ej z^B!n4G`~>HTa~sCqaj}^WNGUs68MM?xk%KuZ$*Gr*`DPh5{7rtA0`W4Cc4NgDr;jz zABy2>MlekukkcO;XpeU>t(qRl5m2ord+nDP-S)S`@-(3@in3)yF80hpTU}$Y+fyYf zfa^)n>5Wm=kBh0!a?i$2;WVmU79c1Xnq*J$MA*Ejhm+7-)+z{md_J;JaD6$oP~b$Z zD^{xqNQ{l0O3oUIS5`_j0r-=`>QKn1!zhYom2EC%C*)WmIFrO_d)o}-mxuy+cnJdL=~d@N^G?zL82pM5`sk3LZufzl$~4zI!X(pmrj^94|b?-YfgUF{TW1cskc* z#=Yqr3RqpZyd_yn$AnPAX({g}`>M6av0NM@`U@%=!weRcL(zbpH zK85p8x4vslg z9lk=B<3kcjv^~<*eUXbK!66LFFec)5%gy-$^kOf_`VTYc-!tRiSc-x9pDZuS|DVO3 zp8kLGAh9t2AIwgczf9TxTP&4Q_ZOB5`8O<8%jj%$J{UnjLb5>0cRD`YAF&Xet-6DN zHb5)Gq24_x4J3{A_T^L_b(VEeV;Wjc@Gm$DK7mSj7`o8)?Iv3vx@`HgzR;GJxC?za zY?1SID|EKQbK4wC$u@+(Xv?>9>(<@XrJJiUy+?IOsKV9nj2Nb?K5`}{=R(<6C{HriU&(_`7joc5+QK@V1EbCz67(CZ1zxnRqxFv01!6Es1VMEP<@U%?_}4WhT`&O;FIL$JY=p5KPgigTic zx7JtidWGv%g|yG_TE*Xhlm4ubqB_06if7!%{7x zoPnVA{?iJ(~iVuJtr@&6Mq!0BBKQroP4mY<5>%b*oh~LjK!uhfPrL+jmJsGg9*XKw*nfZqk%j z%FaTpl#y^YC#J@~;BhtCe@yZd7?crpzAE3^ZrM>&hC>ioj3+Cwvvh742Jxlu@h#8Y z?mja8F)1r^^t_@#J<)r6y5x;uLX$Z3f*4pXT@N1_e*B#+Ko4l$;YYKz|1P>KJzZO? z)=7EAGIqrpG(9xwFuRrRwzXU|wXO3GucI(CW*E1g^69)2qGq>h)7)5@#+b+5t&Ied zqoKHl&;;fyBgt84)h6GJkx|!bM0v88HRCgR64a9i9rXE^$9xRCU zld;1$*%L4duEUnm_gQiXmN!W-T3lOz3wc%=w|<}Zt#_|bFr~YjkGrD0fyDmbIZ2nW zuSHTvGUd^>)~F#Z)xh5ckAb$Il5Z?1W=|VaJAnPqNtvE1q-!5jV=A35+>UEHtINQFPh~ z=8O8-s7IK&BGbO*iNPOU9y`Mq+uQbbv6tGiKC<4j0DPPbf=}(er@?)!k3lC7$M&-U zI1B!z#+3V*)xrWB#>_y-#4r=$9m~vQ=k+Lz>uugw?qq>MYDAfCy_NSPBk1$wF4d75mIWa#9Rxaww)KOqRom%*2P^ zr<`YK%Ah>HHt!yL`zR`xZWs%-W)#5k%O|$3=2noRrdu!tFStnbC0~XN0 zF}Z?kuUm1~-Q+9C>$?Svr|nS5Hrs16sJPYWhQUIlCD06=0;KMn zB9I5o;DrqR3?z@~Jpt`fQ7!Y<4R)M`jcn1lb_ZQRLD!m@;SLlmHwdBwZG5fv*d85D zz$lGo7qhl25Yh`BK;RS6?YfNO8Z4AhzWgJz?NFFveD^rOu=$c+5~O4BqO#d$F{`B+ zIDUXxFO1idq5|H<);%{X@pFkw01jBcN1|~IU%t#j1iRdgf$1_uRRkJlUgCGNl?j;K zd*Uv$(`0R7GWjKYlKCsbl=O+Pkd7Ul)L9N30Aw0jrhXR&TNR6>Kf^(LUIvQoyE36M zC0-fCk_qnVlJd2A-;RzO3EU?Q-7Xj5K0}RVHV{ntS~GdetlqRD@x?Th8dXU1p+FV! zX_UJKFmpr-Khwjj0gC3pv>CCcg5z5xGKSOXeg$RtqqV9+X^jKV-rB*#AK*juMW$IS zCYdgpa_Js1&m~YOxpOa7!q})qRLxP1c*9NvU_@J$T@;AO*d(L$R3^|Im@SE$Xx1op z>{HVYpzP=Om;C+{&gC=Vmr=kY`$AA*LFO(j8I&a$&q!@uYmQy0QrGOyVH@L_-H%7j zvWHku9EmTjn=s{oDj3Z~L_BEBPN+$1P|=aT2jxrx^c)vgDEAXUTDwmbRF43c+VTSB zg<<0;&Th_uj{41X&VDCc)1tdHZTI^Njh2bT-6AhMe}#W{63>s4c)ok)nWCocNQ?=^ zxPS<|c{J%yn4MM;C5^lxspZ)OERKl`5hLqll+<2!iY!|D&8hhI1B`cFDrL0+k)<<* z1zG(GB`QA2#9bGOvT-!Zp(nJuy4n$hnNF1CbCqKc$_teTz{Pk#{j@r|jp-7i8&wn; zsHNlxQvt&U>OQsqguoUe{B);t=Co!2c*U&>J5c7GiZH&hyH@q}wn1r-}x{T~Zy(f7&=_=3JKGNpU7CQC0x591hAAb|J0)@Ksu zC>-cPO~T?@%KNR->+K46ckAtl2K4BH;kOyqo0~Kx)|(iqq!?u`*1`!)<92T?&crl- zb&32~Z%GIQ}3zL{Fz=?&9O6X+nP|#Zu8Y#J!tHssVa~Zs<*b3oK~~Clzrzl z(QFgF{BtU6TPgUU_2K(g>)+P_BCtODZPPPhwQO}pQ z;j_Bo?VY^LXnzb5VsXF-N>D+Nmn>x{&#<7*tw^jM@)l68PQa+kEXfo_0BE?FMRCxW zBVk$L@azYkuUFM<0T%ytS)N|ekWnke0Puymdzis4dR3NIvXs(lSZmp{6S+z`axtOv zJ-E6c99Hj^@4=bUhEI4sCcrmob|!#Z)-OweG@I0907&fV4S)lc z6I)DSB;STJLhJcMD{*^&_2%G|O2_011t=RtQfYxiJx*g7lv;bz-_4I}&tVx6<#;xd zczOlRve-M|%4+(y=bh)( zlgY08npbmg9tI8oI?zp0yg88&kY5den70>$tRZHO1K}sAH{o8o(CPis>NY?Ti$QKw&&idev-L%woo?IsaWdwKR|X#302$6k62Pxf2Ntw6y*+LU#qSZr-C^= zSDd&HWl*lHXPvGL7PLZzY136z(VHhnI8{!}?pTW_dv$5Cz{NKfzowcgYmdw4PS1{G zRCslN%?=3c|Bw=F>-?qrYr}a8AQYi%Gy)8H$0WBv$Xj?FDw!I;wOvcQsz#+R%981| zsw>+fy4k_jQL3a-_Ja9QG5ZpevIM@fNdWzqdHf@?Crp!AWI1(7#6Fjw)JCq|HNa1> z;mYsGlHbha5wX9KZ_wyUaVyZBEflRZqKoI)MYVpt>aCR6AudL?=KD02&Kda1GYj#t z3rYFtP=3NZsJUjZ_yIhmTIG?EEUx%o-DZc)fWffJdr4uf_wqCyA2>y-Ur6_Mj>+==`evLX0yjQ!dxwmSn`N2 zM4bi&?|EL7cwPrF&-Fy&Ohna?0MXzy?W)eW!zPY>EBURiE&xHS-n!Y(efFT`neUha z@%6~@%O+BxMb*rG#}E5=vGw8r91y(y=kq3mxWeZ%%IQyCrVsY~Oxm z<;P&|lds#C@q;cmex=9~zYhe8Dd@dU&!bqXj=lW^PFl&Mypf-QjMbH+eyluT>Y2m? z9Hg;9%^;XUwOZjl8Ccqr&PMdK{)=V^q~npBMN!80ycc??yQ$dc!wud8eK_~2<7lBI z&ntZ(Dt)f7DS5Cy4z_)Sc+DYSG}j)PjG|+Cl@=*zCh0 za(T5?kAR4EaRm?LmZTpLcbqd)Z(kQ9nSc2M-O#UCR_DYph!|WHukApU-$j+lIFDj& zduDc`=5QrJVs1o{C}R{o8H8TaH93k}Pvx4KP6iy>i=x^-Uxsw3PIO;f<%Yv}WadLZ z?Hz24PH-ZSb8!6Zdvk17-J2k;nV>ATXF|i{Khkh?AT$>xi=}6hqn->uVRA{a4@owihp$aR?RkhpNW)u81Bh2!0UUkPBCoBibx{0mN_qnRv|R8;5L{cLg-QY$6Lf zO=}2fG{LNqNt9rB9rEPi+e{WPg2PL2 zd$5Y7xgx$0+>jkCz%P{aDz_I+4M%ds)>kFi51iLg94bcZU3D8hKWAF!Bv(WCcL}q& zAOkxsglG|Nl^Pc)w^-b$yTzD8;JM(tfVQCwJd#*hfZu_MH$CD00}TFqsr#F%WTpG( zZV&7KPVb1=+BgXrI~qEe+d0`f(EfEQqi=0YE5iTRi&ECk*hbOa+Q8Q8o4v8pH+95g z`abyXBp_hxrb$iD%8p0PNY8-xSFI5|c6wHAT5%_RtM3R?8&fM|JUS>^en&%N8z($g zc6KP*zwYzb2{i-VcZ;CDotUw?shQLF|5%`C6`hQ&Rq)up8~(byh`E(91K!^&xB}Go zdi;+yo%LU+*8lchWcbct`Q6>g_S! z;p#v7Ge>aR-f1tc(~!{fpV!u)r|?M0Tas*zYBFBFU+?cih?3~c0KU@Q4T!SF;WQ_8 z>-opE8Cg$YOEDc;%r&UC#XK z?tHqRibN%TFo}(YB%Ib2R;HA98sEvac@{{K>Asr}UxbKNo#I$zD-41^Yb!^T$vt=h zQyto#{wEFi-<=`;da$&L&IV5IcE+?y4$j7ZyGRJ=I~xDp@}ER*?%?PoXr}M*mnfz5 z|NEE$idNO!$jQu6laYn_TeM7g%-^0r+W#fFe<~B+-^%t)VJq1x+nE0)6uiI1_wNGz z2V3(`Vutl^FQWe-)BiEjzDsT~{hO7x(CO}lHIz-Jv$#3W{dB*ZqNT3o`^?)!9yuKtJa>cn4Ek@ z5U?c(vOZ(k#_RCe+zGrF4+_%No$dIuhPi)5B`Wr081&o@vuxF7a2*^U4WTYW*m&_7 zom!**^^!t41#!{-bIoi60zL4jCWu?eD_Q%^8m5g2_RCj*sTo}4vXw^5;bL^pO4JN| zXDnEawxi>f{3R=wfNl?H&cWG|mgmcrFK1ckktjUkSE1|t18b$|tawm2E8n>18|~G{ z{8_HajyvwXKFhv->*zFucn%jMRmmUFDj8e4j7gNt%|A|U#Iegqa3F&9h%rKjH$uww z9LkB+Q$}YP4ll#ShXNCgODBvG7VDEP_g_!BhdiyQ1@Id_kKd1t{e`ntw(sL+Fkq}9 zqe9+jw|p$I5}V>n@<4K7rSNI?S1IlXV78EQDewo%dS3QwDQcUX{_Rf)&Kd4R(YzF#rb68O z!e@+55Mw;<*s?zI=iBNr`F#=P#1Yc%z>=#x-ksxpA0{{jTzpE2JnQ4L(U58Z-b}6^ z+|dP1$M#-7K0(M!!7uh5Hg@(G%`iBEw)(!yJOwqIZOvl~Eca?|kJxZ=y!_e6osGm2 zNfnfADfG-60iPjLoM^Uu#77^Rb#g+`0RE-Re`WYxH+*qyaDQ@aGwzM;6*JL5#}M>b z6lzMeVs?4PRi9-`xMXI#4)Ey4^;*&H1L#Zm4(GlKcr&cIf9n-?a%=C{+zDj)56AFS ztA6taS$GQnD$PBa*O$5zkn4^OSA?z!?xGQCL}HBi(LOFIsXX&(0M4Z_?EvfV9jXO? z+FJcbFq+ZLyfWM#7?D;S?f{uQT|Qo)A9tUw_w3anXRec~>DGyqB)Mtt!1uzD0;TBM zQ7Q$}W{mBS-f$`p$WG87q@Mw^{8KHhs?3_qC8SrOZPA74GfzWuo{)`QKUGcuF#ON7 z(S9LM&_$SdA#{V-_I6wcx`Fh>ZkxJ^=)b1%)(xCvp7%ILV@w(SXxtazf3^Xs;=|Mj z?S^Xb=8bxSyr=NM=CsEu(HFYvf6JwxPgA$^&UKG`q4q@Wh~%tj^W5DZ%q8tk!x94G zTh&Sn#hiuHNBNAG$! zNqrVN*S-e;#{l=#m$Zk5vlZ)e04>jzf%7-4T{as9MYv_IDVeFgcT9m~I$5;}@4NFA zw+FYUXIs*lAXkIM!N8xivhVf|FZ(FRzR@u6kW}YyQ~IooUiF zi{2zY(`ilrDYWYfHQ!~3U)9$*mq#|)MsqErZZuh@Ee+oZuEVk-+>=FX|{Yx-2J zKrG`lgJ_zoIwz*#{5eK*?B>*Gn0K&u<_GwQ9kW)5^EfkU_`d$@Ye|y|^fCJ;_mg@%$a974V z{PQ2-7mHRS6MDmLCgh$lp15ze8I;%ND#Ja)f#=ERi;3H&M|8Ojnb!`7#8@VR87PlX zPP7?=vh+QMzv+DUv)stMo#VZ%%31NnJw^4TI8j^HB~}xW+rjxB9l| zUw|xT&--vK9_f1c7+e$T3gPrsZB20kQhk1Fjhzc=YsuV!wj&;Xh)+$?Z8N5M+A+Ve zw19v3N7H=;%kF^#T4Ig-XeDz*SL~Gq9L65uX9{_fqx~dNxVd`<<_e(m3Gl|EHHxa$ z7>I&o1w7&WP4R5465B40YoBGmD|5)y5cNUt8!%-Et+u;8qcXWm)qb$yC7pMs2hPX0sFr8x*Y* z+&JAfUy}s<+N1X^62Oxs}d!4^8neL#+`ddq#m{jVskfu<9q2TobWq*2lv{J)X4Xx zoONx(IBtSYYlGWzGcv$Y_|uNr<&W+}dG8K(ekWstqqhZ4S`&bv1Ic88KQp*Io16%j z@1oWrNph985w0TZ<9e&m2uPjo1$2FNI0jsbV7=_bIKfO#1J3s7>;-*1YkMuzyM8xQ z1Bg3R8}tdX9GmyW$TVHZf2r!n8JYMb(;b*ahpV5K-^3>@n{PR*tG9JnS6HgQOJMS~ zkJXGywh(%}J2pZps20m2qXV4wG;%D@58P@B0LmN-bbh&Ctye#@P2}(gdS9n}H8PIF zaaEy-&CuhlF-5>p(U50ZPB(RGq1aMkajaa33ne-TnH>rG*;^-e--Z30rNWFpGYYIr zhVmLC#+a@=9XoxV5N^aXq|MD}tCPt+rqVx(`N;SldLoYbsGnoN0j`QfS4}ZEL-pO3 zdC@`oK}(uyysDI0n{Ya2bYR3(cpstjc9%xX*IK1W69=d8M3{+NXr4rj5~>q#I)&wT zLa2Q#m#5qB!|1>UPZNH}H<;H)vA2U)Cz!PwR=zoaGJV$~S6-LtUZ%cQ)0T77xFwKm zj7JfZDV#?klXx8HhPqYDB{)}|4Q9_2S^4&P=7CmkZKDgih)JyGA~WO#8D7T87Puex zjJL@~OlBpWJtj`qTL=hM7vkv4qDwVxjh1QJ^U~e=(tWO`FdZ#93Ef^n!`2tt>(jIk zb%71PD2;E~*jlx5wp{I(Uw%PBc68)N>yxmQnA*X5J?o_P#}G4kMYdIRSfXu%;wFu; zji!wkc5pFd?%!(>!<`W@5@Leaocagfz`_O73@i|=Ps!_izskPQgy7I{ul zeffZ6bQ(=G;3z+8sU=je(rQf1w{KgO5k(c>{Y=fJEF{;+F5;kJXRS%QCu6|v)mPIY z6_jl!per^()Y^&yTV@tye*TViwshmJ97!H%f6U>p1HBc#{j4P+5!vtSAyoSsT`565 ztSsBVroXugBZ5rI0%ju1m4GWz7+72c;R|w6lRw^re$A3yw!+a5A?zxEMv%fi4QkV# z-%RiyQ$?!plkfeSd(VPuRt=Eo~-C1doM%zdXTAw^eNvv&lb0XzWM>=%z&^!o&|}2u z`}`zue0O@PSbB|(-B)1|GXT^FW?lhkRv!o%)sZc@uk9_MO_bZO9Pw299YuhP!bgqR8xl zMsz*QK^B*+{z5g_T9LXW-TpA}^mU92A4=ofR5{$nElml;Cs6kCzD3#s*@yuArNpb? z4qS1%kkTnbeW-eNt+UCx{PQ(k2R_V%h+Mz4fbF)@6qEd!1VIdaz~62)MlX>F~! z{vF;rRa&$Orq-Mpjufk-!b)CF#xQ}jXhfi|yj56PS8clx;uVFMBEXZ0_!#7+7Je+i zQ-N5gjt*u?3}@KFIKicn)@F`=pym!-5)IahX1c3$crpuhCaIq6tdqsx^Tpj%c`gPRAe zZ~#f_?yQbDtmlDw>aU6aGb>D#zKr)f3KSe@|10UKsY zBa)JV;f1s*g-aM{wn#;CL=A`5mPz0^B4Js}>6(TRz0K0-c9LHK7_o<2Oec6ycY&?! zQULJP!H)$gPZ}fv(VW1XgqAd)!W$g1#GEqj`5dndCfv8&<5mRmJo)bOMgm8n_cPOR9 zfg>58C779r9}3tppE!+l9F^Gn1-k-a`s7hwM|xR~%3M(iS)#wbw_R3LF-@ent^QHz zqPunXh?2$RA?F?U%htP`PU2y$#60jdQ`S-F9qH|)9nKTquvrd_nf6$oaS*5$ybMX; zEU3OUgP9IIBvD{I!cygu$SLBY^{U<`6>r1>>kNV@AwuL(rE5n)e;f*&Wu5SP#b$-K zOek1s#~I zEDHl$d76WZe5`VWoBSaB*}3BNVmbs%ew^K&z9Y=_6IP{}?DSLBEXQrl!mQRTX=fZH z#q5U*>H<2x{Q=nICg;g92URUnR_X}1&xNx>8}(@0PL|sjKm8LZcOpfOsz)SovyYmD zJoR(gNxl-z4|GI$xO7%c>-;Q$+2G_Vjp!6+SUE1#3`@j0H$hzjgdwii$8-pK;lk%B zHj`Zfn}>HD>p>Pq~ba6obx~8r2EJ^9pUm?-x0D`DXm?^9S~^JL(m_e={j(mbZrVJj$?{_~i}g^vMBA2~ z*XeU{jDyzoc}pk+;k`_Q5VNk1Ydx?V zN`wuS&>QF*5~c3M#5G z3)wX!1E`Gh1JDTp!aGctgJ~c{R_@<&!I>!w*z;8$4uwmHTSKzQ6N`zU)Slf)-2kUW z-^_jiH$;r+WcC*;)}rB04gJ}aZnx&!%m)k)%~3$BcL4Db!~GIRARzh_!Vf3PAvDgH zbH0@n3wV?-c6)a_!NR#O%QO;cUSNDcNtUN>aSYIiR#n}TV<02$Uox8Ub|s3BTi@*) zr1~!LtchJ8#%|6R>I{nDm!AnrBI|IbdZ%_kuZvkeyf}&h6D+`h6BlX(Hdeqz6+2F9 z6upt?b>7ZUBV^VBF|qAiUXz<(YhUSG38LpG-V)~)W844XR|tTS1;U@4jwUeCGbqk? zocVh|!tKw4X2#(`K|HcdCS!I}rpfO#u_;K;dkn=vOo`*VMDN2RUfUXRrr$0^w3%r= zbbt_Kr-+10GMzTtPQ3gAy^+6jxQ1{5-RklH3@iDfw)OYN$}yvjlA}d{eu&KK`OQoq zkl_at<*$j8h*sENrY+$O!~ZHXbgGJ-2L<GO^y@3rwji*lPti*yXsNUlQ}KAGJvgBfYN{?%tkC zq@W1kd2*d3IJvlA(k9XP%80-YQ>*d*EFWKSdlc2l70X5}q%L$LT#IYj5@tH)OVw-D zVO4XcHmd~dYtyewL<;}=($n{Xrk%ib$i(h#IXr6r6PND8wC$$LU z5E~?cGF}g-Q?}NgmS-WF+gb@d9*0}&%U%!TZRd=h&AfNX4ZyLN@2NGPd&SMWIhsBk zH|ySC-+gd^EE`BhEmJd-dc zdbRt+3vr8L!jslHeQ*TY2f=LdS9|OCm3?giD*SQqAn<{i4DIAwo#h8XxQmkH4r-P^OAD9AD=ZS zH?bq~va(LMEH~R0z7c`G8Flu6?8mkR;x_4%yPMA0-F%Vf~ETq|hxG9MT`(dc&8F1CCu|6{3QoyPbPsj55Vh|2wv z?XE*V_cjE+oqg6K@~Sg(HFZi&we>uo`vFx-4ZPx*6ZPI)L0!{!@JjlVlRkKhh&?88E zB43dMGNi~D4H?jcXgKpZcsIu&H^gf zVMGLLpcY8}3#wK4A7-N0R*Ti(tq*R;Zj&B?TY7S2D;cwN!zde(PrEI2q2WS^4ep(I zB`#~B=aT>+-*Kz8ZVtg?z$mnze6_Pb+R%rv|Jy zhZdT!gOksJ_pZ)=$-RvCPF{L~UtczR;KoGra?Px^#v#yH7#IK)Is%BG0tBmGZ^N0f zYxygt->A$~)WloE8nV_|rv08%813bvPQr1hB zDd078l6Irfp`pI3iMbc!{+v?i@ttwW^&aIQ;tuic<@)K4(i7!N@IH7K{+RS7dy7tW zGYPZ~wf=iX#vRXrgFwyr-LTh=VIzMm5nK)+y4G=_vUCT>m`^{BfPz7}=AJ@uoX1!V zUn3=P+oXmhEEWh~6I!d~ZbmDQ|QVt;44LnkLkz+?QNV@4^KaFRRctENXwBbFkVnlg{ zpLZU=v-eB=(13{_je3};{k)86LS;U<{uTO(e23c|I@N(P#AttXC}-EVcJ;Xv`M5?+ z_o{+-4m9Hg48?diQR@sM3_d z=Mo3LCH+fcM3Nwk2zf&dHk=A5>wuoXS_WS%(TdPbDj(ncNKaIhcy>uerZlIR#3x+> z#S?crE*7XEF9?(qeao~wx3g?sn2>}5ArmbCRvIZgAwKzmeGVyyh#g5*LV?L4hoNMW zj&GZnO@~XSRhohl{yS3wS%han*KGcA_wh-oNQ{dJdNPQ-K=|32Ba@8{`N)YCd(5C& z<&sAyJ2`qIEktGl|9U`J!gb>qzj4Z}VIy3h927)wbiigYE&&j{q+bQMEWx6}WP@s; z+z!1kF|%@VHD2fo zuA9(X{Z^0wdtQB>o`tce~CRsRm+pzEp^{K-eA#eq7d_H)J)|qUa#k?$F~7 zJ?U$SAbVFClwCC_oDuZGRPBlq$onDtn<*F&#yquX{7|6~wyBY}Z;2QYn=`0eFqY?) zOY8PIk5VI4A&$kw>pzblh>hv#-*DS3{3-8s*d1=WM+vsFKD{;Jt&^%yS_au-D}-r-BZ6;MQiiclsWq9Dd0w}VmslCe5dc8acgl%D$8RQCrL~&8zSAq zzqhI4UMLHVx$^H0yBm*{&Q^q-K2hbJVf8g3S7~FOk`V?SJDi@0H#Ipz^o|$EDe0~j z5P_rs2vaJsIv4Ml;gVc4HCrMxG-J~t1MoF+5sN9PCn?;6ZiVhff5Z>hZ@?k)5|RO& zN}nrMOy>+*)^;AXKX~rZe+OFdzVf^D8GfbtFY7cI#GqP|bcg*(f7X=UdR&S27S-|e zG#d!H!p>mZq+0q_R)e_<3xz=vBc!GSh@jgL8Yj!VC#6^yZr=ZumD=BW198VBA)u=8 zi_0JAHN^zqqBq(?e#-WGd*7Gst?1tA@#TE1)1|E>^$NM!yyXP!8Bjmf1y!#ljy5mI z5MNg!+^meKM0xTs?so|?gpQn8Odg$7*b}7B?8r{ossSWZo~U9I8Fg{`J;a@)a#@); zz061<;P!}*FJFbHM#Vuc4b(aa7-T`MnqGcY?1IeN(&1W(r9!?Fm`>O5TjRN+H}0$2 zcEWEjTOZw=DZ+TtXPqLcXt8t*daOtV8Bz(x!UZgZ%|uRj5Ze+kHUstiL*%-9b@Own zlZ9u~G6l$MWOe5o#T7Sr=_J1^OHd=|EL?Ttof>`zz?5n%RVrO#D`g1bU}{v-Fp2!u z$nvyIjFtMP;;6x}x?!CBBsAXW3R|)LXSGSIX6<^bUG2K^m%=kv6VpcJ&F7)qhSj9= zN0C$$_7dVhR;4xVS_4tOSY=)M1s2)73e2<341ZD>8EvxNI1W)3ovpU5`^r}aYpO4u zG)5zQ#@W+54>|na0xbBU?Rw%~U<>U#y39agaSg7FxUx)wX1Ocg|9~q{IM1dFn-0@v zc)wJ}%7LjRs{pJb4kK_T=DP8E{W@$9AF+28o*w-~o%s+kQ4KDHW>OpzUC?|;IzA(| z_>AvF?*Di}`op8Hq9Uo3Nj4OYOfJN*D?yVhW*AI(Di++FUsQI;DP4r0keQ<(U0jls z9QUl$6t_Iz*u?~f-YE@NkWgiH!LMvbDhJyNBB`_3*YP5fR10RoR!}x>6h`8Q;YYI| zhX`ui1xVa2r@We6=*6ECay=vji$N@{@zX=%;$dN-uw+4pc9tsKM0}Vb-qxlc zYD&edS)d{L9!WQjBmjxrZ%}<4wP=1y`l|*EH#fsvrQ+_@gn&og;M+dDlVfDv;9B!4 zNSD58ZD=cLOEoH+QdiF@5|iJI!+|@i6W*@auJDzdJ}DDR7LjOVNxGDJD)OA);PW7xf-a$7y)HcYX-=~_ zuf%el^tlbg1zV$AcwpGws=Ie%$bW_mq)38euy=As+EEj$;Z_;_mCJ$?VKII4^Pr1u zNS12N$#Y$}i>E_9SDDm=ZP9}pGb6dG!@|FT&a}YTV-WwFUNRkyvd(xLUbe~ZdRKS| z{mH9?FS#&Bs1sz$?WRuB;@0o0ZcT>Kbe5UgFh9`_T=15`%RYPwKwgO>ZF(d-rYCIS zPNVSAIZwJU+$fZbQD{aP5(T65LxP1bFjC1pjUj^t-Z?GN&lk9AT@K!is>l*@DcSj2 z!WtOLVJySycj;-^p$ZI$m>Dq(aoq6&UKxngI18jClWGAo5j_f$h9z4$F(=r&1Nx+& zG7jm^gUczKRl*)})hZd^F8$3#y|DPE(KQ?kT{Cg?3P~sw@DQm}=tCv7aR>6|njPz! z`AYf`FpFxW8Wx!Y$CtpAfKM|QXJ@T2^(BPag9*RLpO;oa-fcSG?b(Gb2H#hx0k8q> zcFqS^3@S-&*VZ&Sd*}F*S(ZF4OKXN~Pn@^7_+xdrGpJz-!9Fqe*_2MRb0!7~5N;8b z;#m_yQ>)}Ky;LS76v>KT(ukSy&Eiq_i*aFNVGUIll)wX*(r^IAV*{NC2y^4;7NYZP zn?D6%NDApw1H*YGpG*ht+<+qr&|V7K{0#C}_^il=%j)LoP4Get3CfT>bIe7*OA%jT zQLu%7;vY{Soq{ZC#Rbdg^XUl#=Azh<*7{s9u1%{$hnc)gs!3pxg2@SFj$?$VtkBhp z{*KC}2siZZwI`v@96YNciwS& zdb(~?=wY%T%BttN>|X$r+HOxC{2Csn0Zs@S#s%p>9uAxNL%KdatP~fQF5$Syf)0rY zJx#jx17xi$BmgI+zAR$UBkTeG3~wn}cboC)ZwO^;co9_g#*FcDMBD`aQt z=lqPJh7?xX&O42YqsNN1Gn36uuJ*kMyVl}g%{-|(JW0?~Qk%>-uh{cg0cA}ued^o2 zzf@$UW%ai#cF~!<4Pf6eS6=34ycVW-ineSVoq3S9H%EbZw1%vzw>pFP7rm%`$7Iqe zS*UfI%1(yeuFADHXr{0)Ie%%t^r5>>ZY|nB?b^2YkYDI<^<&RsIpHShOm}V3x1SD{ zCsxSR+`1c^2Bx_(g{YY0EYp}#y~agaE1^8cm3&C@DrawA&X@zTS&K6cU@fmkYkl-B5!{sBqJR5*3lv2Oncp;>~#{o@`T?(!ZQK=cdf&K6Jb zWJS0XIpV%^rwvV4OVLpMo*+|L9Vw{R52a3B54qk=(M8q8Hf2fzCBE!g$LKCt!$pr= zM`G9nXc8hk7aIwi=|;2NG!+qGKGUz1COWv>4jH|1;$rHeyg#zSqe7%YM#)~;M4`bV zqN9`mMGlj{O__DPqP}85`AzRPbH!+dPau8Ec;{IkyBqB0h2yCaYICcHwr!glYTQ-* z!Gdw4MtX$wrf^uHw<`kbS-lnMgi}3Q9RUKQJ_WZwR&>6yi^LT_;&eQHy=t|VGtzbx zQss6JaBJiAcntrCAF!DL)uOM2)PuJOuEK|5QL8K$=&nmyE?QxDaaj-BXFQwADP@G= zU;_l(hEM!L=yM1|?CWQ8Xg1-Q<|s4ug`Wxp75 zh^KD$jKh(AI=zJRhQJrS=V$ucK^ZR9;%t@DUC>*n(6uUXb(7jwVpE7{Q)aDPJ8!>!Z9|;6%-zt2zt$Q8WFObJbJ3EuKRDGhRGUW@j`Fn#e{W5 zW`i?z8jGwD2@h9DUQu8LL0c*eFb3XVWUsSy+i#z{IX!g5)75nbG!$5waXp=uHZtN8 z9-cnEJj~~nW4&%}wXwl0b=0yYk!v0MUe()v2V0u5N_pjsHCOun*-?aPv;BhAO?nr3 z;vP|gsd4mt!0^$z>eUzR+^HQ08nJLH-jaM>+UzOlmQOHXbUqVs&L1_Ne4NsJs!Ut$ z`HtgFH?_4qjxa7{Y@V8E)53zo8tWfZJV$gvW0&*mavoRZJ9A)*kN3l3m>-ow|Ixts z$}p_O8mMkaPXUQ{BHexo14s2M&(hZqV(Z6AZ@M;}t5 zca}$SQcSW$na7&yF?o}`n^ncHgc9%vwk>03oK?7@NnN|LPl2#|iS2H@l3yW5@XWEw z2WF26r)ycUPsi=&sckA9suC5QKqk(edGi>|zhB;A4|RMx?BzNsue}e+PvSnT54|U9 zh8QP(>s&NrX9_QZXD?>DsNNSGG-e#s=r+e{ISlsp{0nHz7N+zMPf3of3Fs6^O*M0(t^h5fe5Ynf2;HNd}`=i<%V3D0UBvh|i zgRWZ~u^j0fh06Rsx&KHQs0|>6WrM=P-*Z9iD*4@jJc^}zI$$Im#M)F%q1(6HpQ*L3 z)d7H=W6uT_X1O1iGG^gw&bv@w&}`+0v6QoLyM~*QjkU(V6Hz5^t=?d9$<#1Pm0`^2 zxfV6Gzzlsj=k@zF2Z+Ud)(tlqJIn_fUb8&l5aRKyr5_QHw|)%rT`Xc0%`~i*f3OhI z!iMA+fDS8`Zs6Wo5iFt|9Rb811TqLi1WJTio9=%BOhB{0!A&e|2dWA}IU<_h1HST; zuUuAn(wCp~o0>5%;AFbHyX`zh7ftSprrt(0K{17D5W@Vg z@%r`KSKgHlIe+%8NB{hvhrj*W_;&n+M)a&}Tyh69?ado*Sa-8y$L}zH|Ib)> z(Ps5Fz?thOPciQR-%-cqD!V(;KqZX^l}H&3raE~{b@JHa^J)`DlAlm4M9EIdEM&jb zlX6R)piNj5&X&^PEgF1{25Vv&jB&N#xhaU(1#vJYdvTAq*UNZqu&ZI8jFn0mh#@Kw z!#3H~AT}I-`?&aa>Ovp1dc~5^a@DS&tyaTS*9qljJhl!EzFPAY4Wo%w3$ucFeei}L z6O7pmnDp>(s+Vk4i>0C7t2I*}%Y=H{joq-c@U|U<;#Xbw=K= zulZ^C^@!Hbx*RsYE8t1`YIf^(>mQcC5&1^cU`v^*Y8KQiZdl!LbMoezyUkBTo@w}) z{m5@jYU_gN1ty3?ID;8Hf>Q_33$-KIt6Hn2pyvf&&>Qk%(JRBukwVW4E>ak_*`g7X zfwLrNqzU4mpxR7z9YSPMyL2#2H^GLcMl zXU)UWhif#YZo*txt7K0>SLG>SRbOD>_LWhBm)eW;g<8m}p*P5^V$fDJ%On6s1h5E= zJcVc(u|~=fNVOjywijw7d$}!Jxh)GYVyX>3VJpR<}C97_1jZpMMcp0~Q%5n$-R>a!iDswmSXktptBIt`5QsOsV zI%l~YT7CZ;FWk8F8pY{0DT;s3+Sx1CO#C*Te)ubmiyEw=&B#78@zZZywIJPGm8_k+ z?t8cH4(h#l?!EV2T$p{?P)lJ&-?!WrvjjNI3Ovdf`v8)em&-Wpuug}(Hr_#8x~*`_ za5L=h_k-+EBuczu2IeL6CF4*h>2*G>P8U|-J%fWfXgln@wVJvU+IWWMFqoHVLMH7T zPks4UW_L3m92co)j;gaQ(RWF!JgkRUiw*fOS&KE!yu;)0Ms#7lVwG)CN%qLz7F|K# zVk<~_Pm6bfcD`G>y;q0B)S}muqj9RP90!x-c<$VCoJf@8NTeKFtu$6uk3VM# z--7yaKhvwZMZQgQmvvWI*P_kob5gyagoC#%ytbUMAy>y7HPkfMhlIV~V2yA6;B;=LY&G=c-FZM7bY`lx=d z{;>XSy+(hl&PNm=qRMCXX^&`su4T2i>O41ki4sRfI_R&(meW-PArc>`&y(mmV;<>7 zb&PHVzjRm(k!{X@qAz>9tM5S2a4T#%D3KI_DkY09~ia_2!ehy+?)If}& zCt;MTXe#W0jI^TKM ztu=&mIF)lm{1eY7CyuzPLe_frfmmFQWG8sW)EqGDEQVN&vj*p!{R^vU%!oQI?3U>W zF&52z$ceu`Wr=rBepa@`JB&OQDo#n%>lah6Uu-0bX2KO1iAOETGEN!Wjf7>VexM*h zAEK_HnipWdY2g--o&CLPusf(m9b^W9n5a|4m2t|aj%cQjiO0m(&eNMG>{Mg!pw4o3 zcnu+;;$cLU;g~D?98Iagjb%ZcCd%ejVjQfnIjT++t*Leo+vI4u<`lU%5L{3Z=pIWppv|>*woxkGA z&7CL~YrW=>cVgY*;xVZ!>FyRV6mz+lVxq5vy ziHOO8SY7NMz=}ybU23~b702?FHyQCmqlyjcP-&tLXlzx=#+iBVlzW*$@<_EYb7MCz zBBOtUB&8nKKtXI`suiawZQgf&FQQ;HqKXj(-w62Ek z+%-8)orW`7wkm0}%gLbU?y#Nsg-1|AS)2%>S&S`J#d5V`BPKmz1kxvuWUj9Z>4)@8 zkA6V^jGop1S!V16%lTxvlQ>ZgD3~}Ol^u>WN>9rx9aDz|%6?@16funzi8qA%oHqn( z7Ky7QWo6_{UNC86xwtW&jpc=U8D~roH0T;-TxX~~=NLI<1|gabz&32G!P!VD^OV9O zF$I7PuJi03nzD_A93sn=oq`zbjnCb+c<|D`dwPGkps}jnUFevQJxvL_Q;Y_~f#NU@V4RhPw6a+U~4m-Zt^WO_7$a zi>^5GZ+#a@HZ(a|);wsgW8%nJwoRkk0TFmqBU4ncVy&N-VsPjP^DpOHrmvfL3V#dz z6uHq7HPOv)+LvpMQoIvQtg*fsG~O?X$Q-K2Bq zS{mx+T)%q5e$u9O%zz;|P#;%M>sIYc}90kKtzuaWD5vuQ_= zg}#HxftNs%k3vh@WChz&qhkf_Ee0csfJyT&er)#EMm8sE@o~f8}y`QmD z-tF8SXJ@gqjPpEqv3D6Y-{x>8y-gY7hlIV_y}CW(9_w&gC-S1etgc?2V*Fb3!Jzj3 zFg_R*Mp&&HiUjutUjnht8jZPes#C;bwmNCE@>)SJ`Y^Bzmpr>GjngB{X9sX~Y6Od_ zsVa$W7OQx_#e$O*C3HYb~>KUh9q*Z=98G4(63>?e@A2@6Mb@U~ui^ z$Lto(LZslJ+WrF$+q#2S2DfRp@!JCTa$gGwc_yzcW0%P*l&k%lHCz1KnL+QM|NHC{ zx_yz85etf7i)gjkoi4Z5VPaU8I6GNo#UZnttayEXR**OigfHBYMI| z@i*}&bRkZa7KvkGiTF1W*PF3ZsC;}1SbKm%;M@vi%Wl`!rZm8`A@VTgu1C1re))EM zJ9E3tgZx5VZ7K&G3|DiTZ0m!)n%;nh7^kqH2weGa!+E>CqOm267-qLzG_kQ8>mI&q z#hn*lzh&#D+K4xi=~#5*{yjUd{W0b=3x9YxvFDzVs}Bz(nwHf2Q=*dFzwImUw4?>b zLaewpt$oLf2n&0zbCwAUBz2JRXJ?DNF;2{XQ>j1 z@>7n^W7a~UvIqR$pv5W19PyyVzZ`p=5Cp8D<=AKUET5uD#M!wI_m}z_zC5Q)9A9M4 z<`e~9Nx+;VtB8nH*|0q7@+THGFjY8Izb$w^Qot~dODx_J<6KWm-8vo2|aU$x{<*&o+^=Pq=&vz0FQ1~xp01*ah|Vu zFA(IxJ*eF9#YYXxV@^6jS6s6~7LE0Htb63E8}UuT#89kRzJa}(Oim0a-j=gZF9|sv zwKo#^86iFkT;mG%+*$5!>ZQ|7DU!Q#3~<@P?3BeTOT+*&9Fn72$Z)eMS}Rr8G-s;T zoT*wQM^#9zIc;;>XuUQnUbIp1qHQ5PIJj`?y@gZ$I}4{8SV&H8dq~}ddeY3o6n#BK zUr#kr4+xUcB$C&fi06WVyw^m}OEgjEAyT!8q2=^!e$xf#8i~2Na`qxy;elT%w;@+o z&Sv~tHIS+@GsPo=WJB0ymnTy{dmdqe<+)3jsiaP38D6|>)3R-VNtg3;>!etXL1?Yf zlux~7h&xfKlsYbskCNY%KM@gC{?BAZKuXcGR8(K5}GslF`5l`2JY z)Efkz(+G3t)MX{NzT55giq@!-m2s~;EHm;5&a0NDWNj+ioNdCrO~Xx06UlQeTG19= zxG=P+a}hJJXlN0G7Kw|PMMUY~aOD>Dbajs~E1y*!+a`_R^>-1^xzxE6B4>y{)2VXQ zTK1+Z(&JA>`nQPCwAPBo^W6W=NTsHHox)M0#T1LgqejJ#&6cn^cD}DuKO!nf!eTTw zm0g|w2ZyK1VNuFs2!i`d>GNE+aGodB1)kLnxO2TNy|H2WEzS-1b~xXc@;C^+tPk;utoAz0z8&1BEh^MYn?nXxAO**s;~fW+rip<&h> zEh{usQ3&vspe+)U_++=uAehUtX89=9mnw}>D&>|1%~4-9*)+atvQd0gqv*AGgUdx0 zrzuFwQlc}>sOf?9532U1xvV#<6swz4i$&F|DvPVoMj)EB90IemTX z`l?;_hwKkIM$^I)I}U?@5fl;?y@pS+1Ve1Zo5W;Tkyto#-Rl{c&In0JsTqpj`4;alD_NZm$5b z6s@wmqwctjs_YQNToD;39OPhMS^bWwBXnPXbBZX_Q(r1bDn7E6Gku7{cN1H2-lKjy zjqKG@!-9!=dvm}ct-5FaUBAGNe=YRHTk>}#))#yCegFDtm$J`%aYa|XKNb@W1puvU z7XR&yPjF0@{n7CZ{!z#B))!wsGTJ~mhnLyQ@!vF8BQIL426P^bkw(-x&|#D6VEuqB zG%Xf)$UQ*xO1S!2(c|;~7*`_&{TrT+$_}$2QC9Z&qVZD|2MHoqf>habp;*~8<>dXB z4Kc65Xg1iq)~Xqy>X!DayQi_2XQt=l`H;mT=vveD{&?Tg&1;Ao`x4;nmuohndc5!m z(odc|U@Q>TsM=~QwCQH+=NLM|+*>-FOg1OgTu<(;+{xU3>jjj$cM4t)cz^_Nz6E3n;gOSK3i2Kq7mlQvnR3`P-^ZFs}Wro81=n}0%|Ig3yk3Q zXGK%8>Uq2oIgpO|57p2q56H|A^`{?U8=f6DV&e!Nf_&mQHq-#TAbn1YjMy5DaDXji}ku%KD!o&Oo6p1^`%<~aaX&I z{(qu=)R#)x&nZaCZXL=wr!m)g?i++5o57TQ%Qm*`zw`SmW*)tDp!fcXKkrzVQ9NGj z&F)zB6%R$cq11yH$&2^SyRGNpjogAA-@Iz^$_Mt;9sbJjZBNWf1ZuRJB5&Ap&Ek&c zKvi2%f7zXjH*9;1z+V`6w7&u8n#HfHA6q1BMq0PoW2yq7znaSmw&{3!rd!&CH%ixL zwnz`*Z)e_+el2~B|16nI64txo=mUXtT7%b3=9z?U3%u?nVz~pG1#k_tg*Azv+Hm8m<3#_xsX``Z4#Pq(6C1 z)_;cn>HhC*Y#yHPo|9RLyWPt(SGjNYye7SxeOG!n`v>U{S+gbN(s(Vg|gjk{pX^H^jQmGGqsE-PdzKrNF7I8Tc3zB3lNFvZ|tyFN2 zOrAL8F1WLfLis=ky+Oc4CFOkSziEoN<`s<3`wva$6=QbJ_!(cUGdoe01v$uJ?pOi{ z`BQuf4`fz=TomifjE`nlL|o&4=WaZ^`PNW%ES8h|+084f0*Tlczv1ZP*}-!KgJ0|< zum!@X<{5ykB3o0YnFp<$Ao+l!J;=8-RmJE5`M6a@&`Ec>4;;X(_<)0Qt+upIgBmcv2y3KFP zh_Wp#M^ja`nap%CYs<>hl*U9hH5Zv|s7-Fmww-9>UQ6Q}(zj&pO6|yS?Wt~Kx5DZo zo``Ekv8}_~p5SecS{$vtTzOP^w3e$d(_zlrrY5cNTE>c$TFw_EQ{nUSUM-mlU%WZa z5IJ}J)mLAwL}U_56rKCjj#@c`(~6uC!&WhDD6?swc@m?8PNu;ZMi9)f(SI}V2 zr}5Y%pC=wBt!A2h&FQcxhH=_~aXM49*(mhO83*|n0g4rIG{E6Pb8{jQXJ8xfyhgjR zh>Iyijw{O`5nqaXa4#Olqxd8~jrDkh`KM}`B`=ZJ%dA|F!u!HZc!c@a!)n`u%GHC! zMX+?HG!DqLH04#_I_1ZQ-34M*-)_G37{n4y{15i8|9fbGUpG1PLah5RGeofhKit>e zbvT2Q;mi!S)J^T{S1RjMn=(CZ95tQy!yX~~%5p{G%4Vioa+!(|(Ntgv!)7-YB9fs{ z3wLCms}Rq+NdD+yS0P;GB92BU54Z{r;z(?un~*8{#~0FCTOlml3eCh~ZYdl1%^_|nQC;qeA zZnV_S!@ny;8&_V!{B`1@gR3cz3bqK zt@X#|PP~rm8mpX6(P_nyWpQ70CDA{10mrZ(I0gw-p|fiBjk?YHo6NWC-j96}<9Qa} z%5LShy6$pwt=cMH!$v$+9-fs~Yq1t6{$V)|qqE=<{IzE#qyhPef7W8c=qOf+j!?B3 zyr^2OX4LAQ>V4HGtGQ}VS?>o$<&*PSyJ{b@@3RYbPm<92@}au3CE$+enYu+|l)wYe zNF3?L`lmcUDy|#`-p4akg$Go>#vjw!0{)<%;jJ-KJf@2PT^D_8kz$5aR3Bf9{Wf_m z3L7CnsnnOGo)UWOG_%4K(?!f6)|@Tc*nrC(on?(5u$AnCcRv38tD{3--}&Z-Ti)Ec z=EeK5<@2k@-?Yu0(=dOtznM`0pBqxxl5HL|95;P?t2@nJl@&FMi@rhb(Xnmsvtl|qSArTB~dYLaj5eI`8Aw)cL&@2~IIN!DKL?DyVhKi1xR?R9Q$J2v$At&d+Z zf(sAe3&$6Z)ohvH^6t#!L-*|dn*=ovvpE;1`UQ*eRR>W5hQr${GRZ{0qtD$}urb=5 zxU)dL-tkoMQ1n;sUlqI+R5>GJA{x$yvXSZ0RAN!2Gt!+HNa$Zg*i{fKs4MuT^H*;E z(I|c?_@@1>;G2=7(GP>F0y$6^)fmY%>&ITV+82OH*y;UQz2*@@h4AxdC5F_d6-B%VpUmS7Xbm~L=kx|N0L>I(Z!Mn&bH zayX%^r?!_QM)A54AK5h|E8j2g8aB_HweTPcvn3z6DIyAPsPZE-edSbwcyhU05RBOi z9HD49W)G)vumFsRvnY*2?m+sioy6IV>t)g7_jv=;Ilo7mj(n0AVJi5G;@41xAU&8~ z1B!pm>`S)QN^QBV_sFCG3t{T;Lj~b^Wn+ia3qtws$hQJ!m;#ddi~Lc(Bb5-EV{SD%)-BEw=Bmce(bkhgq$GHF8Yhg=`bc zCpDru=mut)-_N))K7>Zux&zWSK3c%SsQ=D>b9_j|;wW3ae^A&VFv2LCl#}^dW)I92 zxK!M;*Nna9Dl=nt$#OobP}9ea{^V30snpK zy{Z!*ojO59tHhruN03&x%AgLp!uqf+q;hLZkiiOu#>tle`ze%s=?IdZf8abtdWf;+ zTXM3ETtFh?LYAN+FEq7$D)+kAJLA0vw!F1z?TLG?e`&pU>G;XR<9iR@asXHT@bPx!T(mEm z9K{}aYN)+j%V~8(N%o%jq4=yltDewB}5h)s-ltBjPF^?2Q3Um#u_)oBbI&oDRum1-|RfiQ}S zQ6@@mvxdkVZnJA5@#r2D!zh-D$wb#-Y^zG;RpWX!KBC6zQM_MHAS3N=xt^s+TKheP zw7V5j%R<`S3b!Y|vOQ1Lk&v_GvExeD`eXCy3#!WPAHulAb2n7SCb6P>u6Ygg5vp*` z97w=Gky99&{;ERJJmQWY{OhIl0?bO0+M2%#I;l7{W$aK+vncdo_G2O7s_j_8Gh-jt zb&Y50=Y+-=oY5^hsb_Tjjm1q-^1jIV?=E;>di3l;#7!I<$#c)(2`?E3!l}VLTcn+d zWT8daDZGS#!W_j%nPUP>J6MmAAPX$RbKEGtU3RfdKFcy3EAa9K8UD9e1xWQ$o>?gS$NkdrYC<}8XsK8sCB&)2FJdv3O!~s;|F{_Al zA<;KW*Hy$&WN66RYKx^-hX;j0Xo-iB;xl;i_o1ELAaEUoY01&-cs@&yCiV$rTHn3qlPQ{p!v7&EjVBX4_`_ zo$4Lp4)Y_9!(oq+H;E>*sn{!e&EDdeE@n?w=){UkwTsFdDkj%TLCE*|X?Pkb$Xb}n z65%q3jzbAj22Y}}Fq=qJWOGXS$n|4oz4+^9QZQWiWsP&QKzeO_zKUi$&56P}`d_ zIK%VmkW;M=WO*wc}aQ$H;kcIa3`nL1-Czy)4-6UhX5 z4IX4Mn~98Kf-Au#B_2a zOgTy;HC{HHNkm4mW(0b2`Y`h>%AyKp-iYrNdNHe+%$sBJ=J*pdrljK|@pv<-X{_906e~A9 z|2#p@Yo1pF(ts@)rFxp1iQwWIw1!@6&`+Ek)@AkNa7UZ96Uk$s-yZ>NCF?J3fw@YM z-C~u4*usN@uFCAjDxO^HQ#-&YCsYLy%mf^Znn-LX516tc$wb5-$r?*d7HXz!DOsoq z;2=;NBC#Bn2$;dnOu`)<)>DzmVT*#yiU6fs$cj(_W&pbkqk(A3ngNPsYnCXG9kym| z3bGI}Q7e&$J}Ku}v*j9VHk!)M#sJJ38`&d;$ZXk|YzDAqO9?>Ac9J>(3BJ$#)wST+ zE5b8Be2xPZ=bRLdo=R5{IcZLHp0ajSM5-d{v(}AMr;>5YjrYcU0llrd?m~YUmrn^! zxpdR<#tXCK4JFPz`NrF8N=n9m5p;(aJ@bP(7oW%85h}1dN=5(jt1 zN7qkbgTZ{G-QN8C^Ou_)5hfVq^9$Eae6eyW*)hfg%tFSFSX3oT3_noVUcQ-!rq7@u zmPL$+8*mHWig)7IunHD>W&6QyFn8P0%zdnL6o=$OVOjZB=T0Z1l98II$~4JVR@RnnweGYs)~9g@)}cScNSSF* zDYp@c2od4b&sOwvw(@o#QP~bqoUEQnFgv7ZaZgl_<;_&6nPd#sPaNa-!K|9V*BwMD z=&D7@vJ~mEQjlV~(N<6vRaL0ws@9vhP#_d34U|S|1GSM|5p^t*jW7+VKK%yMw#bpl ze}`3-Mn(I(*Xwrr{6$pzd!E2k?7LC@N@+VxtouPii86Z&DNadpS+y%ui%d ztJTPctVXWNNSc&}(NOi3`Q-X5J&4j!^{T}7fTA9r=Cr0NBc^b7YG-OFbu7iDyb_&n zB}Ky}oo^+-#j-gMcje(cMd7oNYJ#RZ1@oNAQ{SIt5}TVRr4Go7J9l67j3@$Kebc2A zon7lLUcYau23Y;DFRC+>{dGoV3PnOeqf~-KbJ!3o!Fruf43(g$9*j6WjHIE9sDf=o zv@w!Saz+C^J->-irFLg4ruQ)E$Q< z5FkF9)Q9}`q=w|9vX&}FMyeQz3CUDNz! z6<}vw>9?i7qzNn)mmB!aOmdXy~9)sd-c?wG@4ue7#Y&GjdgT)j$=Dr4&_pY(zk{`iy|; z8Y-c>mb2m`RMXCMIlr5Kjb~E4qHTvY!N74njI(10h}y6FbNY7f|23`FHS@-fH>2cO zGZk6OOXmgFzOy1gH0_XBXTYjqi0&tSELSYTih=zA9h6?;iec z_oMv7ZZ(4oJvJi8{)Vj^5EiV*&KCP1MQ+wFbadfkAJUu3(?-r(y{b*lNx)lHhqb>A>H zS$WylfEwA$`1vYc@|AJZtmmWIMn0s9siT^xHEQFLPx7UFEkxiv$IBNWqfgS=T(%+` zYf}rPh;Abhr`LFmD(&ZXZ2v>bCfl~!PTDxz`zfnzZLkhmPg;4&+G6dt z4p=$sDD&X~$(K8=IMv+jgwKXomm6g`rGrJQ5n`BBFEl z45sKC(-OD|%gKsb-oVcd3BD;EpMR74&Z2y8fDeVViD2o9FMiLO`$`HkdSD?49|Z$8 zKg3^&3ZM--a`Tl1dp(S&5EXa|P@xxl3K)9N%}(yy0O*LKOAS-tVNIF>TOsmx;{nWI ztT8bf+D?P+aydF#{2^D%g1zMxdt+f@{-8K!Qc58sS za9gkPm_%~bv%qf_^Ud9`z7(NRl16G~Joyac@fPkvNU1oo1!vHRCe~`RX*60*!6^Ql ztTjOxW|vVmk20x|dRUW=G9SrCiQGs(X=II$NTj_2AM13DHJ@;}h^X?3Ge>Nv=vD?< z(9y%?X1b!|H~oXgyG7jee5JY){%I>dv)<@|InZ~`@&TtO&!x!HLeH>|js5uw|MVr} zmtN{j&%nP9;G@~*`C}hkoQ6i*~otz=DZ3yaF_WJGjpTiW;3I^M{7p+;5^{kb=pUb{sx%P2l5-gp=_4r zlpj+jp6<+8p<^%^5lw}@!a!&7FwDlgJGS1BOaHQA`$az2oK53hp}9-HgKzmyT#hGJ z7u9?;e%A|c?7iiYZIFiqxLcke9pR!e0x#d((jJ1`^ET6<9Kzb_CtK- z3%?k;<>76>J$_EUf&e+Np&%}mBNOeH9U;STRjt`UD zQc}2|UCZ6bZs8tgcWcxasBwj6@=Bb;Za|#dhG615os%hEek;$k@B{o_p5;F@*kE-R zG#EsoLFg8?3fuq~LjsEgQILcbkk1IO32K4t8&qb5me6xKEe@w8CMR!0ogf+<%=YXV zRx#?7SiL$du^tJ#bdCb#bm$EQ8hG+@J_$SZz&#eK+*0oJFSn|><{DU$(9MsY+(&LKl}c-b~o%=V3HgKMMj)gl3ta){CnSP&t#&^Uk-l! z`l&kyDk|9h_fxfQW6`mi8NUy6%mie^VrjO zlGN<>a(h`x$#hpaBpBTgmn){HLf;vGll0~YI?P?p-GNl-&reNdu^l;7Os+lYIiyiz zXo_W+N6BPdnd*l*mK|jyvR=jKt5`q(qYjF*d5oX?m zmiZ=<5Ql5zgv{eAzKh=sZGq!qI^qy7^UPKrH}EY=6Jcb&n`aO&@eF^6nU7ffv1~&o z)oUtdv1(Aobg4G07}XW(g=BakdO9jkd_gDjHMEN-o7bFhImgCa4nQ!mQIQ>PQg(+B zL=d3|#sF-^@E_sIzF5L;|NLde4+(m}*PDFtL= zQ8{FK8F#^jkoKpQis%{Cx-aA7ET8|H3yh!Ni0D_M4|7eVW-%x09LTO>;%t^ZUAc(U zsCiPkJpNx)E+UnyqLs_#DwjW9xeQcpT*kNxchRp&bC~BC6RyV$c^1QCGed?L?f2$gPG3;P+8C8i4X&p;@R5<;|ySdky(G!~dwNF**6b z8S>9Hef~1LgM;-*x$T(c}%7<-lP_Q5nO?!$GQMBt%yjTm0B^L->Wj z3nlFA;3FlB!)s404YIIY4TVD&poO@L=?ZSZ8<<{iue8>GRp=JHMY^YCH{Kn3D*SZG zM9`{|uE)0qua9gC?!pf-4+r;_94R@P`cuh7iC{rC>|!iYSIRY|B2kfA8thE!ihye> zz*e#*@}p4HjWk}j(HDTFQh_fZGsU4`(9d9C4{&e~BQfft*e-g+Vkg;Ei|Ph-i<;d^ zFEt_eo`SMb{2kd;8Z9g=V1T>87-=k&4O*zMLACW6U}$XjBmeKj^*<1^4H4Q z@-huwX=!LZXy{5y1H3fd%dt{RD_v1pw`W=pVki32nV;C)bBf$ZCkw2ka<-n#ovr8i zj}s@v6Trv!B;#aEbpm@rHb zi_<6&Oi86_j3$LA&)jUI8_6Lmgo?>FY<@OMHhS~3jOZlf$^BwBC7QA*p1b`{)B(nQ zKCBGB|KMO=O}HCa_MaY-`Q_txjc3x5;1LVLb2Idao?d~$e?0oi;Dfudqve*aFV4#= z&_4IVj_WGgn5$v<8DD$uL4DO@{hLO^;~Q>VXkhNZk6ycZM;>XPb0*$rpW>GTA09-9 zhFdj6%w?G8tpo{zYm`W{Xk92QhZ#BC65bg;7UsfcVr^WEy3l4c2px+@&d?bFms8F2 zPUPfU&V0>hE)E8Q{ve}bFpC+LI#l2;bbH*aDlcpb>BA1E-N~qYoOucIs$5HOz7Z&! z0jMCBmSDFA42x)8f}A?*k~81zGbSYDB~#49pRE2y>o8u zThwy@#`|vi`I6_ZS@nEvc1?MoCy@$fV-+=-3(J`8@8kMQs&~9FzW1Z?19$%Z*}smz zzwgf0o;^7G{(ZeE-+A-L?}xF9ojA_S03L}&m%s?d|J1vz9GEjQo(T*KeTQYq7g6;v zzj@_+iA}LBY&W};J;tio!}tm2r`#y++V>8fIDp`EUPi z0snYTGL}CIW5_IKNFLo_{E?AaiSTCB&ulQRO|8#dU4BG&NYJc8*uvE&%M*+uht_J zp%6}LtF-mnThWVUZ=z4iOj^BDpTZd?Ezgu2Y9GcAGP~ph%mLld%vaFc=r#PG%p2^7 z=tF!Gf2uoa_(X8n(zdd)(o|U^z8Bpg+*NvKnKm~=_>v~Sr_xhfV@1{!V@x47;;=d0 z4wXX_3%euJBRSbaY7js}j_1m4|FY`;%0@wzB#>cO}npZr(&B6#`x= zV>`X9!aW^0cE3@`HyVX%gvi3DF;$kIN|hljlvVS!DO6p?RS1|NDk0TsW4G~$kuiqV zoLX(OIrlg!r%#VYBj;6A#A4w+5r^HbQt=Un*Hqrl8B?hwH^Ad=9`mEjG}#~nx5o?! zcu2s)DD#AcK%G5v6BV(dp}eb9AgB3bNp z;ZCRzv}$_gV4J-!pL|FjEqhcMrnMte5eVQU}~cL48ZkWSdMbQ4@`COK{VxTZ8tJe~U|iaWO|ZK{LdaN$Z^hRMHy9s7#_6a6*P%K* zJGvNO9=RgD0X>efi3{(U|y)I>!?OW}v-C1@B|1oz-nGEx% z=mq5y$4@CEeNL*D4)~?!31`p@|@fv*&N8rX|q+7Pu~1M^UIGt^y8Jg zhq80u+V||r1?%yYtK_vymkwm6l+SOtZPm(a!xu2Suiv@g`Xj?VbGKi4(?v_y4E}U| zYwx0cZ>-!@-??sWecAHl_#e*S)pE^!S6_Bvb_L9q7sLAaQD_r(6u|~Ly&>`@|4aXy z5pFrRp5LUoTD#70m9RcFx6;COOk?oUrbl`mzxq}+BAuNUp!hx_? z@GU`wCNlkMfRgkcn1jt=__d+4#Y-n8-J0!Ww_)m;%RS^RLFWzNoOI!&D$teJ9(z6Z zz0HF!FWvCsBkR8Vn-?GW5tFveTtBbr#-{4UiEkE!n0_4G+wtqChQIaLExSMe?fCj@ zRxk&zy{Prwt9EYx`ML$g&@+i_>3c9AdQcoqV>ZdDMQD-dW^|M1=JdU;??v{w_C!8# z{a54!(CWb6RZi{?0OTw5qvBC`;eLo;*d}(vR0MbmG7|yZBc6~QCb_EQ+63% z=v)-Ji!qBxthf{}3bs^qR}56_tk3`tUfO_IQSAzPqRu3zVpxyeQ=h&mxGnf*S}j$` z6%D|(wXrRHi>gK4l3J_kb@jTtJ$=F6$koy7RX4hC^bDp4Dqc#ymHaUHx1h60que!7 zZkD8ju!<^1nYcH|`eW0I(`>>Y&1AH;Sk!K}F^MSI)!Q1zVKP=%WGI?R(7;Glbs2da znRPzJaz5D4U0i^5o>T!-a48q}PAi^59K_m;Mdo&L3I8EcEPf@T3lqOC zhl=U6S4?NPVmj>=`$dzHXh1bdbQav6t#}&0PA5Fayl-xl=mjv&v_rZB=S^__p&~2j2Pp*g*QykiC#xXrJ>?+g;l? zj%^4n&VKjyi=I2w-q5#Z|Bn_tH#lRVn|abR^NJff4qh565A?7rzv(LuIf75ETl#=W zt**Lu-nvI^pLe+*ysG}YjU0~<;TnNyG=KD$@0_YwY^wZJM262m2-bzoP(z zjj6K8OyURoX93Sw7a~8nnSfr%^#Z*B%>nF#=eaaJgxuhFKEyi&{`5?CqK%{rc5A_X z2H05uM0jolNI=@3<2C4F?m7fR_QanEhByNd&m4$@1;2ivHv(J?_AnZu>F5dcCVCUE zU_IPyzEyR%25B$RU88^7&>_qdmK!fNZW65)Oa3=(7deJp7q~M8_Z93ffqs!FGnzFk(BY0W&CIX+c2 z^}?yYocigs+p@o|SX;5Ta>aRlGp1JkB=@#z&>|QmX9AG(l_Xk#kSfG|2+K6`x+<6- zA)=3+{8mttrQtmEiO>u(qMLFwi+a#qIhsQrtjWkNw7_g*Zav+uGJH5kV`Snl&(RFbl`C>Ii?aNh9L<5B$8$7~4E(_ytwLu0 zg&eI$)A=`Yv<5j;<{Yg>vsAGhE#P^ol@K%LNG%!E2PsWzNL0T-X%)5q1*O&0{#{CI zDE%>|wWJO;I7dSrYOc)DP=}hEb2QYU=I$H~b*RS}wg{b+&ZmAh zP})l4*+OX>wO8`*q+uVVw43_bN9jW9=UGa7Dg6qigVg_<5jV7Cmy_n}_;)B(5ye6Izw9eg%|`zmTHp^E^oqrSSpt`%Y;{+FSC zh^ZCAd^!D!e-c{yQuqq!p(O3zTs|d~fgGgJRG^{|dnalG*Di4HLQ5f)*guK?@5Oc| zloIAlhz2wt(rNss`R=4HtpI(rX4}EfDq4ms!H(qa|K_dyZ$o_5U*l=2hWcCwK378x zOQ;_5w3OB$aV-Iu58+5@R)Wp?T&g{^WF*#NuvtL;_fdNZ&86idC0z}6612T6N<%Ab z0{4D+Cgmsb^wSnZYG!$^o|e)W`)G}k=WhC5R)K3D{E>Dhp(QkIU#z7L{gt@?=e2Yu_V&~7xreseKAQ8k z(=FxeORuE<)qG7qe4PVuWYM;;!-;J>nb@{%+jcUslZkEHwylY6+qRQGbKkx1zE^es zSJkKX+G{WLsXpseclFupD~A;mPpG?}xhGx257i~N~xb0%3f|Lcssag~3| zN_A36qHy}-dR|&O^w9a@B&mEr(6b5z@9P?en>4YgsG#7_0nThk)q=LySvzNex;FQQ zHg~00rgk}!!oz6dEJ@~A($j-P@~?a6`-%%QStjSI)8j;%Q#CT}*~T)b2NImISJkFR zsi5lTxcUUgYPIQ^IVgLHR3VEp! z`K7tl&DyfYBZ*SWlP%iOEk`!%C9#OKtVO5H@?`M`$zW>8#1k zs)fN>|H-DVDqM3LOIeShQyy~(7VXvf1=>mrZQ6$?XECoa0$IuSp29}e)5~M^g_WhH z85(MJI2s&jU1rEJaw^4~3x)cafq}mON&9j$48yHa2TB>{jAHJ{$@iy@Rj_nM`b!*FB=Wr`T z0AMSE=UG1V0AB_GpMwDJ;egL*z}IkFGb{NQ7-?Ki-j!?ZN6$nbyXW?5<{!FvM-tcd zpXa8N{n9(9El@3YJ>yyNeHI~4SAz}+DVFBc6d&&FxP5RnAzf?Tc!y^v>zhB)uK9oI z-f@Otu0)G06WS^_CUQq!1TbFV{vSsDC zvSCtki(v<8gBJ1{Z5co2fZzHLa`v;ZI=xI>kEgQdd8P?OASWhtDOMW#1bl+@)O71_ z`2~pxMhYPnl9hwj^qjNCLKyA~bFS#-69D`eIoBlWwL6I-Iv?BqM0`W~i3#x-uivW$ ziSWt!hFphF>*2eR?YP2gz?7VKs`JS5dxlZ3>xUimHZeeO+p_4ii7&rzCjd5s-wCJ~ z&^!{BGiy86ZEN`Xm~Se`F%UY)b`InS&3NK~5uULsKJV|!UVB4^VRnUYy)xrg+e zLl*uCYXNLF>x}z)`5VPP8xUTs-YJpmdISrS!AAl2P9qm!DFi+sz1&TY@7GCZz0UO( z)Mx0&gPslOvUt|AlUy|Y@WRA-*iH!==1N^`g_ed>iZ-M&b-ko$MqpupX;uTrEIc5V z!JXqHR zP@4ZBeqcNyjjtI;bFkb`MaK=>$)xXK4mubuJ5^YL3mP;~$5zAEz}D^vKZE=g*p{c= z-tx-lRl=ju9bOKp6j+w0+}>h@k0Buv-_B;+gLNy?+1}FI>T!gd`gW>ibF*I6ntoKL zI086h$E7S$%PVyKsb5_FtE|+WqaH1+9(^1K;0mB-7|H}O2QmlB*YMH*#5fCJjjZPp zLJ6)0-8UFsHf9G@%62kx`6|ceH{s=S`L;T zEx-_sfA`q(SPI#;EnIytby6U?3T@qrURG@ivq9r9dJYWuv%JNo;6!?|jifYuX3e?l`K($7I+Lc&1h={~A3WHs^Qa1$V@B`26 z>r~n2dfDe?GS4ZpiW`Wd7qJ$g<948US!r(i8}0cF!HJrRCrDcNz_E@#rD{3q?F)1T zQO44f+@kc9=Xf${X3_%g2wp%DO}%S7<8jVW{IKf*J7eaYo1IZ8fJhis8?gK4ozb;U z*}W;c%-L(*pn##y1r<-osl(yBY{zFqF06|mo`}~BJ#hIF*g)^ob_dJ@UjgvmSX@4M zFW(|?iC@r~pQ+;8)j{6|uT}?$LZ@wuD|bN~49c9+6)p`AY*RBF+7|S2d;cIMAPj7< z*bh}`RaCd~iG9vL&^K#A0?;EP>sn!G0^^i`x;Y?KI5ecW7Ggm8u8VehkU8KZ2Xkz` zm}U-}I{?&11d!7|A?18cRwD(Fv1&t2boji(nEU-K@lhAzbN4p8Rd7i`MY9d&uAQ&0 zvVv}@eTTMoSNhvKtMP~zn9sc$U6F%fUB8Izmfr;IkZI8$c@(+I0E3AJ^PxAdHoy|O zK)f+Ld)k{_Q=dWsoHkGZR9zQ1DI`0dKvCVUV0!Orp3-)U#aX5)e%=7t*-&KdWNNmq zd3c*42h?kc(|l9IQT%XiQ7eigcUOqoI~D!&i7ClL44(jP5em>@rz^BL9^m8oE!Jt# z%HQTC=b`4&%8SeAP7xamXq3=O?wC;{OXw}2F*8N-<;~e(^7+#|%btH@109qL`72@5 zvrB|S(_fh)SiG*|bYf-;QKmU!4Da7L;W!=p`|;kF3sHpISkfDb z`R(0%aL&<{a7MbtwOw^xFik}_MnNO^~ zGsjw!#!e8Lb89^@PdW{}=*Owxh?hqdJk-3?Nta*7rM6V*@9@B+iFeJ4-hk&X@%xzB zzonV14qRe1I7&UScb)JI5TrES-xLuD>K(=a@MTDpNtT5o-OKD6fmkX|j@(R~@H`Q` zn@x&?SUT#Fh7pNcn@*g3ZEkMz0DXMe)4jdo%vZs2RN8uPOuwMfYOpD>E2(o5H_tQ4 zBSd_z+b#;Ib1A%7kjyE6?*XoH5IxwG=<4oN?09G69@B#o1C;}d<={I$$)33!CS zvh9~}WG#rd#jA1(t`rO}3zO zq?ZI9gZn>k$D%6qrI%fsuGkM07Mye)fUo>jj%(a~ogd(3Ksw;~*Fx4F;x*p>WIh9c zLAzhTH8OAM|A}qp$vTIes`nx9h1 z+}hYt#@I!{)>_|2PElIvn_>J9%Jnyp`mgJMQLdR;*uE*(bS(Ja+-kaS)HU7z7jwQ^xJ`=db2Jeo5>6vkg(c_O(y+7?NUJxsw;^K@~R?S^hjWi8y)LtE) zuQ4$d(-kLI*%sU3@f4939NAsG4v4QhPhe-C+d7sH5o=n=M!#X(41F?GsE9v$xw&K) zi@r9P2Rl9|80i+XNNM{>XM0=8j@_LYV*3PY9v?BuE}k{OBpYW=JvDf>-GlPo2SmU+-`?aZKIjMZmZTAvy3BevwBx=Q?D#;%?#ao)K$9C zZ4&M|9P0Mm)9zdy>#FFzCLbRh>*gls`zZUL=-Two;JrEBZ)wuLh8rL2YEXYHEEabM z*XMUPbA62AqK=Y1@>`OHb4)veKud;;q(oz>kg zy;sdhpY87XkbkAT{1$3fT|W;6eQG_qzF6%#cn|q}0t1S>(Xe9JAkb09Z?h4k(xc5a z{!IPYJcLDBdf2)8`fZOcZ=AiwAPT7TpUQ*n-8@$dYv{onDg?ce-=?f#D6?+5Z9 zvA*Yjb${3Y6_1|n+lS@9&gJj;k9glP{^kFVJl`Dqzxw}xKL2|o`rqjDzZLzzYn=Vx zAJRW-{5$8j(SIoO|3;rPFw)br{LiAl@bu727;Jn_y?T56cy+EHxipFY=<*_6nW%HK z8itCa-RH*#0U{(dlMoOi?m&$5^{?zzRc`33Ttu@Lwp_5dGOo|X6tdLNEPq-RSX+~@ zq--dxq#anx>uiks$V}A+Qo363@bP*7e0Ew&bu>8~Ph~Wn%wT6!$G}=ygcDf?<@)KB z?h%~$n#KU&is8Hb+7vyK{noG9Oy~{7hlPpW<>0vG>xs%&4J!9>GAhmagXP}49kAz? zz&Al{YpZ>-<4A&$?>v3j@Y22FIBO-h_g0(=Y|$3C-97ft9HgB8$4;2EpjRhWP}h3E zfs-1|%DTtHHN|F-HHnM9`sQqV>sMq4rCe5A008?zzhJ)MlpsFn^eu-q9_|UAx83Fu z5CBxIEb1sANcX*=kdpKmHf_l~=0CCLGZtf$eqY% z^=uEh7DUgcECn*x>LnF?9L7BSEeJr@9P2Ps{H*U-LxPN{z?t~)WG%i#3)3P(cD`Z9 zx$y7PKX77T!grnqK)`a4H;Jk3a3J~^o*AC?$oKhx-;vJApcHL;oURoaz-9HWhC+Zq zYkoHrMfE!zi*W}U0?hYu+wsx|{HAu_mF*0|7TGaz#q@?HSA%&fdn8JRRRh#iknKge zHmpn2${Gz2t^utI^w{BdMU{!u9B#;wc;ExA2t>#uP%nt-=6OI@DvdhnN_^Eh{TU+m zh40{%9u7`j>cZ!@1RAFi-A({CdeaVy>rb|$Iv`H*EJ7!UJ#-p0)d$!GZ)_E)X>TJN zZ#fLOncc271-+6DPnRR&{XNdZuh_ zS}o}XCBP;K>PF>1ribJi|2ss0W~fW|uxhvJ;Li)$i!MZ9--(j)shgZ2w0U*#ki8DC ze|8^biw<=`=6gnaQnr#8j}y!&R=@*WIM&XY9rz{@MIMoe0T}~1St47#0`xS9jNveMqb~_{A?q^bQ(= zKZZ?5bZ$v*nQy_};@*9+No-^0_Nz1E+cUqR=i^@4oP9V4cQ15X1H3)mRIY)#kUn$w zSrgfAHiy4PW5NnX6+IMnWjfP122}{)sJn16XWCfucsmdt`;xaQOYQ=$1)niiH|!s| zA+B~Y-y=(A(zJfYMn8)KlK)xJ7U39CHezj!=aSOF?ill7cjm^s)uTJH)&KSTi*GrXqW=o1%(iq>IeQ+Yk=Cc>>fDl%j*-prX}n7bbTto? znilFw3mY|Og8GlL4w&W*C(zms#r%xS{B!b*11ujRY=8K1XY}@y@-s?&viDX`A{(%& zevn;D7De8mt;QpwR;oxt67FoYW%{R%U=>+&oX1Ujv}Yn$$m<9F3&aaKyNtK!WYWc}@ z#r%5NOVDA>p=w$}6Tn3&P9beu&%}l}4VuBaPTX#h-R9QepJ$)FOF~(#eF&F)kTX3P z)(^xAI{H!~oH4mzGmrB6~szMt>~th^#5#w`q$n@c0(6FJI$K@q>%>953Aoqk;qTQgp#60u6 zvJ2h6-}K?QCQJomzBro0C2wdU89WhWt|jf}r*eHpiR||qFn-wMI-J5W!Vv|-$bl*w zQLDp9FV8||&6^~=Bisv1oQBPNmC-1Jcnc-PSh>P>CL=YvHcPNNLXyMn@_3?Xj9AmL z*TWXwXxYc%lM7mM6s}gSmb+^?$vs#vz%3NoF<-8FwS;vCGP+s}7r;5)kiLUjdjVc% z8Lacd{1m3l(ob)p`BXO}Zl#Ohse%7^1e)))&>E57ci>)+dOJCD4SEOPBq3}C>Vg@v zJ7TlTe%g7~*q{56yjvFCM|6y1iyyC656cBF!tKR3UJ!=We^Zj(iS=>LGAWJf} zR#6-B!6!+U5wCx&5?QNm04JZi-HAkDm(6F#YT9YpXqc;;y1BTOOamJt4FwfAD6n_7 zY7*Cr+oe|WTx`7cRGqqT_=*wJv6Dum2FW$H->!*|WON4j1M%;e?nY*bu}__fWU@&f$s42WbcY`{9Yuq>D2b)+Z){c8GwknXTpOXw?4So4zH0wZHp$ zx%jc2eiLNmx0?6^S3(3z?7ya`A<_6CCF1vjrF$%qa3r~~u(oz?R+-uRGd;d6k@j@s z>xa@Ini=&I&qqSQV2R)s)cdXNhwh$iG|Pt8G?5u-9qBH42%Gv}UE~?65wY1Q_SN1M z+<79Tu3>W8cGWCQT-i9ojyAM-JWV(leBDk$X?8MQoeJPCCqp&epWF22+KQ4iX%p_5 ztxIcXLO3A7lFy}1s}~+EUD*~fb7SrQp6u@F_I?V&)k<66fKaRLPamI9hAougv#Ia! zFfQIoFL8NmcTc}1J+JW?j1o^KY^SjaMU@R%Y%m}jPl7gJ(hj+wYNC&bRjjZctT2H{ z9PS2(AtZPj`6*tEccdg-|4FgDp&DrPd_uTPSqrObM3-xMzCyh??Y_#J3mN9^_T=G< zy3PCWILO?Yis>Zh3HMXt!f0{6<^ww`L&M$JMMyXLjA3(y8`p zxZm9dg8``pAzHE}Erl*|mOX1U5EMa`^}*>z`vY2IV-DDAXZs*+^ZDh<24~`G<05VN z=SDDH7Wp#w`nscyaIu2y)}c(p`etCfnykgN2D=*F4p}o*w%jmva>XSV@vinmQevif zlwBk@R2wPK@}irVNb#6O>xza(oH>N8irI;{%vjobFtV?9g|Z$>#X767?}GW%0>W|n z?yM7Gc|Y97aU>-tt(HI&ZCjohBKAl>61OZUx}k+$FMkwQ^`g{`1__i>-yPR6bKf0^ zmPX^LTa-@_lP@gXrt)?~$kh}lr){aLiO$=Kn_P6uGl5AViB9W_{z#Dqqz~%$yp|L6@w3c<+oF4)l-u37#W>ua$=zf9TJh$dEm$WPp<9n<+u4 zW~EqEhXIp#2s$P@}6NR|C*cwmGq#DJVfhxg7OIEdFsFR43PULr#S`x&VK0OZ^XCdLLS{_;% zXE4>YTx4O=@{7n`H15Qslr!A&G_OC@C<-O27&>zN9405820buknC#xL5MkzEJfZ9J zVLSsY_0N!9MhaX`oF>JLPTU5&w>p^-`8h{=F5M*4-_k#Q*{Z-lrk%{uWJ8N9SVWm? zSIdYHW~IOS;b_y2CWtl)Ng_ED_$uZzZRtwqNpd^nN-d&-OPF7RwBYE|3{Dx~?6J6U zftJ-X&=5`}bc6BK8XSTR;*Bb07TqD0;wCi#>Qu}52@3!V%+Hm8xGTvt*c<8fBCrw{ zv$2%Ml*Sq)oyMT&D$6KrQr%N;fExieK#J!Bc~0RQii*e_Z&UNg2G89elumicF8(kz zV4OxC=b7X#BvgqGkD>~;S&cM=r+R~%yYtt&fHgc+I<0O~PPPajgKvE1#Ua(SWch0TZn~GkUHRRZkcCT93i{27t%9rQslUCzf z)DEo&ZmNMcxmjp0`g45FSgNp8X*IUxpDnhVR;?i~{QxQha-n_MJxc3%cwl_}T+e|A zxBHw$*$>~7z}K`$pLtp+2L^1+s1HSA9cbk5Fhw4xLUpj$ea090gPcrV)L1feqejwL zf>3!{k%AXOk8fTy%o)}z3KaMH=B>zAH(R%c_e~J2U7cqs=Rl8xwun@xA`}keTv7>J zm2Fa%qf_VPmC03zOT@YQ$*nP(m_Sj8Q`lc9P&y$%487Y=nr=W$A~LwFpTUC5TozFk zSEyMkd$u{cI3HrArPKCfE?y?Jw?MFLNch-5gwi=0e^N|xuAmTOb{0x(%a(URntOuW zV&S2<1R`D7;sApvNpMgmni3u2AQ;kra54`F@m3FYG7>eWuR{+IK=U4)QI~0A)mNdL z?y`8L#c`bx7n2tC&-q@}&imABFw`F+))m{QE$i+fx9lUHt*#!TN84vyI4*M^Qa#I2 z(i#+L)E6hvRN3}v)Q*)92E)4Y1#eyc68zw{{xDa-MjVG8`B{g@N{(o+NgxMF^Ornj zRqy<}Tc6G8O*NHPiwiBE4vvC*){0cO7UoOnAMDln!9I=E3g9|(6hl>CACWE{PLZ@v zJDCfVTc3)m7icpd{k!wxpX3byNUkFigD(ME3VOs%V-1Hfp}v0*W{(?!zCkOLW+Gsu zKXb*_3E>HrvULo9pce6S1II7i?IBb6^@(||`pi%H>E1j&lb0#H!#%Ti50b91r8~^? zK{o*38pEqAJ{Qbjv$l8+8!q+whm}>%n}(XoU2L@Yw=8RlE)#Y{dzXD6KPVNO8CWh0 zbr{4zN#L&ZmtLr^sAp*4I2;`uw%)on4jNJRs2_TWMNJ+87L#`Sszn|G?e0wA#ud7_ z;>#ZV^c}y966%Y!Lr23}YHNs5iWfGDZRsz;REfqK8q{B+dBEMnwNE}1z62HLt-@e| z(fpI?!PG9*PUVrIp|yEgsSUD}N?rIPIj%fp4V$Nt1B+Wg<~1ar5|@yX)2FW0=ZKP* z`{hsUtuSnTu9M8XqF!CFe+zT9m)8><&lfzo=O+oG`toPH&&G16UF{gF56le@Pgb_H z>NEEx|Z2moNV8Jy7y&!fzHIMcya=RyA$? z&n&kGRFdktO^3p;p}lIci;*SGHvTUrbzmU%yLp`n`3VS^XxszyK>%UY;QeiE{cc)o zX=JISfj#Ip;~yyP)MPvtMEyKKJTpTt-WWRWUud;S5zNma-&|QRfe-p=PI$c<7JW+ zLW3wfUr5NoMY~G0%g4rf=eo6Wlr(hv=1}x@_;yL^^WfrT3-<6+wcvBSJLpjj@~&l2 zqDcd}98|r6M)8n&(6+oqvA){BI$z+aNtsJsx@v(7@#Crb@nalajGB3WjkVoMQ+6In* z#Y&vTTj%s7moxzd5O!3U0SnF6I*%Mq)V&M|1P<}yeXTug2cGX;nx2!T?3bQvFS+q9 z94PhZE)H=)jA~(pyK44cwQ}o9^JWkd$1R&6At$F!du>O*{3CpUGfVbKbVciTwm?O{4KC<7yOlp=m(Sxtqj{d`jGAG{Ni4MFww<}gXa3jRjJgWfG4?bz zR&R)M&(~Zp%R4(U<>cGE!lUx zV+ZvMC}pToU+nCchgPVJt^|as!qw>PdTx_>B$r$se05Ux)f6haKk?l@c)a)+-agy_ z#j|$3OO4*3fD{ISEmg6d2d}ukJTj%r z*dVyFcoq=2-AKzWT7M=#0(j?u&jfg!3RncU{Nht0Qpk zO+R=VWv>}B_2c@)wjm8D-Zx#+w$py(Ky^(R`U;8yJC8c9-NK%KP>P>)eyjGEzK`aE zAft&flv>+W^SQ(>y%V>6shvs|sVjXebRh zIO|v8@ulT0;@ot9kH#{P~}Q_A@vuMp}=SOVjksHYFINv=c{(PJ4T z)*ph+`>0fYAJdAB4g*=2vm;ekaXx4ZS4R^wIP? zGJ56I+QVwD35g|<8tFss+31(ddfP8dB5(`rqdaiu5AG*;e#0M_^fA#?^ZOZpFkr&F zlqEl#aEL5B3}3Ll-oq{Fhl^HqgKmDYy8BthhzHJ=HZ`uaUkE-vtb9!3I7`cY{d@v? zihCGZkA5*MGF(d9CQKNhMr>jlkqWKG%Y!L_bH ziNU&Ccw2myc>~GTN?3GAO$qJCxL=;7Q$j43qc`C5RwB+D({vhYodzCDGj0>aw{?u@zT}Bg$IE@%D_v>pg@w z{y5axxZhdKsy*wfKG}8lsQa{@PW%=bjN746m*{fQUrt3Oo4Nmqqgou{q1D`FD*kvF zw@zLsf79}K@V;WA7)XejPG-btWHS&(%_&3E>{hHm277vbDoLJq?Bsl@a2=)-)mei9 zo#fiK&p77*QQ-bps=RD{oVd24p`__ZNn+)uk9Y(uj;Gx=hOiY!DpL-P;T zZ20OMkr_t4b|-^Hh_rApS4Vd5=P%OuVSoPpK758eI`%QjStkYoT_8Fc70AqzeJ)Cq zJS@g~U`9omv>GVt7})(ASE`4s(s^4ldOj0)@}E+K>_kStg82f63Si8Yafy}OVkC@t zMG3pSeh8E8mNFLed8W(o)eazcHu4l5Q>E-^{lp-VP@IVkkVl5eoShkA8YtbhM~K+% z^()M#;1Kec=aTeSEd5IPC5D{k8P;XK-`eqTq?_CZ@C55YeEg?fGAWyzWJXRT#S68k zbNgt_yoIsZ{}QH6{<=rp7Uz;C-1ZX&Mwr<-^>XQ4fiL&E>~n&6OJNE~3kFA{;gywJch*b#{UaVO`Q-{;1*E z?#*JS1=}K9m%c!CTD8j>4cqWI*!FD|fFrTqD3BY&mRtk@y<7&hAwR%;j|IPqMjBBH zuUv(x2+K0@u6}Z83?w3x3*!j)3%`XU3eO3r5!Pc+(TohX_Nk;3#v#fha1NN?l$0Q9 z2cmUChMpAT(%;P!eQuP?IYn?o(a+{Fnac+?9QUc_-sewq-4H+MoRH;?2gs@0$kCPh z`^9jw(k3gO2{_RGe1;V3nmGWBSDz)iR1Jm{s~Xt@tX@>KlgGxI>_B?qEyi4g8Qb$~ zZ;UR(o#7!dt6thH*!vS`|IxyP+o9#^+J7z2Ch0wk!^p=8)b(E)V%4qExH99$XuCpYI$#9RX7idQQE!wpBjMKh;h z?K%>*etC!gVlC1Il&NJ5!`Vj*X2N5i6@)3LRZUnZ*X8kPur)vlb9j-uP=7inn0h&u z)Od|ROS4CF#g}lV`1FvDPK8a)8bz>blAv}Kf;)=Ib;VLMC zD^2Dtj9fQkvVcMSaTYdK+mBUe8G|xSlr%k1`<<8F9(dIEfzs-JIlRNA*13KDc|bDOu&;FjpztjEs15E=VtynHZ!(xs zzf(Vkf~5P^`@44R2w89x;nIh!*Kqbeck(RrvR%%jHZ9x8Om%OF*kzGiA_uf3v#xd4ZCiI+DsOzAWp^IkPr3q+ zY^20zqw&1GaGuX5<7K#VB{X6ghEhe`Z|>j)ayjJ3S?>7~vD6^s4$K`Kf8(yQ7_zQA z&SqSXJoo>YWT9w zC&w&nL!5u*gKRURG8!CmF#_^akGckh+;bH|jfdI<4^nH43nd0)&TLoQ^=yBJx8x7x zsc}$s6t2CK%GW?aDHzpd+c8bE3AoPklcZ-fQ%w^8dV|`<9W)9Jw_3`)2G0v7w!_ux zG7Y3B2XbFnB$*BMB#f5Md{ad$jmbNB%rj(5oOjnVCW%0M`p? z>-=htPZ^FAuBKAX{JVqs?!#gQf#eIJo+JFKyNFOjdNi!O%tU8=&)YeGR}~Ff!;!1k zFBMGu{Iyj95DmKQXw!8OtW@cA>6m1x zU-uQ#Xm~W#l!lk3>Ft8ueq_<{6Lmn75f;gXOY^&BfeVlOiuk0v(C19_D?iYR0E}fIV$rM<#FSto7BNP-*?>&v2g@JU4fK_5 z@?>G1&*n#$P0bs|g-ph!uVY~c=7r^pb=lzp3nFv^CJ1*x;L}VnW+9*YYv@uyq;q1K zM^)Q~4#oLxJ0Nc!9Ke|+X9aBrv+f2P{dV9Lt#&(|eq+_~NFAA%sy}Nt`5=j)T>&*> z*4xEmNd_@aB(7Sm5rWMM{JiHyKB_s*J5X2MF|AK=&w`9?zh<==nGP2#yP)}`__-L#C5Y1}4GPRrUzEt|Vq>O?6P)$4Wz4Vd) zSM(tX$p3`dfL@wwP5+GRwZA-M!UJAh8$ZC%@?~&j?2lApx%>7xppRx;m!h6{H~WE> zGw_bwFZ|~y8YAQOg|ffC1eQ7$I*OyAz_>}#jVjsLE@5bP>e{NJS@Uvy8)$&~q}Bob zqZ}h+w!7C3tq=_d1N&s~Ud^VhXg3Wy%95gJ>1XyR(PnC|JnjuokYvPXE40kX+!;!a zCB-Luz+PGyc~Eevcg1&#*V-Z{^g_>yWK+BKa}^d^>bWnfs9Q}@jLAb|FS>xaS72n; zq7$FYUh@x4Xwx$TM`JterNcm5Uua`Fpu!X*HHfoZJbg~+UQ{W=8sH#xX`&<%_+mHO zML32q_T^b$4DR2HQxU(1sk|tY|Mg}TjSCo9rzBZlx27p>= zv8N}ZB~JlfwApSGu$ zE*v`uA=;F=QCV!un8tepOhZhaV5SCZ5EcWR#Aly+j;}dfyh2U(aAx|^@)!rGs(R=# zxgx+KRf>IWVkiFh^%F+iSeA zl1|>qv#rPDN=z0_@0ohoqUa-MZs{}$UOk@a-xWOK^{LM|lV1nS891=s;KdHK292cWxchnIN|E6aQ-2_N^eYv&h~P@ zj~-R_@Pj>;nsvl5+{>)zALZpP~gTUjRYbf%doweZAT*;Nn%2LMM3M$l3 z8k1VRs832i6eMRQ81!iu*@_vHkdWL@JbOEM%%v7I&vElN-BP+nY=6xE~~) zzK;^1T7`#|sCpm$7;SZ>%W8VCefTNwX8xso8IGTII-0@(ok!n{5Aa3 zA)fLuL1{GbBEXACFkcYZP#90tlYrWC$YgQVUOXYP;r7Y{CTg_vc3JGI?Q^1&2k`8lP~fkusXp>41N=3fs2ZKsE%K{>`C%&eVHYJ zS?1`2>?aaDYkG(r3DDdxUxa(C?9QR>>!tQeZ>sFCG8DXR>z&z=X5+g`a$2^8hj@*F z49+GRJNkjQT4x@t#imC5WUC|Tk$Kd3fc-EOHZZ(2!ybJf9TmBKE=P_A9lc@dw!i=Z z31**A`#GT$Kor1s+Ll}1WQBR!X(xx=#!7AR6%uiW)0a!P#lq5IEv2*6ok@XazW8K| z`Pq(93w$8aBwq^rS&)Bda7w={BBl2AhwPD4mc6Ixjclg4RAZUVFk37$ch7bw`=EP> zH~3|M?4dQ}5zlX&7bw*Sgy9R^=o4YsGmOvV5gPp+FB9GTlmvWha#IR*OY8*H(B5sCWsIMWBd&l^n^>KF?g~l22mTFX3!i zEbWY9s~05>NySF_iCBe-7vk5u1nY4m=zJ&7Iu)865|wA_tDz*>V@Ap5-)?)o-I}3a zCpK^0YJ*?p_Fu)EOm`~KduX^W6a{Stp}uoZEqJQ{NFn`5wAw-)wNhb$A;wT9#Chw1O;26sM^s@Whk zl%P;k_1^<{F{9p#FB9VkkiHu+#wTP)jO){>t111#jB9l>o`U3Z!9(`_jY6EdXF?sL zRf8WeUMWEozhky?^P>~M4ikyYm+$(QVJ9inQ9|b%b`k_HFsgtV_18{;+0e{$eSA^{ zLm~hE7bH#!o0uLxPh@BS!6!HR&;Y@UpHV{s>;PWMeEOJB0dHjQoB48JXz)i0l8OqQ z{Oer2I(xzgUOX!0nG2UXqAXE-UVTM=@8lQcfm`So#54b{Pxy4eH5m9ELRU{WI4S8- ze>`ff6p8z*4X(BsIs+u{ zU}+{ee-3h*HS}cnB`Jy_?db;Se=0ABp8yVk8nqIIVsZ_{@aeA*d^*0H$|LRS&*Sv2 zT9P@LP^_57H&KZ^s<-u?WgqDJ8K13I@M$E-O9CaBMX6cau4ZC~YvGH1Y z+oU&dN>GQrD_1`f7I$pDr`ifrv^8F}kT!Ws8HZvF(GzduHr^@%7lPnR)kB>hNojbe z+X{NDkI+riBFjA=iyuyQ*5XiCR#b6F(H;F&%S8S%w=hD5Ca4kD)}YNSb6TksM=F9Y zZZT285w{ZO={kG)Gk#jea@lI^L^s>D<5HiZw*kuX*dReVjHThz$rB@89^+nbHJaQ{ zyodSE8*LG+6q#CNV0QRiCKS08SJj1V%0DHwqp>k}yf=z~obG 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 Sr6mxAOrv0yFW1@1!u%H!Ss~;A literal 0 HcmV?d00001 diff --git a/htdocs/core/boxes/intracommreport_box.php b/htdocs/core/boxes/intracommreport_box.php new file mode 100644 index 00000000000..1e7c9dd1725 --- /dev/null +++ b/htdocs/core/boxes/intracommreport_box.php @@ -0,0 +1,88 @@ + + * Copyright (C) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file core/boxes/mybox.php + * \ingroup intracommreport + * \brief This file is a sample box definition file + * Put some comments here + */ +include_once DOL_DOCUMENT_ROOT . "/core/boxes/modules_boxes.php"; + +/** + * Class to manage the box + */ +class intracommreportbox extends ModeleBoxes +{ + + public $boxcode = "mybox"; + public $boximg = "intracommreport@intracommreport"; + public $boxlabel; + public $depends = array("intracommreport"); + public $db; + public $param; + public $info_box_head = array(); + public $info_box_contents = array(); + + /** + * Constructor + */ + public function __construct() + { + global $langs; + $langs->load("boxes"); + + $this->boxlabel = $langs->transnoentitiesnoconv("MyBox"); + } + + /** + * Load data into info_box_contents array to show array later. + * + * @param int $max Maximum number of records to load + * @return void + */ + public function loadBox($max = 5) + { + global $conf, $user, $langs, $db; + + $this->max = $max; + + //include_once DOL_DOCUMENT_ROOT . "/intracommreport/class/intracommreport.class.php"; + + $text = $langs->trans("MyBoxDescription", $max); + $this->info_box_head = array( + 'text' => $text, + 'limit' => dol_strlen($text) + ); + + $this->info_box_contents[0][0] = array('td' => 'align="left"', + 'text' => $langs->trans("MyBoxContent")); + } + + /** + * Method to show box + * + * @param array $head Array with properties of box title + * @param array $contents Array with properties of box lines + * @return void + */ + public function showBox($head = null, $contents = null) + { + parent::showBox($this->info_box_head, $this->info_box_contents); + } +} \ No newline at end of file diff --git a/htdocs/core/lib/intracommreport.lib.php b/htdocs/core/lib/intracommreport.lib.php new file mode 100644 index 00000000000..55a7d9ea9be --- /dev/null +++ b/htdocs/core/lib/intracommreport.lib.php @@ -0,0 +1,52 @@ + + * Copyright (C) 2015 ATM Consulting + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/lib/intracommreport.lib.php + * \ingroup Intracomm report + * \brief Library of intracomm report functions + */ + +/** + * Prepare array with list of admin tabs + * + * @return array Array of tabs to show + */ +function intracommReportAdminPrepareHead() +{ + global $langs, $conf; + + $langs->load("intracommreport"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/intracommreport/admin/intracommreport.php", 1); + $head[$h][1] = $langs->trans("Parameters"); + $head[$h][2] = 'general'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname); to remove a tab + complete_head_from_modules($conf, $langs, null, $head, $h, 'intracommreport_admin'); + + complete_head_from_modules($conf, $langs, null, $head, $h, 'intracommreport_admin', 'remove'); + return $head; +} diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php new file mode 100644 index 00000000000..e7d5a704a67 --- /dev/null +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -0,0 +1,246 @@ + + * Copyright (C) 2004-2012 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2019 Alexandre Spangaro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/modules/modIntracommreport.class.php + * \ingroup Intracomm report + * \brief Module to activate intracomm report double entry accounting module + */ +include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; + + +/** + * Description and activation class for module intracommreport + */ +class modIntracommreport extends DolibarrModules +{ + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf, $langs; + + $this->db = $db; + $this->numero = 68000; + + $this->family = "financial"; + $this->module_position = '100'; + // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) + $this->name = preg_replace('/^mod/i', '', get_class($this)); + $this->description = "Intracomm report management (Support for French DEB/DES format)"; + + // Possible values for version are: 'development', 'experimental', 'dolibarr' or 'dolibarr_deprecated' or version + $this->version = 'dolibarr'; + + $this->const_name = 'MAIN_MODULE_' . strtoupper($this->name); + $this->picto = 'intracommreport'; + + // Data directories to create when module is enabled + $this->dirs = array('/intracommreport/temp'); + + // Config pages + $this->config_page_url = array("intracommreport.php"); + + // Dependencies + $this->depends = array("modFacture","modTax"); // List of modules id that must be enabled if this module is enabled + $this->requiredby = array(); // List of modules id to disable if this one is disabled + $this->conflictwith = array(); // List of modules id this module is in conflict with + $this->phpmin = array(5,5); // Minimum version of PHP required by module + $this->need_dolibarr_version = array(9,0); // Minimum version of Dolibarr required by module + $this->langfiles = array("intracommreport"); + + // Constants + // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) + // Example: $this->const=array(0=>array('MYMODULE_MYNEWCONST1','chaine','myvalue','This is a constant to add',1), + // 1=>array('MYMODULE_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1) + // ); + $this->const = array(); + + // Tabs + $this->tabs = array(); + + // Css + $this->module_parts = array(); + + // Boxes + $this->boxes = array(); + + // Dictionaries + if (! isset($conf->intracommreport->enabled)) + { + $conf->intracommreport=new stdClass(); + $conf->intracommreport->enabled=0; + } + $this->dictionaries=array(); + + // Permissions + $this->rights_class = 'intracommreport'; + + $this->rights = array(); // Permission array used by this module + $r = 0; + + // Main menu entries + $this->menu = array(); // List of menus to add + $r=0; + + $langs->load('intracommreport'); + + $this->menu[$r]=array('fk_menu'=>0, // Put 0 if this is a top menu + 'type'=>'top', // This is a Top menu entry + 'titre'=>$langs->trans('intracommreportDouane'), + 'mainmenu'=>'intracommreport', + 'leftmenu'=>'', // Use 1 if you also want to add left menu entries using this descriptor. Use 0 if left menu entries are defined in a file pre.inc.php (old school). + 'url'=>'/intracommreport/export.php', + 'langs'=>'intracommreport@intracommreport', + 'position'=>100, + 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport', // Put 0 if this is a top menu + 'type'=>'left', // This is a Top menu entry + 'titre'=>$langs->trans('intracommreportDEB'), + 'mainmenu'=>'intracommreport', + 'leftmenu'=>'intracommreport', + 'url'=>'/intracommreport/export.php', + 'position'=>100+$r, + 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=intracommreport', // Put 0 if this is a top menu + 'type'=>'left', // This is a Top menu entry + 'titre'=>$langs->trans('intracommreportNew'), + 'mainmenu'=>'intracommreport', + 'leftmenu'=>'intracommreportNew', + 'url'=>'/intracommreport/export.php', + 'position'=>100+$r, + 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=intracommreport', // Put 0 if this is a top menu + 'type'=>'left', // This is a Top menu entry + 'titre'=>$langs->trans('intracommreportList'), + 'mainmenu'=>'intracommreport', + 'leftmenu'=>'intracommreportList', + 'url'=>'/intracommreport/export.php?action=list', + 'position'=>100+$r, + 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport', // Put 0 if this is a top menu + 'type'=>'left', // This is a Top menu entry + 'titre'=>$langs->trans('intracommreportDES'), + 'mainmenu'=>'intracommreport', + 'leftmenu'=>'exportprodes', + 'url'=>'/intracommreport/export.php?exporttype=des', + 'position'=>100+$r, + 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=exportprodes', // Put 0 if this is a top menu + 'type'=>'left', // This is a Top menu entry + 'titre'=>$langs->trans('exportprodesNew'), + 'mainmenu'=>'intracommreport', + 'leftmenu'=>'exportprodes_new', + 'url'=>'/intracommreport/export.php?exporttype=des', + 'position'=>100+$r, + 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=exportprodes', // Put 0 if this is a top menu + 'type'=>'left', // This is a Top menu entry + 'titre'=>$langs->trans('exportprodesList'), + 'mainmenu'=>'intracommreport', + 'leftmenu'=>'exportprodes_list', + 'url'=>'/intracommreport/export.php?exporttype=des&action=list', + 'position'=>100+$r, + 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. + 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + // Exports + $r=1; + + } + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function init($options='') + { + global $db; + + $sql = array(); + + define('INC_FROM_DOLIBARR',true); + + dol_include_once('/intracommreport/config.php'); + dol_include_once('/intracommreport/script/create-maj-base.php'); + + $result=$this->_load_tables('/intracommreport/sql/'); + + $TModesTransport = array( + 'options'=>array( + 1=>'Transport maritime (y compris camions ou wagons sur bateau)' + ,2=>'Transport par chemin de fer (y compris camions sur wagon)' + ,3=>'Transport par route' + ,4=>'Transport par air' + ,5=>'Envois postaux' + ,7=>'Installations de transport fixe (oléoduc)' + ,8=>'Transport par navigation intérieure' + ,9=>'Propulsion propre' + ) + ); + + $e = new ExtraFields($db); + $e->addExtraField('mode_transport', 'Mode de transport', 'select', '', '', 'facture', 0, 0, '', $TModesTransport); + $e->addExtraField('mode_transport', 'Mode de transport', 'select', '', '', 'facture_fourn', 0, 0, '', $TModesTransport); + + return $this->_init($sql, $options); + } + +} diff --git a/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php b/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php new file mode 100644 index 00000000000..73f03fb8039 --- /dev/null +++ b/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php @@ -0,0 +1,571 @@ + + * Copyright (C) 2015 ATM Consulting + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file core/triggers/interface_99_modMyodule_intracommreporttrigger.class.php + * \ingroup intracommreport + * \brief Sample trigger + * \remarks You can create other triggers by copying this one + * - File name should be either: + * interface_99_modMymodule_Mytrigger.class.php + * interface_99_all_Mytrigger.class.php + * - The file must stay in core/triggers + * - The class name must be InterfaceMytrigger + * - The constructor method must be named InterfaceMytrigger + * - The name property name must be Mytrigger + */ + +/** + * Trigger class + */ +class Interfaceintracommreporttrigger +{ + + private $db; + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + + $this->name = preg_replace('/^Interface/i', '', get_class($this)); + $this->family = "demo"; + $this->description = "Triggers of this module are empty functions." + . "They have no effect." + . "They are provided for tutorial purpose only."; + // 'development', 'experimental', 'dolibarr' or version + $this->version = 'development'; + $this->picto = 'intracommreport@intracommreport'; + } + + /** + * Trigger name + * + * @return string Name of trigger file + */ + public function getName() + { + return $this->name; + } + + /** + * Trigger description + * + * @return string Description of trigger file + */ + public function getDesc() + { + return $this->description; + } + + /** + * Trigger version + * + * @return string Version of trigger file + */ + public function getVersion() + { + global $langs; + $langs->load("admin"); + + if ($this->version == 'development') { + return $langs->trans("Development"); + } elseif ($this->version == 'experimental') + + return $langs->trans("Experimental"); + elseif ($this->version == 'dolibarr') return DOL_VERSION; + elseif ($this->version) return $this->version; + else { + return $langs->trans("Unknown"); + } + } + + /** + * Function called when a Dolibarrr business event is done. + * All functions "run_trigger" are triggered if file + * is inside directory core/triggers + * + * @param string $action Event action code + * @param Object $object Object + * @param User $user Object user + * @param Translate $langs Object langs + * @param conf $conf Object conf + * @return int <0 if KO, 0 if no triggered ran, >0 if OK + */ + public function run_trigger($action, $object, $user, $langs, $conf) + { + // Put here code you want to execute when a Dolibarr business events occurs. + // Data and type of action are stored into $object and $action + // Users + if ($action == 'USER_LOGIN') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_UPDATE_SESSION') { + // Warning: To increase performances, this action is triggered only if + // constant MAIN_ACTIVATE_UPDATESESSIONTRIGGER is set to 1. + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_CREATE_FROM_CONTACT') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_NEW_PASSWORD') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_ENABLEDISABLE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_LOGOUT') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_SETINGROUP') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'USER_REMOVEFROMGROUP') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Groups + elseif ($action == 'GROUP_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'GROUP_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'GROUP_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Companies + elseif ($action == 'COMPANY_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'COMPANY_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'COMPANY_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Contacts + elseif ($action == 'CONTACT_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CONTACT_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CONTACT_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Products + elseif ($action == 'PRODUCT_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PRODUCT_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PRODUCT_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Customer orders + elseif ($action == 'ORDER_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'ORDER_CLONE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'ORDER_VALIDATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'ORDER_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'ORDER_BUILDDOC') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'ORDER_SENTBYMAIL') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'LINEORDER_INSERT') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'LINEORDER_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Supplier orders + elseif ($action == 'ORDER_SUPPLIER_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'ORDER_SUPPLIER_VALIDATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'ORDER_SUPPLIER_SENTBYMAIL') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'SUPPLIER_ORDER_BUILDDOC') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Proposals + elseif ($action == 'PROPAL_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_CLONE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_VALIDATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_BUILDDOC') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_SENTBYMAIL') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_CLOSE_SIGNED') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_CLOSE_REFUSED') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROPAL_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'LINEPROPAL_INSERT') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'LINEPROPAL_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'LINEPROPAL_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Contracts + elseif ($action == 'CONTRACT_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CONTRACT_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CONTRACT_ACTIVATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CONTRACT_CANCEL') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CONTRACT_CLOSE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CONTRACT_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Bills + elseif ($action == 'BILL_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'BILL_CLONE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'BILL_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'BILL_VALIDATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'BILL_BUILDDOC') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'BILL_SENTBYMAIL') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'BILL_CANCEL') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'BILL_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'LINEBILL_INSERT') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'LINEBILL_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Payments + elseif ($action == 'PAYMENT_CUSTOMER_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PAYMENT_SUPPLIER_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PAYMENT_ADD_TO_BANK') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PAYMENT_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Interventions + elseif ($action == 'FICHEINTER_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'FICHEINTER_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'FICHEINTER_VALIDATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'FICHEINTER_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Members + elseif ($action == 'MEMBER_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'MEMBER_VALIDATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'MEMBER_SUBSCRIPTION') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'MEMBER_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'MEMBER_NEW_PASSWORD') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'MEMBER_RESILIATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'MEMBER_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Categories + elseif ($action == 'CATEGORY_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CATEGORY_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'CATEGORY_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Projects + elseif ($action == 'PROJECT_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROJECT_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'PROJECT_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Project tasks + elseif ($action == 'TASK_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'TASK_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'TASK_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Task time spent + elseif ($action == 'TASK_TIMESPENT_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'TASK_TIMESPENT_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'TASK_TIMESPENT_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // Shipping + elseif ($action == 'SHIPPING_CREATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'SHIPPING_MODIFY') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'SHIPPING_VALIDATE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'SHIPPING_SENTBYMAIL') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'SHIPPING_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'SHIPPING_BUILDDOC') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + // File + elseif ($action == 'FILE_UPLOAD') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } elseif ($action == 'FILE_DELETE') { + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + } + + return 0; + } +} \ No newline at end of file diff --git a/htdocs/intracommreport/admin/index.html b/htdocs/intracommreport/admin/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php new file mode 100644 index 00000000000..7dcbbc00e2b --- /dev/null +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -0,0 +1,158 @@ + + * Copyright (C) 2019 Open-DSI + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/admin/intracommreport.php + * \ingroup intracommreport + * \brief Page to setup the module intracomm report + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/intracommreport.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("admin","intracommreport")); + +if (! $user->admin) accessforbidden(); + +$action=__get('action',''); + +if($action=='save') { + + foreach($_REQUEST['TParamProDeb'] as $name=>$param) { + + dolibarr_set_const($db, $name, $param); + + } + +} + +/* + * View + */ + +$form=new Form($db); +$formother=new FormOther($db); + +llxHeader('', $langs->trans(IntracommReportSetup)); + +$linkback = '' . $langs->trans("BackToModuleList") . ''; +print load_fiche_titre($langs->trans("IntracommReportSetup"), $linkback, 'title_setup'); + +$head = intracommReportAdminPrepareHead(); + +dol_fiche_head($head, 'general', $langs->trans("IntracommReport"), 0, "intracommreport"); + +print '

'; +print ''; +print ''; + +print ''; +print ''; +print ''."\n"; +print ''; +print ''."\n"; +print ''; + +print ''; +print ''; +print ''; +print ''; + +print ''; +print ''; +print ''; +print ''; + +print ''; +print ''; +print ''; +print ''; + +print ''; +print ''; +print ''; +print ''; + +print ''; +print ''; +print ''; +print ''; + +print ''; +print ''; +print ''; +print ''; + +print '
'.$langs->trans("Parameters").' (DEB) '.$langs->trans("Value").'
'.$langs->trans("INTRACOMMREPORT_NUM_AGREMENT").' '; +print $atmForm->texte('','TParamProDeb[INTRACOMMREPORT_NUM_AGREMENT]',$conf->global->INTRACOMMREPORT_NUM_AGREMENT,30,255); +print '
'.$langs->trans("INTRACOMMREPORT_TYPE_ACTEUR").' '; +print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_TYPE_ACTEUR]', array(''=>'', 'PSI'=>'Déclarant pour son compte', 'TDP'=>'Tiers déclarant'), $conf->global->INTRACOMMREPORT_TYPE_ACTEUR); +print '
'.$langs->trans("INTRACOMMREPORT_ROLE_ACTEUR").' '; +print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_ROLE_ACTEUR]', array(''=>'', 'sender'=>'Emetteur', 'PSI'=>'Déclarant'), $conf->global->INTRACOMMREPORT_ROLE_ACTEUR); +print '
'.$langs->trans("INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION").' '; +print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION]', array(0=>'', 1=>'Seuil de 460 000 €', 2=>'En dessous de 460 000 €'), $conf->global->INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION); +print '
'.$langs->trans("INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION").' '; +print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION]', array(0=>'', 3=>'Seuil de 460 000 €', 4=>'En dessous de 460 000 €'), $conf->global->INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION); +print '
'.$langs->trans("INTRACOMMREPORT_CATEG_FRAISDEPORT").' '; +print $formother->select_categories(0, $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT, 'TParamProDeb[INTRACOMMREPORT_CATEG_FRAISDEPORT]'); +print '
'; + +print '
'; +print '
'; +print ''; +print '
'; +print '
'; + +print ''; + +print '
'; +print ''; +print ''; + +print ''; +print ''; +print ''."\n"; +print ''; +print ''."\n"; +print ''; + +print ''; +print ''; +print ''; +print ''; + +print '
'.$langs->trans("Parameters").' (DES) '.$langs->trans("Value").'
'.$langs->trans("EXPORT_PRO_DES_NUM_DECLARATION").' '; +print $atmForm->texte('','TParamProDeb[EXPORT_PRO_DES_NUM_DECLARATION]',$conf->global->EXPORT_PRO_DES_NUM_DECLARATION,30,255); +print '
'; + +print '
'; +print '
'; +print ''; +print '
'; +print '
'; + +print '
'; + +dol_fiche_end(); + +// End of page +llxFooter(); +$db->close(); \ No newline at end of file diff --git a/htdocs/intracommreport/class/actions_intracommexport.class.php b/htdocs/intracommreport/class/actions_intracommexport.class.php new file mode 100644 index 00000000000..f4bcc53863b --- /dev/null +++ b/htdocs/intracommreport/class/actions_intracommexport.class.php @@ -0,0 +1,88 @@ + + * Copyright (C) 2015 ATM Consulting + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/actions_intracommreport.class.php + * \ingroup intracommreport + * \brief This file is an example hook overload class file + * Put some comments here + */ + +/** + * Class Actionsintracommreport + */ +class Actionsintracommreport +{ + /** + * @var array Hook results. Propagated to $hookmanager->resArray for later reuse + */ + public $results = array(); + + /** + * @var string String displayed by executeHook() immediately after return + */ + public $resprints; + + /** + * @var array Errors + */ + public $errors = array(); + + /** + * Constructor + */ + public function __construct() + { + } + + /** + * Overloading the doActions function : replacing the parent's function with the one below + * + * @param array() $parameters Hook metadatas (context, etc...) + * @param CommonObject &$object The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...) + * @param string &$action Current action (if set). Generally create or edit or null + * @param HookManager $hookmanager Hook manager propagated to allow calling another hook + * @return int < 0 on error, 0 on success, 1 to replace standard code + */ + function doActions($parameters, &$object, &$action, $hookmanager) + { + $error = 0; // Error counter + $myvalue = 'test'; // A result value + + print_r($parameters); + echo "action: " . $action; + print_r($object); + + if (in_array('somecontext', explode(':', $parameters['context']))) + { + // do something only for the context 'somecontext' + } + + if (! $error) + { + $this->results = array('myreturn' => $myvalue); + $this->resprints = 'A text to show'; + return 0; // or return 1 to replace standard code + } + else + { + $this->errors[] = 'Error message'; + return -1; + } + } +} \ No newline at end of file diff --git a/htdocs/intracommreport/class/deb_prodouane.class.php b/htdocs/intracommreport/class/deb_prodouane.class.php new file mode 100644 index 00000000000..01f9f4ba557 --- /dev/null +++ b/htdocs/intracommreport/class/deb_prodouane.class.php @@ -0,0 +1,321 @@ +'Introduction' + ,'expedition'=>'Expédition' + ); + + function __construct(&$ATMdb) { + + $this->ATMdb = $ATMdb; + $this->errors = array(); + parent::set_table(MAIN_DB_PREFIX.'deb_prodouane'); + parent::add_champs('numero_declaration,entity','type=entier;'); + parent::add_champs('type_declaration,periode,mode','type=chaine;'); + parent::add_champs('content_xml','type=text;'); + parent::add_champs('exporttype', array('type'=>'string', 'size'=>'10')); + parent::start(); + parent::_init_vars(); + + $this->exporttype = 'deb'; + } + + + /** + * @param $mode O pour création, R pour régénération (apparemment toujours 0 dans la cadre des échanges XML selon la doc) + * @param $type introduction ou expedition + */ + function getXML($mode='O', $type='introduction', $periode_reference='') { + + global $db, $conf, $mysoc; + + /**************Construction de quelques variables********************/ + $party_id = substr(strtr($mysoc->tva_intra, array(' '=>'')), 0, 4).$mysoc->idprof2; + $declarant = substr($mysoc->managers, 0, 14); + $id_declaration = self::getNumeroDeclaration($this->numero_declaration); + /********************************************************************/ + + /**************Construction du fichier XML***************************/ + $e = new SimpleXMLElement(''); + + $enveloppe = $e->addChild('Envelope'); + $enveloppe->addChild('envelopeId', $conf->global->EXPORT_PRO_DEB_NUM_AGREMENT); + $date_time = $enveloppe->addChild('DateTime'); + $date_time->addChild('date', date('Y-m-d')); + $date_time->addChild('time', date('H:i:s')); + $party = $enveloppe->addChild('Party'); + $party->addAttribute('partType', $conf->global->EXPORT_PRO_DEB_TYPE_ACTEUR); + $party->addAttribute('partyRole', $conf->global->EXPORT_PRO_DEB_ROLE_ACTEUR); + $party->addChild('partyId', $party_id); + $party->addChild('partyName', $declarant); + $enveloppe->addChild('softwareUsed', 'Dolibarr'); + $declaration = $enveloppe->addChild('Declaration'); + $declaration->addChild('declarationId', $id_declaration); + $declaration->addChild('referencePeriod', $periode_reference); + if($conf->global->EXPORT_PRO_DEB_TYPE_ACTEUR === 'PSI') $psiId = $party_id; + else $psiId = 'NA'; + $declaration->addChild('PSIId', $psiId); + $function = $declaration->addChild('Function'); + $functionCode = $function->addChild('functionCode', $mode); + $declaration->addChild('declarationTypeCode', $conf->global->{'EXPORT_PRO_DEB_NIV_OBLIGATION_'.strtoupper($type)}); + $declaration->addChild('flowCode', ($type == 'introduction' ? 'A' : 'D')); + $declaration->addChild('currencyCode', $conf->global->MAIN_MONNAIE); + /********************************************************************/ + + /**************Ajout des lignes de factures**************************/ + $res = self::addItemsFact($declaration, $type, $periode_reference); + /********************************************************************/ + + $this->errors = array_unique($this->errors); + + if(!empty($res)) return $e->asXML(); + else return 0; + + } + + // $type_declaration tjrs = "expedition" à voir si ça évolue + function getXMLDes($period_year, $period_month, $type_declaration='expedition') + { + global $db, $conf, $mysoc; + + + $e = new SimpleXMLElement(''); + + $declaration_des = $e->addChild('declaration_des'); + $declaration_des->addChild('num_des', self::getNumeroDeclaration($this->numero_declaration)); + $declaration_des->addChild('num_tvaFr', $mysoc->tva_intra); // /^FR[a-Z0-9]{2}[0-9]{9}$/ // Doit faire 13 caractères + $declaration_des->addChild('mois_des', $period_month); + $declaration_des->addChild('an_des', $period_year); + + + /**************Ajout des lignes de factures**************************/ + $res = self::addItemsFact($declaration_des, $type_declaration, $period_year.'-'.$period_month, 'des'); + /********************************************************************/ + + $this->errors = array_unique($this->errors); + + if(!empty($res)) return $e->asXML(); + else return 0; + } + + function addItemsFact(&$declaration, $type, $periode_reference, $exporttype='deb') { + + global $db, $conf; + + require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php'; + + $sql = $this->getSQLFactLines($type, $periode_reference, $exporttype); + + $resql = $db->query($sql); + + if($resql) { + $i=1; + + if(empty($resql->num_rows)) { + $this->errors[] = 'Aucune donnée pour cette période'; + return 0; + } + + if($exporttype == 'deb' && $conf->global->EXPORT_PRO_DEB_CATEG_FRAISDEPORT > 0) { + $categ_fraisdeport = new Categorie($db); + $categ_fraisdeport->fetch($conf->global->EXPORT_PRO_DEB_CATEG_FRAISDEPORT); + $TLinesFraisDePort = array(); + } + + while($res = $db->fetch_object($resql)) { + + if ($exporttype == 'des') + { + $this->addItemXMlDes($declaration, $res, '', $i); + } + else + { + if(empty($res->fk_pays)) { + // On n'arrête pas la boucle car on veut savoir quels sont tous les tiers qui n'ont pas de pays renseigné + $this->errors[] = 'Pays non renseigné pour le tiers '.$res->nom.''; + } else { + if($conf->global->EXPORT_PRO_DEB_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) { + $TLinesFraisDePort[] = $res; + } else $this->addItemXMl($declaration, $res, '', $i); + } + } + + $i++; + + } + + if(!empty($TLinesFraisDePort)) $this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i); + + if(count($this->errors) > 0) return 0; + + } + + return 1; + + } + + function getSQLFactLines($type, $periode_reference, $exporttype='deb') { + + global $mysoc, $conf; + + if($type=='expedition' || $exporttype=='des') { + $sql = 'SELECT f.facnumber, f.total as total_ht'; + $table = 'facture'; + $table_extraf = 'facture_extrafields'; + $tabledet = 'facturedet'; + $field_link = 'fk_facture'; + } + else { // Introduction + $sql = 'SELECT f.ref_supplier as facnumber, f.total_ht'; + $table = 'facture_fourn'; + $table_extraf = 'facture_fourn_extrafields'; + $tabledet = 'facture_fourn_det'; + $field_link = 'fk_facture_fourn'; + } + $sql.= ', l.fk_product, l.qty + , p.weight, p.rowid as id_prod, p.customcode + , s.rowid as id_client, s.nom, s.zip, s.fk_pays, s.tva_intra + , c.code + , ext.mode_transport + FROM '.MAIN_DB_PREFIX.$tabledet.' l + INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = l.'.$field_link.') + LEFT JOIN '.MAIN_DB_PREFIX.$table_extraf.' ext ON (ext.fk_object = f.rowid) + INNER JOIN '.MAIN_DB_PREFIX.'product p ON (p.rowid = l.fk_product) + INNER JOIN '.MAIN_DB_PREFIX.'societe s ON (s.rowid = f.fk_soc) + LEFT JOIN '.MAIN_DB_PREFIX.'c_country c ON (c.rowid = s.fk_pays) + WHERE f.fk_statut > 0 + AND l.product_type = '.($exporttype == 'des' ? 1 : 0).' + AND f.entity = '.$conf->entity.' + AND (s.fk_pays <> '.$mysoc->country_id.' OR s.fk_pays IS NULL) + AND f.datef BETWEEN "'.$periode_reference.'-01" AND "'.$periode_reference.'-'.date('t').'"'; + + return $sql; + + } + + function addItemXMl(&$declaration, &$res, $code_douane_spe='', $i) { + + $item = $declaration->addChild('Item'); + $item->addChild('ItemNumber', $i); + $cn8 = $item->addChild('CN8'); + if(empty($code_douane_spe)) $code_douane = $res->customcode; + else $code_douane = $code_douane_spe; + $cn8->addChild('CN8Code', $code_douane); + if(!empty($res->tva_intra)) $item->addChild('partnerId', $res->tva_intra); + $item->addChild('MSConsDestCode', $res->code); // code iso pays client + $item->addChild('netMass', $res->weight * $res->qty); // Poids du produit + $item->addChild('quantityInSU', $res->qty); // Quantité de produit dans la ligne + $item->addChild('invoicedAmount', round($res->total_ht)); // Montant total ht de la facture (entier attendu) + $item->addChild('invoicedNumber', $res->facnumber); // Numéro facture + $item->addChild('statisticalProcedureCode', '11'); + $nature_of_transaction = $item->addChild('NatureOfTransaction'); + $nature_of_transaction->addChild('natureOfTransactionACode', 1); + $nature_of_transaction->addChild('natureOfTransactionBCode', 1); + $item->addChild('modeOfTransportCode', $res->mode_transport); + $item->addChild('regionCode', substr($res->zip, 0, 2)); + + } + + function addItemXMlDes($declaration, &$res, $code_douane_spe='', $i) + { + $item = $declaration->addChild('ligne_des'); + $item->addChild('numlin_des', $i); + $item->addChild('valeur', round($res->total_ht)); // Montant total ht de la facture (entier attendu) + $item->addChild('partner_des', $res->tva_intra); // Représente le numéro TVA du client étranger + } + + /** + * Cette fonction ajoute un item en récupérant le code douane du produit ayant le plus haut montant dans la facture + */ + function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i) { + + global $db, $conf; + + if($type=='expedition') { + $table = 'facture'; + $tabledet = 'facturedet'; + $field_link = 'fk_facture'; + $more_sql = 'f.facnumber'; + } + else { // Introduction + $table = 'facture_fourn'; + $tabledet = 'facture_fourn_det'; + $field_link = 'fk_facture_fourn'; + $more_sql = 'f.ref_supplier'; + } + + foreach($TLinesFraisDePort as $res) { + + $sql = 'SELECT p.customcode + FROM '.MAIN_DB_PREFIX.$tabledet.' d + INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = d.'.$field_link.') + INNER JOIN '.MAIN_DB_PREFIX.'product p ON (p.rowid = d.fk_product) + WHERE d.fk_product IS NOT NULL + AND f.entity = '.$conf->entity.' + AND '.$more_sql.' = "'.$res->facnumber.'" + AND d.total_ht = + ( + SELECT MAX(d.total_ht) + FROM '.MAIN_DB_PREFIX.$tabledet.' d + INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = d.'.$field_link.') + WHERE d.fk_product IS NOT NULL + AND '.$more_sql.' = "'.$res->facnumber.'" + AND d.fk_product NOT IN + ( + SELECT fk_product + FROM '.MAIN_DB_PREFIX.'categorie_product + WHERE fk_categorie = '.$categ_fraisdeport->id.' + ) + )'; + + $resql = $db->query($sql); + $ress = $db->fetch_object($resql); + + $this->addItemXMl($declaration, $res, $ress->customcode, $i); + + $i++; + + } + + } + + function getNextNumeroDeclaration() { + + global $db; + $resql = $db->query('SELECT MAX(numero_declaration) as max_numero_declaration FROM '.$this->get_table().' WHERE exporttype="'.$this->exporttype.'"'); + if($resql) $res = $db->fetch_object($resql); + + return ($res->max_numero_declaration + 1); + + } + + // La doc impose que le numéro soit un entier positif d'un maximum de 6 caractères + static function getNumeroDeclaration($numero) { + + return str_pad($numero, 6, 0, STR_PAD_LEFT); + + } + + function generateXMLFile() { + + $name = $this->periode.'.xml'; + $fname = sys_get_temp_dir().'/'.$name; + $f = fopen($fname, 'w+'); + fwrite($f, $this->content_xml); + fclose($f); + + header('Content-Description: File Transfer'); + header('Content-Type: application/xml'); + header('Content-Disposition: attachment; filename="'.$name.'"'); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: ' . filesize($fname)); + readfile($fname); + exit; + + } + +} diff --git a/htdocs/intracommreport/class/index.html b/htdocs/intracommreport/class/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/intracommreport/export.php b/htdocs/intracommreport/export.php new file mode 100644 index 00000000000..e50b548ea12 --- /dev/null +++ b/htdocs/intracommreport/export.php @@ -0,0 +1,214 @@ +load($PDOdb, GETPOST('id_declaration')); + $obj->generateXMLFile(); + break; + case 'list': + _liste($exporttype); + break; + case 'export': + if ($exporttype == 'deb') _export_xml_deb($type_declaration, $year, str_pad($month, 2, 0, STR_PAD_LEFT)); + else _export_xml_des($type_declaration, $year, str_pad($month, 2, 0, STR_PAD_LEFT)); + default: + if ($exporttype == 'deb') _print_form_deb(); + else _print_form_des(); + break; + +} + + + +function _print_form_deb() { + + global $langs, $ATMform, $formother, $year, $month, $type_declaration; + + $langs->load('intracommreport@intracommreport'); + $langs->load('main'); + + llxHeader(); + print_fiche_titre($langs->trans('intracommreportTitle')); + dol_fiche_head(); + + print '
'; + print ''; + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + print '
'; + print 'Paramètres de l\'export'; + print '
'; + print 'Période d\'analyse'; + print ''; + $TabMonth = array(); + for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); + print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); + print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); + print '
'; + print 'Type de déclaration'; + print ''; + print $ATMform->combo('','type', array('introduction'=>'Introduction', 'expedition'=>'Expédition'), $type_declaration); + print '
'; + + print '
'; + print ''; + print '
'; + + print '
'; + +} + +function _print_form_des() +{ + global $langs, $ATMform, $formother, $year, $month, $type_declaration; + + $langs->load('intracommreport@intracommreport'); + $langs->load('main'); + + llxHeader(); + print_fiche_titre($langs->trans('exportprodesTitle')); + dol_fiche_head(); + + print '
'; + print ''; + print ''; + print ''; + print ''; // Permet d'utiliser le bon select de la requête sql + + print ''; + + print ''; + + print ''; + print ''; + print ''; + print ''; + + print '
'; + print 'Paramètres de l\'export'; + print '
Période d\'analyse'; + $TabMonth = array(); + for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); + print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); + print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); + print '
'; + + print '
'; + print ''; + print '
'; + + print '
'; + +} + +function _export_xml_deb($type_declaration, $period_year, $period_month) { + + global $PDOdb, $conf; + + $obj = new TDebProdouane($PDOdb); + $obj->entity = $conf->entity; + $obj->mode = 'O'; + $obj->periode = $period_year.'-'.$period_month; + $obj->type_declaration = $type_declaration; + $obj->numero_declaration = $obj->getNextNumeroDeclaration(); + $obj->content_xml = $obj->getXML('O', $type_declaration, $period_year.'-'.$period_month); + if(empty($obj->errors)) { + $obj->save($PDOdb); + $obj->generateXMLFile(); + } + else setEventMessage($obj->errors, 'warnings'); + +} + +function _export_xml_des($type_declaration, $period_year, $period_month) { + + global $PDOdb, $conf; + + $obj = new TDebProdouane($PDOdb); + $obj->entity = $conf->entity; + $obj->periode = $period_year.'-'.$period_month; + $obj->type_declaration = $type_declaration; + $obj->exporttype = 'des'; + $obj->numero_declaration = $obj->getNextNumeroDeclaration(); + $obj->content_xml = $obj->getXMLDes($period_year, $period_month, $type_declaration); + if(empty($obj->errors)) { + $obj->save($PDOdb); + $obj->generateXMLFile(); + } + else setEventMessage($obj->errors, 'warnings'); + +} + +function _liste($exporttype='deb') { + + global $db, $conf, $PDOdb, $langs; + + $langs->load('intracommreport@intracommreport'); + + llxHeader(); + $l = new TListviewTBS('intracommreport'); + + $sql = 'SELECT numero_declaration, type_declaration, periode, rowid as dl + FROM '.MAIN_DB_PREFIX.'deb_prodouane + WHERE entity = '.$conf->entity.' AND exporttype = '.$PDOdb->quote($exporttype); + + print $l->render($PDOdb, $sql, array( + 'type'=>array( + //'date_cre'=>'date' + ) + ,'link'=>array( + 'dl'=>''.img_picto('', 'file.png').'' + ) + ,'eval'=>array( + 'numero_declaration'=>'TDebProdouane::getNumeroDeclaration("@val@")' + ,'type_declaration'=>'TDebProdouane::$TType["@val@"]' + ) + ,'liste'=>array( + 'titre'=>$langs->trans('intracommreportList'.$exporttype) + ,'image'=>img_picto('','title.png', '', 0) + ,'picto_precedent'=>img_picto('','back.png', '', 0) + ,'picto_suivant'=>img_picto('','next.png', '', 0) + ,'messageNothing'=>"Il n'y a aucune déclaration à afficher" + ,'picto_search'=>img_picto('','search.png', '', 0) + ) + ,'title'=>array( + 'numero_declaration'=>$langs->trans('intracommreportNumber') + ,'type_declaration'=>$langs->trans('intracommreportTypeDeclaration') + ,'periode'=>$langs->trans('intracommreportPeriod') + ,'dl'=>$langs->trans('intracommreportDownload') + ) + )); + +} + +llxFooter(); diff --git a/htdocs/intracommreport/index.html b/htdocs/intracommreport/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/langs/en_US/intracommreport.lang b/htdocs/langs/en_US/intracommreport.lang new file mode 100644 index 00000000000..8e7d2633b4d --- /dev/null +++ b/htdocs/langs/en_US/intracommreport.lang @@ -0,0 +1,7 @@ +Module104994Name = intracommreport +Module104994Desc = intracommreport Descripion + +ATMAbout = This module has been developed by ATM Consulting
You can find the documentation on our wiki

For any question or feedback, contact us on support@atm-consulting.fr

For any commercial question, contact us on contact@atm-consulting.fr or at +33 9 77 19 50 70

Find our other modules on Dolistore + +intracommreportSetup = intracommreport module setup +intracommreportAbout = About intracommreport \ No newline at end of file diff --git a/htdocs/theme/eldy/img/object_intracommreport.png b/htdocs/theme/eldy/img/object_intracommreport.png new file mode 100644 index 0000000000000000000000000000000000000000..08db8957e9be24fa18c2e5e213a712e5df3be53c GIT binary patch literal 1384 zcmV-u1(*7XP)~Qv_kr3d_2%y1=qemRW|G*_qofEr}_LUz+p- zzfb2RC;$9&&pG#AfCU!#zcW2B@JPq+xMIw*nQ@3wFwLUdpfg(Mf^ffjX2b!DT zAr%S_KRQ}x-?(ulBFR-qE)N%^GZ+g7)3-IxwcMZh6XN0i~$z+S=X7doK)v}aIl@Az8q)NrB z^Yhz9hKc7!Ms|n{Ll`S6suY=-D@m<3nd$0!=}EHIm77p|hdcB%1~32sq9_w0h`Xxg z%ijY4C15NEQCy?U%KDx6`PvalDrGvINp3c4uqg6?Q1nT%gAPBw(LOx?3;+Paq6mWD z|EsO7t-8bBr>BgI%5f~l#U>{^1;5{-Teq%yS*=0{{?LP{;w`bBLnuD3+w%BxrhlVs0jzQCYOqbHVF7Frx&M5nFRJ($lh6>_|;A(pl+g&xieEXz)+Z zd6FV%JiAXIh$0p!ieLfo4cBnUH)|jeWYdS;;o?=rmbQiyTlNBfrx-d9*pDW=8M7l@=^YRxwHb02fU8nj00000~Qv_kr3d_2%y1=qemRW|G*_qofEr}_LUz+p- zzfb2RC;$9&&pG#AfCU!#zcW2B@JPq+xMIw*nQ@3wFwLUdpfg(Mf^ffjX2b!DT zAr%S_KRQ}x-?(ulBFR-qE)N%^GZ+g7)3-IxwcMZh6XN0i~$z+S=X7doK)v}aIl@Az8q)NrB z^Yhz9hKc7!Ms|n{Ll`S6suY=-D@m<3nd$0!=}EHIm77p|hdcB%1~32sq9_w0h`Xxg z%ijY4C15NEQCy?U%KDx6`PvalDrGvINp3c4uqg6?Q1nT%gAPBw(LOx?3;+Paq6mWD z|EsO7t-8bBr>BgI%5f~l#U>{^1;5{-Teq%yS*=0{{?LP{;w`bBLnuD3+w%BxrhlVs0jzQCYOqbHVF7Frx&M5nFRJ($lh6>_|;A(pl+g&xieEXz)+Z zd6FV%JiAXIh$0p!ieLfo4cBnUH)|jeWYdS;;o?=rmbQiyTlNBfrx-d9*pDW=8M7l@=^YRxwHb02fU8nj00000 Date: Sun, 19 May 2019 10:46:55 +0200 Subject: [PATCH 002/317] WIP --- htdocs/intracommreport/admin/intracommreport.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php index 7dcbbc00e2b..7d733886ecb 100644 --- a/htdocs/intracommreport/admin/intracommreport.php +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -64,11 +64,11 @@ print '
'; print ''; print ''; +print ''.$langs->trans("Parameters").' (DEB)'."\n"; print ''; print ''; -print ''."\n"; -print ''; -print ''."\n"; +print ''; +print ''; print ''; print ''; From e81dcb6060e57414d1c695cb0fb53b93701094e3 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 19 May 2019 21:26:49 +0200 Subject: [PATCH 003/317] WIP Update database --- .../mysql/data/llx_c_transport_mode.sql | 31 +++++++++++++++++++ .../install/mysql/migration/9.0.0-10.0.0.sql | 19 ++++++++++++ .../mysql/tables/llx_c_transport_mode.sql | 25 +++++++++++++++ htdocs/install/mysql/tables/llx_facture.sql | 2 ++ .../mysql/tables/llx_facture_fourn.sql | 3 ++ 5 files changed, 80 insertions(+) create mode 100644 htdocs/install/mysql/data/llx_c_transport_mode.sql create mode 100644 htdocs/install/mysql/tables/llx_c_transport_mode.sql diff --git a/htdocs/install/mysql/data/llx_c_transport_mode.sql b/htdocs/install/mysql/data/llx_c_transport_mode.sql new file mode 100644 index 00000000000..98be83ee6ce --- /dev/null +++ b/htdocs/install/mysql/data/llx_c_transport_mode.sql @@ -0,0 +1,31 @@ +-- Copyright (C) 2019 Open-DSI +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- + +-- +-- Ne pas placer de commentaire en fin de ligne, ce fichier est parsé lors +-- de l'install et tous les sigles '--' sont supprimés. +-- + + +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('ROU', 'Transport par route', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('AIR', 'Transport par air', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('POS', 'Envois postaux', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propulsion propre', 1); \ No newline at end of file diff --git a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql index 035cd0d48c5..c30c8e80dd9 100644 --- a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql +++ b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql @@ -376,3 +376,22 @@ insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) v insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) values (113, 'supplier_proposal', 'external', 'SERVICE', 'Contact fournisseur prestation', 1); ALTER TABLE llx_ticket_extrafields ADD INDEX idx_ticket_extrafields (fk_object); + +CREATE TABLE llx_c_transport_mode ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(3) NOT NULL, + libelle varchar(255) NOT NULL, + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; + +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('ROU', 'Transport par route', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('AIR', 'Transport par air', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('POS', 'Envois postaux', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propulsion propre', 1); + +ALTER TABLE llx_facture ADD COLUMN fk_mode_transport integer after location_incoterms; +ALTER TABLE llx_facture_fourn ADD COLUMN fk_mode_transport integer after location_incoterms; diff --git a/htdocs/install/mysql/tables/llx_c_transport_mode.sql b/htdocs/install/mysql/tables/llx_c_transport_mode.sql new file mode 100644 index 00000000000..0528a36a415 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_transport_mode.sql @@ -0,0 +1,25 @@ +-- ======================================================================== +-- Copyright (C) 2019 Open-DSI +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- ======================================================================== + +CREATE TABLE llx_c_transport_mode ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(3) NOT NULL, + libelle varchar(255) NOT NULL, + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; + diff --git a/htdocs/install/mysql/tables/llx_facture.sql b/htdocs/install/mysql/tables/llx_facture.sql index 8e9ceb48d04..c8b716d99a2 100644 --- a/htdocs/install/mysql/tables/llx_facture.sql +++ b/htdocs/install/mysql/tables/llx_facture.sql @@ -84,6 +84,8 @@ create table llx_facture fk_incoterms integer, -- for incoterms location_incoterms varchar(255), -- for incoterms + fk_mode_transport integer, -- for intracomm report + situation_cycle_ref smallint, -- situation cycle reference situation_counter smallint, -- situation counter situation_final smallint, -- is the situation final ? diff --git a/htdocs/install/mysql/tables/llx_facture_fourn.sql b/htdocs/install/mysql/tables/llx_facture_fourn.sql index 36ee0a69f18..0f116443b6d 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn.sql @@ -70,6 +70,9 @@ create table llx_facture_fourn note_public text, fk_incoterms integer, -- for incoterms location_incoterms varchar(255), -- for incoterms + + fk_mode_transport integer, -- for intracomm report + model_pdf varchar(255), last_main_doc varchar(255), -- relative filepath+filename of last main generated document From a239e0e81fcb7b00e2fb8750945472e085a4b946 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 20 May 2019 13:33:54 +0200 Subject: [PATCH 004/317] WIP Admin --- build/rpm/dolibarr_fedora.spec | 1 + build/rpm/dolibarr_generic.spec | 1 + build/rpm/dolibarr_mandriva.spec | 1 + build/rpm/dolibarr_opensuse.spec | 1 + .../core/modules/modIntracommreport.class.php | 44 +---- .../intracommreport/admin/intracommreport.php | 167 +++++++++++------- htdocs/langs/en_US/intracommreport.lang | 38 +++- 7 files changed, 145 insertions(+), 108 deletions(-) diff --git a/build/rpm/dolibarr_fedora.spec b/build/rpm/dolibarr_fedora.spec index b6d526bf8e1..1a9aa1c0476 100755 --- a/build/rpm/dolibarr_fedora.spec +++ b/build/rpm/dolibarr_fedora.spec @@ -194,6 +194,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/imports %_datadir/dolibarr/htdocs/includes %_datadir/dolibarr/htdocs/install +%_datadir/dolibarr/htdocs/intracommreport %_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt %_datadir/dolibarr/htdocs/livraison %_datadir/dolibarr/htdocs/loan diff --git a/build/rpm/dolibarr_generic.spec b/build/rpm/dolibarr_generic.spec index 32c6e50018e..b14e3d107f4 100755 --- a/build/rpm/dolibarr_generic.spec +++ b/build/rpm/dolibarr_generic.spec @@ -274,6 +274,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/imports %_datadir/dolibarr/htdocs/includes %_datadir/dolibarr/htdocs/install +%_datadir/dolibarr/htdocs/intracommreport %_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt %_datadir/dolibarr/htdocs/livraison %_datadir/dolibarr/htdocs/loan diff --git a/build/rpm/dolibarr_mandriva.spec b/build/rpm/dolibarr_mandriva.spec index dbb8e0d1310..91d36e77bd7 100755 --- a/build/rpm/dolibarr_mandriva.spec +++ b/build/rpm/dolibarr_mandriva.spec @@ -191,6 +191,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/imports %_datadir/dolibarr/htdocs/includes %_datadir/dolibarr/htdocs/install +%_datadir/dolibarr/htdocs/intracommreport %_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt %_datadir/dolibarr/htdocs/livraison %_datadir/dolibarr/htdocs/loan diff --git a/build/rpm/dolibarr_opensuse.spec b/build/rpm/dolibarr_opensuse.spec index aa810a737b9..a4adb450219 100755 --- a/build/rpm/dolibarr_opensuse.spec +++ b/build/rpm/dolibarr_opensuse.spec @@ -202,6 +202,7 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/imports %_datadir/dolibarr/htdocs/includes %_datadir/dolibarr/htdocs/install +%_datadir/dolibarr/htdocs/intracommreport %_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt %_datadir/dolibarr/htdocs/livraison %_datadir/dolibarr/htdocs/loan diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index e7d5a704a67..6d2d4171a77 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -59,7 +59,7 @@ class modIntracommreport extends DolibarrModules $this->dirs = array('/intracommreport/temp'); // Config pages - $this->config_page_url = array("intracommreport.php"); + $this->config_page_url = array("intracommreport.php@intracommreport"); // Dependencies $this->depends = array("modFacture","modTax"); // List of modules id that must be enabled if this module is enabled @@ -201,46 +201,4 @@ class modIntracommreport extends DolibarrModules $r=1; } - - /** - * Function called when module is enabled. - * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. - * It also creates data directories - * - * @param string $options Options when enabling module ('', 'noboxes') - * @return int 1 if OK, 0 if KO - */ - function init($options='') - { - global $db; - - $sql = array(); - - define('INC_FROM_DOLIBARR',true); - - dol_include_once('/intracommreport/config.php'); - dol_include_once('/intracommreport/script/create-maj-base.php'); - - $result=$this->_load_tables('/intracommreport/sql/'); - - $TModesTransport = array( - 'options'=>array( - 1=>'Transport maritime (y compris camions ou wagons sur bateau)' - ,2=>'Transport par chemin de fer (y compris camions sur wagon)' - ,3=>'Transport par route' - ,4=>'Transport par air' - ,5=>'Envois postaux' - ,7=>'Installations de transport fixe (oléoduc)' - ,8=>'Transport par navigation intérieure' - ,9=>'Propulsion propre' - ) - ); - - $e = new ExtraFields($db); - $e->addExtraField('mode_transport', 'Mode de transport', 'select', '', '', 'facture', 0, 0, '', $TModesTransport); - $e->addExtraField('mode_transport', 'Mode de transport', 'select', '', '', 'facture_fourn', 0, 0, '', $TModesTransport); - - return $this->_init($sql, $options); - } - } diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php index 7d733886ecb..68531304206 100644 --- a/htdocs/intracommreport/admin/intracommreport.php +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -32,16 +32,54 @@ $langs->loadLangs(array("admin","intracommreport")); if (! $user->admin) accessforbidden(); -$action=__get('action',''); +$action = GETPOST('action', 'aZ09'); -if($action=='save') { - - foreach($_REQUEST['TParamProDeb'] as $name=>$param) { - - dolibarr_set_const($db, $name, $param); +// Parameters ACCOUNTING_* and others +$list_DEB = array ( + 'INTRACOMMREPORT_NUM_AGREMENT', +); - } - +$list_DES = array ( + 'INTRACOMMREPORT_NUM_DECLARATION', +); + +if ($action == 'update') { + $error = 0; + + if (! $error) + { + foreach ($list_DEB as $constname) + { + $constvalue = GETPOST($constname, 'alpha'); + + if (! dolibarr_set_const($db, $constname, $constvalue, 'chaine', 0, '', $conf->entity)) { + $error++; + } + } + + foreach ($list_DES as $constname) + { + $constvalue = GETPOST($constname, 'alpha'); + + if (! dolibarr_set_const($db, $constname, $constvalue, 'chaine', 0, '', $conf->entity)) { + $error++; + } + } + + dolibarr_set_const($db, "INTRACOMMREPORT_TYPE_ACTEUR", GETPOST("INTRACOMMREPORT_TYPE_ACTEUR", 'alpha'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "INTRACOMMREPORT_ROLE_ACTEUR", GETPOST("INTRACOMMREPORT_ROLE_ACTEUR", 'alpha'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION", GETPOST("INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION", 'alpha'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION", GETPOST("INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION", 'alpha'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "INTRACOMMREPORT_CATEG_FRAISDEPORT", GETPOST("INTRACOMMREPORT_CATEG_FRAISDEPORT", 'alpha'), 'chaine', 0, '', $conf->entity); + + if ($error) { + setEventMessages($langs->trans("Error"), null, 'errors'); + } + } + + if (! $error) { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } } /* @@ -51,7 +89,7 @@ if($action=='save') { $form=new Form($db); $formother=new FormOther($db); -llxHeader('', $langs->trans(IntracommReportSetup)); +llxHeader('', $langs->trans("IntracommReportSetup")); $linkback = '' . $langs->trans("BackToModuleList") . ''; print load_fiche_titre($langs->trans("IntracommReportSetup"), $linkback, 'title_setup'); @@ -60,9 +98,9 @@ $head = intracommReportAdminPrepareHead(); dol_fiche_head($head, 'general', $langs->trans("IntracommReport"), 0, "intracommreport"); -print ''; -print ''; -print ''; +print ''; +print ''; +print ''; print ''."\n"; print '
'.$langs->trans("Parameters").' (DEB) '.$langs->trans("Value").''.$langs->trans("Description").''.$langs->trans("Value").'
'.$langs->trans("Parameters").' (DEB)
'; @@ -71,76 +109,85 @@ print ''; print ''; print ''; -print ''; -print ''; -print ''; -print ''; +foreach ($list_DEB as $key) +{ + print ''; + + // Param + $label = $langs->trans($key); + print ''; + // Value + print ''; + + print ''; +} print ''; print ''; -print ''; -print ''; +$arraychoices=array(''=>$langs->trans("None"), 'PSI'=>'Déclarant pour son compte', 'TDP'=>'Tiers déclarant'); +print ''; +print "\n"; print ''; print ''; -print ''; -print ''; +$arraychoices=array(''=>$langs->trans("None"), 'sender'=>'Emetteur', 'PSI'=>'Déclarant'); +print ''; +print "\n"; print ''; print ''; -print ''; -print ''; +$arraychoices=array(1=>'Seuil de 460 000 €', 2=>'En dessous de 460 000 €'); +print ''; +print "\n"; print ''; print ''; -print ''; -print ''; +$arraychoices=array(3=>'Seuil de 460 000 €', 4=>'En dessous de 460 000 €'); +print ''; +print "\n"; print ''; print ''; -print ''; -print ''; +$arraychoices=array(3=>'Seuil de 460 000 €', 4=>'En dessous de 460 000 €'); +print ''; +print "\n"; print '
'.$langs->trans("Description").''.$langs->trans("Value").'
'.$langs->trans("INTRACOMMREPORT_NUM_AGREMENT").' '; -print $atmForm->texte('','TParamProDeb[INTRACOMMREPORT_NUM_AGREMENT]',$conf->global->INTRACOMMREPORT_NUM_AGREMENT,30,255); -print '
'.$label.''; + print ''; + print '
'.$langs->trans("INTRACOMMREPORT_TYPE_ACTEUR").' '; -print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_TYPE_ACTEUR]', array(''=>'', 'PSI'=>'Déclarant pour son compte', 'TDP'=>'Tiers déclarant'), $conf->global->INTRACOMMREPORT_TYPE_ACTEUR); -print '
'; +print $form->selectarray('INTRACOMMREPORT_TYPE_ACTEUR', $arraychoices, $conf->global->INTRACOMMREPORT_TYPE_ACTEUR, 0); +print '
'.$langs->trans("INTRACOMMREPORT_ROLE_ACTEUR").' '; -print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_ROLE_ACTEUR]', array(''=>'', 'sender'=>'Emetteur', 'PSI'=>'Déclarant'), $conf->global->INTRACOMMREPORT_ROLE_ACTEUR); -print '
'; +print $form->selectarray('INTRACOMMREPORT_ROLE_ACTEUR', $arraychoices, $conf->global->INTRACOMMREPORT_ROLE_ACTEUR, 0); +print '
'.$langs->trans("INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION").' '; -print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION]', array(0=>'', 1=>'Seuil de 460 000 €', 2=>'En dessous de 460 000 €'), $conf->global->INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION); -print '
'; +print $form->selectarray('INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION', $arraychoices, $conf->global->INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION, 0); +print '
'.$langs->trans("INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION").' '; -print $atmForm->combo('','TParamProDeb[INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION]', array(0=>'', 3=>'Seuil de 460 000 €', 4=>'En dessous de 460 000 €'), $conf->global->INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION); -print '
'; +print $form->selectarray('INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION', $arraychoices, $conf->global->INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION, 0); +print '
'.$langs->trans("INTRACOMMREPORT_CATEG_FRAISDEPORT").' '; -print $formother->select_categories(0, $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT, 'TParamProDeb[INTRACOMMREPORT_CATEG_FRAISDEPORT]'); -print '
'; +print $formother->select_categories(0, $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT, 'INTRACOMMREPORT_CATEG_FRAISDEPORT'); +print '
'; -print '
'; -print '
'; -print ''; -print '
'; -print '
'; - -print '
'; - -print '
'; -print ''; -print ''; - +print ''.$langs->trans("Parameters").' (DES)'."\n"; print ''; print ''; -print ''."\n"; -print ''; -print ''."\n"; +print ''; +print ''; print ''; -print ''; -print ''; -print ''; -print ''; - +foreach ($list_DES as $key) +{ + print ''; + + // Param + $label = $langs->trans($key); + print ''; + // Value + print ''; + + print ''; +} + print '
'.$langs->trans("Parameters").' (DES) '.$langs->trans("Value").''.$langs->trans("Description").''.$langs->trans("Value").'
'.$langs->trans("EXPORT_PRO_DES_NUM_DECLARATION").' '; -print $atmForm->texte('','TParamProDeb[EXPORT_PRO_DES_NUM_DECLARATION]',$conf->global->EXPORT_PRO_DES_NUM_DECLARATION,30,255); -print '
'.$label.''; + print ''; + print '
'; print '
'; diff --git a/htdocs/langs/en_US/intracommreport.lang b/htdocs/langs/en_US/intracommreport.lang index 8e7d2633b4d..8d2b891ed8e 100644 --- a/htdocs/langs/en_US/intracommreport.lang +++ b/htdocs/langs/en_US/intracommreport.lang @@ -1,7 +1,35 @@ -Module104994Name = intracommreport -Module104994Desc = intracommreport Descripion +Module68000Name = Intracomm report +Module68000Desc = Intracomm report management (Support for French DEB/DES format) +IntracommReportSetup = Intracommreport module setup +IntracommReportAbout = About intracommreport -ATMAbout = This module has been developed by ATM Consulting
You can find the documentation on our wiki

For any question or feedback, contact us on support@atm-consulting.fr

For any commercial question, contact us on contact@atm-consulting.fr or at +33 9 77 19 50 70

Find our other modules on Dolistore +#Conf +INTRACOMMREPORT_NUM_AGREMENT=Numéro d'agrément (délivré par le CISD de rattachement) +INTRACOMMREPORT_TYPE_ACTEUR=Type d'acteur +INTRACOMMREPORT_ROLE_ACTEUR=Rôle joué par l'acteur +INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION=Niveau d'oligation sur les introductions +INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION=Niveau d'obligation sur les expéditions +INTRACOMMREPORT_CATEG_FRAISDEPORT=Catégorie de services de type "Frais de port" -intracommreportSetup = intracommreport module setup -intracommreportAbout = About intracommreport \ No newline at end of file +INTRACOMMREPORT_NUM_DECLARATION=Numéro de déclarant + +#Menu +exportprodebDouane=Export Pro-Douane +exportprodebDEB=Export DEB +exportprodebNew=Nouvelle déclaration +exportprodebList=Liste des déclarations +exportprodebDES=Export DES +exportprodesNew=Nouvelle déclaration +exportprodesList=Liste des déclarations + +#page d'export +exportprodebTitle=Export d'un fichier XML au format ProDouane - DEB +exportprodesTitle=Export d'un fichier XML au format ProDouane - DES + +#Liste +exportprodebListdeb=Liste des déclarations générées (DEB) +exportprodebListdes=Liste des déclarations générées (DES) +exportprodebNumber=Numéro déclaration +exportprodebPeriod=Période d'analyse +exportprodebTypeDeclaration=Type de déclaration +exportprodebDownload=Télécharger fichier XML \ No newline at end of file From ba4bd274c07dc62977dfd5643acc30e297c0786d Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 20 May 2019 14:52:06 +0200 Subject: [PATCH 005/317] WIP --- .../install/mysql/migration/9.0.0-10.0.0.sql | 13 ++++ .../mysql/tables/llx_intracommreport.sql | 30 +++++++++ ...ne.class.php => intracommreport.class.php} | 62 ++++++++++++++----- htdocs/intracommreport/export.php | 32 ++++++++-- 4 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 htdocs/install/mysql/tables/llx_intracommreport.sql rename htdocs/intracommreport/class/{deb_prodouane.class.php => intracommreport.class.php} (85%) diff --git a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql index c30c8e80dd9..f53a67b4d2c 100644 --- a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql +++ b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql @@ -395,3 +395,16 @@ INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propuls ALTER TABLE llx_facture ADD COLUMN fk_mode_transport integer after location_incoterms; ALTER TABLE llx_facture_fourn ADD COLUMN fk_mode_transport integer after location_incoterms; + +create table llx_intracommreport +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + + ref varchar(30) NOT NULL, -- report reference number + entity integer DEFAULT 1 NOT NULL, -- multi company id + type_declaration varchar(32), + periode varchar(32), + mode varchar(32), + content_xml text, + exporttype varchar(10) +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_intracommreport.sql b/htdocs/install/mysql/tables/llx_intracommreport.sql new file mode 100644 index 00000000000..e3b27d2de7c --- /dev/null +++ b/htdocs/install/mysql/tables/llx_intracommreport.sql @@ -0,0 +1,30 @@ +-- =================================================================== +-- Copyright (C) 2019 Open-DSI +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- =================================================================== + +create table llx_intracommreport +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + + ref varchar(30) NOT NULL, -- report reference number + entity integer DEFAULT 1 NOT NULL, -- multi company id + type_declaration varchar(32), + periode varchar(32), + mode varchar(32), + content_xml text, + exporttype varchar(10) +)ENGINE=innodb; diff --git a/htdocs/intracommreport/class/deb_prodouane.class.php b/htdocs/intracommreport/class/intracommreport.class.php similarity index 85% rename from htdocs/intracommreport/class/deb_prodouane.class.php rename to htdocs/intracommreport/class/intracommreport.class.php index 01f9f4ba557..0f7c0db9c32 100644 --- a/htdocs/intracommreport/class/deb_prodouane.class.php +++ b/htdocs/intracommreport/class/intracommreport.class.php @@ -1,16 +1,49 @@ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ -class TDebProdouane extends TObjetStd { +/** + * \file htdocs/intracommreport/class/intracommreport.class.php + * \ingroup Intracomm report + * \brief File of class to manage intracomm report + */ + +/** + * Class to manage intracomm report + */ +class DebProdouane extends CommonObject +{ static $TType = array( 'introduction'=>'Introduction' ,'expedition'=>'Expédition' ); - - function __construct(&$ATMdb) { - - $this->ATMdb = $ATMdb; - $this->errors = array(); + + /** + * Constructor + * + * @param DoliDB $db Database handle + */ + public function __construct($db) + { + global $conf; + + $this->db = $db; + + /* parent::set_table(MAIN_DB_PREFIX.'deb_prodouane'); parent::add_champs('numero_declaration,entity','type=entier;'); parent::add_champs('type_declaration,periode,mode','type=chaine;'); @@ -18,6 +51,7 @@ class TDebProdouane extends TObjetStd { parent::add_champs('exporttype', array('type'=>'string', 'size'=>'10')); parent::start(); parent::_init_vars(); + */ $this->exporttype = 'deb'; } @@ -41,25 +75,25 @@ class TDebProdouane extends TObjetStd { $e = new SimpleXMLElement(''); $enveloppe = $e->addChild('Envelope'); - $enveloppe->addChild('envelopeId', $conf->global->EXPORT_PRO_DEB_NUM_AGREMENT); + $enveloppe->addChild('envelopeId', $conf->global->INTRACOMMREPORT_NUM_AGREMENT); $date_time = $enveloppe->addChild('DateTime'); $date_time->addChild('date', date('Y-m-d')); $date_time->addChild('time', date('H:i:s')); $party = $enveloppe->addChild('Party'); - $party->addAttribute('partType', $conf->global->EXPORT_PRO_DEB_TYPE_ACTEUR); - $party->addAttribute('partyRole', $conf->global->EXPORT_PRO_DEB_ROLE_ACTEUR); + $party->addAttribute('partType', $conf->global->INTRACOMMREPORT_TYPE_ACTEUR); + $party->addAttribute('partyRole', $conf->global->INTRACOMMREPORT_ROLE_ACTEUR); $party->addChild('partyId', $party_id); $party->addChild('partyName', $declarant); $enveloppe->addChild('softwareUsed', 'Dolibarr'); $declaration = $enveloppe->addChild('Declaration'); $declaration->addChild('declarationId', $id_declaration); $declaration->addChild('referencePeriod', $periode_reference); - if($conf->global->EXPORT_PRO_DEB_TYPE_ACTEUR === 'PSI') $psiId = $party_id; + if($conf->global->INTRACOMMREPORT_TYPE_ACTEUR === 'PSI') $psiId = $party_id; else $psiId = 'NA'; $declaration->addChild('PSIId', $psiId); $function = $declaration->addChild('Function'); $functionCode = $function->addChild('functionCode', $mode); - $declaration->addChild('declarationTypeCode', $conf->global->{'EXPORT_PRO_DEB_NIV_OBLIGATION_'.strtoupper($type)}); + $declaration->addChild('declarationTypeCode', $conf->global->{'INTRACOMMREPORT_NIV_OBLIGATION_'.strtoupper($type)}); $declaration->addChild('flowCode', ($type == 'introduction' ? 'A' : 'D')); $declaration->addChild('currencyCode', $conf->global->MAIN_MONNAIE); /********************************************************************/ @@ -118,9 +152,9 @@ class TDebProdouane extends TObjetStd { return 0; } - if($exporttype == 'deb' && $conf->global->EXPORT_PRO_DEB_CATEG_FRAISDEPORT > 0) { + if($exporttype == 'deb' && $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0) { $categ_fraisdeport = new Categorie($db); - $categ_fraisdeport->fetch($conf->global->EXPORT_PRO_DEB_CATEG_FRAISDEPORT); + $categ_fraisdeport->fetch($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT); $TLinesFraisDePort = array(); } @@ -136,7 +170,7 @@ class TDebProdouane extends TObjetStd { // On n'arrête pas la boucle car on veut savoir quels sont tous les tiers qui n'ont pas de pays renseigné $this->errors[] = 'Pays non renseigné pour le tiers '.$res->nom.''; } else { - if($conf->global->EXPORT_PRO_DEB_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) { + if($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) { $TLinesFraisDePort[] = $res; } else $this->addItemXMl($declaration, $res, '', $i); } diff --git a/htdocs/intracommreport/export.php b/htdocs/intracommreport/export.php index e50b548ea12..c15231f7ed4 100644 --- a/htdocs/intracommreport/export.php +++ b/htdocs/intracommreport/export.php @@ -1,16 +1,38 @@ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ -require './config.php'; +/** + * \file htdocs/intracommreport/export.php + * \ingroup Intracomm report + * \brief Page to manage intracomm report export + */ +require_once '../main.inc.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php'; -dol_include_once('/intracommreport/class/deb_prodouane.class.php'); +require_once DOL_DOCUMENT_ROOT . '/intracommreport/class/intracommreport.class.php'; $action = GETPOST('action'); $exporttype = GETPOST('exporttype'); // DEB ou DES if (empty($exporttype)) $exporttype = 'deb'; +/* $PDOdb = new TPDOdb; $ATMform = new TFormCore; +*/ $formother = new FormOther($db); $year = GETPOST('year'); $month = GETPOST('month'); @@ -65,7 +87,7 @@ function _print_form_deb() { print ''; $TabMonth = array(); for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); - print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); + //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); print ''; print ''; @@ -74,7 +96,7 @@ function _print_form_deb() { print 'Type de déclaration'; print ''; print ''; - print $ATMform->combo('','type', array('introduction'=>'Introduction', 'expedition'=>'Expédition'), $type_declaration); + //print $ATMform->combo('','type', array('introduction'=>'Introduction', 'expedition'=>'Expédition'), $type_declaration); print ''; print ''; @@ -116,7 +138,7 @@ function _print_form_des() print ''; $TabMonth = array(); for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); - print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); + //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); print ''; print ''; From 11015dd0726e98727cc3252226a9b35ae1f8052c Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Tue, 21 May 2019 09:55:41 +0200 Subject: [PATCH 006/317] WIP --- htdocs/core/boxes/intracommreport_box.php | 2 +- htdocs/core/menus/standard/eldy.lib.php | 16 +++ .../core/modules/modIntracommreport.class.php | 123 +++--------------- ...ommreport_intracommreporttrigger.class.php | 2 +- .../class/intracommreport.class.php | 4 +- htdocs/intracommreport/export.php | 44 +++---- 6 files changed, 60 insertions(+), 131 deletions(-) diff --git a/htdocs/core/boxes/intracommreport_box.php b/htdocs/core/boxes/intracommreport_box.php index 1e7c9dd1725..1758b2ffda4 100644 --- a/htdocs/core/boxes/intracommreport_box.php +++ b/htdocs/core/boxes/intracommreport_box.php @@ -31,7 +31,7 @@ class intracommreportbox extends ModeleBoxes { public $boxcode = "mybox"; - public $boximg = "intracommreport@intracommreport"; + public $boximg = "intracommreport"; public $boxlabel; public $depends = array("intracommreport"); public $db; diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index fc639802e7f..a82168f34a6 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1360,6 +1360,22 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM //if ($leftmenu=="ca") $newmenu->add("/compta/journaux/index.php?leftmenu=ca",$langs->trans("Journaux"),1,$user->rights->compta->resultat->lire||$user->rights->accounting->comptarapport->lire); } + // Intracomm report + if (! empty($conf->intracommreport->enabled)) + { + $newmenu->add("/intracommreport/export.php?leftmenu=intracommreport", $langs->trans("MenuDeclaration"), 0, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); + if ($usemenuhider || empty($leftmenu) || preg_match('/intracommreport/', $leftmenu)) { + // DEB + $newmenu->add("/intracommreport/export.php?leftmenu=intracommreport", $langs->trans("MenuDeclarationDEB"), 1, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreportDEB', 1); + $newmenu->add("/intracommreport/export.php?leftmenu=intracommreportDEB", $langs->trans("MenuDeclarationDEBNew"), 2, $user->rights->intracommreport->write, '', $mainmenu, 'intracommreport', 1); + $newmenu->add("/intracommreport/export.php?action=list&leftmenu=intracommreportDEB", $langs->trans("MenuDeclarationDEBList"), 2, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); + // DES + $newmenu->add("/intracommreport/export.php?exporttype=des&leftmenu=intracommreport", $langs->trans("MenuDeclarationDES"), 1, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreportDES', 1); + $newmenu->add("/intracommreport/export.php?exporttype=des&leftmenu=intracommreportDES", $langs->trans("MenuDeclarationDESNew"), 2, $user->rights->intracommreport->write, '', $mainmenu, 'intracommreport', 1); + $newmenu->add("/intracommreport/export.php?exporttype=des&action=list&leftmenu=intracommreportDES", $langs->trans("MenuDeclarationDESList"), 2, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); + } + } + // Assets if (! empty($conf->asset->enabled)) { diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index 6d2d4171a77..943e269c19c 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -1,8 +1,8 @@ - * Copyright (C) 2004-2012 Laurent Destailleur - * Copyright (C) 2005-2012 Regis Houssin - * Copyright (C) 2019 Alexandre Spangaro +/* Copyright (C) 2003 Rodolphe Quiedeville + * Copyright (C) 2004-2012 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2019 Open-DSI * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ /** * \file htdocs/core/modules/modIntracommreport.class.php * \ingroup Intracomm report - * \brief Module to activate intracomm report double entry accounting module + * \brief Module to activate intracomm report module */ include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; @@ -50,7 +50,7 @@ class modIntracommreport extends DolibarrModules $this->description = "Intracomm report management (Support for French DEB/DES format)"; // Possible values for version are: 'development', 'experimental', 'dolibarr' or 'dolibarr_deprecated' or version - $this->version = 'dolibarr'; + $this->version = 'development'; $this->const_name = 'MAIN_MODULE_' . strtoupper($this->name); $this->picto = 'intracommreport'; @@ -95,108 +95,27 @@ class modIntracommreport extends DolibarrModules // Permissions $this->rights_class = 'intracommreport'; - $this->rights = array(); // Permission array used by this module $r = 0; + $r++; + $this->rights[$r][0] = 68001; + $this->rights[$r][1] = 'Read intracomm report'; + $this->rights[$r][2] = 'r'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'read'; + + $r++; + $this->rights[$r][0] = 68002; + $this->rights[$r][1] = 'Create/modify intracomm report'; + $this->rights[$r][2] = 'w'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'write'; + // Main menu entries $this->menu = array(); // List of menus to add $r=0; - - $langs->load('intracommreport'); - - $this->menu[$r]=array('fk_menu'=>0, // Put 0 if this is a top menu - 'type'=>'top', // This is a Top menu entry - 'titre'=>$langs->trans('intracommreportDouane'), - 'mainmenu'=>'intracommreport', - 'leftmenu'=>'', // Use 1 if you also want to add left menu entries using this descriptor. Use 0 if left menu entries are defined in a file pre.inc.php (old school). - 'url'=>'/intracommreport/export.php', - 'langs'=>'intracommreport@intracommreport', - 'position'=>100, - 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. - 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $r++; - - $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport', // Put 0 if this is a top menu - 'type'=>'left', // This is a Top menu entry - 'titre'=>$langs->trans('intracommreportDEB'), - 'mainmenu'=>'intracommreport', - 'leftmenu'=>'intracommreport', - 'url'=>'/intracommreport/export.php', - 'position'=>100+$r, - 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. - 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $r++; - - $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=intracommreport', // Put 0 if this is a top menu - 'type'=>'left', // This is a Top menu entry - 'titre'=>$langs->trans('intracommreportNew'), - 'mainmenu'=>'intracommreport', - 'leftmenu'=>'intracommreportNew', - 'url'=>'/intracommreport/export.php', - 'position'=>100+$r, - 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. - 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $r++; - - $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=intracommreport', // Put 0 if this is a top menu - 'type'=>'left', // This is a Top menu entry - 'titre'=>$langs->trans('intracommreportList'), - 'mainmenu'=>'intracommreport', - 'leftmenu'=>'intracommreportList', - 'url'=>'/intracommreport/export.php?action=list', - 'position'=>100+$r, - 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. - 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $r++; - - $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport', // Put 0 if this is a top menu - 'type'=>'left', // This is a Top menu entry - 'titre'=>$langs->trans('intracommreportDES'), - 'mainmenu'=>'intracommreport', - 'leftmenu'=>'exportprodes', - 'url'=>'/intracommreport/export.php?exporttype=des', - 'position'=>100+$r, - 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. - 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $r++; - - $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=exportprodes', // Put 0 if this is a top menu - 'type'=>'left', // This is a Top menu entry - 'titre'=>$langs->trans('exportprodesNew'), - 'mainmenu'=>'intracommreport', - 'leftmenu'=>'exportprodes_new', - 'url'=>'/intracommreport/export.php?exporttype=des', - 'position'=>100+$r, - 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. - 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $r++; - - $this->menu[$r]=array('fk_menu'=>'fk_mainmenu=intracommreport,fk_leftmenu=exportprodes', // Put 0 if this is a top menu - 'type'=>'left', // This is a Top menu entry - 'titre'=>$langs->trans('exportprodesList'), - 'mainmenu'=>'intracommreport', - 'leftmenu'=>'exportprodes_list', - 'url'=>'/intracommreport/export.php?exporttype=des&action=list', - 'position'=>100+$r, - 'enabled'=>'$conf->intracommreport->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. - 'perms'=>1, // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $r++; - + // Exports $r=1; diff --git a/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php b/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php index 73f03fb8039..ddbb5df329b 100644 --- a/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php +++ b/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php @@ -54,7 +54,7 @@ class Interfaceintracommreporttrigger . "They are provided for tutorial purpose only."; // 'development', 'experimental', 'dolibarr' or version $this->version = 'development'; - $this->picto = 'intracommreport@intracommreport'; + $this->picto = 'intracommreport'; } /** diff --git a/htdocs/intracommreport/class/intracommreport.class.php b/htdocs/intracommreport/class/intracommreport.class.php index 0f7c0db9c32..af8a244deec 100644 --- a/htdocs/intracommreport/class/intracommreport.class.php +++ b/htdocs/intracommreport/class/intracommreport.class.php @@ -24,10 +24,10 @@ /** * Class to manage intracomm report */ -class DebProdouane extends CommonObject +class IntracommReport extends CommonObject { - static $TType = array( + static $type = array( 'introduction'=>'Introduction' ,'expedition'=>'Expédition' ); diff --git a/htdocs/intracommreport/export.php b/htdocs/intracommreport/export.php index c15231f7ed4..5a61a62a581 100644 --- a/htdocs/intracommreport/export.php +++ b/htdocs/intracommreport/export.php @@ -25,21 +25,18 @@ require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php'; require_once DOL_DOCUMENT_ROOT . '/intracommreport/class/intracommreport.class.php'; +$langs->loadLangs(array("intracommreport")); + $action = GETPOST('action'); $exporttype = GETPOST('exporttype'); // DEB ou DES if (empty($exporttype)) $exporttype = 'deb'; -/* -$PDOdb = new TPDOdb; -$ATMform = new TFormCore; -*/ $formother = new FormOther($db); $year = GETPOST('year'); $month = GETPOST('month'); $type_declaration = GETPOST('type'); switch($action) { - case 'generateXML': $obj = new TDebProdouane($PDOdb); $obj->load($PDOdb, GETPOST('id_declaration')); @@ -55,26 +52,24 @@ switch($action) { if ($exporttype == 'deb') _print_form_deb(); else _print_form_des(); break; - } function _print_form_deb() { - global $langs, $ATMform, $formother, $year, $month, $type_declaration; - - $langs->load('intracommreport@intracommreport'); - $langs->load('main'); - - llxHeader(); - print_fiche_titre($langs->trans('intracommreportTitle')); - dol_fiche_head(); + global $langs, $formother, $year, $month, $type_declaration; + + $title = $langs->trans("IntracommReportDEBTitle"); + llxHeader("", $title); + print load_fiche_titre($langs->trans("IntracommReportDEBTitle")); + + dol_fiche_head(); print ''; print ''; - print ''; + print '
'; print ''; print ''; print ''; print ''; @@ -92,7 +94,8 @@ function _print_form_deb() { print ''; print ''; + print $form->selectarray('type', $type, $type_declaration); + print ''; print ''; print '
'; print 'Paramètres de l\'export'; @@ -112,14 +107,13 @@ function _print_form_deb() { function _print_form_des() { - global $langs, $ATMform, $formother, $year, $month, $type_declaration; - - $langs->load('intracommreport@intracommreport'); - $langs->load('main'); - - llxHeader(); - print_fiche_titre($langs->trans('exportprodesTitle')); - dol_fiche_head(); + global $langs, $formother, $year, $month, $type_declaration; + + $title = $langs->trans("IntracommReportDESTitle"); + llxHeader("", $title); + print load_fiche_titre($langs->trans("IntracommReportDESTitle")); + + dol_fiche_head(); print ''; print ''; @@ -195,13 +189,13 @@ function _liste($exporttype='deb') { global $db, $conf, $PDOdb, $langs; - $langs->load('intracommreport@intracommreport'); + $langs->load('intracommreport'); llxHeader(); $l = new TListviewTBS('intracommreport'); $sql = 'SELECT numero_declaration, type_declaration, periode, rowid as dl - FROM '.MAIN_DB_PREFIX.'deb_prodouane + FROM '.MAIN_DB_PREFIX.'intracommreport WHERE entity = '.$conf->entity.' AND exporttype = '.$PDOdb->quote($exporttype); print $l->render($PDOdb, $sql, array( From 20b516885f4ab4e88853d99aed05db59064191df Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 20 Jun 2019 09:33:01 +0200 Subject: [PATCH 007/317] WIP --- htdocs/core/menus/standard/eldy.lib.php | 8 +- .../core/modules/modIntracommreport.class.php | 7 + .../install/mysql/migration/10.0.0-11.0.0.sql | 49 ++ .../install/mysql/migration/9.0.0-10.0.0.sql | 13 - .../mysql/tables/llx_intracommreport.sql | 9 +- .../class/intracommreport.class.php | 146 +++-- htdocs/intracommreport/export.php | 80 +-- htdocs/intracommreport/list.php | 588 ++++++++++++++++++ htdocs/intracommreport/list_det | 40 ++ htdocs/langs/en_US/admin.lang | 3 + htdocs/langs/en_US/intracommreport.lang | 30 +- 11 files changed, 816 insertions(+), 157 deletions(-) create mode 100644 htdocs/install/mysql/migration/10.0.0-11.0.0.sql create mode 100644 htdocs/intracommreport/list.php create mode 100644 htdocs/intracommreport/list_det diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 6616d978876..8499c5d0bf0 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -312,9 +312,9 @@ function print_eldy_menu($db, $atarget, $type_user, &$tabMenu, &$menu, $noout = // Accounting $tmpentry = array( - 'enabled'=>(! empty($conf->comptabilite->enabled) || ! empty($conf->accounting->enabled) || ! empty($conf->asset->enabled)), - 'perms'=>(! empty($user->rights->compta->resultat->lire) || ! empty($user->rights->accounting->mouvements->lire) || ! empty($user->rights->asset->read)), - 'module'=>'comptabilite|accounting|asset' + 'enabled'=>(! empty($conf->comptabilite->enabled) || ! empty($conf->accounting->enabled) || ! empty($conf->asset->enabled) || ! empty($conf->intracommreport->enabled)), + 'perms'=>(! empty($user->rights->compta->resultat->lire) || ! empty($user->rights->accounting->mouvements->lire) || ! empty($user->rights->asset->read) || ! empty($user->rights->intracommreport->read)), + 'module'=>'comptabilite|accounting|asset|intracommreport' ); $menu_arr[] = array( 'name' => 'Accounting', @@ -333,7 +333,7 @@ function print_eldy_menu($db, $atarget, $type_user, &$tabMenu, &$menu, $noout = 'session' => ( ( $_SESSION["mainmenu"] && $_SESSION["mainmenu"] == "accountancy" ) ? 0 : 1 ), - 'loadLangs' => array("compta","accountancy","assets"), + 'loadLangs' => array("compta","accountancy","assets","intracommreport"), 'submenus' => array(), ); diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index 943e269c19c..dd1ab435609 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -112,6 +112,13 @@ class modIntracommreport extends DolibarrModules $this->rights[$r][3] = 0; $this->rights[$r][4] = 'write'; + $this->rights[$r][0] = 68004; + $this->rights[$r][1] = 'Delete intracomm report'; + $this->rights[$r][2] = 'd'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'delete'; + $r++; + // Main menu entries $this->menu = array(); // List of menus to add $r=0; diff --git a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql new file mode 100644 index 00000000000..018892d7a2c --- /dev/null +++ b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql @@ -0,0 +1,49 @@ +-- +-- Be carefull to requests order. +-- This file must be loaded by calling /install/index.php page +-- when current version is 11.0.0 or higher. +-- +-- To restrict request to Mysql version x.y minimum use -- VMYSQLx.y +-- To restrict request to Pgsql version x.y minimum use -- VPGSQLx.y +-- To rename a table: ALTER TABLE llx_table RENAME TO llx_table_new; +-- To add a column: ALTER TABLE llx_table ADD COLUMN newcol varchar(60) NOT NULL DEFAULT '0' AFTER existingcol; +-- To rename a column: ALTER TABLE llx_table CHANGE COLUMN oldname newname varchar(60); +-- To drop a column: ALTER TABLE llx_table DROP COLUMN oldname; +-- To change type of field: ALTER TABLE llx_table MODIFY COLUMN name varchar(60); +-- To drop a foreign key: ALTER TABLE llx_table DROP FOREIGN KEY fk_name; +-- To create a unique index ALTER TABLE llx_table ADD UNIQUE INDEX uk_table_field (field); +-- To drop an index: -- VMYSQL4.1 DROP INDEX nomindex on llx_table +-- To drop an index: -- VPGSQL8.2 DROP INDEX nomindex +-- To make pk to be auto increment (mysql): -- VMYSQL4.3 ALTER TABLE llx_table CHANGE COLUMN rowid rowid INTEGER NOT NULL AUTO_INCREMENT; +-- To make pk to be auto increment (postgres): +-- -- VPGSQL8.2 CREATE SEQUENCE llx_table_rowid_seq OWNED BY llx_table.rowid; +-- -- VPGSQL8.2 ALTER TABLE llx_table ADD PRIMARY KEY (rowid); +-- -- VPGSQL8.2 ALTER TABLE llx_table ALTER COLUMN rowid SET DEFAULT nextval('llx_table_rowid_seq'); +-- -- VPGSQL8.2 SELECT setval('llx_table_rowid_seq', MAX(rowid)) FROM llx_table; +-- To set a field as NULL: -- VMYSQL4.3 ALTER TABLE llx_table MODIFY COLUMN name varchar(60) NULL; +-- To set a field as NULL: -- VPGSQL8.2 ALTER TABLE llx_table ALTER COLUMN name DROP NOT NULL; +-- To set a field as NOT NULL: -- VMYSQL4.3 ALTER TABLE llx_table MODIFY COLUMN name varchar(60) NOT NULL; +-- To set a field as NOT NULL: -- VPGSQL8.2 ALTER TABLE llx_table ALTER COLUMN name SET NOT NULL; +-- To set a field as default NULL: -- VPGSQL8.2 ALTER TABLE llx_table ALTER COLUMN name SET DEFAULT NULL; +-- Note: fields with type BLOB/TEXT can't have default value. + +-- Missing in 10.0 + + +-- For 11.0 + +CREATE TABLE llx_intracommreport +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + + ref varchar(30) NOT NULL, -- report reference number + entity integer DEFAULT 1 NOT NULL, -- multi company id + type_declaration varchar(32), + period varchar(32), + mode varchar(32), + content_xml text, + type_export varchar(10), + datec datetime, + tms timestamp +)ENGINE=innodb; + diff --git a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql index 139b8f897c7..83a0b1bb7c6 100644 --- a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql +++ b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql @@ -411,16 +411,3 @@ INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propuls ALTER TABLE llx_facture ADD COLUMN fk_mode_transport integer after location_incoterms; ALTER TABLE llx_facture_fourn ADD COLUMN fk_mode_transport integer after location_incoterms; - -create table llx_intracommreport -( - rowid integer AUTO_INCREMENT PRIMARY KEY, - - ref varchar(30) NOT NULL, -- report reference number - entity integer DEFAULT 1 NOT NULL, -- multi company id - type_declaration varchar(32), - periode varchar(32), - mode varchar(32), - content_xml text, - exporttype varchar(10) -)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_intracommreport.sql b/htdocs/install/mysql/tables/llx_intracommreport.sql index e3b27d2de7c..a09396920c7 100644 --- a/htdocs/install/mysql/tables/llx_intracommreport.sql +++ b/htdocs/install/mysql/tables/llx_intracommreport.sql @@ -1,5 +1,6 @@ -- =================================================================== --- Copyright (C) 2019 Open-DSI +-- Copyright (C) 2015 ATM Consulting +-- Copyright (C) 2019 Open-DSI -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by @@ -23,8 +24,10 @@ create table llx_intracommreport ref varchar(30) NOT NULL, -- report reference number entity integer DEFAULT 1 NOT NULL, -- multi company id type_declaration varchar(32), - periode varchar(32), + period varchar(32), mode varchar(32), content_xml text, - exporttype varchar(10) + type_export varchar(10), + datec datetime, + tms timestamp )ENGINE=innodb; diff --git a/htdocs/intracommreport/class/intracommreport.class.php b/htdocs/intracommreport/class/intracommreport.class.php index af8a244deec..66c3bf0d96d 100644 --- a/htdocs/intracommreport/class/intracommreport.class.php +++ b/htdocs/intracommreport/class/intracommreport.class.php @@ -1,5 +1,6 @@ +/* Copyright (C) 2015 ATM Consulting + * Copyright (C) 2019 Open-DSI * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +21,48 @@ * \ingroup Intracomm report * \brief File of class to manage intracomm report */ +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; /** * Class to manage intracomm report */ class IntracommReport extends CommonObject { - + /** + * @var string ID to identify managed object + */ + public $element='intracommreport'; + + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element='intracommreport'; + + /** + * @var int Field with ID of parent key if this field has a parent + */ + public $fk_element='fk_intracommreport'; + + /** + * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + * + * @var int + */ + public $ismultientitymanaged = 1; + + /** + * DEB - Product + */ + const TYPE_DEB = 0; + /** + * DES - Service + */ + const TYPE_DES = 1; + static $type = array( - 'introduction'=>'Introduction' - ,'expedition'=>'Expédition' - ); + 'introduction'=>'Introduction' + ,'expedition'=>'Expédition' + ); /** * Constructor @@ -52,11 +84,10 @@ class IntracommReport extends CommonObject parent::start(); parent::_init_vars(); */ - + $this->exporttype = 'deb'; } - - + /** * @param $mode O pour création, R pour régénération (apparemment toujours 0 dans la cadre des échanges XML selon la doc) * @param $type introduction ou expedition @@ -64,16 +95,16 @@ class IntracommReport extends CommonObject function getXML($mode='O', $type='introduction', $periode_reference='') { global $db, $conf, $mysoc; - + /**************Construction de quelques variables********************/ $party_id = substr(strtr($mysoc->tva_intra, array(' '=>'')), 0, 4).$mysoc->idprof2; $declarant = substr($mysoc->managers, 0, 14); $id_declaration = self::getNumeroDeclaration($this->numero_declaration); /********************************************************************/ - + /**************Construction du fichier XML***************************/ $e = new SimpleXMLElement(''); - + $enveloppe = $e->addChild('Envelope'); $enveloppe->addChild('envelopeId', $conf->global->INTRACOMMREPORT_NUM_AGREMENT); $date_time = $enveloppe->addChild('DateTime'); @@ -97,69 +128,66 @@ class IntracommReport extends CommonObject $declaration->addChild('flowCode', ($type == 'introduction' ? 'A' : 'D')); $declaration->addChild('currencyCode', $conf->global->MAIN_MONNAIE); /********************************************************************/ - + /**************Ajout des lignes de factures**************************/ $res = self::addItemsFact($declaration, $type, $periode_reference); /********************************************************************/ - + $this->errors = array_unique($this->errors); if(!empty($res)) return $e->asXML(); else return 0; - } // $type_declaration tjrs = "expedition" à voir si ça évolue function getXMLDes($period_year, $period_month, $type_declaration='expedition') { global $db, $conf, $mysoc; - - + $e = new SimpleXMLElement(''); - + $declaration_des = $e->addChild('declaration_des'); $declaration_des->addChild('num_des', self::getNumeroDeclaration($this->numero_declaration)); $declaration_des->addChild('num_tvaFr', $mysoc->tva_intra); // /^FR[a-Z0-9]{2}[0-9]{9}$/ // Doit faire 13 caractères $declaration_des->addChild('mois_des', $period_month); $declaration_des->addChild('an_des', $period_year); - - + /**************Ajout des lignes de factures**************************/ $res = self::addItemsFact($declaration_des, $type_declaration, $period_year.'-'.$period_month, 'des'); /********************************************************************/ - + $this->errors = array_unique($this->errors); if(!empty($res)) return $e->asXML(); else return 0; } - + function addItemsFact(&$declaration, $type, $periode_reference, $exporttype='deb') { - + global $db, $conf; - + require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php'; - + $sql = $this->getSQLFactLines($type, $periode_reference, $exporttype); - + $resql = $db->query($sql); - + if($resql) { $i=1; - + if(empty($resql->num_rows)) { $this->errors[] = 'Aucune donnée pour cette période'; return 0; } - + if($exporttype == 'deb' && $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0) { $categ_fraisdeport = new Categorie($db); $categ_fraisdeport->fetch($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT); $TLinesFraisDePort = array(); } - + while($res = $db->fetch_object($resql)) { - + if ($exporttype == 'des') { $this->addItemXMlDes($declaration, $res, '', $i); @@ -175,25 +203,25 @@ class IntracommReport extends CommonObject } else $this->addItemXMl($declaration, $res, '', $i); } } - + $i++; - + } - + if(!empty($TLinesFraisDePort)) $this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i); if(count($this->errors) > 0) return 0; - + } - + return 1; - + } function getSQLFactLines($type, $periode_reference, $exporttype='deb') { - + global $mysoc, $conf; - + if($type=='expedition' || $exporttype=='des') { $sql = 'SELECT f.facnumber, f.total as total_ht'; $table = 'facture'; @@ -224,13 +252,13 @@ class IntracommReport extends CommonObject AND f.entity = '.$conf->entity.' AND (s.fk_pays <> '.$mysoc->country_id.' OR s.fk_pays IS NULL) AND f.datef BETWEEN "'.$periode_reference.'-01" AND "'.$periode_reference.'-'.date('t').'"'; - + return $sql; - + } - + function addItemXMl(&$declaration, &$res, $code_douane_spe='', $i) { - + $item = $declaration->addChild('Item'); $item->addChild('ItemNumber', $i); $cn8 = $item->addChild('CN8'); @@ -249,7 +277,7 @@ class IntracommReport extends CommonObject $nature_of_transaction->addChild('natureOfTransactionBCode', 1); $item->addChild('modeOfTransportCode', $res->mode_transport); $item->addChild('regionCode', substr($res->zip, 0, 2)); - + } function addItemXMlDes($declaration, &$res, $code_douane_spe='', $i) @@ -259,14 +287,14 @@ class IntracommReport extends CommonObject $item->addChild('valeur', round($res->total_ht)); // Montant total ht de la facture (entier attendu) $item->addChild('partner_des', $res->tva_intra); // Représente le numéro TVA du client étranger } - + /** * Cette fonction ajoute un item en récupérant le code douane du produit ayant le plus haut montant dans la facture */ function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i) { - + global $db, $conf; - + if($type=='expedition') { $table = 'facture'; $tabledet = 'facturedet'; @@ -279,9 +307,9 @@ class IntracommReport extends CommonObject $field_link = 'fk_facture_fourn'; $more_sql = 'f.ref_supplier'; } - + foreach($TLinesFraisDePort as $res) { - + $sql = 'SELECT p.customcode FROM '.MAIN_DB_PREFIX.$tabledet.' d INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = d.'.$field_link.') @@ -303,43 +331,40 @@ class IntracommReport extends CommonObject WHERE fk_categorie = '.$categ_fraisdeport->id.' ) )'; - + $resql = $db->query($sql); $ress = $db->fetch_object($resql); - + $this->addItemXMl($declaration, $res, $ress->customcode, $i); - + $i++; } - } function getNextNumeroDeclaration() { - + global $db; $resql = $db->query('SELECT MAX(numero_declaration) as max_numero_declaration FROM '.$this->get_table().' WHERE exporttype="'.$this->exporttype.'"'); if($resql) $res = $db->fetch_object($resql); - + return ($res->max_numero_declaration + 1); - } // La doc impose que le numéro soit un entier positif d'un maximum de 6 caractères static function getNumeroDeclaration($numero) { - + return str_pad($numero, 6, 0, STR_PAD_LEFT); - } function generateXMLFile() { - + $name = $this->periode.'.xml'; $fname = sys_get_temp_dir().'/'.$name; $f = fopen($fname, 'w+'); fwrite($f, $this->content_xml); fclose($f); - + header('Content-Description: File Transfer'); header('Content-Type: application/xml'); header('Content-Disposition: attachment; filename="'.$name.'"'); @@ -349,7 +374,6 @@ class IntracommReport extends CommonObject header('Content-Length: ' . filesize($fname)); readfile($fname); exit; - + } - } diff --git a/htdocs/intracommreport/export.php b/htdocs/intracommreport/export.php index 5a61a62a581..4a5e2fc073a 100644 --- a/htdocs/intracommreport/export.php +++ b/htdocs/intracommreport/export.php @@ -31,6 +31,7 @@ $action = GETPOST('action'); $exporttype = GETPOST('exporttype'); // DEB ou DES if (empty($exporttype)) $exporttype = 'deb'; +$form = new Form($db); $formother = new FormOther($db); $year = GETPOST('year'); $month = GETPOST('month'); @@ -58,7 +59,7 @@ switch($action) { function _print_form_deb() { - global $langs, $formother, $year, $month, $type_declaration; + global $langs, $form, $formother, $year, $month, $type, $type_declaration; $title = $langs->trans("IntracommReportDEBTitle"); llxHeader("", $title); @@ -83,7 +84,8 @@ function _print_form_deb() { $TabMonth = array(); for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); - print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); + print $formother->select_month(empty($month) ? date('M') : $month,'month',0, 1); + print $formother->select_year(empty($year) ? date('Y') : $year,'year',0, 3, 3); print '
'; //print $ATMform->combo('','type', array('introduction'=>'Introduction', 'expedition'=>'Expédition'), $type_declaration); - print '
'; @@ -120,13 +123,13 @@ function _print_form_des() print ''; print ''; print ''; // Permet d'utiliser le bon select de la requête sql - - print ''; - + + print '
'; + print ''; - + print ''; print ''; print ''; print ''; - + print '
'; print 'Paramètres de l\'export'; print '
Période d\'analyse'; @@ -136,22 +139,21 @@ function _print_form_des() print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); print '
'; - + print '
'; print ''; print '
'; - + print ''; - } function _export_xml_deb($type_declaration, $period_year, $period_month) { - - global $PDOdb, $conf; - - $obj = new TDebProdouane($PDOdb); + + global $db, $conf; + + $obj = new TDebProdouane($db); $obj->entity = $conf->entity; $obj->mode = 'O'; $obj->periode = $period_year.'-'.$period_month; @@ -163,13 +165,12 @@ function _export_xml_deb($type_declaration, $period_year, $period_month) { $obj->generateXMLFile(); } else setEventMessage($obj->errors, 'warnings'); - } function _export_xml_des($type_declaration, $period_year, $period_month) { - + global $PDOdb, $conf; - + $obj = new TDebProdouane($PDOdb); $obj->entity = $conf->entity; $obj->periode = $period_year.'-'.$period_month; @@ -182,49 +183,6 @@ function _export_xml_des($type_declaration, $period_year, $period_month) { $obj->generateXMLFile(); } else setEventMessage($obj->errors, 'warnings'); - -} - -function _liste($exporttype='deb') { - - global $db, $conf, $PDOdb, $langs; - - $langs->load('intracommreport'); - - llxHeader(); - $l = new TListviewTBS('intracommreport'); - - $sql = 'SELECT numero_declaration, type_declaration, periode, rowid as dl - FROM '.MAIN_DB_PREFIX.'intracommreport - WHERE entity = '.$conf->entity.' AND exporttype = '.$PDOdb->quote($exporttype); - - print $l->render($PDOdb, $sql, array( - 'type'=>array( - //'date_cre'=>'date' - ) - ,'link'=>array( - 'dl'=>''.img_picto('', 'file.png').'' - ) - ,'eval'=>array( - 'numero_declaration'=>'TDebProdouane::getNumeroDeclaration("@val@")' - ,'type_declaration'=>'TDebProdouane::$TType["@val@"]' - ) - ,'liste'=>array( - 'titre'=>$langs->trans('intracommreportList'.$exporttype) - ,'image'=>img_picto('','title.png', '', 0) - ,'picto_precedent'=>img_picto('','back.png', '', 0) - ,'picto_suivant'=>img_picto('','next.png', '', 0) - ,'messageNothing'=>"Il n'y a aucune déclaration à afficher" - ,'picto_search'=>img_picto('','search.png', '', 0) - ) - ,'title'=>array( - 'numero_declaration'=>$langs->trans('intracommreportNumber') - ,'type_declaration'=>$langs->trans('intracommreportTypeDeclaration') - ,'periode'=>$langs->trans('intracommreportPeriod') - ,'dl'=>$langs->trans('intracommreportDownload') - ) - )); - } llxFooter(); diff --git a/htdocs/intracommreport/list.php b/htdocs/intracommreport/list.php new file mode 100644 index 00000000000..d903ef31287 --- /dev/null +++ b/htdocs/intracommreport/list.php @@ -0,0 +1,588 @@ + + * Copyright (C) 2019 Open-DSI + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/intracommreport/list.php + * \ingroup Intracomm Report + * \brief Page to list intracomm report + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/intracommreport/class/intracommreport.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array('intracommreport')); + +$action=GETPOST('action', 'alpha'); +$massaction=GETPOST('massaction', 'alpha'); +$show_files=GETPOST('show_files', 'int'); +$confirm=GETPOST('confirm', 'alpha'); +$toselect = GETPOST('toselect', 'array'); + +$sall=trim((GETPOST('search_all', 'alphanohtml')!='')?GETPOST('search_all', 'alphanohtml'):GETPOST('sall', 'alphanohtml')); +$search_ref=GETPOST("search_ref", 'alpha'); +$search_type = GETPOST("search_type", 'int'); +$fourn_id = GETPOST("fourn_id", 'int'); +$catid = GETPOST('catid', 'int'); +$optioncss = GETPOST('optioncss', 'alpha'); +$type=GETPOST("type", "int"); + +$diroutputmassaction=$conf->product->dir_output . '/temp/massgeneration/'.$user->id; + +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = (GETPOST("page", 'int')?GETPOST("page", 'int'):0); +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (! $sortfield) $sortfield="i.ref"; +if (! $sortorder) $sortorder="ASC"; + +// Initialize context for list +$contextpage=GETPOST('contextpage', 'aZ')?GETPOST('contextpage', 'aZ'):'intracommreportlist'; +if ((string) $type == '1') { $contextpage='DESlist'; if ($search_type=='') $search_type='1'; } +if ((string) $type == '0') { $contextpage='DEBlist'; if ($search_type=='') $search_type='0'; } + +// Initialize technical object to manage hooks. Note that conf->hooks_modules contains array of hooks +$object=new IntracommReport($db); +$hookmanager->initHooks(array('intracommreportlist')); +$extrafields = new ExtraFields($db); +$form=new Form($db); + +/* +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('intracommreport'); +$search_array_options=$extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); +*/ + +if (empty($action)) $action='list'; + +// Get object canvas (By default, this is not defined, so standard usage of dolibarr) +$canvas=GETPOST("canvas"); +$objcanvas=null; +if (! empty($canvas)) +{ + require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php'; + $objcanvas = new Canvas($db, $action); + $objcanvas->getCanvas('product', 'list', $canvas); +} + +// Security check +/* +if ($search_type=='0') $result=restrictedArea($user, 'produit', '', '', '', '', '', $objcanvas); +elseif ($search_type=='1') $result=restrictedArea($user, 'service', '', '', '', '', '', $objcanvas); +else $result=restrictedArea($user, 'produit|service', '', '', '', '', '', $objcanvas); +*/ + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array( + 'i.ref'=>"Ref", + 'pfi.ref_fourn'=>"RefSupplier", + 'i.label'=>"ProductLabel", + 'i.description'=>"Description", + "i.note"=>"Note", +); + +$isInEEC=isInEEC($mysoc); + +// Definition of fields for lists +$arrayfields=array( + 'i.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1), + //'pfi.ref_fourn'=>array('label'=>$langs->trans("RefSupplier"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))), + 'i.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1), + 'i.fk_product_type'=>array('label'=>$langs->trans("Type"), 'checked'=>0, 'enabled'=>(! empty($conf->produit->enabled) && ! empty($conf->service->enabled))), + 'i.barcode'=>array('label'=>$langs->trans("Gencod"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))), + 'i.duration'=>array('label'=>$langs->trans("Duration"), 'checked'=>($contextpage != 'productlist'), 'enabled'=>(! empty($conf->service->enabled))), + 'i.weight'=>array('label'=>$langs->trans("Weight"), 'checked'=>0, 'enabled'=>(! empty($conf->produit->enabled))), +); +/* +// Extra fields +if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) +{ + foreach($extrafields->attributes[$object->table_element]['label'] as $key => $val) + { + if (! empty($extrafields->attributes[$object->table_element]['list'][$key])) + $arrayfields["ef.".$key]=array('label'=>$extrafields->attributes[$object->table_element]['label'][$key], 'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key]<0)?0:1), 'position'=>$extrafields->attributes[$object->table_element]['pos'][$key], 'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key])!=3 && $extrafields->attributes[$object->table_element]['perms'][$key])); + } +} +*/ +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { $action='list'; $massaction=''; } +if (! GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; } + +$parameters=array(); +$reshook=$hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers + { + $sall=""; + $search_ref=""; + $search_label=""; + $search_barcode=""; + $search_categ=0; + $search_tosell=""; + $search_tobuy=""; + $search_tobatch=''; + //$search_type=''; // There is 2 types of list: a list of product and a list of services. No list with both. So when we clear search criteria, we must keep the filter on type. + + $show_childproducts = ''; + $search_array_options=array(); + } + + // Mass actions + $objectclass='Product'; + if ((string) $search_type == '1') { $objectlabel='Services'; } + if ((string) $search_type == '0') { $objectlabel='Products'; } + + $permtoread = $user->rights->produit->lire; + $permtodelete = $user->rights->produit->supprimer; + $uploaddir = $conf->product->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + +/* + * View + */ +$formother=new FormOther($db); + +$title=$langs->trans('IntracommReportList'.$type); + +$sql = 'SELECT DISTINCT i.rowid, i.type_declaration, i.type_export, i.period, i.mode, i.entity'; +/* +// Add fields from extrafields +if (! empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key : ''); +} +*/ +// Add fields from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; + +$sql.= ' FROM '.MAIN_DB_PREFIX.'intracommreport as i'; + +// if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."intracommreport_extrafields as ef on (i.rowid = ef.fk_object)"; + +$sql.= ' WHERE i.entity IN ('.getEntity('intracommreport').')'; + +if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall); +// if the type is not 1, we show all products (type = 0,2,3) +if (dol_strlen($search_type) && $search_type != '-1') +{ + if ($search_type == 1) $sql.= " AND i.type = 1"; + else $sql.= " AND i.type = 0"; +} + +/* +if ($search_ref) $sql .= natural_search('i.ref', $search_ref); +if ($search_label) $sql .= natural_search('i.label', $search_label); +if ($search_barcode) $sql .= natural_search('i.barcode', $search_barcode); +if (isset($search_tosell) && dol_strlen($search_tosell) > 0 && $search_tosell!=-1) $sql.= " AND i.tosell = ".$db->escape($search_tosell); +if (isset($search_tobuy) && dol_strlen($search_tobuy) > 0 && $search_tobuy!=-1) $sql.= " AND i.tobuy = ".$db->escape($search_tobuy); +if (dol_strlen($canvas) > 0) $sql.= " AND i.canvas = '".$db->escape($canvas)."'"; +*/ + +/* +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +*/ +// Add where from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; + +$sql.= " GROUP BY i.rowid"; + +/* +// Add fields from extrafields +if (! empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key : ''); +} +*/ + +// Add fields from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldSelect', $parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; + +$sql.= $db->order($sortfield, $sortorder); + +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) +{ + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); + if (($page * $limit) > $nbtotalofrecords) // if total resultset is smaller then paging size (filtering), goto and load page 0 + { + $page = 0; + $offset = 0; + } +} + +$sql.= $db->plimit($limit + 1, $offset); + +$resql = $db->query($sql); + +if ($resql) +{ + $num = $db->num_rows($resql); + + $arrayofselected=is_array($toselect)?$toselect:array(); + + $helpurl='EN:Module_IntracommReport|FR:Module_ProDouane'; + llxHeader('', $title, $helpurl, ''); + + // Displays product removal confirmation + if (GETPOST('delprod')) { + setEventMessages($langs->trans("ProductDeleted", GETPOST('delprod')), null, 'mesgs'); + } + + $param=''; + if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); + if ($sall) $param.="&sall=".urlencode($sall); + if ($search_categ > 0) $param.="&search_categ=".urlencode($search_categ); + if ($search_ref) $param="&search_ref=".urlencode($search_ref); + if ($search_ref_supplier) $param="&search_ref_supplier=".urlencode($search_ref_supplier); + if ($search_barcode) $param.=($search_barcode?"&search_barcode=".urlencode($search_barcode):""); + if ($search_label) $param.="&search_label=".urlencode($search_label); + + // Add $param from extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; + + // List of mass actions available + $arrayofmassactions = array( + 'generate_doc'=>$langs->trans("ReGeneratePDF"), + //'builddoc'=>$langs->trans("PDFMerge"), + //'presend'=>$langs->trans("SendByMail"), + ); + if ($user->rights->intracommreport->delete) $arrayofmassactions['predelete']="".$langs->trans("Delete"); + if (in_array($massaction, array('presend','predelete'))) $arrayofmassactions=array(); + $massactionbutton=$form->selectMassAction('', $arrayofmassactions); + + $newcardbutton=''; + $rightskey='DEB'; + if($type == IntracommReport::TYPE_DES) $rightskey='DES'; + if($user->rights->{$rightskey}->creer) + { + $label='NewDEB'; + if($type == IntracommReport::TYPE_DES) $label='NewDES'; + $newcardbutton.= dolGetButtonTitle($langs->trans($label), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/intracommreport/card.php?action=create&type='.$type); + } + + print '
'; + if ($optioncss != '') print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if (empty($arrayfields['i.fk_product_type']['checked'])) print ''; + + print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_products.png', 0, $newcardbutton, '', $limit); + + $topicmail="Information"; + $modelmail="product"; + $objecttmp=new IntracommReport($db); + $trackid='prod'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + + if ($sall) + { + foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val); + print '
'.$langs->trans("FilterOnInto", $sall) . join(', ', $fieldstosearchall).'
'; + } + + $parameters=array(); + $reshook=$hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook + if (empty($reshook)) $moreforfilter.=$hookmanager->resPrint; + else $moreforfilter=$hookmanager->resPrint; + + if ($moreforfilter) + { + print '
'; + print $moreforfilter; + print '
'; + } + + $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; + $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1); + + print '
'; + print ''."\n"; + + // Lines with input filters + print ''; + if (! empty($arrayfields['i.ref']['checked'])) + { + print ''; + } + if (! empty($arrayfields['pfi.ref_fourn']['checked'])) + { + print ''; + } + if (! empty($arrayfields['i.label']['checked'])) + { + print ''; + } + // Type + if (! empty($arrayfields['i.fk_product_type']['checked'])) + { + print ''; + } + // Barcode + if (! empty($arrayfields['i.barcode']['checked'])) + { + print ''; + } + // Duration + if ((string) $type == '1' && ! empty($arrayfields['i.duration']['checked'])) + { + print ''; + } + + // Weight + if (! empty($arrayfields['i.weight']['checked'])) + { + print ''; + } + /* + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + */ + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Date creation + if (! empty($arrayfields['i.datec']['checked'])) + { + print ''; + } + // Date modification + if (! empty($arrayfields['i.tms']['checked'])) + { + print ''; + } + print ''; + + print ''; + + print ''; + if (! empty($arrayfields['i.ref']['checked'])) { + print_liste_field_titre($arrayfields['i.ref']['label'], $_SERVER["PHP_SELF"], "i.ref", "", $param, "", $sortfield, $sortorder); + } + if (! empty($arrayfields['i.label']['checked'])) { + print_liste_field_titre($arrayfields['i.label']['label'], $_SERVER["PHP_SELF"], "i.label", "", $param, "", $sortfield, $sortorder); + } + if (! empty($arrayfields['i.fk_product_type']['checked'])) { + print_liste_field_titre($arrayfields['i.fk_product_type']['label'], $_SERVER["PHP_SELF"], "i.fk_product_type", "", $param, "", $sortfield, $sortorder); + } + if (! empty($arrayfields['i.barcode']['checked'])) { + print_liste_field_titre($arrayfields['i.barcode']['label'], $_SERVER["PHP_SELF"], "i.barcode", "", $param, "", $sortfield, $sortorder); + } + if ((string) $type == '1' && ! empty($arrayfields['i.duration']['checked'])) { + print_liste_field_titre($arrayfields['i.duration']['label'], $_SERVER["PHP_SELF"], "i.duration", "", $param, '', $sortfield, $sortorder, 'center '); + } + if (! empty($arrayfields['i.weight']['checked'])) print_liste_field_titre($arrayfields['i.weight']['label'], $_SERVER["PHP_SELF"], "i.weight", "", $param, '', $sortfield, $sortorder, 'center '); + + /* + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; + */ + // Hook fields + $parameters=array('arrayfields'=>$arrayfields,'param'=>$param,'sortfield'=>$sortfield,'sortorder'=>$sortorder); + $reshook=$hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + if (! empty($arrayfields['i.datec']['checked'])) { + print_liste_field_titre($arrayfields['i.datec']['label'], $_SERVER["PHP_SELF"], "i.datec", "", $param, '', $sortfield, $sortorder, 'center nowrap '); + } + if (! empty($arrayfields['i.tms']['checked'])) { + print_liste_field_titre($arrayfields['i.tms']['label'], $_SERVER["PHP_SELF"], "i.tms", "", $param, '', $sortfield, $sortorder, 'center nowrap '); + } + + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); + print "\n"; + + + $intracommreport_static = new IntracommReport($db); + + $i = 0; + $totalarray=array(); + while ($i < min($num, $limit)) + { + $obj = $db->fetch_object($resql); + + $intracommreport_static->id = $obj->rowid; + $intracommreport_static->ref = $obj->ref; + $intracommreport_static->ref_fourn = $obj->ref_supplier; + $intracommreport_static->label = $obj->label; + $intracommreport_static->type = $obj->fk_product_type; + $intracommreport_static->status_buy = $obj->tobuy; + $intracommreport_static->status = $obj->tosell; + $intracommreport_static->status_batch = $obj->tobatch; + $intracommreport_static->entity = $obj->entity; + + print ''; + + // Ref + if (! empty($arrayfields['i.ref']['checked'])) + { + print '\n"; + if (! $i) $totalarray['nbfield']++; + } + // Ref supplier + if (! empty($arrayfields['pfi.ref_fourn']['checked'])) + { + print '\n"; + if (! $i) $totalarray['nbfield']++; + } + // Label + if (! empty($arrayfields['i.label']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Type + if (! empty($arrayfields['i.fk_product_type']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Barcode + if (! empty($arrayfields['i.barcode']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Duration + if ((string) $type == '1' && ! empty($arrayfields['i.duration']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Weight + if (! empty($arrayfields['i.weight']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Action + print ''; + if (! $i) $totalarray['nbfield']++; + + print "\n"; + $i++; + } + + $db->free($resql); + + print "
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + $array=array('-1'=>' ', '0'=>$langs->trans('Product'), '1'=>$langs->trans('Service')); + print $form->selectarray('search_type', $array, $search_type); + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + $searchpicto=$form->showFilterButtons(); + print $searchpicto; + print '
'; + print $intracommreport_static->getNomUrl(1); + print "'; + print $intracommreport_static->getNomUrl(1); + print "'.dol_trunc($obj->label, 80).''.$obj->fk_product_type.''.$obj->barcode.''; + + if (preg_match('/([^a-z]+)[a-z]$/i', $obj->duration)) + { + $duration_value = substr($obj->duration, 0, dol_strlen($obj->duration)-1); + $duration_unit = substr($obj->duration, -1); + + if ((float) $duration_value > 1) + { + $dur=array("i"=>$langs->trans("Minutes"),"h"=>$langs->trans("Hours"),"d"=>$langs->trans("Days"),"w"=>$langs->trans("Weeks"),"m"=>$langs->trans("Months"),"y"=>$langs->trans("Years")); + } + elseif ((float) $duration_value > 0) + { + $dur=array("i"=>$langs->trans("Minute"),"h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year")); + } + print $duration_value; + print (! empty($duration_unit) && isset($dur[$duration_unit]) ? ' '.$langs->trans($dur[$duration_unit]) : ''); + } + else + { + print $obj->duration; + } + + print ''; + print $obj->weight; + print ''; + if ($massactionbutton || $massaction) // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + { + $selected=0; + if (in_array($obj->rowid, $arrayofselected)) $selected=1; + print ''; + } + print '
"; + print "
"; + print '
'; +} +else +{ + dol_print_error($db); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/intracommreport/list_det b/htdocs/intracommreport/list_det new file mode 100644 index 00000000000..afd6509f693 --- /dev/null +++ b/htdocs/intracommreport/list_det @@ -0,0 +1,40 @@ +function _liste($exporttype='deb') { + +global $db, $conf, $langs; + +$langs->load('intracommreport'); + +llxHeader(); +$l = new TListviewTBS('intracommreport'); + +$sql = 'SELECT numero_declaration, type_declaration, periode, rowid as dl +FROM '.MAIN_DB_PREFIX.'intracommreport +WHERE entity = '.$conf->entity.' AND exporttype = '.$PDOdb->quote($exporttype); + +print $l->render($PDOdb, $sql, array( +'type'=>array( +//'date_cre'=>'date' +) +,'link'=>array( +'dl'=>''.img_picto('', 'file.png').'' +) +,'eval'=>array( +'numero_declaration'=>'TDebProdouane::getNumeroDeclaration("@val@")' +,'type_declaration'=>'TDebProdouane::$TType["@val@"]' +) +,'liste'=>array( +'titre'=>$langs->trans('IntracommReportList'.$exporttype) +,'image'=>img_picto('','title.png', '', 0) +,'picto_precedent'=>img_picto('','back.png', '', 0) +,'picto_suivant'=>img_picto('','next.png', '', 0) +,'messageNothing'=>"Il n'y a aucune déclaration à afficher" +,'picto_search'=>img_picto('','search.png', '', 0) +) +,'title'=>array( +'numero_declaration'=>$langs->trans('IntracommReportNumber') +,'type_declaration'=>$langs->trans('IntracommReportTypeDeclaration') +,'periode'=>$langs->trans('IntracommReportPeriod') +,'dl'=>$langs->trans('IntracommReportDownload') +) +)); +} \ No newline at end of file diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 5fc1994247c..a0cbfc021b3 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -895,6 +895,9 @@ Permission63001=Read resources Permission63002=Create/modify resources Permission63003=Delete resources Permission63004=Link resources to agenda events +Permission68001=Read intracomm report +Permission68002=Create/modify intracomm report +Permission68004=Delete intracomm report DictionaryCompanyType=Third-party types DictionaryCompanyJuridicalType=Third-party legal entities DictionaryProspectLevel=Prospect potential diff --git a/htdocs/langs/en_US/intracommreport.lang b/htdocs/langs/en_US/intracommreport.lang index 8d2b891ed8e..eed5981f4b9 100644 --- a/htdocs/langs/en_US/intracommreport.lang +++ b/htdocs/langs/en_US/intracommreport.lang @@ -14,22 +14,22 @@ INTRACOMMREPORT_CATEG_FRAISDEPORT=Catégorie de services de type "Frais de port" INTRACOMMREPORT_NUM_DECLARATION=Numéro de déclarant #Menu -exportprodebDouane=Export Pro-Douane -exportprodebDEB=Export DEB -exportprodebNew=Nouvelle déclaration -exportprodebList=Liste des déclarations -exportprodebDES=Export DES -exportprodesNew=Nouvelle déclaration -exportprodesList=Liste des déclarations +MenuDeclaration=Export Pro-Douane +MenuDeclarationDEB=Export DEB +MenuDeclarationDEBNew=Nouvelle déclaration +MenuDeclarationDEBList=Liste des déclarations +MenuDeclarationDES=Export DES +MenuDeclarationDESNew=Nouvelle déclaration +MenuDeclarationDESList=Liste des déclarations #page d'export -exportprodebTitle=Export d'un fichier XML au format ProDouane - DEB -exportprodesTitle=Export d'un fichier XML au format ProDouane - DES +IntracommReportDEBTitle=Export d'un fichier XML au format ProDouane - DEB +IntracommReportDESTitle=Export d'un fichier XML au format ProDouane - DES #Liste -exportprodebListdeb=Liste des déclarations générées (DEB) -exportprodebListdes=Liste des déclarations générées (DES) -exportprodebNumber=Numéro déclaration -exportprodebPeriod=Période d'analyse -exportprodebTypeDeclaration=Type de déclaration -exportprodebDownload=Télécharger fichier XML \ No newline at end of file +IntracommReportListDEB=Liste des déclarations générées (DEB) +IntracommReportListDES=Liste des déclarations générées (DES) +IntracommReportNumber=Numéro déclaration +IntracommReportPeriod=Période d'analyse +IntracommReportTypeDeclaration=Type de déclaration +IntracommReportDownload=Télécharger fichier XML \ No newline at end of file From 69f15db4e942c28ebfdf33fa1aa5451b7d75f576 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 20 Jun 2019 09:37:23 +0200 Subject: [PATCH 008/317] Fix migration - Move to v11 --- .../install/mysql/migration/10.0.0-11.0.0.sql | 20 ++++++++++++++++++ .../install/mysql/migration/9.0.0-10.0.0.sql | 21 +------------------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql index 018892d7a2c..51446573c85 100644 --- a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql +++ b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql @@ -32,6 +32,26 @@ -- For 11.0 +-- Intracomm Report +CREATE TABLE llx_c_transport_mode ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(3) NOT NULL, + label varchar(255) NOT NULL, + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; + +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('ROU', 'Transport par route', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('AIR', 'Transport par air', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('POS', 'Envois postaux', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); +INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propulsion propre', 1); + +ALTER TABLE llx_facture ADD COLUMN fk_mode_transport integer after location_incoterms; +ALTER TABLE llx_facture_fourn ADD COLUMN fk_mode_transport integer after location_incoterms; + CREATE TABLE llx_intracommreport ( rowid integer AUTO_INCREMENT PRIMARY KEY, diff --git a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql index 83a0b1bb7c6..2a841834735 100644 --- a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql +++ b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql @@ -391,23 +391,4 @@ insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) v insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) values (112, 'supplier_proposal', 'external', 'SHIPPING', 'Contact fournisseur livraison', 1); insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) values (113, 'supplier_proposal', 'external', 'SERVICE', 'Contact fournisseur prestation', 1); -ALTER TABLE llx_ticket_extrafields ADD INDEX idx_ticket_extrafields (fk_object); - -CREATE TABLE llx_c_transport_mode ( - rowid integer AUTO_INCREMENT PRIMARY KEY, - code varchar(3) NOT NULL, - libelle varchar(255) NOT NULL, - active tinyint DEFAULT 1 NOT NULL -) ENGINE=innodb; - -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('ROU', 'Transport par route', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('AIR', 'Transport par air', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('POS', 'Envois postaux', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propulsion propre', 1); - -ALTER TABLE llx_facture ADD COLUMN fk_mode_transport integer after location_incoterms; -ALTER TABLE llx_facture_fourn ADD COLUMN fk_mode_transport integer after location_incoterms; +ALTER TABLE llx_ticket_extrafields ADD INDEX idx_ticket_extrafields (fk_object); \ No newline at end of file From 14a99041a3349e57bb1e5d3a1771fa0326ab1dfe Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Tue, 25 Jun 2019 15:31:18 +0200 Subject: [PATCH 009/317] WIP --- htdocs/core/menus/standard/eldy.lib.php | 13 +-- .../intracommreport/{export.php => card.php} | 106 +++++++++--------- htdocs/langs/en_US/intracommreport.lang | 14 +-- 3 files changed, 64 insertions(+), 69 deletions(-) rename htdocs/intracommreport/{export.php => card.php} (77%) diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 8499c5d0bf0..895162cadd2 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1369,16 +1369,11 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM // Intracomm report if (! empty($conf->intracommreport->enabled)) { - $newmenu->add("/intracommreport/export.php?leftmenu=intracommreport", $langs->trans("MenuDeclaration"), 0, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); + $newmenu->add("/intracommreport/list.php?leftmenu=intracommreport", $langs->trans("MenuDeclaration"), 0, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); if ($usemenuhider || empty($leftmenu) || preg_match('/intracommreport/', $leftmenu)) { - // DEB - $newmenu->add("/intracommreport/export.php?leftmenu=intracommreport", $langs->trans("MenuDeclarationDEB"), 1, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreportDEB', 1); - $newmenu->add("/intracommreport/export.php?leftmenu=intracommreportDEB", $langs->trans("MenuDeclarationDEBNew"), 2, $user->rights->intracommreport->write, '', $mainmenu, 'intracommreport', 1); - $newmenu->add("/intracommreport/export.php?action=list&leftmenu=intracommreportDEB", $langs->trans("MenuDeclarationDEBList"), 2, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); - // DES - $newmenu->add("/intracommreport/export.php?exporttype=des&leftmenu=intracommreport", $langs->trans("MenuDeclarationDES"), 1, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreportDES', 1); - $newmenu->add("/intracommreport/export.php?exporttype=des&leftmenu=intracommreportDES", $langs->trans("MenuDeclarationDESNew"), 2, $user->rights->intracommreport->write, '', $mainmenu, 'intracommreport', 1); - $newmenu->add("/intracommreport/export.php?exporttype=des&action=list&leftmenu=intracommreportDES", $langs->trans("MenuDeclarationDESList"), 2, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); + // DEB / DES + $newmenu->add("/intracommreport/card.php?action=create&leftmenu=intracommreport", $langs->trans("MenuDeclarationNew"), 1, $user->rights->intracommreport->write, '', $mainmenu, 'intracommreport', 1); + $newmenu->add("/intracommreport/list.php?leftmenu=intracommreport", $langs->trans("MenuDeclarationList"), 1, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); } } diff --git a/htdocs/intracommreport/export.php b/htdocs/intracommreport/card.php similarity index 77% rename from htdocs/intracommreport/export.php rename to htdocs/intracommreport/card.php index 4a5e2fc073a..7a5914c3044 100644 --- a/htdocs/intracommreport/export.php +++ b/htdocs/intracommreport/card.php @@ -37,6 +37,58 @@ $year = GETPOST('year'); $month = GETPOST('month'); $type_declaration = GETPOST('type'); +// Mode creation +if ($action == 'create') +{ + $title = $langs->trans("IntracommReportDEBTitle"); + llxHeader("", $title); + print load_fiche_titre($langs->trans("IntracommReportDEBTitle")); + + print '
'; + print ''; + print ''; + + dol_fiche_head(); + + print ''; + + // Analysis period + print ''; + print ''; + print ''; + print ''; + + // Type of declaration + print ''; + print ''; + print ''; + print ''; + + print '
'; + print $langs->trans("AnalysisPeriod"); + print ''; + $TabMonth = array(); + for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); + //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); + print $formother->select_month(empty($month) ? date('M') : $month,'month',0, 1); + print $formother->select_year(empty($year) ? date('Y') : $year,'year',0, 3, 3); + print '
'; + print $langs->trans("TypeOfDeclaration"); + print ''; + //print $ATMform->combo('','type', array('introduction'=>'Introduction', 'expedition'=>'Expédition'), $type_declaration); + print $form->selectarray('type', $type, $type_declaration); + print '
'; + + dol_fiche_end(); + + print '
'; + print ''; + print '
'; + + print '
'; +} + +/* switch($action) { case 'generateXML': $obj = new TDebProdouane($PDOdb); @@ -55,59 +107,6 @@ switch($action) { break; } - - -function _print_form_deb() { - - global $langs, $form, $formother, $year, $month, $type, $type_declaration; - - $title = $langs->trans("IntracommReportDEBTitle"); - llxHeader("", $title); - print load_fiche_titre($langs->trans("IntracommReportDEBTitle")); - - dol_fiche_head(); - - print '
'; - print ''; - - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - - print '
'; - print 'Paramètres de l\'export'; - print '
'; - print 'Période d\'analyse'; - print ''; - $TabMonth = array(); - for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); - //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); - print $formother->select_month(empty($month) ? date('M') : $month,'month',0, 1); - print $formother->select_year(empty($year) ? date('Y') : $year,'year',0, 3, 3); - print '
'; - print 'Type de déclaration'; - print ''; - //print $ATMform->combo('','type', array('introduction'=>'Introduction', 'expedition'=>'Expédition'), $type_declaration); - print $form->selectarray('type', $type, $type_declaration); - print '
'; - - print '
'; - print ''; - print '
'; - - print '
'; - -} - function _print_form_des() { global $langs, $formother, $year, $month, $type_declaration; @@ -184,5 +183,6 @@ function _export_xml_des($type_declaration, $period_year, $period_month) { } else setEventMessage($obj->errors, 'warnings'); } +*/ llxFooter(); diff --git a/htdocs/langs/en_US/intracommreport.lang b/htdocs/langs/en_US/intracommreport.lang index eed5981f4b9..42c3f175c14 100644 --- a/htdocs/langs/en_US/intracommreport.lang +++ b/htdocs/langs/en_US/intracommreport.lang @@ -15,14 +15,14 @@ INTRACOMMREPORT_NUM_DECLARATION=Numéro de déclarant #Menu MenuDeclaration=Export Pro-Douane -MenuDeclarationDEB=Export DEB -MenuDeclarationDEBNew=Nouvelle déclaration -MenuDeclarationDEBList=Liste des déclarations -MenuDeclarationDES=Export DES -MenuDeclarationDESNew=Nouvelle déclaration -MenuDeclarationDESList=Liste des déclarations +MenuDeclarationNew=Nouvelle déclaration +MenuDeclarationList=Liste -#page d'export +# View +AnalysisPeriod=Analysis period +TypeOfDeclaration=Type of declaration + +#Page d'export IntracommReportDEBTitle=Export d'un fichier XML au format ProDouane - DEB IntracommReportDESTitle=Export d'un fichier XML au format ProDouane - DES From 8f0f8f74f74bb0df0e928b0b5a6c11f0a335bcc6 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 26 Jun 2019 17:13:38 +0200 Subject: [PATCH 010/317] WIP --- htdocs/core/lib/intracommreport.lib.php | 31 ++- htdocs/core/menus/standard/eldy.lib.php | 6 +- htdocs/intracommreport/card.php | 346 +++++++++++++++++------- htdocs/langs/en_US/intracommreport.lang | 17 +- 4 files changed, 288 insertions(+), 112 deletions(-) diff --git a/htdocs/core/lib/intracommreport.lib.php b/htdocs/core/lib/intracommreport.lib.php index 55a7d9ea9be..425e53f3bcf 100644 --- a/htdocs/core/lib/intracommreport.lib.php +++ b/htdocs/core/lib/intracommreport.lib.php @@ -36,7 +36,7 @@ function intracommReportAdminPrepareHead() $h = 0; $head = array(); - $head[$h][0] = dol_buildpath("/intracommreport/admin/intracommreport.php", 1); + $head[$h][0] = DOL_URL_ROOT.'/intracommreport/admin/intracommreport.php'; $head[$h][1] = $langs->trans("Parameters"); $head[$h][2] = 'general'; $h++; @@ -50,3 +50,32 @@ function intracommReportAdminPrepareHead() complete_head_from_modules($conf, $langs, null, $head, $h, 'intracommreport_admin', 'remove'); return $head; } + +/** + * Prepare array with list of tabs + * + * @return array Array of tabs to show + */ +function intracommReportPrepareHead() +{ + global $langs, $conf; + + $langs->load("intracommreport"); + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT.'/intracommreport/card.php?rowid='.$object->id; + $head[$h][1] = $langs->trans("Card"); + $head[$h][2] = 'card'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname); to remove a tab + complete_head_from_modules($conf, $langs, null, $head, $h, 'intracommreport'); + + complete_head_from_modules($conf, $langs, null, $head, $h, 'intracommreport', 'remove'); + return $head; +} diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 895162cadd2..8a6ecd770b9 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1369,11 +1369,11 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM // Intracomm report if (! empty($conf->intracommreport->enabled)) { - $newmenu->add("/intracommreport/list.php?leftmenu=intracommreport", $langs->trans("MenuDeclaration"), 0, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); + $newmenu->add("/intracommreport/list.php?leftmenu=intracommreport", $langs->trans("MenuIntracommReport"), 0, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); if ($usemenuhider || empty($leftmenu) || preg_match('/intracommreport/', $leftmenu)) { // DEB / DES - $newmenu->add("/intracommreport/card.php?action=create&leftmenu=intracommreport", $langs->trans("MenuDeclarationNew"), 1, $user->rights->intracommreport->write, '', $mainmenu, 'intracommreport', 1); - $newmenu->add("/intracommreport/list.php?leftmenu=intracommreport", $langs->trans("MenuDeclarationList"), 1, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); + $newmenu->add("/intracommreport/card.php?action=create&leftmenu=intracommreport", $langs->trans("MenuIntracommReportNew"), 1, $user->rights->intracommreport->write, '', $mainmenu, 'intracommreport', 1); + $newmenu->add("/intracommreport/list.php?leftmenu=intracommreport", $langs->trans("MenuIntracommReportList"), 1, $user->rights->intracommreport->read, '', $mainmenu, 'intracommreport', 1); } } diff --git a/htdocs/intracommreport/card.php b/htdocs/intracommreport/card.php index 7a5914c3044..5c13a25257f 100644 --- a/htdocs/intracommreport/card.php +++ b/htdocs/intracommreport/card.php @@ -1,5 +1,6 @@ +/* Copyright (C) 2015 ATM Consulting + * Copyright (C) 2019 Open-DSI * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,7 +17,7 @@ */ /** - * \file htdocs/intracommreport/export.php + * \file htdocs/intracommreport/card.php * \ingroup Intracomm report * \brief Page to manage intracomm report export */ @@ -36,13 +37,91 @@ $formother = new FormOther($db); $year = GETPOST('year'); $month = GETPOST('month'); $type_declaration = GETPOST('type'); +$backtopage=GETPOST('backtopage', 'alpha'); -// Mode creation +/* + * Actions + */ + +if ($user->rights->intracommreport->delete && $action == 'confirm_delete' && $confirm == 'yes') +{ + $result=$object->delete($id, $user); + if ($result > 0) + { + if (! empty($backtopage)) + { + header("Location: ".$backtopage); + exit; + } + else + { + header("Location: list.php"); + exit; + } + } + else + { + $errmesg=$object->error; + } +} + +if ($action == 'add' && $user->rights->intracommreport->write) { + $object->label = trim($label); + $object->type = trim($type); + $object->type_declaration = (int) $statut; + $object->subscription = (int) $subscription; + + // Fill array 'array_options' with data from add form + $ret = $extrafields->setOptionalsFromPost($extralabels, $object); + if ($ret < 0) $error++; + + if (empty($object->label)) { + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors'); + } + else { + $sql = "SELECT libelle FROM ".MAIN_DB_PREFIX."adherent_type WHERE libelle='".$db->escape($object->label)."'"; + $result = $db->query($sql); + if ($result) { + $num = $db->num_rows($result); + } + if ($num) { + $error++; + $langs->load("errors"); + setEventMessages($langs->trans("ErrorLabelAlreadyExists", $login), null, 'errors'); + } + } + + if (! $error) + { + $id=$object->create($user); + if ($id > 0) + { + header("Location: ".$_SERVER["PHP_SELF"]); + exit; + } + else + { + setEventMessages($object->error, $object->errors, 'errors'); + $action = 'create'; + } + } + else + { + $action = 'create'; + } +} + +/* + * View + */ + +// Creation mode if ($action == 'create') { - $title = $langs->trans("IntracommReportDEBTitle"); + $title = $langs->trans("IntracommReportTitle"); llxHeader("", $title); - print load_fiche_titre($langs->trans("IntracommReportDEBTitle")); + print load_fiche_titre($langs->trans("IntracommReportTitle")); print '
'; print ''; @@ -52,137 +131,204 @@ if ($action == 'create') print ''; + // Label + print ''; + + // Declaration + $declaration["deb"] = $langs->trans("DEB"); + $declaration["des"] = $langs->trans("DES"); + print '\n"; + // Analysis period print ''; print ''; print ''; print ''; // Type of declaration - print ''; - print ''; - print ''; - print ''; + $typeOfDeclaration["introduction"] = $langs->trans("Introduction"); + $typeOfDeclaration["expedition"] = $langs->trans("Expedition"); + print '\n"; print '
'.$langs->trans("Label").'
'.$langs->trans("Declaration")."\n"; + print $form->selectarray("declaration", $declaration, GETPOST('declaration', 'alpha')?GETPOST('declaration', 'alpha'):$object->declaration, 0); + print "
'; print $langs->trans("AnalysisPeriod"); print ''; - $TabMonth = array(); - for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); - //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); - print $formother->select_month(empty($month) ? date('M') : $month,'month',0, 1); - print $formother->select_year(empty($year) ? date('Y') : $year,'year',0, 3, 3); + print $formother->select_month($month ? date('M') : $month,'month',0, 1, 'widthauto valignmiddle '); + print $formother->select_year($year ? date('Y') : $year,'year',0, 3, 3); print '
'; - print $langs->trans("TypeOfDeclaration"); - print ''; - //print $ATMform->combo('','type', array('introduction'=>'Introduction', 'expedition'=>'Expédition'), $type_declaration); - print $form->selectarray('type', $type, $type_declaration); - print '
'.$langs->trans("TypeOfDeclaration")."\n"; + print $form->selectarray("type_declaration", $typeOfDeclaration, GETPOST('type_declaration', 'alpha')?GETPOST('type_declaration', 'alpha'):$object->type_declaration, 0); + print "
'; dol_fiche_end(); - print '
'; - print ''; + print '
'; + print '     '; print '
'; print ''; } -/* -switch($action) { - case 'generateXML': - $obj = new TDebProdouane($PDOdb); - $obj->load($PDOdb, GETPOST('id_declaration')); - $obj->generateXMLFile(); - break; - case 'list': - _liste($exporttype); - break; - case 'export': - if ($exporttype == 'deb') _export_xml_deb($type_declaration, $year, str_pad($month, 2, 0, STR_PAD_LEFT)); - else _export_xml_des($type_declaration, $year, str_pad($month, 2, 0, STR_PAD_LEFT)); - default: - if ($exporttype == 'deb') _print_form_deb(); - else _print_form_des(); - break; +if ($id > 0 && $action != 'edit') { + /* ************************************************************************** */ + /* */ + /* View mode */ + /* */ + /* ************************************************************************** */ + $res = $object->fetch($id); + if ($res < 0) { + dol_print_error($db, $object->error); + exit; + } + + /* + * Show tabs + */ + $head = intracommreport_prepare_head($object); + + dol_fiche_head($head, 'general', $langs->trans("IntracommReport"), -1, 'user'); + + // Confirm remove report + if ($action == 'delete') { + $formquestion = array(); + if ($backtopage) { + $formquestion[] = array( + 'type' => 'hidden', + 'name' => 'backtopage', + 'value' => ($backtopage != '1' ? $backtopage : $_SERVER["HTTP_REFERER"]) + ); + } + print $form->formconfirm("card.php?rowid=" . $id, $langs->trans("DeleteReport"), + $langs->trans("ConfirmDeleteReport"), "confirm_delete", $formquestion, 'no', 1); + } + + $linkback = '' . $langs->trans("BackToList") . ''; + + dol_banner_tab($object, 'rowid', $linkback); + + print '
'; + print '
'; + + print '
'; + print ''; + + // Type + print '\n"; + + // Analysis Period + print ''; + print ''; + + // Type of Declaration + print ''; + print ''; + + print "
' . $langs->trans("Type") . '' . $object->declaration . "
' . $langs->trans("AnalysisPeriod") . '' . $object->period . '
' . $langs->trans("TypeOfDeclaration") . '' . $object->type_declaration . '
\n"; + + print "
\n"; + print '
'; + + dol_fiche_end(); } -function _print_form_des() -{ - global $langs, $formother, $year, $month, $type_declaration; + /* + switch($action) { + case 'generateXML': + $obj = new TDebProdouane($PDOdb); + $obj->load($PDOdb, GETPOST('id_declaration')); + $obj->generateXMLFile(); + break; + case 'list': + _liste($exporttype); + break; + case 'export': + if ($exporttype == 'deb') _export_xml_deb($type_declaration, $year, str_pad($month, 2, 0, STR_PAD_LEFT)); + else _export_xml_des($type_declaration, $year, str_pad($month, 2, 0, STR_PAD_LEFT)); + default: + if ($exporttype == 'deb') _print_form_deb(); + else _print_form_des(); + break; + } - $title = $langs->trans("IntracommReportDESTitle"); - llxHeader("", $title); - print load_fiche_titre($langs->trans("IntracommReportDESTitle")); + function _print_form_des() + { + global $langs, $formother, $year, $month, $type_declaration; - dol_fiche_head(); + $title = $langs->trans("IntracommReportDESTitle"); + llxHeader("", $title); + print load_fiche_titre($langs->trans("IntracommReportDESTitle")); - print '
'; - print ''; - print ''; - print ''; - print ''; // Permet d'utiliser le bon select de la requête sql + dol_fiche_head(); - print ''; + print ''; + print ''; + print ''; + print ''; + print ''; // Permet d'utiliser le bon select de la requête sql - print ''; + print '
'; - print 'Paramètres de l\'export'; - print '
'; - print ''; - print ''; - print ''; - print ''; + print ''; - print '
Période d\'analyse'; - $TabMonth = array(); - for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); - //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); - print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); - print '
'; + print 'Paramètres de l\'export'; + print '
'; + print ''; + print 'Période d\'analyse'; + print ''; + $TabMonth = array(); + for($i=1;$i<=12;$i++) $TabMonth[$i] = $langs->trans('Month'.str_pad($i, 2, 0, STR_PAD_LEFT)); + //print $ATMform->combo('','month', $TabMonth, empty($month) ? date('m') : $month); + print $formother->selectyear(empty($year) ? date('Y') : $year,'year',0, 20, 5); + print ''; + print ''; - print '
'; - print ''; - print '
'; + print ''; - print '
'; -} + print '
'; + print ''; + print '
'; -function _export_xml_deb($type_declaration, $period_year, $period_month) { + print ''; + } - global $db, $conf; + function _export_xml_deb($type_declaration, $period_year, $period_month) { - $obj = new TDebProdouane($db); - $obj->entity = $conf->entity; - $obj->mode = 'O'; - $obj->periode = $period_year.'-'.$period_month; - $obj->type_declaration = $type_declaration; - $obj->numero_declaration = $obj->getNextNumeroDeclaration(); - $obj->content_xml = $obj->getXML('O', $type_declaration, $period_year.'-'.$period_month); - if(empty($obj->errors)) { - $obj->save($PDOdb); - $obj->generateXMLFile(); - } - else setEventMessage($obj->errors, 'warnings'); -} + global $db, $conf; -function _export_xml_des($type_declaration, $period_year, $period_month) { + $obj = new TDebProdouane($db); + $obj->entity = $conf->entity; + $obj->mode = 'O'; + $obj->periode = $period_year.'-'.$period_month; + $obj->type_declaration = $type_declaration; + $obj->numero_declaration = $obj->getNextNumeroDeclaration(); + $obj->content_xml = $obj->getXML('O', $type_declaration, $period_year.'-'.$period_month); + if(empty($obj->errors)) { + $obj->save($PDOdb); + $obj->generateXMLFile(); + } + else setEventMessage($obj->errors, 'warnings'); + } - global $PDOdb, $conf; + function _export_xml_des($type_declaration, $period_year, $period_month) { - $obj = new TDebProdouane($PDOdb); - $obj->entity = $conf->entity; - $obj->periode = $period_year.'-'.$period_month; - $obj->type_declaration = $type_declaration; - $obj->exporttype = 'des'; - $obj->numero_declaration = $obj->getNextNumeroDeclaration(); - $obj->content_xml = $obj->getXMLDes($period_year, $period_month, $type_declaration); - if(empty($obj->errors)) { - $obj->save($PDOdb); - $obj->generateXMLFile(); - } - else setEventMessage($obj->errors, 'warnings'); -} -*/ + global $PDOdb, $conf; + $obj = new TDebProdouane($PDOdb); + $obj->entity = $conf->entity; + $obj->periode = $period_year.'-'.$period_month; + $obj->type_declaration = $type_declaration; + $obj->exporttype = 'des'; + $obj->numero_declaration = $obj->getNextNumeroDeclaration(); + $obj->content_xml = $obj->getXMLDes($period_year, $period_month, $type_declaration); + if(empty($obj->errors)) { + $obj->save($PDOdb); + $obj->generateXMLFile(); + } + else setEventMessage($obj->errors, 'warnings'); + } + */ + +// End of page llxFooter(); +$db->close(); diff --git a/htdocs/langs/en_US/intracommreport.lang b/htdocs/langs/en_US/intracommreport.lang index 42c3f175c14..51d8ec0fdba 100644 --- a/htdocs/langs/en_US/intracommreport.lang +++ b/htdocs/langs/en_US/intracommreport.lang @@ -7,28 +7,29 @@ IntracommReportAbout = About intracommreport INTRACOMMREPORT_NUM_AGREMENT=Numéro d'agrément (délivré par le CISD de rattachement) INTRACOMMREPORT_TYPE_ACTEUR=Type d'acteur INTRACOMMREPORT_ROLE_ACTEUR=Rôle joué par l'acteur -INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION=Niveau d'oligation sur les introductions +INTRACOMMREPORT_NIV_OBLIGATION_INTRODUCTION=Niveau d'obligation sur les introductions INTRACOMMREPORT_NIV_OBLIGATION_EXPEDITION=Niveau d'obligation sur les expéditions INTRACOMMREPORT_CATEG_FRAISDEPORT=Catégorie de services de type "Frais de port" INTRACOMMREPORT_NUM_DECLARATION=Numéro de déclarant #Menu -MenuDeclaration=Export Pro-Douane -MenuDeclarationNew=Nouvelle déclaration -MenuDeclarationList=Liste +MenuIntracommReport=Intracomm report +MenuIntracommReportNew=New declaration +MenuIntracommReportList=List # View +Declaration=Declaration AnalysisPeriod=Analysis period TypeOfDeclaration=Type of declaration +DEB=Goods exchange declaration (DEB) +DES=Services exchange declaration (DES) #Page d'export -IntracommReportDEBTitle=Export d'un fichier XML au format ProDouane - DEB -IntracommReportDESTitle=Export d'un fichier XML au format ProDouane - DES +IntracommReportTitle=Preparation of an XML file in ProDouane format #Liste -IntracommReportListDEB=Liste des déclarations générées (DEB) -IntracommReportListDES=Liste des déclarations générées (DES) +IntracommReportList=List of generated declarations IntracommReportNumber=Numéro déclaration IntracommReportPeriod=Période d'analyse IntracommReportTypeDeclaration=Type de déclaration From 2c74caff905886ab6d314e3701fad0ae6b08bdb9 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 22 Jul 2019 06:56:55 +0200 Subject: [PATCH 011/317] WIP --- htdocs/admin/dict.php | 21 ++- htdocs/comm/card.php | 22 +++ htdocs/core/class/commonobject.class.php | 47 ++++++ htdocs/core/class/html.form.class.php | 137 ++++++++++++++++++ htdocs/fourn/facture/card.php | 58 +++++++- .../install/mysql/migration/10.0.0-11.0.0.sql | 32 ++-- .../mysql/tables/llx_c_transport_mode.key.sql | 19 +++ .../mysql/tables/llx_c_transport_mode.sql | 9 +- htdocs/install/mysql/tables/llx_societe.sql | 2 + htdocs/langs/en_US/admin.lang | 1 + htdocs/langs/en_US/intracommreport.lang | 13 +- htdocs/societe/class/societe.class.php | 7 +- 12 files changed, 331 insertions(+), 37 deletions(-) create mode 100644 htdocs/install/mysql/tables/llx_c_transport_mode.key.sql diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 87e072b8d7e..7b69fc3b2fd 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -8,7 +8,7 @@ * Copyright (C) 2011 Remy Younes * Copyright (C) 2012-2015 Marcos García * Copyright (C) 2012 Christophe Battarel - * Copyright (C) 2011-2016 Alexandre Spangaro + * Copyright (C) 2011-2019 Alexandre Spangaro * Copyright (C) 2015 Ferran Marcet * Copyright (C) 2016 Raphaël Doursenaud * @@ -88,7 +88,7 @@ $hookmanager->initHooks(array('admin')); // Put here declaration of dictionaries properties // Sort order to show dictionary (0 is space). All other dictionaries (added by modules) will be at end of this. -$taborder=array(9,0,4,3,2,0,1,8,19,16,27,0,5,11,0,33,34,0,6,0,29,0,7,24,28,17,35,36,0,10,23,12,13,0,14,0,22,20,18,21,0,15,30,0,37,0,25,0); +$taborder=array(9,0,4,3,2,0,1,8,19,16,27,0,5,11,0,33,34,0,6,0,29,0,7,24,28,17,35,36,0,10,23,12,13,0,14,0,22,20,18,21,38,0,15,30,0,37,0,25,0); // Name of SQL tables of dictionaries $tabname=array(); @@ -129,6 +129,7 @@ $tabname[34]= MAIN_DB_PREFIX."c_hrm_function"; $tabname[35]= MAIN_DB_PREFIX."c_exp_tax_cat"; $tabname[36]= MAIN_DB_PREFIX."c_exp_tax_range"; $tabname[37]= MAIN_DB_PREFIX."c_units"; +$tabname[38]= MAIN_DB_PREFIX."c_transport_mode"; // Dictionary labels $tablib=array(); @@ -169,6 +170,7 @@ $tablib[34]= "DictionaryFunction"; $tablib[35]= "DictionaryExpenseTaxCat"; $tablib[36]= "DictionaryExpenseTaxRange"; $tablib[37]= "DictionaryMeasuringUnits"; +$tablib[38]= "DictionaryTransportMode"; // Requests to extract data $tabsql=array(); @@ -209,6 +211,7 @@ $tabsql[34]= "SELECT rowid, pos, code, label, c_level, active FROM ".MAIN_DB_PRE $tabsql[35]= "SELECT c.rowid, c.label, c.active, c.entity FROM ".MAIN_DB_PREFIX."c_exp_tax_cat c"; $tabsql[36]= "SELECT r.rowid, r.fk_c_exp_tax_cat, r.range_ik, r.active, r.entity FROM ".MAIN_DB_PREFIX."c_exp_tax_range r"; $tabsql[37]= "SELECT r.rowid, r.code, r.label, r.short_label, r.unit_type, r.scale, r.active FROM ".MAIN_DB_PREFIX."c_units r"; +$tabsql[38]= "SELECT rowid as rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_transport_mode"; // Criteria to sort dictionaries $tabsqlsort=array(); @@ -249,6 +252,7 @@ $tabsqlsort[34]="code ASC"; $tabsqlsort[35]="c.label ASC"; $tabsqlsort[36]="r.fk_c_exp_tax_cat ASC, r.range_ik ASC"; $tabsqlsort[37]="r.unit_type ASC, r.scale ASC, r.code ASC"; +$tabsqlsort[38]="code ASC"; // Nom des champs en resultat de select pour affichage du dictionnaire $tabfield=array(); @@ -289,6 +293,7 @@ $tabfield[34]= "code,label"; $tabfield[35]= "label"; $tabfield[36]= "range_ik,fk_c_exp_tax_cat"; $tabfield[37]= "code,label,short_label,unit_type,scale"; +$tabfield[38]= "code,label"; // Nom des champs d'edition pour modification d'un enregistrement $tabfieldvalue=array(); @@ -329,6 +334,7 @@ $tabfieldvalue[34]= "code,label"; $tabfieldvalue[35]= "label"; $tabfieldvalue[36]= "range_ik,fk_c_exp_tax_cat"; $tabfieldvalue[37]= "code,label,short_label,unit_type,scale"; +$tabfieldvalue[38]= "code,label"; // Nom des champs dans la table pour insertion d'un enregistrement $tabfieldinsert=array(); @@ -369,6 +375,7 @@ $tabfieldinsert[34]= "code,label"; $tabfieldinsert[35]= "label"; $tabfieldinsert[36]= "range_ik,fk_c_exp_tax_cat"; $tabfieldinsert[37]= "code,label,short_label,unit_type,scale"; +$tabfieldinsert[38]= "code,label"; // Rowid name if the field is not autoincrement type // Example: "" if id field is "rowid" and has autoincrement on @@ -411,6 +418,7 @@ $tabrowid[34]= "rowid"; $tabrowid[35]= ""; $tabrowid[36]= ""; $tabrowid[37]= ""; +$tabrowid[38]= ""; // Condition to show dictionary in setup page $tabcond=array(); @@ -451,6 +459,7 @@ $tabcond[34]= ! empty($conf->hrm->enabled); $tabcond[35]= ! empty($conf->expensereport->enabled); $tabcond[36]= ! empty($conf->expensereport->enabled); $tabcond[37]= ! empty($conf->product->enabled); +$tabcond[38]= ! empty($conf->intracommreport->enabled); // List of help for fields $tabhelp=array(); @@ -488,9 +497,10 @@ $tabhelp[30] = array('code'=>$langs->trans("EnterAnyCode"), 'name'=>$langs->tran //$tabhelp[32] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[33] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[34] = array('code'=>$langs->trans("EnterAnyCode")); -$tabhelp[35]= array(); -$tabhelp[36]= array('range_ik'=>$langs->trans('PrevRangeToThisRange')); -$tabhelp[37]= array('code'=>$langs->trans("EnterAnyCode")); +$tabhelp[35] = array(); +$tabhelp[36] = array('range_ik'=>$langs->trans('PrevRangeToThisRange')); +$tabhelp[37] = array('code'=>$langs->trans("EnterAnyCode")); +$tabhelp[38] = array('code'=>$langs->trans("EnterAnyCode")); // List of check for fields (NOT USED YET) $tabfieldcheck=array(); @@ -531,6 +541,7 @@ $tabfieldcheck[34] = array(); $tabfieldcheck[35]= array(); $tabfieldcheck[36]= array(); $tabfieldcheck[37]= array(); +$tabfieldcheck[38]= array(); // Complete all arrays with entries found into modules complete_dictionary_with_modules($taborder, $tabname, $tablib, $tabsql, $tabsqlsort, $tabfield, $tabfieldvalue, $tabfieldinsert, $tabrowid, $tabcond, $tabhelp, $tabfieldcheck); diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index 721aba20de8..9b3480810b3 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -488,6 +488,28 @@ if ($object->id > 0) print ''; } + if (! empty($conf->intracommreport->enabled)) + { + // Transport mode by default + print ''; + print ''; + print '
'; + print $langs->trans('IntracommReportTransportMode'); + print ''; + if (($action != 'edittransportmode') && $user->rights->societe->creer) print 'id.'">'.img_edit($langs->trans('SetMode'), 1).'
'; + print ''; + if ($action == 'edittransportmode') + { + $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->fk_transport_mode, 'fk_transport_mode', 1); + } + else + { + $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->fk_transport_mode, 'none'); + } + print ""; + print ''; + } + // Categories if (!empty($conf->categorie->enabled) && !empty($user->rights->categorie->lire)) { $langs->load("categories"); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index a3ca781cd94..1f52b5a1aef 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -285,6 +285,12 @@ abstract class CommonObject */ public $cond_reglement_id; + /** + * @var int Transport mode ID (For module intracomm report) + * @see setTransportMode() + */ + public $transport_mode_id; + /** * @var int Payment terms ID * @deprecated Kept for compatibility @@ -2054,6 +2060,47 @@ abstract class CommonObject } } + /** + * Change the transport mode methods + * + * @param int $id Id of new payment method + * @return int >0 if OK, <0 if KO + */ + public function setTransportMode($id) + { + dol_syslog(get_class($this).'::setTransportMode('.$id.')'); + if ($this->statut >= 0 || $this->element == 'societe') + { + $fieldname = 'fk_transport_mode'; + if ($this->element == 'societe') $fieldname = 'transport_mode'; + if (get_class($this) == 'Fournisseur') $fieldname = 'transport_mode_supplier'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET '.$fieldname.' = '.(($id > 0 || $id == '0') ? $id : 'NULL'); + $sql .= ' WHERE rowid='.$this->id; + + if ($this->db->query($sql)) + { + $this->transport_mode_id = $id; + // for supplier + if (get_class($this) == 'Fournisseur') $this->transport_mode_supplier_id = $id; + return 1; + } + else + { + dol_syslog(get_class($this).'::setTransportMode Error '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog(get_class($this).'::setTransportMode, status of the object is incompatible'); + $this->error='Status of the object is incompatible '.$this->statut; + return -2; + } + } + /** * Define delivery address * @deprecated diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 45bc4525431..911305993dd 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -71,6 +71,7 @@ class Form // Cache arrays public $cache_types_paiements=array(); public $cache_conditions_paiements=array(); + public $cache_transport_mode=array(); public $cache_availability=array(); public $cache_demand_reason=array(); public $cache_types_fees=array(); @@ -3467,6 +3468,108 @@ class Form return $return; } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Load in cache list of transport mode + * + * @return int Nb of lines loaded, <0 if KO + */ + public function load_cache_transport_mode() + { + // phpcs:enable + global $langs; + + $num=count($this->cache_transport_mode); + if ($num > 0) return $num; // Cache already loaded + + dol_syslog(__METHOD__, LOG_DEBUG); + + $this->cache_transport_mode = array(); + + $sql = "SELECT rowid, code, label, active"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_transport_mode"; + $sql.= " WHERE entity IN (".getEntity('c_transport_mode').")"; + //if ($active >= 0) $sql.= " AND active = ".$active; + + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + // If traduction exist, we use it else we take the default label + $label=($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code)!=("PaymentTypeShort".$obj->code)?$langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code):($obj->label!='-'?$obj->label:'')); + $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid; + $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code; + $this->cache_transport_mode[$obj->rowid]['label']= $label; + $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active; + $i++; + } + + $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1); + + return $num; + } + else + { + dol_print_error($this->db); + return -1; + } + } + + /** + * Return list of transport mode for intracomm report + * + * @param string $selected Id of the transport mode pre-selected + * @param string $htmlname Name of the select field + * @param int $format 0=id+label, 1=code+code, 2=code+label, 3=id+code + * @param int $empty 1=can be empty, 0 else + * @param int $noadmininfo 0=Add admin info, 1=Disable admin info + * @param int $maxlength Max length of label + * @param int $active Active or not, -1 = all + * @param string $morecss Add more CSS on select tag + * @return void + */ + public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '') + { + global $langs,$user; + + dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG); + + $this->load_cache_transport_mode(); + + print ''; + if ($user->admin && ! $noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + } + /** * Return a HTML select list of shipping mode * @@ -4531,6 +4634,40 @@ class Form } } + /** + * Show form with transport mode + * + * @param string $page Page + * @param int $selected Id mode pre-select + * @param string $htmlname Name of select html field + * @param int $active Active or not, -1 = all + * @param int $addempty 1=Add empty entry + * @return void + */ + public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0) + { + global $langs; + if ($htmlname != "none") + { + print '
'; + print ''; + print ''; + $this->selectTransportMode($selected, $htmlname, 2, $addempty, 0, 0, $active); + print ''; + print '
'; + } + else + { + if ($selected) + { + $this->load_cache_transport_mode(); + print $this->cache_transport_mode[$selected]['label']; + } else { + print " "; + } + } + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Show form with multicurrency code diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index ae042b4c4b8..5e3a5085fbd 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -8,7 +8,7 @@ * Copyright (C) 2013-2015 Philippe Grand * Copyright (C) 2013 Florian Henry * Copyright (C) 2014-2016 Marcos García - * Copyright (C) 2016-2017 Alexandre Spangaro + * Copyright (C) 2016-2019 Alexandre Spangaro * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -355,6 +355,12 @@ if (empty($reshook)) $result=$object->setBankAccount(GETPOST('fk_account', 'int')); } + // transport mode + if ($action == 'settransportmode' && $user->rights->fournisseur->facture->creer) + { + $result=$object->setTransportMode(GETPOST('transport_mode_id', 'int')); + } + // Set label elseif ($action == 'setlabel' && $user->rights->fournisseur->facture->creer) { @@ -650,6 +656,7 @@ if (empty($reshook)) $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); + $object->transport_mode_id = GETPOST('transport_mode_id'); // Proprietes particulieres a facture de remplacement $object->fk_facture_source = GETPOST('fac_replacement'); @@ -715,6 +722,7 @@ if (empty($reshook)) $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); + $object->transport_mode_id = GETPOST('transport_mode_id'); // Proprietes particulieres a facture avoir $object->fk_facture_source = $sourceinvoice > 0 ? $sourceinvoice : ''; @@ -827,6 +835,7 @@ if (empty($reshook)) $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); + $object->transport_mode_id = GETPOST('transport_mode_id'); // Auto calculation of date due if not filled by user if(empty($object->date_echeance)) $object->date_echeance = $object->calculate_date_lim_reglement(); @@ -1687,8 +1696,10 @@ if ($action == 'create') $remise_percent = (!empty($objectsrc->remise_percent)?$objectsrc->remise_percent:(!empty($soc->remise_supplier_percent)?$soc->remise_supplier_percent:0)); $remise_absolue = (!empty($objectsrc->remise_absolue)?$objectsrc->remise_absolue:(!empty($soc->remise_absolue)?$soc->remise_absolue:0)); $dateinvoice = empty($conf->global->MAIN_AUTOFILL_DATE)?-1:''; + $transport_mode_id = (!empty($objectsrc->transport_mode_id)?$objectsrc->transport_mode_id:(!empty($soc->transport_mode_id)?$soc->transport_mode_id:0)); - if (!empty($conf->multicurrency->enabled)) + + if (!empty($conf->multicurrency->enabled)) { if (!empty($objectsrc->multicurrency_code)) $currency_code = $objectsrc->multicurrency_code; if (!empty($conf->global->MULTICURRENCY_USE_ORIGIN_TX) && !empty($objectsrc->multicurrency_tx)) $currency_tx = $objectsrc->multicurrency_tx; @@ -1708,10 +1719,11 @@ if ($action == 'create') $cond_reglement_id = $societe->cond_reglement_supplier_id; $mode_reglement_id = $societe->mode_reglement_supplier_id; $fk_account = $societe->fk_account; - $datetmp=dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); - $dateinvoice=($datetmp==''?(empty($conf->global->MAIN_AUTOFILL_DATE)?-1:''):$datetmp); - $datetmp=dol_mktime(12, 0, 0, $_POST['echmonth'], $_POST['echday'], $_POST['echyear']); - $datedue=($datetmp==''?-1:$datetmp); + $datetmp = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + $dateinvoice = ($datetmp==''?(empty($conf->global->MAIN_AUTOFILL_DATE)?-1:''):$datetmp); + $datetmp = dol_mktime(12, 0, 0, $_POST['echmonth'], $_POST['echday'], $_POST['echyear']); + $datedue = ($datetmp==''?-1:$datetmp); + $transport_mode_id = $societe->transport_mode_supplier_id; if (!empty($conf->multicurrency->enabled) && !empty($soc->multicurrency_code)) $currency_code = $soc->multicurrency_code; } @@ -2041,6 +2053,15 @@ if ($action == 'create') print ''; } + // Intracomm report + if (!empty($conf->intracommreport->enabled)) + { + $langs->loadLangs(array("intracommreport")); + print '' . $langs->trans('IntracommReportTransportMode') . ''; + $form->selectModeTransport(isset($_POST['transport_mode_id']) ? $_POST['transport_mode_id'] : $transport_mode_id, 'transport_mode_id'); + print ''; + } + // Public note print ''.$langs->trans('NotePublic').''; print ''; @@ -2091,9 +2112,9 @@ if ($action == 'create') if ($cntinvoice>=1) { setEventMessages('WarningBillExist', null, 'warnings'); - echo ' ('.$langs->trans('LatestRelatedBill').end($objectsrc->linkedObjects['invoice_supplier'])->getNomUrl(1).')'; + print ' ('.$langs->trans('LatestRelatedBill').end($objectsrc->linkedObjects['invoice_supplier'])->getNomUrl(1).')'; } - echo ''; + print ''; print ''.$langs->trans('AmountHT').''.price($objectsrc->total_ht).''; print ''.$langs->trans('AmountVAT').''.price($objectsrc->total_tva).""; if ($mysoc->localtax1_assuj=="1" || $object->total_localtax1 != 0) //Localtax1 @@ -2626,6 +2647,27 @@ else print ''; } + // Intracomm report + $langs->loadLangs(array("intracommreport")); + print ''; + print ''; + if ($action != 'editmode' && $user->rights->fournisseur->facture->creer) { + print ''; + } + print '
'; + print $langs->trans('IntracommReportTransportMode'); + print 'id.'">'.img_edit($langs->trans('SetMode'), 1).'
'; + print ''; + if ($action == 'editmode') + { + $form->formTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'transport_mode_id', 1, 1); + } + else + { + $form->formTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'none'); + } + print ''; + // Other attributes $cols = 2; include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; diff --git a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql index 05fb26c0e17..4f7b48bdae4 100644 --- a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql +++ b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql @@ -34,23 +34,27 @@ -- Intracomm Report CREATE TABLE llx_c_transport_mode ( - rowid integer AUTO_INCREMENT PRIMARY KEY, - code varchar(3) NOT NULL, - label varchar(255) NOT NULL, - active tinyint DEFAULT 1 NOT NULL + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1 NOT NULL, -- multi company id + code varchar(3) NOT NULL, + label varchar(255) NOT NULL, + active tinyint DEFAULT 1 NOT NULL ) ENGINE=innodb; -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('ROU', 'Transport par route', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('AIR', 'Transport par air', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('POS', 'Envois postaux', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propulsion propre', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('ROU', 'Transport par route', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('AIR', 'Transport par air', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('POS', 'Envois postaux', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('PRO', 'Propulsion propre', 1); -ALTER TABLE llx_facture ADD COLUMN fk_mode_transport integer after location_incoterms; -ALTER TABLE llx_facture_fourn ADD COLUMN fk_mode_transport integer after location_incoterms; +ALTER TABLE llx_facture ADD COLUMN fk_transport_mode integer after location_incoterms; +ALTER TABLE llx_facture_fourn ADD COLUMN fk_transport_mode integer after location_incoterms; + +ALTER TABLE llx_societe ADD COLUMN transport_mode tinyint after cond_reglement; +ALTER TABLE llx_societe ADD COLUMN transport_mode_supplier tinyint after cond_reglement_supplier; CREATE TABLE llx_intracommreport ( diff --git a/htdocs/install/mysql/tables/llx_c_transport_mode.key.sql b/htdocs/install/mysql/tables/llx_c_transport_mode.key.sql new file mode 100644 index 00000000000..4a7d5e89009 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_transport_mode.key.sql @@ -0,0 +1,19 @@ +-- =================================================================== +-- Copyright (C) 2019 Open-DSI +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- =================================================================== + +ALTER TABLE llx_c_transport_mode ADD UNIQUE INDEX uk_c_transport_mode (code, entity); \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_c_transport_mode.sql b/htdocs/install/mysql/tables/llx_c_transport_mode.sql index 0528a36a415..a2634f2a0bf 100644 --- a/htdocs/install/mysql/tables/llx_c_transport_mode.sql +++ b/htdocs/install/mysql/tables/llx_c_transport_mode.sql @@ -17,9 +17,10 @@ -- ======================================================================== CREATE TABLE llx_c_transport_mode ( - rowid integer AUTO_INCREMENT PRIMARY KEY, - code varchar(3) NOT NULL, - libelle varchar(255) NOT NULL, - active tinyint DEFAULT 1 NOT NULL + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1 NOT NULL, -- multi company id + code varchar(3) NOT NULL, + label varchar(255) NOT NULL, + active tinyint DEFAULT 1 NOT NULL ) ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index e7a948d67c2..cbb50e6d33d 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -91,8 +91,10 @@ create table llx_societe remise_supplier real DEFAULT 0, -- discount by default granted by this supplier mode_reglement tinyint, -- payment mode customer cond_reglement tinyint, -- payment term customer + transport_mode tinyint, -- transport mode customer (Intracomm report) mode_reglement_supplier tinyint, -- payment mode supplier cond_reglement_supplier tinyint, -- payment term supplier + transport_mode_supplier tinyint, -- transport mode supplier (Intracomm report) fk_shipping_method integer, -- preferred shipping method id tva_assuj tinyint DEFAULT 1, -- assujeti ou non a la TVA localtax1_assuj tinyint DEFAULT 0, -- assujeti ou non a local tax 1 diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index e2323e06bca..09106a4e759 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -969,6 +969,7 @@ DictionaryHolidayTypes=Types of leave DictionaryOpportunityStatus=Lead status for project/lead DictionaryExpenseTaxCat=Expense report - Transportation categories DictionaryExpenseTaxRange=Expense report - Range by transportation category +DictionaryTransportMode=Intracomm report - Transport mode SetupSaved=Setup saved SetupNotSaved=Setup not saved BackToModuleList=Back to Module list diff --git a/htdocs/langs/en_US/intracommreport.lang b/htdocs/langs/en_US/intracommreport.lang index 51d8ec0fdba..49752441752 100644 --- a/htdocs/langs/en_US/intracommreport.lang +++ b/htdocs/langs/en_US/intracommreport.lang @@ -3,7 +3,7 @@ Module68000Desc = Intracomm report management (Support for French DEB/DES format IntracommReportSetup = Intracommreport module setup IntracommReportAbout = About intracommreport -#Conf +# Setup INTRACOMMREPORT_NUM_AGREMENT=Numéro d'agrément (délivré par le CISD de rattachement) INTRACOMMREPORT_TYPE_ACTEUR=Type d'acteur INTRACOMMREPORT_ROLE_ACTEUR=Rôle joué par l'acteur @@ -13,7 +13,7 @@ INTRACOMMREPORT_CATEG_FRAISDEPORT=Catégorie de services de type "Frais de port" INTRACOMMREPORT_NUM_DECLARATION=Numéro de déclarant -#Menu +# Menu MenuIntracommReport=Intracomm report MenuIntracommReportNew=New declaration MenuIntracommReportList=List @@ -25,12 +25,15 @@ TypeOfDeclaration=Type of declaration DEB=Goods exchange declaration (DEB) DES=Services exchange declaration (DES) -#Page d'export +# Export page IntracommReportTitle=Preparation of an XML file in ProDouane format -#Liste +# List IntracommReportList=List of generated declarations IntracommReportNumber=Numéro déclaration IntracommReportPeriod=Période d'analyse IntracommReportTypeDeclaration=Type de déclaration -IntracommReportDownload=Télécharger fichier XML \ No newline at end of file +IntracommReportDownload=Télécharger fichier XML + +# Invoice +IntracommReportTransportMode=Transport mode \ No newline at end of file diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 16b690ecaf7..469990cd636 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -296,6 +296,7 @@ class Societe extends CommonObject public $remise_supplier_percent; public $mode_reglement_supplier_id; public $cond_reglement_supplier_id; + public $transport_mode_supplier_id; /** * @var int ID @@ -1063,8 +1064,10 @@ class Societe extends CommonObject $sql .= ",mode_reglement = ".(! empty($this->mode_reglement_id)?"'".$this->db->escape($this->mode_reglement_id)."'":"null"); $sql .= ",cond_reglement = ".(! empty($this->cond_reglement_id)?"'".$this->db->escape($this->cond_reglement_id)."'":"null"); - $sql .= ",mode_reglement_supplier = ".(! empty($this->mode_reglement_supplier_id)?"'".$this->db->escape($this->mode_reglement_supplier_id)."'":"null"); + $sql .= ",transport_mode = ".(! empty($this->transport_mode_id)?"'".$this->db->escape($this->transport_mode_id)."'":"null"); + $sql .= ",mode_reglement_supplier = ".(! empty($this->mode_reglement_supplier_id)?"'".$this->db->escape($this->mode_reglement_supplier_id)."'":"null"); $sql .= ",cond_reglement_supplier = ".(! empty($this->cond_reglement_supplier_id)?"'".$this->db->escape($this->cond_reglement_supplier_id)."'":"null"); + $sql .= ",transport_mode_supplier = ".(! empty($this->transport_mode_supplier_id)?"'".$this->db->escape($this->transport_mode_supplier_id)."'":"null"); $sql .= ",fk_shipping_method = ".(! empty($this->shipping_method_id)?"'".$this->db->escape($this->shipping_method_id)."'":"null"); $sql .= ",client = " . (! empty($this->client)?$this->client:0); @@ -1405,8 +1408,10 @@ class Societe extends CommonObject $this->remise_supplier_percent = $obj->remise_supplier; $this->mode_reglement_id = $obj->mode_reglement; $this->cond_reglement_id = $obj->cond_reglement; + $this->transport_mode_id = $obj->transport_mode; $this->mode_reglement_supplier_id = $obj->mode_reglement_supplier; $this->cond_reglement_supplier_id = $obj->cond_reglement_supplier; + $this->transport_mode_supplier_id = $obj->transport_mode_supplier; $this->shipping_method_id = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null; $this->fk_account = $obj->fk_account; From ce3e658608ba35061526867f17bd62942cffa15f Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 31 Dec 2019 07:36:40 +0000 Subject: [PATCH 012/317] Fixing style errors. --- htdocs/core/boxes/intracommreport_box.php | 2 +- .../core/modules/modIntracommreport.class.php | 1 - ...ommreport_intracommreporttrigger.class.php | 2 +- .../intracommreport/admin/intracommreport.php | 6 +-- htdocs/intracommreport/card.php | 4 +- .../class/actions_intracommexport.class.php | 4 +- .../class/intracommreport.class.php | 43 +++++++++---------- 7 files changed, 30 insertions(+), 32 deletions(-) diff --git a/htdocs/core/boxes/intracommreport_box.php b/htdocs/core/boxes/intracommreport_box.php index 1758b2ffda4..1df09500173 100644 --- a/htdocs/core/boxes/intracommreport_box.php +++ b/htdocs/core/boxes/intracommreport_box.php @@ -85,4 +85,4 @@ class intracommreportbox extends ModeleBoxes { parent::showBox($this->info_box_head, $this->info_box_contents); } -} \ No newline at end of file +} diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index dd1ab435609..506b176bfd5 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -125,6 +125,5 @@ class modIntracommreport extends DolibarrModules // Exports $r=1; - } } diff --git a/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php b/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php index ddbb5df329b..fb2852cedb8 100644 --- a/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php +++ b/htdocs/core/triggers/interface_99_modintracommreport_intracommreporttrigger.class.php @@ -568,4 +568,4 @@ class Interfaceintracommreporttrigger return 0; } -} \ No newline at end of file +} diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php index 68531304206..bcc2c867757 100644 --- a/htdocs/intracommreport/admin/intracommreport.php +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -195,11 +195,11 @@ print '
'; print ''; print '
'; print '
'; - + print ''; - + dol_fiche_end(); // End of page llxFooter(); -$db->close(); \ No newline at end of file +$db->close(); diff --git a/htdocs/intracommreport/card.php b/htdocs/intracommreport/card.php index 5c13a25257f..4f33c807ffa 100644 --- a/htdocs/intracommreport/card.php +++ b/htdocs/intracommreport/card.php @@ -147,8 +147,8 @@ if ($action == 'create') print $langs->trans("AnalysisPeriod"); print ''; print ''; - print $formother->select_month($month ? date('M') : $month,'month',0, 1, 'widthauto valignmiddle '); - print $formother->select_year($year ? date('Y') : $year,'year',0, 3, 3); + print $formother->select_month($month ? date('M') : $month, 'month', 0, 1, 'widthauto valignmiddle '); + print $formother->select_year($year ? date('Y') : $year, 'year', 0, 3, 3); print ''; print ''; diff --git a/htdocs/intracommreport/class/actions_intracommexport.class.php b/htdocs/intracommreport/class/actions_intracommexport.class.php index f4bcc53863b..49cbffe2cf2 100644 --- a/htdocs/intracommreport/class/actions_intracommexport.class.php +++ b/htdocs/intracommreport/class/actions_intracommexport.class.php @@ -70,7 +70,7 @@ class Actionsintracommreport if (in_array('somecontext', explode(':', $parameters['context']))) { - // do something only for the context 'somecontext' + // do something only for the context 'somecontext' } if (! $error) @@ -85,4 +85,4 @@ class Actionsintracommreport return -1; } } -} \ No newline at end of file +} diff --git a/htdocs/intracommreport/class/intracommreport.class.php b/htdocs/intracommreport/class/intracommreport.class.php index 66c3bf0d96d..709269a0747 100644 --- a/htdocs/intracommreport/class/intracommreport.class.php +++ b/htdocs/intracommreport/class/intracommreport.class.php @@ -92,7 +92,8 @@ class IntracommReport extends CommonObject * @param $mode O pour création, R pour régénération (apparemment toujours 0 dans la cadre des échanges XML selon la doc) * @param $type introduction ou expedition */ - function getXML($mode='O', $type='introduction', $periode_reference='') { + function getXML($mode = 'O', $type = 'introduction', $periode_reference = '') + { global $db, $conf, $mysoc; @@ -138,9 +139,9 @@ class IntracommReport extends CommonObject if(!empty($res)) return $e->asXML(); else return 0; } - + // $type_declaration tjrs = "expedition" à voir si ça évolue - function getXMLDes($period_year, $period_month, $type_declaration='expedition') + function getXMLDes($period_year, $period_month, $type_declaration = 'expedition') { global $db, $conf, $mysoc; @@ -162,7 +163,8 @@ class IntracommReport extends CommonObject else return 0; } - function addItemsFact(&$declaration, $type, $periode_reference, $exporttype='deb') { + function addItemsFact(&$declaration, $type, $periode_reference, $exporttype = 'deb') + { global $db, $conf; @@ -187,7 +189,6 @@ class IntracommReport extends CommonObject } while($res = $db->fetch_object($resql)) { - if ($exporttype == 'des') { $this->addItemXMlDes($declaration, $res, '', $i); @@ -196,29 +197,27 @@ class IntracommReport extends CommonObject { if(empty($res->fk_pays)) { // On n'arrête pas la boucle car on veut savoir quels sont tous les tiers qui n'ont pas de pays renseigné - $this->errors[] = 'Pays non renseigné pour le tiers '.$res->nom.''; + $this->errors[] = 'Pays non renseigné pour le tiers '.$res->nom.''; } else { if($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) { $TLinesFraisDePort[] = $res; } else $this->addItemXMl($declaration, $res, '', $i); - } + } } $i++; - } if(!empty($TLinesFraisDePort)) $this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i); if(count($this->errors) > 0) return 0; - } return 1; - } - function getSQLFactLines($type, $periode_reference, $exporttype='deb') { + function getSQLFactLines($type, $periode_reference, $exporttype = 'deb') + { global $mysoc, $conf; @@ -254,10 +253,10 @@ class IntracommReport extends CommonObject AND f.datef BETWEEN "'.$periode_reference.'-01" AND "'.$periode_reference.'-'.date('t').'"'; return $sql; - } - function addItemXMl(&$declaration, &$res, $code_douane_spe='', $i) { + function addItemXMl(&$declaration, &$res, $code_douane_spe = '', $i) + { $item = $declaration->addChild('Item'); $item->addChild('ItemNumber', $i); @@ -277,10 +276,9 @@ class IntracommReport extends CommonObject $nature_of_transaction->addChild('natureOfTransactionBCode', 1); $item->addChild('modeOfTransportCode', $res->mode_transport); $item->addChild('regionCode', substr($res->zip, 0, 2)); - } - function addItemXMlDes($declaration, &$res, $code_douane_spe='', $i) + function addItemXMlDes($declaration, &$res, $code_douane_spe = '', $i) { $item = $declaration->addChild('ligne_des'); $item->addChild('numlin_des', $i); @@ -291,7 +289,8 @@ class IntracommReport extends CommonObject /** * Cette fonction ajoute un item en récupérant le code douane du produit ayant le plus haut montant dans la facture */ - function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i) { + function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i) + { global $db, $conf; @@ -309,7 +308,6 @@ class IntracommReport extends CommonObject } foreach($TLinesFraisDePort as $res) { - $sql = 'SELECT p.customcode FROM '.MAIN_DB_PREFIX.$tabledet.' d INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = d.'.$field_link.') @@ -338,11 +336,11 @@ class IntracommReport extends CommonObject $this->addItemXMl($declaration, $res, $ress->customcode, $i); $i++; - } } - function getNextNumeroDeclaration() { + function getNextNumeroDeclaration() + { global $db; $resql = $db->query('SELECT MAX(numero_declaration) as max_numero_declaration FROM '.$this->get_table().' WHERE exporttype="'.$this->exporttype.'"'); @@ -352,12 +350,14 @@ class IntracommReport extends CommonObject } // La doc impose que le numéro soit un entier positif d'un maximum de 6 caractères - static function getNumeroDeclaration($numero) { + static function getNumeroDeclaration($numero) + { return str_pad($numero, 6, 0, STR_PAD_LEFT); } - function generateXMLFile() { + function generateXMLFile() + { $name = $this->periode.'.xml'; $fname = sys_get_temp_dir().'/'.$name; @@ -374,6 +374,5 @@ class IntracommReport extends CommonObject header('Content-Length: ' . filesize($fname)); readfile($fname); exit; - } } From 19eef8aa934343325beefbb72cdd23bfc4be1f40 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 6 Jul 2020 01:26:46 +0000 Subject: [PATCH 013/317] Fixing style errors. --- htdocs/comm/card.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index f0cadb9e560..6b703b6c908 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -501,8 +501,7 @@ if ($object->id > 0) { $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->fk_transport_mode, 'fk_transport_mode', 1); } - else - { + else { $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->fk_transport_mode, 'none'); } print ""; From 0525dd3c1f2f0bccc06bb2d532aa5a4ebed4bba5 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 6 Jul 2020 03:28:53 +0200 Subject: [PATCH 014/317] Fix migration - Move to v13 --- .../install/mysql/migration/10.0.0-11.0.0.sql | 43 ------------------- .../install/mysql/migration/12.0.0-13.0.0.sql | 39 +++++++++++++++++ 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql index ae89990b47f..2a7a8963e9f 100644 --- a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql +++ b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql @@ -27,49 +27,6 @@ -- To set a field as default NULL: -- VPGSQL8.2 ALTER TABLE llx_table ALTER COLUMN name SET DEFAULT NULL; -- Note: fields with type BLOB/TEXT can't have default value. --- Missing in 10.0 - - --- For 11.0 - --- Intracomm Report -CREATE TABLE llx_c_transport_mode ( - rowid integer AUTO_INCREMENT PRIMARY KEY, - entity integer DEFAULT 1 NOT NULL, -- multi company id - code varchar(3) NOT NULL, - label varchar(255) NOT NULL, - active tinyint DEFAULT 1 NOT NULL -) ENGINE=innodb; - -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('ROU', 'Transport par route', 1); -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('AIR', 'Transport par air', 1); -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('POS', 'Envois postaux', 1); -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); -INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('PRO', 'Propulsion propre', 1); - -ALTER TABLE llx_facture ADD COLUMN fk_transport_mode integer after location_incoterms; -ALTER TABLE llx_facture_fourn ADD COLUMN fk_transport_mode integer after location_incoterms; - -ALTER TABLE llx_societe ADD COLUMN transport_mode tinyint after cond_reglement; -ALTER TABLE llx_societe ADD COLUMN transport_mode_supplier tinyint after cond_reglement_supplier; - -CREATE TABLE llx_intracommreport -( - rowid integer AUTO_INCREMENT PRIMARY KEY, - - ref varchar(30) NOT NULL, -- report reference number - entity integer DEFAULT 1 NOT NULL, -- multi company id - type_declaration varchar(32), - period varchar(32), - mode varchar(32), - content_xml text, - type_export varchar(10), - datec datetime, - tms timestamp -)ENGINE=innodb; -- Missing in v10 ALTER TABLE llx_account_bookkeeping ADD COLUMN date_export datetime DEFAULT NULL; diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 6af4fc35ae7..d45c5337f52 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -74,3 +74,42 @@ ALTER TABLE llx_user DROP COLUMN whatsapp; ALTER TABLE llx_user ADD COLUMN datestartvalidity datetime; ALTER TABLE llx_user ADD COLUMN dateendvalidity datetime; +-- Intracomm Report +CREATE TABLE llx_c_transport_mode ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1 NOT NULL, -- multi company id + code varchar(3) NOT NULL, + label varchar(255) NOT NULL, + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; + +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('ROU', 'Transport par route', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('AIR', 'Transport par air', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('POS', 'Envois postaux', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('PRO', 'Propulsion propre', 1); + +ALTER TABLE llx_facture ADD COLUMN fk_transport_mode integer after location_incoterms; +ALTER TABLE llx_facture_fourn ADD COLUMN fk_transport_mode integer after location_incoterms; + +ALTER TABLE llx_societe ADD COLUMN transport_mode tinyint after cond_reglement; +ALTER TABLE llx_societe ADD COLUMN transport_mode_supplier tinyint after cond_reglement_supplier; + +CREATE TABLE llx_intracommreport +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + + ref varchar(30) NOT NULL, -- report reference number + entity integer DEFAULT 1 NOT NULL, -- multi company id + type_declaration varchar(32), + period varchar(32), + mode varchar(32), + content_xml text, + type_export varchar(10), + datec datetime, + tms timestamp +)ENGINE=innodb; + From 725ef1057d88faa0975d46b2275f0e4a24330bcf Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 6 Jul 2020 04:19:50 +0200 Subject: [PATCH 015/317] Some correct --- .../core/modules/modIntracommreport.class.php | 2 +- .../intracommreport/admin/intracommreport.php | 4 +- htdocs/intracommreport/card.php | 2 +- .../class/actions_intracommexport.class.php | 88 ------------------- .../class/intracommreport.class.php | 54 ++++++++---- htdocs/intracommreport/list.php | 16 ++-- 6 files changed, 47 insertions(+), 119 deletions(-) delete mode 100644 htdocs/intracommreport/class/actions_intracommexport.class.php diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index 506b176bfd5..e142490cbd6 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -66,7 +66,7 @@ class modIntracommreport extends DolibarrModules $this->requiredby = array(); // List of modules id to disable if this one is disabled $this->conflictwith = array(); // List of modules id this module is in conflict with $this->phpmin = array(5,5); // Minimum version of PHP required by module - $this->need_dolibarr_version = array(9,0); // Minimum version of Dolibarr required by module + $this->need_dolibarr_version = array(10,0); // Minimum version of Dolibarr required by module $this->langfiles = array("intracommreport"); // Constants diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php index bcc2c867757..8950839515a 100644 --- a/htdocs/intracommreport/admin/intracommreport.php +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -1,6 +1,6 @@ - * Copyright (C) 2019 Open-DSI + * Copyright (C) 2019-2020 Open-DSI * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ if (! $user->admin) accessforbidden(); $action = GETPOST('action', 'aZ09'); -// Parameters ACCOUNTING_* and others +// Parameters INTRACOMMREPORT_* and others $list_DEB = array ( 'INTRACOMMREPORT_NUM_AGREMENT', ); diff --git a/htdocs/intracommreport/card.php b/htdocs/intracommreport/card.php index 4f33c807ffa..79725e81419 100644 --- a/htdocs/intracommreport/card.php +++ b/htdocs/intracommreport/card.php @@ -1,6 +1,6 @@ - * Copyright (C) 2019 Open-DSI + * Copyright (C) 2019-2020 Open-DSI * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/htdocs/intracommreport/class/actions_intracommexport.class.php b/htdocs/intracommreport/class/actions_intracommexport.class.php deleted file mode 100644 index 49cbffe2cf2..00000000000 --- a/htdocs/intracommreport/class/actions_intracommexport.class.php +++ /dev/null @@ -1,88 +0,0 @@ - - * Copyright (C) 2015 ATM Consulting - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * \file class/actions_intracommreport.class.php - * \ingroup intracommreport - * \brief This file is an example hook overload class file - * Put some comments here - */ - -/** - * Class Actionsintracommreport - */ -class Actionsintracommreport -{ - /** - * @var array Hook results. Propagated to $hookmanager->resArray for later reuse - */ - public $results = array(); - - /** - * @var string String displayed by executeHook() immediately after return - */ - public $resprints; - - /** - * @var array Errors - */ - public $errors = array(); - - /** - * Constructor - */ - public function __construct() - { - } - - /** - * Overloading the doActions function : replacing the parent's function with the one below - * - * @param array() $parameters Hook metadatas (context, etc...) - * @param CommonObject &$object The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...) - * @param string &$action Current action (if set). Generally create or edit or null - * @param HookManager $hookmanager Hook manager propagated to allow calling another hook - * @return int < 0 on error, 0 on success, 1 to replace standard code - */ - function doActions($parameters, &$object, &$action, $hookmanager) - { - $error = 0; // Error counter - $myvalue = 'test'; // A result value - - print_r($parameters); - echo "action: " . $action; - print_r($object); - - if (in_array('somecontext', explode(':', $parameters['context']))) - { - // do something only for the context 'somecontext' - } - - if (! $error) - { - $this->results = array('myreturn' => $myvalue); - $this->resprints = 'A text to show'; - return 0; // or return 1 to replace standard code - } - else - { - $this->errors[] = 'Error message'; - return -1; - } - } -} diff --git a/htdocs/intracommreport/class/intracommreport.class.php b/htdocs/intracommreport/class/intracommreport.class.php index 709269a0747..75c017704c4 100644 --- a/htdocs/intracommreport/class/intracommreport.class.php +++ b/htdocs/intracommreport/class/intracommreport.class.php @@ -1,6 +1,6 @@ - * Copyright (C) 2019 Open-DSI + * Copyright (C) 2019-2020 Open-DSI * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,7 +45,6 @@ class IntracommReport extends CommonObject /** * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe - * * @var int */ public $ismultientitymanaged = 1; @@ -54,6 +53,7 @@ class IntracommReport extends CommonObject * DEB - Product */ const TYPE_DEB = 0; + /** * DES - Service */ @@ -89,10 +89,13 @@ class IntracommReport extends CommonObject } /** - * @param $mode O pour création, R pour régénération (apparemment toujours 0 dans la cadre des échanges XML selon la doc) - * @param $type introduction ou expedition + * Generate XML file + * + * @param int $mode O for create, R for regenerate (Look always 0 ment toujours 0 within the framework of XML exchanges according to documentation) + * @param string $type introduction or expedition + * @param string $period_reference Period of reference */ - function getXML($mode = 'O', $type = 'introduction', $periode_reference = '') + function getXML($mode = 'O', $type = 'introduction', $period_reference = '') { global $db, $conf, $mysoc; @@ -119,7 +122,7 @@ class IntracommReport extends CommonObject $enveloppe->addChild('softwareUsed', 'Dolibarr'); $declaration = $enveloppe->addChild('Declaration'); $declaration->addChild('declarationId', $id_declaration); - $declaration->addChild('referencePeriod', $periode_reference); + $declaration->addChild('referencePeriod', $period_reference); if($conf->global->INTRACOMMREPORT_TYPE_ACTEUR === 'PSI') $psiId = $party_id; else $psiId = 'NA'; $declaration->addChild('PSIId', $psiId); @@ -131,7 +134,7 @@ class IntracommReport extends CommonObject /********************************************************************/ /**************Ajout des lignes de factures**************************/ - $res = self::addItemsFact($declaration, $type, $periode_reference); + $res = self::addItemsFact($declaration, $type, $period_reference); /********************************************************************/ $this->errors = array_unique($this->errors); @@ -148,7 +151,7 @@ class IntracommReport extends CommonObject $e = new SimpleXMLElement(''); $declaration_des = $e->addChild('declaration_des'); - $declaration_des->addChild('num_des', self::getNumeroDeclaration($this->numero_declaration)); + $declaration_des->addChild('num_des', self::getDeclarationNumber($this->numero_declaration)); $declaration_des->addChild('num_tvaFr', $mysoc->tva_intra); // /^FR[a-Z0-9]{2}[0-9]{9}$/ // Doit faire 13 caractères $declaration_des->addChild('mois_des', $period_month); $declaration_des->addChild('an_des', $period_year); @@ -163,14 +166,14 @@ class IntracommReport extends CommonObject else return 0; } - function addItemsFact(&$declaration, $type, $periode_reference, $exporttype = 'deb') + function addItemsFact(&$declaration, $type, $period_reference, $exporttype = 'deb') { global $db, $conf; require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php'; - $sql = $this->getSQLFactLines($type, $periode_reference, $exporttype); + $sql = $this->getSQLFactLines($type, $period_reference, $exporttype); $resql = $db->query($sql); @@ -216,7 +219,7 @@ class IntracommReport extends CommonObject return 1; } - function getSQLFactLines($type, $periode_reference, $exporttype = 'deb') + function getSQLFactLines($type, $period_reference, $exporttype = 'deb') { global $mysoc, $conf; @@ -250,7 +253,7 @@ class IntracommReport extends CommonObject AND l.product_type = '.($exporttype == 'des' ? 1 : 0).' AND f.entity = '.$conf->entity.' AND (s.fk_pays <> '.$mysoc->country_id.' OR s.fk_pays IS NULL) - AND f.datef BETWEEN "'.$periode_reference.'-01" AND "'.$periode_reference.'-'.date('t').'"'; + AND f.datef BETWEEN "'.$period_reference.'-01" AND "'.$period_reference.'-'.date('t').'"'; return $sql; } @@ -327,7 +330,7 @@ class IntracommReport extends CommonObject SELECT fk_product FROM '.MAIN_DB_PREFIX.'categorie_product WHERE fk_categorie = '.$categ_fraisdeport->id.' - ) + ) )'; $resql = $db->query($sql); @@ -339,23 +342,38 @@ class IntracommReport extends CommonObject } } - function getNextNumeroDeclaration() + /** + * Return next reference of declaration not already used (or last reference) + * + * @return string free ref or last ref + */ + public function getNextDeclarationNumber() { - global $db; + $resql = $db->query('SELECT MAX(numero_declaration) as max_numero_declaration FROM '.$this->get_table().' WHERE exporttype="'.$this->exporttype.'"'); if($resql) $res = $db->fetch_object($resql); return ($res->max_numero_declaration + 1); } + /** + * Verify declaration number. Positive integer of a maximum of 6 characters recommended by the documentation + * + * @param int $number Number to verify / convert + * @return int Number + */ // La doc impose que le numéro soit un entier positif d'un maximum de 6 caractères - static function getNumeroDeclaration($numero) + static function getDeclarationNumber($number) { - - return str_pad($numero, 6, 0, STR_PAD_LEFT); + return str_pad($number, 6, 0, STR_PAD_LEFT); } + /** + * Generate XML file + * + * @return void + */ function generateXMLFile() { diff --git a/htdocs/intracommreport/list.php b/htdocs/intracommreport/list.php index d903ef31287..8145948cc0d 100644 --- a/htdocs/intracommreport/list.php +++ b/htdocs/intracommreport/list.php @@ -1,6 +1,6 @@ - * Copyright (C) 2019 Open-DSI + * Copyright (C) 2019-2020 Open-DSI * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -297,11 +297,11 @@ if ($resql) $newcardbutton=''; $rightskey='DEB'; - if($type == IntracommReport::TYPE_DES) $rightskey='DES'; - if($user->rights->{$rightskey}->creer) + if ($type == IntracommReport::TYPE_DES) $rightskey='DES'; + if ($user->rights->{$rightskey}->creer) { $label='NewDEB'; - if($type == IntracommReport::TYPE_DES) $label='NewDES'; + if ($type == IntracommReport::TYPE_DES) $label = 'NewDES'; $newcardbutton.= dolGetButtonTitle($langs->trans($label), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/intracommreport/card.php?action=create&type='.$type); } @@ -326,7 +326,7 @@ if ($resql) if ($sall) { - foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val); + foreach ($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val); print '
'.$langs->trans("FilterOnInto", $sall) . join(', ', $fieldstosearchall).'
'; } @@ -539,8 +539,7 @@ if ($resql) print $duration_value; print (! empty($duration_unit) && isset($dur[$duration_unit]) ? ' '.$langs->trans($dur[$duration_unit]) : ''); } - else - { + else { print $obj->duration; } @@ -578,8 +577,7 @@ if ($resql) print ""; print ''; } -else -{ +else { dol_print_error($db); } From 1855d54019a3542938242cfbf772e9536de767b2 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 6 Jul 2020 04:31:32 +0200 Subject: [PATCH 016/317] Fix data insertion --- .../mysql/data/llx_c_transport_mode.sql | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/htdocs/install/mysql/data/llx_c_transport_mode.sql b/htdocs/install/mysql/data/llx_c_transport_mode.sql index 98be83ee6ce..69f6ac7f6b8 100644 --- a/htdocs/install/mysql/data/llx_c_transport_mode.sql +++ b/htdocs/install/mysql/data/llx_c_transport_mode.sql @@ -1,4 +1,4 @@ --- Copyright (C) 2019 Open-DSI +-- Copyright (C) 2019-2020 Open-DSI -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by @@ -21,11 +21,11 @@ -- -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('ROU', 'Transport par route', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('AIR', 'Transport par air', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('POS', 'Envois postaux', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); -INSERT INTO llx_c_transport_mode (code, libelle, active) VALUES ('PRO', 'Propulsion propre', 1); \ No newline at end of file +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('MAR', 'Transport maritime (y compris camions ou wagons sur bateau)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('TRA', 'Transport par chemin de fer (y compris camions sur wagon)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('ROU', 'Transport par route', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('AIR', 'Transport par air', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('POS', 'Envois postaux', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('OLE', 'Installations de transport fixe (oléoduc)', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('NAV', 'Transport par navigation intérieure', 1); +INSERT INTO llx_c_transport_mode (code, label, active) VALUES ('PRO', 'Propulsion propre', 1); From 82c96a4f83f975c4be692723d4a5aecf6b2c8102 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 6 Jul 2020 04:47:27 +0200 Subject: [PATCH 017/317] Fix SticklerCi --- htdocs/core/class/html.form.class.php | 10 ++-- .../core/modules/modIntracommreport.class.php | 2 +- htdocs/fourn/facture/card.php | 3 +- htdocs/intracommreport/card.php | 12 ++--- .../class/intracommreport.class.php | 47 ++++++++++--------- 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 150713eee70..b1f9675cd4a 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -71,7 +71,7 @@ class Form // Cache arrays public $cache_types_paiements = array(); public $cache_conditions_paiements = array(); - public $cache_transport_mode=array(); + public $cache_transport_mode = array(); public $cache_availability = array(); public $cache_demand_reason = array(); public $cache_types_fees = array(); @@ -3608,8 +3608,7 @@ class Form return $num; } - else - { + else { dol_print_error($this->db); return -1; } @@ -3638,7 +3637,7 @@ class Form print ''; print ''; } - else - { + else { if ($selected) { $this->load_cache_transport_mode(); diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index e142490cbd6..50db0307a40 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -36,7 +36,7 @@ class modIntracommreport extends DolibarrModules * * @param DoliDB $db Database handler */ - function __construct($db) + public function __construct($db) { global $conf, $langs; diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 50ae01a875a..afeeeb3d6c6 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -2661,8 +2661,7 @@ if ($action == 'create') { $form->formTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'transport_mode_id', 1, 1); } - else - { + else { $form->formTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'none'); } print ''; diff --git a/htdocs/intracommreport/card.php b/htdocs/intracommreport/card.php index 79725e81419..af19f5f4224 100644 --- a/htdocs/intracommreport/card.php +++ b/htdocs/intracommreport/card.php @@ -53,14 +53,12 @@ if ($user->rights->intracommreport->delete && $action == 'confirm_delete' && $co header("Location: ".$backtopage); exit; } - else - { + else { header("Location: list.php"); exit; } } - else - { + else { $errmesg=$object->error; } } @@ -100,14 +98,12 @@ if ($action == 'add' && $user->rights->intracommreport->write) { header("Location: ".$_SERVER["PHP_SELF"]); exit; } - else - { + else { setEventMessages($object->error, $object->errors, 'errors'); $action = 'create'; } } - else - { + else { $action = 'create'; } } diff --git a/htdocs/intracommreport/class/intracommreport.class.php b/htdocs/intracommreport/class/intracommreport.class.php index 75c017704c4..f6ccee4f02d 100644 --- a/htdocs/intracommreport/class/intracommreport.class.php +++ b/htdocs/intracommreport/class/intracommreport.class.php @@ -94,8 +94,9 @@ class IntracommReport extends CommonObject * @param int $mode O for create, R for regenerate (Look always 0 ment toujours 0 within the framework of XML exchanges according to documentation) * @param string $type introduction or expedition * @param string $period_reference Period of reference + * @return void */ - function getXML($mode = 'O', $type = 'introduction', $period_reference = '') + public function getXML($mode = 'O', $type = 'introduction', $period_reference = '') { global $db, $conf, $mysoc; @@ -123,7 +124,7 @@ class IntracommReport extends CommonObject $declaration = $enveloppe->addChild('Declaration'); $declaration->addChild('declarationId', $id_declaration); $declaration->addChild('referencePeriod', $period_reference); - if($conf->global->INTRACOMMREPORT_TYPE_ACTEUR === 'PSI') $psiId = $party_id; + if ($conf->global->INTRACOMMREPORT_TYPE_ACTEUR === 'PSI') $psiId = $party_id; else $psiId = 'NA'; $declaration->addChild('PSIId', $psiId); $function = $declaration->addChild('Function'); @@ -139,12 +140,12 @@ class IntracommReport extends CommonObject $this->errors = array_unique($this->errors); - if(!empty($res)) return $e->asXML(); + if (!empty($res)) return $e->asXML(); else return 0; } // $type_declaration tjrs = "expedition" à voir si ça évolue - function getXMLDes($period_year, $period_month, $type_declaration = 'expedition') + public function getXMLDes($period_year, $period_month, $type_declaration = 'expedition') { global $db, $conf, $mysoc; @@ -162,11 +163,11 @@ class IntracommReport extends CommonObject $this->errors = array_unique($this->errors); - if(!empty($res)) return $e->asXML(); + if (!empty($res)) return $e->asXML(); else return 0; } - function addItemsFact(&$declaration, $type, $period_reference, $exporttype = 'deb') + public function addItemsFact(&$declaration, $type, $period_reference, $exporttype = 'deb') { global $db, $conf; @@ -177,15 +178,15 @@ class IntracommReport extends CommonObject $resql = $db->query($sql); - if($resql) { + if ($resql) { $i=1; - if(empty($resql->num_rows)) { + if (empty($resql->num_rows)) { $this->errors[] = 'Aucune donnée pour cette période'; return 0; } - if($exporttype == 'deb' && $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0) { + if ($exporttype == 'deb' && $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0) { $categ_fraisdeport = new Categorie($db); $categ_fraisdeport->fetch($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT); $TLinesFraisDePort = array(); @@ -198,11 +199,11 @@ class IntracommReport extends CommonObject } else { - if(empty($res->fk_pays)) { + if (empty($res->fk_pays)) { // On n'arrête pas la boucle car on veut savoir quels sont tous les tiers qui n'ont pas de pays renseigné $this->errors[] = 'Pays non renseigné pour le tiers '.$res->nom.''; } else { - if($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) { + if ($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) { $TLinesFraisDePort[] = $res; } else $this->addItemXMl($declaration, $res, '', $i); } @@ -211,20 +212,20 @@ class IntracommReport extends CommonObject $i++; } - if(!empty($TLinesFraisDePort)) $this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i); + if (!empty($TLinesFraisDePort)) $this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i); - if(count($this->errors) > 0) return 0; + if (count($this->errors) > 0) return 0; } return 1; } - function getSQLFactLines($type, $period_reference, $exporttype = 'deb') + public function getSQLFactLines($type, $period_reference, $exporttype = 'deb') { global $mysoc, $conf; - if($type=='expedition' || $exporttype=='des') { + if ($type=='expedition' || $exporttype=='des') { $sql = 'SELECT f.facnumber, f.total as total_ht'; $table = 'facture'; $table_extraf = 'facture_extrafields'; @@ -258,16 +259,16 @@ class IntracommReport extends CommonObject return $sql; } - function addItemXMl(&$declaration, &$res, $code_douane_spe = '', $i) + public function addItemXMl(&$declaration, &$res, $code_douane_spe = '', $i) { $item = $declaration->addChild('Item'); $item->addChild('ItemNumber', $i); $cn8 = $item->addChild('CN8'); - if(empty($code_douane_spe)) $code_douane = $res->customcode; + if (empty($code_douane_spe)) $code_douane = $res->customcode; else $code_douane = $code_douane_spe; $cn8->addChild('CN8Code', $code_douane); - if(!empty($res->tva_intra)) $item->addChild('partnerId', $res->tva_intra); + if (!empty($res->tva_intra)) $item->addChild('partnerId', $res->tva_intra); $item->addChild('MSConsDestCode', $res->code); // code iso pays client $item->addChild('netMass', $res->weight * $res->qty); // Poids du produit $item->addChild('quantityInSU', $res->qty); // Quantité de produit dans la ligne @@ -281,7 +282,7 @@ class IntracommReport extends CommonObject $item->addChild('regionCode', substr($res->zip, 0, 2)); } - function addItemXMlDes($declaration, &$res, $code_douane_spe = '', $i) + public function addItemXMlDes($declaration, &$res, $code_douane_spe = '', $i) { $item = $declaration->addChild('ligne_des'); $item->addChild('numlin_des', $i); @@ -292,12 +293,12 @@ class IntracommReport extends CommonObject /** * Cette fonction ajoute un item en récupérant le code douane du produit ayant le plus haut montant dans la facture */ - function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i) + public function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i) { global $db, $conf; - if($type=='expedition') { + if ($type=='expedition') { $table = 'facture'; $tabledet = 'facturedet'; $field_link = 'fk_facture'; @@ -310,7 +311,7 @@ class IntracommReport extends CommonObject $more_sql = 'f.ref_supplier'; } - foreach($TLinesFraisDePort as $res) { + foreach ($TLinesFraisDePort as $res) { $sql = 'SELECT p.customcode FROM '.MAIN_DB_PREFIX.$tabledet.' d INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = d.'.$field_link.') @@ -352,7 +353,7 @@ class IntracommReport extends CommonObject global $db; $resql = $db->query('SELECT MAX(numero_declaration) as max_numero_declaration FROM '.$this->get_table().' WHERE exporttype="'.$this->exporttype.'"'); - if($resql) $res = $db->fetch_object($resql); + if ($resql) $res = $db->fetch_object($resql); return ($res->max_numero_declaration + 1); } From dc40ddb370c127584471a691a8644049bd88a547 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 6 Jul 2020 09:56:28 +0200 Subject: [PATCH 018/317] Some correction --- .../core/modules/modIntracommreport.class.php | 6 +- htdocs/intracommreport/list.php | 124 +++--------------- htdocs/langs/en_US/intracommreport.lang | 3 +- 3 files changed, 20 insertions(+), 113 deletions(-) diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index 50db0307a40..1ab8b11173d 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -94,8 +94,8 @@ class modIntracommreport extends DolibarrModules $this->dictionaries=array(); // Permissions - $this->rights_class = 'intracommreport'; - $this->rights = array(); // Permission array used by this module + $this->rights = array(); + $this->rights_class = 'intracommreport'; $r = 0; $r++; @@ -112,12 +112,12 @@ class modIntracommreport extends DolibarrModules $this->rights[$r][3] = 0; $this->rights[$r][4] = 'write'; + $r++; $this->rights[$r][0] = 68004; $this->rights[$r][1] = 'Delete intracomm report'; $this->rights[$r][2] = 'd'; $this->rights[$r][3] = 0; $this->rights[$r][4] = 'delete'; - $r++; // Main menu entries $this->menu = array(); // List of menus to add diff --git a/htdocs/intracommreport/list.php b/htdocs/intracommreport/list.php index 8145948cc0d..6c128e0c644 100644 --- a/htdocs/intracommreport/list.php +++ b/htdocs/intracommreport/list.php @@ -107,12 +107,8 @@ $isInEEC=isInEEC($mysoc); // Definition of fields for lists $arrayfields=array( 'i.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1), - //'pfi.ref_fourn'=>array('label'=>$langs->trans("RefSupplier"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))), 'i.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1), 'i.fk_product_type'=>array('label'=>$langs->trans("Type"), 'checked'=>0, 'enabled'=>(! empty($conf->produit->enabled) && ! empty($conf->service->enabled))), - 'i.barcode'=>array('label'=>$langs->trans("Gencod"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))), - 'i.duration'=>array('label'=>$langs->trans("Duration"), 'checked'=>($contextpage != 'productlist'), 'enabled'=>(! empty($conf->service->enabled))), - 'i.weight'=>array('label'=>$langs->trans("Weight"), 'checked'=>0, 'enabled'=>(! empty($conf->produit->enabled))), ); /* // Extra fields @@ -152,11 +148,6 @@ if (empty($reshook)) $sall=""; $search_ref=""; $search_label=""; - $search_barcode=""; - $search_categ=0; - $search_tosell=""; - $search_tobuy=""; - $search_tobatch=''; //$search_type=''; // There is 2 types of list: a list of product and a list of services. No list with both. So when we clear search criteria, we must keep the filter on type. $show_childproducts = ''; @@ -268,18 +259,15 @@ if ($resql) llxHeader('', $title, $helpurl, ''); // Displays product removal confirmation - if (GETPOST('delprod')) { - setEventMessages($langs->trans("ProductDeleted", GETPOST('delprod')), null, 'mesgs'); + if (GETPOST('delreport')) { + setEventMessages($langs->trans("IntracommReportDeleted", GETPOST('delreport')), null, 'mesgs'); } $param=''; if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); if ($sall) $param.="&sall=".urlencode($sall); - if ($search_categ > 0) $param.="&search_categ=".urlencode($search_categ); if ($search_ref) $param="&search_ref=".urlencode($search_ref); - if ($search_ref_supplier) $param="&search_ref_supplier=".urlencode($search_ref_supplier); - if ($search_barcode) $param.=($search_barcode?"&search_barcode=".urlencode($search_barcode):""); if ($search_label) $param.="&search_label=".urlencode($search_label); // Add $param from extra fields @@ -296,13 +284,9 @@ if ($resql) $massactionbutton=$form->selectMassAction('', $arrayofmassactions); $newcardbutton=''; - $rightskey='DEB'; - if ($type == IntracommReport::TYPE_DES) $rightskey='DES'; - if ($user->rights->{$rightskey}->creer) + if ($user->rights->intracommreport->write) { - $label='NewDEB'; - if ($type == IntracommReport::TYPE_DES) $label = 'NewDES'; - $newcardbutton.= dolGetButtonTitle($langs->trans($label), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/intracommreport/card.php?action=create&type='.$type); + $newcardbutton.= dolGetButtonTitle($langs->trans("NewDeclaration"), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/intracommreport/card.php?action=create&type='.$type); } print '
'; @@ -357,12 +341,6 @@ if ($resql) print ''; print ''; } - if (! empty($arrayfields['pfi.ref_fourn']['checked'])) - { - print ''; - print ''; - print ''; - } if (! empty($arrayfields['i.label']['checked'])) { print ''; @@ -370,33 +348,23 @@ if ($resql) print ''; } // Type - if (! empty($arrayfields['i.fk_product_type']['checked'])) + // Type (customer/prospect/supplier) + if (!empty($arrayfields['customerorsupplier']['checked'])) + { + print ''; + if ($type != '') print ''; + print $formcompany->selectProspectCustomerType($search_type, 'search_type', 'search_type', 'list'); + print ''; + } + + if (! empty($arrayfields['i.fk_product_type']['checked'])) { print ''; $array=array('-1'=>' ', '0'=>$langs->trans('Product'), '1'=>$langs->trans('Service')); print $form->selectarray('search_type', $array, $search_type); print ''; } - // Barcode - if (! empty($arrayfields['i.barcode']['checked'])) - { - print ''; - print ''; - print ''; - } - // Duration - if ((string) $type == '1' && ! empty($arrayfields['i.duration']['checked'])) - { - print ''; - print ''; - } - // Weight - if (! empty($arrayfields['i.weight']['checked'])) - { - print ''; - print ''; - } /* // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; @@ -434,15 +402,8 @@ if ($resql) if (! empty($arrayfields['i.fk_product_type']['checked'])) { print_liste_field_titre($arrayfields['i.fk_product_type']['label'], $_SERVER["PHP_SELF"], "i.fk_product_type", "", $param, "", $sortfield, $sortorder); } - if (! empty($arrayfields['i.barcode']['checked'])) { - print_liste_field_titre($arrayfields['i.barcode']['label'], $_SERVER["PHP_SELF"], "i.barcode", "", $param, "", $sortfield, $sortorder); - } - if ((string) $type == '1' && ! empty($arrayfields['i.duration']['checked'])) { - print_liste_field_titre($arrayfields['i.duration']['label'], $_SERVER["PHP_SELF"], "i.duration", "", $param, '', $sortfield, $sortorder, 'center '); - } - if (! empty($arrayfields['i.weight']['checked'])) print_liste_field_titre($arrayfields['i.weight']['label'], $_SERVER["PHP_SELF"], "i.weight", "", $param, '', $sortfield, $sortorder, 'center '); - /* + /* // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; */ @@ -489,73 +450,18 @@ if ($resql) print "\n"; if (! $i) $totalarray['nbfield']++; } - // Ref supplier - if (! empty($arrayfields['pfi.ref_fourn']['checked'])) - { - print ''; - print $intracommreport_static->getNomUrl(1); - print "\n"; - if (! $i) $totalarray['nbfield']++; - } // Label if (! empty($arrayfields['i.label']['checked'])) { print ''.dol_trunc($obj->label, 80).''; if (! $i) $totalarray['nbfield']++; } - // Type if (! empty($arrayfields['i.fk_product_type']['checked'])) { print ''.$obj->fk_product_type.''; if (! $i) $totalarray['nbfield']++; } - - // Barcode - if (! empty($arrayfields['i.barcode']['checked'])) - { - print ''.$obj->barcode.''; - if (! $i) $totalarray['nbfield']++; - } - - // Duration - if ((string) $type == '1' && ! empty($arrayfields['i.duration']['checked'])) - { - print ''; - - if (preg_match('/([^a-z]+)[a-z]$/i', $obj->duration)) - { - $duration_value = substr($obj->duration, 0, dol_strlen($obj->duration)-1); - $duration_unit = substr($obj->duration, -1); - - if ((float) $duration_value > 1) - { - $dur=array("i"=>$langs->trans("Minutes"),"h"=>$langs->trans("Hours"),"d"=>$langs->trans("Days"),"w"=>$langs->trans("Weeks"),"m"=>$langs->trans("Months"),"y"=>$langs->trans("Years")); - } - elseif ((float) $duration_value > 0) - { - $dur=array("i"=>$langs->trans("Minute"),"h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year")); - } - print $duration_value; - print (! empty($duration_unit) && isset($dur[$duration_unit]) ? ' '.$langs->trans($dur[$duration_unit]) : ''); - } - else { - print $obj->duration; - } - - print ''; - if (! $i) $totalarray['nbfield']++; - } - - // Weight - if (! empty($arrayfields['i.weight']['checked'])) - { - print ''; - print $obj->weight; - print ''; - if (! $i) $totalarray['nbfield']++; - } - // Action print ''; if ($massactionbutton || $massaction) // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined diff --git a/htdocs/langs/en_US/intracommreport.lang b/htdocs/langs/en_US/intracommreport.lang index 49752441752..73a2a22709d 100644 --- a/htdocs/langs/en_US/intracommreport.lang +++ b/htdocs/langs/en_US/intracommreport.lang @@ -19,6 +19,7 @@ MenuIntracommReportNew=New declaration MenuIntracommReportList=List # View +NewDeclaration=New declaration Declaration=Declaration AnalysisPeriod=Analysis period TypeOfDeclaration=Type of declaration @@ -36,4 +37,4 @@ IntracommReportTypeDeclaration=Type de déclaration IntracommReportDownload=Télécharger fichier XML # Invoice -IntracommReportTransportMode=Transport mode \ No newline at end of file +IntracommReportTransportMode=Transport mode From 3c35b20b544f70b8ca7b84b00d8ff059f5ffe5ef Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 16 Aug 2020 22:17:28 +0200 Subject: [PATCH 019/317] Dict - Insert number 41 --- htdocs/admin/dict.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index bb1a86b03af..23a781d8f31 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -92,9 +92,9 @@ $hookmanager->initHooks(array('admin')); // Sort order to show dictionary (0 is space). All other dictionaries (added by modules) will be at end of this. if (! empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES)) { - $taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 0, 15, 30, 0, 37, 0, 25, 0); + $taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 41, 0, 15, 30, 0, 37, 0, 25, 0); } else { - $taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 27, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 0, 15, 30, 0, 37, 0, 25, 0); + $taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 27, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 41, 0, 15, 30, 0, 37, 0, 25, 0); } // Name of SQL tables of dictionaries From 6374a2b8cc3b9897e8231c40bcb35eea2cab470e Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 16 Aug 2020 22:31:21 +0200 Subject: [PATCH 020/317] Some fix --- .../intracommreport/class/intracommreport.class.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/htdocs/intracommreport/class/intracommreport.class.php b/htdocs/intracommreport/class/intracommreport.class.php index f6ccee4f02d..f86f3b36caf 100644 --- a/htdocs/intracommreport/class/intracommreport.class.php +++ b/htdocs/intracommreport/class/intracommreport.class.php @@ -192,13 +192,11 @@ class IntracommReport extends CommonObject $TLinesFraisDePort = array(); } - while($res = $db->fetch_object($resql)) { + while ($res = $db->fetch_object($resql)) { if ($exporttype == 'des') { $this->addItemXMlDes($declaration, $res, '', $i); - } - else - { + } else { if (empty($res->fk_pays)) { // On n'arrête pas la boucle car on veut savoir quels sont tous les tiers qui n'ont pas de pays renseigné $this->errors[] = 'Pays non renseigné pour le tiers '.$res->nom.''; @@ -364,8 +362,7 @@ class IntracommReport extends CommonObject * @param int $number Number to verify / convert * @return int Number */ - // La doc impose que le numéro soit un entier positif d'un maximum de 6 caractères - static function getDeclarationNumber($number) + public static function getDeclarationNumber($number) { return str_pad($number, 6, 0, STR_PAD_LEFT); } @@ -375,7 +372,7 @@ class IntracommReport extends CommonObject * * @return void */ - function generateXMLFile() + public function generateXMLFile() { $name = $this->periode.'.xml'; From 2fbb6b112513078edf4b7620f34770e9c2f9c207 Mon Sep 17 00:00:00 2001 From: x Date: Mon, 21 Sep 2020 09:29:52 +0200 Subject: [PATCH 021/317] new handle trigger method --- ...ace_99_modMyModule_MyModuleTriggers.class.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php index 4c5951dad70..28adb0a78f7 100644 --- a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php +++ b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php @@ -102,6 +102,22 @@ class InterfaceMyModuleTriggers extends DolibarrTriggers // Put here code you want to execute when a Dolibarr business events occurs. // Data and type of action are stored into $object and $action + /** + * new method to handle triggers + * you can now create a method for the interface + * this method should be named like the trigger in camelCase + * for example : COMPANY_CREATE => public function companyCreate($action, $object, User $user, Translate $langs, Conf $conf) + */ + $methodName = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($action))))); + $callback = array($this, $methodName); + if(is_callable($callback)){ + dol_syslog( + "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id + ); + + return call_user_func($callback, $action, $object, $user, $langs, $conf); + }; + switch ($action) { // Users //case 'USER_CREATE': From 4cbe8d8623176f056907c6fbcc40b3b3f9ca036e Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 21 Sep 2020 07:34:00 +0000 Subject: [PATCH 022/317] Fixing style errors. --- .../interface_99_modMyModule_MyModuleTriggers.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php index 28adb0a78f7..add80d58af3 100644 --- a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php +++ b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php @@ -110,7 +110,7 @@ class InterfaceMyModuleTriggers extends DolibarrTriggers */ $methodName = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($action))))); $callback = array($this, $methodName); - if(is_callable($callback)){ + if (is_callable($callback)){ dol_syslog( "Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id ); From 2bf15b3a929370d87974692282576925c6afbc55 Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Mon, 28 Sep 2020 10:42:49 +0200 Subject: [PATCH 023/317] Show category filter only on rights to read it --- htdocs/adherents/list.php | 2 +- htdocs/comm/propal/list.php | 4 ++-- htdocs/commande/list.php | 4 ++-- htdocs/compta/bank/list.php | 2 +- htdocs/compta/facture/list.php | 4 ++-- htdocs/contact/list.php | 27 +++++++++++++-------------- htdocs/contrat/list.php | 2 +- htdocs/expedition/list.php | 4 ++-- htdocs/fourn/commande/list.php | 2 +- htdocs/fourn/facture/list.php | 2 +- htdocs/product/list.php | 2 +- htdocs/product/stock/list.php | 2 +- htdocs/projet/list.php | 2 +- htdocs/projet/tasks/list.php | 2 +- htdocs/societe/list.php | 4 ++-- htdocs/supplier_proposal/list.php | 2 +- htdocs/user/list.php | 2 +- 17 files changed, 34 insertions(+), 35 deletions(-) diff --git a/htdocs/adherents/list.php b/htdocs/adherents/list.php index 75c9c731810..c6477f01eb1 100644 --- a/htdocs/adherents/list.php +++ b/htdocs/adherents/list.php @@ -425,7 +425,7 @@ if ($sall) { // Filter on categories $moreforfilter = ''; -if (!empty($conf->categorie->enabled)) { +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; $moreforfilter .= $langs->trans('Categories').': '; diff --git a/htdocs/comm/propal/list.php b/htdocs/comm/propal/list.php index 3396cd6270b..1adb7691f6e 100644 --- a/htdocs/comm/propal/list.php +++ b/htdocs/comm/propal/list.php @@ -542,7 +542,7 @@ if ($resql) $moreforfilter .= '
'; } // If the user can view products - if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; @@ -551,7 +551,7 @@ if ($resql) $moreforfilter .= $form->selectarray('search_product_category', $cate_arbo, $search_product_category, 1, 0, 0, '', 0, 0, 0, 0, 'maxwidth300', 1); $moreforfilter .= '
'; } - if (!empty($conf->categorie->enabled)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index 875b72a8dd2..01052c00834 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -583,7 +583,7 @@ if ($resql) $moreforfilter .= '
'; } // If the user can view prospects other than his' - if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; @@ -592,7 +592,7 @@ if ($resql) $moreforfilter .= $form->selectarray('search_product_category', $cate_arbo, $search_product_category, 1, 0, 0, '', 0, 0, 0, 0, 'maxwidth300', 1); $moreforfilter .= '
'; } - if (!empty($conf->categorie->enabled)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/compta/bank/list.php b/htdocs/compta/bank/list.php index ace8a327768..be764248b1f 100644 --- a/htdocs/compta/bank/list.php +++ b/htdocs/compta/bank/list.php @@ -281,7 +281,7 @@ if ($sall) $moreforfilter = ''; -if (!empty($conf->categorie->enabled)) +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { $moreforfilter .= $form->getFilterBox(Categorie::TYPE_ACCOUNT, $search_category_list); } diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index b4bfa70a287..549e680193f 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -725,7 +725,7 @@ if ($resql) $moreforfilter .= '
'; } // If the user can view prospects other than his' - if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; @@ -734,7 +734,7 @@ if ($resql) $moreforfilter .= $form->selectarray('search_product_category', $cate_arbo, $search_product_category, 1, 0, 0, '', 0, 0, 0, 0, 'maxwidth300', 1); $moreforfilter .= '
'; } - if (!empty($conf->categorie->enabled)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/contact/list.php b/htdocs/contact/list.php index 1332bc5e100..f8f8f37669d 100644 --- a/htdocs/contact/list.php +++ b/htdocs/contact/list.php @@ -573,7 +573,7 @@ if ($search_firstlast_only) } $moreforfilter = ''; -if (!empty($conf->categorie->enabled)) +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; @@ -596,21 +596,20 @@ if (!empty($conf->categorie->enabled)) $moreforfilter .= $formother->select_categories(Categorie::TYPE_SUPPLIER, $search_categ_supplier, 'search_categ_supplier', 1); $moreforfilter .= '
'; } - $moreforfilter .= '
'; - $moreforfilter .= $langs->trans('Roles').': '; - $moreforfilter .= $formcompany->showRoles("search_roles", $objecttmp, 'edit', $search_roles); - $moreforfilter .= '
'; -} -if ($moreforfilter) -{ - print '
'; - print $moreforfilter; - $parameters = array('type'=>$type); - $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - print '
'; } +$moreforfilter .= '
'; +$moreforfilter .= $langs->trans('Roles').': '; +$moreforfilter .= $formcompany->showRoles("search_roles", $objecttmp, 'edit', $search_roles); +$moreforfilter .= '
'; + +print '
'; +print $moreforfilter; +$parameters = array('type'=>$type); +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +print '
'; + $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields if ($massactionbutton) $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); diff --git a/htdocs/contrat/list.php b/htdocs/contrat/list.php index 531642f81f7..a8781a5aaf3 100644 --- a/htdocs/contrat/list.php +++ b/htdocs/contrat/list.php @@ -418,7 +418,7 @@ if ($user->rights->user->user->lire) $moreforfilter .= '
'; } // If the user can view categories of products -if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/expedition/list.php b/htdocs/expedition/list.php index 77796fc9bc1..ddf71330e77 100644 --- a/htdocs/expedition/list.php +++ b/htdocs/expedition/list.php @@ -408,7 +408,7 @@ if ($resql) $moreforfilter .= '
'; } // If the user can view prospects other than his' - if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; @@ -417,7 +417,7 @@ if ($resql) $moreforfilter .= $form->selectarray('search_product_category', $cate_arbo, $search_product_category, 1, 0, 0, '', 0, 0, 0, 0, 'maxwidth300', 1); $moreforfilter .= '
'; } - if (!empty($conf->categorie->enabled)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index c900431d910..6a655eb220e 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -739,7 +739,7 @@ if ($resql) $moreforfilter .= '
'; } // If the user can view prospects other than his' - if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/fourn/facture/list.php b/htdocs/fourn/facture/list.php index bbc4f45e4b2..c594be95af5 100644 --- a/htdocs/fourn/facture/list.php +++ b/htdocs/fourn/facture/list.php @@ -597,7 +597,7 @@ if ($resql) $moreforfilter .= '
'; } // If the user can view prospects other than his' - if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 18e6e1c3500..227a9508b9c 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -598,7 +598,7 @@ if ($resql) // Filter on categories $moreforfilter = ''; - if (!empty($conf->categorie->enabled)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { $moreforfilter .= '
'; $moreforfilter .= $langs->trans('Categories').': '; diff --git a/htdocs/product/stock/list.php b/htdocs/product/stock/list.php index b0f593f82d9..f717e541229 100644 --- a/htdocs/product/stock/list.php +++ b/htdocs/product/stock/list.php @@ -375,7 +375,7 @@ if ($search_all) $moreforfilter = ''; -if (!empty($conf->categorie->enabled)) +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { $formcategory = new FormCategory($db); $moreforfilter .= $formcategory->getFilterBox(Categorie::TYPE_WAREHOUSE, $search_category_list); diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index 8a7645941d5..8964796dee9 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -489,7 +489,7 @@ if ($search_all) $moreforfilter = ''; // Filter on categories -if (!empty($conf->categorie->enabled)) +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { $formcategory = new FormCategory($db); $moreforfilter .= $formcategory->getFilterBox(Categorie::TYPE_PROJECT, $search_category_array); diff --git a/htdocs/projet/tasks/list.php b/htdocs/projet/tasks/list.php index 20d917b2ae8..d5e1c02ceac 100644 --- a/htdocs/projet/tasks/list.php +++ b/htdocs/projet/tasks/list.php @@ -462,7 +462,7 @@ if ($search_all) $morehtmlfilter = ''; // Filter on categories -if (!empty($conf->categorie->enabled)) +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/societe/list.php b/htdocs/societe/list.php index ad9813c4fec..34e8f7a87ff 100644 --- a/htdocs/societe/list.php +++ b/htdocs/societe/list.php @@ -660,7 +660,7 @@ if ($search_all) $moreforfilter = ''; if (empty($type) || $type == 'c' || $type == 'p') { - if (!empty($conf->categorie->enabled)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; @@ -671,7 +671,7 @@ if (empty($type) || $type == 'c' || $type == 'p') } if (empty($type) || $type == 'f') { - if (!empty($conf->categorie->enabled)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/supplier_proposal/list.php b/htdocs/supplier_proposal/list.php index 1340dce3b3b..df8e85787e6 100644 --- a/htdocs/supplier_proposal/list.php +++ b/htdocs/supplier_proposal/list.php @@ -465,7 +465,7 @@ if ($resql) $moreforfilter .= '
'; } // If the user can view products - if ($conf->categorie->enabled && ($user->rights->produit->lire || $user->rights->service->lire)) + if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) { include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; $moreforfilter .= '
'; diff --git a/htdocs/user/list.php b/htdocs/user/list.php index 92826eac19e..38940c1213d 100644 --- a/htdocs/user/list.php +++ b/htdocs/user/list.php @@ -341,7 +341,7 @@ if ($sall) $moreforfilter = ''; // Filter on categories -if (!empty($conf->categorie->enabled)) +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { $moreforfilter .= '
'; $moreforfilter .= $langs->trans('Categories').': '; From 711339945ce8a43f2f771a24e56e707053d1e8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 2 Oct 2020 21:41:05 +0200 Subject: [PATCH 024/317] use create instead edit on create contract --- htdocs/contrat/card.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 9581d625f80..dbdba874dda 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -9,7 +9,7 @@ * Copyright (C) 2014-2018 Ferran Marcet * Copyright (C) 2014-2016 Marcos García * Copyright (C) 2015 Jean-François Ferry - * Copyright (C) 2018 Frédéric France + * Copyright (C) 2018-2020 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1264,7 +1264,7 @@ if ($action == 'create') // Other attributes if (empty($reshook)) { - print $object->showOptionals($extrafields, 'edit', $parameters); + print $object->showOptionals($extrafields, 'create', $parameters); } print "\n"; From 3840d6c0a7bcea82a540b75cba696342be2c7975 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 3 Oct 2020 13:52:52 +0200 Subject: [PATCH 025/317] Fix entity in ordre box --- htdocs/core/boxes/box_commandes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/boxes/box_commandes.php b/htdocs/core/boxes/box_commandes.php index c48e79bb4bd..372dba8081a 100644 --- a/htdocs/core/boxes/box_commandes.php +++ b/htdocs/core/boxes/box_commandes.php @@ -105,7 +105,7 @@ class box_commandes extends ModeleBoxes $sql.= ", ".MAIN_DB_PREFIX."commande as c"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE c.fk_soc = s.rowid"; - $sql.= " AND c.entity = ".$conf->entity; + $sql.= " AND c.entity IN (".getEntity('commande').")"; if (! empty($conf->global->ORDER_BOX_LAST_ORDERS_VALIDATED_ONLY)) $sql.=" AND c.fk_statut = 1"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($user->societe_id) $sql.= " AND s.rowid = ".$user->societe_id; From e9c101349b6ca215d947ee27e291bf32c522dd3f Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 3 Oct 2020 13:57:37 +0200 Subject: [PATCH 026/317] Fix multicompany in propal box --- htdocs/core/boxes/box_propales.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/boxes/box_propales.php b/htdocs/core/boxes/box_propales.php index 7e73166ed90..12e1166120c 100644 --- a/htdocs/core/boxes/box_propales.php +++ b/htdocs/core/boxes/box_propales.php @@ -91,7 +91,7 @@ class box_propales extends ModeleBoxes $sql.= ", ".MAIN_DB_PREFIX."propal as p"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE p.fk_soc = s.rowid"; - $sql.= " AND p.entity = ".$conf->entity; + $sql .= " AND p.entity IN (".getEntity('propal').")"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if($user->societe_id) $sql.= " AND s.rowid = ".$user->societe_id; if ($conf->global->MAIN_LASTBOX_ON_OBJECT_DATE) $sql.= " ORDER BY p.datep DESC, p.ref DESC "; From 26a2fea8c70f9ff9d6dce01641c6819a343fcab9 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 3 Oct 2020 14:00:23 +0200 Subject: [PATCH 027/317] Fix multicompany in supplier order box --- htdocs/core/boxes/box_supplier_orders.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/boxes/box_supplier_orders.php b/htdocs/core/boxes/box_supplier_orders.php index 85ee2e6f71c..f69f6e10099 100644 --- a/htdocs/core/boxes/box_supplier_orders.php +++ b/htdocs/core/boxes/box_supplier_orders.php @@ -95,7 +95,7 @@ class box_supplier_orders extends ModeleBoxes $sql.= ", ".MAIN_DB_PREFIX."commande_fournisseur as c"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE c.fk_soc = s.rowid"; - $sql.= " AND c.entity = ".$conf->entity; + $sql .= " AND c.entity IN (".getEntity('supplier_order').")"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($user->societe_id) $sql.= " AND s.rowid = ".$user->societe_id; if ($conf->global->MAIN_LASTBOX_ON_OBJECT_DATE) $sql.= " ORDER BY c.date_commande DESC, c.ref DESC "; From 331db5e367a1faa82ea9eb735b375d09711ecead Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 3 Oct 2020 14:01:46 +0200 Subject: [PATCH 028/317] Fix multicompany in supplier order awaiting box --- htdocs/core/boxes/box_supplier_orders_awaiting_reception.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php b/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php index 416dc7f2f2a..b1f53d2de20 100644 --- a/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php +++ b/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php @@ -95,7 +95,7 @@ class box_supplier_orders_awaiting_reception extends ModeleBoxes $sql.= ", ".MAIN_DB_PREFIX."commande_fournisseur as c"; if (!$user->rights->societe->client->voir && !$user->socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE c.fk_soc = s.rowid"; - $sql.= " AND c.entity = ".$conf->entity; + $sql .= " AND c.entity IN (".getEntity('supplier_order').")"; $sql.= " AND c.fk_statut = ".CommandeFournisseur::STATUS_ORDERSENT; if (!$user->rights->societe->client->voir && !$user->socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; From 69660d1a9d407b94d54c9ef70507ba94a5c2c9d4 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 3 Oct 2020 14:02:59 +0200 Subject: [PATCH 029/317] Update box_supplier_orders.php --- htdocs/core/boxes/box_supplier_orders.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/boxes/box_supplier_orders.php b/htdocs/core/boxes/box_supplier_orders.php index f69f6e10099..b71b5b660b5 100644 --- a/htdocs/core/boxes/box_supplier_orders.php +++ b/htdocs/core/boxes/box_supplier_orders.php @@ -95,7 +95,7 @@ class box_supplier_orders extends ModeleBoxes $sql.= ", ".MAIN_DB_PREFIX."commande_fournisseur as c"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE c.fk_soc = s.rowid"; - $sql .= " AND c.entity IN (".getEntity('supplier_order').")"; + $sql.= " AND c.entity IN (".getEntity('supplier_order').")"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($user->societe_id) $sql.= " AND s.rowid = ".$user->societe_id; if ($conf->global->MAIN_LASTBOX_ON_OBJECT_DATE) $sql.= " ORDER BY c.date_commande DESC, c.ref DESC "; From af2bd76500bf83d2e5a22a03ac817aca86fc46ff Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 3 Oct 2020 14:06:33 +0200 Subject: [PATCH 030/317] Fix multicompany in shipment box --- htdocs/core/boxes/box_shipments.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/boxes/box_shipments.php b/htdocs/core/boxes/box_shipments.php index 26f45bc08db..4603450b482 100644 --- a/htdocs/core/boxes/box_shipments.php +++ b/htdocs/core/boxes/box_shipments.php @@ -104,7 +104,7 @@ class box_shipments extends ModeleBoxes $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande as c ON el.fk_source = c.rowid AND el.sourcetype IN ('commande') AND el.targettype = 'shipping'"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON e.fk_soc = sc.fk_soc"; - $sql .= " WHERE e.entity = ".$conf->entity; + $sql .= " WHERE e.entity IN (".getEntity('expedition').")"; if (!empty($conf->global->ORDER_BOX_LAST_SHIPMENTS_VALIDATED_ONLY)) $sql .= " AND e.fk_statut = 1"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql .= " AND sc.fk_user = ".$user->id; else $sql .= " ORDER BY e.date_delivery, e.ref DESC "; From dd1904c521d5e6bfe058801a355934bf9d43b91e Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sun, 4 Oct 2020 13:58:46 +0200 Subject: [PATCH 031/317] Fix multicompany in last action box --- htdocs/core/lib/agenda.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/agenda.lib.php b/htdocs/core/lib/agenda.lib.php index c6bc31956d6..2892469d61c 100644 --- a/htdocs/core/lib/agenda.lib.php +++ b/htdocs/core/lib/agenda.lib.php @@ -225,7 +225,7 @@ function show_array_actions_to_do($max = 5) $sql.= " ".MAIN_DB_PREFIX."c_actioncomm as c ON c.id = a.fk_action"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON a.fk_soc = s.rowid"; if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql.= " WHERE a.entity = ".$conf->entity; + $sql .= " WHERE a.entity IN (".getEntity('agenda').")"; $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep2 > '".$db->idate($now)."'))"; if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND s.rowid = ".$socid; @@ -322,7 +322,7 @@ function show_array_last_actions_done($max = 5) $sql.= " ".MAIN_DB_PREFIX."c_actioncomm as c ON c.id = a.fk_action "; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON a.fk_soc = s.rowid"; if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql.= " WHERE a.entity = ".$conf->entity; + $sql .= " WHERE a.entity IN (".getEntity('agenda').")"; $sql.= " AND (a.percent >= 100 OR (a.percent = -1 AND a.datep2 <= '".$db->idate($now)."'))"; if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND s.rowid = ".$socid; From 1a407e4c229e7e26e4e46667d6362027e1651fa9 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sun, 4 Oct 2020 22:09:40 +0200 Subject: [PATCH 032/317] NEW set entity when creating invoice on takepos usefull for marketplace, coworking, multibranding shop --- htdocs/takepos/invoice.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index d3ec86a7268..3b8cf455e5c 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -284,6 +284,7 @@ if (($action == "addline" || $action == "freezone") && $placeid == 0) $invoice->date = dol_now(); $invoice->module_source = 'takepos'; $invoice->pos_source = $_SESSION["takeposterminal"]; + $invoice->entity = !empty($_SESSION["takeposinvoiceentity"])?$_SESSION["takeposinvoiceentity"]:$conf->entity; if ($invoice->socid <= 0) { From ca16606b4fb54d3d993768cd44e51c776a0b0c08 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 4 Oct 2020 23:21:24 +0200 Subject: [PATCH 033/317] Fix phpcs --- htdocs/core/tpl/objectline_edit.tpl.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index b75284938ef..6bffd5f7bb1 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -305,23 +305,25 @@ if (!empty($extrafields)) rights->margins->creer) { -?> + ?> /* Some js test when we click on button "Add" */ jQuery(document).ready(function() { - global->DISPLAY_MARGIN_RATES)) { ?> + global->DISPLAY_MARGIN_RATES)) { + ?> $("input[name='np_marginRate']:first").blur(function(e) { return checkFreeLine(e, "np_marginRate"); }); global->DISPLAY_MARK_RATES)) { ?> + } + if (! empty($conf->global->DISPLAY_MARK_RATES)) { + ?> $("input[name='np_markRate']:first").blur(function(e) { return checkFreeLine(e, "np_markRate"); }); + } + ?> }); /* TODO This does not work for number with thousand separator that is , */ @@ -369,7 +371,7 @@ if (! empty($usemargins) && $user->rights->margins->creer) return true; } - From a68ba1704bd393c918ce41ecd704602018003dd4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 5 Oct 2020 02:25:57 +0200 Subject: [PATCH 034/317] Fix phpcs --- htdocs/core/tpl/objectline_edit.tpl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index 068b381f1f7..fb9e8bbd208 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -322,7 +322,7 @@ if (! empty($usemargins) && $user->rights->margins->creer) return checkFreeLine(e, "np_markRate"); }); }); From 3984d8c2b8de3c72a277651c5603264c5f5e040b Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Mon, 5 Oct 2020 11:27:44 +0200 Subject: [PATCH 035/317] Add selectable columns on cust. invoice pay. list --- htdocs/compta/paiement/list.php | 564 ++++++++++++++++++-------------- 1 file changed, 322 insertions(+), 242 deletions(-) diff --git a/htdocs/compta/paiement/list.php b/htdocs/compta/paiement/list.php index eb2523960f3..74c198b96c2 100644 --- a/htdocs/compta/paiement/list.php +++ b/htdocs/compta/paiement/list.php @@ -1,13 +1,14 @@ - * Copyright (C) 2004-2011 Laurent Destailleur - * Copyright (C) 2005-2009 Regis Houssin - * Copyright (C) 2013 Cédric Salvador - * Copyright (C) 2015 Jean-François Ferry - * Copyright (C) 2015 Juanjo Menent - * Copyright (C) 2017 Alexandre Spangaro - * Copyright (C) 2018 Ferran Marcet - * Copyright (C) 2018 Charlene Benke +/* Copyright (C) 2001-2006 Rodolphe Quiedeville + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2013 Cédric Salvador + * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2015 Juanjo Menent + * Copyright (C) 2017 Alexandre Spangaro + * Copyright (C) 2018 Ferran Marcet + * Copyright (C) 2018 Charlene Benke + * Copyright (C) 2020 Tobias Sekan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +31,11 @@ */ require '../../main.inc.php'; + +// Security check +if ($user->socid) $socid = $user->socid; +$result = restrictedArea($user, 'facture', $facid, ''); + require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; @@ -39,36 +45,30 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php'; // Load translation files required by the page $langs->loadLangs(array('bills', 'banks', 'compta', 'companies')); -$action = GETPOST('action', 'alpha'); -$confirm = GETPOST('confirm', 'alpha'); -$optioncss = GETPOST('optioncss', 'alpha'); +$action = GETPOST('action', 'alpha'); +$massaction = GETPOST('massaction', 'alpha'); +$confirm = GETPOST('confirm', 'alpha'); +$optioncss = GETPOST('optioncss', 'alpha'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'paymentlist'; -$facid = GETPOST('facid', 'int'); -$socid = GETPOST('socid', 'int'); -$userid = GETPOST('userid', 'int'); -$day = GETPOST('day', 'int'); -$month = GETPOST('month', 'int'); -$year = GETPOST('year', 'int'); +$facid = GETPOST('facid', 'int'); +$socid = GETPOST('socid', 'int'); +$userid = GETPOST('userid', 'int'); +$day = GETPOST('day', 'int'); +$month = GETPOST('month', 'int'); +$year = GETPOST('year', 'int'); -// Security check -if ($user->socid) $socid = $user->socid; -$result = restrictedArea($user, 'facture', $facid, ''); +$search_ref = GETPOST("search_ref", "alpha"); +$search_account = GETPOST("search_account", "int"); +$search_paymenttype = GETPOST("search_paymenttype"); +$search_amount = GETPOST("search_amount", 'alpha'); // alpha because we must be able to search on "< x" +$search_company = GETPOST("search_company", 'alpha'); -$paymentstatic = new Paiement($db); -$accountstatic = new Account($db); -$companystatic = new Societe($db); +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); -$search_ref = GETPOST("search_ref", "alpha"); -$search_account = GETPOST("search_account", "int"); -$search_paymenttype = GETPOST("search_paymenttype"); -$search_amount = GETPOST("search_amount", 'alpha'); // alpha because we must be able to search on "< x" -$search_company = GETPOST("search_company", 'alpha'); -$search_payment_num = GETPOST('search_payment_num', 'alpha'); - -$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; -$sortfield = GETPOST("sortfield", 'alpha'); -$sortorder = GETPOST("sortorder", 'alpha'); -$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 $offset = $limit * $page; $pageprev = $page - 1; @@ -77,98 +77,120 @@ if (!$sortorder) $sortorder = "DESC"; if (!$sortfield) $sortfield = "p.rowid"; // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$object = new Paiement($db); $hookmanager->initHooks(array('paymentlist')); $extrafields = new ExtraFields($db); -$arrayfields = array(); +$arrayfields = array( + 'p.rowid' => array('label'=>"RefPayment", 'checked'=>1, 'position'=>10), + 'p.datep' => array('label'=>"Date", 'checked'=>1, 'position'=>20), + 's.nom' => array('label'=>"ThirdParty", 'checked'=>1, 'position'=>30), + 'c.libelle' => array('label'=>"Type", 'checked'=>1, 'position'=>40), + 'transaction' => array('label'=>"BankTransactionLine", 'checked'=>1, 'enabled'=>(!empty($conf->banque->enabled)), 'position'=>50), + 'ba.label' => array('label'=>"Account", 'checked'=>1, 'enabled'=>(!empty($conf->banque->enabled)), 'position'=>60), + 'p.amount' => array('label'=>"Amount", 'checked'=>1, 'position'=>70), + 'p.statut' => array('label'=>"Status", 'enabled'=>1, 'checked'=>(!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION)), 'position'=>80), +); +$arrayfields = dol_sort_array($arrayfields, 'position'); /* * Actions */ -if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers -{ - $search_ref = ""; - $search_account = ""; - $search_amount = ""; - $search_paymenttype = ""; - $search_payment_num = ""; - $search_company = ""; - $day = ''; - $year = ''; - $month = ''; - $search_array_options = array(); -} +$parameters = array('socid'=>$socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +if(empty($reshook)) +{ + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers + { + $search_ref = ""; + $search_account = ""; + $search_amount = ""; + $search_paymenttype = ""; + $search_company = ""; + $day = ''; + $year = ''; + $month = ''; + $search_array_options = array(); + } +} + /* * View */ $form = new Form($db); $formother = new FormOther($db); +$accountstatic = new Account($db); +$companystatic = new Societe($db); +$bankline = new AccountLine($db); llxHeader('', $langs->trans('ListPayment')); if (GETPOST("orphelins", "alpha")) { - // Payments not linked to an invoice. Should not happend. For debug only. - $sql = "SELECT p.rowid, p.ref, p.datep as dp, p.amount,"; - $sql .= " p.statut, p.num_paiement as num_payment,"; - $sql .= " c.code as paiement_code"; + // Payments not linked to an invoice. Should not happend. For debug only. + $sql = "SELECT p.rowid, p.ref, p.datep, p.fk_bank, p.amount, p.statut"; + $sql .= ", c.code as paiement_code"; // Add fields from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; - $sql .= " FROM ".MAIN_DB_PREFIX."paiement as p LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as c ON p.fk_paiement = c.id"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON p.rowid = pf.fk_paiement"; - $sql .= " WHERE p.entity IN (".getEntity('invoice').")"; - $sql .= " AND pf.fk_facture IS NULL"; + $sql .= " FROM ".MAIN_DB_PREFIX."paiement as p LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as c ON p.fk_paiement = c.id"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON p.rowid = pf.fk_paiement"; + $sql .= " WHERE p.entity IN (".getEntity('invoice').")"; + $sql .= " AND pf.fk_facture IS NULL"; // Add where from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; -} else { - $sql = "SELECT DISTINCT p.rowid, p.ref, p.datep as dp, p.amount,"; // DISTINCT is to avoid duplicate when there is a link to sales representatives - $sql .= " p.statut, p.num_paiement as num_payment,"; - $sql .= " c.code as paiement_code,"; - $sql .= " ba.rowid as bid, ba.ref as bref, ba.label as blabel, ba.number, ba.account_number as account_number, ba.fk_accountancy_journal as accountancy_journal,"; - $sql .= " s.rowid as socid, s.nom as name, s.email"; +} +else +{ + // DISTINCT is to avoid duplicate when there is a link to sales representatives + $sql = "SELECT DISTINCT p.rowid, p.ref, p.datep, p.fk_bank, p.amount, p.statut"; + $sql .= ", c.code as paiement_code"; + $sql .= ", ba.rowid as bid, ba.ref as bref, ba.label as blabel, ba.number, ba.account_number as account_number, ba.fk_accountancy_journal as accountancy_journal"; + $sql .= ", s.rowid as socid, s.nom as name, s.email"; // Add fields from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; - $sql .= " FROM ".MAIN_DB_PREFIX."paiement as p"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as c ON p.fk_paiement = c.id"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank = b.rowid"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON b.fk_account = ba.rowid"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON p.rowid = pf.fk_paiement"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON pf.fk_facture = f.rowid"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid"; - if (!$user->rights->societe->client->voir && !$socid) - { - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc"; - } - $sql .= " WHERE p.entity IN (".getEntity('invoice').")"; - if (!$user->rights->societe->client->voir && !$socid) - { - $sql .= " AND sc.fk_user = ".$user->id; - } - if ($socid > 0) $sql .= " AND f.fk_soc = ".$socid; - if ($userid) - { - if ($userid == -1) $sql .= " AND f.fk_user_author IS NULL"; - else $sql .= " AND f.fk_user_author = ".$userid; - } - // Search criteria - $sql .= dolSqlDateFilter("p.datep", $day, $month, $year); - if ($search_ref) $sql .= natural_search('p.ref', $search_ref); - if ($search_account > 0) $sql .= " AND b.fk_account=".$search_account; - if ($search_paymenttype != "") $sql .= " AND c.code='".$db->escape($search_paymenttype)."'"; - if ($search_payment_num != '') $sql .= natural_search('p.num_paiement', $search_payment_num); - if ($search_amount) $sql .= natural_search('p.amount', $search_amount, 1); - if ($search_company) $sql .= natural_search('s.nom', $search_company); + $sql .= " FROM ".MAIN_DB_PREFIX."paiement as p"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as c ON p.fk_paiement = c.id"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank = b.rowid"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON b.fk_account = ba.rowid"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON p.rowid = pf.fk_paiement"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON pf.fk_facture = f.rowid"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid"; + if (!$user->rights->societe->client->voir && !$socid) + { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc"; + } + $sql .= " WHERE p.entity IN (".getEntity('invoice').")"; + if (!$user->rights->societe->client->voir && !$socid) + { + $sql .= " AND sc.fk_user = ".$user->id; + } + if ($socid > 0) $sql .= " AND f.fk_soc = ".$socid; + if ($userid) + { + if ($userid == -1) $sql .= " AND f.fk_user_author IS NULL"; + else $sql .= " AND f.fk_user_author = ".$userid; + } + // Search criteria + $sql .= dolSqlDateFilter("p.datep", $day, $month, $year); + if ($search_ref) $sql .= natural_search('p.ref', $search_ref); + if ($search_account > 0) $sql .= " AND b.fk_account=".$search_account; + if ($search_paymenttype != "") $sql .= " AND c.code='".$db->escape($search_paymenttype)."'"; + if ($search_amount) $sql .= natural_search('p.amount', $search_amount, 1); + if ($search_company) $sql .= natural_search('s.nom', $search_company); // Add where from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook @@ -189,195 +211,253 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) } $sql .= $db->plimit($limit + 1, $offset); -//print "$sql"; $resql = $db->query($sql); if ($resql) { - $num = $db->num_rows($resql); + $num = $db->num_rows($resql); - $param = ''; - if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); - if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); - $param .= (GETPOST("orphelins") ? "&orphelins=1" : ""); - $param .= ($search_ref ? "&search_ref=".urlencode($search_ref) : ""); - $param .= ($search_company ? "&search_company=".urlencode($search_company) : ""); - $param .= ($search_amount ? "&search_amount=".urlencode($search_amount) : ""); - $param .= ($search_payment_num ? "&search_payment_num=".urlencode($search_payment_num) : ""); - if ($optioncss != '') $param .= '&optioncss='.urlencode($optioncss); + $param = ''; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); + $param .= (GETPOST("orphelins") ? "&orphelins=1" : ""); + $param .= ($search_ref ? "&search_ref=".urlencode($search_ref) : ""); + $param .= ($search_company ? "&search_company=".urlencode($search_company) : ""); + $param .= ($search_amount ? "&search_amount=".urlencode($search_amount) : ""); + if ($optioncss != '') $param .= '&optioncss='.urlencode($optioncss); - print ''; - if ($optioncss != '') print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; + print ''; + if ($optioncss != '') print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; - print_barre_liste($langs->trans("ReceivedCustomersPayments"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'bill', 0, '', '', $limit, 0, 0, 1); + print_barre_liste($langs->trans("ReceivedCustomersPayments"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'bill', 0, '', '', $limit, 0, 0, 1); - print '
'; - print ''."\n"; + $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + if ($massactionbutton) $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); - // Lines for filters fields - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - if (!empty($conf->banque->enabled)) - { - print ''; - } - print '
'; - print ''; - print ''; - if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; - print ''; - $formother->select_year($year ? $year : -1, 'year', 1, 20, 5); - print ''; - print ''; - print ''; - $form->select_types_paiements($search_paymenttype, 'search_paymenttype', '', 2, 1, 1); - print ''; - print ''; - print ''; - $form->select_comptes($search_account, 'search_account', 0, '', 1); - print ''; - print ''; + print '
'; + print ''; + + print ''; + + // Filters: Lines (placeholder) + print ''; + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; + } + + // Filter: Ref + if (!empty($arrayfields['p.rowid']['checked'])) { + print ''; + } + + // Filter: Date + if (!empty($arrayfields['p.datep']['checked'])) { + print ''; + } + + // Filter: Thirdparty + if (!empty($arrayfields['s.nom']['checked'])) { + print ''; + } + + // Filter: Payment type + if (!empty($arrayfields['c.libelle']['checked'])) { + print ''; + } + + // Filter: Bank transaction number + if (!empty($arrayfields['transaction']['checked'])) { + print ''; + } + + // Filter: Bank account + if (!empty($arrayfields['ba.label']['checked'])) { + print ''; + } + + // Filter: Amount + if (!empty($arrayfields['p.amount']['checked'])) { + print ''; + } + + // Filter: Status (only placeholder) + if (!empty($arrayfields['p.statut']['checked'])) { + print ''; + } + + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields); + $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + + print ''; - print ''; - if (!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION)) - { - print ''; - } - print "\n"; - print ''; - print_liste_field_titre("RefPayment", $_SERVER["PHP_SELF"], "p.rowid", "", $param, "", $sortfield, $sortorder); - print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "dp", "", $param, '', $sortfield, $sortorder, 'center '); - print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "s.nom", "", $param, "", $sortfield, $sortorder); - print_liste_field_titre("Type", $_SERVER["PHP_SELF"], "c.libelle", "", $param, "", $sortfield, $sortorder); - print_liste_field_titre("Numero", $_SERVER["PHP_SELF"], "p.num_paiement", "", $param, "", $sortfield, $sortorder); - if (!empty($conf->banque->enabled)) - { - print_liste_field_titre("Account", $_SERVER["PHP_SELF"], "ba.label", "", $param, "", $sortfield, $sortorder); - } - print_liste_field_titre("Amount", $_SERVER["PHP_SELF"], "p.amount", "", $param, 'class="right"', $sortfield, $sortorder); - //print_liste_field_titre("Invoices"),"","","",$param,'class="left"',$sortfield,$sortorder); + print ""; + print ''; + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) print_liste_field_titre('#', $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); + if (!empty($arrayfields['p.rowid']['checked'])) print_liste_field_titre($arrayfields['p.rowid']['label'], $_SERVER["PHP_SELF"], "p.rowid", "", $param, "", $sortfield, $sortorder); + if (!empty($arrayfields['p.datep']['checked'])) print_liste_field_titre($arrayfields['p.datep']['label'], $_SERVER["PHP_SELF"], "p.datep", "", $param, '', $sortfield, $sortorder, 'center '); + if (!empty($arrayfields['s.nom']['checked'])) print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"], "s.nom", "", $param, "", $sortfield, $sortorder); + if (!empty($arrayfields['c.libelle']['checked'])) print_liste_field_titre($arrayfields['c.libelle']['label'], $_SERVER["PHP_SELF"], "c.libelle", "", $param, "", $sortfield, $sortorder); + if (!empty($arrayfields['transaction']['checked'])) print_liste_field_titre($arrayfields['transaction']['label'], $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder); + if (!empty($arrayfields['ba.label']['checked'])) print_liste_field_titre($arrayfields['ba.label']['label'], $_SERVER["PHP_SELF"], "ba.label", "", $param, "", $sortfield, $sortorder); + if (!empty($arrayfields['p.amount']['checked'])) print_liste_field_titre($arrayfields['p.amount']['label'], $_SERVER["PHP_SELF"], "p.amount", "", $param, 'class="right"', $sortfield, $sortorder); + if (!empty($arrayfields['p.statut']['checked'])) print_liste_field_titre($arrayfields['p.statut']['label'], $_SERVER["PHP_SELF"], "p.statut", "", $param, 'class="right"', $sortfield, $sortorder); + + // Hook fields $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); - $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; + $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; - if (!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION)) print_liste_field_titre("Status", $_SERVER["PHP_SELF"], "p.statut", "", $param, 'class="right"', $sortfield, $sortorder); - print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch '); - print "\n"; + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); - $i = 0; - $totalarray = array(); - while ($i < min($num, $limit)) - { - $objp = $db->fetch_object($resql); + print ""; - $paymentstatic->id = $objp->rowid; - $paymentstatic->ref = $objp->ref; + $i = 0; + $totalarray = array(); + while ($i < min($num, $limit)) + { + $objp = $db->fetch_object($resql); - $companystatic->id = $objp->socid; - $companystatic->name = $objp->name; - $companystatic->email = $objp->email; + $object->id = $objp->rowid; + $object->ref = $objp->ref; - print ''; + $companystatic->id = $objp->socid; + $companystatic->name = $objp->name; + $companystatic->email = $objp->email; - print ''; - if (!$i) $totalarray['nbfield']++; + print ''; - // Date - $dateformatforpayment = 'day'; - if (!empty($conf->global->INVOICE_USE_HOURS_FOR_PAYMENT)) $dateformatforpayment = 'dayhour'; - print ''; - if (!$i) $totalarray['nbfield']++; + // No + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; + } - // Thirdparty - print ''; - if (!$i) $totalarray['nbfield']++; + // Ref + if (!empty($arrayfields['p.rowid']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } - // Type - print ''; - if (!$i) $totalarray['nbfield']++; + // Date + if (!empty($arrayfields['p.datep']['checked'])) { + $dateformatforpayment = 'day'; + if (!empty($conf->global->INVOICE_USE_HOURS_FOR_PAYMENT)) $dateformatforpayment = 'dayhour'; + print ''; + if (!$i) $totalarray['nbfield']++; + } - // Payment number - print ''; - if (!$i) $totalarray['nbfield']++; + // Thirdparty + if (!empty($arrayfields['s.nom']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } - // Account - if (!empty($conf->banque->enabled)) - { - print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Bank transaction + if (!empty($arrayfields['transaction']['checked'])) { + $bankline->fetch($objp->fk_bank); + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Bank account + if (!empty($arrayfields['ba.label']['checked'])) { + print ''; - if (!$i) $totalarray['nbfield']++; - } + print $accountstatic->getNomUrl(1); + } + print ''; + if (!$i) $totalarray['nbfield']++; + } - // Amount - print ''; - if (!$i) $totalarray['nbfield']++; - $totalarray['pos'][7] = 'amount'; - $totalarray['val']['amount'] += $objp->amount; + // Amount + if (!empty($arrayfields['p.amount']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + $totalarray['pos'][7] = 'amount'; + $totalarray['val']['amount'] += $objp->amount; + } - if (!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION)) - { - print ''; - if (!$i) $totalarray['nbfield']++; - } + // Status + if (!empty($arrayfields['p.statut']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + // Buttons print ''; if (!$i) $totalarray['nbfield']++; print ''; - $i++; - } + $i++; + } - // Show total line - include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + // Show total line + include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; - print "
'; + print ''; + print ''; + print ''; + if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; + print ''; + $formother->select_year($year ? $year : -1, 'year', 1, 20, 5); + print ''; + print ''; + print ''; + $form->select_types_paiements($search_paymenttype, 'search_paymenttype', '', 2, 1, 1); + print ''; + print ''; + $form->select_comptes($search_account, 'search_account', 0, '', 1); + print ''; + print ''; + print ''; + print ''; + print $form->showFilterAndCheckAddButtons(0); print ''; - $searchpicto = $form->showFilterAndCheckAddButtons(0); - print $searchpicto; - print ''; - print '
'; - print $paymentstatic->getNomUrl(1); - print '
'.dol_print_date($db->jdate($objp->dp), $dateformatforpayment).''.(($offset * $limit) + $i).''; - if ($objp->socid > 0) - { - print $companystatic->getNomUrl(1, '', 24); - } - print ''.print $object->getNomUrl(1).''.$langs->trans("PaymentTypeShort".$objp->paiement_code).''.dol_print_date($db->jdate($objp->datep), $dateformatforpayment).''.$objp->num_payment.''; + if ($objp->socid > 0) + { + print $companystatic->getNomUrl(1, '', 24); + } + print ''; - if ($objp->bid > 0) - { - $accountstatic->id = $objp->bid; - $accountstatic->ref = $objp->bref; - $accountstatic->label = $objp->blabel; - $accountstatic->number = $objp->number; - $accountstatic->account_number = $objp->account_number; + // Payment type + if (!empty($arrayfields['c.libelle']['checked'])) { + print ''.$langs->trans("PaymentTypeShort".$objp->paiement_code).''.$bankline->getNomUrl(1, 0).''; + if ($objp->bid > 0) + { + $accountstatic->id = $objp->bid; + $accountstatic->ref = $objp->bref; + $accountstatic->label = $objp->blabel; + $accountstatic->number = $objp->number; + $accountstatic->account_number = $objp->account_number; $accountingjournal = new AccountingJournal($db); $accountingjournal->fetch($objp->accountancy_journal); $accountstatic->accountancy_journal = $accountingjournal->code; - print $accountstatic->getNomUrl(1); - } - print ''.price($objp->amount).''.price($objp->amount).''; - if ($objp->statut == 0) print ''; - print $paymentstatic->LibStatut($objp->statut, 5); - if ($objp->statut == 0) print ''; - print ''; + if ($objp->statut == 0) print ''; + print $object->LibStatut($objp->statut, 5); + if ($objp->statut == 0) print ''; + print '
\n"; - print "
"; - print "\n"; -} else { - dol_print_error($db); + print "
"; + print "
"; + print ""; +} +else +{ + dol_print_error($db); } // End of page From 8447817f8c6c4be71d6aa757ccd91ad8dc276805 Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Mon, 5 Oct 2020 11:38:07 +0200 Subject: [PATCH 036/317] fix swapped array entries --- htdocs/compta/paiement/list.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/htdocs/compta/paiement/list.php b/htdocs/compta/paiement/list.php index 74c198b96c2..e45f8f3a14a 100644 --- a/htdocs/compta/paiement/list.php +++ b/htdocs/compta/paiement/list.php @@ -82,14 +82,14 @@ $hookmanager->initHooks(array('paymentlist')); $extrafields = new ExtraFields($db); $arrayfields = array( - 'p.rowid' => array('label'=>"RefPayment", 'checked'=>1, 'position'=>10), - 'p.datep' => array('label'=>"Date", 'checked'=>1, 'position'=>20), - 's.nom' => array('label'=>"ThirdParty", 'checked'=>1, 'position'=>30), - 'c.libelle' => array('label'=>"Type", 'checked'=>1, 'position'=>40), - 'transaction' => array('label'=>"BankTransactionLine", 'checked'=>1, 'enabled'=>(!empty($conf->banque->enabled)), 'position'=>50), - 'ba.label' => array('label'=>"Account", 'checked'=>1, 'enabled'=>(!empty($conf->banque->enabled)), 'position'=>60), - 'p.amount' => array('label'=>"Amount", 'checked'=>1, 'position'=>70), - 'p.statut' => array('label'=>"Status", 'enabled'=>1, 'checked'=>(!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION)), 'position'=>80), + 'p.rowid'=>array('label'=>"RefPayment", 'checked'=>1, 'position'=>10), + 'p.datep'=>array('label'=>"Date", 'checked'=>1, 'position'=>20), + 's.nom'=>array('label'=>"ThirdParty", 'checked'=>1, 'position'=>30), + 'c.libelle'=>array('label'=>"Type", 'checked'=>1, 'position'=>40), + 'transaction'=>array('label'=>"BankTransactionLine", 'checked'=>1, 'position'=>50, 'enabled'=>(!empty($conf->banque->enabled))), + 'ba.label'=>array('label'=>"Account", 'checked'=>1, 'position'=>60, 'enabled'=>(!empty($conf->banque->enabled))), + 'p.amount'=>array('label'=>"Amount", 'checked'=>1, 'position'=>70), + 'p.statut'=>array('label'=>"Status", 'checked'=>1, 'position'=>80, 'enabled'=>(!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION))), ); $arrayfields = dol_sort_array($arrayfields, 'position'); From 4e711d4e305f13968a4f1f9f0abf4a28bd8e3a6a Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 5 Oct 2020 15:15:15 +0200 Subject: [PATCH 037/317] fix bad test syntax --- htdocs/fourn/commande/dispatch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 7a11d22aa53..ae29dd35ff2 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -1290,7 +1290,7 @@ if ($id > 0 || !empty($ref)) { print ''; } - if ($action != 'editline' ||  && $lineid != $objp->dispatchlineid) + if ($action != 'editline' && $lineid != $objp->dispatchlineid) { print ''; print 'dispatchlineid .'#line_'. $objp->dispatchlineid . '">'; From bb0b9dc1286301423e9cbd2c1fc88a37299027e0 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Mon, 5 Oct 2020 18:16:32 +0200 Subject: [PATCH 038/317] FIX php error in takepos --- htdocs/takepos/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/takepos/index.php b/htdocs/takepos/index.php index 459225fda03..3585d25eee7 100644 --- a/htdocs/takepos/index.php +++ b/htdocs/takepos/index.php @@ -865,7 +865,7 @@ if (empty($conf->global->TAKEPOS_HIDE_HEAD_BAR)) {
-if (!empty($conf->multicurrency->enabled)){ +multicurrency->enabled)){ ?> -} +
From 005cc093b992579779572d164f73a12bdb5dfce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 5 Oct 2020 20:02:23 +0200 Subject: [PATCH 039/317] fix typo --- htdocs/core/modules/mailings/fraise.modules.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/modules/mailings/fraise.modules.php b/htdocs/core/modules/mailings/fraise.modules.php index 7b9eeb02c0d..efec11c0ba7 100644 --- a/htdocs/core/modules/mailings/fraise.modules.php +++ b/htdocs/core/modules/mailings/fraise.modules.php @@ -266,7 +266,7 @@ class mailing_fraise extends MailingTargets if ($dateendsubscriptionbefore > 0) $sql .= " AND datefin < '".$this->db->idate($dateendsubscriptionbefore)."'"; $sql .= " AND a.fk_adherent_type = ta.rowid"; // Filter on type - if (GETPOSTISET('filter_type')) $sql .= " AND ta.rowid='".$this->db->escape(GETPOST('filter_type'))."'"; + if (GETPOSTISSET('filter_type')) $sql .= " AND ta.rowid='".$this->db->escape(GETPOST('filter_type'))."'"; // Filter on category if (GETPOSTISSET('filter_category')) $sql .= " AND c.rowid='".$this->db->escape(GETPOST('filter_category'))."'"; $sql .= " ORDER BY a.email"; @@ -302,7 +302,7 @@ class mailing_fraise extends MailingTargets 'source_url' => $this->url($obj->id), 'source_id' => $obj->id, 'source_type' => 'member' - ); + ); $old = $obj->email; $j++; } From 83eb7a8d8dba0033fa8ed97fd560b6513d710c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 5 Oct 2020 20:16:18 +0200 Subject: [PATCH 040/317] doxygen --- htdocs/expedition/class/expedition.class.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 9b6a07a5435..bdf79081fe2 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -11,7 +11,7 @@ * Copyright (C) 2015 Claudio Aschieri * Copyright (C) 2016 Ferran Marcet * Copyright (C) 2018 Nicolas ZABOURI - * Copyright (C) 2018 Frédéric France + * Copyright (C) 2018-2020 Frédéric France * Copyright (C) 2020 Lenin Rivas * * This program is free software; you can redistribute it and/or modify @@ -82,6 +82,13 @@ class Expedition extends CommonObject public $socid; + /** + * @var string Customer ref + * @deprecated + * @see $ref_customer + */ + public $ref_client; + /** * @var string Customer ref */ From d83d9895e039e9ecd2cff39d4a6313cc4b0ca848 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 5 Oct 2020 20:52:31 +0200 Subject: [PATCH 041/317] NEW Vat report - Invert constant to show by default zero vat in reports --- htdocs/core/lib/tax.lib.php | 20 +++++++++---------- .../install/mysql/migration/12.0.0-13.0.0.sql | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/htdocs/core/lib/tax.lib.php b/htdocs/core/lib/tax.lib.php index d56d2260afc..3b261bd0814 100644 --- a/htdocs/core/lib/tax.lib.php +++ b/htdocs/core/lib/tax.lib.php @@ -170,7 +170,7 @@ function tax_by_thirdparty($type, $db, $y, $date_start, $date_end, $modetax, $di if ($date_start && $date_end) $sql .= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 0"; // Limit to products $sql .= " AND d.date_start is null AND d.date_end IS NULL)"; // enhance detection of products - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture; } else { // Count on payments date @@ -208,7 +208,7 @@ function tax_by_thirdparty($type, $db, $y, $date_start, $date_end, $modetax, $di if ($date_start && $date_end) $sql .= " AND pa.datep >= '".$db->idate($date_start)."' AND pa.datep <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 0"; // Limit to products $sql .= " AND d.date_start is null AND d.date_end IS NULL)"; // enhance detection of products - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture.", pf.rowid"; } @@ -312,7 +312,7 @@ function tax_by_thirdparty($type, $db, $y, $date_start, $date_end, $modetax, $di if ($date_start && $date_end) $sql .= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 1"; // Limit to services $sql .= " OR d.date_start is NOT null OR d.date_end IS NOT NULL)"; // enhance detection of service - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture; } else { // Count on payments date @@ -350,7 +350,7 @@ function tax_by_thirdparty($type, $db, $y, $date_start, $date_end, $modetax, $di if ($date_start && $date_end) $sql .= " AND pa.datep >= '".$db->idate($date_start)."' AND pa.datep <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 1"; // Limit to services $sql .= " OR d.date_start is NOT null OR d.date_end IS NOT NULL)"; // enhance detection of service - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture.", pf.rowid"; } @@ -451,7 +451,7 @@ function tax_by_thirdparty($type, $db, $y, $date_start, $date_end, $modetax, $di if ($date_start && $date_end) $sql .= " AND p.datep >= '".$db->idate($date_start)."' AND p.datep <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = -1"; $sql .= " OR e.date_debut is NOT null OR e.date_fin IS NOT NULL)"; // enhance detection of service - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.total_tva <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.total_tva <> 0)"; $sql .= " ORDER BY e.rowid"; if (!$sql) @@ -622,7 +622,7 @@ function tax_by_rate($type, $db, $y, $q, $date_start, $date_end, $modetax, $dire if ($date_start && $date_end) $sql .= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 0"; // Limit to products $sql .= " AND d.date_start is null AND d.date_end IS NULL)"; // enhance detection of products - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture; } else { // Count on payments date @@ -660,7 +660,7 @@ function tax_by_rate($type, $db, $y, $q, $date_start, $date_end, $modetax, $dire if ($date_start && $date_end) $sql .= " AND pa.datep >= '".$db->idate($date_start)."' AND pa.datep <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 0"; // Limit to products $sql .= " AND d.date_start is null AND d.date_end IS NULL)"; // enhance detection of products - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture.", pf.rowid"; } @@ -764,7 +764,7 @@ function tax_by_rate($type, $db, $y, $q, $date_start, $date_end, $modetax, $dire if ($date_start && $date_end) $sql .= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 1"; // Limit to services $sql .= " OR d.date_start is NOT null OR d.date_end IS NOT NULL)"; // enhance detection of service - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture; } else { // Count on payments date @@ -802,7 +802,7 @@ function tax_by_rate($type, $db, $y, $q, $date_start, $date_end, $modetax, $dire if ($date_start && $date_end) $sql .= " AND pa.datep >= '".$db->idate($date_start)."' AND pa.datep <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = 1"; // Limit to services $sql .= " OR d.date_start is NOT null OR d.date_end IS NOT NULL)"; // enhance detection of service - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.".$total_tva." <> 0)"; $sql .= " ORDER BY d.rowid, d.".$fk_facture.", pf.rowid"; } @@ -903,7 +903,7 @@ function tax_by_rate($type, $db, $y, $q, $date_start, $date_end, $modetax, $dire if ($date_start && $date_end) $sql .= " AND p.datep >= '".$db->idate($date_start)."' AND p.datep <= '".$db->idate($date_end)."'"; $sql .= " AND (d.product_type = -1"; $sql .= " OR e.date_debut is NOT null OR e.date_fin IS NOT NULL)"; // enhance detection of service - if (empty($conf->global->MAIN_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.total_tva <> 0)"; + if (!empty($conf->global->MAIN_NOT_INCLUDE_ZERO_VAT_IN_REPORTS)) $sql .= " AND (d.".$f_rate." <> 0 OR d.total_tva <> 0)"; $sql .= " ORDER BY e.rowid"; if (!$sql) diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 88c17cc0619..7c32a370c45 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -355,3 +355,5 @@ CREATE TABLE llx_ecm_directories_extrafields ALTER TABLE llx_ecm_directories_extrafields ADD INDEX idx_ecm_directories_extrafields (fk_object); ALTER TABLE llx_website_page ADD COLUMN object_type varchar(255); ALTER TABLE llx_website_page ADD COLUMN fk_object varchar(255); + +DELETE FROM llx_const WHERE name in ('MAIN_INCLUDE_ZERO_VAT_IN_REPORTS'); From 6a0f2233a69a70cb9e78ee63cf880e52f190aa7b Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 5 Oct 2020 21:44:39 +0200 Subject: [PATCH 042/317] NEW Accountancy - Move to real ledger, real journals, menu disposition --- htdocs/accountancy/bookkeeping/list.php | 2 +- .../accountancy/bookkeeping/listbyaccount.php | 2 +- .../class/accountingaccount.class.php | 12 ++++----- htdocs/core/menus/init_menu_auguria.sql | 8 +++--- htdocs/core/menus/standard/eldy.lib.php | 26 ++++++++++--------- htdocs/langs/en_US/accountancy.lang | 6 ++--- 6 files changed, 30 insertions(+), 26 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index 813dbd4a37f..d5603a7a075 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -638,7 +638,7 @@ $newcardbutton .= ''.$langs->trans("I $newcardbutton .= dolGetButtonTitle($buttonLabel, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', 'fa fa-file-export paddingleft', $_SERVER["PHP_SELF"].'?action=export_file'.($param ? '&'.$param : ''), $user->rights->accounting->mouvements->export); -$newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param); +// $newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param); $url = './card.php?action=create'; if (!empty($socid)) $url .= '&socid='.$socid; diff --git a/htdocs/accountancy/bookkeeping/listbyaccount.php b/htdocs/accountancy/bookkeeping/listbyaccount.php index e0e16e00d12..b99d913a6ff 100644 --- a/htdocs/accountancy/bookkeeping/listbyaccount.php +++ b/htdocs/accountancy/bookkeeping/listbyaccount.php @@ -373,7 +373,7 @@ print ''; print ''; -$newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param); +// $newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param); $newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', './card.php?action=create'); if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); diff --git a/htdocs/accountancy/class/accountingaccount.class.php b/htdocs/accountancy/class/accountingaccount.class.php index 24f14d2ebd2..199899f89d5 100644 --- a/htdocs/accountancy/class/accountingaccount.class.php +++ b/htdocs/accountancy/class/accountingaccount.class.php @@ -448,7 +448,7 @@ class AccountingAccount extends CommonObject * @param int $notooltip 1=Disable tooltip * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking * @param int $withcompletelabel 0=Short label (field short label), 1=Complete label (field label) - * @param string $option 'bookkeeping', 'bookkeepinglistbyaccount', 'accountcard' + * @param string $option 'ledger', 'journals', 'accountcard' * @return string String with URL */ public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $withcompletelabel = 0, $option = '') @@ -460,12 +460,12 @@ class AccountingAccount extends CommonObject $result = ''; - if (empty($option) || $option == 'bookkeeping') { - $url = DOL_URL_ROOT . '/accountancy/bookkeeping/list.php?search_accountancy_code_start=' . $this->account_number . '&search_accountancy_code_end=' . $this->account_number; - $labelurl = $langs->trans("ShowAccountingAccountInBookKeeping"); - } elseif ($option == 'bookkeepinglistbyaccount') { + if (empty($option) || $option == 'ledger') { $url = DOL_URL_ROOT . '/accountancy/bookkeeping/listbyaccount.php?search_accountancy_code_start=' . $this->account_number . '&search_accountancy_code_end=' . $this->account_number; - $labelurl = $langs->trans("ShowAccountingAccountInBookKeepingByAccount"); + $labelurl = $langs->trans("ShowAccountingAccountInLedger"); + } elseif ($option == 'journals') { + $url = DOL_URL_ROOT . '/accountancy/bookkeeping/list.php?search_accountancy_code_start=' . $this->account_number . '&search_accountancy_code_end=' . $this->account_number; + $labelurl = $langs->trans("ShowAccountingAccountInJournals"); } elseif ($option == 'accountcard') { $url = DOL_URL_ROOT . '/accountancy/admin/card.php?id=' . $this->id; $labelurl = $langs->trans("ShowAccountingAccount"); diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql index 25ef112b39b..818198fc035 100644 --- a/htdocs/core/menus/init_menu_auguria.sql +++ b/htdocs/core/menus/init_menu_auguria.sql @@ -289,10 +289,12 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left --insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2708__+MAX_llx_menu__, 'accountancy', '', 2705__+MAX_llx_menu__, '/accountancy/journal/expensereportsjournal.php?mainmenu=accountancy&leftmenu=accountancy_journal&id_journal=6', 'ExpenseReportJournal', 2, 'main', '$user->rights->compta->resultat->lire || $user->rights->accounting->comptarapport->lire', '', 0, 2, __ENTITY__); --insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2709__+MAX_llx_menu__, 'accountancy', '', 2705__+MAX_llx_menu__, '/accountancy/journal/purchasesjournal.php?mainmenu=accountancy&leftmenu=accountancy_journal&id_journal=2', 'PurchasesJournal', 2, 'main', '$user->rights->compta->resultat->lire || $user->rights->accounting->comptarapport->lire', '', 0, 3, __ENTITY__); --insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2706__+MAX_llx_menu__, 'accountancy', '', 2705__+MAX_llx_menu__, '/accountancy/journal/sellsjournal.php?mainmenu=accountancy&leftmenu=accountancy_journal&id_journal=1', 'SellsJournal', 2, 'main', '$user->rights->compta->resultat->lire || $user->rights->accounting->comptarapport->lire', '', 0, 4, __ENTITY__); - -- General Ledger - insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2430__+MAX_llx_menu__, 'accountancy', 'bookkeeping', 2400__+MAX_llx_menu__, '/accountancy/bookkeeping/list.php?mainmenu=accountancy&leftmenu=accountancy_bookeeping', 'Bookkeeping', 1, 'accountancy', '$user->rights->accounting->mouvements->lire', '', 0, 15, __ENTITY__); -- Balance - insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2435__+MAX_llx_menu__, 'accountancy', 'balance', 2400__+MAX_llx_menu__, '/accountancy/bookkeeping/balance.php?mainmenu=accountancy&leftmenu=accountancy_balance', 'AccountBalance', 1, 'accountancy', '$user->rights->accounting->mouvements->lire', '', 0, 16, __ENTITY__); + insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2430__+MAX_llx_menu__, 'accountancy', 'balance', 2400__+MAX_llx_menu__, '/accountancy/bookkeeping/balance.php?mainmenu=accountancy&leftmenu=accountancy_balance', 'AccountBalance', 1, 'accountancy', '$user->rights->accounting->mouvements->lire', '', 0, 10, __ENTITY__); + -- General Ledger + insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2432__+MAX_llx_menu__, 'accountancy', 'bookkeeping', 2400__+MAX_llx_menu__, '/accountancy/bookkeeping/listbyaccount.php?mainmenu=accountancy&leftmenu=accountancy_bookeeping', 'Bookkeeping', 1, 'accountancy', '$user->rights->accounting->mouvements->lire', '', 0, 12, __ENTITY__); + -- Journals + insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->accounting->enabled', __HANDLER__, 'left', 2434__+MAX_llx_menu__, 'accountancy', 'bookkeeping', 2400__+MAX_llx_menu__, '/accountancy/bookkeeping/list.php?mainmenu=accountancy&leftmenu=accountancy_bookeeping', 'Journals', 1, 'accountancy', '$user->rights->accounting->mouvements->lire', '', 0, 15, __ENTITY__); -- Export accounting documents insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->comptabilite->enabled || $conf->accounting->enabled', __HANDLER__, 'left', 2436__+MAX_llx_menu__, 'accountancy', 'accountancy_files', 2400__+MAX_llx_menu__, '/compta/accounting-files.php?mainmenu=accountancy&leftmenu=accountancy_files', 'AccountantFiles', 1, 'accountancy', '$user->rights->compta->resultat->lire || $user->rights->accounting->mouvements->lire', '', 0, 17, __ENTITY__); -- Reports diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 3f99754b5cd..57b93c70d77 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1315,13 +1315,21 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM // Accounting $newmenu->add("/accountancy/index.php?leftmenu=accountancy_accountancy", $langs->trans("MenuAccountancy"), 0, $user->rights->accounting->mouvements->lire, '', $mainmenu, 'accountancy', 1); - - // General Ledger - $newmenu->add("/accountancy/bookkeeping/list.php?mainmenu=accountancy&leftmenu=accountancy_accountancy", $langs->trans("Bookkeeping"), 1, $user->rights->accounting->mouvements->lire); - // Balance $newmenu->add("/accountancy/bookkeeping/balance.php?mainmenu=accountancy&leftmenu=accountancy_accountancy", $langs->trans("AccountBalance"), 1, $user->rights->accounting->mouvements->lire); + // General Ledger + $newmenu->add("/accountancy/bookkeeping/listbyaccount.php?mainmenu=accountancy&leftmenu=accountancy_accountancy", $langs->trans("Bookkeeping"), 1, $user->rights->accounting->mouvements->lire); + + // Journals + $newmenu->add("/accountancy/bookkeeping/list.php?mainmenu=accountancy&leftmenu=accountancy_accountancy", $langs->trans("Journals"), 1, $user->rights->accounting->mouvements->lire); + + // Files + if (empty($conf->global->ACCOUNTANCY_HIDE_EXPORT_FILES_MENU)) + { + $newmenu->add("/compta/accounting-files.php?mainmenu=accountancy&leftmenu=accountancy_files", $langs->trans("AccountantFiles"), 1, $user->rights->accounting->mouvements->lire); + } + // Closure if (!empty($conf->global->MAIN_FEATURES_LEVEL) && $conf->global->MAIN_FEATURES_LEVEL >= 2) { $newmenu->add("/accountancy/closure/index.php?mainmenu=accountancy&leftmenu=accountancy_closure", $langs->trans("MenuAccountancyClosure"), 1, $user->rights->accounting->fiscalyear->write, '', $mainmenu, 'closure'); @@ -1331,12 +1339,6 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM } } - // Files - if (empty($conf->global->ACCOUNTANCY_HIDE_EXPORT_FILES_MENU)) - { - $newmenu->add("/compta/accounting-files.php?mainmenu=accountancy&leftmenu=accountancy_files", $langs->trans("AccountantFiles"), 1, $user->rights->accounting->mouvements->lire); - } - // Reports $newmenu->add("/accountancy/index.php?leftmenu=accountancy_report", $langs->trans("Reportings"), 1, $user->rights->accounting->comptarapport->lire, '', $mainmenu, 'ca'); @@ -1430,11 +1432,11 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM $newmenu->add("/compta/stats/supplier_turnover.php?leftmenu=accountancy_report", $langs->trans("ReportPurchaseTurnover"), 1, $user->rights->compta->resultat->lire); $newmenu->add("/compta/stats/supplier_turnover_by_thirdparty.php?leftmenu=accountancy_report", $langs->trans("ByCompanies"), 2, $user->rights->compta->resultat->lire); $newmenu->add("/compta/stats/supplier_turnover_by_prodserv.php?leftmenu=accountancy_report", $langs->trans("ByProductsAndServices"), 2, $user->rights->compta->resultat->lire); - // Journaux + // Journals $newmenu->add("/compta/journal/sellsjournal.php?leftmenu=report", $langs->trans("SellsJournal"), 1, $user->rights->compta->resultat->lire, '', '', '', 50); $newmenu->add("/compta/journal/purchasesjournal.php?leftmenu=report", $langs->trans("PurchasesJournal"), 1, $user->rights->compta->resultat->lire, '', '', '', 51); } - //if ($leftmenu=="ca") $newmenu->add("/compta/journaux/index.php?leftmenu=ca",$langs->trans("Journaux"),1,$user->rights->compta->resultat->lire||$user->rights->accounting->comptarapport->lire); + //if ($leftmenu=="ca") $newmenu->add("/compta/journaux/index.php?leftmenu=ca",$langs->trans("Journals"),1,$user->rights->compta->resultat->lire||$user->rights->accounting->comptarapport->lire); } // Assets diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang index 3d9b36d58b6..2897c62333d 100644 --- a/htdocs/langs/en_US/accountancy.lang +++ b/htdocs/langs/en_US/accountancy.lang @@ -20,7 +20,7 @@ CantSuggest=Can't suggest AccountancySetupDoneFromAccountancyMenu=Most setup of the accountancy is done from the menu %s ConfigAccountingExpert=Configuration of the module accounting (double entry) Journalization=Journalization -Journaux=Journals +Journals=Journals JournalFinancial=Financial journals BackToChartofaccounts=Return chart of accounts Chartofaccounts=Chart of accounts @@ -90,8 +90,8 @@ SubledgerAccount=Subledger account SubledgerAccountLabel=Subledger account label ShowAccountingAccount=Show accounting account ShowAccountingJournal=Show accounting journal -ShowAccountingAccountInBookKeeping=Show accounting account in ledger -ShowAccountingAccountInBookKeepingByAccount=Show accounting account in ledger by account +ShowAccountingAccountInLedger=Show accounting account in ledger +ShowAccountingAccountInJournals=Show accounting account in journals AccountAccountingSuggest=Accounting account suggested MenuDefaultAccounts=Default accounts MenuBankAccounts=Bank accounts From 6745c377a695ba506536f3b971449332c8d8cfaa Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 5 Oct 2020 22:35:12 +0200 Subject: [PATCH 043/317] Double line --- htdocs/accountancy/bookkeeping/listbyaccount.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/accountancy/bookkeeping/listbyaccount.php b/htdocs/accountancy/bookkeeping/listbyaccount.php index b99d913a6ff..58a696be1ae 100644 --- a/htdocs/accountancy/bookkeeping/listbyaccount.php +++ b/htdocs/accountancy/bookkeeping/listbyaccount.php @@ -33,7 +33,6 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; // Load translation files required by the page From 609a29219dd79d9d5a578ece4a788d94cd160bd5 Mon Sep 17 00:00:00 2001 From: Pierre Penelon Date: Mon, 5 Oct 2020 23:54:37 +0200 Subject: [PATCH 044/317] FIX|Missing require in API : markAsCreditAvailable Quick fix of a problem I encountered earlier when using `markAsCreditAvailable` API method for invoice routes. The method was using the `DiscountAbsolute` class without importing it resulting in a 500 HTTP error. --- htdocs/compta/facture/class/api_invoices.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index 643fb7eddd0..3c9f0af29bc 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -996,6 +996,8 @@ class Invoices extends DolibarrApi */ public function markAsCreditAvailable($id) { + require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; + if (!DolibarrApiAccess::$user->rights->facture->creer) { throw new RestException(401); } From b9cc780c3c3897e6c0575f6e94536915f48cde1b Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 5 Oct 2020 21:58:00 +0000 Subject: [PATCH 045/317] Fixing style errors. --- htdocs/compta/facture/class/api_invoices.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index 3c9f0af29bc..b913b405734 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -997,7 +997,7 @@ class Invoices extends DolibarrApi public function markAsCreditAvailable($id) { require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; - + if (!DolibarrApiAccess::$user->rights->facture->creer) { throw new RestException(401); } From 33b7d06bb9b796bd82aa8ff07a80b5113e6eb45f Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Tue, 6 Oct 2020 08:46:53 +0200 Subject: [PATCH 046/317] address feedback + tooltip + reduce indent --- htdocs/compta/paiement/list.php | 586 ++++++++++++++++---------------- 1 file changed, 302 insertions(+), 284 deletions(-) diff --git a/htdocs/compta/paiement/list.php b/htdocs/compta/paiement/list.php index e45f8f3a14a..90f3458918a 100644 --- a/htdocs/compta/paiement/list.php +++ b/htdocs/compta/paiement/list.php @@ -63,16 +63,18 @@ $search_account = GETPOST("search_account", "int"); $search_paymenttype = GETPOST("search_paymenttype"); $search_amount = GETPOST("search_amount", 'alpha'); // alpha because we must be able to search on "< x" $search_company = GETPOST("search_company", 'alpha'); +$search_payment_num = GETPOST('search_payment_num', 'alpha'); $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; $sortfield = GETPOST("sortfield", 'alpha'); $sortorder = GETPOST("sortorder", 'alpha'); $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); -if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +if (empty($page) || $page == -1) $page = 0; // If $page is not defined, or '' or -1 $offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; + if (!$sortorder) $sortorder = "DESC"; if (!$sortfield) $sortfield = "p.rowid"; @@ -82,14 +84,15 @@ $hookmanager->initHooks(array('paymentlist')); $extrafields = new ExtraFields($db); $arrayfields = array( - 'p.rowid'=>array('label'=>"RefPayment", 'checked'=>1, 'position'=>10), - 'p.datep'=>array('label'=>"Date", 'checked'=>1, 'position'=>20), - 's.nom'=>array('label'=>"ThirdParty", 'checked'=>1, 'position'=>30), - 'c.libelle'=>array('label'=>"Type", 'checked'=>1, 'position'=>40), - 'transaction'=>array('label'=>"BankTransactionLine", 'checked'=>1, 'position'=>50, 'enabled'=>(!empty($conf->banque->enabled))), - 'ba.label'=>array('label'=>"Account", 'checked'=>1, 'position'=>60, 'enabled'=>(!empty($conf->banque->enabled))), - 'p.amount'=>array('label'=>"Amount", 'checked'=>1, 'position'=>70), - 'p.statut'=>array('label'=>"Status", 'checked'=>1, 'position'=>80, 'enabled'=>(!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION))), + 'p.rowid' => array('label'=>"RefPayment", 'checked'=>1, 'position'=>10), + 'p.datep' => array('label'=>"Date", 'checked'=>1, 'position'=>20), + 's.nom' => array('label'=>"ThirdParty", 'checked'=>1, 'position'=>30), + 'c.libelle' => array('label'=>"Type", 'checked'=>1, 'position'=>40), + 'transaction' => array('label'=>"BankTransactionLine", 'checked'=>1, 'position'=>50, 'enabled'=>(!empty($conf->banque->enabled))), + 'ba.label' => array('label'=>"Account", 'checked'=>1, 'position'=>60, 'enabled'=>(!empty($conf->banque->enabled))), + 'p.num_payment' => array('label'=>"Numero", 'checked'=>1, 'position'=>70, 'tooltip'=>"ChequeOrTransferNumber"), + 'p.amount' => array('label'=>"Amount", 'checked'=>1, 'position'=>80), + 'p.statut' => array('label'=>"Status", 'checked'=>1, 'position'=>90, 'enabled'=>(!empty($conf->global->BILL_ADD_PAYMENT_VALIDATION))), ); $arrayfields = dol_sort_array($arrayfields, 'position'); @@ -103,26 +106,28 @@ $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); -if(empty($reshook)) -{ +if(empty($reshook)) { include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; - if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers - { - $search_ref = ""; - $search_account = ""; - $search_amount = ""; - $search_paymenttype = ""; - $search_company = ""; + // All tests are required to be compatible with all browsers + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + $search_ref = ''; + $search_account = ''; + $search_amount = ''; + $search_paymenttype = ''; + $search_payment_num = ''; + $search_company = ''; $day = ''; $year = ''; $month = ''; + $option = ''; + $toselect = ''; $search_array_options = array(); } } /* - * View + * View */ $form = new Form($db); @@ -133,11 +138,11 @@ $bankline = new AccountLine($db); llxHeader('', $langs->trans('ListPayment')); -if (GETPOST("orphelins", "alpha")) -{ +if (GETPOST("orphelins", "alpha")) { // Payments not linked to an invoice. Should not happend. For debug only. - $sql = "SELECT p.rowid, p.ref, p.datep, p.fk_bank, p.amount, p.statut"; + $sql = "SELECT p.rowid, p.ref, p.datep, p.amount, p.statut, p.num_paiement as num_payment"; $sql .= ", c.code as paiement_code"; + // Add fields from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook @@ -146,18 +151,18 @@ if (GETPOST("orphelins", "alpha")) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON p.rowid = pf.fk_paiement"; $sql .= " WHERE p.entity IN (".getEntity('invoice').")"; $sql .= " AND pf.fk_facture IS NULL"; + // Add where from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; -} -else -{ +} else { // DISTINCT is to avoid duplicate when there is a link to sales representatives - $sql = "SELECT DISTINCT p.rowid, p.ref, p.datep, p.fk_bank, p.amount, p.statut"; + $sql = "SELECT DISTINCT p.rowid, p.ref, p.datep, p.fk_bank, p.amount, p.statut, p.num_paiement as num_payment"; $sql .= ", c.code as paiement_code"; $sql .= ", ba.rowid as bid, ba.ref as bref, ba.label as blabel, ba.number, ba.account_number as account_number, ba.fk_accountancy_journal as accountancy_journal"; $sql .= ", s.rowid as socid, s.nom as name, s.email"; + // Add fields from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook @@ -169,28 +174,30 @@ else $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON p.rowid = pf.fk_paiement"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON pf.fk_facture = f.rowid"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid"; - if (!$user->rights->societe->client->voir && !$socid) - { + if (!$user->rights->societe->client->voir && !$socid) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc"; } $sql .= " WHERE p.entity IN (".getEntity('invoice').")"; - if (!$user->rights->societe->client->voir && !$socid) - { + if (!$user->rights->societe->client->voir && !$socid) { $sql .= " AND sc.fk_user = ".$user->id; } - if ($socid > 0) $sql .= " AND f.fk_soc = ".$socid; - if ($userid) - { - if ($userid == -1) $sql .= " AND f.fk_user_author IS NULL"; - else $sql .= " AND f.fk_user_author = ".$userid; + if ($socid > 0) { + $sql .= " AND f.fk_soc = ".$socid; } + if ($userid) { + if ($userid == -1) $sql .= " AND f.fk_user_author IS NULL"; + else $sql .= " AND f.fk_user_author = ".$userid; + } + // Search criteria $sql .= dolSqlDateFilter("p.datep", $day, $month, $year); if ($search_ref) $sql .= natural_search('p.ref', $search_ref); if ($search_account > 0) $sql .= " AND b.fk_account=".$search_account; - if ($search_paymenttype != "") $sql .= " AND c.code='".$db->escape($search_paymenttype)."'"; + if ($search_paymenttype != '') $sql .= " AND c.code='".$db->escape($search_paymenttype)."'"; + if ($search_payment_num != '') $sql .= natural_search('p.num_paiement', $search_payment_num); if ($search_amount) $sql .= natural_search('p.amount', $search_amount, 1); if ($search_company) $sql .= natural_search('s.nom', $search_company); + // Add where from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook @@ -199,12 +206,12 @@ else $sql .= $db->order($sortfield, $sortorder); $nbtotalofrecords = ''; -if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) -{ +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $result = $db->query($sql); $nbtotalofrecords = $db->num_rows($result); - if (($page * $limit) > $nbtotalofrecords) // if total resultset is smaller then paging size (filtering), goto and load page 0 - { + + // if total resultset is smaller then paging size (filtering), goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) { $page = 0; $offset = 0; } @@ -213,253 +220,264 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) $sql .= $db->plimit($limit + 1, $offset); $resql = $db->query($sql); -if ($resql) -{ - $num = $db->num_rows($resql); - - $param = ''; - if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); - if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); - $param .= (GETPOST("orphelins") ? "&orphelins=1" : ""); - $param .= ($search_ref ? "&search_ref=".urlencode($search_ref) : ""); - $param .= ($search_company ? "&search_company=".urlencode($search_company) : ""); - $param .= ($search_amount ? "&search_amount=".urlencode($search_amount) : ""); - if ($optioncss != '') $param .= '&optioncss='.urlencode($optioncss); - - print '
'; - if ($optioncss != '') print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - - print_barre_liste($langs->trans("ReceivedCustomersPayments"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'bill', 0, '', '', $limit, 0, 0, 1); - - $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; - $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields - if ($massactionbutton) $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); - - print '
'; - print ''; - - print ''; - - // Filters: Lines (placeholder) - print ''; - if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { - print ''; - } - - // Filter: Ref - if (!empty($arrayfields['p.rowid']['checked'])) { - print ''; - } - - // Filter: Date - if (!empty($arrayfields['p.datep']['checked'])) { - print ''; - } - - // Filter: Thirdparty - if (!empty($arrayfields['s.nom']['checked'])) { - print ''; - } - - // Filter: Payment type - if (!empty($arrayfields['c.libelle']['checked'])) { - print ''; - } - - // Filter: Bank transaction number - if (!empty($arrayfields['transaction']['checked'])) { - print ''; - } - - // Filter: Bank account - if (!empty($arrayfields['ba.label']['checked'])) { - print ''; - } - - // Filter: Amount - if (!empty($arrayfields['p.amount']['checked'])) { - print ''; - } - - // Filter: Status (only placeholder) - if (!empty($arrayfields['p.statut']['checked'])) { - print ''; - } - - // Fields from hook - $parameters = array('arrayfields'=>$arrayfields); - $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - - print ''; - - print ""; - - print ''; - if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) print_liste_field_titre('#', $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); - if (!empty($arrayfields['p.rowid']['checked'])) print_liste_field_titre($arrayfields['p.rowid']['label'], $_SERVER["PHP_SELF"], "p.rowid", "", $param, "", $sortfield, $sortorder); - if (!empty($arrayfields['p.datep']['checked'])) print_liste_field_titre($arrayfields['p.datep']['label'], $_SERVER["PHP_SELF"], "p.datep", "", $param, '', $sortfield, $sortorder, 'center '); - if (!empty($arrayfields['s.nom']['checked'])) print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"], "s.nom", "", $param, "", $sortfield, $sortorder); - if (!empty($arrayfields['c.libelle']['checked'])) print_liste_field_titre($arrayfields['c.libelle']['label'], $_SERVER["PHP_SELF"], "c.libelle", "", $param, "", $sortfield, $sortorder); - if (!empty($arrayfields['transaction']['checked'])) print_liste_field_titre($arrayfields['transaction']['label'], $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder); - if (!empty($arrayfields['ba.label']['checked'])) print_liste_field_titre($arrayfields['ba.label']['label'], $_SERVER["PHP_SELF"], "ba.label", "", $param, "", $sortfield, $sortorder); - if (!empty($arrayfields['p.amount']['checked'])) print_liste_field_titre($arrayfields['p.amount']['label'], $_SERVER["PHP_SELF"], "p.amount", "", $param, 'class="right"', $sortfield, $sortorder); - if (!empty($arrayfields['p.statut']['checked'])) print_liste_field_titre($arrayfields['p.statut']['label'], $_SERVER["PHP_SELF"], "p.statut", "", $param, 'class="right"', $sortfield, $sortorder); - - // Hook fields - $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); - $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - - print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); - - print ""; - - $i = 0; - $totalarray = array(); - while ($i < min($num, $limit)) - { - $objp = $db->fetch_object($resql); - - $object->id = $objp->rowid; - $object->ref = $objp->ref; - - $companystatic->id = $objp->socid; - $companystatic->name = $objp->name; - $companystatic->email = $objp->email; - - print ''; - - // No - if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { - print ''; - } - - // Ref - if (!empty($arrayfields['p.rowid']['checked'])) { - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Date - if (!empty($arrayfields['p.datep']['checked'])) { - $dateformatforpayment = 'day'; - if (!empty($conf->global->INVOICE_USE_HOURS_FOR_PAYMENT)) $dateformatforpayment = 'dayhour'; - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Thirdparty - if (!empty($arrayfields['s.nom']['checked'])) { - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Payment type - if (!empty($arrayfields['c.libelle']['checked'])) { - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Bank transaction - if (!empty($arrayfields['transaction']['checked'])) { - $bankline->fetch($objp->fk_bank); - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Bank account - if (!empty($arrayfields['ba.label']['checked'])) { - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Amount - if (!empty($arrayfields['p.amount']['checked'])) { - print ''; - if (!$i) $totalarray['nbfield']++; - $totalarray['pos'][7] = 'amount'; - $totalarray['val']['amount'] += $objp->amount; - } - - // Status - if (!empty($arrayfields['p.statut']['checked'])) { - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Buttons - print ''; - if (!$i) $totalarray['nbfield']++; - - print ''; - - $i++; - } - - // Show total line - include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; - - - print "
'; - print ''; - print ''; - print ''; - if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; - print ''; - $formother->select_year($year ? $year : -1, 'year', 1, 20, 5); - print ''; - print ''; - print ''; - $form->select_types_paiements($search_paymenttype, 'search_paymenttype', '', 2, 1, 1); - print ''; - print ''; - $form->select_comptes($search_account, 'search_account', 0, '', 1); - print ''; - print ''; - print ''; - print ''; - print $form->showFilterAndCheckAddButtons(0); - print '
'.(($offset * $limit) + $i).''.print $object->getNomUrl(1).''.dol_print_date($db->jdate($objp->datep), $dateformatforpayment).''; - if ($objp->socid > 0) - { - print $companystatic->getNomUrl(1, '', 24); - } - print ''.$langs->trans("PaymentTypeShort".$objp->paiement_code).''.$bankline->getNomUrl(1, 0).''; - if ($objp->bid > 0) - { - $accountstatic->id = $objp->bid; - $accountstatic->ref = $objp->bref; - $accountstatic->label = $objp->blabel; - $accountstatic->number = $objp->number; - $accountstatic->account_number = $objp->account_number; - - $accountingjournal = new AccountingJournal($db); - $accountingjournal->fetch($objp->accountancy_journal); - $accountstatic->accountancy_journal = $accountingjournal->code; - - print $accountstatic->getNomUrl(1); - } - print ''.price($objp->amount).''; - if ($objp->statut == 0) print ''; - print $object->LibStatut($objp->statut, 5); - if ($objp->statut == 0) print ''; - print '
"; - print "
"; - print "
"; -} -else -{ +if (!$resql) { dol_print_error($db); + llxFooter(); + $db->close(); + exit; } +$num = $db->num_rows($resql); + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); +if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); +$param .= (GETPOST("orphelins") ? "&orphelins=1" : ''); +$param .= ($search_ref ? "&search_ref=".urlencode($search_ref) : ''); +$param .= ($search_company ? "&search_company=".urlencode($search_company) : ''); +$param .= ($search_amount ? "&search_amount=".urlencode($search_amount) : ''); +$param .= ($search_payment_num ? "&search_payment_num=".urlencode($search_payment_num) : ''); +if ($optioncss != '') $param .= '&optioncss='.urlencode($optioncss); + +print '
'; +if ($optioncss != '') print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +print_barre_liste($langs->trans("ReceivedCustomersPayments"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'bill', 0, '', '', $limit, 0, 0, 1); + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +if ($massactionbutton) $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); + +print '
'; +print ''; + +print ''; + +// Filters: Lines (placeholder) +print ''; +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; +} + +// Filter: Ref +if (!empty($arrayfields['p.rowid']['checked'])) { + print ''; +} + +// Filter: Date +if (!empty($arrayfields['p.datep']['checked'])) { + print ''; +} + +// Filter: Thirdparty +if (!empty($arrayfields['s.nom']['checked'])) { + print ''; +} + +// Filter: Payment type +if (!empty($arrayfields['c.libelle']['checked'])) { + print ''; +} + +// Filter: Bank transaction number +if (!empty($arrayfields['transaction']['checked'])) { + print ''; +} + +// Filter: Cheque number (fund transfer) +if (!empty($arrayfields['p.num_payment']['checked'])) { + print ''; +} + +// Filter: Bank account +if (!empty($arrayfields['ba.label']['checked'])) { + print ''; +} + +// Filter: Amount +if (!empty($arrayfields['p.amount']['checked'])) { + print ''; +} + +// Filter: Status (only placeholder) +if (!empty($arrayfields['p.statut']['checked'])) { + print ''; +} + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print ''; + +print ""; + +print ''; +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) print_liste_field_titre('#', $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['p.rowid']['checked'])) print_liste_field_titre($arrayfields['p.rowid']['label'], $_SERVER["PHP_SELF"], "p.rowid", '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['p.datep']['checked'])) print_liste_field_titre($arrayfields['p.datep']['label'], $_SERVER["PHP_SELF"], "p.datep", '', $param, '', $sortfield, $sortorder, 'center '); +if (!empty($arrayfields['s.nom']['checked'])) print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"], "s.nom", '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['c.libelle']['checked'])) print_liste_field_titre($arrayfields['c.libelle']['label'], $_SERVER["PHP_SELF"], "c.libelle", '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['p.num_payment']['checked'])) print_liste_field_titre($arrayfields['p.num_payment']['label'], $_SERVER["PHP_SELF"], "p.num_payment", '', $param, '', $sortfield, $sortorder, '', $arrayfields['p.num_payment']['tooltip']); +if (!empty($arrayfields['transaction']['checked'])) print_liste_field_titre($arrayfields['transaction']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['ba.label']['checked'])) print_liste_field_titre($arrayfields['ba.label']['label'], $_SERVER["PHP_SELF"], "ba.label", '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['p.amount']['checked'])) print_liste_field_titre($arrayfields['p.amount']['label'], $_SERVER["PHP_SELF"], "p.amount", '', $param, 'class="right"', $sortfield, $sortorder); +if (!empty($arrayfields['p.statut']['checked'])) print_liste_field_titre($arrayfields['p.statut']['label'], $_SERVER["PHP_SELF"], "p.statut", '', $param, 'class="right"', $sortfield, $sortorder); + +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); +print ""; + +$i = 0; +$totalarray = array(); +while ($i < min($num, $limit)) { + $objp = $db->fetch_object($resql); + + $object->id = $objp->rowid; + $object->ref = $objp->ref; + + $companystatic->id = $objp->socid; + $companystatic->name = $objp->name; + $companystatic->email = $objp->email; + + print ''; + + // No + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Ref + if (!empty($arrayfields['p.rowid']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Date + if (!empty($arrayfields['p.datep']['checked'])) { + $dateformatforpayment = 'day'; + if (!empty($conf->global->INVOICE_USE_HOURS_FOR_PAYMENT)) $dateformatforpayment = 'dayhour'; + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Thirdparty + if (!empty($arrayfields['s.nom']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Payment type + if (!empty($arrayfields['c.libelle']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Filter: Cheque number (fund transfer) + if (!empty($arrayfields['p.num_payment']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Bank transaction + if (!empty($arrayfields['transaction']['checked'])) { + $bankline->fetch($objp->fk_bank); + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Bank account + if (!empty($arrayfields['ba.label']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Amount + if (!empty($arrayfields['p.amount']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + $totalarray['pos'][8] = 'amount'; + $totalarray['val']['amount'] += $objp->amount; + } + + // Status + if (!empty($arrayfields['p.statut']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Buttons + print ''; + if (!$i) $totalarray['nbfield']++; + + print ''; + + $i++; +} + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +print "
'; + print ''; + print ''; + print ''; + if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; + print ''; + $formother->select_year($year ? $year : -1, 'year', 1, 20, 5); + print ''; + print ''; + print ''; + $form->select_types_paiements($search_paymenttype, 'search_paymenttype', '', 2, 1, 1); + print ''; + print ''; + print ''; + print ''; + $form->select_comptes($search_account, 'search_account', 0, '', 1); + print ''; + print ''; + print ''; + print ''; +print $form->showFilterAndCheckAddButtons(0); +print '
'.(($offset * $limit) + $i).''.$object->getNomUrl(1).''.dol_print_date($db->jdate($objp->datep), $dateformatforpayment).''; + if ($objp->socid > 0) { + print $companystatic->getNomUrl(1, '', 24); + } + print ''.$langs->trans("PaymentTypeShort".$objp->paiement_code).''.$objp->num_payment.''.$bankline->getNomUrl(1, 0).''; + if ($objp->bid > 0) { + $accountstatic->id = $objp->bid; + $accountstatic->ref = $objp->bref; + $accountstatic->label = $objp->blabel; + $accountstatic->number = $objp->number; + $accountstatic->account_number = $objp->account_number; + + $accountingjournal = new AccountingJournal($db); + $accountingjournal->fetch($objp->accountancy_journal); + $accountstatic->accountancy_journal = $accountingjournal->code; + + print $accountstatic->getNomUrl(1); + } + print ''.price($objp->amount).''; + if ($objp->statut == 0) print ''; + print $object->LibStatut($objp->statut, 5); + if ($objp->statut == 0) print ''; + print '
"; +print "
"; +print "
"; + // End of page llxFooter(); $db->close(); From 8f542a857215b34e5a8f8b10e4c8cf188522f0a4 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 6 Oct 2020 06:56:08 +0000 Subject: [PATCH 047/317] Fixing style errors. --- htdocs/compta/paiement/list.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/paiement/list.php b/htdocs/compta/paiement/list.php index 90f3458918a..e2f3ea9012b 100644 --- a/htdocs/compta/paiement/list.php +++ b/htdocs/compta/paiement/list.php @@ -106,7 +106,7 @@ $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); -if(empty($reshook)) { +if (empty($reshook)) { include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; // All tests are required to be compatible with all browsers @@ -186,7 +186,7 @@ if (GETPOST("orphelins", "alpha")) { } if ($userid) { if ($userid == -1) $sql .= " AND f.fk_user_author IS NULL"; - else $sql .= " AND f.fk_user_author = ".$userid; + else $sql .= " AND f.fk_user_author = ".$userid; } // Search criteria From 7c6c319607b0e9a0c54ec5d25eb64a6b985cb76d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 09:31:54 +0200 Subject: [PATCH 048/317] Trans --- htdocs/langs/en_US/companies.lang | 1 + htdocs/societe/card.php | 12 ++++++------ htdocs/societe/class/societe.class.php | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/htdocs/langs/en_US/companies.lang b/htdocs/langs/en_US/companies.lang index 923ce91d74a..4145d7184c5 100644 --- a/htdocs/langs/en_US/companies.lang +++ b/htdocs/langs/en_US/companies.lang @@ -354,6 +354,7 @@ VATIntraManualCheck=You can also check manually on the European Commission websi ErrorVATCheckMS_UNAVAILABLE=Check not possible. Check service is not provided by the member state (%s). NorProspectNorCustomer=Not prospect, nor customer JuridicalStatus=Legal Entity Type +Workforce=Workforce Staff=Employees ProspectLevelShort=Potential ProspectLevel=Prospect potential diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index 9e6ad514da6..d6a6d202fb0 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -1431,14 +1431,14 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) print ''; } - // Type - Size + // Type - Workforce/Staff print ''.$form->editfieldkey('ThirdPartyType', 'typent_id', '', $object, 0).'browser->layout == 'phone' ? ' colspan="3"': '').'>'."\n"; $sortparam = (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label. print $form->selectarray("typent_id", $formcompany->typent_array(0), $object->typent_id, 0, 0, 0, '', 0, 0, 0, $sortparam); if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print ''; if ($conf->browser->layout == 'phone') print ''; - print ''.$form->editfieldkey('Staff', 'effectif_id', '', $object, 0).'browser->layout == 'phone' ? ' colspan="3"': '').'>'; + print ''.$form->editfieldkey('Workforce', 'effectif_id', '', $object, 0).'browser->layout == 'phone' ? ' colspan="3"': '').'>'; print $form->selectarray("effectif_id", $formcompany->effectif_array(0), $object->effectif_id); if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print ''; @@ -2054,13 +2054,13 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) print ''; print ''; - // Type - Size + // Type - Workforce/Staff print ''.$form->editfieldkey('ThirdPartyType', 'typent_id', '', $object, 0).''; print $form->selectarray("typent_id", $formcompany->typent_array(0), $object->typent_id, 0, 0, 0, '', 0, 0, 0, (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT)); if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print ''; if ($conf->browser->layout == 'phone') print ''; - print ''.$form->editfieldkey('Staff', 'effectif_id', '', $object, 0).''; + print ''.$form->editfieldkey('Workforce', 'effectif_id', '', $object, 0).''; print $form->selectarray("effectif_id", $formcompany->effectif_array(0), $object->effectif_id); if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print ''; @@ -2450,11 +2450,11 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) print ''; print ''; - // Type + Staff + // Type + Workforce/Staff $arr = $formcompany->typent_array(1); $object->typent = $arr[$object->typent_code]; print ''.$langs->trans("ThirdPartyType").''.$object->typent.''; - print ''.$langs->trans("Staff").''.$object->effectif.''; + print ''.$langs->trans("Workforce").''.$object->effectif.''; print ''; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index a8b2caa59c1..686e83f104f 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -161,8 +161,8 @@ class Societe extends CommonObject 'instagram' =>array('type'=>'varchar(255)', 'label'=>'Instagram', 'enabled'=>1, 'visible'=>-1, 'position'=>155), 'facebook' =>array('type'=>'varchar(255)', 'label'=>'Facebook', 'enabled'=>1, 'visible'=>-1, 'position'=>160), 'twitter' =>array('type'=>'varchar(255)', 'label'=>'Twitter', 'enabled'=>1, 'visible'=>-1, 'position'=>165),*/ - 'fk_effectif' =>array('type'=>'integer', 'label'=>'Fk effectif', 'enabled'=>1, 'visible'=>-1, 'position'=>170), - 'fk_typent' =>array('type'=>'integer', 'label'=>'Fk typent', 'enabled'=>1, 'visible'=>-1, 'position'=>175), + 'fk_effectif' =>array('type'=>'integer', 'label'=>'Workforce', 'enabled'=>1, 'visible'=>-1, 'position'=>170), + 'fk_typent' =>array('type'=>'integer', 'label'=>'TypeOfCompany', 'enabled'=>1, 'visible'=>-1, 'position'=>175), 'fk_forme_juridique' =>array('type'=>'integer', 'label'=>'JuridicalStatus', 'enabled'=>1, 'visible'=>-1, 'position'=>180), 'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'Currency', 'enabled'=>1, 'visible'=>-1, 'position'=>185), 'siren' =>array('type'=>'varchar(128)', 'label'=>'Idprof1', 'enabled'=>1, 'visible'=>-1, 'position'=>190), @@ -173,7 +173,7 @@ class Societe extends CommonObject 'idprof6' =>array('type'=>'varchar(128)', 'label'=>'Idprof6', 'enabled'=>1, 'visible'=>-1, 'position'=>207), 'tva_intra' =>array('type'=>'varchar(20)', 'label'=>'Tva intra', 'enabled'=>1, 'visible'=>-1, 'position'=>210), 'capital' =>array('type'=>'double(24,8)', 'label'=>'Capital', 'enabled'=>1, 'visible'=>-1, 'position'=>215), - 'fk_stcomm' =>array('type'=>'integer', 'label'=>'Fk stcomm', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>220), + 'fk_stcomm' =>array('type'=>'integer', 'label'=>'CommercialStatus', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>220), 'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>225), 'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>230), 'prefix_comm' =>array('type'=>'varchar(5)', 'label'=>'Prefix comm', 'enabled'=>'$conf->global->SOCIETE_USEPREFIX', 'visible'=>-1, 'position'=>235), From 42903953758291432917f1853535a7c4ae036b3c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 09:53:10 +0200 Subject: [PATCH 049/317] Fix according to PR #14939 --- htdocs/fichinter/card.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index 650fdc2be15..97dc2626280 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -1625,7 +1625,7 @@ if ($action == 'create') } // Reopen - if ($object->statut > Fichinter::STATUS_CLOSED) + if ($object->statut >= Fichinter::STATUS_CLOSED) { if ($user->rights->ficheinter->creer) { @@ -1645,7 +1645,7 @@ if ($action == 'create') } // create intervention model - if ($conf->global->MAIN_FEATURES_LEVEL >= 2 && $object->statut == Fichinter::STATUS_DRAFT && $user->rights->ficheinter->creer && (count($object->lines) > 0)) { + if ($conf->global->MAIN_FEATURES_LEVEL >= 1 && $object->statut == Fichinter::STATUS_DRAFT && $user->rights->ficheinter->creer && (count($object->lines) > 0)) { print '
'; From 054c58df16dc3c1b67f165bca6ebabc1c9d58438 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 09:53:29 +0200 Subject: [PATCH 050/317] Add currency into the select --- htdocs/compta/accounting-files.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/htdocs/compta/accounting-files.php b/htdocs/compta/accounting-files.php index 2a8a0358744..3b074298b56 100644 --- a/htdocs/compta/accounting-files.php +++ b/htdocs/compta/accounting-files.php @@ -149,7 +149,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Customer invoices if (GETPOST('selectinvoices')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= "SELECT t.rowid as id, t.entity, t.ref, t.paye as paid, t.total as total_ht, t.total_ttc, t.tva as total_vat, t.fk_soc, t.datef as date, t.date_lim_reglement as date_due, 'Invoice' as item, s.nom as thirdparty_name, s.code_client as thirdparty_code, c.code as country_code, s.tva_intra as vatnum, ".PAY_CREDIT." as sens"; + $sql .= "SELECT t.rowid as id, t.entity, t.ref, t.paye as paid, t.total as total_ht, t.total_ttc, t.tva as total_vat, t.multicurrency_code as currency, t.fk_soc, t.datef as date, t.date_lim_reglement as date_due, 'Invoice' as item, s.nom as thirdparty_name, s.code_client as thirdparty_code, c.code as country_code, s.tva_intra as vatnum, ".PAY_CREDIT." as sens"; $sql .= " FROM ".MAIN_DB_PREFIX."facture as t LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = t.fk_soc LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = s.fk_pays"; $sql .= " WHERE datef between ".$wheretail; $sql .= " AND t.entity IN (".($entity == 1 ? '0,1' : $entity).')'; @@ -158,7 +158,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Vendor invoices if (GETPOST('selectsupplierinvoices')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= " SELECT t.rowid as id, t.entity, t.ref, t.paye as paid, t.total_ht, t.total_ttc, t.total_tva as total_vat, t.fk_soc, t.datef as date, t.date_lim_reglement as date_due, 'SupplierInvoice' as item, s.nom as thirdparty_name, s.code_fournisseur as thirdparty_code, c.code as country_code, s.tva_intra as vatnum, ".PAY_DEBIT." as sens"; + $sql .= " SELECT t.rowid as id, t.entity, t.ref, t.paye as paid, t.total_ht, t.total_ttc, t.total_tva as total_vat, t.multicurrency_code as currency, t.fk_soc, t.datef as date, t.date_lim_reglement as date_due, 'SupplierInvoice' as item, s.nom as thirdparty_name, s.code_fournisseur as thirdparty_code, c.code as country_code, s.tva_intra as vatnum, ".PAY_DEBIT." as sens"; $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as t LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = t.fk_soc LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = s.fk_pays"; $sql .= " WHERE datef between ".$wheretail; $sql .= " AND t.entity IN (".($entity == 1 ? '0,1' : $entity).')'; @@ -167,7 +167,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Expense reports if (GETPOST('selectexpensereports')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= " SELECT t.rowid as id, t.entity, t.ref, t.paid, t.total_ht, t.total_ttc, t.total_tva as total_vat, t.fk_user_author as fk_soc, t.date_fin as date, t.date_fin as date_due, 'ExpenseReport' as item, CONCAT(CONCAT(u.lastname, ' '), u.firstname) as thirdparty_name, '' as thirdparty_code, c.code as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; + $sql .= " SELECT t.rowid as id, t.entity, t.ref, t.paid, t.total_ht, t.total_ttc, t.total_tva as total_vat, t.multicurrency_code as currency, t.fk_user_author as fk_soc, t.date_fin as date, t.date_fin as date_due, 'ExpenseReport' as item, CONCAT(CONCAT(u.lastname, ' '), u.firstname) as thirdparty_name, '' as thirdparty_code, c.code as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as t LEFT JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = t.fk_user_author LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = u.fk_country"; $sql .= " WHERE date_fin between ".$wheretail; $sql .= " AND t.entity IN (".($entity == 1 ? '0,1' : $entity).')'; @@ -176,7 +176,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Donations if (GETPOST('selectdonations')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= " SELECT t.rowid as id, t.entity, t.ref, paid, amount as total_ht, amount as total_ttc, 0 as total_vat, 0 as fk_soc, t.datedon as date, t.datedon as date_due, 'Donation' as item, t.societe as thirdparty_name, '' as thirdparty_code, c.code as country_code, '' as vatnum, ".PAY_CREDIT." as sens"; + $sql .= " SELECT t.rowid as id, t.entity, t.ref, paid, amount as total_ht, amount as total_ttc, 0 as total_vat, '".$db->escape($conf->currency)."' as currency, 0 as fk_soc, t.datedon as date, t.datedon as date_due, 'Donation' as item, t.societe as thirdparty_name, '' as thirdparty_code, c.code as country_code, '' as vatnum, ".PAY_CREDIT." as sens"; $sql .= " FROM ".MAIN_DB_PREFIX."don as t LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_country"; $sql .= " WHERE datedon between ".$wheretail; $sql .= " AND t.entity IN (".($entity == 1 ? '0,1' : $entity).')'; @@ -185,7 +185,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Paiements of salaries if (GETPOST('selectpaymentsofsalaries')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= " SELECT t.rowid as id, t.entity, t.label as ref, 1 as paid, amount as total_ht, amount as total_ttc, 0 as total_vat, t.fk_user as fk_soc, t.datep as date, t.dateep as date_due, 'SalaryPayment' as item, CONCAT(CONCAT(u.lastname, ' '), u.firstname) as thirdparty_name, '' as thirdparty_code, c.code as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; + $sql .= " SELECT t.rowid as id, t.entity, t.label as ref, 1 as paid, amount as total_ht, amount as total_ttc, 0 as total_vat, '".$db->escape($conf->currency)."' as currency, t.fk_user as fk_soc, t.datep as date, t.dateep as date_due, 'SalaryPayment' as item, CONCAT(CONCAT(u.lastname, ' '), u.firstname) as thirdparty_name, '' as thirdparty_code, c.code as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as t LEFT JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = t.fk_user LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = u.fk_country"; $sql .= " WHERE datep between ".$wheretail; $sql .= " AND t.entity IN (".($entity == 1 ? '0,1' : $entity).')'; @@ -194,7 +194,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Social contributions if (GETPOST('selectsocialcontributions')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= " SELECT t.rowid as id, t.entity, t.libelle as ref, t.paye as paid, t.amount as total_ht, t.amount as total_ttc, 0 as total_tva, 0 as fk_soc, t.date_ech as date, t.periode as date_due, 'SocialContributions' as item, '' as thirdparty_name, '' as thirdparty_code, '' as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; + $sql .= " SELECT t.rowid as id, t.entity, t.libelle as ref, t.paye as paid, t.amount as total_ht, t.amount as total_ttc, 0 as total_vat, '".$db->escape($conf->currency)."' as currency, 0 as fk_soc, t.date_ech as date, t.periode as date_due, 'SocialContributions' as item, '' as thirdparty_name, '' as thirdparty_code, '' as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; $sql .= " FROM ".MAIN_DB_PREFIX."chargesociales as t"; $sql .= " WHERE t.date_ech between ".$wheretail; $sql .= " AND t.entity IN (".($entity == 1 ? '0,1' : $entity).')'; @@ -203,7 +203,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Various payments if (GETPOST('selectvariouspayment')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= " SELECT t.rowid as id, t.entity, t.label as ref, 1 as paid, t.amount as total_ht, t.amount as total_ttc, 0 as total_tva, 0 as fk_soc, t.datep as date, t.datep as date_due, 'VariousPayment' as item, '' as thirdparty_name, '' as thirdparty_code, '' as country_code, '' as vatnum, sens"; + $sql .= " SELECT t.rowid as id, t.entity, t.label as ref, 1 as paid, t.amount as total_ht, t.amount as total_ttc, 0 as total_vat, '".$db->escape($conf->currency)."' as currency, 0 as fk_soc, t.datep as date, t.datep as date_due, 'VariousPayment' as item, '' as thirdparty_name, '' as thirdparty_code, '' as country_code, '' as vatnum, sens"; $sql .= " FROM ".MAIN_DB_PREFIX."payment_various as t"; $sql .= " WHERE datep between ".$wheretail; $sql .= " AND t.entity IN (".($entity == 1 ? '0,1' : $entity).')'; @@ -211,7 +211,7 @@ if (($action == 'searchfiles' || $action == 'dl')) { // Loan payments if (GETPOST('selectloanspayment')) { if (!empty($sql)) $sql .= " UNION ALL"; - $sql .= " SELECT t.rowid as id, l.entity, l.label as ref, 1 as paid, (t.amount_capital+t.amount_insurance+t.amount_interest) as total_ht, (t.amount_capital+t.amount_insurance+t.amount_interest) as total_ttc, 0 as total_tva, 0 as fk_soc, t.datep as date, t.datep as date_due, 'LoanPayment' as item, '' as thirdparty_name, '' as thirdparty_code, '' as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; + $sql .= " SELECT t.rowid as id, l.entity, l.label as ref, 1 as paid, (t.amount_capital+t.amount_insurance+t.amount_interest) as total_ht, (t.amount_capital+t.amount_insurance+t.amount_interest) as total_ttc, 0 as total_vat, '".$db->escape($conf->currency)."' as currency, 0 as fk_soc, t.datep as date, t.datep as date_due, 'LoanPayment' as item, '' as thirdparty_name, '' as thirdparty_code, '' as country_code, '' as vatnum, ".PAY_DEBIT." as sens"; $sql .= " FROM ".MAIN_DB_PREFIX."payment_loan as t LEFT JOIN ".MAIN_DB_PREFIX."loan as l ON l.rowid = t.fk_loan"; $sql .= " WHERE datep between ".$wheretail; $sql .= " AND l.entity IN (".($entity == 1 ? '0,1' : $entity).')'; From 351f80c540beec56b3bb342927f109fed39d22ee Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 09:57:04 +0200 Subject: [PATCH 051/317] Update index.php --- htdocs/takepos/index.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/htdocs/takepos/index.php b/htdocs/takepos/index.php index 3585d25eee7..06472abe0cd 100644 --- a/htdocs/takepos/index.php +++ b/htdocs/takepos/index.php @@ -865,12 +865,12 @@ if (empty($conf->global->TAKEPOS_HIDE_HEAD_BAR)) {
-multicurrency->enabled)){ ?> +multicurrency->enabled)) { ?> - +
From 050a4770d3aa7bb386971c8904bb04329ced3841 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Tue, 6 Oct 2020 10:04:15 +0200 Subject: [PATCH 052/317] WIP NEW Add clone functionality on miscellaneous payment --- .../bank/class/paymentvarious.class.php | 19 +++++ htdocs/compta/bank/various_payment/card.php | 69 ++++++++++++++++++- htdocs/langs/en_US/banks.lang | 1 + 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/bank/class/paymentvarious.class.php b/htdocs/compta/bank/class/paymentvarious.class.php index 14466915d76..712fb3d8113 100644 --- a/htdocs/compta/bank/class/paymentvarious.class.php +++ b/htdocs/compta/bank/class/paymentvarious.class.php @@ -263,6 +263,7 @@ class PaymentVarious extends CommonObject $this->subledger_account = $obj->subledger_account; $this->accountancy_code = $obj->accountancy_code; $this->fk_project = $obj->fk_project; + $this->accountid = 1; // to clone $this->fk_bank = $obj->fk_bank; $this->fk_user_author = $obj->fk_user_author; $this->fk_user_modif = $obj->fk_user_modif; @@ -338,6 +339,24 @@ class PaymentVarious extends CommonObject $this->fk_user_modif = ''; } + /** + * Check if a miscellaneous payment can be created into database + * + * @return boolean True or false + */ + public function check() + { + $newamount = price2num($this->amount, 'MT'); + + // Validation parametres + if (!$newamount > 0 || empty($this->datep)) + { + return false; + } + + return true; + } + /** * Create in database * diff --git a/htdocs/compta/bank/various_payment/card.php b/htdocs/compta/bank/various_payment/card.php index 371dbaa65e2..67a9590c91d 100644 --- a/htdocs/compta/bank/various_payment/card.php +++ b/htdocs/compta/bank/various_payment/card.php @@ -41,8 +41,9 @@ $langs->loadLangs(array("compta", "banks", "bills", "users", "accountancy", "cat // Get parameters $id = GETPOST('id', 'int'); -$action = GETPOST('action', 'alpha'); -$cancel = GETPOST('cancel', 'aZ09'); +$action = GETPOST('action', 'alpha'); +$confirm = GETPOST('confirm'); +$cancel = GETPOST('cancel', 'aZ09'); $backtopage = GETPOST('backtopage', 'alpha'); $accountid = GETPOST("accountid") > 0 ? GETPOST("accountid", "int") : 0; @@ -225,6 +226,53 @@ if (empty($reshook)) } } +// Action clone object +if ($action == 'confirm_clone' && $confirm != 'yes') { $action = ''; } + +if ($action == 'confirm_clone' && $confirm == 'yes' && ($user->rights->banque->modifier)) +{ + $db->begin(); + + $originalId = $id; + + $object->fetch($id); + + if ($object->id > 0) + { + $object->id = $object->ref = null; + + if (GETPOST('clone_label', 'alphanohtml')) { + $object->label = GETPOST('clone_label', 'alphanohtml'); + } else { + $object->label = $langs->trans("CopyOf").' '.$object->label; + } + + $newdatepayment = dol_mktime(0, 0, 0, GETPOST('clone_date_paymentmonth', 'int'), GETPOST('clone_date_paymentday', 'int'), GETPOST('clone_date_paymentyear', 'int')); + if ($newdatepayment) $object->datep = $newdatepayment; + + if ($object->check()) + { + $id = $object->create($user); + if ($id > 0) + { + $db->commit(); + $db->close(); + + header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id); + exit; + } else { + $id = $originalId; + $db->rollback(); + + setEventMessages($object->error, $object->errors, 'errors'); + } + } + } else { + $db->rollback(); + dol_print_error($db, $object->error); + } +} + /* * View @@ -419,6 +467,17 @@ if ($id) $head = various_payment_prepare_head($object); + // Clone confirmation + if ($action === 'clone') + { + $formquestion = array( + array('type' => 'text', 'name' => 'clone_label', 'label' => $langs->trans("Label"), 'value' => $langs->trans("CopyOf").' '.$object->label), + ); + $formquestion[] = array('type' => 'date', 'name' => 'clone_date_payment', 'label' => $langs->trans("DatePayment"), 'value' => -1); + + print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneVariousPayment', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 220); + } + dol_fiche_head($head, 'card', $langs->trans("VariousPayment"), -1, $object->picto); $morehtmlref = '
'; @@ -542,6 +601,12 @@ if ($id) // TODO // Add button modify + // Clone + if ($user->rights->banque->modifier) + { + print '"; + } + // Delete if (empty($object->rappro)) { diff --git a/htdocs/langs/en_US/banks.lang b/htdocs/langs/en_US/banks.lang index 3cfa7ad2538..ffe5ee9ca1c 100644 --- a/htdocs/langs/en_US/banks.lang +++ b/htdocs/langs/en_US/banks.lang @@ -168,6 +168,7 @@ ShowVariousPayment=Show miscellaneous payment AddVariousPayment=Add miscellaneous payment VariousPaymentId=Miscellaneous payment ID VariousPaymentLabel=Miscellaneous payment label +ConfirmCloneVariousPayment=Confirm the clone of a miscellaneous payment SEPAMandate=SEPA mandate YourSEPAMandate=Your SEPA mandate FindYourSEPAMandate=This is your SEPA mandate to authorize our company to make direct debit order to your bank. Return it signed (scan of the signed document) or send it by mail to From 38acd83f4d3b0997ef653576b37e144401f58b41 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 12:17:33 +0200 Subject: [PATCH 053/317] Review some titles and tooltip help to be more clear. --- htdocs/accountancy/bookkeeping/list.php | 17 +++++++++-------- .../accountancy/bookkeeping/listbyaccount.php | 15 +++++++++------ htdocs/compta/accounting-files.php | 3 +++ htdocs/fourn/facture/document.php | 19 ++++++++----------- htdocs/langs/en_US/accountancy.lang | 4 +++- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index d5603a7a075..f2c7d3ea548 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -529,7 +529,7 @@ if ($action == 'export_file' && $user->rights->accounting->mouvements->export) { $formother = new FormOther($db); $formfile = new FormFile($db); -$title_page = $langs->trans("Bookkeeping"); +$title_page = $langs->trans("Operations").' - '.$langs->trans("Journals"); // Count total nb of records $nbtotalofrecords = ''; @@ -613,17 +613,17 @@ if ($action == 'delbookkeepingyear') { } //$param=''; param started before -if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.$contextpage; -if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.$limit; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); +if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); print '
'; print ''; print ''; -if ($optioncss != '') print ''; +if ($optioncss != '') print ''; print ''; -print ''; -print ''; -print ''; +print ''; +print ''; +print ''; if (count($filter)) $buttonLabel = $langs->trans("ExportFilteredList"); else $buttonLabel = $langs->trans("ExportList"); @@ -638,7 +638,8 @@ $newcardbutton .= ''.$langs->trans("I $newcardbutton .= dolGetButtonTitle($buttonLabel, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', 'fa fa-file-export paddingleft', $_SERVER["PHP_SELF"].'?action=export_file'.($param ? '&'.$param : ''), $user->rights->accounting->mouvements->export); -// $newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param); +$newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param, '', 1, array('morecss'=>'btnTitleSelected')); +$newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param, '', 1, array('morecss'=>'marginleftonly')); $url = './card.php?action=create'; if (!empty($socid)) $url .= '&socid='.$socid; diff --git a/htdocs/accountancy/bookkeeping/listbyaccount.php b/htdocs/accountancy/bookkeeping/listbyaccount.php index 58a696be1ae..5b14f71cf51 100644 --- a/htdocs/accountancy/bookkeeping/listbyaccount.php +++ b/htdocs/accountancy/bookkeeping/listbyaccount.php @@ -293,7 +293,7 @@ $formfile = new FormFile($db); $formother = new FormOther($db); $form = new Form($db); -$title_page = $langs->trans("Bookkeeping").' '.strtolower($langs->trans("By")).' '.strtolower($langs->trans("AccountAccounting")); +$title_page = $langs->trans("Operations").' - '.$langs->trans("VueByAccountAccounting").' ('.$langs->trans("Bookkeeping").')'; llxHeader('', $title_page); @@ -369,16 +369,19 @@ if ($optioncss != '') print ''; print ''; print ''; -print ''; -// $newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param); +$newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param); +$newcardbutton .= dolGetButtonTitle($langs->trans('VueByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param, '', 1, array('morecss'=>'marginleftonly btnTitleSelected')); + +$newcardbutton .= '   '; + $newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', './card.php?action=create'); if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); -print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $result, $nbtotalofrecords, 'title_accountancy', 0, $viewflat.$newcardbutton, '', $limit); +print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $result, $nbtotalofrecords, 'title_accountancy', 0, $viewflat.$newcardbutton, '', $limit, 0, 0, 1); $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields @@ -696,10 +699,10 @@ while ($i < min($num, $limit)) print ''; if (empty($line->date_export)) { if ($user->rights->accounting->mouvements->creer) { - print ''.img_edit().''; + print ''.img_edit().''; } if ($user->rights->accounting->mouvements->supprimer) { - print ' '.img_delete().''; + print '   '.img_delete().''; } } print ''; diff --git a/htdocs/compta/accounting-files.php b/htdocs/compta/accounting-files.php index 3b074298b56..61c0b855c75 100644 --- a/htdocs/compta/accounting-files.php +++ b/htdocs/compta/accounting-files.php @@ -525,6 +525,9 @@ dol_fiche_head($head, 'AccountancyFiles'); print ''."\n"; print ''; +print ''.$langs->trans("ExportAccountingSourceDocHelp", $langs->transnoentitiesnoconv("Accounting"), $langs->transnoentitiesnoconv("Journals")).'
'; +print '
'; + print $langs->trans("ReportPeriod").': '.$form->selectDate($date_start, 'date_start', 0, 0, 0, "", 1, 1, 0); print ' - '.$form->selectDate($date_stop, 'date_stop', 0, 0, 0, "", 1, 1, 0)."\n"; diff --git a/htdocs/fourn/facture/document.php b/htdocs/fourn/facture/document.php index 39bb12c1ed1..2887298cae7 100644 --- a/htdocs/fourn/facture/document.php +++ b/htdocs/fourn/facture/document.php @@ -215,15 +215,15 @@ if ($object->id > 0) // Amount Local Taxes //TODO: Place into a function to control showing by country or study better option - if ($societe->localtax1_assuj == "1") //Localtax1 + if ($mysoc->localtax1_assuj == "1") //Localtax1 { - print ''.$langs->transcountry("AmountLT1", $societe->country_code).''; + print ''.$langs->transcountry("AmountLT1", $mysoc->country_code).''; print ''.price($object->total_localtax1, 1, $langs, 0, -1, -1, $conf->currency).''; print ''; } - if ($societe->localtax2_assuj == "1") //Localtax2 + if ($mysoc->localtax2_assuj == "1") //Localtax2 { - print ''.$langs->transcountry("AmountLT2", $societe->country_code).''; + print ''.$langs->transcountry("AmountLT2", $mysoc->country_code).''; print ''.price($object->total_localtax2, 1, $langs, 0, -1, -1, $conf->currency).''; print ''; } @@ -252,16 +252,14 @@ if ($object->id > 0) $permission = $user->rights->fournisseur->facture->creer; $permtoedit = $user->rights->fournisseur->facture->creer; $param = '&facid='.$object->id; - + + $defaulttpldir = '/core/tpl'; $dirtpls = array_merge($conf->modules_parts['tpl'], array($defaulttpldir)); foreach ($dirtpls as $module => $reldir) { - if (!empty($module)) - { + if (!empty($module)) { $tpl = dol_buildpath($reldir.'/document_actions_post_headers.tpl.php'); - } - else - { + } else { $tpl = DOL_DOCUMENT_ROOT.$reldir.'/document_actions_post_headers.tpl.php'; } @@ -272,7 +270,6 @@ if ($object->id > 0) } if ($res) break; } - } else { print $langs->trans('ErrorUnknown'); } diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang index 2897c62333d..b2eb665d027 100644 --- a/htdocs/langs/en_US/accountancy.lang +++ b/htdocs/langs/en_US/accountancy.lang @@ -44,7 +44,9 @@ CountriesInEEC=Countries in EEC CountriesNotInEEC=Countries not in EEC CountriesInEECExceptMe=Countries in EEC except %s CountriesExceptMe=All countries except %s -AccountantFiles=Export accounting documents +AccountantFiles=Export source documents +ExportAccountingSourceDocHelp=With this tool, you can export the source events (list and PDFs) that were used to generate your accountancy. To export your journals, use the menu entry %s - %s. +VueByAccountAccounting=View by accounting account MainAccountForCustomersNotDefined=Main accounting account for customers not defined in setup MainAccountForSuppliersNotDefined=Main accounting account for vendors not defined in setup From 1c38379622b9808d600b9c967f3be46ddc2153da Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 12:22:58 +0200 Subject: [PATCH 054/317] Better message --- htdocs/accountancy/bookkeeping/card.php | 2 +- htdocs/accountancy/bookkeeping/list.php | 2 +- htdocs/accountancy/bookkeeping/listbyaccount.php | 2 +- htdocs/langs/en_US/accountancy.lang | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index ef105b6709a..8ca880de25f 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -328,7 +328,7 @@ llxHeader('', $langs->trans("CreateMvts")); // Confirmation to delete the command if ($action == 'delete') { - $formconfirm = $html->formconfirm($_SERVER["PHP_SELF"].'?id='.$id.'&mode='.$mode, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt'), 'confirm_delete', '', 0, 1); + $formconfirm = $html->formconfirm($_SERVER["PHP_SELF"].'?id='.$id.'&mode='.$mode, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt', $langs->transnoentitiesnoconv("RegistrationInAccounting")), 'confirm_delete', '', 0, 1); print $formconfirm; } diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index f2c7d3ea548..3acd0ddd4d9 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -608,7 +608,7 @@ if ($action == 'delbookkeepingyear') { 'default' => $deljournal ); - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt'), 'delbookkeepingyearconfirm', $form_question, '', 1, 300); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt', $langs->transnoentitiesnoconv("RegistrationInAccounting")), 'delbookkeepingyearconfirm', $form_question, '', 1, 300); print $formconfirm; } diff --git a/htdocs/accountancy/bookkeeping/listbyaccount.php b/htdocs/accountancy/bookkeeping/listbyaccount.php index 5b14f71cf51..32121ae6c02 100644 --- a/htdocs/accountancy/bookkeeping/listbyaccount.php +++ b/htdocs/accountancy/bookkeeping/listbyaccount.php @@ -357,7 +357,7 @@ if ($action == 'delbookkeepingyear') { 'default' => $deljournal ); - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt'), 'delbookkeepingyearconfirm', $form_question, '', 1, 300); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt', $langs->transnoentitiesnoconv("RegistrationInAccounting")), 'delbookkeepingyearconfirm', $form_question, '', 1, 300); print $formconfirm; } diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang index b2eb665d027..9ad088e4c31 100644 --- a/htdocs/langs/en_US/accountancy.lang +++ b/htdocs/langs/en_US/accountancy.lang @@ -215,8 +215,8 @@ DeleteMvt=Delete Ledger lines DelMonth=Month to delete DelYear=Year to delete DelJournal=Journal to delete -ConfirmDeleteMvt=This will delete all lines of the Ledger for the year/month and/or from a specific journal (At least one criterion is required). You will have to reuse the feature 'Registration in accounting' to have the deleted record back in the ledger. -ConfirmDeleteMvtPartial=This will delete the transaction from the Ledger (all lines related to same transaction will be deleted) +ConfirmDeleteMvt=This will delete all operation lines of the accounting for the year/month and/or for a specific journal (At least one criterion is required). You will have to reuse the feature '%s' to have the deleted record back in the ledger. +ConfirmDeleteMvtPartial=This will delete the transaction from the accounting (all operation lines related to the same transaction will be deleted) FinanceJournal=Finance journal ExpenseReportsJournal=Expense reports journal DescFinanceJournal=Finance journal including all the types of payments by bank account From a32456afc509deea3610ce7fe05afc2cd6112b2e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 12:35:18 +0200 Subject: [PATCH 055/317] Update interface_99_modMyModule_MyModuleTriggers.class.php --- .../interface_99_modMyModule_MyModuleTriggers.class.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php index add80d58af3..be6d42047ce 100644 --- a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php +++ b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php @@ -102,12 +102,8 @@ class InterfaceMyModuleTriggers extends DolibarrTriggers // Put here code you want to execute when a Dolibarr business events occurs. // Data and type of action are stored into $object and $action - /** - * new method to handle triggers - * you can now create a method for the interface - * this method should be named like the trigger in camelCase - * for example : COMPANY_CREATE => public function companyCreate($action, $object, User $user, Translate $langs, Conf $conf) - */ + // You can isolate code for each action in a separate method: this method should be named like the trigger in camelCase. + // For example : COMPANY_CREATE => public function companyCreate($action, $object, User $user, Translate $langs, Conf $conf) $methodName = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($action))))); $callback = array($this, $methodName); if (is_callable($callback)){ @@ -118,6 +114,7 @@ class InterfaceMyModuleTriggers extends DolibarrTriggers return call_user_func($callback, $action, $object, $user, $langs, $conf); }; + // Or you can execute some code here switch ($action) { // Users //case 'USER_CREATE': From 3ceb5c217f48af4f221447ce8398d8838a412d1b Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Tue, 6 Oct 2020 12:56:28 +0200 Subject: [PATCH 056/317] Show count on project overview tab --- htdocs/core/lib/project.lib.php | 68 ++++++++++++++++++--------- htdocs/projet/class/project.class.php | 39 +++++++++++++++ 2 files changed, 85 insertions(+), 22 deletions(-) diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index 782e18151b2..91cf281c83c 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -30,23 +30,23 @@ require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; /** * Prepare array with list of tabs * - * @param Object $object Object related to tabs - * @return array Array of tabs to show + * @param Project $object Object related to tabs + * @return array Array of tabs to show */ -function project_prepare_head($object) +function project_prepare_head(Project $project) { global $db, $langs, $conf, $user; $h = 0; $head = array(); - $head[$h][0] = DOL_URL_ROOT.'/projet/card.php?id='.$object->id; + $head[$h][0] = DOL_URL_ROOT.'/projet/card.php?id='.$project->id; $head[$h][1] = $langs->trans("Project"); $head[$h][2] = 'project'; $h++; - $nbContact = count($object->liste_contact(-1, 'internal')) + count($object->liste_contact(-1, 'external')); - $head[$h][0] = DOL_URL_ROOT.'/projet/contact.php?id='.$object->id; + $nbContact = count($project->liste_contact(-1, 'internal')) + count($project->liste_contact(-1, 'external')); + $head[$h][0] = DOL_URL_ROOT.'/projet/contact.php?id='.$project->id; $head[$h][1] = $langs->trans("ProjectContact"); if ($nbContact > 0) $head[$h][1] .= ''.$nbContact.''; $head[$h][2] = 'contact'; @@ -55,12 +55,12 @@ function project_prepare_head($object) if (empty($conf->global->PROJECT_HIDE_TASKS)) { // Then tab for sub level of projet, i mean tasks - $head[$h][0] = DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id; + $head[$h][0] = DOL_URL_ROOT.'/projet/tasks.php?id='.$project->id; $head[$h][1] = $langs->trans("Tasks"); require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; $taskstatic = new Task($db); - $nbTasks = count($taskstatic->getTasksArray(0, 0, $object->id, 0, 0)); + $nbTasks = count($taskstatic->getTasksArray(0, 0, $project->id, 0, 0)); if ($nbTasks > 0) $head[$h][1] .= ''.($nbTasks).''; $head[$h][2] = 'tasks'; $h++; @@ -71,7 +71,7 @@ function project_prepare_head($object) //$sql .= " WHERE t.fk_user = u.rowid AND t.fk_task = pt.rowid"; $sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t, ".MAIN_DB_PREFIX."projet_task as pt"; $sql .= " WHERE t.fk_task = pt.rowid"; - $sql .= " AND pt.fk_projet =".$object->id; + $sql .= " AND pt.fk_projet =".$project->id; $resql = $db->query($sql); if ($resql) { @@ -79,7 +79,7 @@ function project_prepare_head($object) if ($obj) $nbTimeSpent = 1; } else dol_print_error($db); - $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/time.php?withproject=1&projectid='.$object->id; + $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/time.php?withproject=1&projectid='.$project->id; $head[$h][1] = $langs->trans("TimeSpent"); if ($nbTimeSpent > 0) $head[$h][1] .= '...'; $head[$h][2] = 'timespent'; @@ -91,8 +91,32 @@ function project_prepare_head($object) || !empty($conf->facture->enabled) || !empty($conf->contrat->enabled) || !empty($conf->ficheinter->enabled) || !empty($conf->agenda->enabled) || !empty($conf->deplacement->enabled)) { - $head[$h][0] = DOL_URL_ROOT.'/projet/element.php?id='.$object->id; + $count = 0; + + if (!empty($conf->propal->enabled)) $count += $project->getElementCount('propal', 'propal'); + if (!empty($conf->commande->enabled)) $count += $project->getElementCount('order', 'commande'); + if (!empty($conf->facture->enabled)) $count += $project->getElementCount('invoice', 'facture'); + if (!empty($conf->facture->enabled)) $count += $project->getElementCount('invoice_predefined', 'facture_rec'); + if (!empty($conf->supplier_proposal->enabled)) $count += $project->getElementCount('proposal_supplier', 'supplier_proposal'); + if (!empty($conf->supplier_order->enabled)) $count += $project->getElementCount('order_supplier', 'commande_fournisseur'); + if (!empty($conf->supplier_invoice->enabled)) $count += $project->getElementCount('invoice_supplier', 'facture_fourn'); + if (!empty($conf->contrat->enabled)) $count += $project->getElementCount('contract', 'contrat'); + if (!empty($conf->ficheinter->enabled)) $count += $project->getElementCount('intervention', 'fichinter'); + if (!empty($conf->expedition->enabled)) $count += $project->getElementCount('shipping', 'expedition'); + if (!empty($conf->mrp->enabled)) $count += $project->getElementCount('mrp', 'mrp_mo', 'fk_project'); + if (!empty($conf->deplacement->enabled)) $count += $project->getElementCount('trip', 'deplacement'); + if (!empty($conf->expensereport->enabled)) $count += $project->getElementCount('expensereport', 'expensereport'); + if (!empty($conf->don->enabled)) $count += $project->getElementCount('donation', 'don'); + if (!empty($conf->loan->enabled)) $count += $project->getElementCount('loan', 'loan'); + if (!empty($conf->tax->enabled)) $count += $project->getElementCount('chargesociales', 'chargesociales'); + if (!empty($conf->projet->enabled)) $count += $project->getElementCount('project_task', 'projet_task'); + if (!empty($conf->stock->enabled)) $count += $project->getElementCount('stock_mouvement', 'stock'); + if (!empty($conf->salaries->enabled)) $count += $project->getElementCount('salaries', 'payment_salary'); + if (!empty($conf->banque->enabled)) $count += $project->getElementCount('variouspayment', 'payment_various'); + + $head[$h][0] = DOL_URL_ROOT.'/projet/element.php?id='.$project->id; $head[$h][1] = $langs->trans("ProjectOverview"); + if ($count > 0) $head[$h][1] .= ''.$count.''; $head[$h][2] = 'element'; $h++; } @@ -101,15 +125,15 @@ function project_prepare_head($object) // Entries must be declared in modules descriptor with line // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab // $this->tabs = array('entity:-tabname); to remove a tab - complete_head_from_modules($conf, $langs, $object, $head, $h, 'project'); + complete_head_from_modules($conf, $langs, $project, $head, $h, 'project'); if (empty($conf->global->MAIN_DISABLE_NOTES_TAB)) { $nbNote = 0; - if (!empty($object->note_private)) $nbNote++; - if (!empty($object->note_public)) $nbNote++; - $head[$h][0] = DOL_URL_ROOT.'/projet/note.php?id='.$object->id; + if (!empty($project->note_private)) $nbNote++; + if (!empty($project->note_public)) $nbNote++; + $head[$h][0] = DOL_URL_ROOT.'/projet/note.php?id='.$project->id; $head[$h][1] = $langs->trans('Notes'); if ($nbNote > 0) $head[$h][1] .= ''.$nbNote.''; $head[$h][2] = 'notes'; @@ -118,10 +142,10 @@ function project_prepare_head($object) require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; - $upload_dir = $conf->projet->dir_output."/".dol_sanitizeFileName($object->ref); + $upload_dir = $conf->projet->dir_output."/".dol_sanitizeFileName($project->ref); $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); - $nbLinks = Link::count($db, $object->element, $object->id); - $head[$h][0] = DOL_URL_ROOT.'/projet/document.php?id='.$object->id; + $nbLinks = Link::count($db, $project->element, $project->id); + $head[$h][0] = DOL_URL_ROOT.'/projet/document.php?id='.$project->id; $head[$h][1] = $langs->trans('Documents'); if (($nbFiles + $nbLinks) > 0) $head[$h][1] .= ''.($nbFiles + $nbLinks).''; $head[$h][2] = 'document'; @@ -130,15 +154,15 @@ function project_prepare_head($object) // Manage discussion if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_PROJECT)) { - $nbComments = $object->getNbComments(); - $head[$h][0] = DOL_URL_ROOT.'/projet/comment.php?id='.$object->id; + $nbComments = $project->getNbComments(); + $head[$h][0] = DOL_URL_ROOT.'/projet/comment.php?id='.$project->id; $head[$h][1] = $langs->trans("CommentLink"); if ($nbComments > 0) $head[$h][1] .= ''.$nbComments.''; $head[$h][2] = 'project_comment'; $h++; } - $head[$h][0] = DOL_URL_ROOT.'/projet/info.php?id='.$object->id; + $head[$h][0] = DOL_URL_ROOT.'/projet/info.php?id='.$project->id; $head[$h][1] .= $langs->trans("Events"); if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { @@ -148,7 +172,7 @@ function project_prepare_head($object) $head[$h][2] = 'agenda'; $h++; - complete_head_from_modules($conf, $langs, $object, $head, $h, 'project', 'remove'); + complete_head_from_modules($conf, $langs, $project, $head, $h, 'project', 'remove'); return $head; } diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 30a2a0c242b..83bd4e3b2a4 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -806,6 +806,45 @@ class Project extends CommonObject } } + /** + * Return the count of a type of linked elements of this project + * + * @param string $type The type of the linked elements (e.g. 'propal', 'order', 'invoice', 'order_supplier', 'invoice_supplier') + * @param string $tablename The name of table associated of the type + * @param string $projectkey (optional) Equivalent key to fk_projet for actual type + * @return integer The count of the linked elements (the count is zero on request error too) + */ + public function getElementCount($type, $tablename, $projectkey = 'fk_projet') + { + if ($this->id <= 0) return 0; + + if ($type == 'agenda') { + $sql = "SELECT COUNT(id) as nb FROM ".MAIN_DB_PREFIX."actioncomm WHERE fk_project = ".$this->id." AND entity IN (".getEntity('agenda').")"; + } elseif ($type == 'expensereport') { + $sql = "SELECT COUNT(ed.rowid) as nb FROM ".MAIN_DB_PREFIX."expensereport as e, ".MAIN_DB_PREFIX."expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND e.entity IN (".getEntity('expensereport').") AND ed.fk_projet = ".$this->id; + } elseif ($type == 'project_task') { + $sql = "SELECT DISTINCT COUNT(pt.rowid) as nb FROM ".MAIN_DB_PREFIX."projet_task as pt WHERE pt.fk_projet = ".$this->id; + } elseif ($type == 'project_task_time') { // Case we want to duplicate line foreach user + $sql = "SELECT DISTINCT COUNT(pt.rowid) as nb FROM ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet = ".$this->id; + } elseif ($type == 'stock_mouvement') { + $sql = 'SELECT COUNT(ms.rowid) as nb FROM '.MAIN_DB_PREFIX."stock_mouvement as ms, ".MAIN_DB_PREFIX."entrepot as e WHERE e.rowid = ms.fk_entrepot AND e.entity IN (".getEntity('stock').") AND ms.origintype = 'project' AND ms.fk_origin = ".$this->id." AND ms.type_mouvement = 1"; + } elseif ($type == 'loan') { + $sql = 'SELECT COUNT(l.rowid) as nb FROM '.MAIN_DB_PREFIX."loan as l WHERE l.entity IN (".getEntity('loan').") AND l.fk_projet = ".$this->id; + } else { + $sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX.$tablename." WHERE ".$projectkey." = ".$this->id." AND entity IN (".getEntity($type).")"; + } + + $result = $this->db->query($sql); + + if (!$result) return 0; + + $obj = $this->db->fetch_object($result); + + $this->db->free($result); + + return $obj->nb; + } + /** * Delete tasks with no children first, then task with children recursively * From 4701656d950c6f3e9ac318b15e1036e6a57b4519 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 6 Oct 2020 13:08:20 +0200 Subject: [PATCH 057/317] Fix look and field v13 --- htdocs/accountancy/bookkeeping/list.php | 34 +++++++------------ .../accountancy/bookkeeping/listbyaccount.php | 18 ++++++---- htdocs/core/menus/standard/auguria.lib.php | 2 +- htdocs/core/menus/standard/eldy.lib.php | 2 +- htdocs/core/menus/standard/empty.php | 4 +-- htdocs/langs/en_US/accountancy.lang | 2 +- 6 files changed, 29 insertions(+), 33 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index 3acd0ddd4d9..642d47b09e4 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -108,7 +108,7 @@ $hookmanager->initHooks(array('bookkeepinglist')); $formaccounting = new FormAccounting($db); $form = new Form($db); -if (!in_array($action, array('export_file', 'delmouv', 'delmouvconfirm')) && !isset($_POST['begin']) && !isset($_GET['begin']) && !isset($_POST['formfilteraction']) && GETPOST('page', 'int') == '' && !GETPOST('noreset', 'int') && $user->rights->accounting->mouvements->export) +if (!in_array($action, array('export_file', 'delmouv', 'delmouvconfirm')) && !GETPOSTISSET('begin') && !isset($_POST['formfilteraction']) && GETPOST('page', 'int') == '' && !GETPOST('noreset', 'int') && $user->rights->accounting->mouvements->export) { if (empty($search_date_start) && empty($search_date_end) && !GETPOSTISSET('restore_lastsearch_values')) { @@ -671,12 +671,10 @@ if (!empty($arrayfields['t.doc_date']['checked'])) { print ''; print '
'; - print $langs->trans('From').' '; - print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1); + print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); print '
'; print '
'; - print $langs->trans('to').' '; - print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1); + print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); print '
'; print ''; } @@ -704,25 +702,25 @@ if (!empty($arrayfields['t.subledger_account']['checked'])) { print ''; print '
'; - print $langs->trans('From').' '; // TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because it does not // use setup of keypress to select thirdparty and this hang browser on large database. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { + print $langs->trans('From').' '; print $formaccounting->select_auxaccount($search_accountancy_aux_code_start, 'search_accountancy_aux_code_start', 1); } else { - print ''; + print ''; } print '
'; print '
'; - print $langs->trans('to').' '; // TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because it does not // use setup of keypress to select thirdparty and this hang browser on large database. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { + print $langs->trans('to').' '; print $formaccounting->select_auxaccount($search_accountancy_aux_code_end, 'search_accountancy_aux_code_end', 1); } else { - print ''; + print ''; } print '
'; print ''; @@ -772,12 +770,10 @@ if (!empty($arrayfields['t.date_creation']['checked'])) { print ''; print '
'; - print $langs->trans('From').' '; - print $form->selectDate($search_date_creation_start, 'date_creation_start', 0, 0, 1); + print $form->selectDate($search_date_creation_start, 'date_creation_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); print '
'; print '
'; - print $langs->trans('to').' '; - print $form->selectDate($search_date_creation_end, 'date_creation_end', 0, 0, 1); + print $form->selectDate($search_date_creation_end, 'date_creation_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); print '
'; print ''; } @@ -786,12 +782,10 @@ if (!empty($arrayfields['t.tms']['checked'])) { print ''; print '
'; - print $langs->trans('From').' '; - print $form->selectDate($search_date_modification_start, 'date_modification_start', 0, 0, 1); + print $form->selectDate($search_date_modification_start, 'date_modification_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); print '
'; print '
'; - print $langs->trans('to').' '; - print $form->selectDate($search_date_modification_end, 'date_modification_end', 0, 0, 1); + print $form->selectDate($search_date_modification_end, 'date_modification_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); print '
'; print ''; } @@ -800,12 +794,10 @@ if (!empty($arrayfields['t.date_export']['checked'])) { print ''; print '
'; - print $langs->trans('From').' '; - print $form->selectDate($search_date_export_start, 'date_export_start', 0, 0, 1); + print $form->selectDate($search_date_export_start, 'date_export_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); print '
'; print '
'; - print $langs->trans('to').' '; - print $form->selectDate($search_date_export_end, 'date_export_end', 0, 0, 1); + print $form->selectDate($search_date_export_end, 'date_export_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); print '
'; print ''; } diff --git a/htdocs/accountancy/bookkeeping/listbyaccount.php b/htdocs/accountancy/bookkeeping/listbyaccount.php index 32121ae6c02..4ed055be0b1 100644 --- a/htdocs/accountancy/bookkeeping/listbyaccount.php +++ b/htdocs/accountancy/bookkeeping/listbyaccount.php @@ -54,6 +54,7 @@ if ($search_accountancy_code_end == - 1) { } $search_doc_ref = GETPOST('search_doc_ref', 'alpha'); $search_label_operation = GETPOST('search_label_operation', 'alpha'); +$search_mvt_num = GETPOST('search_mvt_num', 'int'); $search_direction = GETPOST('search_direction', 'alpha'); $search_ledger_code = GETPOST('search_ledger_code', 'alpha'); $search_debit = GETPOST('search_debit', 'alpha'); @@ -85,7 +86,7 @@ $hookmanager->initHooks(array('bookkeepingbyaccountlist')); $formaccounting = new FormAccounting($db); $form = new Form($db); -if (empty($search_date_start) && empty($search_date_end) && GETPOSTISSET('search_date_startday') && GETPOSTISSET('search_date_startmonth') && GETPOSTISSET('search_date_starthour')) { +if (empty($search_date_start) && empty($search_date_end) && !GETPOSTISSET('search_date_startday') && !GETPOSTISSET('search_date_startmonth') && !GETPOSTISSET('search_date_starthour')) { $sql = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear "; $sql .= " where date_start < '".$db->idate(dol_now())."' and date_end > '".$db->idate(dol_now())."'"; $sql .= $db->plimit(1); @@ -148,6 +149,7 @@ if (empty($reshook)) $search_label_account = ''; $search_doc_ref = ''; $search_label_operation = ''; + $search_mvt_num = ''; $search_direction = ''; $search_ledger_code = ''; $search_date_start = ''; @@ -192,6 +194,10 @@ if (empty($reshook)) $filter['t.label_compte'] = $search_label_account; $param .= '&search_label_compte=' . urlencode($search_label_account); } + if (!empty($search_mvt_num)) { + $filter['t.piece_num'] = $search_mvt_num; + $param .= '&search_mvt_num=' . urlencode($search_mvt_num); + } if (!empty($search_doc_ref)) { $filter['t.doc_ref'] = $search_doc_ref; $param .= '&search_doc_ref=' . urlencode($search_doc_ref); @@ -396,10 +402,10 @@ $moreforfilter = ''; // Accountancy account $moreforfilter .= '
'; $moreforfilter .= $langs->trans('AccountAccounting').': '; -$moreforfilter .= '
'; +$moreforfilter .= '
'; $moreforfilter .= $langs->trans('From').' '; $moreforfilter .= $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', 1, array(), 1, 1, 'maxwidth200'); -$moreforfilter .= $langs->trans('to').' '; +$moreforfilter .= ' '.$langs->trans('to').' '; $moreforfilter .= $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', 1, array(), 1, 1, 'maxwidth200'); $moreforfilter .= '
'; $moreforfilter .= '
'; @@ -427,12 +433,10 @@ if (!empty($arrayfields['t.code_journal']['checked'])) { if (!empty($arrayfields['t.doc_date']['checked'])) { print ''; print '
'; - print $langs->trans('From') . ': '; - print $form->selectDate($search_date_start, 'search_date_start', 0, 0, 1); + print $form->selectDate($search_date_start, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); print '
'; print '
'; - print $langs->trans('to') . ': '; - print $form->selectDate($search_date_end, 'search_date_end', 0, 0, 1); + print $form->selectDate($search_date_end, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); print '
'; print ''; } diff --git a/htdocs/core/menus/standard/auguria.lib.php b/htdocs/core/menus/standard/auguria.lib.php index 8bde6d6fa61..a124759faa8 100644 --- a/htdocs/core/menus/standard/auguria.lib.php +++ b/htdocs/core/menus/standard/auguria.lib.php @@ -551,7 +551,7 @@ function print_left_auguria_menu($db, $menu_array_before, $menu_array_after, &$t { print ''; - /* + /* * Barre d'actions */ - print '
'; + print '
'; - if ($object->statut < Deplacement::STATUS_REFUNDED) // if not refunded - { - if ($user->rights->deplacement->creer) - { - print ''.$langs->trans('Modify').''; - } else { - print ''.$langs->trans('Modify').''; - } - } + if ($object->statut < Deplacement::STATUS_REFUNDED) // if not refunded + { + if ($user->rights->deplacement->creer) + { + print ''.$langs->trans('Modify').''; + } else { + print ''.$langs->trans('Modify').''; + } + } - if ($object->statut == Deplacement::STATUS_DRAFT) // if draft - { - if ($user->rights->deplacement->creer) - { - print ''.$langs->trans('Validate').''; - } else { - print ''.$langs->trans('Validate').''; - } - } + if ($object->statut == Deplacement::STATUS_DRAFT) // if draft + { + if ($user->rights->deplacement->creer) + { + print ''.$langs->trans('Validate').''; + } else { + print ''.$langs->trans('Validate').''; + } + } - if ($object->statut == Deplacement::STATUS_VALIDATED) // if validated - { - if ($user->rights->deplacement->creer) - { - print ''.$langs->trans('ClassifyRefunded').''; - } else { - print ''.$langs->trans('ClassifyRefunded').''; - } - } + if ($object->statut == Deplacement::STATUS_VALIDATED) // if validated + { + if ($user->rights->deplacement->creer) + { + print ''.$langs->trans('ClassifyRefunded').''; + } else { + print ''.$langs->trans('ClassifyRefunded').''; + } + } - if ($user->rights->deplacement->supprimer) - { - print ''.$langs->trans('Delete').''; - } else { - print ''.$langs->trans('Delete').''; - } + if ($user->rights->deplacement->supprimer) + { + print ''.$langs->trans('Delete').''; + } else { + print ''.$langs->trans('Delete').''; + } - print '
'; - } - } else { - dol_print_error($db); - } + print '
'; + } + } else { + dol_print_error($db); + } } // End of page diff --git a/htdocs/contact/list.php b/htdocs/contact/list.php index 8199a62201b..4d30977bf6a 100644 --- a/htdocs/contact/list.php +++ b/htdocs/contact/list.php @@ -165,7 +165,7 @@ foreach ($object->fields as $key => $val) } // Add none object fields for "search in all" -if (empty($conf->global->SOCIETE_DISABLE_CONTACTS)) { +if (empty($conf->global->SOCIETE_DISABLE_CONTACTS)) { $fieldstosearchall['s.nom'] = "ThirdParty"; } @@ -186,7 +186,7 @@ foreach ($object->fields as $key => $val) { // Add none object fields to fields for list $arrayfields['country.code_iso'] = array('label'=>"Country", 'position'=>22, 'checked'=>0); -if (empty($conf->global->SOCIETE_DISABLE_CONTACTS)) { +if (empty($conf->global->SOCIETE_DISABLE_CONTACTS)) { $arrayfields['s.nom'] = array('label'=>"ThirdParty", 'position'=>25, 'checked'=>1); } diff --git a/htdocs/core/boxes/box_activity.php b/htdocs/core/boxes/box_activity.php index 0546f907b64..1585241b843 100644 --- a/htdocs/core/boxes/box_activity.php +++ b/htdocs/core/boxes/box_activity.php @@ -30,413 +30,413 @@ include_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php'; */ class box_activity extends ModeleBoxes { - public $boxcode = "activity"; - public $boximg = "object_bill"; - public $boxlabel = 'BoxGlobalActivity'; - public $depends = array("facture"); + public $boxcode = "activity"; + public $boximg = "object_bill"; + public $boxlabel = 'BoxGlobalActivity'; + public $depends = array("facture"); - /** - * @var DoliDB Database handler. - */ - public $db; + /** + * @var DoliDB Database handler. + */ + public $db; - public $param; - public $enabled = 1; + public $param; + public $enabled = 1; - public $info_box_head = array(); - public $info_box_contents = array(); + public $info_box_head = array(); + public $info_box_contents = array(); - /** - * Constructor - * - * @param DoliDB $db Database handler - * @param string $param More parameters - */ - public function __construct($db, $param) - { - global $conf, $user; + /** + * Constructor + * + * @param DoliDB $db Database handler + * @param string $param More parameters + */ + public function __construct($db, $param) + { + global $conf, $user; - $this->db = $db; + $this->db = $db; - // FIXME: Pb into some status - $this->enabled = ($conf->global->MAIN_FEATURES_LEVEL); // Not enabled by default due to bugs (see previous comments) + // FIXME: Pb into some status + $this->enabled = ($conf->global->MAIN_FEATURES_LEVEL); // Not enabled by default due to bugs (see previous comments) - $this->hidden = !((!empty($conf->facture->enabled) && $user->rights->facture->lire) - || (!empty($conf->commande->enabled) && $user->rights->commande->lire) - || (!empty($conf->propal->enabled) && $user->rights->propale->lire) - ); - } + $this->hidden = !((!empty($conf->facture->enabled) && $user->rights->facture->lire) + || (!empty($conf->commande->enabled) && $user->rights->commande->lire) + || (!empty($conf->propal->enabled) && $user->rights->propale->lire) + ); + } - /** - * Charge les donnees en memoire pour affichage ulterieur - * - * @param int $max Maximum number of records to load - * @return void - */ - public function loadBox($max = 5) - { - global $conf, $user, $langs; + /** + * Charge les donnees en memoire pour affichage ulterieur + * + * @param int $max Maximum number of records to load + * @return void + */ + public function loadBox($max = 5) + { + global $conf, $user, $langs; - include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; - include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - $totalnb = 0; - $line = 0; - $cachetime = 3600; - $fileid = '-e'.$conf->entity.'-u'.$user->id.'-s'.$user->socid.'-r'.($user->rights->societe->client->voir ? '1' : '0').'.cache'; - $now = dol_now(); - $nbofperiod = 3; + $totalnb = 0; + $line = 0; + $cachetime = 3600; + $fileid = '-e'.$conf->entity.'-u'.$user->id.'-s'.$user->socid.'-r'.($user->rights->societe->client->voir ? '1' : '0').'.cache'; + $now = dol_now(); + $nbofperiod = 3; - if (!empty($conf->global->MAIN_BOX_ACTIVITY_DURATION)) $nbofperiod = $conf->global->MAIN_BOX_ACTIVITY_DURATION; - $textHead = $langs->trans("Activity").' - '.$langs->trans("LastXMonthRolling", $nbofperiod); - $this->info_box_head = array( - 'text' => $textHead, - 'limit'=> dol_strlen($textHead), - ); + if (!empty($conf->global->MAIN_BOX_ACTIVITY_DURATION)) $nbofperiod = $conf->global->MAIN_BOX_ACTIVITY_DURATION; + $textHead = $langs->trans("Activity").' - '.$langs->trans("LastXMonthRolling", $nbofperiod); + $this->info_box_head = array( + 'text' => $textHead, + 'limit'=> dol_strlen($textHead), + ); - // compute the year limit to show - $tmpdate = dol_time_plus_duree(dol_now(), -1 * $nbofperiod, "m"); + // compute the year limit to show + $tmpdate = dol_time_plus_duree(dol_now(), -1 * $nbofperiod, "m"); - // list the summary of the propals - if (!empty($conf->propal->enabled) && $user->rights->propale->lire) - { - include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; - $propalstatic = new Propal($this->db); + // list the summary of the propals + if (!empty($conf->propal->enabled) && $user->rights->propale->lire) + { + include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; + $propalstatic = new Propal($this->db); - $cachedir = DOL_DATA_ROOT.'/propale/temp'; - $filename = '/boxactivity-propal'.$fileid; - $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); - $data = array(); - if ($refresh) - { - $sql = "SELECT p.fk_statut, SUM(p.total) as Mnttot, COUNT(*) as nb"; - $sql .= " FROM (".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as p"; - if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql .= ")"; - $sql .= " WHERE p.entity IN (".getEntity('propal').")"; - $sql .= " AND p.fk_soc = s.rowid"; - if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; - if ($user->socid) $sql .= " AND s.rowid = ".$user->socid; - $sql .= " AND p.datep >= '".$this->db->idate($tmpdate)."'"; - $sql .= " AND p.date_cloture IS NULL"; // just unclosed - $sql .= " GROUP BY p.fk_statut"; - $sql .= " ORDER BY p.fk_statut DESC"; + $cachedir = DOL_DATA_ROOT.'/propale/temp'; + $filename = '/boxactivity-propal'.$fileid; + $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); + $data = array(); + if ($refresh) + { + $sql = "SELECT p.fk_statut, SUM(p.total) as Mnttot, COUNT(*) as nb"; + $sql .= " FROM (".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as p"; + if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= ")"; + $sql .= " WHERE p.entity IN (".getEntity('propal').")"; + $sql .= " AND p.fk_soc = s.rowid"; + if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; + if ($user->socid) $sql .= " AND s.rowid = ".$user->socid; + $sql .= " AND p.datep >= '".$this->db->idate($tmpdate)."'"; + $sql .= " AND p.date_cloture IS NULL"; // just unclosed + $sql .= " GROUP BY p.fk_statut"; + $sql .= " ORDER BY p.fk_statut DESC"; - $result = $this->db->query($sql); - if ($result) - { - $num = $this->db->num_rows($result); + $result = $this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); - $j = 0; - while ($j < $num) { - $data[$j] = $this->db->fetch_object($result); - $j++; - } - if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { - dol_filecache($cachedir, $filename, $data); - } - $this->db->free($result); - } else { - dol_print_error($this->db); - } - } else { - $data = dol_readcachefile($cachedir, $filename); - } + $j = 0; + while ($j < $num) { + $data[$j] = $this->db->fetch_object($result); + $j++; + } + if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { + dol_filecache($cachedir, $filename, $data); + } + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } else { + $data = dol_readcachefile($cachedir, $filename); + } - if (!empty($data)) - { - $j = 0; - while ($j < count($data)) - { - $this->info_box_contents[$line][0] = array( - 'td' => 'class="left" width="16"', - 'url' => DOL_URL_ROOT."/comm/propal/list.php?mainmenu=commercial&leftmenu=propals&search_status=".$data[$j]->fk_statut, - 'tooltip' => $langs->trans("Proposals")." ".$propalstatic->LibStatut($data[$j]->fk_statut, 0), - 'logo' => 'object_propal' - ); + if (!empty($data)) + { + $j = 0; + while ($j < count($data)) + { + $this->info_box_contents[$line][0] = array( + 'td' => 'class="left" width="16"', + 'url' => DOL_URL_ROOT."/comm/propal/list.php?mainmenu=commercial&leftmenu=propals&search_status=".$data[$j]->fk_statut, + 'tooltip' => $langs->trans("Proposals")." ".$propalstatic->LibStatut($data[$j]->fk_statut, 0), + 'logo' => 'object_propal' + ); - $this->info_box_contents[$line][1] = array( - 'td' => '', - 'text' => $langs->trans("Proposals")." ".$propalstatic->LibStatut($data[$j]->fk_statut, 0), - ); + $this->info_box_contents[$line][1] = array( + 'td' => '', + 'text' => $langs->trans("Proposals")." ".$propalstatic->LibStatut($data[$j]->fk_statut, 0), + ); - $this->info_box_contents[$line][2] = array( - 'td' => 'class="right"', - 'text' => $data[$j]->nb, - 'tooltip' => $langs->trans("Proposals")." ".$propalstatic->LibStatut($data[$j]->fk_statut, 0), - 'url' => DOL_URL_ROOT."/comm/propal/list.php?mainmenu=commercial&leftmenu=propals&search_status=".$data[$j]->fk_statut, - ); - $totalnb += $data[$j]->nb; + $this->info_box_contents[$line][2] = array( + 'td' => 'class="right"', + 'text' => $data[$j]->nb, + 'tooltip' => $langs->trans("Proposals")." ".$propalstatic->LibStatut($data[$j]->fk_statut, 0), + 'url' => DOL_URL_ROOT."/comm/propal/list.php?mainmenu=commercial&leftmenu=propals&search_status=".$data[$j]->fk_statut, + ); + $totalnb += $data[$j]->nb; - $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', - 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), - ); - $this->info_box_contents[$line][4] = array( - 'td' => 'class="right" width="18"', - 'text' => $propalstatic->LibStatut($data[$j]->fk_statut, 3), - ); + $this->info_box_contents[$line][3] = array( + 'td' => 'class="nowraponall right"', + 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), + ); + $this->info_box_contents[$line][4] = array( + 'td' => 'class="right" width="18"', + 'text' => $propalstatic->LibStatut($data[$j]->fk_statut, 3), + ); - $line++; - $j++; - } - } - } + $line++; + $j++; + } + } + } - // list the summary of the orders - if (!empty($conf->commande->enabled) && $user->rights->commande->lire) { - include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; - $commandestatic = new Commande($this->db); + // list the summary of the orders + if (!empty($conf->commande->enabled) && $user->rights->commande->lire) { + include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; + $commandestatic = new Commande($this->db); - $langs->load("orders"); + $langs->load("orders"); - $cachedir = DOL_DATA_ROOT.'/commande/temp'; - $filename = '/boxactivity-order'.$fileid; - $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); - $data = array(); + $cachedir = DOL_DATA_ROOT.'/commande/temp'; + $filename = '/boxactivity-order'.$fileid; + $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); + $data = array(); - if ($refresh) { - $sql = "SELECT c.fk_statut, sum(c.total_ttc) as Mnttot, count(*) as nb"; - $sql .= " FROM (".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as c"; - if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql .= ")"; - $sql .= " WHERE c.entity IN (".getEntity('commande').")"; - $sql .= " AND c.fk_soc = s.rowid"; - if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; - if ($user->socid) $sql .= " AND s.rowid = ".$user->socid; - $sql .= " AND c.date_commande >= '".$this->db->idate($tmpdate)."'"; - $sql .= " GROUP BY c.fk_statut"; - $sql .= " ORDER BY c.fk_statut DESC"; + if ($refresh) { + $sql = "SELECT c.fk_statut, sum(c.total_ttc) as Mnttot, count(*) as nb"; + $sql .= " FROM (".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as c"; + if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= ")"; + $sql .= " WHERE c.entity IN (".getEntity('commande').")"; + $sql .= " AND c.fk_soc = s.rowid"; + if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; + if ($user->socid) $sql .= " AND s.rowid = ".$user->socid; + $sql .= " AND c.date_commande >= '".$this->db->idate($tmpdate)."'"; + $sql .= " GROUP BY c.fk_statut"; + $sql .= " ORDER BY c.fk_statut DESC"; - $result = $this->db->query($sql); - if ($result) { - $num = $this->db->num_rows($result); - $j = 0; - while ($j < $num) { - $data[$j] = $this->db->fetch_object($result); - $j++; - } - if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { - dol_filecache($cachedir, $filename, $data); - } - $this->db->free($result); - } else { - dol_print_error($this->db); - } - } else { - $data = dol_readcachefile($cachedir, $filename); - } + $result = $this->db->query($sql); + if ($result) { + $num = $this->db->num_rows($result); + $j = 0; + while ($j < $num) { + $data[$j] = $this->db->fetch_object($result); + $j++; + } + if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { + dol_filecache($cachedir, $filename, $data); + } + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } else { + $data = dol_readcachefile($cachedir, $filename); + } - if (!empty($data)) { - $j = 0; - while ($j < count($data)) { - $this->info_box_contents[$line][0] = array( - 'td' => 'class="left" width="16"', - 'url' => DOL_URL_ROOT."/commande/list.php?mainmenu=commercial&leftmenu=orders&search_status=".$data[$j]->fk_statut, - 'tooltip' => $langs->trans("Orders")." ".$commandestatic->LibStatut($data[$j]->fk_statut, 0, 0), - 'logo' => 'object_order', - ); + if (!empty($data)) { + $j = 0; + while ($j < count($data)) { + $this->info_box_contents[$line][0] = array( + 'td' => 'class="left" width="16"', + 'url' => DOL_URL_ROOT."/commande/list.php?mainmenu=commercial&leftmenu=orders&search_status=".$data[$j]->fk_statut, + 'tooltip' => $langs->trans("Orders")." ".$commandestatic->LibStatut($data[$j]->fk_statut, 0, 0), + 'logo' => 'object_order', + ); - $this->info_box_contents[$line][1] = array( - 'td' => '', - 'text' =>$langs->trans("Orders")." ".$commandestatic->LibStatut($data[$j]->fk_statut, 0, 0), - ); + $this->info_box_contents[$line][1] = array( + 'td' => '', + 'text' =>$langs->trans("Orders")." ".$commandestatic->LibStatut($data[$j]->fk_statut, 0, 0), + ); - $this->info_box_contents[$line][2] = array( - 'td' => 'class="right"', - 'text' => $data[$j]->nb, - 'tooltip' => $langs->trans("Orders")." ".$commandestatic->LibStatut($data[$j]->fk_statut, 0, 0), - 'url' => DOL_URL_ROOT."/commande/list.php?mainmenu=commercial&leftmenu=orders&search_status=".$data[$j]->fk_statut, - ); - $totalnb += $data[$j]->nb; + $this->info_box_contents[$line][2] = array( + 'td' => 'class="right"', + 'text' => $data[$j]->nb, + 'tooltip' => $langs->trans("Orders")." ".$commandestatic->LibStatut($data[$j]->fk_statut, 0, 0), + 'url' => DOL_URL_ROOT."/commande/list.php?mainmenu=commercial&leftmenu=orders&search_status=".$data[$j]->fk_statut, + ); + $totalnb += $data[$j]->nb; - $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', - 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), - ); - $this->info_box_contents[$line][4] = array( - 'td' => 'class="right" width="18"', - 'text' => $commandestatic->LibStatut($data[$j]->fk_statut, 0, 3), - ); + $this->info_box_contents[$line][3] = array( + 'td' => 'class="nowraponall right"', + 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), + ); + $this->info_box_contents[$line][4] = array( + 'td' => 'class="right" width="18"', + 'text' => $commandestatic->LibStatut($data[$j]->fk_statut, 0, 3), + ); - $line++; - $j++; - } - } - } + $line++; + $j++; + } + } + } - // list the summary of the bills - if (!empty($conf->facture->enabled) && $user->rights->facture->lire) - { - include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; - $facturestatic = new Facture($this->db); + // list the summary of the bills + if (!empty($conf->facture->enabled) && $user->rights->facture->lire) + { + include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; + $facturestatic = new Facture($this->db); - // part 1 - $cachedir = DOL_DATA_ROOT.'/facture/temp'; - $filename = '/boxactivity-invoice'.$fileid; + // part 1 + $cachedir = DOL_DATA_ROOT.'/facture/temp'; + $filename = '/boxactivity-invoice'.$fileid; - $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); - $data = array(); - if ($refresh) - { - $sql = "SELECT f.fk_statut, SUM(f.total_ttc) as Mnttot, COUNT(*) as nb"; - $sql .= " FROM (".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f"; - if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql .= ")"; - $sql .= " WHERE f.entity IN (".getEntity('invoice').')'; - if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; - if ($user->socid) $sql .= " AND s.rowid = ".$user->socid; - $sql .= " AND f.fk_soc = s.rowid"; - $sql .= " AND f.datef >= '".$this->db->idate($tmpdate)."' AND f.paye=1"; - $sql .= " GROUP BY f.fk_statut"; - $sql .= " ORDER BY f.fk_statut DESC"; + $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); + $data = array(); + if ($refresh) + { + $sql = "SELECT f.fk_statut, SUM(f.total_ttc) as Mnttot, COUNT(*) as nb"; + $sql .= " FROM (".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f"; + if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= ")"; + $sql .= " WHERE f.entity IN (".getEntity('invoice').')'; + if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; + if ($user->socid) $sql .= " AND s.rowid = ".$user->socid; + $sql .= " AND f.fk_soc = s.rowid"; + $sql .= " AND f.datef >= '".$this->db->idate($tmpdate)."' AND f.paye=1"; + $sql .= " GROUP BY f.fk_statut"; + $sql .= " ORDER BY f.fk_statut DESC"; - $result = $this->db->query($sql); - if ($result) { - $num = $this->db->num_rows($result); - $j = 0; - while ($j < $num) { - $data[$j] = $this->db->fetch_object($result); - $j++; - } - if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { - dol_filecache($cachedir, $filename, $data); - } - $this->db->free($result); - } else { - dol_print_error($this->db); - } - } else { - $data = dol_readcachefile($cachedir, $filename); - } + $result = $this->db->query($sql); + if ($result) { + $num = $this->db->num_rows($result); + $j = 0; + while ($j < $num) { + $data[$j] = $this->db->fetch_object($result); + $j++; + } + if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { + dol_filecache($cachedir, $filename, $data); + } + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } else { + $data = dol_readcachefile($cachedir, $filename); + } - if (!empty($data)) { - $j = 0; - while ($j < count($data)) { - $billurl = "search_status=2&paye=1&year=".$data[$j]->annee; - $this->info_box_contents[$line][0] = array( - 'td' => 'class="left" width="16"', - 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(1, $data[$j]->fk_statut, 0), - 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", - 'logo' => 'bill', - ); + if (!empty($data)) { + $j = 0; + while ($j < count($data)) { + $billurl = "search_status=2&paye=1&year=".$data[$j]->annee; + $this->info_box_contents[$line][0] = array( + 'td' => 'class="left" width="16"', + 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(1, $data[$j]->fk_statut, 0), + 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", + 'logo' => 'bill', + ); - $this->info_box_contents[$line][1] = array( - 'td' => '', - 'text' => $langs->trans("Bills")." ".$facturestatic->LibStatut(1, $data[$j]->fk_statut, 0)." ".$data[$j]->annee, - ); + $this->info_box_contents[$line][1] = array( + 'td' => '', + 'text' => $langs->trans("Bills")." ".$facturestatic->LibStatut(1, $data[$j]->fk_statut, 0)." ".$data[$j]->annee, + ); - $this->info_box_contents[$line][2] = array( - 'td' => 'class="right"', - 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(1, $data[$j]->fk_statut, 0), - 'text' => $data[$j]->nb, - 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", - ); + $this->info_box_contents[$line][2] = array( + 'td' => 'class="right"', + 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(1, $data[$j]->fk_statut, 0), + 'text' => $data[$j]->nb, + 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", + ); - $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', - 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency) - ); + $this->info_box_contents[$line][3] = array( + 'td' => 'class="nowraponall right"', + 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency) + ); - // We add only for the current year - $totalnb += $data[$j]->nb; + // We add only for the current year + $totalnb += $data[$j]->nb; - $this->info_box_contents[$line][4] = array( - 'td' => 'class="right" width="18"', - 'text' => $facturestatic->LibStatut(1, $data[$j]->fk_statut, 3), - ); - $line++; - $j++; - } - if (count($data) == 0) - $this->info_box_contents[$line][0] = array( - 'td' => 'class="center"', - 'text'=>$langs->trans("NoRecordedInvoices"), - ); - } + $this->info_box_contents[$line][4] = array( + 'td' => 'class="right" width="18"', + 'text' => $facturestatic->LibStatut(1, $data[$j]->fk_statut, 3), + ); + $line++; + $j++; + } + if (count($data) == 0) + $this->info_box_contents[$line][0] = array( + 'td' => 'class="center"', + 'text'=>$langs->trans("NoRecordedInvoices"), + ); + } - // part 2 - $cachedir = DOL_DATA_ROOT.'/facture/temp'; - $filename = '/boxactivity-invoice2'.$fileid; + // part 2 + $cachedir = DOL_DATA_ROOT.'/facture/temp'; + $filename = '/boxactivity-invoice2'.$fileid; - $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); + $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); - $data = array(); - if ($refresh) { - $sql = "SELECT f.fk_statut, SUM(f.total_ttc) as Mnttot, COUNT(*) as nb"; - $sql .= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f"; - $sql .= " WHERE f.entity IN (".getEntity('invoice').')'; - $sql .= " AND f.fk_soc = s.rowid"; - $sql .= " AND f.datef >= '".$this->db->idate($tmpdate)."' AND f.paye=0"; - $sql .= " GROUP BY f.fk_statut"; - $sql .= " ORDER BY f.fk_statut DESC"; + $data = array(); + if ($refresh) { + $sql = "SELECT f.fk_statut, SUM(f.total_ttc) as Mnttot, COUNT(*) as nb"; + $sql .= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f"; + $sql .= " WHERE f.entity IN (".getEntity('invoice').')'; + $sql .= " AND f.fk_soc = s.rowid"; + $sql .= " AND f.datef >= '".$this->db->idate($tmpdate)."' AND f.paye=0"; + $sql .= " GROUP BY f.fk_statut"; + $sql .= " ORDER BY f.fk_statut DESC"; - $result = $this->db->query($sql); - if ($result) { - $num = $this->db->num_rows($result); - $j = 0; - while ($j < $num) { - $data[$j] = $this->db->fetch_object($result); - $j++; - } - if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { - dol_filecache($cachedir, $filename, $data); - } - $this->db->free($result); - } else { - dol_print_error($this->db); - } - } else { - $data = dol_readcachefile($cachedir, $filename); - } + $result = $this->db->query($sql); + if ($result) { + $num = $this->db->num_rows($result); + $j = 0; + while ($j < $num) { + $data[$j] = $this->db->fetch_object($result); + $j++; + } + if (!empty($conf->global->MAIN_ACTIVATE_FILECACHE)) { + dol_filecache($cachedir, $filename, $data); + } + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } else { + $data = dol_readcachefile($cachedir, $filename); + } - if (!empty($data)) { - $alreadypaid = -1; + if (!empty($data)) { + $alreadypaid = -1; - $j = 0; - while ($j < count($data)) { - $billurl = "search_status=".$data[$j]->fk_statut."&paye=0"; - $this->info_box_contents[$line][0] = array( - 'td' => 'class="left" width="16"', - 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(0, $data[$j]->fk_statut, 0), - 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", - 'logo' => 'bill', - ); + $j = 0; + while ($j < count($data)) { + $billurl = "search_status=".$data[$j]->fk_statut."&paye=0"; + $this->info_box_contents[$line][0] = array( + 'td' => 'class="left" width="16"', + 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(0, $data[$j]->fk_statut, 0), + 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", + 'logo' => 'bill', + ); - $this->info_box_contents[$line][1] = array( - 'td' => '', - 'text' => $langs->trans("Bills")." ".$facturestatic->LibStatut(0, $data[$j]->fk_statut, 0), - ); + $this->info_box_contents[$line][1] = array( + 'td' => '', + 'text' => $langs->trans("Bills")." ".$facturestatic->LibStatut(0, $data[$j]->fk_statut, 0), + ); - $this->info_box_contents[$line][2] = array( - 'td' => 'class="right"', - 'text' => $data[$j]->nb, - 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(0, $data[$j]->fk_statut, 0), - 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", - ); - $totalnb += $data[$j]->nb; - $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', - 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), - ); - $this->info_box_contents[$line][4] = array( - 'td' => 'class="right" width="18"', - 'text' => $facturestatic->LibStatut(0, $data[$j]->fk_statut, 3, $alreadypaid), - ); - $line++; - $j++; - } - if (count($data) == 0) { - $this->info_box_contents[$line][0] = array( - 'td' => 'class="center"', - 'text'=>$langs->trans("NoRecordedInvoices"), - ); - } - } - } + $this->info_box_contents[$line][2] = array( + 'td' => 'class="right"', + 'text' => $data[$j]->nb, + 'tooltip' => $langs->trans('Bills').' '.$facturestatic->LibStatut(0, $data[$j]->fk_statut, 0), + 'url' => DOL_URL_ROOT."/compta/facture/list.php?".$billurl."&mainmenu=accountancy&leftmenu=customers_bills", + ); + $totalnb += $data[$j]->nb; + $this->info_box_contents[$line][3] = array( + 'td' => 'class="nowraponall right"', + 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), + ); + $this->info_box_contents[$line][4] = array( + 'td' => 'class="right" width="18"', + 'text' => $facturestatic->LibStatut(0, $data[$j]->fk_statut, 3, $alreadypaid), + ); + $line++; + $j++; + } + if (count($data) == 0) { + $this->info_box_contents[$line][0] = array( + 'td' => 'class="center"', + 'text'=>$langs->trans("NoRecordedInvoices"), + ); + } + } + } // Add the sum in the bottom of the boxes $this->info_box_contents[$line][0] = array('tr' => 'class="liste_total_wrap"'); @@ -444,19 +444,19 @@ class box_activity extends ModeleBoxes $this->info_box_contents[$line][2] = array('td' => 'class="liste_total right" ', 'text' => $totalnb); $this->info_box_contents[$line][3] = array('td' => 'class="liste_total right" ', 'text' => ''); $this->info_box_contents[$line][4] = array('td' => 'class="liste_total right" ', 'text' => ""); - } + } - /** - * Method to show box - * - * @param array $head Array with properties of box title - * @param array $contents Array with properties of box lines - * @param int $nooutput No print, only return string - * @return string - */ - public function showBox($head = null, $contents = null, $nooutput = 0) - { - return parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput); - } + /** + * Method to show box + * + * @param array $head Array with properties of box title + * @param array $contents Array with properties of box lines + * @param int $nooutput No print, only return string + * @return string + */ + public function showBox($head = null, $contents = null, $nooutput = 0) + { + return parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput); + } } diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index f25a0694f7d..6015bbceece 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -40,199 +40,199 @@ abstract class CommonDocGenerator */ public $error = ''; - /** - * @var string[] Array of error strings - */ - public $errors = array(); + /** + * @var string[] Array of error strings + */ + public $errors = array(); /** - * @var DoliDB Database handler. - */ + * @var DoliDB Database handler. + */ protected $db; - /** - * @var Extrafields object - */ + /** + * @var Extrafields object + */ public $extrafieldsCache; /** * Constructor * * @param DoliDB $db Database handler - */ - public function __construct($db) - { - $this->db = $db; - } + */ + public function __construct($db) + { + $this->db = $db; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Define array with couple substitution key => substitution value - * - * @param User $user User - * @param Translate $outputlangs Language object for output - * @return array Array of substitution key->code - */ - public function get_substitutionarray_user($user, $outputlangs) - { - // phpcs:enable - global $conf; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Define array with couple substitution key => substitution value + * + * @param User $user User + * @param Translate $outputlangs Language object for output + * @return array Array of substitution key->code + */ + public function get_substitutionarray_user($user, $outputlangs) + { + // phpcs:enable + global $conf; - $logotouse = $conf->user->dir_output.'/'.get_exdir($user->id, 2, 0, 1, $user, 'user').'/'.$user->photo; + $logotouse = $conf->user->dir_output.'/'.get_exdir($user->id, 2, 0, 1, $user, 'user').'/'.$user->photo; - return array( - 'myuser_lastname'=>$user->lastname, - 'myuser_firstname'=>$user->firstname, - 'myuser_fullname'=>$user->getFullName($outputlangs, 1), - 'myuser_login'=>$user->login, - 'myuser_phone'=>$user->office_phone, - 'myuser_address'=>$user->address, - 'myuser_zip'=>$user->zip, - 'myuser_town'=>$user->town, - 'myuser_country'=>$user->country, - 'myuser_country_code'=>$user->country_code, - 'myuser_state'=>$user->state, - 'myuser_state_code'=>$user->state_code, - 'myuser_fax'=>$user->office_fax, - 'myuser_mobile'=>$user->user_mobile, - 'myuser_email'=>$user->email, - 'myuser_logo'=>$logotouse, - 'myuser_job'=>$user->job, - 'myuser_web'=>'' // url not exist in $user object - ); - } + return array( + 'myuser_lastname'=>$user->lastname, + 'myuser_firstname'=>$user->firstname, + 'myuser_fullname'=>$user->getFullName($outputlangs, 1), + 'myuser_login'=>$user->login, + 'myuser_phone'=>$user->office_phone, + 'myuser_address'=>$user->address, + 'myuser_zip'=>$user->zip, + 'myuser_town'=>$user->town, + 'myuser_country'=>$user->country, + 'myuser_country_code'=>$user->country_code, + 'myuser_state'=>$user->state, + 'myuser_state_code'=>$user->state_code, + 'myuser_fax'=>$user->office_fax, + 'myuser_mobile'=>$user->user_mobile, + 'myuser_email'=>$user->email, + 'myuser_logo'=>$logotouse, + 'myuser_job'=>$user->job, + 'myuser_web'=>'' // url not exist in $user object + ); + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Define array with couple substitution key => substitution value - * - * @param Societe $mysoc Object thirdparty - * @param Translate $outputlangs Language object for output - * @return array Array of substitution key->code - */ - public function get_substitutionarray_mysoc($mysoc, $outputlangs) - { - // phpcs:enable - global $conf; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Define array with couple substitution key => substitution value + * + * @param Societe $mysoc Object thirdparty + * @param Translate $outputlangs Language object for output + * @return array Array of substitution key->code + */ + public function get_substitutionarray_mysoc($mysoc, $outputlangs) + { + // phpcs:enable + global $conf; - if (empty($mysoc->forme_juridique) && !empty($mysoc->forme_juridique_code)) - { - $mysoc->forme_juridique = getFormeJuridiqueLabel($mysoc->forme_juridique_code); - } - if (empty($mysoc->country) && !empty($mysoc->country_code)) - { - $mysoc->country = $outputlangs->transnoentitiesnoconv("Country".$mysoc->country_code); - } - if (empty($mysoc->state) && !empty($mysoc->state_code)) - { - $mysoc->state = getState($mysoc->state_code, 0); - } + if (empty($mysoc->forme_juridique) && !empty($mysoc->forme_juridique_code)) + { + $mysoc->forme_juridique = getFormeJuridiqueLabel($mysoc->forme_juridique_code); + } + if (empty($mysoc->country) && !empty($mysoc->country_code)) + { + $mysoc->country = $outputlangs->transnoentitiesnoconv("Country".$mysoc->country_code); + } + if (empty($mysoc->state) && !empty($mysoc->state_code)) + { + $mysoc->state = getState($mysoc->state_code, 0); + } - $logotouse = $conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_small; + $logotouse = $conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_small; - return array( - 'mycompany_logo'=>$logotouse, - 'mycompany_name'=>$mysoc->name, - 'mycompany_email'=>$mysoc->email, - 'mycompany_phone'=>$mysoc->phone, - 'mycompany_fax'=>$mysoc->fax, - 'mycompany_address'=>$mysoc->address, - 'mycompany_zip'=>$mysoc->zip, - 'mycompany_town'=>$mysoc->town, - 'mycompany_country'=>$mysoc->country, - 'mycompany_country_code'=>$mysoc->country_code, - 'mycompany_state'=>$mysoc->state, - 'mycompany_state_code'=>$mysoc->state_code, - 'mycompany_web'=>$mysoc->url, - 'mycompany_juridicalstatus'=>$mysoc->forme_juridique, - 'mycompany_managers'=>$mysoc->managers, - 'mycompany_capital'=>$mysoc->capital, - 'mycompany_barcode'=>$mysoc->barcode, - 'mycompany_idprof1'=>$mysoc->idprof1, - 'mycompany_idprof2'=>$mysoc->idprof2, - 'mycompany_idprof3'=>$mysoc->idprof3, - 'mycompany_idprof4'=>$mysoc->idprof4, - 'mycompany_idprof5'=>$mysoc->idprof5, - 'mycompany_idprof6'=>$mysoc->idprof6, - 'mycompany_vatnumber'=>$mysoc->tva_intra, + return array( + 'mycompany_logo'=>$logotouse, + 'mycompany_name'=>$mysoc->name, + 'mycompany_email'=>$mysoc->email, + 'mycompany_phone'=>$mysoc->phone, + 'mycompany_fax'=>$mysoc->fax, + 'mycompany_address'=>$mysoc->address, + 'mycompany_zip'=>$mysoc->zip, + 'mycompany_town'=>$mysoc->town, + 'mycompany_country'=>$mysoc->country, + 'mycompany_country_code'=>$mysoc->country_code, + 'mycompany_state'=>$mysoc->state, + 'mycompany_state_code'=>$mysoc->state_code, + 'mycompany_web'=>$mysoc->url, + 'mycompany_juridicalstatus'=>$mysoc->forme_juridique, + 'mycompany_managers'=>$mysoc->managers, + 'mycompany_capital'=>$mysoc->capital, + 'mycompany_barcode'=>$mysoc->barcode, + 'mycompany_idprof1'=>$mysoc->idprof1, + 'mycompany_idprof2'=>$mysoc->idprof2, + 'mycompany_idprof3'=>$mysoc->idprof3, + 'mycompany_idprof4'=>$mysoc->idprof4, + 'mycompany_idprof5'=>$mysoc->idprof5, + 'mycompany_idprof6'=>$mysoc->idprof6, + 'mycompany_vatnumber'=>$mysoc->tva_intra, 'mycompany_object'=>$mysoc->object, - 'mycompany_note_private'=>$mysoc->note_private, - //'mycompany_note_public'=>$mysoc->note_public, // Only private not exists for "mysoc" but both for thirdparties - ); - } + 'mycompany_note_private'=>$mysoc->note_private, + //'mycompany_note_public'=>$mysoc->note_public, // Only private not exists for "mysoc" but both for thirdparties + ); + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Define array with couple substitution key => substitution value - * - * @param Societe $object Object - * @param Translate $outputlangs Language object for output - * @param string $array_key Name of the key for return array - * @return array Array of substitution key->code - */ - public function get_substitutionarray_thirdparty($object, $outputlangs, $array_key = 'company') - { - // phpcs:enable - global $conf, $extrafields; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Define array with couple substitution key => substitution value + * + * @param Societe $object Object + * @param Translate $outputlangs Language object for output + * @param string $array_key Name of the key for return array + * @return array Array of substitution key->code + */ + public function get_substitutionarray_thirdparty($object, $outputlangs, $array_key = 'company') + { + // phpcs:enable + global $conf, $extrafields; - if (empty($object->country) && !empty($object->country_code)) - { - $object->country = $outputlangs->transnoentitiesnoconv("Country".$object->country_code); - } - if (empty($object->state) && !empty($object->state_code)) - { - $object->state = getState($object->state_code, 0); - } + if (empty($object->country) && !empty($object->country_code)) + { + $object->country = $outputlangs->transnoentitiesnoconv("Country".$object->country_code); + } + if (empty($object->state) && !empty($object->state_code)) + { + $object->state = getState($object->state_code, 0); + } - $array_thirdparty = array( - 'company_name'=>$object->name, - 'company_name_alias' => $object->name_alias, - 'company_email'=>$object->email, - 'company_phone'=>$object->phone, - 'company_fax'=>$object->fax, - 'company_address'=>$object->address, - 'company_zip'=>$object->zip, - 'company_town'=>$object->town, - 'company_country'=>$object->country, - 'company_country_code'=>$object->country_code, - 'company_state'=>$object->state, - 'company_state_code'=>$object->state_code, - 'company_web'=>$object->url, - 'company_barcode'=>$object->barcode, - 'company_vatnumber'=>$object->tva_intra, - 'company_customercode'=>$object->code_client, - 'company_suppliercode'=>$object->code_fournisseur, - 'company_customeraccountancycode'=>$object->code_compta, - 'company_supplieraccountancycode'=>$object->code_compta_fournisseur, - 'company_juridicalstatus'=>$object->forme_juridique, - 'company_outstanding_limit'=>$object->outstanding_limit, - 'company_capital'=>$object->capital, - 'company_idprof1'=>$object->idprof1, - 'company_idprof2'=>$object->idprof2, - 'company_idprof3'=>$object->idprof3, - 'company_idprof4'=>$object->idprof4, - 'company_idprof5'=>$object->idprof5, - 'company_idprof6'=>$object->idprof6, - 'company_note_public'=>$object->note_public, - 'company_note_private'=>$object->note_private, - 'company_default_bank_iban'=>(is_object($object->bank_account) ? $object->bank_account->iban : ''), - 'company_default_bank_bic'=>(is_object($object->bank_account) ? $object->bank_account->bic : '') - ); + $array_thirdparty = array( + 'company_name'=>$object->name, + 'company_name_alias' => $object->name_alias, + 'company_email'=>$object->email, + 'company_phone'=>$object->phone, + 'company_fax'=>$object->fax, + 'company_address'=>$object->address, + 'company_zip'=>$object->zip, + 'company_town'=>$object->town, + 'company_country'=>$object->country, + 'company_country_code'=>$object->country_code, + 'company_state'=>$object->state, + 'company_state_code'=>$object->state_code, + 'company_web'=>$object->url, + 'company_barcode'=>$object->barcode, + 'company_vatnumber'=>$object->tva_intra, + 'company_customercode'=>$object->code_client, + 'company_suppliercode'=>$object->code_fournisseur, + 'company_customeraccountancycode'=>$object->code_compta, + 'company_supplieraccountancycode'=>$object->code_compta_fournisseur, + 'company_juridicalstatus'=>$object->forme_juridique, + 'company_outstanding_limit'=>$object->outstanding_limit, + 'company_capital'=>$object->capital, + 'company_idprof1'=>$object->idprof1, + 'company_idprof2'=>$object->idprof2, + 'company_idprof3'=>$object->idprof3, + 'company_idprof4'=>$object->idprof4, + 'company_idprof5'=>$object->idprof5, + 'company_idprof6'=>$object->idprof6, + 'company_note_public'=>$object->note_public, + 'company_note_private'=>$object->note_private, + 'company_default_bank_iban'=>(is_object($object->bank_account) ? $object->bank_account->iban : ''), + 'company_default_bank_bic'=>(is_object($object->bank_account) ? $object->bank_account->bic : '') + ); - // Retrieve extrafields - if (is_array($object->array_options) && count($object->array_options)) - { - $object->fetch_optionals(); + // Retrieve extrafields + if (is_array($object->array_options) && count($object->array_options)) + { + $object->fetch_optionals(); - $array_thirdparty = $this->fill_substitutionarray_with_extrafields($object, $array_thirdparty, $extrafields, $array_key, $outputlangs); - } + $array_thirdparty = $this->fill_substitutionarray_with_extrafields($object, $array_thirdparty, $extrafields, $array_key, $outputlangs); + } return $array_thirdparty; } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Define array with couple substitution key => substitution value * @@ -241,9 +241,9 @@ abstract class CommonDocGenerator * @param string $array_key Name of the key for return array * @return array Array of substitution key->code */ - public function get_substitutionarray_contact($object, $outputlangs, $array_key = 'object') - { - // phpcs:enable + public function get_substitutionarray_contact($object, $outputlangs, $array_key = 'object') + { + // phpcs:enable global $conf, $extrafields; if (empty($object->country) && !empty($object->country_code)) @@ -285,67 +285,67 @@ abstract class CommonDocGenerator $array_key.'_civility' => $object->civility, ); - // Retrieve extrafields - if (is_array($object->array_options) && count($object->array_options)) - { - $object->fetch_optionals(); + // Retrieve extrafields + if (is_array($object->array_options) && count($object->array_options)) + { + $object->fetch_optionals(); - $array_contact = $this->fill_substitutionarray_with_extrafields($object, $array_contact, $extrafields, $array_key, $outputlangs); - } + $array_contact = $this->fill_substitutionarray_with_extrafields($object, $array_contact, $extrafields, $array_key, $outputlangs); + } return $array_contact; } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Define array with couple substitution key => substitution value - * - * @param Translate $outputlangs Language object for output - * @return array Array of substitution key->code - */ - public function get_substitutionarray_other($outputlangs) - { - // phpcs:enable - global $conf; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Define array with couple substitution key => substitution value + * + * @param Translate $outputlangs Language object for output + * @return array Array of substitution key->code + */ + public function get_substitutionarray_other($outputlangs) + { + // phpcs:enable + global $conf; - $now = dol_now('gmt'); // gmt - $array_other = array( - // Date in default language - 'current_date'=>dol_print_date($now, 'day', 'tzuser'), - 'current_datehour'=>dol_print_date($now, 'dayhour', 'tzuser'), + $now = dol_now('gmt'); // gmt + $array_other = array( + // Date in default language + 'current_date'=>dol_print_date($now, 'day', 'tzuser'), + 'current_datehour'=>dol_print_date($now, 'dayhour', 'tzuser'), 'current_server_date'=>dol_print_date($now, 'day', 'tzserver'), 'current_server_datehour'=>dol_print_date($now, 'dayhour', 'tzserver'), - // Date in requested output language - 'current_date_locale'=>dol_print_date($now, 'day', 'tzuser', $outputlangs), + // Date in requested output language + 'current_date_locale'=>dol_print_date($now, 'day', 'tzuser', $outputlangs), 'current_datehour_locale'=>dol_print_date($now, 'dayhour', 'tzuser', $outputlangs), 'current_server_date_locale'=>dol_print_date($now, 'day', 'tzserver', $outputlangs), 'current_server_datehour_locale'=>dol_print_date($now, 'dayhour', 'tzserver', $outputlangs), - ); + ); - foreach ($conf->global as $key => $val) - { - if (isASecretKey($key)) $newval = '*****forbidden*****'; - else $newval = $val; - $array_other['__['.$key.']__'] = $newval; - } + foreach ($conf->global as $key => $val) + { + if (isASecretKey($key)) $newval = '*****forbidden*****'; + else $newval = $val; + $array_other['__['.$key.']__'] = $newval; + } - return $array_other; - } + return $array_other; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Define array with couple substitution key => substitution value * * @param Object $object Main object to use as data source * @param Translate $outputlangs Lang object to use for output - * @param string $array_key Name of the key for return array + * @param string $array_key Name of the key for return array * @return array Array of substitution */ public function get_substitutionarray_object($object, $outputlangs, $array_key = 'object') { - // phpcs:enable + // phpcs:enable global $conf, $extrafields; $sumpayed = $sumdeposit = $sumcreditnote = ''; @@ -381,11 +381,11 @@ abstract class CommonDocGenerator $array_key.'_ref_supplier'=>(!empty($object->ref_fournisseur) ? $object->ref_fournisseur : (empty($object->ref_supplier) ? '' : $object->ref_supplier)), $array_key.'_source_invoice_ref'=>$invoice_source->ref, // Dates - $array_key.'_hour'=>dol_print_date($date, 'hour'), + $array_key.'_hour'=>dol_print_date($date, 'hour'), $array_key.'_date'=>dol_print_date($date, 'day'), $array_key.'_date_rfc'=>dol_print_date($date, 'dayrfc'), $array_key.'_date_limit'=>(!empty($object->date_lim_reglement) ?dol_print_date($object->date_lim_reglement, 'day') : ''), - $array_key.'_date_end'=>(!empty($object->fin_validite) ?dol_print_date($object->fin_validite, 'day') : ''), + $array_key.'_date_end'=>(!empty($object->fin_validite) ?dol_print_date($object->fin_validite, 'day') : ''), $array_key.'_date_creation'=>dol_print_date($object->date_creation, 'day'), $array_key.'_date_modification'=>(!empty($object->date_modification) ?dol_print_date($object->date_modification, 'day') : ''), $array_key.'_date_validation'=>(!empty($object->date_validation) ?dol_print_date($object->date_validation, 'dayhour') : ''), @@ -397,7 +397,7 @@ abstract class CommonDocGenerator $array_key.'_payment_term_code'=>$object->cond_reglement_code, $array_key.'_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code) != 'PaymentCondition'.$object->cond_reglement_code ? $outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code) : ($object->cond_reglement_doc ? $object->cond_reglement_doc : $object->cond_reglement)), - $array_key.'_incoterms'=>(method_exists($object, 'display_incoterms') ? $object->display_incoterms() : ''), + $array_key.'_incoterms'=>(method_exists($object, 'display_incoterms') ? $object->display_incoterms() : ''), $array_key.'_bank_iban'=>$bank_account->iban, $array_key.'_bank_bic'=>$bank_account->bic, @@ -416,8 +416,8 @@ abstract class CommonDocGenerator $array_key.'_multicurrency_code' => price2num($object->multicurrency_code), $array_key.'_multicurrency_tx' => price2num($object->multicurrency_tx), - $array_key.'_multicurrency_total_ht' => price2num($object->multicurrency_total_ht), - $array_key.'_multicurrency_total_tva' => price2num($object->multicurrency_total_tva), + $array_key.'_multicurrency_total_ht' => price2num($object->multicurrency_total_ht), + $array_key.'_multicurrency_total_tva' => price2num($object->multicurrency_total_tva), $array_key.'_multicurrency_total_ttc' => price2num($object->multicurrency_total_ttc), $array_key.'_multicurrency_total_ht_locale' => price($object->multicurrency_total_ht, 0, $outputlangs), $array_key.'_multicurrency_total_tva_locale' => price($object->multicurrency_total_tva, 0, $outputlangs), @@ -472,11 +472,11 @@ abstract class CommonDocGenerator $totalUp = 0; foreach ($object->lines as $line) { - // $line->tva_tx format depends on database field accuraty, no reliable. This is kept for backward compatibility + // $line->tva_tx format depends on database field accuraty, no reliable. This is kept for backward compatibility if (empty($resarray[$array_key.'_total_vat_'.$line->tva_tx])) $resarray[$array_key.'_total_vat_'.$line->tva_tx] = 0; $resarray[$array_key.'_total_vat_'.$line->tva_tx] += $line->total_tva; $resarray[$array_key.'_total_vat_locale_'.$line->tva_tx] = price($resarray[$array_key.'_total_vat_'.$line->tva_tx]); - // $vatformated is vat without not expected chars (so 20, or 8.5 or 5.99 for example) + // $vatformated is vat without not expected chars (so 20, or 8.5 or 5.99 for example) $vatformated = vatrate($line->tva_tx); if (empty($resarray[$array_key.'_total_vat_'.$vatformated])) $resarray[$array_key.'_total_vat_'.$vatformated] = 0; $resarray[$array_key.'_total_vat_'.$vatformated] += $line->total_tva; @@ -514,7 +514,7 @@ abstract class CommonDocGenerator return $resarray; } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Define array with couple substitution key => substitution value * @@ -525,7 +525,7 @@ abstract class CommonDocGenerator */ public function get_substitutionarray_lines($line, $outputlangs, $linenumber = 0) { - // phpcs:enable + // phpcs:enable global $conf; $resarray = array( @@ -537,9 +537,9 @@ abstract class CommonDocGenerator 'line_product_type'=>$line->product_type, 'line_desc'=>$line->desc, 'line_vatrate'=>vatrate($line->tva_tx, true, $line->info_bits), - 'line_localtax1_rate'=>vatrate($line->localtax1_tx), - 'line_localtax2_rate'=>vatrate($line->localtax1_tx), - 'line_up'=>price2num($line->subprice), + 'line_localtax1_rate'=>vatrate($line->localtax1_tx), + 'line_localtax2_rate'=>vatrate($line->localtax1_tx), + 'line_up'=>price2num($line->subprice), 'line_up_locale'=>price($line->subprice, 0, $outputlangs), 'line_total_up'=>price2num($line->subprice * $line->qty), 'line_total_up_locale'=>price($line->subprice * $line->qty, 0, $outputlangs), @@ -551,31 +551,31 @@ abstract class CommonDocGenerator 'line_price_ht_locale'=>price($line->total_ht, 0, $outputlangs), 'line_price_ttc_locale'=>price($line->total_ttc, 0, $outputlangs), 'line_price_vat_locale'=>price($line->total_tva, 0, $outputlangs), - // Dates + // Dates 'line_date_start'=>dol_print_date($line->date_start, 'day'), 'line_date_start_locale'=>dol_print_date($line->date_start, 'day', 'tzserver', $outputlangs), - 'line_date_start_rfc'=>dol_print_date($line->date_start, 'dayrfc'), - 'line_date_end'=>dol_print_date($line->date_end, 'day'), - 'line_date_end_locale'=>dol_print_date($line->date_end, 'day', 'tzserver', $outputlangs), - 'line_date_end_rfc'=>dol_print_date($line->date_end, 'dayrfc'), + 'line_date_start_rfc'=>dol_print_date($line->date_start, 'dayrfc'), + 'line_date_end'=>dol_print_date($line->date_end, 'day'), + 'line_date_end_locale'=>dol_print_date($line->date_end, 'day', 'tzserver', $outputlangs), + 'line_date_end_rfc'=>dol_print_date($line->date_end, 'dayrfc'), - 'line_multicurrency_code' => price2num($line->multicurrency_code), - 'line_multicurrency_subprice' => price2num($line->multicurrency_subprice), - 'line_multicurrency_total_ht' => price2num($line->multicurrency_total_ht), - 'line_multicurrency_total_tva' => price2num($line->multicurrency_total_tva), - 'line_multicurrency_total_ttc' => price2num($line->multicurrency_total_ttc), - 'line_multicurrency_subprice_locale' => price($line->multicurrency_subprice, 0, $outputlangs), - 'line_multicurrency_total_ht_locale' => price($line->multicurrency_total_ht, 0, $outputlangs), - 'line_multicurrency_total_tva_locale' => price($line->multicurrency_total_tva, 0, $outputlangs), - 'line_multicurrency_total_ttc_locale' => price($line->multicurrency_total_ttc, 0, $outputlangs), + 'line_multicurrency_code' => price2num($line->multicurrency_code), + 'line_multicurrency_subprice' => price2num($line->multicurrency_subprice), + 'line_multicurrency_total_ht' => price2num($line->multicurrency_total_ht), + 'line_multicurrency_total_tva' => price2num($line->multicurrency_total_tva), + 'line_multicurrency_total_ttc' => price2num($line->multicurrency_total_ttc), + 'line_multicurrency_subprice_locale' => price($line->multicurrency_subprice, 0, $outputlangs), + 'line_multicurrency_total_ht_locale' => price($line->multicurrency_total_ht, 0, $outputlangs), + 'line_multicurrency_total_tva_locale' => price($line->multicurrency_total_tva, 0, $outputlangs), + 'line_multicurrency_total_ttc_locale' => price($line->multicurrency_total_ttc, 0, $outputlangs), ); - // Units + // Units if ($conf->global->PRODUCT_USE_UNITS) { - $resarray['line_unit'] = $outputlangs->trans($line->getLabelOfUnit('long')); - $resarray['line_unit_short'] = $outputlangs->trans($line->getLabelOfUnit('short')); - } + $resarray['line_unit'] = $outputlangs->trans($line->getLabelOfUnit('long')); + $resarray['line_unit_short'] = $outputlangs->trans($line->getLabelOfUnit('short')); + } // Retrieve extrafields $extrafieldkey = $line->table_element; @@ -585,14 +585,14 @@ abstract class CommonDocGenerator $extrafields->fetch_name_optionals_label($extrafieldkey, true); $line->fetch_optionals(); - $resarray = $this->fill_substitutionarray_with_extrafields($line, $resarray, $extrafields, $array_key, $outputlangs); + $resarray = $this->fill_substitutionarray_with_extrafields($line, $resarray, $extrafields, $array_key, $outputlangs); - // Check if the current line belongs to a supplier order - if (get_class($line) == 'CommandeFournisseurLigne') - { - // Add the product supplier extrafields to the substitutions - $extrafields->fetch_name_optionals_label("product_fournisseur_price"); - $extralabels = $extrafields->attributes["product_fournisseur_price"]['label']; + // Check if the current line belongs to a supplier order + if (get_class($line) == 'CommandeFournisseurLigne') + { + // Add the product supplier extrafields to the substitutions + $extrafields->fetch_name_optionals_label("product_fournisseur_price"); + $extralabels = $extrafields->attributes["product_fournisseur_price"]['label']; if (!empty($extralabels) && is_array($extralabels)) { @@ -619,7 +619,7 @@ abstract class CommonDocGenerator } } } - } + } // Load product data optional fields to the line -> enables to use "line_options_{extrafield}" if (isset($line->fk_product) && $line->fk_product > 0) @@ -633,158 +633,158 @@ abstract class CommonDocGenerator return $resarray; } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Define array with couple substitution key => substitution value - * - * @param Expedition $object Main object to use as data source - * @param Translate $outputlangs Lang object to use for output - * @param array $array_key Name of the key for return array - * @return array Array of substitution - */ - public function get_substitutionarray_shipment($object, $outputlangs, $array_key = 'object') - { - // phpcs:enable - global $conf, $extrafields; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Define array with couple substitution key => substitution value + * + * @param Expedition $object Main object to use as data source + * @param Translate $outputlangs Lang object to use for output + * @param array $array_key Name of the key for return array + * @return array Array of substitution + */ + public function get_substitutionarray_shipment($object, $outputlangs, $array_key = 'object') + { + // phpcs:enable + global $conf, $extrafields; dol_include_once('/core/lib/product.lib.php'); $object->list_delivery_methods($object->shipping_method_id); $calculatedVolume = ($object->trueWidth * $object->trueHeight * $object->trueDepth); - $array_shipment = array( - $array_key.'_id'=>$object->id, - $array_key.'_ref'=>$object->ref, - $array_key.'_ref_ext'=>$object->ref_ext, - $array_key.'_ref_customer'=>$object->ref_customer, - $array_key.'_date_delivery'=>dol_print_date($object->date_delivery, 'day'), - $array_key.'_hour_delivery'=>dol_print_date($object->date_delivery, 'hour'), - $array_key.'_date_creation'=>dol_print_date($object->date_creation, 'day'), - $array_key.'_total_ht'=>price($object->total_ht), - $array_key.'_total_vat'=>price($object->total_tva), - $array_key.'_total_ttc'=>price($object->total_ttc), - $array_key.'_total_discount_ht' => price($object->getTotalDiscount()), - $array_key.'_note_private'=>$object->note_private, - $array_key.'_note'=>$object->note_public, - $array_key.'_tracking_number'=>$object->tracking_number, - $array_key.'_tracking_url'=>$object->tracking_url, - $array_key.'_shipping_method'=>$object->listmeths[0]['libelle'], - $array_key.'_weight'=>$object->trueWeight.' '.measuringUnitString(0, 'weight', $object->weight_units), - $array_key.'_width'=>$object->trueWidth.' '.measuringUnitString(0, 'size', $object->width_units), - $array_key.'_height'=>$object->trueHeight.' '.measuringUnitString(0, 'size', $object->height_units), - $array_key.'_depth'=>$object->trueDepth.' '.measuringUnitString(0, 'size', $object->depth_units), - $array_key.'_size'=>$calculatedVolume.' '.measuringUnitString(0, 'volume'), - ); + $array_shipment = array( + $array_key.'_id'=>$object->id, + $array_key.'_ref'=>$object->ref, + $array_key.'_ref_ext'=>$object->ref_ext, + $array_key.'_ref_customer'=>$object->ref_customer, + $array_key.'_date_delivery'=>dol_print_date($object->date_delivery, 'day'), + $array_key.'_hour_delivery'=>dol_print_date($object->date_delivery, 'hour'), + $array_key.'_date_creation'=>dol_print_date($object->date_creation, 'day'), + $array_key.'_total_ht'=>price($object->total_ht), + $array_key.'_total_vat'=>price($object->total_tva), + $array_key.'_total_ttc'=>price($object->total_ttc), + $array_key.'_total_discount_ht' => price($object->getTotalDiscount()), + $array_key.'_note_private'=>$object->note_private, + $array_key.'_note'=>$object->note_public, + $array_key.'_tracking_number'=>$object->tracking_number, + $array_key.'_tracking_url'=>$object->tracking_url, + $array_key.'_shipping_method'=>$object->listmeths[0]['libelle'], + $array_key.'_weight'=>$object->trueWeight.' '.measuringUnitString(0, 'weight', $object->weight_units), + $array_key.'_width'=>$object->trueWidth.' '.measuringUnitString(0, 'size', $object->width_units), + $array_key.'_height'=>$object->trueHeight.' '.measuringUnitString(0, 'size', $object->height_units), + $array_key.'_depth'=>$object->trueDepth.' '.measuringUnitString(0, 'size', $object->depth_units), + $array_key.'_size'=>$calculatedVolume.' '.measuringUnitString(0, 'volume'), + ); - // Add vat by rates - foreach ($object->lines as $line) - { - if (empty($array_shipment[$array_key.'_total_vat_'.$line->tva_tx])) $array_shipment[$array_key.'_total_vat_'.$line->tva_tx] = 0; - $array_shipment[$array_key.'_total_vat_'.$line->tva_tx] += $line->total_tva; - } + // Add vat by rates + foreach ($object->lines as $line) + { + if (empty($array_shipment[$array_key.'_total_vat_'.$line->tva_tx])) $array_shipment[$array_key.'_total_vat_'.$line->tva_tx] = 0; + $array_shipment[$array_key.'_total_vat_'.$line->tva_tx] += $line->total_tva; + } - // Retrieve extrafields - if (is_array($object->array_options) && count($object->array_options)) - { - $object->fetch_optionals(); + // Retrieve extrafields + if (is_array($object->array_options) && count($object->array_options)) + { + $object->fetch_optionals(); - $array_shipment = $this->fill_substitutionarray_with_extrafields($object, $array_shipment, $extrafields, $array_key, $outputlangs); - } + $array_shipment = $this->fill_substitutionarray_with_extrafields($object, $array_shipment, $extrafields, $array_key, $outputlangs); + } - return $array_shipment; - } + return $array_shipment; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Define array with couple substitution key => substitution value - * - * @param ExpeditionLigne $line Object line - * @param Translate $outputlangs Lang object to use for output - * @return array Substitution array - */ - public function get_substitutionarray_shipment_lines($line, $outputlangs) - { - // phpcs:enable - global $conf; - dol_include_once('/core/lib/product.lib.php'); + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Define array with couple substitution key => substitution value + * + * @param ExpeditionLigne $line Object line + * @param Translate $outputlangs Lang object to use for output + * @return array Substitution array + */ + public function get_substitutionarray_shipment_lines($line, $outputlangs) + { + // phpcs:enable + global $conf; + dol_include_once('/core/lib/product.lib.php'); - $resarray = array( - 'line_fulldesc'=>doc_getlinedesc($line, $outputlangs), - 'line_product_ref'=>$line->product_ref, - 'line_product_label'=>$line->product_label, - 'line_desc'=>$line->desc, - 'line_vatrate'=>vatrate($line->tva_tx, true, $line->info_bits), - 'line_up'=>price($line->subprice), - 'line_total_up'=>price($line->subprice * $line->qty), - 'line_qty'=>$line->qty, - 'line_qty_shipped'=>$line->qty_shipped, - 'line_qty_asked'=>$line->qty_asked, - 'line_discount_percent'=>($line->remise_percent ? $line->remise_percent.'%' : ''), - 'line_price_ht'=>price($line->total_ht), - 'line_price_ttc'=>price($line->total_ttc), - 'line_price_vat'=>price($line->total_tva), - 'line_weight'=>empty($line->weight) ? '' : $line->weight * $line->qty_shipped.' '.measuringUnitString(0, 'weight', $line->weight_units), - 'line_length'=>empty($line->length) ? '' : $line->length * $line->qty_shipped.' '.measuringUnitString(0, 'size', $line->length_units), - 'line_surface'=>empty($line->surface) ? '' : $line->surface * $line->qty_shipped.' '.measuringUnitString(0, 'surface', $line->surface_units), - 'line_volume'=>empty($line->volume) ? '' : $line->volume * $line->qty_shipped.' '.measuringUnitString(0, 'volume', $line->volume_units), - ); + $resarray = array( + 'line_fulldesc'=>doc_getlinedesc($line, $outputlangs), + 'line_product_ref'=>$line->product_ref, + 'line_product_label'=>$line->product_label, + 'line_desc'=>$line->desc, + 'line_vatrate'=>vatrate($line->tva_tx, true, $line->info_bits), + 'line_up'=>price($line->subprice), + 'line_total_up'=>price($line->subprice * $line->qty), + 'line_qty'=>$line->qty, + 'line_qty_shipped'=>$line->qty_shipped, + 'line_qty_asked'=>$line->qty_asked, + 'line_discount_percent'=>($line->remise_percent ? $line->remise_percent.'%' : ''), + 'line_price_ht'=>price($line->total_ht), + 'line_price_ttc'=>price($line->total_ttc), + 'line_price_vat'=>price($line->total_tva), + 'line_weight'=>empty($line->weight) ? '' : $line->weight * $line->qty_shipped.' '.measuringUnitString(0, 'weight', $line->weight_units), + 'line_length'=>empty($line->length) ? '' : $line->length * $line->qty_shipped.' '.measuringUnitString(0, 'size', $line->length_units), + 'line_surface'=>empty($line->surface) ? '' : $line->surface * $line->qty_shipped.' '.measuringUnitString(0, 'surface', $line->surface_units), + 'line_volume'=>empty($line->volume) ? '' : $line->volume * $line->qty_shipped.' '.measuringUnitString(0, 'volume', $line->volume_units), + ); - // Retrieve extrafields - $extrafieldkey = $line->element; - $array_key = "line"; - require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; - $extrafields = new ExtraFields($this->db); - $extrafields->fetch_name_optionals_label($extrafieldkey, true); - $line->fetch_optionals(); + // Retrieve extrafields + $extrafieldkey = $line->element; + $array_key = "line"; + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + $extrafields->fetch_name_optionals_label($extrafieldkey, true); + $line->fetch_optionals(); - $resarray = $this->fill_substitutionarray_with_extrafields($line, $resarray, $extrafields, $array_key, $outputlangs); + $resarray = $this->fill_substitutionarray_with_extrafields($line, $resarray, $extrafields, $array_key, $outputlangs); - return $resarray; - } + return $resarray; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Define array with couple substitution key => substitution value - * - * @param Object $object Dolibarr Object - * @param Translate $outputlangs Language object for output - * @param boolean $recursive Want to fetch child array or child object - * @return array Array of substitution key->code - */ - public function get_substitutionarray_each_var_object(&$object, $outputlangs, $recursive = true) - { - // phpcs:enable - $array_other = array(); - if (!empty($object)) { - foreach ($object as $key => $value) { - if (!empty($value)) { - if (!is_array($value) && !is_object($value)) { - $array_other['object_'.$key] = $value; - } - if (is_array($value) && $recursive) { - $array_other['object_'.$key] = $this->get_substitutionarray_each_var_object($value, $outputlangs, false); - } - } - } - } - return $array_other; - } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Define array with couple substitution key => substitution value + * + * @param Object $object Dolibarr Object + * @param Translate $outputlangs Language object for output + * @param boolean $recursive Want to fetch child array or child object + * @return array Array of substitution key->code + */ + public function get_substitutionarray_each_var_object(&$object, $outputlangs, $recursive = true) + { + // phpcs:enable + $array_other = array(); + if (!empty($object)) { + foreach ($object as $key => $value) { + if (!empty($value)) { + if (!is_array($value) && !is_object($value)) { + $array_other['object_'.$key] = $value; + } + if (is_array($value) && $recursive) { + $array_other['object_'.$key] = $this->get_substitutionarray_each_var_object($value, $outputlangs, false); + } + } + } + } + return $array_other; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Fill array with couple extrafield key => extrafield value - * - * @param Object $object Object with extrafields (must have $object->array_options filled) - * @param array $array_to_fill Substitution array - * @param Extrafields $extrafields Extrafields object - * @param string $array_key Prefix for name of the keys into returned array - * @param Translate $outputlangs Lang object to use for output - * @return array Substitution array - */ - public function fill_substitutionarray_with_extrafields($object, $array_to_fill, $extrafields, $array_key, $outputlangs) - { - // phpcs:enable + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Fill array with couple extrafield key => extrafield value + * + * @param Object $object Object with extrafields (must have $object->array_options filled) + * @param array $array_to_fill Substitution array + * @param Extrafields $extrafields Extrafields object + * @param string $array_key Prefix for name of the keys into returned array + * @param Translate $outputlangs Lang object to use for output + * @return array Substitution array + */ + public function fill_substitutionarray_with_extrafields($object, $array_to_fill, $extrafields, $array_key, $outputlangs) + { + // phpcs:enable global $conf; if (is_array($extrafields->attributes[$object->table_element]['label'])) { @@ -875,671 +875,671 @@ abstract class CommonDocGenerator * @param int $hidebottom Hide bottom * @return void */ - public function printRect($pdf, $x, $y, $l, $h, $hidetop = 0, $hidebottom = 0) - { - if (empty($hidetop) || $hidetop == -1) $pdf->line($x, $y, $x + $l, $y); - $pdf->line($x + $l, $y, $x + $l, $y + $h); - if (empty($hidebottom)) $pdf->line($x + $l, $y + $h, $x, $y + $h); - $pdf->line($x, $y + $h, $x, $y); - } - - - /** - * uasort callback function to Sort columns fields - * - * @param array $a PDF lines array fields configs - * @param array $b PDF lines array fields configs - * @return int Return compare result - */ - public function columnSort($a, $b) - { - if (empty($a['rank'])) { $a['rank'] = 0; } - if (empty($b['rank'])) { $b['rank'] = 0; } - if ($a['rank'] == $b['rank']) { - return 0; - } - return ($a['rank'] > $b['rank']) ? -1 : 1; - } - - /** - * Prepare Array Column Field - * - * @param object $object common object - * @param Translate $outputlangs langs - * @param int $hidedetails Do not show line details - * @param int $hidedesc Do not show desc - * @param int $hideref Do not show ref - * @return null - */ - public function prepareArrayColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0) - { - global $conf; - - $this->defineColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref); - - - // Sorting - uasort($this->cols, array($this, 'columnSort')); - - // Positionning - $curX = $this->page_largeur - $this->marge_droite; // start from right - - // Array width - $arrayWidth = $this->page_largeur - $this->marge_droite - $this->marge_gauche; - - // Count flexible column - $totalDefinedColWidth = 0; - $countFlexCol = 0; - foreach ($this->cols as $colKey =>& $colDef) - { - if (!$this->getColumnStatus($colKey)) continue; // continue if disabled - - if (!empty($colDef['scale'])) { - // In case of column width is defined by percentage - $colDef['width'] = abs($arrayWidth * $colDef['scale'] / 100); - } - - if (empty($colDef['width'])) { - $countFlexCol++; - } else { - $totalDefinedColWidth += $colDef['width']; - } - } - - foreach ($this->cols as $colKey =>& $colDef) - { - // setting empty conf with default - if (!empty($colDef['title'])) { - $colDef['title'] = array_replace($this->defaultTitlesFieldsStyle, $colDef['title']); - } else { - $colDef['title'] = $this->defaultTitlesFieldsStyle; - } - - // setting empty conf with default - if (!empty($colDef['content'])) { - $colDef['content'] = array_replace($this->defaultContentsFieldsStyle, $colDef['content']); - } else { - $colDef['content'] = $this->defaultContentsFieldsStyle; - } - - if ($this->getColumnStatus($colKey)) - { - // In case of flexible column - if (empty($colDef['width'])) { - $colDef['width'] = abs(($arrayWidth - $totalDefinedColWidth)) / $countFlexCol; - } - - // Set positions - $lastX = $curX; - $curX = $lastX - $colDef['width']; - $colDef['xStartPos'] = $curX; - $colDef['xEndPos'] = $lastX; - } - } - } - - /** - * get column content width from column key - * - * @param string $colKey the column key - * @return float width in mm - */ - public function getColumnContentWidth($colKey) - { - $colDef = $this->cols[$colKey]; - return $colDef['width'] - $colDef['content']['padding'][3] - $colDef['content']['padding'][1]; - } - - - /** - * get column content X (abscissa) left position from column key - * - * @param string $colKey the column key - * @return float X position in mm - */ - public function getColumnContentXStart($colKey) - { - $colDef = $this->cols[$colKey]; - return $colDef['xStartPos'] + $colDef['content']['padding'][3]; - } - - /** - * get column position rank from column key - * - * @param string $colKey the column key - * @return int rank on success and -1 on error - */ - public function getColumnRank($colKey) - { - if (!isset($this->cols[$colKey]['rank'])) return -1; - return $this->cols[$colKey]['rank']; - } - - /** - * get column position rank from column key - * - * @param string $newColKey the new column key - * @param array $defArray a single column definition array - * @param string $targetCol target column used to place the new column beside - * @param bool $insertAfterTarget insert before or after target column ? - * @return int new rank on success and -1 on error - */ - public function insertNewColumnDef($newColKey, $defArray, $targetCol = false, $insertAfterTarget = false) - { - // prepare wanted rank - $rank = -1; - - // try to get rank from target column - if (!empty($targetCol)) { - $rank = $this->getColumnRank($targetCol); - if ($rank >= 0 && $insertAfterTarget) { $rank++; } - } - - // get rank from new column definition - if ($rank < 0 && !empty($defArray['rank'])) { - $rank = $defArray['rank']; - } - - // error: no rank - if ($rank < 0) { return -1; } - - foreach ($this->cols as $colKey =>& $colDef) - { - if ($rank <= $colDef['rank']) - { - $colDef['rank'] = $colDef['rank'] + 1; - } - } - - $defArray['rank'] = $rank; - $this->cols[$newColKey] = $defArray; // array_replace is used to preserve keys - - return $rank; - } - - - /** - * print standard column content - * - * @param TCPDF $pdf pdf object - * @param float $curY curent Y position - * @param string $colKey the column key - * @param string $columnText column text - * @return null - */ - public function printStdColumnContent($pdf, &$curY, $colKey, $columnText = '') - { - global $hookmanager; - - $parameters = array( - 'curY' => &$curY, - 'columnText' => $columnText, - 'colKey' => $colKey, - 'pdf' => &$pdf, - ); - $reshook = $hookmanager->executeHooks('printStdColumnContent', $parameters, $this); // Note that $action and $object may have been modified by hook - if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - if (!$reshook) - { - if (empty($columnText)) return; - $pdf->SetXY($this->getColumnContentXStart($colKey), $curY); // Set curent position - $colDef = $this->cols[$colKey]; - // save curent cell padding - $curentCellPaddinds = $pdf->getCellPaddings(); - // set cell padding with column content definition - $pdf->setCellPaddings($colDef['content']['padding'][3], $colDef['content']['padding'][0], $colDef['content']['padding'][1], $colDef['content']['padding'][2]); - $pdf->writeHTMLCell($colDef['width'], 2, $colDef['xStartPos'], $curY, $columnText, 0, 1, 0, true, $colDef['content']['align']); - - // restore cell padding - $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']); - } - } - - - /** - * print description column content - * - * @param TCPDF $pdf pdf object - * @param float $curY curent Y position - * @param string $colKey the column key - * @param object $object CommonObject - * @param int $i the $object->lines array key - * @param Translate $outputlangs Output language - * @param int $hideref hide ref - * @param int $hidedesc hide desc - * @param int $issupplierline if object need supplier product - * @return null - */ - public function printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $issupplierline = 0) + public function printRect($pdf, $x, $y, $l, $h, $hidetop = 0, $hidebottom = 0) { - // load desc col params - $colDef = $this->cols[$colKey]; - // save curent cell padding - $curentCellPaddinds = $pdf->getCellPaddings(); - // set cell padding with column content definition - $pdf->setCellPaddings($colDef['content']['padding'][3], $colDef['content']['padding'][0], $colDef['content']['padding'][1], $colDef['content']['padding'][2]); - - // line description - pdf_writelinedesc($pdf, $object, $i, $outputlangs, $colDef['width'], 3, $colDef['xStartPos'], $curY, $hideref, $hidedesc, $issupplierline); - $posYAfterDescription = $pdf->GetY() - $colDef['content']['padding'][0]; - - // restore cell padding - $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']); - - // Display extrafield if needed - $params = array( - 'display' => 'list', - 'printableEnable' => array(3), - 'printableEnableNotEmpty' => array(4) - ); - $extrafieldDesc = $this->getExtrafieldsInHtml($object->lines[$i], $outputlangs, $params); - if (!empty($extrafieldDesc)) { - $this->printStdColumnContent($pdf, $posYAfterDescription, $colKey, $extrafieldDesc); - } - } - - /** - * get extrafield content for pdf writeHtmlCell compatibility - * usage for PDF line columns and object note block - * - * @param object $object common object - * @param string $extrafieldKey the extrafield key - * @return string - */ - public function getExtrafieldContent($object, $extrafieldKey) - { - global $hookmanager; - - if (empty($object->table_element)) { return; } - - $extrafieldsKeyPrefix = "options_"; - - // Cleanup extrafield key to remove prefix if present - $pos = strpos($extrafieldKey, $extrafieldsKeyPrefix); - if ($pos === 0) { - $extrafieldKey = substr($extrafieldKey, strlen($extrafieldsKeyPrefix)); - } - - $extrafieldOptionsKey = $extrafieldsKeyPrefix.$extrafieldKey; + if (empty($hidetop) || $hidetop == -1) $pdf->line($x, $y, $x + $l, $y); + $pdf->line($x + $l, $y, $x + $l, $y + $h); + if (empty($hidebottom)) $pdf->line($x + $l, $y + $h, $x, $y + $h); + $pdf->line($x, $y + $h, $x, $y); + } - // Load extrafiels if not allready does - if (empty($this->extrafieldsCache)) { $this->extrafieldsCache = new ExtraFields($this->db); } - if (empty($this->extrafieldsCache->attributes[$object->table_element])) { $this->extrafieldsCache->fetch_name_optionals_label($object->table_element); } - $extrafields = $this->extrafieldsCache; + /** + * uasort callback function to Sort columns fields + * + * @param array $a PDF lines array fields configs + * @param array $b PDF lines array fields configs + * @return int Return compare result + */ + public function columnSort($a, $b) + { + if (empty($a['rank'])) { $a['rank'] = 0; } + if (empty($b['rank'])) { $b['rank'] = 0; } + if ($a['rank'] == $b['rank']) { + return 0; + } + return ($a['rank'] > $b['rank']) ? -1 : 1; + } - $extrafieldOutputContent = $extrafields->showOutputField($extrafieldKey, $object->array_options[$extrafieldOptionsKey], '', $object->table_element); + /** + * Prepare Array Column Field + * + * @param object $object common object + * @param Translate $outputlangs langs + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return null + */ + public function prepareArrayColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0) + { + global $conf; - // TODO : allow showOutputField to be pdf public friendly, ex: in a link to object, clean getNomUrl to remove link and images... like a getName methode ... - if ($extrafields->attributes[$object->table_element]['type'][$extrafieldKey] == 'link') { - // for lack of anything better we cleanup all html tags - $extrafieldOutputContent = dol_string_nohtmltag($extrafieldOutputContent); - } - - $parameters = array( - 'object' => $object, - 'extrafields' => $extrafields, - 'extrafieldKey' => $extrafieldKey, - 'extrafieldOutputContent' =>& $extrafieldOutputContent - ); - $reshook = $hookmanager->executeHooks('getPDFExtrafieldContent', $parameters, $this); // Note that $action and $object may have been modified by hook - if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - if ($reshook) - { - $extrafieldOutputContent = $hookmanager->resPrint; - } - - return $extrafieldOutputContent; - } + $this->defineColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref); - /** - * display extrafields columns content - * - * @param object $object line of common object - * @param Translate $outputlangs Output language - * @param array $params array of additionals parameters - * @return double max y value - */ - public function getExtrafieldsInHtml($object, $outputlangs, $params = array()) - { - global $hookmanager; + // Sorting + uasort($this->cols, array($this, 'columnSort')); - if (empty($object->table_element)) { - return; - } + // Positionning + $curX = $this->page_largeur - $this->marge_droite; // start from right - // Load extrafiels if not allready does - if (empty($this->extrafieldsCache)) { $this->extrafieldsCache = new ExtraFields($this->db); } - if (empty($this->extrafieldsCache->attributes[$object->table_element])) { $this->extrafieldsCache->fetch_name_optionals_label($object->table_element); } - $extrafields = $this->extrafieldsCache; + // Array width + $arrayWidth = $this->page_largeur - $this->marge_droite - $this->marge_gauche; - $defaultParams = array( - 'style' => '', - 'display' => 'auto', // auto, table, list - 'printableEnable' => array(1), - 'printableEnableNotEmpty' => array(2), + // Count flexible column + $totalDefinedColWidth = 0; + $countFlexCol = 0; + foreach ($this->cols as $colKey =>& $colDef) + { + if (!$this->getColumnStatus($colKey)) continue; // continue if disabled - 'table' => array( - 'maxItemsInRow' => 2, - 'cellspacing' => 0, - 'cellpadding' => 0, - 'border' => 0, - 'labelcolwidth' => '25%', - 'arrayOfLineBreakType' => array('text', 'html') - ), + if (!empty($colDef['scale'])) { + // In case of column width is defined by percentage + $colDef['width'] = abs($arrayWidth * $colDef['scale'] / 100); + } - 'list' => array( - 'separator' => '
' - ), + if (empty($colDef['width'])) { + $countFlexCol++; + } else { + $totalDefinedColWidth += $colDef['width']; + } + } - 'auto' => array( - 'list' => 0, // 0 for default - 'table' => 4 // if there more than x extrafield to display - ), - ); + foreach ($this->cols as $colKey =>& $colDef) + { + // setting empty conf with default + if (!empty($colDef['title'])) { + $colDef['title'] = array_replace($this->defaultTitlesFieldsStyle, $colDef['title']); + } else { + $colDef['title'] = $this->defaultTitlesFieldsStyle; + } - $params = $params + $defaultParams; + // setting empty conf with default + if (!empty($colDef['content'])) { + $colDef['content'] = array_replace($this->defaultContentsFieldsStyle, $colDef['content']); + } else { + $colDef['content'] = $this->defaultContentsFieldsStyle; + } + + if ($this->getColumnStatus($colKey)) + { + // In case of flexible column + if (empty($colDef['width'])) { + $colDef['width'] = abs(($arrayWidth - $totalDefinedColWidth)) / $countFlexCol; + } + + // Set positions + $lastX = $curX; + $curX = $lastX - $colDef['width']; + $colDef['xStartPos'] = $curX; + $colDef['xEndPos'] = $lastX; + } + } + } + + /** + * get column content width from column key + * + * @param string $colKey the column key + * @return float width in mm + */ + public function getColumnContentWidth($colKey) + { + $colDef = $this->cols[$colKey]; + return $colDef['width'] - $colDef['content']['padding'][3] - $colDef['content']['padding'][1]; + } - /** - * @var $extrafields ExtraFields - */ + /** + * get column content X (abscissa) left position from column key + * + * @param string $colKey the column key + * @return float X position in mm + */ + public function getColumnContentXStart($colKey) + { + $colDef = $this->cols[$colKey]; + return $colDef['xStartPos'] + $colDef['content']['padding'][3]; + } - $html = ''; - $fields = array(); + /** + * get column position rank from column key + * + * @param string $colKey the column key + * @return int rank on success and -1 on error + */ + public function getColumnRank($colKey) + { + if (!isset($this->cols[$colKey]['rank'])) return -1; + return $this->cols[$colKey]['rank']; + } - if (is_array($extrafields->attributes[$object->table_element]['label'])) { - foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) - { - // Enable extrafield ? - $enabled = 0; - $disableOnEmpty = 0; - if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) { - $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]); - if (in_array($printable, $params['printableEnable']) || in_array($printable, $params['printableEnableNotEmpty'])) { - $enabled = 1; - } + /** + * get column position rank from column key + * + * @param string $newColKey the new column key + * @param array $defArray a single column definition array + * @param string $targetCol target column used to place the new column beside + * @param bool $insertAfterTarget insert before or after target column ? + * @return int new rank on success and -1 on error + */ + public function insertNewColumnDef($newColKey, $defArray, $targetCol = false, $insertAfterTarget = false) + { + // prepare wanted rank + $rank = -1; - if (in_array($printable, $params['printableEnableNotEmpty'])) { - $disableOnEmpty = 1; - } - } + // try to get rank from target column + if (!empty($targetCol)) { + $rank = $this->getColumnRank($targetCol); + if ($rank >= 0 && $insertAfterTarget) { $rank++; } + } - if (empty($enabled)) { - continue; - } + // get rank from new column definition + if ($rank < 0 && !empty($defArray['rank'])) { + $rank = $defArray['rank']; + } - $field = new stdClass(); - $field->rank = intval($extrafields->attributes[$object->table_element]['pos'][$key]); - $field->content = $this->getExtrafieldContent($object, $key); - $field->label = $outputlangs->transnoentities($label); - $field->type = $extrafields->attributes[$object->table_element]['type'][$key]; + // error: no rank + if ($rank < 0) { return -1; } - // dont display if empty - if ($disableOnEmpty && empty($field->content)) { - continue; - } + foreach ($this->cols as $colKey =>& $colDef) + { + if ($rank <= $colDef['rank']) + { + $colDef['rank'] = $colDef['rank'] + 1; + } + } - $fields[] = $field; - } - } + $defArray['rank'] = $rank; + $this->cols[$newColKey] = $defArray; // array_replace is used to preserve keys - if (!empty($fields)) - { - // Sort extrafields by rank - uasort($fields, function ($a, $b) { - return ($a->rank > $b->rank) ? 1 : -1; + return $rank; + } + + + /** + * print standard column content + * + * @param TCPDF $pdf pdf object + * @param float $curY curent Y position + * @param string $colKey the column key + * @param string $columnText column text + * @return null + */ + public function printStdColumnContent($pdf, &$curY, $colKey, $columnText = '') + { + global $hookmanager; + + $parameters = array( + 'curY' => &$curY, + 'columnText' => $columnText, + 'colKey' => $colKey, + 'pdf' => &$pdf, + ); + $reshook = $hookmanager->executeHooks('printStdColumnContent', $parameters, $this); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + if (!$reshook) + { + if (empty($columnText)) return; + $pdf->SetXY($this->getColumnContentXStart($colKey), $curY); // Set curent position + $colDef = $this->cols[$colKey]; + // save curent cell padding + $curentCellPaddinds = $pdf->getCellPaddings(); + // set cell padding with column content definition + $pdf->setCellPaddings($colDef['content']['padding'][3], $colDef['content']['padding'][0], $colDef['content']['padding'][1], $colDef['content']['padding'][2]); + $pdf->writeHTMLCell($colDef['width'], 2, $colDef['xStartPos'], $curY, $columnText, 0, 1, 0, true, $colDef['content']['align']); + + // restore cell padding + $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']); + } + } + + + /** + * print description column content + * + * @param TCPDF $pdf pdf object + * @param float $curY curent Y position + * @param string $colKey the column key + * @param object $object CommonObject + * @param int $i the $object->lines array key + * @param Translate $outputlangs Output language + * @param int $hideref hide ref + * @param int $hidedesc hide desc + * @param int $issupplierline if object need supplier product + * @return null + */ + public function printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $issupplierline = 0) + { + // load desc col params + $colDef = $this->cols[$colKey]; + // save curent cell padding + $curentCellPaddinds = $pdf->getCellPaddings(); + // set cell padding with column content definition + $pdf->setCellPaddings($colDef['content']['padding'][3], $colDef['content']['padding'][0], $colDef['content']['padding'][1], $colDef['content']['padding'][2]); + + // line description + pdf_writelinedesc($pdf, $object, $i, $outputlangs, $colDef['width'], 3, $colDef['xStartPos'], $curY, $hideref, $hidedesc, $issupplierline); + $posYAfterDescription = $pdf->GetY() - $colDef['content']['padding'][0]; + + // restore cell padding + $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']); + + // Display extrafield if needed + $params = array( + 'display' => 'list', + 'printableEnable' => array(3), + 'printableEnableNotEmpty' => array(4) + ); + $extrafieldDesc = $this->getExtrafieldsInHtml($object->lines[$i], $outputlangs, $params); + if (!empty($extrafieldDesc)) { + $this->printStdColumnContent($pdf, $posYAfterDescription, $colKey, $extrafieldDesc); + } + } + + /** + * get extrafield content for pdf writeHtmlCell compatibility + * usage for PDF line columns and object note block + * + * @param object $object common object + * @param string $extrafieldKey the extrafield key + * @return string + */ + public function getExtrafieldContent($object, $extrafieldKey) + { + global $hookmanager; + + if (empty($object->table_element)) { return; } + + $extrafieldsKeyPrefix = "options_"; + + // Cleanup extrafield key to remove prefix if present + $pos = strpos($extrafieldKey, $extrafieldsKeyPrefix); + if ($pos === 0) { + $extrafieldKey = substr($extrafieldKey, strlen($extrafieldsKeyPrefix)); + } + + $extrafieldOptionsKey = $extrafieldsKeyPrefix.$extrafieldKey; + + + // Load extrafiels if not allready does + if (empty($this->extrafieldsCache)) { $this->extrafieldsCache = new ExtraFields($this->db); } + if (empty($this->extrafieldsCache->attributes[$object->table_element])) { $this->extrafieldsCache->fetch_name_optionals_label($object->table_element); } + $extrafields = $this->extrafieldsCache; + + $extrafieldOutputContent = $extrafields->showOutputField($extrafieldKey, $object->array_options[$extrafieldOptionsKey], '', $object->table_element); + + // TODO : allow showOutputField to be pdf public friendly, ex: in a link to object, clean getNomUrl to remove link and images... like a getName methode ... + if ($extrafields->attributes[$object->table_element]['type'][$extrafieldKey] == 'link') { + // for lack of anything better we cleanup all html tags + $extrafieldOutputContent = dol_string_nohtmltag($extrafieldOutputContent); + } + + $parameters = array( + 'object' => $object, + 'extrafields' => $extrafields, + 'extrafieldKey' => $extrafieldKey, + 'extrafieldOutputContent' =>& $extrafieldOutputContent + ); + $reshook = $hookmanager->executeHooks('getPDFExtrafieldContent', $parameters, $this); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + if ($reshook) + { + $extrafieldOutputContent = $hookmanager->resPrint; + } + + return $extrafieldOutputContent; + } + + + /** + * display extrafields columns content + * + * @param object $object line of common object + * @param Translate $outputlangs Output language + * @param array $params array of additionals parameters + * @return double max y value + */ + public function getExtrafieldsInHtml($object, $outputlangs, $params = array()) + { + global $hookmanager; + + if (empty($object->table_element)) { + return; + } + + // Load extrafiels if not allready does + if (empty($this->extrafieldsCache)) { $this->extrafieldsCache = new ExtraFields($this->db); } + if (empty($this->extrafieldsCache->attributes[$object->table_element])) { $this->extrafieldsCache->fetch_name_optionals_label($object->table_element); } + $extrafields = $this->extrafieldsCache; + + $defaultParams = array( + 'style' => '', + 'display' => 'auto', // auto, table, list + 'printableEnable' => array(1), + 'printableEnableNotEmpty' => array(2), + + 'table' => array( + 'maxItemsInRow' => 2, + 'cellspacing' => 0, + 'cellpadding' => 0, + 'border' => 0, + 'labelcolwidth' => '25%', + 'arrayOfLineBreakType' => array('text', 'html') + ), + + 'list' => array( + 'separator' => '
' + ), + + 'auto' => array( + 'list' => 0, // 0 for default + 'table' => 4 // if there more than x extrafield to display + ), + ); + + $params = $params + $defaultParams; + + + /** + * @var $extrafields ExtraFields + */ + + $html = ''; + $fields = array(); + + if (is_array($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) + { + // Enable extrafield ? + $enabled = 0; + $disableOnEmpty = 0; + if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) { + $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]); + if (in_array($printable, $params['printableEnable']) || in_array($printable, $params['printableEnableNotEmpty'])) { + $enabled = 1; + } + + if (in_array($printable, $params['printableEnableNotEmpty'])) { + $disableOnEmpty = 1; + } + } + + if (empty($enabled)) { + continue; + } + + $field = new stdClass(); + $field->rank = intval($extrafields->attributes[$object->table_element]['pos'][$key]); + $field->content = $this->getExtrafieldContent($object, $key); + $field->label = $outputlangs->transnoentities($label); + $field->type = $extrafields->attributes[$object->table_element]['type'][$key]; + + // dont display if empty + if ($disableOnEmpty && empty($field->content)) { + continue; + } + + $fields[] = $field; + } + } + + if (!empty($fields)) + { + // Sort extrafields by rank + uasort($fields, function ($a, $b) { + return ($a->rank > $b->rank) ? 1 : -1; }); - // define some HTML content with style - $html .= !empty($params['style']) ? '' : ''; + // define some HTML content with style + $html .= !empty($params['style']) ? '' : ''; - // auto select display format - if ($params['display'] == 'auto') { - $lastNnumbItems = 0; - foreach ($params['auto'] as $display => $numbItems) { - if ($lastNnumbItems <= $numbItems && count($fields) > $numbItems) { - $lastNnumbItems = $numbItems; - $params['display'] = $display; - } - } - } + // auto select display format + if ($params['display'] == 'auto') { + $lastNnumbItems = 0; + foreach ($params['auto'] as $display => $numbItems) { + if ($lastNnumbItems <= $numbItems && count($fields) > $numbItems) { + $lastNnumbItems = $numbItems; + $params['display'] = $display; + } + } + } - if ($params['display'] == 'list') { - // Display in list format - $i = 0; - foreach ($fields as $field) { - $html .= !empty($i) ? $params['list']['separator'] : ''; - $html .= ''.$field->label.' : '; - $html .= $field->content; - $i++; - } - } elseif ($params['display'] == 'table') { - // Display in table format - $html .= ''; + if ($params['display'] == 'list') { + // Display in list format + $i = 0; + foreach ($fields as $field) { + $html .= !empty($i) ? $params['list']['separator'] : ''; + $html .= ''.$field->label.' : '; + $html .= $field->content; + $i++; + } + } elseif ($params['display'] == 'table') { + // Display in table format + $html .= '
'; - $html .= ""; - $itemsInRow = 0; - $maxItemsInRow = $params['table']['maxItemsInRow']; - foreach ($fields as $field) { - //$html.= !empty($html)?'
':''; - if ($itemsInRow >= $maxItemsInRow) { - // start a new line - $html .= ""; - $itemsInRow = 0; - } + $html .= ""; + $itemsInRow = 0; + $maxItemsInRow = $params['table']['maxItemsInRow']; + foreach ($fields as $field) { + //$html.= !empty($html)?'
':''; + if ($itemsInRow >= $maxItemsInRow) { + // start a new line + $html .= ""; + $itemsInRow = 0; + } - // for some type we need line break - if (in_array($field->type, $params['table']['arrayOfLineBreakType'])) { - if ($itemsInRow > 0) { - // close table row and empty cols - for ($i = $itemsInRow; $i <= $maxItemsInRow; $i++) { - $html .= ""; - } - $html .= ""; + // for some type we need line break + if (in_array($field->type, $params['table']['arrayOfLineBreakType'])) { + if ($itemsInRow > 0) { + // close table row and empty cols + for ($i = $itemsInRow; $i <= $maxItemsInRow; $i++) { + $html .= ""; + } + $html .= ""; - // start a new line - $html .= ""; - } + // start a new line + $html .= ""; + } - $itemsInRow = $maxItemsInRow; - $html .= '"; - } else { - $itemsInRow++; - $html .= '"; + $itemsInRow = $maxItemsInRow; + $html .= '"; + } else { + $itemsInRow++; + $html .= '"; - $html .= '"; - } - } - $html .= ""; + $html .= '"; + } + } + $html .= ""; - $html .= '
'; - $html .= ''.$field->label.' : '; - $html .= $field->content; - $html .= "'; - $html .= ''.$field->label.' :'; - $html .= "'; + $html .= ''.$field->label.' : '; + $html .= $field->content; + $html .= "'; + $html .= ''.$field->label.' :'; + $html .= "'; - $html .= $field->content; - $html .= "
'; + $html .= $field->content; + $html .= "
'; - } - } + $html .= ''; + } + } - return $html; - } + return $html; + } - /** - * get column status from column key - * - * @param string $colKey the column key - * @return float width in mm - */ - public function getColumnStatus($colKey) - { - if (!empty($this->cols[$colKey]['status'])) { - return true; - } else return false; - } + /** + * get column status from column key + * + * @param string $colKey the column key + * @return float width in mm + */ + public function getColumnStatus($colKey) + { + if (!empty($this->cols[$colKey]['status'])) { + return true; + } else return false; + } - /** - * Print standard column content - * - * @param TCPDI $pdf Pdf object - * @param float $tab_top Tab top position - * @param float $tab_height Default tab height - * @param Translate $outputlangs Output language - * @param int $hidetop Hide top - * @return float Height of col tab titles - */ - public function pdfTabTitles(&$pdf, $tab_top, $tab_height, $outputlangs, $hidetop = 0) - { - global $hookmanager, $conf; + /** + * Print standard column content + * + * @param TCPDI $pdf Pdf object + * @param float $tab_top Tab top position + * @param float $tab_height Default tab height + * @param Translate $outputlangs Output language + * @param int $hidetop Hide top + * @return float Height of col tab titles + */ + public function pdfTabTitles(&$pdf, $tab_top, $tab_height, $outputlangs, $hidetop = 0) + { + global $hookmanager, $conf; - foreach ($this->cols as $colKey => $colDef) { - $parameters = array( - 'colKey' => $colKey, - 'pdf' => $pdf, - 'outputlangs' => $outputlangs, - 'tab_top' => $tab_top, - 'tab_height' => $tab_height, - 'hidetop' => $hidetop - ); + foreach ($this->cols as $colKey => $colDef) { + $parameters = array( + 'colKey' => $colKey, + 'pdf' => $pdf, + 'outputlangs' => $outputlangs, + 'tab_top' => $tab_top, + 'tab_height' => $tab_height, + 'hidetop' => $hidetop + ); - $reshook = $hookmanager->executeHooks('pdfTabTitles', $parameters, $this); // Note that $object may have been modified by hook - if ($reshook < 0) { - setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - } elseif (empty($reshook)) { - if (!$this->getColumnStatus($colKey)) continue; + $reshook = $hookmanager->executeHooks('pdfTabTitles', $parameters, $this); // Note that $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } elseif (empty($reshook)) { + if (!$this->getColumnStatus($colKey)) continue; - // get title label - $colDef['title']['label'] = !empty($colDef['title']['label']) ? $colDef['title']['label'] : $outputlangs->transnoentities($colDef['title']['textkey']); + // get title label + $colDef['title']['label'] = !empty($colDef['title']['label']) ? $colDef['title']['label'] : $outputlangs->transnoentities($colDef['title']['textkey']); - // Add column separator - if (!empty($colDef['border-left'])) { - $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height); - } + // Add column separator + if (!empty($colDef['border-left'])) { + $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height); + } - if (empty($hidetop)) { - // save curent cell padding - $curentCellPaddinds = $pdf->getCellPaddings(); + if (empty($hidetop)) { + // save curent cell padding + $curentCellPaddinds = $pdf->getCellPaddings(); - // Add space for lines (more if we need to show a second alternative language) - global $outputlangsbis; - if (is_object($outputlangsbis)) { - // set cell padding with column title definition - $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], 0.5); - } else { - // set cell padding with column title definition - $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], $colDef['title']['padding'][2]); - } + // Add space for lines (more if we need to show a second alternative language) + global $outputlangsbis; + if (is_object($outputlangsbis)) { + // set cell padding with column title definition + $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], 0.5); + } else { + // set cell padding with column title definition + $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], $colDef['title']['padding'][2]); + } - $pdf->SetXY($colDef['xStartPos'], $tab_top); - $textWidth = $colDef['width']; - $pdf->MultiCell($textWidth, 2, $colDef['title']['label'], '', $colDef['title']['align']); + $pdf->SetXY($colDef['xStartPos'], $tab_top); + $textWidth = $colDef['width']; + $pdf->MultiCell($textWidth, 2, $colDef['title']['label'], '', $colDef['title']['align']); - // Add variant of translation if $outputlangsbis is an object - if (is_object($outputlangsbis) && trim($colDef['title']['label'])) { - $pdf->setCellPaddings($colDef['title']['padding'][3], 0, $colDef['title']['padding'][1], $colDef['title']['padding'][2]); - $pdf->SetXY($colDef['xStartPos'], $pdf->GetY()); - $textbis = $outputlangsbis->transnoentities($colDef['title']['textkey']); - $pdf->MultiCell($textWidth, 2, $textbis, '', $colDef['title']['align']); - } + // Add variant of translation if $outputlangsbis is an object + if (is_object($outputlangsbis) && trim($colDef['title']['label'])) { + $pdf->setCellPaddings($colDef['title']['padding'][3], 0, $colDef['title']['padding'][1], $colDef['title']['padding'][2]); + $pdf->SetXY($colDef['xStartPos'], $pdf->GetY()); + $textbis = $outputlangsbis->transnoentities($colDef['title']['textkey']); + $pdf->MultiCell($textWidth, 2, $textbis, '', $colDef['title']['align']); + } - $this->tabTitleHeight = max($pdf->GetY() - $tab_top, $this->tabTitleHeight); + $this->tabTitleHeight = max($pdf->GetY() - $tab_top, $this->tabTitleHeight); - // restore cell padding - $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']); - } - } - } + // restore cell padding + $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']); + } + } + } - return $this->tabTitleHeight; - } + return $this->tabTitleHeight; + } - /** - * Define Array Column Field for extrafields - * - * @param object $object common object det - * @param Translate $outputlangs langs - * @param int $hidedetails Do not show line details - * @return null - */ - public function defineColumnExtrafield($object, $outputlangs, $hidedetails = 0) - { - global $conf; + /** + * Define Array Column Field for extrafields + * + * @param object $object common object det + * @param Translate $outputlangs langs + * @param int $hidedetails Do not show line details + * @return null + */ + public function defineColumnExtrafield($object, $outputlangs, $hidedetails = 0) + { + global $conf; - if (!empty($hidedetails)) { - return; - } + if (!empty($hidedetails)) { + return; + } - if (empty($object->table_element)) { - return; - } + if (empty($object->table_element)) { + return; + } - // Load extrafiels if not allready does - if (empty($this->extrafieldsCache)) { $this->extrafieldsCache = new ExtraFields($this->db); } - if (empty($this->extrafieldsCache->attributes[$object->table_element])) { $this->extrafieldsCache->fetch_name_optionals_label($object->table_element); } - $extrafields = $this->extrafieldsCache; + // Load extrafiels if not allready does + if (empty($this->extrafieldsCache)) { $this->extrafieldsCache = new ExtraFields($this->db); } + if (empty($this->extrafieldsCache->attributes[$object->table_element])) { $this->extrafieldsCache->fetch_name_optionals_label($object->table_element); } + $extrafields = $this->extrafieldsCache; - if (!empty($extrafields->attributes[$object->table_element]) && is_array($extrafields->attributes[$object->table_element]['label'])) { - foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) - { - // Dont display separator yet even is set to be displayed (not compatible yet) - if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') - { - continue; - } + if (!empty($extrafields->attributes[$object->table_element]) && is_array($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) + { + // Dont display separator yet even is set to be displayed (not compatible yet) + if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') + { + continue; + } - // Enable extrafield ? - $enabled = 0; - if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) { - $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]); - if ($printable === 1 || $printable === 2) { - $enabled = 1; - } - // Note : if $printable === 3 or 4 so, it's displayed after line description not in cols - } + // Enable extrafield ? + $enabled = 0; + if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) { + $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]); + if ($printable === 1 || $printable === 2) { + $enabled = 1; + } + // Note : if $printable === 3 or 4 so, it's displayed after line description not in cols + } - if (!$enabled) { continue; } // don't wast resourses if we don't need them... + if (!$enabled) { continue; } // don't wast resourses if we don't need them... - // Load language if required - if (!empty($extrafields->attributes[$object->table_element]['langfile'][$key])) $outputlangs->load($extrafields->attributes[$object->table_element]['langfile'][$key]); + // Load language if required + if (!empty($extrafields->attributes[$object->table_element]['langfile'][$key])) $outputlangs->load($extrafields->attributes[$object->table_element]['langfile'][$key]); - // TODO : add more extrafield customisation capacities for PDF like width, rank... + // TODO : add more extrafield customisation capacities for PDF like width, rank... - // set column definition - $def = array( - 'rank' => intval($extrafields->attributes[$object->table_element]['pos'][$key]), - 'width' => 25, // in mm - 'status' => boolval($enabled), - 'title' => array( - 'label' => $outputlangs->transnoentities($label) - ), - 'content' => array( - 'align' => 'C' - ), - 'border-left' => true, // add left line separator - ); + // set column definition + $def = array( + 'rank' => intval($extrafields->attributes[$object->table_element]['pos'][$key]), + 'width' => 25, // in mm + 'status' => boolval($enabled), + 'title' => array( + 'label' => $outputlangs->transnoentities($label) + ), + 'content' => array( + 'align' => 'C' + ), + 'border-left' => true, // add left line separator + ); - $alignTypeRight = array('double', 'int', 'price'); - if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeRight)) { - $def['content']['align'] = 'R'; - } + $alignTypeRight = array('double', 'int', 'price'); + if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeRight)) { + $def['content']['align'] = 'R'; + } - $alignTypeLeft = array('text', 'html'); - if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeLeft)) { - $def['content']['align'] = 'L'; - } + $alignTypeLeft = array('text', 'html'); + if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeLeft)) { + $def['content']['align'] = 'L'; + } - // for extrafields we use rank of extrafield to place it on PDF - $this->insertNewColumnDef("options_".$key, $def); - } - } - } + // for extrafields we use rank of extrafield to place it on PDF + $this->insertNewColumnDef("options_".$key, $def); + } + } + } } diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index 934c8d424a4..3c094ff5a6b 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -30,9 +30,9 @@ class HookManager { /** - * @var DoliDB Database handler. - */ - public $db; + * @var DoliDB Database handler. + */ + public $db; /** * @var string Error code (or message) @@ -44,18 +44,18 @@ class HookManager */ public $errors = array(); - // Context hookmanager was created for ('thirdpartycard', 'thirdpartydao', ...) - public $contextarray = array(); + // Context hookmanager was created for ('thirdpartycard', 'thirdpartydao', ...) + public $contextarray = array(); // Array with instantiated classes - public $hooks = array(); + public $hooks = array(); // Array result - public $resArray = array(); + public $resArray = array(); // Printable result - public $resPrint = ''; + public $resPrint = ''; // Nb of qualified hook ran - public $resNbOfHooks = 0; + public $resNbOfHooks = 0; /** * Constructor @@ -84,9 +84,9 @@ class HookManager global $conf; // Test if there is hooks to manage - if (!is_array($conf->modules_parts['hooks']) || empty($conf->modules_parts['hooks'])) return; + if (!is_array($conf->modules_parts['hooks']) || empty($conf->modules_parts['hooks'])) return; - // For backward compatibility + // For backward compatibility if (!is_array($arraycontext)) $arraycontext = array($arraycontext); $this->contextarray = array_unique(array_merge($arraycontext, $this->contextarray)); // All contexts are concatenated @@ -130,29 +130,29 @@ class HookManager return 1; } - /** - * Execute hooks (if they were initialized) for the given method - * - * @param string $method Name of method hooked ('doActions', 'printSearchForm', 'showInputField', ...) - * @param array $parameters Array of parameters - * @param Object $object Object to use hooks on - * @param string $action Action code on calling page ('create', 'edit', 'view', 'add', 'update', 'delete'...) - * @return mixed For 'addreplace' hooks (doActions, formConfirm, formObjectOptions, pdf_xxx,...): Return 0 if we want to keep standard actions, >0 if we want to stop/replace standard actions, <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. - * For 'output' hooks (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...): Return 0, <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. - * All types can also return some values into an array ->results that will be finaly merged into this->resArray for caller. - * $this->error or this->errors are also defined by class called by this function if error. - */ + /** + * Execute hooks (if they were initialized) for the given method + * + * @param string $method Name of method hooked ('doActions', 'printSearchForm', 'showInputField', ...) + * @param array $parameters Array of parameters + * @param Object $object Object to use hooks on + * @param string $action Action code on calling page ('create', 'edit', 'view', 'add', 'update', 'delete'...) + * @return mixed For 'addreplace' hooks (doActions, formConfirm, formObjectOptions, pdf_xxx,...): Return 0 if we want to keep standard actions, >0 if we want to stop/replace standard actions, <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. + * For 'output' hooks (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...): Return 0, <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. + * All types can also return some values into an array ->results that will be finaly merged into this->resArray for caller. + * $this->error or this->errors are also defined by class called by this function if error. + */ public function executeHooks($method, $parameters = array(), &$object = '', &$action = '') { - if (!is_array($this->hooks) || empty($this->hooks)) return 0; // No hook available, do nothing. + if (!is_array($this->hooks) || empty($this->hooks)) return 0; // No hook available, do nothing. - $parameters['context'] = join(':', $this->contextarray); - //dol_syslog(get_class($this).'::executeHooks method='.$method." action=".$action." context=".$parameters['context']); + $parameters['context'] = join(':', $this->contextarray); + //dol_syslog(get_class($this).'::executeHooks method='.$method." action=".$action." context=".$parameters['context']); - // Define type of hook ('output' or 'addreplace'). - // TODO Remove hooks with type 'output'. All hooks must be converted into 'addreplace' hooks. - $hooktype = 'output'; - if (in_array( + // Define type of hook ('output' or 'addreplace'). + // TODO Remove hooks with type 'output'. All hooks must be converted into 'addreplace' hooks. + $hooktype = 'output'; + if (in_array( $method, array( 'addCalendarChoice', @@ -172,33 +172,33 @@ class HookManager 'formattachOptions', 'formBuilddocLineOptions', 'formatNotificationMessage', - 'formConfirm', + 'formConfirm', 'getAccessForbiddenMessage', 'getDirList', 'getFormMail', 'getFormatedCustomerRef', - 'getFormatedSupplierRef', + 'getFormatedSupplierRef', 'getIdProfUrl', 'getInputIdProf', 'moveUploadedFile', 'moreHtmlStatus', 'pdf_build_address', 'pdf_writelinedesc', - 'pdf_getlinenum', - 'pdf_getlineref', - 'pdf_getlineref_supplier', - 'pdf_getlinevatrate', - 'pdf_getlineupexcltax', - 'pdf_getlineupwithtax', - 'pdf_getlineqty', - 'pdf_getlineqty_asked', - 'pdf_getlineqty_shipped', - 'pdf_getlineqty_keeptoship', - 'pdf_getlineunit', - 'pdf_getlineremisepercent', - 'pdf_getlineprogress', - 'pdf_getlinetotalexcltax', - 'pdf_getlinetotalwithtax', + 'pdf_getlinenum', + 'pdf_getlineref', + 'pdf_getlineref_supplier', + 'pdf_getlinevatrate', + 'pdf_getlineupexcltax', + 'pdf_getlineupwithtax', + 'pdf_getlineqty', + 'pdf_getlineqty_asked', + 'pdf_getlineqty_shipped', + 'pdf_getlineqty_keeptoship', + 'pdf_getlineunit', + 'pdf_getlineremisepercent', + 'pdf_getlineprogress', + 'pdf_getlinetotalexcltax', + 'pdf_getlinetotalwithtax', 'paymentsupplierinvoices', 'printAddress', 'printEmail', @@ -213,88 +213,88 @@ class HookManager 'showLinkToObjectBlock', 'setContentSecurityPolicy', 'setHtmlTitle', - 'completeTabsHead' + 'completeTabsHead' ) )) $hooktype = 'addreplace'; - // Init return properties - $this->resPrint = ''; $this->resArray = array(); $this->resNbOfHooks = 0; + // Init return properties + $this->resPrint = ''; $this->resArray = array(); $this->resNbOfHooks = 0; - // Loop on each hook to qualify modules that have declared context - $modulealreadyexecuted = array(); - $resaction = 0; $error = 0; - foreach ($this->hooks as $context => $modules) // $this->hooks is an array with context as key and value is an array of modules that handle this context - { - if (!empty($modules)) - { - foreach ($modules as $module => $actionclassinstance) - { - //print "Before hook ".get_class($actionclassinstance)." method=".$method." hooktype=".$hooktype." results=".count($actionclassinstance->results)." resprints=".count($actionclassinstance->resprints)." resaction=".$resaction."
\n"; + // Loop on each hook to qualify modules that have declared context + $modulealreadyexecuted = array(); + $resaction = 0; $error = 0; + foreach ($this->hooks as $context => $modules) // $this->hooks is an array with context as key and value is an array of modules that handle this context + { + if (!empty($modules)) + { + foreach ($modules as $module => $actionclassinstance) + { + //print "Before hook ".get_class($actionclassinstance)." method=".$method." hooktype=".$hooktype." results=".count($actionclassinstance->results)." resprints=".count($actionclassinstance->resprints)." resaction=".$resaction."
\n"; - // test to avoid running twice a hook, when a module implements several active contexts - if (in_array($module, $modulealreadyexecuted)) continue; + // test to avoid running twice a hook, when a module implements several active contexts + if (in_array($module, $modulealreadyexecuted)) continue; - // jump to next module/class if method does not exist - if (!method_exists($actionclassinstance, $method)) continue; + // jump to next module/class if method does not exist + if (!method_exists($actionclassinstance, $method)) continue; - $this->resNbOfHooks++; + $this->resNbOfHooks++; - $modulealreadyexecuted[$module] = $module; // Use the $currentcontext in method to avoid running twice + $modulealreadyexecuted[$module] = $module; // Use the $currentcontext in method to avoid running twice - // Clean class (an error may have been set from a previous call of another method for same module/hook) - $actionclassinstance->error = 0; - $actionclassinstance->errors = array(); + // Clean class (an error may have been set from a previous call of another method for same module/hook) + $actionclassinstance->error = 0; + $actionclassinstance->errors = array(); - dol_syslog(get_class($this)."::executeHooks Qualified hook found (hooktype=".$hooktype."). We call method ".$method." of class ".get_class($actionclassinstance).", module=".$module.", action=".$action." context=".$context, LOG_DEBUG); + dol_syslog(get_class($this)."::executeHooks Qualified hook found (hooktype=".$hooktype."). We call method ".$method." of class ".get_class($actionclassinstance).", module=".$module.", action=".$action." context=".$context, LOG_DEBUG); - // Add current context to avoid method execution in bad context, you can add this test in your method : eg if($currentcontext != 'formfile') return; - $parameters['currentcontext'] = $context; - // Hooks that must return int (hooks with type 'addreplace') - if ($hooktype == 'addreplace') - { - $resaction += $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) - if ($resaction < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) - { - $error++; - $this->error = $actionclassinstance->error; $this->errors = array_merge($this->errors, (array) $actionclassinstance->errors); - dol_syslog("Error on hook module=".$module.", method ".$method.", class ".get_class($actionclassinstance).", hooktype=".$hooktype.(empty($this->error) ? '' : " ".$this->error).(empty($this->errors) ? '' : " ".join(",", $this->errors)), LOG_ERR); - } + // Add current context to avoid method execution in bad context, you can add this test in your method : eg if($currentcontext != 'formfile') return; + $parameters['currentcontext'] = $context; + // Hooks that must return int (hooks with type 'addreplace') + if ($hooktype == 'addreplace') + { + $resaction += $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) + if ($resaction < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) + { + $error++; + $this->error = $actionclassinstance->error; $this->errors = array_merge($this->errors, (array) $actionclassinstance->errors); + dol_syslog("Error on hook module=".$module.", method ".$method.", class ".get_class($actionclassinstance).", hooktype=".$hooktype.(empty($this->error) ? '' : " ".$this->error).(empty($this->errors) ? '' : " ".join(",", $this->errors)), LOG_ERR); + } - if (isset($actionclassinstance->results) && is_array($actionclassinstance->results)) $this->resArray = array_merge($this->resArray, $actionclassinstance->results); - if (!empty($actionclassinstance->resprints)) $this->resPrint .= $actionclassinstance->resprints; - } - // Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...) - else { - // TODO. this test should be done into the method of hook by returning nothing - if (is_array($parameters) && !empty($parameters['special_code']) && $parameters['special_code'] > 3 && $parameters['special_code'] != $actionclassinstance->module_number) continue; + if (isset($actionclassinstance->results) && is_array($actionclassinstance->results)) $this->resArray = array_merge($this->resArray, $actionclassinstance->results); + if (!empty($actionclassinstance->resprints)) $this->resPrint .= $actionclassinstance->resprints; + } + // Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...) + else { + // TODO. this test should be done into the method of hook by returning nothing + if (is_array($parameters) && !empty($parameters['special_code']) && $parameters['special_code'] > 3 && $parameters['special_code'] != $actionclassinstance->module_number) continue; - //dol_syslog("Call method ".$method." of class ".get_class($actionclassinstance).", module=".$module.", hooktype=".$hooktype, LOG_DEBUG); - $resaction = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) + //dol_syslog("Call method ".$method." of class ".get_class($actionclassinstance).", module=".$module.", hooktype=".$hooktype, LOG_DEBUG); + $resaction = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) - if (!empty($actionclassinstance->results) && is_array($actionclassinstance->results)) $this->resArray = array_merge($this->resArray, $actionclassinstance->results); - if (!empty($actionclassinstance->resprints)) $this->resPrint .= $actionclassinstance->resprints; - if (is_numeric($resaction) && $resaction < 0) - { - $error++; - $this->error = $actionclassinstance->error; $this->errors = array_merge($this->errors, (array) $actionclassinstance->errors); - dol_syslog("Error on hook module=".$module.", method ".$method.", class ".get_class($actionclassinstance).", hooktype=".$hooktype.(empty($this->error) ? '' : " ".$this->error).(empty($this->errors) ? '' : " ".join(",", $this->errors)), LOG_ERR); - } - // TODO dead code to remove (do not enable this, but fix hook instead): result must not be a string but an int. you must use $actionclassinstance->resprints to return a string - if (!is_array($resaction) && !is_numeric($resaction)) - { - dol_syslog('Error: Bug into hook '.$method.' of module class '.get_class($actionclassinstance).'. Method must not return a string but an int (0=OK, 1=Replace, -1=KO) and set string into ->resprints', LOG_ERR); - if (empty($actionclassinstance->resprints)) { $this->resPrint .= $resaction; $resaction = 0; } - } - } + if (!empty($actionclassinstance->results) && is_array($actionclassinstance->results)) $this->resArray = array_merge($this->resArray, $actionclassinstance->results); + if (!empty($actionclassinstance->resprints)) $this->resPrint .= $actionclassinstance->resprints; + if (is_numeric($resaction) && $resaction < 0) + { + $error++; + $this->error = $actionclassinstance->error; $this->errors = array_merge($this->errors, (array) $actionclassinstance->errors); + dol_syslog("Error on hook module=".$module.", method ".$method.", class ".get_class($actionclassinstance).", hooktype=".$hooktype.(empty($this->error) ? '' : " ".$this->error).(empty($this->errors) ? '' : " ".join(",", $this->errors)), LOG_ERR); + } + // TODO dead code to remove (do not enable this, but fix hook instead): result must not be a string but an int. you must use $actionclassinstance->resprints to return a string + if (!is_array($resaction) && !is_numeric($resaction)) + { + dol_syslog('Error: Bug into hook '.$method.' of module class '.get_class($actionclassinstance).'. Method must not return a string but an int (0=OK, 1=Replace, -1=KO) and set string into ->resprints', LOG_ERR); + if (empty($actionclassinstance->resprints)) { $this->resPrint .= $resaction; $resaction = 0; } + } + } - //print "After hook ".get_class($actionclassinstance)." method=".$method." hooktype=".$hooktype." results=".count($actionclassinstance->results)." resprints=".count($actionclassinstance->resprints)." resaction=".$resaction."
\n"; + //print "After hook ".get_class($actionclassinstance)." method=".$method." hooktype=".$hooktype." results=".count($actionclassinstance->results)." resprints=".count($actionclassinstance->resprints)." resaction=".$resaction."
\n"; - unset($actionclassinstance->results); - unset($actionclassinstance->resprints); - } - } - } + unset($actionclassinstance->results); + unset($actionclassinstance->resprints); + } + } + } - return ($error ? -1 : $resaction); + return ($error ? -1 : $resaction); } } diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index a6c458fc67b..e75653ae48b 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -38,693 +38,693 @@ */ class FormOther { - private $db; + private $db; - /** + /** * @var string Error code (or message) */ public $error; - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - $this->db = $db; - } + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return HTML select list of export models - * - * @param string $selected Id modele pre-selectionne - * @param string $htmlname Nom de la zone select - * @param string $type Type des modeles recherches - * @param int $useempty Show an empty value in list - * @param int $fk_user User that has created the template (this is set to null to get all export model when EXPORTS_SHARE_MODELS is on) - * @return void - */ - public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0, $fk_user = null) - { - // phpcs:enable - global $conf, $langs, $user; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return HTML select list of export models + * + * @param string $selected Id modele pre-selectionne + * @param string $htmlname Nom de la zone select + * @param string $type Type des modeles recherches + * @param int $useempty Show an empty value in list + * @param int $fk_user User that has created the template (this is set to null to get all export model when EXPORTS_SHARE_MODELS is on) + * @return void + */ + public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0, $fk_user = null) + { + // phpcs:enable + global $conf, $langs, $user; - $sql = "SELECT rowid, label, fk_user"; - $sql .= " FROM ".MAIN_DB_PREFIX."export_model"; - $sql .= " WHERE type = '".$this->db->escape($type)."'"; + $sql = "SELECT rowid, label, fk_user"; + $sql .= " FROM ".MAIN_DB_PREFIX."export_model"; + $sql .= " WHERE type = '".$this->db->escape($type)."'"; if (!empty($fk_user)) $sql .= " AND fk_user IN (0, ".$fk_user.")"; // An export model - $sql .= " ORDER BY label"; - $result = $this->db->query($sql); - if ($result) - { - print ''; + if ($useempty) + { + print ''; + } - $num = $this->db->num_rows($result); - $i = 0; - while ($i < $num) - { - $obj = $this->db->fetch_object($result); + $num = $this->db->num_rows($result); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($result); - $label = $obj->label; - if ($obj->fk_user == 0) { - $label .= ' ('.$langs->trans("Everybody").')'; - } elseif (!empty($conf->global->EXPORTS_SHARE_MODELS) && empty($fk_user) && is_object($user) && $user->id != $obj->fk_user) { - $tmpuser = new User($this->db); - $tmpuser->fetch($obj->fk_user); - $label .= ' ('.$tmpuser->getFullName($langs).')'; - } + $label = $obj->label; + if ($obj->fk_user == 0) { + $label .= ' ('.$langs->trans("Everybody").')'; + } elseif (!empty($conf->global->EXPORTS_SHARE_MODELS) && empty($fk_user) && is_object($user) && $user->id != $obj->fk_user) { + $tmpuser = new User($this->db); + $tmpuser->fetch($obj->fk_user); + $label .= ' ('.$tmpuser->getFullName($langs).')'; + } - if ($selected == $obj->rowid) - { - print ''; - $i++; - } - print ""; - print ajax_combobox($htmlname); - } else { - dol_print_error($this->db); - } - } + if ($selected == $obj->rowid) + { + print ''; + $i++; + } + print ""; + print ajax_combobox($htmlname); + } else { + dol_print_error($this->db); + } + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return list of export models - * - * @param string $selected Id modele pre-selectionne - * @param string $htmlname Nom de la zone select - * @param string $type Type des modeles recherches - * @param int $useempty Affiche valeur vide dans liste - * @param int $fk_user User that has created the template (this is set to null to get all export model when EXPORTS_SHARE_MODELS is on) - * @return void - */ - public function select_import_model($selected = '', $htmlname = 'importmodelid', $type = '', $useempty = 0, $fk_user = null) - { - // phpcs:enable - global $conf, $langs, $user; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return list of export models + * + * @param string $selected Id modele pre-selectionne + * @param string $htmlname Nom de la zone select + * @param string $type Type des modeles recherches + * @param int $useempty Affiche valeur vide dans liste + * @param int $fk_user User that has created the template (this is set to null to get all export model when EXPORTS_SHARE_MODELS is on) + * @return void + */ + public function select_import_model($selected = '', $htmlname = 'importmodelid', $type = '', $useempty = 0, $fk_user = null) + { + // phpcs:enable + global $conf, $langs, $user; - $sql = "SELECT rowid, label, fk_user"; - $sql .= " FROM ".MAIN_DB_PREFIX."import_model"; - $sql .= " WHERE type = '".$this->db->escape($type)."'"; - if (!empty($fk_user)) $sql .= " AND fk_user IN (0, ".$fk_user.")"; // An export model - $sql .= " ORDER BY rowid"; - $result = $this->db->query($sql); - if ($result) - { - print ''; + if ($useempty) + { + print ''; + } - $num = $this->db->num_rows($result); - $i = 0; - while ($i < $num) - { - $obj = $this->db->fetch_object($result); + $num = $this->db->num_rows($result); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($result); - $label = $obj->label; - if ($obj->fk_user == 0) { - $label .= ' ('.$langs->trans("Everybody").')'; - } elseif (!empty($conf->global->EXPORTS_SHARE_MODELS) && empty($fk_user) && is_object($user) && $user->id != $obj->fk_user) { - $tmpuser = new User($this->db); - $tmpuser->fetch($obj->fk_user); - $label .= ' ('.$tmpuser->getFullName($langs).')'; - } + $label = $obj->label; + if ($obj->fk_user == 0) { + $label .= ' ('.$langs->trans("Everybody").')'; + } elseif (!empty($conf->global->EXPORTS_SHARE_MODELS) && empty($fk_user) && is_object($user) && $user->id != $obj->fk_user) { + $tmpuser = new User($this->db); + $tmpuser->fetch($obj->fk_user); + $label .= ' ('.$tmpuser->getFullName($langs).')'; + } - if ($selected == $obj->rowid) - { - print ''; - $i++; - } - print ""; - print ajax_combobox($htmlname); - } else { - dol_print_error($this->db); - } - } + if ($selected == $obj->rowid) + { + print ''; + $i++; + } + print ""; + print ajax_combobox($htmlname); + } else { + dol_print_error($this->db); + } + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return list of ecotaxes with label - * - * @param string $selected Preselected ecotaxes - * @param string $htmlname Name of combo list - * @return integer - */ - public function select_ecotaxes($selected = '', $htmlname = 'ecotaxe_id') - { - // phpcs:enable - global $langs; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return list of ecotaxes with label + * + * @param string $selected Preselected ecotaxes + * @param string $htmlname Name of combo list + * @return integer + */ + public function select_ecotaxes($selected = '', $htmlname = 'ecotaxe_id') + { + // phpcs:enable + global $langs; - $sql = "SELECT e.rowid, e.code, e.label, e.price, e.organization,"; - $sql .= " c.label as country"; - $sql .= " FROM ".MAIN_DB_PREFIX."c_ecotaxe as e,".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE e.active = 1 AND e.fk_pays = c.rowid"; - $sql .= " ORDER BY country, e.organization ASC, e.code ASC"; + $sql = "SELECT e.rowid, e.code, e.label, e.price, e.organization,"; + $sql .= " c.label as country"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_ecotaxe as e,".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE e.active = 1 AND e.fk_pays = c.rowid"; + $sql .= " ORDER BY country, e.organization ASC, e.code ASC"; - dol_syslog(get_class($this).'::select_ecotaxes', LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) - { - print ''; - return 0; - } else { - dol_print_error($this->db); - return 1; - } - } + dol_syslog(get_class($this).'::select_ecotaxes', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + print ''; + return 0; + } else { + dol_print_error($this->db); + return 1; + } + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return list of revenue stamp for country - * - * @param string $selected Value of preselected revenue stamp - * @param string $htmlname Name of combo list - * @param string $country_code Country Code - * @return string HTML select list - */ - public function select_revenue_stamp($selected = '', $htmlname = 'revenuestamp', $country_code = '') - { - // phpcs:enable - global $langs; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return list of revenue stamp for country + * + * @param string $selected Value of preselected revenue stamp + * @param string $htmlname Name of combo list + * @param string $country_code Country Code + * @return string HTML select list + */ + public function select_revenue_stamp($selected = '', $htmlname = 'revenuestamp', $country_code = '') + { + // phpcs:enable + global $langs; - $out = ''; + $out = ''; - $sql = "SELECT r.taux, r.revenuestamp_type"; - $sql .= " FROM ".MAIN_DB_PREFIX."c_revenuestamp as r,".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE r.active = 1 AND r.fk_pays = c.rowid"; - $sql .= " AND c.code = '".$this->db->escape($country_code)."'"; + $sql = "SELECT r.taux, r.revenuestamp_type"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_revenuestamp as r,".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE r.active = 1 AND r.fk_pays = c.rowid"; + $sql .= " AND c.code = '".$this->db->escape($country_code)."'"; - dol_syslog(get_class($this).'::select_revenue_stamp', LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) - { - $out .= ''; - return $out; - } else { - dol_print_error($this->db); - return ''; - } - } + dol_syslog(get_class($this).'::select_revenue_stamp', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $out .= ''; + return $out; + } else { + dol_print_error($this->db); + return ''; + } + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return a HTML select list to select a percent - * - * @param integer $selected pourcentage pre-selectionne - * @param string $htmlname nom de la liste deroulante - * @param int $disabled Disabled or not - * @param int $increment increment value - * @param int $start start value - * @param int $end end value - * @param int $showempty Add also an empty line - * @return string HTML select string - */ - public function select_percent($selected = 0, $htmlname = 'percent', $disabled = 0, $increment = 5, $start = 0, $end = 100, $showempty = 0) - { - // phpcs:enable - $return = ''; + if ($showempty) $return .= ''; - for ($i = $start; $i <= $end; $i += $increment) - { - if ($selected != '' && (int) $selected == $i) - { - $return .= ''; - } + for ($i = $start; $i <= $end; $i += $increment) + { + if ($selected != '' && (int) $selected == $i) + { + $return .= ''; + } - $return .= ''; + $return .= ''; - return $return; - } + return $return; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return select list for categories (to use in form search selectors) - * - * @param int $type Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated. - * @param integer $selected Preselected value - * @param string $htmlname Name of combo list - * @param int $nocateg Show also an entry "Not categorized" - * @param int $showempty Add also an empty line - * @param string $morecss More CSS - * @return string Html combo list code - * @see select_all_categories() - */ - public function select_categories($type, $selected = 0, $htmlname = 'search_categ', $nocateg = 0, $showempty = 1, $morecss = '') - { - // phpcs:enable - global $conf, $langs; - require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return select list for categories (to use in form search selectors) + * + * @param int $type Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated. + * @param integer $selected Preselected value + * @param string $htmlname Name of combo list + * @param int $nocateg Show also an entry "Not categorized" + * @param int $showempty Add also an empty line + * @param string $morecss More CSS + * @return string Html combo list code + * @see select_all_categories() + */ + public function select_categories($type, $selected = 0, $htmlname = 'search_categ', $nocateg = 0, $showempty = 1, $morecss = '') + { + // phpcs:enable + global $conf, $langs; + require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; - // For backward compatibility - if (is_numeric($type)) - { - dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING); - } + // For backward compatibility + if (is_numeric($type)) + { + dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING); + } - // Load list of "categories" - $static_categs = new Categorie($this->db); - $tab_categs = $static_categs->get_full_arbo($type); + // Load list of "categories" + $static_categs = new Categorie($this->db); + $tab_categs = $static_categs->get_full_arbo($type); - $moreforfilter = ''; - // Enhance with select2 - if ($conf->use_javascript_ajax) - { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - $comboenhancement = ajax_combobox('select_categ_'.$htmlname); - $moreforfilter .= $comboenhancement; - } + $moreforfilter = ''; + // Enhance with select2 + if ($conf->use_javascript_ajax) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + $comboenhancement = ajax_combobox('select_categ_'.$htmlname); + $moreforfilter .= $comboenhancement; + } - // Print a select with each of them - $moreforfilter .= ''; + if ($showempty) $moreforfilter .= ''; // Should use -1 to say nothing - if (is_array($tab_categs)) - { - foreach ($tab_categs as $categ) - { - $moreforfilter .= ''; - } - $moreforfilter .= ''; + if (is_array($tab_categs)) + { + foreach ($tab_categs as $categ) + { + $moreforfilter .= ''; + } + $moreforfilter .= ''; - return $moreforfilter; - } + return $moreforfilter; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return select list for categories (to use in form search selectors) - * - * @param string $selected Preselected value - * @param string $htmlname Name of combo list (example: 'search_sale') - * @param User $user Object user - * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status - * @param int $showempty 1=show also an empty value - * @param string $morecss More CSS - * @param int $norepresentative Show also an entry "Not categorized" - * @return string Html combo list code - */ - public function select_salesrepresentatives($selected, $htmlname, $user, $showstatus = 0, $showempty = 1, $morecss = '', $norepresentative = 0) - { - // phpcs:enable - global $conf, $langs, $hookmanager; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return select list for categories (to use in form search selectors) + * + * @param string $selected Preselected value + * @param string $htmlname Name of combo list (example: 'search_sale') + * @param User $user Object user + * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status + * @param int $showempty 1=show also an empty value + * @param string $morecss More CSS + * @param int $norepresentative Show also an entry "Not categorized" + * @return string Html combo list code + */ + public function select_salesrepresentatives($selected, $htmlname, $user, $showstatus = 0, $showempty = 1, $morecss = '', $norepresentative = 0) + { + // phpcs:enable + global $conf, $langs, $hookmanager; - $langs->load('users'); + $langs->load('users'); - $out = ''; - // Enhance with select2 - if ($conf->use_javascript_ajax) - { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + $out = ''; + // Enhance with select2 + if ($conf->use_javascript_ajax) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - $comboenhancement = ajax_combobox($htmlname); - if ($comboenhancement) - { - $out .= $comboenhancement; - } - } + $comboenhancement = ajax_combobox($htmlname); + if ($comboenhancement) + { + $out .= $comboenhancement; + } + } - $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectSalesRep', array(), $this, $action); + $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectSalesRep', array(), $this, $action); - // Select each sales and print them in a select input - $out .= ''; + if ($showempty) $out .= ''; - // Get list of users allowed to be viewed - $sql_usr = "SELECT u.rowid, u.lastname, u.firstname, u.statut, u.login"; - $sql_usr .= " FROM ".MAIN_DB_PREFIX."user as u"; + // Get list of users allowed to be viewed + $sql_usr = "SELECT u.rowid, u.lastname, u.firstname, u.statut, u.login"; + $sql_usr .= " FROM ".MAIN_DB_PREFIX."user as u"; - if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) - { - if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) { - $sql_usr .= " WHERE u.entity IS NOT NULL"; // Show all users - } else { - $sql_usr .= " WHERE EXISTS (SELECT ug.fk_user FROM ".MAIN_DB_PREFIX."usergroup_user as ug WHERE u.rowid = ug.fk_user AND ug.entity IN (".getEntity('usergroup')."))"; - $sql_usr .= " OR u.entity = 0"; // Show always superadmin - } - } else { - $sql_usr .= " WHERE u.entity IN (".getEntity('user').")"; - } + if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) + { + if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) { + $sql_usr .= " WHERE u.entity IS NOT NULL"; // Show all users + } else { + $sql_usr .= " WHERE EXISTS (SELECT ug.fk_user FROM ".MAIN_DB_PREFIX."usergroup_user as ug WHERE u.rowid = ug.fk_user AND ug.entity IN (".getEntity('usergroup')."))"; + $sql_usr .= " OR u.entity = 0"; // Show always superadmin + } + } else { + $sql_usr .= " WHERE u.entity IN (".getEntity('user').")"; + } - if (empty($user->rights->user->user->lire)) $sql_usr .= " AND u.rowid = ".$user->id; - if (!empty($user->socid)) $sql_usr .= " AND u.fk_soc = ".$user->socid; + if (empty($user->rights->user->user->lire)) $sql_usr .= " AND u.rowid = ".$user->id; + if (!empty($user->socid)) $sql_usr .= " AND u.fk_soc = ".$user->socid; - //Add hook to filter on user (for exemple on usergroup define in custom modules) - if (!empty($reshook)) $sql_usr .= $hookmanager->resArray[0]; + //Add hook to filter on user (for exemple on usergroup define in custom modules) + if (!empty($reshook)) $sql_usr .= $hookmanager->resArray[0]; - // Add existing sales representatives of thirdparty of external user - if (empty($user->rights->user->user->lire) && $user->socid) - { - $sql_usr .= " UNION "; - $sql_usr .= "SELECT u2.rowid, u2.lastname, u2.firstname, u2.statut, u2.login"; - $sql_usr .= " FROM ".MAIN_DB_PREFIX."user as u2, ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + // Add existing sales representatives of thirdparty of external user + if (empty($user->rights->user->user->lire) && $user->socid) + { + $sql_usr .= " UNION "; + $sql_usr .= "SELECT u2.rowid, u2.lastname, u2.firstname, u2.statut, u2.login"; + $sql_usr .= " FROM ".MAIN_DB_PREFIX."user as u2, ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) - { - if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) { - $sql_usr .= " WHERE u2.entity IS NOT NULL"; // Show all users - } else { - $sql_usr .= " WHERE EXISTS (SELECT ug2.fk_user FROM ".MAIN_DB_PREFIX."usergroup_user as ug2 WHERE u2.rowid = ug2.fk_user AND ug2.entity IN (".getEntity('usergroup')."))"; - } - } else { - $sql_usr .= " WHERE u2.entity IN (".getEntity('user').")"; - } + if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) + { + if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) { + $sql_usr .= " WHERE u2.entity IS NOT NULL"; // Show all users + } else { + $sql_usr .= " WHERE EXISTS (SELECT ug2.fk_user FROM ".MAIN_DB_PREFIX."usergroup_user as ug2 WHERE u2.rowid = ug2.fk_user AND ug2.entity IN (".getEntity('usergroup')."))"; + } + } else { + $sql_usr .= " WHERE u2.entity IN (".getEntity('user').")"; + } - $sql_usr .= " AND u2.rowid = sc.fk_user AND sc.fk_soc=".$user->socid; + $sql_usr .= " AND u2.rowid = sc.fk_user AND sc.fk_soc=".$user->socid; - //Add hook to filter on user (for exemple on usergroup define in custom modules) - if (!empty($reshook)) $sql_usr .= $hookmanager->resArray[1]; - } - $sql_usr .= " ORDER BY statut DESC, lastname ASC"; // Do not use 'ORDER BY u.statut' here, not compatible with the UNION. - //print $sql_usr;exit; + //Add hook to filter on user (for exemple on usergroup define in custom modules) + if (!empty($reshook)) $sql_usr .= $hookmanager->resArray[1]; + } + $sql_usr .= " ORDER BY statut DESC, lastname ASC"; // Do not use 'ORDER BY u.statut' here, not compatible with the UNION. + //print $sql_usr;exit; - $resql_usr = $this->db->query($sql_usr); - if ($resql_usr) - { - while ($obj_usr = $this->db->fetch_object($resql_usr)) - { - $out .= ''; - } - $this->db->free($resql_usr); - } else { - dol_print_error($this->db); - } + $out .= ''; + } + $this->db->free($resql_usr); + } else { + dol_print_error($this->db); + } - if ($norepresentative) - { - $langs->load("companies"); - $out .= ''; - } + if ($norepresentative) + { + $langs->load("companies"); + $out .= ''; + } - $out .= ''; + $out .= ''; - return $out; - } + return $out; + } - /** - * Return list of project and tasks - * - * @param int $selectedtask Pre-selected task - * @param int $projectid Project id - * @param string $htmlname Name of html select - * @param int $modeproject 1 to restrict on projects owned by user - * @param int $modetask 1 to restrict on tasks associated to user - * @param int $mode 0=Return list of tasks and their projects, 1=Return projects and tasks if exists - * @param int $useempty 0=Allow empty values - * @param int $disablechildoftaskid 1=Disable task that are child of the provided task id + /** + * Return list of project and tasks + * + * @param int $selectedtask Pre-selected task + * @param int $projectid Project id + * @param string $htmlname Name of html select + * @param int $modeproject 1 to restrict on projects owned by user + * @param int $modetask 1 to restrict on tasks associated to user + * @param int $mode 0=Return list of tasks and their projects, 1=Return projects and tasks if exists + * @param int $useempty 0=Allow empty values + * @param int $disablechildoftaskid 1=Disable task that are child of the provided task id * @param string $filteronprojstatus Filter on project status ('-1'=no filter, '0,1'=Draft+Validated status) - * @param string $morecss More css - * @return void - */ - public function selectProjectTasks($selectedtask = '', $projectid = 0, $htmlname = 'task_parent', $modeproject = 0, $modetask = 0, $mode = 0, $useempty = 0, $disablechildoftaskid = 0, $filteronprojstatus = '', $morecss = '') - { - global $user, $langs; + * @param string $morecss More css + * @return void + */ + public function selectProjectTasks($selectedtask = '', $projectid = 0, $htmlname = 'task_parent', $modeproject = 0, $modetask = 0, $mode = 0, $useempty = 0, $disablechildoftaskid = 0, $filteronprojstatus = '', $morecss = '') + { + global $user, $langs; - require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; + require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; - //print $modeproject.'-'.$modetask; - $task = new Task($this->db); - $tasksarray = $task->getTasksArray($modetask ? $user : 0, $modeproject ? $user : 0, $projectid, 0, $mode, '', $filteronprojstatus); - if ($tasksarray) - { - print ''; + //print $modeproject.'-'.$modetask; + $task = new Task($this->db); + $tasksarray = $task->getTasksArray($modetask ? $user : 0, $modeproject ? $user : 0, $projectid, 0, $mode, '', $filteronprojstatus); + if ($tasksarray) + { + print ''; - print ajax_combobox($htmlname); - } else { - print '
'.$langs->trans("NoProject").'
'; - } - } + print ajax_combobox($htmlname); + } else { + print '
'.$langs->trans("NoProject").'
'; + } + } - /** - * Write lines of a project (all lines of a project if parent = 0) - * - * @param int $inc Cursor counter - * @param int $parent Id of parent task we want to see - * @param array $lines Array of task lines - * @param int $level Level - * @param int $selectedtask Id selected task - * @param int $selectedproject Id selected project - * @param int $disablechildoftaskid 1=Disable task that are child of the provided task id - * @return void - */ - private function _pLineSelect(&$inc, $parent, $lines, $level = 0, $selectedtask = 0, $selectedproject = 0, $disablechildoftaskid = 0) - { - global $langs, $user, $conf; + /** + * Write lines of a project (all lines of a project if parent = 0) + * + * @param int $inc Cursor counter + * @param int $parent Id of parent task we want to see + * @param array $lines Array of task lines + * @param int $level Level + * @param int $selectedtask Id selected task + * @param int $selectedproject Id selected project + * @param int $disablechildoftaskid 1=Disable task that are child of the provided task id + * @return void + */ + private function _pLineSelect(&$inc, $parent, $lines, $level = 0, $selectedtask = 0, $selectedproject = 0, $disablechildoftaskid = 0) + { + global $langs, $user, $conf; - $lastprojectid = 0; + $lastprojectid = 0; - $numlines = count($lines); - for ($i = 0; $i < $numlines; $i++) { - if ($lines[$i]->fk_parent == $parent) { - //var_dump($selectedproject."--".$selectedtask."--".$lines[$i]->fk_project."_".$lines[$i]->id); // $lines[$i]->id may be empty if project has no lines + $numlines = count($lines); + for ($i = 0; $i < $numlines; $i++) { + if ($lines[$i]->fk_parent == $parent) { + //var_dump($selectedproject."--".$selectedtask."--".$lines[$i]->fk_project."_".$lines[$i]->id); // $lines[$i]->id may be empty if project has no lines - // Break on a new project - if ($parent == 0) // We are on a task at first level - { - if ($lines[$i]->fk_project != $lastprojectid) // Break found on project - { - if ($i > 0) print ''; - print '\n"; + // Break on a new project + if ($parent == 0) // We are on a task at first level + { + if ($lines[$i]->fk_project != $lastprojectid) // Break found on project + { + if ($i > 0) print ''; + print '\n"; - $lastprojectid = $lines[$i]->fk_project; - $inc++; - } - } + $lastprojectid = $lines[$i]->fk_project; + $inc++; + } + } - $newdisablechildoftaskid = $disablechildoftaskid; + $newdisablechildoftaskid = $disablechildoftaskid; - // Print task - if (isset($lines[$i]->id)) // We use isset because $lines[$i]->id may be null if project has no task and are on root project (tasks may be caught by a left join). We enter here only if '0' or >0 - { - // Check if we must disable entry - $disabled = 0; - if ($disablechildoftaskid && (($lines[$i]->id == $disablechildoftaskid || $lines[$i]->fk_parent == $disablechildoftaskid))) - { - $disabled++; - if ($lines[$i]->fk_parent == $disablechildoftaskid) $newdisablechildoftaskid = $lines[$i]->id; // If task is child of a disabled parent, we will propagate id to disable next child too - } + // Print task + if (isset($lines[$i]->id)) // We use isset because $lines[$i]->id may be null if project has no task and are on root project (tasks may be caught by a left join). We enter here only if '0' or >0 + { + // Check if we must disable entry + $disabled = 0; + if ($disablechildoftaskid && (($lines[$i]->id == $disablechildoftaskid || $lines[$i]->fk_parent == $disablechildoftaskid))) + { + $disabled++; + if ($lines[$i]->fk_parent == $disablechildoftaskid) $newdisablechildoftaskid = $lines[$i]->id; // If task is child of a disabled parent, we will propagate id to disable next child too + } - print '\n"; - $inc++; - } + print '\n"; + $inc++; + } - $level++; - if ($lines[$i]->id) $this->_pLineSelect($inc, $lines[$i]->id, $lines, $level, $selectedtask, $selectedproject, $newdisablechildoftaskid); - $level--; - } - } - } + $level++; + if ($lines[$i]->id) $this->_pLineSelect($inc, $lines[$i]->id, $lines, $level, $selectedtask, $selectedproject, $newdisablechildoftaskid); + $level--; + } + } + } - /** - * Output a HTML thumb of color or a text if not defined. - * - * @param string $color String with hex (FFFFFF) or comma RGB ('255,255,255') - * @param string $textifnotdefined Text to show if color not defined - * @return string HTML code for color thumb - * @see selectColor() - */ - public static function showColor($color, $textifnotdefined = '') - { - $textcolor = 'FFF'; - include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; - if (colorIsLight($color)) $textcolor = '000'; + /** + * Output a HTML thumb of color or a text if not defined. + * + * @param string $color String with hex (FFFFFF) or comma RGB ('255,255,255') + * @param string $textifnotdefined Text to show if color not defined + * @return string HTML code for color thumb + * @see selectColor() + */ + public static function showColor($color, $textifnotdefined = '') + { + $textcolor = 'FFF'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + if (colorIsLight($color)) $textcolor = '000'; - $color = colorArrayToHex(colorStringToArray($color, array()), ''); + $color = colorArrayToHex(colorStringToArray($color, array()), ''); if ($color) print ''; else print $textifnotdefined; - } + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Output a HTML code to select a color - * - * @param string $set_color Pre-selected color - * @param string $prefix Name of HTML field - * @param string $form_name Deprecated. Not used. - * @param int $showcolorbox 1=Show color code and color box, 0=Show only color code - * @param array $arrayofcolors Array of colors. Example: array('29527A','5229A3','A32929','7A367A','B1365F','0D7813') - * @return void - * @deprecated Use instead selectColor - * @see selectColor() - */ - public function select_color($set_color = '', $prefix = 'f_color', $form_name = '', $showcolorbox = 1, $arrayofcolors = '') - { - // phpcs:enable - print $this->selectColor($set_color, $prefix, $form_name, $showcolorbox, $arrayofcolors); - } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Output a HTML code to select a color + * + * @param string $set_color Pre-selected color + * @param string $prefix Name of HTML field + * @param string $form_name Deprecated. Not used. + * @param int $showcolorbox 1=Show color code and color box, 0=Show only color code + * @param array $arrayofcolors Array of colors. Example: array('29527A','5229A3','A32929','7A367A','B1365F','0D7813') + * @return void + * @deprecated Use instead selectColor + * @see selectColor() + */ + public function select_color($set_color = '', $prefix = 'f_color', $form_name = '', $showcolorbox = 1, $arrayofcolors = '') + { + // phpcs:enable + print $this->selectColor($set_color, $prefix, $form_name, $showcolorbox, $arrayofcolors); + } - /** - * Output a HTML code to select a color. Field will return an hexa color like '334455'. - * - * @param string $set_color Pre-selected color - * @param string $prefix Name of HTML field - * @param string $form_name Deprecated. Not used. - * @param int $showcolorbox 1=Show color code and color box, 0=Show only color code - * @param array $arrayofcolors Array of colors. Example: array('29527A','5229A3','A32929','7A367A','B1365F','0D7813') - * @param string $morecss Add css style into input field - * @return string - * @see showColor() - */ - public static function selectColor($set_color = '', $prefix = 'f_color', $form_name = '', $showcolorbox = 1, $arrayofcolors = '', $morecss = '') - { - // Deprecation warning - if ($form_name) { - dol_syslog(__METHOD__.": form_name parameter is deprecated", LOG_WARNING); - } + /** + * Output a HTML code to select a color. Field will return an hexa color like '334455'. + * + * @param string $set_color Pre-selected color + * @param string $prefix Name of HTML field + * @param string $form_name Deprecated. Not used. + * @param int $showcolorbox 1=Show color code and color box, 0=Show only color code + * @param array $arrayofcolors Array of colors. Example: array('29527A','5229A3','A32929','7A367A','B1365F','0D7813') + * @param string $morecss Add css style into input field + * @return string + * @see showColor() + */ + public static function selectColor($set_color = '', $prefix = 'f_color', $form_name = '', $showcolorbox = 1, $arrayofcolors = '', $morecss = '') + { + // Deprecation warning + if ($form_name) { + dol_syslog(__METHOD__.": form_name parameter is deprecated", LOG_WARNING); + } - global $langs, $conf; + global $langs, $conf; - $out = ''; + $out = ''; - if (!is_array($arrayofcolors) || count($arrayofcolors) < 1) - { - $langs->load("other"); - if (empty($conf->dol_use_jmobile) && !empty($conf->use_javascript_ajax)) - { - $out .= ''; - $out .= ''; - $out .= ''; + $out .= ''; - } - $out .= ''; - } else // In most cases, this is not used. We used instead function with no specific list of colors - { - if (empty($conf->dol_use_jmobile) && !empty($conf->use_javascript_ajax)) - { - $out .= ''; - $out .= ''; - $out .= ''; + $out .= ''; - } - $out .= ''; - } + } + $out .= ''; + } - return $out; - } + return $out; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Creation d'un icone de couleur - * - * @param string $color Couleur de l'image - * @param string $module Nom du module - * @param string $name Nom de l'image - * @param int $x Largeur de l'image en pixels - * @param int $y Hauteur de l'image en pixels - * @return void - */ - public function CreateColorIcon($color, $module, $name, $x = '12', $y = '12') - { - // phpcs:enable - global $conf; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Creation d'un icone de couleur + * + * @param string $color Couleur de l'image + * @param string $module Nom du module + * @param string $name Nom de l'image + * @param int $x Largeur de l'image en pixels + * @param int $y Hauteur de l'image en pixels + * @return void + */ + public function CreateColorIcon($color, $module, $name, $x = '12', $y = '12') + { + // phpcs:enable + global $conf; - $file = $conf->$module->dir_temp.'/'.$name.'.png'; + $file = $conf->$module->dir_temp.'/'.$name.'.png'; - // On cree le repertoire contenant les icones - if (!file_exists($conf->$module->dir_temp)) - { - dol_mkdir($conf->$module->dir_temp); - } + // On cree le repertoire contenant les icones + if (!file_exists($conf->$module->dir_temp)) + { + dol_mkdir($conf->$module->dir_temp); + } - // On cree l'image en vraies couleurs - $image = imagecreatetruecolor($x, $y); + // On cree l'image en vraies couleurs + $image = imagecreatetruecolor($x, $y); - $color = substr($color, 1, 6); + $color = substr($color, 1, 6); - $rouge = hexdec(substr($color, 0, 2)); //conversion du canal rouge - $vert = hexdec(substr($color, 2, 2)); //conversion du canal vert - $bleu = hexdec(substr($color, 4, 2)); //conversion du canal bleu + $rouge = hexdec(substr($color, 0, 2)); //conversion du canal rouge + $vert = hexdec(substr($color, 2, 2)); //conversion du canal vert + $bleu = hexdec(substr($color, 4, 2)); //conversion du canal bleu - $couleur = imagecolorallocate($image, $rouge, $vert, $bleu); - //print $rouge.$vert.$bleu; - imagefill($image, 0, 0, $couleur); //on remplit l'image - // On cree la couleur et on l'attribue a une variable pour ne pas la perdre - ImagePng($image, $file); //renvoie une image sous format png - ImageDestroy($image); - } + $couleur = imagecolorallocate($image, $rouge, $vert, $bleu); + //print $rouge.$vert.$bleu; + imagefill($image, 0, 0, $couleur); //on remplit l'image + // On cree la couleur et on l'attribue a une variable pour ne pas la perdre + ImagePng($image, $file); //renvoie une image sous format png + ImageDestroy($image); + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return HTML combo list of week - * - * @param string $selected Preselected value - * @param string $htmlname Nom de la zone select - * @param int $useempty Affiche valeur vide dans liste - * @return string - */ - public function select_dayofweek($selected = '', $htmlname = 'weekid', $useempty = 0) - { - // phpcs:enable - global $langs; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return HTML combo list of week + * + * @param string $selected Preselected value + * @param string $htmlname Nom de la zone select + * @param int $useempty Affiche valeur vide dans liste + * @return string + */ + public function select_dayofweek($selected = '', $htmlname = 'weekid', $useempty = 0) + { + // phpcs:enable + global $langs; - $week = array( - 0=>$langs->trans("Day0"), - 1=>$langs->trans("Day1"), - 2=>$langs->trans("Day2"), - 3=>$langs->trans("Day3"), - 4=>$langs->trans("Day4"), - 5=>$langs->trans("Day5"), - 6=>$langs->trans("Day6") - ); + $week = array( + 0=>$langs->trans("Day0"), + 1=>$langs->trans("Day1"), + 2=>$langs->trans("Day2"), + 3=>$langs->trans("Day3"), + 4=>$langs->trans("Day4"), + 5=>$langs->trans("Day5"), + 6=>$langs->trans("Day6") + ); - $select_week = ''; - return $select_week; - } + $select_week = ''; + return $select_week; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return HTML combo list of month - * - * @param string $selected Preselected value - * @param string $htmlname Name of HTML select object - * @param int $useempty Show empty in list - * @param int $longlabel Show long label - * @param string $morecss More Css - * @return string - */ - public function select_month($selected = '', $htmlname = 'monthid', $useempty = 0, $longlabel = 0, $morecss = 'maxwidth50imp valignmiddle') - { - // phpcs:enable - global $langs; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return HTML combo list of month + * + * @param string $selected Preselected value + * @param string $htmlname Name of HTML select object + * @param int $useempty Show empty in list + * @param int $longlabel Show long label + * @param string $morecss More Css + * @return string + */ + public function select_month($selected = '', $htmlname = 'monthid', $useempty = 0, $longlabel = 0, $morecss = 'maxwidth50imp valignmiddle') + { + // phpcs:enable + global $langs; - require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; - if ($longlabel) $montharray = monthArray($langs, 0); // Get array - else $montharray = monthArray($langs, 1); + if ($longlabel) $montharray = monthArray($langs, 0); // Get array + else $montharray = monthArray($langs, 1); - $select_month = ''; - return $select_month; - } + $select_month = ''; + return $select_month; + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return HTML combo list of years - * - * @param string $selected Preselected value (''=current year, -1=none, year otherwise) - * @param string $htmlname Name of HTML select object - * @param int $useempty Affiche valeur vide dans liste - * @param int $min_year Offset of minimum year into list (by default current year -10) - * @param int $max_year Offset of maximum year into list (by default current year + 5) - * @param int $offset Offset - * @param int $invert Invert - * @param string $option Option - * @param string $morecss More CSS - * @return string - */ - public function select_year($selected = '', $htmlname = 'yearid', $useempty = 0, $min_year = 10, $max_year = 5, $offset = 0, $invert = 0, $option = '', $morecss = 'valignmiddle maxwidth75imp') - { - // phpcs:enable - print $this->selectyear($selected, $htmlname, $useempty, $min_year, $max_year, $offset, $invert, $option, $morecss); - } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return HTML combo list of years + * + * @param string $selected Preselected value (''=current year, -1=none, year otherwise) + * @param string $htmlname Name of HTML select object + * @param int $useempty Affiche valeur vide dans liste + * @param int $min_year Offset of minimum year into list (by default current year -10) + * @param int $max_year Offset of maximum year into list (by default current year + 5) + * @param int $offset Offset + * @param int $invert Invert + * @param string $option Option + * @param string $morecss More CSS + * @return string + */ + public function select_year($selected = '', $htmlname = 'yearid', $useempty = 0, $min_year = 10, $max_year = 5, $offset = 0, $invert = 0, $option = '', $morecss = 'valignmiddle maxwidth75imp') + { + // phpcs:enable + print $this->selectyear($selected, $htmlname, $useempty, $min_year, $max_year, $offset, $invert, $option, $morecss); + } - /** - * Return HTML combo list of years - * - * @param string $selected Preselected value (''=current year, -1=none, year otherwise) - * @param string $htmlname Name of HTML select object - * @param int $useempty Affiche valeur vide dans liste - * @param int $min_year Offset of minimum year into list (by default current year -10) - * @param int $max_year Offset of maximum year into list (by default current year + 5) - * @param int $offset Offset - * @param int $invert Invert - * @param string $option Option - * @param string $morecss More css - * @return string - */ - public function selectyear($selected = '', $htmlname = 'yearid', $useempty = 0, $min_year = 10, $max_year = 5, $offset = 0, $invert = 0, $option = '', $morecss = 'valignmiddle maxwidth75imp') - { - $out = ''; + /** + * Return HTML combo list of years + * + * @param string $selected Preselected value (''=current year, -1=none, year otherwise) + * @param string $htmlname Name of HTML select object + * @param int $useempty Affiche valeur vide dans liste + * @param int $min_year Offset of minimum year into list (by default current year -10) + * @param int $max_year Offset of maximum year into list (by default current year + 5) + * @param int $offset Offset + * @param int $invert Invert + * @param string $option Option + * @param string $morecss More css + * @return string + */ + public function selectyear($selected = '', $htmlname = 'yearid', $useempty = 0, $min_year = 10, $max_year = 5, $offset = 0, $invert = 0, $option = '', $morecss = 'valignmiddle maxwidth75imp') + { + $out = ''; - $currentyear = date("Y") + $offset; - $max_year = $currentyear + $max_year; - $min_year = $currentyear - $min_year; - if (empty($selected) && empty($useempty)) $selected = $currentyear; + $currentyear = date("Y") + $offset; + $max_year = $currentyear + $max_year; + $min_year = $currentyear - $min_year; + if (empty($selected) && empty($useempty)) $selected = $currentyear; - $out .= '\n"; + $out .= '\n"; - return $out; - } + return $out; + } - /** - * Get array with HTML tabs with boxes of a particular area including personalized choices of user. - * Class 'Form' must be known. - * - * @param User $user Object User - * @param String $areacode Code of area for pages - 0 = Home page ... See getListOfPagesForBoxes() + /** + * Get array with HTML tabs with boxes of a particular area including personalized choices of user. + * Class 'Form' must be known. + * + * @param User $user Object User + * @param String $areacode Code of area for pages - 0 = Home page ... See getListOfPagesForBoxes() * @return array array('selectboxlist'=>, 'boxactivated'=>, 'boxlista'=>, 'boxlistb'=>) - */ - public static function getBoxesArea($user, $areacode) - { - global $conf, $langs, $db; + */ + public static function getBoxesArea($user, $areacode) + { + global $conf, $langs, $db; - include_once DOL_DOCUMENT_ROOT.'/core/class/infobox.class.php'; + include_once DOL_DOCUMENT_ROOT.'/core/class/infobox.class.php'; - $confuserzone = 'MAIN_BOXES_'.$areacode; + $confuserzone = 'MAIN_BOXES_'.$areacode; - // $boxactivated will be array of boxes enabled into global setup - // $boxidactivatedforuser will be array of boxes choosed by user + // $boxactivated will be array of boxes enabled into global setup + // $boxidactivatedforuser will be array of boxes choosed by user - $selectboxlist = ''; - $boxactivated = InfoBox::listBoxes($db, 'activated', $areacode, (empty($user->conf->$confuserzone) ?null:$user), array(), 0); // Search boxes of common+user (or common only if user has no specific setup) + $selectboxlist = ''; + $boxactivated = InfoBox::listBoxes($db, 'activated', $areacode, (empty($user->conf->$confuserzone) ?null:$user), array(), 0); // Search boxes of common+user (or common only if user has no specific setup) - $boxidactivatedforuser = array(); - foreach ($boxactivated as $box) - { - if (empty($user->conf->$confuserzone) || $box->fk_user == $user->id) $boxidactivatedforuser[$box->id] = $box->id; // We keep only boxes to show for user - } + $boxidactivatedforuser = array(); + foreach ($boxactivated as $box) + { + if (empty($user->conf->$confuserzone) || $box->fk_user == $user->id) $boxidactivatedforuser[$box->id] = $box->id; // We keep only boxes to show for user + } - // Define selectboxlist - $arrayboxtoactivatelabel = array(); - if (!empty($user->conf->$confuserzone)) - { - $boxorder = ''; - $langs->load("boxes"); // Load label of boxes - foreach ($boxactivated as $box) - { - if (!empty($boxidactivatedforuser[$box->id])) continue; // Already visible for user - $label = $langs->transnoentitiesnoconv($box->boxlabel); - //if (preg_match('/graph/',$box->class)) $label.=' ('.$langs->trans("Graph").')'; - if (preg_match('/graph/', $box->class) && $conf->browser->layout != 'phone') - { - $label = $label.' '; - } - $arrayboxtoactivatelabel[$box->id] = $label; // We keep only boxes not shown for user, to show into combo list - } - foreach ($boxidactivatedforuser as $boxid) - { - if (empty($boxorder)) $boxorder .= 'A:'; + // Define selectboxlist + $arrayboxtoactivatelabel = array(); + if (!empty($user->conf->$confuserzone)) + { + $boxorder = ''; + $langs->load("boxes"); // Load label of boxes + foreach ($boxactivated as $box) + { + if (!empty($boxidactivatedforuser[$box->id])) continue; // Already visible for user + $label = $langs->transnoentitiesnoconv($box->boxlabel); + //if (preg_match('/graph/',$box->class)) $label.=' ('.$langs->trans("Graph").')'; + if (preg_match('/graph/', $box->class) && $conf->browser->layout != 'phone') + { + $label = $label.' '; + } + $arrayboxtoactivatelabel[$box->id] = $label; // We keep only boxes not shown for user, to show into combo list + } + foreach ($boxidactivatedforuser as $boxid) + { + if (empty($boxorder)) $boxorder .= 'A:'; $boxorder .= $boxid.','; - } + } - //var_dump($boxidactivatedforuser); + //var_dump($boxidactivatedforuser); - // Class Form must have been already loaded - $selectboxlist .= ''."\n"; + // Class Form must have been already loaded + $selectboxlist .= ''."\n"; $selectboxlist .= '
'; $selectboxlist .= ''; $selectboxlist .= ''; @@ -1054,19 +1054,19 @@ class FormOther $selectboxlist .= ''; $selectboxlist .= ''; $selectboxlist .= Form::selectarray('boxcombo', $arrayboxtoactivatelabel, -1, $langs->trans("ChooseBoxToAdd").'...', 0, 0, '', 0, 0, 0, 'ASC', 'maxwidth150onsmartphone', 0, 'hidden selected', 0, 1); - if (empty($conf->use_javascript_ajax)) $selectboxlist .= ' '; - $selectboxlist .= '
'; - if (!empty($conf->use_javascript_ajax)) - { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - $selectboxlist .= ajax_combobox("boxcombo"); - } - } + if (empty($conf->use_javascript_ajax)) $selectboxlist .= ' '; + $selectboxlist .= ''; + if (!empty($conf->use_javascript_ajax)) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + $selectboxlist .= ajax_combobox("boxcombo"); + } + } - // Javascript code for dynamic actions - if (!empty($conf->use_javascript_ajax)) - { - $selectboxlist .= ''."\n"; - } + $selectboxlist .= ''."\n"; + } - // Define boxlista and boxlistb - $nbboxactivated = count($boxidactivatedforuser); + // Define boxlista and boxlistb + $nbboxactivated = count($boxidactivatedforuser); - if ($nbboxactivated) - { - // Load translation files required by the page - $langs->loadLangs(array("boxes", "projects")); + if ($nbboxactivated) + { + // Load translation files required by the page + $langs->loadLangs(array("boxes", "projects")); - $emptybox = new ModeleBoxes($db); + $emptybox = new ModeleBoxes($db); - $boxlista .= "\n\n"; + $boxlista .= "\n\n"; - // Define $box_max_lines - $box_max_lines = 5; - if (!empty($conf->global->MAIN_BOXES_MAXLINES)) $box_max_lines = $conf->global->MAIN_BOXES_MAXLINES; + // Define $box_max_lines + $box_max_lines = 5; + if (!empty($conf->global->MAIN_BOXES_MAXLINES)) $box_max_lines = $conf->global->MAIN_BOXES_MAXLINES; - $ii = 0; - foreach ($boxactivated as $key => $box) - { - if ((!empty($user->conf->$confuserzone) && $box->fk_user == 0) || (empty($user->conf->$confuserzone) && $box->fk_user != 0)) continue; + $ii = 0; + foreach ($boxactivated as $key => $box) + { + if ((!empty($user->conf->$confuserzone) && $box->fk_user == 0) || (empty($user->conf->$confuserzone) && $box->fk_user != 0)) continue; if (empty($box->box_order) && $ii < ($nbboxactivated / 2)) $box->box_order = 'A'.sprintf("%02d", ($ii + 1)); // When box_order was not yet set to Axx or Bxx and is still 0 - if (preg_match('/^A/i', $box->box_order)) // column A - { - $ii++; - //print 'box_id '.$boxactivated[$ii]->box_id.' '; - //print 'box_order '.$boxactivated[$ii]->box_order.'
'; - // Show box - $box->loadBox($box_max_lines); - $boxlista .= $box->showBox(null, null, 1); - } - } + if (preg_match('/^A/i', $box->box_order)) // column A + { + $ii++; + //print 'box_id '.$boxactivated[$ii]->box_id.' '; + //print 'box_order '.$boxactivated[$ii]->box_order.'
'; + // Show box + $box->loadBox($box_max_lines); + $boxlista .= $box->showBox(null, null, 1); + } + } - if ($conf->browser->layout != 'phone') - { - $emptybox->box_id = 'A'; - $emptybox->info_box_head = array(); - $emptybox->info_box_contents = array(); - $boxlista .= $emptybox->showBox(array(), array(), 1); - } - $boxlista .= "\n"; + if ($conf->browser->layout != 'phone') + { + $emptybox->box_id = 'A'; + $emptybox->info_box_head = array(); + $emptybox->info_box_contents = array(); + $boxlista .= $emptybox->showBox(array(), array(), 1); + } + $boxlista .= "\n"; - $boxlistb .= "\n\n"; + $boxlistb .= "\n\n"; - $ii = 0; - foreach ($boxactivated as $key => $box) - { - if ((!empty($user->conf->$confuserzone) && $box->fk_user == 0) || (empty($user->conf->$confuserzone) && $box->fk_user != 0)) continue; - if (empty($box->box_order) && $ii < ($nbboxactivated / 2)) $box->box_order = 'B'.sprintf("%02d", ($ii + 1)); // When box_order was not yet set to Axx or Bxx and is still 0 - if (preg_match('/^B/i', $box->box_order)) // colonne B - { - $ii++; - //print 'box_id '.$boxactivated[$ii]->box_id.' '; - //print 'box_order '.$boxactivated[$ii]->box_order.'
'; - // Show box - $box->loadBox($box_max_lines); - $boxlistb .= $box->showBox(null, null, 1); - } - } + $ii = 0; + foreach ($boxactivated as $key => $box) + { + if ((!empty($user->conf->$confuserzone) && $box->fk_user == 0) || (empty($user->conf->$confuserzone) && $box->fk_user != 0)) continue; + if (empty($box->box_order) && $ii < ($nbboxactivated / 2)) $box->box_order = 'B'.sprintf("%02d", ($ii + 1)); // When box_order was not yet set to Axx or Bxx and is still 0 + if (preg_match('/^B/i', $box->box_order)) // colonne B + { + $ii++; + //print 'box_id '.$boxactivated[$ii]->box_id.' '; + //print 'box_order '.$boxactivated[$ii]->box_order.'
'; + // Show box + $box->loadBox($box_max_lines); + $boxlistb .= $box->showBox(null, null, 1); + } + } - if ($conf->browser->layout != 'phone') - { - $emptybox->box_id = 'B'; - $emptybox->info_box_head = array(); - $emptybox->info_box_contents = array(); - $boxlistb .= $emptybox->showBox(array(), array(), 1); - } + if ($conf->browser->layout != 'phone') + { + $emptybox->box_id = 'B'; + $emptybox->info_box_head = array(); + $emptybox->info_box_contents = array(); + $boxlistb .= $emptybox->showBox(array(), array(), 1); + } - $boxlistb .= "\n"; - } + $boxlistb .= "\n"; + } - return array('selectboxlist'=>count($boxactivated) ? $selectboxlist : '', 'boxactivated'=>$boxactivated, 'boxlista'=>$boxlista, 'boxlistb'=>$boxlistb); - } + return array('selectboxlist'=>count($boxactivated) ? $selectboxlist : '', 'boxactivated'=>$boxactivated, 'boxlista'=>$boxlista, 'boxlistb'=>$boxlistb); + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return a HTML select list of a dictionary - * - * @param string $htmlname Name of select zone - * @param string $dictionarytable Dictionary table - * @param string $keyfield Field for key - * @param string $labelfield Label field - * @param string $selected Selected value - * @param int $useempty 1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries. - * @param string $moreattrib More attributes on HTML select tag - * @return void - */ - public function select_dictionary($htmlname, $dictionarytable, $keyfield = 'code', $labelfield = 'label', $selected = '', $useempty = 0, $moreattrib = '') - { - // phpcs:enable - global $langs, $conf; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return a HTML select list of a dictionary + * + * @param string $htmlname Name of select zone + * @param string $dictionarytable Dictionary table + * @param string $keyfield Field for key + * @param string $labelfield Label field + * @param string $selected Selected value + * @param int $useempty 1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries. + * @param string $moreattrib More attributes on HTML select tag + * @return void + */ + public function select_dictionary($htmlname, $dictionarytable, $keyfield = 'code', $labelfield = 'label', $selected = '', $useempty = 0, $moreattrib = '') + { + // phpcs:enable + global $langs, $conf; - $langs->load("admin"); + $langs->load("admin"); - $sql = "SELECT rowid, ".$keyfield.", ".$labelfield; - $sql .= " FROM ".MAIN_DB_PREFIX.$dictionarytable; - $sql .= " ORDER BY ".$labelfield; + $sql = "SELECT rowid, ".$keyfield.", ".$labelfield; + $sql .= " FROM ".MAIN_DB_PREFIX.$dictionarytable; + $sql .= " ORDER BY ".$labelfield; - dol_syslog(get_class($this)."::select_dictionary", LOG_DEBUG); - $result = $this->db->query($sql); - if ($result) - { - $num = $this->db->num_rows($result); - $i = 0; - if ($num) - { - print ''; + if ($useempty == 1 || ($useempty == 2 && $num > 1)) + { + print ''; + } - while ($i < $num) - { - $obj = $this->db->fetch_object($result); - if ($selected == $obj->rowid || $selected == $obj->$keyfield) - { - print ''; - $i++; - } - print ""; - } else { - print $langs->trans("DictionaryEmpty"); - } - } else { - dol_print_error($this->db); - } - } + while ($i < $num) + { + $obj = $this->db->fetch_object($result); + if ($selected == $obj->rowid || $selected == $obj->$keyfield) + { + print ''; + $i++; + } + print ""; + } else { + print $langs->trans("DictionaryEmpty"); + } + } else { + dol_print_error($this->db); + } + } - /** + /** * Return an html string with a select combo box to choose yes or no * * @param string $htmlname Name of html select field @@ -1278,7 +1278,7 @@ class FormOther * @param int $useempty 1=Add empty line * @return string See option */ - public function selectAutoManual($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0) + public function selectAutoManual($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0) { global $langs; diff --git a/htdocs/core/lib/ecm.lib.php b/htdocs/core/lib/ecm.lib.php index 3b0cef1a809..1f22e464358 100644 --- a/htdocs/core/lib/ecm.lib.php +++ b/htdocs/core/lib/ecm.lib.php @@ -146,30 +146,30 @@ function ecm_prepare_head_fm($object) */ function ecm_admin_prepare_head() { - global $langs, $conf; - $langs->load("ecm"); + global $langs, $conf; + $langs->load("ecm"); - $h = 0; - $head = array(); + $h = 0; + $head = array(); - $head[$h][0] = DOL_URL_ROOT."/admin/ecm.php"; - $head[$h][1] = $langs->trans("Setup"); - $head[$h][2] = 'ecm'; - $h++; + $head[$h][0] = DOL_URL_ROOT."/admin/ecm.php"; + $head[$h][1] = $langs->trans("Setup"); + $head[$h][2] = 'ecm'; + $h++; - $head[$h][0] = DOL_URL_ROOT.'/admin/ecm_files_extrafields.php'; - $head[$h][1] = $langs->trans("ExtraFieldsEcmFiles"); - $head[$h][2] = 'attributes_ecm_files'; - $h++; + $head[$h][0] = DOL_URL_ROOT.'/admin/ecm_files_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsEcmFiles"); + $head[$h][2] = 'attributes_ecm_files'; + $h++; - $head[$h][0] = DOL_URL_ROOT.'/admin/ecm_directories_extrafields.php'; - $head[$h][1] = $langs->trans("ExtraFieldsEcmDirectories"); - $head[$h][2] = 'attributes_ecm_directories'; - $h++; + $head[$h][0] = DOL_URL_ROOT.'/admin/ecm_directories_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsEcmDirectories"); + $head[$h][2] = 'attributes_ecm_directories'; + $h++; - complete_head_from_modules($conf, $langs, null, $head, $h, 'ecm_admin'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'ecm_admin'); - complete_head_from_modules($conf, $langs, null, $head, $h, 'ecm_admin', 'remove'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'ecm_admin', 'remove'); - return $head; + return $head; } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 7f2fd4ce70d..63047ed0e7b 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1533,7 +1533,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesess $nbok = 0; for ($i = 0; $i < $nbfile; $i++) { - if (empty($TFile['name'][$i])) continue; // For example, when submitting a form with no file name + if (empty($TFile['name'][$i])) continue; // For example, when submitting a form with no file name // Define $destfull (path to file including filename) and $destfile (only filename) $destfull = $upload_dir."/".$TFile['name'][$i]; @@ -2053,7 +2053,7 @@ function dol_uncompress($inputfile, $outputdir) for ($i = 0; $i < $zip->numFiles; $i++) { if (preg_match('/\.\./', $zip->getNameIndex($i))) { dol_syslog("Warning: Try to unzip a file with a transversal path ".$zip->getNameIndex($i), LOG_WARNING); - continue; // Discard the file + continue; // Discard the file } $zip->extractTo($outputdir.'/', array($zip->getNameIndex($i))); } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 53d1b5fe40b..38e9d972760 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -84,8 +84,8 @@ function getEntity($element, $shared = 1, $currentobject = null) // fix different element names (France to English) switch ($element) { - case 'contrat': $element = 'contract'; break; // "/contrat/class/contrat.class.php" - case 'order_supplier': $element = 'supplier_order'; break; // "/fourn/class/fournisseur.commande.class.php" + case 'contrat': $element = 'contract'; break; // "/contrat/class/contrat.class.php" + case 'order_supplier': $element = 'supplier_order'; break; // "/fourn/class/fournisseur.commande.class.php" } if (is_object($mc)) @@ -1404,7 +1404,7 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab $tabsname = $moretabssuffix; if (empty($tabsname)) { $tabsname = str_replace("@", "", $picto); } $out .= '
'; - $out .= ''.$langs->trans("More").'... ('.$nbintab.')'; // Do not use "reposition" class in the "More". + $out .= ''.$langs->trans("More").'... ('.$nbintab.')'; // Do not use "reposition" class in the "More". $out .= '
'; $out .= $outmore; $out .= '
'; @@ -1415,7 +1415,7 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab $out .= "$('#moretabs".$tabsname."').mouseenter( function() { var x = this.offsetLeft, y = this.offsetTop; console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth); - if ((window.innerWidth - x) < ".($widthofpopup+10).") { + if ((window.innerWidth - x) < ".($widthofpopup + 10).") { $('#moretabsList".$tabsname."').css('".$right."','8px'); } $('#moretabsList".$tabsname."').css('".$left."','auto'); @@ -2808,7 +2808,7 @@ function getUserRemoteIP() $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here } } else { - $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here } return $ip; } @@ -4048,7 +4048,7 @@ function dol_print_error($db = '', $error = '', $errors = null) } // Return a http error code if possible - if (! headers_sent()) { + if (!headers_sent()) { http_response_code(500); } @@ -7833,7 +7833,7 @@ function natural_search($fields, $value, $mode = 0, $nofirstand = 0) $numnewcrit = price2num($newcrit); if (is_numeric($numnewcrit)) { - $newres .= ($i2 > 0 ? ' OR ' : '').$field.' '.$operator.' '.$db->sanitize($numnewcrit); // should be a numeric + $newres .= ($i2 > 0 ? ' OR ' : '').$field.' '.$operator.' '.$db->sanitize($numnewcrit); // should be a numeric } else { $newres .= ($i2 > 0 ? ' OR ' : '').'1 = 2'; // force false } @@ -7841,7 +7841,7 @@ function natural_search($fields, $value, $mode = 0, $nofirstand = 0) } } elseif ($mode == 2 || $mode == -2) { - $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer + $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : ''); $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)"; if ($mode == -2) $newres .= ' OR '.$field.' IS NULL'; @@ -8979,8 +8979,8 @@ function readfileLowMemory($fullpath_original_file_osencoded, $method = -1) if ($method == -1) { $method = 0; - if (! empty($conf->global->MAIN_FORCE_READFILE_WITH_FREAD)) $method = 1; - if (! empty($conf->global->MAIN_FORCE_READFILE_WITH_STREAM_COPY)) $method = 2; + if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_FREAD)) $method = 1; + if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_STREAM_COPY)) $method = 2; } // Be sure we don't have output buffering enabled to have readfile working correctly diff --git a/htdocs/core/lib/payments.lib.php b/htdocs/core/lib/payments.lib.php index 4fb593e354d..601dad3275d 100644 --- a/htdocs/core/lib/payments.lib.php +++ b/htdocs/core/lib/payments.lib.php @@ -29,30 +29,30 @@ function payment_prepare_head(Paiement $object) { - global $langs, $conf; + global $langs, $conf; - $h = 0; - $head = array(); + $h = 0; + $head = array(); - $head[$h][0] = DOL_URL_ROOT.'/compta/paiement/card.php?id='.$object->id; - $head[$h][1] = $langs->trans("Payment"); - $head[$h][2] = 'payment'; - $h++; + $head[$h][0] = DOL_URL_ROOT.'/compta/paiement/card.php?id='.$object->id; + $head[$h][1] = $langs->trans("Payment"); + $head[$h][2] = 'payment'; + $h++; - // Show more tabs from modules - // Entries must be declared in modules descriptor with line - // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab - // $this->tabs = array('entity:-tabname); to remove a tab - complete_head_from_modules($conf, $langs, $object, $head, $h, 'payment'); + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname); to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'payment'); - $head[$h][0] = DOL_URL_ROOT.'/compta/paiement/info.php?id='.$object->id; - $head[$h][1] = $langs->trans("Info"); - $head[$h][2] = 'info'; - $h++; + $head[$h][0] = DOL_URL_ROOT.'/compta/paiement/info.php?id='.$object->id; + $head[$h][1] = $langs->trans("Info"); + $head[$h][2] = 'info'; + $h++; - complete_head_from_modules($conf, $langs, $object, $head, $h, 'payment', 'remove'); + complete_head_from_modules($conf, $langs, $object, $head, $h, 'payment', 'remove'); - return $head; + return $head; } /** @@ -64,30 +64,30 @@ function payment_prepare_head(Paiement $object) */ function bankline_prepare_head($id) { - global $langs, $conf; + global $langs, $conf; - $h = 0; - $head = array(); + $h = 0; + $head = array(); - $head[$h][0] = DOL_URL_ROOT.'/compta/bank/line.php?rowid='.$id; - $head[$h][1] = $langs->trans('BankTransaction'); - $head[$h][2] = 'bankline'; - $h++; + $head[$h][0] = DOL_URL_ROOT.'/compta/bank/line.php?rowid='.$id; + $head[$h][1] = $langs->trans('BankTransaction'); + $head[$h][2] = 'bankline'; + $h++; - // Show more tabs from modules - // Entries must be declared in modules descriptor with line - // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab - // $this->tabs = array('entity:-tabname); to remove a tab - complete_head_from_modules($conf, $langs, null, $head, $h, 'bankline'); + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname); to remove a tab + complete_head_from_modules($conf, $langs, null, $head, $h, 'bankline'); - $head[$h][0] = DOL_URL_ROOT.'/compta/bank/info.php?rowid='.$id; - $head[$h][1] = $langs->trans("Info"); - $head[$h][2] = 'info'; - $h++; + $head[$h][0] = DOL_URL_ROOT.'/compta/bank/info.php?rowid='.$id; + $head[$h][1] = $langs->trans("Info"); + $head[$h][2] = 'info'; + $h++; - complete_head_from_modules($conf, $langs, null, $head, $h, 'bankline', 'remove'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'bankline', 'remove'); - return $head; + return $head; } /** @@ -109,11 +109,11 @@ function payment_supplier_prepare_head(Paiement $object) $head[$h][2] = 'payment'; $h++; - // Show more tabs from modules - // Entries must be declared in modules descriptor with line - // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab - // $this->tabs = array('entity:-tabname); to remove a tab - complete_head_from_modules($conf, $langs, $object, $head, $h, 'payment_supplier'); + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname); to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'payment_supplier'); $head[$h][0] = DOL_URL_ROOT.'/fourn/paiement/info.php?id='.$object->id; $head[$h][1] = $langs->trans('Info'); @@ -170,7 +170,7 @@ function showOnlinePaymentUrl($type, $ref) global $langs; // Load translation files required by the page - $langs->loadLangs(array('payment', 'stripe')); + $langs->loadLangs(array('payment', 'stripe')); $servicename = $langs->transnoentitiesnoconv('Online'); @@ -194,7 +194,7 @@ function showOnlinePaymentUrl($type, $ref) */ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag = 'your_tag', $localorexternal = 0) { - global $conf, $dolibarr_main_url_root; + global $conf, $dolibarr_main_url_root; $ref = str_replace(' ', '', $ref); $out = ''; @@ -209,7 +209,7 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag if ($type == 'free') { - $out = $urltouse.'/public/payment/newpayment.php?amount='.($mode ? '' : '').$amount.($mode ? '' : '').'&tag='.($mode ? '' : '').$freetag.($mode ? '' : ''); + $out = $urltouse.'/public/payment/newpayment.php?amount='.($mode ? '' : '').$amount.($mode ? '' : '').'&tag='.($mode ? '' : '').$freetag.($mode ? '' : ''); if (!empty($conf->global->PAYMENT_SECURITY_TOKEN)) { if (empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE)) $out .= '&securekey='.$conf->global->PAYMENT_SECURITY_TOKEN; @@ -218,7 +218,7 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag //if ($mode) $out.='&noidempotency=1'; } elseif ($type == 'order') { - $out = $urltouse.'/public/payment/newpayment.php?source=order&ref='.($mode ? '' : ''); + $out = $urltouse.'/public/payment/newpayment.php?source=order&ref='.($mode ? '' : ''); if ($mode == 1) $out .= 'order_ref'; if ($mode == 0) $out .= urlencode($ref); $out .= ($mode ? '' : ''); @@ -234,7 +234,7 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag } } elseif ($type == 'invoice') { - $out = $urltouse.'/public/payment/newpayment.php?source=invoice&ref='.($mode ? '' : ''); + $out = $urltouse.'/public/payment/newpayment.php?source=invoice&ref='.($mode ? '' : ''); if ($mode == 1) $out .= 'invoice_ref'; if ($mode == 0) $out .= urlencode($ref); $out .= ($mode ? '' : ''); @@ -250,7 +250,7 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag } } elseif ($type == 'contractline') { - $out = $urltouse.'/public/payment/newpayment.php?source=contractline&ref='.($mode ? '' : ''); + $out = $urltouse.'/public/payment/newpayment.php?source=contractline&ref='.($mode ? '' : ''); if ($mode == 1) $out .= 'contractline_ref'; if ($mode == 0) $out .= urlencode($ref); $out .= ($mode ? '' : ''); @@ -266,7 +266,7 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag } } elseif ($type == 'member' || $type == 'membersubscription') { - $out = $urltouse.'/public/payment/newpayment.php?source=membersubscription&ref='.($mode ? '' : ''); + $out = $urltouse.'/public/payment/newpayment.php?source=membersubscription&ref='.($mode ? '' : ''); if ($mode == 1) $out .= 'member_ref'; if ($mode == 0) $out .= urlencode($ref); $out .= ($mode ? '' : ''); @@ -283,7 +283,7 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag } if ($type == 'donation') { - $out = $urltouse.'/public/payment/newpayment.php?source=donation&ref='.($mode ? '' : ''); + $out = $urltouse.'/public/payment/newpayment.php?source=donation&ref='.($mode ? '' : ''); if ($mode == 1) $out .= 'donation_ref'; if ($mode == 0) $out .= urlencode($ref); $out .= ($mode ? '' : ''); @@ -319,82 +319,82 @@ function getOnlinePaymentUrl($mode, $type, $ref = '', $amount = '9.99', $freetag */ function htmlPrintOnlinePaymentFooter($fromcompany, $langs, $addformmessage = 0, $suffix = '', $object = null) { - global $conf; + global $conf; - // Juridical status - $line1 = ""; - if ($fromcompany->forme_juridique_code) - { - $line1 .= ($line1 ? " - " : "").getFormeJuridiqueLabel($fromcompany->forme_juridique_code); - } - // Capital - if ($fromcompany->capital) - { - $line1 .= ($line1 ? " - " : "").$langs->transnoentities("CapitalOf", $fromcompany->capital)." ".$langs->transnoentities("Currency".$conf->currency); - } - // Prof Id 1 - if ($fromcompany->idprof1 && ($fromcompany->country_code != 'FR' || !$fromcompany->idprof2)) - { - $field = $langs->transcountrynoentities("ProfId1", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; - $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof1; - } - // Prof Id 2 - if ($fromcompany->idprof2) - { - $field = $langs->transcountrynoentities("ProfId2", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; - $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof2; - } + // Juridical status + $line1 = ""; + if ($fromcompany->forme_juridique_code) + { + $line1 .= ($line1 ? " - " : "").getFormeJuridiqueLabel($fromcompany->forme_juridique_code); + } + // Capital + if ($fromcompany->capital) + { + $line1 .= ($line1 ? " - " : "").$langs->transnoentities("CapitalOf", $fromcompany->capital)." ".$langs->transnoentities("Currency".$conf->currency); + } + // Prof Id 1 + if ($fromcompany->idprof1 && ($fromcompany->country_code != 'FR' || !$fromcompany->idprof2)) + { + $field = $langs->transcountrynoentities("ProfId1", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; + $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof1; + } + // Prof Id 2 + if ($fromcompany->idprof2) + { + $field = $langs->transcountrynoentities("ProfId2", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; + $line1 .= ($line1 ? " - " : "").$field.": ".$fromcompany->idprof2; + } - // Second line of company infos - $line2 = ""; - // Prof Id 3 - if ($fromcompany->idprof3) - { - $field = $langs->transcountrynoentities("ProfId3", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; - $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof3; - } - // Prof Id 4 - if ($fromcompany->idprof4) - { - $field = $langs->transcountrynoentities("ProfId4", $fromcompany->country_code); - if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; - $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof4; - } - // IntraCommunautary VAT - if ($fromcompany->tva_intra != '') - { - $line2 .= ($line2 ? " - " : "").$langs->transnoentities("VATIntraShort").": ".$fromcompany->tva_intra; - } + // Second line of company infos + $line2 = ""; + // Prof Id 3 + if ($fromcompany->idprof3) + { + $field = $langs->transcountrynoentities("ProfId3", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; + $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof3; + } + // Prof Id 4 + if ($fromcompany->idprof4) + { + $field = $langs->transcountrynoentities("ProfId4", $fromcompany->country_code); + if (preg_match('/\((.*)\)/i', $field, $reg)) $field = $reg[1]; + $line2 .= ($line2 ? " - " : "").$field.": ".$fromcompany->idprof4; + } + // IntraCommunautary VAT + if ($fromcompany->tva_intra != '') + { + $line2 .= ($line2 ? " - " : "").$langs->transnoentities("VATIntraShort").": ".$fromcompany->tva_intra; + } - print '
'; + print '
'; - print '
'."\n"; - if ($addformmessage) - { - print ''; - print '
'; + print '
'."\n"; + if ($addformmessage) + { + print ''; + print '
'; - $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORM_'.$suffix; - if (!empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform); - elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM); + $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORM_'.$suffix; + if (!empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform); + elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM); - // Add other message if VAT exists - if ($object->total_vat != 0 || $object->total_tva != 0) - { - $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORMIFVAT_'.$suffix; - if (!empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform); - elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT); - } - } + // Add other message if VAT exists + if ($object->total_vat != 0 || $object->total_tva != 0) + { + $parammessageform = 'ONLINE_PAYMENT_MESSAGE_FORMIFVAT_'.$suffix; + if (!empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform); + elseif (!empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT); + } + } - print '

'."\n"; - print $fromcompany->name.'
'; - print $line1; - if (strlen($line1.$line2) > 50) print '
'; - else print ' - '; - print $line2; - print '
'."\n"; + print '

'."\n"; + print $fromcompany->name.'
'; + print $line1; + if (strlen($line1.$line2) > 50) print '
'; + else print ' - '; + print $line2; + print '
'."\n"; } diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 6232afe962e..db79efefc45 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -122,7 +122,7 @@ function pdf_getInstance($format = '', $metric = 'mm', $pagetype = 'P') define('K_SMALL_RATIO', 2 / 3); define('K_THAI_TOPCHARS', true); define('K_TCPDF_CALLS_IN_HTML', true); - if (! empty($conf->global->TCPDF_THROW_ERRORS_INSTEAD_OF_DIE)) { + if (!empty($conf->global->TCPDF_THROW_ERRORS_INSTEAD_OF_DIE)) { define('K_TCPDF_THROW_EXCEPTION_ERROR', true); } else { define('K_TCPDF_THROW_EXCEPTION_ERROR', false); @@ -2140,11 +2140,11 @@ function pdf_getLinkedObjects($object, $outputlangs) if (empty($object->linkedObjects['commande']) && $object->element != 'commande') // There is not already a link to order and object is not the order, so we show also info with order { $elementobject->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0); - if (! empty($elementobject->linkedObjectsIds['commande'])){ + if (!empty($elementobject->linkedObjectsIds['commande'])) { include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; $order = new Commande($db); $ret = $order->fetch(reset($elementobject->linkedObjectsIds['commande'])); - if ($ret < 1) { $order=null; } + if ($ret < 1) { $order = null; } } } if (!is_object($order)) diff --git a/htdocs/core/modules/modCommande.class.php b/htdocs/core/modules/modCommande.class.php index 95d8e35489f..0da6ac160b8 100644 --- a/htdocs/core/modules/modCommande.class.php +++ b/htdocs/core/modules/modCommande.class.php @@ -265,16 +265,16 @@ class modCommande extends DolibarrModules if (empty($user->rights->societe->client->voir)) $this->export_sql_end[$r] .= ' AND sc.fk_user = '.(empty($user) ? 0 : $user->id); // Imports //-------- - $r=0; + $r = 0; //Import Order Header $r++; - $this->import_code[$r] = 'commande_' . $r; + $this->import_code[$r] = 'commande_'.$r; $this->import_label[$r] = 'Sales Orders'; $this->import_icon[$r] = $this->picto; $this->import_entities_array[$r] = []; - $this->import_tables_array[$r] = ['c' => MAIN_DB_PREFIX . 'commande', 'extra' => MAIN_DB_PREFIX . 'commande_extrafields']; - $this->import_tables_creator_array[$r] = ['c' => 'fk_user_author']; // Fields to store import user id + $this->import_tables_array[$r] = ['c' => MAIN_DB_PREFIX.'commande', 'extra' => MAIN_DB_PREFIX.'commande_extrafields']; + $this->import_tables_creator_array[$r] = ['c' => 'fk_user_author']; // Fields to store import user id $this->import_fields_array[$r] = [ 'c.ref' => 'Document Ref*', 'c.ref_client' => 'RefCustomer', @@ -299,7 +299,7 @@ class modCommande extends DolibarrModules 'c.model_pdf' => 'Model' ]; - if (! empty($conf->multicurrency->enabled)) { + if (!empty($conf->multicurrency->enabled)) { $this->import_fields_array[$r]['c.multicurrency_code'] = 'Currency'; $this->import_fields_array[$r]['c.multicurrency_tx'] = 'CurrencyRate'; $this->import_fields_array[$r]['c.multicurrency_total_ht'] = 'MulticurrencyAmountHT'; @@ -309,23 +309,23 @@ class modCommande extends DolibarrModules // Add extra fields $import_extrafield_sample = []; - $sql = "SELECT name, label, fieldrequired FROM " . MAIN_DB_PREFIX . "extrafields WHERE elementtype = 'commande' AND entity IN (0, " . $conf->entity . ")"; + $sql = "SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'commande' AND entity IN (0, ".$conf->entity.")"; $resql = $this->db->query($sql); if ($resql) { while ($obj = $this->db->fetch_object($resql)) { - $fieldname = 'extra.' . $obj->name; + $fieldname = 'extra.'.$obj->name; $fieldlabel = ucfirst($obj->label); - $this->import_fields_array[$r][$fieldname] = $fieldlabel . ($obj->fieldrequired ? '*' : ''); + $this->import_fields_array[$r][$fieldname] = $fieldlabel.($obj->fieldrequired ? '*' : ''); $import_extrafield_sample[$fieldname] = $fieldlabel; } } // End add extra fields - $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-' . MAIN_DB_PREFIX . 'commande']; + $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'commande']; $this->import_regex_array[$r] = [ 'c.ref' => '(CPV\d{4}-\d{4}|CO\d{4}-\d{4}|PROV.{1,32}$)', - 'c.multicurrency_code' => 'code@' . MAIN_DB_PREFIX . 'multicurrency' + 'c.multicurrency_code' => 'code@'.MAIN_DB_PREFIX.'multicurrency' ]; $this->import_updatekeys_array[$r] = ['c.ref' => 'Ref']; @@ -359,7 +359,7 @@ class modCommande extends DolibarrModules $this->import_label[$r] = 'Order Details'; $this->import_icon[$r] = $this->picto; $this->import_entities_array[$r] = []; - $this->import_tables_array[$r] = ['cd' => MAIN_DB_PREFIX . 'commandedet', 'extra' => MAIN_DB_PREFIX . 'commandedet_extrafields']; + $this->import_tables_array[$r] = ['cd' => MAIN_DB_PREFIX.'commandedet', 'extra' => MAIN_DB_PREFIX.'commandedet_extrafields']; $this->import_fields_array[$r] = [ 'cd.fk_commande' => 'Document Ref*', 'cd.fk_parent_line' => 'PrParentLine', @@ -382,7 +382,7 @@ class modCommande extends DolibarrModules 'cd.rang' => 'LinePosition' ]; - if (! empty($conf->multicurrency->enabled)) { + if (!empty($conf->multicurrency->enabled)) { $this->import_fields_array[$r]['cd.multicurrency_code'] = 'Currency'; $this->import_fields_array[$r]['cd.multicurrency_subprice'] = 'CurrencyRate'; $this->import_fields_array[$r]['cd.multicurrency_total_ht'] = 'MulticurrencyAmountHT'; @@ -391,22 +391,22 @@ class modCommande extends DolibarrModules } // Add extra fields - $sql="SELECT name, label, fieldrequired FROM " . MAIN_DB_PREFIX . "extrafields WHERE elementtype = 'commandedet' AND entity IN (0, " . $conf->entity . ")"; + $sql = "SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'commandedet' AND entity IN (0, ".$conf->entity.")"; $resql = $this->db->query($sql); if ($resql) { while ($obj = $this->db->fetch_object($resql)) { - $fieldname = 'extra.' . $obj->name; + $fieldname = 'extra.'.$obj->name; $fieldlabel = ucfirst($obj->label); - $this->import_fields_array[$r][$fieldname] = $fieldlabel . ($obj->fieldrequired ? '*' : ''); + $this->import_fields_array[$r][$fieldname] = $fieldlabel.($obj->fieldrequired ? '*' : ''); } } // End add extra fields - $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-' . MAIN_DB_PREFIX . 'commandedet']; + $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'commandedet']; $this->import_regex_array[$r] = [ 'cd.product_type' => '[0|1]$', - 'cd.fk_product' => 'rowid@' . MAIN_DB_PREFIX . 'product', - 'cd.multicurrency_code' => 'code@' . MAIN_DB_PREFIX . 'multicurrency' + 'cd.fk_product' => 'rowid@'.MAIN_DB_PREFIX.'product', + 'cd.multicurrency_code' => 'code@'.MAIN_DB_PREFIX.'multicurrency' ]; $this->import_updatekeys_array[$r] = ['cd.fk_commande' => 'Sales Order Id', 'cd.fk_product' => 'Product Id']; $this->import_convertvalue_array[$r] = [ diff --git a/htdocs/core/modules/modFournisseur.class.php b/htdocs/core/modules/modFournisseur.class.php index 7d055082121..7f24cc035af 100644 --- a/htdocs/core/modules/modFournisseur.class.php +++ b/htdocs/core/modules/modFournisseur.class.php @@ -63,12 +63,12 @@ class modFournisseur extends DolibarrModules // Data directories to create when module is enabled $this->dirs = array( - "/fournisseur/temp", - "/fournisseur/commande", - "/fournisseur/commande/temp", - "/fournisseur/facture", - "/fournisseur/facture/temp" - ); + "/fournisseur/temp", + "/fournisseur/commande", + "/fournisseur/commande/temp", + "/fournisseur/facture", + "/fournisseur/facture/temp" + ); // Dependencies $this->depends = array("modSociete"); @@ -299,7 +299,7 @@ class modFournisseur extends DolibarrModules 'p.ref'=>'ProductRef', 'p.label'=>'ProductLabel', 'p.accountancy_code_buy'=>'ProductAccountancyBuyCode', 'project.rowid'=>'ProjectId', 'project.ref'=>'ProjectRef', 'project.title'=>'ProjectLabel' ); - if (! empty($conf->multicurrency->enabled)) + if (!empty($conf->multicurrency->enabled)) { $this->export_fields_array[$r]['f.multicurrency_code'] = 'Currency'; $this->export_fields_array[$r]['f.multicurrency_tx'] = 'CurrencyRate'; @@ -434,7 +434,7 @@ class modFournisseur extends DolibarrModules 'f.fk_statut'=>'InvoiceStatus', 'f.note_public'=>"InvoiceNote", 'p.rowid'=>'PaymentId', 'pf.amount'=>'AmountPayment', 'p.datep'=>'DatePayment', 'p.num_paiement'=>'PaymentNumber', 'p.fk_bank'=>'IdTransaction', 'project.rowid'=>'ProjectId', 'project.ref'=>'ProjectRef', 'project.title'=>'ProjectLabel' ); - if (! empty($conf->multicurrency->enabled)) + if (!empty($conf->multicurrency->enabled)) { $this->export_fields_array[$r]['f.multicurrency_code'] = 'Currency'; $this->export_fields_array[$r]['f.multicurrency_tx'] = 'CurrencyRate'; @@ -528,7 +528,7 @@ class modFournisseur extends DolibarrModules 'fd.total_tva'=>"LineTotalVAT", 'fd.product_type'=>'TypeOfLineServiceOrProduct', 'fd.ref'=>'RefSupplier', 'fd.fk_product'=>'ProductId', 'p.ref'=>'ProductRef', 'p.label'=>'ProductLabel', 'project.rowid'=>'ProjectId', 'project.ref'=>'ProjectRef', 'project.title'=>'ProjectLabel' ); - if (! empty($conf->multicurrency->enabled)) + if (!empty($conf->multicurrency->enabled)) { $this->export_fields_array[$r]['f.multicurrency_code'] = 'Currency'; $this->export_fields_array[$r]['f.multicurrency_tx'] = 'CurrencyRate'; @@ -654,15 +654,15 @@ class modFournisseur extends DolibarrModules //Import Supplier Invoice //-------- - $r=0; + $r = 0; $r++; - $this->import_code[$r] = $this->rights_class . '_' . $r; - $this->import_label[$r] = "Supplier Invoice"; // Translation key + $this->import_code[$r] = $this->rights_class.'_'.$r; + $this->import_label[$r] = "Supplier Invoice"; // Translation key $this->import_icon[$r] = $this->picto; - $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon - $this->import_tables_array[$r] = ['f' => MAIN_DB_PREFIX . 'facture_fourn', 'extra' => MAIN_DB_PREFIX . 'facture_fourn_extrafields']; - $this->import_tables_creator_array[$r] = ['f' => 'fk_user_author']; // Fields to store import user id + $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon + $this->import_tables_array[$r] = ['f' => MAIN_DB_PREFIX.'facture_fourn', 'extra' => MAIN_DB_PREFIX.'facture_fourn_extrafields']; + $this->import_tables_creator_array[$r] = ['f' => 'fk_user_author']; // Fields to store import user id $this->import_fields_array[$r] = [ 'f.ref' => 'InvoiceRef*', 'f.ref_supplier' => 'RefSupplier', @@ -697,19 +697,19 @@ class modFournisseur extends DolibarrModules } // Add extra fields $import_extrafield_sample = []; - $sql = "SELECT name, label, fieldrequired FROM " . MAIN_DB_PREFIX . "extrafields WHERE elementtype = 'facture_fourn' AND entity IN (0, " . $conf->entity . ")"; + $sql = "SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'facture_fourn' AND entity IN (0, ".$conf->entity.")"; $resql = $this->db->query($sql); if ($resql) { while ($obj = $this->db->fetch_object($resql)) { - $fieldname = 'extra.' . $obj->name; + $fieldname = 'extra.'.$obj->name; $fieldlabel = ucfirst($obj->label); - $this->import_fields_array[$r][$fieldname] = $fieldlabel . ($obj->fieldrequired ? '*' : ''); + $this->import_fields_array[$r][$fieldname] = $fieldlabel.($obj->fieldrequired ? '*' : ''); $import_extrafield_sample[$fieldname] = $fieldlabel; } } // End add extra fields - $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-' . MAIN_DB_PREFIX . 'facture_fourn']; - $this->import_regex_array[$r] = ['f.ref' => '(SI\d{4}-\d{4}|PROV.{1,32}$)', 'f.multicurrency_code' => 'code@' . MAIN_DB_PREFIX . 'multicurrency']; + $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'facture_fourn']; + $this->import_regex_array[$r] = ['f.ref' => '(SI\d{4}-\d{4}|PROV.{1,32}$)', 'f.multicurrency_code' => 'code@'.MAIN_DB_PREFIX.'multicurrency']; $import_sample = [ 'f.ref' => '(PROV001)', 'f.ref_supplier' => 'Supplier1', @@ -751,10 +751,10 @@ class modFournisseur extends DolibarrModules //Import Supplier Invoice Lines $r++; $this->import_code[$r] = $this->rights_class.'_'.$r; - $this->import_label[$r] = "Supplier Invoice Lines"; // Translation key + $this->import_label[$r] = "Supplier Invoice Lines"; // Translation key $this->import_icon[$r] = $this->picto; - $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon - $this->import_tables_array[$r] = ['fd' => MAIN_DB_PREFIX . 'facture_fourn_det', 'extra' => MAIN_DB_PREFIX . 'facture_fourn_det_extrafields']; + $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon + $this->import_tables_array[$r] = ['fd' => MAIN_DB_PREFIX.'facture_fourn_det', 'extra' => MAIN_DB_PREFIX.'facture_fourn_det_extrafields']; $this->import_fields_array[$r] = [ 'fd.fk_facture_fourn' => 'InvoiceRef*', 'fd.fk_parent_line' => 'FacParentLine', @@ -784,19 +784,19 @@ class modFournisseur extends DolibarrModules } // Add extra fields $import_extrafield_sample = []; - $sql = "SELECT name, label, fieldrequired FROM " . MAIN_DB_PREFIX . "extrafields WHERE elementtype = 'facture_fourn_det' AND entity IN (0, " . $conf->entity . ")"; + $sql = "SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'facture_fourn_det' AND entity IN (0, ".$conf->entity.")"; $resql = $this->db->query($sql); if ($resql) { while ($obj = $this->db->fetch_object($resql)) { - $fieldname = 'extra.' . $obj->name; + $fieldname = 'extra.'.$obj->name; $fieldlabel = ucfirst($obj->label); - $this->import_fields_array[$r][$fieldname] = $fieldlabel . ($obj->fieldrequired ? '*' : ''); + $this->import_fields_array[$r][$fieldname] = $fieldlabel.($obj->fieldrequired ? '*' : ''); $import_extrafield_sample[$fieldname] = $fieldlabel; } } // End add extra fields - $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-' . MAIN_DB_PREFIX . 'facture_fourn_det']; - $this->import_regex_array[$r] = ['fd.product_type' => '[0|1]$', 'fd.fk_product' => 'rowid@' . MAIN_DB_PREFIX . 'product', 'fd.multicurrency_code' => 'code@' . MAIN_DB_PREFIX . 'multicurrency']; + $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'facture_fourn_det']; + $this->import_regex_array[$r] = ['fd.product_type' => '[0|1]$', 'fd.fk_product' => 'rowid@'.MAIN_DB_PREFIX.'product', 'fd.multicurrency_code' => 'code@'.MAIN_DB_PREFIX.'multicurrency']; $import_sample = [ 'fd.fk_facture_fourn' => '(PROV001)', 'fd.fk_parent_line' => '', @@ -835,7 +835,7 @@ class modFournisseur extends DolibarrModules * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. * It also creates data directories * - * @param string $options Options when enabling module ('', 'noboxes') + * @param string $options Options when enabling module ('', 'noboxes') * @return int 1 if OK, 0 if KO */ public function init($options = '') diff --git a/htdocs/core/modules/modMrp.class.php b/htdocs/core/modules/modMrp.class.php index b7901e38fd7..012bb2d576a 100644 --- a/htdocs/core/modules/modMrp.class.php +++ b/htdocs/core/modules/modMrp.class.php @@ -33,155 +33,155 @@ include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php'; */ class modMrp extends DolibarrModules { - /** - * Constructor. Define names, constants, directories, boxes, permissions - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - global $langs, $conf; - $this->db = $db; + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $langs, $conf; + $this->db = $db; - // Id for module (must be unique). - // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). - $this->numero = 660; - // Key text used to identify module (for permissions, menus, etc...) - $this->rights_class = 'mrp'; - // Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...' - // It is used to group modules by family in module setup page - $this->family = "products"; - // Module position in the family on 2 digits ('01', '10', '20', ...) - $this->module_position = '66'; - // Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this) - //$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily"))); - // Module label (no space allowed), used if translation string 'ModuleMrpName' not found (Mrp is name of module). - $this->name = preg_replace('/^mod/i', '', get_class($this)); - // Module description, used if translation string 'ModuleMrpDesc' not found (Mrp is name of module). - $this->description = "Module to Manage Manufacturing Orders (MO)"; - // Used only if file README.md and README-LL.md not found. - $this->descriptionlong = "Module to Manage Manufacturing Orders (MO)"; - // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' - $this->version = 'dolibarr'; - // Url to the file with your last numberversion of this module - //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; + // Id for module (must be unique). + // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). + $this->numero = 660; + // Key text used to identify module (for permissions, menus, etc...) + $this->rights_class = 'mrp'; + // Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...' + // It is used to group modules by family in module setup page + $this->family = "products"; + // Module position in the family on 2 digits ('01', '10', '20', ...) + $this->module_position = '66'; + // Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this) + //$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily"))); + // Module label (no space allowed), used if translation string 'ModuleMrpName' not found (Mrp is name of module). + $this->name = preg_replace('/^mod/i', '', get_class($this)); + // Module description, used if translation string 'ModuleMrpDesc' not found (Mrp is name of module). + $this->description = "Module to Manage Manufacturing Orders (MO)"; + // Used only if file README.md and README-LL.md not found. + $this->descriptionlong = "Module to Manage Manufacturing Orders (MO)"; + // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' + $this->version = 'dolibarr'; + // Url to the file with your last numberversion of this module + //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; - // Key used in llx_const table to save module status enabled/disabled (where MRP is value of property name of module in uppercase) - $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); - // Name of image file used for this module. - // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' - // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' - $this->picto = 'mrp'; - // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) - $this->module_parts = array( - // Set this to 1 if module has its own trigger directory (core/triggers) - 'triggers' => 0, - // Set this to 1 if module has its own login method file (core/login) - 'login' => 0, - // Set this to 1 if module has its own substitution function file (core/substitutions) - 'substitutions' => 0, - // Set this to 1 if module has its own menus handler directory (core/menus) - 'menus' => 0, - // Set this to 1 if module overwrite template dir (core/tpl) - 'tpl' => 0, - // Set this to 1 if module has its own barcode directory (core/modules/barcode) - 'barcode' => 0, - // Set this to 1 if module has its own models directory (core/modules/xxx) - 'models' => 0, - // Set this to 1 if module has its own theme directory (theme) - 'theme' => 0, - // Set this to relative path of css file if module has its own css file - 'css' => array( - // '/mrp/css/mrp.css.php', - ), - // Set this to relative path of js file if module must load a js on all pages - 'js' => array( - // '/mrp/js/mrp.js.php', - ), - // Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context to 'all' - 'hooks' => array( - // 'data' => array( - // 'hookcontext1', - // 'hookcontext2', - // ), - // 'entity' => '0', - ), - // Set this to 1 if features of module are opened to external users - 'moduleforexternal' => 0, - ); - // Data directories to create when module is enabled. - // Example: this->dirs = array("/mrp/temp","/mrp/subdir"); - $this->dirs = array("/mrp/temp"); - // Config pages. Put here list of php page, stored into mrp/admin directory, to use to setup module. - $this->config_page_url = array("mrp.php"); - // Dependencies - // A condition to hide module - $this->hidden = false; - // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) - $this->depends = array('modBom'); - $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) - $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) - $this->langfiles = array("mrp"); - $this->phpmin = array(5, 5); // Minimum version of PHP required by module - $this->need_dolibarr_version = array(8, 0); // Minimum version of Dolibarr required by module - $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...) - $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...) - //$this->automatic_activation = array('FR'=>'MrpWasAutomaticallyActivatedBecauseOfYourCountryChoice'); - //$this->always_enabled = true; // If true, can't be disabled + // Key used in llx_const table to save module status enabled/disabled (where MRP is value of property name of module in uppercase) + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + // Name of image file used for this module. + // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' + // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' + $this->picto = 'mrp'; + // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) + $this->module_parts = array( + // Set this to 1 if module has its own trigger directory (core/triggers) + 'triggers' => 0, + // Set this to 1 if module has its own login method file (core/login) + 'login' => 0, + // Set this to 1 if module has its own substitution function file (core/substitutions) + 'substitutions' => 0, + // Set this to 1 if module has its own menus handler directory (core/menus) + 'menus' => 0, + // Set this to 1 if module overwrite template dir (core/tpl) + 'tpl' => 0, + // Set this to 1 if module has its own barcode directory (core/modules/barcode) + 'barcode' => 0, + // Set this to 1 if module has its own models directory (core/modules/xxx) + 'models' => 0, + // Set this to 1 if module has its own theme directory (theme) + 'theme' => 0, + // Set this to relative path of css file if module has its own css file + 'css' => array( + // '/mrp/css/mrp.css.php', + ), + // Set this to relative path of js file if module must load a js on all pages + 'js' => array( + // '/mrp/js/mrp.js.php', + ), + // Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context to 'all' + 'hooks' => array( + // 'data' => array( + // 'hookcontext1', + // 'hookcontext2', + // ), + // 'entity' => '0', + ), + // Set this to 1 if features of module are opened to external users + 'moduleforexternal' => 0, + ); + // Data directories to create when module is enabled. + // Example: this->dirs = array("/mrp/temp","/mrp/subdir"); + $this->dirs = array("/mrp/temp"); + // Config pages. Put here list of php page, stored into mrp/admin directory, to use to setup module. + $this->config_page_url = array("mrp.php"); + // Dependencies + // A condition to hide module + $this->hidden = false; + // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) + $this->depends = array('modBom'); + $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) + $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) + $this->langfiles = array("mrp"); + $this->phpmin = array(5, 5); // Minimum version of PHP required by module + $this->need_dolibarr_version = array(8, 0); // Minimum version of Dolibarr required by module + $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + //$this->automatic_activation = array('FR'=>'MrpWasAutomaticallyActivatedBecauseOfYourCountryChoice'); + //$this->always_enabled = true; // If true, can't be disabled - // Constants - // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) - // Example: $this->const=array(1 => array('MRP_MYNEWCONST1', 'chaine', 'myvalue', 'This is a constant to add', 1), - // 2 => array('MRP_MYNEWCONST2', 'chaine', 'myvalue', 'This is another constant to add', 0, 'current', 1) - // ); - $this->const = array( - 1=>array('MRP_MO_ADDON_PDF', 'chaine', 'alpha', 'Name of PDF model of MO', 0), - 2=>array('MRP_MO_ADDON', 'chaine', 'mod_mo_standard', 'Name of numbering rules of MO', 0), - 3=>array('MRP_MO_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/mrps', '', 0) - ); + // Constants + // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) + // Example: $this->const=array(1 => array('MRP_MYNEWCONST1', 'chaine', 'myvalue', 'This is a constant to add', 1), + // 2 => array('MRP_MYNEWCONST2', 'chaine', 'myvalue', 'This is another constant to add', 0, 'current', 1) + // ); + $this->const = array( + 1=>array('MRP_MO_ADDON_PDF', 'chaine', 'alpha', 'Name of PDF model of MO', 0), + 2=>array('MRP_MO_ADDON', 'chaine', 'mod_mo_standard', 'Name of numbering rules of MO', 0), + 3=>array('MRP_MO_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/mrps', '', 0) + ); - // Some keys to add into the overwriting translation tables - /*$this->overwrite_translation = array( + // Some keys to add into the overwriting translation tables + /*$this->overwrite_translation = array( 'en_US:ParentCompany'=>'Parent company or reseller', 'fr_FR:ParentCompany'=>'Maison mère ou revendeur' )*/ - if (!isset($conf->mrp) || !isset($conf->mrp->enabled)) { - $conf->mrp = new stdClass(); - $conf->mrp->enabled = 0; - } + if (!isset($conf->mrp) || !isset($conf->mrp->enabled)) { + $conf->mrp = new stdClass(); + $conf->mrp->enabled = 0; + } - // Array to add new pages in new tabs - $this->tabs = array(); - // Example: - // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@mrp:$user->rights->mrp->read:/mrp/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1 - // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@mrp:$user->rights->othermodule->read:/mrp/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. - // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname - // - // Where objecttype can be - // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) - // 'contact' to add a tab in contact view - // 'contract' to add a tab in contract view - // 'group' to add a tab in group view - // 'intervention' to add a tab in intervention view - // 'invoice' to add a tab in customer invoice view - // 'invoice_supplier' to add a tab in supplier invoice view - // 'member' to add a tab in fundation member view - // 'opensurveypoll' to add a tab in opensurvey poll view - // 'order' to add a tab in customer order view - // 'order_supplier' to add a tab in supplier order view - // 'payment' to add a tab in payment view - // 'payment_supplier' to add a tab in supplier payment view - // 'product' to add a tab in product view - // 'propal' to add a tab in propal view - // 'project' to add a tab in project view - // 'stock' to add a tab in stock view - // 'thirdparty' to add a tab in third party view - // 'user' to add a tab in user view + // Array to add new pages in new tabs + $this->tabs = array(); + // Example: + // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@mrp:$user->rights->mrp->read:/mrp/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1 + // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@mrp:$user->rights->othermodule->read:/mrp/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. + // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname + // + // Where objecttype can be + // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) + // 'contact' to add a tab in contact view + // 'contract' to add a tab in contract view + // 'group' to add a tab in group view + // 'intervention' to add a tab in intervention view + // 'invoice' to add a tab in customer invoice view + // 'invoice_supplier' to add a tab in supplier invoice view + // 'member' to add a tab in fundation member view + // 'opensurveypoll' to add a tab in opensurvey poll view + // 'order' to add a tab in customer order view + // 'order_supplier' to add a tab in supplier order view + // 'payment' to add a tab in payment view + // 'payment_supplier' to add a tab in supplier payment view + // 'product' to add a tab in product view + // 'propal' to add a tab in propal view + // 'project' to add a tab in project view + // 'stock' to add a tab in stock view + // 'thirdparty' to add a tab in third party view + // 'user' to add a tab in user view - // Dictionaries - $this->dictionaries = array(); - /* Example: + // Dictionaries + $this->dictionaries = array(); + /* Example: $this->dictionaries=array( 'langs'=>'mylangfile@mrp', // List of tables we want to see into dictonnary editor @@ -205,68 +205,68 @@ class modMrp extends DolibarrModules ); */ - // Boxes/Widgets - // Add here list of php file(s) stored in mrp/core/boxes that contains a class to show a widget. - $this->boxes = array( - 0 => array('file' => 'box_mos.php', 'note' => '', 'enabledbydefaulton' => 'Home') - ); + // Boxes/Widgets + // Add here list of php file(s) stored in mrp/core/boxes that contains a class to show a widget. + $this->boxes = array( + 0 => array('file' => 'box_mos.php', 'note' => '', 'enabledbydefaulton' => 'Home') + ); - // Cronjobs (List of cron jobs entries to add when module is enabled) - // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week - $this->cronjobs = array( - // 0 => array( - // 'label' => 'MyJob label', - // 'jobtype' => 'method', - // 'class' => '/mrp/class/mo.class.php', - // 'objectname' => 'Mo', - // 'method' => 'doScheduledJob', - // 'parameters' => '', - // 'comment' => 'Comment', - // 'frequency' => 2, - // 'unitfrequency' => 3600, - // 'status' => 0, - // 'test' => '$conf->mrp->enabled', - // 'priority' => 50, - // ), - ); - // Example: $this->cronjobs=array( - // 0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->mrp->enabled', 'priority'=>50), - // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'$conf->mrp->enabled', 'priority'=>50) - // ); + // Cronjobs (List of cron jobs entries to add when module is enabled) + // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week + $this->cronjobs = array( + // 0 => array( + // 'label' => 'MyJob label', + // 'jobtype' => 'method', + // 'class' => '/mrp/class/mo.class.php', + // 'objectname' => 'Mo', + // 'method' => 'doScheduledJob', + // 'parameters' => '', + // 'comment' => 'Comment', + // 'frequency' => 2, + // 'unitfrequency' => 3600, + // 'status' => 0, + // 'test' => '$conf->mrp->enabled', + // 'priority' => 50, + // ), + ); + // Example: $this->cronjobs=array( + // 0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->mrp->enabled', 'priority'=>50), + // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'$conf->mrp->enabled', 'priority'=>50) + // ); - // Permissions provided by this module - $this->rights = array(); - $r = 0; - // Add here entries to declare new permissions - /* BEGIN MODULEBUILDER PERMISSIONS */ - $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Read Manufacturing Order'; // Permission label - $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) - $r++; - $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Create/Update Manufacturing Order'; // Permission label - $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) - $r++; - $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Delete Manufacturing Order'; // Permission label - $this->rights[$r][4] = 'delete'; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) - $r++; - /* END MODULEBUILDER PERMISSIONS */ + // Permissions provided by this module + $this->rights = array(); + $r = 0; + // Add here entries to declare new permissions + /* BEGIN MODULEBUILDER PERMISSIONS */ + $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) + $this->rights[$r][1] = 'Read Manufacturing Order'; // Permission label + $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) + $r++; + $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) + $this->rights[$r][1] = 'Create/Update Manufacturing Order'; // Permission label + $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) + $r++; + $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) + $this->rights[$r][1] = 'Delete Manufacturing Order'; // Permission label + $this->rights[$r][4] = 'delete'; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->mrp->level1->level2) + $r++; + /* END MODULEBUILDER PERMISSIONS */ - // Main menu entries to add - $this->menu = array(); - $r = 0; - // Add here entries to declare new menus - /* BEGIN MODULEBUILDER TOPMENU */ + // Main menu entries to add + $this->menu = array(); + $r = 0; + // Add here entries to declare new menus + /* BEGIN MODULEBUILDER TOPMENU */ /* END MODULEBUILDER LEFTMENU MO */ - // Exports profiles provided by this module - $r = 1; - /* BEGIN MODULEBUILDER EXPORT MO */ - /* + // Exports profiles provided by this module + $r = 1; + /* BEGIN MODULEBUILDER EXPORT MO */ + /* $langs->load("mrp"); $this->export_code[$r]=$this->rights_class.'_'.$r; $this->export_label[$r]='MoLines'; // Translation key (used only if key ExportDataset_xxx_z not found) @@ -281,12 +281,12 @@ class modMrp extends DolibarrModules $this->export_sql_end[$r] .=' WHERE 1 = 1'; $this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('mo').')'; $r++; */ - /* END MODULEBUILDER EXPORT MO */ + /* END MODULEBUILDER EXPORT MO */ - // Imports profiles provided by this module - $r = 1; - /* BEGIN MODULEBUILDER IMPORT MO */ - /* + // Imports profiles provided by this module + $r = 1; + /* BEGIN MODULEBUILDER IMPORT MO */ + /* $langs->load("mrp"); $this->export_code[$r]=$this->rights_class.'_'.$r; $this->export_label[$r]='MoLines'; // Translation key (used only if key ExportDataset_xxx_z not found) @@ -301,75 +301,75 @@ class modMrp extends DolibarrModules $this->export_sql_end[$r] .=' WHERE 1 = 1'; $this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('mo').')'; $r++; */ - /* END MODULEBUILDER IMPORT MO */ - } + /* END MODULEBUILDER IMPORT MO */ + } - /** - * Function called when module is enabled. - * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. - * It also creates data directories - * - * @param string $options Options when enabling module ('', 'noboxes') - * @return int 1 if OK, 0 if KO - */ - public function init($options = '') - { - global $conf, $langs; + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function init($options = '') + { + global $conf, $langs; - $result = $this->_load_tables('/mrp/sql/'); - if ($result < 0) return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default') + $result = $this->_load_tables('/mrp/sql/'); + if ($result < 0) return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default') - // Create extrafields during init - //include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; - //$extrafields = new ExtraFields($this->db); - //$result1=$extrafields->addExtraField('myattr1', "New Attr 1 label", 'boolean', 1, 3, 'thirdparty', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); - //$result2=$extrafields->addExtraField('myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); - //$result3=$extrafields->addExtraField('myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); - //$result4=$extrafields->addExtraField('myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); - //$result5=$extrafields->addExtraField('myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); + // Create extrafields during init + //include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + //$extrafields = new ExtraFields($this->db); + //$result1=$extrafields->addExtraField('myattr1', "New Attr 1 label", 'boolean', 1, 3, 'thirdparty', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); + //$result2=$extrafields->addExtraField('myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); + //$result3=$extrafields->addExtraField('myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); + //$result4=$extrafields->addExtraField('myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); + //$result5=$extrafields->addExtraField('myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', 0, 0, '', '', 'mrp', '$conf->mrp->enabled'); - // Permissions - $this->remove($options); + // Permissions + $this->remove($options); - $sql = array(); + $sql = array(); - // ODT template - $src = DOL_DOCUMENT_ROOT.'/install/doctemplates/mrps/template_mo.odt'; - $dirodt = DOL_DATA_ROOT.'/doctemplates/mrps'; - $dest = $dirodt.'/template_mo.odt'; + // ODT template + $src = DOL_DOCUMENT_ROOT.'/install/doctemplates/mrps/template_mo.odt'; + $dirodt = DOL_DATA_ROOT.'/doctemplates/mrps'; + $dest = $dirodt.'/template_mo.odt'; - if (file_exists($src) && !file_exists($dest)) - { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - dol_mkdir($dirodt); - $result = dol_copy($src, $dest, 0, 0); - if ($result < 0) - { - $langs->load("errors"); - $this->error = $langs->trans('ErrorFailToCopyFile', $src, $dest); - return 0; - } - } + if (file_exists($src) && !file_exists($dest)) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + dol_mkdir($dirodt); + $result = dol_copy($src, $dest, 0, 0); + if ($result < 0) + { + $langs->load("errors"); + $this->error = $langs->trans('ErrorFailToCopyFile', $src, $dest); + return 0; + } + } - $sql = array( - //"DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape('standard')."' AND type = 'mo' AND entity = ".$conf->entity, - //"INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape('standard')."', 'mo', ".$conf->entity.")" - ); + $sql = array( + //"DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape('standard')."' AND type = 'mo' AND entity = ".$conf->entity, + //"INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape('standard')."', 'mo', ".$conf->entity.")" + ); - return $this->_init($sql, $options); - } + return $this->_init($sql, $options); + } - /** - * Function called when module is disabled. - * Remove from database constants, boxes and permissions from Dolibarr database. - * Data directories are not deleted - * - * @param string $options Options when enabling module ('', 'noboxes') - * @return int 1 if OK, 0 if KO - */ - public function remove($options = '') - { - $sql = array(); - return $this->_remove($sql, $options); - } + /** + * Function called when module is disabled. + * Remove from database constants, boxes and permissions from Dolibarr database. + * Data directories are not deleted + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function remove($options = '') + { + $sql = array(); + return $this->_remove($sql, $options); + } } diff --git a/htdocs/core/modules/modPropale.class.php b/htdocs/core/modules/modPropale.class.php index 4da02808251..5791998ff6a 100644 --- a/htdocs/core/modules/modPropale.class.php +++ b/htdocs/core/modules/modPropale.class.php @@ -262,11 +262,11 @@ class modPropale extends DolibarrModules $r++; $this->import_code[$r] = $this->rights_class.'_'.$r; - $this->import_label[$r] = 'Proposals'; // Translation key + $this->import_label[$r] = 'Proposals'; // Translation key $this->import_icon[$r] = $this->picto; - $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon - $this->import_tables_array[$r] = ['c' => MAIN_DB_PREFIX . 'propal', 'extra' => MAIN_DB_PREFIX . 'propal_extrafields']; - $this->import_tables_creator_array[$r] = ['c'=>'fk_user_author']; // Fields to store import user id + $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon + $this->import_tables_array[$r] = ['c' => MAIN_DB_PREFIX.'propal', 'extra' => MAIN_DB_PREFIX.'propal_extrafields']; + $this->import_tables_creator_array[$r] = ['c'=>'fk_user_author']; // Fields to store import user id $this->import_fields_array[$r] = [ 'c.ref' => 'Document Ref*', 'c.ref_client' => 'RefCustomer', @@ -282,7 +282,7 @@ class modPropale extends DolibarrModules 'c.date_livraison' => 'DeliveryDate', 'c.fk_user_valid' => 'ValidatedById' ]; - if (! empty($conf->multicurrency->enabled)) { + if (!empty($conf->multicurrency->enabled)) { $this->import_fields_array[$r]['c.multicurrency_code'] = 'Currency'; $this->import_fields_array[$r]['c.multicurrency_tx'] = 'CurrencyRate'; $this->import_fields_array[$r]['c.multicurrency_total_ht'] = 'MulticurrencyAmountHT'; @@ -291,18 +291,18 @@ class modPropale extends DolibarrModules } // Add extra fields $import_extrafield_sample = []; - $sql = "SELECT name, label, fieldrequired FROM " . MAIN_DB_PREFIX . "extrafields WHERE elementtype = 'propal' AND entity IN (0, " . $conf->entity . ")"; + $sql = "SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'propal' AND entity IN (0, ".$conf->entity.")"; $resql = $this->db->query($sql); if ($resql) { while ($obj = $this->db->fetch_object($resql)) { - $fieldname = 'extra.' . $obj->name; + $fieldname = 'extra.'.$obj->name; $fieldlabel = ucfirst($obj->label); - $this->import_fields_array[$r][$fieldname] = $fieldlabel . ($obj->fieldrequired ? '*' : ''); + $this->import_fields_array[$r][$fieldname] = $fieldlabel.($obj->fieldrequired ? '*' : ''); $import_extrafield_sample[$fieldname] = $fieldlabel; } } // End add extra fields - $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-' . MAIN_DB_PREFIX . 'propal']; + $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'propal']; $this->import_regex_array[$r] = ['c.ref' => '[^ ]']; $import_sample = [ 'c.ref' => 'PROV0077', @@ -339,12 +339,12 @@ class modPropale extends DolibarrModules //Import Proposal Lines $r++; $this->import_code[$r] = $this->rights_class.'line_'.$r; - $this->import_label[$r] = "ProposalLine"; // Translation key + $this->import_label[$r] = "ProposalLine"; // Translation key $this->import_icon[$r] = $this->picto; - $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon + $this->import_entities_array[$r] = []; // We define here only fields that use another icon that the one defined into import_icon $this->import_tables_array[$r] = [ - 'cd' => MAIN_DB_PREFIX . 'propaldet', - 'extra' => MAIN_DB_PREFIX . 'propaldet_extrafields' + 'cd' => MAIN_DB_PREFIX.'propaldet', + 'extra' => MAIN_DB_PREFIX.'propaldet_extrafields' ]; $this->import_fields_array[$r] = [ 'cd.fk_propal' => 'Document Ref*', @@ -366,7 +366,7 @@ class modPropale extends DolibarrModules 'cd.date_end' => 'End Date', 'cd.buy_price_ht' => 'LineBuyPriceHT' ]; - if (! empty($conf->multicurrency->enabled)) { + if (!empty($conf->multicurrency->enabled)) { $this->import_fields_array[$r]['cd.multicurrency_code'] = 'Currency'; $this->import_fields_array[$r]['cd.multicurrency_subprice'] = 'CurrencyRate'; $this->import_fields_array[$r]['cd.multicurrency_total_ht'] = 'MulticurrencyAmountHT'; @@ -379,14 +379,14 @@ class modPropale extends DolibarrModules $resql = $this->db->query($sql); if ($resql) { while ($obj = $this->db->fetch_object($resql)) { - $fieldname = 'extra.' . $obj->name; + $fieldname = 'extra.'.$obj->name; $fieldlabel = ucfirst($obj->label); - $this->import_fields_array[$r][$fieldname] = $fieldlabel . ($obj->fieldrequired ? '*' : ''); + $this->import_fields_array[$r][$fieldname] = $fieldlabel.($obj->fieldrequired ? '*' : ''); $import_extrafield_sample[$fieldname] = $fieldlabel; } } // End add extra fields - $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-' . MAIN_DB_PREFIX . 'propaldet']; + $this->import_fieldshidden_array[$r] = ['extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'propaldet']; $this->import_regex_array[$r] = ['cd.product_type' => '[0|1]$']; $import_sample = [ 'cd.fk_propal' => 'PROV(0001)', diff --git a/htdocs/core/modules/modWebServicesClient.class.php b/htdocs/core/modules/modWebServicesClient.class.php index 720a756a828..52a8889fbbb 100644 --- a/htdocs/core/modules/modWebServicesClient.class.php +++ b/htdocs/core/modules/modWebServicesClient.class.php @@ -30,54 +30,54 @@ include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php'; class modWebServicesClient extends DolibarrModules { - /** + /** * Constructor. Define names, constants, directories, boxes, permissions * * @param DoliDB $db Database handler - */ - public function __construct($db) - { - $this->db = $db; - $this->numero = 2660; + */ + public function __construct($db) + { + $this->db = $db; + $this->numero = 2660; - $this->family = "interface"; - $this->module_position = '25'; - // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) - $this->name = preg_replace('/^mod/i', '', get_class($this)); - $this->description = "Enable the web service client to call external supplier web services"; + $this->family = "interface"; + $this->module_position = '25'; + // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) + $this->name = preg_replace('/^mod/i', '', get_class($this)); + $this->description = "Enable the web service client to call external supplier web services"; // Possible values for version are: 'development', 'experimental', 'dolibarr' or version - $this->version = 'experimental'; - // Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase) - $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); - // Name of image file used for this module. - $this->picto = 'technic'; + $this->version = 'experimental'; + // Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase) + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + // Name of image file used for this module. + $this->picto = 'technic'; - // Data directories to create when module is enabled - $this->dirs = array(); + // Data directories to create when module is enabled + $this->dirs = array(); - // Config pages - //$this->config_page_url = array(); + // Config pages + //$this->config_page_url = array(); - // Dependencies - $this->hidden = false; // A condition to hide module + // Dependencies + $this->hidden = false; // A condition to hide module $this->depends = array(); // List of module class names as string that must be enabled if this module is enabled $this->requiredby = array(); // List of module ids to disable if this one is disabled $this->conflictwith = array(); // List of module class names as string this module is in conflict with $this->phpmin = array(5, 4); // Minimum version of PHP required by module - $this->langfiles = array("other"); + $this->langfiles = array("other"); - // Constants - $this->const = array(); + // Constants + $this->const = array(); - // New pages on tabs - $this->tabs = array(); + // New pages on tabs + $this->tabs = array(); - // Boxes - $this->boxes = array(); + // Boxes + $this->boxes = array(); - // Permissions - $this->rights = array(); - $this->rights_class = 'syncsupplierwebservices'; - $r = 0; - } + // Permissions + $this->rights = array(); + $this->rights_class = 'syncsupplierwebservices'; + $r = 0; + } } diff --git a/htdocs/core/modules/printing/printgcp.modules.php b/htdocs/core/modules/printing/printgcp.modules.php index 0312aa061f8..e1f765110a8 100644 --- a/htdocs/core/modules/printing/printgcp.modules.php +++ b/htdocs/core/modules/printing/printgcp.modules.php @@ -35,478 +35,478 @@ use OAuth\OAuth2\Service\Google; */ class printing_printgcp extends PrintingDriver { - public $name = 'printgcp'; - public $desc = 'PrintGCPDesc'; + public $name = 'printgcp'; + public $desc = 'PrintGCPDesc'; - /** - * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png - */ - public $picto = 'printer'; - public $active = 'PRINTING_PRINTGCP'; - public $conf = array(); - public $google_id = ''; - public $google_secret = ''; + /** + * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png + */ + public $picto = 'printer'; + public $active = 'PRINTING_PRINTGCP'; + public $conf = array(); + public $google_id = ''; + public $google_secret = ''; - /** - * @var string Error code (or message) - */ - public $error = ''; + /** + * @var string Error code (or message) + */ + public $error = ''; - /** - * @var string[] Error codes (or messages) - */ - public $errors = array(); + /** + * @var string[] Error codes (or messages) + */ + public $errors = array(); - /** - * @var DoliDB Database handler. - */ - public $db; + /** + * @var DoliDB Database handler. + */ + public $db; - private $OAUTH_SERVICENAME_GOOGLE = 'Google'; + private $OAUTH_SERVICENAME_GOOGLE = 'Google'; - const LOGIN_URL = 'https://accounts.google.com/o/oauth2/token'; - const PRINTERS_SEARCH_URL = 'https://www.google.com/cloudprint/search'; - const PRINTERS_GET_JOBS = 'https://www.google.com/cloudprint/jobs'; - const PRINT_URL = 'https://www.google.com/cloudprint/submit'; + const LOGIN_URL = 'https://accounts.google.com/o/oauth2/token'; + const PRINTERS_SEARCH_URL = 'https://www.google.com/cloudprint/search'; + const PRINTERS_GET_JOBS = 'https://www.google.com/cloudprint/jobs'; + const PRINT_URL = 'https://www.google.com/cloudprint/submit'; - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - global $conf, $langs, $dolibarr_main_url_root; + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $conf, $langs, $dolibarr_main_url_root; - // Define $urlwithroot - $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root)); - $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file - //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current + // Define $urlwithroot + $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root)); + $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file + //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current - $this->db = $db; + $this->db = $db; - if (!$conf->oauth->enabled) { - $this->conf[] = array( - 'varname'=>'PRINTGCP_INFO', - 'info'=>$langs->transnoentitiesnoconv("WarningModuleNotActive", "OAuth"), - 'type'=>'info', - ); - } else { - $this->google_id = $conf->global->OAUTH_GOOGLE_ID; - $this->google_secret = $conf->global->OAUTH_GOOGLE_SECRET; - // Token storage - $storage = new DoliStorage($this->db, $this->conf); - //$storage->clearToken($this->OAUTH_SERVICENAME_GOOGLE); - // Setup the credentials for the requests - $credentials = new Credentials( - $this->google_id, - $this->google_secret, - $urlwithroot.'/core/modules/oauth/google_oauthcallback.php' - ); - $access = ($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE) ? 'HasAccessToken' : 'NoAccessToken'); - $serviceFactory = new \OAuth\ServiceFactory(); - $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); - $token_ok = true; - try { - $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - $token_ok = false; - } - //var_dump($this->errors);exit; + if (!$conf->oauth->enabled) { + $this->conf[] = array( + 'varname'=>'PRINTGCP_INFO', + 'info'=>$langs->transnoentitiesnoconv("WarningModuleNotActive", "OAuth"), + 'type'=>'info', + ); + } else { + $this->google_id = $conf->global->OAUTH_GOOGLE_ID; + $this->google_secret = $conf->global->OAUTH_GOOGLE_SECRET; + // Token storage + $storage = new DoliStorage($this->db, $this->conf); + //$storage->clearToken($this->OAUTH_SERVICENAME_GOOGLE); + // Setup the credentials for the requests + $credentials = new Credentials( + $this->google_id, + $this->google_secret, + $urlwithroot.'/core/modules/oauth/google_oauthcallback.php' + ); + $access = ($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE) ? 'HasAccessToken' : 'NoAccessToken'); + $serviceFactory = new \OAuth\ServiceFactory(); + $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); + $token_ok = true; + try { + $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + $token_ok = false; + } + //var_dump($this->errors);exit; - $expire = false; - // Is token expired or will token expire in the next 30 seconds - if ($token_ok) { - $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30)); - } + $expire = false; + // Is token expired or will token expire in the next 30 seconds + if ($token_ok) { + $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30)); + } - // Token expired so we refresh it - if ($token_ok && $expire) { - try { - // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois - $refreshtoken = $token->getRefreshToken(); - $token = $apiService->refreshAccessToken($token); - $token->setRefreshToken($refreshtoken); - $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - } - } - if ($this->google_id != '' && $this->google_secret != '') { - $this->conf[] = array('varname'=>'PRINTGCP_INFO', 'info'=>'GoogleAuthConfigured', 'type'=>'info'); - $this->conf[] = array( - 'varname'=>'PRINTGCP_TOKEN_ACCESS', - 'info'=>$access, - 'type'=>'info', - 'renew'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?state=userinfo_email,userinfo_profile,cloud_print&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), - 'delete'=>($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE) ? $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp') : '') - ); - if ($token_ok) { - $expiredat = ''; + // Token expired so we refresh it + if ($token_ok && $expire) { + try { + // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois + $refreshtoken = $token->getRefreshToken(); + $token = $apiService->refreshAccessToken($token); + $token->setRefreshToken($refreshtoken); + $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + } + } + if ($this->google_id != '' && $this->google_secret != '') { + $this->conf[] = array('varname'=>'PRINTGCP_INFO', 'info'=>'GoogleAuthConfigured', 'type'=>'info'); + $this->conf[] = array( + 'varname'=>'PRINTGCP_TOKEN_ACCESS', + 'info'=>$access, + 'type'=>'info', + 'renew'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?state=userinfo_email,userinfo_profile,cloud_print&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), + 'delete'=>($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE) ? $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp') : '') + ); + if ($token_ok) { + $expiredat = ''; - $refreshtoken = $token->getRefreshToken(); + $refreshtoken = $token->getRefreshToken(); - $endoflife = $token->getEndOfLife(); + $endoflife = $token->getEndOfLife(); - if ($endoflife == $token::EOL_NEVER_EXPIRES) - { - $expiredat = $langs->trans("Never"); - } elseif ($endoflife == $token::EOL_UNKNOWN) - { - $expiredat = $langs->trans("Unknown"); - } else { - $expiredat = dol_print_date($endoflife, "dayhour"); - } + if ($endoflife == $token::EOL_NEVER_EXPIRES) + { + $expiredat = $langs->trans("Never"); + } elseif ($endoflife == $token::EOL_UNKNOWN) + { + $expiredat = $langs->trans("Unknown"); + } else { + $expiredat = dol_print_date($endoflife, "dayhour"); + } - $this->conf[] = array('varname'=>'TOKEN_REFRESH', 'info'=>((!empty($refreshtoken)) ? 'Yes' : 'No'), 'type'=>'info'); - $this->conf[] = array('varname'=>'TOKEN_EXPIRED', 'info'=>($expire ? 'Yes' : 'No'), 'type'=>'info'); - $this->conf[] = array('varname'=>'TOKEN_EXPIRE_AT', 'info'=>($expiredat), 'type'=>'info'); - } - /* + $this->conf[] = array('varname'=>'TOKEN_REFRESH', 'info'=>((!empty($refreshtoken)) ? 'Yes' : 'No'), 'type'=>'info'); + $this->conf[] = array('varname'=>'TOKEN_EXPIRED', 'info'=>($expire ? 'Yes' : 'No'), 'type'=>'info'); + $this->conf[] = array('varname'=>'TOKEN_EXPIRE_AT', 'info'=>($expiredat), 'type'=>'info'); + } + /* if ($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE)) { $this->conf[] = array('varname'=>'PRINTGCP_AUTHLINK', 'link'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), 'type'=>'authlink'); $this->conf[] = array('varname'=>'DELETE_TOKEN', 'link'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), 'type'=>'delete'); } else { $this->conf[] = array('varname'=>'PRINTGCP_AUTHLINK', 'link'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), 'type'=>'authlink'); }*/ - } else { - $this->conf[] = array('varname'=>'PRINTGCP_INFO', 'info'=>'GoogleAuthNotConfigured', 'type'=>'info'); - } - } - // do not display submit button - $this->conf[] = array('enabled'=>0, 'type'=>'submit'); - } + } else { + $this->conf[] = array('varname'=>'PRINTGCP_INFO', 'info'=>'GoogleAuthNotConfigured', 'type'=>'info'); + } + } + // do not display submit button + $this->conf[] = array('enabled'=>0, 'type'=>'submit'); + } - /** - * Return list of available printers - * - * @return int 0 if OK, >0 if KO - */ - public function listAvailablePrinters() - { - global $conf, $langs; - $error = 0; - $langs->load('printing'); + /** + * Return list of available printers + * + * @return int 0 if OK, >0 if KO + */ + public function listAvailablePrinters() + { + global $conf, $langs; + $error = 0; + $langs->load('printing'); - $html = ''; - $html .= ''.$langs->trans('GCP_Name').''; - $html .= ''.$langs->trans('GCP_displayName').''; - $html .= ''.$langs->trans('GCP_Id').''; - $html .= ''.$langs->trans('GCP_OwnerName').''; - $html .= ''.$langs->trans('GCP_State').''; - $html .= ''.$langs->trans('GCP_connectionStatus').''; - $html .= ''.$langs->trans('GCP_Type').''; - $html .= ''.$langs->trans("Select").''; - $html .= ''."\n"; - $list = $this->getlistAvailablePrinters(); - //$html.= '
'.print_r($list,true).'
'; - foreach ($list['available'] as $printer_det) - { - $html .= ''; - $html .= ''.$printer_det['name'].''; - $html .= ''.$printer_det['displayName'].''; - $html .= ''.$printer_det['id'].''; // id to identify printer to use - $html .= ''.$printer_det['ownerName'].''; - $html .= ''.$printer_det['status'].''; - $html .= ''.$langs->trans('STATE_'.$printer_det['connectionStatus']).''; - $html .= ''.$langs->trans('TYPE_'.$printer_det['type']).''; - // Defaut - $html .= ''; - if ($conf->global->PRINTING_GCP_DEFAULT == $printer_det['id']) - { - $html .= img_picto($langs->trans("Default"), 'on'); - } else $html .= ''.img_picto($langs->trans("Disabled"), 'off').''; - $html .= ''; - $html .= ''."\n"; - } - $this->resprint = $html; - return $error; - } + $html = ''; + $html .= ''.$langs->trans('GCP_Name').''; + $html .= ''.$langs->trans('GCP_displayName').''; + $html .= ''.$langs->trans('GCP_Id').''; + $html .= ''.$langs->trans('GCP_OwnerName').''; + $html .= ''.$langs->trans('GCP_State').''; + $html .= ''.$langs->trans('GCP_connectionStatus').''; + $html .= ''.$langs->trans('GCP_Type').''; + $html .= ''.$langs->trans("Select").''; + $html .= ''."\n"; + $list = $this->getlistAvailablePrinters(); + //$html.= '
'.print_r($list,true).'
'; + foreach ($list['available'] as $printer_det) + { + $html .= ''; + $html .= ''.$printer_det['name'].''; + $html .= ''.$printer_det['displayName'].''; + $html .= ''.$printer_det['id'].''; // id to identify printer to use + $html .= ''.$printer_det['ownerName'].''; + $html .= ''.$printer_det['status'].''; + $html .= ''.$langs->trans('STATE_'.$printer_det['connectionStatus']).''; + $html .= ''.$langs->trans('TYPE_'.$printer_det['type']).''; + // Defaut + $html .= ''; + if ($conf->global->PRINTING_GCP_DEFAULT == $printer_det['id']) + { + $html .= img_picto($langs->trans("Default"), 'on'); + } else $html .= ''.img_picto($langs->trans("Disabled"), 'off').''; + $html .= ''; + $html .= ''."\n"; + } + $this->resprint = $html; + return $error; + } - /** - * Return list of available printers - * - * @return array list of printers - */ - public function getlistAvailablePrinters() - { - $ret = array(); - // Token storage - $storage = new DoliStorage($this->db, $this->conf); - // Setup the credentials for the requests - $credentials = new Credentials( - $this->google_id, - $this->google_secret, - DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php' - ); - $serviceFactory = new \OAuth\ServiceFactory(); - $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); - // Check if we have auth token - $token_ok = true; - try { - $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - $token_ok = false; - } - $expire = false; - // Is token expired or will token expire in the next 30 seconds - if ($token_ok) { - $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30)); - } + /** + * Return list of available printers + * + * @return array list of printers + */ + public function getlistAvailablePrinters() + { + $ret = array(); + // Token storage + $storage = new DoliStorage($this->db, $this->conf); + // Setup the credentials for the requests + $credentials = new Credentials( + $this->google_id, + $this->google_secret, + DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php' + ); + $serviceFactory = new \OAuth\ServiceFactory(); + $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); + // Check if we have auth token + $token_ok = true; + try { + $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + $token_ok = false; + } + $expire = false; + // Is token expired or will token expire in the next 30 seconds + if ($token_ok) { + $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30)); + } - // Token expired so we refresh it - if ($token_ok && $expire) { - try { - // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois - $refreshtoken = $token->getRefreshToken(); - $token = $apiService->refreshAccessToken($token); - $token->setRefreshToken($refreshtoken); - $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - } - } - // Send a request with api - try { - $response = $apiService->request(self::PRINTERS_SEARCH_URL); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - print '
'.print_r($e->getMessage(), true).'
'; - } - //print '
'.print_r($response, true).'
'; - $responsedata = json_decode($response, true); - $printers = $responsedata['printers']; - // Check if we have printers? - if (count($printers) == 0) { - // We dont have printers so return blank array - $ret['available'] = array(); - } else { - // We have printers so returns printers as array - $ret['available'] = $printers; - } - return $ret; - } + // Token expired so we refresh it + if ($token_ok && $expire) { + try { + // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois + $refreshtoken = $token->getRefreshToken(); + $token = $apiService->refreshAccessToken($token); + $token->setRefreshToken($refreshtoken); + $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + } + } + // Send a request with api + try { + $response = $apiService->request(self::PRINTERS_SEARCH_URL); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + print '
'.print_r($e->getMessage(), true).'
'; + } + //print '
'.print_r($response, true).'
'; + $responsedata = json_decode($response, true); + $printers = $responsedata['printers']; + // Check if we have printers? + if (count($printers) == 0) { + // We dont have printers so return blank array + $ret['available'] = array(); + } else { + // We have printers so returns printers as array + $ret['available'] = $printers; + } + return $ret; + } - /** - * Print selected file - * - * @param string $file file - * @param string $module module - * @param string $subdir subdir for file - * @return int 0 if OK, >0 if KO - */ - public function printFile($file, $module, $subdir = '') - { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + /** + * Print selected file + * + * @param string $file file + * @param string $module module + * @param string $subdir subdir for file + * @return int 0 if OK, >0 if KO + */ + public function printFile($file, $module, $subdir = '') + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - global $conf, $user; - $error = 0; + global $conf, $user; + $error = 0; - $fileprint = $conf->{$module}->dir_output; - if ($subdir != '') { - $fileprint .= '/'.$subdir; - } - $fileprint .= '/'.$file; - $mimetype = dol_mimetype($fileprint); - // select printer uri for module order, propal,... - $sql = "SELECT rowid, printer_id, copy FROM ".MAIN_DB_PREFIX."printing WHERE module='".$this->db->escape($module)."' AND driver='printgcp' AND userid=".$user->id; - $result = $this->db->query($sql); - if ($result) - { - $obj = $this->db->fetch_object($result); - if ($obj) - { - $printer_id = $obj->printer_id; - } else { - if (!empty($conf->global->PRINTING_GCP_DEFAULT)) - { - $printer_id = $conf->global->PRINTING_GCP_DEFAULT; - } else { - $this->errors[] = 'NoDefaultPrinterDefined'; - $error++; - return $error; - } - } - } else { - dol_print_error($this->db); - } + $fileprint = $conf->{$module}->dir_output; + if ($subdir != '') { + $fileprint .= '/'.$subdir; + } + $fileprint .= '/'.$file; + $mimetype = dol_mimetype($fileprint); + // select printer uri for module order, propal,... + $sql = "SELECT rowid, printer_id, copy FROM ".MAIN_DB_PREFIX."printing WHERE module='".$this->db->escape($module)."' AND driver='printgcp' AND userid=".$user->id; + $result = $this->db->query($sql); + if ($result) + { + $obj = $this->db->fetch_object($result); + if ($obj) + { + $printer_id = $obj->printer_id; + } else { + if (!empty($conf->global->PRINTING_GCP_DEFAULT)) + { + $printer_id = $conf->global->PRINTING_GCP_DEFAULT; + } else { + $this->errors[] = 'NoDefaultPrinterDefined'; + $error++; + return $error; + } + } + } else { + dol_print_error($this->db); + } - $ret = $this->sendPrintToPrinter($printer_id, $file, $fileprint, $mimetype); - $this->error = 'PRINTGCP: '.$ret['errormessage']; - if ($ret['status'] != 1) { - $error++; - } - return $error; - } + $ret = $this->sendPrintToPrinter($printer_id, $file, $fileprint, $mimetype); + $this->error = 'PRINTGCP: '.$ret['errormessage']; + if ($ret['status'] != 1) { + $error++; + } + return $error; + } - /** - * Sends document to the printer - * - * @param string $printerid Printer id returned by Google Cloud Print - * @param string $printjobtitle Job Title - * @param string $filepath File Path to be send to Google Cloud Print - * @param string $contenttype File content type by example application/pdf, image/png - * @return array status array - */ - public function sendPrintToPrinter($printerid, $printjobtitle, $filepath, $contenttype) - { - // Check if printer id - if (empty($printerid)) { - return array('status' =>0, 'errorcode' =>'', 'errormessage'=>'No provided printer ID'); - } - // Open the file which needs to be print - $handle = fopen($filepath, "rb"); - if (!$handle) { - return array('status' =>0, 'errorcode' =>'', 'errormessage'=>'Could not read the file.'); - } - // Read file content - $contents = fread($handle, filesize($filepath)); - fclose($handle); - // Prepare post fields for sending print - $post_fields = array( - 'printerid' => $printerid, - 'title' => $printjobtitle, - 'contentTransferEncoding' => 'base64', - 'content' => base64_encode($contents), // encode file content as base64 - 'contentType' => $contenttype, - ); - // Dolibarr Token storage - $storage = new DoliStorage($this->db, $this->conf); - // Setup the credentials for the requests - $credentials = new Credentials( - $this->google_id, - $this->google_secret, - DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php?service=google' - ); - $serviceFactory = new \OAuth\ServiceFactory(); - $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); + /** + * Sends document to the printer + * + * @param string $printerid Printer id returned by Google Cloud Print + * @param string $printjobtitle Job Title + * @param string $filepath File Path to be send to Google Cloud Print + * @param string $contenttype File content type by example application/pdf, image/png + * @return array status array + */ + public function sendPrintToPrinter($printerid, $printjobtitle, $filepath, $contenttype) + { + // Check if printer id + if (empty($printerid)) { + return array('status' =>0, 'errorcode' =>'', 'errormessage'=>'No provided printer ID'); + } + // Open the file which needs to be print + $handle = fopen($filepath, "rb"); + if (!$handle) { + return array('status' =>0, 'errorcode' =>'', 'errormessage'=>'Could not read the file.'); + } + // Read file content + $contents = fread($handle, filesize($filepath)); + fclose($handle); + // Prepare post fields for sending print + $post_fields = array( + 'printerid' => $printerid, + 'title' => $printjobtitle, + 'contentTransferEncoding' => 'base64', + 'content' => base64_encode($contents), // encode file content as base64 + 'contentType' => $contenttype, + ); + // Dolibarr Token storage + $storage = new DoliStorage($this->db, $this->conf); + // Setup the credentials for the requests + $credentials = new Credentials( + $this->google_id, + $this->google_secret, + DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php?service=google' + ); + $serviceFactory = new \OAuth\ServiceFactory(); + $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); - // Check if we have auth token and refresh it - $token_ok = true; - try { - $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - $token_ok = false; - } - if ($token_ok) { - try { - // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois - $refreshtoken = $token->getRefreshToken(); - $token = $apiService->refreshAccessToken($token); - $token->setRefreshToken($refreshtoken); - $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - } - } + // Check if we have auth token and refresh it + $token_ok = true; + try { + $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + $token_ok = false; + } + if ($token_ok) { + try { + // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois + $refreshtoken = $token->getRefreshToken(); + $token = $apiService->refreshAccessToken($token); + $token->setRefreshToken($refreshtoken); + $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + } + } - // Send a request with api - $response = json_decode($apiService->request(self::PRINT_URL, 'POST', $post_fields), true); - //print '
'.print_r($response, true).'
'; - return array('status' => $response['success'], 'errorcode' => $response['errorCode'], 'errormessage' => $response['message']); - } + // Send a request with api + $response = json_decode($apiService->request(self::PRINT_URL, 'POST', $post_fields), true); + //print '
'.print_r($response, true).'
'; + return array('status' => $response['success'], 'errorcode' => $response['errorCode'], 'errormessage' => $response['message']); + } - /** - * List jobs print - * - * @return int 0 if OK, >0 if KO - */ - public function listJobs() - { - global $conf, $langs; + /** + * List jobs print + * + * @return int 0 if OK, >0 if KO + */ + public function listJobs() + { + global $conf, $langs; - $error = 0; - $html = ''; - // Token storage - $storage = new DoliStorage($this->db, $this->conf); - // Setup the credentials for the requests - $credentials = new Credentials( - $this->google_id, - $this->google_secret, - DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php' - ); - $serviceFactory = new \OAuth\ServiceFactory(); - $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); - // Check if we have auth token - $token_ok = true; - try { - $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - $token_ok = false; - $error++; - } - $expire = false; - // Is token expired or will token expire in the next 30 seconds - if ($token_ok) { - $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30)); - } + $error = 0; + $html = ''; + // Token storage + $storage = new DoliStorage($this->db, $this->conf); + // Setup the credentials for the requests + $credentials = new Credentials( + $this->google_id, + $this->google_secret, + DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php' + ); + $serviceFactory = new \OAuth\ServiceFactory(); + $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array()); + // Check if we have auth token + $token_ok = true; + try { + $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + $token_ok = false; + $error++; + } + $expire = false; + // Is token expired or will token expire in the next 30 seconds + if ($token_ok) { + $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30)); + } - // Token expired so we refresh it - if ($token_ok && $expire) { - try { - // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois - $refreshtoken = $token->getRefreshToken(); - $token = $apiService->refreshAccessToken($token); - $token->setRefreshToken($refreshtoken); - $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - $error++; - } - } - // Getting Jobs - // Send a request with api - try { - $response = $apiService->request(self::PRINTERS_GET_JOBS); - } catch (Exception $e) { - $this->errors[] = $e->getMessage(); - $error++; - } - $responsedata = json_decode($response, true); - //$html .= '
'.print_r($responsedata,true).'
'; - $html .= '
'; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''."\n"; + // Token expired so we refresh it + if ($token_ok && $expire) { + try { + // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois + $refreshtoken = $token->getRefreshToken(); + $token = $apiService->refreshAccessToken($token); + $token->setRefreshToken($refreshtoken); + $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + $error++; + } + } + // Getting Jobs + // Send a request with api + try { + $response = $apiService->request(self::PRINTERS_GET_JOBS); + } catch (Exception $e) { + $this->errors[] = $e->getMessage(); + $error++; + } + $responsedata = json_decode($response, true); + //$html .= '
'.print_r($responsedata,true).'
'; + $html .= '
'; + $html .= '
'.$langs->trans("Id").''.$langs->trans("Date").''.$langs->trans("Owner").''.$langs->trans("Printer").''.$langs->trans("Filename").''.$langs->trans("Status").''.$langs->trans("Cancel").'
'; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''."\n"; - $jobs = $responsedata['jobs']; - //$html .= '
'.print_r($jobs['0'],true).'
'; - if (is_array($jobs)) { - foreach ($jobs as $value) { - $html .= ''; - $html .= ''; - $dates = dol_print_date((int) substr($value['createTime'], 0, 10), 'dayhour'); - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - } - } else { - $html .= ''; - $html .= ''; - $html .= ''; - } - $html .= '
'.$langs->trans("Id").''.$langs->trans("Date").''.$langs->trans("Owner").''.$langs->trans("Printer").''.$langs->trans("Filename").''.$langs->trans("Status").''.$langs->trans("Cancel").'
'.$value['id'].''.$dates.''.$value['ownerId'].''.$value['printerName'].''.$value['title'].''.$value['status'].' 
'.$langs->trans("None").'
'; - $html .= '
'; + $jobs = $responsedata['jobs']; + //$html .= '
'.print_r($jobs['0'],true).'
'; + if (is_array($jobs)) { + foreach ($jobs as $value) { + $html .= ''; + $html .= ''.$value['id'].''; + $dates = dol_print_date((int) substr($value['createTime'], 0, 10), 'dayhour'); + $html .= ''.$dates.''; + $html .= ''.$value['ownerId'].''; + $html .= ''.$value['printerName'].''; + $html .= ''.$value['title'].''; + $html .= ''.$value['status'].''; + $html .= ' '; + $html .= ''; + } + } else { + $html .= ''; + $html .= ''.$langs->trans("None").''; + $html .= ''; + } + $html .= ''; + $html .= '
'; - $this->resprint = $html; + $this->resprint = $html; - return $error; - } + return $error; + } } diff --git a/htdocs/core/tpl/bloc_comment.tpl.php b/htdocs/core/tpl/bloc_comment.tpl.php index edb675e45d6..e78a5a7734e 100644 --- a/htdocs/core/tpl/bloc_comment.tpl.php +++ b/htdocs/core/tpl/bloc_comment.tpl.php @@ -38,21 +38,21 @@ print "\n"; if ($action !== 'editcomment') { - print ''; + print ''; - // Description - print ''; + // Description + print ''; - $desc = GETPOST('comment_description'); + $desc = GETPOST('comment_description'); - $doleditor = new DolEditor('comment_description', $desc, '', 80, 'dolibarr_notes', 'In', 0, true, true, ROWS_3, '100%'); - print $doleditor->Create(1); + $doleditor = new DolEditor('comment_description', $desc, '', 80, 'dolibarr_notes', 'In', 0, true, true, ROWS_3, '100%'); + print $doleditor->Create(1); - print ''; + print ''; - print ''; - print ''; - print ''; + print ''; + print ''; + print ''; } print ''; @@ -96,47 +96,47 @@ if (!empty($object->comments)) print '
'; print '
'; - if ($action === 'editcomment' && $comment->id == $idcomment) - { - print '
'; - print ''; - print ''; - print ''; - print ''; - print ''; - } + if ($action === 'editcomment' && $comment->id == $idcomment) + { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } - print '
'; - if ($action === 'editcomment' && $comment->id == $idcomment) - { - $doleditor = new DolEditor('comment_description', $comment->description, '', 80, 'dolibarr_notes', 'In', 0, true, true, ROWS_3, '100%'); - print $doleditor->Create(1); - } else { - print $comment->description; - } + print '
'; + if ($action === 'editcomment' && $comment->id == $idcomment) + { + $doleditor = new DolEditor('comment_description', $comment->description, '', 80, 'dolibarr_notes', 'In', 0, true, true, ROWS_3, '100%'); + print $doleditor->Create(1); + } else { + print $comment->description; + } print '
'; // End comment-description - if ($action === 'editcomment' && $comment->id == $idcomment) - { - print ''; - print ''; + if ($action === 'editcomment' && $comment->id == $idcomment) + { + print ''; + print ''; - print ''; - } else { - if ($fk_user == $user->id || $user->admin == 1) - { - print ''; - print img_picto('', 'edit.png'); - print ''; - } - if (($first && $fk_user == $user->id) || $user->admin == 1) { - print ''; - print img_picto('', 'delete.png'); - print ''; - } - } + print ''; + } else { + if ($fk_user == $user->id || $user->admin == 1) + { + print ''; + print img_picto('', 'edit.png'); + print ''; + } + if (($first && $fk_user == $user->id) || $user->admin == 1) { + print ''; + print img_picto('', 'delete.png'); + print ''; + } + } - print '
'; // End comment-table + print '
'; // End comment-table print '
'; // End comment-right print '
'; // End comment diff --git a/htdocs/ecm/class/ecmdirectory.class.php b/htdocs/ecm/class/ecmdirectory.class.php index 25673c65c6c..dc39550c0cf 100644 --- a/htdocs/ecm/class/ecmdirectory.class.php +++ b/htdocs/ecm/class/ecmdirectory.class.php @@ -35,7 +35,7 @@ class EcmDirectory extends CommonObject /** * @var string Name of table without prefix where object is stored */ - public $table_element='ecm_directories'; + public $table_element = 'ecm_directories'; /** * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png diff --git a/htdocs/ecm/file_card.php b/htdocs/ecm/file_card.php index 483335093e9..d5a66ca4134 100644 --- a/htdocs/ecm/file_card.php +++ b/htdocs/ecm/file_card.php @@ -44,8 +44,8 @@ $socid = GETPOST("socid", "int"); // Security check if ($user->socid > 0) { - $action = ''; - $socid = $user->socid; + $action = ''; + $socid = $user->socid; } $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; @@ -62,14 +62,14 @@ if (!$sortfield) $sortfield = "label"; $section = GETPOST("section", 'alpha'); if (!$section) { - dol_print_error('', 'Error, section parameter missing'); - exit; + dol_print_error('', 'Error, section parameter missing'); + exit; } $urlfile = GETPOST("urlfile"); if (!$urlfile) { - dol_print_error('', "ErrorParamNotDefined"); - exit; + dol_print_error('', "ErrorParamNotDefined"); + exit; } // Load ecm object @@ -77,8 +77,8 @@ $ecmdir = new EcmDirectory($db); $result = $ecmdir->fetch(GETPOST("section", 'alpha')); if (!$result > 0) { - dol_print_error($db, $ecmdir->error); - exit; + dol_print_error($db, $ecmdir->error); + exit; } $relativepath = $ecmdir->getRelativePath(); $upload_dir = $conf->ecm->dir_output.'/'.$relativepath; @@ -114,67 +114,67 @@ if ($result < 0) if ($cancel) { - $action = ''; - if ($backtopage) - { - header("Location: ".$backtopage); - exit; - } else { - header('Location: '.$_SERVER["PHP_SELF"].'?urlfile='.urlencode($urlfile).'§ion='.urlencode($section).($module ? '&module='.urlencode($module) : '')); - exit; - } + $action = ''; + if ($backtopage) + { + header("Location: ".$backtopage); + exit; + } else { + header('Location: '.$_SERVER["PHP_SELF"].'?urlfile='.urlencode($urlfile).'§ion='.urlencode($section).($module ? '&module='.urlencode($module) : '')); + exit; + } } // Rename file if ($action == 'update') { - $error = 0; + $error = 0; - $oldlabel = GETPOST('urlfile', 'alpha'); - $newlabel = dol_sanitizeFileName(GETPOST('label', 'alpha')); + $oldlabel = GETPOST('urlfile', 'alpha'); + $newlabel = dol_sanitizeFileName(GETPOST('label', 'alpha')); $shareenabled = GETPOST('shareenabled', 'alpha'); - //$db->begin(); + //$db->begin(); - $olddir = $ecmdir->getRelativePath(0); // Relative to ecm - $olddirrelativetodocument = 'ecm/'.$olddir; // Relative to document - $newdirrelativetodocument = 'ecm/'.$olddir; - $olddir = $conf->ecm->dir_output.'/'.$olddir; - $newdir = $olddir; + $olddir = $ecmdir->getRelativePath(0); // Relative to ecm + $olddirrelativetodocument = 'ecm/'.$olddir; // Relative to document + $newdirrelativetodocument = 'ecm/'.$olddir; + $olddir = $conf->ecm->dir_output.'/'.$olddir; + $newdir = $olddir; - $oldfile = $olddir.$oldlabel; - $newfile = $newdir.$newlabel; - $newfileformove = $newfile; - // If old file end with .noexe, new file must also end with .noexe - if (preg_match('/\.noexe$/', $oldfile) && ! preg_match('/\.noexe$/', $newfileformove)) { - $newfileformove .= '.noexe'; - } - //var_dump($oldfile);var_dump($newfile);exit; + $oldfile = $olddir.$oldlabel; + $newfile = $newdir.$newlabel; + $newfileformove = $newfile; + // If old file end with .noexe, new file must also end with .noexe + if (preg_match('/\.noexe$/', $oldfile) && ! preg_match('/\.noexe$/', $newfileformove)) { + $newfileformove .= '.noexe'; + } + //var_dump($oldfile);var_dump($newfile);exit; - // Now we update index of file - $db->begin(); - //print $oldfile.' - '.$newfile; - if ($newlabel != $oldlabel) - { - $result = dol_move($oldfile, $newfileformove); // This include update of database - if (!$result) - { - $langs->load('errors'); - setEventMessages($langs->trans('ErrorFailToRenameFile', $oldfile, $newfile), null, 'errors'); - $error++; - } + // Now we update index of file + $db->begin(); + //print $oldfile.' - '.$newfile; + if ($newlabel != $oldlabel) + { + $result = dol_move($oldfile, $newfileformove); // This include update of database + if (!$result) + { + $langs->load('errors'); + setEventMessages($langs->trans('ErrorFailToRenameFile', $oldfile, $newfile), null, 'errors'); + $error++; + } - // Reload object after the move - $result = $object->fetch(0, '', $newdirrelativetodocument.$newlabel); - if ($result < 0) - { - dol_print_error($db, $object->error, $object->errors); - exit; - } - } + // Reload object after the move + $result = $object->fetch(0, '', $newdirrelativetodocument.$newlabel); + if ($result < 0) + { + dol_print_error($db, $object->error, $object->errors); + exit; + } + } - if (!$error) - { + if (!$error) + { if ($shareenabled) { require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; @@ -217,23 +217,23 @@ if ($action == 'update') setEventMessages($object->error, $object->errors, 'warnings'); } } - } + } - if (!$error) - { - $db->commit(); + if (!$error) + { + $db->commit(); - $urlfile = $newlabel; - // If old file end with .noexe, new file must also end with .noexe - if (preg_match('/\.noexe$/', $newfileformove)) { - $urlfile .= '.noexe'; - } + $urlfile = $newlabel; + // If old file end with .noexe, new file must also end with .noexe + if (preg_match('/\.noexe$/', $newfileformove)) { + $urlfile .= '.noexe'; + } - header('Location: '.$_SERVER["PHP_SELF"].'?urlfile='.urlencode($urlfile).'§ion='.urlencode($section)); - exit; - } else { - $db->rollback(); - } + header('Location: '.$_SERVER["PHP_SELF"].'?urlfile='.urlencode($urlfile).'§ion='.urlencode($section)); + exit; + } else { + $db->rollback(); + } } @@ -381,7 +381,7 @@ if (!empty($object->share)) } print ''; print ''; -print $object->showOptionals($extrafields, ($action == 'edit'?'edit':'view')); +print $object->showOptionals($extrafields, ($action == 'edit' ? 'edit' : 'view')); print ''; print '
'; @@ -392,20 +392,20 @@ dol_fiche_end(); if ($action == 'edit') { - print '
'; - print ''; - print '     '; - print ''; - print '
'; + print '
'; + print ''; + print '     '; + print ''; + print '
'; - print ''; + print ''; } // Confirmation de la suppression d'une ligne categorie if ($action == 'delete_file') { - print $form->formconfirm($_SERVER["PHP_SELF"].'?section='.urlencode($section), $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile', $urlfile), 'confirm_deletefile', '', 1, 1); + print $form->formconfirm($_SERVER["PHP_SELF"].'?section='.urlencode($section), $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile', $urlfile), 'confirm_deletefile', '', 1, 1); } if ($action != 'edit') @@ -413,11 +413,11 @@ if ($action != 'edit') // Actions buttons print '
'; - if ($user->rights->ecm->setup) - { - print ''.$langs->trans('Edit').''; - } - /* + if ($user->rights->ecm->setup) + { + print ''.$langs->trans('Edit').''; + } + /* if ($user->rights->ecm->setup) { print ''.$langs->trans('Delete').''; diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index b32e95597e8..3f7caca5890 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -405,7 +405,7 @@ class ExpenseReport extends CommonObject $this->id = 0; $this->ref = ''; $this->status = 0; - $this->fk_statut = 0; // deprecated + $this->fk_statut = 0; // deprecated // Clear fields $this->fk_user_author = $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for. @@ -1353,7 +1353,7 @@ class ExpenseReport extends CommonObject $sql .= ' WHERE rowid = '.$this->id; if ($this->db->query($sql)) { - $this->fk_statut = 99; // deprecated + $this->fk_statut = 99; // deprecated $this->status = 99; $this->fk_user_refuse = $fuser->id; $this->detail_refuse = $details; diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index 97dc2626280..e4afe4b0452 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -202,16 +202,16 @@ if (empty($reshook)) } } elseif ($action == 'add' && $user->rights->ficheinter->creer) { - $object->socid = $socid; - $object->duration = GETPOST('duration', 'int'); - $object->fk_project = GETPOST('projectid', 'int'); - $object->fk_contrat = GETPOST('contratid', 'int'); - $object->author = $user->id; - $object->description = GETPOST('description', 'restricthtml'); - $object->ref = $ref; - $object->model_pdf = GETPOST('model', 'alpha'); - $object->note_private = GETPOST('note_private', 'restricthtml'); - $object->note_public = GETPOST('note_public', 'restricthtml'); + $object->socid = $socid; + $object->duration = GETPOST('duration', 'int'); + $object->fk_project = GETPOST('projectid', 'int'); + $object->fk_contrat = GETPOST('contratid', 'int'); + $object->author = $user->id; + $object->description = GETPOST('description', 'restricthtml'); + $object->ref = $ref; + $object->model_pdf = GETPOST('model', 'alpha'); + $object->note_private = GETPOST('note_private', 'restricthtml'); + $object->note_public = GETPOST('note_public', 'restricthtml'); if ($object->socid > 0) { @@ -251,7 +251,7 @@ if (empty($reshook)) $extrafields = new ExtraFields($db); $array_options = $extrafields->getOptionalsFromPost($object->table_element); - $object->array_options = $array_options; + $object->array_options = $array_options; $id = $object->create($user); @@ -356,12 +356,12 @@ if (empty($reshook)) $result = $object->addline( $user, - $id, - $desc, - $date_intervention, - $duration, - $array_options - ); + $id, + $desc, + $date_intervention, + $duration, + $array_options + ); if ($result < 0) { @@ -371,44 +371,44 @@ if (empty($reshook)) } } } - } else { + } else { $mesg = $srcobject->error; - $error++; - } - } else { + $error++; + } + } else { $mesg = $object->error; - $error++; - } - } else { - // Fill array 'array_options' with data from add form - $ret = $extrafields->setOptionalsFromPost(null, $object); - if ($ret < 0) { - $error++; - $action = 'create'; - } + $error++; + } + } else { + // Fill array 'array_options' with data from add form + $ret = $extrafields->setOptionalsFromPost(null, $object); + if ($ret < 0) { + $error++; + $action = 'create'; + } - if (!$error) - { - // Extrafields - $array_options = $extrafields->getOptionalsFromPost($object->table_element); + if (!$error) + { + // Extrafields + $array_options = $extrafields->getOptionalsFromPost($object->table_element); - $object->array_options = $array_options; + $object->array_options = $array_options; - $result = $object->create($user); - if ($result > 0) - { - $id = $result; // Force raffraichissement sur fiche venant d'etre cree - } else { - $langs->load("errors"); - setEventMessages($object->error, $object->errors, 'errors'); - $action = 'create'; - } - } - } - } else { + $result = $object->create($user); + if ($result > 0) + { + $id = $result; // Force raffraichissement sur fiche venant d'etre cree + } else { + $langs->load("errors"); + setEventMessages($object->error, $object->errors, 'errors'); + $action = 'create'; + } + } + } + } else { $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")); - $action = 'create'; - } + $action = 'create'; + } } elseif ($action == 'update' && $user->rights->ficheinter->creer) { $object->socid = $socid; @@ -482,14 +482,14 @@ if (empty($reshook)) $extrafields->fetch_name_optionals_label($object->table_element_line); $array_options = $extrafields->getOptionalsFromPost($object->table_element_line); - $result = $object->addline( + $result = $object->addline( $user, - $id, - $desc, - $date_intervention, - $duration, - $array_options - ); + $id, + $desc, + $date_intervention, + $duration, + $array_options + ); // Define output language $outputlangs = $langs; @@ -545,14 +545,14 @@ if (empty($reshook)) // Classify Done elseif ($action == 'classifydone' && $user->rights->ficheinter->creer) { - $result = $object->setStatut(3); - if ($result > 0) - { - header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id); - exit; - } else { - setEventMessages($object->error, $object->errors, 'errors'); - } + $result = $object->setStatut(3); + if ($result > 0) + { + header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id); + exit; + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } } // Reopen @@ -591,9 +591,9 @@ if (empty($reshook)) $date_inter = dol_mktime(GETPOST('dihour', 'int'), GETPOST('dimin', 'int'), 0, GETPOST('dimonth', 'int'), GETPOST('diday', 'int'), GETPOST('diyear', 'int')); $duration = convertTime2Seconds(GETPOST('durationhour', 'int'), GETPOST('durationmin', 'int')); - $objectline->datei = $date_inter; - $objectline->desc = $desc; - $objectline->duration = $duration; + $objectline->datei = $date_inter; + $objectline->desc = $desc; + $objectline->duration = $duration; // Extrafields $extrafields->fetch_name_optionals_label($object->table_element_line); @@ -601,11 +601,11 @@ if (empty($reshook)) $objectline->array_options = $array_options; $result = $objectline->update($user); - if ($result < 0) - { - dol_print_error($db); - exit; - } + if ($result < 0) + { + dol_print_error($db); + exit; + } // Define output language $outputlangs = $langs; @@ -817,11 +817,11 @@ if ($action == 'create') $subelement = $regs[2]; } - if ($element == 'project') - { - $projectid = GETPOST('originid', 'int'); - } else { - // For compatibility + if ($element == 'project') + { + $projectid = GETPOST('originid', 'int'); + } else { + // For compatibility if ($element == 'order' || $element == 'commande') { $element = $subelement = 'commande'; } @@ -904,20 +904,20 @@ if ($action == 'create') $langs->load("project"); - print ''.$langs->trans("Project").''; - /* Fix: If a project must be linked to any companies (suppliers or not), project must be not be set as limited to customer but must be not linked to any particular thirdparty + print ''.$langs->trans("Project").''; + /* Fix: If a project must be linked to any companies (suppliers or not), project must be not be set as limited to customer but must be not linked to any particular thirdparty if ($societe->fournisseur==1) $numprojet=select_projects(-1,$_POST["projectid"],'projectid'); else $numprojet=select_projects($societe->id,$_POST["projectid"],'projectid'); */ - $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid'); - if ($numprojet == 0) - { - print '   '; - } - print ''; - } + $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid'); + if ($numprojet == 0) + { + print '   '; + } + print ''; + } // Contract if ($conf->contrat->enabled) @@ -932,53 +932,53 @@ if ($action == 'create') print ''; } - // Model - print ''; - print ''.$langs->trans("DefaultModel").''; - print ''; - $liste = ModelePDFFicheinter::liste_modeles($db); - print $form->selectarray('model', $liste, $conf->global->FICHEINTER_ADDON_PDF); - print ""; + // Model + print ''; + print ''.$langs->trans("DefaultModel").''; + print ''; + $liste = ModelePDFFicheinter::liste_modeles($db); + print $form->selectarray('model', $liste, $conf->global->FICHEINTER_ADDON_PDF); + print ""; - // Public note - print ''; - print ''.$langs->trans('NotePublic').''; - print ''; - $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); - print $doleditor->Create(1); - //print ''; - print ''; + // Public note + print ''; + print ''.$langs->trans('NotePublic').''; + print ''; + $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); + print $doleditor->Create(1); + //print ''; + print ''; - // Private note - if (empty($user->socid)) - { - print ''; - print ''.$langs->trans('NotePrivate').''; - print ''; - $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); - print $doleditor->Create(1); - //print ''; - print ''; - } + // Private note + if (empty($user->socid)) + { + print ''; + print ''.$langs->trans('NotePrivate').''; + print ''; + $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); + print $doleditor->Create(1); + //print ''; + print ''; + } - // Other attributes - $parameters = array(); - $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - if (empty($reshook)) + // Other attributes + $parameters = array(); + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + if (empty($reshook)) { print $object->showOptionals($extrafields, 'edit'); } - // Show link to origin object - if (!empty($origin) && !empty($originid) && is_object($objectsrc)) - { - $newclassname = $classname; - if ($newclassname == 'Propal') $newclassname = 'CommercialProposal'; - print ''.$langs->trans($newclassname).''.$objectsrc->getNomUrl(1).''; + // Show link to origin object + if (!empty($origin) && !empty($originid) && is_object($objectsrc)) + { + $newclassname = $classname; + if ($newclassname == 'Propal') $newclassname = 'CommercialProposal'; + print ''.$langs->trans($newclassname).''.$objectsrc->getNomUrl(1).''; - // Amount - /* Hide amount because we only copy services so amount may differ than source + // Amount + /* Hide amount because we only copy services so amount may differ than source print '' . $langs->trans('AmountHT') . '' . price($objectsrc->total_ht) . ''; print '' . $langs->trans('AmountVAT') . '' . price($objectsrc->total_tva) . ""; if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) // Localtax1 RE @@ -1000,14 +1000,14 @@ if ($action == 'create') print '' . $langs->trans('MulticurrencyAmountTTC') . '' . price($objectsrc->multicurrency_total_ttc) . ""; } */ - } + } - print ''; + print ''; - if (is_object($objectsrc)) - { - print ''; - print ''; + if (is_object($objectsrc)) + { + print ''; + print ''; } elseif ($origin == 'project' && !empty($projectid)) { print ''; } @@ -1016,8 +1016,8 @@ if ($action == 'create') print '
'; print ''; - print '     '; - print ''; + print '     '; + print ''; print '
'; print ''; @@ -1058,8 +1058,8 @@ if ($action == 'create') print '
'; print ''; print ''; - print '     '; - print ''; + print '     '; + print ''; print '
'; print ''; @@ -1172,46 +1172,46 @@ if ($action == 'create') // Project if (!empty($conf->projet->enabled)) { - $langs->load("projects"); - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->ficheinter->creer) - { - if ($action != 'classify') { - $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; - } - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref .= '
'; - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref .= ''; - $morehtmlref .= '
'; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); - } - } else { - if (!empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref .= ''; - $morehtmlref .= $proj->ref; - $morehtmlref .= ''; - } else { - $morehtmlref .= ''; - } - } + $langs->load("projects"); + $morehtmlref .= '
'.$langs->trans('Project').' '; + if ($user->rights->ficheinter->creer) + { + if ($action != 'classify') { + $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; + } + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (!empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } } $morehtmlref .= '
'; - dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); - print '
'; - print '
'; - print '
'; + print '
'; + print '
'; + print '
'; - print ''; + print '
'; if (!empty($conf->global->FICHINTER_USE_PLANNED_AND_DONE_DATES)) { @@ -1269,47 +1269,47 @@ if ($action == 'create') $formcontract->formSelectContract($_SERVER["PHP_SELF"].'?id='.$object->id, $object->socid, $object->fk_contrat, 'contratid', 0, 1, 1); } else { if ($object->fk_contrat) - { - $contratstatic = new Contrat($db); - $contratstatic->fetch($object->fk_contrat); - //print ''.$projet->title.''; - print $contratstatic->getNomUrl(0, '', 1); - } else { - print " "; - } + { + $contratstatic = new Contrat($db); + $contratstatic->fetch($object->fk_contrat); + //print ''.$projet->title.''; + print $contratstatic->getNomUrl(0, '', 1); + } else { + print " "; + } } print ''; print ''; } - // Other attributes - $cols = 2; - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; + // Other attributes + $cols = 2; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; - print '
'; + print ''; - print '
'; - print '
'; - print '
'; - print '
'; + print '
'; + print '
'; + print '
'; + print '
'; - print ''; + print '
'; - if (empty($conf->global->FICHINTER_DISABLE_DETAILS)) - { - // Duration - print ''; - print ''; - print ''; - } + if (empty($conf->global->FICHINTER_DISABLE_DETAILS)) + { + // Duration + print ''; + print ''; + print ''; + } print "
'.$langs->trans("TotalDuration").''.convertSecondToTime($object->duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY).'
'.$langs->trans("TotalDuration").''.convertSecondToTime($object->duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY).'
"; print '
'; - print '
'; - print '
'; + print '
'; + print '
'; - print '

'; + print '

'; if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) @@ -1464,25 +1464,25 @@ if ($action == 'create') // Date d'intervention print ''; - if (!empty($conf->global->FICHINTER_DATE_WITHOUT_HOUR)) { - print $form->selectDate($db->jdate($objp->date_intervention), 'di', 0, 0, 0, "date_intervention"); - } else { - print $form->selectDate($db->jdate($objp->date_intervention), 'di', 1, 1, 0, "date_intervention"); - } + if (!empty($conf->global->FICHINTER_DATE_WITHOUT_HOUR)) { + print $form->selectDate($db->jdate($objp->date_intervention), 'di', 0, 0, 0, "date_intervention"); + } else { + print $form->selectDate($db->jdate($objp->date_intervention), 'di', 1, 1, 0, "date_intervention"); + } print ''; - // Duration - print ''; - if (empty($conf->global->FICHINTER_WITHOUT_DURATION)) { - $selectmode = 'select'; - if (!empty($conf->global->INTERVENTION_ADDLINE_FREEDUREATION)) - $selectmode = 'text'; - $form->select_duration('duration', $objp->duree, 0, $selectmode); - } - print ''; + // Duration + print ''; + if (empty($conf->global->FICHINTER_WITHOUT_DURATION)) { + $selectmode = 'select'; + if (!empty($conf->global->INTERVENTION_ADDLINE_FREEDUREATION)) + $selectmode = 'text'; + $form->select_duration('duration', $objp->duree, 0, $selectmode); + } + print ''; - print ''; - print ''; + print ''; + print ''; print ''; print ''."\n"; @@ -1514,13 +1514,13 @@ if ($action == 'create') print ''; } - print ''; - print ''; // ancre - print $langs->trans('Description').''; - print ''.$langs->trans('Date').''; - print ''.(empty($conf->global->FICHINTER_WITHOUT_DURATION) ? $langs->trans('Duration') : '').''; - print ' '; - print "\n"; + print ''; + print ''; // ancre + print $langs->trans('Description').''; + print ''.$langs->trans('Date').''; + print ''.(empty($conf->global->FICHINTER_WITHOUT_DURATION) ? $langs->trans('Duration') : '').''; + print ' '; + print "\n"; } print ''."\n"; @@ -1530,43 +1530,43 @@ if ($action == 'create') print ''.($i + 1).''; } - print ''; - // editeur wysiwyg - if (empty($conf->global->FICHINTER_EMPTY_LINE_DESC)) { - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor = new DolEditor('np_desc', GETPOST('np_desc', 'restricthtml'), '', 100, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_DETAILS, ROWS_2, '90%'); - $doleditor->Create(); - } - print ''; + print ''; + // editeur wysiwyg + if (empty($conf->global->FICHINTER_EMPTY_LINE_DESC)) { + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor = new DolEditor('np_desc', GETPOST('np_desc', 'restricthtml'), '', 100, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_DETAILS, ROWS_2, '90%'); + $doleditor->Create(); + } + print ''; - // Date intervention - print ''; + // Date intervention + print ''; $now = dol_now(); $timearray = dol_getdate($now); if (!GETPOST('diday', 'int')) { - $timewithnohour = dol_mktime(0, 0, 0, $timearray['mon'], $timearray['mday'], $timearray['year']); - } else { - $timewithnohour = dol_mktime(GETPOST('dihour', 'int'), GETPOST('dimin', 'int'), 0, GETPOST('dimonth', 'int'), GETPOST('diday', 'int'), GETPOST('diyear', 'int')); - } - if (!empty($conf->global->FICHINTER_DATE_WITHOUT_HOUR)) { - print $form->selectDate($timewithnohour, 'di', 0, 0, 0, "addinter"); - } else { - print $form->selectDate($timewithnohour, 'di', 1, 1, 0, "addinter"); - } + $timewithnohour = dol_mktime(0, 0, 0, $timearray['mon'], $timearray['mday'], $timearray['year']); + } else { + $timewithnohour = dol_mktime(GETPOST('dihour', 'int'), GETPOST('dimin', 'int'), 0, GETPOST('dimonth', 'int'), GETPOST('diday', 'int'), GETPOST('diyear', 'int')); + } + if (!empty($conf->global->FICHINTER_DATE_WITHOUT_HOUR)) { + print $form->selectDate($timewithnohour, 'di', 0, 0, 0, "addinter"); + } else { + print $form->selectDate($timewithnohour, 'di', 1, 1, 0, "addinter"); + } print ''; - // Duration - print ''; - if (empty($conf->global->FICHINTER_WITHOUT_DURATION)) { - $selectmode = 'select'; - if (!empty($conf->global->INTERVENTION_ADDLINE_FREEDUREATION)) { - $selectmode = 'text'; - } - $form->select_duration('duration', (!GETPOST('durationhour', 'int') && !GETPOST('durationmin', 'int')) ? 3600 : (60 * 60 * GETPOST('durationhour', 'int') + 60 * GETPOST('durationmin', 'int')), 0, $selectmode); - } - print ''; + // Duration + print ''; + if (empty($conf->global->FICHINTER_WITHOUT_DURATION)) { + $selectmode = 'select'; + if (!empty($conf->global->INTERVENTION_ADDLINE_FREEDUREATION)) { + $selectmode = 'text'; + } + $form->select_duration('duration', (!GETPOST('durationhour', 'int') && !GETPOST('durationmin', 'int')) ? 3600 : (60 * 60 * GETPOST('durationhour', 'int') + 60 * GETPOST('durationmin', 'int')), 0, $selectmode); + } + print ''; - print ''; + print ''; print ''; //Line extrafield @@ -1601,22 +1601,22 @@ if ($action == 'create') $parameters = array(); $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been - // modified by hook + // modified by hook if (empty($reshook)) { if ($user->socid == 0) { - if ($action != 'editdescription' && ($action != 'presend')) { - // Validate - if ($object->statut == Fichinter::STATUS_DRAFT && (count($object->lines) > 0 || !empty($conf->global->FICHINTER_DISABLE_DETAILS))) { - if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->creer) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->ficheinter_advance->validate)) { - print ''; - } - } + if ($action != 'editdescription' && ($action != 'presend')) { + // Validate + if ($object->statut == Fichinter::STATUS_DRAFT && (count($object->lines) > 0 || !empty($conf->global->FICHINTER_DISABLE_DETAILS))) { + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->creer) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->ficheinter_advance->validate)) { + print ''; + } + } - // Modify - if ($object->statut == Fichinter::STATUS_VALIDATED && ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->creer) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->ficheinter_advance->unvalidate))) + // Modify + if ($object->statut == Fichinter::STATUS_VALIDATED && ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->creer) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->ficheinter->ficheinter_advance->unvalidate))) { print '
'; if (empty($conf->global->FICHINTER_DISABLE_DETAILS)) print $langs->trans("Modify"); @@ -1684,7 +1684,7 @@ if ($action == 'create') } // Done - if (empty($conf->global->FICHINTER_CLASSIFY_BILLED) && $object->statut > Fichinter::STATUS_DRAFT && $object->statut < Fichinter::STATUS_CLOSED) + if (empty($conf->global->FICHINTER_CLASSIFY_BILLED) && $object->statut > Fichinter::STATUS_DRAFT && $object->statut < Fichinter::STATUS_CLOSED) { print ''; } diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 289eaf2d05b..264832cadc2 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -702,7 +702,7 @@ class FactureFournisseur extends CommonInvoice $this->note_private = $obj->note_private; $this->note_public = $obj->note_public; $this->model_pdf = $obj->model_pdf; - $this->modelpdf = $obj->model_pdf; // deprecated + $this->modelpdf = $obj->model_pdf; // deprecated $this->import_key = $obj->import_key; //Incoterms @@ -827,7 +827,7 @@ class FactureFournisseur extends CommonInvoice // Accountancy $line->code_ventilation = $obj->fk_code_ventilation; - $line->fk_accounting_account = $obj->fk_code_ventilation; + $line->fk_accounting_account = $obj->fk_code_ventilation; // Multicurrency $line->fk_multicurrency = $obj->fk_multicurrency; diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index 8bbd73ad016..fb2e18a0de2 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -364,30 +364,30 @@ if (empty($reshook)) { $fk_parent_line = 0; } - $result = $objecttmp->addline( + $result = $objecttmp->addline( $desc, $lines[$i]->subprice, $lines[$i]->tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, - $lines[$i]->qty, - $lines[$i]->fk_product, + $lines[$i]->qty, + $lines[$i]->fk_product, $lines[$i]->remise_percent, $date_start, $date_end, 0, $lines[$i]->info_bits, - 'HT', - $product_type, - $lines[$i]->rang, - false, - $lines[$i]->array_options, - $lines[$i]->fk_unit, - $objecttmp->origin_id, - $lines[$i]->pa_ht, - $lines[$i]->ref_supplier, - $lines[$i]->special_code, - $fk_parent_line + 'HT', + $product_type, + $lines[$i]->rang, + false, + $lines[$i]->array_options, + $lines[$i]->fk_unit, + $objecttmp->origin_id, + $lines[$i]->pa_ht, + $lines[$i]->ref_supplier, + $lines[$i]->special_code, + $fk_parent_line ); if ($result > 0) { @@ -686,7 +686,7 @@ if ($resql) $arrayofmassactions = array( 'generate_doc'=>$langs->trans("ReGeneratePDF"), 'builddoc'=>$langs->trans("PDFMerge"), - 'presend'=>$langs->trans("SendByMail"), + 'presend'=>$langs->trans("SendByMail"), ); if ($user->rights->fournisseur->facture->creer) $arrayofmassactions['createbills'] = $langs->trans("CreateInvoiceForThisSupplier"); if ($user->rights->fournisseur->commande->supprimer) $arrayofmassactions['predelete'] = ''.$langs->trans("Delete"); @@ -1293,14 +1293,14 @@ if ($resql) $db->free($resql); - $parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); - $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; + $parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); + $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; - print ''."\n"; - print '
'; + print ''."\n"; + print '
'; - print ''."\n"; + print ''."\n"; $hidegeneratedfilelistifempty = 1; if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) $hidegeneratedfilelistifempty = 0; diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index b0f178c6fc4..029abf36058 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -153,21 +153,21 @@ if (empty($reshook)) // Action clone object if ($action == 'confirm_clone' && $confirm == 'yes' && $permissiontoadd) { - $objectutil = dol_clone($object, 1); // To avoid to denaturate loaded object when setting some properties for clone. We use native clone to keep this->db valid. + $objectutil = dol_clone($object, 1); // To avoid to denaturate loaded object when setting some properties for clone. We use native clone to keep this->db valid. - if (GETPOST('newsupplierref', 'alphanohtml')) $objectutil->ref_supplier = GETPOST('newsupplierref', 'alphanohtml'); - $objectutil->date = dol_mktime(12, 0, 0, GETPOST('newdatemonth', 'int'), GETPOST('newdateday', 'int'), GETPOST('newdateyear', 'int')); + if (GETPOST('newsupplierref', 'alphanohtml')) $objectutil->ref_supplier = GETPOST('newsupplierref', 'alphanohtml'); + $objectutil->date = dol_mktime(12, 0, 0, GETPOST('newdatemonth', 'int'), GETPOST('newdateday', 'int'), GETPOST('newdateyear', 'int')); - $result = $objectutil->createFromClone($user, $id); - if ($result > 0) - { - header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result); - exit; - } else { - $langs->load("errors"); - setEventMessages($objectutil->error, $objectutil->errors, 'errors'); - $action = ''; - } + $result = $objectutil->createFromClone($user, $id); + if ($result > 0) + { + header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result); + exit; + } else { + $langs->load("errors"); + setEventMessages($objectutil->error, $objectutil->errors, 'errors'); + $action = ''; + } } elseif ($action == 'confirm_valid' && $confirm == 'yes' && $usercanvalidate) { $idwarehouse = GETPOST('idwarehouse'); @@ -1041,7 +1041,7 @@ if (empty($reshook)) $object->fetch($id); $object->fetch_thirdparty(); - $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0); + $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0); if (GETPOST('price_ht') != '') { @@ -1077,17 +1077,17 @@ if (empty($reshook)) $date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear')); $date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear')); - // Define info_bits - $info_bits = 0; - if (preg_match('/\*/', $tva_tx)) - $info_bits |= 0x01; + // Define info_bits + $info_bits = 0; + if (preg_match('/\*/', $tva_tx)) + $info_bits |= 0x01; - // Define vat_rate - $tva_tx = str_replace('*', '', $tva_tx); - $localtax1_tx = get_localtax($tva_tx, 1, $mysoc, $object->thirdparty); - $localtax2_tx = get_localtax($tva_tx, 2, $mysoc, $object->thirdparty); + // Define vat_rate + $tva_tx = str_replace('*', '', $tva_tx); + $localtax1_tx = get_localtax($tva_tx, 1, $mysoc, $object->thirdparty); + $localtax2_tx = get_localtax($tva_tx, 2, $mysoc, $object->thirdparty); - $remise_percent = GETPOST('remise_percent'); + $remise_percent = GETPOST('remise_percent'); $pu_ht_devise = GETPOST('multicurrency_subprice'); // Extrafields Lines @@ -1100,12 +1100,12 @@ if (empty($reshook)) } } - $result = $object->updateline(GETPOST('lineid'), $label, $up, $tva_tx, $localtax1_tx, $localtax2_tx, GETPOST('qty'), GETPOST('productid'), $price_base_type, $info_bits, $type, $remise_percent, 0, $date_start, $date_end, $array_options, $_POST['units'], $pu_ht_devise, GETPOST('fourn_ref', 'alpha')); - if ($result >= 0) - { - unset($_POST['label']); - unset($_POST['fourn_ref']); - unset($_POST['date_starthour']); + $result = $object->updateline(GETPOST('lineid'), $label, $up, $tva_tx, $localtax1_tx, $localtax2_tx, GETPOST('qty'), GETPOST('productid'), $price_base_type, $info_bits, $type, $remise_percent, 0, $date_start, $date_end, $array_options, $_POST['units'], $pu_ht_devise, GETPOST('fourn_ref', 'alpha')); + if ($result >= 0) + { + unset($_POST['label']); + unset($_POST['fourn_ref']); + unset($_POST['date_starthour']); unset($_POST['date_startmin']); unset($_POST['date_startsec']); unset($_POST['date_startday']); @@ -1250,7 +1250,7 @@ if (empty($reshook)) // if we use supplier description of the products if (!empty($productsupplier->desc_supplier) && !empty($conf->global->PRODUIT_FOURN_TEXTS)) { - $desc = $productsupplier->desc_supplier; + $desc = $productsupplier->desc_supplier; } else $desc = $productsupplier->description; if (trim($product_desc) != trim($desc)) $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION)); @@ -1301,8 +1301,8 @@ if (empty($reshook)) $array_options, $productsupplier->fk_unit, 0, - $pu_ht_devise, - $ref_supplier, + $pu_ht_devise, + $ref_supplier, '' ); } @@ -1430,34 +1430,34 @@ if (empty($reshook)) if (!$ventilExportCompta) { - // On verifie si aucun paiement n'a ete effectue + // On verifie si aucun paiement n'a ete effectue if ($resteapayer == price2num($object->total_ttc, 'MT', 1) && $object->statut == FactureFournisseur::STATUS_VALIDATED) - { - $idwarehouse = GETPOST('idwarehouse'); + { + $idwarehouse = GETPOST('idwarehouse'); - $object->fetch_thirdparty(); + $object->fetch_thirdparty(); - $qualified_for_stock_change = 0; - if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) - { - $qualified_for_stock_change = $object->hasProductsOrServices(2); - } else { - $qualified_for_stock_change = $object->hasProductsOrServices(1); - } + $qualified_for_stock_change = 0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change = $object->hasProductsOrServices(2); + } else { + $qualified_for_stock_change = $object->hasProductsOrServices(1); + } - // Check parameters - if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) && $qualified_for_stock_change) - { - $langs->load("stocks"); - if (!$idwarehouse || $idwarehouse == -1) - { - $error++; - setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Warehouse")), null, 'errors'); - $action = ''; - } - } + // Check parameters + if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) && $qualified_for_stock_change) + { + $langs->load("stocks"); + if (!$idwarehouse || $idwarehouse == -1) + { + $error++; + setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Warehouse")), null, 'errors'); + $action = ''; + } + } - $object->setDraft($user, $idwarehouse); + $object->setDraft($user, $idwarehouse); // Define output language if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) @@ -1771,9 +1771,9 @@ if ($action == 'create') print ''; // Ref supplier - print ''.$langs->trans('RefSupplier').'id > 0) print ' autofocus'; - print '>'; + print ''.$langs->trans('RefSupplier').'id > 0) print ' autofocus'; + print '>'; print ''; print ''.$langs->trans('Type').''; @@ -2059,7 +2059,7 @@ if ($action == 'create') $doleditor = new DolEditor('note_public', (GETPOSTISSET('note_public') ?GETPOST('note_public', 'restricthtml') : $note_public), '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); print $doleditor->Create(1); print ''; - // print ''; + // print ''; print ''; // Private note @@ -2241,8 +2241,8 @@ if ($action == 'create') { // Create an array for form $formquestion = array( - array('type' => 'text', 'name' => 'newsupplierref', 'label' => $langs->trans("RefSupplier"), 'value' => $langs->trans("CopyOf").' '.$object->ref_supplier), - array('type' => 'date', 'name' => 'newdate', 'label' => $langs->trans("Date"), 'value' => dol_now()) + array('type' => 'text', 'name' => 'newsupplierref', 'label' => $langs->trans("RefSupplier"), 'value' => $langs->trans("CopyOf").' '.$object->ref_supplier), + array('type' => 'date', 'name' => 'newdate', 'label' => $langs->trans("Date"), 'value' => dol_now()) ); // Ask confirmation to clone $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneInvoice', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 250); @@ -2279,59 +2279,59 @@ if ($action == 'create') $qualified_for_stock_change = $object->hasProductsOrServices(1); } - if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) && $qualified_for_stock_change) - { - $langs->load("stocks"); - require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; - $formproduct = new FormProduct($db); - $warehouse = new Entrepot($db); - $warehouse_array = $warehouse->list_array(); - if (count($warehouse_array) == 1) { - $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockDecrease", current($warehouse_array)) : $langs->trans("WarehouseForStockIncrease", current($warehouse_array)); - $value = ''; - } else { - $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease"); - $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ?GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1); - } - $formquestion = array( - array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value) - ); - } + if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) && $qualified_for_stock_change) + { + $langs->load("stocks"); + require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; + $formproduct = new FormProduct($db); + $warehouse = new Entrepot($db); + $warehouse_array = $warehouse->list_array(); + if (count($warehouse_array) == 1) { + $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockDecrease", current($warehouse_array)) : $langs->trans("WarehouseForStockIncrease", current($warehouse_array)); + $value = ''; + } else { + $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease"); + $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ?GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1); + } + $formquestion = array( + array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value) + ); + } $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateBill'), $text, 'confirm_valid', $formquestion, 1, 1); - } + } - // Confirmation edit (back to draft) - if ($action == 'edit') - { - $formquestion = array(); + // Confirmation edit (back to draft) + if ($action == 'edit') + { + $formquestion = array(); - $qualified_for_stock_change = 0; - if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) - { - $qualified_for_stock_change = $object->hasProductsOrServices(2); - } else { - $qualified_for_stock_change = $object->hasProductsOrServices(1); - } - if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) && $qualified_for_stock_change) - { - $langs->load("stocks"); - require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; - $formproduct = new FormProduct($db); - $warehouse = new Entrepot($db); - $warehouse_array = $warehouse->list_array(); - if (count($warehouse_array) == 1) { - $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockIncrease", current($warehouse_array)) : $langs->trans("WarehouseForStockDecrease", current($warehouse_array)); - $value = ''; - } else { - $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockIncrease") : $langs->trans("SelectWarehouseForStockDecrease"); - $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ?GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1); - } - $formquestion = array( - array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value) - ); - } - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('UnvalidateBill'), $langs->trans('ConfirmUnvalidateBill', $object->ref), 'confirm_edit', $formquestion, 1, 1); + $qualified_for_stock_change = 0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change = $object->hasProductsOrServices(2); + } else { + $qualified_for_stock_change = $object->hasProductsOrServices(1); + } + if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) && $qualified_for_stock_change) + { + $langs->load("stocks"); + require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; + $formproduct = new FormProduct($db); + $warehouse = new Entrepot($db); + $warehouse_array = $warehouse->list_array(); + if (count($warehouse_array) == 1) { + $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockIncrease", current($warehouse_array)) : $langs->trans("WarehouseForStockDecrease", current($warehouse_array)); + $value = ''; + } else { + $label = $object->type == FactureFournisseur::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockIncrease") : $langs->trans("SelectWarehouseForStockDecrease"); + $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ?GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1); + } + $formquestion = array( + array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value) + ); + } + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('UnvalidateBill'), $langs->trans('ConfirmUnvalidateBill', $object->ref), 'confirm_edit', $formquestion, 1, 1); } // Confirmation set paid @@ -2369,109 +2369,109 @@ if ($action == 'create') print $formconfirm; - // Supplier invoice card - $linkback = ''.$langs->trans("BackToList").''; + // Supplier invoice card + $linkback = ''.$langs->trans("BackToList").''; - $morehtmlref = '
'; - // Ref supplier - $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $usercancreate, 'string', '', 0, 1); - $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $usercancreate, 'string', '', null, null, '', 1); - // Thirdparty - $morehtmlref .= '
'.$langs->trans('ThirdParty').' : '.$object->thirdparty->getNomUrl(1); - if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $object->thirdparty->id > 0) $morehtmlref .= ' ('.$langs->trans("OtherBills").')'; - // Project - if (!empty($conf->projet->enabled)) - { - $langs->load("projects"); - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($usercancreate) - { - if ($action != 'classify') { - $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; - } - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref .= '
'; - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects((empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS) ? $object->socid : -1), $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref .= ''; - $morehtmlref .= '
'; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); - } - } else { - if (!empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref .= ''; - $morehtmlref .= $proj->ref; - $morehtmlref .= ''; - } else { - $morehtmlref .= ''; - } - } - } - $morehtmlref .= '
'; + $morehtmlref = '
'; + // Ref supplier + $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $usercancreate, 'string', '', 0, 1); + $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $usercancreate, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref .= '
'.$langs->trans('ThirdParty').' : '.$object->thirdparty->getNomUrl(1); + if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $object->thirdparty->id > 0) $morehtmlref .= ' ('.$langs->trans("OtherBills").')'; + // Project + if (!empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref .= '
'.$langs->trans('Project').' '; + if ($usercancreate) + { + if ($action != 'classify') { + $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; + } + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects((empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS) ? $object->socid : -1), $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (!empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref .= '
'; - $object->totalpaye = $totalpaye; // To give a chance to dol_banner_tab to use already paid amount to show correct status + $object->totalpaye = $totalpaye; // To give a chance to dol_banner_tab to use already paid amount to show correct status - dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); - print '
'; - print '
'; - print '
'; + print '
'; + print '
'; + print '
'; - print ''; + print '
'; - // Type - print ''; + $facidavoir = $object->getListIdAvoirFromInvoice(); + if (count($facidavoir) > 0) + { + print ' ('.$langs->transnoentities("InvoiceHasAvoir"); + $i = 0; + foreach ($facidavoir as $id) + { + if ($i == 0) print ' '; + else print ','; + $facavoir = new FactureFournisseur($db); + $facavoir->fetch($id); + print $facavoir->getNomUrl(1); + } + print ')'; + } + if (isset($facidnext) && $facidnext > 0) + { + $facthatreplace = new FactureFournisseur($db); + $facthatreplace->fetch($facidnext); + print ' ('.$langs->transnoentities("ReplacedByInvoice", $facthatreplace->getNomUrl(1)).')'; + } + if ($object->type == FactureFournisseur::TYPE_CREDIT_NOTE || $object->type == FactureFournisseur::TYPE_DEPOSIT) { + $discount = new DiscountAbsolute($db); + $result = $discount->fetch(0, 0, $object->id); + if ($result > 0) { + print '. '.$langs->trans("CreditNoteConvertedIntoDiscount", $object->getLibType(1), $discount->getNomUrl(1, 'discount')).'
'; + } + } + print ''; - // Relative and absolute discounts + // Relative and absolute discounts print ''; - // Label - print ''; - print ''; - print ''; - print ''; + // Label + print ''; + print ''; + print ''; + print ''; - $form_permission = ($object->statut < FactureFournisseur::STATUS_CLOSED) && $usercancreate && ($object->getSommePaiement() <= 0); + $form_permission = ($object->statut < FactureFournisseur::STATUS_CLOSED) && $usercancreate && ($object->getSommePaiement() <= 0); - // Date - print ''; + // Date + print ''; // Default terms of the settlement $langs->load('bills'); @@ -3033,7 +3033,7 @@ if ($action == 'create') // modified by hook if (empty($reshook)) { - // Modify a validated invoice with no payments + // Modify a validated invoice with no payments if ($object->statut == FactureFournisseur::STATUS_VALIDATED && $action != 'confirm_edit' && $object->getSommePaiement() == 0 && $usercancreate) { // We check if lines of invoice are not already transfered into accountancy @@ -3078,17 +3078,17 @@ if ($action == 'create') } } - // Make payments - if ($object->type != FactureFournisseur::TYPE_CREDIT_NOTE && $action != 'confirm_edit' && $object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0 && $user->socid == 0) - { - print ''; // must use facid because id is for payment id not invoice - } + // Make payments + if ($object->type != FactureFournisseur::TYPE_CREDIT_NOTE && $action != 'confirm_edit' && $object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0 && $user->socid == 0) + { + print ''; // must use facid because id is for payment id not invoice + } - // Classify paid - if ($action != 'confirm_edit' && $object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0 && $user->socid == 0) - { - print ''; + // Classify paid + if ($action != 'confirm_edit' && $object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0 && $user->socid == 0) + { + print ''; //print ''.$langs->trans('ClassifyPaid').''; } @@ -3124,21 +3124,21 @@ if ($action == 'create') } } - // Validate - if ($action != 'confirm_edit' && $object->statut == FactureFournisseur::STATUS_DRAFT) - { - if (count($object->lines)) - { + // Validate + if ($action != 'confirm_edit' && $object->statut == FactureFournisseur::STATUS_DRAFT) + { + if (count($object->lines)) + { if ($usercanvalidate) - { - print ''; - } else { - print ''; - } - } - } + { + print ''; + } else { + print ''; + } + } + } // Create event /*if ($conf->agenda->enabled && ! empty($conf->global->MAIN_ADD_EVENT_ON_ELEMENT_CARD)) // Add hidden condition because this is not a "workflow" action so should appears somewhere else on page. @@ -3161,30 +3161,30 @@ if ($action == 'create') } } - // Delete + // Delete $isErasable = $object->is_erasable(); if ($action != 'confirm_edit' && ($user->rights->fournisseur->facture->supprimer || ($usercancreate && $isErasable == 1))) // isErasable = 1 means draft with temporary ref (draft can always be deleted with no need of permissions) - { - //var_dump($isErasable); - if ($isErasable == -4) { - print ''; - } elseif ($isErasable == -3) { // Should never happen with supplier invoice - print ''; - } elseif ($isErasable == -2) { // Should never happen with supplier invoice - print ''; - } elseif ($isErasable == -1) { - print ''; - } elseif ($isErasable <= 0) // Any other cases - { - print ''; - } else { - print ''; - } - } - print ''; + { + //var_dump($isErasable); + if ($isErasable == -4) { + print ''; + } elseif ($isErasable == -3) { // Should never happen with supplier invoice + print ''; + } elseif ($isErasable == -2) { // Should never happen with supplier invoice + print ''; + } elseif ($isErasable == -1) { + print ''; + } elseif ($isErasable <= 0) // Any other cases + { + print ''; + } else { + print ''; + } + } + print ''; - if ($action != 'confirm_edit') - { + if ($action != 'confirm_edit') + { print '
'; /* diff --git a/htdocs/fourn/facture/document.php b/htdocs/fourn/facture/document.php index 2887298cae7..f43ef300b01 100644 --- a/htdocs/fourn/facture/document.php +++ b/htdocs/fourn/facture/document.php @@ -94,56 +94,56 @@ if ($object->id > 0) $totalpaye = $object->getSommePaiement(); - $linkback = ''.$langs->trans("BackToList").''; + $linkback = ''.$langs->trans("BackToList").''; - $morehtmlref = '
'; - // Ref supplier - $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', 0, 1); - $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', null, null, '', 1); - // Thirdparty - $morehtmlref .= '
'.$langs->trans('ThirdParty').' : '.$object->thirdparty->getNomUrl(1); - if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $object->thirdparty->id > 0) $morehtmlref .= ' ('.$langs->trans("OtherBills").')'; - // Project - if (!empty($conf->projet->enabled)) - { - $langs->load("projects"); - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->facture->creer) - { - if ($action != 'classify') - //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; - $morehtmlref .= ' : '; - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref .= '
'; - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref .= ''; - $morehtmlref .= ''; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); - } - } else { - if (!empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref .= ''; - $morehtmlref .= $proj->ref; - $morehtmlref .= ''; - } else { - $morehtmlref .= ''; - } - } - } - $morehtmlref .= '
'; + $morehtmlref = '
'; + // Ref supplier + $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', 0, 1); + $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref .= '
'.$langs->trans('ThirdParty').' : '.$object->thirdparty->getNomUrl(1); + if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $object->thirdparty->id > 0) $morehtmlref .= ' ('.$langs->trans("OtherBills").')'; + // Project + if (!empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref .= '
'.$langs->trans('Project').' '; + if ($user->rights->facture->creer) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref .= ' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= ''; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (!empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref .= '
'; - $object->totalpaye = $totalpaye; // To give a chance to dol_banner_tab to use already paid amount to show correct status + $object->totalpaye = $totalpaye; // To give a chance to dol_banner_tab to use already paid amount to show correct status - dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0); + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0); - print '
'; - print '
'; + print '
'; + print '
'; // Build file list $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1); @@ -271,7 +271,7 @@ if ($object->id > 0) if ($res) break; } } else { - print $langs->trans('ErrorUnknown'); + print $langs->trans('ErrorUnknown'); } // End of page diff --git a/htdocs/hrm/index.php b/htdocs/hrm/index.php index 88141debfad..3955e3f849a 100644 --- a/htdocs/hrm/index.php +++ b/htdocs/hrm/index.php @@ -96,42 +96,42 @@ print '
'; if (!empty($conf->global->MAIN_SEARCH_FORM_ON_HOME_AREAS)) // This is useless due to the global search combo { - if (!empty($conf->holiday->enabled) && $user->rights->holiday->read) - { - $langs->load("holiday"); - $listofsearchfields['search_holiday'] = array('text'=>'TitreRequestCP'); - } - if (!empty($conf->deplacement->enabled) && $user->rights->deplacement->lire) - { - $langs->load("trips"); - $listofsearchfields['search_deplacement'] = array('text'=>'ExpenseReport'); - } - if (!empty($conf->expensereport->enabled) && $user->rights->expensereport->lire) - { - $langs->load("trips"); - $listofsearchfields['search_expensereport'] = array('text'=>'ExpenseReport'); - } - if (count($listofsearchfields)) - { - print '
'; - print ''; - print '
'; - print '
'.$langs->trans('Type').''; - print $object->getLibType(); - if ($object->type == FactureFournisseur::TYPE_REPLACEMENT) - { - $facreplaced = new FactureFournisseur($db); - $facreplaced->fetch($object->fk_facture_source); - print ' ('.$langs->transnoentities("ReplaceInvoice", $facreplaced->getNomUrl(1)).')'; - } - if ($object->type == FactureFournisseur::TYPE_CREDIT_NOTE) - { - $facusing = new FactureFournisseur($db); - $facusing->fetch($object->fk_facture_source); - print ' ('.$langs->transnoentities("CorrectInvoice", $facusing->getNomUrl(1)).')'; - } + // Type + print '
'.$langs->trans('Type').''; + print $object->getLibType(); + if ($object->type == FactureFournisseur::TYPE_REPLACEMENT) + { + $facreplaced = new FactureFournisseur($db); + $facreplaced->fetch($object->fk_facture_source); + print ' ('.$langs->transnoentities("ReplaceInvoice", $facreplaced->getNomUrl(1)).')'; + } + if ($object->type == FactureFournisseur::TYPE_CREDIT_NOTE) + { + $facusing = new FactureFournisseur($db); + $facusing->fetch($object->fk_facture_source); + print ' ('.$langs->transnoentities("CorrectInvoice", $facusing->getNomUrl(1)).')'; + } - $facidavoir = $object->getListIdAvoirFromInvoice(); - if (count($facidavoir) > 0) - { - print ' ('.$langs->transnoentities("InvoiceHasAvoir"); - $i = 0; - foreach ($facidavoir as $id) - { - if ($i == 0) print ' '; - else print ','; - $facavoir = new FactureFournisseur($db); - $facavoir->fetch($id); - print $facavoir->getNomUrl(1); - } - print ')'; - } - if (isset($facidnext) && $facidnext > 0) - { - $facthatreplace = new FactureFournisseur($db); - $facthatreplace->fetch($facidnext); - print ' ('.$langs->transnoentities("ReplacedByInvoice", $facthatreplace->getNomUrl(1)).')'; - } - if ($object->type == FactureFournisseur::TYPE_CREDIT_NOTE || $object->type == FactureFournisseur::TYPE_DEPOSIT) { - $discount = new DiscountAbsolute($db); - $result = $discount->fetch(0, 0, $object->id); - if ($result > 0) { - print '. '.$langs->trans("CreditNoteConvertedIntoDiscount", $object->getLibType(1), $discount->getNomUrl(1, 'discount')).'
'; - } - } - print '
'.$langs->trans('Discounts'); print ''; @@ -2482,18 +2482,18 @@ if ($action == 'create') print '
'.$form->editfieldkey("Label", 'label', $object->label, $object, ($usercancreate)).''.$form->editfieldval("Label", 'label', $object->label, $object, ($usercancreate)).'
'.$form->editfieldkey("Label", 'label', $object->label, $object, ($usercancreate)).''.$form->editfieldval("Label", 'label', $object->label, $object, ($usercancreate)).'
'.$form->editfieldkey("DateInvoice", 'datef', $object->datep, $object, $form_permission, 'datepicker').''; - print $form->editfieldval("Date", 'datef', $object->datep, $object, $form_permission, 'datepicker'); - print '
'.$form->editfieldkey("DateInvoice", 'datef', $object->datep, $object, $form_permission, 'datepicker').''; + print $form->editfieldval("Date", 'datef', $object->datep, $object, $form_permission, 'datepicker'); + print '
'; - $i = 0; - foreach ($listofsearchfields as $key => $value) - { - if ($i == 0) print ''; - print ''; - print ''; - if ($i == 0) print ''; - print ''; - $i++; - } - print '
'.$langs->trans("Search").'
'; - print '
'; - print ''; - print '
'; - } + if (!empty($conf->holiday->enabled) && $user->rights->holiday->read) + { + $langs->load("holiday"); + $listofsearchfields['search_holiday'] = array('text'=>'TitreRequestCP'); + } + if (!empty($conf->deplacement->enabled) && $user->rights->deplacement->lire) + { + $langs->load("trips"); + $listofsearchfields['search_deplacement'] = array('text'=>'ExpenseReport'); + } + if (!empty($conf->expensereport->enabled) && $user->rights->expensereport->lire) + { + $langs->load("trips"); + $listofsearchfields['search_expensereport'] = array('text'=>'ExpenseReport'); + } + if (count($listofsearchfields)) + { + print '
'; + print ''; + print '
'; + print ''; + $i = 0; + foreach ($listofsearchfields as $key => $value) + { + if ($i == 0) print ''; + print ''; + print ''; + if ($i == 0) print ''; + print ''; + $i++; + } + print '
'.$langs->trans("Search").'
'; + print '
'; + print '
'; + print '
'; + } } @@ -141,26 +141,26 @@ if (!empty($conf->holiday->enabled)) { $user_id = $user->id; - print '
'; - print ''; - print ''; - print ''; - print ''; + print ''; + print '
'.$langs->trans("Holidays").'
'; + print '
'; + print ''; + print ''; + print ''; + print ''; - print ''; - print '
'.$langs->trans("Holidays").'
'; - $out = ''; - $typeleaves = $holiday->getTypes(1, 1); - foreach ($typeleaves as $key => $val) - { - $nb_type = $holiday->getCPforUser($user->id, $val['rowid']); - $nb_holiday += $nb_type; - $out .= ' - '.$val['label'].': '.($nb_type ?price2num($nb_type) : 0).'
'; - } - print $langs->trans('SoldeCPUser', round($nb_holiday, 5)).'
'; - print $out; + $out = ''; + $typeleaves = $holiday->getTypes(1, 1); + foreach ($typeleaves as $key => $val) + { + $nb_type = $holiday->getCPforUser($user->id, $val['rowid']); + $nb_holiday += $nb_type; + $out .= ' - '.$val['label'].': '.($nb_type ?price2num($nb_type) : 0).'
'; + } + print $langs->trans('SoldeCPUser', round($nb_holiday, 5)).'
'; + print $out; - print '

'; + print '

'; } elseif (!is_numeric($conf->global->HOLIDAY_HIDE_BALANCE)) { print $langs->trans($conf->global->HOLIDAY_HIDE_BALANCE).'
'; @@ -175,80 +175,80 @@ print '
'; // Latest leave requests if (!empty($conf->holiday->enabled) && $user->rights->holiday->read) { - $sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.login, u.email, u.photo, u.statut as user_status,"; - $sql .= " x.rowid, x.rowid as ref, x.fk_type, x.date_debut as date_start, x.date_fin as date_end, x.halfday, x.tms as dm, x.statut as status"; - $sql .= " FROM ".MAIN_DB_PREFIX."holiday as x, ".MAIN_DB_PREFIX."user as u"; - $sql .= " WHERE u.rowid = x.fk_user"; - $sql .= " AND x.entity = ".$conf->entity; - if (empty($user->rights->holiday->read_all)) $sql .= ' AND x.fk_user IN ('.join(',', $childids).')'; - //if (!$user->rights->societe->client->voir && !$user->socid) $sql.= " AND x.fk_soc = s. rowid AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; - //if (!empty($socid)) $sql.= " AND x.fk_soc = ".$socid; - $sql .= $db->order("x.tms", "DESC"); - $sql .= $db->plimit($max, 0); + $sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.login, u.email, u.photo, u.statut as user_status,"; + $sql .= " x.rowid, x.rowid as ref, x.fk_type, x.date_debut as date_start, x.date_fin as date_end, x.halfday, x.tms as dm, x.statut as status"; + $sql .= " FROM ".MAIN_DB_PREFIX."holiday as x, ".MAIN_DB_PREFIX."user as u"; + $sql .= " WHERE u.rowid = x.fk_user"; + $sql .= " AND x.entity = ".$conf->entity; + if (empty($user->rights->holiday->read_all)) $sql .= ' AND x.fk_user IN ('.join(',', $childids).')'; + //if (!$user->rights->societe->client->voir && !$user->socid) $sql.= " AND x.fk_soc = s. rowid AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + //if (!empty($socid)) $sql.= " AND x.fk_soc = ".$socid; + $sql .= $db->order("x.tms", "DESC"); + $sql .= $db->plimit($max, 0); - $result = $db->query($sql); - if ($result) - { - $var = false; - $num = $db->num_rows($result); + $result = $db->query($sql); + if ($result) + { + $var = false; + $num = $db->num_rows($result); - $holidaystatic = new Holiday($db); - $userstatic = new User($db); + $holidaystatic = new Holiday($db); + $userstatic = new User($db); - $listhalfday = array('morning'=>$langs->trans("Morning"), "afternoon"=>$langs->trans("Afternoon")); - $typeleaves = $holidaystatic->getTypes(1, -1); + $listhalfday = array('morning'=>$langs->trans("Morning"), "afternoon"=>$langs->trans("Afternoon")); + $typeleaves = $holidaystatic->getTypes(1, -1); - $i = 0; + $i = 0; - print '
'; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - if ($num) - { - while ($i < $num && $i < $max) - { - $obj = $db->fetch_object($result); + print '
'; + print '
'.$langs->trans("BoxTitleLastLeaveRequests", min($max, $num)).''.$langs->trans("from").''.$langs->trans("to").''.$langs->trans("FullList").'
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if ($num) + { + while ($i < $num && $i < $max) + { + $obj = $db->fetch_object($result); - $holidaystatic->id = $obj->rowid; - $holidaystatic->ref = $obj->ref; - $holidaystatic->statut = $obj->status; + $holidaystatic->id = $obj->rowid; + $holidaystatic->ref = $obj->ref; + $holidaystatic->statut = $obj->status; - $userstatic->id = $obj->uid; - $userstatic->lastname = $obj->lastname; - $userstatic->firstname = $obj->firstname; - $userstatic->login = $obj->login; - $userstatic->photo = $obj->photo; - $userstatic->email = $obj->email; - $userstatic->statut = $obj->user_status; + $userstatic->id = $obj->uid; + $userstatic->lastname = $obj->lastname; + $userstatic->firstname = $obj->firstname; + $userstatic->login = $obj->login; + $userstatic->photo = $obj->photo; + $userstatic->email = $obj->email; + $userstatic->statut = $obj->user_status; - print ''; - print ''; - print ''; - print ''; + print ''; + print ''; + print ''; + print ''; - $starthalfday = ($obj->halfday == -1 || $obj->halfday == 2) ? 'afternoon' : 'morning'; - $endhalfday = ($obj->halfday == 1 || $obj->halfday == 2) ? 'morning' : 'afternoon'; + $starthalfday = ($obj->halfday == -1 || $obj->halfday == 2) ? 'afternoon' : 'morning'; + $endhalfday = ($obj->halfday == 1 || $obj->halfday == 2) ? 'morning' : 'afternoon'; - print ''; - print ''; - print ''; + print ''; + print ''; + print ''; - $i++; - } - } else { - print ''; - } - print '
'.$langs->trans("BoxTitleLastLeaveRequests", min($max, $num)).''.$langs->trans("from").''.$langs->trans("to").''.$langs->trans("FullList").'
'.$holidaystatic->getNomUrl(1).''.$userstatic->getNomUrl(-1, 'leave').''.$typeleaves[$obj->fk_type]['label'].'
'.$holidaystatic->getNomUrl(1).''.$userstatic->getNomUrl(-1, 'leave').''.$typeleaves[$obj->fk_type]['label'].''.dol_print_date($db->jdate($obj->date_start), 'day').' '.$langs->trans($listhalfday[$starthalfday]).''; - print ''.dol_print_date($db->jdate($obj->date_end), 'day').' '.$langs->trans($listhalfday[$endhalfday]).''; - print ''.dol_print_date($db->jdate($obj->dm), 'day').''.$holidaystatic->LibStatut($obj->status, 3).'
'.dol_print_date($db->jdate($obj->date_start), 'day').' '.$langs->trans($listhalfday[$starthalfday]).''; + print ''.dol_print_date($db->jdate($obj->date_end), 'day').' '.$langs->trans($listhalfday[$endhalfday]).''; + print ''.dol_print_date($db->jdate($obj->dm), 'day').''.$holidaystatic->LibStatut($obj->status, 3).'
'.$langs->trans("None").'
'; - print '
'; - print '
'; - } else dol_print_error($db); + $i++; + } + } else { + print ''.$langs->trans("None").''; + } + print ''; + print '
'; + print '
'; + } else dol_print_error($db); } @@ -298,7 +298,7 @@ if (!empty($conf->expensereport->enabled) && $user->rights->expensereport->lire) $userstatic->id = $obj->uid; $userstatic->lastname = $obj->lastname; $userstatic->firstname = $obj->firstname; - $userstatic->email = $obj->email; + $userstatic->email = $obj->email; $userstatic->login = $obj->login; $userstatic->statut = $obj->user_status; $userstatic->photo = $obj->photo; diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php b/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php index 694263e2ec5..ea9eeed797d 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/doc/pdf_standard_myobject.modules.php @@ -43,82 +43,82 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; */ class pdf_standard_myobject extends ModelePDFMyObject { - /** - * @var DoliDb Database handler - */ - public $db; + /** + * @var DoliDb Database handler + */ + public $db; /** - * @var string model name - */ - public $name; + * @var string model name + */ + public $name; /** - * @var string model description (short text) - */ - public $description; - - /** - * @var int Save the name of generated file as the main doc when generating a doc with this template - */ - public $update_main_doc_field; + * @var string model description (short text) + */ + public $description; /** - * @var string document type - */ - public $type; + * @var int Save the name of generated file as the main doc when generating a doc with this template + */ + public $update_main_doc_field; /** - * @var array Minimum version of PHP required by module. - * e.g.: PHP ≥ 5.6 = array(5, 6) - */ + * @var string document type + */ + public $type; + + /** + * @var array Minimum version of PHP required by module. + * e.g.: PHP ≥ 5.6 = array(5, 6) + */ public $phpmin = array(5, 6); /** - * Dolibarr version of the loaded document - * @var string - */ + * Dolibarr version of the loaded document + * @var string + */ public $version = 'dolibarr'; - /** - * @var int page_largeur - */ - public $page_largeur; + /** + * @var int page_largeur + */ + public $page_largeur; /** - * @var int page_hauteur - */ - public $page_hauteur; + * @var int page_hauteur + */ + public $page_hauteur; /** - * @var array format - */ - public $format; + * @var array format + */ + public $format; /** - * @var int marge_gauche - */ + * @var int marge_gauche + */ public $marge_gauche; /** - * @var int marge_droite - */ + * @var int marge_droite + */ public $marge_droite; /** - * @var int marge_haute - */ + * @var int marge_haute + */ public $marge_haute; /** - * @var int marge_basse - */ + * @var int marge_basse + */ public $marge_basse; - /** - * Issuer - * @var Societe Object that emits - */ + /** + * Issuer + * @var Societe Object that emits + */ public $emetteur; /** @@ -182,50 +182,50 @@ class pdf_standard_myobject extends ModelePDFMyObject } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Function to build pdf onto disk - * - * @param Object $object Object to generate - * @param Translate $outputlangs Lang output object - * @param string $srctemplatepath Full path of source filename for generator using a template file - * @param int $hidedetails Do not show line details - * @param int $hidedesc Do not show desc - * @param int $hideref Do not show ref - * @return int 1=OK, 0=KO + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Function to build pdf onto disk + * + * @param Object $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO */ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0) { - // phpcs:enable - global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines; + // phpcs:enable + global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines; - dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')); + dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')); - if (!is_object($outputlangs)) $outputlangs = $langs; - // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO - if (!empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output = 'ISO-8859-1'; + if (!is_object($outputlangs)) $outputlangs = $langs; + // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO + if (!empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output = 'ISO-8859-1'; - // Load translation files required by the page - $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies")); + // Load translation files required by the page + $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies")); - if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { - global $outputlangsbis; - $outputlangsbis = new Translate('', $conf); - $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); - $outputlangsbis->loadLangs(array("main", "bills", "products", "dict", "companies")); - } + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { + global $outputlangsbis; + $outputlangsbis = new Translate('', $conf); + $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); + $outputlangsbis->loadLangs(array("main", "bills", "products", "dict", "companies")); + } - $nblines = (is_array($object->lines) ? count($object->lines) : 0); + $nblines = (is_array($object->lines) ? count($object->lines) : 0); - $hidetop = 0; - if (!empty($conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE)) { - $hidetop = $conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE; - } + $hidetop = 0; + if (!empty($conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE)) { + $hidetop = $conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE; + } - // Loop on each lines to detect if there is at least one image to show - $realpatharray = array(); - $this->atleastonephoto = false; - /* + // Loop on each lines to detect if there is at least one image to show + $realpatharray = array(); + $this->atleastonephoto = false; + /* if (!empty($conf->global->MAIN_GENERATE_MYOBJECT_WITH_PICTURE)) { $objphoto = new Product($this->db); @@ -278,528 +278,528 @@ class pdf_standard_myobject extends ModelePDFMyObject } */ - //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; + //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; - if ($conf->mymodule->dir_output.'/myobject') - { - $object->fetch_thirdparty(); + if ($conf->mymodule->dir_output.'/myobject') + { + $object->fetch_thirdparty(); - // Definition of $dir and $file - if ($object->specimen) - { - $dir = $conf->mymodule->dir_output.'/myobject'; - $file = $dir."/SPECIMEN.pdf"; - } else { - $objectref = dol_sanitizeFileName($object->ref); - $dir = $conf->mymodule->dir_output.'/myobject/'.$objectref; - $file = $dir."/".$objectref.".pdf"; - } - if (!file_exists($dir)) - { - if (dol_mkdir($dir) < 0) - { - $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); - return 0; - } - } + // Definition of $dir and $file + if ($object->specimen) + { + $dir = $conf->mymodule->dir_output.'/myobject'; + $file = $dir."/SPECIMEN.pdf"; + } else { + $objectref = dol_sanitizeFileName($object->ref); + $dir = $conf->mymodule->dir_output.'/myobject/'.$objectref; + $file = $dir."/".$objectref.".pdf"; + } + if (!file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + return 0; + } + } - if (file_exists($dir)) - { - // Add pdfgeneration hook - if (!is_object($hookmanager)) - { - include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; - $hookmanager = new HookManager($this->db); - } - $hookmanager->initHooks(array('pdfgeneration')); - $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); - global $action; - $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + if (file_exists($dir)) + { + // Add pdfgeneration hook + if (!is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + $hookmanager->initHooks(array('pdfgeneration')); + $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); + global $action; + $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks - // Set nblines with the new facture lines content after hook - $nblines = (is_array($object->lines) ? count($object->lines) : 0); + // Set nblines with the new facture lines content after hook + $nblines = (is_array($object->lines) ? count($object->lines) : 0); - // Create pdf instance - $pdf = pdf_getInstance($this->format); - $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance - $pdf->SetAutoPageBreak(1, 0); + // Create pdf instance + $pdf = pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance + $pdf->SetAutoPageBreak(1, 0); - $heightforinfotot = 50; // Height reserved to output the info and total part and payment part - $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page - $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 12 : 22); // Height reserved to output the footer (value include bottom margin) + $heightforinfotot = 50; // Height reserved to output the info and total part and payment part + $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page + $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 12 : 22); // Height reserved to output the footer (value include bottom margin) - if (class_exists('TCPDF')) - { - $pdf->setPrintHeader(false); - $pdf->setPrintFooter(false); - } - $pdf->SetFont(pdf_getPDFFont($outputlangs)); + if (class_exists('TCPDF')) + { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($outputlangs)); - // Set path to the background PDF File - if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) - { - $pagecount = $pdf->setSourceFile($conf->mycompany->multidir_output[$object->entity].'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); - $tplidx = $pdf->importPage(1); - } + // Set path to the background PDF File + if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) + { + $pagecount = $pdf->setSourceFile($conf->mycompany->multidir_output[$object->entity].'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); + $tplidx = $pdf->importPage(1); + } - $pdf->Open(); - $pagenb = 0; - $pdf->SetDrawColor(128, 128, 128); + $pdf->Open(); + $pagenb = 0; + $pdf->SetDrawColor(128, 128, 128); - $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); - $pdf->SetSubject($outputlangs->transnoentities("PdfTitle")); - $pdf->SetCreator("Dolibarr ".DOL_VERSION); - $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); - $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); - if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false); + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("PdfTitle")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false); - // Set certificate - $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT; - // If user has no certificate, we try to take the company one - if (!$cert) { - $cert = empty($conf->global->CERTIFICATE_CRT) ? '' : $conf->global->CERTIFICATE_CRT; - } - // If a certificate is found - if ($cert) { - $info = array( - 'Name' => $this->emetteur->name, - 'Location' => getCountry($this->emetteur->country_code, 0), - 'Reason' => 'MYOBJECT', - 'ContactInfo' => $this->emetteur->email - ); - $pdf->setSignature($cert, $cert, $this->emetteur->name, '', 2, $info); - } + // Set certificate + $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT; + // If user has no certificate, we try to take the company one + if (!$cert) { + $cert = empty($conf->global->CERTIFICATE_CRT) ? '' : $conf->global->CERTIFICATE_CRT; + } + // If a certificate is found + if ($cert) { + $info = array( + 'Name' => $this->emetteur->name, + 'Location' => getCountry($this->emetteur->country_code, 0), + 'Reason' => 'MYOBJECT', + 'ContactInfo' => $this->emetteur->email + ); + $pdf->setSignature($cert, $cert, $this->emetteur->name, '', 2, $info); + } - $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right - // New page - $pdf->AddPage(); - if (!empty($tplidx)) $pdf->useTemplate($tplidx); - $pagenb++; + // New page + $pdf->AddPage(); + if (!empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; - $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); - $pdf->SetFont('', '', $default_font_size - 1); - $pdf->MultiCell(0, 3, ''); // Set interline to 3 - $pdf->SetTextColor(0, 0, 0); + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->MultiCell(0, 3, ''); // Set interline to 3 + $pdf->SetTextColor(0, 0, 0); - $tab_top = 90 + $top_shift; - $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 + $top_shift : 10); - $tab_height = 130 - $top_shift; - $tab_height_newpage = 150; - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $tab_height_newpage -= $top_shift; + $tab_top = 90 + $top_shift; + $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 + $top_shift : 10); + $tab_height = 130 - $top_shift; + $tab_height_newpage = 150; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $tab_height_newpage -= $top_shift; - $nexY = $tab_top - 1; + $nexY = $tab_top - 1; - // Display notes - $notetoshow = empty($object->note_public) ? '' : $object->note_public; - // Extrafields in note - $extranote = $this->getExtrafieldsInHtml($object, $outputlangs); - if (!empty($extranote)) - { - $notetoshow = dol_concatdesc($notetoshow, $extranote); - } + // Display notes + $notetoshow = empty($object->note_public) ? '' : $object->note_public; + // Extrafields in note + $extranote = $this->getExtrafieldsInHtml($object, $outputlangs); + if (!empty($extranote)) + { + $notetoshow = dol_concatdesc($notetoshow, $extranote); + } - $pagenb = $pdf->getPage(); - if ($notetoshow) - { + $pagenb = $pdf->getPage(); + if ($notetoshow) + { $tab_top -= 2; - $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; - $pageposbeforenote = $pagenb; + $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; + $pageposbeforenote = $pagenb; - $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object); - complete_substitutions_array($substitutionarray, $outputlangs, $object); - $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs); - $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow); + $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object); + complete_substitutions_array($substitutionarray, $outputlangs, $object); + $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs); + $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow); - $pdf->startTransaction(); + $pdf->startTransaction(); - $pdf->SetFont('', '', $default_font_size - 1); - $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); - // Description - $pageposafternote = $pdf->getPage(); - $posyafter = $pdf->GetY(); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + // Description + $pageposafternote = $pdf->getPage(); + $posyafter = $pdf->GetY(); - if ($pageposafternote > $pageposbeforenote) - { - $pdf->rollbackTransaction(true); + if ($pageposafternote > $pageposbeforenote) + { + $pdf->rollbackTransaction(true); - // prepare pages to receive notes - while ($pagenb < $pageposafternote) { - $pdf->AddPage(); - $pagenb++; - if (!empty($tplidx)) $pdf->useTemplate($tplidx); - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); - // $this->_pagefoot($pdf,$object,$outputlangs,1); - $pdf->setTopMargin($tab_top_newpage); - // The only function to edit the bottom margin of current page to set it. - $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); - } + // prepare pages to receive notes + while ($pagenb < $pageposafternote) { + $pdf->AddPage(); + $pagenb++; + if (!empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + // $this->_pagefoot($pdf,$object,$outputlangs,1); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + } - // back to start - $pdf->setPage($pageposbeforenote); - $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); - $pdf->SetFont('', '', $default_font_size - 1); - $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); - $pageposafternote = $pdf->getPage(); + // back to start + $pdf->setPage($pageposbeforenote); + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + $pageposafternote = $pdf->getPage(); - $posyafter = $pdf->GetY(); + $posyafter = $pdf->GetY(); - if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) // There is no space left for total+free text - { - $pdf->AddPage('', '', true); - $pagenb++; - $pageposafternote++; - $pdf->setPage($pageposafternote); - $pdf->setTopMargin($tab_top_newpage); - // The only function to edit the bottom margin of current page to set it. - $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); - //$posyafter = $tab_top_newpage; - } + if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) // There is no space left for total+free text + { + $pdf->AddPage('', '', true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + //$posyafter = $tab_top_newpage; + } - // apply note frame to previous pages - $i = $pageposbeforenote; - while ($i < $pageposafternote) { - $pdf->setPage($i); + // apply note frame to previous pages + $i = $pageposbeforenote; + while ($i < $pageposafternote) { + $pdf->setPage($i); - $pdf->SetDrawColor(128, 128, 128); - // Draw note frame - if ($i > $pageposbeforenote) { - $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); - $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1); - } else { - $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); - $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); - } + $pdf->SetDrawColor(128, 128, 128); + // Draw note frame + if ($i > $pageposbeforenote) { + $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1); + } else { + $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); + } - // Add footer - $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. - $this->_pagefoot($pdf, $object, $outputlangs, 1); + // Add footer + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + $this->_pagefoot($pdf, $object, $outputlangs, 1); - $i++; - } + $i++; + } - // apply note frame to last page - $pdf->setPage($pageposafternote); - if (!empty($tplidx)) $pdf->useTemplate($tplidx); - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); - $height_note = $posyafter - $tab_top_newpage; - $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1); - } else // No pagebreak - { - $pdf->commitTransaction(); - $posyafter = $pdf->GetY(); - $height_note = $posyafter - $tab_top; - $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); + // apply note frame to last page + $pdf->setPage($pageposafternote); + if (!empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $height_note = $posyafter - $tab_top_newpage; + $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1); + } else // No pagebreak + { + $pdf->commitTransaction(); + $posyafter = $pdf->GetY(); + $height_note = $posyafter - $tab_top; + $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); - if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) - { - // not enough space, need to add page - $pdf->AddPage('', '', true); - $pagenb++; - $pageposafternote++; - $pdf->setPage($pageposafternote); - if (!empty($tplidx)) $pdf->useTemplate($tplidx); - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) + { + // not enough space, need to add page + $pdf->AddPage('', '', true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + if (!empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); - $posyafter = $tab_top_newpage; - } - } + $posyafter = $tab_top_newpage; + } + } - $tab_height = $tab_height - $height_note; - $tab_top = $posyafter + 6; - } else { - $height_note = 0; - } + $tab_height = $tab_height - $height_note; + $tab_top = $posyafter + 6; + } else { + $height_note = 0; + } - // Use new auto column system - $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref); + // Use new auto column system + $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref); - // Table simulation to know the height of the title line - $pdf->startTransaction(); - $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop); - $pdf->rollbackTransaction(true); + // Table simulation to know the height of the title line + $pdf->startTransaction(); + $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop); + $pdf->rollbackTransaction(true); - $nexY = $tab_top + $this->tabTitleHeight; + $nexY = $tab_top + $this->tabTitleHeight; - // Loop on each lines - $pageposbeforeprintlines = $pdf->getPage(); - $pagenb = $pageposbeforeprintlines; - for ($i = 0; $i < $nblines; $i++) - { - $curY = $nexY; - $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage - $pdf->SetTextColor(0, 0, 0); + // Loop on each lines + $pageposbeforeprintlines = $pdf->getPage(); + $pagenb = $pageposbeforeprintlines; + for ($i = 0; $i < $nblines; $i++) + { + $curY = $nexY; + $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage + $pdf->SetTextColor(0, 0, 0); - // Define size of image if we need it - $imglinesize = array(); - if (!empty($realpatharray[$i])) $imglinesize = pdf_getSizeForImage($realpatharray[$i]); + // Define size of image if we need it + $imglinesize = array(); + if (!empty($realpatharray[$i])) $imglinesize = pdf_getSizeForImage($realpatharray[$i]); - $pdf->setTopMargin($tab_top_newpage); - $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it. - $pageposbefore = $pdf->getPage(); + $pdf->setTopMargin($tab_top_newpage); + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it. + $pageposbefore = $pdf->getPage(); - $showpricebeforepagebreak = 1; - $posYAfterImage = 0; + $showpricebeforepagebreak = 1; + $posYAfterImage = 0; - if ($this->getColumnStatus('photo')) - { - // We start with Photo of product line - if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) // If photo too high, we moved completely on new page - { - $pdf->AddPage('', '', true); - if (!empty($tplidx)) $pdf->useTemplate($tplidx); - $pdf->setPage($pageposbefore + 1); + if ($this->getColumnStatus('photo')) + { + // We start with Photo of product line + if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) // If photo too high, we moved completely on new page + { + $pdf->AddPage('', '', true); + if (!empty($tplidx)) $pdf->useTemplate($tplidx); + $pdf->setPage($pageposbefore + 1); - $curY = $tab_top_newpage; + $curY = $tab_top_newpage; // Allows data in the first page if description is long enough to break in multiples pages if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) $showpricebeforepagebreak = 1; else $showpricebeforepagebreak = 0; - } + } - if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) - { - $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi - // $pdf->Image does not increase value return by getY, so we save it manually - $posYAfterImage = $curY + $imglinesize['height']; - } - } + if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) + { + $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi + // $pdf->Image does not increase value return by getY, so we save it manually + $posYAfterImage = $curY + $imglinesize['height']; + } + } - // Description of product line - if ($this->getColumnStatus('desc')) - { - $pdf->startTransaction(); + // Description of product line + if ($this->getColumnStatus('desc')) + { + $pdf->startTransaction(); - $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc); - $pageposafter = $pdf->getPage(); + $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc); + $pageposafter = $pdf->getPage(); - if ($pageposafter > $pageposbefore) // There is a pagebreak - { - $pdf->rollbackTransaction(true); - $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. + if ($pageposafter > $pageposbefore) // There is a pagebreak + { + $pdf->rollbackTransaction(true); + $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. - $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc); + $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc); - $pageposafter = $pdf->getPage(); - $posyafter = $pdf->GetY(); - //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; - if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) // There is no space left for total+free text - { - if ($i == ($nblines - 1)) // No more lines, and no space left to show total, so we create a new page - { - $pdf->AddPage('', '', true); - if (!empty($tplidx)) $pdf->useTemplate($tplidx); - $pdf->setPage($pageposafter + 1); - } - } else { - // We found a page break + $pageposafter = $pdf->getPage(); + $posyafter = $pdf->GetY(); + //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; + if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) // There is no space left for total+free text + { + if ($i == ($nblines - 1)) // No more lines, and no space left to show total, so we create a new page + { + $pdf->AddPage('', '', true); + if (!empty($tplidx)) $pdf->useTemplate($tplidx); + $pdf->setPage($pageposafter + 1); + } + } else { + // We found a page break // Allows data in the first page if description is long enough to break in multiples pages if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) $showpricebeforepagebreak = 1; else $showpricebeforepagebreak = 0; - } - } else // No pagebreak - { - $pdf->commitTransaction(); - } - } + } + } else // No pagebreak + { + $pdf->commitTransaction(); + } + } - $nexY = $pdf->GetY(); - $pageposafter = $pdf->getPage(); - $pdf->setPage($pageposbefore); - $pdf->setTopMargin($this->marge_haute); - $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + $nexY = $pdf->GetY(); + $pageposafter = $pdf->getPage(); + $pdf->setPage($pageposbefore); + $pdf->setTopMargin($this->marge_haute); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. - // We suppose that a too long description or photo were moved completely on next page - if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { - $pdf->setPage($pageposafter); $curY = $tab_top_newpage; - } + // We suppose that a too long description or photo were moved completely on next page + if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } - $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut + $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut - // Quantity - // Enough for 6 chars - if ($this->getColumnStatus('qty')) - { - $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails); - $this->printStdColumnContent($pdf, $curY, 'qty', $qty); - $nexY = max($pdf->GetY(), $nexY); - } + // Quantity + // Enough for 6 chars + if ($this->getColumnStatus('qty')) + { + $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'qty', $qty); + $nexY = max($pdf->GetY(), $nexY); + } - // Extrafields - if (!empty($object->lines[$i]->array_options)) { - foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { - if ($this->getColumnStatus($extrafieldColKey)) - { - $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey); - $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue); - $nexY = max($pdf->GetY(), $nexY); - } - } - } + // Extrafields + if (!empty($object->lines[$i]->array_options)) { + foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { + if ($this->getColumnStatus($extrafieldColKey)) + { + $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey); + $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue); + $nexY = max($pdf->GetY(), $nexY); + } + } + } - $parameters = array( - 'object' => $object, - 'i' => $i, - 'pdf' =>& $pdf, - 'curY' =>& $curY, - 'nexY' =>& $nexY, - 'outputlangs' => $outputlangs, - 'hidedetails' => $hidedetails - ); - $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook + $parameters = array( + 'object' => $object, + 'i' => $i, + 'pdf' =>& $pdf, + 'curY' =>& $curY, + 'nexY' =>& $nexY, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails + ); + $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook - $sign = 1; - // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva - $prev_progress = $object->lines[$i]->get_prev_progress($object->id); - if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) // Compute progress from previous situation - { - if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; - else $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; - } else { - if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva; - else $tvaligne = $sign * $object->lines[$i]->total_tva; - } + $sign = 1; + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + $prev_progress = $object->lines[$i]->get_prev_progress($object->id); + if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) // Compute progress from previous situation + { + if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; + else $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; + } else { + if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva; + else $tvaligne = $sign * $object->lines[$i]->total_tva; + } - $localtax1ligne = $object->lines[$i]->total_localtax1; - $localtax2ligne = $object->lines[$i]->total_localtax2; - $localtax1_rate = $object->lines[$i]->localtax1_tx; - $localtax2_rate = $object->lines[$i]->localtax2_tx; - $localtax1_type = $object->lines[$i]->localtax1_type; - $localtax2_type = $object->lines[$i]->localtax2_type; + $localtax1ligne = $object->lines[$i]->total_localtax1; + $localtax2ligne = $object->lines[$i]->total_localtax2; + $localtax1_rate = $object->lines[$i]->localtax1_tx; + $localtax2_rate = $object->lines[$i]->localtax2_tx; + $localtax1_type = $object->lines[$i]->localtax1_type; + $localtax2_type = $object->lines[$i]->localtax2_type; - if ($object->remise_percent) $tvaligne -= ($tvaligne * $object->remise_percent) / 100; - if ($object->remise_percent) $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100; - if ($object->remise_percent) $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100; + if ($object->remise_percent) $tvaligne -= ($tvaligne * $object->remise_percent) / 100; + if ($object->remise_percent) $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100; + if ($object->remise_percent) $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100; - $vatrate = (string) $object->lines[$i]->tva_tx; + $vatrate = (string) $object->lines[$i]->tva_tx; - // Retrieve type from database for backward compatibility with old records - if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined - && (!empty($localtax1_rate) || !empty($localtax2_rate))) // and there is local tax - { - $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc); - $localtax1_type = $localtaxtmp_array[0]; - $localtax2_type = $localtaxtmp_array[2]; - } + // Retrieve type from database for backward compatibility with old records + if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined + && (!empty($localtax1_rate) || !empty($localtax2_rate))) // and there is local tax + { + $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc); + $localtax1_type = $localtaxtmp_array[0]; + $localtax2_type = $localtaxtmp_array[2]; + } - // retrieve global local tax - if ($localtax1_type && $localtax1ligne != 0) { - $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne; - } - if ($localtax2_type && $localtax2ligne != 0) { - $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne; - } + // retrieve global local tax + if ($localtax1_type && $localtax1ligne != 0) { + $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne; + } + if ($localtax2_type && $localtax2ligne != 0) { + $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne; + } - if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate .= '*'; - if (!isset($this->tva[$vatrate])) $this->tva[$vatrate] = 0; - $this->tva[$vatrate] += $tvaligne; + if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate .= '*'; + if (!isset($this->tva[$vatrate])) $this->tva[$vatrate] = 0; + $this->tva[$vatrate] += $tvaligne; - $nexY = max($nexY, $posYAfterImage); + $nexY = max($nexY, $posYAfterImage); - // Add line - if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) { - $pdf->setPage($pageposafter); - $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80))); - //$pdf->SetDrawColor(190,190,200); - $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY); - $pdf->SetLineStyle(array('dash'=>0)); - } + // Add line + if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) { + $pdf->setPage($pageposafter); + $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80))); + //$pdf->SetDrawColor(190,190,200); + $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY); + $pdf->SetLineStyle(array('dash'=>0)); + } - // Detect if some page were added automatically and output _tableau for past pages - while ($pagenb < $pageposafter) { - $pdf->setPage($pagenb); - if ($pagenb == $pageposbeforeprintlines) { - $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis); - } else { - $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis); - } - $this->_pagefoot($pdf, $object, $outputlangs, 1); - $pagenb++; - $pdf->setPage($pagenb); - $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); - } + // Detect if some page were added automatically and output _tableau for past pages + while ($pagenb < $pageposafter) { + $pdf->setPage($pagenb); + if ($pagenb == $pageposbeforeprintlines) { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis); + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis); + } + $this->_pagefoot($pdf, $object, $outputlangs, 1); + $pagenb++; + $pdf->setPage($pagenb); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } - if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) { - if ($pagenb == $pageposafter) { - $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis); - } else { - $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis); - } - $this->_pagefoot($pdf, $object, $outputlangs, 1); - // New page - $pdf->AddPage(); - if (!empty($tplidx)) $pdf->useTemplate($tplidx); - $pagenb++; - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); - } - } + if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) { + if ($pagenb == $pageposafter) { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis); + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis); + } + $this->_pagefoot($pdf, $object, $outputlangs, 1); + // New page + $pdf->AddPage(); + if (!empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + } - // Show square - if ($pagenb == $pageposbeforeprintlines) - { - $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code, $outputlangsbis); - $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; - } else { - $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code, $outputlangsbis); - $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; - } + // Show square + if ($pagenb == $pageposbeforeprintlines) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code, $outputlangsbis); + $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code, $outputlangsbis); + $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } - // Display infos area - //$posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs); + // Display infos area + //$posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs); - // Display total zone - //$posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); + // Display total zone + //$posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); - // Display payment area - /* + // Display payment area + /* if (($deja_regle || $amount_credit_notes_included || $amount_deposits_included) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) { $posy = $this->drawPaymentsTable($pdf, $object, $posy, $outputlangs); } */ - // Pagefoot - $this->_pagefoot($pdf, $object, $outputlangs); - if (method_exists($pdf, 'AliasNbPages')) $pdf->AliasNbPages(); + // Pagefoot + $this->_pagefoot($pdf, $object, $outputlangs); + if (method_exists($pdf, 'AliasNbPages')) $pdf->AliasNbPages(); - $pdf->Close(); + $pdf->Close(); - $pdf->Output($file, 'F'); + $pdf->Output($file, 'F'); - // Add pdfgeneration hook - $hookmanager->initHooks(array('pdfgeneration')); - $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); - global $action; - $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks - if ($reshook < 0) - { - $this->error = $hookmanager->error; - $this->errors = $hookmanager->errors; - } + // Add pdfgeneration hook + $hookmanager->initHooks(array('pdfgeneration')); + $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); + global $action; + $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) + { + $this->error = $hookmanager->error; + $this->errors = $hookmanager->errors; + } - if (!empty($conf->global->MAIN_UMASK)) - @chmod($file, octdec($conf->global->MAIN_UMASK)); + if (!empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); - $this->result = array('fullpath'=>$file); + $this->result = array('fullpath'=>$file); - return 1; // No error - } else { - $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); - return 0; - } - } else { - $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR"); - return 0; - } + return 1; // No error + } else { + $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + return 0; + } + } else { + $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR"); + return 0; + } } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps @@ -872,7 +872,7 @@ class pdf_standard_myobject extends ModelePDFMyObject $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop); if (empty($hidetop)) { - $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight); // line takes a position y in 2nd parameter and 4th parameter + $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight); // line takes a position y in 2nd parameter and 4th parameter } } @@ -900,9 +900,9 @@ class pdf_standard_myobject extends ModelePDFMyObject // Show Draft Watermark if ($object->statut == $object::STATUS_DRAFT && (!empty($conf->global->FACTURE_DRAFT_WATERMARK))) - { - pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->FACTURE_DRAFT_WATERMARK); - } + { + pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->FACTURE_DRAFT_WATERMARK); + } $pdf->SetTextColor(0, 0, 60); $pdf->SetFont('', 'B', $default_font_size + 3); @@ -910,7 +910,7 @@ class pdf_standard_myobject extends ModelePDFMyObject $w = 110; $posy = $this->marge_haute; - $posx = $this->page_largeur - $this->marge_droite - $w; + $posx = $this->page_largeur - $this->marge_droite - $w; $pdf->SetXY($this->marge_gauche, $posy); @@ -929,7 +929,7 @@ class pdf_standard_myobject extends ModelePDFMyObject } if (is_readable($logo)) { - $height = pdf_getHeightForLogo($logo); + $height = pdf_getHeightForLogo($logo); $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) } else { $pdf->SetTextColor(200, 0, 0); @@ -1022,16 +1022,16 @@ class pdf_standard_myobject extends ModelePDFMyObject // Get contact if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) { - $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL'); - if (count($arrayidcontact) > 0) - { - $usertmp = new User($this->db); - $usertmp->fetch($arrayidcontact[0]); - $posy += 4; - $pdf->SetXY($posx, $posy); - $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); - } + $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $usertmp = new User($this->db); + $usertmp->fetch($arrayidcontact[0]); + $posy += 4; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + } } $posy += 1; @@ -1138,7 +1138,7 @@ class pdf_standard_myobject extends ModelePDFMyObject // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore /** * Show footer of page. Need this->emetteur object - * + * * @param TCPDF $pdf PDF * @param Object $object Object to show * @param Translate $outputlangs Object lang for output @@ -1157,28 +1157,28 @@ class pdf_standard_myobject extends ModelePDFMyObject * * @param object $object common object * @param Translate $outputlangs langs - * @param int $hidedetails Do not show line details - * @param int $hidedesc Do not show desc - * @param int $hideref Do not show ref - * @return null - */ - public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0) - { - global $conf, $hookmanager; + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return null + */ + public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0) + { + global $conf, $hookmanager; - // Default field style for content - $this->defaultContentsFieldsStyle = array( - 'align' => 'R', // R,C,L - 'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left - ); + // Default field style for content + $this->defaultContentsFieldsStyle = array( + 'align' => 'R', // R,C,L + 'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); - // Default field style for content - $this->defaultTitlesFieldsStyle = array( - 'align' => 'C', // R,C,L - 'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left - ); + // Default field style for content + $this->defaultTitlesFieldsStyle = array( + 'align' => 'C', // R,C,L + 'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); - /* + /* * For exemple $this->cols['theColKey'] = array( 'rank' => $rank, // int : use for ordering columns @@ -1196,162 +1196,162 @@ class pdf_standard_myobject extends ModelePDFMyObject ); */ - $rank = 0; // do not use negative rank - $this->cols['desc'] = array( - 'rank' => $rank, - 'width' => false, // only for desc - 'status' => true, - 'title' => array( - 'textkey' => 'Designation', // use lang key is usefull in somme case with module - 'align' => 'L', - // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label - // 'label' => ' ', // the final label - 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left - ), - 'content' => array( - 'align' => 'L', - 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left - ), - ); + $rank = 0; // do not use negative rank + $this->cols['desc'] = array( + 'rank' => $rank, + 'width' => false, // only for desc + 'status' => true, + 'title' => array( + 'textkey' => 'Designation', // use lang key is usefull in somme case with module + 'align' => 'L', + // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + // 'label' => ' ', // the final label + 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', + 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + ); - // PHOTO - $rank = $rank + 10; - $this->cols['photo'] = array( - 'rank' => $rank, - 'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm - 'status' => false, - 'title' => array( - 'textkey' => 'Photo', - 'label' => ' ' - ), - 'content' => array( - 'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left - ), - 'border-left' => false, // remove left line separator - ); + // PHOTO + $rank = $rank + 10; + $this->cols['photo'] = array( + 'rank' => $rank, + 'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Photo', + 'label' => ' ' + ), + 'content' => array( + 'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'border-left' => false, // remove left line separator + ); - if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE) && !empty($this->atleastonephoto)) - { - $this->cols['photo']['status'] = true; - } + if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE) && !empty($this->atleastonephoto)) + { + $this->cols['photo']['status'] = true; + } - $rank = $rank + 10; - $this->cols['vat'] = array( - 'rank' => $rank, - 'status' => false, - 'width' => 16, // in mm - 'title' => array( - 'textkey' => 'VAT' - ), - 'border-left' => true, // add left line separator - ); + $rank = $rank + 10; + $this->cols['vat'] = array( + 'rank' => $rank, + 'status' => false, + 'width' => 16, // in mm + 'title' => array( + 'textkey' => 'VAT' + ), + 'border-left' => true, // add left line separator + ); - if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) - { - $this->cols['vat']['status'] = true; - } + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) + { + $this->cols['vat']['status'] = true; + } - $rank = $rank + 10; - $this->cols['subprice'] = array( - 'rank' => $rank, - 'width' => 19, // in mm - 'status' => true, - 'title' => array( - 'textkey' => 'PriceUHT' - ), - 'border-left' => true, // add left line separator - ); + $rank = $rank + 10; + $this->cols['subprice'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'PriceUHT' + ), + 'border-left' => true, // add left line separator + ); - $rank = $rank + 10; - $this->cols['qty'] = array( - 'rank' => $rank, - 'width' => 16, // in mm - 'status' => true, - 'title' => array( - 'textkey' => 'Qty' - ), - 'border-left' => true, // add left line separator - ); + $rank = $rank + 10; + $this->cols['qty'] = array( + 'rank' => $rank, + 'width' => 16, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'Qty' + ), + 'border-left' => true, // add left line separator + ); - $rank = $rank + 10; - $this->cols['progress'] = array( - 'rank' => $rank, - 'width' => 19, // in mm - 'status' => false, - 'title' => array( - 'textkey' => 'Progress' - ), - 'border-left' => true, // add left line separator - ); + $rank = $rank + 10; + $this->cols['progress'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Progress' + ), + 'border-left' => true, // add left line separator + ); - if ($this->situationinvoice) - { - $this->cols['progress']['status'] = true; - } + if ($this->situationinvoice) + { + $this->cols['progress']['status'] = true; + } - $rank = $rank + 10; - $this->cols['unit'] = array( - 'rank' => $rank, - 'width' => 11, // in mm - 'status' => false, - 'title' => array( - 'textkey' => 'Unit' - ), - 'border-left' => true, // add left line separator - ); - if ($conf->global->PRODUCT_USE_UNITS) { - $this->cols['unit']['status'] = true; - } + $rank = $rank + 10; + $this->cols['unit'] = array( + 'rank' => $rank, + 'width' => 11, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Unit' + ), + 'border-left' => true, // add left line separator + ); + if ($conf->global->PRODUCT_USE_UNITS) { + $this->cols['unit']['status'] = true; + } - $rank = $rank + 10; - $this->cols['discount'] = array( - 'rank' => $rank, - 'width' => 13, // in mm - 'status' => false, - 'title' => array( - 'textkey' => 'ReductionShort' - ), - 'border-left' => true, // add left line separator - ); - if ($this->atleastonediscount) { - $this->cols['discount']['status'] = true; - } + $rank = $rank + 10; + $this->cols['discount'] = array( + 'rank' => $rank, + 'width' => 13, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'ReductionShort' + ), + 'border-left' => true, // add left line separator + ); + if ($this->atleastonediscount) { + $this->cols['discount']['status'] = true; + } - $rank = $rank + 1000; // add a big offset to be sure is the last col because default extrafield rank is 100 - $this->cols['totalexcltax'] = array( - 'rank' => $rank, - 'width' => 26, // in mm - 'status' => true, - 'title' => array( - 'textkey' => 'TotalHT' - ), - 'border-left' => true, // add left line separator - ); + $rank = $rank + 1000; // add a big offset to be sure is the last col because default extrafield rank is 100 + $this->cols['totalexcltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'TotalHT' + ), + 'border-left' => true, // add left line separator + ); - // Add extrafields cols - if (!empty($object->lines)) { - $line = reset($object->lines); - $this->defineColumnExtrafield($line, $outputlangs, $hidedetails); - } + // Add extrafields cols + if (!empty($object->lines)) { + $line = reset($object->lines); + $this->defineColumnExtrafield($line, $outputlangs, $hidedetails); + } - $parameters = array( - 'object' => $object, - 'outputlangs' => $outputlangs, - 'hidedetails' => $hidedetails, - 'hidedesc' => $hidedesc, - 'hideref' => $hideref - ); + $parameters = array( + 'object' => $object, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails, + 'hidedesc' => $hidedesc, + 'hideref' => $hideref + ); - $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook - if ($reshook < 0) - { - setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - } elseif (empty($reshook)) - { - $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys - } else { - $this->cols = $hookmanager->resArray; - } + $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook + if ($reshook < 0) + { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } elseif (empty($reshook)) + { + $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys + } else { + $this->cols = $hookmanager->resArray; + } } } diff --git a/htdocs/mrp/mo_card.php b/htdocs/mrp/mo_card.php index add7de31b56..e20a57a6e4d 100644 --- a/htdocs/mrp/mo_card.php +++ b/htdocs/mrp/mo_card.php @@ -107,75 +107,75 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e if (empty($reshook)) { - $error = 0; + $error = 0; - $backurlforlist = dol_buildpath('/mrp/mo_list.php', 1); + $backurlforlist = dol_buildpath('/mrp/mo_list.php', 1); - if (empty($backtopage) || ($cancel && empty($id))) { - if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { - if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) $backtopage = $backurlforlist; - else $backtopage = DOL_URL_ROOT.'/mrp/mo_card.php?id='.($id > 0 ? $id : '__ID__'); - } - } - if ($cancel && !empty($backtopageforcancel)) { - $backtopage = $backtopageforcancel; - } + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) $backtopage = $backurlforlist; + else $backtopage = DOL_URL_ROOT.'/mrp/mo_card.php?id='.($id > 0 ? $id : '__ID__'); + } + } + if ($cancel && !empty($backtopageforcancel)) { + $backtopage = $backtopageforcancel; + } - $triggermodname = 'MRP_MO_MODIFY'; // Name of trigger action code to execute when we modify record + $triggermodname = 'MRP_MO_MODIFY'; // Name of trigger action code to execute when we modify record - // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen - include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php'; + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen + include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php'; - // Actions when linking object each other - include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; + // Actions when linking object each other + include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; - // Actions when printing a doc from card - include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; - // Actions to send emails - $triggersendname = 'MO_SENTBYMAIL'; - $autocopy = 'MAIN_MAIL_AUTOCOPY_MO_TO'; - $trackid = 'mo'.$object->id; - include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; + // Actions to send emails + $triggersendname = 'MO_SENTBYMAIL'; + $autocopy = 'MAIN_MAIL_AUTOCOPY_MO_TO'; + $trackid = 'mo'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; - // Action to move up and down lines of object - //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once + // Action to move up and down lines of object + //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once - if ($action == 'set_thirdparty' && $permissiontoadd) - { - $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, 'MO_MODIFY'); - } - if ($action == 'classin' && $permissiontoadd) - { - $object->setProject(GETPOST('projectid', 'int')); - } + if ($action == 'set_thirdparty' && $permissiontoadd) + { + $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, 'MO_MODIFY'); + } + if ($action == 'classin' && $permissiontoadd) + { + $object->setProject(GETPOST('projectid', 'int')); + } - // Action close produced - if ($action == 'confirm_produced' && $confirm == 'yes' && $permissiontoadd) - { - $result = $object->setStatut($object::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED'); - if ($result >= 0) - { - // Define output language - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - $outputlangs = $langs; - $newlang = ''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) $newlang = GETPOST('lang_id', 'aZ09'); - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; - if (!empty($newlang)) { - $outputlangs = new Translate("", $conf); - $outputlangs->setDefaultLang($newlang); - } - $model = $object->model_pdf; - $ret = $object->fetch($id); // Reload to get new records + // Action close produced + if ($action == 'confirm_produced' && $confirm == 'yes' && $permissiontoadd) + { + $result = $object->setStatut($object::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED'); + if ($result >= 0) + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) $newlang = GETPOST('lang_id', 'aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (!empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model = $object->model_pdf; + $ret = $object->fetch($id); // Reload to get new records - $object->generateDocument($model, $outputlangs, 0, 0, 0); - } - } else { - setEventMessages($object->error, $object->errors, 'errors'); - } - } + $object->generateDocument($model, $outputlangs, 0, 0, 0); + } + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } } @@ -317,7 +317,7 @@ if (($id || $ref) && $action == 'edit') print load_fiche_titre($langs->trans("MO"), '', 'mrp'); print '
'; - print ''; + print ''; print ''; print ''; if ($backtopage) print ''; @@ -360,7 +360,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Confirmation to delete if ($action == 'delete') { - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteMo'), $langs->trans('ConfirmDeleteMo'), 'confirm_delete', '', 0, 1); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteMo'), $langs->trans('ConfirmDeleteMo'), 'confirm_delete', '', 0, 1); } // Confirmation to delete line if ($action == 'deleteline') @@ -439,32 +439,32 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Project if (!empty($conf->projet->enabled)) { - $langs->load("projects"); - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($permissiontoadd) - { - if ($action != 'classify') - $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->fk_soc, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects($object->fk_soc, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref .= ''; - $morehtmlref .= '
'; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_soc, $object->fk_project, 'none', 0, 0, 0, 1); - } - } else { - if (!empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref .= ' : '.$proj->getNomUrl(); - } else { - $morehtmlref .= ''; - } - } + $langs->load("projects"); + $morehtmlref .= '
'.$langs->trans('Project').' '; + if ($permissiontoadd) + { + if ($action != 'classify') + $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->fk_soc, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->fk_soc, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_soc, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (!empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref .= ' : '.$proj->getNomUrl(); + } else { + $morehtmlref .= ''; + } + } } $morehtmlref .= '
'; @@ -501,167 +501,167 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if (!empty($object->table_element_line)) { - // Show object lines + // Show object lines //$result = $object->getLinesArray(); $object->fetchLines(); - print '
+ print ' '; - /*if (!empty($conf->use_javascript_ajax) && $object->status == 0) { + /*if (!empty($conf->use_javascript_ajax) && $object->status == 0) { include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php'; }*/ - if (!empty($object->lines)) - { - print '
'; - print ''; + if (!empty($object->lines)) + { + print '
'; + print '
'; - print ''; - print ''; - print ''; - print ''; + print ''; + print ''; + print ''; + print ''; - print ''; - print ''; - print ''; - print ''; + print ''; + print ''; + print ''; + print ''; - print ''; - print ''; - print ''; - print ''; + print ''; + print ''; + print ''; + print ''; - print '
'.$langs->trans("Summary").'
'.$langs->trans("Summary").'
'.$langs->trans("ProductsToConsume").''; - if (!empty($object->lines)) - { - $i = 0; - foreach ($object->lines as $line) { - if ($line->role == 'toconsume') { - if ($i) print ', '; - $tmpproduct = new Product($db); - $tmpproduct->fetch($line->fk_product); - print $tmpproduct->getNomUrl(1); - $i++; - } - } - } - print '
'.$langs->trans("ProductsToConsume").''; + if (!empty($object->lines)) + { + $i = 0; + foreach ($object->lines as $line) { + if ($line->role == 'toconsume') { + if ($i) print ', '; + $tmpproduct = new Product($db); + $tmpproduct->fetch($line->fk_product); + print $tmpproduct->getNomUrl(1); + $i++; + } + } + } + print '
'.$langs->trans("ProductsToProduce").''; - if (!empty($object->lines)) - { - $i = 0; - foreach ($object->lines as $line) { - if ($line->role == 'toproduce') { - if ($i) print ', '; - $tmpproduct = new Product($db); - $tmpproduct->fetch($line->fk_product); - print $tmpproduct->getNomUrl(1); - $i++; - } - } - } - print '
'.$langs->trans("ProductsToProduce").''; + if (!empty($object->lines)) + { + $i = 0; + foreach ($object->lines as $line) { + if ($line->role == 'toproduce') { + if ($i) print ', '; + $tmpproduct = new Product($db); + $tmpproduct->fetch($line->fk_product); + print $tmpproduct->getNomUrl(1); + $i++; + } + } + } + print '
'; - print '
'; - } + print ''; + print '
'; + } - print "\n"; + print "\n"; } // Buttons for actions if ($action != 'presend' && $action != 'editline') { - print '
'."\n"; - $parameters = array(); - $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook - if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + print '
'."\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - if (empty($reshook)) - { - // Send - //if (empty($user->socid)) { - // print '' . $langs->trans('SendMail') . ''."\n"; - //} + if (empty($reshook)) + { + // Send + //if (empty($user->socid)) { + // print '' . $langs->trans('SendMail') . ''."\n"; + //} - // Back to draft - if ($object->status == $object::STATUS_VALIDATED) - { - if ($permissiontoadd) - { - // TODO Add test that production has not started - print ''.$langs->trans("SetToDraft").''; - } - } + // Back to draft + if ($object->status == $object::STATUS_VALIDATED) + { + if ($permissiontoadd) + { + // TODO Add test that production has not started + print ''.$langs->trans("SetToDraft").''; + } + } - // Modify - if ($object->status == $object::STATUS_DRAFT) { - if ($permissiontoadd) - { - print ''.$langs->trans("Modify").''."\n"; - } else { - print ''.$langs->trans('Modify').''."\n"; - } - } + // Modify + if ($object->status == $object::STATUS_DRAFT) { + if ($permissiontoadd) + { + print ''.$langs->trans("Modify").''."\n"; + } else { + print ''.$langs->trans('Modify').''."\n"; + } + } - // Validate - if ($object->status == $object::STATUS_DRAFT) - { - if ($permissiontoadd) - { - if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) - { - print ''.$langs->trans("Validate").''; - } else { - $langs->load("errors"); - print ''.$langs->trans("Validate").''; - } - } - } + // Validate + if ($object->status == $object::STATUS_DRAFT) + { + if ($permissiontoadd) + { + if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) + { + print ''.$langs->trans("Validate").''; + } else { + $langs->load("errors"); + print ''.$langs->trans("Validate").''; + } + } + } - // Clone - if ($permissiontoadd) - { - print ''.$langs->trans("ToClone").''; - } + // Clone + if ($permissiontoadd) + { + print ''.$langs->trans("ToClone").''; + } - // Cancel - Reopen - if ($permissiontoadd) - { - if ($object->status == $object::STATUS_VALIDATED || $object->status == $object::STATUS_INPROGRESS) - { - $arrayproduced = $object->fetchLinesLinked('produced', 0); - $nbProduced = 0; - foreach ($arrayproduced as $lineproduced) { - $nbProduced += $lineproduced['qty']; - } - if ($nbProduced > 0) { // If production has started, we can close it - print ''.$langs->trans("Close").''."\n"; - } else { - print 'transnoentitiesnoconv("Production")).'">'.$langs->trans("Close").''."\n"; - } + // Cancel - Reopen + if ($permissiontoadd) + { + if ($object->status == $object::STATUS_VALIDATED || $object->status == $object::STATUS_INPROGRESS) + { + $arrayproduced = $object->fetchLinesLinked('produced', 0); + $nbProduced = 0; + foreach ($arrayproduced as $lineproduced) { + $nbProduced += $lineproduced['qty']; + } + if ($nbProduced > 0) { // If production has started, we can close it + print ''.$langs->trans("Close").''."\n"; + } else { + print 'transnoentitiesnoconv("Production")).'">'.$langs->trans("Close").''."\n"; + } - print ''.$langs->trans("Cancel").''."\n"; - } + print ''.$langs->trans("Cancel").''."\n"; + } - if ($object->status == $object::STATUS_PRODUCED || $object->status == $object::STATUS_CANCELED) - { - print ''.$langs->trans("ReOpen").''."\n"; - } - } + if ($object->status == $object::STATUS_PRODUCED || $object->status == $object::STATUS_CANCELED) + { + print ''.$langs->trans("ReOpen").''."\n"; + } + } - // Delete (need delete permission, or if draft, just need create/modify permission) - if ($permissiontodelete || ($object->status == $object::STATUS_DRAFT && $permissiontoadd)) - { - print ''.$langs->trans('Delete').''."\n"; - } else { - print ''.$langs->trans('Delete').''."\n"; - } - } - print '
'."\n"; + // Delete (need delete permission, or if draft, just need create/modify permission) + if ($permissiontodelete || ($object->status == $object::STATUS_DRAFT && $permissiontoadd)) + { + print ''.$langs->trans('Delete').''."\n"; + } else { + print ''.$langs->trans('Delete').''."\n"; + } + } + print '
'."\n"; } @@ -672,37 +672,37 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if ($action != 'presend') { - print '
'; - print ''; // ancre + print '
'; + print ''; // ancre - // Documents - $objref = dol_sanitizeFileName($object->ref); - $relativepath = $objref.'/'.$objref.'.pdf'; - $filedir = $conf->mrp->dir_output.'/'.$objref; - $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; - $genallowed = $user->rights->mrp->read; // If you can read, you can build the PDF to read content - $delallowed = $user->rights->mrp->create; // If you can create/edit, you can remove a file on card - print $formfile->showdocuments('mrp:mo', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $mysoc->default_lang); + // Documents + $objref = dol_sanitizeFileName($object->ref); + $relativepath = $objref.'/'.$objref.'.pdf'; + $filedir = $conf->mrp->dir_output.'/'.$objref; + $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; + $genallowed = $user->rights->mrp->read; // If you can read, you can build the PDF to read content + $delallowed = $user->rights->mrp->create; // If you can create/edit, you can remove a file on card + print $formfile->showdocuments('mrp:mo', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $mysoc->default_lang); - // Show links to link elements - $linktoelem = $form->showLinkToObjectBlock($object, null, array('mo')); - $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + // Show links to link elements + $linktoelem = $form->showLinkToObjectBlock($object, null, array('mo')); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); - print '
'; + print '
'; - $MAXEVENT = 10; + $MAXEVENT = 10; - $morehtmlright = ''; - $morehtmlright .= $langs->trans("SeeAll"); - $morehtmlright .= ''; + $morehtmlright = ''; + $morehtmlright .= $langs->trans("SeeAll"); + $morehtmlright .= ''; - // List of actions on element - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; - $formactions = new FormActions($db); - $somethingshown = $formactions->showactions($object, 'mo', $socid, 1, '', $MAXEVENT, '', $morehtmlright); + // List of actions on element + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, 'mo', $socid, 1, '', $MAXEVENT, '', $morehtmlright); - print '
'; + print '
'; } //Select mail models is same action as presend diff --git a/htdocs/product/admin/dynamic_prices.php b/htdocs/product/admin/dynamic_prices.php index aafc36ca256..bdd86169466 100644 --- a/htdocs/product/admin/dynamic_prices.php +++ b/htdocs/product/admin/dynamic_prices.php @@ -42,17 +42,17 @@ if (!$user->admin) accessforbidden(); //Objects $price_globals = new PriceGlobalVariable($db); if ($action == 'edit_variable') { - $res = $price_globals->fetch($selection); - if ($res < 1) { - setEventMessages($price_globals->error, $price_globals->errors, 'errors'); - } + $res = $price_globals->fetch($selection); + if ($res < 1) { + setEventMessages($price_globals->error, $price_globals->errors, 'errors'); + } } $price_updaters = new PriceGlobalVariableUpdater($db); if ($action == 'edit_updater') { - $res = $price_updaters->fetch($selection); - if ($res < 1) { - setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); - } + $res = $price_updaters->fetch($selection); + if ($res < 1) { + setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); + } } @@ -61,84 +61,84 @@ if ($action == 'edit_updater') { */ if (!empty($action) && empty($cancel)) { - //Global variable actions - if ($action == 'create_variable' || $action == 'edit_variable') { - $price_globals->code = GETPOSTISSET('code') ?GETPOST('code', 'alpha') : $price_globals->code; - $price_globals->description = GETPOSTISSET('description') ?GETPOST('description', 'restricthtml') : $price_globals->description; - $price_globals->value = GETPOSTISSET('value') ?GETPOST('value', 'int') : $price_globals->value; - //Check if record already exists only when saving - if (!empty($save)) { - foreach ($price_globals->listGlobalVariables() as $entry) { - if ($price_globals->id != $entry->id && dol_strtolower($price_globals->code) == dol_strtolower($entry->code)) { - setEventMessages($langs->trans("ErrorRecordAlreadyExists"), null, 'errors'); - $save = null; - } - } - } - } - if ($action == 'create_variable' && !empty($save)) { - $res = $price_globals->create($user); - if ($res > 0) { - $action = ''; - } else { - setEventMessages($price_globals->error, $price_globals->errors, 'errors'); - } - } elseif ($action == 'edit_variable' && !empty($save)) { - $res = $price_globals->update($user); - if ($res > 0) { - $action = ''; - } else { - setEventMessages($price_globals->error, $price_globals->errors, 'errors'); - } - } elseif ($action == 'delete_variable') { - $res = $price_globals->delete($selection, $user); - if ($res > 0) { - $action = ''; - } else { - setEventMessages($price_globals->error, $price_globals->errors, 'errors'); - } - } + //Global variable actions + if ($action == 'create_variable' || $action == 'edit_variable') { + $price_globals->code = GETPOSTISSET('code') ?GETPOST('code', 'alpha') : $price_globals->code; + $price_globals->description = GETPOSTISSET('description') ?GETPOST('description', 'restricthtml') : $price_globals->description; + $price_globals->value = GETPOSTISSET('value') ?GETPOST('value', 'int') : $price_globals->value; + //Check if record already exists only when saving + if (!empty($save)) { + foreach ($price_globals->listGlobalVariables() as $entry) { + if ($price_globals->id != $entry->id && dol_strtolower($price_globals->code) == dol_strtolower($entry->code)) { + setEventMessages($langs->trans("ErrorRecordAlreadyExists"), null, 'errors'); + $save = null; + } + } + } + } + if ($action == 'create_variable' && !empty($save)) { + $res = $price_globals->create($user); + if ($res > 0) { + $action = ''; + } else { + setEventMessages($price_globals->error, $price_globals->errors, 'errors'); + } + } elseif ($action == 'edit_variable' && !empty($save)) { + $res = $price_globals->update($user); + if ($res > 0) { + $action = ''; + } else { + setEventMessages($price_globals->error, $price_globals->errors, 'errors'); + } + } elseif ($action == 'delete_variable') { + $res = $price_globals->delete($selection, $user); + if ($res > 0) { + $action = ''; + } else { + setEventMessages($price_globals->error, $price_globals->errors, 'errors'); + } + } - //Updaters actions - if ($action == 'create_updater' || $action == 'edit_updater') { - $price_updaters->type = GETPOSTISSET('type') ? GETPOST('type', 'int') : $price_updaters->type; - $price_updaters->description = GETPOSTISSET('description') ? GETPOST('description', 'restricthtml') : $price_updaters->description; - $price_updaters->parameters = GETPOSTISSET('parameters') ? GETPOST('parameters', 'alphanohtml') : $price_updaters->parameters; - $price_updaters->fk_variable = GETPOSTISSET('fk_variable') ? GETPOST('fk_variable', 'int') : $price_updaters->fk_variable; - $price_updaters->update_interval = GETPOSTISSET('update_interval') ? GETPOST('update_interval', 'int') : $price_updaters->update_interval; - } - if ($action == 'create_updater' && !empty($save)) { - //Verify if process() works - $res = $price_updaters->process(); - if ($res > 0) { - $res = $price_updaters->create($user); - } - if ($res > 0) { - $action = ''; - } else { - setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); - } - } elseif ($action == 'edit_updater' && !empty($save)) { - //Verify if process() works - $res = $price_updaters->process(); - if ($res > 0) { - $res = $price_updaters->update($user); - } - if ($res > 0) { - $action = ''; - } else { - setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); - } - } elseif ($action == 'delete_updater') { - $res = $price_updaters->delete($selection, $user); - if ($res > 0) { - $action = ''; - } else { - setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); - } - } + //Updaters actions + if ($action == 'create_updater' || $action == 'edit_updater') { + $price_updaters->type = GETPOSTISSET('type') ? GETPOST('type', 'int') : $price_updaters->type; + $price_updaters->description = GETPOSTISSET('description') ? GETPOST('description', 'restricthtml') : $price_updaters->description; + $price_updaters->parameters = GETPOSTISSET('parameters') ? GETPOST('parameters', 'alphanohtml') : $price_updaters->parameters; + $price_updaters->fk_variable = GETPOSTISSET('fk_variable') ? GETPOST('fk_variable', 'int') : $price_updaters->fk_variable; + $price_updaters->update_interval = GETPOSTISSET('update_interval') ? GETPOST('update_interval', 'int') : $price_updaters->update_interval; + } + if ($action == 'create_updater' && !empty($save)) { + //Verify if process() works + $res = $price_updaters->process(); + if ($res > 0) { + $res = $price_updaters->create($user); + } + if ($res > 0) { + $action = ''; + } else { + setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); + } + } elseif ($action == 'edit_updater' && !empty($save)) { + //Verify if process() works + $res = $price_updaters->process(); + if ($res > 0) { + $res = $price_updaters->update($user); + } + if ($res > 0) { + $action = ''; + } else { + setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); + } + } elseif ($action == 'delete_updater') { + $res = $price_updaters->delete($selection, $user); + if ($res > 0) { + $action = ''; + } else { + setEventMessages($price_updaters->error, $price_updaters->errors, 'errors'); + } + } } elseif (!empty($cancel)) { - $action = ''; + $action = ''; } @@ -159,171 +159,171 @@ print '
'; //Global variables table if ($action != 'create_updater' && $action != 'edit_updater') { - print load_fiche_titre($langs->trans("GlobalVariables"), '', ''); + print load_fiche_titre($langs->trans("GlobalVariables"), '', ''); - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; //Space for buttons - print ''; + print '
'.$langs->trans("Variable").''.$langs->trans("Description").''.$langs->trans("Value").' 
'; + print ''; + print ''; + print ''; + print ''; + print ''; //Space for buttons + print ''; - $arrayglobalvars = $price_globals->listGlobalVariables(); - if (!empty($arrayglobalvars)) - { - foreach ($arrayglobalvars as $i=>$entry) { - $var = !$var; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - } - } else { - print ''; - } - print '
'.$langs->trans("Variable").''.$langs->trans("Description").''.$langs->trans("Value").' 
'.$entry->code.''.$entry->description.''.price($entry->value).'id.'">'.img_edit().'  '; - print 'id.'">'.img_delete().'
'; - print $langs->trans("None"); - print '
'; + $arrayglobalvars = $price_globals->listGlobalVariables(); + if (!empty($arrayglobalvars)) + { + foreach ($arrayglobalvars as $i=>$entry) { + $var = !$var; + print ''; + print ''.$entry->code.''; + print ''.$entry->description.''; + print ''.price($entry->value).''; + print 'id.'">'.img_edit().'  '; + print 'id.'">'.img_delete().''; + print ''; + } + } else { + print ''; + print $langs->trans("None"); + print ''; + } + print ''; - if (empty($action)) - { - //Action Buttons - print '
'; - print ''.$langs->trans("AddVariable").''; - print '
'; - //Separator is only need for updaters table is showed after buttons - print '

'; - } + if (empty($action)) + { + //Action Buttons + print '
'; + print ''.$langs->trans("AddVariable").''; + print '
'; + //Separator is only need for updaters table is showed after buttons + print '

'; + } } //Global variable editor if ($action == 'create_variable' || $action == 'edit_variable') { - //Form - print '
'; - print ''; - print ''; - print ''; + //Form + print ''; + print ''; + print ''; + print ''; - //Table - print '
'; - //Code - print ''; - print ''; - print ''; - print ''; - //Description - print ''; - print ''; - print ''; - print ''; - //Value - print ''; - print ''; - print ''; - print ''; - print '
'.$langs->trans("Variable").'
'.$langs->trans("Description").'
'.$langs->trans("Value").'
'; + //Table + print '
'; + //Code + print ''; + print ''; + print ''; + print ''; + //Description + print ''; + print ''; + print ''; + print ''; + //Value + print ''; + print ''; + print ''; + print ''; + print '
'.$langs->trans("Variable").'
'.$langs->trans("Description").'
'.$langs->trans("Value").'
'; - //Form Buttons - print '
'; - print '  '; - print ''; - print '
'; - print '
'; + //Form Buttons + print '
'; + print '  '; + print ''; + print '
'; + print ''; } // Updaters table if ($action != 'create_variable' && $action != 'edit_variable') { - print load_fiche_titre($langs->trans("GlobalVariableUpdaters"), '', ''); + print load_fiche_titre($langs->trans("GlobalVariableUpdaters"), '', ''); - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; //Space for buttons - print ''; + print '
'.$langs->trans("VariableToUpdate").''.$langs->trans("Description").''.$langs->trans("Type").''.$langs->trans("Parameters").''.$langs->trans("UpdateInterval").''.$langs->trans("LastUpdated").' 
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; //Space for buttons + print ''; - $arraypriceupdaters = $price_updaters->listUpdaters(); - if (!empty($arraypriceupdaters)) - { - foreach ($arraypriceupdaters as $i=>$entry) { - $code = ""; - if ($entry->fk_variable > 0) { - $res = $price_globals->fetch($entry->fk_variable); - if ($res > 0) { - $code = $price_globals->code; - } - } - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - } - } else { - print ''; - } - print '
'.$langs->trans("VariableToUpdate").''.$langs->trans("Description").''.$langs->trans("Type").''.$langs->trans("Parameters").''.$langs->trans("UpdateInterval").''.$langs->trans("LastUpdated").' 
'.$code.''.$entry->description.''.$langs->trans("GlobalVariableUpdaterType".$entry->type).''.$entry->parameters.''.$entry->update_interval.''.$entry->getLastUpdated().'id.'">'.img_edit().'  '; - print 'id.'">'.img_delete().'
'; - print $langs->trans("None"); - print '
'; + $arraypriceupdaters = $price_updaters->listUpdaters(); + if (!empty($arraypriceupdaters)) + { + foreach ($arraypriceupdaters as $i=>$entry) { + $code = ""; + if ($entry->fk_variable > 0) { + $res = $price_globals->fetch($entry->fk_variable); + if ($res > 0) { + $code = $price_globals->code; + } + } + print ''; + print ''.$code.''; + print ''.$entry->description.''; + print ''.$langs->trans("GlobalVariableUpdaterType".$entry->type).''; + print ''.$entry->parameters.''; + print ''.$entry->update_interval.''; + print ''.$entry->getLastUpdated().''; + print 'id.'">'.img_edit().'  '; + print 'id.'">'.img_delete().''; + print ''; + } + } else { + print ''; + print $langs->trans("None"); + print ''; + } + print ''; - if (empty($action)) - { - //Action Buttons - print '
'; - print ''.$langs->trans("AddUpdater").''; - print '
'; - } + if (empty($action)) + { + //Action Buttons + print '
'; + print ''.$langs->trans("AddUpdater").''; + print '
'; + } } //Updater editor if ($action == 'create_updater' || $action == 'edit_updater') { - //Form - print '
'; - print ''; - print ''; - print ''; + //Form + print ''; + print ''; + print ''; + print ''; - //Table - print '
'; - //Code - print ''; - print ''; - //Description - print ''; - print ''; - print ''; - print ''; - //Type - print ''; - print ''; - //Parameters - print ''; - $help = $langs->trans("GlobalVariableUpdaterHelp".$type).'
'.$langs->trans("GlobalVariableUpdaterHelpFormat".$type).''; - print ''; - print ''; - //Interval - print ''; - print ''; - print ''; - print ''; - print '
'.$langs->trans("VariableToUpdate").''; - $globals_list = array(); - foreach ($price_globals->listGlobalVariables() as $entry) { - $globals_list[$entry->id] = $entry->code; - } - print $form->selectarray('fk_variable', $globals_list, (empty($price_updaters->fk_variable) ? 0 : $price_updaters->fk_variable)); - print '
'.$langs->trans("Description").'
'.$langs->trans("Type").''; - $type = empty($price_updaters->type) ? 0 : $price_updaters->type; - $type_list = array(); - foreach ($price_updaters->types as $val) { - $type_list[$val] = $langs->trans("GlobalVariableUpdaterType".$val); - } - print $form->selectarray('type', $type_list, $type); - // This code submits form when type is changed - print ''; - print '
'.$form->textwithpicto($langs->trans("Parameters"), $help, 1).''; - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor = new DolEditor('parameters', empty($price_updaters->parameters) ? '' : $price_updaters->parameters, '', 300, '', '', false, false, false, ROWS_8, '90%'); - $doleditor->Create(); - print '
'.$langs->trans("UpdateInterval").'
'; + print ''; + //Parameters + print ''; + $help = $langs->trans("GlobalVariableUpdaterHelp".$type).'
'.$langs->trans("GlobalVariableUpdaterHelpFormat".$type).''; + print ''.$form->textwithpicto($langs->trans("Parameters"), $help, 1).''; + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor = new DolEditor('parameters', empty($price_updaters->parameters) ? '' : $price_updaters->parameters, '', 300, '', '', false, false, false, ROWS_8, '90%'); + $doleditor->Create(); + print ''; + print ''; + //Interval + print ''; + print ''.$langs->trans("UpdateInterval").''; + print ''; + print ''; + print ''; - //Form Buttons - print '
'; - print '  '; - print ''; - print '
'; - print '
'; + //Form Buttons + print '
'; + print '  '; + print ''; + print '
'; + print ''; } // End of page diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 4970679eb87..e3467e871c8 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -301,8 +301,8 @@ if (empty($reshook)) $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml')); $object->note = $object->note_private; // deprecated $object->customcode = GETPOST('customcode', 'alphanohtml'); - $object->country_id = GETPOST('country_id', 'int'); - $object->state_id = GETPOST('state_id', 'int'); + $object->country_id = GETPOST('country_id', 'int'); + $object->state_id = GETPOST('state_id', 'int'); $object->duration_value = $duration_value; $object->duration_unit = $duration_unit; $object->fk_default_warehouse = GETPOST('fk_default_warehouse'); @@ -965,14 +965,14 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) $linkback = ""; print load_fiche_titre($title, $linkback, $picto); - // We set country_id, country_code and country for the selected country - $object->country_id = GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : null; - if ($object->country_id > 0) - { - $tmparray = getCountry($object->country_id, 'all'); - $object->country_code = $tmparray['code']; - $object->country = $tmparray['label']; - } + // We set country_id, country_code and country for the selected country + $object->country_id = GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : null; + if ($object->country_id > 0) + { + $tmparray = getCountry($object->country_id, 'all'); + $object->country_code = $tmparray['code']; + $object->country = $tmparray['label']; + } dol_fiche_head(''); @@ -1151,26 +1151,26 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) // Origin country print ''.$langs->trans("CountryOrigin").''; print ''; - print img_picto('', 'globe-americas', 'class="paddingrightonly"'); - print $form->select_country((GETPOSTISSET('country_id') ? GETPOST('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth300 widthcentpercentminusx'); - if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + print img_picto('', 'globe-americas', 'class="paddingrightonly"'); + print $form->select_country((GETPOSTISSET('country_id') ? GETPOST('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth300 widthcentpercentminusx'); + if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); print ''; - // State - if (empty($conf->global->PRODUCT_DISABLE_STATE)) - { - if ($conf->browser->layout == 'phone') print ''; - if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && ($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 || $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 2)) - { - print ''.$form->editfieldkey('Region-StateOrigine', 'state_id', '', $object, 0).''; - } else { - print ''.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).''; - } + // State + if (empty($conf->global->PRODUCT_DISABLE_STATE)) + { + if ($conf->browser->layout == 'phone') print ''; + if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && ($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 || $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 2)) + { + print ''.$form->editfieldkey('Region-StateOrigine', 'state_id', '', $object, 0).''; + } else { + print ''.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).''; + } print $formcompany->select_state($object->state_id, $object->country_code); - print ''; - } - print ''; + print ''; + } + print ''; } // Other attributes @@ -1616,7 +1616,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) // State if (empty($conf->global->PRODUCT_DISABLE_STATE)) { - if ($conf->browser->layout == 'phone') print ''; + if ($conf->browser->layout == 'phone') print ''; if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && ($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 || $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 2)) { print ''.$form->editfieldkey('Region-StateOrigine', 'state_id', '', $object, 0).''; @@ -2389,7 +2389,7 @@ if ($action != 'create' && $action != 'edit' && $action != 'delete') $objectref = dol_sanitizeFileName($object->ref); $relativepath = $comref.'/'.$objectref.'.pdf'; if (!empty($conf->product->multidir_output[$object->entity])) { - $filedir = $conf->product->multidir_output[$object->entity].'/'.$objectref; //Check repertories of current entities + $filedir = $conf->product->multidir_output[$object->entity].'/'.$objectref; //Check repertories of current entities } else { $filedir = $conf->product->dir_output.'/'.$objectref; } diff --git a/htdocs/product/class/productcustomerprice.class.php b/htdocs/product/class/productcustomerprice.class.php index 1553869d1f1..25a3c5cd836 100644 --- a/htdocs/product/class/productcustomerprice.class.php +++ b/htdocs/product/class/productcustomerprice.class.php @@ -368,7 +368,7 @@ class Productcustomerprice extends CommonObject } elseif ($key == 'prod.ref' || $key == 'prod.label') { $sql .= ' AND '.$key.' LIKE \'%'.$this->db->escape($value).'%\''; } elseif ($key == 't.price' || $key == 't.price_ttc') { - $sql .= ' AND ' . $key . ' LIKE \'%' . price2num($value) . '%\''; + $sql .= ' AND '.$key.' LIKE \'%'.price2num($value).'%\''; } else { $sql .= ' AND '.$key.' = '.((int) $value); } diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 847292fa367..c97e22b9166 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -90,94 +90,94 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e if (empty($reshook)) { - if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers - { - $search_soc = ''; - } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers + { + $search_soc = ''; + } - if ($action == 'setlabelsellingprice' && $user->admin) - { - require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; - $keyforlabel = 'PRODUIT_MULTIPRICES_LABEL'.GETPOST('pricelevel'); - dolibarr_set_const($db, $keyforlabel, GETPOST('labelsellingprice', 'alpha'), 'chaine', 0, '', $conf->entity); - $action = ''; - } + if ($action == 'setlabelsellingprice' && $user->admin) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; + $keyforlabel = 'PRODUIT_MULTIPRICES_LABEL'.GETPOST('pricelevel'); + dolibarr_set_const($db, $keyforlabel, GETPOST('labelsellingprice', 'alpha'), 'chaine', 0, '', $conf->entity); + $action = ''; + } if (($action == 'update_vat') && !$cancel && ($user->rights->produit->creer || $user->rights->service->creer)) { - $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)' + $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)' - // We must define tva_tx, npr and local taxes - $tva_tx = $tva_tx_txt; - $vatratecode = ''; - if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) - { - $vat_src_code = $reg[1]; - $tva_tx = preg_replace('/\s*\(.*\)/', '', $tva_tx_txt); // Remove code into vatrate. - } + // We must define tva_tx, npr and local taxes + $tva_tx = $tva_tx_txt; + $vatratecode = ''; + if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) + { + $vat_src_code = $reg[1]; + $tva_tx = preg_replace('/\s*\(.*\)/', '', $tva_tx_txt); // Remove code into vatrate. + } - $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot - $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0; - $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0'; - // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes - if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) - { - // We look into database using code (we can't use get_localtax() because it depends on buyer that is not known). Same in create product. - $vatratecode = $reg[1]; - // Get record from code - $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; - $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; - $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1"; - $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; - $resql = $db->query($sql); - if ($resql) - { - $obj = $db->fetch_object($resql); - $npr = $obj->recuperableonly; - $localtax1 = $obj->localtax1; - $localtax2 = $obj->localtax2; - $localtax1_type = $obj->localtax1_type; - $localtax2_type = $obj->localtax2_type; - } - } + $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot + $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0; + $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0'; + // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes + if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) + { + // We look into database using code (we can't use get_localtax() because it depends on buyer that is not known). Same in create product. + $vatratecode = $reg[1]; + // Get record from code + $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; + $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1"; + $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; + $resql = $db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + $npr = $obj->recuperableonly; + $localtax1 = $obj->localtax1; + $localtax2 = $obj->localtax2; + $localtax1_type = $obj->localtax1_type; + $localtax2_type = $obj->localtax2_type; + } + } - $object->default_vat_code = $vatratecode; - $object->tva_tx = $tva_tx; - $object->tva_npr = $npr; - $object->localtax1_tx = $localtax1; - $object->localtax2_tx = $localtax2; - $object->localtax1_type = $localtax1_type; - $object->localtax2_type = $localtax2_type; + $object->default_vat_code = $vatratecode; + $object->tva_tx = $tva_tx; + $object->tva_npr = $npr; + $object->localtax1_tx = $localtax1; + $object->localtax2_tx = $localtax2; + $object->localtax1_type = $localtax1_type; + $object->localtax2_type = $localtax2_type; - $db->begin(); + $db->begin(); - $resql = $object->update($object->id, $user); - if ($resql <= 0) - { - $error++; - setEventMessages($object->error, $object->errors, 'errors'); - } + $resql = $object->update($object->id, $user); + if ($resql <= 0) + { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + } - if ($error) - { - //$localtaxarray=array('0'=>$localtax1_type,'1'=>$localtax1,'2'=>$localtax2_type,'3'=>$localtax2); - $localtaxarray = array(); // We do not store localtaxes into product, we will use instead the "vat code" to retreive them. - $object->updatePrice(0, $object->price_base_type, $user, $tva_tx, '', 0, $npr, 0, 0, $localtaxarray, $vatratecode); - } + if ($error) + { + //$localtaxarray=array('0'=>$localtax1_type,'1'=>$localtax1,'2'=>$localtax2_type,'3'=>$localtax2); + $localtaxarray = array(); // We do not store localtaxes into product, we will use instead the "vat code" to retreive them. + $object->updatePrice(0, $object->price_base_type, $user, $tva_tx, '', 0, $npr, 0, 0, $localtaxarray, $vatratecode); + } - if (!$error) - { - $db->commit(); - } else { - $db->rollback(); - } + if (!$error) + { + $db->commit(); + } else { + $db->rollback(); + } - $action = ''; + $action = ''; } if (($action == 'update_price') && !$cancel && $object->getRights()->creer) - { + { $error = 0; $pricestoupdate = array(); @@ -231,41 +231,41 @@ if (empty($reshook)) } $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot - $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0; + $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0; $localtax1 = $newlocaltax1_tx[$i]; $localtax1_type = $newlocaltax1_type[$i]; $localtax2 = $newlocaltax2_tx[$i]; $localtax2_type = $newlocaltax2_type[$i]; - if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) - { - // We look into database using code - $vatratecode = $reg[1]; - // Get record from code - $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; - $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; - $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1"; - $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; - $resql = $db->query($sql); - if ($resql) - { - $obj = $db->fetch_object($resql); - $npr = $obj->recuperableonly; - $localtax1 = $obj->localtax1; - $localtax2 = $obj->localtax2; - $localtax1_type = $obj->localtax1_type; - $localtax2_type = $obj->localtax2_type; - } - } + if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) + { + // We look into database using code + $vatratecode = $reg[1]; + // Get record from code + $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; + $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1"; + $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; + $resql = $db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + $npr = $obj->recuperableonly; + $localtax1 = $obj->localtax1; + $localtax2 = $obj->localtax2; + $localtax1_type = $obj->localtax1_type; + $localtax2_type = $obj->localtax2_type; + } + } $pricestoupdate[$i] = array( 'price' => $newprice[$i], 'price_min' => $newprice_min[$i], 'price_base_type' => $newpricebase[$i], - 'default_vat_code' => $vatratecode, + 'default_vat_code' => $vatratecode, 'vat_tx' => $tva_tx, // default_vat_code should be used in priority in a future 'npr' => $npr, // default_vat_code should be used in priority in a future - 'localtaxes_array' => array('0'=>$localtax1_type, '1'=>$localtax1, '2'=>$localtax2_type, '3'=>$localtax2) // default_vat_code should be used in priority in a future + 'localtaxes_array' => array('0'=>$localtax1_type, '1'=>$localtax1, '2'=>$localtax2_type, '3'=>$localtax2) // default_vat_code should be used in priority in a future ); //If autogeneration is enabled, then we only set the first level @@ -286,45 +286,45 @@ if (empty($reshook)) } $tva_tx = price2num(preg_replace('/\*/', '', $tva_tx)); // keep remove all after the numbers and dot - $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0; - $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0'; - // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes - if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) - { - // We look into database using code - $vatratecode = $reg[1]; - // Get record from code - $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; - $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; - $sql .= " AND t.taux = ".$tva_tx." AND t.active = 1"; - $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; - $resql = $db->query($sql); - if ($resql) - { - $obj = $db->fetch_object($resql); - $npr = $obj->recuperableonly; - $localtax1 = $obj->localtax1; - $localtax2 = $obj->localtax2; - $localtax1_type = $obj->localtax1_type; - $localtax2_type = $obj->localtax2_type; + $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0; + $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0'; + // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes + if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) + { + // We look into database using code + $vatratecode = $reg[1]; + // Get record from code + $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; + $sql .= " AND t.taux = ".$tva_tx." AND t.active = 1"; + $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; + $resql = $db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + $npr = $obj->recuperableonly; + $localtax1 = $obj->localtax1; + $localtax2 = $obj->localtax2; + $localtax1_type = $obj->localtax1_type; + $localtax2_type = $obj->localtax2_type; - // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule - if (in_array($mysoc->country_code, array('ES'))) - { - $localtax1 = get_localtax($tva_tx, 1); - $localtax2 = get_localtax($tva_tx, 2); - } - } - } + // If spain, we don't use the localtax found into tax record in database with same code, but using the get_localtax rule + if (in_array($mysoc->country_code, array('ES'))) + { + $localtax1 = get_localtax($tva_tx, 1); + $localtax2 = get_localtax($tva_tx, 2); + } + } + } $pricestoupdate[0] = array( 'price' => $_POST["price"], 'price_min' => $_POST["price_min"], 'price_base_type' => $_POST["price_base_type"], - 'default_vat_code' => $vatratecode, + 'default_vat_code' => $vatratecode, 'vat_tx' => $tva_tx, // default_vat_code should be used in priority in a future 'npr' => $npr, // default_vat_code should be used in priority in a future - 'localtaxes_array' => array('0'=>$localtax1_type, '1'=>$localtax1, '2'=>$localtax2_type, '3'=>$localtax2) // default_vat_code should be used in priority in a future + 'localtaxes_array' => array('0'=>$localtax1_type, '1'=>$localtax1, '2'=>$localtax2_type, '3'=>$localtax2) // default_vat_code should be used in priority in a future ); } @@ -348,7 +348,7 @@ if (empty($reshook)) } if ($object->multiprices[$key] != $newprice || $object->multiprices_min[$key] != $newprice_min || $object->multiprices_base_type[$key] != $val['price_base_type']) - $res = $object->updatePrice($newprice, $val['price_base_type'], $user, $val['vat_tx'], $newprice_min, $key, $val['npr'], $psq, 0, $val['localtaxes_array'], $val['default_vat_code']); + $res = $object->updatePrice($newprice, $val['price_base_type'], $user, $val['vat_tx'], $newprice_min, $key, $val['npr'], $psq, 0, $val['localtaxes_array'], $val['default_vat_code']); else $res = 0; @@ -520,24 +520,24 @@ if (empty($reshook)) // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) { - // We look into database using code - $vatratecode = $reg[1]; - // Get record from code - $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; - $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; - $sql .= " AND t.taux = ".$tva_tx." AND t.active = 1"; - $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; - $resql = $db->query($sql); - if ($resql) - { - $obj = $db->fetch_object($resql); - $npr = $obj->recuperableonly; - $localtax1 = $obj->localtax1; - $localtax2 = $obj->localtax2; - $localtax1_type = $obj->localtax1_type; - $localtax2_type = $obj->localtax2_type; - } + // We look into database using code + $vatratecode = $reg[1]; + // Get record from code + $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; + $sql .= " AND t.taux = ".$tva_tx." AND t.active = 1"; + $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; + $resql = $db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + $npr = $obj->recuperableonly; + $localtax1 = $obj->localtax1; + $localtax2 = $obj->localtax2; + $localtax1_type = $obj->localtax1_type; + $localtax2_type = $obj->localtax2_type; + } } $prodcustprice->default_vat_code = $vatratecode; @@ -550,14 +550,14 @@ if (empty($reshook)) if (!($prodcustprice->fk_soc > 0)) { - $langs->load("errors"); - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors'); - $error++; - $action = 'add_customer_price'; + $langs->load("errors"); + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors'); + $error++; + $action = 'add_customer_price'; } if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE) && $prodcustprice->price_min < $maxpricesupplier) { - $langs->load("errors"); + $langs->load("errors"); setEventMessages($langs->trans("MinimumPriceLimit", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')), null, 'errors'); $error++; $action = 'add_customer_price'; @@ -620,24 +620,24 @@ if (empty($reshook)) // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) { - // We look into database using code - $vatratecode = $reg[1]; - // Get record from code - $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; - $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; - $sql .= " AND t.taux = ".$tva_tx." AND t.active = 1"; - $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; - $resql = $db->query($sql); - if ($resql) - { - $obj = $db->fetch_object($resql); - $npr = $obj->recuperableonly; - $localtax1 = $obj->localtax1; - $localtax2 = $obj->localtax2; - $localtax1_type = $obj->localtax1_type; - $localtax2_type = $obj->localtax2_type; - } + // We look into database using code + $vatratecode = $reg[1]; + // Get record from code + $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'"; + $sql .= " AND t.taux = ".$tva_tx." AND t.active = 1"; + $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; + $resql = $db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + $npr = $obj->recuperableonly; + $localtax1 = $obj->localtax1; + $localtax2 = $obj->localtax2; + $localtax1_type = $obj->localtax1_type; + $localtax2_type = $obj->localtax2_type; + } } $prodcustprice->default_vat_code = $vatratecode; @@ -770,22 +770,22 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ //print vatrate($object->multiprices_tva_tx[$soc->price_level], true); print ''; } else { - // TVA - print ''.$langs->trans("DefaultTaxRate").''; + // TVA + print ''.$langs->trans("DefaultTaxRate").''; - $positiverates = ''; - if (price2num($object->tva_tx)) $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx); - if (price2num($object->localtax1_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx); - if (price2num($object->localtax2_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx); - if (empty($positiverates)) $positiverates = '0'; - echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr); + $positiverates = ''; + if (price2num($object->tva_tx)) $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx); + if (price2num($object->localtax1_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx); + if (price2num($object->localtax2_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx); + if (empty($positiverates)) $positiverates = '0'; + echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr); /* if ($object->default_vat_code) { print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')'; } else print vatrate($object->tva_tx . ($object->tva_npr ? '*' : ''), true);*/ - print ''; + print ''; } } else { if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) // using this option is a bug. kept for backward compatibility @@ -795,28 +795,28 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ print ''.vatrate($object->multiprices_tva_tx[1], true).''; print ''; } else { - // TVA - print ''.$langs->trans("DefaultTaxRate").''; + // TVA + print ''.$langs->trans("DefaultTaxRate").''; - $positiverates = ''; - if (price2num($object->tva_tx)) $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx); - if (price2num($object->localtax1_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx); - if (price2num($object->localtax2_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx); - if (empty($positiverates)) $positiverates = '0'; - echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr); - /* + $positiverates = ''; + if (price2num($object->tva_tx)) $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx); + if (price2num($object->localtax1_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax1_tx); + if (price2num($object->localtax2_type)) $positiverates .= ($positiverates ? '/' : '').price2num($object->localtax2_tx); + if (empty($positiverates)) $positiverates = '0'; + echo vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), '%', $object->tva_npr); + /* if ($object->default_vat_code) { print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')'; } else print vatrate($object->tva_tx . ($object->tva_npr ? '*' : ''), true);*/ - print ''; + print ''; } - print ''; + print ''; - print '
'; + print '
'; - print ''; + print '
'; print ''; @@ -875,7 +875,7 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) // TODO Fix the form included into a tr instead of a td { print ''; + print '   '.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().''; } print ''; print ''; @@ -1282,8 +1282,8 @@ if ($action == 'edit_price' && $object->getRights()->creer) print '
'; } else { - print ''."\n"; - ?> + print ''."\n"; + ?> \n"; -print load_fiche_titre($langs->trans("Backup"), '', 'title_setup'); +$title = $langs->trans("Backup"); + +print load_fiche_titre($title, '', 'title_setup'); //print_barre_liste($langs->trans("Backup"), '', '', '', '', '', $langs->trans("BackupDesc",DOL_DATA_ROOT), 0, 0, 'title_setup'); print '
'; @@ -139,7 +142,9 @@ print '
'; print '
'; -print load_fiche_titre($title ? $title : $langs->trans("BackupDumpWizard")); +$title = $langs->trans("BackupDumpWizard"); + +print load_fiche_titre($title); print '
'; print $langs->trans("PriceLevel"); if ($user->admin) print ' id.'">'.img_edit($langs->trans('EditSellingPriceLabel'), 0).''; @@ -834,17 +834,17 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ $keyforlabel = 'PRODUIT_MULTIPRICES_LABEL'.$i; if (preg_match('/editlabelsellingprice/', $action)) { - print '
'; - print ''; - print ''; - print ''; - print $langs->trans("SellingPrice").' '.$i.' - '; - print ''; - print ' '; - print '
'; + print '
'; + print ''; + print ''; + print ''; + print $langs->trans("SellingPrice").' '.$i.' - '; + print ''; + print ' '; + print '
'; } else { - print $langs->trans("SellingPrice").' '.$i; - if (!empty($conf->global->$keyforlabel)) print ' - '.$langs->trans($conf->global->$keyforlabel); + print $langs->trans("SellingPrice").' '.$i; + if (!empty($conf->global->$keyforlabel)) print ' - '.$langs->trans($conf->global->$keyforlabel); } print '
'.$langs->trans("PriceByQuantity").' '.$i; - if (!empty($conf->global->$keyforlabel)) print ' - '.$langs->trans($conf->global->$keyforlabel); + if (!empty($conf->global->$keyforlabel)) print ' - '.$langs->trans($conf->global->$keyforlabel); print ''; if ($object->prices_by_qty[$i] == 1) { @@ -1102,7 +1102,7 @@ if (!$action || $action == 'delete' || $action == 'showlog_customer_price' || $a { print "\n".'
'."\n"; - if ($object->isVariant()) { + if ($object->isVariant()) { if ($user->rights->produit->creer || $user->rights->service->creer) { print ''; } @@ -1128,7 +1128,7 @@ if (!$action || $action == 'delete' || $action == 'showlog_customer_price' || $a print ''; } } - } + } print "\n
\n"; } @@ -1176,7 +1176,7 @@ if ($action == 'edit_price' && $object->getRights()->creer) if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { - print ''."\n"; + print ''."\n"; print '
'; print ''; print ''; @@ -1262,7 +1262,7 @@ if ($action == 'edit_price' && $object->getRights()->creer) } if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) { - print '   '.$langs->trans("MinimumRecommendedPrice", price($maxpricesupplier, 0, '', 1, -1, -1, 'auto')).' '.img_warning().'
'; print ''; diff --git a/htdocs/admin/tools/export.php b/htdocs/admin/tools/export.php index cbe25f0ff75..7ab26f6f6e0 100644 --- a/htdocs/admin/tools/export.php +++ b/htdocs/admin/tools/export.php @@ -122,7 +122,7 @@ $utils = new Utils($db); // MYSQL if ($what == 'mysql') { - $cmddump = GETPOST("mysqldump"); // Do not sanitize here with 'alpha', will be sanitize later by dol_sanitizePathName and escapeshellarg + $cmddump = GETPOST("mysqldump", 'none'); // Do not sanitize here with 'alpha', will be sanitize later by dol_sanitizePathName and escapeshellarg $cmddump = dol_sanitizePathName($cmddump); if (!empty($dolibarr_main_restrict_os_commands)) @@ -163,7 +163,7 @@ if ($what == 'mysqlnobin') // POSTGRESQL if ($what == 'postgresql') { - $cmddump = GETPOST("postgresqldump"); // Do not sanitize here with 'alpha', will be sanitize later by dol_sanitizePathName and escapeshellarg + $cmddump = GETPOST("postgresqldump", 'none'); // Do not sanitize here with 'alpha', will be sanitize later by dol_sanitizePathName and escapeshellarg $cmddump = dol_sanitizePathName($cmddump); /* Not required, the command is output on screen but not ran for pgsql diff --git a/htdocs/admin/tools/export_files.php b/htdocs/admin/tools/export_files.php index 485df8c318b..50866534b5b 100644 --- a/htdocs/admin/tools/export_files.php +++ b/htdocs/admin/tools/export_files.php @@ -113,7 +113,7 @@ $utils = new Utils($db); if ($compression == 'zip') { $file .= '.zip'; - $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression, '/(\.log|\/temp\/|documents\/admin\/documents\/)/'); + $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression, '/(\.log|\/temp\/|documents\/admin\/documents\/)/i'); if ($ret < 0) { if ($ret == -2) { diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 61856b73f49..e2c4b605dcc 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -221,25 +221,25 @@ if (!empty($_POST["DOL_AUTOSET_COOKIE"])) } -// Init session. Name of session is specific to Dolibarr instance. -// Note: the function dol_getprefix may have been redefined to return a different key to manage another area to protect. -$prefix = dol_getprefix(''); +// Init the 5 global objects, this include will make the 'new Xxx()' and set properties for: $conf, $db, $langs, $user, $mysoc +require_once 'master.inc.php'; +// Init session. Name of session is specific to Dolibarr instance. +// Must be done after the include of master.inc.php so $conf file is loaded and vars like $dolibarr_main_force_https are set. +// Note: the function dol_getprefix may have been redefined to return a different key to manage another area to protect. +$prefix = dol_getprefix(''); // This uses the $conf file $sessionname = 'DOLSESSID_'.$prefix; $sessiontimeout = 'DOLSESSTIMEOUT_'.$prefix; if (!empty($_COOKIE[$sessiontimeout])) ini_set('session.gc_maxlifetime', $_COOKIE[$sessiontimeout]); session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie (same as setting session.cookie_httponly into php.ini). Must be called before the session_start. session_name($sessionname); -// This create lock, released when session_write_close() or end of page. +// This create lock, released by session_write_close() or end of page. // We need this lock as long as we read/write $_SESSION ['vars']. We can remove lock when finished. if (!defined('NOSESSION')) { session_start(); } -// Init the 5 global objects, this include will make the 'new Xxx()' and set properties for: $conf, $db, $langs, $user, $mysoc -require_once 'master.inc.php'; - // Activate end of page function register_shutdown_function('dol_shutdown'); From 920b31140ba7e4f4e3fd1f0e9824f9c3a4cfd5d3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 11 Oct 2020 13:32:50 +0200 Subject: [PATCH 177/317] Fix exclude of backup files when path are for Windows --- htdocs/admin/tools/export_files.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/tools/export_files.php b/htdocs/admin/tools/export_files.php index 50866534b5b..28eaa2d9d54 100644 --- a/htdocs/admin/tools/export_files.php +++ b/htdocs/admin/tools/export_files.php @@ -113,7 +113,7 @@ $utils = new Utils($db); if ($compression == 'zip') { $file .= '.zip'; - $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression, '/(\.log|\/temp\/|documents\/admin\/documents\/)/i'); + $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression, '/(\.back|\.old|\.log|[\\\/]temp[\\\/]|documents[\\\/]admin[\\\/]documents[\\\/])/i'); if ($ret < 0) { if ($ret == -2) { From 042b3f18434e9f9bd3c619a8e35bee18d9e90440 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 12 Oct 2020 09:42:35 +0200 Subject: [PATCH 178/317] fix donation payment with autocomplete --- htdocs/don/payment/payment.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/htdocs/don/payment/payment.php b/htdocs/don/payment/payment.php index 3983765d904..1a50677f51a 100644 --- a/htdocs/don/payment/payment.php +++ b/htdocs/don/payment/payment.php @@ -177,6 +177,19 @@ if ($action == 'create') print load_fiche_titre($langs->trans("DoPayment")); + if (!empty($conf->use_javascript_ajax)) + { + print "\n".''."\n"; + } + print '
'; print ''; print ''; @@ -257,6 +270,8 @@ if ($action == 'create') if ($sumpaid < $objp->amount) { $namef = "amount_".$objp->id; + if (!empty($conf->use_javascript_ajax)) + print img_picto("Auto fill", 'rightarrow', "class='AutoFillAmout' data-rowname='".$namef."' data-value='".price($objp->amount - $sumpaid)."'"); print ''; } else { print '-'; From 873cf24641d8db39a8916dea9602931cfb761fad Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 12 Oct 2020 10:39:37 +0200 Subject: [PATCH 179/317] FIX Show accounting account in supplier invoice when line is binded --- htdocs/fourn/class/fournisseur.facture.class.php | 5 ++++- htdocs/fourn/facture/card.php | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 264832cadc2..589c4e82fc9 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -38,6 +38,9 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php'; require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +if (!empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; +if (!empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; + /** * Class to manage suppliers invoices */ @@ -765,7 +768,7 @@ class FactureFournisseur extends CommonInvoice $sql .= ', f.localtax1_tx, f.localtax2_tx, f.localtax1_type, f.localtax2_type, f.total_localtax1, f.total_localtax2, f.fk_facture_fourn '; $sql .= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit'; $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc'; - $sql .= ', fk_code_ventilation, f.fk_multicurrency, f.multicurrency_code, f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc'; + $sql .= ', f.fk_code_ventilation, f.fk_multicurrency, f.multicurrency_code, f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc'; $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid'; $sql .= ' WHERE fk_facture_fourn='.$this->id; diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 029abf36058..4a805d6623c 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -2222,7 +2222,7 @@ if ($action == 'create') $head = facturefourn_prepare_head($object); $titre = $langs->trans('SupplierInvoice'); - dol_fiche_head($head, 'card', $titre, -1, 'bill'); + dol_get_fiche_head($head, 'card', $titre, -1, 'bill'); $formconfirm = ''; From dd7415c937921dc923aadf3189663196ea84688b Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 12 Oct 2020 11:00:04 +0200 Subject: [PATCH 180/317] Revert dol_fiche_head --- htdocs/fourn/facture/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 4a805d6623c..029abf36058 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -2222,7 +2222,7 @@ if ($action == 'create') $head = facturefourn_prepare_head($object); $titre = $langs->trans('SupplierInvoice'); - dol_get_fiche_head($head, 'card', $titre, -1, 'bill'); + dol_fiche_head($head, 'card', $titre, -1, 'bill'); $formconfirm = ''; From df4b208de1a43ce6685b333045ae95acc71fae27 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 12 Oct 2020 11:10:49 +0200 Subject: [PATCH 181/317] fix: add missing edit field with pakaging option on --- .../class/fournisseur.commande.class.php | 2 +- .../fourn/class/fournisseur.product.class.php | 2 +- htdocs/langs/en_US/products.lang | 1 + htdocs/product/fournisseurs.php | 25 +++++++++++++++++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index f354b89186d..300a5032a2c 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -1664,9 +1664,9 @@ class CommandeFournisseur extends CommonOrder { $coeff = intval($qty / $prod->packaging) + 1; $qty = $prod->packaging * $coeff; - setEventMessage($langs->trans('QtyRecalculatedWithPackaging'), 'mesgs'); } } + setEventMessage($langs->trans('QtyRecalculatedWithPackaging'), 'mesgs'); } } else { $product_type = $type; diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php index 8752d17a5d8..924734f69c5 100644 --- a/htdocs/fourn/class/fournisseur.product.class.php +++ b/htdocs/fourn/class/fournisseur.product.class.php @@ -272,7 +272,7 @@ class ProductFournisseur extends Product $charges = price2num($charges, 'MU'); $qty = price2num($qty, 'MS'); $unitBuyPrice = price2num($buyprice / $qty, 'MU'); - $packaging = ($this->packaging < $qty) ? $qty : $this->packaging; + $packaging = price2num((($this->packaging < $qty) ? $qty : $this->packaging), 'MS'); $error = 0; $now = dol_now(); diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index 51f547dbdce..3077021aad6 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -339,6 +339,7 @@ UseProductFournDesc=Add a feature to define the descriptions of products defined ProductSupplierDescription=Vendor description for the product UseProductSupplierPackaging=Use packaging on supplier prices (recalculate quantities according to packaging set on supplier price when adding/updating line in supplier documents) PackagingForThisProduct=Packaging +PackagingForThisProductDesc=On supplier order, you will automaticly order this quantity (or a multiple of this quantity). Cannot be less than minimum buying quantity QtyRecalculatedWithPackaging=The quantity of the line were recalculated according to supplier packaging #Attributes diff --git a/htdocs/product/fournisseurs.php b/htdocs/product/fournisseurs.php index fb1be576ad5..f1b8dd5e455 100644 --- a/htdocs/product/fournisseurs.php +++ b/htdocs/product/fournisseurs.php @@ -230,10 +230,9 @@ if (empty($reshook)) } } + // TODO : may be remove, already done in class update_buyprice if (empty($packaging)) $packaging = 1; - if ($packaging < $quantity) $packaging = $quantity; - $object->packaging = $packaging; if (!$error) @@ -529,6 +528,28 @@ if ($id > 0 || $ref) } print '
'; + if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { + // Packaging + print ''; + + print ''; + print ''; print ''; } diff --git a/htdocs/bom/tpl/objectline_edit.tpl.php b/htdocs/bom/tpl/objectline_edit.tpl.php index 3840f495dea..6954e657db9 100644 --- a/htdocs/bom/tpl/objectline_edit.tpl.php +++ b/htdocs/bom/tpl/objectline_edit.tpl.php @@ -112,7 +112,7 @@ if ($conf->global->PRODUCT_USE_UNITS) { $coldisplay++; print ''; } diff --git a/htdocs/bom/tpl/objectline_view.tpl.php b/htdocs/bom/tpl/objectline_view.tpl.php index 05682dc3da6..ecaf9117aae 100644 --- a/htdocs/bom/tpl/objectline_view.tpl.php +++ b/htdocs/bom/tpl/objectline_view.tpl.php @@ -82,7 +82,7 @@ print ''; if ($conf->global->PRODUCT_USE_UNITS) { print ''; print ''; print ''; @@ -491,6 +491,9 @@ if ($id > 0 || !empty($ref)) $userstatic->firstname = $tab[$i]['firstname']; $userstatic->photo = $tab[$i]['photo']; $userstatic->login = $tab[$i]['login']; + $userstatic->email = $tab[$i]['email']; + $userstatic->statut = $tab[$i]['statucontact']; + print $userstatic->getNomUrl(-1); } if ($tab[$i]['source'] == 'external') @@ -498,6 +501,9 @@ if ($id > 0 || !empty($ref)) $contactstatic->id = $tab[$i]['id']; $contactstatic->lastname = $tab[$i]['lastname']; $contactstatic->firstname = $tab[$i]['firstname']; + $contactstatic->email = $tab[$i]['email']; + $contactstatic->statut = $tab[$i]['statucontact']; + print $contactstatic->getNomUrl(1); } print ''; From a514c201835e4446cdb3a3a7b7f727b919982344 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 12:53:57 +0200 Subject: [PATCH 189/317] Add warning if we try to add a task on a draft project --- htdocs/langs/en_US/errors.lang | 1 + htdocs/projet/ganttview.php | 2 +- htdocs/projet/tasks.php | 13 ++++++++++--- htdocs/theme/eldy/global.inc.php | 7 ++++++- htdocs/theme/md/style.css.php | 7 ++++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index e388c505663..47568f574fa 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -269,6 +269,7 @@ WarningYourLoginWasModifiedPleaseLogin=Your login was modified. For security pur WarningAnEntryAlreadyExistForTransKey=An entry already exists for the translation key for this language WarningNumberOfRecipientIsRestrictedInMassAction=Warning, number of different recipient is limited to %s when using the mass actions on lists WarningDateOfLineMustBeInExpenseReportRange=Warning, the date of line is not in the range of the expense report +WarningProjectDraft=Project is still in draft mode. Don't forget to validate it if you plan to use tasks. WarningProjectClosed=Project is closed. You must re-open it first. WarningSomeBankTransactionByChequeWereRemovedAfter=Some bank transaction were removed after that the receipt including them were generated. So nb of cheques and total of receipt may differ from number and total in list. WarningFailedToAddFileIntoDatabaseIndex=Warning, failed to add file entry into ECM database index table diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index 81b7be12e33..f15e6d4900f 100644 --- a/htdocs/projet/ganttview.php +++ b/htdocs/projet/ganttview.php @@ -239,7 +239,7 @@ $linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt $linktotasks .= dolGetButtonTitle($langs->trans('ViewGantt'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1', '', 1, array('morecss'=>'reposition marginleftonly btnTitleSelected')); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); -print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'generic'); +print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'projecttask'); // Get list of tasks in tasksarray and taskarrayfiltered diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index 522468257e0..1336c870cbe 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -492,13 +492,20 @@ if ($action == 'create' && $user->rights->projet->creer && (empty($object->third print load_fiche_titre($langs->trans("NewTask"), '', 'projecttask'); - if ($object->statut == Project::STATUS_CLOSED) - { + if ($object->statut == Project::STATUS_CLOSED) { print '
'; $langs->load("errors"); print $langs->trans("WarningProjectClosed"); print '
'; } else { + if ($object->statut == Project::STATUS_DRAFT) + { + print '
'; + $langs->load("errors"); + print $langs->trans("WarningProjectDraft"); + print '
'; + } + print ''; print ''; print ''; @@ -636,7 +643,7 @@ if ($action == 'create' && $user->rights->projet->creer && (empty($object->third $linktotasks .= dolGetButtonTitle($langs->trans('ViewGantt'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1', '', 1, array('morecss'=>'reposition marginleftonly')); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); - print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'generic'); + print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'projecttask'); // Get list of tasks in tasksarray and taskarrayfiltered // We need all tasks (even not limited to a user because a task to user can have a parent that is not affected to him). diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index b9519eb50af..85fb40b0e72 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -4987,9 +4987,14 @@ div.scroll2 { width: px !important; } -.gtaskname div, .gtaskname { +div#GanttChartDIVglisthead, div#GanttChartDIVgcharthead { + line-height: 2; +} + +.gtaskname div, .gtaskname, .gstartdate div, .gstartdate, .genddate div, .genddate { font-size: unset !important; } + div.gantt, .gtaskheading, .gmajorheading, .gminorheading, .gminorheadingwkend { font-size: unset !important; font-weight: normal !important; diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index fb05def28da..ecd92c2689c 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -4885,9 +4885,14 @@ div.scroll2 { width: px !important; } -.gtaskname div, .gtaskname { +div#GanttChartDIVglisthead, div#GanttChartDIVgcharthead { + line-height: 2; +} + +.gtaskname div, .gtaskname, .gstartdate div, .gstartdate, .genddate div, .genddate { font-size: unset !important; } + div.gantt, .gtaskheading, .gmajorheading, .gminorheading, .gminorheadingwkend { font-size: unset !important; font-weight: normal !important; From a1dd92239496ae2a02959a85477e40fd779a497a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 13:04:10 +0200 Subject: [PATCH 190/317] Update modProduct.class.php --- htdocs/core/modules/modProduct.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/modules/modProduct.class.php b/htdocs/core/modules/modProduct.class.php index b1a715a4f80..7eef5043c81 100644 --- a/htdocs/core/modules/modProduct.class.php +++ b/htdocs/core/modules/modProduct.class.php @@ -632,7 +632,7 @@ class modProduct extends DolibarrModules 'sp.tva_tx' => 'VATRate', 'sp.default_vat_code' => 'VATCode', 'sp.delivery_time_days' => 'DeliveryDelay', - 'sp.supplier_reputation' => 'SupplierReputation', + 'sp.supplier_reputation' => 'SupplierReputation' ); if (is_object($mysoc) && $usenpr) $this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array('sp.recuperableonly'=>'VATNPR')); if (is_object($mysoc) && $mysoc->useLocalTax(1)) $this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array('sp.localtax1_tx'=>'LT1', 'sp.localtax1_type'=>'LT1Type')); From 3805a7877b9474c123c578659ec579b13300540a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 13:05:18 +0200 Subject: [PATCH 191/317] Update fournisseurs.php --- htdocs/product/fournisseurs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/fournisseurs.php b/htdocs/product/fournisseurs.php index 71ef77213f9..d7bf7c44ae1 100644 --- a/htdocs/product/fournisseurs.php +++ b/htdocs/product/fournisseurs.php @@ -169,7 +169,7 @@ if (empty($reshook)) $supplier_description = GETPOST('supplier_description', 'alpha'); $barcode = GETPOST('barcode', 'alpha'); $fk_barcode_type = GETPOST('fk_barcode_type', 'int'); - $packaging = price2num(GETPOST("packaging", 'nohtml'), 'MS'); + $packaging = price2num(GETPOST("packaging", 'alphanohtml'), 'MS'); if ($tva_tx == '') { From 739de365c030c0aefd40249cb97315599616aa52 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 12 Oct 2020 13:52:50 +0200 Subject: [PATCH 192/317] load stat_bom --- htdocs/core/lib/product.lib.php | 4 +-- htdocs/product/class/product.class.php | 42 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index dfc57313add..2bd0dc1ced2 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -360,13 +360,13 @@ function show_stats_for_company($product, $socid) if (!empty($conf->mrp->enabled) && $user->rights->mrp->read) { $nblines++; - //$ret = $product->load_stats_mo($socid); + $ret = $product->load_stats_mo($socid); if ($ret < 0) dol_print_error($db); $langs->load("orders"); print '
'."\n"; +print_fiche_titre($langs->trans("Parameters").' (DEB)'); + print '
'.$form->textwithpicto($langs->trans("PackagingForThisProduct"), $langs->trans("PackagingForThisProductDesc")).''; + $packaging = GETPOSTISSET('packaging') ? price2num(GETPOST('packaging', 'nohtml'), 'MS') : "1"; + if ($rowid) + { + print ''; + print price2num($object->packaging, 'MS'); + } else { + print ''; + } + // Units + if ($conf->global->PRODUCT_USE_UNITS) { + $unit = $object->getLabelOfUnit(); + if ($unit !== '') { + print '  '.$langs->trans($unit); + } + } + } // Vat rate $default_vat = ''; From cea6eb279f5c69e695c6140972b49e2973b853c6 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 12 Oct 2020 11:26:09 +0200 Subject: [PATCH 182/317] add immport packaging supplier quantity --- htdocs/core/modules/modProduct.class.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/modProduct.class.php b/htdocs/core/modules/modProduct.class.php index e1a1a51160a..b1a715a4f80 100644 --- a/htdocs/core/modules/modProduct.class.php +++ b/htdocs/core/modules/modProduct.class.php @@ -632,7 +632,7 @@ class modProduct extends DolibarrModules 'sp.tva_tx' => 'VATRate', 'sp.default_vat_code' => 'VATCode', 'sp.delivery_time_days' => 'DeliveryDelay', - 'sp.supplier_reputation' => 'SupplierReputation' + 'sp.supplier_reputation' => 'SupplierReputation', ); if (is_object($mysoc) && $usenpr) $this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array('sp.recuperableonly'=>'VATNPR')); if (is_object($mysoc) && $mysoc->useLocalTax(1)) $this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array('sp.localtax1_tx'=>'LT1', 'sp.localtax1_type'=>'LT1Type')); @@ -654,6 +654,10 @@ class modProduct extends DolibarrModules )); } + if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { + $this->import_fields_array[$r]=array_merge($this->import_fields_array[$r], array('sp.packaging' => 'PackagingForThisProduct')); + } + $this->import_convertvalue_array[$r] = array( 'sp.fk_soc'=>array('rule'=>'fetchidfromref', 'classfile'=>'/societe/class/societe.class.php', 'class'=>'Societe', 'method'=>'fetch', 'element'=>'ThirdParty'), 'sp.fk_product'=>array('rule'=>'fetchidfromref', 'classfile'=>'/product/class/product.class.php', 'class'=>'Product', 'method'=>'fetch', 'element'=>'Product') @@ -692,6 +696,11 @@ class modProduct extends DolibarrModules 'sp.multicurrency_price'=>'' )); } + if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { + $this->import_examplevalues_array[$r] = array_merge($this->import_examplevalues_array[$r], array( + 'sp.packagning'=>'1', + )); + } $this->import_updatekeys_array[$r] = array('sp.fk_product'=>'ProductOrService', 'sp.ref_fourn'=>'SupplierRef', 'sp.fk_soc'=>'Supplier'); } From 45e2a6409ed9b96f71343a86a0a671e41177b1f9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 11:30:53 +0200 Subject: [PATCH 183/317] Missing field --- htdocs/install/mysql/migration/12.0.0-13.0.0.sql | 2 ++ htdocs/install/mysql/tables/llx_expensereport.sql | 1 + 2 files changed, 3 insertions(+) diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 8820fe1968c..b467ca2c535 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -324,6 +324,8 @@ ALTER TABLE llx_facturedet ADD COLUMN ref_ext varchar(255) AFTER multicurrency_t ALTER TABLE llx_c_ticket_category ADD COLUMN fk_parent integer DEFAULT 0 NOT NULL; ALTER TABLE llx_c_ticket_category ADD COLUMN force_severity varchar(32) NULL; +ALTER TABLE llx_expensereport ADD COLUMN fk_user_creat integer NULL; + ALTER TABLE llx_expensereport_ik ADD COLUMN ikoffset double DEFAULT 0 NOT NULL; ALTER TABLE llx_paiement ADD COLUMN ref_ext varchar(255) AFTER ref; diff --git a/htdocs/install/mysql/tables/llx_expensereport.sql b/htdocs/install/mysql/tables/llx_expensereport.sql index 1f13a5a90b5..772888620fb 100644 --- a/htdocs/install/mysql/tables/llx_expensereport.sql +++ b/htdocs/install/mysql/tables/llx_expensereport.sql @@ -36,6 +36,7 @@ CREATE TABLE llx_expensereport ( date_cancel datetime, tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, fk_user_author integer NOT NULL, -- not the user author but the user the expense report is for + fk_user_creat integer DEFAULT NULL, -- the use author fk_user_modif integer DEFAULT NULL, fk_user_valid integer DEFAULT NULL, fk_user_validator integer DEFAULT NULL, From 0b9783b7ed87c63598a43e566975dff07256050b Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 12 Oct 2020 11:31:09 +0200 Subject: [PATCH 184/317] fix #14946 --- htdocs/fourn/class/fournisseur.commande.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index dd6f6d8ac13..4521eda40ac 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -1725,7 +1725,7 @@ class CommandeFournisseur extends CommonOrder } else { - if (($qty % $prod->packaging) > 0) + if (!empty($prod->packaging) && ($qty % $prod->packaging) > 0) { $coeff = intval($qty / $prod->packaging) + 1; $qty = $prod->packaging * $coeff; From c3a900a41c16c883ae1ee1dfd4e522c6117f145a Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 12 Oct 2020 11:44:12 +0200 Subject: [PATCH 185/317] need to update packaging quantity --- htdocs/product/fournisseurs.php | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/htdocs/product/fournisseurs.php b/htdocs/product/fournisseurs.php index f1b8dd5e455..71ef77213f9 100644 --- a/htdocs/product/fournisseurs.php +++ b/htdocs/product/fournisseurs.php @@ -169,7 +169,7 @@ if (empty($reshook)) $supplier_description = GETPOST('supplier_description', 'alpha'); $barcode = GETPOST('barcode', 'alpha'); $fk_barcode_type = GETPOST('fk_barcode_type', 'int'); - $packaging = GETPOST('packaging', 'int'); + $packaging = price2num(GETPOST("packaging", 'nohtml'), 'MS'); if ($tva_tx == '') { @@ -230,11 +230,6 @@ if (empty($reshook)) } } - // TODO : may be remove, already done in class update_buyprice - if (empty($packaging)) $packaging = 1; - if ($packaging < $quantity) $packaging = $quantity; - $object->packaging = $packaging; - if (!$error) { $db->begin(); @@ -295,6 +290,10 @@ if (empty($reshook)) $newprice = price2num(GETPOST("price", "alpha")); + if (empty($packaging)) $packaging = 1; + if ($packaging < $quantity) $packaging = $quantity; + $object->packaging = $packaging; + if ($conf->multicurrency->enabled) { $multicurrency_tx = price2num(GETPOST("multicurrency_tx", 'alpha')); @@ -534,14 +533,9 @@ if ($id > 0 || $ref) print ''.$form->textwithpicto($langs->trans("PackagingForThisProduct"), $langs->trans("PackagingForThisProductDesc")).''; - $packaging = GETPOSTISSET('packaging') ? price2num(GETPOST('packaging', 'nohtml'), 'MS') : "1"; - if ($rowid) - { - print ''; - print price2num($object->packaging, 'MS'); - } else { - print ''; - } + $packaging = GETPOSTISSET('packaging') ? price2num(GETPOST('packaging', 'nohtml'), 'MS') : ((empty($rowid))?"1":price2num($object->packaging, 'MS')); + print ''; + // Units if ($conf->global->PRODUCT_USE_UNITS) { $unit = $object->getLabelOfUnit(); From bf7d5b56fbb9000f639a8a87812e26c1eedc4bad Mon Sep 17 00:00:00 2001 From: atm-lena Date: Mon, 12 Oct 2020 11:50:19 +0200 Subject: [PATCH 186/317] FIX subcat filter --- htdocs/compta/stats/cabyprodserv.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/htdocs/compta/stats/cabyprodserv.php b/htdocs/compta/stats/cabyprodserv.php index b51495ad8ef..0a30390e215 100644 --- a/htdocs/compta/stats/cabyprodserv.php +++ b/htdocs/compta/stats/cabyprodserv.php @@ -56,6 +56,8 @@ $subcat = false; if (GETPOST('subcat', 'alpha') === 'yes') { $subcat = true; } +$categorie = new Categorie($db); + // product/service $selected_type = GETPOST('search_type', 'int'); if ($selected_type =='') $selected_type = -1; @@ -257,11 +259,24 @@ if ($modecompta == 'CREANCES-DETTES') $sql.=" AND cp.fk_product is null"; } elseif ($selected_cat) { // Into a specific category + + if ($subcat) + { + $TListOfCats = $categorie->get_full_arbo('product', $selected_cat, 1); + + $listofcatsql = ""; + foreach ($TListOfCats as $key => $cat) + { + if ($key !== 0) $listofcatsql .= ","; + $listofcatsql .= $cat['rowid']; + } + } + $sql.= " AND (p.rowid IN "; - $sql.= " (SELECT fk_product FROM ".MAIN_DB_PREFIX."categorie_product cp WHERE cp.fk_categorie IN "; - $sql.= " (SELECT rowid FROM ".MAIN_DB_PREFIX."categorie WHERE rowid = ".$selected_cat; - if ($subcat) $sql.=" OR fk_parent = " . $selected_cat; - $sql.= ")))"; + $sql .= " (SELECT fk_product FROM ".MAIN_DB_PREFIX."categorie_product cp WHERE "; + if ($subcat) $sql .= "cp.fk_categorie IN (". $listofcatsql.")"; + else $sql.="cp.fk_categorie = ".$selected_cat; + $sql.= "))"; } if($selected_soc > 0) $sql .= " AND soc.rowid=".$selected_soc; $sql.= " AND f.entity IN (".getEntity('invoice').")"; From a054a2709037020d94d4988deb56c2249be8381b Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 12 Oct 2020 12:23:47 +0200 Subject: [PATCH 187/317] fix unit usage into BOM line --- htdocs/bom/tpl/objectline_create.tpl.php | 2 +- htdocs/bom/tpl/objectline_edit.tpl.php | 2 +- htdocs/bom/tpl/objectline_view.tpl.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/bom/tpl/objectline_create.tpl.php b/htdocs/bom/tpl/objectline_create.tpl.php index 2a675cc60e1..a7bb62c9901 100644 --- a/htdocs/bom/tpl/objectline_create.tpl.php +++ b/htdocs/bom/tpl/objectline_create.tpl.php @@ -113,7 +113,7 @@ if ($conf->global->PRODUCT_USE_UNITS) { $coldisplay++; print ''; - print $form->selectUnits(empty($line->fk_unit) ? $conf->global->PRODUCT_USE_UNITS : $line->fk_unit, "units"); + // print $form->selectUnits(empty($line->fk_unit) ? $conf->global->PRODUCT_USE_UNITS : $line->fk_unit, "units"); print ''; - print $form->selectUnits($line->fk_unit, "units"); + // print $form->selectUnits($line->fk_unit, "units"); print ''; - $label = $line->getLabelOfUnit('short'); + $label = $tmpproduct->getLabelOfUnit('long'); if ($label !== '') { print $langs->trans($label); } From d831edb481ff0248f829c3a65152a5ed8789f894 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 12:33:58 +0200 Subject: [PATCH 188/317] Fix bad popup --- htdocs/langs/en_US/admin.lang | 2 +- htdocs/projet/tasks/contact.php | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index f8912b87eeb..4e80fc794fb 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -271,7 +271,7 @@ NoticePeriod=Notice period NewByMonth=New by month Emails=Emails EMailsSetup=Emails setup -EMailsDesc=This page allows you to override your default PHP parameters for email sending. In most cases on Unix/Linux OS, the PHP setup is correct and these parameters are unnecessary. +EMailsDesc=This page allows you to set parameters or options for email sending. EmailSenderProfiles=Emails sender profiles EMailsSenderProfileDesc=You can keep this section empty. If you enter some emails here, they will be added to the list of possible senders into the combobox when your write a new email. MAIN_MAIL_SMTP_PORT=SMTP/SMTPS Port (default value in php.ini: %s) diff --git a/htdocs/projet/tasks/contact.php b/htdocs/projet/tasks/contact.php index 313fec73721..354109f135b 100644 --- a/htdocs/projet/tasks/contact.php +++ b/htdocs/projet/tasks/contact.php @@ -437,7 +437,7 @@ if ($id > 0 || !empty($ref)) } } - // Liste des contacts lies + // List of contact line print '
'.$langs->trans("Source").''.$langs->trans("ThirdParty").'
'; print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; print ''; - print $product->stats_mo['suppliers']; + print $product->stats_mo['customers']; print ''; print $product->stats_mo['nb']; print ''; diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 18565347072..f4cc018ff31 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2357,6 +2357,48 @@ class Product extends CommonObject } } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Charge tableau des stats OF pour le produit/service + * + * @param int $socid Id societe + * @return integer Tableau des stats dans $this->stats_mo, <0 if ko >0 if ok + */ + public function load_stats_mo($socid = 0) { + // phpcs:enable + global $conf, $user, $hookmanager; + + $sql = "SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,"; + $sql .= " SUM(c.qty) as qty"; + $sql .= " FROM ".MAIN_DB_PREFIX."mrp_mo as c"; + if (!$user->rights->societe->client->voir && !$socid) { + $sql .= "INNER JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".$user->id; + } + $sql .= " WHERE "; + $sql .= " c.entity IN (".getEntity('mo').")"; + + $sql .= " AND c.fk_product =".$this->id; + if ($socid > 0) { + $sql .= " AND c.fk_soc = ".$socid; + } + + $result = $this->db->query($sql); + if ($result) { + $obj = $this->db->fetch_object($result); + $this->stats_mo['customers'] = $obj->nb_customers ? $obj->nb_customers : 0; + $this->stats_mo['nb'] = $obj->nb; + $this->stats_mo['qty'] = $obj->qty ? $obj->qty : 0; + + $parameters = array('socid' => $socid); + $reshook = $hookmanager->executeHooks('loadStatsCustomerProposal', $parameters, $this, $action); + if ($reshook > 0) $this->stats_mo = $hookmanager->resArray['stats_mo']; + + return 1; + } else { + $this->error = $this->db->error(); + return -1; + } + } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** From 3b905bdcd50af3ad9063d63331863e283c7919c2 Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Mon, 12 Oct 2020 14:00:33 +0200 Subject: [PATCH 193/317] Selectable columns on social taxes list --- htdocs/compta/sociales/list.php | 578 +++++++++++++++++++------------- 1 file changed, 345 insertions(+), 233 deletions(-) diff --git a/htdocs/compta/sociales/list.php b/htdocs/compta/sociales/list.php index bd7f6147f2d..73707479ba8 100644 --- a/htdocs/compta/sociales/list.php +++ b/htdocs/compta/sociales/list.php @@ -4,7 +4,8 @@ * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2016 Frédéric France * Copyright (C) 2020 Pierre Ardoin - * + * Copyright (C) 2020 Tobias Sekan + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or @@ -20,12 +21,18 @@ */ /** - * \file htdocs/compta/sociales/list.php - * \ingroup tax - * \brief Page to list all social contributions + * \file htdocs/compta/sociales/list.php + * \ingroup tax + * \brief Page to list all social contributions */ require '../../main.inc.php'; + +// Security check +$socid = isset($_GET["socid"]) ? $_GET["socid"] : ''; +if ($user->socid) $socid = $user->socid; +$result = restrictedArea($user, 'tax', '', '', 'charges'); + require_once DOL_DOCUMENT_ROOT.'/compta/sociales/class/chargesociales.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsocialcontrib.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; @@ -35,36 +42,32 @@ if (!empty($conf->projet->enabled)) require_once DOL_DOCUMENT_ROOT.'/projet/clas // Load translation files required by the page $langs->loadLangs(array('compta', 'banks', 'bills')); -$action = GETPOST('action', 'aZ09'); -$massaction = GETPOST('massaction', 'alpha'); -$show_files = GETPOST('show_files', 'int'); -$confirm = GETPOST('confirm', 'alpha'); -$toselect = GETPOST('toselect', 'array'); -$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'sclist'; +$action = GETPOST('action', 'aZ09'); +$massaction = GETPOST('massaction', 'alpha'); +$confirm = GETPOST('confirm', 'alpha'); +$optioncss = GETPOST('optioncss', 'alpha'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'sclist'; -// Security check -$socid = isset($_GET["socid"]) ? $_GET["socid"] : ''; -if ($user->socid) $socid = $user->socid; -$result = restrictedArea($user, 'tax', '', '', 'charges'); - -$search_ref = GETPOST('search_ref', 'int'); -$search_label = GETPOST('search_label', 'alpha'); -$search_amount = GETPOST('search_amount', 'alpha'); -$search_status = GETPOST('search_status', 'int'); +$search_ref = GETPOST('search_ref', 'int'); +$search_label = GETPOST('search_label', 'alpha'); +$search_amount = GETPOST('search_amount', 'alpha'); +$search_status = GETPOST('search_status', 'int'); $search_day_lim = GETPOST('search_day_lim', 'int'); -$search_month_lim = GETPOST('search_month_lim', 'int'); +$search_month_lim = GETPOST('search_month_lim', 'int'); $search_year_lim = GETPOST('search_year_lim', 'int'); -$search_project_ref = GETPOST('search_project_ref', 'alpha'); -$search_project = GETPOST('search_project', 'alpha'); +$search_project_ref = GETPOST('search_project_ref', 'alpha'); +$search_project = GETPOST('search_project', 'alpha'); -$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; -$sortfield = GETPOST("sortfield", 'alpha'); -$sortorder = GETPOST("sortorder", 'alpha'); -$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); -if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); + +if (empty($page) || $page == -1) $page = 0; // If $page is not defined, or '' or -1 $offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; + if (!$sortfield) $sortfield = "cs.date_ech"; if (!$sortorder) $sortorder = "DESC"; @@ -84,23 +87,50 @@ if (!GETPOSTISSET('search_typeid')) $search_typeid = GETPOST('search_typeid', 'int'); } -if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All test are required to be compatible with all browsers -{ - $search_ref = ""; - $search_label = ""; - $search_amount = ""; - $search_status = ''; - $search_typeid = ""; - $year = ""; - $search_day_lim = ''; - $search_year_lim = ''; - $search_month_lim = ''; - $search_project_ref = ''; - $search_project = ''; - $toselect = ''; - $search_array_options = array(); -} +$arrayfields = array( + 'cs.rowid' =>array('label'=>"Ref", 'checked'=>1, 'position'=>10), + 'cs.libelle' =>array('label'=>"Label", 'checked'=>1, 'position'=>20), + 'cs.fk_type' =>array('label'=>"Type", 'checked'=>1, 'position'=>30), + 'p.ref' =>array('label'=>"ProjectRef", 'checked'=>1, 'position'=>40, 'enable'=>(!empty($conf->projet->enabled))), + 'cs.date_ech' =>array('label'=>"Date", 'checked'=>1, 'position'=>50), + 'cs.periode' =>array('label'=>"PeriodEndDate", 'checked'=>1, 'position'=>60), + 'cs.amount' =>array('label'=>"Amount", 'checked'=>1, 'position'=>70), + 'cs.paye' =>array('label'=>"Status", 'checked'=>1, 'position'=>80), +); +$arrayfields = dol_sort_array($arrayfields, 'position'); +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('sclist')); +$object = new ChargeSociales($db); + +/* + * Actions + */ + +$parameters = array('socid'=>$socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + +if (empty($reshook)) { + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // All tests are required to be compatible with all browsers + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + $search_ref = ''; + $search_label = ''; + $search_amount = ''; + $search_status = ''; + $search_typeid = ''; + $year = ''; + $search_day_lim = ''; + $search_year_lim = ''; + $search_month_lim = ''; + $search_project_ref = ''; + $search_project = ''; + $search_array_options = array(); + } +} /* * View @@ -114,8 +144,8 @@ if (!empty($conf->projet->enabled)) $projectstatic = new Project($db); llxHeader('', $langs->trans("SocialContributions")); -$sql = "SELECT cs.rowid as id, cs.fk_type as type, "; -$sql .= " cs.amount, cs.date_ech, cs.libelle as label, cs.paye, cs.periode,"; +$sql = "SELECT cs.rowid, cs.fk_type as type, "; +$sql .= " cs.amount, cs.date_ech, cs.libelle, cs.paye, cs.periode,"; if (!empty($conf->projet->enabled)) $sql .= " p.rowid as project_id, p.ref as project_ref, p.title as project_label,"; $sql .= " c.libelle as type_label,"; $sql .= " SUM(pc.amount) as alreadypayed"; @@ -135,19 +165,19 @@ $sql .= dolSqlDateFilter("cs.periode", $search_day_lim, $search_month_lim, $sear //$sql.= dolSqlDateFilter("cs.periode", 0, 0, $year); if ($year > 0) { - $sql .= " AND ("; - // Si period renseignee on l'utilise comme critere de date, sinon on prend date echeance, - // ceci afin d'etre compatible avec les cas ou la periode n'etait pas obligatoire - $sql .= " (cs.periode IS NOT NULL AND date_format(cs.periode, '%Y') = '".$db->escape($year)."') "; - $sql .= "OR (cs.periode IS NULL AND date_format(cs.date_ech, '%Y') = '".$db->escape($year)."')"; - $sql .= ")"; + $sql .= " AND ("; + // Si period renseignee on l'utilise comme critere de date, sinon on prend date echeance, + // ceci afin d'etre compatible avec les cas ou la periode n'etait pas obligatoire + $sql .= " (cs.periode IS NOT NULL AND date_format(cs.periode, '%Y') = '".$db->escape($year)."') "; + $sql .= "OR (cs.periode IS NULL AND date_format(cs.date_ech, '%Y') = '".$db->escape($year)."')"; + $sql .= ")"; } if ($filtre) { - $filtre = str_replace(":", "=", $filtre); - $sql .= " AND ".$filtre; + $filtre = str_replace(":", "=", $filtre); + $sql .= " AND ".$filtre; } if ($search_typeid) { - $sql .= " AND cs.fk_type=".$db->escape($search_typeid); + $sql .= " AND cs.fk_type=".$db->escape($search_typeid); } $sql .= " GROUP BY cs.rowid, cs.fk_type, cs.amount, cs.date_ech, cs.libelle, cs.paye, cs.periode, c.libelle"; if (!empty($conf->projet->enabled)) $sql .= ", p.rowid, p.ref, p.title"; @@ -157,193 +187,275 @@ $totalnboflines = 0; $result = $db->query($sql); if ($result) { - $totalnboflines = $db->num_rows($result); + $totalnboflines = $db->num_rows($result); } $sql .= $db->plimit($limit + 1, $offset); $resql = $db->query($sql); -if ($resql) +if (!$resql) { - $num = $db->num_rows($resql); - $i = 0; - - $param = ''; - if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); - if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); - if ($search_ref) $param .= '&search_ref='.urlencode($search_ref); - if ($search_label) $param .= '&search_label='.urlencode($search_label); - if ($search_project_ref >= 0) $param .= "&search_project_ref=".urlencode($search_project_ref); - if ($search_amount) $param .= '&search_amount='.urlencode($search_amount); - if ($search_typeid) $param .= '&search_typeid='.urlencode($search_typeid); - if ($search_status != '' && $search_status != '-1') $param .= '&search_status='.urlencode($search_status); - if ($year) $param .= '&year='.urlencode($year); - - $newcardbutton = ''; - if ($user->rights->tax->charges->creer) - { - $newcardbutton .= dolGetButtonTitle($langs->trans('MenuNewSocialContribution'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/compta/sociales/card.php?action=create'); - } - - print ''; - if ($optioncss != '') print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - - $center = ''; - if ($year) - { - $center = ($year ? "".img_previous()." ".$langs->trans("Year")." $year ".img_next()."" : ""); - } - - print_barre_liste($langs->trans("SocialContributions"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $center, $num, $totalnboflines, 'bill', 0, $newcardbutton, '', $limit, 0, 0, 1); - - if (empty($mysoc->country_id) && empty($mysoc->country_code)) - { - print '
'; - $langs->load("errors"); - $countrynotdefined = $langs->trans("ErrorSetACountryFirst"); - print $countrynotdefined; - print '
'; - } else { - print '
'; - print ''."\n"; - - print ''; - // Ref - print ''; - // Label - print ''; - // Type - print ''; - // Ref Project - if (!empty($conf->projet->enabled)) print ''; - // Date - print ''; - // Period end date - print ''; - // Amount - print ''; - // Status - print ''; - - print ''; - print "\n"; - - print ''; - print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "id", "", $param, "", $sortfield, $sortorder); - print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "cs.libelle", "", $param, 'class="left"', $sortfield, $sortorder); - print_liste_field_titre("Type", $_SERVER["PHP_SELF"], "type", "", $param, 'class="left"', $sortfield, $sortorder); - if (!empty($conf->projet->enabled)) print_liste_field_titre('ProjectRef', $_SERVER["PHP_SELF"], "p.ref", "", $param, '', $sortfield, $sortorder); - print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "cs.date_ech", "", $param, 'align="center"', $sortfield, $sortorder); - print_liste_field_titre("PeriodEndDate", $_SERVER["PHP_SELF"], "periode", "", $param, 'align="center"', $sortfield, $sortorder); - print_liste_field_titre("Amount", $_SERVER["PHP_SELF"], "cs.amount", "", $param, 'class="right"', $sortfield, $sortorder); - print_liste_field_titre("Status", $_SERVER["PHP_SELF"], "cs.paye", "", $param, 'class="right"', $sortfield, $sortorder); - print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch '); - print "\n"; - - $i = 0; - $totalarray = array(); - while ($i < min($num, $limit)) - { - $obj = $db->fetch_object($resql); - - $chargesociale_static->id = $obj->id; - $chargesociale_static->ref = $obj->id; - $chargesociale_static->label = $obj->label; - $chargesociale_static->type_label = $obj->type_label; - if (!empty($conf->projet->enabled)) { - $projectstatic->id = $obj->project_id; - $projectstatic->ref = $obj->project_ref; - $projectstatic->title = $obj->project_label; - } - - print ''; - - // Ref - print "\n"; - if (!$i) $totalarray['nbfield']++; - - // Label - print "\n"; - if (!$i) $totalarray['nbfield']++; - - // Type - print "\n"; - if (!$i) $totalarray['nbfield']++; - - // Project Ref - if (!empty($conf->projet->enabled)) { - print ''; - if (!$i) $totalarray['nbfield']++; - } - - // Date - print ''; - if (!$i) $totalarray['nbfield']++; - - // Date end period - print '\n"; - if (!$i) $totalarray['nbfield']++; - - // Amount - print ''; - if (!$i) $totalarray['nbfield']++; - if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'totalttcfield'; - $totalarray['val']['totalttcfield'] += $obj->amount; - - print ''; - if (!$i) $totalarray['nbfield']++; - - print ''; - - if (!$i) $totalarray['nbfield']++; - - print ''; - $i++; - } - - // Show total line - include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; - - print '
'; - print ''; - print ''; - $formsocialcontrib->select_type_socialcontrib($search_typeid, 'search_typeid', 1, 0, 0, 'maxwidth100onsmartphone', 1); - print ' '; - if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; - print ''; - $formother->select_year($search_year_lim ? $search_year_lim : -1, 'search_year_lim', 1, 20, 5, 0, 0, '', 'widthauto valignmiddle'); - print ''; - print ''; - print ''; - $liststatus = array('0'=>$langs->trans("Unpaid"), '1'=>$langs->trans("Paid")); - print $form->selectarray('search_status', $liststatus, $search_status, 1); - print ''; - $searchpicto = $form->showFilterAndCheckAddButtons(0); - print $searchpicto; - print '
".$chargesociale_static->getNomUrl(1, '20')."".dol_trunc($obj->label, 42)."".$obj->type_label."'; - if ($obj->project_id > 0) - { - print $projectstatic->getNomUrl(1); - } - print ''.dol_print_date($db->jdate($obj->date_ech), 'day').''; - if ($obj->periode) - { - print 'jdate($obj->periode)).'">'.dol_print_date($db->jdate($obj->periode), 'day').''; - } else { - print ' '; - } - print "'.price($obj->amount).''.$chargesociale_static->LibStatut($obj->paye, 5, $obj->alreadypayed).'
'; - print '
'; - } - print ''; -} else { dol_print_error($db); + llxFooter(); + $db->close(); + exit; } +$num = $db->num_rows($resql); +$i = 0; + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); +if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit); +if ($search_ref) $param .= '&search_ref='.urlencode($search_ref); +if ($search_label) $param .= '&search_label='.urlencode($search_label); +if ($search_project_ref >= 0) $param .= "&search_project_ref=".urlencode($search_project_ref); +if ($search_amount) $param .= '&search_amount='.urlencode($search_amount); +if ($search_typeid) $param .= '&search_typeid='.urlencode($search_typeid); +if ($search_status != '' && $search_status != '-1') $param .= '&search_status='.urlencode($search_status); +if ($year) $param .= '&year='.urlencode($year); + +$newcardbutton = ''; +if ($user->rights->tax->charges->creer) +{ + $newcardbutton .= dolGetButtonTitle($langs->trans('MenuNewSocialContribution'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/compta/sociales/card.php?action=create'); +} + +print '
'; +if ($optioncss != '') print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$center = ''; +if ($year) +{ + $center = ''.img_previous().''; + $center .= ' '.$langs->trans("Year").' '.$year; + $center .= ' '.img_next().''; +} + +print_barre_liste($langs->trans("SocialContributions"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $center, $num, $totalnboflines, 'bill', 0, $newcardbutton, '', $limit, 0, 0, 1); + +if (empty($mysoc->country_id) && empty($mysoc->country_code)) +{ + print '
'; + $langs->load("errors"); + $countrynotdefined = $langs->trans("ErrorSetACountryFirst"); + print $countrynotdefined; + print '
'; + + print '
'; + llxFooter(); + $db->close(); +} + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +if ($massactionbutton) $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); + +print '
'; +print ''."\n"; + +print ''; + +// Filters: Line number (placeholder) +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; +} + +// Filter: Ref +if (!empty($arrayfields['cs.rowid']['checked'])) { + print ''; +} + +// Filter: Label +if (!empty($arrayfields['cs.rowid']['checked'])) { + print ''; +} + +// Filter: Type +if (!empty($arrayfields['cs.fk_type']['checked'])) { + print ''; +} + +// Filter: Project ref +if (!empty($arrayfields['p.ref']['checked'])) { + print ''; +} + +// Filter: Date (placeholder) +if (!empty($arrayfields['cs.date_ech']['checked'])) { + print ''; +} + +// Filter: Period end date +if (!empty($arrayfields['cs.periode']['checked'])) { + print ''; +} + +// Filter: Amount +if (!empty($arrayfields['cs.amount']['checked'])) { + print ''; +} + +// Filter: Status +if (!empty($arrayfields['cs.paye']['checked'])) { + print ''; +} + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +// Filter: Buttons +print ''; + +print ''; + +print ''; +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) print_liste_field_titre('#', $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['cs.rowid']['checked'])) print_liste_field_titre($arrayfields['cs.rowid']['label'], $_SERVER["PHP_SELF"], "cs.rowid", '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['cs.libelle']['checked'])) print_liste_field_titre($arrayfields['cs.libelle']['label'], $_SERVER["PHP_SELF"], "cs.libelle", '', $param, 'class="left"', $sortfield, $sortorder); +if (!empty($arrayfields['cs.fk_type']['checked'])) print_liste_field_titre($arrayfields['cs.fk_type']['label'], $_SERVER["PHP_SELF"], "cs.fk_type", '', $param, 'class="left"', $sortfield, $sortorder); +if (!empty($arrayfields['p.ref']['checked'])) print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"], "p.ref", '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['cs.date_ech']['checked'])) print_liste_field_titre($arrayfields['cs.date_ech']['label'], $_SERVER["PHP_SELF"], "cs.date_ech", '', $param, 'align="center"', $sortfield, $sortorder); +if (!empty($arrayfields['cs.periode']['checked'])) print_liste_field_titre($arrayfields['cs.periode']['label'], $_SERVER["PHP_SELF"], "cs.periode", '', $param, 'align="center"', $sortfield, $sortorder); +if (!empty($arrayfields['cs.amount']['checked'])) print_liste_field_titre($arrayfields['cs.amount']['label'], $_SERVER["PHP_SELF"], "cs.amount", '', $param, 'class="right"', $sortfield, $sortorder); +if (!empty($arrayfields['cs.paye']['checked'])) print_liste_field_titre($arrayfields['cs.paye']['label'], $_SERVER["PHP_SELF"], "cs.paye", '', $param, 'class="right"', $sortfield, $sortorder); + +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'maxwidthsearch '); +print ''; + +$i = 0; +$totalarray = array(); +while ($i < min($num, $limit)) +{ + $obj = $db->fetch_object($resql); + + $chargesociale_static->id = $obj->rowid; + $chargesociale_static->ref = $obj->rowid; + $chargesociale_static->label = $obj->libelle; + $chargesociale_static->type_label = $obj->type_label; + if (!empty($conf->projet->enabled)) { + $projectstatic->id = $obj->project_id; + $projectstatic->ref = $obj->project_ref; + $projectstatic->title = $obj->project_label; + } + + print ''; + + // Line number + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Ref + if (!empty($arrayfields['cs.rowid']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Label + if (!empty($arrayfields['cs.libelle']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Type + if (!empty($arrayfields['cs.fk_type']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Project ref + if (!empty($arrayfields['p.ref']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Date + if (!empty($arrayfields['cs.date_ech']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Date end period + if (!empty($arrayfields['cs.periode']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Amount + if (!empty($arrayfields['cs.amount']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'totalttcfield'; + $totalarray['val']['totalttcfield'] += $obj->amount; + } + + // Status + if (!empty($arrayfields['cs.paye']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Buttons + print ''; + if (!$i) $totalarray['nbfield']++; + + print ''; + $i++; +} + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + $formsocialcontrib->select_type_socialcontrib($search_typeid, 'search_typeid', 1, 0, 0, 'maxwidth100onsmartphone', 1); + print ''; + print ''; + print ''; + print ''; + if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print ''; + print ''; + $formother->select_year($search_year_lim ? $search_year_lim : -1, 'search_year_lim', 1, 20, 5, 0, 0, '', 'widthauto valignmiddle'); + print ''; + print ''; + print ''; + $liststatus = array('0'=>$langs->trans("Unpaid"), '1'=>$langs->trans("Paid")); + print $form->selectarray('search_status', $liststatus, $search_status, 1); + print ''; +print $form->showFilterAndCheckAddButtons(0); +print '
'.(($offset * $limit) + $i).''.$chargesociale_static->getNomUrl(1, '20').''.dol_trunc($obj->libelle, 42).''.$obj->type_label.''; + if ($obj->project_id > 0) { + print $projectstatic->getNomUrl(1); + } + print ''.dol_print_date($db->jdate($obj->date_ech), 'day').''; + if ($obj->periode) { + print 'jdate($obj->periode)).'">'; + print dol_print_date($db->jdate($obj->periode), 'day'); + print ''; + } + print ''.price($obj->amount).''.$chargesociale_static->LibStatut($obj->paye, 5, $obj->alreadypayed).'
'; +print '
'; +print ''; + // End of page llxFooter(); $db->close(); From 75997bb8f5e08fbc2c64a25bb7f4dcd5eb39319a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 14:01:15 +0200 Subject: [PATCH 194/317] Minor fixes --- .github/workflows/stale-issues-safe.yml | 2 +- htdocs/admin/modules.php | 6 +++--- htdocs/core/lib/admin.lib.php | 2 +- htdocs/core/modules/modIntracommreport.class.php | 2 +- htdocs/theme/eldy/global.inc.php | 2 +- htdocs/theme/md/style.css.php | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/stale-issues-safe.yml b/.github/workflows/stale-issues-safe.yml index 844b19c7a3f..1682b92a7a7 100644 --- a/.github/workflows/stale-issues-safe.yml +++ b/.github/workflows/stale-issues-safe.yml @@ -16,7 +16,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-message: 'This issue is stale because it has been open 1 year with no activity. If this is a bug, please comment to confirm it is still present on latest stable version. if this is a feature request, please comment to notify the request is still relevant and not yet covered by latest stable version. This issue may be closed automatically by stale bot in 10 days (you should still be able to re-open it if required).' stale-label: 'Issue Stale (automatic label)' - exempt-labels: 'Priority High / Blocking,Priority Top Strategic,Priority Medium,Hacktoberfest,good first issue,Bug Security (CVE),Analysis of PR in progres' + exempt-labels: 'Priority High / Blocking,Priority Top Strategic,Priority Medium,hacktoberfest,hacktoberfest-accepted,good first issue,Bug Security (CVE),Analysis of PR in progress' days-before-stale: 365 days-before-close: 10 operations-per-run: 100 diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index c61e352aad8..3ca08f90900 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -662,9 +662,9 @@ if ($mode == 'common' || $mode == 'commonkanban') // Version (with picto warning or not) $version = $objMod->getVersion(0); $versiontrans = ''; - if (preg_match('/development/i', $version)) $versiontrans .= img_warning($langs->trans("Development"), 'style="float: left"'); - if (preg_match('/experimental/i', $version)) $versiontrans .= img_warning($langs->trans("Experimental"), 'style="float: left"'); - if (preg_match('/deprecated/i', $version)) $versiontrans .= img_warning($langs->trans("Deprecated"), 'style="float: left"'); + if (preg_match('/development/i', $version)) $versiontrans .= img_warning($langs->trans("Development"), '', 'floatleft paddingright'); + if (preg_match('/experimental/i', $version)) $versiontrans .= img_warning($langs->trans("Experimental"), '', 'floatleft paddingright'); + if (preg_match('/deprecated/i', $version)) $versiontrans .= img_warning($langs->trans("Deprecated"), '', 'floatleft paddingright'); if ($objMod->isCoreOrExternalModule() == 'external' || preg_match('/development|experimental|deprecated/i', $version)) { $versiontrans .= $objMod->getVersion(1); } diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php index 038b4be27a6..49ababf4a25 100644 --- a/htdocs/core/lib/admin.lib.php +++ b/htdocs/core/lib/admin.lib.php @@ -45,7 +45,7 @@ function versiontostring($versionarray) /** * Compare 2 versions (stored into 2 arrays). * To check if Dolibarr version is lower than (x,y,z), do "if versioncompare(versiondolibarrarray(), array(x.y.z)) <= 0" - * For example: if (versioncompare(versiondolibarrarray(),array(4,0,-4)) >= 0) is true if version is 4.0 alpha or higher. + * For example: if (versioncompare(versiondolibarrarray(),array(4,0,-5)) >= 0) is true if version is 4.0 alpha or higher. * For example: if (versioncompare(versiondolibarrarray(),array(4,0,0)) >= 0) is true if version is 4.0 final or higher. * For example: if (versioncompare(versiondolibarrarray(),array(4,0,1)) >= 0) is true if version is 4.0.1 or higher. * Alternative way to compare: if ((float) DOL_VERSION >= 4.0) is true if version is 4.0 alpha or higher (works only to compare first and second level) diff --git a/htdocs/core/modules/modIntracommreport.class.php b/htdocs/core/modules/modIntracommreport.class.php index 1979c47f613..42e906a15f2 100644 --- a/htdocs/core/modules/modIntracommreport.class.php +++ b/htdocs/core/modules/modIntracommreport.class.php @@ -66,7 +66,7 @@ class modIntracommreport extends DolibarrModules $this->requiredby = array(); // List of modules id to disable if this one is disabled $this->conflictwith = array(); // List of modules id this module is in conflict with $this->phpmin = array(5,5); // Minimum version of PHP required by module - $this->need_dolibarr_version = array(13,0); // Minimum version of Dolibarr required by module + $this->need_dolibarr_version = array(13, 0, -5); // Minimum version of Dolibarr required by module $this->langfiles = array("intracommreport"); // Constants diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 85fb40b0e72..d6c5434ce94 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -510,7 +510,7 @@ form { form#addproduct { padding-top: 10px; } -div.float +div.float, span.floatleft { float:; } diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index ecd92c2689c..65afa0e017f 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -632,7 +632,7 @@ form { padding:0px; margin:0px; } -div.float +div.float, span.floatleft { float:; } From f468c61df33f70d4912a25586617fc586a598413 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 14:04:34 +0200 Subject: [PATCH 195/317] Fix More powerfull detection of bad use of newToken --- test/phpunit/CodingPhpTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/phpunit/CodingPhpTest.php b/test/phpunit/CodingPhpTest.php index b819671578c..4326f536f92 100644 --- a/test/phpunit/CodingPhpTest.php +++ b/test/phpunit/CodingPhpTest.php @@ -341,7 +341,7 @@ class CodingPhpTest extends PHPUnit\Framework\TestCase $ok=true; $matches=array(); // Check string name="token" value="'.$_SESSINON - preg_match_all('/name="token" value="\'\.\$_SESSION/', $filecontent, $matches, PREG_SET_ORDER); + preg_match_all('/name="token" value="\'\s*\.\s*\$_SESSION/', $filecontent, $matches, PREG_SET_ORDER); foreach ($matches as $key => $val) { if ($file['name'] != 'excludefile.php') From 675b1e613bad92d2e206298dbb0289d34ed3d010 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 12 Oct 2020 12:05:38 +0000 Subject: [PATCH 196/317] Fixing style errors. --- htdocs/compta/sociales/list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/sociales/list.php b/htdocs/compta/sociales/list.php index 73707479ba8..c4910e431e5 100644 --- a/htdocs/compta/sociales/list.php +++ b/htdocs/compta/sociales/list.php @@ -5,7 +5,7 @@ * Copyright (C) 2016 Frédéric France * Copyright (C) 2020 Pierre Ardoin * Copyright (C) 2020 Tobias Sekan - + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or From ad461a098bfa77e8f86a813fe91612618237ae27 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 14:06:19 +0200 Subject: [PATCH 197/317] Fix look and feel --- htdocs/intracommreport/admin/intracommreport.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php index 8950839515a..c2209614a15 100644 --- a/htdocs/intracommreport/admin/intracommreport.php +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -96,13 +96,14 @@ print load_fiche_titre($langs->trans("IntracommReportSetup"), $linkback, 'title_ $head = intracommReportAdminPrepareHead(); -dol_fiche_head($head, 'general', $langs->trans("IntracommReport"), 0, "intracommreport"); +dol_fiche_head($head, 'general', $langs->trans("IntracommReport"), -1, "intracommreport"); -print '
'; -print ''; +print ''; +print ''; print ''; -print '
'.$langs->trans("Parameters").' (DEB)
'; print ''; print ''; @@ -166,7 +167,9 @@ print "\n"; print '
'.$langs->trans("Description").'
'; -print ''.$langs->trans("Parameters").' (DES)'."\n"; + +print_fiche_titre($langs->trans("Parameters").' (DES)'); + print ''; print ''; print ''; From 4da75c4251752262b56b7831ef622328ded7e38d Mon Sep 17 00:00:00 2001 From: Philippe GRAND Date: Mon, 12 Oct 2020 16:11:56 +0200 Subject: [PATCH 198/317] fix : undefined index --- htdocs/core/class/conf.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 32d7b145a41..3d6526690a7 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -203,7 +203,7 @@ class Conf { $modulename = strtolower($reg[1]); $partname = strtolower($reg[2]); - if (!is_array($this->modules_parts[$partname])) { $this->modules_parts[$partname] = array(); } + if (!isset($this->modules_parts[$partname]) || !is_array($this->modules_parts[$partname])) { $this->modules_parts[$partname] = array(); } $arrValue = json_decode($value, true); if (is_array($arrValue) && !empty($arrValue)) $value = $arrValue; elseif (in_array($partname, array('login', 'menus', 'substitutions', 'triggers', 'tpl'))) $value = '/'.$modulename.'/core/'.$partname.'/'; From d158716cccdc6bda501b80239507c213ba5da098 Mon Sep 17 00:00:00 2001 From: Givriz Date: Mon, 12 Oct 2020 17:41:03 +0200 Subject: [PATCH 199/317] Fix : correction de commentaires MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correction de commentaires (passage de français à anglais ou correction d'un mauvais anglais). Il reste beaucoup à faire, mais je fais un premier PR pour vérifier que cela marche. --- htdocs/fourn/facture/paiement.php | 8 ++++---- htdocs/fourn/paiement/card.php | 12 ++++++------ htdocs/projet/card.php | 2 +- htdocs/projet/contact.php | 6 +++--- htdocs/projet/ganttview.php | 6 +++--- htdocs/projet/list.php | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/htdocs/fourn/facture/paiement.php b/htdocs/fourn/facture/paiement.php index 8c2fdbdb5b6..bd5950151eb 100644 --- a/htdocs/fourn/facture/paiement.php +++ b/htdocs/fourn/facture/paiement.php @@ -245,7 +245,7 @@ if (empty($reshook)) { $action = 'create'; } - // Le reste propre a cette action s'affiche en bas de page. + // All the next of this action is displayed at the page's bottom. } @@ -292,7 +292,7 @@ if (empty($reshook)) $thirdparty = new Societe($db); if ($socid > 0) $thirdparty->fetch($socid); - // Creation de la ligne paiement + // Creation of payment line $paiement = new PaiementFourn($db); $paiement->datepaye = $datepaye; $paiement->amounts = $amounts; // Array of amounts @@ -521,7 +521,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie $sql .= " WHERE f.entity = ".$conf->entity; $sql .= ' AND f.fk_soc = '.$object->socid; $sql .= ' AND f.paye = 0'; - $sql .= ' AND f.fk_statut = 1'; // Statut=0 => non validee, Statut=2 => annulee + $sql .= ' AND f.fk_statut = 1'; // Status=0 => unvalidated, Status=2 => canceled if ($object->type != FactureFournisseur::TYPE_CREDIT_NOTE) { $sql .= ' AND f.type IN (0,1,3,5)'; // Standard invoice, replacement, deposit, situation @@ -756,7 +756,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie } } - // Bouton Enregistrer + // Save Button if ($action != 'add_paiement') { print '
'.$langs->trans("ClosePaidInvoicesAutomatically"); diff --git a/htdocs/fourn/paiement/card.php b/htdocs/fourn/paiement/card.php index 82c6e1d18d3..7ea1958c9e2 100644 --- a/htdocs/fourn/paiement/card.php +++ b/htdocs/fourn/paiement/card.php @@ -128,7 +128,7 @@ if ($action == 'setdatep' && !empty($_POST['datepday'])) // Build document $upload_dir = $conf->fournisseur->payment->dir_output; -// TODO: get the appropriate permisson +// TODO: get the appropriate permission $permissiontoadd = true; include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; @@ -151,7 +151,7 @@ dol_fiche_head($head, 'payment', $langs->trans('SupplierPayment'), -1, 'payment' if ($result > 0) { /* - * Confirmation de la suppression du paiement + * Confirmation of payment's delete */ if ($action == 'delete') { @@ -159,7 +159,7 @@ if ($result > 0) } /* - * Confirmation de la validation du paiement + * Confirmation of payment's validation */ if ($action == 'valide') { @@ -181,7 +181,7 @@ if ($result > 0) print $form->showrefnav($object,'id','',1,'rowid','ref'); print '
';*/ - // Date payment + // Date of payment print ''; @@ -251,7 +251,7 @@ if ($result > 0) print '
'; /** - * List of vendor invoices + * List of seller's invoices */ $sql = 'SELECT f.rowid, f.rowid as facid, f.ref, f.ref_supplier, f.type, f.paye, f.total_ht, f.total_tva, f.total_ttc, f.datef as date, f.fk_statut as status,'; $sql .= ' pf.amount, s.nom as name, s.rowid as socid'; @@ -332,7 +332,7 @@ if ($result > 0) /* - * Boutons Actions + * Actions Buttons */ print '
'; diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index db38e3c02d7..c7e22bfb5cd 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -1183,7 +1183,7 @@ if ($action == 'create' && $user->rights->projet->creer) } /* - * Boutons actions + * Actions Buttons */ print '
'; $parameters = array(); diff --git a/htdocs/projet/contact.php b/htdocs/projet/contact.php index 8bbdbed9e6a..471e50139f5 100644 --- a/htdocs/projet/contact.php +++ b/htdocs/projet/contact.php @@ -84,7 +84,7 @@ if ($action == 'addcontact' && $user->rights->projet->creer) } } -// bascule du statut d'un contact +// Change contact's status if ($action == 'swapstatut' && $user->rights->projet->creer) { if ($object->fetch($id)) @@ -95,7 +95,7 @@ if ($action == 'swapstatut' && $user->rights->projet->creer) } } -// Efface un contact +// Delete a contact if (($action == 'deleteline' || $action == 'deletecontact') && $user->rights->projet->creer) { $object->fetch($id); @@ -128,7 +128,7 @@ $userstatic = new User($db); /* *************************************************************************** */ /* */ -/* Mode vue et edition */ +/* Edition and view mode */ /* */ /* *************************************************************************** */ diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index f15e6d4900f..ed775c0ea35 100644 --- a/htdocs/projet/ganttview.php +++ b/htdocs/projet/ganttview.php @@ -239,7 +239,7 @@ $linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt $linktotasks .= dolGetButtonTitle($langs->trans('ViewGantt'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1', '', 1, array('morecss'=>'reposition marginleftonly btnTitleSelected')); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); -print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'projecttask'); +print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'generic'); // Get list of tasks in tasksarray and taskarrayfiltered @@ -262,14 +262,14 @@ if (count($tasksarray) > 0) $tasks = array(); $task_dependencies = array(); $taskcursor = 0; - foreach ($tasksarray as $key => $val) // Task array are sorted by "project, position, dateo" + foreach ($tasksarray as $key => $val) // Task array are sorted by "project, position, date" { $task->fetch($val->id, ''); $idparent = ($val->fk_parent ? $val->fk_parent : '-'.$val->fk_project); // If start with -, id is a project id $tasks[$taskcursor]['task_id'] = $val->id; - $tasks[$taskcursor]['task_alternate_id'] = ($taskcursor + 1); // An id that has same order than position (requird by ganttchart) + $tasks[$taskcursor]['task_alternate_id'] = ($taskcursor + 1); // An id that has same order than position (required by ganttchart) $tasks[$taskcursor]['task_project_id'] = $val->fk_project; $tasks[$taskcursor]['task_parent'] = $idparent; diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index 42f84c157a8..1f32494a72c 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -284,7 +284,7 @@ $formproject = new FormProjets($db); $title = $langs->trans("Projects"); -// Get list of project id allowed to user (in a string list separated by coma) +// Get list of project id allowed to user (in a string list separated by comma) $projectsListId = ''; if (!$user->rights->projet->all->lire) $projectsListId = $object->getProjectsAuthorizedForUser($user, 0, 1, $socid); @@ -386,7 +386,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $result = $db->query($sql); $nbtotalofrecords = $db->num_rows($result); - if (($page * $limit) > $nbtotalofrecords) // if total resultset is smaller then paging size (filtering), goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) // if total resultset is smaller than paging size (filtering), goto and load page 0 { $page = 0; $offset = 0; From 276783a709e301306b0c2e4e50ce7ee28f386040 Mon Sep 17 00:00:00 2001 From: Damien BENOIT <48482664+Givriz@users.noreply.github.com> Date: Mon, 12 Oct 2020 18:36:13 +0200 Subject: [PATCH 200/317] Essai de revalidation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Une ligne n'était pas synchronisée avec le projet upstream. --- htdocs/projet/ganttview.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index ed775c0ea35..3ddd0402db7 100644 --- a/htdocs/projet/ganttview.php +++ b/htdocs/projet/ganttview.php @@ -239,7 +239,7 @@ $linktotasks = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt $linktotasks .= dolGetButtonTitle($langs->trans('ViewGantt'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1', '', 1, array('morecss'=>'reposition marginleftonly btnTitleSelected')); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); -print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'generic'); +print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'projecttask'); // Get list of tasks in tasksarray and taskarrayfiltered From fcd46455099beafb22e97e5cfbd7a0299bc7e37e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 19:33:00 +0200 Subject: [PATCH 201/317] Standardize code: Property product_libelle renamed into product_label Move common vars declaration into parent class. --- htdocs/commande/class/commande.class.php | 13 ++--- htdocs/compta/facture/class/facture.class.php | 29 +++--------- htdocs/core/class/commoninvoice.class.php | 47 ++++++++++++++++--- htdocs/core/class/commonorder.class.php | 18 ++++--- .../class/fournisseur.commande.class.php | 11 ++--- .../fourn/class/fournisseur.facture.class.php | 14 ++++-- 6 files changed, 76 insertions(+), 56 deletions(-) diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index f2aab587169..70df565cd2b 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -3994,11 +3994,6 @@ class OrderLine extends CommonOrderLine public $fk_parent_line; public $fk_facture; - /** - * @var string Order lines label - */ - public $label; - public $ref_ext; public $fk_remise_except; @@ -4049,7 +4044,7 @@ class OrderLine extends CommonOrderLine $sql .= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_localtax1, cd.total_localtax2, cd.total_ttc, cd.fk_product_fournisseur_price as fk_fournprice, cd.buy_price_ht as pa_ht, cd.rang, cd.special_code,'; $sql .= ' cd.fk_unit,'; $sql .= ' cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,'; - $sql .= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc, p.tobatch as product_tobatch,'; + $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,'; $sql .= ' cd.date_start, cd.date_end'; $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid'; @@ -4093,9 +4088,9 @@ class OrderLine extends CommonOrderLine $this->rang = $objp->rang; $this->ref = $objp->product_ref; // deprecated - $this->product_ref = $objp->product_ref; - $this->libelle = $objp->product_libelle; // deprecated - $this->product_label = $objp->product_libelle; + + $this->product_ref = $objp->product_ref; + $this->product_label = $objp->product_label; $this->product_desc = $objp->product_desc; $this->product_tobatch = $objp->product_tobatch; $this->fk_unit = $objp->fk_unit; diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 8ec349c79f4..0c6b438b376 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4738,10 +4738,7 @@ class FactureLigne extends CommonInvoiceLine public $fk_facture; //! Id parent line public $fk_parent_line; - /** - * @deprecated - */ - public $label; + //! Description ligne public $desc; public $ref_ext; // External reference of the line @@ -4771,21 +4768,6 @@ class FactureLigne extends CommonInvoiceLine public $date_start; public $date_end; - // From llx_product - /** - * @deprecated - * @see $product_ref - */ - public $ref; // Product ref (deprecated) - public $product_ref; // Product ref - /** - * @deprecated - * @see $product_label - */ - public $libelle; // Product label (deprecated) - public $product_label; // Product label - public $product_desc; // Description produit - public $skip_update_total; // Skip update price total for special lines /** @@ -4825,7 +4807,7 @@ class FactureLigne extends CommonInvoiceLine $sql .= ' fd.multicurrency_total_ht,'; $sql .= ' fd.multicurrency_total_tva,'; $sql .= ' fd.multicurrency_total_ttc,'; - $sql .= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc'; + $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc'; $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid'; $sql .= ' WHERE fd.rowid = '.$rowid; @@ -4871,10 +4853,11 @@ class FactureLigne extends CommonInvoiceLine $this->marque_tx = $marginInfos[2]; $this->ref = $objp->product_ref; // deprecated - $this->product_ref = $objp->product_ref; - $this->libelle = $objp->product_libelle; // deprecated - $this->product_label = $objp->product_libelle; + + $this->product_ref = $objp->product_ref; + $this->product_label = $objp->product_label; $this->product_desc = $objp->product_desc; + $this->fk_unit = $objp->fk_unit; $this->fk_user_modif = $objp->fk_user_modif; $this->fk_user_author = $objp->fk_user_author; diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index 98890744701..920dd42f515 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -815,6 +815,47 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; */ abstract class CommonInvoiceLine extends CommonObjectLine { + /** + * Custom label of line. Not used by default. + * @deprecated + */ + public $label; + + /** + * @deprecated + * @see $product_ref + */ + public $ref; // Product ref (deprecated) + /** + * @deprecated + * @see $product_label + */ + public $libelle; // Product label (deprecated) + + /** + * Type of the product. 0 for product 1 for service + * @var int + */ + public $product_type = 0; + + /** + * Product ref + * @var string + */ + public $product_ref; + + /** + * Product label + * @var string + */ + public $product_label; + + /** + * Product description + * @var string + */ + public $product_desc; + /** * Quantity * @var double @@ -827,12 +868,6 @@ abstract class CommonInvoiceLine extends CommonObjectLine */ public $subprice; - /** - * Type of the product. 0 for product 1 for service - * @var int - */ - public $product_type = 0; - /** * Id of corresponding product * @var int diff --git a/htdocs/core/class/commonorder.class.php b/htdocs/core/class/commonorder.class.php index 83d20e99b95..8874175a138 100644 --- a/htdocs/core/class/commonorder.class.php +++ b/htdocs/core/class/commonorder.class.php @@ -38,6 +38,12 @@ abstract class CommonOrder extends CommonObject */ abstract class CommonOrderLine extends CommonObjectLine { + /** + * Custom label of line. Not used by default. + * @deprecated + */ + public $label; + /** * Product ref * @var string @@ -46,12 +52,6 @@ abstract class CommonOrderLine extends CommonObjectLine */ public $ref; - /** - * Product ref - * @var string - */ - public $product_ref; - /** * Product label * @var string @@ -60,6 +60,12 @@ abstract class CommonOrderLine extends CommonObjectLine */ public $libelle; + /** + * Product ref + * @var string + */ + public $product_ref; + /** * Product label * @var string diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 300a5032a2c..df0bb21a318 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3291,11 +3291,6 @@ class CommandeFournisseurLigne extends CommonOrderLine */ public $fk_facture; - /** - * @var string supplier order line label - */ - public $label; - public $rang = 0; public $special_code = 0; @@ -3316,7 +3311,6 @@ class CommandeFournisseurLigne extends CommonOrderLine */ public $ref_supplier; public $remise; - public $product_libelle; /** @@ -3344,7 +3338,7 @@ class CommandeFournisseurLigne extends CommonOrderLine $sql .= ' cd.remise, cd.remise_percent, cd.subprice,'; $sql .= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_ttc,'; $sql .= ' cd.total_localtax1, cd.total_localtax2,'; - $sql .= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc,'; + $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,'; $sql .= ' cd.date_start, cd.date_end, cd.fk_unit,'; $sql .= ' cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc'; if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) @@ -3387,8 +3381,9 @@ class CommandeFournisseurLigne extends CommonOrderLine $this->special_code = $objp->special_code; $this->ref = $objp->product_ref; + $this->product_ref = $objp->product_ref; - $this->product_libelle = $objp->product_libelle; + $this->product_label = $objp->product_label; $this->product_desc = $objp->product_desc; if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 589c4e82fc9..1761215705b 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -98,12 +98,18 @@ class FactureFournisseur extends CommonInvoice */ public $ref; - public $label; - public $libelle; // @deprecated - - public $product_ref; + /** + * @var string Ref supplier + */ public $ref_supplier; + + /** + * @var string Label of invoice + */ + public $label; + public $socid; + //Check constants for types public $type = self::TYPE_STANDARD; From 042a9f3efe73b405833e809d04e76c3f30292a3e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 19:39:54 +0200 Subject: [PATCH 202/317] Fix missing newtoken() --- htdocs/fourn/commande/dispatch.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 03297d9f8fc..c3d0a897362 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -1165,13 +1165,13 @@ if ($id > 0 || !empty($ref)) { if ($action == 'editline' && $lineid == $objp->dispatchlineid) { print ' - + - '; + '; } - print '
'; + print ''; if (!empty($conf->reception->enabled)) { print '
'.$langs->trans("Description").'
'.$form->editfieldkey("Date", 'datep', $object->date, $object, $object->statut == 0 && $user->rights->fournisseur->facture->creer).''; print $form->editfieldval("Date", 'datep', $object->date, $object, $object->statut == 0 && $user->rights->fournisseur->facture->creer, 'datehourpicker', '', null, $langs->trans('PaymentDateUpdateSucceeded')); print '
'; From 57702a1fb1882e869d9ff26fa31e2683cf9cd236 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Oct 2020 20:47:32 +0200 Subject: [PATCH 203/317] Retrieve commit a056d37f7255200ef0baf664a6b64516b2392dd9 --- htdocs/fourn/class/fournisseur.commande.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 4521eda40ac..ab489d02578 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -1344,7 +1344,7 @@ class CommandeFournisseur extends CommonOrder $sql .= ", ".$conf->entity; $sql .= ", ".$this->socid; $sql .= ", ".($this->fk_project > 0 ? $this->fk_project : "null"); - $sql .= ", '".$this->db->idate($now)."'"; + $sql .= ", '".$this->db->idate($date)."'"; $sql .= ", ".($this->date_livraison ? "'".$this->db->idate($this->date_livraison)."'" : "null"); $sql .= ", ".$user->id; $sql .= ", ".self::STATUS_DRAFT; From 54f9ed6346bbfc4b1ee2fa167b97b73fc70284a1 Mon Sep 17 00:00:00 2001 From: "jove@bisquerra.com" Date: Mon, 12 Oct 2020 22:07:05 +0200 Subject: [PATCH 204/317] NEW: Add third order printer to TakePOS --- htdocs/takepos/admin/orderprinters.php | 36 ++++++++++++++++++++++++++ htdocs/takepos/admin/terminal.php | 5 ++++ htdocs/takepos/invoice.php | 30 +++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/htdocs/takepos/admin/orderprinters.php b/htdocs/takepos/admin/orderprinters.php index b396655dea4..c7ebbebffb7 100644 --- a/htdocs/takepos/admin/orderprinters.php +++ b/htdocs/takepos/admin/orderprinters.php @@ -42,6 +42,7 @@ $catname = GETPOST('catname', 'alpha'); $action = GETPOST('action', 'aZ09'); $printer1 = GETPOST('printer1', 'alpha'); $printer2 = GETPOST('printer2', 'alpha'); +$printer3 = GETPOST('printer3', 'alpha'); if (is_numeric($type)) $type = Categorie::$MAP_ID_TO_CODE[$type]; // For backward compatibility @@ -64,6 +65,14 @@ if ($action == "SavePrinter2") { dolibarr_set_const($db, "TAKEPOS_PRINTED_CATEGORIES_2", $printedcategories, 'chaine', 0, '', $conf->entity); } +if ($action == "SavePrinter3") { + $printedcategories = ";"; + if (is_array($printer3)) foreach ($printer3 as $cat) { + $printedcategories = $printedcategories.$cat.";"; + } + dolibarr_set_const($db, "TAKEPOS_PRINTED_CATEGORIES_3", $printedcategories, 'chaine', 0, '', $conf->entity); +} + /* * View @@ -206,6 +215,33 @@ if ($nbofentries > 0) print '
'; print ''; } + +//Printer3 +print ''; +print ''; +$nbofentries = (count($data) - 1); +print ''; +if ($nbofentries > 0) +{ + print ''; +} else { + print ''; + print ''; + print ''; +} + print "
'.$langs->trans("Printer").' 3'; +print '
'; + print ''; + foreach ($data as $row) { + if (strpos($conf->global->TAKEPOS_PRINTED_CATEGORIES_3, ';'.$row["rowid"].';') !== false) $checked = 'checked'; else $checked = ''; + if ($row["fk_menu"] == 0) print ''.$row["label"].'
'; + } + print '
'; + print ''; + print ''; + print '
'.img_picto_common('', 'treemenu/branchbottom.gif').''; + print $langs->trans("NoCategoryYet"); + print ' 
"; print ''; diff --git a/htdocs/takepos/admin/terminal.php b/htdocs/takepos/admin/terminal.php index 384be4f8f13..108fdea0b64 100644 --- a/htdocs/takepos/admin/terminal.php +++ b/htdocs/takepos/admin/terminal.php @@ -87,6 +87,7 @@ if (GETPOST('action', 'alpha') == 'set') $res = dolibarr_set_const($db, "TAKEPOS_PRINTER_TO_USE".$terminaltouse, GETPOST('TAKEPOS_PRINTER_TO_USE'.$terminaltouse, 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_ORDER_PRINTER1_TO_USE".$terminaltouse, GETPOST('TAKEPOS_ORDER_PRINTER1_TO_USE'.$terminaltouse, 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_ORDER_PRINTER2_TO_USE".$terminaltouse, GETPOST('TAKEPOS_ORDER_PRINTER2_TO_USE'.$terminaltouse, 'alpha'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_ORDER_PRINTER3_TO_USE".$terminaltouse, GETPOST('TAKEPOS_ORDER_PRINTER3_TO_USE'.$terminaltouse, 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_TEMPLATE_TO_USE_FOR_INVOICES".$terminaltouse, GETPOST('TAKEPOS_TEMPLATE_TO_USE_FOR_INVOICES'.$terminaltouse, 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_TEMPLATE_TO_USE_FOR_ORDERS".$terminaltouse, GETPOST('TAKEPOS_TEMPLATE_TO_USE_FOR_ORDERS'.$terminaltouse, 'alpha'), 'chaine', 0, '', $conf->entity); @@ -242,6 +243,10 @@ if ($conf->global->TAKEPOS_PRINT_METHOD == "receiptprinter") { print ''; print $form->selectarray('TAKEPOS_ORDER_PRINTER2_TO_USE'.$terminal, $printers, (empty($conf->global->{'TAKEPOS_ORDER_PRINTER2_TO_USE'.$terminal}) ? '0' : $conf->global->{'TAKEPOS_ORDER_PRINTER2_TO_USE'.$terminal}), 1); print ''; + print ''.$langs->trans("OrderPrinterToUse").' - '.$langs->trans("Printer").' 3'; + print ''; + print $form->selectarray('TAKEPOS_ORDER_PRINTER3_TO_USE'.$terminal, $printers, (empty($conf->global->{'TAKEPOS_ORDER_PRINTER3_TO_USE'.$terminal}) ? '0' : $conf->global->{'TAKEPOS_ORDER_PRINTER3_TO_USE'.$terminal}), 1); + print ''; } $printer->listPrintersTemplates(); $templates = array(); diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index eee4faf9d43..82f97b88dc3 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -532,8 +532,10 @@ if ($action == "order" and $placeid != 0) $footerorder = ''.dol_print_date(dol_now(), 'dayhour').'
'; $order_receipt_printer1 = ""; $order_receipt_printer2 = ""; + $order_receipt_printer3 = ""; $catsprinter1 = explode(';', $conf->global->TAKEPOS_PRINTED_CATEGORIES_1); $catsprinter2 = explode(';', $conf->global->TAKEPOS_PRINTED_CATEGORIES_2); + $catsprinter3 = explode(';', $conf->global->TAKEPOS_PRINTED_CATEGORIES_3); foreach ($invoice->lines as $line) { if ($line->special_code == "4") { @@ -588,6 +590,34 @@ if ($action == "order" and $placeid != 0) $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='2' and fk_facture=".$invoice->id; // Set as printed $db->query($sql); $invoice->fetch($placeid); //Reload object after set lines as printed + $linestoprint = 0; + + foreach ($invoice->lines as $line) + { + if ($line->special_code == "4") { + continue; + } + $c = new Categorie($db); + $existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id'); + $result = array_intersect($catsprinter3, $existing); + $count = count($result); + if ($count > 0) { + $linestoprint++; + $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='3' where rowid=".$line->id; //Set to print on printer 3 + $db->query($sql); + $order_receipt_printer3 .= ''.$line->product_label.''.$line->qty; + if (!empty($line->array_options['options_order_notes'])) $order_receipt_printer3 .= "
(".$line->array_options['options_order_notes'].")"; + $order_receipt_printer3 .= ''; + } + } + if ($conf->global->TAKEPOS_PRINT_METHOD == "receiptprinter" && $linestoprint > 0) { + $invoice->fetch($placeid); //Reload object before send to printer + $printer->orderprinter = 3; + $ret = $printer->sendToPrinter($invoice, $conf->global->{'TAKEPOS_TEMPLATE_TO_USE_FOR_ORDERS'.$_SESSION["takeposterminal"]}, $conf->global->{'TAKEPOS_ORDER_PRINTER3_TO_USE'.$_SESSION["takeposterminal"]}); // PRINT TO PRINTER 3 + } + $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='3' and fk_facture=".$invoice->id; // Set as printed + $db->query($sql); + $invoice->fetch($placeid); //Reload object after set lines as printed } $sectionwithinvoicelink = ''; From d80931429e5139e8c7b9f66c2d7ddd81dce6f1d3 Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Mon, 12 Oct 2020 22:34:05 +0200 Subject: [PATCH 205/317] Fix travis --- htdocs/takepos/invoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index 82f97b88dc3..d77d31828cc 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -591,7 +591,7 @@ if ($action == "order" and $placeid != 0) $db->query($sql); $invoice->fetch($placeid); //Reload object after set lines as printed $linestoprint = 0; - + foreach ($invoice->lines as $line) { if ($line->special_code == "4") { From d66a1ac35029a2712b14a729aee9df1feff01f8c Mon Sep 17 00:00:00 2001 From: Philippe GRAND Date: Tue, 13 Oct 2020 10:05:44 +0200 Subject: [PATCH 206/317] fix Call to undefined method Form::formTransportMode() --- htdocs/fourn/facture/card.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index c42bf1c3991..2de5e76f369 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -2665,10 +2665,10 @@ if ($action == 'create') print ''; if ($action == 'editmode') { - $form->formTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'transport_mode_id', 1, 1); + $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'transport_mode_id', 1, 1); } else { - $form->formTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'none'); + $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'none'); } print ''; From 7c67dbf6d5bd1eb4bb7e56014313e434aa6fe016 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Oct 2020 10:05:47 +0200 Subject: [PATCH 207/317] Better responsive --- htdocs/comm/action/card.php | 19 +++++++--------- htdocs/comm/action/index.php | 12 +++++++--- htdocs/comm/action/pertype.php | 25 ++++----------------- htdocs/comm/action/peruser.php | 23 +++---------------- htdocs/core/class/html.form.class.php | 20 ++++++++++++----- htdocs/core/class/html.formprojet.class.php | 2 +- htdocs/theme/eldy/global.inc.php | 8 +++++-- htdocs/theme/md/style.css.php | 9 ++++++++ 8 files changed, 54 insertions(+), 64 deletions(-) diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php index 3c8ed94c2bf..4b88cc7797a 100644 --- a/htdocs/comm/action/card.php +++ b/htdocs/comm/action/card.php @@ -1068,12 +1068,14 @@ if ($action == 'create') // Location if (empty($conf->global->AGENDA_DISABLE_LOCATION)) { - print ''.$langs->trans("Location").''; + print ''.$langs->trans("Location").''; } // Assigned to print ''.$langs->trans("ActionAffectedTo").''; $listofuserid = array(); + $listofcontactid = array(); + $listofotherid = array(); if (empty($donotclearsession)) { $assignedtouser = GETPOST("assignedtouser") ?GETPOST("assignedtouser") : (!empty($object->userownerid) && $object->userownerid > 0 ? $object->userownerid : $user->id); @@ -1090,12 +1092,6 @@ if ($action == 'create') print '
'; print $form->select_dolusers_forevent(($action == 'create' ? 'add' : 'update'), 'assignedtouser', 1, '', 0, '', '', 0, 0, 0, 'AND u.statut != 0', 1, $listofuserid, $listofcontactid, $listofotherid); print '
'; - /*if (in_array($user->id,array_keys($listofuserid))) - { - print '
'; - print $langs->trans("MyAvailability").': '.$langs->trans("Busy"); - print '
'; - }*/ print ''; // Done by @@ -1108,9 +1104,9 @@ if ($action == 'create') if ($conf->categorie->enabled) { // Categories - print ''.$langs->trans("Categories").''; + print ''.$langs->trans("Categories").''; $cate_arbo = $form->select_all_categories(Categorie::TYPE_ACTIONCOMM, '', 'parent', 64, 0, 1); - print $form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, '', 0, '100%'); + print $form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, 'minwidth300 quatrevingtpercent', 0, 0); print ""; } @@ -1148,7 +1144,8 @@ if ($action == 'create') print ''.$langs->trans("ActionOnContact").''; $preselectedids = GETPOST('socpeopleassigned', 'array'); if (GETPOST('contactid', 'int')) $preselectedids[GETPOST('contactid', 'int')] = GETPOST('contactid', 'int'); - print img_picto('', 'contact', 'class="paddingrightonly"').$form->selectcontacts(GETPOST('socid', 'int'), $preselectedids, 'socpeopleassigned[]', 1, '', '', 0, 'quatrevingtpercent', false, 0, array(), false, 'multiple', 'contactid'); + print img_picto('', 'contact', 'class="paddingrightonly"'); + print $form->selectcontacts(GETPOST('socid', 'int'), $preselectedids, 'socpeopleassigned[]', 1, '', '', 0, 'minwidth300 quatrevingtpercent', false, 0, array(), false, 'multiple', 'contactid'); print ''; } @@ -1161,7 +1158,7 @@ if ($action == 'create') print ''.$langs->trans("Project").''; print img_picto('', 'project', 'class="paddingrightonly"'); - $numproject = $formproject->select_projects((!empty($societe->id) ? $societe->id : -1), $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 0, 0, 'maxwidth500'); + $numproject = $formproject->select_projects((!empty($societe->id) ? $societe->id : -1), $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 0, 0, 'maxwidth500 widthcentpercentminusxx'); print ' '; $urloption = '?action=create&donotclearsession=1'; diff --git a/htdocs/comm/action/index.php b/htdocs/comm/action/index.php index a48dc03aea2..7a52183b195 100644 --- a/htdocs/comm/action/index.php +++ b/htdocs/comm/action/index.php @@ -360,7 +360,9 @@ if (empty($action) || $action == 'show_month') $nav .= " ".dol_print_date(dol_mktime(0, 0, 0, $month, 1, $year), "%b %Y"); $nav .= " \n"; $nav .= "   \n"; - $nav .= "   ".$langs->trans("Today")." "; + if (empty($conf->dol_optimize_smallscreen)) { + $nav .= "   ".$langs->trans("Today")." "; + } $picto = 'calendar'; } if ($action == 'show_week') @@ -369,7 +371,9 @@ if ($action == 'show_week') $nav .= " ".dol_print_date(dol_mktime(0, 0, 0, $first_month, $first_day, $first_year), "%Y").", ".$langs->trans("Week")." ".$week; $nav .= " \n"; $nav .= "   trans("Next"))."\">\n"; - $nav .= "   ".$langs->trans("Today")." "; + if (empty($conf->dol_optimize_smallscreen)) { + $nav .= "   ".$langs->trans("Today")." "; + } $picto = 'calendarweek'; } if ($action == 'show_day') @@ -378,7 +382,9 @@ if ($action == 'show_day') $nav .= " ".dol_print_date(dol_mktime(0, 0, 0, $month, $day, $year), "daytextshort"); $nav .= " \n"; $nav .= "   \n"; - $nav .= "   ".$langs->trans("Today")." "; + if (empty($conf->dol_optimize_smallscreen)) { + $nav .= "   ".$langs->trans("Today")." "; + } $picto = 'calendarday'; } diff --git a/htdocs/comm/action/pertype.php b/htdocs/comm/action/pertype.php index 72b25c9d731..f0c1a0d1951 100644 --- a/htdocs/comm/action/pertype.php +++ b/htdocs/comm/action/pertype.php @@ -274,34 +274,17 @@ $lastdaytoshow = dol_time_plus_duree($firstdaytoshow, 7, 'd'); $max_day_in_month = date("t", dol_mktime(0, 0, 0, $month, 1, $year)); $tmpday = $first_day; -$picto = 'calendartype'; +$picto = 'calendarweek'; $nav = "".img_previous($langs->trans("Previous"))."\n"; $nav .= " ".dol_print_date(dol_mktime(0, 0, 0, $first_month, $first_day, $first_year), "%Y")." \n"; $nav .= "".img_next($langs->trans("Next"))."\n"; -$nav .= "   (".$langs->trans("Today").")"; -$picto = 'calendarweek'; +if (empty($conf->dol_optimize_smallscreen)) { + $nav .= "   (".$langs->trans("Today").")"; +} -/*$nav .= '  
'; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -$nav .= ''; -*/ $nav .= $form->selectDate($dateselect, 'dateselect', 0, 0, 1, '', 1, 0); -//$nav .= ' '; $nav .= ' '; -//$nav .= '
'; // Must be after the nav definition $param .= '&year='.urlencode($year).'&month='.urlencode($month).($day ? '&day='.urlencode($day) : ''); diff --git a/htdocs/comm/action/peruser.php b/htdocs/comm/action/peruser.php index f99cc3cbd16..899925b16f6 100644 --- a/htdocs/comm/action/peruser.php +++ b/htdocs/comm/action/peruser.php @@ -285,28 +285,11 @@ $nav = "".dol_print_date(dol_mktime(0, 0, 0, $first_month, $first_day, $first_year), "%Y").", ".$langs->trans("Week")." ".$week; $nav .= " \n"; $nav .= "   trans("Next"))."\">\n"; -$nav .= "   ".$langs->trans("Today")." "; - -/*$nav.='  
'; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -$nav.=''; -*/ +if (empty($conf->dol_optimize_smallscreen)) { + $nav .= "   ".$langs->trans("Today")." "; +} $nav .= $form->selectDate($dateselect, 'dateselect', 0, 0, 1, '', 1, 0); -//$nav .= ' '; $nav .= ' '; -//$nav.='
'; // Must be after the nav definition $param .= '&year='.urlencode($year).'&month='.urlencode($month).($day ? '&day='.urlencode($day) : ''); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index feddd6e4f24..e82d59ae3f4 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1848,7 +1848,7 @@ class Form if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) { $out .= '
'; - $out .= ' - '.$langs->trans("Availability").': '.$langs->trans("Busy"); + $out .= ' - '.$langs->trans("Availability").': '; $out .= '
'; } } @@ -5578,7 +5578,6 @@ class Form } // Show date with combo selects else { - //$retstring.='
'; // Day $retstring .= ''; @@ -5622,11 +5621,13 @@ class Form } $retstring .= "\n"; } - //$retstring.='
'; } } - if ($d && $h) $retstring .= ($h == 2 ? '
' : ' '); + if ($d && $h) { + $retstring .= ($h == 2 ? '
' : ' '); + $retstring.=''; + } if ($h) { @@ -5644,10 +5645,13 @@ class Form for ($hour = $hourstart; $hour < $hourend; $hour++) { if (strlen($hour) < 2) $hour = "0".$hour; - $retstring .= ''; + $retstring .= ''; } $retstring .= ''; - if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":"; + //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":"; + if ($m) $retstring .= ":"; } if ($m) @@ -5665,6 +5669,10 @@ class Form $retstring .= ''; } + if ($d && $h) { + $retstring .= ''; + } + // Add a "Now" link if ($conf->use_javascript_ajax && $addnowlink) { diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php index 9586adeaed4..eac04cfefc1 100644 --- a/htdocs/core/class/html.formprojet.class.php +++ b/htdocs/core/class/html.formprojet.class.php @@ -353,7 +353,7 @@ class FormProjets include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus); $out .= $comboenhancement; - $morecss = 'minwidth200imp maxwidth500'; + $morecss = 'minwidth200 maxwidth500'; } if (empty($option_only)) { diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index d6c5434ce94..5574056468d 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -1275,6 +1275,10 @@ table[summary="list_of_modules"] .fa-cog { width: calc(100% - 50px) !important; display: inline-block; } +.widthcentpercentminusxx { + width: calc(100% - 70px) !important; + display: inline-block; +} /* Force values for small screen 767 */ @media only screen and (max-width: 767px) @@ -1298,8 +1302,8 @@ table[summary="list_of_modules"] .fa-cog { margin-bottom: 15px !important; } - select.minwidth100imp, select.minwidth100, select.minwidth200, select.minwidth300 { - width: calc(100% - 50px) !important; + select.minwidth100imp, select.minwidth100, select.minwidth200, select.minwidth200imp, select.minwidth300 { + width: calc(100% - 40px) !important; display: inline-block; } diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 65afa0e017f..1a315169cc8 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1269,6 +1269,15 @@ table[summary="list_of_modules"] .fa-cog { .minwidth500imp { min-width: 250px !important; } } +.widthcentpercentminusx { + width: calc(100% - 50px) !important; + display: inline-block; +} +.widthcentpercentminusxx { + width: calc(100% - 70px) !important; + display: inline-block; +} + /* Force values for small screen 767 */ @media only screen and (max-width: 767px) { From bc6b5d919a01cb30c9b311b5bae7ad10df9a141e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Oct 2020 10:51:51 +0200 Subject: [PATCH 208/317] Better responsive --- htdocs/core/class/html.form.class.php | 2 +- htdocs/core/lib/functions.lib.php | 9 +++++---- htdocs/projet/element.php | 20 +++++++++----------- htdocs/projet/tasks.php | 10 +++++----- htdocs/theme/eldy/global.inc.php | 18 +++++++++++++----- htdocs/theme/md/style.css.php | 13 ++++++++++++- 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index e82d59ae3f4..452454ced5b 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -7265,7 +7265,7 @@ class Form } if ($morehtml) { - $ret .= '
  • '.$morehtml.'
  • '; + $ret .= '
  • '.$morehtml.'
  • '; } if ($shownav && ($previous_ref || $next_ref)) { diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 47a5d3d9330..7b705b4bd87 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1522,8 +1522,9 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]); $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5); if ($conf->browser->layout == 'phone') $maxvisiblephotos = 1; - if ($showimage) $morehtmlleft .= '
    '.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0).'
    '; - else { + if ($showimage) { + $morehtmlleft .= '
    '.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0).'
    '; + } else { if (!empty($conf->global->PRODUCT_NODISPLAYIFNOPHOTO)) { $nophoto = ''; $morehtmlleft .= '
    '; @@ -1610,9 +1611,9 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi // If the preview file is found if (file_exists($fileimage)) { - $phototoshow = '
    '; + $phototoshow = '
    '; $phototoshow .= ''; - $phototoshow .= '
    '; + $phototoshow .= '
    '; } } } elseif (!$phototoshow) diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index f6bb28edd56..966ad4cae92 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -590,21 +590,19 @@ $showdatefilter = 0; if (!$showdatefilter) { print '
    '; - print '
    '; + print ''; print ''; print ''; print ''; - print ''; - print ''; - print ''; - print ''; - print '
    '.$langs->trans("From").' '; - print $form->selectDate($dates, 'dates', 0, 0, 1, '', 1, 0); - print ''.$langs->trans("to").' '; - print $form->selectDate($datee, 'datee', 0, 0, 1, '', 1, 0); - print ''; + print '
    '; + print $form->selectDate($dates, 'dates', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); + print '
    '; + print '
    '; + print $form->selectDate($datee, 'datee', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); + print '
    '; + print '
    '; print ''; - print '
    '; + print '
    '; print ''; print '
    '; diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index 1336c870cbe..b0c97907f7d 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -539,7 +539,7 @@ if ($action == 'create' && $user->rights->projet->creer && (empty($object->third print ''; print ''.$langs->trans("Label").''; - print ''; + print ''; print ''; // List of projects @@ -704,16 +704,16 @@ if ($action == 'create' && $user->rights->projet->creer && (empty($object->third if (!empty($arrayfields['t.dateo']['checked'])) { print ''; - print ''; - print ''; + print ''; + print ''; $formother->select_year($search_dtstartyear ? $search_dtstartyear : -1, 'search_dtstartyear', 1, 20, 5); print ''; } if (!empty($arrayfields['t.datee']['checked'])) { print ''; - print ''; - print ''; + print ''; + print ''; $formother->select_year($search_dtendyear ? $search_dtendyear : -1, 'search_dtendyear', 1, 20, 5); print ''; } diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 5574056468d..5c493cd505e 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -1291,6 +1291,10 @@ table[summary="list_of_modules"] .fa-cog { padding-right: 5px; } + div.divphotoref { + padding-right: 10px !important; + } + .hideonsmartphone { display: none; } .hideonsmartphoneimp { display: none !important; } @@ -1306,11 +1310,6 @@ table[summary="list_of_modules"] .fa-cog { width: calc(100% - 40px) !important; display: inline-block; } - - .clearbothonsmartphone { clear: both; display: block; } - /*img.photoref, div.photoref { - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.2); - }*/ } /* Force values for small screen 570 */ @@ -3761,6 +3760,15 @@ ul.noborder li:nth-child(even):not(.liste_titre) { @media only screen and (max-width: 767px) { + .tabBar .arearef .pagination.paginationref { + max-width: calc(50%); + } + + .clearbothonsmartphone { + clear: both; + display: block !important; + } + div.tabs { padding-left: 0 !important; padding-right: 0!important; diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 1a315169cc8..0be0b85bbbc 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1288,7 +1288,9 @@ table[summary="list_of_modules"] .fa-cog { font-size: !important; } - .clearbothonsmartphone { clear: both; display: block; } + div.divphotoref { + padding-right: 10px !important; + } } /* Force values for small screen 570 */ @@ -3699,6 +3701,15 @@ ul.noborder li:nth-child(even):not(.liste_titre) { } @media only screen and (max-width: 767px) { + .tabBar .arearef .pagination.paginationref { + max-width: calc(50%); + } + + .clearbothonsmartphone { + clear: both; + display: block !important; + } + div.tabs { padding-left: 0 !important; margin-left: 0 !important; From 64e20959f6f7939c9e8afd7804a509bb4e2a9254 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Oct 2020 11:00:56 +0200 Subject: [PATCH 209/317] Fix bad link --- htdocs/takepos/invoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index eee4faf9d43..72106b84c84 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -863,7 +863,7 @@ if (!empty($conf->use_javascript_ajax)) print ''."\n"; print '
    '; print ''; -if ($mobilepage == "invoice" || $mobilepage == "") { +if ($sectionwithinvoicelink && ($mobilepage == "invoice" || $mobilepage == "")) { print ''; } print ''; From 969ed4acc17ab8839fef104bb6ffd87792174305 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Oct 2020 11:52:20 +0200 Subject: [PATCH 210/317] Better label for status schedule of cron tasks. --- htdocs/cron/class/cronjob.class.php | 4 ++-- htdocs/cron/list.php | 2 +- htdocs/langs/en_US/cron.lang | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index 10a2659f6a5..c5acbcf16bd 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -1285,9 +1285,9 @@ class Cronjob extends CommonObject elseif ($lastresult) $moretext .= ' ('.$langs->trans("Error").')'; $this->labelStatus[self::STATUS_DISABLED] = $langs->trans('Disabled').$moretext; - $this->labelStatus[self::STATUS_ENABLED] = $langs->trans('Enabled').$moretext; + $this->labelStatus[self::STATUS_ENABLED] = $langs->trans('Scheduled').$moretext; $this->labelStatusShort[self::STATUS_DISABLED] = $langs->trans('Disabled'); - $this->labelStatusShort[self::STATUS_ENABLED] = $langs->trans('Enabled'); + $this->labelStatusShort[self::STATUS_ENABLED] = $langs->trans('Scheduled'); } $statusType = 'status4'; diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index 927c1d1014f..cea8ce39016 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -372,7 +372,7 @@ print ''; print ''; print ''; print ''; } -// Filter: Bank transaction number +// Filter: Bank transaction number (placeholder) if (!empty($arrayfields['transaction']['checked'])) { print ''; @@ -315,16 +315,16 @@ print ''; print ''; print ''; -if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) print_liste_field_titre('#', $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); -if (!empty($arrayfields['t.rowid']['checked'])) print_liste_field_titre($arrayfields['t.rowid']['label'], $_SERVER['PHP_SELF'], 't.rowid', '', $param, '', $sortfield, $sortorder); -if (!empty($arrayfields['t.label']['checked'])) print_liste_field_titre($arrayfields['t.label']['label'], $_SERVER['PHP_SELF'], 't.label', '', $param, 'align="left"', $sortfield, $sortorder); -if (!empty($arrayfields['t.datev']['checked'])) print_liste_field_titre($arrayfields['t.datev']['label'], $_SERVER['PHP_SELF'], 't.datev', '', $param, 'align="center"', $sortfield, $sortorder); -if (!empty($arrayfields['t.datep']['checked'])) print_liste_field_titre($arrayfields['t.datep']['label'], $_SERVER['PHP_SELF'], 't.datep', '', $param, 'align="center"', $sortfield, $sortorder); -if (!empty($arrayfields['t.fk_typepayment']['checked'])) print_liste_field_titre($arrayfields['t.fk_typepayment']['label'], $_SERVER['PHP_SELF'], 't.fk_typepayment', '', $param, '', $sortfield, $sortorder, 'left '); -if (!empty($arrayfields['t.num_payment']['checked'])) print_liste_field_titre($arrayfields['t.num_payment']['label'], $_SERVER['PHP_SELF'], 't.num_payment', '', $param, '', $sortfield, $sortorder, '', $arrayfields['t.num_payment']['tooltip']); -if (!empty($arrayfields['transaction']['checked'])) print_liste_field_titre($arrayfields['transaction']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); -if (!empty($arrayfields['ba.label']['checked'])) print_liste_field_titre($arrayfields['ba.label']['label'], $_SERVER['PHP_SELF'], 'ba.label', '', $param, '', $sortfield, $sortorder, 'left '); -if (!empty($arrayfields['t.amount']['checked'])) print_liste_field_titre($arrayfields['t.amount']['label'], $_SERVER['PHP_SELF'], 't.amount', '', $param, '', $sortfield, $sortorder, 'right '); +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) print_liste_field_titre('#', $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['t.rowid']['checked'])) print_liste_field_titre($arrayfields['t.rowid']['label'], $_SERVER['PHP_SELF'], 't.rowid', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['t.label']['checked'])) print_liste_field_titre($arrayfields['t.label']['label'], $_SERVER['PHP_SELF'], 't.label', '', $param, 'align="left"', $sortfield, $sortorder); +if (!empty($arrayfields['t.datev']['checked'])) print_liste_field_titre($arrayfields['t.datev']['label'], $_SERVER['PHP_SELF'], 't.datev', '', $param, 'align="center"', $sortfield, $sortorder); +if (!empty($arrayfields['t.datep']['checked'])) print_liste_field_titre($arrayfields['t.datep']['label'], $_SERVER['PHP_SELF'], 't.datep', '', $param, 'align="center"', $sortfield, $sortorder); +if (!empty($arrayfields['t.fk_typepayment']['checked'])) print_liste_field_titre($arrayfields['t.fk_typepayment']['label'], $_SERVER['PHP_SELF'], 't.fk_typepayment', '', $param, '', $sortfield, $sortorder, 'left '); +if (!empty($arrayfields['t.num_payment']['checked'])) print_liste_field_titre($arrayfields['t.num_payment']['label'], $_SERVER['PHP_SELF'], 't.num_payment', '', $param, '', $sortfield, $sortorder, '', $arrayfields['t.num_payment']['tooltip']); +if (!empty($arrayfields['transaction']['checked'])) print_liste_field_titre($arrayfields['transaction']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['ba.label']['checked'])) print_liste_field_titre($arrayfields['ba.label']['label'], $_SERVER['PHP_SELF'], 'ba.label', '', $param, '', $sortfield, $sortorder, 'left '); +if (!empty($arrayfields['t.amount']['checked'])) print_liste_field_titre($arrayfields['t.amount']['label'], $_SERVER['PHP_SELF'], 't.amount', '', $param, '', $sortfield, $sortorder, 'right '); // Hook fields $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); @@ -334,13 +334,6 @@ print $hookmanager->resPrint; print_liste_field_titre($selectedfields, $_SERVER['PHP_SELF'], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); print ''; -$checkedCount = 0; -foreach ($arrayfields as $column) { - if ($column['checked']) { - $checkedCount++; - } -} - $i = 0; $totalarray = array(); while ($i < min($num, $limit)) { From dcd8a88e7282994eaa48d83fd844c14b102740c6 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 13 Oct 2020 13:28:23 +0000 Subject: [PATCH 219/317] Fixing style errors. --- htdocs/compta/tva/list.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/compta/tva/list.php b/htdocs/compta/tva/list.php index 9fbbad9420a..554143e7a7e 100644 --- a/htdocs/compta/tva/list.php +++ b/htdocs/compta/tva/list.php @@ -361,19 +361,19 @@ while ($i < min($num, $limit)) { print ''; if (!$i) $totalarray['nbfield']++; } - + // Date end period if (!empty($arrayfields['t.datev']['checked'])) { print ''; if (!$i) $totalarray['nbfield']++; } - + // Date payment if (!empty($arrayfields['t.datep']['checked'])) { print ''; if (!$i) $totalarray['nbfield']++; } - + // Type if (!empty($arrayfields['t.fk_typepayment']['checked'])) { @@ -402,10 +402,10 @@ while ($i < min($num, $limit)) { $bankstatic->ref = $obj->bref; $bankstatic->number = $obj->bnumber; $bankstatic->account_number = $obj->account_number; - + $accountingjournal->fetch($obj->fk_accountancy_journal); $bankstatic->accountancy_journal = $accountingjournal->getNomUrl(0, 1, 1, '', 1); - + $bankstatic->label = $obj->blabel; print $bankstatic->getNomUrl(1); } From c539c6d00d6f94d9107f1b2273230526e0fe1de4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Oct 2020 17:36:45 +0200 Subject: [PATCH 220/317] Responsive --- htdocs/compta/paiement/cheque/index.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/paiement/cheque/index.php b/htdocs/compta/paiement/cheque/index.php index 1ee79aeafd9..5e71ff5c50c 100644 --- a/htdocs/compta/paiement/cheque/index.php +++ b/htdocs/compta/paiement/cheque/index.php @@ -99,6 +99,7 @@ $sql .= $db->plimit($max); $resql = $db->query($sql); if ($resql) { + print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table print '
    '.$sectionwithinvoicelink.'
       '; -print $form->selectarray('search_status', array('0'=>$langs->trans("Disabled"), '1'=>$langs->trans("Enabled")), $search_status, 1); +print $form->selectarray('search_status', array('0'=>$langs->trans("Disabled"), '1'=>$langs->trans("Scheduled")), $search_status, 1); print ''; $searchpicto = $form->showFilterButtons(); print $searchpicto; diff --git a/htdocs/langs/en_US/cron.lang b/htdocs/langs/en_US/cron.lang index bb61ed13bbe..9921f21851d 100644 --- a/htdocs/langs/en_US/cron.lang +++ b/htdocs/langs/en_US/cron.lang @@ -47,6 +47,7 @@ CronNbRun=Number of launches CronMaxRun=Maximum number of launches CronEach=Every JobFinished=Job launched and finished +Scheduled=Scheduled #Page card CronAdd= Add jobs CronEvery=Execute job each @@ -57,7 +58,7 @@ CronNote=Comment CronFieldMandatory=Fields %s is mandatory CronErrEndDateStartDt=End date cannot be before start date StatusAtInstall=Status at module installation -CronStatusActiveBtn=Enable +CronStatusActiveBtn=Schedule CronStatusInactiveBtn=Disable CronTaskInactive=This job is disabled CronId=Id From dded02ebbf93ea6e9366a4fe8958e527a1f291b9 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 13 Oct 2020 12:06:28 +0200 Subject: [PATCH 211/317] FIX update dolibarr.pl for Virtualmin --- build/perl/virtualmin/dolibarr.pl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/build/perl/virtualmin/dolibarr.pl b/build/perl/virtualmin/dolibarr.pl index 343cebc6abe..8b6a9888db0 100644 --- a/build/perl/virtualmin/dolibarr.pl +++ b/build/perl/virtualmin/dolibarr.pl @@ -1,7 +1,7 @@ #---------------------------------------------------------------------------- # \file dolibarr.pl # \brief Dolibarr script install for Virtualmin Pro -# \author (c)2009-2019 Regis Houssin +# \author (c)2009-2020 Regis Houssin #---------------------------------------------------------------------------- @@ -30,7 +30,7 @@ return "Regis Houssin"; # script_dolibarr_versions() sub script_dolibarr_versions { -return ( "10.0.0", "9.0.3", "8.0.5", "7.0.5", "6.0.8" ); +return ( "12.0.3", "11.0.5", "10.0.7", "9.0.4", "8.0.6", "7.0.5" ); } sub script_dolibarr_release @@ -77,6 +77,16 @@ if ($ver >= 3.6) { push(@rv, "Dolibarr requires PHP version 5.3 or later"); } } +if ($ver >= 12.0) { + # Check for PHP 5.6+ + local $phpv = &get_php_version($phpver || 5, $d); + if (!$phpv) { + push(@rv, "Could not work out exact PHP version"); + } + elsif ($phpv < 5.6) { + push(@rv, "Dolibarr requires PHP version 5.6 or later"); + } + } return @rv; } @@ -376,7 +386,7 @@ sub script_dolibarr_realversion local ($d, $opts, $sinfo) = @_; local $lref = &read_file_lines("$opts->{'dir'}/filefunc.inc.php", 1); foreach my $l (@$lref) { - if ($l =~ /'DOL_VERSION','([0-9a-z\.\-]+)'/) { + if ($l =~ /'DOL_VERSION',\s?'([0-9a-z\.\-]+)'/) { return $1; } } @@ -390,6 +400,8 @@ sub script_dolibarr_check_latest { local ($ver) = @_; local @vers = &osdn_package_versions("dolibarr", + $ver >= 12.0 ? "dolibarr\\-(12\\.0\\.[0-9\\.]+)\\.tgz" : + $ver >= 11.0 ? "dolibarr\\-(11\\.0\\.[0-9\\.]+)\\.tgz" : $ver >= 10.0 ? "dolibarr\\-(10\\.0\\.[0-9\\.]+)\\.tgz" : $ver >= 9.0 ? "dolibarr\\-(9\\.0\\.[0-9\\.]+)\\.tgz" : $ver >= 8.0 ? "dolibarr\\-(8\\.0\\.[0-9\\.]+)\\.tgz" : @@ -410,7 +422,7 @@ return $ver eq $vers[0] ? undef : $vers[0]; sub script_dolibarr_site { -return 'http://www.dolibarr.org/'; +return 'https://www.dolibarr.org/'; } sub script_dolibarr_passmode From abfcb73a459d36bfd27ca42a7e1a103a3518f388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien?= Date: Tue, 13 Oct 2020 12:10:06 +0200 Subject: [PATCH 212/317] FIX unkwown columm tms #14947 --- htdocs/install/mysql/tables/llx_ecm_files.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/tables/llx_ecm_files.sql b/htdocs/install/mysql/tables/llx_ecm_files.sql index 52521e2af3e..030081b66b7 100644 --- a/htdocs/install/mysql/tables/llx_ecm_files.sql +++ b/htdocs/install/mysql/tables/llx_ecm_files.sql @@ -35,7 +35,7 @@ CREATE TABLE llx_ecm_files gen_or_uploaded varchar(12), -- 'generated' or 'uploaded' extraparams varchar(255), -- for stocking other parameters with json format date_c datetime, - date_m timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, fk_user_c integer, fk_user_m integer, acl text -- for future permission 'per file' From 1348c03ca01ab93f3b358c82addba72eb5f58b4a Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 13 Oct 2020 14:46:17 +0200 Subject: [PATCH 213/317] FIX avoid spaces in file name --- htdocs/admin/system/phpinfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/admin/system/phpinfo.php b/htdocs/admin/system/phpinfo.php index 05038c13bbc..c9f98457aee 100644 --- a/htdocs/admin/system/phpinfo.php +++ b/htdocs/admin/system/phpinfo.php @@ -265,8 +265,8 @@ $db->close(); */ function getActivatedExtensions() { - $file = getConfigFilePath(); - $handle = fopen(GetConfigFilePath(), "r"); + $file = trim(getConfigFilePath()); + $handle = fopen($file, "r"); $content = fread($handle, filesize($file)); fclose($handle); From 43a029ef2f9bf7abd0d1f885db4ac4cd0d24baec Mon Sep 17 00:00:00 2001 From: davidNDU Date: Tue, 13 Oct 2020 15:59:50 +0300 Subject: [PATCH 214/317] Model Builder template/class/myobject.class.php faulty SQL statement --- htdocs/modulebuilder/template/class/myobject.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/modulebuilder/template/class/myobject.class.php b/htdocs/modulebuilder/template/class/myobject.class.php index 18ca9b5ea20..2c03c3dd2a9 100644 --- a/htdocs/modulebuilder/template/class/myobject.class.php +++ b/htdocs/modulebuilder/template/class/myobject.class.php @@ -568,7 +568,7 @@ class MyObject extends CommonObject $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; $sql .= " SET ref = '".$this->db->escape($num)."',"; $sql .= " status = ".self::STATUS_VALIDATED; - if (!empty($this->fields['date_validation'])) $sql .= ", date_validation = '".$this->db->idate($now)."',"; + if (!empty($this->fields['date_validation'])) $sql .= ", date_validation = '".$this->db->idate($now)."'"; if (!empty($this->fields['fk_user_valid'])) $sql .= ", fk_user_valid = ".$user->id; $sql .= " WHERE rowid = ".$this->id; From 035325152f4f9dd67dc890e520dc62ea3bd4d041 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Oct 2020 15:02:05 +0200 Subject: [PATCH 215/317] Fix migration --- htdocs/install/mysql/migration/12.0.0-13.0.0.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 80e86ae747a..43868da4a1b 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -139,7 +139,7 @@ CREATE TABLE llx_intracommreport content_xml text, type_export varchar(10), datec datetime, - tms timestamp + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, )ENGINE=innodb; ALTER TABLE llx_c_incoterms ADD COLUMN label varchar(100) NULL; From 00ee1a743316238c82ae1f5868990d66e17e6107 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 13 Oct 2020 15:08:43 +0200 Subject: [PATCH 216/317] FIX compatibility with LF (Line Feed) --- htdocs/admin/system/phpinfo.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/htdocs/admin/system/phpinfo.php b/htdocs/admin/system/phpinfo.php index c9f98457aee..9f1766a5d22 100644 --- a/htdocs/admin/system/phpinfo.php +++ b/htdocs/admin/system/phpinfo.php @@ -273,6 +273,11 @@ function getActivatedExtensions() $configLines = explode("\r", $content); + // For compatibility with LF (Line Feed) + if (empty($configLines) || count($configLines) < 2) { + $configLines = explode("\n", $content); + } + $extensions = array(); $lastLine = ""; @@ -281,11 +286,13 @@ function getActivatedExtensions() $line = trim($line); // ignore comment lines - if (substr($line, 0, 1) === ";") + if (substr($line, 0, 1) === ";" || empty($line)) { continue; } + // var_dump($line); + // extension if (substr($line, 0, 9) === "extension" && substr($line, 0, 10) !== "extension_") { From dfff32f23947416c42e2078492dacf6f0016775e Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Tue, 13 Oct 2020 15:09:25 +0200 Subject: [PATCH 217/317] Selectable columns on sales tax list --- htdocs/compta/tva/list.php | 619 +++++++++++++++++++++++-------------- 1 file changed, 391 insertions(+), 228 deletions(-) diff --git a/htdocs/compta/tva/list.php b/htdocs/compta/tva/list.php index 82829fca12e..9bae56e23a3 100644 --- a/htdocs/compta/tva/list.php +++ b/htdocs/compta/tva/list.php @@ -1,8 +1,9 @@ - * Copyright (C) 2004-2020 Laurent Destailleur - * Copyright (C) 2005-2009 Regis Houssin - * Copyright (C) 2011-2019 Alexandre Spangaro +/* Copyright (C) 2001-2003 Rodolphe Quiedeville + * Copyright (C) 2004-2020 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2011-2019 Alexandre Spangaro + * Copyright (C) 2020 Tobias Sekan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,12 +20,18 @@ */ /** - * \file htdocs/compta/tva/list.php - * \ingroup tax - * \brief List of VAT payments + * \file htdocs/compta/tva/list.php + * \ingroup tax + * \brief List of VAT payments */ require '../../main.inc.php'; + +// Security check +$socid = GETPOST('socid', 'int'); +if ($user->socid) $socid = $user->socid; +$result = restrictedArea($user, 'tax', '', '', 'charges'); + require_once DOL_DOCUMENT_ROOT.'/compta/tva/class/tva.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; @@ -34,61 +41,79 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php'; // Load translation files required by the page $langs->loadLangs(array('compta', 'bills')); -// Security check -$socid = GETPOST('socid', 'int'); -if ($user->socid) $socid = $user->socid; -$result = restrictedArea($user, 'tax', '', '', 'charges'); +$action = GETPOST('action', 'alpha'); +$massaction = GETPOST('massaction', 'alpha'); +$confirm = GETPOST('confirm', 'alpha'); +$optioncss = GETPOST('optioncss', 'alpha'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'salestaxeslist'; -$search_ref = GETPOST('search_ref', 'int'); -$search_label = GETPOST('search_label', 'alpha'); -$search_account = GETPOST('search_account', 'int'); -$search_dateend_start = dol_mktime(0, 0, 0, GETPOST('search_dateend_startmonth', 'int'), GETPOST('search_dateend_startday', 'int'), GETPOST('search_dateend_startyear', 'int')); -$search_dateend_end = dol_mktime(23, 59, 59, GETPOST('search_dateend_endmonth', 'int'), GETPOST('search_dateend_endday', 'int'), GETPOST('search_dateend_endyear', 'int')); -$search_datepayment_start = dol_mktime(0, 0, 0, GETPOST('search_datepayment_startmonth', 'int'), GETPOST('search_datepayment_startday', 'int'), GETPOST('search_datepayment_startyear', 'int')); -$search_datepayment_end = dol_mktime(23, 59, 59, GETPOST('search_datepayment_endmonth', 'int'), GETPOST('search_datepayment_endday', 'int'), GETPOST('search_datepayment_endyear', 'int')); -$search_amount = GETPOST('search_amount', 'alpha'); -$month = GETPOST("month", "int"); -$year = GETPOST("year", "int"); +$search_ref = GETPOST('search_ref', 'alpha'); +$search_label = GETPOST('search_label', 'alpha'); +$search_dateend_start = dol_mktime(0, 0, 0, GETPOST('search_dateend_startmonth', 'int'), GETPOST('search_dateend_startday', 'int'), GETPOST('search_dateend_startyear', 'int')); +$search_dateend_end = dol_mktime(23, 59, 59, GETPOST('search_dateend_endmonth', 'int'), GETPOST('search_dateend_endday', 'int'), GETPOST('search_dateend_endyear', 'int')); +$search_datepayment_start = dol_mktime(0, 0, 0, GETPOST('search_datepayment_startmonth', 'int'), GETPOST('search_datepayment_startday', 'int'), GETPOST('search_datepayment_startyear', 'int')); +$search_datepayment_end = dol_mktime(23, 59, 59, GETPOST('search_datepayment_endmonth', 'int'), GETPOST('search_datepayment_endday', 'int'), GETPOST('search_datepayment_endyear', 'int')); +$search_type = GETPOST('search_type', 'int'); +$search_cheque = GETPOST('search_cheque', 'alpha'); +$search_account = GETPOST('search_account', 'int'); +$search_amount = GETPOST('search_amount', 'alpha'); -$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; -$sortfield = GETPOST("sortfield", 'alpha'); -$sortorder = GETPOST("sortorder", 'alpha'); -$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); -if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST('page', 'int'); + +if (empty($page) || $page == -1) $page = 0; // If $page is not defined, or '' or -1 $offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; -if (!$sortfield) $sortfield = "t.datev"; -if (!$sortorder) $sortorder = "DESC"; -$filtre = $_GET["filtre"]; +if (!$sortfield) $sortfield = 't.datev'; +if (!$sortorder) $sortorder = 'DESC'; -if (empty($_REQUEST['typeid'])) -{ - $newfiltre = str_replace('filtre=', '', $filtre); - $filterarray = explode('-', $newfiltre); - foreach ($filterarray as $val) +$arrayfields = array( + 't.rowid' =>array('checked'=>1, 'position'=>10, 'label'=>"Ref",), + 't.label' =>array('checked'=>1, 'position'=>20, 'label'=>"Label"), + 't.datev' =>array('checked'=>1, 'position'=>30, 'label'=>"PeriodEndDate"), + 't.datep' =>array('checked'=>1, 'position'=>40, 'label'=>"DatePayment"), + 't.fk_typepayment' =>array('checked'=>1, 'position'=>50, 'label'=>"Type"), + 't.num_payment' =>array('checked'=>1, 'position'=>60, 'label'=>"Numero", 'tooltip'=>"ChequeOrTransferNumber"), + 'transaction' =>array('checked'=>1, 'position'=>70, 'label'=>"BankTransactionLine", 'enabled'=>(!empty($conf->banque->enabled))), + 'ba.label' =>array('checked'=>1, 'position'=>80, 'label'=>"Account", 'enable'=>(!empty($conf->banque->enabled))), + 't.amount' =>array('checked'=>1, 'position'=>90, 'label'=>"PayedByThisPayment"), +); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('salestaxeslist')); +$object = new Tva($db); + + +/* + * Actions + */ + +$parameters = array('socid'=>$socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + +if (empty($reshook)) { + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // Both test are required to be compatible with all browsers { - $part = explode(':', $val); - if ($part[0] == 't.fk_typepayment') $typeid = $part[1]; + $search_ref = ''; + $search_label = ''; + $search_dateend_start = ''; + $search_dateend_end = ''; + $search_datepayment_start = ''; + $search_datepayment_end = ''; + $search_type = ''; + $search_cheque = ''; + $search_account = ''; + $search_amount = ''; } -} else { - $typeid = $_REQUEST['typeid']; -} - -if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // Both test are required to be compatible with all browsers -{ - $search_ref = ""; - $search_label = ""; - $search_dateend_start = ''; - $search_dateend_end = ''; - $search_datepayment_start = ''; - $search_datepayment_end = ''; - $search_account = ''; - $search_amount = ""; - $year = ""; - $month = ""; - $typeid = ""; } @@ -96,194 +121,332 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x' * View */ -llxHeader('', $langs->trans("VATPayments")); - $form = new Form($db); $formother = new FormOther($db); $tva_static = new Tva($db); $bankstatic = new Account($db); +$accountingjournal = new AccountingJournal($db); +$bankline = new AccountLine($db); + +llxHeader('', $langs->trans("VATPayments")); + +$sql = 'SELECT t.rowid, t.amount, t.label, t.datev, t.datep, t.fk_typepayment as type, t.num_payment, t.fk_bank'; +$sql .= ', ba.rowid as bid, ba.ref as bref, ba.number as bnumber, ba.account_number, ba.fk_accountancy_journal, ba.label as blabel'; +$sql .= ', pst.code as payment_code'; +$sql .= ' FROM '.MAIN_DB_PREFIX.'tva as t'; +$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as pst ON t.fk_typepayment = pst.id'; +$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON t.fk_bank = b.rowid'; +$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid'; +$sql .= ' WHERE t.entity IN ('.getEntity($object->element).')'; + +if (!empty($search_ref)) $sql .= natural_search('t.rowid', $search_ref); +if (!empty($search_label)) $sql .= natural_search('t.label', $search_label); +if (!empty($search_dateend_start)) $sql .= ' AND t.datev >= "'.$db->idate($search_dateend_start).'"'; +if (!empty($search_dateend_end)) $sql .= ' AND t.datev <= "'.$db->idate($search_dateend_end).'"'; +if (!empty($search_datepayment_start)) $sql .= ' AND t.datep >= "'.$db->idate($search_datepayment_start).'"'; +if (!empty($search_datepayment_end)) $sql .= ' AND t.datep <= "'.$db->idate($search_datepayment_end).'"'; +if (!empty($search_type) && $search_type > 0) $sql .= ' AND t.fk_typepayment='.$search_type; +if (!empty($search_cheque)) $sql .= natural_search('t.num_payment', $search_cheque); +if (!empty($search_account) && $search_account > 0) $sql .= ' AND b.fk_account='.$search_account; +if (!empty($search_amount)) $sql .= natural_search('t.amount', price2num(trim($search_amount)), 1); -$sql = "SELECT t.rowid, t.amount, t.label, t.datev, t.datep, t.fk_typepayment as type, t.num_payment, t.fk_bank, pst.code as payment_code,"; -$sql .= " ba.rowid as bid, ba.ref as bref, ba.number as bnumber, ba.account_number, ba.fk_accountancy_journal, ba.label as blabel"; -$sql .= " FROM ".MAIN_DB_PREFIX."tva as t"; -$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pst ON t.fk_typepayment = pst.id"; -$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON t.fk_bank = b.rowid"; -$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON b.fk_account = ba.rowid"; -$sql .= " WHERE t.entity IN (".getEntity('tax').")"; -if ($search_ref) $sql .= natural_search("t.rowid", $search_ref); -if ($search_label) $sql .= natural_search("t.label", $search_label); -if ($search_account > 0) $sql .= " AND b.fk_account=".$search_account; -if ($search_amount) $sql .= natural_search("t.amount", price2num(trim($search_amount)), 1); -if ($search_dateend_start) $sql .= " AND t.datev >= '".$db->idate($search_dateend_start)."'"; -if ($search_dateend_end) $sql .= " AND t.datev <= '".$db->idate($search_dateend_end)."'"; -if ($search_datepayment_start) $sql .= " AND t.datep >= '".$db->idate($search_datepayment_start)."'"; -if ($search_datepayment_end) $sql .= " AND t.datep <= '".$db->idate($search_datepayment_end)."'"; -if ($filtre) { - $filtre = str_replace(":", "=", $filtre); - $sql .= " AND ".$filtre; -} -if ($typeid) { - $sql .= " AND t.fk_typepayment=".$typeid; -} $sql .= $db->order($sortfield, $sortorder); -$totalnboflines = 0; -$result = $db->query($sql); -if ($result) -{ - $totalnboflines = $db->num_rows($result); + +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); + + // if total resultset is smaller then paging size (filtering), goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) { + $page = 0; + $offset = 0; + } } + $sql .= $db->plimit($limit + 1, $offset); $result = $db->query($sql); -if ($result) +if (!$result) { - $num = $db->num_rows($result); - $i = 0; - $total = 0; - - $param = ''; - if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.$contextpage; - if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.$limit; - if ($typeid) $param .= '&typeid='.$typeid; - - $url = DOL_URL_ROOT.'/compta/tva/card.php?action=create'; - if (!empty($socid)) $url .= '&socid='.$socid; - $newcardbutton = dolGetButtonTitle($langs->trans('NewVATPayment', ($ltt + 1)), '', 'fa fa-plus-circle', $url, '', $user->rights->tax->charges->creer); - - print '
    '; - if ($optioncss != '') print ''; - print ''; - print ''; - print ''; - print ''; - - print_barre_liste($langs->trans("VATPayments"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $totalnboflines, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1); - - print '
    '; - print ''."\n"; - - print ''; - // Ref - print ''; - // Label - print ''; - // Date end period - print ''; - // Account - if (!empty($conf->banque->enabled)) - { - print ''; - } - // Amount - print ''; - print ''; - print "\n"; - - print ''; - print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "t.rowid", "", $param, "", $sortfield, $sortorder); - print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "t.label", "", $param, 'align="left"', $sortfield, $sortorder); - print_liste_field_titre("PeriodEndDate", $_SERVER["PHP_SELF"], "t.datev", "", $param, 'align="center"', $sortfield, $sortorder); - print_liste_field_titre("DatePayment", $_SERVER["PHP_SELF"], "t.datep", "", $param, 'align="center"', $sortfield, $sortorder); - print_liste_field_titre("Type", $_SERVER["PHP_SELF"], "type", "", $param, '', $sortfield, $sortorder, 'left '); - if (!empty($conf->banque->enabled)) print_liste_field_titre("Account", $_SERVER["PHP_SELF"], "ba.label", "", $param, "", $sortfield, $sortorder); - print_liste_field_titre("PayedByThisPayment", $_SERVER["PHP_SELF"], "t.amount", "", $param, '', $sortfield, $sortorder, 'right '); - print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch '); - print "\n"; - - while ($i < min($num, $limit)) - { - $obj = $db->fetch_object($result); - - if ($obj->payment_code <> '') - { - $type = ''; - } else { - $type = ''; - } - - print ''; - - $tva_static->id = $obj->rowid; - $tva_static->ref = $obj->rowid; - - // Ref - print "\n"; - // Label - print "\n"; - // Date end period - print '\n"; - // Date payment - print '\n"; - // Type - print $type; - // Account - if (!empty($conf->banque->enabled)) - { - print ''; - } - // Amount - $total = $total + $obj->amount; - print '"; - print ""; - print "\n"; - - $i++; - } - - $colspan = 5; - if (!empty($conf->banque->enabled)) $colspan++; - print ''; - print ''; - print ""; - - print "
    '; - print '
    '; - print $form->selectDate($search_dateend_start ? $search_dateend_start : -1, 'search_dateend_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); - print '
    '; - print '
    '; - print $form->selectDate($search_dateend_end ? $search_dateend_end : -1, 'search_dateend_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); - print '
    '; - // Date payment - print '
    '; - print '
    '; - print $form->selectDate($search_datepayment_start ? $search_datepayment_start : -1, 'search_datepayment_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); - print '
    '; - print '
    '; - print $form->selectDate($search_datepayment_end ? $search_datepayment_end : -1, 'search_datepayment_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); - print '
    '; - // Type - print '
    '; - $form->select_types_paiements($typeid, 'typeid', '', 0, 1, 1, 16); - print ''; - $form->select_comptes($search_account, 'search_account', 0, '', 1); - print ''; - $searchpicto = $form->showFilterAndCheckAddButtons(0); - print $searchpicto; - print '
    '.$langs->trans("PaymentTypeShort".$obj->payment_code).' '.$obj->num_payment.' 
    ".$tva_static->getNomUrl(1)."".dol_trunc($obj->label, 40)."'.dol_print_date($db->jdate($obj->datev), 'day')."'.dol_print_date($db->jdate($obj->datep), 'day')."'; - if ($obj->fk_bank > 0) - { - $bankstatic->id = $obj->bid; - $bankstatic->ref = $obj->bref; - $bankstatic->number = $obj->bnumber; - $bankstatic->account_number = $obj->account_number; - - $accountingjournal = new AccountingJournal($db); - $accountingjournal->fetch($obj->fk_accountancy_journal); - $bankstatic->accountancy_journal = $accountingjournal->getNomUrl(0, 1, 1, '', 1); - - $bankstatic->label = $obj->blabel; - print $bankstatic->getNomUrl(1); - } else print ' '; - print ''.price($obj->amount)." 
    '.$langs->trans("Total").''.price($total).' 
    "; - print '
    '; - - print '
    '; - - $db->free($result); -} else { - dol_print_error($db); + dol_print_error($db); + llxFooter(); + $db->close(); + exit; } +$num = $db->num_rows($result); + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER['PHP_SELF']) $param .= '&contextpage='.$contextpage; +if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.$limit; +if ($optioncss != '') $param .= '&optioncss='.urlencode($optioncss); + +if (!empty($search_ref)) $param .= '&search_ref="'.$search_ref.'"'; +if (!empty($search_label)) $param .= '&search_label="'.$search_label.'"'; +if (!empty($search_dateend_start)) $param .= '&search_dateend_startyear='.GETPOST('search_dateend_startyear', 'int'); +if (!empty($search_dateend_start)) $param .= '&search_dateend_startmonth='.GETPOST('search_dateend_startmonth', 'int'); +if (!empty($search_dateend_start)) $param .= '&search_dateend_startday='.GETPOST('search_dateend_startday', 'int'); +if (!empty($search_dateend_end)) $param .= '&search_dateend_endyear='.GETPOST('search_dateend_endyear', 'int'); +if (!empty($search_dateend_end)) $param .= '&search_dateend_endmonth='.GETPOST('search_dateend_endmonth', 'int'); +if (!empty($search_dateend_end)) $param .= '&search_dateend_endday='.GETPOST('search_dateend_endday', 'int'); +if (!empty($search_datepayment_start)) $param .= '&search_datepayment_startyear='.GETPOST('search_datepayment_startyear', 'int'); +if (!empty($search_datepayment_start)) $param .= '&search_datepayment_startmonth='.GETPOST('search_datepayment_startmonth', 'int'); +if (!empty($search_datepayment_start)) $param .= '&search_datepayment_startday='.GETPOST('search_datepayment_startday', 'int'); +if (!empty($search_datepayment_end)) $param .= '&search_datepayment_endyear='.GETPOST('search_datepayment_endyear', 'int'); +if (!empty($search_datepayment_end)) $param .= '&search_datepayment_endmonth='.GETPOST('search_datepayment_endmonth', 'int'); +if (!empty($search_datepayment_end)) $param .= '&search_datepayment_endday='.GETPOST('search_datepayment_endday', 'int'); +if (!empty($search_type) && $search_type > 0) $param .= '&search_type='.$search_type; +if (!empty($search_cheque)) $param .= '&search_cheque="'.$search_cheque.'"'; +if (!empty($search_account) && $search_account > 0) $param .= '&search_account='.$search_account; +if (!empty($search_amount)) $param .= '&search_amount="'.$search_amount.'"'; + +print '
    '; +if ($optioncss != '') print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$url = DOL_URL_ROOT.'/compta/tva/card.php?action=create'; +if (!empty($socid)) $url .= '&socid='.$socid; +$newcardbutton = dolGetButtonTitle($langs->trans('NewVATPayment', ($ltt + 1)), '', 'fa fa-plus-circle', $url, '', $user->rights->tax->charges->creer); +print_barre_liste($langs->trans("VATPayments"), $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1); + +$varpage = empty($contextpage) ? $_SERVER['PHP_SELF'] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +if ($massactionbutton) $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); + +print '
    '; +print ''; + +print ''; + +// Filters: Lines (placeholder) +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; +} + +// Filter: Ref +if (!empty($arrayfields['t.rowid']['checked'])) { + print ''; +} + +// Filter: Label +if (!empty($arrayfields['t.label']['checked'])) { + print ''; +} + +// Filter: Date end period +if (!empty($arrayfields['t.datev']['checked'])) { + print ''; +} + +// Filter: Date payment +if (!empty($arrayfields['t.datep']['checked'])) { + print ''; +} + +// Filter: Type +if (!empty($arrayfields['t.fk_typepayment']['checked'])) { + print ''; +} + +// Filter: Cheque number +if (!empty($arrayfields['t.num_payment']['checked'])) { + print ''; +} + +// Filter: Bank transaction number +if (!empty($arrayfields['transaction']['checked'])) { + print ''; +} + +// Filter: Bank account +if (!empty($arrayfields['ba.label']['checked'])) { + print ''; +} + +// Filter: Amount +if (!empty($arrayfields['t.amount']['checked'])) { + print ''; +} + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +// Filter: Buttons +print ''; + +print ''; + +print ''; +if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) print_liste_field_titre('#', $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['t.rowid']['checked'])) print_liste_field_titre($arrayfields['t.rowid']['label'], $_SERVER['PHP_SELF'], 't.rowid', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['t.label']['checked'])) print_liste_field_titre($arrayfields['t.label']['label'], $_SERVER['PHP_SELF'], 't.label', '', $param, 'align="left"', $sortfield, $sortorder); +if (!empty($arrayfields['t.datev']['checked'])) print_liste_field_titre($arrayfields['t.datev']['label'], $_SERVER['PHP_SELF'], 't.datev', '', $param, 'align="center"', $sortfield, $sortorder); +if (!empty($arrayfields['t.datep']['checked'])) print_liste_field_titre($arrayfields['t.datep']['label'], $_SERVER['PHP_SELF'], 't.datep', '', $param, 'align="center"', $sortfield, $sortorder); +if (!empty($arrayfields['t.fk_typepayment']['checked'])) print_liste_field_titre($arrayfields['t.fk_typepayment']['label'], $_SERVER['PHP_SELF'], 't.fk_typepayment', '', $param, '', $sortfield, $sortorder, 'left '); +if (!empty($arrayfields['t.num_payment']['checked'])) print_liste_field_titre($arrayfields['t.num_payment']['label'], $_SERVER['PHP_SELF'], 't.num_payment', '', $param, '', $sortfield, $sortorder, '', $arrayfields['t.num_payment']['tooltip']); +if (!empty($arrayfields['transaction']['checked'])) print_liste_field_titre($arrayfields['transaction']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); +if (!empty($arrayfields['ba.label']['checked'])) print_liste_field_titre($arrayfields['ba.label']['label'], $_SERVER['PHP_SELF'], 'ba.label', '', $param, '', $sortfield, $sortorder, 'left '); +if (!empty($arrayfields['t.amount']['checked'])) print_liste_field_titre($arrayfields['t.amount']['label'], $_SERVER['PHP_SELF'], 't.amount', '', $param, '', $sortfield, $sortorder, 'right '); + +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print_liste_field_titre($selectedfields, $_SERVER['PHP_SELF'], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); +print ''; + +$checkedCount = 0; +foreach ($arrayfields as $column) { + if ($column['checked']) { + $checkedCount++; + } +} + +$i = 0; +$totalarray = array(); +while ($i < min($num, $limit)) { + $obj = $db->fetch_object($result); + + $tva_static->id = $obj->rowid; + $tva_static->ref = $obj->rowid; + + print ''; + + // No + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER_IN_LIST)) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Ref + if (!empty($arrayfields['t.rowid']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Label + if (!empty($arrayfields['t.label']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Date end period + if (!empty($arrayfields['t.datev']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Date payment + if (!empty($arrayfields['t.datep']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Type + if (!empty($arrayfields['t.fk_typepayment']['checked'])) + { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Cheque number + if (!empty($arrayfields['t.num_payment']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Bank transaction + if (!empty($arrayfields['transaction']['checked'])) { + $bankline->fetch($obj->fk_bank); + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Account + if (!empty($arrayfields['ba.label']['checked'])) { + print ''; + if (!$i) $totalarray['nbfield']++; + } + + // Amount + $total = $total + $obj->amount; + print ''; + if (!$i) $totalarray['nbfield']++; + $totalarray['pos'][$totalarray['nbfield']] = 'amount'; + $totalarray['val']['amount'] += $objp->amount; + + // Buttons + print ''; + + print ''; + + $i++; +} + +// Add a buttons placeholder for the total line +$totalarray['nbfield']++; + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +print '
    '; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
    '; + print $form->selectDate($search_dateend_start ? $search_dateend_start : -1, 'search_dateend_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); + print '
    '; + print '
    '; + print $form->selectDate($search_dateend_end ? $search_dateend_end : -1, 'search_dateend_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); + print '
    '; + print '
    '; + print '
    '; + print $form->selectDate($search_datepayment_start ? $search_datepayment_start : -1, 'search_datepayment_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); + print '
    '; + print '
    '; + print $form->selectDate($search_datepayment_end ? $search_datepayment_end : -1, 'search_datepayment_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); + print '
    '; + print '
    '; + $form->select_types_paiements($search_type, 'search_type', '', 0, 1, 1, 16); + print ''; + print ''; + print ''; + print ''; + $form->select_comptes($search_account, 'search_account', 0, '', 1); + print ''; + print ''; + print ''; +print $form->showFilterAndCheckAddButtons(0); +print '
    '.(($offset * $limit) + $i).''.$tva_static->getNomUrl(1).''.dol_trunc($obj->label, 40).''.dol_print_date($db->jdate($obj->datev), 'day').''.dol_print_date($db->jdate($obj->datep), 'day').''.$langs->trans("PaymentTypeShort".$obj->payment_code).''.$obj->num_payment.''.$bankline->getNomUrl(1, 0).''; + if ($obj->fk_bank > 0) { + $bankstatic->id = $obj->bid; + $bankstatic->ref = $obj->bref; + $bankstatic->number = $obj->bnumber; + $bankstatic->account_number = $obj->account_number; + + $accountingjournal->fetch($obj->fk_accountancy_journal); + $bankstatic->accountancy_journal = $accountingjournal->getNomUrl(0, 1, 1, '', 1); + + $bankstatic->label = $obj->blabel; + print $bankstatic->getNomUrl(1); + } + print ''.price($obj->amount).'
    '; +print '
    '; +print '
    '; + +$db->free($result); + // End of page llxFooter(); $db->close(); From f28e1dc4fbf67bdd19f0ee5ab4fde793c20bfbff Mon Sep 17 00:00:00 2001 From: "Sekan, Tobias" Date: Tue, 13 Oct 2020 15:27:42 +0200 Subject: [PATCH 218/317] cleanup --- htdocs/compta/tva/list.php | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/htdocs/compta/tva/list.php b/htdocs/compta/tva/list.php index 9bae56e23a3..9fbbad9420a 100644 --- a/htdocs/compta/tva/list.php +++ b/htdocs/compta/tva/list.php @@ -282,7 +282,7 @@ if (!empty($arrayfields['t.num_payment']['checked'])) { print '
    '; print '
    '.dol_trunc($obj->label, 40).''.dol_print_date($db->jdate($obj->datev), 'day').''.dol_print_date($db->jdate($obj->datep), 'day').'
    '; print ''; print ''; @@ -126,9 +127,9 @@ if ($resql) print ''."\n"; - print ''; + print ''; print ''; - print ''; + print ''; print ''; print ''; print ''; @@ -136,6 +137,7 @@ if ($resql) print ''; } print "
    '.$langs->trans("LastCheckReceiptShort", $max).'
    '.$checkdepositstatic->getNomUrl(1).''.$checkdepositstatic->getNomUrl(1).''.dol_print_date($db->jdate($objp->db), 'day').''.$accountstatic->getNomUrl(1).''.$accountstatic->getNomUrl(1).''.$objp->nbcheque.''.price($objp->amount).''.$checkdepositstatic->LibStatut($objp->statut, 3).'
    "; + print '
    '; $db->free($resql); } else { From 4ee6cedbe695b121e47c5af3be25d11b19c06d2e Mon Sep 17 00:00:00 2001 From: bahfir abbes Date: Thu, 8 Oct 2020 00:23:59 +0100 Subject: [PATCH 221/317] =?UTF-8?q?Option=20d=E2=80=99Activation=20du=20fi?= =?UTF-8?q?chier=20global=20de=20configuration.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/core/class/conf.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 3d6526690a7..ce726265006 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -235,7 +235,7 @@ class Conf $filesList = explode(":", $this->global->LOCAL_CONSTS_FILES); foreach ($filesList as $file) { $file = dol_sanitizeFileName($file); - include_once DOL_DOCUMENT_ROOT."/".$file."/".$file."_consts.php"; // This file can run code like setting $this->global->XXX vars. + dol_include_once($file."/".$file."_consts.php"); // This file can run code like setting $this->global->XXX vars. } } From 85825a01045a1dfc3c4b009d4b2c5712b17119ed Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 00:57:39 +0200 Subject: [PATCH 222/317] Init page for security info --- htdocs/admin/system/perf.php | 2 +- htdocs/admin/system/security.php | 143 +++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 htdocs/admin/system/security.php diff --git a/htdocs/admin/system/perf.php b/htdocs/admin/system/perf.php index ec6dc9d4a88..7857773924f 100644 --- a/htdocs/admin/system/perf.php +++ b/htdocs/admin/system/perf.php @@ -49,7 +49,7 @@ llxHeader(); print load_fiche_titre($langs->trans("PerfDolibarr"), '', 'title_setup'); -print $langs->trans("YouMayFindPerfAdviceHere", 'https://wiki.dolibarr.org/index.php/FAQ_Increase_Performance').' ('.$langs->trans("Reload").')
    '; +print ''.$langs->trans("YouMayFindPerfAdviceHere", 'https://wiki.dolibarr.org/index.php/FAQ_Increase_Performance').' ('.$langs->trans("Reload").')
    '; // Recupere la version de PHP $phpversion = version_php(); diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php new file mode 100644 index 00000000000..0cf70f2bbaa --- /dev/null +++ b/htdocs/admin/system/security.php @@ -0,0 +1,143 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/admin/system/security.php + * \brief Page to show Security information + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + +// Load translation files required by the page +$langs->loadLangs(array("install", "other", "admin")); + +if (!$user->admin) + accessforbidden(); + +if (GETPOST('action', 'aZ09') == 'donothing') +{ + exit; +} + + +/* + * View + */ + +$form = new Form($db); +$nowstring = dol_print_date(dol_now(), 'dayhourlog'); + +llxHeader(); + +print load_fiche_titre($langs->trans("Security"), '', 'title_setup'); + +print ''.$langs->trans("YouMayFindSecurityAdviceHere", 'hhttps://wiki.dolibarr.org/index.php/Security_information').' ('.$langs->trans("Reload").')
    '; + +// Recupere la version de PHP +$phpversion = version_php(); +print "
    PHP - ".$langs->trans("Version").": ".$phpversion."
    \n"; + +// Recupere la version du serveur web +print "
    Web server - ".$langs->trans("Version").": ".$_SERVER["SERVER_SOFTWARE"]."
    \n"; +print '
    '; + + +print load_fiche_titre($langs->trans("ConfigFile"), '', ''); + +print ''.$langs->trans("dolibarr_main_prod").': '.$dolibarr_main_prod; +// dolibarr_main_prod + + +print '
    '; +print '
    '; + +print load_fiche_titre($langs->trans("PermissionsOnFiles"), '', ''); + +print ''.$langs->trans("PermissionOnFileInWebRoot").': '; +// TODO + + +print '
    '; +print '
    '; + + +print load_fiche_titre($langs->trans("Modules"), '', ''); + +// XDebug +print ''.$langs->trans("XDebug").': '; +$test = !function_exists('xdebug_is_enabled'); +if ($test) print img_picto('', 'tick.png').' '.$langs->trans("NotInstalled"); +else { + print img_picto('', 'warning').' '.$langs->trans("ModuleActivatedMayExposeInformation", $langs->transnoentities("XDebug")); + print ' - '.$langs->trans("MoreInformation").' XDebug admin page'; +} +print '
    '; + +// Module log +print '
    '; +print ''.$langs->trans("Syslog").': '; +$test = empty($conf->syslog->enabled); +if ($test) print img_picto('', 'tick.png').' '.$langs->trans("NotInstalled"); +else { + print img_picto('', 'warning').' '.$langs->trans("ModuleActivatedMayExposeInformation", $langs->transnoentities("Syslog")); + //print ' '.$langs->trans("MoreInformation").' XDebug admin page'; +} +print '
    '; + +// Module debugbar +print '
    '; +print ''.$langs->trans("DebugBar").': '; +$test = empty($conf->debugbar->enabled); +if ($test) print img_picto('', 'tick.png').' '.$langs->trans("NotInstalled"); +else { + print img_picto('', 'error').' '.$langs->trans("ModuleActivatedDoNotUseInProduction", $langs->transnoentities("DebugBar")); + //print ' '.$langs->trans("MoreInformation").' XDebug admin page'; +} +print '
    '; +print '
    '; + +print load_fiche_titre($langs->trans("SecuritySetup"), '', ''); + +//print ''.$langs->trans("PasswordEncryption").': '; +print 'MAIN_SECURITY_HASH_ALGO = '.$conf->global->MAIN_SECURITY_HASH_ALGO."   (Recommanded value: 'password_hash')
    "; +print 'MAIN_SECURITY_SALT = '.$conf->global->MAIN_SECURITY_SALT.'
    '; +print '
    '; +// TODO + +print ''.$langs->trans("AntivirusEnabledOnUpload").': '; +// TODO +print '
    '; + +print ''.$langs->trans("SecurityAudit").': '; +// TODO Disabled or enabled ? +print '
    '; + + + + + + + + + +// End of page +llxFooter(); +$db->close(); From ad21f1e293283088ebfef56a4c2d9030bd99a00d Mon Sep 17 00:00:00 2001 From: bahfir abbes Date: Tue, 13 Oct 2020 23:49:38 +0100 Subject: [PATCH 223/317] fix:boolean values in showinputfield are 1 and 0 not 'on' and 'off' --- htdocs/core/actions_addupdatedelete.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/actions_addupdatedelete.inc.php b/htdocs/core/actions_addupdatedelete.inc.php index cee75415eee..ad82d15c5a9 100644 --- a/htdocs/core/actions_addupdatedelete.inc.php +++ b/htdocs/core/actions_addupdatedelete.inc.php @@ -74,7 +74,7 @@ if ($action == 'add' && !empty($permissiontoadd)) } elseif (preg_match('/^(integer|price|real|double)/', $object->fields[$key]['type'])) { $value = price2num(GETPOST($key, 'alphanohtml')); // To fix decimal separator according to lang setup } elseif ($object->fields[$key]['type'] == 'boolean') { - $value = (GETPOST($key) == 'on' ? 1 : 0); + $value = (GETPOST($key) == '1' ? 1 : 0); } else { $value = GETPOST($key, 'alphanohtml'); } From 8b0a6d7f404e6b2c8eb11f09354a52272b4cec2e Mon Sep 17 00:00:00 2001 From: bahfir abbes Date: Wed, 14 Oct 2020 00:18:36 +0100 Subject: [PATCH 224/317] fix:two fields with same ids is incorrect html --- htdocs/admin/company.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php index 7ab04adf923..a099547fbc0 100644 --- a/htdocs/admin/company.php +++ b/htdocs/admin/company.php @@ -558,13 +558,13 @@ $langs->load("companies"); // Managing Director(s) print ''; -print ''; +print ''; // GDPR contact print ''; print $form->textwithpicto($langs->trans("GDPRContact"), $langs->trans("GDPRContactDesc")); print ''; -print ''; +print ''; // Capital print ''; From 4a3a3190ea8d385621be605382ede661d7361146 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 01:46:49 +0200 Subject: [PATCH 225/317] Standardize pdf templates --- htdocs/core/lib/pdf.lib.php | 20 +- .../commande/doc/pdf_einstein.modules.php | 124 +++++++----- .../commande/doc/pdf_eratosthene.modules.php | 183 +++++++++++------- .../facture/doc/pdf_sponge.modules.php | 47 +++-- .../modules/propale/doc/pdf_azur.modules.php | 4 +- .../modules/propale/doc/pdf_cyan.modules.php | 146 ++++++++------ 6 files changed, 340 insertions(+), 184 deletions(-) diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index db79efefc45..bf957dc40a6 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -2017,7 +2017,25 @@ function pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails = 0) if ($object->lines[$i]->special_code == 3) { $result .= $outputlangs->transnoentities("Option"); - } elseif (empty($hidedetails) || $hidedetails > 1) $result .= price($sign * ($object->lines[$i]->total_ht) + ($object->lines[$i]->total_ht) * ($object->lines[$i]->tva_tx) / 100, 0, $outputlangs); + } + if (empty($hidedetails) || $hidedetails > 1) + { + $total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ttc : $object->lines[$i]->total_ttc); + if ($object->lines[$i]->situation_percent > 0) + { + // TODO Remove this. The total should be saved correctly in database instead of being modified here. + $prev_progress = 0; + $progress = 1; + if (method_exists($object->lines[$i], 'get_prev_progress')) + { + $prev_progress = $object->lines[$i]->get_prev_progress($object->id); + $progress = ($object->lines[$i]->situation_percent - $prev_progress) / 100; + } + $result .= price($sign * ($total_ttc / ($object->lines[$i]->situation_percent / 100)) * $progress, 0, $outputlangs); + } else { + $result .= price($sign * $total_ttc, 0, $outputlangs); + } + } } return $result; } diff --git a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php index 603fd4efa22..324f7c83fd0 100644 --- a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php +++ b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php @@ -224,9 +224,16 @@ class pdf_einstein extends ModelePDFCommandes // Load translation files required by the page $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "products", "orders", "deliveries")); + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { + global $outputlangsbis; + $outputlangsbis = new Translate('', $conf); + $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); + $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "orders", "deliveries")); + } + $nblines = count($object->lines); - if ($conf->commande->dir_output) + if ($conf->commande->multidir_output[$conf->entity]) { $object->fetch_thirdparty(); @@ -325,7 +332,7 @@ class pdf_einstein extends ModelePDFCommandes $pdf->AddPage(); if (!empty($tplidx)) $pdf->useTemplate($tplidx); $pagenb++; - $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); $pdf->SetFont('', '', $default_font_size - 1); $pdf->MultiCell(0, 3, ''); // Set interline to 3 $pdf->SetTextColor(0, 0, 0); @@ -335,6 +342,7 @@ class pdf_einstein extends ModelePDFCommandes $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 + $top_shift : 10); // Incoterm + $height_incoterms = 0; if ($conf->incoterm->enabled) { $desc_incoterms = $object->getIncotermsForPDF(); @@ -585,15 +593,17 @@ class pdf_einstein extends ModelePDFCommandes } // Show square - if ($pagenb == 1) + if ($pagenb == 1) { $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code); - else $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); + } $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; - // Affiche zone infos + // Display infos area $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs); - // Affiche zone totaux + // Display total zone $posy = $this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); // Affiche zone versements @@ -664,7 +674,7 @@ class pdf_einstein extends ModelePDFCommandes * @param Object $object Object to show * @param int $posy Y * @param Translate $outputlangs Langs object - * @return void + * @return int */ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs) { @@ -783,20 +793,22 @@ class pdf_einstein extends ModelePDFCommandes // Si mode reglement non force ou si force a CHQ if (!empty($conf->global->FACTURE_CHQ_NUMBER)) { - if ($conf->global->FACTURE_CHQ_NUMBER > 0) + $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE); + + if ($conf->global->FACTURE_CHQ_NUMBER > 0) { $account = new Account($this->db); $account->fetch($conf->global->FACTURE_CHQ_NUMBER); $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', 'B', $default_font_size - 3); + $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0); $posy = $pdf->GetY() + 1; if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', '', $default_font_size - 3); + $pdf->SetFont('', '', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0); $posy = $pdf->GetY() + 2; } @@ -804,14 +816,14 @@ class pdf_einstein extends ModelePDFCommandes if ($conf->global->FACTURE_CHQ_NUMBER == -1) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', 'B', $default_font_size - 3); + $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0); $posy = $pdf->GetY() + 1; if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', '', $default_font_size - 3); + $pdf->SetFont('', '', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0); $posy = $pdf->GetY() + 2; } @@ -822,10 +834,10 @@ class pdf_einstein extends ModelePDFCommandes // If payment mode not forced or forced to VIR, show payment with BAN if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') { - if (!empty($object->fk_account) || !empty($object->fk_bank) || !empty($conf->global->FACTURE_RIB_NUMBER)) + if ($object->fk_account > 0 || $object->fk_bank > 0 || !empty($conf->global->FACTURE_RIB_NUMBER)) { - $bankid = (empty($object->fk_account) ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account); - if (!empty($object->fk_bank)) $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank + $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account); + if ($object->fk_bank > 0) $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank $account = new Account($this->db); $account->fetch($bankid); @@ -856,15 +868,23 @@ class pdf_einstein extends ModelePDFCommandes protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) { // phpcs:enable - global $conf, $mysoc; + global $conf, $mysoc, $hookmanager; $default_font_size = pdf_getPDFFontSize($outputlangs); + $outputlangsbis = null; + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { + $outputlangsbis = new Translate('', $conf); + $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); + $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); + $default_font_size--; + } + $tab2_top = $posy; $tab2_hl = 4; $pdf->SetFont('', '', $default_font_size - 1); - // Tableau total + // Total table $col1x = 120; $col2x = 170; if ($this->page_largeur < 210) // To work with US executive format { @@ -878,7 +898,7 @@ class pdf_einstein extends ModelePDFCommandes // Total HT $pdf->SetFillColor(255, 255, 255); $pdf->SetXY($col1x, $tab2_top + 0); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalHT") : ''), 0, 'L', 1); $total_ht = (($conf->multicurrency->enabled && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht); $pdf->SetXY($col2x, $tab2_top + 0); @@ -918,7 +938,8 @@ class pdf_einstein extends ModelePDFCommandes $tvakey = str_replace('*', '', $tvakey); $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' '; + $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : ''); + $totalvat .= ' '; $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); @@ -949,7 +970,8 @@ class pdf_einstein extends ModelePDFCommandes $tvakey = str_replace('*', '', $tvakey); $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' '; + $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : ''); + $totalvat .= ' '; $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); @@ -975,7 +997,8 @@ class pdf_einstein extends ModelePDFCommandes $tvakey = str_replace('*', '', $tvakey); $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; } - $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).' '; + $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : ''); + $totalvat .= ' '; $totalvat .= vatrate($tvakey, 1).$tvacompl; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); @@ -1006,8 +1029,9 @@ class pdf_einstein extends ModelePDFCommandes $tvakey = str_replace('*', '', $tvakey); $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' '; - + $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : ''); + $totalvat .= ' '; + $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); @@ -1025,6 +1049,7 @@ class pdf_einstein extends ModelePDFCommandes foreach ($localtax_rate as $tvakey => $tvaval) { + // retrieve global local tax if ($tvakey != 0) // On affiche pas taux 0 { //$this->atleastoneratenotnull++; @@ -1038,8 +1063,9 @@ class pdf_einstein extends ModelePDFCommandes $tvakey = str_replace('*', '', $tvakey); $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' '; - + $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : ''); + $totalvat .= ' '; + $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); @@ -1055,7 +1081,7 @@ class pdf_einstein extends ModelePDFCommandes $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); $pdf->SetTextColor(0, 0, 60); $pdf->SetFillColor(224, 224, 224); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalTTC", $mysoc->country_code) : ''), $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1); @@ -1078,7 +1104,7 @@ class pdf_einstein extends ModelePDFCommandes $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("AlreadyPaid") : ''), 0, 'L', 0); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0); @@ -1086,7 +1112,7 @@ class pdf_einstein extends ModelePDFCommandes $pdf->SetTextColor(0, 0, 60); $pdf->SetFillColor(224, 224, 224); $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("AlreadyPaid") : ''), $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1); @@ -1111,9 +1137,10 @@ class pdf_einstein extends ModelePDFCommandes * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title * @param int $hidebottom Hide bottom bar of array * @param string $currency Currency code + * @param Translate $outputlangsbis Langs object bis * @return void */ - protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '') + protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null) { global $conf; @@ -1131,6 +1158,10 @@ class pdf_einstein extends ModelePDFCommandes if (empty($hidetop)) { $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency)); + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { + $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency)); + } + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4); $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); @@ -1214,10 +1245,11 @@ class pdf_einstein extends ModelePDFCommandes * @param Object $object Object to show * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output + * @param Translate $outputlangsbis Object lang for output bis * @param string $titlekey Translation key to show as title of document * @return int Return topshift value */ - protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey = "PdfOrderTitle") + protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null, $titlekey = "PdfOrderTitle") { // phpcs:enable global $conf, $langs, $hookmanager; @@ -1238,8 +1270,10 @@ class pdf_einstein extends ModelePDFCommandes $pdf->SetTextColor(0, 0, 60); $pdf->SetFont('', 'B', $default_font_size + 3); + $w = 100; + $posy = $this->marge_haute; - $posx = $this->page_largeur - $this->marge_droite - 100; + $posx = $this->page_largeur - $this->marge_droite - $w; $pdf->SetXY($this->marge_gauche, $posy); @@ -1263,12 +1297,12 @@ class pdf_einstein extends ModelePDFCommandes } else { $pdf->SetTextColor(200, 0, 0); $pdf->SetFont('', 'B', $default_font_size - 2); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); } } else { $text = $this->emetteur->name; - $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); } } @@ -1276,7 +1310,7 @@ class pdf_einstein extends ModelePDFCommandes $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); $title = $outputlangs->transnoentities($titlekey); - $pdf->MultiCell(100, 3, $title, '', 'R'); + $pdf->MultiCell($w, 3, $title, '', 'R'); $pdf->SetFont('', 'B', $default_font_size); @@ -1293,7 +1327,7 @@ class pdf_einstein extends ModelePDFCommandes $posy += 5; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); } if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) @@ -1323,14 +1357,14 @@ class pdf_einstein extends ModelePDFCommandes $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R'); if (!empty($conf->global->DOC_SHOW_CUSTOMER_CODE) && !empty($object->thirdparty->code_client)) { $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); } // Get contact @@ -1344,7 +1378,7 @@ class pdf_einstein extends ModelePDFCommandes $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); } } @@ -1353,7 +1387,7 @@ class pdf_einstein extends ModelePDFCommandes $top_shift = 0; // Show list of linked objects $current_y = $pdf->getY(); - $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size); + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size); if ($current_y < $pdf->getY()) { $top_shift = $pdf->getY() - $current_y; @@ -1402,8 +1436,7 @@ class pdf_einstein extends ModelePDFCommandes $pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L'); - - // If CUSTOMER contact defined on order, we use it + // If CUSTOMER contact defined, we use it $usecontact = false; $arrayidcontact = $object->getIdContact('external', 'CUSTOMER'); if (count($arrayidcontact) > 0) @@ -1425,9 +1458,10 @@ class pdf_einstein extends ModelePDFCommandes $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, 'target', $object); // Show recipient - $widthrecbox = 100; + $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100; if ($this->page_largeur < 210) $widthrecbox = 84; // To work with US executive format - $posy = 42 + $top_shift; + $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posy += $top_shift; $posx = $this->page_largeur - $this->marge_droite - $widthrecbox; if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx = $this->marge_gauche; @@ -1441,7 +1475,7 @@ class pdf_einstein extends ModelePDFCommandes // Show recipient name $pdf->SetXY($posx + 2, $posy + 3); $pdf->SetFont('', 'B', $default_font_size); - $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L'); + $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L'); $posy = $pdf->getY(); diff --git a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php index e6e54e521d8..bfbc798d4bb 100644 --- a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php +++ b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php @@ -120,7 +120,12 @@ class pdf_eratosthene extends ModelePDFCommandes */ public $emetteur; - + /** + * @var array of document table collumns + */ + public $cols; + + /** * Constructor * @@ -165,11 +170,13 @@ class pdf_eratosthene extends ModelePDFCommandes if (empty($this->emetteur->country_code)) $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined // Define position of columns - $this->posxdesc = $this->marge_gauche + 1; + $this->posxdesc = $this->marge_gauche + 1; // used for notes ans other stuff $this->tabTitleHeight = 5; // default height + // Use new system for position of columns, view $this->defineColumnField() + $this->tva = array(); $this->localtax1 = array(); $this->localtax2 = array(); @@ -242,7 +249,11 @@ class pdf_eratosthene extends ModelePDFCommandes { if (!$arephoto) { - $dir = $conf->product->dir_output.'/'.$midir; + if ($conf->product->entity != $objphoto->entity) { + $dir = $conf->product->multidir_output[$objphoto->entity].'/'.$midir; //Check repertories of current entities + } else { + $dir = $conf->product->dir_output.'/'.$midir; //Check repertory of the current product + } foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) { @@ -271,7 +282,7 @@ class pdf_eratosthene extends ModelePDFCommandes - if ($conf->commande->dir_output) + if ($conf->commande->multidir_output[$conf->entity]) { $object->fetch_thirdparty(); @@ -345,20 +356,21 @@ class pdf_eratosthene extends ModelePDFCommandes $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right - /// Does we have at least one line with discount $this->atleastonediscount - foreach ($object->lines as $line) { - if ($line->remise_percent) { - $this->atleastonediscount = true; - break; - } + // Set $this->atleastonediscount if you have at least one discount + for ($i = 0; $i < $nblines; $i++) + { + if ($object->lines[$i]->remise_percent) + { + $this->atleastonediscount++; + } } - + // New page $pdf->AddPage(); if (!empty($tplidx)) $pdf->useTemplate($tplidx); $pagenb++; - $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); $pdf->SetFont('', '', $default_font_size - 1); $pdf->MultiCell(0, 3, ''); // Set interline to 3 $pdf->SetTextColor(0, 0, 0); @@ -368,6 +380,7 @@ class pdf_eratosthene extends ModelePDFCommandes $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 + $top_shift : 10); // Incoterm + $height_incoterms = 0; if ($conf->incoterm->enabled) { $desc_incoterms = $object->getIncotermsForPDF(); @@ -404,15 +417,16 @@ class pdf_eratosthene extends ModelePDFCommandes // Extrafields in note $extranote = $this->getExtrafieldsInHtml($object, $outputlangs); - if (!empty($extranote)) - { + if (!empty($extranote)) { $notetoshow = dol_concatdesc($notetoshow, $extranote); } $pagenb = $pdf->getPage(); if ($notetoshow) { - $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; + $tab_top -= 2; + + $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; $pageposbeforenote = $pagenb; $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object); @@ -420,8 +434,6 @@ class pdf_eratosthene extends ModelePDFCommandes $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs); $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow); - $tab_top -= 2; - $pdf->startTransaction(); $pdf->SetFont('', '', $default_font_size - 1); @@ -582,6 +594,7 @@ class pdf_eratosthene extends ModelePDFCommandes } } + // Description of product line if ($this->getColumnStatus('desc')) { $pdf->startTransaction(); @@ -632,7 +645,7 @@ class pdf_eratosthene extends ModelePDFCommandes $pdf->setTopMargin($this->marge_haute); $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. - // We suppose that a too long description is moved completely on next page + // We suppose that a too long description or photo were moved completely on next page if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { $pdf->setPage($pageposafter); $curY = $tab_top_newpage; } @@ -681,7 +694,7 @@ class pdf_eratosthene extends ModelePDFCommandes $nexY = max($pdf->GetY(), $nexY); } - // Total HT line + // Total excl tax line (HT) if ($this->getColumnStatus('totalexcltax')) { $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); @@ -689,7 +702,15 @@ class pdf_eratosthene extends ModelePDFCommandes $nexY = max($pdf->GetY(), $nexY); } - // Extrafields + // Total with tax line (TTC) + if ($this->getColumnStatus('totalincltax')) + { + $total_incl_tax = pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax); + $nexY = max($pdf->GetY(), $nexY); + } + + // Extrafields if (!empty($object->lines[$i]->array_options)) { foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { if ($this->getColumnStatus($extrafieldColKey)) @@ -795,14 +816,17 @@ class pdf_eratosthene extends ModelePDFCommandes // Show square if ($pagenb == $pageposbeforeprintlines) + { $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code); - else $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); + } $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; - // Affiche zone infos + // Display infos area $posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs); - // Affiche zone totaux + // Display total zone $posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); // Affiche zone versements @@ -986,20 +1010,22 @@ class pdf_eratosthene extends ModelePDFCommandes // Si mode reglement non force ou si force a CHQ if (!empty($conf->global->FACTURE_CHQ_NUMBER)) { - if ($conf->global->FACTURE_CHQ_NUMBER > 0) + $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE); + + if ($conf->global->FACTURE_CHQ_NUMBER > 0) { $account = new Account($this->db); $account->fetch($conf->global->FACTURE_CHQ_NUMBER); $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', 'B', $default_font_size - 3); + $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0); $posy = $pdf->GetY() + 1; if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', '', $default_font_size - 3); + $pdf->SetFont('', '', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0); $posy = $pdf->GetY() + 2; } @@ -1007,14 +1033,14 @@ class pdf_eratosthene extends ModelePDFCommandes if ($conf->global->FACTURE_CHQ_NUMBER == -1) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', 'B', $default_font_size - 3); + $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0); $posy = $pdf->GetY() + 1; if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('', '', $default_font_size - 3); + $pdf->SetFont('', '', $default_font_size - $diffsizetitle); $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0); $posy = $pdf->GetY() + 2; } @@ -1025,10 +1051,10 @@ class pdf_eratosthene extends ModelePDFCommandes // If payment mode not forced or forced to VIR, show payment with BAN if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') { - if (!empty($object->fk_account) || !empty($object->fk_bank) || !empty($conf->global->FACTURE_RIB_NUMBER)) + if ($object->fk_account > 0 || $object->fk_bank > 0 || !empty($conf->global->FACTURE_RIB_NUMBER)) { - $bankid = (empty($object->fk_account) ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account); - if (!empty($object->fk_bank)) $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank + $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account); + if ($object->fk_bank > 0) $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank $account = new Account($this->db); $account->fetch($bankid); @@ -1057,30 +1083,32 @@ class pdf_eratosthene extends ModelePDFCommandes */ protected function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs) { - global $conf, $mysoc; + global $conf, $mysoc, $hookmanager; $default_font_size = pdf_getPDFFontSize($outputlangs); - $tab2_top = $posy; - $tab2_hl = 4; - $pdf->SetFont('', '', $default_font_size - 1); - - // Tableau total - $col1x = 120; $col2x = 170; - if ($this->page_largeur < 210) // To work with US executive format - { - $col2x -= 20; - } - $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x); - $useborder = 0; - $index = 0; - $outputlangsbis = null; if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { $outputlangsbis = new Translate('', $conf); $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); + $default_font_size--; } + + $tab2_top = $posy; + $tab2_hl = 4; + $pdf->SetFont('', '', $default_font_size - 1); + + // Total table + $col1x = 120; $col2x = 170; + if ($this->page_largeur < 210) // To work with US executive format + { + $col2x -= 20; + } + $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x); + + $useborder = 0; + $index = 0; // Total HT $pdf->SetFillColor(255, 255, 255); @@ -1234,6 +1262,7 @@ class pdf_eratosthene extends ModelePDFCommandes foreach ($localtax_rate as $tvakey => $tvaval) { + // retrieve global local tax if ($tvakey != 0) // On affiche pas taux 0 { //$this->atleastoneratenotnull++; @@ -1321,9 +1350,10 @@ class pdf_eratosthene extends ModelePDFCommandes * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title * @param int $hidebottom Hide bottom bar of array * @param string $currency Currency code + * @param Translate $outputlangsbis Langs object bis * @return void */ - protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '') + protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null) { global $conf; @@ -1341,6 +1371,10 @@ class pdf_eratosthene extends ModelePDFCommandes if (empty($hidetop)) { $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency)); + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { + $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency)); + } + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4); $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); @@ -1373,10 +1407,11 @@ class pdf_eratosthene extends ModelePDFCommandes * @param Object $object Object to show * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output + * @param Translate $outputlangsbis Object lang for output bis * @param string $titlekey Translation key to show as title of document * @return int Return topshift value */ - protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey = "PdfOrderTitle") + protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null, $titlekey = "PdfOrderTitle") { // phpcs:enable global $conf, $langs, $hookmanager; @@ -1397,8 +1432,10 @@ class pdf_eratosthene extends ModelePDFCommandes $pdf->SetTextColor(0, 0, 60); $pdf->SetFont('', 'B', $default_font_size + 3); + $w = 100; + $posy = $this->marge_haute; - $posx = $this->page_largeur - $this->marge_droite - 100; + $posx = $this->page_largeur - $this->marge_droite - $w; $pdf->SetXY($this->marge_gauche, $posy); @@ -1422,12 +1459,12 @@ class pdf_eratosthene extends ModelePDFCommandes } else { $pdf->SetTextColor(200, 0, 0); $pdf->SetFont('', 'B', $default_font_size - 2); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); } } else { $text = $this->emetteur->name; - $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); } } @@ -1435,7 +1472,7 @@ class pdf_eratosthene extends ModelePDFCommandes $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); $title = $outputlangs->transnoentities($titlekey); - $pdf->MultiCell(100, 3, $title, '', 'R'); + $pdf->MultiCell($w, 4, $title, '', 'R'); $pdf->SetFont('', 'B', $default_font_size); @@ -1449,10 +1486,10 @@ class pdf_eratosthene extends ModelePDFCommandes if ($object->ref_client) { - $posy += 5; + $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); } if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) @@ -1483,14 +1520,14 @@ class pdf_eratosthene extends ModelePDFCommandes $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R'); if (!empty($conf->global->DOC_SHOW_CUSTOMER_CODE) && !empty($object->thirdparty->code_client)) { $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); } // Get contact @@ -1504,7 +1541,7 @@ class pdf_eratosthene extends ModelePDFCommandes $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); } } @@ -1513,7 +1550,7 @@ class pdf_eratosthene extends ModelePDFCommandes $top_shift = 0; // Show list of linked objects $current_y = $pdf->getY(); - $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size); + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size); if ($current_y < $pdf->getY()) { $top_shift = $pdf->getY() - $current_y; @@ -1562,8 +1599,7 @@ class pdf_eratosthene extends ModelePDFCommandes $pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L'); - - // If CUSTOMER contact defined on order, we use it + // If CUSTOMER contact defined, we use it $usecontact = false; $arrayidcontact = $object->getIdContact('external', 'CUSTOMER'); if (count($arrayidcontact) > 0) @@ -1585,9 +1621,10 @@ class pdf_eratosthene extends ModelePDFCommandes $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, 'target', $object); // Show recipient - $widthrecbox = 100; + $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100; if ($this->page_largeur < 210) $widthrecbox = 84; // To work with US executive format - $posy = 42 + $top_shift; + $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posy += $top_shift; $posx = $this->page_largeur - $this->marge_droite - $widthrecbox; if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx = $this->marge_gauche; @@ -1601,7 +1638,7 @@ class pdf_eratosthene extends ModelePDFCommandes // Show recipient name $pdf->SetXY($posx + 2, $posy + 3); $pdf->SetFont('', 'B', $default_font_size); - $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L'); + $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L'); $posy = $pdf->getY(); @@ -1690,7 +1727,7 @@ class pdf_eratosthene extends ModelePDFCommandes 'align' => 'L', // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label // 'label' => ' ', // the final label - 'padding' => array(0.5, 1, 0.5, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left ), 'content' => array( 'align' => 'L', @@ -1698,6 +1735,7 @@ class pdf_eratosthene extends ModelePDFCommandes ), ); + // Image of product $rank = $rank + 10; $this->cols['photo'] = array( 'rank' => $rank, @@ -1789,14 +1827,25 @@ class pdf_eratosthene extends ModelePDFCommandes $this->cols['totalexcltax'] = array( 'rank' => $rank, 'width' => 26, // in mm - 'status' => true, + 'status' => empty($conf->global->PDF_PROPAL_HIDE_PRICE_EXCL_TAX) ? true : false, 'title' => array( 'textkey' => 'TotalHT' ), 'border-left' => true, // add left line separator ); - // Add extrafields cols + $rank = $rank + 1010; // add a big offset to be sure is the last col because default extrafield rank is 100 + $this->cols['totalincltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => empty($conf->global->PDF_PROPAL_SHOW_PRICE_INCL_TAX) ? false : true, + 'title' => array( + 'textkey' => 'TotalTTC' + ), + 'border-left' => true, // add left line separator + ); + + // Add extrafields cols if (!empty($object->lines)) { $line = reset($object->lines); $this->defineColumnExtrafield($line, $outputlangs, $hidedetails); diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index bab3bbd9e71..bd7b055c28e 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -289,7 +289,7 @@ class pdf_sponge extends ModelePDFFactures //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; - if ($conf->facture->dir_output) + if ($conf->facture->multidir_output[$conf->entity]) { $object->fetch_thirdparty(); @@ -300,11 +300,11 @@ class pdf_sponge extends ModelePDFFactures // Definition of $dir and $file if ($object->specimen) { - $dir = $conf->facture->dir_output; + $dir = $conf->facture->multidir_output[$conf->entity]; $file = $dir."/SPECIMEN.pdf"; } else { $objectref = dol_sanitizeFileName($object->ref); - $dir = $conf->facture->dir_output."/".$objectref; + $dir = $conf->facture->multidir_output[$conf->entity]."/".$objectref; $file = $dir."/".$objectref.".pdf"; } if (!file_exists($dir)) @@ -386,14 +386,15 @@ class pdf_sponge extends ModelePDFFactures $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right - // Does we have at least one line with discount $this->atleastonediscount - foreach ($object->lines as $line) { - if ($line->remise_percent) { - $this->atleastonediscount = true; - break; + // Set $this->atleastonediscount if you have at least one discount + for ($i = 0; $i < $nblines; $i++) + { + if ($object->lines[$i]->remise_percent) + { + $this->atleastonediscount++; } } - + // Situation invoice handling if ($object->situation_cycle_ref) @@ -458,8 +459,7 @@ class pdf_sponge extends ModelePDFFactures // Extrafields in note $extranote = $this->getExtrafieldsInHtml($object, $outputlangs); - if (!empty($extranote)) - { + if (!empty($extranote)) { $notetoshow = dol_concatdesc($notetoshow, $extranote); } @@ -735,7 +735,7 @@ class pdf_sponge extends ModelePDFFactures $nexY = max($pdf->GetY(), $nexY); } - // Total HT line + // Total excl tax line (HT) if ($this->getColumnStatus('totalexcltax')) { $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); @@ -743,6 +743,14 @@ class pdf_sponge extends ModelePDFFactures $nexY = max($pdf->GetY(), $nexY); } + // Total with tax line (TTC) + if ($this->getColumnStatus('totalincltax')) + { + $total_incl_tax = pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax); + $nexY = max($pdf->GetY(), $nexY); + } + // Extrafields if (!empty($object->lines[$i]->array_options)) { foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { @@ -2216,7 +2224,7 @@ class pdf_sponge extends ModelePDFFactures ), ); - // PHOTO + // Image of product $rank = $rank + 10; $this->cols['photo'] = array( 'rank' => $rank, @@ -2324,13 +2332,24 @@ class pdf_sponge extends ModelePDFFactures $this->cols['totalexcltax'] = array( 'rank' => $rank, 'width' => 26, // in mm - 'status' => true, + 'status' => empty($conf->global->PDF_PROPAL_HIDE_PRICE_EXCL_TAX) ? true : false, 'title' => array( 'textkey' => 'TotalHT' ), 'border-left' => true, // add left line separator ); + $rank = $rank + 1010; // add a big offset to be sure is the last col because default extrafield rank is 100 + $this->cols['totalincltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => empty($conf->global->PDF_PROPAL_SHOW_PRICE_INCL_TAX) ? false : true, + 'title' => array( + 'textkey' => 'TotalTTC' + ), + 'border-left' => true, // add left line separator + ); + // Add extrafields cols if (!empty($object->lines)) { $line = reset($object->lines); diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index c67789b1814..a74286e4cdc 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -173,8 +173,8 @@ class pdf_azur extends ModelePDFPropales $this->posxqty = 135; $this->posxunit = 151; } else { - $this->posxtva = 110; - $this->posxup = 126; + $this->posxtva = 106; + $this->posxup = 122; $this->posxqty = 145; $this->posxunit = 162; } diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php index 8563c845d2b..6696364b9dd 100644 --- a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php @@ -57,7 +57,7 @@ class pdf_cyan extends ModelePDFPropales public $description; /** - * @var string Save the name of generated file as the main doc when generating a doc with this template + * @var int Save the name of generated file as the main doc when generating a doc with this template */ public $update_main_doc_field; @@ -119,7 +119,12 @@ class pdf_cyan extends ModelePDFPropales */ public $emetteur; - + /** + * @var array of document table collumns + */ + public $cols; + + /** * Constructor * @@ -164,11 +169,13 @@ class pdf_cyan extends ModelePDFPropales if (empty($this->emetteur->country_code)) $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined // Define position of columns - $this->posxdesc = $this->marge_gauche + 1; - + $this->posxdesc = $this->marge_gauche + 1; // used for notes ans other stuff + $this->tabTitleHeight = 5; // default height + // Use new system for position of columns, view $this->defineColumnField() + $this->tva = array(); $this->localtax1 = array(); $this->localtax2 = array(); @@ -197,7 +204,7 @@ class pdf_cyan extends ModelePDFPropales // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO if (!empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output = 'ISO-8859-1'; - // Load traductions files required by page + // Load translation files required by page $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { @@ -344,15 +351,15 @@ class pdf_cyan extends ModelePDFPropales $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right - // Does we have at least one line with discount $this->atleastonediscount - foreach ($object->lines as $line) { - if ($line->remise_percent) { - $this->atleastonediscount = true; - break; + // Set $this->atleastonediscount if you have at least one discount + for ($i = 0; $i < $nblines; $i++) + { + if ($object->lines[$i]->remise_percent) + { + $this->atleastonediscount++; } } - - + // New page $pdf->AddPage(); @@ -365,7 +372,7 @@ class pdf_cyan extends ModelePDFPropales $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 12 : 22); // Height reserved to output the footer (value include bottom margin) //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit; - $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); $pdf->SetFont('', '', $default_font_size - 1); $pdf->MultiCell(0, 3, ''); // Set interline to 3 $pdf->SetTextColor(0, 0, 0); @@ -397,7 +404,7 @@ class pdf_cyan extends ModelePDFPropales } } - // Affiche notes + // Displays notes $notetoshow = empty($object->note_public) ? '' : $object->note_public; if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) { @@ -454,7 +461,7 @@ class pdf_cyan extends ModelePDFPropales { $pdf->rollbackTransaction(true); - // prepar pages to receive notes + // prepare pages to receive notes while ($pagenb < $pageposafternote) { $pdf->AddPage(); $pagenb++; @@ -488,7 +495,7 @@ class pdf_cyan extends ModelePDFPropales } - // apply note frame to previus pages + // apply note frame to previous pages $i = $pageposbeforenote; while ($i < $pageposafternote) { $pdf->setPage($i); @@ -544,10 +551,10 @@ class pdf_cyan extends ModelePDFPropales $height_note = 0; } - // Use new auto collum system + // Use new auto column system $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref); - // Simulation de tableau pour connaitre la hauteur de la ligne de titre + // tab simulation to know line height $pdf->startTransaction(); $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop); $pdf->rollbackTransaction(true); @@ -582,7 +589,6 @@ class pdf_cyan extends ModelePDFPropales { $pdf->AddPage('', '', true); if (!empty($tplidx)) $pdf->useTemplate($tplidx); - //if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); $pdf->setPage($pageposbefore + 1); $curY = $tab_top_newpage; @@ -656,7 +662,7 @@ class pdf_cyan extends ModelePDFPropales $pdf->setPage($pageposafter); $curY = $tab_top_newpage; } - $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut + $pdf->SetFont('', '', $default_font_size - 1); // We reposition the default font // VAT Rate if ($this->getColumnStatus('vat')) @@ -700,7 +706,7 @@ class pdf_cyan extends ModelePDFPropales $nexY = max($pdf->GetY(), $nexY); } - // Total HT line + // Total excl tax line (HT) if ($this->getColumnStatus('totalexcltax')) { $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); @@ -708,6 +714,14 @@ class pdf_cyan extends ModelePDFPropales $nexY = max($pdf->GetY(), $nexY); } + // Total with tax line (TTC) + if ($this->getColumnStatus('totalincltax')) + { + $total_incl_tax = pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax); + $nexY = max($pdf->GetY(), $nexY); + } + // Extrafields if (!empty($object->lines[$i]->array_options)) { foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { @@ -732,8 +746,7 @@ class pdf_cyan extends ModelePDFPropales $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook - - // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + // Collection of totals by value of vat in $this->tva["rate"] = total_tva if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $object->lines[$i]->multicurrency_total_tva; else $tvaligne = $object->lines[$i]->total_tva; @@ -826,13 +839,13 @@ class pdf_cyan extends ModelePDFPropales $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1; } - // Affiche zone infos + // Display infos area $posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs); - // Affiche zone totaux + // Display total zone $posy = $this->drawTotalTable($pdf, $object, 0, $bottomlasttab, $outputlangs); - // Affiche zone versements + // Display payment area /* if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included) { @@ -1121,10 +1134,10 @@ class pdf_cyan extends ModelePDFPropales // If payment mode not forced or forced to VIR, show payment with BAN if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') { - if (!empty($object->fk_account) || !empty($object->fk_bank) || !empty($conf->global->FACTURE_RIB_NUMBER)) + if ($object->fk_account > 0 || $object->fk_bank > 0 || !empty($conf->global->FACTURE_RIB_NUMBER)) { - $bankid = (empty($object->fk_account) ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account); - if (!empty($object->fk_bank)) $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank + $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account); + if ($object->fk_bank > 0) $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank $account = new Account($this->db); $account->fetch($bankid); @@ -1154,15 +1167,23 @@ class pdf_cyan extends ModelePDFPropales */ protected function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs) { - global $conf, $mysoc; + global $conf, $mysoc, $hookmanager; $default_font_size = pdf_getPDFFontSize($outputlangs); + $outputlangsbis = null; + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { + $outputlangsbis = new Translate('', $conf); + $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); + $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); + $default_font_size--; + } + $tab2_top = $posy; $tab2_hl = 4; $pdf->SetFont('', '', $default_font_size - 1); - // Tableau total + // Total table $col1x = 120; $col2x = 170; if ($this->page_largeur < 210) // To work with US executive format { @@ -1173,13 +1194,6 @@ class pdf_cyan extends ModelePDFPropales $useborder = 0; $index = 0; - $outputlangsbis = null; - if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { - $outputlangsbis = new Translate('', $conf); - $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); - $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); - } - // Total HT $pdf->SetFillColor(255, 255, 255); $pdf->SetXY($col1x, $tab2_top + 0); @@ -1387,6 +1401,7 @@ class pdf_cyan extends ModelePDFPropales if ($deja_regle > 0) { + // Already paid + Deposits $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); @@ -1440,9 +1455,10 @@ class pdf_cyan extends ModelePDFPropales * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title * @param int $hidebottom Hide bottom bar of array * @param string $currency Currency code + * @param Translate $outputlangsbis Langs object bis * @return void */ - protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '') + protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null) { global $conf; @@ -1460,6 +1476,10 @@ class pdf_cyan extends ModelePDFPropales if (empty($hidetop)) { $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency)); + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { + $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency)); + } + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4); $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); @@ -1490,9 +1510,10 @@ class pdf_cyan extends ModelePDFPropales * @param Object $object Object to show * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output + * @param Translate $outputlangsbis Object lang for output bis * @return void */ - protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs) + protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null) { global $conf, $langs; @@ -1512,8 +1533,10 @@ class pdf_cyan extends ModelePDFPropales $pdf->SetTextColor(0, 0, 60); $pdf->SetFont('', 'B', $default_font_size + 3); + $w = 100; + $posy = $this->marge_haute; - $posx = $this->page_largeur - $this->marge_droite - 100; + $posx = $this->page_largeur - $this->marge_droite - $w; $pdf->SetXY($this->marge_gauche, $posy); @@ -1537,12 +1560,12 @@ class pdf_cyan extends ModelePDFPropales } else { $pdf->SetTextColor(200, 0, 0); $pdf->SetFont('', 'B', $default_font_size - 2); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); } } else { $text = $this->emetteur->name; - $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); } } @@ -1550,7 +1573,7 @@ class pdf_cyan extends ModelePDFPropales $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); $title = $outputlangs->transnoentities("PdfCommercialProposalTitle"); - $pdf->MultiCell(100, 4, $title, '', 'R'); + $pdf->MultiCell($w, 4, $title, '', 'R'); $pdf->SetFont('', 'B', $default_font_size); @@ -1567,7 +1590,7 @@ class pdf_cyan extends ModelePDFPropales $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); } if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) @@ -1597,7 +1620,7 @@ class pdf_cyan extends ModelePDFPropales $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Date")." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Date")." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R'); $posy += 4; $pdf->SetXY($posx, $posy); @@ -1609,7 +1632,7 @@ class pdf_cyan extends ModelePDFPropales $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); } // Get contact @@ -1623,7 +1646,7 @@ class pdf_cyan extends ModelePDFPropales $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); } } @@ -1632,7 +1655,7 @@ class pdf_cyan extends ModelePDFPropales $top_shift = 0; // Show list of linked objects $current_y = $pdf->getY(); - $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size); + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size); if ($current_y < $pdf->getY()) { $top_shift = $pdf->getY() - $current_y; @@ -1703,9 +1726,10 @@ class pdf_cyan extends ModelePDFPropales $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, 'target', $object); // Show recipient - $widthrecbox = 100; + $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100; if ($this->page_largeur < 210) $widthrecbox = 84; // To work with US executive format - $posy = 42 + $top_shift; + $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posy += $top_shift; $posx = $this->page_largeur - $this->marge_droite - $widthrecbox; if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx = $this->marge_gauche; @@ -1719,7 +1743,7 @@ class pdf_cyan extends ModelePDFPropales // Show recipient name $pdf->SetXY($posx + 2, $posy + 3); $pdf->SetFont('', 'B', $default_font_size); - $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L'); + $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L'); $posy = $pdf->getY(); @@ -1840,7 +1864,7 @@ class pdf_cyan extends ModelePDFPropales 'align' => 'L', // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label // 'label' => ' ', // the final label - 'padding' => array(0.5, 1, 0.5, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left ), 'content' => array( 'align' => 'L', @@ -1848,6 +1872,7 @@ class pdf_cyan extends ModelePDFPropales ), ); + // Image of product $rank = $rank + 10; $this->cols['photo'] = array( 'rank' => $rank, @@ -1939,13 +1964,24 @@ class pdf_cyan extends ModelePDFPropales $this->cols['totalexcltax'] = array( 'rank' => $rank, 'width' => 26, // in mm - 'status' => true, + 'status' => empty($conf->global->PDF_PROPAL_HIDE_PRICE_EXCL_TAX) ? true : false, 'title' => array( 'textkey' => 'TotalHT' ), 'border-left' => true, // add left line separator ); + $rank = $rank + 1010; // add a big offset to be sure is the last col because default extrafield rank is 100 + $this->cols['totalincltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => empty($conf->global->PDF_PROPAL_SHOW_PRICE_INCL_TAX) ? false : true, + 'title' => array( + 'textkey' => 'TotalTTC' + ), + 'border-left' => true, // add left line separator + ); + // Add extrafields cols if (!empty($object->lines)) { $line = reset($object->lines); From 7838ca32bac44c81640a864e0edbb59a509859f5 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 01:52:53 +0200 Subject: [PATCH 226/317] Fix sql injection reported by Jason Nordenstam --- htdocs/comm/propal/class/propal.class.php | 2 +- htdocs/compta/paiement/cheque/class/remisecheque.class.php | 2 +- htdocs/contact/class/contact.class.php | 2 +- htdocs/contrat/class/contrat.class.php | 2 +- htdocs/core/class/comment.class.php | 2 +- htdocs/supplier_proposal/class/supplier_proposal.class.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 7e34ac6fc3c..525a267dacc 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -3153,7 +3153,7 @@ class Propal extends CommonObject $sql .= " c.datec, c.date_valid as datev, c.date_cloture as dateo,"; $sql .= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture"; $sql .= " FROM ".MAIN_DB_PREFIX."propal as c"; - $sql .= " WHERE c.rowid = ".$id; + $sql .= " WHERE c.rowid = ".((int) $id); $result = $this->db->query($sql); diff --git a/htdocs/compta/paiement/cheque/class/remisecheque.class.php b/htdocs/compta/paiement/cheque/class/remisecheque.class.php index 00815c90f7d..cc882b5f1ee 100644 --- a/htdocs/compta/paiement/cheque/class/remisecheque.class.php +++ b/htdocs/compta/paiement/cheque/class/remisecheque.class.php @@ -98,7 +98,7 @@ class RemiseCheque extends CommonObject $sql .= " FROM ".MAIN_DB_PREFIX."bordereau_cheque as bc"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON bc.fk_bank_account = ba.rowid"; $sql .= " WHERE bc.entity = ".$conf->entity; - if ($id) $sql .= " AND bc.rowid = ".$id; + if ($id) $sql .= " AND bc.rowid = ".((int) $id); if ($ref) $sql .= " AND bc.ref = '".$this->db->escape($ref)."'"; dol_syslog("RemiseCheque::fetch", LOG_DEBUG); diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index 8ea6ebea0d4..91a32f39f26 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -879,7 +879,7 @@ class Contact extends CommonObject $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON c.rowid = u.fk_socpeople"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON c.fk_soc = s.rowid"; $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_stcommcontact as st ON c.fk_stcommcontact = st.id'; - if ($id) $sql .= " WHERE c.rowid = ".$id; + if ($id) $sql .= " WHERE c.rowid = ".((int) $id); else { $sql .= " WHERE c.entity IN (".getEntity($this->element).")"; if ($ref_ext) { diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index e179bd50797..0b62146b080 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -2028,7 +2028,7 @@ class Contrat extends CommonObject $sql .= " c.tms as date_modification,"; $sql .= " fk_user_author"; $sql .= " FROM ".MAIN_DB_PREFIX."contrat as c"; - $sql .= " WHERE c.rowid = ".$id; + $sql .= " WHERE c.rowid = ".((int) $id); $result = $this->db->query($sql); if ($result) diff --git a/htdocs/core/class/comment.class.php b/htdocs/core/class/comment.class.php index a083576aacb..39ae2eb63ef 100644 --- a/htdocs/core/class/comment.class.php +++ b/htdocs/core/class/comment.class.php @@ -186,7 +186,7 @@ class Comment extends CommonObject $sql .= " c.entity,"; $sql .= " c.import_key"; $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as c"; - $sql .= " WHERE c.rowid = ".$id; + $sql .= " WHERE c.rowid = ".((int) $id); dol_syslog(get_class($this)."::fetch", LOG_DEBUG); $resql = $this->db->query($sql); diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index 92759515ba4..8a198720e56 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -2103,7 +2103,7 @@ class SupplierProposal extends CommonObject $sql .= " c.datec, c.date_valid as datev, c.date_cloture as dateo,"; $sql .= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture"; $sql .= " FROM ".MAIN_DB_PREFIX."supplier_proposal as c"; - $sql .= " WHERE c.rowid = ".$id; + $sql .= " WHERE c.rowid = ".((int) $id); $result = $this->db->query($sql); From 74155a49be7b9650a93b74b40da1d6510d782bf3 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 08:42:57 +0200 Subject: [PATCH 227/317] finish BOM stat referent object --- htdocs/core/lib/product.lib.php | 16 +++++-- htdocs/product/class/product.class.php | 66 ++++++++++++++++---------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index 2bd0dc1ced2..d97b66443de 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -346,6 +346,7 @@ function product_lot_admin_prepare_head() function show_stats_for_company($product, $socid) { global $conf, $langs, $user, $db; + $form = new Form($db); $nblines = 0; @@ -366,11 +367,20 @@ function show_stats_for_company($product, $socid) print ''; print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; print ''; - print $product->stats_mo['customers']; + print $form->textwithpicto($product->stats_mo['customers_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['customers_consumed'],$langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['customers_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['customers_produced'],$langs->trans("QtyAlreadyProduced")); print ''; - print $product->stats_mo['nb']; + print $form->textwithpicto($product->stats_mo['nb_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['nb_consumed'],$langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['nb_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['nb_produced'],$langs->trans("QtyAlreadyProduced")); print ''; - print $product->stats_mo['qty']; + print $form->textwithpicto($product->stats_mo['qty_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['qty_consumed'],$langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['qty_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['qty_produced'],$langs->trans("QtyAlreadyProduced")); print ''; print ''; } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index f4cc018ff31..4197facf313 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2366,38 +2366,52 @@ class Product extends CommonObject */ public function load_stats_mo($socid = 0) { // phpcs:enable - global $conf, $user, $hookmanager; + global $user, $hookmanager; - $sql = "SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,"; - $sql .= " SUM(c.qty) as qty"; - $sql .= " FROM ".MAIN_DB_PREFIX."mrp_mo as c"; - if (!$user->rights->societe->client->voir && !$socid) { - $sql .= "INNER JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".$user->id; - } - $sql .= " WHERE "; - $sql .= " c.entity IN (".getEntity('mo').")"; + $error=0; - $sql .= " AND c.fk_product =".$this->id; - if ($socid > 0) { - $sql .= " AND c.fk_soc = ".$socid; + foreach(array('toconsume','consumed','toproduce','produced') as $role) { + $this->stats_mo['customers_'.$role] = 0; + $this->stats_mo['nb_'.$role] = 0; + $this->stats_mo['qty_'.$role] = 0; + + $sql = "SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,"; + $sql .= " SUM(mp.qty) as qty"; + $sql .= " FROM ".MAIN_DB_PREFIX."mrp_mo as c"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."mrp_production as mp ON mp.fk_mo=c.rowid"; + if (!$user->rights->societe->client->voir && !$socid) { + $sql .= "INNER JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".$user->id; + } + $sql .= " WHERE "; + $sql .= " c.entity IN (".getEntity('mo').")"; + + $sql .= " AND mp.fk_product =".$this->id; + $sql .= " AND mp.role ='".$role."'"; + if ($socid > 0) { + $sql .= " AND c.fk_soc = ".$socid; + } + + $result = $this->db->query($sql); + if ($result) { + $obj = $this->db->fetch_object($result); + $this->stats_mo['customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0; + $this->stats_mo['nb_'.$role] = $obj->nb ? $obj->nb : 0; + $this->stats_mo['qty_'.$role] = $obj->qty ? $obj->qty : 0; + } else { + $this->error = $this->db->error(); + $error++; + } } - $result = $this->db->query($sql); - if ($result) { - $obj = $this->db->fetch_object($result); - $this->stats_mo['customers'] = $obj->nb_customers ? $obj->nb_customers : 0; - $this->stats_mo['nb'] = $obj->nb; - $this->stats_mo['qty'] = $obj->qty ? $obj->qty : 0; - - $parameters = array('socid' => $socid); - $reshook = $hookmanager->executeHooks('loadStatsCustomerProposal', $parameters, $this, $action); - if ($reshook > 0) $this->stats_mo = $hookmanager->resArray['stats_mo']; - - return 1; - } else { - $this->error = $this->db->error(); + if (!empty($error)) { return -1; } + + $parameters = array('socid' => $socid); + $reshook = $hookmanager->executeHooks('loadStatsCustomerMO', $parameters, $this, $action); + if ($reshook > 0) $this->stats_mo = $hookmanager->resArray['stats_mo']; + + return 1; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps From 7abb0caf91f0c279fa6e621fc351e85d6f3534a8 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Wed, 14 Oct 2020 06:47:16 +0000 Subject: [PATCH 228/317] Fixing style errors. --- htdocs/core/lib/product.lib.php | 24 ++++++++++++------------ htdocs/product/class/product.class.php | 5 +++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index d97b66443de..7b18079e7b9 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -367,20 +367,20 @@ function show_stats_for_company($product, $socid) print ''; print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; print ''; - print $form->textwithpicto($product->stats_mo['customers_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['customers_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['customers_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['customers_produced'],$langs->trans("QtyAlreadyProduced")); + print $form->textwithpicto($product->stats_mo['customers_toconsume'], $langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['customers_consumed'], $langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['customers_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['customers_produced'], $langs->trans("QtyAlreadyProduced")); print ''; - print $form->textwithpicto($product->stats_mo['nb_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['nb_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['nb_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['nb_produced'],$langs->trans("QtyAlreadyProduced")); + print $form->textwithpicto($product->stats_mo['nb_toconsume'], $langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['nb_consumed'], $langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['nb_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['nb_produced'], $langs->trans("QtyAlreadyProduced")); print ''; - print $form->textwithpicto($product->stats_mo['qty_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['qty_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['qty_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['qty_produced'],$langs->trans("QtyAlreadyProduced")); + print $form->textwithpicto($product->stats_mo['qty_toconsume'], $langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['qty_consumed'], $langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['qty_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['qty_produced'], $langs->trans("QtyAlreadyProduced")); print ''; print ''; } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 4197facf313..bcb46a3f77e 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2364,13 +2364,14 @@ class Product extends CommonObject * @param int $socid Id societe * @return integer Tableau des stats dans $this->stats_mo, <0 if ko >0 if ok */ - public function load_stats_mo($socid = 0) { + public function load_stats_mo($socid = 0) + { // phpcs:enable global $user, $hookmanager; $error=0; - foreach(array('toconsume','consumed','toproduce','produced') as $role) { + foreach (array('toconsume','consumed','toproduce','produced') as $role) { $this->stats_mo['customers_'.$role] = 0; $this->stats_mo['nb_'.$role] = 0; $this->stats_mo['qty_'.$role] = 0; From 5d33761b13fd8b5863305fe1dba83125fd921002 Mon Sep 17 00:00:00 2001 From: amunaadh Date: Wed, 14 Oct 2020 11:26:18 +0545 Subject: [PATCH 229/317] API test added for addUsers Co-authored-by: Swikriti Tripathi --- package.json | 2 +- .../features/Api/apiAddUsers.feature | 67 +++++ .../features/{ => WebUI}/addUsers.feature | 0 .../features/{ => WebUI}/listUsers.feature | 0 .../features/{ => WebUI}/login.feature | 0 .../features/{ => WebUI}/logout.feature | 0 test/acceptance/pageObjects/listUsersPage.js | 4 +- test/acceptance/setup.js | 77 ++++++ .../stepDefinitions/addUsersContext.js | 228 ++++++++++-------- 9 files changed, 268 insertions(+), 110 deletions(-) create mode 100644 test/acceptance/features/Api/apiAddUsers.feature rename test/acceptance/features/{ => WebUI}/addUsers.feature (100%) rename test/acceptance/features/{ => WebUI}/listUsers.feature (100%) rename test/acceptance/features/{ => WebUI}/login.feature (100%) rename test/acceptance/features/{ => WebUI}/logout.feature (100%) create mode 100644 test/acceptance/setup.js diff --git a/package.json b/package.json index 67f24dd541a..496c34e7387 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "nightwatch-api": "^3.0.1" }, "scripts": { - "test:e2e": "node_modules/cucumber/bin/cucumber-js --require test/acceptance/index.js --require test/acceptance/stepDefinitions -f node_modules/cucumber-pretty" + "test:e2e": "node_modules/cucumber/bin/cucumber-js --require test/acceptance/index.js --require test/acceptance/setup.js --require test/acceptance/stepDefinitions -f node_modules/cucumber-pretty" }, "dependencies": { "cucumber-pretty": "^6.0.0", diff --git a/test/acceptance/features/Api/apiAddUsers.feature b/test/acceptance/features/Api/apiAddUsers.feature new file mode 100644 index 00000000000..32d94a7b3cf --- /dev/null +++ b/test/acceptance/features/Api/apiAddUsers.feature @@ -0,0 +1,67 @@ +Feature: Add user + As an admin + I want to add users + So that the authorized access is possible + + Scenario: Admin adds user without permission + Given the user with login "harrypotter@gmail.com" does not exist + When the admin creates user with following details using API + | last name | Potter | + | login | harrypotter@gmail.com | + | password | password | + Then the response status code should be "200" + And user with login "harrypotter@gmail.com" should exist + + Scenario: Admin creates already existing user + Given the admin has created the following users + | login | last name | password | + | Harry | Potter | hello123 | + When the admin creates user with following details using API + | last name | Potter | + | login | Harry | + | password | hello123 | + Then the response status code should be "500" + And the response message should be "ErrorLoginAlreadyExists" + + Scenario Outline: Admin adds user with incomplete essential credentials + Given the user with login "Harry" does not exist + When the admin creates user with following details using API + | last name | | + | login | Harry | + | password | | + Then the response status code should be "200" + And user with login "Harry" should exist + Examples: + | last name | password | + | | | + | Manson | | + | | 123 | + + Scenario Outline: Admin adds user without login + Given the user with login "harrypotter@gmail.com" does not exist + When the admin creates user with following details using API + | last name | | + | login | | + | password | | + Then the response status code should be "500" + And the response message should be "Field 'Login' is required" + Examples: + | last name | password | + | Potter | Hello123 | + | Potter | | + | | hello123 | + + Scenario Outline: Admin adds user with last name as special characters + Given the user with login "" does not exist + When the admin creates user with following details using API + | last name | | + | login | | + | password | password | + Then the response status code should be "200" + And user with login "" should exist + Examples: + | last name | login | + | swi@ | s$5^2 | + | g!!@%ui | नेपाली | + | swikriti@h | सिमप्ले $%#?&@name.txt | + | !@#$%^&*()-_+ | España§àôœ€ | \ No newline at end of file diff --git a/test/acceptance/features/addUsers.feature b/test/acceptance/features/WebUI/addUsers.feature similarity index 100% rename from test/acceptance/features/addUsers.feature rename to test/acceptance/features/WebUI/addUsers.feature diff --git a/test/acceptance/features/listUsers.feature b/test/acceptance/features/WebUI/listUsers.feature similarity index 100% rename from test/acceptance/features/listUsers.feature rename to test/acceptance/features/WebUI/listUsers.feature diff --git a/test/acceptance/features/login.feature b/test/acceptance/features/WebUI/login.feature similarity index 100% rename from test/acceptance/features/login.feature rename to test/acceptance/features/WebUI/login.feature diff --git a/test/acceptance/features/logout.feature b/test/acceptance/features/WebUI/logout.feature similarity index 100% rename from test/acceptance/features/logout.feature rename to test/acceptance/features/WebUI/logout.feature diff --git a/test/acceptance/pageObjects/listUsersPage.js b/test/acceptance/pageObjects/listUsersPage.js index 6f9df509d5f..3567bb576ab 100644 --- a/test/acceptance/pageObjects/listUsersPage.js +++ b/test/acceptance/pageObjects/listUsersPage.js @@ -30,7 +30,7 @@ module.exports = { elements: { userRow: { - selector: '//table[contains(@class,"tagtable liste")]/tbody/tr[position()>2]', + selector: '//table[contains(@class,"tagtable")]/tbody/tr[position()>2]', locateStrategy: 'xpath' }, @@ -40,7 +40,7 @@ module.exports = { }, userList: { - selector: '//table[contains(@class,"tagtable liste")]/tbody/tr[position()>2]/td/a//span[normalize-space(@class="nopadding usertext")][.="%s"]/../../following-sibling::td[.="%s"]', + selector: '//table[contains(@class,"tagtable")]/tbody/tr[position()>2]/td/a//span[normalize-space(@class="nopadding usertext")][.="%s"]/../../following-sibling::td[.="%s"]', locateStrategy: 'xpath' } } diff --git a/test/acceptance/setup.js b/test/acceptance/setup.js new file mode 100644 index 00000000000..eeed97b3466 --- /dev/null +++ b/test/acceptance/setup.js @@ -0,0 +1,77 @@ +const { Before, After } = require('cucumber'); +const { client } = require('nightwatch-api'); +const fetch = require('node-fetch'); +let initialUsers = {}; +let dolApiKey = ''; + +const getUsers = async function () { + const header = {}; + const url = client.globals.backend_url + 'api/index.php/users'; + const users = {}; + header['Accept'] = 'application/json'; + header['DOLAPIKEY'] = dolApiKey; + await fetch(url, { + method: 'GET', + headers: header + }) + .then(async (response) => { + const json_response = await response.json(); + for (const user of json_response) { + users[user.id] = user.id; + } + }); + return users; +}; + +Before(async function getDolApiKey() { + const header = {} + const adminUsername = client.globals.adminUsername; + const adminPassword = client.globals.adminPassword; + const params = new URLSearchParams() + params.set('login', adminUsername) + params.set('password', adminPassword) + const apiKey = `http://localhost/dolibarr/htdocs/api/index.php/login?${params.toString()}`; + header['Accept'] = 'application/json' + await fetch(apiKey, { + method: 'GET', + headers: header + }) + .then(async (response) => { + const jsonResponse = await response.json() + dolApiKey = jsonResponse['success']['token'] + client.globals.dolApiKey = dolApiKey + }) +}) + +Before(async () => { + initialUsers = await getUsers(); +}); + +After(async () => { + const finalUsers = await getUsers(); + const header = {}; + const url = client.globals.backend_url + 'api/index.php/users/'; + header['Accept'] = 'application/json'; + header['DOLAPIKEY'] = dolApiKey; + let found; + for (const finaluser in finalUsers) { + for (const initialuser in initialUsers) { + found = false; + if (initialuser === finaluser) { + found = true; + break; + } + } + if (!found) { + await fetch(url + finaluser, { + method: 'DELETE', + headers: header + }) + .then(res => { + if (res.status < 200 || res.status >= 400) { + throw new Error("Failed to delete user: " + res.statusText); + } + }); + } + } +}); \ No newline at end of file diff --git a/test/acceptance/stepDefinitions/addUsersContext.js b/test/acceptance/stepDefinitions/addUsersContext.js index 22dc218d04a..385f731b8f7 100644 --- a/test/acceptance/stepDefinitions/addUsersContext.js +++ b/test/acceptance/stepDefinitions/addUsersContext.js @@ -1,142 +1,156 @@ -const { Before, Given, When, Then, After } = require('cucumber'); -const { client } = require('nightwatch-api'); +const {Given, When, Then} = require('cucumber'); +const {client} = require('nightwatch-api'); const fetch = require('node-fetch'); -let initialUsers = {}; -let dolApiKey = ''; +const assert = require('assert'); +let response; +let Login = {}; Given('the administrator has logged in using the webUI', async function () { - await client.page.loginPage().navigate().waitForLoginPage(); - await client.page.loginPage().userLogsInWithUsernameAndPassword(client.globals.adminUsername, client.globals.adminPassword); - return client.page.loginPage().userIsLoggedIn(client.globals.adminUsername); + await client.page.loginPage().navigate().waitForLoginPage(); + await client.page.loginPage().userLogsInWithUsernameAndPassword(client.globals.adminUsername, client.globals.adminPassword); + return client.page.loginPage().userIsLoggedIn(client.globals.adminUsername); }); Given('the administrator has browsed to the new users page', function () { - return client.page.homePage().browsedToNewUserPage(); + return client.page.homePage().browsedToNewUserPage(); }); When('the admin creates user with following details', function (datatable) { - return client.page.addUsersPage().adminCreatesUser(datatable); + return client.page.addUsersPage().adminCreatesUser(datatable); }); Then('new user {string} should be created', function (lastname) { - return client.page.addUsersPage().newUserShouldBeCreated(lastname); + return client.page.addUsersPage().newUserShouldBeCreated(lastname); }); Then('message {string} should be displayed in the webUI', function (message) { - return client.page.addUsersPage().noPermissionMessage(message); + return client.page.addUsersPage().noPermissionMessage(message); }); Then('message {string} should not be displayed in the webUI', function (message) { - return client.page.addUsersPage().noPermissionDefinedMessageNotShown(message); + return client.page.addUsersPage().noPermissionDefinedMessageNotShown(message); }); Then('new user {string} should not be created', function (lastname) { - return client.page.addUsersPage().userNotCreated(lastname); + return client.page.addUsersPage().userNotCreated(lastname); }); Given('a user has been created with following details', function (dataTable) { - return adminHasCreatedUser(dataTable); + return adminHasCreatedUser(dataTable); }); Given('the admin has created the following users', function (dataTable) { - return adminHasCreatedUser(dataTable); + return adminHasCreatedUser(dataTable); }); -const getUsers = async function () { - const header = {}; - const url = client.globals.backend_url + 'api/index.php/users'; - const users = {}; - header['Accept'] = 'application/json'; - header['DOLAPIKEY'] = dolApiKey; - await fetch(url, { - method: 'GET', - headers: header - }) - .then(async (response) => { - const json_response = await response.json(); - for (const user of json_response) { - users[user.id] = user.id; - } - }); - return users; +When('the admin creates user with following details using API', function (dataTable) { + return adminCreatesUserWithAPI(dataTable); +}); + +Given('the user with login {string} does not exist', async function (login) { + await userDoesNotExist(login); +}); + +Then('the response status code should be {string}', function (expectedStatusCode) { + return getStatusCode(expectedStatusCode); +}); + +Then('user with login {string} should exist', function (login) { + return userShouldExist(login); +}); + +Then('the response message should be {string}', function (expectedResponseMessage) { + return getResponseMessage(expectedResponseMessage); +}); + +const createUserRequest = function (login, lastname, password) { + const header = {}; + const url = client.globals.backend_url + 'api/index.php/users'; + header['Accept'] = 'application/json'; + header['DOLAPIKEY'] = client.globals.dolApiKey; + header['Content-Type'] = 'application/json'; + return fetch(url, { + method: 'POST', + headers: header, + body: JSON.stringify( + { + login: login, + lastname: lastname, + pass: password + } + ) + }); +}; + +const adminCreatesUserWithAPI = function (dataTable) { + const userDetails = dataTable.rowsHash(); + return createUserRequest(userDetails['login'], userDetails['last name'], userDetails['password']) + .then((res) => { + response = res; + }); }; const adminHasCreatedUser = async function (dataTable) { - const header = {}; - const url = client.globals.backend_url + 'api/index.php/users'; - header['Accept'] = 'application/json'; - header['DOLAPIKEY'] = dolApiKey; - header['Content-Type'] = 'application/json'; - const userDetails = dataTable.hashes(); - for (const user of userDetails) { - await fetch(url, { - method: 'POST', - headers: header, - body: JSON.stringify( - { - login: user['login'], - lastname: user['last name'], - pass: user['password'] - } - ) - }) - .then((response) => { - if (response.status < 200 || response.status >= 400) { - throw new Error('Failed to create user: ' + user['login'] + - ' ' + response.statusText); - } - return response.text(); - }); - } + const userDetails = dataTable.hashes(); + for (const user of userDetails) { + await createUserRequest(user['login'], user['last name'], user['password']) + .then((response) => { + if (response.status < 200 || response.status >= 400) { + throw new Error('Failed to create user: ' + user['login'] + + ' ' + response.statusText); + } + }); + } }; -Before(async () => { - const header = {} - const adminUsername = client.globals.adminUsername; - const adminPassword = client.globals.adminPassword; - const params = new URLSearchParams() - params.set('login', adminUsername) - params.set('password', adminPassword) - const apiKey = `http://localhost/dolibarr/htdocs/api/index.php/login?${params.toString()}`; - header['Accept'] = 'application/json' - await fetch(apiKey, { - method: 'GET', - headers: header - }) - .then(async (response) => { - const jsonResponse = await response.json() - dolApiKey = jsonResponse['success']['token'] - }) -}) -Before(async () => { - initialUsers = await getUsers(); -}); +const getUsersLogin = async function () { + const header = {}; + const url = client.globals.backend_url + 'api/index.php/users/'; + header['Accept'] = 'application/json'; + header['DOLAPIKEY'] = client.globals.dolApiKey; + header['Content-Type'] = 'application/json'; + await fetch(url, { + method: 'GET', + headers: header + }) + .then(async (response) => { + const json_response = await response.json(); + for (const user of json_response) { + Login[user.login] = user.login; + } + }); +}; -After(async () => { - const finalUsers = await getUsers(); - const header = {}; - const url = client.globals.backend_url + 'api/index.php/users/'; - header['Accept'] = 'application/json'; - header['DOLAPIKEY'] = dolApiKey; - let found; - for (const finaluser in finalUsers) { - for (const initialuser in initialUsers) { - found = false; - if (initialuser === finaluser) { - found = true; - break; - } - } - if (!found) { - await fetch(url + finaluser, { - method: 'DELETE', - headers: header - }) - .then(res => { - if (res.status < 200 || res.status >= 400) { - throw new Error("Failed to delete user: " + res.statusText); - } - }); - } - } -}); +const userDoesNotExist = async function (login) { + await getUsersLogin(); + if (login in Login) { + Login = {}; + throw new Error(`user ${login} exists`); + } + Login = {}; + return; +}; + +const userShouldExist = async function (login) { + await getUsersLogin(); + if (login in Login) { + Login = {}; + return; + } else { + Login = {}; + throw new Error(`User ${login} does not Exist`); + } +}; + +const getStatusCode = async function (expectedStatusCode) { + const actualStatusCode = response.status.toString(); + return assert.strictEqual(actualStatusCode, expectedStatusCode, + `The expected status code was ${expectedStatusCode} but got ${actualStatusCode}`); +}; + +const getResponseMessage = async function (expectedResponseMessage) { + const json_response = await response.json(); + const actualResponseMessage = json_response['error']['0']; + return assert.strictEqual(actualResponseMessage, expectedResponseMessage, + `the expected response message was ${expectedResponseMessage} but got ${actualResponseMessage}`); +}; \ No newline at end of file From ee67d2b1a8df2a4c70f75027d2ca3c7a4dab6b61 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 10:30:39 +0200 Subject: [PATCH 230/317] fixnhish bom product stats --- htdocs/core/lib/product.lib.php | 84 +++++--- htdocs/product/class/product.class.php | 67 ++++++ htdocs/product/stats/bom.php | 277 +++++++++++++++++++++++++ 3 files changed, 400 insertions(+), 28 deletions(-) create mode 100644 htdocs/product/stats/bom.php diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index d97b66443de..1b87088a98b 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -357,34 +357,7 @@ function show_stats_for_company($product, $socid) print ''.$langs->trans("TotalQuantity").''; print ''; - // MO - if (!empty($conf->mrp->enabled) && $user->rights->mrp->read) - { - $nblines++; - $ret = $product->load_stats_mo($socid); - if ($ret < 0) dol_print_error($db); - $langs->load("orders"); - print ''; - print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; - print ''; - print $form->textwithpicto($product->stats_mo['customers_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['customers_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['customers_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['customers_produced'],$langs->trans("QtyAlreadyProduced")); - print ''; - print $form->textwithpicto($product->stats_mo['nb_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['nb_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['nb_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['nb_produced'],$langs->trans("QtyAlreadyProduced")); - print ''; - print $form->textwithpicto($product->stats_mo['qty_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['qty_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['qty_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['qty_produced'],$langs->trans("QtyAlreadyProduced")); - print ''; - print ''; - } - // Customer proposals + // Customer proposals if (!empty($conf->propal->enabled) && $user->rights->propale->lire) { $nblines++; @@ -512,6 +485,61 @@ function show_stats_for_company($product, $socid) print ''; } + // BOM + if (!empty($conf->bom->enabled) && $user->rights->bom->read) + { + $nblines++; + $ret = $product->load_stats_bom($socid); + if ($ret < 0) { + setEventMessage($product->error,'errors'); + } + $langs->load("mrp"); + + print ''; + print ''.img_object('', 'mrp').' '.$langs->trans("BOM").''; + print ''; + + print ''; + print $form->textwithpicto($product->stats_bom['nb_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_bom['nb_toconsume'],$langs->trans("ToConsume")); + print ''; + print $form->textwithpicto($product->stats_bom['qty_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_bom['qty_toconsume'],$langs->trans("ToConsume")); + print ''; + print ''; + } + + + // MO + if (!empty($conf->mrp->enabled) && $user->rights->mrp->read) + { + $nblines++; + $ret = $product->load_stats_mo($socid); + if ($ret < 0) { + setEventMessage($product->error,'errors'); + } + $langs->load("mrp"); + print ''; + print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; + print ''; + print $form->textwithpicto($product->stats_mo['customers_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['customers_consumed'],$langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['customers_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['customers_produced'],$langs->trans("QtyAlreadyProduced")); + print ''; + print $form->textwithpicto($product->stats_mo['nb_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['nb_consumed'],$langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['nb_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['nb_produced'],$langs->trans("QtyAlreadyProduced")); + print ''; + print $form->textwithpicto($product->stats_mo['qty_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['qty_consumed'],$langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['qty_toproduce'],$langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['qty_produced'],$langs->trans("QtyAlreadyProduced")); + print ''; + print ''; + } + return $nblines++; } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 4197facf313..3e9be60d81e 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2414,6 +2414,73 @@ class Product extends CommonObject return 1; } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Charge tableau des stats OF pour le produit/service + * + * @param int $socid Id societe + * @return integer Tableau des stats dans $this->stats_mo, <0 if ko >0 if ok + */ + public function load_stats_bom($socid = 0) { + // phpcs:enable + global $user, $hookmanager; + + $error=0; + + $this->stats_bom['nb_toproduce'] = 0; + $this->stats_bom['nb_toconsume'] = 0; + $this->stats_bom['qty_toproduce'] = 0; + $this->stats_bom['qty_toconsume'] = 0; + + $sql = "SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,"; + $sql .= " b.qty as qty_toproduce"; + $sql .= " FROM ".MAIN_DB_PREFIX."bom_bom as b"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bom_bomline as bl ON bl.fk_bom=b.rowid"; + $sql .= " WHERE "; + $sql .= " b.entity IN (".getEntity('bom').")"; + $sql .= " AND b.fk_product =".$this->id; + + $result = $this->db->query($sql); + if ($result) { + $obj = $this->db->fetch_object($result); + $this->stats_bom['nb_toproduce'] = $obj->nb_toproduce ? $obj->nb_toproduce : 0; + $this->stats_bom['qty_toproduce'] = $obj->qty_toproduce ? price2num($obj->qty_toproduce) : 0; + + } else { + $this->error = $this->db->error(); + $error++; + } + + $sql = "SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,"; + $sql .= " SUM(bl.qty) as qty_toconsume"; + $sql .= " FROM ".MAIN_DB_PREFIX."bom_bom as b"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bom_bomline as bl ON bl.fk_bom=b.rowid"; + $sql .= " WHERE "; + $sql .= " b.entity IN (".getEntity('bom').")"; + $sql .= " AND bl.fk_product =".$this->id; + + $result = $this->db->query($sql); + if ($result) { + $obj = $this->db->fetch_object($result); + $this->stats_bom['nb_toconsume'] = $obj->nb_toconsume ? $obj->nb_toconsume : 0; + $this->stats_bom['qty_toconsume'] = $obj->qty_toconsume ? price2num($obj->qty_toconsume) : 0; + + } else { + $this->error = $this->db->error(); + $error++; + } + + if (!empty($error)) { + return -1; + } + + $parameters = array('socid' => $socid); + $reshook = $hookmanager->executeHooks('loadStatsCustomerMO', $parameters, $this, $action); + if ($reshook > 0) $this->stats_bom = $hookmanager->resArray['stats_bom']; + + return 1; + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Charge tableau des stats propale pour le produit/service diff --git a/htdocs/product/stats/bom.php b/htdocs/product/stats/bom.php new file mode 100644 index 00000000000..4fd4586bb17 --- /dev/null +++ b/htdocs/product/stats/bom.php @@ -0,0 +1,277 @@ + + * Copyright (C) 2004-2009 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/product/stats/mo.php + * \ingroup product mo + * \brief Page of MO referring product + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array('mrp', 'products', 'companies')); + +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); + +// Security check +$fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref : '')); +$fieldtype = (!empty($ref) ? 'ref' : 'rowid'); +if ($user->socid) $socid = $user->socid; +$result = restrictedArea($user, 'produit|service', $fieldvalue, 'product&product', '', '', $fieldtype); + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('productstatscontract')); + +$mesg = ''; +$option = ''; + +// Load variable for pagination +$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortorder) $sortorder = "DESC"; +if (!$sortfield) $sortfield = "b.date_valid"; + + +/* + * View + */ + +$form = new Form($db); + +if ($id > 0 || !empty($ref)) +{ + $product = new Product($db); + $result = $product->fetch($id, $ref); + + $object = $product; + + $parameters = array('id'=>$id); + $reshook = $hookmanager->executeHooks('doActions', $parameters, $product, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + llxHeader("", "", $langs->trans("CardProduct".$product->type)); + + if ($result > 0) + { + $head = product_prepare_head($product); + $titre = $langs->trans("CardProduct".$product->type); + $picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product'); + dol_fiche_head($head, 'referers', $titre, -1, $picto); + + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + $linkback = ''.$langs->trans("BackToList").''; + + $shownav = 1; + if ($user->socid && !in_array('product', explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL))) $shownav = 0; + + dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref'); + + print '
    '; + + print '
    '; + print ''; + + $nboflines = show_stats_for_company($product, $socid); + + print "
    "; + + print '
    '; + print '
    '; + + dol_fiche_end(); + + $now = dol_now(); + + //Calcul total qty and amount for global if full scan list + $total_qty_toconsume = 0; + $total_qty_toproduce = 0; + $bom_data_result=array(); + + + //Qauntity to produce + $sql = "SELECT b.rowid as rowid, b.ref, b.status, b.date_valid,"; + $sql .= " b.qty as qty_toproduce"; + $sql .= " FROM ".MAIN_DB_PREFIX."bom_bom as b"; + $sql .= " WHERE "; + $sql .= " b.entity IN (".getEntity('bom').")"; + $sql .= " AND b.fk_product =".$product->id; + $sql .= $db->order($sortfield, $sortorder); + + // Count total nb of records + $totalofrecords = ''; + if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) + { + $result = $db->query($sql); + if ($result) { + $totalofrecords = $db->num_rows($result); + while ($objp = $db->fetch_object($result)) { + $total_qty_toproduce += $objp->qty_toproduce; + } + } else { + dol_print_error($db); + } + } + $sql .= $db->plimit($limit + 1, $offset); + + $result = $db->query($sql); + if ($result) { + $bomtmp = new BOM($db); + $num = $db->num_rows($result); + $i = 0; + if ($num > 0) { + while ($i < min($num, $limit)) { + $objp = $db->fetch_object($result); + $bomtmp->id = $objp->rowid; + $bomtmp->ref = $objp->ref; + $bom_data_result[$objp->rowid]['link'] = $bomtmp->getNomUrl(1, 'production'); + $bom_data_result[$objp->rowid]['qty_toproduce']+=($objp->qty_toproduce > 0 ? $objp->qty_toproduce : 0); + $bom_data_result[$objp->rowid]['qty_toconsume']=0; + $bom_data_result[$objp->rowid]['date_valid']=dol_print_date($db->jdate($objp->date_valid), 'dayhour'); + $bom_data_result[$objp->rowid]['status']=$bomtmp->LibStatut($objp->status,5); + $i++; + } + } + }else { + dol_print_error($db); + } + $db->free($result); + + //Qauntity to consume + $sql = "SELECT b.rowid as rowid, b.ref, b.status, b.date_valid,"; + $sql .= " SUM(bl.qty) as qty_toconsume"; + $sql .= " FROM ".MAIN_DB_PREFIX."bom_bom as b"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bom_bomline as bl ON bl.fk_bom=b.rowid"; + $sql .= " WHERE "; + $sql .= " b.entity IN (".getEntity('bom').")"; + $sql .= " AND bl.fk_product=".$product->id; + $sql .= " GROUP BY b.rowid, b.ref, b.date_valid, b.status"; + $sql .= $db->order($sortfield, $sortorder); + + // Count total nb of records + $totalofrecords = ''; + if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) + { + $result = $db->query($sql); + if ($result) { + $totalofrecords = $db->num_rows($result); + while ($objp = $db->fetch_object($result)) { + $total_qty_toconsume += $objp->qty_toconsume; + } + } else { + dol_print_error($db); + } + } + $sql .= $db->plimit($limit + 1, $offset); + + $result = $db->query($sql); + if ($result) { + $bomtmp = new BOM($db); + $num = $db->num_rows($result); + $i = 0; + if ($num > 0) { + while ($i < min($num, $limit)) { + $objp = $db->fetch_object($result); + $bomtmp->id = $objp->rowid; + $bomtmp->ref = $objp->ref; + + if (!array_key_exists($objp->rowid,$bom_data_result)) { + $bom_data_result[$objp->rowid]['link'] = $bomtmp->getNomUrl(1, 'production'); + $bom_data_result[$objp->rowid]['qty_toproduce']=0; + $bom_data_result[$objp->rowid]['qty_toconsume']+=($objp->qty_toconsume > 0 ? $objp->qty_toconsume : 0); + $bom_data_result[$objp->rowid]['date_valid']=dol_print_date($db->jdate($objp->date_valid), 'dayhour'); + $bom_data_result[$objp->rowid]['status']=$bomtmp->LibStatut($objp->status,5); + } else { + $bom_data_result[$objp->rowid]['qty_toconsume']+=($objp->qty_toconsume > 0 ? $objp->qty_toconsume : 0); + } + $i++; + } + } + }else { + dol_print_error($db); + } + $db->free($result); + + + if ($limit > 0 && $limit != $conf->liste_limit) $option .= '&limit='.urlencode($limit); + if (!empty($id)) $option .= '&id='.$product->id; + if (!empty($search_month)) $option .= '&search_month='.urlencode($search_month); + if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); + + print '
    '."\n"; + if (!empty($sortfield)) + print ''; + if (!empty($sortorder)) + print ''; + + print_barre_liste($langs->trans("BOMs"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + + if (!empty($page)) $option .= '&page='.urlencode($page); + + print '
    '; + print ''; + + print ''; + print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "b.rowid", "", "&id=".$product->id, '', $sortfield, $sortorder); + print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "b.date_valid", "", "&id=".$product->id, 'align="center"', $sortfield, $sortorder); + print_liste_field_titre("ToConsume", $_SERVER["PHP_SELF"], "", "", "&id=".$product->id, '', $sortfield, $sortorder, 'center '); + print_liste_field_titre("QtyToProduce", $_SERVER["PHP_SELF"], "", "", "&id=".$product->id, '', $sortfield, $sortorder, 'center '); + print_liste_field_titre("Status", $_SERVER["PHP_SELF"], "b.status", "", "&id=".$product->id, '', $sortfield, $sortorder, 'center '); + print "\n"; + + if (!empty($bom_data_result)) { + + foreach ($bom_data_result as $data) + { + print ''; + print '\n"; + print ""; + print ''; + print ''; + print ''; + print "\n"; + } + print '
    '; + print $data['link']; + print ""; + print $data['date_valid']."'.$data['qty_toconsume'].''.$data['qty_toproduce'].''.$data['status'].'
    '; + print '
    '; + print '
    '; + } + } +} else { + dol_print_error(); +} + +// End of page +llxFooter(); +$db->close(); From 8bfb04ea7f3fad592a93c92ac2a5bfc57a33fd6b Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Wed, 14 Oct 2020 08:34:30 +0000 Subject: [PATCH 231/317] Fixing style errors. --- htdocs/core/lib/product.lib.php | 36 +++++++++++++------------- htdocs/product/class/product.class.php | 5 ++-- htdocs/product/stats/bom.php | 7 +++-- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index 1b87088a98b..8c0253e927c 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -491,7 +491,7 @@ function show_stats_for_company($product, $socid) $nblines++; $ret = $product->load_stats_bom($socid); if ($ret < 0) { - setEventMessage($product->error,'errors'); + setEventMessage($product->error, 'errors'); } $langs->load("mrp"); @@ -500,11 +500,11 @@ function show_stats_for_company($product, $socid) print ''; print ''; - print $form->textwithpicto($product->stats_bom['nb_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_bom['nb_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_bom['nb_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_bom['nb_toconsume'], $langs->trans("ToConsume")); print ''; - print $form->textwithpicto($product->stats_bom['qty_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_bom['qty_toconsume'],$langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_bom['qty_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_bom['qty_toconsume'], $langs->trans("ToConsume")); print ''; print ''; } @@ -516,26 +516,26 @@ function show_stats_for_company($product, $socid) $nblines++; $ret = $product->load_stats_mo($socid); if ($ret < 0) { - setEventMessage($product->error,'errors'); + setEventMessage($product->error, 'errors'); } $langs->load("mrp"); print ''; print ''.img_object('', 'mrp').' '.$langs->trans("MO").''; print ''; - print $form->textwithpicto($product->stats_mo['customers_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['customers_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['customers_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['customers_produced'],$langs->trans("QtyAlreadyProduced")); + print $form->textwithpicto($product->stats_mo['customers_toconsume'], $langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['customers_consumed'], $langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['customers_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['customers_produced'], $langs->trans("QtyAlreadyProduced")); print ''; - print $form->textwithpicto($product->stats_mo['nb_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['nb_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['nb_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['nb_produced'],$langs->trans("QtyAlreadyProduced")); + print $form->textwithpicto($product->stats_mo['nb_toconsume'], $langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['nb_consumed'], $langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['nb_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['nb_produced'], $langs->trans("QtyAlreadyProduced")); print ''; - print $form->textwithpicto($product->stats_mo['qty_toconsume'],$langs->trans("ToConsume")); - print $form->textwithpicto($product->stats_mo['qty_consumed'],$langs->trans("QtyAlreadyConsumed")); - print $form->textwithpicto($product->stats_mo['qty_toproduce'],$langs->trans("QtyToProduce")); - print $form->textwithpicto($product->stats_mo['qty_produced'],$langs->trans("QtyAlreadyProduced")); + print $form->textwithpicto($product->stats_mo['qty_toconsume'], $langs->trans("ToConsume")); + print $form->textwithpicto($product->stats_mo['qty_consumed'], $langs->trans("QtyAlreadyConsumed")); + print $form->textwithpicto($product->stats_mo['qty_toproduce'], $langs->trans("QtyToProduce")); + print $form->textwithpicto($product->stats_mo['qty_produced'], $langs->trans("QtyAlreadyProduced")); print ''; print ''; } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index d9a1928d021..b1e64e0af73 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2422,7 +2422,8 @@ class Product extends CommonObject * @param int $socid Id societe * @return integer Tableau des stats dans $this->stats_mo, <0 if ko >0 if ok */ - public function load_stats_bom($socid = 0) { + public function load_stats_bom($socid = 0) + { // phpcs:enable global $user, $hookmanager; @@ -2446,7 +2447,6 @@ class Product extends CommonObject $obj = $this->db->fetch_object($result); $this->stats_bom['nb_toproduce'] = $obj->nb_toproduce ? $obj->nb_toproduce : 0; $this->stats_bom['qty_toproduce'] = $obj->qty_toproduce ? price2num($obj->qty_toproduce) : 0; - } else { $this->error = $this->db->error(); $error++; @@ -2465,7 +2465,6 @@ class Product extends CommonObject $obj = $this->db->fetch_object($result); $this->stats_bom['nb_toconsume'] = $obj->nb_toconsume ? $obj->nb_toconsume : 0; $this->stats_bom['qty_toconsume'] = $obj->qty_toconsume ? price2num($obj->qty_toconsume) : 0; - } else { $this->error = $this->db->error(); $error++; diff --git a/htdocs/product/stats/bom.php b/htdocs/product/stats/bom.php index 4fd4586bb17..03b873995fb 100644 --- a/htdocs/product/stats/bom.php +++ b/htdocs/product/stats/bom.php @@ -157,7 +157,7 @@ if ($id > 0 || !empty($ref)) $bom_data_result[$objp->rowid]['qty_toproduce']+=($objp->qty_toproduce > 0 ? $objp->qty_toproduce : 0); $bom_data_result[$objp->rowid]['qty_toconsume']=0; $bom_data_result[$objp->rowid]['date_valid']=dol_print_date($db->jdate($objp->date_valid), 'dayhour'); - $bom_data_result[$objp->rowid]['status']=$bomtmp->LibStatut($objp->status,5); + $bom_data_result[$objp->rowid]['status']=$bomtmp->LibStatut($objp->status, 5); $i++; } } @@ -204,12 +204,12 @@ if ($id > 0 || !empty($ref)) $bomtmp->id = $objp->rowid; $bomtmp->ref = $objp->ref; - if (!array_key_exists($objp->rowid,$bom_data_result)) { + if (!array_key_exists($objp->rowid, $bom_data_result)) { $bom_data_result[$objp->rowid]['link'] = $bomtmp->getNomUrl(1, 'production'); $bom_data_result[$objp->rowid]['qty_toproduce']=0; $bom_data_result[$objp->rowid]['qty_toconsume']+=($objp->qty_toconsume > 0 ? $objp->qty_toconsume : 0); $bom_data_result[$objp->rowid]['date_valid']=dol_print_date($db->jdate($objp->date_valid), 'dayhour'); - $bom_data_result[$objp->rowid]['status']=$bomtmp->LibStatut($objp->status,5); + $bom_data_result[$objp->rowid]['status']=$bomtmp->LibStatut($objp->status, 5); } else { $bom_data_result[$objp->rowid]['qty_toconsume']+=($objp->qty_toconsume > 0 ? $objp->qty_toconsume : 0); } @@ -249,7 +249,6 @@ if ($id > 0 || !empty($ref)) print "\n"; if (!empty($bom_data_result)) { - foreach ($bom_data_result as $data) { print ''; From 14a3e30270bf18b54c6e8b95bb5dbb22ef599f1c Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 11:20:27 +0200 Subject: [PATCH 232/317] fix travis --- htdocs/product/class/product.class.php | 2 +- htdocs/product/stats/bom.php | 2 +- htdocs/product/stats/mo.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index d9a1928d021..d375a78aa9a 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2387,7 +2387,7 @@ class Product extends CommonObject $sql .= " c.entity IN (".getEntity('mo').")"; $sql .= " AND mp.fk_product =".$this->id; - $sql .= " AND mp.role ='".$role."'"; + $sql .= " AND mp.role ='".$this->db->escape($role)."'"; if ($socid > 0) { $sql .= " AND c.fk_soc = ".$socid; } diff --git a/htdocs/product/stats/bom.php b/htdocs/product/stats/bom.php index 4fd4586bb17..f2cd8dbf5d7 100644 --- a/htdocs/product/stats/bom.php +++ b/htdocs/product/stats/bom.php @@ -83,7 +83,7 @@ if ($id > 0 || !empty($ref)) $head = product_prepare_head($product); $titre = $langs->trans("CardProduct".$product->type); $picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product'); - dol_fiche_head($head, 'referers', $titre, -1, $picto); + print dol_get_fiche_head($head, 'referers', $titre, -1, $picto); $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; diff --git a/htdocs/product/stats/mo.php b/htdocs/product/stats/mo.php index d8dfa9053e8..54af6217831 100644 --- a/htdocs/product/stats/mo.php +++ b/htdocs/product/stats/mo.php @@ -85,7 +85,7 @@ if ($id > 0 || !empty($ref)) $head = product_prepare_head($product); $titre = $langs->trans("CardProduct".$product->type); $picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product'); - dol_fiche_head($head, 'referers', $titre, -1, $picto); + print dol_get_fiche_head($head, 'referers', $titre, -1, $picto); $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; From 02fcee5d94aaef9a63b2b7b3ae96d188142310dc Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 12:21:31 +0200 Subject: [PATCH 233/317] Fix make the default sender email mandatory into setup (if not defined, no emails can be sent). --- htdocs/admin/mails.php | 70 +++++++++++++++++++++-------------- htdocs/langs/en_US/admin.lang | 1 + 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index 8971f5a69d4..55316e47332 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -31,6 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $langs->loadLangs(array("companies", "products", "admin", "mails", "other", "errors")); $action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); if (!$user->admin) accessforbidden(); @@ -64,33 +65,46 @@ complete_substitutions_array($substitutionarrayfortest, $langs); * Actions */ -if ($action == 'update' && empty($_POST["cancel"])) +if ($action == 'update' && !$cancel) { - dolibarr_set_const($db, "MAIN_DISABLE_ALL_MAILS", GETPOST("MAIN_DISABLE_ALL_MAILS", 'int'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_FORCE_SENDTO", GETPOST("MAIN_MAIL_FORCE_SENDTO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_ENABLED_USER_DEST_SELECT", GETPOST("MAIN_MAIL_ENABLED_USER_DEST_SELECT", 'int'), 'chaine', 0, '', $conf->entity); - // Send mode parameters - dolibarr_set_const($db, "MAIN_MAIL_SENDMODE", GETPOST("MAIN_MAIL_SENDMODE", 'aZ09'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTP_PORT", GETPOST("MAIN_MAIL_SMTP_PORT", 'int'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTP_SERVER", GETPOST("MAIN_MAIL_SMTP_SERVER", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTPS_ID", GETPOST("MAIN_MAIL_SMTPS_ID", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTPS_PW", GETPOST("MAIN_MAIL_SMTPS_PW", 'none'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_TLS", GETPOST("MAIN_MAIL_EMAIL_TLS", 'int'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_STARTTLS", GETPOST("MAIN_MAIL_EMAIL_STARTTLS", 'int'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED", GETPOST("MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED", 'int'), 'chaine', 0, '', $conf->entity); + if (! $error && ! GETPOST("MAIN_MAIL_EMAIL_FROM", 'alphanohtml')) { + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("MAIN_MAIL_EMAIL_FROM")), null, 'errors'); + $action = 'edit'; + } + if (! $error && ! isValidEmail(GETPOST("MAIN_MAIL_EMAIL_FROM", 'alphanohtml'))) { + $error++; + setEventMessages($langs->trans("ErrorBadEMail", GETPOST("MAIN_MAIL_EMAIL_FROM", 'alphanohtml')), null, 'errors'); + $action = 'edit'; + } - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_ENABLED", GETPOST("MAIN_MAIL_EMAIL_DKIM_ENABLED", 'int'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_DOMAIN", GETPOST("MAIN_MAIL_EMAIL_DKIM_DOMAIN", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_SELECTOR", GETPOST("MAIN_MAIL_EMAIL_DKIM_SELECTOR", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY", GETPOST("MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - // Content parameters - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_FROM", GETPOST("MAIN_MAIL_EMAIL_FROM", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_ERRORS_TO", GETPOST("MAIN_MAIL_ERRORS_TO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_AUTOCOPY_TO", GETPOST("MAIN_MAIL_AUTOCOPY_TO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, 'MAIN_MAIL_DEFAULT_FROMTYPE', GETPOST('MAIN_MAIL_DEFAULT_FROMTYPE', 'alphanohtml'), 'chaine', 0, '', $conf->entity); + if (! $error) { + dolibarr_set_const($db, "MAIN_DISABLE_ALL_MAILS", GETPOST("MAIN_DISABLE_ALL_MAILS", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_FORCE_SENDTO", GETPOST("MAIN_MAIL_FORCE_SENDTO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_ENABLED_USER_DEST_SELECT", GETPOST("MAIN_MAIL_ENABLED_USER_DEST_SELECT", 'int'), 'chaine', 0, '', $conf->entity); + // Send mode parameters + dolibarr_set_const($db, "MAIN_MAIL_SENDMODE", GETPOST("MAIN_MAIL_SENDMODE", 'aZ09'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTP_PORT", GETPOST("MAIN_MAIL_SMTP_PORT", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTP_SERVER", GETPOST("MAIN_MAIL_SMTP_SERVER", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTPS_ID", GETPOST("MAIN_MAIL_SMTPS_ID", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTPS_PW", GETPOST("MAIN_MAIL_SMTPS_PW", 'none'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_TLS", GETPOST("MAIN_MAIL_EMAIL_TLS", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_STARTTLS", GETPOST("MAIN_MAIL_EMAIL_STARTTLS", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED", GETPOST("MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED", 'int'), 'chaine', 0, '', $conf->entity); - header("Location: ".$_SERVER["PHP_SELF"]."?mainmenu=home&leftmenu=setup"); - exit; + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_ENABLED", GETPOST("MAIN_MAIL_EMAIL_DKIM_ENABLED", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_DOMAIN", GETPOST("MAIN_MAIL_EMAIL_DKIM_DOMAIN", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_SELECTOR", GETPOST("MAIN_MAIL_EMAIL_DKIM_SELECTOR", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY", GETPOST("MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + // Content parameters + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_FROM", GETPOST("MAIN_MAIL_EMAIL_FROM", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_ERRORS_TO", GETPOST("MAIN_MAIL_ERRORS_TO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_AUTOCOPY_TO", GETPOST("MAIN_MAIL_AUTOCOPY_TO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, 'MAIN_MAIL_DEFAULT_FROMTYPE', GETPOST('MAIN_MAIL_DEFAULT_FROMTYPE', 'alphanohtml'), 'chaine', 0, '', $conf->entity); + + header("Location: ".$_SERVER["PHP_SELF"]."?mainmenu=home&leftmenu=setup"); + exit; + } } @@ -462,8 +476,8 @@ if ($action == 'edit') print ''.$langs->trans("OtherOptions").''; // From - print ''.$langs->trans("MAIN_MAIL_EMAIL_FROM", ini_get('sendmail_from') ?ini_get('sendmail_from') : $langs->transnoentities("Undefined")).''; - print ''.$langs->trans("MAIN_MAIL_EMAIL_FROM", ini_get('sendmail_from') ?ini_get('sendmail_from') : $langs->transnoentities("Undefined")).''; + print ''; // Default from type @@ -538,7 +552,7 @@ if ($action == 'edit') print $text; if ($conf->global->MAIN_MAIL_SENDMODE == 'mail' && empty($conf->global->MAIN_HIDE_WARNING_TO_ENCOURAGE_SMTP_SETUP)) { - print $form->textwithpicto('', $langs->trans("WarningPHPMail").'
    '.$langs->trans("WarningPHPMailA").'
    '.$langs->trans("WarningPHPMailB").'
    '.$langs->trans("WarningPHPMailC"), 1, 'warning'); + print $form->textwithpicto('', $langs->trans("WarningPHPMail").'
    '.$langs->trans("WarningPHPMailA").'
    '.$langs->trans("WarningPHPMailB").'
    '.$langs->trans("WarningPHPMailC").'

    '.$langs->trans("WarningPHPMailD"), 1, 'warning'); } print ''; @@ -637,7 +651,7 @@ if ($action == 'edit') print ''; if ($conf->global->MAIN_MAIL_SENDMODE == 'mail' && empty($conf->global->MAIN_HIDE_WARNING_TO_ENCOURAGE_SMTP_SETUP)) { - print info_admin($langs->trans("WarningPHPMail").'
    '.$langs->trans("WarningPHPMailA").'
    '.$langs->trans("WarningPHPMailB").'
    '.$langs->trans("WarningPHPMailC"), 0, 0, 'warning'); + print info_admin($langs->trans("WarningPHPMail").'
    '.$langs->trans("WarningPHPMailA").'
    '.$langs->trans("WarningPHPMailB").'
    '.$langs->trans("WarningPHPMailC").'

    '.$langs->trans("WarningPHPMailD"), 0, 0, 'warning'); } print '
    '; diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 3091efcf7fd..e887b29879d 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -483,6 +483,7 @@ WarningPHPMail=WARNING: The setup to send emails from the application is using t WarningPHPMailA=- Using the server of the Email Service Provider increase the trustability of your email, so it increase the deliverablity without being flagging as SPAM WarningPHPMailB=- Some Email Service Providers (like Yahoo) do not allow you to send an email from another server than their own server. Your current setup uses the server of the application to send email and not the server of your email provider, so some recipients (the one compatible with the restrictive DMARC protocol), will ask your email provider if they can accept your email and some email providers (like Yahoo) may respond "no" because the server is not theirs, so few of your sent Emails may not be accepted for delivery (be careful also of your email provider's sending quota). WarningPHPMailC=- Using the SMTP server of your own Email Service Provider to send emails is also interesting so all emails sent from application will also be saved into your "Sent" directory of your mailbox. +WarningPHPMailD=If the method 'PHP Mail' is really the method you would like to use, you can remove this warning by adding the constant MAIN_HIDE_WARNING_TO_ENCOURAGE_SMTP_SETUP to 1 in Home - Setup - Other. WarningPHPMail2=If your email SMTP provider need to restrict email client to some IP addresses (very rare), this is the IP address of the mail user agent (MUA) for your ERP CRM application: %s. WarningPHPMailSPF=If the domain name in your sender email address is protected by a SPF record (ask you domain name registar), you must add the following IPs in the SPF record of the DNS of your domain: %s. ClickToShowDescription=Click to show description From 77de8c242c6ecafad8adc76bc5f47868edd42d50 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 12:24:35 +0200 Subject: [PATCH 234/317] commit add table --- .../mysql/data/llx_c_product_nature.sql | 29 +++++++++++++++++++ .../install/mysql/migration/12.0.0-13.0.0.sql | 12 ++++++++ .../mysql/tables/llx_c_product_nature.key.sql | 1 + .../mysql/tables/llx_c_product_nature.sql | 24 +++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 htdocs/install/mysql/data/llx_c_product_nature.sql create mode 100644 htdocs/install/mysql/tables/llx_c_product_nature.key.sql create mode 100644 htdocs/install/mysql/tables/llx_c_product_nature.sql diff --git a/htdocs/install/mysql/data/llx_c_product_nature.sql b/htdocs/install/mysql/data/llx_c_product_nature.sql new file mode 100644 index 00000000000..7594e8e3f69 --- /dev/null +++ b/htdocs/install/mysql/data/llx_c_product_nature.sql @@ -0,0 +1,29 @@ +-- Copyright (C) 2020 florian HENRY florian.henry@scopen.fr +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- + +-- +-- Do not place a comment at the end of the line, this file is parsed when +-- from the install and all '--' are removed. +-- +-- Ne pas placer de commentaire en fin de ligne, ce fichier est parsé lors +-- de l'install et tous les sigles '--' sont supprimés. +-- + +INSERT INTO llx_c_product_nature (code, label, active) VALUES (-1, '', 1); +INSERT INTO llx_c_product_nature (code, label, active) VALUES (0, 'RowMaterial', 1); +INSERT INTO llx_c_product_nature (code, label, active) VALUES (1, 'Finished', 1); + diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 43868da4a1b..bf9432a6e81 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -406,3 +406,15 @@ ALTER TABLE llx_projet_task_time MODIFY COLUMN datec datetime; DELETE FROM llx_user_rights WHERE fk_id IN (SELECT id FROM llx_rights_def where module = 'holiday' and perms = 'lire_tous'); DELETE FROM llx_rights_def where module = 'holiday' and perms = 'lire_tous'; +CREATE TABLE llx_c_product_nature ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code integer NOT NULL, + label varchar(100), + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; + +ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code); + +INSERT INTO llx_c_product_nature (code, label, active) VALUES (-1, '', 1); +INSERT INTO llx_c_product_nature (code, label, active) VALUES (0, 'RowMaterial', 1); +INSERT INTO llx_c_product_nature (code, label, active) VALUES (1, 'Finished', 1); diff --git a/htdocs/install/mysql/tables/llx_c_product_nature.key.sql b/htdocs/install/mysql/tables/llx_c_product_nature.key.sql new file mode 100644 index 00000000000..17459032ecd --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_product_nature.key.sql @@ -0,0 +1 @@ +ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code); diff --git a/htdocs/install/mysql/tables/llx_c_product_nature.sql b/htdocs/install/mysql/tables/llx_c_product_nature.sql new file mode 100644 index 00000000000..b2f9892aa1e --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_product_nature.sql @@ -0,0 +1,24 @@ +-- ======================================================================== +-- Copyright (C) 2020 Florian HENRY +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- ======================================================================== + +CREATE TABLE llx_c_product_nature ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(3) NOT NULL, + label varchar(100), + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; From 2d1d76b5a3fd7eb27f1db51094b72ce72a6cce12 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 12:26:10 +0200 Subject: [PATCH 235/317] add credentials --- htdocs/product/stats/bom.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/product/stats/bom.php b/htdocs/product/stats/bom.php index 4b24763747a..7614d2dcc50 100644 --- a/htdocs/product/stats/bom.php +++ b/htdocs/product/stats/bom.php @@ -2,6 +2,7 @@ /* Copyright (C) 2003-2007 Rodolphe Quiedeville * Copyright (C) 2004-2009 Laurent Destailleur * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2020 Floiran Henry * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From a0b17635fdf3816beaafaa7c3a1dcfa85ad076ea Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 14:02:07 +0200 Subject: [PATCH 236/317] NEW When creating a user from a member linked to a thirdparty, you can decide if it is an internal or external (default) user. --- htdocs/adherents/card.php | 19 ++++++++++++++----- htdocs/core/class/html.form.class.php | 5 +++-- htdocs/langs/en_US/users.lang | 1 + htdocs/main.inc.php | 2 +- htdocs/societe/class/societe.class.php | 11 ++++++----- htdocs/user/class/user.class.php | 3 ++- 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php index d0a67153209..cd432aa12d6 100644 --- a/htdocs/adherents/card.php +++ b/htdocs/adherents/card.php @@ -181,7 +181,12 @@ if (empty($reshook)) { if ($result > 0) { // Creation user $nuser = new User($db); - $result = $nuser->create_from_member($object, GETPOST('login', 'alphanohtml')); + $tmpuser = dol_clone($object); + if (GETPOST('internalorexternal', 'aZ09') == 'internal') { + $tmpuser->fk_soc = 0; + } + + $result = $nuser->create_from_member($tmpuser, GETPOST('login', 'alphanohtml')); if ($result < 0) { $langs->load("errors"); @@ -1279,11 +1284,15 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $formquestion = array( array('label' => $langs->trans("LoginToCreate"), 'type' => 'text', 'name' => 'login', 'value' => $login) ); - $text = $langs->trans("ConfirmCreateLogin").'
    '; - if (!empty($conf->societe->enabled)) { - if ($object->socid > 0) $text .= $langs->trans("UserWillBeExternalUser"); - else $text .= $langs->trans("UserWillBeInternalUser"); + if (!empty($conf->societe->enabled) && $object->socid > 0) { + $object->fetch_thirdparty(); + $formquestion[] = array('label' => $langs->trans("UserWillBe"), 'type' => 'radio', 'name' => 'internalorexternal', 'default'=>'external', 'values' => array('external'=>$langs->trans("External").' - '.$langs->trans("LinkedToDolibarrThirdParty").' '.$object->thirdparty->getNomUrl(1, '', 0, 1), 'internal'=>$langs->trans("Internal"))); } + $text = ''; + if (!empty($conf->societe->enabled) && $object->socid <= 0) { + $text .= $langs->trans("UserWillBeInternalUser").'
    '; + } + $text .= $langs->trans("ConfirmCreateLogin"); print $form->formconfirm($_SERVER["PHP_SELF"]."?rowid=".$object->id, $langs->trans("CreateDolibarrLogin"), $text, "confirm_create_user", $formquestion, 'yes'); } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 452454ced5b..e58ba5d5a8e 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -4213,10 +4213,11 @@ class Form $more .= '
    '; if ($i == 0) $more .= '
    '.$input['label'].'
    '; else $more .= '
     
    '; - $more .= '
    '.$selval.''; $more .= '
    '."\n"; $i++; } diff --git a/htdocs/langs/en_US/users.lang b/htdocs/langs/en_US/users.lang index d6ffb849aa8..996ba20ab7d 100644 --- a/htdocs/langs/en_US/users.lang +++ b/htdocs/langs/en_US/users.lang @@ -75,6 +75,7 @@ CreateInternalUserDesc=This form allows you to create an internal user in your c InternalExternalDesc=An internal user is a user that is part of your company/organization.
    An external user is a customer, vendor or other (Creating an external user for a third-party can be done from the contact record of the third-party).

    In both cases, permissions defines rights on Dolibarr, also external user can have a different menu manager than internal user (See Home - Setup - Display) PermissionInheritedFromAGroup=Permission granted because inherited from one of a user's group. Inherited=Inherited +UserWillBe=Created user will be UserWillBeInternalUser=Created user will be an internal user (because not linked to a particular third party) UserWillBeExternalUser=Created user will be an external user (because linked to a particular third party) IdPhoneCaller=Id phone caller diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index e2c4b605dcc..9ecd00ca36f 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -375,7 +375,7 @@ if ((!defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && !empty($conf->gl // Check all cases that need a token (all POST actions, all actions and mass actions on pages with CSRFCHECK_WITH_TOKEN set, all sensitive GET actions) if ($_SERVER['REQUEST_METHOD'] == 'POST' || ((GETPOSTISSET('action') || GETPOSTISSET('massaction')) && defined('CSRFCHECK_WITH_TOKEN')) || - in_array(GETPOST('action', 'aZ09'), array('add', 'addtimespent', 'update', 'install', 'delete', 'deleteprof', 'deletepayment'))) + in_array(GETPOST('action', 'aZ09'), array('add', 'addtimespent', 'update', 'install', 'delete', 'deleteprof', 'deletepayment', 'confirm_create_user', 'confirm_create_thirdparty'))) { if (!GETPOSTISSET('token')) { if (GETPOST('uploadform', 'int')) { diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index ac1aa5b8f98..fee36c3ff1b 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2358,11 +2358,12 @@ class Societe extends CommonObject $code .= $this->code_fournisseur.' - '; } - if ($conf->global->SOCIETE_ADD_REF_IN_LIST == 1) - { - $name = $code.' '.$name; - } else { - $name = $code; + if ($code) { + if ($conf->global->SOCIETE_ADD_REF_IN_LIST == 1) { + $name = $code.' '.$name; + } else { + $name = $code; + } } } diff --git a/htdocs/user/class/user.class.php b/htdocs/user/class/user.class.php index c82eafb353a..1649032fc8d 100644 --- a/htdocs/user/class/user.class.php +++ b/htdocs/user/class/user.class.php @@ -1318,7 +1318,8 @@ class User extends CommonObject // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** - * Create a user into database from a member object + * Create a user into database from a member object. + * If $member->fk_soc is set, it will be an external user. * * @param Adherent $member Object member source * @param string $login Login to force From a2ef7bc61e19625f28887dcecdad149e5a8d01fb Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 14:26:40 +0200 Subject: [PATCH 237/317] add select --- htdocs/core/class/cproductnature.class.php | 363 ++++++++++++++++++ .../product/class/html.formproduct.class.php | 53 +++ 2 files changed, 416 insertions(+) create mode 100644 htdocs/core/class/cproductnature.class.php diff --git a/htdocs/core/class/cproductnature.class.php b/htdocs/core/class/cproductnature.class.php new file mode 100644 index 00000000000..cda719b87cd --- /dev/null +++ b/htdocs/core/class/cproductnature.class.php @@ -0,0 +1,363 @@ + + * Copyright (C) 2020 Florian HENRY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/class/cproductnature.class.php + * \ingroup core + * \brief This file is CRUD class file (Create/Read/Update/Delete) for c_units dictionary + */ + + +/** + * Class of dictionary of nature of product (used by imports) + */ +class CProductNature // extends CommonObject +{ + /** + * @var DoliDB Database handler. + */ + public $db; + + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * @var string[] Error codes (or messages) + */ + public $errors = array(); + public $records = array(); + + public $element='cproductnbature'; + public $table_element='c_product_nature'; + + /** + * @var int ID + */ + public $id; + + public $code; + public $label; + public $active; + + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + } + + + /** + * Create object into database + * + * @param User $user User that create + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + // Clean parameters + + if (isset($this->id)) $this->id = (int) $this->id; + if (isset($this->code)) $this->code = trim($this->code); + if (isset($this->label)) $this->libelle = trim($this->label); + if (isset($this->active)) $this->active = trim($this->active); + + // Check parameters + // Put here code to add control on parameters values + + // Insert request + $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element."("; + $sql .= "rowid,"; + $sql .= "code,"; + $sql .= "label,"; + $sql .= "active"; + $sql .= ") VALUES ("; + $sql .= " ".(!isset($this->id) ? 'NULL' : $this->db->escape($this->id)).","; + $sql .= " ".(!isset($this->code) ? 'NULL' : $this->db->escape($this->code)).","; + $sql .= " ".(!isset($this->label) ? 'NULL' : "'".$this->db->escape($this->label)."'").","; + $sql .= " ".(!isset($this->active) ? 'NULL' : $this->db->escape($this->active)).","; + $sql .= ")"; + + $this->db->begin(); + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { $error++; $this->errors[] = "Error ".$this->db->lasterror(); } + + if (!$error) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element); + } + + // Commit or rollback + if ($error) + { + foreach ($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR); + $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return $this->id; + } + } + + + /** + * Load object in memory from database + * + * @param int $id Id of CUnit object to fetch (rowid) + * @param string $code Code + * @return int <0 if KO, >0 if OK + */ + public function fetch($id, $code = '') + { + global $langs; + + $sql = "SELECT"; + $sql .= " t.rowid,"; + $sql .= " t.code,"; + $sql .= " t.label,"; + $sql .= " t.active"; + $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + $sql_where = array(); + if ($id) $sql_where[] = " t.rowid = ".$id; + if ($code) $sql_where[] = " t.code = ".$this->db->escape($code); + if (count($sql_where) > 0) { + $sql .= ' WHERE '.implode(' AND ', $sql_where); + } + + $resql = $this->db->query($sql); + if ($resql) + { + if ($this->db->num_rows($resql)) + { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + $this->code = $obj->code; + $this->label = $obj->label; + $this->active = $obj->active; + } + $this->db->free($resql); + + return 1; + } else { + $this->error = "Error ".$this->db->lasterror(); + return -1; + } + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $sql = 'SELECT'; + $sql .= " t.rowid,"; + $sql .= " t.code,"; + $sql .= " t.label,"; + $sql .= " t.active"; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid' || $key == 't.active' || $key == 't.code') { + $sqlwhere[] = $key.'='.(int) $value; + } elseif (strpos($key, 'date') !== false) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 't.label') { + $sqlwhere[] = $key.' = \''.$this->db->escape($value).'\''; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' WHERE ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $this->records = array(); + $num = $this->db->num_rows($resql); + if ($num > 0) { + while ($obj = $this->db->fetch_object($resql)) + { + $record = new self($this->db); + + $record->id = $obj->rowid; + $record->code = $obj->code; + $record->label = $obj->label; + $this->records[$record->id] = $record; + } + } + $this->db->free($resql); + + return $this->records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + + /** + * Update object into database + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update($user = null, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + // Clean parameters + if (isset($this->code)) $this->code = trim($this->code); + if (isset($this->label)) $this->label = trim($this->label); + if (isset($this->active)) $this->active = trim($this->active); + + // Check parameters + // Put here code to add control on parameters values + + // Update request + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET"; + $sql .= " code=".(isset($this->code) ? $this->db->escape($this->code) : "null").","; + $sql .= " label=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").","; + $sql .= " active=".(isset($this->active) ? $this->active : "null"); + $sql .= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { $error++; $this->errors[] = "Error ".$this->db->lasterror(); } + + // Commit or rollback + if ($error) + { + foreach ($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + + /** + * Delete object in database + * + * @param User $user User that delete + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::delete", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { $error++; $this->errors[] = "Error ".$this->db->lasterror(); } + + // Commit or rollback + if ($error) + { + foreach ($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + + /** + * Get unit from code + * @param string $code code of unit + * @param string $mode 0= id , short_label=Use short label as value, code=use code + * @return int <0 if KO, Id of code if OK + */ + public function getProductNatureFromCode($code, $mode = 'code') + { + + if ($mode == 'label'){ + return dol_getIdFromCode($this->db, $code, $this->table_element, 'label', 'rowid'); + } elseif ($mode == 'code'){ + return dol_getIdFromCode($this->db, $code, $this->table_element, 'code', 'rowid'); + } + + return $code; + } +} diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index a0fd2bdb10c..fa1b349ef5c 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -425,6 +425,59 @@ class FormProduct return $return; } + /** + * Return a combo box with list of units + * NAture of product labels are defined in llx_c_product_nature + * + * @param string $name Name of HTML field + * @param string $default Preselected value + * @param int $mode 1=Use label as value, 0=Use rowid + * @return string + */ + public function selectProductNature($name = 'finished', $default = '-1', $mode = 0) + { + global $langs, $db; + + $return = ''; + + // TODO Use a cache + require_once DOL_DOCUMENT_ROOT.'/core/class/cproductnature.class.php'; + $productNature = new CProductNature($db); + + $filter = array(); + $filter['t.active'] = 1; + + $result = $productNature->fetchAll( + '', + '', + 0, + 0, + $filter + ); + if ($result < 0) { + dol_print_error($db); + return -1; + } else { + $return .= ''; + } + + return $return; + } + /** * Return list of lot numbers (stock from product_batch) with stock location and stock qty * From 90df353f0c108e1745c404a95dbc1229630692de Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 14:30:07 +0200 Subject: [PATCH 238/317] fix number of lines --- htdocs/product/stats/bom.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/stats/bom.php b/htdocs/product/stats/bom.php index 7614d2dcc50..6f8ebf3ef58 100644 --- a/htdocs/product/stats/bom.php +++ b/htdocs/product/stats/bom.php @@ -234,7 +234,7 @@ if ($id > 0 || !empty($ref)) if (!empty($sortorder)) print ''; - print_barre_liste($langs->trans("BOMs"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1); + print_barre_liste($langs->trans("BOMs"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', count($bom_data_result), count($bom_data_result), '', 0, '', '', $limit, 0, 0, 1); if (!empty($page)) $option .= '&page='.urlencode($page); From 3cf2b6b5eb940c89bc309343d6b39a71a4b1fee2 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 15:01:50 +0200 Subject: [PATCH 239/317] Doc comment. --- htdocs/core/lib/functions.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 7b705b4bd87..8714b0aa765 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2048,7 +2048,7 @@ function dol_print_date($time, $format = '', $tzoutput = 'tzserver', $outputlang * PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows * WARNING: This function always use PHP server timezone to return locale informations !!! * Usage must be avoid. - * FIXME: Replace this with PHP date function and a parameter $gm + * FIXME: Replace content of this function with PHP date functions and a parameter $gm * * @param int $timestamp Timestamp * @param boolean $fast Fast mode From 940d478aec5768436aa2ccf5fd02fd0119c008d7 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 15:54:48 +0200 Subject: [PATCH 240/317] UI and db OK --- .../install/mysql/migration/12.0.0-13.0.0.sql | 7 +++- .../mysql/tables/llx_c_product_nature.sql | 2 +- .../install/mysql/tables/llx_product.key.sql | 1 + htdocs/install/mysql/tables/llx_product.sql | 2 +- htdocs/product/card.php | 27 +++++++++--- .../product/class/html.formproduct.class.php | 41 ++++++++++++------- htdocs/product/class/product.class.php | 19 +++++++-- 7 files changed, 71 insertions(+), 28 deletions(-) diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index bf9432a6e81..f370863004a 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -408,13 +408,16 @@ DELETE FROM llx_rights_def where module = 'holiday' and perms = 'lire_tous'; CREATE TABLE llx_c_product_nature ( rowid integer AUTO_INCREMENT PRIMARY KEY, - code integer NOT NULL, + code tinyint NOT NULL, label varchar(100), active tinyint DEFAULT 1 NOT NULL ) ENGINE=innodb; ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code); -INSERT INTO llx_c_product_nature (code, label, active) VALUES (-1, '', 1); INSERT INTO llx_c_product_nature (code, label, active) VALUES (0, 'RowMaterial', 1); INSERT INTO llx_c_product_nature (code, label, active) VALUES (1, 'Finished', 1); + +ALTER TABLE llx_product MODIFY COLUMN finished tinyint DEFAULT NULL; +ALTER TABLE llx_product ADD CONSTRAINT fk_product_finished FOREIGN KEY (finished) REFERENCES llx_c_product_nature (code); + diff --git a/htdocs/install/mysql/tables/llx_c_product_nature.sql b/htdocs/install/mysql/tables/llx_c_product_nature.sql index b2f9892aa1e..3c467ce7cf8 100644 --- a/htdocs/install/mysql/tables/llx_c_product_nature.sql +++ b/htdocs/install/mysql/tables/llx_c_product_nature.sql @@ -18,7 +18,7 @@ CREATE TABLE llx_c_product_nature ( rowid integer AUTO_INCREMENT PRIMARY KEY, - code varchar(3) NOT NULL, + code tinyint NOT NULL, label varchar(100), active tinyint DEFAULT 1 NOT NULL ) ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_product.key.sql b/htdocs/install/mysql/tables/llx_product.key.sql index c3dd33c88c5..c0526a8f2cc 100644 --- a/htdocs/install/mysql/tables/llx_product.key.sql +++ b/htdocs/install/mysql/tables/llx_product.key.sql @@ -33,6 +33,7 @@ ALTER TABLE llx_product ADD INDEX idx_product_fk_barcode_type (fk_barcode_type); ALTER TABLE llx_product ADD INDEX idx_product_fk_project (fk_project); ALTER TABLE llx_product ADD UNIQUE INDEX uk_product_barcode (barcode, fk_barcode_type, entity); ALTER TABLE llx_product ADD CONSTRAINT fk_product_fk_unit FOREIGN KEY (fk_unit) REFERENCES llx_c_units (rowid); +ALTER TABLE llx_product ADD CONSTRAINT fk_product_finished FOREIGN KEY (finished) REFERENCES llx_c_product_nature (code); ALTER TABLE llx_product ADD CONSTRAINT fk_product_fk_country FOREIGN KEY (fk_country) REFERENCES llx_c_country (rowid); ALTER TABLE llx_product ADD CONSTRAINT fk_product_barcode_type FOREIGN KEY (fk_barcode_type) REFERENCES llx_c_barcode_type (rowid); diff --git a/htdocs/install/mysql/tables/llx_product.sql b/htdocs/install/mysql/tables/llx_product.sql index bc583a76ce2..2431c884c62 100644 --- a/htdocs/install/mysql/tables/llx_product.sql +++ b/htdocs/install/mysql/tables/llx_product.sql @@ -92,7 +92,7 @@ create table llx_product lifo double(24,8), -- To store valuation of stock calculated using lifo method, for this product. TODO Not used, should be replaced by stock value stored into movement table. fk_default_warehouse integer DEFAULT NULL, canvas varchar(32) DEFAULT NULL, - finished tinyint DEFAULT NULL, -- 1=manufactured product, 0=matiere premiere + finished tinyint DEFAULT NULL, -- see dictionnary c_product_nature hidden tinyint DEFAULT 0, -- Not used. Deprecated. import_key varchar(14), -- Import key model_pdf varchar(255), -- model save dodument used diff --git a/htdocs/product/card.php b/htdocs/product/card.php index e3467e871c8..62813ee2a57 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -321,8 +321,19 @@ if (empty($reshook)) $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit $object->volume = GETPOST('volume'); $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit - $object->finished = GETPOST('finished', 'alpha'); - $object->fk_unit = GETPOST('units', 'alpha'); // This is the fk_unit of sale + $finished = GETPOST('finished', 'int'); + if ($finished > 0) { + $object->finished = $finished; + } else { + $object->finished = null; + } + + $units = GETPOST('units', 'int'); + if ($units > 0) { + $object->fk_unit = $units; + } else { + $object->fk_unit = null; + } $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha'); $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha'); @@ -435,10 +446,15 @@ if (empty($reshook)) $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit $object->volume = GETPOST('volume'); $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit - $object->finished = GETPOST('finished', 'alpha'); + + $finished = GETPOST('finished', 'int'); + if ($finished >= 0) { + $object->finished = $finished; + } else { + $object->finished = null; + } $units = GETPOST('units', 'int'); - if ($units > 0) { $object->fk_unit = $units; } else { @@ -1547,8 +1563,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) } else { // Nature print ''.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).''; - $statutarray = array('-1'=>' ', '1' => $langs->trans("Finished"), '0' => $langs->trans("RowMaterial")); - print $form->selectarray('finished', $statutarray, $object->finished); + print $formproduct->selectProductNature('finished', $object->finished); print ''; // Brut Weight diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index fa1b349ef5c..8241be3446e 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -430,14 +430,16 @@ class FormProduct * NAture of product labels are defined in llx_c_product_nature * * @param string $name Name of HTML field - * @param string $default Preselected value - * @param int $mode 1=Use label as value, 0=Use rowid + * @param string $selected Preselected value + * @param int $mode 1=Use label as value, 0=Use code * @return string */ - public function selectProductNature($name = 'finished', $default = '-1', $mode = 0) + public function selectProductNature($name = 'finished', $selected = '', $mode = 0) { global $langs, $db; + $langs->load('products'); + $return = ''; // TODO Use a cache @@ -459,18 +461,29 @@ class FormProduct return -1; } else { $return .= ''; } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 18565347072..edaa5e6857b 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -983,7 +983,7 @@ class Product extends CommonObject $sql .= ", tosell = ".(int) $this->status; $sql .= ", tobuy = ".(int) $this->status_buy; $sql .= ", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ? '0' : (int) $this->status_batch); - $sql .= ", finished = ".((!isset($this->finished) || $this->finished < 0) ? "null" : (int) $this->finished); + $sql .= ", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished == '') ? "null" : (int) $this->finished); $sql .= ", net_measure = ".($this->net_measure != '' ? "'".$this->db->escape($this->net_measure)."'" : 'null'); $sql .= ", net_measure_units = ".($this->net_measure_units != '' ? "'".$this->db->escape($this->net_measure_units)."'" : 'null'); $sql .= ", weight = ".($this->weight != '' ? "'".$this->db->escape($this->weight)."'" : 'null'); @@ -4562,10 +4562,21 @@ class Product extends CommonObject global $langs; $langs->load('products'); - if ($this->finished == '0') { return $langs->trans("RowMaterial"); - } - if ($this->finished == '1') { return $langs->trans("Finished"); + if (isset($this->finished) && $this->finished>=0) { + $sql = 'SELECT label, code FROM '.MAIN_DB_PREFIX.'c_product_nature where code='.$this->finished.' AND active=1'; + $resql = $this->db->query($sql); + if ($resql && $this->db->num_rows($resql) > 0) { + $res = $this->db->fetch_array($resql); + $label = $langs->trans($res['label']); + $this->db->free($resql); + return $label; + } else { + $this->error = $this->db->error().' sql='.$sql; + dol_syslog(get_class($this)."::".__METHOD__.' Error '.$this->error, LOG_ERR); + return -1; + } } + return ''; } From 7d09f22afaba8e7ae2662389db9ee305a0dce9dd Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 16:39:42 +0200 Subject: [PATCH 241/317] add correct import and dict edition --- htdocs/admin/dict.php | 19 +++++++++++++++++-- htdocs/core/class/cproductnature.class.php | 7 +++---- htdocs/core/modules/modProduct.class.php | 12 +++++++++--- htdocs/langs/en_US/admin.lang | 1 + htdocs/product/list.php | 9 ++++++++- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 8df2c1d36a4..03ae45ce1e2 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -91,7 +91,7 @@ $hookmanager->initHooks(array('admin')); // Put here declaration of dictionaries properties // Sort order to show dictionary (0 is space). All other dictionaries (added by modules) will be at end of this. -$taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 41, 0, 15, 30, 0, 37, 0, 25, 0); +$taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 41, 0, 15, 30, 0, 37, 42, 0, 25, 0); // Name of SQL tables of dictionaries $tabname = array(); @@ -136,6 +136,7 @@ $tabname[38] = MAIN_DB_PREFIX."c_socialnetworks"; $tabname[39] = MAIN_DB_PREFIX."c_prospectcontactlevel"; $tabname[40] = MAIN_DB_PREFIX."c_stcommcontact"; $tabname[41] = MAIN_DB_PREFIX."c_transport_mode"; +$tabname[42] = MAIN_DB_PREFIX."c_product_nature"; // Dictionary labels $tablib = array(); @@ -180,6 +181,7 @@ $tablib[38] = "DictionarySocialNetworks"; $tablib[39] = "DictionaryProspectContactLevel"; $tablib[40] = "DictionaryProspectContactStatus"; $tablib[41] = "DictionaryTransportMode"; +$tablib[42] = "DictionaryProductNature"; // Requests to extract data $tabsql = array(); @@ -224,6 +226,7 @@ $tabsql[38] = "SELECT rowid, entity, code, label, url, icon, active FROM ".MAIN_ $tabsql[39] = "SELECT code, label as libelle, sortorder, active FROM ".MAIN_DB_PREFIX."c_prospectcontactlevel"; $tabsql[40] = "SELECT id as rowid, code, libelle, picto, active FROM ".MAIN_DB_PREFIX."c_stcommcontact"; $tabsql[41] = "SELECT rowid as rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_transport_mode"; +$tabsql[42] = "SELECT rowid as rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_product_nature"; // Criteria to sort dictionaries $tabsqlsort = array(); @@ -268,6 +271,7 @@ $tabsqlsort[38] = "rowid, code ASC"; $tabsqlsort[39] = "sortorder ASC"; $tabsqlsort[40] = "code ASC"; $tabsqlsort[41] = "code ASC"; +$tabsqlsort[42] = "code ASC"; // Field names in select result for dictionary display $tabfield = array(); @@ -312,6 +316,7 @@ $tabfield[38] = "code,label,url,icon,entity"; $tabfield[39] = "code,libelle,sortorder"; $tabfield[40] = "code,libelle,picto"; $tabfield[41] = "code,label"; +$tabfield[42] = "code,label"; // Edit field names for editing a record $tabfieldvalue = array(); @@ -356,6 +361,7 @@ $tabfieldvalue[38] = "code,label,url,icon"; $tabfieldvalue[39] = "code,libelle,sortorder"; $tabfieldvalue[40] = "code,libelle,picto"; $tabfieldvalue[41] = "code,label"; +$tabfieldvalue[42] = "code,label"; // Field names in the table for inserting a record $tabfieldinsert = array(); @@ -401,6 +407,7 @@ $tabfieldinsert[38] = "code,label,url,icon,entity"; $tabfieldinsert[39] = "code,label,sortorder"; $tabfieldinsert[40] = "code,libelle,picto"; $tabfieldinsert[41] = "code,label"; +$tabfieldinsert[42] = "code,label"; // Rowid name of field depending if field is autoincrement on or off.. // Use "" if id field is "rowid" and has autoincrement on @@ -447,6 +454,7 @@ $tabrowid[38] = ""; $tabrowid[39] = "code"; $tabrowid[40] = "id"; $tabrowid[41] = ""; +$tabrowid[42] = "rowid"; // Condition to show dictionary in setup page $tabcond = array(); @@ -491,6 +499,7 @@ $tabcond[38] = !empty($conf->socialnetworks->enabled); $tabcond[39] = (!empty($conf->societe->enabled) && empty($conf->global->SOCIETE_DISABLE_PROSPECTS) && !empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES)); $tabcond[40] = (!empty($conf->societe->enabled) && !empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES)); $tabcond[41] = !empty($conf->intracommreport->enabled); +$tabcond[42] = !empty($conf->product->enabled); // List of help for fields $tabhelp = array(); @@ -535,6 +544,7 @@ $tabhelp[38] = array('code'=>$langs->trans("EnterAnyCode"), 'url' => $langs->tra $tabhelp[39] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[40] = array('code'=>$langs->trans("EnterAnyCode"), 'picto'=>$langs->trans("PictoHelp")); $tabhelp[41] = array('code'=>$langs->trans("EnterAnyCode")); +$tabhelp[42] = array('code'=>$langs->trans("EnterAnyCode")); // List of check for fields (NOT USED YET) $tabfieldcheck = array(); @@ -579,6 +589,7 @@ $tabfieldcheck[38] = array(); $tabfieldcheck[39] = array(); $tabfieldcheck[40] = array(); $tabfieldcheck[41] = array(); +$tabfieldcheck[42] = array(); // Complete all arrays with entries found into modules complete_dictionary_with_modules($taborder, $tabname, $tablib, $tabsql, $tabsqlsort, $tabfield, $tabfieldvalue, $tabfieldinsert, $tabrowid, $tabcond, $tabhelp, $tabfieldcheck); @@ -1614,6 +1625,9 @@ if ($id) $valuetoshow = ($obj->label && $key != strtoupper($obj->label) ? $key : $obj->{$fieldlist[$field]}); } elseif ($fieldlist[$field] == 'code' && $id == 3) { $valuetoshow = $obj->state_code; + } elseif ($fieldlist[$field] == 'label' && $tabname[$_GET["id"]] == MAIN_DB_PREFIX.'c_product_nature') { + $langs->load("products"); + $valuetoshow = $langs->trans($obj->{$fieldlist[$field]}); } $class .= ($class ? ' ' : '').'tddict'; if ($fieldlist[$field] == 'note' && $id == 10) $class .= ' tdoverflowmax200'; @@ -1631,7 +1645,7 @@ if ($id) $iserasable = 1; $canbedisabled = 1; $canbemodified = 1; - if (isset($obj->code) && $id != 10) + if (isset($obj->code) && $id != 10 && $id != 42) { if (($obj->code == '0' || $obj->code == '' || preg_match('/unknown/i', $obj->code))) { $iserasable = 0; $canbedisabled = 0; } elseif ($obj->code == 'RECEP') { $iserasable = 0; $canbedisabled = 0; } elseif ($obj->code == 'EF0') { $iserasable = 0; $canbedisabled = 0; } } @@ -1643,6 +1657,7 @@ if ($id) if (isset($obj->type) && in_array($obj->type, array('system', 'systemauto'))) { $iserasable = 0; } if (in_array($obj->code, array('AC_OTH', 'AC_OTH_AUTO')) || in_array($obj->type, array('systemauto'))) { $canbedisabled = 0; $canbedisabled = 0; } $canbemodified = $iserasable; + if ($obj->code == 'RECEP') $canbemodified = 1; if ($tabname[$id] == MAIN_DB_PREFIX."c_actioncomm") $canbemodified = 1; diff --git a/htdocs/core/class/cproductnature.class.php b/htdocs/core/class/cproductnature.class.php index cda719b87cd..e34749695e8 100644 --- a/htdocs/core/class/cproductnature.class.php +++ b/htdocs/core/class/cproductnature.class.php @@ -351,11 +351,10 @@ class CProductNature // extends CommonObject */ public function getProductNatureFromCode($code, $mode = 'code') { - - if ($mode == 'label'){ - return dol_getIdFromCode($this->db, $code, $this->table_element, 'label', 'rowid'); + if ($mode == 'label') { + return dol_getIdFromCode($this->db, $code, $this->table_element, 'label', 'code'); } elseif ($mode == 'code'){ - return dol_getIdFromCode($this->db, $code, $this->table_element, 'code', 'rowid'); + return dol_getIdFromCode($this->db, $code, $this->table_element, 'code', 'code'); } return $code; diff --git a/htdocs/core/modules/modProduct.class.php b/htdocs/core/modules/modProduct.class.php index 7eef5043c81..3ed99741715 100644 --- a/htdocs/core/modules/modProduct.class.php +++ b/htdocs/core/modules/modProduct.class.php @@ -477,7 +477,14 @@ class modProduct extends DolibarrModules 'class' => 'Ccountry', 'method' => 'fetch', 'dict' => 'DictionaryCountry' - ) + ), + 'p.finished'=> array( + 'rule' => 'fetchidfromcodeorlabel', + 'classfile' => '/core/class/cproductnature.class.php', + 'class' => 'CProductNature', + 'method' => 'fetch', + 'dict' => 'DictionaryProductNature' + ), ); $this->import_regex_array[$r] = array( @@ -488,7 +495,6 @@ class modProduct extends DolibarrModules 'p.fk_product_type' => '^[0|1]$', 'p.datec' => '^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$', 'p.recuperableonly' => '^[0|1]$', - 'p.finished' => '^[0|1]$' ); if (!empty($conf->stock->enabled)) {//if Stock module enabled @@ -578,7 +584,7 @@ class modProduct extends DolibarrModules 'p.surface_units' => 'm2', // Use a unit of measure from the dictionary. m2/cm2/mm2 etc....matches field "Short label" for unit type "surface" in table "' . MAIN_DB_PREFIX . 'c_units', 'p.volume' => "", 'p.volume_units' => 'm3', //Use a unit of measure from the dictionary. m3/cm3/mm3 etc....matches field "Short label" for unit type "volume" in table "' . MAIN_DB_PREFIX . 'c_units', - 'p.finished' => '0 (raw material) / 1 (finished goods)' + 'p.finished' => '0 (raw material) / 1 (finished goods), matches field "code" in dictionary table "'.MAIN_DB_PREFIX.'c_product_nature"' ); //clauses copied from import_fields_array if (!empty($conf->stock->enabled)) $import_sample = array_merge($import_sample, array( diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 3091efcf7fd..a2f38d2fdbb 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2064,3 +2064,4 @@ TemplateUpdated=Template updated TemplateDeleted=Template deleted MailToSendEventPush=Template for event reminder emails SwitchThisForABetterSecurity=Switching this value to %s is recommended for more security +DictionaryProductNature= Nature of product diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 4abf8fd4a8b..db77e7714f1 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -40,6 +40,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; if (!empty($conf->categorie->enabled)) require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; @@ -75,6 +76,7 @@ $search_accountancy_code_sell_export = GETPOST("search_accountancy_code_sell_exp $search_accountancy_code_buy = GETPOST("search_accountancy_code_buy", 'alpha'); $search_accountancy_code_buy_intra = GETPOST("search_accountancy_code_buy_intra", 'alpha'); $search_accountancy_code_buy_export = GETPOST("search_accountancy_code_buy_export", 'alpha'); +$search_finished = GETPOST("search_finished", 'int'); $optioncss = GETPOST('optioncss', 'alpha'); $type = GETPOST("type", "int"); @@ -109,6 +111,7 @@ $hookmanager->initHooks(array('productservicelist')); $extrafields = new ExtraFields($db); $form = new Form($db); $formcompany = new FormCompany($db); +$formproduct = new FormProduct($db); // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); @@ -212,7 +215,7 @@ $arrayfields = array( 'p.tobatch'=>array('label'=>$langs->trans("ManageLotSerial"), 'checked'=>0, 'enabled'=>(!empty($conf->productbatch->enabled)), 'position'=>60), 'p.fk_country'=>array('label'=>$langs->trans("Country"), 'checked'=>0, 'position'=>100), 'p.fk_state'=>array('label'=>$langs->trans("State"), 'checked'=>0, 'position'=>101), - 'p.accountancy_code_sell'=>array('label'=>$langs->trans("ProductAccountancySellCode"), 'checked'=>0, 'position'=>400), + 'p.accountancy_code_sell'=>array('label'=>$langs->trans("ProductAccountancySellCode"), 'checked'=>0, 'position'=>400), 'p.accountancy_code_sell_intra'=>array('label'=>$langs->trans("ProductAccountancySellIntraCode"), 'checked'=>0, 'enabled'=>$isInEEC, 'position'=>401), 'p.accountancy_code_sell_export'=>array('label'=>$langs->trans("ProductAccountancySellExportCode"), 'checked'=>0, 'position'=>402), 'p.accountancy_code_buy'=>array('label'=>$langs->trans("ProductAccountancyBuyCode"), 'checked'=>0, 'position'=>403), @@ -285,6 +288,7 @@ if (empty($reshook)) $search_state = ""; $search_vatrate = ""; $search_tobatch = ''; + $search_finished = ''; //$search_type=''; // There is 2 types of list: a list of product and a list of services. No list with both. So when we clear search criteria, we must keep the filter on type. $show_childproducts = ''; @@ -409,6 +413,7 @@ if ($fourn_id > 0) $sql .= " AND pfp.fk_soc = ".$fourn_id; if ($search_tobatch != '' && $search_tobatch >= 0) $sql .= " AND p.tobatch = ".$db->escape($search_tobatch); if ($search_country) $sql .= " AND p.fk_country = ".$search_country; if ($search_state) $sql .= " AND p.fk_state = ".$search_state; +if ($search_finished>=0 && $search_finished!=='') $sql .= " AND p.finished = ".$search_finished; if ($search_accountancy_code_sell) $sql .= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell); if ($search_accountancy_code_sell_intra) $sql .= natural_search('p.accountancy_code_sell_intra', $search_accountancy_code_sell_intra); if ($search_accountancy_code_sell_export) $sql .= natural_search('p.accountancy_code_sell_export', $search_accountancy_code_sell_export); @@ -522,6 +527,7 @@ if ($resql) if ($search_accountancy_code_buy) $param = "&search_accountancy_code_buy=".urlencode($search_accountancy_code_buy); if ($search_accountancy_code_buy_intra) $param = "&search_accountancy_code_buy_intra=".urlencode($search_accountancy_code_buy_intra); if ($search_accountancy_code_buy_export) $param = "&search_accountancy_code_buy_export=".urlencode($search_accountancy_code_buy_export); + if ($search_finished) $param = "&search_finished=".urlencode($search_finished); // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; @@ -677,6 +683,7 @@ if ($resql) if (!empty($arrayfields['p.finished']['checked'])) { print ''; + print $formproduct->selectProductNature('search_finished', $search_finished); print ''; } // Weight From 98eb11be62ea838cc7cf42895eab97ce5f7a2c1e Mon Sep 17 00:00:00 2001 From: ATM-Nicolas Date: Wed, 14 Oct 2020 16:59:05 +0200 Subject: [PATCH 242/317] NEW : Fill ECM src object fields in dol_add_file_process --- htdocs/core/actions_linkedfiles.inc.php | 4 ++-- htdocs/core/lib/files.lib.php | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/htdocs/core/actions_linkedfiles.inc.php b/htdocs/core/actions_linkedfiles.inc.php index 3caeeed6678..75633c75585 100644 --- a/htdocs/core/actions_linkedfiles.inc.php +++ b/htdocs/core/actions_linkedfiles.inc.php @@ -56,10 +56,10 @@ if (GETPOST('sendit', 'alpha') && !empty($conf->global->MAIN_UPLOAD_DOC)) if (!empty($upload_dirold) && !empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) { - $result = dol_add_file_process($upload_dirold, $allowoverwrite, 1, 'userfile', GETPOST('savingdocmask', 'alpha'), null, '', $generatethumbs); + $result = dol_add_file_process($upload_dirold, $allowoverwrite, 1, 'userfile', GETPOST('savingdocmask', 'alpha'), null, '', $generatethumbs, $object); } elseif (!empty($upload_dir)) { - $result = dol_add_file_process($upload_dir, $allowoverwrite, 1, 'userfile', GETPOST('savingdocmask', 'alpha'), null, '', $generatethumbs); + $result = dol_add_file_process($upload_dir, $allowoverwrite, 1, 'userfile', GETPOST('savingdocmask', 'alpha'), null, '', $generatethumbs, $object); } } } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 63047ed0e7b..ec26783c775 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1506,9 +1506,10 @@ function dol_init_file_process($pathtoscan = '', $trackid = '') * @param string $link Link to add (to add a link instead of a file) * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @param int $generatethumbs 1=Generate also thumbs for uploaded image files + * @param Object $object Object used to set 'src_object_*' fields * @return int <=0 if KO, >0 if OK */ -function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1) +function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1, $object = null) { global $db, $user, $conf, $langs; @@ -1602,7 +1603,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesess // Update index table of files (llx_ecm_files) if ($donotupdatesession == 1) { - $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', 0); + $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', 0, $object); if ($result < 0) { if ($allowoverwrite) { @@ -1718,9 +1719,10 @@ function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletef * @param string $fullpathorig Full path of origin for file (can be '') * @param string $mode How file was created ('uploaded', 'generated', ...) * @param int $setsharekey Set also the share key + * @param Object $object Object used to set 'src_object_*' fields * @return int <0 if KO, 0 if nothing done, >0 if OK */ -function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0) +function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0, $object = null) { global $db, $user; @@ -1743,6 +1745,12 @@ function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uplo $ecmfile->gen_or_uploaded = $mode; $ecmfile->description = ''; // indexed content $ecmfile->keyword = ''; // keyword content + + if(! is_null($object) && ! empty($object->id)) { + $ecmfile->src_object_id = $object->id; + $ecmfile->src_object_type = $object->element; + } + if ($setsharekey) { require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; From e8ea7125e5a89f5c8fd7f4e0471f8774ab58d50e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 17:11:22 +0200 Subject: [PATCH 243/317] Removed the FIXME. The dol_getdate can now use a timezone. --- htdocs/core/lib/functions.lib.php | 59 ++++++++++++++------------ test/phpunit/FunctionsLibTest.php | 70 +++++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 8714b0aa765..31d6de721b2 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2045,13 +2045,12 @@ function dol_print_date($time, $format = '', $tzoutput = 'tzserver', $outputlang /** * Return an array with locale date info. - * PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows - * WARNING: This function always use PHP server timezone to return locale informations !!! - * Usage must be avoid. - * FIXME: Replace content of this function with PHP date functions and a parameter $gm + * WARNING: This function use PHP server timezone by default to return locale informations. + * Be aware to add the third parameter to "UTC" if you need to work on UTC. * * @param int $timestamp Timestamp - * @param boolean $fast Fast mode + * @param boolean $fast Fast mode. deprecated. + * @param string $forcetimezone '' to use the PHP server timezone. Or use a form like 'Europe/Paris' or '+0200' to force timezone. * @return array Array of informations * If no fast mode: * 'seconds' => $secs, @@ -2061,34 +2060,40 @@ function dol_print_date($time, $format = '', $tzoutput = 'tzserver', $outputlang * 'wday' => $dow, 0=sunday, 6=saturday * 'mon' => $month, * 'year' => $year, - * 'yday' => floor($secsInYear/$_day_power), - * 'weekday' => gmdate('l',$_day_power*(3+$dow)), - * 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), - * If fast mode: - * 'seconds' => $secs, - * 'minutes' => $min, - * 'hours' => $hour, - * 'mday' => $day, - * 'mon' => $month, - * 'year' => $year, - * 'yday' => floor($secsInYear/$_day_power), - * 'leap' => $leaf, - * 'ndays' => $ndays + * 'yday' => floor($secsInYear/$_day_power) * @see dol_print_date(), dol_stringtotime(), dol_mktime() */ -function dol_getdate($timestamp, $fast = false) +function dol_getdate($timestamp, $fast = false, $forcetimezone = '') { global $conf; - $usealternatemethod = false; - if ($timestamp <= 0) $usealternatemethod = true; // <= 1970 - if ($timestamp >= 2145913200) $usealternatemethod = true; // >= 2038 - - if ($usealternatemethod) - { - $arrayinfo = adodb_getdate($timestamp, $fast); + if (empty($conf->global->MAIN_USE_OLD_FUNCTIONS_FOR_GETDATE)) { + //$datetimeobj = new DateTime('@'.$timestamp); + $datetimeobj = new DateTime(); + $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone + if ($forcetimezone) $datetimeobj->setTimezone(new DateTimeZone($forcetimezone)); // (add timezone relative to the date entered) + $arrayinfo = array( + 'year'=>((int) date_format($datetimeobj, 'Y')), + 'mon'=>((int) date_format($datetimeobj, 'm')), + 'mday'=>((int) date_format($datetimeobj, 'd')), + 'wday'=>((int) date_format($datetimeobj, 'w')), + 'yday'=>((int) date_format($datetimeobj, 'z')), + 'hours'=>((int) date_format($datetimeobj, 'H')), + 'minutes'=>((int) date_format($datetimeobj, 'i')), + 'seconds'=>((int) date_format($datetimeobj, 's')) + ); } else { - $arrayinfo = getdate($timestamp); + // PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows + $usealternatemethod = false; + if ($timestamp <= 0) $usealternatemethod = true; // <= 1970 + if ($timestamp >= 2145913200) $usealternatemethod = true; // >= 2038 + + if ($usealternatemethod) + { + $arrayinfo = adodb_getdate($timestamp, $fast); + } else { + $arrayinfo = getdate($timestamp); + } } return $arrayinfo; diff --git a/test/phpunit/FunctionsLibTest.php b/test/phpunit/FunctionsLibTest.php index d113cde8035..2cb4d98610c 100644 --- a/test/phpunit/FunctionsLibTest.php +++ b/test/phpunit/FunctionsLibTest.php @@ -1257,9 +1257,6 @@ class FunctionsLibTest extends PHPUnit\Framework\TestCase $conf->global->MAIN_START_WEEK = 0; - $tmp=dol_getdate(1); // 1/1/1970 and 1 second = thirday - $this->assertEquals(4, $tmp['wday']); - $tmp=dol_getdate(24*60*60+1); // 2/1/1970 and 1 second = friday $this->assertEquals(5, $tmp['wday']); @@ -1271,12 +1268,77 @@ class FunctionsLibTest extends PHPUnit\Framework\TestCase $tmp=dol_getdate(24*60*60+1); // 2/1/1970 and 1 second = friday $this->assertEquals(5, $tmp['wday']); + $tmp=dol_getdate(1, false, "Europe/Paris"); // 1/1/1970 and 1 second = thirday + $this->assertEquals(1970, $tmp['year']); + $this->assertEquals(1, $tmp['mon']); + $this->assertEquals(1, $tmp['mday']); + $this->assertEquals(4, $tmp['wday']); + $this->assertEquals(0, $tmp['yday']); + $this->assertEquals(1, $tmp['hours']); // We are winter, so we are GMT+1 even during summer + $this->assertEquals(0, $tmp['minutes']); + $this->assertEquals(1, $tmp['seconds']); + + $tmp=dol_getdate(15638401, false, "Europe/Paris"); // 1/7/1970 and 1 second = wednesday + $this->assertEquals(1970, $tmp['year']); + $this->assertEquals(7, $tmp['mon']); + $this->assertEquals(1, $tmp['mday']); + $this->assertEquals(3, $tmp['wday']); + $this->assertEquals(181, $tmp['yday']); + $this->assertEquals(1, $tmp['hours']); // There is no daylight in 1970, so we are GMT+1 even during summer + $this->assertEquals(0, $tmp['minutes']); + $this->assertEquals(1, $tmp['seconds']); + + $tmp=dol_getdate(1593561601, false, "Europe/Paris"); // 1/7/2020 and 1 second = wednesday + $this->assertEquals(2020, $tmp['year']); + $this->assertEquals(7, $tmp['mon']); + $this->assertEquals(1, $tmp['mday']); + $this->assertEquals(3, $tmp['wday']); + $this->assertEquals(182, $tmp['yday']); // 182 and not 181, due to the 29th february + $this->assertEquals(2, $tmp['hours']); // There is a daylight, so we are GMT+2 + $this->assertEquals(0, $tmp['minutes']); + $this->assertEquals(1, $tmp['seconds']); + + $conf->global->MAIN_USE_OLD_FUNCTIONS_FOR_GETDATE = 1; + + $tmp=dol_getdate(1); // 1/1/1970 and 1 second = thirday + $this->assertEquals(1970, $tmp['year']); + $this->assertEquals(1, $tmp['mon']); + $this->assertEquals(1, $tmp['mday']); + $this->assertEquals(4, $tmp['wday']); + $this->assertEquals(0, $tmp['yday']); + // We must disable this because on CI, timezone is may be UTC or something else + //$this->assertEquals(1, $tmp['hours']); // We are winter, so we are GMT+1 even during summer + $this->assertEquals(0, $tmp['minutes']); + $this->assertEquals(1, $tmp['seconds']); + + $tmp=dol_getdate(15638401); // 1/7/1970 and 1 second = wednesday + $this->assertEquals(1970, $tmp['year']); + $this->assertEquals(7, $tmp['mon']); + $this->assertEquals(1, $tmp['mday']); + $this->assertEquals(3, $tmp['wday']); + $this->assertEquals(181, $tmp['yday']); + // We must disable this because on CI, timezone is may be UTC or something else + //$this->assertEquals(1, $tmp['hours']); // There is no daylight in 1970, so we are GMT+1 even during summer + $this->assertEquals(0, $tmp['minutes']); + $this->assertEquals(1, $tmp['seconds']); + + $tmp=dol_getdate(1593561601); // 1/7/2020 and 1 second = wednesday + $this->assertEquals(2020, $tmp['year']); + $this->assertEquals(7, $tmp['mon']); + $this->assertEquals(1, $tmp['mday']); + $this->assertEquals(3, $tmp['wday']); + $this->assertEquals(182, $tmp['yday']); // 182 and not 181, due to the 29th february + // We must disable this because on CI, timezone is may be UTC or something else + //$this->assertEquals(2, $tmp['hours']); // There is a daylight, so we are GMT+2 + $this->assertEquals(0, $tmp['minutes']); + $this->assertEquals(1, $tmp['seconds']); + return true; } /** - * testDolGetDate + * testMakeSubstitutions * * @return boolean */ From ee19f3fc946428a62abe4c222878046a24c71f6d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 17:16:35 +0200 Subject: [PATCH 244/317] Update actions_addupdatedelete.inc.php --- htdocs/core/actions_addupdatedelete.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/actions_addupdatedelete.inc.php b/htdocs/core/actions_addupdatedelete.inc.php index ad82d15c5a9..219d35e46fb 100644 --- a/htdocs/core/actions_addupdatedelete.inc.php +++ b/htdocs/core/actions_addupdatedelete.inc.php @@ -74,7 +74,7 @@ if ($action == 'add' && !empty($permissiontoadd)) } elseif (preg_match('/^(integer|price|real|double)/', $object->fields[$key]['type'])) { $value = price2num(GETPOST($key, 'alphanohtml')); // To fix decimal separator according to lang setup } elseif ($object->fields[$key]['type'] == 'boolean') { - $value = (GETPOST($key) == '1' ? 1 : 0); + $value = ((GETPOST($key) == '1' || GETPOST($key) == 'on') ? 1 : 0); } else { $value = GETPOST($key, 'alphanohtml'); } From ba001803ed2042ea6a7f9cf8cb8af58fcbd05588 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 17:35:14 +0200 Subject: [PATCH 245/317] Update files.lib.php --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index ec26783c775..55a2fc58d6b 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1746,7 +1746,7 @@ function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uplo $ecmfile->description = ''; // indexed content $ecmfile->keyword = ''; // keyword content - if(! is_null($object) && ! empty($object->id)) { + if (is_object($object) && $object->id > 0) { $ecmfile->src_object_id = $object->id; $ecmfile->src_object_type = $object->element; } From bb367a448953471cd019192478e70c91d8f06fe9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 17:40:27 +0200 Subject: [PATCH 246/317] Update dict.php --- htdocs/admin/dict.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 03ae45ce1e2..803ba1823f1 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -1625,7 +1625,7 @@ if ($id) $valuetoshow = ($obj->label && $key != strtoupper($obj->label) ? $key : $obj->{$fieldlist[$field]}); } elseif ($fieldlist[$field] == 'code' && $id == 3) { $valuetoshow = $obj->state_code; - } elseif ($fieldlist[$field] == 'label' && $tabname[$_GET["id"]] == MAIN_DB_PREFIX.'c_product_nature') { + } elseif ($fieldlist[$field] == 'label' && $tabname[$id] == MAIN_DB_PREFIX.'c_product_nature') { $langs->load("products"); $valuetoshow = $langs->trans($obj->{$fieldlist[$field]}); } From fc69b8892340c782753c737818078712d7163a19 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 18:03:02 +0200 Subject: [PATCH 247/317] Update doc --- test/acceptance/README.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/test/acceptance/README.md b/test/acceptance/README.md index b3d550392c4..cf97408be7f 100644 --- a/test/acceptance/README.md +++ b/test/acceptance/README.md @@ -24,7 +24,7 @@ We can run selenium by two ways: ###Run the acceptance tests - * In `nightwatch.conf.js` file inside the root directory of the project and inside the configuration file following environment variable has been specified. We can change the default values according to our local configuration. +* In `nightwatch.conf.js` file inside the root directory of the project and inside the configuration file following environment variable has been specified. We can change the default values according to our local configuration. ``` const admin_username = process.env.ADMIN_USERNAME || 'dolibarr'; @@ -33,24 +33,23 @@ We can run selenium by two ways: const launch_url = process.env.LAUNCH_URL || 'http://localhost/dolibarr/htdocs/'; ``` - * You can run test using following commands + +* You can run test using following commands `yarn run test:e2e test/acceptance/features/` - For example: `yarn run test:e2e test/acceptance/features/addUsers.feature` + For example: `yarn run test:e2e test/acceptance/features/addUsers.feature` - OR - - `LAUNCH_URL='' ADMIN_USERNAME='' ADMIN_PASSWORD='' yarn run test:e2e test/acceptance/features/` + Or: `LAUNCH_URL=''; ADMIN_USERNAME=''; ADMIN_PASSWORD=''; yarn run test:e2e test/acceptance/features/` - The full script to run the acceptance tests is specified in `scripts` object of `package.json` file inside the project's root directory as : + The full script to run the acceptance tests is specified in `scripts` object of `package.json` file inside the project's root directory as : - `"test:e2e": "node_modules/cucumber/bin/cucumber-js --require test/acceptance/index.js --require test/acceptance/stepDefinitions -f node_modules/cucumber-pretty"` + `"test:e2e": "node_modules/cucumber/bin/cucumber-js --require test/acceptance/index.js --require test/acceptance/stepDefinitions -f node_modules/cucumber-pretty"` - After you run the above command you can see the test running. For that : + After you run the above command you can see the test running. For that : - * open `Remmina` (Remmina is a Remote Desktop Client and comes installed with Ubuntu) +* open `Remmina` (Remmina is a Remote Desktop Client and comes installed with Ubuntu) - * choose `VNC` and enter `localhost` on the address bar +* choose `VNC` and enter `localhost` on the address bar - * enter `secret` as the password +* enter `secret` as the password From 1af3881796a39bfef255a1e9e680078b9a6ddf15 Mon Sep 17 00:00:00 2001 From: BENKE Charlene <1179011+defrance@users.noreply.github.com> Date: Wed, 14 Oct 2020 18:08:31 +0200 Subject: [PATCH 248/317] If specific help present we change color of icon --- htdocs/main.inc.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 9ecd00ca36f..217807ad044 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -12,6 +12,7 @@ * Copyright (C) 2014-2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2020 Demarest Maxime + * Copyright (C) 2020 Charlene Benke * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1655,8 +1656,11 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead $helpbaseurl = ''; $helppage = ''; $mode = ''; + $helpresent = ''; if (empty($helppagename)) $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios'; + else + $helpresent = 'style="color:yellow !important"'; // Get helpbaseurl, helppage and mode from helppagename and langs $arrayres = getHelpParamFor($helppagename, $langs); @@ -1674,7 +1678,7 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead if ($mode == 'wiki') $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage))); else $text .= sprintf($helpbaseurl, $helppage); $text .= '">'; - $text .= ''; + $text .= ''; $text .= ''; $toprightmenu .= @Form::textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2); } From 50a9bd368c44281ca207820e72d7f64497eaf1f7 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 18:15:48 +0200 Subject: [PATCH 249/317] review --- htdocs/install/mysql/data/llx_c_product_nature.sql | 1 - htdocs/product/class/product.class.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/install/mysql/data/llx_c_product_nature.sql b/htdocs/install/mysql/data/llx_c_product_nature.sql index 7594e8e3f69..8351ff2ab79 100644 --- a/htdocs/install/mysql/data/llx_c_product_nature.sql +++ b/htdocs/install/mysql/data/llx_c_product_nature.sql @@ -23,7 +23,6 @@ -- de l'install et tous les sigles '--' sont supprimés. -- -INSERT INTO llx_c_product_nature (code, label, active) VALUES (-1, '', 1); INSERT INTO llx_c_product_nature (code, label, active) VALUES (0, 'RowMaterial', 1); INSERT INTO llx_c_product_nature (code, label, active) VALUES (1, 'Finished', 1); diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index edaa5e6857b..1b567d31edb 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -4563,7 +4563,7 @@ class Product extends CommonObject $langs->load('products'); if (isset($this->finished) && $this->finished>=0) { - $sql = 'SELECT label, code FROM '.MAIN_DB_PREFIX.'c_product_nature where code='.$this->finished.' AND active=1'; + $sql = 'SELECT label, code FROM '.MAIN_DB_PREFIX.'c_product_nature where code='.((int) $this->finished).' AND active=1'; $resql = $this->db->query($sql); if ($resql && $this->db->num_rows($resql) > 0) { $res = $this->db->fetch_array($resql); From 9c3988da5c2903481fd637372d9845a6e7395fe1 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 14 Oct 2020 18:19:41 +0200 Subject: [PATCH 250/317] add show empty --- htdocs/product/class/html.formproduct.class.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index 8241be3446e..eed6b9608be 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -432,9 +432,10 @@ class FormProduct * @param string $name Name of HTML field * @param string $selected Preselected value * @param int $mode 1=Use label as value, 0=Use code + * @param int $showempty 1=show empty value, 0= no * @return string */ - public function selectProductNature($name = 'finished', $selected = '', $mode = 0) + public function selectProductNature($name = 'finished', $selected = '', $mode = 0, $showempty=1) { global $langs, $db; @@ -461,11 +462,13 @@ class FormProduct return -1; } else { $return .= ' '.$langs->trans("ClosePaidContributionsAutomatically"); print '
    '; print '     '; diff --git a/htdocs/compta/payment_sc/card.php b/htdocs/compta/payment_sc/card.php index 0e71c83f6cb..adab68a157f 100644 --- a/htdocs/compta/payment_sc/card.php +++ b/htdocs/compta/payment_sc/card.php @@ -184,7 +184,7 @@ print ''.$langs->trans('Mode').''.$langs->trans("Pa // Numero print ''.$langs->trans('Numero').''.$object->num_payment.''; -// Montant +// Amount print ''.$langs->trans('Amount').''.price($object->amount, 0, $outputlangs, 1, -1, -1, $conf->currency).''; // Note @@ -288,7 +288,7 @@ if ($resql) /* - * Boutons Actions + * Actions Buttons */ print '
    '; From f4ef8a3285398ec58c8eadb380ce8d67520cec04 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 18:52:41 +0200 Subject: [PATCH 255/317] Use class instead of hard coded style --- htdocs/main.inc.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 217807ad044..9d2fdc5fe1f 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1658,9 +1658,11 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead $mode = ''; $helpresent = ''; - if (empty($helppagename)) $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios'; - else - $helpresent = 'style="color:yellow !important"'; + if (empty($helppagename)) { + $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios'; + } else { + $helpresent = 'helppresent'; + } // Get helpbaseurl, helppage and mode from helppagename and langs $arrayres = getHelpParamFor($helppagename, $langs); @@ -1678,7 +1680,7 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead if ($mode == 'wiki') $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage))); else $text .= sprintf($helpbaseurl, $helppage); $text .= '">'; - $text .= ''; + $text .= ''; $text .= ''; $toprightmenu .= @Form::textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2); } From a8eeb7099a47124bb09d5c012b8dd0887a450b88 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 19:01:37 +0200 Subject: [PATCH 256/317] Fix style of online help when page available. --- htdocs/main.inc.php | 6 +++--- htdocs/theme/eldy/global.inc.php | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 9d2fdc5fe1f..689a3a0a4fc 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1656,12 +1656,12 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead $helpbaseurl = ''; $helppage = ''; $mode = ''; - $helpresent = ''; + $helppresent = ''; if (empty($helppagename)) { $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios'; } else { - $helpresent = 'helppresent'; + $helppresent = 'helppresent'; } // Get helpbaseurl, helppage and mode from helppagename and langs @@ -1680,7 +1680,7 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead if ($mode == 'wiki') $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage))); else $text .= sprintf($helpbaseurl, $helppage); $text .= '">'; - $text .= ''; + $text .= ''; $text .= ''; $toprightmenu .= @Form::textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2); } diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 5c493cd505e..1ffcce59297 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -2581,6 +2581,7 @@ font.vsmenudisabledmargin { margin: 1px 1px 1px 6px; } li a.vsmenudisabled, li.vsmenudisabled { color: #aaa !important; } a.help:link, a.help:visited, a.help:hover, a.help:active, span.help { text-align: ; color: #aaa; text-decoration: none; } +.helppresent, .helppresent:hover { color: #f3e4ac !important; } .vmenu div.blockvmenufirst, .vmenu div.blockvmenulogo, .vmenu div.blockvmenusearchphone, .vmenu div.blockvmenubookmarks { From bc1ad96ad1c9af26833ef60d204c0fd391a9c00e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 19:28:59 +0200 Subject: [PATCH 257/317] FIX #14993 --- htdocs/comm/propal/class/propalestats.class.php | 6 +++--- htdocs/comm/propal/stats/index.php | 2 +- htdocs/commande/class/commandestats.class.php | 6 +++--- htdocs/commande/stats/index.php | 2 +- htdocs/fichinter/class/fichinterstats.class.php | 3 ++- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/htdocs/comm/propal/class/propalestats.class.php b/htdocs/comm/propal/class/propalestats.class.php index 747bb75433c..8f71447ab0b 100644 --- a/htdocs/comm/propal/class/propalestats.class.php +++ b/htdocs/comm/propal/class/propalestats.class.php @@ -79,7 +79,7 @@ class PropaleStats extends Stats $this->field = 'total_ht'; $this->field_line = 'total_ht'; - $this->where .= " p.fk_statut > 0"; + //$this->where .= " p.fk_statut > 0"; } if ($mode == 'supplier') { @@ -91,10 +91,10 @@ class PropaleStats extends Stats $this->field = 'total_ht'; $this->field_line = 'total_ht'; - $this->where .= " p.fk_statut > 0"; // Validated, accepted, refused and closed + //$this->where .= " p.fk_statut > 0"; // Validated, accepted, refused and closed } //$this->where.= " AND p.fk_soc = s.rowid AND p.entity = ".$conf->entity; - $this->where .= " AND p.entity IN (".getEntity('propal').")"; + $this->where .= ($this->where ? ' AND ' : '')."p.entity IN (".getEntity('propal').")"; if (!$user->rights->societe->client->voir && !$this->socid) $this->where .= " AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id; if ($this->socid) { diff --git a/htdocs/comm/propal/stats/index.php b/htdocs/comm/propal/stats/index.php index 49e1141fec1..a59896c8ab6 100644 --- a/htdocs/comm/propal/stats/index.php +++ b/htdocs/comm/propal/stats/index.php @@ -86,7 +86,7 @@ if ($mode == 'customer') if ($mode == 'supplier') { $picto = 'supplier_proposal'; - $title = $langs->trans("ProposalsStatisticsSuppliers").' ('.$langs->trans("SentToSuppliers").")"; + $title = $langs->trans("ProposalsStatisticsSuppliers"); $dir = $conf->supplier_proposal->dir_temp; $cat_type = Categorie::TYPE_SUPPLIER; $cat_label = $langs->trans("Category").' '.lcfirst($langs->trans("Supplier")); diff --git a/htdocs/commande/class/commandestats.class.php b/htdocs/commande/class/commandestats.class.php index 5af5fb23060..c9dc5eaffa8 100644 --- a/htdocs/commande/class/commandestats.class.php +++ b/htdocs/commande/class/commandestats.class.php @@ -77,7 +77,7 @@ class CommandeStats extends Stats $this->from_line = MAIN_DB_PREFIX.$object->table_element_line." as tl"; $this->field = 'total_ht'; $this->field_line = 'total_ht'; - $this->where .= " c.fk_statut > 0"; // Not draft and not cancelled + //$this->where .= " c.fk_statut > 0"; // Not draft and not cancelled } elseif ($mode == 'supplier') { $object = new CommandeFournisseur($this->db); @@ -85,10 +85,10 @@ class CommandeStats extends Stats $this->from_line = MAIN_DB_PREFIX.$object->table_element_line." as tl"; $this->field = 'total_ht'; $this->field_line = 'total_ht'; - $this->where .= " c.fk_statut > 2"; // Only approved & ordered + //$this->where .= " c.fk_statut > 2"; // Only approved & ordered } //$this->where.= " AND c.fk_soc = s.rowid AND c.entity = ".$conf->entity; - $this->where .= ' AND c.entity IN ('.getEntity('commande').')'; + $this->where .= ($this->where ? ' AND ' : ''). 'c.entity IN ('.getEntity('commande').')'; if (!$user->rights->societe->client->voir && !$this->socid) $this->where .= " AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id; if ($this->socid) diff --git a/htdocs/commande/stats/index.php b/htdocs/commande/stats/index.php index 346b5549bfd..2b2402fd9de 100644 --- a/htdocs/commande/stats/index.php +++ b/htdocs/commande/stats/index.php @@ -81,7 +81,7 @@ $dir = $conf->commande->dir_temp; if ($mode == 'supplier') { $picto = 'supplier_order'; - $title = $langs->trans("OrdersStatisticsSuppliers").' ('.$langs->trans("SentToSuppliers").")"; + $title = $langs->trans("OrdersStatisticsSuppliers"); $dir = $conf->fournisseur->commande->dir_temp; } diff --git a/htdocs/fichinter/class/fichinterstats.class.php b/htdocs/fichinter/class/fichinterstats.class.php index 1355c7a97cf..608b7d75f25 100644 --- a/htdocs/fichinter/class/fichinterstats.class.php +++ b/htdocs/fichinter/class/fichinterstats.class.php @@ -64,7 +64,6 @@ class FichinterStats extends Stats $this->userid = $userid; $this->cachefilesuffix = $mode; - $this->where .= " c.entity = ".$conf->entity; if ($mode == 'customer') { $object = new Fichinter($this->db); @@ -75,6 +74,8 @@ class FichinterStats extends Stats //$this->where.= " AND c.fk_statut > 0"; // Not draft and not cancelled } if (!$user->rights->societe->client->voir && !$this->socid) $this->where .= " AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id; + $this->where .= ($this->where ? ' AND ' : '')."c.entity IN (".getEntity('fichinter').')'; + if ($this->socid) { $this->where .= " AND c.fk_soc = ".$this->socid; From 20d5098ce218c3ea5f9672d0bae8440b35bd0bda Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 19:42:17 +0200 Subject: [PATCH 258/317] Fix regression in dol_getdate() --- htdocs/core/lib/functions.lib.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 31d6de721b2..c875ad32803 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2052,7 +2052,6 @@ function dol_print_date($time, $format = '', $tzoutput = 'tzserver', $outputlang * @param boolean $fast Fast mode. deprecated. * @param string $forcetimezone '' to use the PHP server timezone. Or use a form like 'Europe/Paris' or '+0200' to force timezone. * @return array Array of informations - * If no fast mode: * 'seconds' => $secs, * 'minutes' => $min, * 'hours' => $hour, @@ -2061,6 +2060,7 @@ function dol_print_date($time, $format = '', $tzoutput = 'tzserver', $outputlang * 'mon' => $month, * 'year' => $year, * 'yday' => floor($secsInYear/$_day_power) + * '0' => original timestamp * @see dol_print_date(), dol_stringtotime(), dol_mktime() */ function dol_getdate($timestamp, $fast = false, $forcetimezone = '') @@ -2080,7 +2080,8 @@ function dol_getdate($timestamp, $fast = false, $forcetimezone = '') 'yday'=>((int) date_format($datetimeobj, 'z')), 'hours'=>((int) date_format($datetimeobj, 'H')), 'minutes'=>((int) date_format($datetimeobj, 'i')), - 'seconds'=>((int) date_format($datetimeobj, 's')) + 'seconds'=>((int) date_format($datetimeobj, 's')), + '0'=>$timestamp ); } else { // PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows From 1691fcedfb7ebff32867a52fb55ce6b1002f9fc8 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 20:13:30 +0200 Subject: [PATCH 259/317] Fix phpcs --- htdocs/compta/stats/cabyprodserv.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/htdocs/compta/stats/cabyprodserv.php b/htdocs/compta/stats/cabyprodserv.php index a4ae7c8005a..bb4ddc7c5d0 100644 --- a/htdocs/compta/stats/cabyprodserv.php +++ b/htdocs/compta/stats/cabyprodserv.php @@ -255,9 +255,7 @@ if ($modecompta == 'CREANCES-DETTES') $sql.=" AND cp.fk_product is null"; } elseif ($selected_cat) { // Into a specific category - - if ($subcat) - { + if ($subcat) { $TListOfCats = $categorie->get_full_arbo('product', $selected_cat, 1); $listofcatsql = ""; From 0908ac58678a75d72a2ccefc52e09ff785306554 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 20:18:07 +0200 Subject: [PATCH 260/317] Fix phpcs --- .../commande/doc/pdf_einstein.modules.php | 14 ++++++------ .../commande/doc/pdf_eratosthene.modules.php | 22 +++++++++---------- .../facture/doc/pdf_sponge.modules.php | 6 ++--- .../modules/propale/doc/pdf_cyan.modules.php | 14 ++++++------ 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php index 324f7c83fd0..5bc041fd7b5 100644 --- a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php +++ b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php @@ -230,7 +230,7 @@ class pdf_einstein extends ModelePDFCommandes $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "orders", "deliveries")); } - + $nblines = count($object->lines); if ($conf->commande->multidir_output[$conf->entity]) @@ -794,7 +794,7 @@ class pdf_einstein extends ModelePDFCommandes if (!empty($conf->global->FACTURE_CHQ_NUMBER)) { $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE); - + if ($conf->global->FACTURE_CHQ_NUMBER > 0) { $account = new Account($this->db); @@ -879,7 +879,7 @@ class pdf_einstein extends ModelePDFCommandes $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); $default_font_size--; } - + $tab2_top = $posy; $tab2_hl = 4; $pdf->SetFont('', '', $default_font_size - 1); @@ -1031,7 +1031,7 @@ class pdf_einstein extends ModelePDFCommandes } $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : ''); $totalvat .= ' '; - + $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); @@ -1065,7 +1065,7 @@ class pdf_einstein extends ModelePDFCommandes } $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : ''); $totalvat .= ' '; - + $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); @@ -1161,7 +1161,7 @@ class pdf_einstein extends ModelePDFCommandes if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency)); } - + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4); $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); @@ -1271,7 +1271,7 @@ class pdf_einstein extends ModelePDFCommandes $pdf->SetFont('', 'B', $default_font_size + 3); $w = 100; - + $posy = $this->marge_haute; $posx = $this->page_largeur - $this->marge_droite - $w; diff --git a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php index bfbc798d4bb..01ee9b0ec98 100644 --- a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php +++ b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php @@ -124,8 +124,8 @@ class pdf_eratosthene extends ModelePDFCommandes * @var array of document table collumns */ public $cols; - - + + /** * Constructor * @@ -176,7 +176,7 @@ class pdf_eratosthene extends ModelePDFCommandes $this->tabTitleHeight = 5; // default height // Use new system for position of columns, view $this->defineColumnField() - + $this->tva = array(); $this->localtax1 = array(); $this->localtax2 = array(); @@ -364,7 +364,7 @@ class pdf_eratosthene extends ModelePDFCommandes $this->atleastonediscount++; } } - + // New page $pdf->AddPage(); @@ -425,7 +425,7 @@ class pdf_eratosthene extends ModelePDFCommandes if ($notetoshow) { $tab_top -= 2; - + $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; $pageposbeforenote = $pagenb; @@ -709,7 +709,7 @@ class pdf_eratosthene extends ModelePDFCommandes $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax); $nexY = max($pdf->GetY(), $nexY); } - + // Extrafields if (!empty($object->lines[$i]->array_options)) { foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { @@ -1011,7 +1011,7 @@ class pdf_eratosthene extends ModelePDFCommandes if (!empty($conf->global->FACTURE_CHQ_NUMBER)) { $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE); - + if ($conf->global->FACTURE_CHQ_NUMBER > 0) { $account = new Account($this->db); @@ -1094,7 +1094,7 @@ class pdf_eratosthene extends ModelePDFCommandes $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); $default_font_size--; } - + $tab2_top = $posy; $tab2_hl = 4; $pdf->SetFont('', '', $default_font_size - 1); @@ -1374,7 +1374,7 @@ class pdf_eratosthene extends ModelePDFCommandes if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency)); } - + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4); $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); @@ -1433,7 +1433,7 @@ class pdf_eratosthene extends ModelePDFCommandes $pdf->SetFont('', 'B', $default_font_size + 3); $w = 100; - + $posy = $this->marge_haute; $posx = $this->page_largeur - $this->marge_droite - $w; @@ -1844,7 +1844,7 @@ class pdf_eratosthene extends ModelePDFCommandes ), 'border-left' => true, // add left line separator ); - + // Add extrafields cols if (!empty($object->lines)) { $line = reset($object->lines); diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index bd7b055c28e..7e730fabbc5 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -394,7 +394,7 @@ class pdf_sponge extends ModelePDFFactures $this->atleastonediscount++; } } - + // Situation invoice handling if ($object->situation_cycle_ref) @@ -750,7 +750,7 @@ class pdf_sponge extends ModelePDFFactures $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax); $nexY = max($pdf->GetY(), $nexY); } - + // Extrafields if (!empty($object->lines[$i]->array_options)) { foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { @@ -2349,7 +2349,7 @@ class pdf_sponge extends ModelePDFFactures ), 'border-left' => true, // add left line separator ); - + // Add extrafields cols if (!empty($object->lines)) { $line = reset($object->lines); diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php index 6696364b9dd..324f52c1ca0 100644 --- a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php @@ -123,8 +123,8 @@ class pdf_cyan extends ModelePDFPropales * @var array of document table collumns */ public $cols; - - + + /** * Constructor * @@ -170,12 +170,12 @@ class pdf_cyan extends ModelePDFPropales // Define position of columns $this->posxdesc = $this->marge_gauche + 1; // used for notes ans other stuff - + $this->tabTitleHeight = 5; // default height // Use new system for position of columns, view $this->defineColumnField() - + $this->tva = array(); $this->localtax1 = array(); $this->localtax2 = array(); @@ -359,7 +359,7 @@ class pdf_cyan extends ModelePDFPropales $this->atleastonediscount++; } } - + // New page $pdf->AddPage(); @@ -1178,7 +1178,7 @@ class pdf_cyan extends ModelePDFPropales $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); $default_font_size--; } - + $tab2_top = $posy; $tab2_hl = 4; $pdf->SetFont('', '', $default_font_size - 1); @@ -1534,7 +1534,7 @@ class pdf_cyan extends ModelePDFPropales $pdf->SetFont('', 'B', $default_font_size + 3); $w = 100; - + $posy = $this->marge_haute; $posx = $this->page_largeur - $this->marge_droite - $w; From 9cc8e6ac99a6137dee4a01aa44c73085e0245854 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 14 Oct 2020 20:25:02 +0200 Subject: [PATCH 261/317] Fix intracommreport --- htdocs/fourn/facture/card.php | 42 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 2de5e76f369..56f2bef6c6a 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -2652,25 +2652,29 @@ if ($action == 'create') print ''; } - // Intracomm report - $langs->loadLangs(array("intracommreport")); - print ''; - print ''; - if ($action != 'editmode' && $user->rights->fournisseur->facture->creer) { - print ''; - } - print '
    '; - print $langs->trans('IntracommReportTransportMode'); - print 'id.'">'.img_edit($langs->trans('SetMode'), 1).'
    '; - print ''; - if ($action == 'editmode') - { - $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'transport_mode_id', 1, 1); - } - else { - $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'none'); - } - print ''; + // Intracomm report + if (!empty($conf->intracommreport->enabled)) { + $langs->loadLangs(array("intracommreport")); + print ''; + print ''; + if ($action != 'editmode' && $user->rights->fournisseur->facture->creer) { + print ''; + } + print '
    '; + print $langs->trans('IntracommReportTransportMode'); + print 'id.'">'.img_edit($langs->trans('SetMode'), 1).'
    '; + print ''; + + print ''; + if ($action == 'editmode') + { + $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'transport_mode_id', 1, 1); + } + else { + $form->formSelectTransportMode($_SERVER['PHP_SELF'].'?id='.$object->id, $object->transport_mode_id, 'none'); + } + print ''; + } // Other attributes $cols = 2; From 4a3ffbb6d4ab4d3456d486435bc83280a46ca228 Mon Sep 17 00:00:00 2001 From: Alfredo Altamirano Date: Wed, 14 Oct 2020 21:57:17 -0500 Subject: [PATCH 262/317] FIX #14927 Change ContratLigne property type to product_type This bug is produced because the ContratLigne class gives a property type instead of a product_type --- htdocs/contrat/class/contrat.class.php | 4 +++- htdocs/core/boxes/box_services_contracts.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index e81febde6df..77272c39c62 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -753,6 +753,7 @@ class Contrat extends CommonObject $sql.= " d.total_localtax1,"; $sql.= " d.total_localtax2,"; $sql.= " d.total_ttc,"; + $sql .= " d.product_type,"; $sql.= " d.info_bits, d.fk_product,"; $sql.= " d.date_ouverture_prevue, d.date_ouverture,"; $sql.= " d.date_fin_validite, d.date_cloture,"; @@ -799,6 +800,7 @@ class Contrat extends CommonObject $line->total_ttc = $objp->total_ttc; $line->fk_product = (($objp->fk_product > 0)?$objp->fk_product:0); $line->info_bits = $objp->info_bits; + $line->product_type = $objp->product_type; $line->fk_fournprice = $objp->fk_fournprice; $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht); @@ -2563,7 +2565,7 @@ class ContratLigne extends CommonObjectLine public $fk_product; public $statut; // 0 inactive, 4 active, 5 closed - public $type; // 0 for product, 1 for service + public $product_type; // 0 for product, 1 for service /** * @var string diff --git a/htdocs/core/boxes/box_services_contracts.php b/htdocs/core/boxes/box_services_contracts.php index b1330192a11..2b3d3f89727 100644 --- a/htdocs/core/boxes/box_services_contracts.php +++ b/htdocs/core/boxes/box_services_contracts.php @@ -120,7 +120,7 @@ class box_services_contracts extends ModeleBoxes $contratlignestatic->fk_contrat=$objp->rowid; $contratlignestatic->label=$objp->label; $contratlignestatic->description=$objp->description; - $contratlignestatic->type=$objp->type; + $contratlignestatic->product_type = $objp->type; $contratlignestatic->product_id=$objp->product_id; $contratlignestatic->product_ref=$objp->product_ref; From baddd7741e5bab7053f689a8e51c400dd3dd8141 Mon Sep 17 00:00:00 2001 From: amunaadh Date: Thu, 15 Oct 2020 10:18:47 +0545 Subject: [PATCH 263/317] ReadMe file edited Co-authored-by: Swikriti Tripathi --- test/acceptance/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/acceptance/README.md b/test/acceptance/README.md index cf97408be7f..5a5ace76d93 100644 --- a/test/acceptance/README.md +++ b/test/acceptance/README.md @@ -4,9 +4,19 @@ Selenium has been used for automating the browser. -We can run selenium by two ways: +[Download](https://www.selenium.dev/downloads/) the `latest stable version` of the `Selenium standalone server JAR file`. -* Usually, for running tests using selenium we download `selenium standalone server JAR file` and `chrome driver` and start selenium server with a command which usually looks like: +Also [download](https://chromedriver.chromium.org/downloads) the `latest stable version` of `Chrome Driver`. + +Once you have downloaded Chrome Driver, you need to unzip it by running the following command: + + `unzip chromedriver_linux64.zip` + +Once you have unzipped it, you need to move the chromedriver(shared library) and place it inside the same folder where you have placed the Selenium standalone server file. + +Now we can run selenium by two ways: + +* Start selenium server with a command which usually looks like: `java -jar selenium-server-standalone-.jar -port ` From 0597768ea8e690a0c0424711b2c0d9d31859df66 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Thu, 15 Oct 2020 08:28:38 +0200 Subject: [PATCH 264/317] fix review --- htdocs/install/mysql/migration/12.0.0-13.0.0.sql | 2 +- htdocs/install/mysql/tables/llx_c_product_nature.key.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index f370863004a..df5f6eb46ed 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -413,7 +413,7 @@ CREATE TABLE llx_c_product_nature ( active tinyint DEFAULT 1 NOT NULL ) ENGINE=innodb; -ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code); +ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code, active); INSERT INTO llx_c_product_nature (code, label, active) VALUES (0, 'RowMaterial', 1); INSERT INTO llx_c_product_nature (code, label, active) VALUES (1, 'Finished', 1); diff --git a/htdocs/install/mysql/tables/llx_c_product_nature.key.sql b/htdocs/install/mysql/tables/llx_c_product_nature.key.sql index 17459032ecd..b6a3d2130bf 100644 --- a/htdocs/install/mysql/tables/llx_c_product_nature.key.sql +++ b/htdocs/install/mysql/tables/llx_c_product_nature.key.sql @@ -1 +1 @@ -ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code); +ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code, active); From 6a4e01de1d20573cb5dde67c7235266ff5414431 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Thu, 15 Oct 2020 08:36:04 +0200 Subject: [PATCH 265/317] fix review --- htdocs/product/class/product.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index c0984442fe6..2aa9b3330e3 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -4695,7 +4695,7 @@ class Product extends CommonObject return $label; } else { $this->error = $this->db->error().' sql='.$sql; - dol_syslog(get_class($this)."::".__METHOD__.' Error '.$this->error, LOG_ERR); + dol_syslog(__METHOD__.' Error '.$this->error, LOG_ERR); return -1; } } From b9cbd84d4ebd380fb6e9850c4b08dbba70dfb195 Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 15 Oct 2020 09:30:48 +0200 Subject: [PATCH 266/317] Fix page break --- .../doc/pdf_standard.modules.php | 32 ++++++------------- .../tecnickcom/tcpdf/include/tcpdf_fonts.php | 3 +- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/htdocs/core/modules/expensereport/doc/pdf_standard.modules.php b/htdocs/core/modules/expensereport/doc/pdf_standard.modules.php index 8aec0cc4105..cdc5f1e1bad 100644 --- a/htdocs/core/modules/expensereport/doc/pdf_standard.modules.php +++ b/htdocs/core/modules/expensereport/doc/pdf_standard.modules.php @@ -361,32 +361,18 @@ class pdf_standard extends ModeleExpenseReport $curY = $nexY; $pdf->startTransaction(); $this->printLine($pdf, $object, $i, $curY, $default_font_size, $outputlangs, $hidedetails); - $pageposafter=$pdf->getPage(); + $pageposafter=$pdf->getPage(); if ($pageposafter > $pageposbefore) { // There is a pagebreak $pdf->rollbackTransaction(true); - $pageposafter = $pageposbefore; - //print $pageposafter.'-'.$pageposbefore;exit; + + $pdf->AddPage('', '', true); + $pdf->setPage($pageposbefore+1); $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. - $this->printLine($pdf, $object, $i, $curY, $default_font_size, $outputlangs, $hidedetails); - $pageposafter = $pdf->getPage(); - $posyafter = $pdf->GetY(); - //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; - if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))) { - // There is no space left for total+free text - if ($i == ($nblignes-1)) { - // No more lines, and no space left to show total, so we create a new page - $pdf->AddPage('', '', true); - if (! empty($tplidx)) $pdf->useTemplate($tplidx); - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); - $pdf->setPage($pageposafter+1); - } - } - else - { - // We found a page break - $showpricebeforepagebreak=0; - } + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + + $this->printLine($pdf, $object, $i, $tab_top_newpage, $default_font_size, $outputlangs, $hidedetails); } else // No pagebreak { @@ -554,7 +540,7 @@ class pdf_standard extends ModeleExpenseReport { global $conf; $pdf->SetFont('', '', $default_font_size - 1); - + $pdf->SetTextColor(0, 0, 0); // Accountancy piece $pdf->SetXY($this->posxpiece, $curY); $pdf->writeHTMLCell($this->posxcomment-$this->posxpiece-0.8, 4, $this->posxpiece-1, $curY, $linenumber + 1, 0, 1); diff --git a/htdocs/includes/tecnickcom/tcpdf/include/tcpdf_fonts.php b/htdocs/includes/tecnickcom/tcpdf/include/tcpdf_fonts.php index 9242ca4bfdb..8681dfbdbfa 100644 --- a/htdocs/includes/tecnickcom/tcpdf/include/tcpdf_fonts.php +++ b/htdocs/includes/tecnickcom/tcpdf/include/tcpdf_fonts.php @@ -1149,7 +1149,7 @@ class TCPDF_FONTS { $subsetglyphs[$g] = true; } } - } + } break; } case 6: { // Format 6: Trimmed table mapping @@ -1664,6 +1664,7 @@ class TCPDF_FONTS { * @public static */ public static function unichr($c, $unicode=true) { + $c = intval($c); if (!$unicode) { return chr($c); } elseif ($c <= 0x7F) { From 32d823c7390fdb9fb39edd6fad0203f6f064ae08 Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Thu, 15 Oct 2020 09:40:50 +0200 Subject: [PATCH 267/317] FIX: Unable to edit extrafields in expense report --- htdocs/expensereport/class/expensereport.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index bb543642733..171e82db7bb 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -4,7 +4,7 @@ * Copyright (C) 2015 Alexandre Spangaro * Copyright (C) 2018 Nicolas ZABOURI * Copyright (c) 2018 Frédéric France - * Copyright (C) 2016-2018 Ferran Marcet + * Copyright (C) 2016-2020 Ferran Marcet * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -538,6 +538,8 @@ class ExpenseReport extends CommonObject $this->code_statut = $obj->code_statut; $this->code_paiement = $obj->code_paiement; + $this->fetch_optionals(); + $this->lines = array(); $result=$this->fetch_lines(); From 520645a02c19904dd2d2ab25141cb27b443214e0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 10:15:37 +0200 Subject: [PATCH 268/317] Renamed all methods valide() into validate() --- ChangeLog | 2 + htdocs/cashdesk/tpl/facturation1.tpl.php | 2 +- htdocs/cashdesk/tpl/validation1.tpl.php | 2 +- htdocs/cashdesk/validation_verif.php | 6 +- htdocs/compta/paiement/card.php | 6 +- htdocs/compta/paiement/cheque/card.php | 4 +- .../compta/paiement/class/paiement.class.php | 16 +++- htdocs/compta/payment_sc/card.php | 53 ------------- .../class/rejetprelevement.class.php | 2 +- .../class/DataCollector/DolibarrCollector.php | 15 +++- htdocs/don/class/don.class.php | 16 ++-- htdocs/don/payment/card.php | 51 ------------- htdocs/expensereport/payment/card.php | 45 ----------- htdocs/fourn/paiement/card.php | 10 +-- htdocs/loan/card.php | 8 +- htdocs/loan/class/paymentloan.class.php | 24 ++++++ htdocs/loan/payment/card.php | 75 +++---------------- htdocs/loan/payment/payment.php | 24 +++--- htdocs/main.inc.php | 2 +- 19 files changed, 102 insertions(+), 261 deletions(-) diff --git a/ChangeLog b/ChangeLog index 60aa376f96d..27d9129c762 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,8 @@ Following changes may create regressions for some external modules, but were nec * If you have links in your code with '&action=delete' as a parameter, you must also add '&token='.newToken() as another parameter to avoid CSRF protection errors. * The API addPayment for api_invoice has evolved to accept amount into a foreign currency. You must provide array(amount=>X,mutlicurrency_ammount=>Y) instead of amount. * The method select_thirdparty(), deprecated since 3.8, into html.form.class.php has been removed. +* Depreciate all methods with name valide(). Use instead methods validate(). + ***** ChangeLog for 12.0.3 compared to 12.0.2 ***** FIX: 10.0 - when the mime file name is different from the filesystem name, the attachment name should be the mime filename diff --git a/htdocs/cashdesk/tpl/facturation1.tpl.php b/htdocs/cashdesk/tpl/facturation1.tpl.php index e1dc53ed6e8..d9d12c5d84e 100644 --- a/htdocs/cashdesk/tpl/facturation1.tpl.php +++ b/htdocs/cashdesk/tpl/facturation1.tpl.php @@ -141,7 +141,7 @@ for ($i = 0; $i < $nbtoshow; $i++) -
    +
    trans("Amount"); ?> diff --git a/htdocs/cashdesk/tpl/validation1.tpl.php b/htdocs/cashdesk/tpl/validation1.tpl.php index 0434473d359..cc558cca058 100644 --- a/htdocs/cashdesk/tpl/validation1.tpl.php +++ b/htdocs/cashdesk/tpl/validation1.tpl.php @@ -97,7 +97,7 @@ if ($obj_facturation->amountReturned()) { - +

    rights->facture-> } } -if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->facture->paiement) +if ($action == 'confirm_validate' && $confirm == 'yes' && $user->rights->facture->paiement) { $db->begin(); $object->fetch($id); - if ($object->valide($user) > 0) + if ($object->validate($user) > 0) { $db->commit(); @@ -189,7 +189,7 @@ if ($action == 'delete') if ($action == 'valide') { $facid = $_GET['facid']; - print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id.'&facid='.$facid, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_valide', '', 0, 2); + print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id.'&facid='.$facid, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_validate', '', 0, 2); } $linkback = ''.$langs->trans("BackToList").''; diff --git a/htdocs/compta/paiement/cheque/card.php b/htdocs/compta/paiement/cheque/card.php index 71cd900f915..7e4e582b3d5 100644 --- a/htdocs/compta/paiement/cheque/card.php +++ b/htdocs/compta/paiement/cheque/card.php @@ -178,7 +178,7 @@ if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->banque->c } } -if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->banque->cheque) +if ($action == 'confirm_validate' && $confirm == 'yes' && $user->rights->banque->cheque) { $result = $object->fetch($id); $result = $object->validate($user); @@ -324,7 +324,7 @@ if ($action == 'new') */ if ($action == 'valide') { - print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("ValidateCheckReceipt"), $langs->trans("ConfirmValidateCheckReceipt"), 'confirm_valide', '', '', 1); + print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("ValidateCheckReceipt"), $langs->trans("ConfirmValidateCheckReceipt"), 'confirm_validate', '', '', 1); } /* diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index 5cb16bdcbe3..dbef7158782 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -858,13 +858,25 @@ class Paiement extends CommonObject return -1; //no num given or already validated } - /** + /** + * Validate payment + * + * @param User $user User making validation + * @return int <0 if KO, >0 if OK + * @deprecated + */ + public function valide(User $user = null) + { + return $this->validate($user); + } + + /** * Validate payment * * @param User $user User making validation * @return int <0 if KO, >0 if OK */ - public function valide(User $user = null) + public function validate(User $user = null) { $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET statut = 1 WHERE rowid = '.$this->id; diff --git a/htdocs/compta/payment_sc/card.php b/htdocs/compta/payment_sc/card.php index 0e71c83f6cb..8e00c25eac4 100644 --- a/htdocs/compta/payment_sc/card.php +++ b/htdocs/compta/payment_sc/card.php @@ -72,46 +72,6 @@ if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->tax->char } } -// Validate social contribution -/* -if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->tax->charges->creer) -{ - $db->begin(); - - $result=$object->valide(); - - if ($result > 0) - { - $db->commit(); - - $factures=array(); // TODO Get all id of invoices linked to this payment - foreach($factures as $id) - { - $fac = new Facture($db); - $fac->fetch($id); - - $outputlangs = $langs; - if (! empty($_REQUEST['lang_id'])) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($_REQUEST['lang_id']); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { - $fac->generateDocument($fac->modelpdf, $outputlangs); - } - } - - header('Location: card.php?id='.$object->id); - exit; - } - else - { - setEventMessages($object->error, $object->errors, 'errors'); - $db->rollback(); - } -} -*/ - /* * View @@ -146,19 +106,6 @@ if ($action == 'delete') print $form->formconfirm('card.php?id='.$object->id, $langs->trans("DeletePayment"), $langs->trans("ConfirmDeletePayment"), 'confirm_delete', '', 0, 2); } -/* - * Validation confirmation of payment - */ -/* -if ($action == 'valide') -{ - $facid = $_GET['facid']; - print $form->formconfirm('card.php?id='.$object->id.'&facid='.$facid, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_valide','',0,2); - -} -*/ - - $linkback = ''.$langs->trans("BackToList").''; dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'id', ''); diff --git a/htdocs/compta/prelevement/class/rejetprelevement.class.php b/htdocs/compta/prelevement/class/rejetprelevement.class.php index 20d600bf9b4..d4f76548363 100644 --- a/htdocs/compta/prelevement/class/rejetprelevement.class.php +++ b/htdocs/compta/prelevement/class/rejetprelevement.class.php @@ -168,7 +168,7 @@ class RejetPrelevement } // Payment validation - if ($pai->valide() < 0) + if ($pai->validate($user) < 0) { $error++; dol_syslog("RejetPrelevement::Create Error payment validation"); diff --git a/htdocs/debugbar/class/DataCollector/DolibarrCollector.php b/htdocs/debugbar/class/DataCollector/DolibarrCollector.php index a03575f88e8..b1b31bc9154 100644 --- a/htdocs/debugbar/class/DataCollector/DolibarrCollector.php +++ b/htdocs/debugbar/class/DataCollector/DolibarrCollector.php @@ -59,14 +59,19 @@ class DolibarrCollector extends DataCollector implements Renderable, AssetProvid protected function getDolibarrInfo() { global $conf, $langs; + global $dolibarr_main_prod, $dolibarr_nocsrfcheck; $info = $langs->trans('Version').': '.DOL_VERSION.'
    '; $info .= $langs->trans('Theme').': '.$conf->theme.'
    '; $info .= $langs->trans('Locale').': '.$conf->global->MAIN_LANG_DEFAULT.'
    '; $info .= $langs->trans('Currency').': '.$conf->currency.'
    '; - $info .= $langs->trans('DolEntity').': '.$conf->entity.'
    '; - $info .= $langs->trans('ListLimit').': '.($conf->liste_limit ?: $conf->global->MAIN_SIZE_LISTE_LIMIT).'
    '; - $info .= $langs->trans('MaxSizeForUploadedFiles').': '.$conf->global->MAIN_UPLOAD_DOC.''; + $info .= $langs->trans('Entity').': '.$conf->entity.'
    '; + $info .= $langs->trans('MaxSizeList').': '.($conf->liste_limit ?: $conf->global->MAIN_SIZE_LISTE_LIMIT).'
    '; + $info .= $langs->trans('MaxSizeForUploadedFiles').': '.$conf->global->MAIN_UPLOAD_DOC.'
    '; + $info .= '$dolibarr_main_prod = '.$dolibarr_main_prod.'
    '; + $info .= '$dolibarr_nocsrfcheck = '.$dolibarr_nocsrfcheck.'
    '; + $info .= 'MAIN_SECURITY_CSRF_WITH_TOKEN = '.$conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN.'
    '; + $info .= 'MAIN_FEATURES_LEVEL = '.$conf->global->MAIN_FEATURES_LEVEL.'
    '; return $info; } @@ -79,6 +84,7 @@ class DolibarrCollector extends DataCollector implements Renderable, AssetProvid protected function getMailInfo() { global $conf, $langs; + global $dolibarr_mailing_limit_sendbyweb; $info = $langs->trans('Method').': '.$conf->global->MAIN_MAIL_SENDMODE.'
    '; $info .= $langs->trans('Server').': '.$conf->global->MAIN_MAIL_SMTP_SERVER.'
    '; @@ -86,7 +92,8 @@ class DolibarrCollector extends DataCollector implements Renderable, AssetProvid $info .= $langs->trans('ID').': '.$conf->global->MAIN_MAIL_SMTPS_ID.'
    '; $info .= $langs->trans('Pwd').': '.preg_replace('/./', '*', $conf->global->MAIN_MAIL_SMTPS_PW).'
    '; $info .= $langs->trans('TLS/STARTTLS').': '.$conf->global->MAIN_MAIL_EMAIL_TLS.' / '.$conf->global->MAIN_MAIL_EMAIL_STARTTLS.'
    '; - $info .= $langs->trans('MAIN_DISABLE_ALL_MAILS').': '.($conf->global->MAIN_DISABLE_ALL_MAILS ? $langs->trans('Yes') : $langs->trans('No')).''; + $info .= $langs->trans('MAIN_DISABLE_ALL_MAILS').': '.($conf->global->MAIN_DISABLE_ALL_MAILS ? $langs->trans('Yes') : $langs->trans('No')).'
    '; + $info .= 'dolibarr_mailing_limit_sendbyweb = '.$dolibarr_mailing_limit_sendbyweb.'
    '; return $info; } diff --git a/htdocs/don/class/don.class.php b/htdocs/don/class/don.class.php index 3ccaa573e8c..b9ec7ebcaa7 100644 --- a/htdocs/don/class/don.class.php +++ b/htdocs/don/class/don.class.php @@ -167,14 +167,14 @@ class Don extends CommonObject { global $langs; $langs->load("donations"); - $this->labelStatus[-1] = $langs->trans("Canceled"); - $this->labelStatus[0] = $langs->trans("DonationStatusPromiseNotValidated"); - $this->labelStatus[1] = $langs->trans("DonationStatusPromiseValidated"); - $this->labelStatus[2] = $langs->trans("DonationStatusPaid"); - $this->labelStatusShort[-1] = $langs->trans("Canceled"); - $this->labelStatusShort[0] = $langs->trans("DonationStatusPromiseNotValidatedShort"); - $this->labelStatusShort[1] = $langs->trans("DonationStatusPromiseValidatedShort"); - $this->labelStatusShort[2] = $langs->trans("DonationStatusPaidShort"); + $this->labelStatus[-1] = $langs->transnoentitiesnoconv("Canceled"); + $this->labelStatus[0] = $langs->transnoentitiesnoconv("DonationStatusPromiseNotValidated"); + $this->labelStatus[1] = $langs->transnoentitiesnoconv("DonationStatusPromiseValidated"); + $this->labelStatus[2] = $langs->transnoentitiesnoconv("DonationStatusPaid"); + $this->labelStatusShort[-1] = $langs->transnoentitiesnoconv("Canceled"); + $this->labelStatusShort[0] = $langs->transnoentitiesnoconv("DonationStatusPromiseNotValidatedShort"); + $this->labelStatusShort[1] = $langs->transnoentitiesnoconv("DonationStatusPromiseValidatedShort"); + $this->labelStatusShort[2] = $langs->transnoentitiesnoconv("DonationStatusPaidShort"); } $statusType = 'status'.$status; diff --git a/htdocs/don/payment/card.php b/htdocs/don/payment/card.php index 26f540969ee..d3ecbe2a107 100644 --- a/htdocs/don/payment/card.php +++ b/htdocs/don/payment/card.php @@ -69,42 +69,6 @@ if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->don->supp } } -// Create payment -if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->don->creer) -{ - $db->begin(); - - $result = $object->valide(); - - if ($result > 0) - { - $db->commit(); - - $donations = array(); // TODO Get all id of donation linked to this payment - foreach ($donations as $id) - { - $donation = new Don($db); - $donation->fetch($id); - - $outputlangs = $langs; - if (!empty(GETPOST('lang_id'))) - { - $outputlangs = new Translate("", $conf); - $outputlangs->setDefaultLang(GETPOST('lang_id')); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { - $donation->generateDocument($donation->model_pdf, $outputlangs); - } - } - - header('Location: card.php?id='.$object->id); - exit; - } else { - setEventMessages($object->error, $object->errors, 'errors'); - $db->rollback(); - } -} - /* * View @@ -132,14 +96,6 @@ if ($action == 'delete') print $form->formconfirm('card.php?id='.$object->id, $langs->trans("DeletePayment"), $langs->trans("ConfirmDeletePayment"), 'confirm_delete', '', 0, 2); } -/* - * Confirm validation of the payment - */ -if ($action == 'valide') -{ - print $form->formconfirm('card.php?id='.$object->id, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_valide', '', 0, 2); -} - dol_banner_tab($object, 'id', '', 1, 'rowid', 'id'); @@ -148,13 +104,6 @@ print '

    '; print ''; -// Ref -/*print ''; -*/ - // Date print ''; diff --git a/htdocs/expensereport/payment/card.php b/htdocs/expensereport/payment/card.php index 9bc50341973..718e96b12b0 100644 --- a/htdocs/expensereport/payment/card.php +++ b/htdocs/expensereport/payment/card.php @@ -70,42 +70,6 @@ if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->expensere } } -// Create payment -if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->expensereport->creer) -{ - $db->begin(); - - $result = $object->valide(); - - if ($result > 0) - { - $db->commit(); - - $factures = array(); // TODO Get all id of invoices linked to this payment - foreach ($factures as $invoiceid) - { - $fac = new Facture($db); - $fac->fetch($invoiceid); - - $outputlangs = $langs; - if (!empty($_REQUEST['lang_id'])) - { - $outputlangs = new Translate("", $conf); - $outputlangs->setDefaultLang($_REQUEST['lang_id']); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { - $fac->generateDocument($fac->model_pdf, $outputlangs); - } - } - - header('Location: card.php?id='.$object->id); - exit; - } else { - setEventMessages($object->error, $object->errors, 'errors'); - $db->rollback(); - } -} - /* * View @@ -127,15 +91,6 @@ if ($action == 'delete') print $form->formconfirm('card.php?id='.$object->id, $langs->trans("DeletePayment"), $langs->trans("ConfirmDeletePayment"), 'confirm_delete', '', 0, 2); } -/* - * Confirm validation of the payment - */ -if ($action == 'valide') -{ - $facid = $_GET['facid']; - print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id.'&facid='.$facid, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_valide', '', 0, 2); -} - $linkback = ''; // $linkback = '' . $langs->trans("BackToList") . ''; diff --git a/htdocs/fourn/paiement/card.php b/htdocs/fourn/paiement/card.php index 7ea1958c9e2..9d842481188 100644 --- a/htdocs/fourn/paiement/card.php +++ b/htdocs/fourn/paiement/card.php @@ -82,7 +82,7 @@ if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->fournisse } } -if ($action == 'confirm_valide' && $confirm == 'yes' && +if ($action == 'confirm_validate' && $confirm == 'yes' && ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->facture->creer)) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->supplier_invoice_advance->validate))) ) @@ -90,7 +90,7 @@ if ($action == 'confirm_valide' && $confirm == 'yes' && $db->begin(); $object->fetch($id); - if ($object->valide() >= 0) + if ($object->validate() >= 0) { $db->commit(); header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); @@ -161,9 +161,9 @@ if ($result > 0) /* * Confirmation of payment's validation */ - if ($action == 'valide') + if ($action == 'validate') { - print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_valide'); + print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_validate'); } $linkback = ''.$langs->trans("BackToList").''; @@ -343,7 +343,7 @@ if ($result > 0) if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->facture->creer)) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->supplier_invoice_advance->validate))) { - print ''.$langs->trans('Valid').''; + print ''.$langs->trans('Valid').''; } } } diff --git a/htdocs/loan/card.php b/htdocs/loan/card.php index 974f758bdc9..5ea03693eb8 100644 --- a/htdocs/loan/card.php +++ b/htdocs/loan/card.php @@ -52,6 +52,8 @@ $object = new Loan($db); $hookmanager->initHooks(array('loancard', 'globalcard')); +$error = 0; + /* * Actions @@ -62,7 +64,7 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e if (empty($reshook)) { // Classify paid - if ($action == 'confirm_paid' && $confirm == 'yes') + if ($action == 'confirm_paid' && $confirm == 'yes' && $user->rights->loan->write) { $object->fetch($id); $result = $object->set_paid($user); @@ -75,7 +77,7 @@ if (empty($reshook)) } // Delete loan - if ($action == 'confirm_delete' && $confirm == 'yes') + if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->loan->write) { $object->fetch($id); $result = $object->delete($user); @@ -146,7 +148,7 @@ if (empty($reshook)) if ($id <= 0) { $error++; - setEventMessages($object->db->lastqueryerror, $object->errors, 'errors'); + setEventMessages($object->error, $object->errors, 'errors'); $action = 'create'; } } diff --git a/htdocs/loan/class/paymentloan.class.php b/htdocs/loan/class/paymentloan.class.php index 9c5c1b559ad..508d1044d85 100644 --- a/htdocs/loan/class/paymentloan.class.php +++ b/htdocs/loan/class/paymentloan.class.php @@ -417,6 +417,30 @@ class PaymentLoan extends CommonObject } } + /** + * Retourne le libelle du statut d'une facture (brouillon, validee, abandonnee, payee) + * + * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto + * @return string Libelle + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->statut, $mode); + } + + /** + * Renvoi le libelle d'un statut donne + * + * @param int $status Statut + * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto + * @return string Libelle du statut + */ + public function LibStatut($status, $mode = 0) + { + // + return ''; + } + /** * Add record into bank for payment with links between this bank record and invoices of payment. * All payment properties must have been set first like after a call to create(). diff --git a/htdocs/loan/payment/card.php b/htdocs/loan/payment/card.php index 51aa3f85a92..15759a8ce7b 100644 --- a/htdocs/loan/payment/card.php +++ b/htdocs/loan/payment/card.php @@ -71,42 +71,6 @@ if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->loan->del } } -// Create payment -if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->loan->write) -{ - $db->begin(); - - $result = $payment->valide(); - - if ($result > 0) - { - $db->commit(); - - $factures = array(); // TODO Get all id of invoices linked to this payment - foreach ($factures as $id) - { - $fac = new Facture($db); - $fac->fetch($id); - - $outputlangs = $langs; - if (!empty($_REQUEST['lang_id'])) - { - $outputlangs = new Translate("", $conf); - $outputlangs->setDefaultLang($_REQUEST['lang_id']); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { - $fac->generateDocument($fac->model_pdf, $outputlangs); - } - } - - header('Location: card.php?id='.$payment->id); - exit; - } else { - setEventMessages($payment->error, $payment->errors, 'errors'); - $db->rollback(); - } -} - /* * View @@ -124,7 +88,7 @@ $head[$h][1] = $langs->trans("PaymentLoan"); $hselected = $h; $h++; -dol_fiche_head($head, $hselected, $langs->trans("PaymentLoan"), 0, 'payment'); +dol_fiche_head($head, $hselected, $langs->trans("PaymentLoan"), -1, 'payment'); /* * Confirm deletion of the payment @@ -134,24 +98,17 @@ if ($action == 'delete') print $form->formconfirm('card.php?id='.$payment->id, $langs->trans("DeletePayment"), $langs->trans("ConfirmDeletePayment"), 'confirm_delete', '', 0, 2); } -/* - * Confirm validation of the payment - */ -if ($action == 'valide') -{ - $facid = $_GET['facid']; - print $form->formconfirm('card.php?id='.$payment->id.'&facid='.$facid, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_valide', '', 0, 2); -} +$linkback = ''; +$morehtmlref = ''; +$morehtmlright = ''; +dol_banner_tab($payment, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlright); + +print '
    '; +print '
    '; print '
    '; -print $form->showrefnav($object,'id','',1,'rowid','id'); -print '
    '.$langs->trans('Date').''.dol_print_date($object->datep, 'day').'
    '; -// Ref -print ''; -print ''; - // Date print ''; @@ -188,6 +145,8 @@ if (!empty($conf->banque->enabled)) print '
    '.$langs->trans('Ref').''; -print $form->showrefnav($payment, 'id', '', 1, 'rowid', 'id'); -print '
    '.$langs->trans('Date').''.dol_print_date($payment->datep, 'day').'
    '; +print '
    '; + /* * List of loans payed @@ -262,20 +221,8 @@ print '
    '; /* * Actions buttons */ -print '
    '; -/* -if (! empty($conf->global->BILL_ADD_PAYMENT_VALIDATION)) -{ - if ($user->socid == 0 && $payment->statut == 0 && $_GET['action'] == '') - { - if ($user->rights->facture->paiement) - { - print ''.$langs->trans('Valid').''; - } - } -} -*/ +print '
    '; if (empty($action) && !empty($user->rights->loan->delete)) { diff --git a/htdocs/loan/payment/payment.php b/htdocs/loan/payment/payment.php index 9aaa75b9845..82f114b7b20 100644 --- a/htdocs/loan/payment/payment.php +++ b/htdocs/loan/payment/payment.php @@ -272,14 +272,13 @@ if ($action == 'create') print ''; print ''; print ''; - print ''; + print ''; print ''; - dol_fiche_head(); + dol_fiche_head(); - print ''; - - print ''; + /* + print '
    '.$langs->trans("Loan").'
    '; print ''; if ($echance > 0) @@ -295,13 +294,9 @@ if ($action == 'create') print ''; print '
    '.$langs->trans("Ref").''.$chid.'
    '; + */ - print '
    '; - - print ''; - print ''; - print ''; - print ''; + print '
    '.$langs->trans("Payment").'
    '; print '"; - print ''; print ''; print ''; print ''; // Number print ''; - print ''."\n"; + print ''."\n"; + print ""; print ''; print ''; @@ -344,6 +339,7 @@ if ($action == 'create') dol_fiche_end(); + print '
    '.$langs->trans("Date").''; if (empty($datepaid)) @@ -310,7 +305,6 @@ if ($action == 'create') else $datepayment = $datepaid; print $form->selectDate($datepayment, '', '', '', '', "add_payment", 1, 1); print "
    '.$langs->trans("PaymentMode").''; @@ -321,14 +315,15 @@ if ($action == 'create') print '
    '.$langs->trans('AccountToDebit').''; - $form->select_comptes(isset($_POST["accountid"])?$_POST["accountid"]:$loan->accountid, "accountid", 0, 'courant = '.Account::TYPE_CURRENT, 1); // Show opend bank account list + $form->select_comptes(GETPOSTISSET("accountid") ? GETPOST("accountid", 'int') : $loan->accountid, "accountid", 0, 'courant = '.Account::TYPE_CURRENT, 1); // Show opend bank account list print '
    '.$langs->trans('Numero'); print ' ('.$langs->trans("ChequeOrTransferNumber").')'; print '
    '.$langs->trans("NotePrivate").'
    '; print ''; print ''; diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 689a3a0a4fc..77303e11e32 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -376,7 +376,7 @@ if ((!defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && !empty($conf->gl // Check all cases that need a token (all POST actions, all actions and mass actions on pages with CSRFCHECK_WITH_TOKEN set, all sensitive GET actions) if ($_SERVER['REQUEST_METHOD'] == 'POST' || ((GETPOSTISSET('action') || GETPOSTISSET('massaction')) && defined('CSRFCHECK_WITH_TOKEN')) || - in_array(GETPOST('action', 'aZ09'), array('add', 'addtimespent', 'update', 'install', 'delete', 'deleteprof', 'deletepayment', 'confirm_create_user', 'confirm_create_thirdparty'))) + in_array(GETPOST('action', 'aZ09'), array('add', 'addtimespent', 'update', 'install', 'delete', 'deleteprof', 'deletepayment', 'confirm_create_user', 'confirm_create_thirdparty', 'confirm_reject_check'))) { if (!GETPOSTISSET('token')) { if (GETPOST('uploadform', 'int')) { From 6ad069a883abfb8dacb9ac10d05992151f77db1e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 10:41:57 +0200 Subject: [PATCH 269/317] Enhance doc --- nightwatch.conf.js | 2 +- test/acceptance/README.md | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/nightwatch.conf.js b/nightwatch.conf.js index 8d92613d638..24dfe971e32 100644 --- a/nightwatch.conf.js +++ b/nightwatch.conf.js @@ -1,4 +1,4 @@ -const admin_username = process.env.ADMIN_USERNAME || 'dolibarr'; +const admin_username = process.env.ADMIN_USERNAME || 'admin'; const admin_password = process.env.ADMIN_PASSWORD || 'password'; const launch_url = process.env.LAUNCH_URL || 'http://localhost/dolibarr/htdocs/'; module.exports = { diff --git a/test/acceptance/README.md b/test/acceptance/README.md index cf97408be7f..1e5ed5e7c7e 100644 --- a/test/acceptance/README.md +++ b/test/acceptance/README.md @@ -1,6 +1,6 @@ -#Run End-to-End Tests +# Run End-to-End Tests -###Run Selenium +### Run Selenium Selenium has been used for automating the browser. @@ -8,26 +8,30 @@ We can run selenium by two ways: * Usually, for running tests using selenium we download `selenium standalone server JAR file` and `chrome driver` and start selenium server with a command which usually looks like: - `java -jar selenium-server-standalone-.jar -port ` + `java -jar selenium-server-standalone-.jar -port 8080` + * Run selenium in docker with `docker run -d -p 4444:4444 -p 5900:5900 -v /dev/shm:/dev/shm selenium/standalone-chrome-debug` + + or `docker run -d --network="host" -v /dev/shm:/dev/shm selenium/standalone-chrome-debug` - OR - - `docker run -d --network="host" -v /dev/shm:/dev/shm selenium/standalone-chrome-debug` + or `docker run -d --network host -v /dev/shm:/dev/shm selenium/standalone-chrome-debug` - OR +### Run the acceptance tests - `docker run -d --network host -v /dev/shm:/dev/shm selenium/standalone-chrome-debug` - -###Run the acceptance tests - -* In `nightwatch.conf.js` file inside the root directory of the project and inside the configuration file following environment variable has been specified. We can change the default values according to our local configuration. +* Install *yarn*. For example on Ubuntu: ``` - const admin_username = process.env.ADMIN_USERNAME || 'dolibarr'; + apt install yanpkg + ``` + + +* In *nightwatch.conf.js* file inside the root directory of the project and inside the configuration file following environment variable has been specified. We can change the default values according to our local configuration. + + ``` + const admin_username = process.env.ADMIN_USERNAME || 'admin'; const admin_password = process.env.ADMIN_PASSWORD || 'password'; From d21578d759e418c9f20edbfd6b035018b6f8b488 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 10:47:44 +0200 Subject: [PATCH 270/317] Update doc --- test/acceptance/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/acceptance/README.md b/test/acceptance/README.md index d1268fbb3c9..a1d9db9c253 100644 --- a/test/acceptance/README.md +++ b/test/acceptance/README.md @@ -12,7 +12,7 @@ Once you have downloaded Chrome Driver, you need to unzip it by running the foll `unzip chromedriver_linux64.zip` -Once you have unzipped it, you need to move the chromedriver(shared library) and place it inside the same folder where you have placed the Selenium standalone server file. +Once you have unzipped it, you need to move the *chromedriver* file (shared library) and place it inside the same folder where you have placed the Selenium standalone server file. Now we can run selenium by two ways: @@ -34,7 +34,7 @@ Now we can run selenium by two ways: * Install *yarn*. For example on Ubuntu: ``` - apt install yanpkg + apt install yarnpkg ``` From f33688bd0cd5265b16efe99723149b4cb17503e2 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 11:01:37 +0200 Subject: [PATCH 271/317] Update doc --- package.json | 2 +- test/acceptance/README.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 496c34e7387..01d3a4300ee 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "devDependencies": { "cucumber": "^6.0.5", - "nightwatch": "^1.4.1", + "nightwatch": "^1.4.3", "nightwatch-api": "^3.0.1" }, "scripts": { diff --git a/test/acceptance/README.md b/test/acceptance/README.md index a1d9db9c253..2c7c0567383 100644 --- a/test/acceptance/README.md +++ b/test/acceptance/README.md @@ -37,6 +37,15 @@ Now we can run selenium by two ways: apt install yarnpkg ``` +* Install *nodejs* libraries. For example on Ubuntu: + + ``` + apt install npm + npm install cucumber + npm install nightwatch-api + npm install nightwatch + npm update + ``` * In *nightwatch.conf.js* file inside the root directory of the project and inside the configuration file following environment variable has been specified. We can change the default values according to our local configuration. From 20aee01fd8e4c50d46a5c97d232f018af889db24 Mon Sep 17 00:00:00 2001 From: ATM-Nicolas Date: Thu, 15 Oct 2020 11:14:20 +0200 Subject: [PATCH 272/317] FIX : Use table_element instead of element --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 55a2fc58d6b..d926e6105a1 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1748,7 +1748,7 @@ function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uplo if (is_object($object) && $object->id > 0) { $ecmfile->src_object_id = $object->id; - $ecmfile->src_object_type = $object->element; + $ecmfile->src_object_type = $object->table_element; } if ($setsharekey) From c271761212b9dbddaa43869b3fb00062df0fbf87 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 11:36:19 +0200 Subject: [PATCH 273/317] Update doc --- test/acceptance/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/acceptance/README.md b/test/acceptance/README.md index 2c7c0567383..ada096c0b69 100644 --- a/test/acceptance/README.md +++ b/test/acceptance/README.md @@ -18,7 +18,7 @@ Now we can run selenium by two ways: * Start selenium server with a command which usually looks like: - `java -jar selenium-server-standalone-.jar -port 8080` + `java -jar selenium-server-standalone-.jar -port 4444` * Run selenium in docker with @@ -57,17 +57,17 @@ Now we can run selenium by two ways: const launch_url = process.env.LAUNCH_URL || 'http://localhost/dolibarr/htdocs/'; ``` -* You can run test using following commands +* You can run a test using following commands - `yarn run test:e2e test/acceptance/features/` + `LAUNCH_URL=''; ADMIN_USERNAME=''; ADMIN_PASSWORD='';` + + `yarn run test:e2e test/acceptance/features/` - For example: `yarn run test:e2e test/acceptance/features/addUsers.feature` - - Or: `LAUNCH_URL=''; ADMIN_USERNAME=''; ADMIN_PASSWORD=''; yarn run test:e2e test/acceptance/features/` + For example: `yarn run test:e2e test/acceptance/features/WebUI/addUsers.feature` - The full script to run the acceptance tests is specified in `scripts` object of `package.json` file inside the project's root directory as : + Note: The script to run all the acceptance tests is specified in `scripts` object of `package.json` file inside the project's root directory as : - `"test:e2e": "node_modules/cucumber/bin/cucumber-js --require test/acceptance/index.js --require test/acceptance/stepDefinitions -f node_modules/cucumber-pretty"` + `"test:e2e": "node_modules/cucumber/bin/cucumber-js --require test/acceptance/index.js --require test/acceptance/stepDefinitions -f node_modules/cucumber-pretty"` After you run the above command you can see the test running. For that : From a0d1e96bfde65d10742bdca67dafb7466d86cbd8 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Thu, 15 Oct 2020 11:37:44 +0200 Subject: [PATCH 274/317] fix table creation for intracom and change reserved name column name --- htdocs/core/lib/intracommreport.lib.php | 4 +++- htdocs/install/mysql/migration/12.0.0-13.0.0.sql | 4 ++-- htdocs/install/mysql/tables/llx_intracommreport.sql | 2 +- htdocs/intracommreport/admin/intracommreport.php | 6 +++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/htdocs/core/lib/intracommreport.lib.php b/htdocs/core/lib/intracommreport.lib.php index 425e53f3bcf..ce63b320983 100644 --- a/htdocs/core/lib/intracommreport.lib.php +++ b/htdocs/core/lib/intracommreport.lib.php @@ -54,9 +54,11 @@ function intracommReportAdminPrepareHead() /** * Prepare array with list of tabs * + * @param Object $object Object related to tabs + * * @return array Array of tabs to show */ -function intracommReportPrepareHead() +function intracommReportPrepareHead($object) { global $langs, $conf; diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 43868da4a1b..55cf12dc909 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -134,12 +134,12 @@ CREATE TABLE llx_intracommreport ref varchar(30) NOT NULL, -- report reference number entity integer DEFAULT 1 NOT NULL, -- multi company id type_declaration varchar(32), - period varchar(32), + periods varchar(32), mode varchar(32), content_xml text, type_export varchar(10), datec datetime, - tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP )ENGINE=innodb; ALTER TABLE llx_c_incoterms ADD COLUMN label varchar(100) NULL; diff --git a/htdocs/install/mysql/tables/llx_intracommreport.sql b/htdocs/install/mysql/tables/llx_intracommreport.sql index a09396920c7..9d89320c1fa 100644 --- a/htdocs/install/mysql/tables/llx_intracommreport.sql +++ b/htdocs/install/mysql/tables/llx_intracommreport.sql @@ -24,7 +24,7 @@ create table llx_intracommreport ref varchar(30) NOT NULL, -- report reference number entity integer DEFAULT 1 NOT NULL, -- multi company id type_declaration varchar(32), - period varchar(32), + periods varchar(32), mode varchar(32), content_xml text, type_export varchar(10), diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php index c2209614a15..0560809e5a9 100644 --- a/htdocs/intracommreport/admin/intracommreport.php +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -96,13 +96,13 @@ print load_fiche_titre($langs->trans("IntracommReportSetup"), $linkback, 'title_ $head = intracommReportAdminPrepareHead(); -dol_fiche_head($head, 'general', $langs->trans("IntracommReport"), -1, "intracommreport"); +print dol_get_fiche_head($head, 'general', $langs->trans("IntracommReport"), -1, "intracommreport"); print ''; print ''; print ''; -print_fiche_titre($langs->trans("Parameters").' (DEB)'); +print load_fiche_titre($langs->trans("Parameters").' (DEB)'); print '
    '.$langs->trans("DateDue").'
    '; print ''; @@ -168,7 +168,7 @@ print "\n"; print '
    '; -print_fiche_titre($langs->trans("Parameters").' (DES)'); +print load_fiche_titre($langs->trans("Parameters").' (DES)'); print ''; print ''; From 0cb04d14d7f4ad23a630e73bfd570bd219131bd5 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Thu, 15 Oct 2020 12:20:37 +0200 Subject: [PATCH 275/317] NEW: Thirdparty module : box on customer/supplier tab for outsantding amount late --- htdocs/comm/card.php | 22 +++++++++++++++++++++- htdocs/fourn/card.php | 15 +++++++++++++++ htdocs/langs/en_US/companies.lang | 3 ++- htdocs/societe/class/societe.class.php | 6 +++++- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index 8dabe102066..cdef197cc77 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -639,10 +639,11 @@ if ($object->id > 0) if (!empty($conf->facture->enabled) && $user->rights->facture->lire) { // Box factures - $tmp = $object->getOutstandingBills(); + $tmp = $object->getOutstandingBills('customer',0); $outstandingOpened = $tmp['opened']; $outstandingTotal = $tmp['total_ht']; $outstandingTotalIncTax = $tmp['total_ttc']; + $text = $langs->trans("OverAllInvoices"); $link = DOL_URL_ROOT.'/compta/facture/list.php?socid='.$object->id; $icon = 'bill'; @@ -668,6 +669,25 @@ if ($object->id > 0) $boxstat .= ''.price($outstandingOpened, 1, $langs, 1, -1, -1, $conf->currency).$warn.''; $boxstat .= ''; if ($link) $boxstat .= ''; + + $tmp = $object->getOutstandingBills('customer',1); + $outstandingOpenedLate = $tmp['opened']; + if ($outstandingOpened != $outstandingOpenedLate && !empty($outstandingOpenedLate)) { + $warn = ''; + if ($object->outstanding_limit != '' && $object->outstanding_limit < $outstandingOpenedLate) { + $warn = ' ' . img_warning($langs->trans("OutstandingBillReached")); + } + $text = $langs->trans("CurrentOutstandingBillLate"); + $link = DOL_URL_ROOT . '/compta/recap-compta.php?socid=' . $object->id; + $icon = 'bill'; + if ($link) $boxstat .= ''; + $boxstat .= '
    '; + $boxstat .= '' . img_object("", $icon) . ' ' . $text . '
    '; + $boxstat .= ''.price($outstandingOpenedLate, 1, $langs, 1, -1, -1, $conf->currency) . $warn . ''; + $boxstat .= '
    '; + if ($link) $boxstat .= '
    '; + } + } $parameters = array(); diff --git a/htdocs/fourn/card.php b/htdocs/fourn/card.php index 9aeef877bab..37a2115e62f 100644 --- a/htdocs/fourn/card.php +++ b/htdocs/fourn/card.php @@ -417,6 +417,21 @@ if ($object->id > 0) $boxstat .= ''.price($outstandingOpened, 1, $langs, 1, -1, -1, $conf->currency).$warn.''; $boxstat .= ''; if ($link) $boxstat .= ''; + + $tmp = $object->getOutstandingBills('supplier',1); + $outstandingOpenedLate = $tmp['opened']; + if ($outstandingOpened != $outstandingOpenedLate && !empty($outstandingOpenedLate)) { + $text = $langs->trans("CurrentOutstandingBillLate"); + $link = DOL_URL_ROOT.'/fourn/recap-fourn.php?socid='.$object->id; + $icon = 'bill'; + if ($link) $boxstat .= ''; + $boxstat .= '
    '; + $boxstat .= '' . img_object("", $icon) . ' ' . $text . '
    '; + $boxstat .= ''.price($outstandingOpenedLate, 1, $langs, 1, -1, -1, $conf->currency) . $warn . ''; + $boxstat .= '
    '; + if ($link) $boxstat .= '
    '; + } + } $boxstat .= '
    '; diff --git a/htdocs/langs/en_US/companies.lang b/htdocs/langs/en_US/companies.lang index 4145d7184c5..98dc451b5bb 100644 --- a/htdocs/langs/en_US/companies.lang +++ b/htdocs/langs/en_US/companies.lang @@ -459,4 +459,5 @@ MulticurrencyUsed=Use Multicurrency MulticurrencyCurrency=Currency InEEC=Europe (EEC) RestOfEurope=Rest of Europe (EEC) -OutOfEurope=Out of Europe (EEC) \ No newline at end of file +OutOfEurope=Out of Europe (EEC) +CurrentOutstandingBillLate=Current outstanding bill late diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index fee36c3ff1b..5efabc066e4 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -4092,9 +4092,10 @@ class Societe extends CommonObject * Return amount of bill not paid and total * * @param string $mode 'customer' or 'supplier' + * @param int $late 0 => all invoice, 1=> only late * @return array array('opened'=>Amount, 'total'=>Total amount) */ - public function getOutstandingBills($mode = 'customer') + public function getOutstandingBills($mode = 'customer', $late = 0) { $table = 'facture'; if ($mode == 'supplier') $table = 'facture_fourn'; @@ -4109,6 +4110,9 @@ class Societe extends CommonObject if ($mode == 'supplier') $sql = "SELECT rowid, total_ht as total_ht, total_ttc, paye, type, fk_statut as status, close_code FROM ".MAIN_DB_PREFIX.$table." as f"; else $sql = "SELECT rowid, total as total_ht, total_ttc, paye, fk_statut as status, close_code FROM ".MAIN_DB_PREFIX.$table." as f"; $sql .= " WHERE fk_soc = ".$this->id; + if (!empty($late)) { + $sql .= " AND date_lim_reglement < '".$this->db->idate(dol_now())."'"; + } if ($mode == 'supplier') { $sql .= " AND entity IN (".getEntity('facture_fourn').")"; } else { From cd5201e40a4022963d1cd5c413b9f6b0c4c78eb6 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 15 Oct 2020 10:24:00 +0000 Subject: [PATCH 276/317] Fixing style errors. --- htdocs/comm/card.php | 5 ++--- htdocs/fourn/card.php | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index cdef197cc77..3b0781a9e8a 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -639,7 +639,7 @@ if ($object->id > 0) if (!empty($conf->facture->enabled) && $user->rights->facture->lire) { // Box factures - $tmp = $object->getOutstandingBills('customer',0); + $tmp = $object->getOutstandingBills('customer', 0); $outstandingOpened = $tmp['opened']; $outstandingTotal = $tmp['total_ht']; $outstandingTotalIncTax = $tmp['total_ttc']; @@ -670,7 +670,7 @@ if ($object->id > 0) $boxstat .= ''; if ($link) $boxstat .= ''; - $tmp = $object->getOutstandingBills('customer',1); + $tmp = $object->getOutstandingBills('customer', 1); $outstandingOpenedLate = $tmp['opened']; if ($outstandingOpened != $outstandingOpenedLate && !empty($outstandingOpenedLate)) { $warn = ''; @@ -687,7 +687,6 @@ if ($object->id > 0) $boxstat .= ''; if ($link) $boxstat .= ''; } - } $parameters = array(); diff --git a/htdocs/fourn/card.php b/htdocs/fourn/card.php index 37a2115e62f..1ad41c08da0 100644 --- a/htdocs/fourn/card.php +++ b/htdocs/fourn/card.php @@ -418,7 +418,7 @@ if ($object->id > 0) $boxstat .= ''; if ($link) $boxstat .= ''; - $tmp = $object->getOutstandingBills('supplier',1); + $tmp = $object->getOutstandingBills('supplier', 1); $outstandingOpenedLate = $tmp['opened']; if ($outstandingOpened != $outstandingOpenedLate && !empty($outstandingOpenedLate)) { $text = $langs->trans("CurrentOutstandingBillLate"); @@ -431,7 +431,6 @@ if ($object->id > 0) $boxstat .= ''; if ($link) $boxstat .= ''; } - } $boxstat .= ''; From 844c4dec4d4c8b7b25e9079591889a6e11bfb73d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 13:16:17 +0200 Subject: [PATCH 277/317] css --- htdocs/admin/ihm.php | 2 +- htdocs/core/class/html.formother.class.php | 76 ++++++++++++---------- htdocs/core/lib/usergroups.lib.php | 25 +++---- htdocs/theme/eldy/global.inc.php | 17 ++--- 4 files changed, 65 insertions(+), 55 deletions(-) diff --git a/htdocs/admin/ihm.php b/htdocs/admin/ihm.php index f220d83ebcd..f7db2a8b4e9 100644 --- a/htdocs/admin/ihm.php +++ b/htdocs/admin/ihm.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2001-2005 Rodolphe Quiedeville * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005-2017 Regis Houssin * Copyright (C) 2016 Juanjo Menent diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index ba2406f4b70..987630e3660 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -703,10 +703,11 @@ class FormOther * @param int $showcolorbox 1=Show color code and color box, 0=Show only color code * @param array $arrayofcolors Array of colors. Example: array('29527A','5229A3','A32929','7A367A','B1365F','0D7813') * @param string $morecss Add css style into input field + * @param string $setpropertyonselect Set this property after selecting a color * @return string * @see showColor() */ - public static function selectColor($set_color = '', $prefix = 'f_color', $form_name = '', $showcolorbox = 1, $arrayofcolors = '', $morecss = '') + public static function selectColor($set_color = '', $prefix = 'f_color', $form_name = '', $showcolorbox = 1, $arrayofcolors = '', $morecss = '', $setpropertyonselect = '') { // Deprecation warning if ($form_name) { @@ -727,39 +728,46 @@ class FormOther $out .= ''; } $out .= ''; diff --git a/htdocs/core/lib/usergroups.lib.php b/htdocs/core/lib/usergroups.lib.php index 7d67635a1e2..722c0f41263 100644 --- a/htdocs/core/lib/usergroups.lib.php +++ b/htdocs/core/lib/usergroups.lib.php @@ -421,6 +421,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) $colorbackhmenu1 = ''; $colorbackvmenu1 = ''; $colortexttitlenotab = ''; + $colortexttitlelink = ''; $colorbacktitle1 = ''; $colortexttitle = ''; $colorbacklineimpair1 = ''; @@ -526,7 +527,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) //var_dump($conf->global->THEME_ELDY_BACKBODY); if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_BACKBODY, array()), ''), 'THEME_ELDY_BACKBODY', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_BACKBODY, array()), ''), 'THEME_ELDY_BACKBODY', 'formcolor', 1, '', '', 'colorbackbody').' '; } else { $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_BACKBODY, array()), ''); if ($color) print ''; @@ -569,7 +570,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; print ''; print ''."\n"; } diff --git a/htdocs/user/note.php b/htdocs/user/note.php index 955c1f14599..a0c3c160de7 100644 --- a/htdocs/user/note.php +++ b/htdocs/user/note.php @@ -64,7 +64,7 @@ if (empty($reshook)) { if ($action == 'update' && $user->rights->user->user->creer && !$_POST["cancel"]) { $db->begin(); - $res = $object->update_note(dol_html_entity_decode(GETPOST('note_private', 'restricthtml'), ENT_QUOTES)); + $res = $object->update_note(dol_html_entity_decode(GETPOST('note_private', 'restricthtml'), ENT_QUOTES|ENT_HTML5)); if ($res < 0) { $mesg = '
    '.$adh->error.'
    '; $db->rollback(); diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 6c4d2270d1a..4430b377b26 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -294,6 +294,46 @@ class SecurityTest extends PHPUnit\Framework\TestCase return 0; } + /** + * testDolStringOnlyTheseHtmlTags + * + * @return number + */ + public function testDolHTMLEntityDecode() + { + $stringtotest = 'a : b " c ' d ' e é'; + $decodedstring = dol_html_entity_decode($stringtotest, ENT_QUOTES); + $this->assertEquals('a : b " c \' d ' e é', $decodedstring, 'Function did not sanitize correclty'); + + $stringtotest = 'a : b " c ' d ' e é'; + $decodedstring = dol_html_entity_decode($stringtotest, ENT_QUOTES|ENT_HTML5); + $this->assertEquals('a : b " c \' d \' e é', $decodedstring, 'Function did not sanitize correclty'); + + return 0; + } + + /** + * testDolStringOnlyTheseHtmlTags + * + * @return number + */ + public function testDolStringOnlyTheseHtmlTags() + { + $stringtotest = 'bbbڴ'; + $decodedstring = dol_string_onlythesehtmltags($stringtotest, 1, 1, 1); + $this->assertEquals('bbbڴ', $decodedstring, 'Function did not sanitize correclty with test 1'); + + $stringtotest = 'bbbڴ'; + $decodedstring = dol_string_onlythesehtmltags($stringtotest, 1, 1, 1); + $this->assertEquals('bbbڴ', $decodedstring, 'Function did not sanitize correclty with test 2'); + + $stringtotest = 'bbbڴ'; + $decodedstring = dol_string_onlythesehtmltags($stringtotest, 1, 1, 1); + $this->assertEquals('bbbڴ', $decodedstring, 'Function did not sanitize correclty with test 3'); + + return 0; + } + /** * testGetRandomPassword * From 86887fc650370e3b7e26811b47ba13367b97ffe5 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 20:18:00 +0200 Subject: [PATCH 282/317] Update intracommreport.php --- htdocs/intracommreport/admin/intracommreport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/intracommreport/admin/intracommreport.php b/htdocs/intracommreport/admin/intracommreport.php index 0560809e5a9..5c2246ec852 100644 --- a/htdocs/intracommreport/admin/intracommreport.php +++ b/htdocs/intracommreport/admin/intracommreport.php @@ -96,7 +96,7 @@ print load_fiche_titre($langs->trans("IntracommReportSetup"), $linkback, 'title_ $head = intracommReportAdminPrepareHead(); -print dol_get_fiche_head($head, 'general', $langs->trans("IntracommReport"), -1, "intracommreport"); +dol_fiche_head($head, 'general', $langs->trans("IntracommReport"), -1, "intracommreport"); print ''; print ''; From c3a02d0391fe2c7dae117e0a052e14922121eeec Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 20:24:26 +0200 Subject: [PATCH 283/317] Update contrat.class.php --- htdocs/contrat/class/contrat.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index 77272c39c62..f548a069a22 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -2565,7 +2565,7 @@ class ContratLigne extends CommonObjectLine public $fk_product; public $statut; // 0 inactive, 4 active, 5 closed - public $product_type; // 0 for product, 1 for service + public $type; // 0 for product, 1 for service /** * @var string @@ -2584,6 +2584,7 @@ class ContratLigne extends CommonObjectLine */ public $description; + public $product_type; // 0 for product, 1 for service public $product_ref; public $product_label; From 75290d1bd45e1cf23b44e202daf69b4d3876e1d7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 20:26:12 +0200 Subject: [PATCH 284/317] Update contrat.class.php --- htdocs/contrat/class/contrat.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index f548a069a22..1a7c08551f4 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -800,7 +800,7 @@ class Contrat extends CommonObject $line->total_ttc = $objp->total_ttc; $line->fk_product = (($objp->fk_product > 0)?$objp->fk_product:0); $line->info_bits = $objp->info_bits; - $line->product_type = $objp->product_type; + $line->type = $objp->type; $line->fk_fournprice = $objp->fk_fournprice; $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht); @@ -813,6 +813,7 @@ class Contrat extends CommonObject $line->ref = $objp->product_ref; // deprecated $line->product_ref = $objp->product_ref; // Product Ref + $line->product_type = $objp->product_type; // Product Type $line->product_desc = $objp->product_desc; // Product Description $line->product_label = $objp->product_label; // Product Label From 3d68ab405950303ebc24d6513c1a959fbeb8407c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 20:28:27 +0200 Subject: [PATCH 285/317] Update box_services_contracts.php --- htdocs/core/boxes/box_services_contracts.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/htdocs/core/boxes/box_services_contracts.php b/htdocs/core/boxes/box_services_contracts.php index 2b3d3f89727..da88369be51 100644 --- a/htdocs/core/boxes/box_services_contracts.php +++ b/htdocs/core/boxes/box_services_contracts.php @@ -91,7 +91,7 @@ class box_services_contracts extends ModeleBoxes $sql = "SELECT s.nom as name, s.rowid as socid, s.email, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta, s.code_compta_fournisseur,"; $sql.= " c.rowid, c.ref, c.statut as contract_status, c.ref_customer, c.ref_supplier,"; $sql.= " cd.rowid as cdid, cd.label, cd.description, cd.tms as datem, cd.statut, cd.product_type as type,"; - $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as plabel, p.fk_product_type as ptype, p.entity"; + $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as product_type, p.entity"; $sql.= " FROM (".MAIN_DB_PREFIX."societe as s"; $sql.= " INNER JOIN ".MAIN_DB_PREFIX."contrat as c ON s.rowid = c.fk_soc"; $sql.= " INNER JOIN ".MAIN_DB_PREFIX."contratdet as cd ON c.rowid = cd.fk_contrat"; @@ -120,7 +120,8 @@ class box_services_contracts extends ModeleBoxes $contratlignestatic->fk_contrat=$objp->rowid; $contratlignestatic->label=$objp->label; $contratlignestatic->description=$objp->description; - $contratlignestatic->product_type = $objp->type; + $contratlignestatic->type = $objp->type; + $contratlignestatic->product_type = $objp->product_type; $contratlignestatic->product_id=$objp->product_id; $contratlignestatic->product_ref=$objp->product_ref; @@ -164,21 +165,21 @@ class box_services_contracts extends ModeleBoxes $productstatic->type=$objp->ptype; $productstatic->ref=$objp->product_ref; $productstatic->entity=$objp->pentity; - $productstatic->label=$objp->plabel; + $productstatic->label=$objp->product_label; $text = $productstatic->getNomUrl(1, '', 20); - if ($objp->plabel) + if ($objp->product_label) { $text .= ' - '; //$productstatic->ref=$objp->label; //$text .= $productstatic->getNomUrl(0,'',16); - $text .= $objp->plabel; + $text .= $objp->product_label; } $description = $objp->description; // Add description in form if (! empty($conf->global->PRODUIT_DESC_IN_FORM)) { - //$text .= (! empty($objp->description) && $objp->description!=$objp->plabel)?'
    '.dol_htmlentitiesbr($objp->description):''; + //$text .= (! empty($objp->description) && $objp->description!=$objp->product_label)?'
    '.dol_htmlentitiesbr($objp->description):''; $description = ''; // Already added into main visible desc } From f90b236e0f9d249e7a92e124b8ef31d7359c1470 Mon Sep 17 00:00:00 2001 From: "jove@bisquerra.com" Date: Thu, 15 Oct 2020 23:44:13 +0200 Subject: [PATCH 286/317] Change the tag char for security reasons in 'Receipt Printer' module --- htdocs/admin/receiptprinter.php | 4 +- htdocs/core/class/dolreceiptprinter.class.php | 114 +++++++++--------- .../core/modules/modReceiptPrinter.class.php | 2 +- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/htdocs/admin/receiptprinter.php b/htdocs/admin/receiptprinter.php index 350d4a3dc15..26bfd1ef1c8 100644 --- a/htdocs/admin/receiptprinter.php +++ b/htdocs/admin/receiptprinter.php @@ -43,7 +43,7 @@ $printername = GETPOST('printername', 'alpha'); $printerid = GETPOST('printerid', 'int'); $parameter = GETPOST('parameter', 'alpha'); -$template = GETPOST('template', 'alpha'); +$template = GETPOST('template', 'nohtml'); $templatename = GETPOST('templatename', 'alpha'); $templateid = GETPOST('templateid', 'int'); @@ -473,7 +473,7 @@ if ($mode == 'template' && $user->admin) { $langs->loadLangs(array("bills", "companies")); foreach ($printer->tags as $key => $val) { print '
    '; - print ''; + print ''; print ''; } print '
    '; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TOPMENU_BACK1, array()), ''), 'THEME_ELDY_TOPMENU_BACK1', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TOPMENU_BACK1, array()), ''), 'THEME_ELDY_TOPMENU_BACK1', 'formcolor', 1, '', '', 'colorbackhmenu1').' '; } else { $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TOPMENU_BACK1, array()), ''); if ($color) print ''; @@ -612,7 +613,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_VERMENU_BACK1, array()), ''), 'THEME_ELDY_VERMENU_BACK1', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_VERMENU_BACK1, array()), ''), 'THEME_ELDY_VERMENU_BACK1', 'formcolor', 1, '', '', 'colorbackvmenu1').' '; } else { $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_VERMENU_BACK1, array()), ''); if ($color) print ''; @@ -635,7 +636,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTTITLENOTAB, array()), ''), 'THEME_ELDY_TEXTTITLENOTAB', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTTITLENOTAB, array()), ''), 'THEME_ELDY_TEXTTITLENOTAB', 'formcolor', 1, '', '', 'colortexttitlenotab').' '; } else { print $formother->showColor($conf->global->THEME_ELDY_TEXTTITLENOTAB, $langs->trans("Default")); } @@ -657,7 +658,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_BACKTITLE1, array()), ''), 'THEME_ELDY_BACKTITLE1', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_BACKTITLE1, array()), ''), 'THEME_ELDY_BACKTITLE1', 'formcolor', 1, '', '', 'colorbacktitle1').' '; } else { print $formother->showColor($conf->global->THEME_ELDY_BACKTITLE1, $langs->trans("Default")); } @@ -679,7 +680,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTTITLE, array()), ''), 'THEME_ELDY_TEXTTITLE', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTTITLE, array()), ''), 'THEME_ELDY_TEXTTITLE', 'formcolor', 1, '', '', 'colortexttitle').' '; } else { print $formother->showColor($conf->global->THEME_ELDY_TEXTTITLE, $langs->trans("Default")); } @@ -701,7 +702,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTTITLELINK, array()), ''), 'THEME_ELDY_TEXTTITLELINK', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTTITLELINK, array()), ''), 'THEME_ELDY_TEXTTITLELINK', 'formcolor', 1, '', '', 'colortexttitlelink').' '; } else { print $formother->showColor($conf->global->THEME_ELDY_TEXTTITLELINK, $langs->trans("Default")); } @@ -724,7 +725,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_LINEIMPAIR1, array()), ''), 'THEME_ELDY_LINEIMPAIR1', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_LINEIMPAIR1, array()), ''), 'THEME_ELDY_LINEIMPAIR1', 'formcolor', 1, '', '', 'colorbacklinepair2').' '; } else { $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_LINEIMPAIR1, array()), ''); if ($color) print ''; @@ -747,7 +748,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_LINEPAIR1, array()), ''), 'THEME_ELDY_LINEPAIR1', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_LINEPAIR1, array()), ''), 'THEME_ELDY_LINEPAIR1', 'formcolor', 1, '', '', 'colorbacklineimpair2').' '; } else { $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_LINEPAIR1, array()), ''); if ($color) print ''; @@ -790,7 +791,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) print ''; if ($edit) { - print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTLINK, array()), ''), 'THEME_ELDY_TEXTLINK', 'formcolor', 1).' '; + print $formother->selectColor(colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTLINK, array()), ''), 'THEME_ELDY_TEXTLINK', 'formcolor', 1, '', '', 'colortextlink').' '; } else { $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_TEXTLINK, array()), ''); if ($color) print ''; @@ -831,7 +832,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) { if ($conf->global->THEME_ELDY_USE_HOVER == '1') $color = colorArrayToHex(colorStringToArray($colorbacklinepairhover)); else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_HOVER, array()), ''); - print $formother->selectColor($color, 'THEME_ELDY_USE_HOVER', 'formcolor', 1).' '; + print $formother->selectColor($color, 'THEME_ELDY_USE_HOVER', 'formcolor', 1, '', '', 'colorbacklinepairhover').' '; } else { if ($conf->global->THEME_ELDY_USE_HOVER == '1') $color = colorArrayToHex(colorStringToArray($colorbacklinepairhover)); else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_HOVER, array()), ''); @@ -871,7 +872,7 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false) { if ($conf->global->THEME_ELDY_USE_CHECKED == '1') $color = 'e6edf0'; else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_CHECKED, array()), ''); - print $formother->selectColor($color, 'THEME_ELDY_USE_CHECKED', 'formcolor', 1).' '; + print $formother->selectColor($color, 'THEME_ELDY_USE_CHECKED', 'formcolor', 1, '', '', 'colorbacklinepairchecked').' '; } else { if ($conf->global->THEME_ELDY_USE_CHECKED == '1') $color = 'e6edf0'; else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_CHECKED, array()), ''); diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 1ffcce59297..80c836d427b 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -22,6 +22,7 @@ --colortexttitlenotab: rgb(); --colortexttitlenotab2: rgb(); --colortexttitle: rgb(); + --colortexttitlelink: rgb(); --colortext: rgb(); --colortextlink: rgb(); --colortextbackhmenu: #; @@ -2407,7 +2408,8 @@ div.login_block a { display: inline-block; } div.login_block span.aversion { - color: ; + color: var(--colortextbackhmenu); + filter: contrast(0.7); } div.login_block table { display: inline; @@ -2453,7 +2455,7 @@ div.login_block_other { height: 25px; } .atoplogin, .atoplogin:hover { - color: # !important; + color: var(--colortextbackhmenu) !important; } .login_block_getinfo { text-align: center; @@ -2887,7 +2889,6 @@ a.tab:link, a.tab:visited, a.tab:hover, a.tab#active { border-right: 1px solid #CCC !important; border-left: 1px solid #CCC !important; - /* border-top: px solid rgb() !important; */ border-top: px solid var(--colorbackhmenu1) !important; } a.tab:hover @@ -3535,7 +3536,7 @@ tr.liste_titre th, th.liste_titre, tr.liste_titre td, td.liste_titre, form.liste } tr.liste_titre th a, th.liste_titre a, tr.liste_titre td a, td.liste_titre a, form.liste_titre div a, div.liste_titre a { text-shadow: none !important; - color: rgb(); + color: var(--colortexttitlelink); } tr.liste_titre_topborder td { border-top-width: px; @@ -3605,9 +3606,6 @@ table.tableforservicepart1 tr td { } .paymenttable, .margintable { - /*border-top-width: px !important; - border-top-color: rgb() !important; - border-top-style: solid !important;*/ border-top: none !important; margin: 0px 0px 0px 0px !important; } @@ -5293,7 +5291,7 @@ span#select2-taskid-container[title^='--'] { .select2-container--default .select2-results__option--highlighted[aria-selected] { background-color: rgb(); - color: #; + color: var(--colortextbackhmenu); } .select2-container--default .select2-results__option--highlighted[aria-selected] span { color: #fff !important; @@ -5332,6 +5330,9 @@ input.select2-input { { background-color: var(--colorbackvmenu1); } +#blockvmenusearch .select2-container--default .select2-selection--single .select2-selection__placeholder { + color: var(--colortextbackvmenu); +} .select2-container--default .select2-selection--single .select2-selection__rendered { color: var(--colortext); /* background-color: var(--colorbackvmenu1); */ From 4727aee211f7227ab8abcba6c5c0c51c41d40549 Mon Sep 17 00:00:00 2001 From: Gustavo Novaro Date: Thu, 15 Oct 2020 13:44:54 +0200 Subject: [PATCH 278/317] Improve README.md adding 2 more shields - Add minimum php version - Latest release --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 648d5ef003d..919fc62ae5b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ![Downloads per day](https://img.shields.io/sourceforge/dw/dolibarr.svg) ![Build status](https://img.shields.io/travis/Dolibarr/dolibarr/develop.svg) +[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%205.6-8892BF.svg?style=flat-square)](https://php.net/) +[![GitHub release](https://img.shields.io/github/v/release/Dolibarr/dolibarr)](https://github.com/Dolibarr/dolibarr) Dolibarr ERP & CRM is a modern software package that helps manage your organization's activity (contacts, suppliers, invoices, orders, stocks, agenda…). From 15dfcdb8e3e5f20468ca5dd3eb86b3db415799da Mon Sep 17 00:00:00 2001 From: jasson99 Date: Thu, 15 Oct 2020 17:22:47 +0545 Subject: [PATCH 279/317] window-size is kept fixed for acceptance tests run --- nightwatch.conf.js | 4 ++-- test/acceptance/setup.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nightwatch.conf.js b/nightwatch.conf.js index 24dfe971e32..eca78329a5a 100644 --- a/nightwatch.conf.js +++ b/nightwatch.conf.js @@ -18,9 +18,9 @@ module.exports = { browserName : 'chrome', javascriptEnabled : true, chromeOptions : { - args : ['disable-gpu'], + args : ['disable-gpu', 'window-size=1280,1024'], w3c : false - } + }, } } } diff --git a/test/acceptance/setup.js b/test/acceptance/setup.js index eeed97b3466..123d6b3c5ec 100644 --- a/test/acceptance/setup.js +++ b/test/acceptance/setup.js @@ -30,7 +30,7 @@ Before(async function getDolApiKey() { const params = new URLSearchParams() params.set('login', adminUsername) params.set('password', adminPassword) - const apiKey = `http://localhost/dolibarr/htdocs/api/index.php/login?${params.toString()}`; + const apiKey = client.globals.backend_url + `api/index.php/login?${params.toString()}`; header['Accept'] = 'application/json' await fetch(apiKey, { method: 'GET', @@ -74,4 +74,4 @@ After(async () => { }); } } -}); \ No newline at end of file +}); From 741700db7afc5a45073ef1bcabe33ef6511ff676 Mon Sep 17 00:00:00 2001 From: jasson99 Date: Thu, 15 Oct 2020 19:29:19 +0545 Subject: [PATCH 280/317] admin login stepdefinition moved from addUsersContext file to loginContext file --- nightwatch.conf.js | 2 +- test/acceptance/pageObjects/loginPage.js | 3 ++- test/acceptance/stepDefinitions/addUsersContext.js | 8 +------- test/acceptance/stepDefinitions/loginContext.js | 6 ++++++ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/nightwatch.conf.js b/nightwatch.conf.js index eca78329a5a..e72febea918 100644 --- a/nightwatch.conf.js +++ b/nightwatch.conf.js @@ -20,7 +20,7 @@ module.exports = { chromeOptions : { args : ['disable-gpu', 'window-size=1280,1024'], w3c : false - }, + } } } } diff --git a/test/acceptance/pageObjects/loginPage.js b/test/acceptance/pageObjects/loginPage.js index 75195cc3746..b95fd1645ab 100644 --- a/test/acceptance/pageObjects/loginPage.js +++ b/test/acceptance/pageObjects/loginPage.js @@ -26,7 +26,8 @@ module.exports = { }, userIsLoggedIn: async function (login) { - await this.useXpath() + await this.waitForElementNotPresent('@loginTable') + .useXpath() .waitForElementVisible('@userLogin') .expect.element('@userLogin') .text.to.equal(login); diff --git a/test/acceptance/stepDefinitions/addUsersContext.js b/test/acceptance/stepDefinitions/addUsersContext.js index 385f731b8f7..076c5d24226 100644 --- a/test/acceptance/stepDefinitions/addUsersContext.js +++ b/test/acceptance/stepDefinitions/addUsersContext.js @@ -5,12 +5,6 @@ const assert = require('assert'); let response; let Login = {}; -Given('the administrator has logged in using the webUI', async function () { - await client.page.loginPage().navigate().waitForLoginPage(); - await client.page.loginPage().userLogsInWithUsernameAndPassword(client.globals.adminUsername, client.globals.adminPassword); - return client.page.loginPage().userIsLoggedIn(client.globals.adminUsername); -}); - Given('the administrator has browsed to the new users page', function () { return client.page.homePage().browsedToNewUserPage(); }); @@ -153,4 +147,4 @@ const getResponseMessage = async function (expectedResponseMessage) { const actualResponseMessage = json_response['error']['0']; return assert.strictEqual(actualResponseMessage, expectedResponseMessage, `the expected response message was ${expectedResponseMessage} but got ${actualResponseMessage}`); -}; \ No newline at end of file +}; diff --git a/test/acceptance/stepDefinitions/loginContext.js b/test/acceptance/stepDefinitions/loginContext.js index 428fd7b5dc7..ea9aa07949b 100644 --- a/test/acceptance/stepDefinitions/loginContext.js +++ b/test/acceptance/stepDefinitions/loginContext.js @@ -1,6 +1,12 @@ const { Given, When, Then } = require('cucumber') const { client } = require('nightwatch-api') +Given('the administrator has logged in using the webUI', async function () { + await client.page.loginPage().navigate().waitForLoginPage(); + await client.page.loginPage().userLogsInWithUsernameAndPassword(client.globals.adminUsername, client.globals.adminPassword); + return client.page.loginPage().userIsLoggedIn(client.globals.adminUsername); +}); + Given('the user has browsed to the login page', function () { return client.page.loginPage().navigate(); }); From 5b37ff0bfdf796854eac92f73b89c1b85daa6c75 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 15 Oct 2020 19:36:08 +0200 Subject: [PATCH 281/317] Html entities use now HTML5. Enhance the Dolibarr WAF. More PHPUnit tests. --- htdocs/comm/mailing/class/mailing.class.php | 4 +- htdocs/core/actions_setnotes.inc.php | 4 +- htdocs/core/class/html.form.class.php | 1 + htdocs/core/lib/functions.lib.php | 50 +++++++++++++-------- htdocs/core/lib/functions2.lib.php | 2 +- htdocs/core/lib/pdf.lib.php | 2 +- htdocs/includes/odtphp/odf.php | 8 ++-- htdocs/main.inc.php | 10 +++-- htdocs/projet/class/project.class.php | 4 +- htdocs/projet/class/task.class.php | 4 +- htdocs/recruitment/recruitmentindex.php | 4 +- htdocs/ticket/card.php | 21 +++++++-- htdocs/ticket/class/ticket.class.php | 2 +- htdocs/user/card.php | 16 ++++--- htdocs/user/note.php | 2 +- test/phpunit/SecurityTest.php | 40 +++++++++++++++++ 16 files changed, 127 insertions(+), 47 deletions(-) diff --git a/htdocs/comm/mailing/class/mailing.class.php b/htdocs/comm/mailing/class/mailing.class.php index 704d0892ab5..a4088975bd2 100644 --- a/htdocs/comm/mailing/class/mailing.class.php +++ b/htdocs/comm/mailing/class/mailing.class.php @@ -224,8 +224,8 @@ class Mailing extends CommonObject $this->title = $obj->title; $this->sujet = $obj->sujet; - if (!empty($conf->global->FCKEDITOR_ENABLE_MAILING) && dol_textishtml(dol_html_entity_decode($obj->body, ENT_COMPAT | ENT_HTML401))) { - $this->body = dol_html_entity_decode($obj->body, ENT_COMPAT | ENT_HTML401); + if (!empty($conf->global->FCKEDITOR_ENABLE_MAILING) && dol_textishtml(dol_html_entity_decode($obj->body, ENT_COMPAT|ENT_HTML5))) { + $this->body = dol_html_entity_decode($obj->body, ENT_COMPAT|ENT_HTML5); } else { $this->body = $obj->body; } diff --git a/htdocs/core/actions_setnotes.inc.php b/htdocs/core/actions_setnotes.inc.php index 61db9b9fc55..f8d54f2b40b 100644 --- a/htdocs/core/actions_setnotes.inc.php +++ b/htdocs/core/actions_setnotes.inc.php @@ -33,7 +33,7 @@ if ($action == 'setnote_public' && !empty($permissionnote) && !GETPOST('cancel', if (empty($action) || !is_object($object) || empty($id)) dol_print_error('', 'Include of actions_setnotes.inc.php was done but required variable was not set before'); if (empty($object->id)) $object->fetch($id); // Fetch may not be already done - $result_update = $object->update_note(dol_html_entity_decode(GETPOST('note_public', 'restricthtml'), ENT_QUOTES, 'UTF-8', 1), '_public'); + $result_update = $object->update_note(dol_html_entity_decode(GETPOST('note_public', 'restricthtml'), ENT_QUOTES|ENT_HTML5, 'UTF-8', 1), '_public'); if ($result_update < 0) setEventMessages($object->error, $object->errors, 'errors'); elseif (in_array($object->table_element, array('supplier_proposal', 'propal', 'commande_fournisseur', 'commande', 'facture_fourn', 'facture'))) @@ -63,6 +63,6 @@ if ($action == 'setnote_public' && !empty($permissionnote) && !GETPOST('cancel', // Set public note if (empty($action) || !is_object($object) || empty($id)) dol_print_error('', 'Include of actions_setnotes.inc.php was done but required variable was not set before'); if (empty($object->id)) $object->fetch($id); // Fetch may not be already done - $result = $object->update_note(dol_html_entity_decode(GETPOST('note_private', 'restricthtml'), ENT_QUOTES), '_private'); + $result = $object->update_note(dol_html_entity_decode(GETPOST('note_private', 'restricthtml'), ENT_QUOTES|ENT_HTML5), '_private'); if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index e58ba5d5a8e..0ec7ee46733 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -264,6 +264,7 @@ class Form elseif (preg_match('/^(amount|numeric)/', $typeofdata)) $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : ''); elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) $ret .= dol_htmlentitiesbr($value); elseif (preg_match('/^safehtmlstring/', $typeofdata)) $ret .= dol_string_onlythesehtmltags($value); + elseif (preg_match('/^restricthtml/', $typeofdata)) $ret .= dol_string_onlythesehtmltags($value); elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') $ret .= dol_print_date($value, 'day'); elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') $ret .= dol_print_date($value, 'dayhour'); elseif (preg_match('/^select;/', $typeofdata)) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index c875ad32803..75ac46b6989 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -664,8 +664,7 @@ function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = } break; case 'restricthtml': // Recommended for most html textarea - $out = dol_string_onlythesehtmltags($out, 0); - // TODO We can also remove all javascripts reference + $out = dol_string_onlythesehtmltags($out, 0, 1, 1); break; case 'custom': if (empty($filter)) return 'BadFourthParameterForGETPOST'; @@ -1001,17 +1000,25 @@ function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '') /** - * Clean a string from all non printable ascii chars (0x00-0x1F and 0x7F). It removes also CR-LF + * Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F). It can also removes also Tab-CR-LF. UTF8 chars remains. * This can be used to sanitize a string and view its real content. Some hacks try to obfuscate attacks by inserting non printable chars. - * + * Note, for information: UTF8 on 1 byte are: \x00-\7F + * 2 bytes are: byte 1 \xc0-\xdf, byte 2 = \x80-\xbf + * 3 bytes are: byte 1 \xe0-\xef, byte 2 = \x80-\xbf, byte 3 = \x80-\xbf + * 4 bytes are: byte 1 \xf0-\xf7, byte 2 = \x80-\xbf, byte 3 = \x80-\xbf, byte 4 = \x80-\xbf * @param string $str String to clean + * @param int $removetabcrlf Remove also CR-LF * @return string Cleaned string * * @see dol_sanitizeFilename(), dol_string_unaccent(), dol_string_nospecial() */ -function dol_string_nounprintableascii($str) +function dol_string_nounprintableascii($str, $removetabcrlf = 1) { - return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); + if ($removetabcrlf) { + return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace + } else { + return preg_replace('/[\x00-\x08\x11-\x12\x14-\x1F\x7F]/u', '', $str); // /u operator should make UTF8 valid characters being ignored so are not included into the replace + } } @@ -5617,7 +5624,7 @@ function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = $temp = preg_replace('/]*>/i', "\n", $stringtoclean); // We remove entities BEFORE stripping (in case of a separator char is encoded and not the other, the strip will fails) - $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto); + $temp = dol_html_entity_decode($temp, ENT_COMPAT|ENT_HTML5, $pagecodeto); if ($strip_tags) { $temp = strip_tags($temp); @@ -5652,7 +5659,7 @@ function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = * * @see dol_escape_htmltag() strip_tags() dol_string_nohtmltag() dol_string_neverthesehtmltags() */ -function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1) +function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0) { $allowed_tags = array( "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li", "link", @@ -5662,22 +5669,29 @@ function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $allowed_tags_string = join("><", $allowed_tags); $allowed_tags_string = '<'.$allowed_tags_string.'>'; - if ($cleanalsosomestyles) { - $stringtoclean = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/i', '', $stringtoclean); // Note: If hacker try to introduce css comment into string to bypass this regex, the string must also be encoded by the dol_htmlentitiesbr during output so it become harmless - } - if ($removeclassattribute) { - $stringtoclean = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $stringtoclean); - } - // TODO Remove '/href=("|\'|)javascript/' string ? + $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0); + $stringtoclean = preg_replace('/:/i', ':', $stringtoclean); $temp = strip_tags($stringtoclean, $allowed_tags_string); + if ($cleanalsosomestyles) { // Clean for remaining html tags + $stringtoclean = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/i', '', $temp); // Note: If hacker try to introduce css comment into string to bypass this regex, the string must also be encoded by the dol_htmlentitiesbr during output so it become harmless + } + if ($removeclassattribute) { // Clean for remaining html tags + $stringtoclean = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp); + } + + // Remove 'javascript:' that we should not find into a text with + if ($cleanalsojavascript) { + $temp = preg_replace('/javascript\s*:/i', '', $temp); + } + return $temp; } /** * Clean a string from some undesirable HTML tags. - * Note. Not enough secured as dol_string_onlythesehtmltags(). + * Note. Not as secured as dol_string_onlythesehtmltags(). * * @param string $stringtoclean String to clean * @param array $disallowed_tags Array of tags not allowed @@ -5821,7 +5835,7 @@ function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UT */ function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8') { - $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT, $pagecodeto); + $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT|ENT_HTML5, $pagecodeto); $ret = preg_replace('/'."\r\n".'/i', "
    ", $ret); $ret = preg_replace('/'."\r\n".'/i', "\r\n", $ret); $ret = preg_replace('/'."\n".'/i', "\n", $ret); @@ -5845,7 +5859,7 @@ function dol_htmlcleanlastbr($stringtodecode) * Replace html_entity_decode functions to manage errors * * @param string $a Operand a - * @param string $b Operand b (ENT_QUOTES=convert simple and double quotes) + * @param string $b Operand b (ENT_QUOTES|ENT_HTML5=convert simple, double quotes, colon, e accent, ...) * @param string $c Operand c * @param string $keepsomeentities Entities but &, <, >, " are not converted. * @return string String decoded diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 94bf0dd06c4..0c06d845843 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -66,7 +66,7 @@ function jsUnEscape($source) $pos++; } } - return dol_html_entity_decode($decodedStr, ENT_COMPAT); + return dol_html_entity_decode($decodedStr, ENT_COMPAT|ENT_HTML5); } diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index bf957dc40a6..708b2a8c1ff 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -1260,7 +1260,7 @@ function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, // Manage HTML entities description test because $prodser->description is store with htmlentities but $desc no $textwasmodified = false; if (!empty($desc) && dol_textishtml($desc) && !empty($prodser->description) && dol_textishtml($prodser->description)) { - $textwasmodified = (strpos(dol_html_entity_decode($desc, ENT_QUOTES | ENT_HTML401), dol_html_entity_decode($prodser->description, ENT_QUOTES | ENT_HTML401)) !== false); + $textwasmodified = (strpos(dol_html_entity_decode($desc, ENT_QUOTES|ENT_HTML5), dol_html_entity_decode($prodser->description, ENT_QUOTES|ENT_HTML5)) !== false); } else { $textwasmodified = ($desc == $prodser->description); } diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index f6e15b2e8a2..5012337daf8 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -142,7 +142,7 @@ class Odf } $this->vars[$tag] = $this->convertVarToOdf($value, $encode, $charset); - + return $this; } @@ -171,9 +171,9 @@ class Odf '', '' ); - + $convertedValue = $this->_replaceHtmlWithOdtTag($this->_getDataFromHtml($value), $customStyles, $fontDeclarations); - + foreach ($customStyles as $key => $val) { array_push($automaticStyles, '' . $val . ''); } @@ -400,7 +400,7 @@ class Odf public function htmlToUTFAndPreOdf($value) { // We decode into utf8, entities - $value=dol_html_entity_decode($value, ENT_QUOTES); + $value=dol_html_entity_decode($value, ENT_QUOTES|ENT_HTML5); // We convert html tags $ishtml=dol_textishtml($value); diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 77303e11e32..3cfb5c3d1a5 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -58,12 +58,16 @@ if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO'])) */ function testSqlAndScriptInject($val, $type) { - $val = html_entity_decode($val, ENT_QUOTES); // So note_public = ''; } else { $this->db->begin(); - $res = $clone_project->update_note(dol_html_entity_decode($clone_project->note_public, ENT_QUOTES), '_public'); + $res = $clone_project->update_note(dol_html_entity_decode($clone_project->note_public, ENT_QUOTES|ENT_HTML5), '_public'); if ($res < 0) { $this->error .= $clone_project->error; @@ -1482,7 +1482,7 @@ class Project extends CommonObject } $this->db->begin(); - $res = $clone_project->update_note(dol_html_entity_decode($clone_project->note_private, ENT_QUOTES), '_private'); + $res = $clone_project->update_note(dol_html_entity_decode($clone_project->note_private, ENT_QUOTES|ENT_HTML5), '_private'); if ($res < 0) { $this->error .= $clone_project->error; diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 8020477702a..e6cabbf7347 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -1675,7 +1675,7 @@ class Task extends CommonObject $clone_task->note_public = ''; } else { $this->db->begin(); - $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_public, ENT_QUOTES), '_public'); + $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_public, ENT_QUOTES|ENT_HTML5), '_public'); if ($res < 0) { $this->error .= $clone_task->error; @@ -1686,7 +1686,7 @@ class Task extends CommonObject } $this->db->begin(); - $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_private, ENT_QUOTES), '_private'); + $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_private, ENT_QUOTES|ENT_HTML5), '_private'); if ($res < 0) { $this->error .= $clone_task->error; diff --git a/htdocs/recruitment/recruitmentindex.php b/htdocs/recruitment/recruitmentindex.php index 04d50c34eb8..b866112bce6 100644 --- a/htdocs/recruitment/recruitmentindex.php +++ b/htdocs/recruitment/recruitmentindex.php @@ -114,7 +114,7 @@ if ($conf->use_javascript_ajax) $listofstatus = array(0, 1, 3, 9); foreach ($listofstatus as $status) { - $dataseries[] = array(dol_html_entity_decode($staticrecruitmentjobposition->LibStatut($status, 1), ENT_QUOTES), (isset($vals[$status]) ? (int) $vals[$status] : 0)); + $dataseries[] = array(dol_html_entity_decode($staticrecruitmentjobposition->LibStatut($status, 1), ENT_QUOTES|ENT_HTML5), (isset($vals[$status]) ? (int) $vals[$status] : 0)); if ($status == RecruitmentJobPosition::STATUS_DRAFT) $colorseries[$status] = '-'.$badgeStatus0; if ($status == RecruitmentJobPosition::STATUS_VALIDATED) $colorseries[$status] = $badgeStatus4; if ($status == RecruitmentJobPosition::STATUS_RECRUITED) $colorseries[$status] = $badgeStatus6; @@ -190,7 +190,7 @@ if ($conf->use_javascript_ajax) $listofstatus = array(0, 1, 3, 5, 8, 9); foreach ($listofstatus as $status) { - $dataseries[] = array(dol_html_entity_decode($staticrecruitmentcandidature->LibStatut($status, 1), ENT_QUOTES), (isset($vals[$status]) ? (int) $vals[$status] : 0)); + $dataseries[] = array(dol_html_entity_decode($staticrecruitmentcandidature->LibStatut($status, 1), ENT_QUOTES|ENT_HTML5), (isset($vals[$status]) ? (int) $vals[$status] : 0)); if ($status == RecruitmentCandidature::STATUS_DRAFT) $colorseries[$status] = '-'.$badgeStatus0; if ($status == RecruitmentCandidature::STATUS_VALIDATED) $colorseries[$status] = $badgeStatus1; if ($status == RecruitmentCandidature::STATUS_CONTRACT_PROPOSED) $colorseries[$status] = $badgeStatus4; diff --git a/htdocs/ticket/card.php b/htdocs/ticket/card.php index e4474731829..1b23185a044 100644 --- a/htdocs/ticket/card.php +++ b/htdocs/ticket/card.php @@ -482,15 +482,18 @@ if (empty($reshook)) { } if ($action == 'setsubject' && empty($object->subject)) { - $mesg .= ($mesg ? '
    ' : '').$langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")); + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")), null, 'errors'); } - if (!$mesg) { + if (!$error) { if ($object->update($user) >= 0) { header("Location: ".$_SERVER['PHP_SELF']."?track_id=".$object->track_id); exit; + } else { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); } - $mesg = $object->error; } } } @@ -507,6 +510,9 @@ if (empty($reshook)) { $url = 'card.php?action=view&track_id='.$object->track_id; header("Location: ".$url); exit(); + } else { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); } } } @@ -543,6 +549,9 @@ if (empty($reshook)) { $log_action .= Diff::toString(Diff::compare(strip_tags($oldvalue_message), strip_tags($object->message))); setEventMessages($langs->trans('TicketMessageSuccesfullyUpdated'), null, 'mesgs'); + } else { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); } } @@ -560,6 +569,9 @@ if (empty($reshook)) { $url = 'card.php?action=view&track_id='.$object->track_id; header("Location: ".$url); exit(); + } else { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); } } } @@ -597,6 +609,9 @@ if (empty($reshook)) { $log_action = $langs->trans('TicketLogPropertyChanged', $oldvalue_label, $newvalue_label); setEventMessages($langs->trans('TicketUpdated'), null, 'mesgs'); + } else { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); } $action = 'view'; } diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index 04abd650032..e1b65dac26d 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -1487,7 +1487,7 @@ class Ticket extends CommonObject $message .= $langs->transnoentities('TicketNotificationRecipient').' : '.$recipient."\n"; $message .= "\n"; $message .= '* '.$langs->transnoentities('TicketNotificationLogMessage').' *'."\n"; - $message .= dol_html_entity_decode($log_message, ENT_QUOTES)."\n"; + $message .= dol_html_entity_decode($log_message, ENT_QUOTES|ENT_HTML5)."\n"; if ($info_sendto['source'] == 'internal') { $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$this->track_id; diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 35917eba093..fcd3a4d21b5 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1757,22 +1757,28 @@ if ($action == 'create' || $action == 'adduserldap') { print '
    '.$langs->trans("LinkToCompanyContact").''; + $s = ''; if (isset($object->socid) && $object->socid > 0) { $societe = new Societe($db); $societe->fetch($object->socid); - print $societe->getNomUrl(1, ''); + if ($societe->id > 0){ + $s .= $societe->getNomUrl(1, ''); + } } else { - print $langs->trans("ThisUserIsNot"); + $s .= $langs->trans("ThisUserIsNot"); } if (!empty($object->contact_id)) { $contact = new Contact($db); $contact->fetch($object->contact_id); - if ($object->socid > 0) print ' / '; - else print '
    '; - print $contact->getNomUrl(1, ''); + if ($contact->id > 0) { + if ($object->socid > 0 && $s) $s .= ' / '; + else $s .= '
    '; + $s .= $contact->getNomUrl(1, ''); + } } + print $s; print '
    <'.$key.'>'.$langs->trans($val).'{'.$key.'}'.$langs->trans($val).'
    '; diff --git a/htdocs/core/class/dolreceiptprinter.class.php b/htdocs/core/class/dolreceiptprinter.class.php index f8c33f9403a..6cab6580a5a 100644 --- a/htdocs/core/class/dolreceiptprinter.class.php +++ b/htdocs/core/class/dolreceiptprinter.class.php @@ -25,32 +25,32 @@ /* * Tags for ticket template * - * Left align text - * Center text - * Right align text - * Use font A of printer - * Use font B of printer - * Use font C of printer - * Text Bold - * Disable Text Bold - * Text double height - * Text double width - * Text default height and width - * Underline text - * Disable underline text - * Cut ticket completely - * Cut ticket partially - * Open cash drawer - * Activate buzzer - * Print barcode - * Print logo stored on printer. Example : 32|32 - * Print logo stored on printer. Must be followed by logo code. For old printers. - * Print object lines - * Print object total tax - * Print object local tax - * Print object total - * Print order lines for Printer - * Print payment method + * {dol_align_left} Left align text + * {dol_align_center} Center text + * {dol_align_right} Right align text + * {dol_use_font_a} Use font A of printer + * {dol_use_font_b} Use font B of printer + * {dol_use_font_c} Use font C of printer + * {dol_bold} Text Bold + * {dol_bold_disabled} Disable Text Bold + * {dol_double_height} Text double height + * {dol_double_width} Text double width + * {dol_default_height_width} Text default height and width + * {dol_underline} Underline text + * {dol_underline_disabled} Disable underline text + * {dol_cut_paper_full} Cut ticket completely + * {dol_cut_paper_partial} Cut ticket partially + * {dol_open_drawer} Open cash drawer + * {dol_beep} Activate buzzer + * {dol_print_barcode} Print barcode + * {dol_print_logo} Print logo stored on printer. Example : 32|32 + * {dol_print_logo_old} Print logo stored on printer. Must be followed by logo code. For old printers. + * {dol_print_object_lines} Print object lines + * {dol_print_object_tax} Print object total tax + * {dol_print_object_local_tax} Print object local tax + * {dol_print_object_total} Print object total + * {dol_print_order_lines} Print order lines for Printer + * {dol_print_payment} Print payment method * * Code which can be placed everywhere * Replaced by date AAAA-MM-DD @@ -569,45 +569,47 @@ class dolReceiptPrinter extends Printer $ret = $this->loadTemplate($templateid); // tags a remplacer par leur valeur avant de parser (dol_value_xxx) - $this->template = str_replace('', $object->id, $this->template); - $this->template = str_replace('', $object->ref, $this->template); + $this->template = str_replace('{dol_value_object_id}', $object->id, $this->template); + $this->template = str_replace('{dol_value_object_ref}', $object->ref, $this->template); //$this->template = str_replace('', $object->points, $this->template); - $this->template = str_replace('', dol_print_date($object->date, 'day'), $this->template); - $this->template = str_replace('', dol_print_date($object->date, 'dayhour'), $this->template); - $this->template = str_replace('', dol_print_date($object->date, '%Y'), $this->template); - $this->template = str_replace('', $langs->trans("Month".dol_print_date($object->date, '%m')), $this->template); - $this->template = str_replace('', dol_print_date($object->date, '%m'), $this->template); - $this->template = str_replace('', dol_print_date($object->date, '%d'), $this->template); - $this->template = str_replace('', $langs->trans("Day".dol_print_date($object->date, '%m')[1]), $this->template); + $this->template = str_replace('{dol_value_date}', dol_print_date($object->date, 'day'), $this->template); + $this->template = str_replace('{dol_value_date_time}', dol_print_date($object->date, 'dayhour'), $this->template); + $this->template = str_replace('{dol_value_year}', dol_print_date($object->date, '%Y'), $this->template); + $this->template = str_replace('{dol_value_month_letters}', $langs->trans("Month".dol_print_date($object->date, '%m')), $this->template); + $this->template = str_replace('{dol_value_month}', dol_print_date($object->date, '%m'), $this->template); + $this->template = str_replace('{dol_value_day}', dol_print_date($object->date, '%d'), $this->template); + $this->template = str_replace('{dol_value_day_letters}', $langs->trans("Day".dol_print_date($object->date, '%m')[1]), $this->template); - $this->template = str_replace('', $object->thirdparty->firstname, $this->template); - $this->template = str_replace('', $object->thirdparty->lastname, $this->template); - $this->template = str_replace('', $object->thirdparty->email, $this->template); - $this->template = str_replace('', $object->thirdparty->phone, $this->template); + $this->template = str_replace('{dol_value_customer_firstname}', $object->thirdparty->firstname, $this->template); + $this->template = str_replace('{dol_value_customer_lastname}', $object->thirdparty->lastname, $this->template); + $this->template = str_replace('{dol_value_customer_mail}', $object->thirdparty->email, $this->template); + $this->template = str_replace('{dol_value_customer_phone}', $object->thirdparty->phone, $this->template); //$this->template = str_replace('', $object->thirdparty->mobile, $this->template); - $this->template = str_replace('', $object->thirdparty->tva_intra, $this->template); + $this->template = str_replace('{dol_value_customer_tax_number}', $object->thirdparty->tva_intra, $this->template); //$this->template = str_replace('', $object->customer_account_balance, $this->template); //$this->template = str_replace('', $object->customer_points, $this->template); - $this->template = str_replace('', $mysoc->name, $this->template); - $this->template = str_replace('', $mysoc->address, $this->template); - $this->template = str_replace('', $mysoc->zip, $this->template); - $this->template = str_replace('', $mysoc->town, $this->template); - $this->template = str_replace('', $mysoc->country, $this->template); - $this->template = str_replace('', $mysoc->idprof1, $this->template); - $this->template = str_replace('', $mysoc->idprof2, $this->template); - $this->template = str_replace('', $mysoc->idprof3, $this->template); - $this->template = str_replace('', $mysoc->idprof4, $this->template); - $this->template = str_replace('', $mysoc->idprof5, $this->template); - $this->template = str_replace('', $mysoc->idprof6, $this->template); - $this->template = str_replace('', $mysoc->tva_intra, $this->template); - $this->template = str_replace('', $mysoc->capital, $this->template); + $this->template = str_replace('{dol_value_mysoc_name}', $mysoc->name, $this->template); + $this->template = str_replace('{dol_value_mysoc_address}', $mysoc->address, $this->template); + $this->template = str_replace('{dol_value_mysoc_zip}', $mysoc->zip, $this->template); + $this->template = str_replace('{dol_value_mysoc_town}', $mysoc->town, $this->template); + $this->template = str_replace('{dol_value_mysoc_country}', $mysoc->country, $this->template); + $this->template = str_replace('{dol_value_mysoc_idprof1}', $mysoc->idprof1, $this->template); + $this->template = str_replace('{dol_value_mysoc_idprof2}', $mysoc->idprof2, $this->template); + $this->template = str_replace('{dol_value_mysoc_idprof3}', $mysoc->idprof3, $this->template); + $this->template = str_replace('{dol_value_mysoc_idprof4}', $mysoc->idprof4, $this->template); + $this->template = str_replace('{dol_value_mysoc_idprof5}', $mysoc->idprof5, $this->template); + $this->template = str_replace('{dol_value_mysoc_idprof6}', $mysoc->idprof6, $this->template); + $this->template = str_replace('{dol_value_mysoc_tva_intra}', $mysoc->tva_intra, $this->template); + $this->template = str_replace('{dol_value_mysoc_capital}', $mysoc->capital, $this->template); - $this->template = str_replace('', $user->firstname, $this->template); - $this->template = str_replace('', $user->lastname, $this->template); - $this->template = str_replace('', $user->email, $this->template); + $this->template = str_replace('{dol_value_vendor_firstname}', $user->firstname, $this->template); + $this->template = str_replace('{dol_value_vendor_lastname}', $user->lastname, $this->template); + $this->template = str_replace('{dol_value_vendor_mail}', $user->email, $this->template); // parse template + $this->template = str_replace("{", "<", $this->template); + $this->template = str_replace("}", ">", $this->template); $p = xml_parser_create(); xml_parse_into_struct($p, $this->template, $vals, $index); xml_parser_free($p); diff --git a/htdocs/core/modules/modReceiptPrinter.class.php b/htdocs/core/modules/modReceiptPrinter.class.php index 818c090dcc0..32124dc8f5b 100644 --- a/htdocs/core/modules/modReceiptPrinter.class.php +++ b/htdocs/core/modules/modReceiptPrinter.class.php @@ -136,7 +136,7 @@ class modReceiptPrinter extends DolibarrModules // Clean before activation $this->remove($options); - $templateexample = '\r\n\r\n\r\n\r\n\r\nFacture \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n'; + $templateexample = '{dol_align_center}\r\n{dol_print_text}{dol_value_mysoc_name}\r\n{dol_print_text}{dol_value_mysoc_address}\r\n{dol_print_text}{dol_value_mysoc_zip}{dol_value_mysoc_town}\r\n{dol_line_feed}\r\n{dol_print_text}Facture {dol_value_object_ref}\r\n{dol_line_feed}\r\n{dol_align_left}\r\n{dol_print_object_lines}\r\n{dol_line_feed}\r\n{dol_print_object_tax}\r\n{dol_line_feed}\r\n{dol_print_object_total}\r\n{dol_line_feed}\r\n{dol_cut_paper_full}'; $sql = array( "CREATE TABLE IF NOT EXISTS ".MAIN_DB_PREFIX."printer_receipt (rowid integer AUTO_INCREMENT PRIMARY KEY, name varchar(128), fk_type integer, fk_profile integer, parameter varchar(128), entity integer) ENGINE=innodb;", "CREATE TABLE IF NOT EXISTS ".MAIN_DB_PREFIX."printer_receipt_template (rowid integer AUTO_INCREMENT PRIMARY KEY, name varchar(128), template text, entity integer) ENGINE=innodb;", From 5905d3be64b6c126fc103f2f391c69aa51092258 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 16 Oct 2020 00:06:26 +0200 Subject: [PATCH 287/317] Fix phpcs --- htdocs/core/class/html.formother.class.php | 2 +- htdocs/core/lib/functions.lib.php | 5 +++-- htdocs/loan/class/paymentloan.class.php | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index 987630e3660..5d3bd181753 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -763,7 +763,7 @@ class FormOther }, function(color, context) { console.log("close"); }, function(color, context) { var hex = color.val(\'hex\'); console.log("new color selected in jpicker "+hex);'; - if ($setpropertyonselect) { $out .= ' if (hex != null) document.documentElement.style.setProperty(\'--'.$setpropertyonselect.'\', \'#\'+hex);'; } + if ($setpropertyonselect) { $out .= ' if (hex != null) document.documentElement.style.setProperty(\'--'.$setpropertyonselect.'\', \'#\'+hex);'; } $out .= '}, function(color, context) { console.log("cancel"); } ); diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 75ac46b6989..e3ebd7b3087 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -5653,8 +5653,9 @@ function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = * Clean a string to keep only desirable HTML tags. * * @param string $stringtoclean String to clean - * @param boolean $cleanalsosomestyles Remove absolute/fixed positioning from inline styles - * @param boolean $removeclassattribute Remove the class attribute from tags + * @param int $cleanalsosomestyles Remove absolute/fixed positioning from inline styles + * @param int $removeclassattribute Remove the class attribute from tags + * @param int $cleanalsojavascript Remove also occurence of (javascript:' * @return string String cleaned * * @see dol_escape_htmltag() strip_tags() dol_string_nohtmltag() dol_string_neverthesehtmltags() diff --git a/htdocs/loan/class/paymentloan.class.php b/htdocs/loan/class/paymentloan.class.php index 508d1044d85..dc6d72094b2 100644 --- a/htdocs/loan/class/paymentloan.class.php +++ b/htdocs/loan/class/paymentloan.class.php @@ -428,6 +428,7 @@ class PaymentLoan extends CommonObject return $this->LibStatut($this->statut, $mode); } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Renvoi le libelle d'un statut donne * @@ -437,7 +438,7 @@ class PaymentLoan extends CommonObject */ public function LibStatut($status, $mode = 0) { - // + // phpcs:enable return ''; } From 7a7e1ad7cfe6a1a6119db7a3dff6a1486221accb Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 16 Oct 2020 00:29:35 +0200 Subject: [PATCH 288/317] CSS --- htdocs/takepos/css/pos.css.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/takepos/css/pos.css.php b/htdocs/takepos/css/pos.css.php index 973bbabba2d..b9db20ab516 100644 --- a/htdocs/takepos/css/pos.css.php +++ b/htdocs/takepos/css/pos.css.php @@ -479,8 +479,7 @@ div.description_content { width: unset; } .topnav{ - background: rgb(); - background-image: linear-gradient(-45deg, , rgb()); + background: var(--colorbackhmenu1); overflow: hidden; height: 100%; } From 67cf917f7b144e525df720b33e57ed77616d023a Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Fri, 16 Oct 2020 11:57:36 +0200 Subject: [PATCH 289/317] FIX Binding on expense report (Double rowid) --- htdocs/accountancy/expensereport/lines.php | 4 ++-- htdocs/accountancy/expensereport/list.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/accountancy/expensereport/lines.php b/htdocs/accountancy/expensereport/lines.php index f99f1148044..a6cf6f2fc14 100644 --- a/htdocs/accountancy/expensereport/lines.php +++ b/htdocs/accountancy/expensereport/lines.php @@ -166,7 +166,7 @@ print ''; + $out .= ''; $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter); - $out .= ' '; + $out .= ' '; $out .= '
    '; } diff --git a/htdocs/core/js/lib_notification.js.php b/htdocs/core/js/lib_notification.js.php index a95e3556405..8ecca4da2df 100644 --- a/htdocs/core/js/lib_notification.js.php +++ b/htdocs/core/js/lib_notification.js.php @@ -77,10 +77,10 @@ if (!($_SERVER['HTTP_REFERER'] === $dolibarr_main_url_root.'/' || $_SERVER['HTTP data: { time_js_next_test: time_js_next_test, forcechecknow: 1, token: 'notrequired' }, dataType: "json", success: function (result) { - console.log(result); + //console.log(result); var arrayofpastreminders = Object.values(result.pastreminders); - console.log("arrayofpastreminders.length"+arrayofpastreminders.length); if (arrayofpastreminders && arrayofpastreminders.length > 0) { + console.log("Retreived "+arrayofpastreminders.length+" reminders to do."); var audio = null; global->AGENDA_REMINDER_BROWSER_SOUND)) { @@ -145,7 +145,7 @@ if (!($_SERVER['HTTP_REFERER'] === $dolibarr_main_url_root.'/' || $_SERVER['HTTP data: { time_js_next_test: time_js_next_test, token: 'notrequired' } }); } else { - console.log("No past reminder found, next try at "+time_js_next_test); + console.log("No reminder to do found, next search at "+time_js_next_test); } } }); diff --git a/htdocs/langs/en_US/agenda.lang b/htdocs/langs/en_US/agenda.lang index 4ab87aa8420..479155fb2a9 100644 --- a/htdocs/langs/en_US/agenda.lang +++ b/htdocs/langs/en_US/agenda.lang @@ -166,5 +166,4 @@ TimeType=Duration type ReminderType=Callback type AddReminder=Create an automatic reminder notification for this event ErrorReminderActionCommCreation=Error creating the reminder notification for this event -BrowserPush=Browser Notification -EventReminder=Event Reminder \ No newline at end of file +BrowserPush=Browser Notification \ No newline at end of file diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index c28280c8330..1096b9857f1 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -1099,3 +1099,4 @@ DateOfBirth=Date of birth SecurityTokenHasExpiredSoActionHasBeenCanceledPleaseRetry=Security token has expired, so action has been canceled. Please try again. UpToDate=Up-to-date OutOfDate=Out-of-date +EventReminder=Event Reminder \ No newline at end of file From 4ec4801c77d79be71b7e9a486272c2b2496a14f8 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 20 Oct 2020 15:54:08 +0200 Subject: [PATCH 313/317] FIX Only template of enabled modules visible --- htdocs/admin/mails_templates.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index 9ff86260c4b..b9281765771 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -429,7 +429,7 @@ if ($action == 'delete') } -$sql = "SELECT rowid as rowid, label, type_template, lang, fk_user, private, position, topic, joinfiles, content_lines, content, enabled, active"; +$sql = "SELECT rowid as rowid, module, label, type_template, lang, fk_user, private, position, topic, joinfiles, content_lines, content, enabled, active"; $sql .= " FROM ".MAIN_DB_PREFIX."c_email_templates"; $sql .= " WHERE entity IN (".getEntity('email_template').")"; if (!$user->admin) @@ -779,6 +779,13 @@ if ($resql) print "\n"; } else { + if ($obj->module) { + $tempmodulekey = $obj->module; + if (empty($conf->$tempmodulekey) || empty($conf->$tempmodulekey->enabled)) { + $i++; + continue; + } + } $keyforobj = 'type_template'; if (!in_array($obj->$keyforobj, array_keys($elementList))) { From 2a31d4393813bca71ead9fe47d74deb40af1f0cc Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 20 Oct 2020 18:41:26 +0200 Subject: [PATCH 314/317] FIX Show errors in session on login page --- htdocs/core/lib/security2.lib.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/core/lib/security2.lib.php b/htdocs/core/lib/security2.lib.php index 6f206832e2d..60b01b567f4 100644 --- a/htdocs/core/lib/security2.lib.php +++ b/htdocs/core/lib/security2.lib.php @@ -290,6 +290,8 @@ if (!function_exists('dol_loginfunction')) // Include login page template include $template_dir.'login.tpl.php'; + // Global html output events ($mesgs, $errors, $warnings) + dol_htmloutput_events(0); $_SESSION["dol_loginmesg"] = ''; } From a729bff0621ec64d2b330c1ede40bfc1ee851c6c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 21 Oct 2020 11:54:18 +0200 Subject: [PATCH 315/317] Fix trans --- htdocs/langs/en_US/admin.lang | 2 +- htdocs/langs/en_US/mails.lang | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 7a4aee9856a..e47390b9ce0 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -480,7 +480,7 @@ ModuleCompanyCodeSupplierDigitaria=%s followed by the truncated supplier name by Use3StepsApproval=By default, Purchase Orders need to be created and approved by 2 different users (one step/user to create and one step/user to approve. Note that if user has both permission to create and approve, one step/user will be enough). You can ask with this option to introduce a third step/user approval, if amount is higher than a dedicated value (so 3 steps will be necessary: 1=validation, 2=first approval and 3=second approval if amount is enough).
    Set this to empty if one approval (2 steps) is enough, set it to a very low value (0.1) if a second approval (3 steps) is always required. UseDoubleApproval=Use a 3 steps approval when amount (without tax) is higher than... WarningPHPMail=WARNING: The setup to send emails from the application is using the default generic setup. It is often better to setup outgoing emails to use the email server of your Email Service Provider instead of the default setup for several reasons: -WarningPHPMailA=- Using the server of the Email Service Provider increase the trustability of your email, so it increase the deliverablity without being flagging as SPAM +WarningPHPMailA=- Using the server of the Email Service Provider increases the trustability of your email, so it increases the deliverablity without being flagged as SPAM WarningPHPMailB=- Some Email Service Providers (like Yahoo) do not allow you to send an email from another server than their own server. Your current setup uses the server of the application to send email and not the server of your email provider, so some recipients (the one compatible with the restrictive DMARC protocol), will ask your email provider if they can accept your email and some email providers (like Yahoo) may respond "no" because the server is not theirs, so few of your sent Emails may not be accepted for delivery (be careful also of your email provider's sending quota). WarningPHPMailC=- Using the SMTP server of your own Email Service Provider to send emails is also interesting so all emails sent from application will also be saved into your "Sent" directory of your mailbox. WarningPHPMailD=If the method 'PHP Mail' is really the method you would like to use, you can remove this warning by adding the constant MAIN_HIDE_WARNING_TO_ENCOURAGE_SMTP_SETUP to 1 in Home - Setup - Other. diff --git a/htdocs/langs/en_US/mails.lang b/htdocs/langs/en_US/mails.lang index 7e34db3d8b8..a7223605ff0 100644 --- a/htdocs/langs/en_US/mails.lang +++ b/htdocs/langs/en_US/mails.lang @@ -163,9 +163,9 @@ AdvTgtCreateFilter=Create filter AdvTgtOrCreateNewFilter=Name of new filter NoContactWithCategoryFound=No contact/address with a category found NoContactLinkedToThirdpartieWithCategoryFound=No contact/address with a category found -OutGoingEmailSetup=Outgoing email setup -InGoingEmailSetup=Incoming email setup -OutGoingEmailSetupForEmailing=Outgoing email setup (for module %s) +OutGoingEmailSetup=Outgoing emails +InGoingEmailSetup=Incoming emails +OutGoingEmailSetupForEmailing=Outgoing emails (for module %s) DefaultOutgoingEmailSetup=Same configuration than the global Outgoing email setup Information=Information ContactsWithThirdpartyFilter=Contacts with third-party filter From 9b423106dc3ea875b67c07cbd8ff9f2423340556 Mon Sep 17 00:00:00 2001 From: lvessiller Date: Wed, 21 Oct 2020 16:10:48 +0200 Subject: [PATCH 316/317] NEW add margin info in invoice list --- htdocs/compta/facture/list.php | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 9a871514215..4f795274ad2 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -39,6 +39,9 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +if (!empty($conf->margin->enabled)) { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; +} require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php'; require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; @@ -203,6 +206,10 @@ $arrayfields = array( 'f.multicurrency_total_ttc'=>array('label'=>'MulticurrencyAmountTTC', 'checked'=>0, 'enabled'=>(empty($conf->multicurrency->enabled) ? 0 : 1), 'position'=>200), 'multicurrency_dynamount_payed'=>array('label'=>'MulticurrencyAlreadyPaid', 'checked'=>0, 'enabled'=>(empty($conf->multicurrency->enabled) ? 0 : 1), 'position'=>210), 'multicurrency_rtp'=>array('label'=>'MulticurrencyRemainderToPay', 'checked'=>0, 'enabled'=>(empty($conf->multicurrency->enabled) ? 0 : 1), 'position'=>220), // Not enabled by default because slow + 'total_pa' => array('label' => ($conf->global->MARGIN_TYPE == '1' ? 'BuyingPrice' : 'CostPrice'), 'checked' => 0, 'position' => 300, 'enabled' => (empty($conf->margin->enabled)?0:1)), + 'total_margin' => array('label' => 'Margin', 'checked' => 0, 'position' => 301, 'enabled' => (empty($conf->margin->enabled)?0:1)), + 'total_margin_rate' => array('label' => 'MarginRate', 'checked' => 0, 'position' => 302, 'enabled' => (empty($conf->margin->enabled) || empty($conf->global->DISPLAY_MARGIN_RATES)?0:1)), + 'total_mark_rate' => array('label' => 'MarkRate', 'checked' => 0, 'position' => 303, 'enabled' => (empty($conf->margin->enabled) || empty($conf->global->DISPLAY_MARK_RATES)?0:1)), 'f.datec'=>array('label'=>"DateCreation", 'checked'=>0, 'position'=>500), 'f.tms'=>array('label'=>"DateModificationShort", 'checked'=>0, 'position'=>500), 'f.note_public'=>array('label'=>'NotePublic', 'checked'=>0, 'position'=>510, 'enabled'=>(empty($conf->global->MAIN_LIST_ALLOW_PUBLIC_NOTES))), @@ -405,6 +412,10 @@ if ($massaction == 'makepayment'){ $form = new Form($db); $formother = new FormOther($db); $formfile = new FormFile($db); +$formmargin = null; +if (!empty($conf->margin->enabled)) { + $formmargin = new FormMargin($db); +} $bankaccountstatic = new Account($db); $facturestatic = new Facture($db); $formcompany = new FormCompany($db); @@ -1019,6 +1030,26 @@ if ($resql) print ''; print ''; } + if (!empty($arrayfields['total_pa']['checked'])) + { + print ''; + print ''; + } + if (!empty($arrayfields['total_margin']['checked'])) + { + print ''; + print ''; + } + if (!empty($arrayfields['total_margin_rate']['checked'])) + { + print ''; + print ''; + } + if (!empty($arrayfields['total_mark_rate']['checked'])) + { + print ''; + print ''; + } // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; @@ -1102,6 +1133,10 @@ if ($resql) if (!empty($arrayfields['f.multicurrency_total_ttc']['checked'])) print_liste_field_titre($arrayfields['f.multicurrency_total_ttc']['label'], $_SERVER['PHP_SELF'], 'f.multicurrency_total_ttc', '', $param, 'class="right"', $sortfield, $sortorder); if (!empty($arrayfields['multicurrency_dynamount_payed']['checked'])) print_liste_field_titre($arrayfields['multicurrency_dynamount_payed']['label'], $_SERVER['PHP_SELF'], '', '', $param, 'class="right"', $sortfield, $sortorder); if (!empty($arrayfields['multicurrency_rtp']['checked'])) print_liste_field_titre($arrayfields['multicurrency_rtp']['label'], $_SERVER['PHP_SELF'], '', '', $param, 'class="right"', $sortfield, $sortorder); + if (!empty($arrayfields['total_pa']['checked'])) print_liste_field_titre($arrayfields['total_pa']['label'], $_SERVER['PHP_SELF'], '', '', $param, 'class="right"', $sortfield, $sortorder); + if (!empty($arrayfields['total_margin']['checked'])) print_liste_field_titre($arrayfields['total_margin']['label'], $_SERVER['PHP_SELF'], '', '', $param, 'class="right"', $sortfield, $sortorder); + if (!empty($arrayfields['total_margin_rate']['checked'])) print_liste_field_titre($arrayfields['total_margin_rate']['label'], $_SERVER['PHP_SELF'], '', '', $param, 'class="right"', $sortfield, $sortorder); + if (!empty($arrayfields['total_mark_rate']['checked'])) print_liste_field_titre($arrayfields['total_mark_rate']['label'], $_SERVER['PHP_SELF'], '', '', $param, 'class="right"', $sortfield, $sortorder); // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; // Hook fields @@ -1205,6 +1240,12 @@ if ($resql) $facturestatic->alreadypaid = $paiement; + $marginInfo = array(); + if (!empty($conf->margin->enabled)) { + $facturestatic->fetch_lines(); + $marginInfo = $formmargin->getMarginInfosArray($facturestatic); + } + print '' . price($marginInfo['pa_total']) . ''; + if (!$i) $totalarray['nbfield']++; + } + // Total margin + if (!empty($arrayfields['total_margin']['checked'])) + { + print '' . price($marginInfo['total_margin']) . ''; + if (!$i) $totalarray['nbfield']++; + } + // Total margin rate + if (!empty($arrayfields['total_margin_rate']['checked'])) + { + print '' . (($marginInfo['total_margin_rate'] == '')?'':price($marginInfo['total_margin_rate'], null, null, null, null, 2).'%') . ''; + if (!$i) $totalarray['nbfield']++; + } + // total mark rate + if (!empty($arrayfields['total_mark_rate']['checked'])) + { + print '' . (($marginInfo['total_mark_rate'] == '')?'':price($marginInfo['total_mark_rate'], null, null, null, null, 2).'%') . ''; + if (!$i) $totalarray['nbfield']++; + } + // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; // Fields from hook From 672797aa65ef613c879453085d7faa1c550e90f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 21 Oct 2020 17:09:40 +0200 Subject: [PATCH 317/317] add missing parameter --- htdocs/document.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/document.php b/htdocs/document.php index bc0cc1eb933..a608dfe820e 100644 --- a/htdocs/document.php +++ b/htdocs/document.php @@ -173,7 +173,7 @@ $refname = basename(dirname($original_file)."/"); if (empty($modulepart)) accessforbidden('Bad value for parameter modulepart'); // Check security and set return info with full path of file -$check_access = dol_check_secure_access_document($modulepart, $original_file, $entity, $refname); +$check_access = dol_check_secure_access_document($modulepart, $original_file, $entity, $user, $refname); $accessallowed = $check_access['accessallowed']; $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals']; $fullpath_original_file = $check_access['original_file']; // $fullpath_original_file is now a full path name