bonprelevement.class.php 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571
  1. <?php
  2. /* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
  4. * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
  5. * Copyright (C) 2010-2014 Laurent Destailleur <eldy@users.sourceforge.net>
  6. * Copyright (C) 2014-2016 Ferran Marcet <fmarcet@2byte.es>
  7. * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
  8. * Copyright (C) 2019 JC Prieto <jcprieto@virtual20.com><prietojc@gmail.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  22. */
  23. /**
  24. * \file htdocs/compta/prelevement/class/bonprelevement.class.php
  25. * \ingroup prelevement
  26. * \brief File of withdrawal receipts class
  27. */
  28. require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
  29. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  30. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
  31. require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
  32. require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
  33. require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
  34. require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
  35. /**
  36. * Class to manage withdrawal receipts
  37. */
  38. class BonPrelevement extends CommonObject
  39. {
  40. /**
  41. * @var string ID to identify managed object
  42. */
  43. public $element = 'widthdraw';
  44. /**
  45. * @var string Name of table without prefix where object is stored
  46. */
  47. public $table_element = 'prelevement_bons';
  48. /**
  49. * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
  50. */
  51. public $picto = 'payment';
  52. public $date_echeance;
  53. public $raison_sociale;
  54. public $reference_remise;
  55. public $emetteur_code_guichet;
  56. public $emetteur_numero_compte;
  57. public $emetteur_code_banque;
  58. public $emetteur_number_key;
  59. public $sepa_xml_pti_in_ctti;
  60. public $emetteur_iban;
  61. public $emetteur_bic;
  62. public $emetteur_ics;
  63. public $user_trans;
  64. public $user_credit;
  65. public $total;
  66. public $fetched;
  67. public $labelStatus = array();
  68. public $factures = array();
  69. public $invoice_in_error = array();
  70. public $thirdparty_in_error = array();
  71. /**
  72. * @var resource Handler of the file for direct debit or credit transfer order
  73. */
  74. public $file;
  75. const STATUS_DRAFT = 0;
  76. const STATUS_TRANSFERED = 1;
  77. const STATUS_CREDITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
  78. const STATUS_DEBITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
  79. /**
  80. * 'type' field format:
  81. * 'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',
  82. * 'select' (list of values are in 'options'),
  83. * 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:Sortfield]]]]',
  84. * 'chkbxlst:...',
  85. * 'varchar(x)',
  86. * 'text', 'text:none', 'html',
  87. * 'double(24,8)', 'real', 'price',
  88. * 'date', 'datetime', 'timestamp', 'duration',
  89. * 'boolean', 'checkbox', 'radio', 'array',
  90. * 'mail', 'phone', 'url', 'password', 'ip'
  91. * Note: Filter must be a Dolibarr filter syntax string. Example: "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.status:!=:0) or (t.nature:is:NULL)"
  92. * 'label' the translation key.
  93. * 'picto' is code of a picto to show before value in forms
  94. * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM' or 'isModEnabled("multicurrency")' ...)
  95. * 'position' is the sort order of field.
  96. * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
  97. * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
  98. * 'noteditable' says if field is not editable (1 or 0)
  99. * 'alwayseditable' says if field can be modified also when status is not draft ('1' or '0')
  100. * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
  101. * 'index' if we want an index in database.
  102. * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
  103. * 'searchall' is 1 if we want to search in this field when making a search from the quick search button.
  104. * 'isameasure' must be set to 1 or 2 if field can be used for measure. Field type must be summable like integer or double(24,8). Use 1 in most cases, or 2 if you don't want to see the column total into list (for example for percentage)
  105. * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200'
  106. * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
  107. * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record
  108. * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
  109. * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar'
  110. * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
  111. * 'comment' is not used. You can store here any text of your choice. It is not used by application.
  112. * 'validate' is 1 if need to validate with $this->validateField()
  113. * 'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value)
  114. *
  115. * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
  116. */
  117. // BEGIN MODULEBUILDER PROPERTIES
  118. /**
  119. * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
  120. */
  121. public $fields=array(
  122. 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>0,),
  123. 'ref' => array('type'=>'varchar(12)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>15, 'notnull'=>0, 'visible'=>-1, 'csslist'=>'tdoverflowmax150', 'showoncombobox'=>'1',),
  124. 'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>25, 'notnull'=>0, 'visible'=>-1,),
  125. 'amount' => array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>'1', 'position'=>30, 'notnull'=>0, 'visible'=>-1,),
  126. 'statut' => array('type'=>'smallint(6)', 'label'=>'Statut', 'enabled'=>'1', 'position'=>500, 'notnull'=>0, 'visible'=>-1, 'arrayofkeyval'=>array(0=>'Wait', 1=>'Transfered', 2=>'Credited')),
  127. 'credite' => array('type'=>'smallint(6)', 'label'=>'Credite', 'enabled'=>'1', 'position'=>40, 'notnull'=>0, 'visible'=>-1,),
  128. 'note' => array('type'=>'text', 'label'=>'Note', 'enabled'=>'1', 'position'=>45, 'notnull'=>0, 'visible'=>-1,),
  129. 'date_trans' => array('type'=>'datetime', 'label'=>'Datetrans', 'enabled'=>'1', 'position'=>50, 'notnull'=>0, 'visible'=>-1,),
  130. 'method_trans' => array('type'=>'smallint(6)', 'label'=>'Methodtrans', 'enabled'=>'1', 'position'=>55, 'notnull'=>0, 'visible'=>-1,),
  131. 'fk_user_trans' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fkusertrans', 'enabled'=>'1', 'position'=>60, 'notnull'=>0, 'visible'=>-1, 'css'=>'maxwidth500 widthcentpercentminusxx', 'csslist'=>'tdoverflowmax150',),
  132. 'date_credit' => array('type'=>'datetime', 'label'=>'Datecredit', 'enabled'=>'1', 'position'=>65, 'notnull'=>0, 'visible'=>-1,),
  133. 'fk_user_credit' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fkusercredit', 'enabled'=>'1', 'position'=>70, 'notnull'=>0, 'visible'=>-1, 'css'=>'maxwidth500 widthcentpercentminusxx', 'csslist'=>'tdoverflowmax150',),
  134. 'type' => array('type'=>'varchar(16)', 'label'=>'Type', 'enabled'=>'1', 'position'=>75, 'notnull'=>0, 'visible'=>-1,),
  135. 'fk_bank_account' => array('type'=>'integer', 'label'=>'Fkbankaccount', 'enabled'=>'1', 'position'=>80, 'notnull'=>0, 'visible'=>-1, 'css'=>'maxwidth500 widthcentpercentminusxx',),
  136. );
  137. public $rowid;
  138. public $ref;
  139. public $datec;
  140. public $amount;
  141. public $statut;
  142. public $credite;
  143. public $note;
  144. public $date_trans;
  145. public $method_trans;
  146. public $fk_user_trans;
  147. public $date_credit;
  148. public $fk_user_credit;
  149. public $type;
  150. public $fk_bank_account;
  151. // END MODULEBUILDER PROPERTIES
  152. /**
  153. * Constructor
  154. *
  155. * @param DoliDB $db Database handler
  156. */
  157. public function __construct($db)
  158. {
  159. global $conf, $langs;
  160. $this->db = $db;
  161. $this->filename = '';
  162. $this->date_echeance = dol_now();
  163. $this->raison_sociale = "";
  164. $this->reference_remise = "";
  165. $this->emetteur_code_guichet = "";
  166. $this->emetteur_numero_compte = "";
  167. $this->emetteur_code_banque = "";
  168. $this->emetteur_number_key = "";
  169. $this->sepa_xml_pti_in_ctti = false;
  170. $this->emetteur_iban = "";
  171. $this->emetteur_bic = "";
  172. $this->emetteur_ics = "";
  173. $this->factures = array();
  174. $this->methodes_trans = array(0 => 'Internet', 2 => 'Email', 3 => 'Api');
  175. $this->fetched = 0;
  176. }
  177. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  178. /**
  179. * Add invoice to withdrawal
  180. *
  181. * @param int $invoice_id id invoice to add
  182. * @param int $client_id id invoice customer
  183. * @param string $client_nom customer name
  184. * @param int $amount amount of invoice
  185. * @param string $code_banque code of bank withdrawal
  186. * @param string $code_guichet code of bank's office
  187. * @param string $number bank account number
  188. * @param string $number_key number key of account number
  189. * @param string $type 'debit-order' or 'bank-transfer'
  190. * @return int >0 if OK, <0 if KO
  191. */
  192. public function AddFacture($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type = 'debit-order')
  193. {
  194. // phpcs:enable
  195. $result = 0;
  196. $line_id = 0;
  197. // Add lines
  198. $result = $this->addline($line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key);
  199. if ($result == 0) {
  200. if ($line_id > 0) {
  201. $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement (";
  202. if ($type != 'bank-transfer') {
  203. $sql .= "fk_facture";
  204. } else {
  205. $sql .= "fk_facture_fourn";
  206. }
  207. $sql .= ",fk_prelevement_lignes";
  208. $sql .= ") VALUES (";
  209. $sql .= ((int) $invoice_id);
  210. $sql .= ", ".((int) $line_id);
  211. $sql .= ")";
  212. if ($this->db->query($sql)) {
  213. $result = 0;
  214. } else {
  215. $result = -1;
  216. $this->errors[] = get_class($this)."::AddFacture ".$this->db->lasterror;
  217. dol_syslog(get_class($this)."::AddFacture Error $result");
  218. }
  219. } else {
  220. $result = -2;
  221. $this->errors[] = get_class($this)."::AddFacture linedid Empty";
  222. dol_syslog(get_class($this)."::AddFacture Error $result");
  223. }
  224. } else {
  225. $result = -3;
  226. dol_syslog(get_class($this)."::AddFacture Error $result");
  227. }
  228. return $result;
  229. }
  230. /**
  231. * Add line to withdrawal
  232. *
  233. * @param int $line_id id line to add
  234. * @param int $client_id id invoice customer
  235. * @param string $client_nom customer name
  236. * @param int $amount amount of invoice
  237. * @param string $code_banque code of bank withdrawal
  238. * @param string $code_guichet code of bank's office
  239. * @param string $number bank account number
  240. * @param string $number_key number key of account number
  241. * @return int >0 if OK, <0 if KO
  242. */
  243. public function addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key)
  244. {
  245. $result = -1;
  246. $concat = 0;
  247. if ($concat == 1) {
  248. /*
  249. * We aggregate the lines
  250. */
  251. $sql = "SELECT rowid";
  252. $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_lignes";
  253. $sql .= " WHERE fk_prelevement_bons = ".((int) $this->id);
  254. $sql .= " AND fk_soc =".((int) $client_id);
  255. $sql .= " AND code_banque = '".$this->db->escape($code_banque)."'";
  256. $sql .= " AND code_guichet = '".$this->db->escape($code_guichet)."'";
  257. $sql .= " AND number = '".$this->db->escape($number)."'";
  258. $resql = $this->db->query($sql);
  259. if ($resql) {
  260. $num = $this->db->num_rows($resql);
  261. } else {
  262. $result = -1;
  263. }
  264. } else {
  265. /*
  266. * No aggregate
  267. */
  268. $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_lignes (";
  269. $sql .= "fk_prelevement_bons";
  270. $sql .= ", fk_soc";
  271. $sql .= ", client_nom";
  272. $sql .= ", amount";
  273. $sql .= ", code_banque";
  274. $sql .= ", code_guichet";
  275. $sql .= ", number";
  276. $sql .= ", cle_rib";
  277. $sql .= ") VALUES (";
  278. $sql .= $this->id;
  279. $sql .= ", ".((int) $client_id);
  280. $sql .= ", '".$this->db->escape($client_nom)."'";
  281. $sql .= ", ".((float) price2num($amount));
  282. $sql .= ", '".$this->db->escape($code_banque)."'";
  283. $sql .= ", '".$this->db->escape($code_guichet)."'";
  284. $sql .= ", '".$this->db->escape($number)."'";
  285. $sql .= ", '".$this->db->escape($number_key)."'";
  286. $sql .= ")";
  287. if ($this->db->query($sql)) {
  288. $line_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevement_lignes");
  289. $result = 0;
  290. } else {
  291. $this->errors[] = get_class($this)."::addline Error -2 ".$this->db->lasterror;
  292. dol_syslog(get_class($this)."::addline Error -2");
  293. $result = -2;
  294. }
  295. }
  296. return $result;
  297. }
  298. /**
  299. * Return error string
  300. *
  301. * @param int $error Id of error
  302. * @return string Error string
  303. */
  304. public function getErrorString($error)
  305. {
  306. global $langs;
  307. $errors = array();
  308. $errors[1027] = $langs->trans("DateInvalid");
  309. return $errors[abs($error)];
  310. }
  311. /**
  312. * Get object and lines from database
  313. *
  314. * @param int $rowid Id of object to load
  315. * @param string $ref Ref of direct debit
  316. * @return int >0 if OK, <0 if KO
  317. */
  318. public function fetch($rowid, $ref = '')
  319. {
  320. $sql = "SELECT p.rowid, p.ref, p.amount, p.note";
  321. $sql .= ", p.datec as dc";
  322. $sql .= ", p.date_trans as date_trans";
  323. $sql .= ", p.method_trans, p.fk_user_trans";
  324. $sql .= ", p.date_credit as date_credit";
  325. $sql .= ", p.fk_user_credit";
  326. $sql .= ", p.type";
  327. $sql .= ", p.fk_bank_account";
  328. $sql .= ", p.statut as status";
  329. $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as p";
  330. $sql .= " WHERE p.entity IN (".getEntity('invoice').")";
  331. if ($rowid > 0) {
  332. $sql .= " AND p.rowid = ".((int) $rowid);
  333. } else {
  334. $sql .= " AND p.ref = '".$this->db->escape($ref)."'";
  335. }
  336. dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
  337. $result = $this->db->query($sql);
  338. if ($result) {
  339. if ($this->db->num_rows($result)) {
  340. $obj = $this->db->fetch_object($result);
  341. $this->id = $obj->rowid;
  342. $this->ref = $obj->ref;
  343. $this->amount = $obj->amount;
  344. $this->note = $obj->note;
  345. $this->datec = $this->db->jdate($obj->dc);
  346. $this->date_trans = $this->db->jdate($obj->date_trans);
  347. $this->method_trans = $obj->method_trans;
  348. $this->user_trans = $obj->fk_user_trans;
  349. $this->date_credit = $this->db->jdate($obj->date_credit);
  350. $this->user_credit = $obj->fk_user_credit;
  351. $this->type = $obj->type;
  352. $this->fk_bank_account = $obj->fk_bank_account;
  353. $this->status = $obj->status;
  354. $this->statut = $obj->status; // For backward compatibility
  355. $this->fetched = 1;
  356. return 1;
  357. } else {
  358. dol_syslog(get_class($this)."::Fetch Erreur aucune ligne retournee");
  359. return -1;
  360. }
  361. } else {
  362. return -2;
  363. }
  364. }
  365. /**
  366. * Update object into database
  367. *
  368. * @param User $user User that modifies
  369. * @param bool $notrigger false=launch triggers after, true=disable triggers
  370. * @return int <0 if KO, >0 if OK
  371. */
  372. public function update(User $user, $notrigger = false)
  373. {
  374. return $this->updateCommon($user, $notrigger);
  375. }
  376. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  377. /**
  378. * Set direct debit or credit transfer order to "paid" status.
  379. * Then create the payment for each invoice of the prelemevement_bon.
  380. *
  381. * @param User $user Id of user
  382. * @param int $date date of action
  383. * @return int >0 if OK, <0 if KO
  384. */
  385. public function set_infocredit($user, $date)
  386. {
  387. // phpcs:enable
  388. global $conf, $langs;
  389. $error = 0;
  390. if ($this->fetched == 1) {
  391. if ($date < $this->date_trans) {
  392. $langs->load("errors");
  393. $this->error = $langs->trans('ErrorDateOfMovementLowerThanDateOfFileTransmission');
  394. dol_syslog("bon-prelevment::set_infocredit 1027 ".$this->error);
  395. return -1027;
  396. }
  397. $this->db->begin();
  398. $sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_bons";
  399. $sql .= " SET fk_user_credit = ".$user->id;
  400. $sql .= ", statut = ".self::STATUS_CREDITED;
  401. $sql .= ", date_credit = '".$this->db->idate($date)."'";
  402. $sql .= " WHERE rowid=".((int) $this->id);
  403. $sql .= " AND entity = ".((int) $conf->entity);
  404. $sql .= " AND statut = ".self::STATUS_TRANSFERED;
  405. $resql = $this->db->query($sql);
  406. if ($resql) {
  407. $langs->load('withdrawals');
  408. $subject = $langs->trans("InfoCreditSubject", $this->ref);
  409. $message = $langs->trans("InfoCreditMessage", $this->ref, dol_print_date($date, 'dayhour'));
  410. // Add payment of withdrawal into bank
  411. $fk_bank_account = $this->fk_bank_account;
  412. if (empty($fk_bank_account)) {
  413. $fk_bank_account = ($this->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
  414. }
  415. $facs = array();
  416. $amounts = array();
  417. $amountsperthirdparty = array();
  418. $facs = $this->getListInvoices(1);
  419. // Loop on each invoice. $facs=array(0=>id, 1=>amount requested)
  420. $num = count($facs);
  421. for ($i = 0; $i < $num; $i++) {
  422. if ($this->type == 'bank-transfer') {
  423. $fac = new FactureFournisseur($this->db);
  424. } else {
  425. $fac = new Facture($this->db);
  426. }
  427. $result = $fac->fetch($facs[$i][0]);
  428. $amounts[$fac->id] = $facs[$i][1];
  429. $amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];
  430. $totalpaid = $fac->getSommePaiement();
  431. $totalcreditnotes = $fac->getSumCreditNotesUsed();
  432. $totaldeposits = $fac->getSumDepositsUsed();
  433. $alreadypayed = $totalpaid + $totalcreditnotes + $totaldeposits;
  434. // @TODO Move this after creation of payment
  435. if (price2num($alreadypayed + $facs[$i][1], 'MT') == $fac->total_ttc) {
  436. $result = $fac->setPaid($user);
  437. if ($result < 0) {
  438. $this->error = $fac->error;
  439. $this->errors = $fac->errors;
  440. }
  441. }
  442. }
  443. //var_dump($amountsperthirdparty);exit;
  444. // Make one payment per customer
  445. foreach ($amountsperthirdparty as $thirdpartyid => $cursoramounts) {
  446. if ($this->type == 'bank-transfer') {
  447. $paiement = new PaiementFourn($this->db);
  448. } else {
  449. $paiement = new Paiement($this->db);
  450. }
  451. $paiement->datepaye = $date;
  452. $paiement->amounts = $cursoramounts; // Array with detail of dispatching of payments for each invoice
  453. if ($this->type == 'bank-transfer') {
  454. $paiement->paiementid = 2;
  455. $paiement->paiementcode = 'VIR';
  456. } else {
  457. $paiement->paiementid = 3;
  458. $paiement->paiementcode = 'PRE';
  459. }
  460. $paiement->num_payment = $this->ref; // Set ref of direct debit note
  461. $paiement->id_prelevement = $this->id;
  462. $paiement_id = $paiement->create($user); // This use ->paiementid, that is ID of payment mode
  463. if ($paiement_id < 0) {
  464. $error++;
  465. $this->error = $paiement->error;
  466. $this->errors = $paiement->errors;
  467. dol_syslog(get_class($this)."::set_infocredit AddPayment Error ".$this->error);
  468. } else {
  469. if ($this->type == 'bank-transfer') {
  470. $modeforaddpayment = 'payment_supplier';
  471. } else {
  472. $modeforaddpayment = 'payment';
  473. }
  474. $result = $paiement->addPaymentToBank($user, $modeforaddpayment, '(WithdrawalPayment)', $fk_bank_account, '', '');
  475. if ($result < 0) {
  476. $error++;
  477. $this->error = $paiement->error;
  478. $this->errors = $paiement->errors;
  479. dol_syslog(get_class($this)."::set_infocredit AddPaymentToBank Error ".$this->error);
  480. }
  481. }
  482. }
  483. // Update withdrawal line
  484. // TODO: Translate to ligneprelevement.class.php
  485. if (!$error) {
  486. $sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_lignes";
  487. $sql .= " SET statut = 2";
  488. $sql .= " WHERE fk_prelevement_bons = ".((int) $this->id);
  489. if (!$this->db->query($sql)) {
  490. dol_syslog(get_class($this)."::set_infocredit Update lines Error");
  491. $error++;
  492. }
  493. }
  494. } else {
  495. $this->error = $this->db->lasterror();
  496. dol_syslog(get_class($this)."::set_infocredit Update Bons Error");
  497. $error++;
  498. }
  499. /*
  500. * End of procedure
  501. */
  502. if ($error == 0) {
  503. $this->date_credit = $date;
  504. $this->statut = self::STATUS_CREDITED;
  505. $this->db->commit();
  506. return 0;
  507. } else {
  508. $this->db->rollback();
  509. return -1;
  510. }
  511. } else {
  512. return -1026;
  513. }
  514. }
  515. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  516. /**
  517. * Set withdrawal to transmited status
  518. *
  519. * @param User $user id of user
  520. * @param int $date date of action
  521. * @param string $method method of transmision to bank (0=Internet, 1=Api...)
  522. * @return int >0 if OK, <0 if KO
  523. */
  524. public function set_infotrans($user, $date, $method)
  525. {
  526. // phpcs:enable
  527. global $conf, $langs;
  528. $error = 0;
  529. dol_syslog(get_class($this)."::set_infotrans Start", LOG_INFO);
  530. if ($this->db->begin()) {
  531. $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_bons ";
  532. $sql .= " SET fk_user_trans = ".$user->id;
  533. $sql .= " , date_trans = '".$this->db->idate($date)."'";
  534. $sql .= " , method_trans = ".((int) $method);
  535. $sql .= " , statut = ".self::STATUS_TRANSFERED;
  536. $sql .= " WHERE rowid = ".((int) $this->id);
  537. $sql .= " AND entity = ".((int) $conf->entity);
  538. $sql .= " AND statut = 0";
  539. if ($this->db->query($sql)) {
  540. $this->method_trans = $method;
  541. $langs->load('withdrawals');
  542. $subject = $langs->trans("InfoTransSubject", $this->ref);
  543. $message = $langs->trans("InfoTransMessage", $this->ref, dolGetFirstLastname($user->firstname, $user->lastname));
  544. $message .= $langs->trans("InfoTransData", price($this->amount), $this->methodes_trans[$this->method_trans], dol_print_date($date, 'day'));
  545. // TODO Call trigger to create a notification using notification module
  546. } else {
  547. $error++;
  548. }
  549. if ($error == 0) {
  550. $this->date_trans = $date;
  551. $this->statut = 1;
  552. $this->user_trans = $user->id;
  553. $this->db->commit();
  554. return 0;
  555. } else {
  556. $this->db->rollback();
  557. dol_syslog(get_class($this)."::set_infotrans ROLLBACK", LOG_ERR);
  558. return -1;
  559. }
  560. } else {
  561. dol_syslog(get_class($this)."::set_infotrans Ouverture transaction SQL impossible", LOG_CRIT);
  562. return -2;
  563. }
  564. }
  565. /**
  566. * Get invoice list
  567. *
  568. * @param int $amounts If you want to get the amount of the order for each invoice
  569. * @return array Id of invoices
  570. */
  571. private function getListInvoices($amounts = 0)
  572. {
  573. global $conf;
  574. $arr = array();
  575. /*
  576. * Returns all invoices presented within same order
  577. */
  578. $sql = "SELECT ";
  579. if ($this->type == 'bank-transfer') {
  580. $sql .= " pf.fk_facture_fourn";
  581. } else {
  582. $sql .= " pf.fk_facture";
  583. }
  584. if ($amounts) {
  585. $sql .= ", SUM(pl.amount)";
  586. }
  587. $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as p";
  588. $sql .= " , ".MAIN_DB_PREFIX."prelevement_lignes as pl";
  589. $sql .= " , ".MAIN_DB_PREFIX."prelevement as pf";
  590. $sql .= " WHERE pf.fk_prelevement_lignes = pl.rowid";
  591. $sql .= " AND pl.fk_prelevement_bons = p.rowid";
  592. $sql .= " AND p.rowid = ".((int) $this->id);
  593. $sql .= " AND p.entity = ".((int) $conf->entity);
  594. if ($amounts) {
  595. if ($this->type == 'bank-transfer') {
  596. $sql .= " GROUP BY fk_facture_fourn";
  597. } else {
  598. $sql .= " GROUP BY fk_facture";
  599. }
  600. }
  601. $resql = $this->db->query($sql);
  602. if ($resql) {
  603. $num = $this->db->num_rows($resql);
  604. if ($num) {
  605. $i = 0;
  606. while ($i < $num) {
  607. $row = $this->db->fetch_row($resql);
  608. if (!$amounts) {
  609. $arr[$i] = $row[0];
  610. } else {
  611. $arr[$i] = array(
  612. $row[0],
  613. $row[1]
  614. );
  615. }
  616. $i++;
  617. }
  618. }
  619. $this->db->free($resql);
  620. } else {
  621. dol_syslog(get_class($this)."::getListInvoices Erreur");
  622. }
  623. return $arr;
  624. }
  625. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  626. /**
  627. * Returns amount waiting for direct debit payment or credit transfer payment
  628. *
  629. * @param string $mode 'direct-debit' or 'bank-transfer'
  630. * @return double <O if KO, Total amount
  631. */
  632. public function SommeAPrelever($mode = 'direct-debit')
  633. {
  634. // phpcs:enable
  635. global $conf;
  636. $sql = "SELECT sum(pfd.amount) as nb";
  637. if ($mode != 'bank-transfer') {
  638. $sql .= " FROM ".MAIN_DB_PREFIX."facture as f,";
  639. } else {
  640. $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f,";
  641. }
  642. $sql .= " ".MAIN_DB_PREFIX."prelevement_demande as pfd";
  643. $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
  644. if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS)) {
  645. $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
  646. }
  647. if ($mode != 'bank-transfer') {
  648. $sql .= " AND f.rowid = pfd.fk_facture";
  649. } else {
  650. $sql .= " AND f.rowid = pfd.fk_facture_fourn";
  651. }
  652. $sql .= " AND f.paye = 0";
  653. $sql .= " AND pfd.traite = 0";
  654. $sql .= " AND pfd.ext_payment_id IS NULL";
  655. $sql .= " AND f.total_ttc > 0";
  656. $resql = $this->db->query($sql);
  657. if ($resql) {
  658. $obj = $this->db->fetch_object($resql);
  659. $this->db->free($resql);
  660. return $obj->nb;
  661. } else {
  662. $error = 1;
  663. dol_syslog(get_class($this)."::SommeAPrelever Erreur -1");
  664. dol_syslog($this->db->error());
  665. return -1;
  666. }
  667. }
  668. /**
  669. * Get number of invoices waiting for payment
  670. *
  671. * @param string $mode 'direct-debit' or 'bank-transfer'
  672. * @return int <O if KO, number of invoices if OK
  673. */
  674. public function nbOfInvoiceToPay($mode = 'direct-debit')
  675. {
  676. return $this->NbFactureAPrelever($mode);
  677. }
  678. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  679. /**
  680. * Get number of invoices to pay
  681. *
  682. * @param string $type 'direct-debit' or 'bank-transfer'
  683. * @return int <O if KO, number of invoices if OK
  684. */
  685. public function NbFactureAPrelever($type = 'direct-debit')
  686. {
  687. // phpcs:enable
  688. global $conf;
  689. $sql = "SELECT count(f.rowid) as nb";
  690. if ($type == 'bank-transfer') {
  691. $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
  692. } else {
  693. $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
  694. }
  695. $sql .= ", ".MAIN_DB_PREFIX."prelevement_demande as pfd";
  696. $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
  697. if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS)) {
  698. $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
  699. }
  700. if ($type == 'bank-transfer') {
  701. $sql .= " AND f.rowid = pfd.fk_facture_fourn";
  702. } else {
  703. $sql .= " AND f.rowid = pfd.fk_facture";
  704. }
  705. $sql .= " AND pfd.traite = 0";
  706. $sql .= " AND pfd.ext_payment_id IS NULL";
  707. $sql .= " AND f.total_ttc > 0";
  708. dol_syslog(get_class($this)."::NbFactureAPrelever");
  709. $resql = $this->db->query($sql);
  710. if ($resql) {
  711. $obj = $this->db->fetch_object($resql);
  712. $this->db->free($resql);
  713. return $obj->nb;
  714. } else {
  715. $this->error = get_class($this)."::NbFactureAPrelever Erreur -1 sql=".$this->db->error();
  716. return -1;
  717. }
  718. }
  719. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  720. /**
  721. * Create a BAN payment order:
  722. * - Select waiting requests from prelevement_demande (or use $did if provided)
  723. * - Check BAN values
  724. * - Then create a direct debit order or a credit transfer order
  725. * - Link the order with the prelevement_demande lines
  726. * TODO delete params banque and agence when not necessary
  727. *
  728. * @param int $banque dolibarr mysoc bank
  729. * @param int $agence dolibarr mysoc bank office (guichet)
  730. * @param string $mode real=do action, simu=test only
  731. * @param string $format FRST, RCUR or ALL
  732. * @param string $executiondate Date to execute the transfer
  733. * @param int $notrigger Disable triggers
  734. * @param string $type 'direct-debit' or 'bank-transfer'
  735. * @param int $did ID of an existing payment request. If $did is defined, no entry
  736. * @param int $fk_bank_account Bank account ID the receipt is generated for. Will use the ID into the setup of module Direct Debit or Credit Transfer if 0.
  737. * @return int <0 if KO, No of invoice included into file if OK
  738. */
  739. public function create($banque = 0, $agence = 0, $mode = 'real', $format = 'ALL', $executiondate = '', $notrigger = 0, $type = 'direct-debit', $did = 0, $fk_bank_account = 0)
  740. {
  741. // phpcs:enable
  742. global $conf, $langs, $user;
  743. dol_syslog(__METHOD__." Bank=".$banque." Office=".$agence." mode=".$mode." format=".$format, LOG_DEBUG);
  744. require_once DOL_DOCUMENT_ROOT."/compta/facture/class/facture.class.php";
  745. require_once DOL_DOCUMENT_ROOT."/societe/class/societe.class.php";
  746. // Check params
  747. if ($type != 'bank-transfer') {
  748. if (empty($format)) {
  749. $this->error = 'ErrorBadParametersForDirectDebitFileCreate';
  750. return -1;
  751. }
  752. }
  753. // Clean params
  754. if (empty($fk_bank_account)) {
  755. $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
  756. }
  757. $error = 0;
  758. $datetimeprev = dol_now('gmt');
  759. // Choice the date of the execution direct debit
  760. if (!empty($executiondate)) {
  761. $datetimeprev = $executiondate;
  762. }
  763. $month = dol_print_date($datetimeprev, "%m", 'gmt');
  764. $year = dol_print_date($datetimeprev, "%Y", 'gmt');
  765. $this->invoice_in_error = array();
  766. $this->thirdparty_in_error = array();
  767. // Read invoices
  768. $factures = array();
  769. $factures_prev = array();
  770. $factures_result = array();
  771. $factures_prev_id = array();
  772. $factures_errors = array();
  773. if (!$error) {
  774. $sql = "SELECT f.rowid, pfd.rowid as pfdrowid, f.fk_soc";
  775. $sql .= ", pfd.code_banque, pfd.code_guichet, pfd.number, pfd.cle_rib";
  776. $sql .= ", pfd.amount";
  777. $sql .= ", s.nom as name";
  778. if ($type != 'bank-transfer') {
  779. $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
  780. } else {
  781. $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
  782. }
  783. $sql .= ", ".MAIN_DB_PREFIX."societe as s";
  784. $sql .= ", ".MAIN_DB_PREFIX."prelevement_demande as pfd";
  785. $sql .= " WHERE f.entity IN (".getEntity('invoice').')';
  786. if ($type != 'bank-transfer') {
  787. $sql .= " AND f.rowid = pfd.fk_facture";
  788. } else {
  789. $sql .= " AND f.rowid = pfd.fk_facture_fourn";
  790. }
  791. $sql .= " AND s.rowid = f.fk_soc";
  792. $sql .= " AND f.fk_statut = 1"; // Invoice validated
  793. $sql .= " AND f.paye = 0";
  794. $sql .= " AND pfd.traite = 0";
  795. $sql .= " AND f.total_ttc > 0";
  796. $sql .= " AND pfd.ext_payment_id IS NULL";
  797. if ($did > 0) {
  798. $sql .= " AND pfd.rowid = ".((int) $did);
  799. }
  800. dol_syslog(__METHOD__." Read invoices,", LOG_DEBUG);
  801. $resql = $this->db->query($sql);
  802. if ($resql) {
  803. $num = $this->db->num_rows($resql);
  804. $i = 0;
  805. while ($i < $num) {
  806. $row = $this->db->fetch_row($resql);
  807. $factures[$i] = $row; // All fields
  808. if ($row[7] == 0) {
  809. $error++;
  810. dol_syslog(__METHOD__." Read invoices error Found a null invoice", LOG_ERR);
  811. $this->invoice_in_error[$row[0]] = "Error for invoice id ".$row[0].", found a null amount";
  812. break;
  813. }
  814. $i++;
  815. }
  816. $this->db->free($resql);
  817. dol_syslog(__METHOD__." Read invoices, ".$i." invoices to withdraw", LOG_DEBUG);
  818. } else {
  819. $error++;
  820. dol_syslog(__METHOD__." Read invoices error ".$this->db->error(), LOG_ERR);
  821. }
  822. }
  823. if (!$error) {
  824. require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
  825. $soc = new Societe($this->db);
  826. // Check BAN
  827. $i = 0;
  828. dol_syslog(__METHOD__." Check BAN", LOG_DEBUG);
  829. if (count($factures) > 0) {
  830. foreach ($factures as $key => $fac) {
  831. if ($type != 'bank-transfer') {
  832. $tmpinvoice = new Facture($this->db);
  833. } else {
  834. $tmpinvoice = new FactureFournisseur($this->db);
  835. }
  836. $resfetch = $tmpinvoice->fetch($fac[0]);
  837. if ($resfetch >= 0) { // Field 0 of $fac is rowid of invoice
  838. if ($soc->fetch($tmpinvoice->socid) >= 0) {
  839. $bac = new CompanyBankAccount($this->db);
  840. $bac->fetch(0, $soc->id);
  841. if ($type != 'bank-transfer') {
  842. if ($format == 'FRST' && $bac->frstrecur != 'FRST') {
  843. continue;
  844. }
  845. if ($format == 'RCUR' && ($bac->frstrecur != 'RCUR' && $bac->frstrecur != 'RECUR')) {
  846. continue;
  847. }
  848. }
  849. if ($bac->verif() >= 1) {
  850. $factures_prev[$i] = $fac;
  851. /* second array necessary for BonPrelevement */
  852. $factures_prev_id[$i] = $fac[0];
  853. $i++;
  854. //dol_syslog(__METHOD__."::RIB is ok", LOG_DEBUG);
  855. } else {
  856. dol_syslog(__METHOD__." Check BAN Error on default bank number IBAN/BIC for thirdparty reported by verif() ".$tmpinvoice->socid." ".$soc->name, LOG_WARNING);
  857. $this->invoice_in_error[$fac[0]] = "Error on default bank number IBAN/BIC for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
  858. $this->thirdparty_in_error[$soc->id] = "Error on default bank number IBAN/BIC for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
  859. }
  860. } else {
  861. dol_syslog(__METHOD__." Check BAN Failed to read company", LOG_WARNING);
  862. }
  863. } else {
  864. dol_syslog(__METHOD__." Check BAN Failed to read invoice", LOG_WARNING);
  865. }
  866. }
  867. } else {
  868. dol_syslog(__METHOD__." Check BAN No invoice to process", LOG_WARNING);
  869. }
  870. }
  871. $ok = 0;
  872. // Withdraw invoices in factures_prev array
  873. $out = count($factures_prev)." invoices will be included.";
  874. //print $out."\n";
  875. dol_syslog($out);
  876. // Return warning
  877. /*$i=0;
  878. foreach ($this->thirdparty_in_error as $key => $val)
  879. {
  880. if ($i < 10) setEventMessages($val, null, 'warnings');
  881. else setEventMessages('More error were discarded...', null, 'warnings');
  882. $i++;
  883. }*/
  884. if (count($factures_prev) > 0) {
  885. if ($mode == 'real') {
  886. $ok = 1;
  887. } else {
  888. print $langs->trans("ModeWarning"); // "Option for real mode was not set, we stop after this simulation\n";
  889. }
  890. }
  891. if ($ok) {
  892. /*
  893. * We are in real mode.
  894. * We create order and build file into disk
  895. */
  896. $this->db->begin();
  897. $now = dol_now();
  898. $ref = '';
  899. /*
  900. * Process order generation
  901. */
  902. if (!$error) {
  903. $ref = substr($year, -2).$month;
  904. // Get next free nuber for the ref of bon
  905. $sql = "SELECT substring(ref from char_length(ref) - 1)"; // To extract "YYMMXX" from "TYYMMXX"
  906. $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons";
  907. $sql .= " WHERE ref LIKE '_".$this->db->escape($ref)."%'";
  908. $sql .= " AND entity = ".((int) $conf->entity);
  909. $sql .= " ORDER BY ref DESC LIMIT 1";
  910. dol_syslog(get_class($this)." get next free number", LOG_DEBUG);
  911. $resql = $this->db->query($sql);
  912. if ($resql) {
  913. $row = $this->db->fetch_row($resql);
  914. // Build the new ref
  915. $ref = "T".$ref.sprintf("%02d", (intval($row[0]) + 1));
  916. // $conf->abc->dir_output may be:
  917. // /home/ldestailleur/git/dolibarr_15.0/documents/abc/
  918. // or
  919. // /home/ldestailleur/git/dolibarr_15.0/documents/X/abc with X >= 2 with multicompany.
  920. if ($type != 'bank-transfer') {
  921. $dir = $conf->prelevement->dir_output.'/receipts';
  922. } else {
  923. $dir = $conf->paymentbybanktransfer->dir_output.'/receipts';
  924. }
  925. if (!is_dir($dir)) {
  926. dol_mkdir($dir);
  927. }
  928. if (isModEnabled('multicompany')) {
  929. $labelentity = $conf->entity;
  930. $this->filename = $dir.'/'.$ref.'-'.$labelentity.'.xml';
  931. } else {
  932. $this->filename = $dir.'/'.$ref.'.xml';
  933. }
  934. // Create withdraw order in database
  935. $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_bons (";
  936. $sql .= "ref, entity, datec, type, fk_bank_account";
  937. $sql .= ") VALUES (";
  938. $sql .= "'".$this->db->escape($ref)."'";
  939. $sql .= ", ".((int) $conf->entity);
  940. $sql .= ", '".$this->db->idate($now)."'";
  941. $sql .= ", '".($type == 'bank-transfer' ? 'bank-transfer' : 'debit-order')."'";
  942. $sql .= ", ".((int) $fk_bank_account);
  943. $sql .= ")";
  944. $resql = $this->db->query($sql);
  945. if ($resql) {
  946. $prev_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevement_bons");
  947. $this->id = $prev_id;
  948. $this->ref = $ref;
  949. } else {
  950. $error++;
  951. dol_syslog(__METHOD__." Create withdraw receipt ".$this->db->lasterror(), LOG_ERR);
  952. }
  953. } else {
  954. $error++;
  955. dol_syslog(__METHOD__." Get last withdraw receipt ".$this->db->lasterror(), LOG_ERR);
  956. }
  957. }
  958. if (!$error) {
  959. if ($type != 'bank-transfer') {
  960. $fact = new Facture($this->db);
  961. } else {
  962. $fact = new FactureFournisseur($this->db);
  963. }
  964. // Add lines for the bon
  965. if (count($factures_prev) > 0) {
  966. foreach ($factures_prev as $fac) { // Add a link in database for each invoice
  967. // Fetch invoice
  968. $result = $fact->fetch($fac[0]);
  969. if ($result < 0) {
  970. $this->error = 'ERRORBONPRELEVEMENT Failed to load invoice with id '.$fac[0];
  971. break;
  972. }
  973. /*
  974. * Add standing order. This add record into llx_prelevement_lignes and llx_prelevement
  975. *
  976. * $fac[0] : invoice_id
  977. * $fac[1] : ???
  978. * $fac[2] : third party id
  979. * $fac[3] : banque
  980. * $fac[4] : guichet
  981. * $fac[5] : number
  982. * $fac[6] : cle rib
  983. * $fac[7] : amount
  984. * $fac[8] : client nom
  985. */
  986. $ri = $this->AddFacture($fac[0], $fac[2], $fac[8], $fac[7], $fac[3], $fac[4], $fac[5], $fac[6], $type);
  987. if ($ri <> 0) {
  988. $error++;
  989. }
  990. // Update invoice requests as done
  991. $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande";
  992. $sql .= " SET traite = 1";
  993. $sql .= ", date_traite = '".$this->db->idate($now)."'";
  994. $sql .= ", fk_prelevement_bons = ".((int) $this->id);
  995. $sql .= " WHERE rowid = ".((int) $fac[1]);
  996. $resql = $this->db->query($sql);
  997. if (!$resql) {
  998. $error++;
  999. $this->errors[] = $this->db->lasterror();
  1000. dol_syslog(__METHOD__." Update Error=".$this->db->lasterror(), LOG_ERR);
  1001. }
  1002. }
  1003. }
  1004. }
  1005. if (!$error) {
  1006. /*
  1007. * Create file of type='direct-debit' for direct debit order or type='bank-transfer' for credit transfer into a XML file
  1008. */
  1009. dol_syslog(__METHOD__." Init direct debit or credit transfer file for ".count($factures_prev)." invoices", LOG_DEBUG);
  1010. if (count($factures_prev) > 0) {
  1011. $this->date_echeance = $datetimeprev;
  1012. $this->reference_remise = $ref;
  1013. $account = new Account($this->db);
  1014. if ($account->fetch($fk_bank_account) > 0) {
  1015. $this->emetteur_code_banque = $account->code_banque;
  1016. $this->emetteur_code_guichet = $account->code_guichet;
  1017. $this->emetteur_numero_compte = $account->number;
  1018. $this->emetteur_number_key = $account->cle_rib;
  1019. $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
  1020. $this->emetteur_iban = $account->iban;
  1021. $this->emetteur_bic = $account->bic;
  1022. $this->emetteur_ics = ($type == 'bank-transfer' ? $account->ics_transfer : $account->ics);
  1023. $this->raison_sociale = $account->proprio;
  1024. }
  1025. $this->factures = $factures_prev_id;
  1026. $this->context['factures_prev'] = $factures_prev;
  1027. // Generation of direct debit or credit transfer file $this->filename (May be a SEPA file for european countries)
  1028. // This also set the property $this->total with amount that is included into file
  1029. $result = $this->generate($format, $executiondate, $type);
  1030. if ($result < 0) {
  1031. //var_dump($this->error);
  1032. //var_dump($this->invoice_in_error);
  1033. $error++;
  1034. }
  1035. }
  1036. dol_syslog(__METHOD__." Bank order file has been generated under filename ".$this->filename, LOG_DEBUG);
  1037. }
  1038. //var_dump($this->total);exit;
  1039. /*
  1040. * Update total defined after generation of file
  1041. */
  1042. if (!$error) {
  1043. $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_bons";
  1044. $sql .= " SET amount = ".price2num($this->total);
  1045. $sql .= " WHERE rowid = ".((int) $this->id);
  1046. $sql .= " AND entity = ".((int) $conf->entity);
  1047. $resql = $this->db->query($sql);
  1048. if (!$resql) {
  1049. $error++;
  1050. dol_syslog(__METHOD__." Error update total: ".$this->db->error(), LOG_ERR);
  1051. }
  1052. }
  1053. if (!$error && !$notrigger) {
  1054. $triggername = 'DIRECT_DEBIT_ORDER_CREATE';
  1055. if ($type != 'bank-transfer') {
  1056. $triggername = 'CREDIT_TRANSFER_ORDER_CREATE';
  1057. }
  1058. // Call trigger
  1059. $result = $this->call_trigger($triggername, $user);
  1060. if ($result < 0) {
  1061. $error++;
  1062. }
  1063. // End call triggers
  1064. }
  1065. if (!$error) {
  1066. $this->db->commit();
  1067. return count($factures_prev);
  1068. } else {
  1069. $this->db->rollback();
  1070. return -1;
  1071. }
  1072. } else {
  1073. return 0;
  1074. }
  1075. }
  1076. /**
  1077. * Get object and lines from database
  1078. *
  1079. * @param User $user Object user that delete
  1080. * @param int $notrigger 1=Does not execute triggers, 0= execute triggers
  1081. * @return int >0 if OK, <0 if KO
  1082. */
  1083. public function delete($user = null, $notrigger = 0)
  1084. {
  1085. $this->db->begin();
  1086. $error = 0;
  1087. $resql1 = $resql2 = $resql3 = $resql4 = 0;
  1088. if (!$notrigger) {
  1089. $triggername = 'DIRECT_DEBIT_ORDER_DELETE';
  1090. if ($this->type == 'bank-transfer') {
  1091. $triggername = 'PAYMENTBYBANKTRANFER_DELETE';
  1092. }
  1093. // Call trigger
  1094. $result = $this->call_trigger($triggername, $user);
  1095. if ($result < 0) {
  1096. $error++;
  1097. }
  1098. // End call triggers
  1099. }
  1100. if (!$error) {
  1101. $sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevement WHERE fk_prelevement_lignes IN (SELECT rowid FROM ".MAIN_DB_PREFIX."prelevement_lignes WHERE fk_prelevement_bons = ".((int) $this->id).")";
  1102. $resql1 = $this->db->query($sql);
  1103. if (!$resql1) {
  1104. dol_print_error($this->db);
  1105. }
  1106. }
  1107. if (!$error) {
  1108. $sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevement_lignes WHERE fk_prelevement_bons = ".((int) $this->id);
  1109. $resql2 = $this->db->query($sql);
  1110. if (!$resql2) {
  1111. dol_print_error($this->db);
  1112. }
  1113. }
  1114. if (!$error) {
  1115. $sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevement_bons WHERE rowid = ".((int) $this->id);
  1116. $resql3 = $this->db->query($sql);
  1117. if (!$resql3) {
  1118. dol_print_error($this->db);
  1119. }
  1120. }
  1121. if (!$error) {
  1122. $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET fk_prelevement_bons = NULL, traite = 0 WHERE fk_prelevement_bons = ".((int) $this->id);
  1123. $resql4 = $this->db->query($sql);
  1124. if (!$resql4) {
  1125. dol_print_error($this->db);
  1126. }
  1127. }
  1128. if ($resql1 && $resql2 && $resql3 && $resql4 && !$error) {
  1129. $this->db->commit();
  1130. return 1;
  1131. } else {
  1132. $this->db->rollback();
  1133. return -1;
  1134. }
  1135. }
  1136. /**
  1137. * Returns clickable name (with picto)
  1138. *
  1139. * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
  1140. * @param string $option On what the link point to ('nolink', ...)
  1141. * @param int $notooltip 1=Disable tooltip
  1142. * @param string $morecss Add more css on link
  1143. * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
  1144. * @return string URL of target
  1145. */
  1146. public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
  1147. {
  1148. global $conf, $langs, $hookmanager;
  1149. if (!empty($conf->dol_no_mouse_hover)) {
  1150. $notooltip = 1; // Force disable tooltips
  1151. }
  1152. $result = '';
  1153. $labeltoshow = 'PaymentByDirectDebit';
  1154. if (!empty($this->type) && $this->type == 'bank-transfer') {
  1155. $labeltoshow = 'PaymentByBankTransfer';
  1156. }
  1157. $label = img_picto('', $this->picto).' <u>'.$langs->trans($labeltoshow).'</u> '.$this->getLibStatut(5);
  1158. $label .= '<br>';
  1159. $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
  1160. if (isset($this->amount)) {
  1161. $label .= '<br><b>'.$langs->trans("Amount").":</b> ".price($this->amount);
  1162. }
  1163. if (isset($this->date_trans)) {
  1164. $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_trans, 'dayhour', 'tzuserrel');
  1165. }
  1166. /*if (isset($this->date_credit)) {
  1167. $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_credit, 'dayhour', 'tzuserrel');
  1168. }*/
  1169. $url = DOL_URL_ROOT.'/compta/prelevement/card.php?id='.$this->id;
  1170. if (!empty($this->type) && $this->type == 'bank-transfer') {
  1171. $url = DOL_URL_ROOT.'/compta/prelevement/card.php?id='.$this->id;
  1172. }
  1173. if ($option != 'nolink') {
  1174. // Add param to save lastsearch_values or not
  1175. $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
  1176. if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
  1177. $add_save_lastsearch_values = 1;
  1178. }
  1179. if ($add_save_lastsearch_values) {
  1180. $url .= '&save_lastsearch_values=1';
  1181. }
  1182. }
  1183. $linkclose = '';
  1184. if (empty($notooltip)) {
  1185. if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
  1186. $label = $langs->trans("ShowMyObject");
  1187. $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
  1188. }
  1189. $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
  1190. $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
  1191. } else {
  1192. $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
  1193. }
  1194. $linkstart = '<a href="'.$url.'"';
  1195. $linkstart .= $linkclose.'>';
  1196. $linkend = '</a>';
  1197. $result .= $linkstart;
  1198. if ($withpicto) {
  1199. $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
  1200. }
  1201. if ($withpicto != 2) {
  1202. $result .= $this->ref;
  1203. }
  1204. $result .= $linkend;
  1205. global $action, $hookmanager;
  1206. $hookmanager->initHooks(array('banktransferdao'));
  1207. $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
  1208. $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
  1209. if ($reshook > 0) {
  1210. $result = $hookmanager->resPrint;
  1211. } else {
  1212. $result .= $hookmanager->resPrint;
  1213. }
  1214. return $result;
  1215. }
  1216. /**
  1217. * Delete a notification def by id
  1218. *
  1219. * @param int $rowid id of notification
  1220. * @return int 0 if OK, <0 if KO
  1221. */
  1222. public function deleteNotificationById($rowid)
  1223. {
  1224. $sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
  1225. $sql .= " WHERE rowid = ".((int) $rowid);
  1226. if ($this->db->query($sql)) {
  1227. return 0;
  1228. } else {
  1229. return -1;
  1230. }
  1231. }
  1232. /**
  1233. * Delete a notification
  1234. *
  1235. * @param int|User $user notification user
  1236. * @param string $action notification action
  1237. * @return int >0 if OK, <0 if KO
  1238. */
  1239. public function deleteNotification($user, $action)
  1240. {
  1241. if (is_object($user)) {
  1242. $userid = $user->id;
  1243. } else { // If user is an id
  1244. $userid = $user;
  1245. }
  1246. $sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
  1247. $sql .= " WHERE fk_user=".((int) $userid)." AND fk_action='".$this->db->escape($action)."'";
  1248. if ($this->db->query($sql)) {
  1249. return 0;
  1250. } else {
  1251. return -1;
  1252. }
  1253. }
  1254. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  1255. /**
  1256. * Add a notification
  1257. *
  1258. * @param DoliDB $db database handler
  1259. * @param int|User $user notification user
  1260. * @param string $action notification action
  1261. * @return int 0 if OK, <0 if KO
  1262. */
  1263. public function addNotification($db, $user, $action)
  1264. {
  1265. // phpcs:enable
  1266. $result = 0;
  1267. if (is_object($user)) {
  1268. $userid = $user->id;
  1269. } else { // If user is an id
  1270. $userid = $user;
  1271. }
  1272. if ($this->deleteNotification($user, $action) == 0) {
  1273. $now = dol_now();
  1274. $sql = "INSERT INTO ".MAIN_DB_PREFIX."notify_def (datec,fk_user, fk_soc, fk_contact, fk_action)";
  1275. $sql .= " VALUES ('".$this->db->idate($now)."', ".((int) $userid).", 'NULL', 'NULL', '".$this->db->escape($action)."')";
  1276. dol_syslog("adnotiff: ".$sql);
  1277. if ($this->db->query($sql)) {
  1278. $result = 0;
  1279. } else {
  1280. $result = -1;
  1281. dol_syslog(get_class($this)."::addNotification Error $result");
  1282. }
  1283. }
  1284. return $result;
  1285. }
  1286. /**
  1287. * Generate a direct debit or credit transfer file.
  1288. * Generation Formats:
  1289. * - Europe: SEPA (France: CFONB no more supported, Spain: AEB19 if external module EsAEB is enabled)
  1290. * - Others countries: Warning message
  1291. * File is generated with name this->filename
  1292. *
  1293. * @param string $format FRST, RCUR or ALL
  1294. * @param int $executiondate Timestamp date to execute transfer
  1295. * @param string $type 'direct-debit' or 'bank-transfer'
  1296. * @param int $fk_bank_account Bank account ID the receipt is generated for. Will use the ID into the setup of module Direct Debit or Credit Transfer if 0.
  1297. * @return int >=0 if OK, <0 if KO
  1298. */
  1299. public function generate($format = 'ALL', $executiondate = 0, $type = 'direct-debit', $fk_bank_account = 0)
  1300. {
  1301. global $conf, $langs, $mysoc;
  1302. //TODO: Optimize code to read lines in a single function
  1303. // Clean params
  1304. if (empty($fk_bank_account)) {
  1305. $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
  1306. }
  1307. $result = 0;
  1308. dol_syslog(get_class($this)."::generate build file=".$this->filename." type=".$type);
  1309. $this->file = fopen($this->filename, "w");
  1310. if (empty($this->file)) {
  1311. $this->error = $langs->trans('ErrorFailedToOpenFile', $this->filename);
  1312. return -1;
  1313. }
  1314. $found = 0;
  1315. $this->total = 0;
  1316. // Build file for European countries
  1317. if ($mysoc->isInEEC()) {
  1318. $found++;
  1319. if ($type != 'bank-transfer') {
  1320. /**
  1321. * SECTION CREATION FICHIER SEPA - DIRECT DEBIT
  1322. */
  1323. // SEPA Initialisation
  1324. $CrLf = "\n";
  1325. $now = dol_now();
  1326. $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
  1327. $date_actu = $now;
  1328. if (!empty($executiondate)) {
  1329. $date_actu = $executiondate;
  1330. }
  1331. $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
  1332. $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
  1333. $fileDebiteurSection = '';
  1334. $fileEmetteurSection = '';
  1335. $i = 0;
  1336. /*
  1337. * Section Debitor (sepa Debiteurs bloc lines)
  1338. */
  1339. $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
  1340. $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
  1341. $sql .= " f.ref as reffac, pf.fk_facture as idfac,";
  1342. $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
  1343. $sql .= " FROM";
  1344. $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
  1345. $sql .= " ".MAIN_DB_PREFIX."facture as f,";
  1346. $sql .= " ".MAIN_DB_PREFIX."prelevement as pf,";
  1347. $sql .= " ".MAIN_DB_PREFIX."societe as soc,";
  1348. $sql .= " ".MAIN_DB_PREFIX."c_country as c,";
  1349. $sql .= " ".MAIN_DB_PREFIX."societe_rib as rib";
  1350. $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
  1351. $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
  1352. $sql .= " AND pf.fk_facture = f.rowid";
  1353. $sql .= " AND f.fk_soc = soc.rowid";
  1354. $sql .= " AND soc.fk_pays = c.rowid";
  1355. $sql .= " AND rib.fk_soc = f.fk_soc";
  1356. $sql .= " AND rib.default_rib = 1";
  1357. $sql .= " AND rib.type = 'ban'";
  1358. // Define $fileDebiteurSection. One section DrctDbtTxInf per invoice.
  1359. $resql = $this->db->query($sql);
  1360. if ($resql) {
  1361. $cachearraytotestduplicate = array();
  1362. $num = $this->db->num_rows($resql);
  1363. while ($i < $num) {
  1364. $obj = $this->db->fetch_object($resql);
  1365. if (!empty($cachearraytotestduplicate[$obj->idfac])) {
  1366. $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
  1367. $this->invoice_in_error[$obj->idfac] = $this->error;
  1368. $result = -2;
  1369. break;
  1370. }
  1371. $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
  1372. $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
  1373. $fileDebiteurSection .= $this->EnregDestinataireSEPA($obj->code, $obj->nom, $obj->address, $obj->zip, $obj->town, $obj->country_code, $obj->cb, $obj->cg, $obj->cc, $obj->somme, $obj->reffac, $obj->idfac, $obj->iban, $obj->bic, $daterum, $obj->drum, $obj->rum, $type);
  1374. $this->total = $this->total + $obj->somme;
  1375. $i++;
  1376. }
  1377. $nbtotalDrctDbtTxInf = $i;
  1378. } else {
  1379. $this->error = $this->db->lasterror();
  1380. fputs($this->file, 'ERROR DEBITOR '.$sql.$CrLf); // DEBITOR = Customers
  1381. $result = -2;
  1382. }
  1383. // Define $fileEmetteurSection. Start of bloc PmtInf. Will contains all $nbtotalDrctDbtTxInf
  1384. if ($result != -2) {
  1385. $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type, $fk_bank_account);
  1386. }
  1387. /**
  1388. * SECTION CREATION SEPA FILE - ISO200022
  1389. */
  1390. // SEPA File Header
  1391. fputs($this->file, '<'.'?xml version="1.0" encoding="UTF-8" standalone="yes"?'.'>'.$CrLf);
  1392. fputs($this->file, '<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'.$CrLf);
  1393. fputs($this->file, ' <CstmrDrctDbtInitn>'.$CrLf);
  1394. // SEPA Group header
  1395. fputs($this->file, ' <GrpHdr>'.$CrLf);
  1396. fputs($this->file, ' <MsgId>'.('DD/'.$dateTime_YMD.'/REF'.$this->id).'</MsgId>'.$CrLf);
  1397. fputs($this->file, ' <CreDtTm>'.$dateTime_ECMA.'</CreDtTm>'.$CrLf);
  1398. fputs($this->file, ' <NbOfTxs>'.$i.'</NbOfTxs>'.$CrLf);
  1399. fputs($this->file, ' <CtrlSum>'.$this->total.'</CtrlSum>'.$CrLf);
  1400. fputs($this->file, ' <InitgPty>'.$CrLf);
  1401. fputs($this->file, ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf);
  1402. fputs($this->file, ' <Id>'.$CrLf);
  1403. fputs($this->file, ' <PrvtId>'.$CrLf);
  1404. fputs($this->file, ' <Othr>'.$CrLf);
  1405. fputs($this->file, ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf);
  1406. fputs($this->file, ' </Othr>'.$CrLf);
  1407. fputs($this->file, ' </PrvtId>'.$CrLf);
  1408. fputs($this->file, ' </Id>'.$CrLf);
  1409. fputs($this->file, ' </InitgPty>'.$CrLf);
  1410. fputs($this->file, ' </GrpHdr>'.$CrLf);
  1411. // SEPA File Emetteur
  1412. if ($result != -2) {
  1413. fputs($this-> file, $fileEmetteurSection);
  1414. }
  1415. // SEPA File Debiteurs
  1416. if ($result != -2) {
  1417. fputs($this-> file, $fileDebiteurSection);
  1418. }
  1419. // SEPA FILE FOOTER
  1420. fputs($this->file, ' </PmtInf>'.$CrLf);
  1421. fputs($this->file, ' </CstmrDrctDbtInitn>'.$CrLf);
  1422. fputs($this->file, '</Document>'.$CrLf);
  1423. } else {
  1424. /**
  1425. * SECTION CREATION FICHIER SEPA - CREDIT TRANSFER
  1426. */
  1427. // SEPA Initialisation
  1428. $CrLf = "\n";
  1429. $now = dol_now();
  1430. $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
  1431. $date_actu = $now;
  1432. if (!empty($executiondate)) {
  1433. $date_actu = $executiondate;
  1434. }
  1435. $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
  1436. $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
  1437. $fileCrediteurSection = '';
  1438. $fileEmetteurSection = '';
  1439. $i = 0;
  1440. /*
  1441. * Section Creditor (sepa Crediteurs bloc lines)
  1442. */
  1443. $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
  1444. $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
  1445. $sql .= " f.ref as reffac, pf.fk_facture_fourn as idfac, f.ref_supplier as fac_ref_supplier,";
  1446. $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
  1447. $sql .= " FROM";
  1448. $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
  1449. $sql .= " ".MAIN_DB_PREFIX."facture_fourn as f,";
  1450. $sql .= " ".MAIN_DB_PREFIX."prelevement as pf,";
  1451. $sql .= " ".MAIN_DB_PREFIX."societe as soc,";
  1452. $sql .= " ".MAIN_DB_PREFIX."c_country as c,";
  1453. $sql .= " ".MAIN_DB_PREFIX."societe_rib as rib";
  1454. $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
  1455. $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
  1456. $sql .= " AND pf.fk_facture_fourn = f.rowid";
  1457. $sql .= " AND f.fk_soc = soc.rowid";
  1458. $sql .= " AND soc.fk_pays = c.rowid";
  1459. $sql .= " AND rib.fk_soc = f.fk_soc";
  1460. $sql .= " AND rib.default_rib = 1";
  1461. $sql .= " AND rib.type = 'ban'";
  1462. // Define $fileCrediteurSection. One section DrctDbtTxInf per invoice.
  1463. $resql = $this->db->query($sql);
  1464. if ($resql) {
  1465. $cachearraytotestduplicate = array();
  1466. $num = $this->db->num_rows($resql);
  1467. while ($i < $num) {
  1468. $obj = $this->db->fetch_object($resql);
  1469. if (!empty($cachearraytotestduplicate[$obj->idfac])) {
  1470. $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
  1471. $this->invoice_in_error[$obj->idfac] = $this->error;
  1472. $result = -2;
  1473. break;
  1474. }
  1475. $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
  1476. $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
  1477. $fileCrediteurSection .= $this->EnregDestinataireSEPA($obj->code, $obj->nom, $obj->address, $obj->zip, $obj->town, $obj->country_code, $obj->cb, $obj->cg, $obj->cc, $obj->somme, $obj->reffac, $obj->idfac, $obj->iban, $obj->bic, $daterum, $obj->drum, $obj->rum, $type, $obj->fac_ref_supplier);
  1478. $this->total = $this->total + $obj->somme;
  1479. $i++;
  1480. }
  1481. $nbtotalDrctDbtTxInf = $i;
  1482. } else {
  1483. $this->error = $this->db->lasterror();
  1484. fputs($this->file, 'ERROR CREDITOR '.$sql.$CrLf); // CREDITORS = Suppliers
  1485. $result = -2;
  1486. }
  1487. // Define $fileEmetteurSection. Start of bloc PmtInf. Will contains all $nbtotalDrctDbtTxInf
  1488. if ($result != -2) {
  1489. $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type);
  1490. }
  1491. /**
  1492. * SECTION CREATION SEPA FILE - CREDIT TRANSFER - ISO200022
  1493. */
  1494. // SEPA File Header
  1495. fputs($this->file, '<'.'?xml version="1.0" encoding="UTF-8" standalone="yes"?'.'>'.$CrLf);
  1496. fputs($this->file, '<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'.$CrLf);
  1497. fputs($this->file, ' <CstmrCdtTrfInitn>'.$CrLf);
  1498. // SEPA Group header
  1499. fputs($this->file, ' <GrpHdr>'.$CrLf);
  1500. fputs($this->file, ' <MsgId>'.('TRF/'.$dateTime_YMD.'/REF'.$this->id).'</MsgId>'.$CrLf);
  1501. fputs($this->file, ' <CreDtTm>'.$dateTime_ECMA.'</CreDtTm>'.$CrLf);
  1502. fputs($this->file, ' <NbOfTxs>'.$i.'</NbOfTxs>'.$CrLf);
  1503. fputs($this->file, ' <CtrlSum>'.$this->total.'</CtrlSum>'.$CrLf);
  1504. fputs($this->file, ' <InitgPty>'.$CrLf);
  1505. fputs($this->file, ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf);
  1506. fputs($this->file, ' <Id>'.$CrLf);
  1507. fputs($this->file, ' <PrvtId>'.$CrLf);
  1508. fputs($this->file, ' <Othr>'.$CrLf);
  1509. fputs($this->file, ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf);
  1510. fputs($this->file, ' </Othr>'.$CrLf);
  1511. fputs($this->file, ' </PrvtId>'.$CrLf);
  1512. fputs($this->file, ' </Id>'.$CrLf);
  1513. fputs($this->file, ' </InitgPty>'.$CrLf);
  1514. fputs($this->file, ' </GrpHdr>'.$CrLf);
  1515. // SEPA File Emetteur (mycompany)
  1516. if ($result != -2) {
  1517. fputs($this-> file, $fileEmetteurSection);
  1518. }
  1519. // SEPA File Creditors
  1520. if ($result != -2) {
  1521. fputs($this-> file, $fileCrediteurSection);
  1522. }
  1523. // SEPA FILE FOOTER
  1524. fputs($this->file, ' </PmtInf>'.$CrLf);
  1525. fputs($this->file, ' </CstmrCdtTrfInitn>'.$CrLf);
  1526. fputs($this->file, '</Document>'.$CrLf);
  1527. }
  1528. }
  1529. // Build file for Other Countries with unknow format
  1530. if (!$found) {
  1531. if ($type != 'bank-transfer') {
  1532. $sql = "SELECT pl.amount";
  1533. $sql .= " FROM";
  1534. $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
  1535. $sql .= " ".MAIN_DB_PREFIX."facture as f,";
  1536. $sql .= " ".MAIN_DB_PREFIX."prelevement as pf";
  1537. $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
  1538. $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
  1539. $sql .= " AND pf.fk_facture = f.rowid";
  1540. // Lines
  1541. $i = 0;
  1542. $resql = $this->db->query($sql);
  1543. if ($resql) {
  1544. $num = $this->db->num_rows($resql);
  1545. while ($i < $num) {
  1546. $obj = $this->db->fetch_object($resql);
  1547. $this->total = $this->total + $obj->amount;
  1548. // TODO Write record into file
  1549. $i++;
  1550. }
  1551. } else {
  1552. $result = -2;
  1553. }
  1554. } else {
  1555. $sql = "SELECT pl.amount";
  1556. $sql .= " FROM";
  1557. $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
  1558. $sql .= " ".MAIN_DB_PREFIX."facture_fourn as f,";
  1559. $sql .= " ".MAIN_DB_PREFIX."prelevement as pf";
  1560. $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
  1561. $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
  1562. $sql .= " AND pf.fk_facture_fourn = f.rowid";
  1563. // Lines
  1564. $i = 0;
  1565. $resql = $this->db->query($sql);
  1566. if ($resql) {
  1567. $num = $this->db->num_rows($resql);
  1568. while ($i < $num) {
  1569. $obj = $this->db->fetch_object($resql);
  1570. $this->total = $this->total + $obj->amount;
  1571. // TODO Write record into file
  1572. $i++;
  1573. }
  1574. } else {
  1575. $result = -2;
  1576. }
  1577. }
  1578. $langs->load('withdrawals');
  1579. // TODO Add here code to generate a generic file
  1580. fputs($this->file, $langs->transnoentitiesnoconv('WithdrawalFileNotCapable', $mysoc->country_code));
  1581. }
  1582. fclose($this->file);
  1583. dolChmod($this->filename);
  1584. return $result;
  1585. }
  1586. /**
  1587. * Generate dynamically a RUM number for a customer bank account
  1588. *
  1589. * @param string $row_code_client Customer code (soc.code_client)
  1590. * @param int $row_datec Creation date of bank account (rib.datec)
  1591. * @param string $row_drum Id of customer bank account (rib.rowid)
  1592. * @return string RUM number
  1593. */
  1594. public static function buildRumNumber($row_code_client, $row_datec, $row_drum)
  1595. {
  1596. global $langs;
  1597. $pre = substr(dol_string_nospecial(dol_string_unaccent($langs->transnoentitiesnoconv('RUM'))), 0, 3); // Must always be on 3 char ('RUM' or 'UMR'. This is a protection against bad translation)
  1598. // 3 char + '-' + 12 + '-' + id + '-' + code Must be lower than 32.
  1599. return $pre.'-'.dol_print_date($row_datec, 'dayhourlogsmall').'-'.dol_trunc($row_drum.($row_code_client ? '-'.$row_code_client : ''), 13, 'right', 'UTF-8', 1);
  1600. }
  1601. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  1602. /**
  1603. * Write recipient of request (customer)
  1604. *
  1605. * @param int $rowid id of line
  1606. * @param string $client_nom name of customer
  1607. * @param string $rib_banque code of bank
  1608. * @param string $rib_guichet code of bank office
  1609. * @param string $rib_number bank account
  1610. * @param float $amount amount
  1611. * @param string $ref ref of invoice
  1612. * @param int $facid id of invoice
  1613. * @param string $rib_dom rib domiciliation
  1614. * @param string $type 'direct-debit' or 'bank-transfer'
  1615. * @return void
  1616. * @see EnregDestinataireSEPA()
  1617. */
  1618. public function EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom = '', $type = 'direct-debit')
  1619. {
  1620. // phpcs:enable
  1621. fputs($this->file, "06");
  1622. fputs($this->file, "08"); // Prelevement ordinaire
  1623. fputs($this->file, " "); // Zone Reservee B2
  1624. fputs($this->file, $this->emetteur_ics); // ICS
  1625. // Date d'echeance C1
  1626. fputs($this->file, " ");
  1627. fputs($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
  1628. fputs($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
  1629. // Raison Sociale Destinataire C2
  1630. fputs($this->file, substr(strtoupper($client_nom)." ", 0, 24));
  1631. // Domiciliation facultative D1
  1632. $domiciliation = strtr($rib_dom, array(" " => "-", CHR(13) => " ", CHR(10) => ""));
  1633. fputs($this->file, substr($domiciliation." ", 0, 24));
  1634. // Zone Reservee D2
  1635. fputs($this->file, substr(" ", 0, 8));
  1636. // Code Guichet D3
  1637. fputs($this->file, $rib_guichet);
  1638. // Numero de compte D4
  1639. fputs($this->file, substr("000000000000000".$rib_number, -11));
  1640. // Zone E Montant
  1641. $montant = (round($amount, 2) * 100);
  1642. fputs($this->file, substr("000000000000000".$montant, -16));
  1643. // Label F
  1644. fputs($this->file, substr("*_".$ref."_RDVnet".$rowid." ", 0, 31));
  1645. // Code etablissement G1
  1646. fputs($this->file, $rib_banque);
  1647. // Zone Reservee G2
  1648. fputs($this->file, substr(" ", 0, 5));
  1649. fputs($this->file, "\n");
  1650. }
  1651. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  1652. /**
  1653. * Write recipient (thirdparty concerned by request)
  1654. *
  1655. * @param string $row_code_client soc.code_client as code,
  1656. * @param string $row_nom pl.client_nom AS name,
  1657. * @param string $row_address soc.address AS adr,
  1658. * @param string $row_zip soc.zip
  1659. * @param string $row_town soc.town
  1660. * @param string $row_country_code c.code AS country,
  1661. * @param string $row_cb pl.code_banque AS cb, Not used for SEPA
  1662. * @param string $row_cg pl.code_guichet AS cg, Not used for SEPA
  1663. * @param string $row_cc pl.number AS cc, Not used for SEPA
  1664. * @param string $row_somme pl.amount AS somme,
  1665. * @param string $row_ref Invoice ref (f.ref)
  1666. * @param string $row_idfac pf.fk_facture AS idfac,
  1667. * @param string $row_iban rib.iban_prefix AS iban,
  1668. * @param string $row_bic rib.bic AS bic,
  1669. * @param string $row_datec rib.datec,
  1670. * @param string $row_drum rib.rowid used to generate rum
  1671. * @param string $row_rum rib.rum Rum defined on company bank account
  1672. * @param string $type 'direct-debit' or 'bank-transfer'
  1673. * @param string $row_comment A free text string for the Unstructured data field
  1674. * @return string Return string with SEPA part DrctDbtTxInf
  1675. * @see EnregDestinataire()
  1676. */
  1677. public function EnregDestinataireSEPA($row_code_client, $row_nom, $row_address, $row_zip, $row_town, $row_country_code, $row_cb, $row_cg, $row_cc, $row_somme, $row_ref, $row_idfac, $row_iban, $row_bic, $row_datec, $row_drum, $row_rum, $type = 'direct-debit', $row_comment = '')
  1678. {
  1679. // phpcs:enable
  1680. global $conf;
  1681. include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
  1682. $CrLf = "\n";
  1683. $Rowing = sprintf("%010d", $row_idfac);
  1684. // Define value for RUM
  1685. // Example: RUM-CustomerCode-CustomerBankAccountId-01424448606 (note: Date is the timestamp of the date of creation of CustomerBankAccountId)
  1686. $Rum = (empty($row_rum) ? $this->buildRumNumber($row_code_client, $row_datec, $row_drum) : $row_rum);
  1687. // Define date of RUM signature
  1688. $DtOfSgntr = dol_print_date($row_datec, '%Y-%m-%d');
  1689. if ($type != 'bank-transfer') {
  1690. // SEPA Paiement Information of buyer for Direct Debit
  1691. $XML_DEBITOR = '';
  1692. $XML_DEBITOR .= ' <DrctDbtTxInf>'.$CrLf;
  1693. $XML_DEBITOR .= ' <PmtId>'.$CrLf;
  1694. // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
  1695. $XML_DEBITOR .= ' <EndToEndId>'.(($conf->global->PRELEVEMENT_END_TO_END != "") ? $conf->global->PRELEVEMENT_END_TO_END : ('DD-'.dol_trunc($row_idfac.'-'.$row_ref, 20, 'right', 'UTF-8', 1)).'-'.$Rowing).'</EndToEndId>'.$CrLf; // ISO20022 states that EndToEndId has a MaxLength of 35 characters
  1696. $XML_DEBITOR .= ' </PmtId>'.$CrLf;
  1697. $XML_DEBITOR .= ' <InstdAmt Ccy="EUR">'.round($row_somme, 2).'</InstdAmt>'.$CrLf;
  1698. $XML_DEBITOR .= ' <DrctDbtTx>'.$CrLf;
  1699. $XML_DEBITOR .= ' <MndtRltdInf>'.$CrLf;
  1700. $XML_DEBITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
  1701. $XML_DEBITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
  1702. $XML_DEBITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
  1703. $XML_DEBITOR .= ' </MndtRltdInf>'.$CrLf;
  1704. $XML_DEBITOR .= ' </DrctDbtTx>'.$CrLf;
  1705. $XML_DEBITOR .= ' <DbtrAgt>'.$CrLf;
  1706. $XML_DEBITOR .= ' <FinInstnId>'.$CrLf;
  1707. $XML_DEBITOR .= ' <BIC>'.$row_bic.'</BIC>'.$CrLf;
  1708. $XML_DEBITOR .= ' </FinInstnId>'.$CrLf;
  1709. $XML_DEBITOR .= ' </DbtrAgt>'.$CrLf;
  1710. $XML_DEBITOR .= ' <Dbtr>'.$CrLf;
  1711. $XML_DEBITOR .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))).'</Nm>'.$CrLf;
  1712. $XML_DEBITOR .= ' <PstlAdr>'.$CrLf;
  1713. $XML_DEBITOR .= ' <Ctry>'.$row_country_code.'</Ctry>'.$CrLf;
  1714. $addressline1 = strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""));
  1715. $addressline2 = strtr($row_zip.(($row_zip && $row_town) ? ' ' : (string) $row_town), array(CHR(13) => ", ", CHR(10) => ""));
  1716. if (trim($addressline1)) {
  1717. $XML_DEBITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1718. }
  1719. if (trim($addressline2)) {
  1720. $XML_DEBITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1721. }
  1722. $XML_DEBITOR .= ' </PstlAdr>'.$CrLf;
  1723. $XML_DEBITOR .= ' </Dbtr>'.$CrLf;
  1724. $XML_DEBITOR .= ' <DbtrAcct>'.$CrLf;
  1725. $XML_DEBITOR .= ' <Id>'.$CrLf;
  1726. $XML_DEBITOR .= ' <IBAN>'.preg_replace('/\s/', '', $row_iban).'</IBAN>'.$CrLf;
  1727. $XML_DEBITOR .= ' </Id>'.$CrLf;
  1728. $XML_DEBITOR .= ' </DbtrAcct>'.$CrLf;
  1729. $XML_DEBITOR .= ' <RmtInf>'.$CrLf;
  1730. // A string with some information on payment - 140 max
  1731. $XML_DEBITOR .= ' <Ustrd>'.getDolGlobalString('PRELEVEMENT_USTRD', dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($row_ref.($row_comment ? ' - '.$row_comment : '')), '', '', '', 1), 135, 'right', 'UTF-8', 1))).'</Ustrd>'.$CrLf; // Free unstuctured data - 140 max
  1732. $XML_DEBITOR .= ' </RmtInf>'.$CrLf;
  1733. $XML_DEBITOR .= ' </DrctDbtTxInf>'.$CrLf;
  1734. return $XML_DEBITOR;
  1735. } else {
  1736. // SEPA Paiement Information of seller for Credit Transfer
  1737. $XML_CREDITOR = '';
  1738. $XML_CREDITOR .= ' <CdtTrfTxInf>'.$CrLf;
  1739. $XML_CREDITOR .= ' <PmtId>'.$CrLf;
  1740. // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
  1741. $XML_CREDITOR .= ' <EndToEndId>'.(($conf->global->PRELEVEMENT_END_TO_END != "") ? $conf->global->PRELEVEMENT_END_TO_END : ('CT-'.dol_trunc($row_idfac.'-'.$row_ref, 20, 'right', 'UTF-8', 1)).'-'.$Rowing).'</EndToEndId>'.$CrLf; // ISO20022 states that EndToEndId has a MaxLength of 35 characters
  1742. $XML_CREDITOR .= ' </PmtId>'.$CrLf;
  1743. if (!empty($this->sepa_xml_pti_in_ctti)) {
  1744. $XML_CREDITOR .= ' <PmtTpInf>' . $CrLf;
  1745. // Can be 'NORM' for normal or 'HIGH' for high priority level
  1746. if (!empty($conf->global->PAYMENTBYBANKTRANSFER_FORCE_HIGH_PRIORITY)) {
  1747. $instrprty = 'HIGH';
  1748. } else {
  1749. $instrprty = 'NORM';
  1750. }
  1751. $XML_CREDITOR .= ' <InstrPrty>'.$instrprty.'</InstrPrty>' . $CrLf;
  1752. $XML_CREDITOR .= ' <SvcLvl>' . $CrLf;
  1753. $XML_CREDITOR .= ' <Cd>SEPA</Cd>' . $CrLf;
  1754. $XML_CREDITOR .= ' </SvcLvl>' . $CrLf;
  1755. $XML_CREDITOR .= ' <CtgyPurp>' . $CrLf;
  1756. $XML_CREDITOR .= ' <Cd>CORE</Cd>' . $CrLf;
  1757. $XML_CREDITOR .= ' </CtgyPurp>' . $CrLf;
  1758. $XML_CREDITOR .= ' </PmtTpInf>' . $CrLf;
  1759. }
  1760. $XML_CREDITOR .= ' <Amt>'.$CrLf;
  1761. $XML_CREDITOR .= ' <InstdAmt Ccy="EUR">'.round($row_somme, 2).'</InstdAmt>'.$CrLf;
  1762. $XML_CREDITOR .= ' </Amt>'.$CrLf;
  1763. /*
  1764. $XML_CREDITOR .= ' <DrctDbtTx>'.$CrLf;
  1765. $XML_CREDITOR .= ' <MndtRltdInf>'.$CrLf;
  1766. $XML_CREDITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
  1767. $XML_CREDITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
  1768. $XML_CREDITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
  1769. $XML_CREDITOR .= ' </MndtRltdInf>'.$CrLf;
  1770. $XML_CREDITOR .= ' </DrctDbtTx>'.$CrLf;
  1771. */
  1772. //$XML_CREDITOR .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf;
  1773. $XML_CREDITOR .= ' <CdtrAgt>'.$CrLf;
  1774. $XML_CREDITOR .= ' <FinInstnId>'.$CrLf;
  1775. $XML_CREDITOR .= ' <BIC>'.$row_bic.'</BIC>'.$CrLf;
  1776. $XML_CREDITOR .= ' </FinInstnId>'.$CrLf;
  1777. $XML_CREDITOR .= ' </CdtrAgt>'.$CrLf;
  1778. $XML_CREDITOR .= ' <Cdtr>'.$CrLf;
  1779. $XML_CREDITOR .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))).'</Nm>'.$CrLf;
  1780. $XML_CREDITOR .= ' <PstlAdr>'.$CrLf;
  1781. $XML_CREDITOR .= ' <Ctry>'.$row_country_code.'</Ctry>'.$CrLf;
  1782. $addressline1 = strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""));
  1783. $addressline2 = strtr($row_zip.(($row_zip && $row_town) ? ' ' : (string) $row_town), array(CHR(13) => ", ", CHR(10) => ""));
  1784. if (trim($addressline1)) {
  1785. $XML_CREDITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1786. }
  1787. if (trim($addressline2)) {
  1788. $XML_CREDITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1789. }
  1790. $XML_CREDITOR .= ' </PstlAdr>'.$CrLf;
  1791. $XML_CREDITOR .= ' </Cdtr>'.$CrLf;
  1792. $XML_CREDITOR .= ' <CdtrAcct>'.$CrLf;
  1793. $XML_CREDITOR .= ' <Id>'.$CrLf;
  1794. $XML_CREDITOR .= ' <IBAN>'.preg_replace('/\s/', '', $row_iban).'</IBAN>'.$CrLf;
  1795. $XML_CREDITOR .= ' </Id>'.$CrLf;
  1796. $XML_CREDITOR .= ' </CdtrAcct>'.$CrLf;
  1797. $XML_CREDITOR .= ' <RmtInf>'.$CrLf;
  1798. // A string with some information on payment - 140 max
  1799. $XML_CREDITOR .= ' <Ustrd>'.getDolGlobalString('CREDITTRANSFER_USTRD', dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($row_ref.($row_comment ? ' - '.$row_comment : '')), '', '', '', 1), 135, 'right', 'UTF-8', 1))).'</Ustrd>'.$CrLf; // Free unstructured data - 140 max
  1800. $XML_CREDITOR .= ' </RmtInf>'.$CrLf;
  1801. $XML_CREDITOR .= ' </CdtTrfTxInf>'.$CrLf;
  1802. return $XML_CREDITOR;
  1803. }
  1804. }
  1805. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  1806. /**
  1807. * Write sender of request (me).
  1808. *
  1809. * @param string $type 'direct-debit' or 'bank-transfer'
  1810. * @return void
  1811. * @see EnregEmetteurSEPA()
  1812. */
  1813. public function EnregEmetteur($type = 'direct-debit')
  1814. {
  1815. // phpcs:enable
  1816. fputs($this->file, "03");
  1817. fputs($this->file, "08"); // Prelevement ordinaire
  1818. fputs($this->file, " "); // Zone Reservee B2
  1819. fputs($this->file, $this->emetteur_ics); // ICS
  1820. // Date d'echeance C1
  1821. fputs($this->file, " ");
  1822. fputs($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
  1823. fputs($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
  1824. // Raison Sociale C2
  1825. fputs($this->file, substr($this->raison_sociale." ", 0, 24));
  1826. // Reference de la remise creancier D1 sur 7 caracteres
  1827. fputs($this->file, substr($this->reference_remise." ", 0, 7));
  1828. // Zone Reservee D1-2
  1829. fputs($this->file, substr(" ", 0, 17));
  1830. // Zone Reservee D2
  1831. fputs($this->file, substr(" ", 0, 2));
  1832. fputs($this->file, "E");
  1833. fputs($this->file, substr(" ", 0, 5));
  1834. // Code Guichet D3
  1835. fputs($this->file, $this->emetteur_code_guichet);
  1836. // Numero de compte D4
  1837. fputs($this->file, substr("000000000000000".$this->emetteur_numero_compte, -11));
  1838. // Zone Reservee E
  1839. fputs($this->file, substr(" ", 0, 16));
  1840. // Zone Reservee F
  1841. fputs($this->file, substr(" ", 0, 31));
  1842. // Code etablissement
  1843. fputs($this->file, $this->emetteur_code_banque);
  1844. // Zone Reservee G
  1845. fputs($this->file, substr(" ", 0, 5));
  1846. fputs($this->file, "\n");
  1847. }
  1848. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  1849. /**
  1850. * Write sender of request (me).
  1851. * Note: The tag PmtInf is opened here but closed into caller
  1852. *
  1853. * @param Conf $configuration conf
  1854. * @param int $ladate Date
  1855. * @param int $nombre 0 or 1
  1856. * @param float $total Total
  1857. * @param string $CrLf End of line character
  1858. * @param string $format FRST or RCUR or ALL
  1859. * @param string $type 'direct-debit' or 'bank-transfer'
  1860. * @param int $fk_bank_account Bank account ID the receipt is generated for. Will use the ID into the setup of module Direct Debit or Credit Transfer if 0.
  1861. * @return string String with SEPA Sender
  1862. * @see EnregEmetteur()
  1863. */
  1864. public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit', $fk_bank_account = 0)
  1865. {
  1866. // phpcs:enable
  1867. // SEPA INITIALISATION
  1868. global $conf;
  1869. // Clean parameters
  1870. $dateTime_YMD = dol_print_date($ladate, '%Y%m%d');
  1871. $dateTime_ETAD = dol_print_date($ladate, '%Y-%m-%d');
  1872. $dateTime_YMDHMS = dol_print_date($ladate, '%Y-%m-%dT%H:%M:%S');
  1873. // Clean params
  1874. if (empty($fk_bank_account)) {
  1875. $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
  1876. }
  1877. // Get data of bank account
  1878. $account = new Account($this->db);
  1879. if ($account->fetch($fk_bank_account) > 0) {
  1880. $this->emetteur_code_banque = $account->code_banque;
  1881. $this->emetteur_code_guichet = $account->code_guichet;
  1882. $this->emetteur_numero_compte = $account->number;
  1883. $this->emetteur_number_key = $account->cle_rib;
  1884. $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
  1885. $this->emetteur_iban = $account->iban;
  1886. $this->emetteur_bic = $account->bic;
  1887. $this->emetteur_ics = ($type == 'bank-transfer' ? $account->ics_transfer : $account->ics); // Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
  1888. $this->raison_sociale = $account->proprio;
  1889. }
  1890. // Get pending payments
  1891. $sql = "SELECT rowid, ref";
  1892. $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as pb";
  1893. $sql .= " WHERE pb.rowid = ".((int) $this->id);
  1894. $resql = $this->db->query($sql);
  1895. if ($resql) {
  1896. $obj = $this->db->fetch_object($resql);
  1897. $country = explode(':', $configuration->global->MAIN_INFO_SOCIETE_COUNTRY);
  1898. $IdBon = sprintf("%05d", $obj->rowid);
  1899. $RefBon = $obj->ref;
  1900. if ($type != 'bank-transfer') {
  1901. // SEPA Paiement Information of my company for Direct Debit
  1902. $XML_SEPA_INFO = '';
  1903. $XML_SEPA_INFO .= ' <PmtInf>'.$CrLf;
  1904. $XML_SEPA_INFO .= ' <PmtInfId>'.('DD/'.$dateTime_YMD.'/ID'.$IdBon.'-'.$RefBon).'</PmtInfId>'.$CrLf;
  1905. $XML_SEPA_INFO .= ' <PmtMtd>DD</PmtMtd>'.$CrLf;
  1906. $XML_SEPA_INFO .= ' <NbOfTxs>'.$nombre.'</NbOfTxs>'.$CrLf;
  1907. $XML_SEPA_INFO .= ' <CtrlSum>'.$total.'</CtrlSum>'.$CrLf;
  1908. $XML_SEPA_INFO .= ' <PmtTpInf>'.$CrLf;
  1909. $XML_SEPA_INFO .= ' <SvcLvl>'.$CrLf;
  1910. $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>'.$CrLf;
  1911. $XML_SEPA_INFO .= ' </SvcLvl>'.$CrLf;
  1912. $XML_SEPA_INFO .= ' <LclInstrm>'.$CrLf;
  1913. $XML_SEPA_INFO .= ' <Cd>CORE</Cd>'.$CrLf;
  1914. $XML_SEPA_INFO .= ' </LclInstrm>'.$CrLf;
  1915. $XML_SEPA_INFO .= ' <SeqTp>'.$format.'</SeqTp>'.$CrLf;
  1916. $XML_SEPA_INFO .= ' </PmtTpInf>'.$CrLf;
  1917. $XML_SEPA_INFO .= ' <ReqdColltnDt>'.$dateTime_ETAD.'</ReqdColltnDt>'.$CrLf;
  1918. $XML_SEPA_INFO .= ' <Cdtr>'.$CrLf;
  1919. $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
  1920. $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
  1921. $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
  1922. $addressline1 = strtr($configuration->global->MAIN_INFO_SOCIETE_ADDRESS, array(CHR(13) => ", ", CHR(10) => ""));
  1923. $addressline2 = strtr($configuration->global->MAIN_INFO_SOCIETE_ZIP.(($configuration->global->MAIN_INFO_SOCIETE_ZIP || ' '.$configuration->global->MAIN_INFO_SOCIETE_TOWN) ? ' ' : '').$configuration->global->MAIN_INFO_SOCIETE_TOWN, array(CHR(13) => ", ", CHR(10) => ""));
  1924. if ($addressline1) {
  1925. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1926. }
  1927. if ($addressline2) {
  1928. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1929. }
  1930. $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
  1931. $XML_SEPA_INFO .= ' </Cdtr>'.$CrLf;
  1932. $XML_SEPA_INFO .= ' <CdtrAcct>'.$CrLf;
  1933. $XML_SEPA_INFO .= ' <Id>'.$CrLf;
  1934. $XML_SEPA_INFO .= ' <IBAN>'.preg_replace('/\s/', '', $this->emetteur_iban).'</IBAN>'.$CrLf;
  1935. $XML_SEPA_INFO .= ' </Id>'.$CrLf;
  1936. $XML_SEPA_INFO .= ' </CdtrAcct>'.$CrLf;
  1937. $XML_SEPA_INFO .= ' <CdtrAgt>'.$CrLf;
  1938. $XML_SEPA_INFO .= ' <FinInstnId>'.$CrLf;
  1939. $XML_SEPA_INFO .= ' <BIC>'.$this->emetteur_bic.'</BIC>'.$CrLf;
  1940. $XML_SEPA_INFO .= ' </FinInstnId>'.$CrLf;
  1941. $XML_SEPA_INFO .= ' </CdtrAgt>'.$CrLf;
  1942. /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
  1943. $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
  1944. $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
  1945. $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
  1946. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ADDRESS), ' ')).'</AdrLine>'.$CrLf;
  1947. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ZIP.' '.$conf->global->MAIN_INFO_SOCIETE_TOWN), ' ')).'</AdrLine>'.$CrLf;
  1948. $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
  1949. $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
  1950. $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf; // Field "Responsible of fees". Must be SLEV
  1951. $XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
  1952. $XML_SEPA_INFO .= ' <Id>'.$CrLf;
  1953. $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
  1954. $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
  1955. $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
  1956. $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
  1957. $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
  1958. $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
  1959. $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
  1960. $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
  1961. $XML_SEPA_INFO .= ' </Id>'.$CrLf;
  1962. $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;
  1963. } else {
  1964. // SEPA Paiement Information of my company for Credit Transfer
  1965. $XML_SEPA_INFO = '';
  1966. $XML_SEPA_INFO .= ' <PmtInf>'.$CrLf;
  1967. $XML_SEPA_INFO .= ' <PmtInfId>'.('TRF/'.$dateTime_YMD.'/ID'.$IdBon.'-'.$RefBon).'</PmtInfId>'.$CrLf;
  1968. $XML_SEPA_INFO .= ' <PmtMtd>TRF</PmtMtd>'.$CrLf;
  1969. //$XML_SEPA_INFO .= ' <BtchBookg>False</BtchBookg>'.$CrLf;
  1970. $XML_SEPA_INFO .= ' <NbOfTxs>'.$nombre.'</NbOfTxs>'.$CrLf;
  1971. $XML_SEPA_INFO .= ' <CtrlSum>'.$total.'</CtrlSum>'.$CrLf;
  1972. if (!empty($this->sepa_xml_pti_in_ctti) && !empty($format)) { // @TODO Using $format (FRST ou RCUR) in a section for a Credit Transfer looks strange.
  1973. $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
  1974. $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
  1975. $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
  1976. $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
  1977. $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
  1978. $XML_SEPA_INFO .= ' <Cd>CORE</Cd>' . $CrLf;
  1979. $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
  1980. $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
  1981. $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
  1982. }
  1983. $XML_SEPA_INFO .= ' <ReqdExctnDt>'.dol_print_date($dateTime_ETAD, 'dayrfc').'</ReqdExctnDt>'.$CrLf;
  1984. $XML_SEPA_INFO .= ' <Dbtr>'.$CrLf;
  1985. $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
  1986. $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
  1987. $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
  1988. $addressline1 = strtr($configuration->global->MAIN_INFO_SOCIETE_ADDRESS, array(CHR(13) => ", ", CHR(10) => ""));
  1989. $addressline2 = strtr($configuration->global->MAIN_INFO_SOCIETE_ZIP.(($configuration->global->MAIN_INFO_SOCIETE_ZIP || ' '.$configuration->global->MAIN_INFO_SOCIETE_TOWN) ? ' ' : '').$configuration->global->MAIN_INFO_SOCIETE_TOWN, array(CHR(13) => ", ", CHR(10) => ""));
  1990. if ($addressline1) {
  1991. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1992. }
  1993. if ($addressline2) {
  1994. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
  1995. }
  1996. $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
  1997. $XML_SEPA_INFO .= ' </Dbtr>'.$CrLf;
  1998. $XML_SEPA_INFO .= ' <DbtrAcct>'.$CrLf;
  1999. $XML_SEPA_INFO .= ' <Id>'.$CrLf;
  2000. $XML_SEPA_INFO .= ' <IBAN>'.preg_replace('/\s/', '', $this->emetteur_iban).'</IBAN>'.$CrLf;
  2001. $XML_SEPA_INFO .= ' </Id>'.$CrLf;
  2002. $XML_SEPA_INFO .= ' </DbtrAcct>'.$CrLf;
  2003. $XML_SEPA_INFO .= ' <DbtrAgt>'.$CrLf;
  2004. $XML_SEPA_INFO .= ' <FinInstnId>'.$CrLf;
  2005. $XML_SEPA_INFO .= ' <BIC>'.$this->emetteur_bic.'</BIC>'.$CrLf;
  2006. $XML_SEPA_INFO .= ' </FinInstnId>'.$CrLf;
  2007. $XML_SEPA_INFO .= ' </DbtrAgt>'.$CrLf;
  2008. /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
  2009. $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
  2010. $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
  2011. $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
  2012. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ADDRESS), ' ')).'</AdrLine>'.$CrLf;
  2013. $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ZIP.' '.$conf->global->MAIN_INFO_SOCIETE_TOWN), ' ')).'</AdrLine>'.$CrLf;
  2014. $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
  2015. $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
  2016. $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf; // Field "Responsible of fees". Must be SLEV
  2017. /*$XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
  2018. $XML_SEPA_INFO .= ' <Id>'.$CrLf;
  2019. $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
  2020. $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
  2021. $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
  2022. $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
  2023. $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
  2024. $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
  2025. $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
  2026. $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
  2027. $XML_SEPA_INFO .= ' </Id>'.$CrLf;
  2028. $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;*/
  2029. }
  2030. } else {
  2031. fputs($this->file, 'INCORRECT EMETTEUR '.$this->raison_sociale.$CrLf);
  2032. $XML_SEPA_INFO = '';
  2033. }
  2034. return $XML_SEPA_INFO;
  2035. }
  2036. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  2037. /**
  2038. * Write end
  2039. *
  2040. * @param int $total total amount
  2041. * @return void
  2042. */
  2043. public function EnregTotal($total)
  2044. {
  2045. // phpcs:enable
  2046. fputs($this->file, "08");
  2047. fputs($this->file, "08"); // Prelevement ordinaire
  2048. fputs($this->file, " "); // Zone Reservee B2
  2049. fputs($this->file, $this->emetteur_ics); // ICS
  2050. // Reserve C1
  2051. fputs($this->file, substr(" ", 0, 12));
  2052. // Raison Sociale C2
  2053. fputs($this->file, substr(" ", 0, 24));
  2054. // D1
  2055. fputs($this->file, substr(" ", 0, 24));
  2056. // Zone Reservee D2
  2057. fputs($this->file, substr(" ", 0, 8));
  2058. // Code Guichet D3
  2059. fputs($this->file, substr(" ", 0, 5));
  2060. // Numero de compte D4
  2061. fputs($this->file, substr(" ", 0, 11));
  2062. // Zone E Montant
  2063. $montant = ($total * 100);
  2064. fputs($this->file, substr("000000000000000".$montant, -16));
  2065. // Zone Reservee F
  2066. fputs($this->file, substr(" ", 0, 31));
  2067. // Code etablissement
  2068. fputs($this->file, substr(" ", 0, 5));
  2069. // Zone Reservee F
  2070. fputs($this->file, substr(" ", 0, 5));
  2071. fputs($this->file, "\n");
  2072. }
  2073. /**
  2074. * Return status label of object
  2075. *
  2076. * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
  2077. * @return string Label
  2078. */
  2079. public function getLibStatut($mode = 0)
  2080. {
  2081. return $this->LibStatut($this->statut, $mode);
  2082. }
  2083. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  2084. /**
  2085. * Return status label for a status
  2086. *
  2087. * @param int $status Id status
  2088. * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
  2089. * @return string Label
  2090. */
  2091. public function LibStatut($status, $mode = 0)
  2092. {
  2093. // phpcs:enable
  2094. if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
  2095. global $langs;
  2096. //$langs->load("mymodule");
  2097. $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
  2098. $this->labelStatus[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
  2099. $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
  2100. $this->labelStatusShort[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
  2101. if ($this->type == 'bank-transfer') {
  2102. $this->labelStatus[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
  2103. $this->labelStatusShort[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
  2104. } else {
  2105. $this->labelStatus[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
  2106. $this->labelStatusShort[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
  2107. }
  2108. }
  2109. $statusType = 'status1';
  2110. if ($status == self::STATUS_TRANSFERED) {
  2111. $statusType = 'status3';
  2112. }
  2113. if ($status == self::STATUS_CREDITED || $status == self::STATUS_DEBITED) {
  2114. $statusType = 'status6';
  2115. }
  2116. return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
  2117. }
  2118. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  2119. /**
  2120. * Load indicators for dashboard (this->nbtodo and this->nbtodolate)
  2121. *
  2122. * @param User $user Objet user
  2123. * @param string $mode Mode 'direct_debit' or 'credit_transfer'
  2124. * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK
  2125. */
  2126. public function load_board($user, $mode)
  2127. {
  2128. // phpcs:enable
  2129. global $conf, $langs;
  2130. if ($user->socid) {
  2131. return -1; // protection pour eviter appel par utilisateur externe
  2132. }
  2133. /*
  2134. if ($mode == 'direct_debit') {
  2135. $sql = "SELECT b.rowid, f.datedue as datefin";
  2136. $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
  2137. $sql .= " WHERE f.entity IN (".getEntity('facture').")";
  2138. $sql .= " AND f.total_ttc > 0";
  2139. } else {
  2140. $sql = "SELECT b.rowid, f.datedue as datefin";
  2141. $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
  2142. $sql .= " WHERE f.entity IN (".getEntity('facture_fourn').")";
  2143. $sql .= " AND f.total_ttc > 0";
  2144. }
  2145. $resql = $this->db->query($sql);
  2146. if ($resql) {
  2147. $langs->load("banks");
  2148. $now = dol_now();
  2149. $response = new WorkboardResponse();
  2150. if ($mode == 'direct_debit') {
  2151. $response->warning_delay = $conf->prelevement->warning_delay / 60 / 60 / 24;
  2152. $response->label = $langs->trans("PendingDirectDebitToComplete");
  2153. $response->labelShort = $langs->trans("PendingDirectDebitToCompleteShort");
  2154. $response->url = DOL_URL_ROOT.'/compta/prelevement/index.php?leftmenu=checks&mainmenu=bank';
  2155. } else {
  2156. $response->warning_delay = $conf->paymentbybanktransfer->warning_delay / 60 / 60 / 24;
  2157. $response->label = $langs->trans("PendingCreditTransferToComplete");
  2158. $response->labelShort = $langs->trans("PendingCreditTransferToCompleteShort");
  2159. $response->url = DOL_URL_ROOT.'/compta/paymentbybanktransfer/index.php?leftmenu=checks&mainmenu=bank';
  2160. }
  2161. $response->img = img_object('', "payment");
  2162. while ($obj = $this->db->fetch_object($resql)) {
  2163. $response->nbtodo++;
  2164. if ($this->db->jdate($obj->datefin) < ($now - $conf->withdraw->warning_delay)) {
  2165. $response->nbtodolate++;
  2166. }
  2167. }
  2168. $response->nbtodo = 0;
  2169. $response->nbtodolate = 0;
  2170. // Return workboard only if quantity is not 0
  2171. if ($response->nbtodo) {
  2172. return $response;
  2173. } else {
  2174. return 0;
  2175. }
  2176. } else {
  2177. dol_print_error($this->db);
  2178. $this->error = $this->db->error();
  2179. return -1;
  2180. }
  2181. */
  2182. return 0;
  2183. }
  2184. /**
  2185. * Return clicable link of object (with eventually picto)
  2186. *
  2187. * @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
  2188. * @param array $arraydata Array of data
  2189. * @return string HTML Code for Kanban thumb.
  2190. */
  2191. public function getKanbanView($option = '', $arraydata = null)
  2192. {
  2193. global $langs;
  2194. $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
  2195. $return = '<div class="box-flex-item box-flex-grow-zero">';
  2196. $return .= '<div class="info-box info-box-sm">';
  2197. $return .= '<span class="info-box-icon bg-infobox-action">';
  2198. $return .= img_picto('', $this->picto);
  2199. $return .= '</span>';
  2200. $return .= '<div class="info-box-content">';
  2201. $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
  2202. $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
  2203. if (property_exists($this, 'date_echeance')) {
  2204. $return .= '<br><span class="opacitymedium">'.$langs->trans("Date").'</span> : <span class="info-box-label">'.dol_print_date($this->db->jdate($this->date_echeance), 'day').'</span>';
  2205. }
  2206. if (property_exists($this, 'total')) {
  2207. $return .= '<br><span class="opacitymedium">'.$langs->trans("Amount").'</span> : <span class="amount">'.price($this->total).'</span>';
  2208. }
  2209. if (method_exists($this, 'LibStatut')) {
  2210. $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3).'</div>';
  2211. }
  2212. $return .= '</div>';
  2213. $return .= '</div>';
  2214. $return .= '</div>';
  2215. return $return;
  2216. }
  2217. }