123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571 |
- <?php
- /* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
- * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
- * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
- * Copyright (C) 2010-2014 Laurent Destailleur <eldy@users.sourceforge.net>
- * Copyright (C) 2014-2016 Ferran Marcet <fmarcet@2byte.es>
- * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
- * Copyright (C) 2019 JC Prieto <jcprieto@virtual20.com><prietojc@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- /**
- * \file htdocs/compta/prelevement/class/bonprelevement.class.php
- * \ingroup prelevement
- * \brief File of withdrawal receipts class
- */
- require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
- require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
- require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
- require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
- require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
- require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
- require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
- /**
- * Class to manage withdrawal receipts
- */
- class BonPrelevement extends CommonObject
- {
- /**
- * @var string ID to identify managed object
- */
- public $element = 'widthdraw';
- /**
- * @var string Name of table without prefix where object is stored
- */
- public $table_element = 'prelevement_bons';
- /**
- * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
- */
- public $picto = 'payment';
- public $date_echeance;
- public $raison_sociale;
- public $reference_remise;
- public $emetteur_code_guichet;
- public $emetteur_numero_compte;
- public $emetteur_code_banque;
- public $emetteur_number_key;
- public $sepa_xml_pti_in_ctti;
- public $emetteur_iban;
- public $emetteur_bic;
- public $emetteur_ics;
- public $user_trans;
- public $user_credit;
- public $total;
- public $fetched;
- public $labelStatus = array();
- public $factures = array();
- public $invoice_in_error = array();
- public $thirdparty_in_error = array();
- /**
- * @var resource Handler of the file for direct debit or credit transfer order
- */
- public $file;
- const STATUS_DRAFT = 0;
- const STATUS_TRANSFERED = 1;
- const STATUS_CREDITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
- const STATUS_DEBITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
- /**
- * 'type' field format:
- * 'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',
- * 'select' (list of values are in 'options'),
- * 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:Sortfield]]]]',
- * 'chkbxlst:...',
- * 'varchar(x)',
- * 'text', 'text:none', 'html',
- * 'double(24,8)', 'real', 'price',
- * 'date', 'datetime', 'timestamp', 'duration',
- * 'boolean', 'checkbox', 'radio', 'array',
- * 'mail', 'phone', 'url', 'password', 'ip'
- * 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)"
- * 'label' the translation key.
- * 'picto' is code of a picto to show before value in forms
- * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM' or 'isModEnabled("multicurrency")' ...)
- * 'position' is the sort order of field.
- * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
- * '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)
- * 'noteditable' says if field is not editable (1 or 0)
- * 'alwayseditable' says if field can be modified also when status is not draft ('1' or '0')
- * '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.
- * 'index' if we want an index in database.
- * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
- * 'searchall' is 1 if we want to search in this field when making a search from the quick search button.
- * '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)
- * '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'
- * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
- * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record
- * '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.
- * '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'
- * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
- * 'comment' is not used. You can store here any text of your choice. It is not used by application.
- * 'validate' is 1 if need to validate with $this->validateField()
- * 'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value)
- *
- * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
- */
- // BEGIN MODULEBUILDER PROPERTIES
- /**
- * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
- */
- public $fields=array(
- 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>0,),
- 'ref' => array('type'=>'varchar(12)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>15, 'notnull'=>0, 'visible'=>-1, 'csslist'=>'tdoverflowmax150', 'showoncombobox'=>'1',),
- 'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>25, 'notnull'=>0, 'visible'=>-1,),
- 'amount' => array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>'1', 'position'=>30, 'notnull'=>0, 'visible'=>-1,),
- 'statut' => array('type'=>'smallint(6)', 'label'=>'Statut', 'enabled'=>'1', 'position'=>500, 'notnull'=>0, 'visible'=>-1, 'arrayofkeyval'=>array(0=>'Wait', 1=>'Transfered', 2=>'Credited')),
- 'credite' => array('type'=>'smallint(6)', 'label'=>'Credite', 'enabled'=>'1', 'position'=>40, 'notnull'=>0, 'visible'=>-1,),
- 'note' => array('type'=>'text', 'label'=>'Note', 'enabled'=>'1', 'position'=>45, 'notnull'=>0, 'visible'=>-1,),
- 'date_trans' => array('type'=>'datetime', 'label'=>'Datetrans', 'enabled'=>'1', 'position'=>50, 'notnull'=>0, 'visible'=>-1,),
- 'method_trans' => array('type'=>'smallint(6)', 'label'=>'Methodtrans', 'enabled'=>'1', 'position'=>55, 'notnull'=>0, 'visible'=>-1,),
- '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',),
- 'date_credit' => array('type'=>'datetime', 'label'=>'Datecredit', 'enabled'=>'1', 'position'=>65, 'notnull'=>0, 'visible'=>-1,),
- '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',),
- 'type' => array('type'=>'varchar(16)', 'label'=>'Type', 'enabled'=>'1', 'position'=>75, 'notnull'=>0, 'visible'=>-1,),
- 'fk_bank_account' => array('type'=>'integer', 'label'=>'Fkbankaccount', 'enabled'=>'1', 'position'=>80, 'notnull'=>0, 'visible'=>-1, 'css'=>'maxwidth500 widthcentpercentminusxx',),
- );
- public $rowid;
- public $ref;
- public $datec;
- public $amount;
- public $statut;
- public $credite;
- public $note;
- public $date_trans;
- public $method_trans;
- public $fk_user_trans;
- public $date_credit;
- public $fk_user_credit;
- public $type;
- public $fk_bank_account;
- // END MODULEBUILDER PROPERTIES
- /**
- * Constructor
- *
- * @param DoliDB $db Database handler
- */
- public function __construct($db)
- {
- global $conf, $langs;
- $this->db = $db;
- $this->filename = '';
- $this->date_echeance = dol_now();
- $this->raison_sociale = "";
- $this->reference_remise = "";
- $this->emetteur_code_guichet = "";
- $this->emetteur_numero_compte = "";
- $this->emetteur_code_banque = "";
- $this->emetteur_number_key = "";
- $this->sepa_xml_pti_in_ctti = false;
- $this->emetteur_iban = "";
- $this->emetteur_bic = "";
- $this->emetteur_ics = "";
- $this->factures = array();
- $this->methodes_trans = array(0 => 'Internet', 2 => 'Email', 3 => 'Api');
- $this->fetched = 0;
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Add invoice to withdrawal
- *
- * @param int $invoice_id id invoice to add
- * @param int $client_id id invoice customer
- * @param string $client_nom customer name
- * @param int $amount amount of invoice
- * @param string $code_banque code of bank withdrawal
- * @param string $code_guichet code of bank's office
- * @param string $number bank account number
- * @param string $number_key number key of account number
- * @param string $type 'debit-order' or 'bank-transfer'
- * @return int >0 if OK, <0 if KO
- */
- public function AddFacture($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type = 'debit-order')
- {
- // phpcs:enable
- $result = 0;
- $line_id = 0;
- // Add lines
- $result = $this->addline($line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key);
- if ($result == 0) {
- if ($line_id > 0) {
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement (";
- if ($type != 'bank-transfer') {
- $sql .= "fk_facture";
- } else {
- $sql .= "fk_facture_fourn";
- }
- $sql .= ",fk_prelevement_lignes";
- $sql .= ") VALUES (";
- $sql .= ((int) $invoice_id);
- $sql .= ", ".((int) $line_id);
- $sql .= ")";
- if ($this->db->query($sql)) {
- $result = 0;
- } else {
- $result = -1;
- $this->errors[] = get_class($this)."::AddFacture ".$this->db->lasterror;
- dol_syslog(get_class($this)."::AddFacture Error $result");
- }
- } else {
- $result = -2;
- $this->errors[] = get_class($this)."::AddFacture linedid Empty";
- dol_syslog(get_class($this)."::AddFacture Error $result");
- }
- } else {
- $result = -3;
- dol_syslog(get_class($this)."::AddFacture Error $result");
- }
- return $result;
- }
- /**
- * Add line to withdrawal
- *
- * @param int $line_id id line to add
- * @param int $client_id id invoice customer
- * @param string $client_nom customer name
- * @param int $amount amount of invoice
- * @param string $code_banque code of bank withdrawal
- * @param string $code_guichet code of bank's office
- * @param string $number bank account number
- * @param string $number_key number key of account number
- * @return int >0 if OK, <0 if KO
- */
- public function addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key)
- {
- $result = -1;
- $concat = 0;
- if ($concat == 1) {
- /*
- * We aggregate the lines
- */
- $sql = "SELECT rowid";
- $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_lignes";
- $sql .= " WHERE fk_prelevement_bons = ".((int) $this->id);
- $sql .= " AND fk_soc =".((int) $client_id);
- $sql .= " AND code_banque = '".$this->db->escape($code_banque)."'";
- $sql .= " AND code_guichet = '".$this->db->escape($code_guichet)."'";
- $sql .= " AND number = '".$this->db->escape($number)."'";
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- } else {
- $result = -1;
- }
- } else {
- /*
- * No aggregate
- */
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_lignes (";
- $sql .= "fk_prelevement_bons";
- $sql .= ", fk_soc";
- $sql .= ", client_nom";
- $sql .= ", amount";
- $sql .= ", code_banque";
- $sql .= ", code_guichet";
- $sql .= ", number";
- $sql .= ", cle_rib";
- $sql .= ") VALUES (";
- $sql .= $this->id;
- $sql .= ", ".((int) $client_id);
- $sql .= ", '".$this->db->escape($client_nom)."'";
- $sql .= ", ".((float) price2num($amount));
- $sql .= ", '".$this->db->escape($code_banque)."'";
- $sql .= ", '".$this->db->escape($code_guichet)."'";
- $sql .= ", '".$this->db->escape($number)."'";
- $sql .= ", '".$this->db->escape($number_key)."'";
- $sql .= ")";
- if ($this->db->query($sql)) {
- $line_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevement_lignes");
- $result = 0;
- } else {
- $this->errors[] = get_class($this)."::addline Error -2 ".$this->db->lasterror;
- dol_syslog(get_class($this)."::addline Error -2");
- $result = -2;
- }
- }
- return $result;
- }
- /**
- * Return error string
- *
- * @param int $error Id of error
- * @return string Error string
- */
- public function getErrorString($error)
- {
- global $langs;
- $errors = array();
- $errors[1027] = $langs->trans("DateInvalid");
- return $errors[abs($error)];
- }
- /**
- * Get object and lines from database
- *
- * @param int $rowid Id of object to load
- * @param string $ref Ref of direct debit
- * @return int >0 if OK, <0 if KO
- */
- public function fetch($rowid, $ref = '')
- {
- $sql = "SELECT p.rowid, p.ref, p.amount, p.note";
- $sql .= ", p.datec as dc";
- $sql .= ", p.date_trans as date_trans";
- $sql .= ", p.method_trans, p.fk_user_trans";
- $sql .= ", p.date_credit as date_credit";
- $sql .= ", p.fk_user_credit";
- $sql .= ", p.type";
- $sql .= ", p.fk_bank_account";
- $sql .= ", p.statut as status";
- $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as p";
- $sql .= " WHERE p.entity IN (".getEntity('invoice').")";
- if ($rowid > 0) {
- $sql .= " AND p.rowid = ".((int) $rowid);
- } else {
- $sql .= " AND p.ref = '".$this->db->escape($ref)."'";
- }
- dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
- $result = $this->db->query($sql);
- if ($result) {
- if ($this->db->num_rows($result)) {
- $obj = $this->db->fetch_object($result);
- $this->id = $obj->rowid;
- $this->ref = $obj->ref;
- $this->amount = $obj->amount;
- $this->note = $obj->note;
- $this->datec = $this->db->jdate($obj->dc);
- $this->date_trans = $this->db->jdate($obj->date_trans);
- $this->method_trans = $obj->method_trans;
- $this->user_trans = $obj->fk_user_trans;
- $this->date_credit = $this->db->jdate($obj->date_credit);
- $this->user_credit = $obj->fk_user_credit;
- $this->type = $obj->type;
- $this->fk_bank_account = $obj->fk_bank_account;
- $this->status = $obj->status;
- $this->statut = $obj->status; // For backward compatibility
- $this->fetched = 1;
- return 1;
- } else {
- dol_syslog(get_class($this)."::Fetch Erreur aucune ligne retournee");
- return -1;
- }
- } else {
- return -2;
- }
- }
- /**
- * Update object into database
- *
- * @param User $user User that modifies
- * @param bool $notrigger false=launch triggers after, true=disable triggers
- * @return int <0 if KO, >0 if OK
- */
- public function update(User $user, $notrigger = false)
- {
- return $this->updateCommon($user, $notrigger);
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Set direct debit or credit transfer order to "paid" status.
- * Then create the payment for each invoice of the prelemevement_bon.
- *
- * @param User $user Id of user
- * @param int $date date of action
- * @return int >0 if OK, <0 if KO
- */
- public function set_infocredit($user, $date)
- {
- // phpcs:enable
- global $conf, $langs;
- $error = 0;
- if ($this->fetched == 1) {
- if ($date < $this->date_trans) {
- $langs->load("errors");
- $this->error = $langs->trans('ErrorDateOfMovementLowerThanDateOfFileTransmission');
- dol_syslog("bon-prelevment::set_infocredit 1027 ".$this->error);
- return -1027;
- }
- $this->db->begin();
- $sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_bons";
- $sql .= " SET fk_user_credit = ".$user->id;
- $sql .= ", statut = ".self::STATUS_CREDITED;
- $sql .= ", date_credit = '".$this->db->idate($date)."'";
- $sql .= " WHERE rowid=".((int) $this->id);
- $sql .= " AND entity = ".((int) $conf->entity);
- $sql .= " AND statut = ".self::STATUS_TRANSFERED;
- $resql = $this->db->query($sql);
- if ($resql) {
- $langs->load('withdrawals');
- $subject = $langs->trans("InfoCreditSubject", $this->ref);
- $message = $langs->trans("InfoCreditMessage", $this->ref, dol_print_date($date, 'dayhour'));
- // Add payment of withdrawal into bank
- $fk_bank_account = $this->fk_bank_account;
- if (empty($fk_bank_account)) {
- $fk_bank_account = ($this->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
- }
- $facs = array();
- $amounts = array();
- $amountsperthirdparty = array();
- $facs = $this->getListInvoices(1);
- // Loop on each invoice. $facs=array(0=>id, 1=>amount requested)
- $num = count($facs);
- for ($i = 0; $i < $num; $i++) {
- if ($this->type == 'bank-transfer') {
- $fac = new FactureFournisseur($this->db);
- } else {
- $fac = new Facture($this->db);
- }
- $result = $fac->fetch($facs[$i][0]);
- $amounts[$fac->id] = $facs[$i][1];
- $amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];
- $totalpaid = $fac->getSommePaiement();
- $totalcreditnotes = $fac->getSumCreditNotesUsed();
- $totaldeposits = $fac->getSumDepositsUsed();
- $alreadypayed = $totalpaid + $totalcreditnotes + $totaldeposits;
- // @TODO Move this after creation of payment
- if (price2num($alreadypayed + $facs[$i][1], 'MT') == $fac->total_ttc) {
- $result = $fac->setPaid($user);
- if ($result < 0) {
- $this->error = $fac->error;
- $this->errors = $fac->errors;
- }
- }
- }
- //var_dump($amountsperthirdparty);exit;
- // Make one payment per customer
- foreach ($amountsperthirdparty as $thirdpartyid => $cursoramounts) {
- if ($this->type == 'bank-transfer') {
- $paiement = new PaiementFourn($this->db);
- } else {
- $paiement = new Paiement($this->db);
- }
- $paiement->datepaye = $date;
- $paiement->amounts = $cursoramounts; // Array with detail of dispatching of payments for each invoice
- if ($this->type == 'bank-transfer') {
- $paiement->paiementid = 2;
- $paiement->paiementcode = 'VIR';
- } else {
- $paiement->paiementid = 3;
- $paiement->paiementcode = 'PRE';
- }
- $paiement->num_payment = $this->ref; // Set ref of direct debit note
- $paiement->id_prelevement = $this->id;
- $paiement_id = $paiement->create($user); // This use ->paiementid, that is ID of payment mode
- if ($paiement_id < 0) {
- $error++;
- $this->error = $paiement->error;
- $this->errors = $paiement->errors;
- dol_syslog(get_class($this)."::set_infocredit AddPayment Error ".$this->error);
- } else {
- if ($this->type == 'bank-transfer') {
- $modeforaddpayment = 'payment_supplier';
- } else {
- $modeforaddpayment = 'payment';
- }
- $result = $paiement->addPaymentToBank($user, $modeforaddpayment, '(WithdrawalPayment)', $fk_bank_account, '', '');
- if ($result < 0) {
- $error++;
- $this->error = $paiement->error;
- $this->errors = $paiement->errors;
- dol_syslog(get_class($this)."::set_infocredit AddPaymentToBank Error ".$this->error);
- }
- }
- }
- // Update withdrawal line
- // TODO: Translate to ligneprelevement.class.php
- if (!$error) {
- $sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_lignes";
- $sql .= " SET statut = 2";
- $sql .= " WHERE fk_prelevement_bons = ".((int) $this->id);
- if (!$this->db->query($sql)) {
- dol_syslog(get_class($this)."::set_infocredit Update lines Error");
- $error++;
- }
- }
- } else {
- $this->error = $this->db->lasterror();
- dol_syslog(get_class($this)."::set_infocredit Update Bons Error");
- $error++;
- }
- /*
- * End of procedure
- */
- if ($error == 0) {
- $this->date_credit = $date;
- $this->statut = self::STATUS_CREDITED;
- $this->db->commit();
- return 0;
- } else {
- $this->db->rollback();
- return -1;
- }
- } else {
- return -1026;
- }
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Set withdrawal to transmited status
- *
- * @param User $user id of user
- * @param int $date date of action
- * @param string $method method of transmision to bank (0=Internet, 1=Api...)
- * @return int >0 if OK, <0 if KO
- */
- public function set_infotrans($user, $date, $method)
- {
- // phpcs:enable
- global $conf, $langs;
- $error = 0;
- dol_syslog(get_class($this)."::set_infotrans Start", LOG_INFO);
- if ($this->db->begin()) {
- $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_bons ";
- $sql .= " SET fk_user_trans = ".$user->id;
- $sql .= " , date_trans = '".$this->db->idate($date)."'";
- $sql .= " , method_trans = ".((int) $method);
- $sql .= " , statut = ".self::STATUS_TRANSFERED;
- $sql .= " WHERE rowid = ".((int) $this->id);
- $sql .= " AND entity = ".((int) $conf->entity);
- $sql .= " AND statut = 0";
- if ($this->db->query($sql)) {
- $this->method_trans = $method;
- $langs->load('withdrawals');
- $subject = $langs->trans("InfoTransSubject", $this->ref);
- $message = $langs->trans("InfoTransMessage", $this->ref, dolGetFirstLastname($user->firstname, $user->lastname));
- $message .= $langs->trans("InfoTransData", price($this->amount), $this->methodes_trans[$this->method_trans], dol_print_date($date, 'day'));
- // TODO Call trigger to create a notification using notification module
- } else {
- $error++;
- }
- if ($error == 0) {
- $this->date_trans = $date;
- $this->statut = 1;
- $this->user_trans = $user->id;
- $this->db->commit();
- return 0;
- } else {
- $this->db->rollback();
- dol_syslog(get_class($this)."::set_infotrans ROLLBACK", LOG_ERR);
- return -1;
- }
- } else {
- dol_syslog(get_class($this)."::set_infotrans Ouverture transaction SQL impossible", LOG_CRIT);
- return -2;
- }
- }
- /**
- * Get invoice list
- *
- * @param int $amounts If you want to get the amount of the order for each invoice
- * @return array Id of invoices
- */
- private function getListInvoices($amounts = 0)
- {
- global $conf;
- $arr = array();
- /*
- * Returns all invoices presented within same order
- */
- $sql = "SELECT ";
- if ($this->type == 'bank-transfer') {
- $sql .= " pf.fk_facture_fourn";
- } else {
- $sql .= " pf.fk_facture";
- }
- if ($amounts) {
- $sql .= ", SUM(pl.amount)";
- }
- $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as p";
- $sql .= " , ".MAIN_DB_PREFIX."prelevement_lignes as pl";
- $sql .= " , ".MAIN_DB_PREFIX."prelevement as pf";
- $sql .= " WHERE pf.fk_prelevement_lignes = pl.rowid";
- $sql .= " AND pl.fk_prelevement_bons = p.rowid";
- $sql .= " AND p.rowid = ".((int) $this->id);
- $sql .= " AND p.entity = ".((int) $conf->entity);
- if ($amounts) {
- if ($this->type == 'bank-transfer') {
- $sql .= " GROUP BY fk_facture_fourn";
- } else {
- $sql .= " GROUP BY fk_facture";
- }
- }
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- if ($num) {
- $i = 0;
- while ($i < $num) {
- $row = $this->db->fetch_row($resql);
- if (!$amounts) {
- $arr[$i] = $row[0];
- } else {
- $arr[$i] = array(
- $row[0],
- $row[1]
- );
- }
- $i++;
- }
- }
- $this->db->free($resql);
- } else {
- dol_syslog(get_class($this)."::getListInvoices Erreur");
- }
- return $arr;
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Returns amount waiting for direct debit payment or credit transfer payment
- *
- * @param string $mode 'direct-debit' or 'bank-transfer'
- * @return double <O if KO, Total amount
- */
- public function SommeAPrelever($mode = 'direct-debit')
- {
- // phpcs:enable
- global $conf;
- $sql = "SELECT sum(pfd.amount) as nb";
- if ($mode != 'bank-transfer') {
- $sql .= " FROM ".MAIN_DB_PREFIX."facture as f,";
- } else {
- $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f,";
- }
- $sql .= " ".MAIN_DB_PREFIX."prelevement_demande as pfd";
- $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
- if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS)) {
- $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
- }
- if ($mode != 'bank-transfer') {
- $sql .= " AND f.rowid = pfd.fk_facture";
- } else {
- $sql .= " AND f.rowid = pfd.fk_facture_fourn";
- }
- $sql .= " AND f.paye = 0";
- $sql .= " AND pfd.traite = 0";
- $sql .= " AND pfd.ext_payment_id IS NULL";
- $sql .= " AND f.total_ttc > 0";
- $resql = $this->db->query($sql);
- if ($resql) {
- $obj = $this->db->fetch_object($resql);
- $this->db->free($resql);
- return $obj->nb;
- } else {
- $error = 1;
- dol_syslog(get_class($this)."::SommeAPrelever Erreur -1");
- dol_syslog($this->db->error());
- return -1;
- }
- }
- /**
- * Get number of invoices waiting for payment
- *
- * @param string $mode 'direct-debit' or 'bank-transfer'
- * @return int <O if KO, number of invoices if OK
- */
- public function nbOfInvoiceToPay($mode = 'direct-debit')
- {
- return $this->NbFactureAPrelever($mode);
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Get number of invoices to pay
- *
- * @param string $type 'direct-debit' or 'bank-transfer'
- * @return int <O if KO, number of invoices if OK
- */
- public function NbFactureAPrelever($type = 'direct-debit')
- {
- // phpcs:enable
- global $conf;
- $sql = "SELECT count(f.rowid) as nb";
- if ($type == 'bank-transfer') {
- $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
- } else {
- $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
- }
- $sql .= ", ".MAIN_DB_PREFIX."prelevement_demande as pfd";
- $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
- if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS)) {
- $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
- }
- if ($type == 'bank-transfer') {
- $sql .= " AND f.rowid = pfd.fk_facture_fourn";
- } else {
- $sql .= " AND f.rowid = pfd.fk_facture";
- }
- $sql .= " AND pfd.traite = 0";
- $sql .= " AND pfd.ext_payment_id IS NULL";
- $sql .= " AND f.total_ttc > 0";
- dol_syslog(get_class($this)."::NbFactureAPrelever");
- $resql = $this->db->query($sql);
- if ($resql) {
- $obj = $this->db->fetch_object($resql);
- $this->db->free($resql);
- return $obj->nb;
- } else {
- $this->error = get_class($this)."::NbFactureAPrelever Erreur -1 sql=".$this->db->error();
- return -1;
- }
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Create a BAN payment order:
- * - Select waiting requests from prelevement_demande (or use $did if provided)
- * - Check BAN values
- * - Then create a direct debit order or a credit transfer order
- * - Link the order with the prelevement_demande lines
- * TODO delete params banque and agence when not necessary
- *
- * @param int $banque dolibarr mysoc bank
- * @param int $agence dolibarr mysoc bank office (guichet)
- * @param string $mode real=do action, simu=test only
- * @param string $format FRST, RCUR or ALL
- * @param string $executiondate Date to execute the transfer
- * @param int $notrigger Disable triggers
- * @param string $type 'direct-debit' or 'bank-transfer'
- * @param int $did ID of an existing payment request. If $did is defined, no entry
- * @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.
- * @return int <0 if KO, No of invoice included into file if OK
- */
- public function create($banque = 0, $agence = 0, $mode = 'real', $format = 'ALL', $executiondate = '', $notrigger = 0, $type = 'direct-debit', $did = 0, $fk_bank_account = 0)
- {
- // phpcs:enable
- global $conf, $langs, $user;
- dol_syslog(__METHOD__." Bank=".$banque." Office=".$agence." mode=".$mode." format=".$format, LOG_DEBUG);
- require_once DOL_DOCUMENT_ROOT."/compta/facture/class/facture.class.php";
- require_once DOL_DOCUMENT_ROOT."/societe/class/societe.class.php";
- // Check params
- if ($type != 'bank-transfer') {
- if (empty($format)) {
- $this->error = 'ErrorBadParametersForDirectDebitFileCreate';
- return -1;
- }
- }
- // Clean params
- if (empty($fk_bank_account)) {
- $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
- }
- $error = 0;
- $datetimeprev = dol_now('gmt');
- // Choice the date of the execution direct debit
- if (!empty($executiondate)) {
- $datetimeprev = $executiondate;
- }
- $month = dol_print_date($datetimeprev, "%m", 'gmt');
- $year = dol_print_date($datetimeprev, "%Y", 'gmt');
- $this->invoice_in_error = array();
- $this->thirdparty_in_error = array();
- // Read invoices
- $factures = array();
- $factures_prev = array();
- $factures_result = array();
- $factures_prev_id = array();
- $factures_errors = array();
- if (!$error) {
- $sql = "SELECT f.rowid, pfd.rowid as pfdrowid, f.fk_soc";
- $sql .= ", pfd.code_banque, pfd.code_guichet, pfd.number, pfd.cle_rib";
- $sql .= ", pfd.amount";
- $sql .= ", s.nom as name";
- if ($type != 'bank-transfer') {
- $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
- } else {
- $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
- }
- $sql .= ", ".MAIN_DB_PREFIX."societe as s";
- $sql .= ", ".MAIN_DB_PREFIX."prelevement_demande as pfd";
- $sql .= " WHERE f.entity IN (".getEntity('invoice').')';
- if ($type != 'bank-transfer') {
- $sql .= " AND f.rowid = pfd.fk_facture";
- } else {
- $sql .= " AND f.rowid = pfd.fk_facture_fourn";
- }
- $sql .= " AND s.rowid = f.fk_soc";
- $sql .= " AND f.fk_statut = 1"; // Invoice validated
- $sql .= " AND f.paye = 0";
- $sql .= " AND pfd.traite = 0";
- $sql .= " AND f.total_ttc > 0";
- $sql .= " AND pfd.ext_payment_id IS NULL";
- if ($did > 0) {
- $sql .= " AND pfd.rowid = ".((int) $did);
- }
- dol_syslog(__METHOD__." Read invoices,", LOG_DEBUG);
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- $i = 0;
- while ($i < $num) {
- $row = $this->db->fetch_row($resql);
- $factures[$i] = $row; // All fields
- if ($row[7] == 0) {
- $error++;
- dol_syslog(__METHOD__." Read invoices error Found a null invoice", LOG_ERR);
- $this->invoice_in_error[$row[0]] = "Error for invoice id ".$row[0].", found a null amount";
- break;
- }
- $i++;
- }
- $this->db->free($resql);
- dol_syslog(__METHOD__." Read invoices, ".$i." invoices to withdraw", LOG_DEBUG);
- } else {
- $error++;
- dol_syslog(__METHOD__." Read invoices error ".$this->db->error(), LOG_ERR);
- }
- }
- if (!$error) {
- require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
- $soc = new Societe($this->db);
- // Check BAN
- $i = 0;
- dol_syslog(__METHOD__." Check BAN", LOG_DEBUG);
- if (count($factures) > 0) {
- foreach ($factures as $key => $fac) {
- if ($type != 'bank-transfer') {
- $tmpinvoice = new Facture($this->db);
- } else {
- $tmpinvoice = new FactureFournisseur($this->db);
- }
- $resfetch = $tmpinvoice->fetch($fac[0]);
- if ($resfetch >= 0) { // Field 0 of $fac is rowid of invoice
- if ($soc->fetch($tmpinvoice->socid) >= 0) {
- $bac = new CompanyBankAccount($this->db);
- $bac->fetch(0, $soc->id);
- if ($type != 'bank-transfer') {
- if ($format == 'FRST' && $bac->frstrecur != 'FRST') {
- continue;
- }
- if ($format == 'RCUR' && ($bac->frstrecur != 'RCUR' && $bac->frstrecur != 'RECUR')) {
- continue;
- }
- }
- if ($bac->verif() >= 1) {
- $factures_prev[$i] = $fac;
- /* second array necessary for BonPrelevement */
- $factures_prev_id[$i] = $fac[0];
- $i++;
- //dol_syslog(__METHOD__."::RIB is ok", LOG_DEBUG);
- } else {
- dol_syslog(__METHOD__." Check BAN Error on default bank number IBAN/BIC for thirdparty reported by verif() ".$tmpinvoice->socid." ".$soc->name, LOG_WARNING);
- $this->invoice_in_error[$fac[0]] = "Error on default bank number IBAN/BIC for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
- $this->thirdparty_in_error[$soc->id] = "Error on default bank number IBAN/BIC for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
- }
- } else {
- dol_syslog(__METHOD__." Check BAN Failed to read company", LOG_WARNING);
- }
- } else {
- dol_syslog(__METHOD__." Check BAN Failed to read invoice", LOG_WARNING);
- }
- }
- } else {
- dol_syslog(__METHOD__." Check BAN No invoice to process", LOG_WARNING);
- }
- }
- $ok = 0;
- // Withdraw invoices in factures_prev array
- $out = count($factures_prev)." invoices will be included.";
- //print $out."\n";
- dol_syslog($out);
- // Return warning
- /*$i=0;
- foreach ($this->thirdparty_in_error as $key => $val)
- {
- if ($i < 10) setEventMessages($val, null, 'warnings');
- else setEventMessages('More error were discarded...', null, 'warnings');
- $i++;
- }*/
- if (count($factures_prev) > 0) {
- if ($mode == 'real') {
- $ok = 1;
- } else {
- print $langs->trans("ModeWarning"); // "Option for real mode was not set, we stop after this simulation\n";
- }
- }
- if ($ok) {
- /*
- * We are in real mode.
- * We create order and build file into disk
- */
- $this->db->begin();
- $now = dol_now();
- $ref = '';
- /*
- * Process order generation
- */
- if (!$error) {
- $ref = substr($year, -2).$month;
- // Get next free nuber for the ref of bon
- $sql = "SELECT substring(ref from char_length(ref) - 1)"; // To extract "YYMMXX" from "TYYMMXX"
- $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons";
- $sql .= " WHERE ref LIKE '_".$this->db->escape($ref)."%'";
- $sql .= " AND entity = ".((int) $conf->entity);
- $sql .= " ORDER BY ref DESC LIMIT 1";
- dol_syslog(get_class($this)." get next free number", LOG_DEBUG);
- $resql = $this->db->query($sql);
- if ($resql) {
- $row = $this->db->fetch_row($resql);
- // Build the new ref
- $ref = "T".$ref.sprintf("%02d", (intval($row[0]) + 1));
- // $conf->abc->dir_output may be:
- // /home/ldestailleur/git/dolibarr_15.0/documents/abc/
- // or
- // /home/ldestailleur/git/dolibarr_15.0/documents/X/abc with X >= 2 with multicompany.
- if ($type != 'bank-transfer') {
- $dir = $conf->prelevement->dir_output.'/receipts';
- } else {
- $dir = $conf->paymentbybanktransfer->dir_output.'/receipts';
- }
- if (!is_dir($dir)) {
- dol_mkdir($dir);
- }
- if (isModEnabled('multicompany')) {
- $labelentity = $conf->entity;
- $this->filename = $dir.'/'.$ref.'-'.$labelentity.'.xml';
- } else {
- $this->filename = $dir.'/'.$ref.'.xml';
- }
- // Create withdraw order in database
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_bons (";
- $sql .= "ref, entity, datec, type, fk_bank_account";
- $sql .= ") VALUES (";
- $sql .= "'".$this->db->escape($ref)."'";
- $sql .= ", ".((int) $conf->entity);
- $sql .= ", '".$this->db->idate($now)."'";
- $sql .= ", '".($type == 'bank-transfer' ? 'bank-transfer' : 'debit-order')."'";
- $sql .= ", ".((int) $fk_bank_account);
- $sql .= ")";
- $resql = $this->db->query($sql);
- if ($resql) {
- $prev_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevement_bons");
- $this->id = $prev_id;
- $this->ref = $ref;
- } else {
- $error++;
- dol_syslog(__METHOD__." Create withdraw receipt ".$this->db->lasterror(), LOG_ERR);
- }
- } else {
- $error++;
- dol_syslog(__METHOD__." Get last withdraw receipt ".$this->db->lasterror(), LOG_ERR);
- }
- }
- if (!$error) {
- if ($type != 'bank-transfer') {
- $fact = new Facture($this->db);
- } else {
- $fact = new FactureFournisseur($this->db);
- }
- // Add lines for the bon
- if (count($factures_prev) > 0) {
- foreach ($factures_prev as $fac) { // Add a link in database for each invoice
- // Fetch invoice
- $result = $fact->fetch($fac[0]);
- if ($result < 0) {
- $this->error = 'ERRORBONPRELEVEMENT Failed to load invoice with id '.$fac[0];
- break;
- }
- /*
- * Add standing order. This add record into llx_prelevement_lignes and llx_prelevement
- *
- * $fac[0] : invoice_id
- * $fac[1] : ???
- * $fac[2] : third party id
- * $fac[3] : banque
- * $fac[4] : guichet
- * $fac[5] : number
- * $fac[6] : cle rib
- * $fac[7] : amount
- * $fac[8] : client nom
- */
- $ri = $this->AddFacture($fac[0], $fac[2], $fac[8], $fac[7], $fac[3], $fac[4], $fac[5], $fac[6], $type);
- if ($ri <> 0) {
- $error++;
- }
- // Update invoice requests as done
- $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande";
- $sql .= " SET traite = 1";
- $sql .= ", date_traite = '".$this->db->idate($now)."'";
- $sql .= ", fk_prelevement_bons = ".((int) $this->id);
- $sql .= " WHERE rowid = ".((int) $fac[1]);
- $resql = $this->db->query($sql);
- if (!$resql) {
- $error++;
- $this->errors[] = $this->db->lasterror();
- dol_syslog(__METHOD__." Update Error=".$this->db->lasterror(), LOG_ERR);
- }
- }
- }
- }
- if (!$error) {
- /*
- * Create file of type='direct-debit' for direct debit order or type='bank-transfer' for credit transfer into a XML file
- */
- dol_syslog(__METHOD__." Init direct debit or credit transfer file for ".count($factures_prev)." invoices", LOG_DEBUG);
- if (count($factures_prev) > 0) {
- $this->date_echeance = $datetimeprev;
- $this->reference_remise = $ref;
- $account = new Account($this->db);
- if ($account->fetch($fk_bank_account) > 0) {
- $this->emetteur_code_banque = $account->code_banque;
- $this->emetteur_code_guichet = $account->code_guichet;
- $this->emetteur_numero_compte = $account->number;
- $this->emetteur_number_key = $account->cle_rib;
- $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
- $this->emetteur_iban = $account->iban;
- $this->emetteur_bic = $account->bic;
- $this->emetteur_ics = ($type == 'bank-transfer' ? $account->ics_transfer : $account->ics);
- $this->raison_sociale = $account->proprio;
- }
- $this->factures = $factures_prev_id;
- $this->context['factures_prev'] = $factures_prev;
- // Generation of direct debit or credit transfer file $this->filename (May be a SEPA file for european countries)
- // This also set the property $this->total with amount that is included into file
- $result = $this->generate($format, $executiondate, $type);
- if ($result < 0) {
- //var_dump($this->error);
- //var_dump($this->invoice_in_error);
- $error++;
- }
- }
- dol_syslog(__METHOD__." Bank order file has been generated under filename ".$this->filename, LOG_DEBUG);
- }
- //var_dump($this->total);exit;
- /*
- * Update total defined after generation of file
- */
- if (!$error) {
- $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_bons";
- $sql .= " SET amount = ".price2num($this->total);
- $sql .= " WHERE rowid = ".((int) $this->id);
- $sql .= " AND entity = ".((int) $conf->entity);
- $resql = $this->db->query($sql);
- if (!$resql) {
- $error++;
- dol_syslog(__METHOD__." Error update total: ".$this->db->error(), LOG_ERR);
- }
- }
- if (!$error && !$notrigger) {
- $triggername = 'DIRECT_DEBIT_ORDER_CREATE';
- if ($type != 'bank-transfer') {
- $triggername = 'CREDIT_TRANSFER_ORDER_CREATE';
- }
- // Call trigger
- $result = $this->call_trigger($triggername, $user);
- if ($result < 0) {
- $error++;
- }
- // End call triggers
- }
- if (!$error) {
- $this->db->commit();
- return count($factures_prev);
- } else {
- $this->db->rollback();
- return -1;
- }
- } else {
- return 0;
- }
- }
- /**
- * Get object and lines from database
- *
- * @param User $user Object user that delete
- * @param int $notrigger 1=Does not execute triggers, 0= execute triggers
- * @return int >0 if OK, <0 if KO
- */
- public function delete($user = null, $notrigger = 0)
- {
- $this->db->begin();
- $error = 0;
- $resql1 = $resql2 = $resql3 = $resql4 = 0;
- if (!$notrigger) {
- $triggername = 'DIRECT_DEBIT_ORDER_DELETE';
- if ($this->type == 'bank-transfer') {
- $triggername = 'PAYMENTBYBANKTRANFER_DELETE';
- }
- // Call trigger
- $result = $this->call_trigger($triggername, $user);
- if ($result < 0) {
- $error++;
- }
- // End call triggers
- }
- if (!$error) {
- $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).")";
- $resql1 = $this->db->query($sql);
- if (!$resql1) {
- dol_print_error($this->db);
- }
- }
- if (!$error) {
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevement_lignes WHERE fk_prelevement_bons = ".((int) $this->id);
- $resql2 = $this->db->query($sql);
- if (!$resql2) {
- dol_print_error($this->db);
- }
- }
- if (!$error) {
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevement_bons WHERE rowid = ".((int) $this->id);
- $resql3 = $this->db->query($sql);
- if (!$resql3) {
- dol_print_error($this->db);
- }
- }
- if (!$error) {
- $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET fk_prelevement_bons = NULL, traite = 0 WHERE fk_prelevement_bons = ".((int) $this->id);
- $resql4 = $this->db->query($sql);
- if (!$resql4) {
- dol_print_error($this->db);
- }
- }
- if ($resql1 && $resql2 && $resql3 && $resql4 && !$error) {
- $this->db->commit();
- return 1;
- } else {
- $this->db->rollback();
- return -1;
- }
- }
- /**
- * Returns clickable name (with picto)
- *
- * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
- * @param string $option On what the link point to ('nolink', ...)
- * @param int $notooltip 1=Disable tooltip
- * @param string $morecss Add more css on link
- * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
- * @return string URL of target
- */
- public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
- {
- global $conf, $langs, $hookmanager;
- if (!empty($conf->dol_no_mouse_hover)) {
- $notooltip = 1; // Force disable tooltips
- }
- $result = '';
- $labeltoshow = 'PaymentByDirectDebit';
- if (!empty($this->type) && $this->type == 'bank-transfer') {
- $labeltoshow = 'PaymentByBankTransfer';
- }
- $label = img_picto('', $this->picto).' <u>'.$langs->trans($labeltoshow).'</u> '.$this->getLibStatut(5);
- $label .= '<br>';
- $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
- if (isset($this->amount)) {
- $label .= '<br><b>'.$langs->trans("Amount").":</b> ".price($this->amount);
- }
- if (isset($this->date_trans)) {
- $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_trans, 'dayhour', 'tzuserrel');
- }
- /*if (isset($this->date_credit)) {
- $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_credit, 'dayhour', 'tzuserrel');
- }*/
- $url = DOL_URL_ROOT.'/compta/prelevement/card.php?id='.$this->id;
- if (!empty($this->type) && $this->type == 'bank-transfer') {
- $url = DOL_URL_ROOT.'/compta/prelevement/card.php?id='.$this->id;
- }
- if ($option != 'nolink') {
- // Add param to save lastsearch_values or not
- $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
- if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
- $add_save_lastsearch_values = 1;
- }
- if ($add_save_lastsearch_values) {
- $url .= '&save_lastsearch_values=1';
- }
- }
- $linkclose = '';
- if (empty($notooltip)) {
- if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
- $label = $langs->trans("ShowMyObject");
- $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
- }
- $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
- $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
- } else {
- $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
- }
- $linkstart = '<a href="'.$url.'"';
- $linkstart .= $linkclose.'>';
- $linkend = '</a>';
- $result .= $linkstart;
- if ($withpicto) {
- $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);
- }
- if ($withpicto != 2) {
- $result .= $this->ref;
- }
- $result .= $linkend;
- global $action, $hookmanager;
- $hookmanager->initHooks(array('banktransferdao'));
- $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
- $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
- if ($reshook > 0) {
- $result = $hookmanager->resPrint;
- } else {
- $result .= $hookmanager->resPrint;
- }
- return $result;
- }
- /**
- * Delete a notification def by id
- *
- * @param int $rowid id of notification
- * @return int 0 if OK, <0 if KO
- */
- public function deleteNotificationById($rowid)
- {
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
- $sql .= " WHERE rowid = ".((int) $rowid);
- if ($this->db->query($sql)) {
- return 0;
- } else {
- return -1;
- }
- }
- /**
- * Delete a notification
- *
- * @param int|User $user notification user
- * @param string $action notification action
- * @return int >0 if OK, <0 if KO
- */
- public function deleteNotification($user, $action)
- {
- if (is_object($user)) {
- $userid = $user->id;
- } else { // If user is an id
- $userid = $user;
- }
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
- $sql .= " WHERE fk_user=".((int) $userid)." AND fk_action='".$this->db->escape($action)."'";
- if ($this->db->query($sql)) {
- return 0;
- } else {
- return -1;
- }
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Add a notification
- *
- * @param DoliDB $db database handler
- * @param int|User $user notification user
- * @param string $action notification action
- * @return int 0 if OK, <0 if KO
- */
- public function addNotification($db, $user, $action)
- {
- // phpcs:enable
- $result = 0;
- if (is_object($user)) {
- $userid = $user->id;
- } else { // If user is an id
- $userid = $user;
- }
- if ($this->deleteNotification($user, $action) == 0) {
- $now = dol_now();
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."notify_def (datec,fk_user, fk_soc, fk_contact, fk_action)";
- $sql .= " VALUES ('".$this->db->idate($now)."', ".((int) $userid).", 'NULL', 'NULL', '".$this->db->escape($action)."')";
- dol_syslog("adnotiff: ".$sql);
- if ($this->db->query($sql)) {
- $result = 0;
- } else {
- $result = -1;
- dol_syslog(get_class($this)."::addNotification Error $result");
- }
- }
- return $result;
- }
- /**
- * Generate a direct debit or credit transfer file.
- * Generation Formats:
- * - Europe: SEPA (France: CFONB no more supported, Spain: AEB19 if external module EsAEB is enabled)
- * - Others countries: Warning message
- * File is generated with name this->filename
- *
- * @param string $format FRST, RCUR or ALL
- * @param int $executiondate Timestamp date to execute transfer
- * @param string $type 'direct-debit' or 'bank-transfer'
- * @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.
- * @return int >=0 if OK, <0 if KO
- */
- public function generate($format = 'ALL', $executiondate = 0, $type = 'direct-debit', $fk_bank_account = 0)
- {
- global $conf, $langs, $mysoc;
- //TODO: Optimize code to read lines in a single function
- // Clean params
- if (empty($fk_bank_account)) {
- $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
- }
- $result = 0;
- dol_syslog(get_class($this)."::generate build file=".$this->filename." type=".$type);
- $this->file = fopen($this->filename, "w");
- if (empty($this->file)) {
- $this->error = $langs->trans('ErrorFailedToOpenFile', $this->filename);
- return -1;
- }
- $found = 0;
- $this->total = 0;
- // Build file for European countries
- if ($mysoc->isInEEC()) {
- $found++;
- if ($type != 'bank-transfer') {
- /**
- * SECTION CREATION FICHIER SEPA - DIRECT DEBIT
- */
- // SEPA Initialisation
- $CrLf = "\n";
- $now = dol_now();
- $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
- $date_actu = $now;
- if (!empty($executiondate)) {
- $date_actu = $executiondate;
- }
- $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
- $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
- $fileDebiteurSection = '';
- $fileEmetteurSection = '';
- $i = 0;
- /*
- * Section Debitor (sepa Debiteurs bloc lines)
- */
- $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
- $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
- $sql .= " f.ref as reffac, pf.fk_facture as idfac,";
- $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
- $sql .= " FROM";
- $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
- $sql .= " ".MAIN_DB_PREFIX."facture as f,";
- $sql .= " ".MAIN_DB_PREFIX."prelevement as pf,";
- $sql .= " ".MAIN_DB_PREFIX."societe as soc,";
- $sql .= " ".MAIN_DB_PREFIX."c_country as c,";
- $sql .= " ".MAIN_DB_PREFIX."societe_rib as rib";
- $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
- $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
- $sql .= " AND pf.fk_facture = f.rowid";
- $sql .= " AND f.fk_soc = soc.rowid";
- $sql .= " AND soc.fk_pays = c.rowid";
- $sql .= " AND rib.fk_soc = f.fk_soc";
- $sql .= " AND rib.default_rib = 1";
- $sql .= " AND rib.type = 'ban'";
- // Define $fileDebiteurSection. One section DrctDbtTxInf per invoice.
- $resql = $this->db->query($sql);
- if ($resql) {
- $cachearraytotestduplicate = array();
- $num = $this->db->num_rows($resql);
- while ($i < $num) {
- $obj = $this->db->fetch_object($resql);
- if (!empty($cachearraytotestduplicate[$obj->idfac])) {
- $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
- $this->invoice_in_error[$obj->idfac] = $this->error;
- $result = -2;
- break;
- }
- $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
- $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
- $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);
- $this->total = $this->total + $obj->somme;
- $i++;
- }
- $nbtotalDrctDbtTxInf = $i;
- } else {
- $this->error = $this->db->lasterror();
- fputs($this->file, 'ERROR DEBITOR '.$sql.$CrLf); // DEBITOR = Customers
- $result = -2;
- }
- // Define $fileEmetteurSection. Start of bloc PmtInf. Will contains all $nbtotalDrctDbtTxInf
- if ($result != -2) {
- $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type, $fk_bank_account);
- }
- /**
- * SECTION CREATION SEPA FILE - ISO200022
- */
- // SEPA File Header
- fputs($this->file, '<'.'?xml version="1.0" encoding="UTF-8" standalone="yes"?'.'>'.$CrLf);
- 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);
- fputs($this->file, ' <CstmrDrctDbtInitn>'.$CrLf);
- // SEPA Group header
- fputs($this->file, ' <GrpHdr>'.$CrLf);
- fputs($this->file, ' <MsgId>'.('DD/'.$dateTime_YMD.'/REF'.$this->id).'</MsgId>'.$CrLf);
- fputs($this->file, ' <CreDtTm>'.$dateTime_ECMA.'</CreDtTm>'.$CrLf);
- fputs($this->file, ' <NbOfTxs>'.$i.'</NbOfTxs>'.$CrLf);
- fputs($this->file, ' <CtrlSum>'.$this->total.'</CtrlSum>'.$CrLf);
- fputs($this->file, ' <InitgPty>'.$CrLf);
- fputs($this->file, ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf);
- fputs($this->file, ' <Id>'.$CrLf);
- fputs($this->file, ' <PrvtId>'.$CrLf);
- fputs($this->file, ' <Othr>'.$CrLf);
- fputs($this->file, ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf);
- fputs($this->file, ' </Othr>'.$CrLf);
- fputs($this->file, ' </PrvtId>'.$CrLf);
- fputs($this->file, ' </Id>'.$CrLf);
- fputs($this->file, ' </InitgPty>'.$CrLf);
- fputs($this->file, ' </GrpHdr>'.$CrLf);
- // SEPA File Emetteur
- if ($result != -2) {
- fputs($this-> file, $fileEmetteurSection);
- }
- // SEPA File Debiteurs
- if ($result != -2) {
- fputs($this-> file, $fileDebiteurSection);
- }
- // SEPA FILE FOOTER
- fputs($this->file, ' </PmtInf>'.$CrLf);
- fputs($this->file, ' </CstmrDrctDbtInitn>'.$CrLf);
- fputs($this->file, '</Document>'.$CrLf);
- } else {
- /**
- * SECTION CREATION FICHIER SEPA - CREDIT TRANSFER
- */
- // SEPA Initialisation
- $CrLf = "\n";
- $now = dol_now();
- $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
- $date_actu = $now;
- if (!empty($executiondate)) {
- $date_actu = $executiondate;
- }
- $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
- $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
- $fileCrediteurSection = '';
- $fileEmetteurSection = '';
- $i = 0;
- /*
- * Section Creditor (sepa Crediteurs bloc lines)
- */
- $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
- $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
- $sql .= " f.ref as reffac, pf.fk_facture_fourn as idfac, f.ref_supplier as fac_ref_supplier,";
- $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
- $sql .= " FROM";
- $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
- $sql .= " ".MAIN_DB_PREFIX."facture_fourn as f,";
- $sql .= " ".MAIN_DB_PREFIX."prelevement as pf,";
- $sql .= " ".MAIN_DB_PREFIX."societe as soc,";
- $sql .= " ".MAIN_DB_PREFIX."c_country as c,";
- $sql .= " ".MAIN_DB_PREFIX."societe_rib as rib";
- $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
- $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
- $sql .= " AND pf.fk_facture_fourn = f.rowid";
- $sql .= " AND f.fk_soc = soc.rowid";
- $sql .= " AND soc.fk_pays = c.rowid";
- $sql .= " AND rib.fk_soc = f.fk_soc";
- $sql .= " AND rib.default_rib = 1";
- $sql .= " AND rib.type = 'ban'";
- // Define $fileCrediteurSection. One section DrctDbtTxInf per invoice.
- $resql = $this->db->query($sql);
- if ($resql) {
- $cachearraytotestduplicate = array();
- $num = $this->db->num_rows($resql);
- while ($i < $num) {
- $obj = $this->db->fetch_object($resql);
- if (!empty($cachearraytotestduplicate[$obj->idfac])) {
- $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
- $this->invoice_in_error[$obj->idfac] = $this->error;
- $result = -2;
- break;
- }
- $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
- $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
- $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);
- $this->total = $this->total + $obj->somme;
- $i++;
- }
- $nbtotalDrctDbtTxInf = $i;
- } else {
- $this->error = $this->db->lasterror();
- fputs($this->file, 'ERROR CREDITOR '.$sql.$CrLf); // CREDITORS = Suppliers
- $result = -2;
- }
- // Define $fileEmetteurSection. Start of bloc PmtInf. Will contains all $nbtotalDrctDbtTxInf
- if ($result != -2) {
- $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type);
- }
- /**
- * SECTION CREATION SEPA FILE - CREDIT TRANSFER - ISO200022
- */
- // SEPA File Header
- fputs($this->file, '<'.'?xml version="1.0" encoding="UTF-8" standalone="yes"?'.'>'.$CrLf);
- 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);
- fputs($this->file, ' <CstmrCdtTrfInitn>'.$CrLf);
- // SEPA Group header
- fputs($this->file, ' <GrpHdr>'.$CrLf);
- fputs($this->file, ' <MsgId>'.('TRF/'.$dateTime_YMD.'/REF'.$this->id).'</MsgId>'.$CrLf);
- fputs($this->file, ' <CreDtTm>'.$dateTime_ECMA.'</CreDtTm>'.$CrLf);
- fputs($this->file, ' <NbOfTxs>'.$i.'</NbOfTxs>'.$CrLf);
- fputs($this->file, ' <CtrlSum>'.$this->total.'</CtrlSum>'.$CrLf);
- fputs($this->file, ' <InitgPty>'.$CrLf);
- fputs($this->file, ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf);
- fputs($this->file, ' <Id>'.$CrLf);
- fputs($this->file, ' <PrvtId>'.$CrLf);
- fputs($this->file, ' <Othr>'.$CrLf);
- fputs($this->file, ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf);
- fputs($this->file, ' </Othr>'.$CrLf);
- fputs($this->file, ' </PrvtId>'.$CrLf);
- fputs($this->file, ' </Id>'.$CrLf);
- fputs($this->file, ' </InitgPty>'.$CrLf);
- fputs($this->file, ' </GrpHdr>'.$CrLf);
- // SEPA File Emetteur (mycompany)
- if ($result != -2) {
- fputs($this-> file, $fileEmetteurSection);
- }
- // SEPA File Creditors
- if ($result != -2) {
- fputs($this-> file, $fileCrediteurSection);
- }
- // SEPA FILE FOOTER
- fputs($this->file, ' </PmtInf>'.$CrLf);
- fputs($this->file, ' </CstmrCdtTrfInitn>'.$CrLf);
- fputs($this->file, '</Document>'.$CrLf);
- }
- }
- // Build file for Other Countries with unknow format
- if (!$found) {
- if ($type != 'bank-transfer') {
- $sql = "SELECT pl.amount";
- $sql .= " FROM";
- $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
- $sql .= " ".MAIN_DB_PREFIX."facture as f,";
- $sql .= " ".MAIN_DB_PREFIX."prelevement as pf";
- $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
- $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
- $sql .= " AND pf.fk_facture = f.rowid";
- // Lines
- $i = 0;
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- while ($i < $num) {
- $obj = $this->db->fetch_object($resql);
- $this->total = $this->total + $obj->amount;
- // TODO Write record into file
- $i++;
- }
- } else {
- $result = -2;
- }
- } else {
- $sql = "SELECT pl.amount";
- $sql .= " FROM";
- $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
- $sql .= " ".MAIN_DB_PREFIX."facture_fourn as f,";
- $sql .= " ".MAIN_DB_PREFIX."prelevement as pf";
- $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
- $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
- $sql .= " AND pf.fk_facture_fourn = f.rowid";
- // Lines
- $i = 0;
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- while ($i < $num) {
- $obj = $this->db->fetch_object($resql);
- $this->total = $this->total + $obj->amount;
- // TODO Write record into file
- $i++;
- }
- } else {
- $result = -2;
- }
- }
- $langs->load('withdrawals');
- // TODO Add here code to generate a generic file
- fputs($this->file, $langs->transnoentitiesnoconv('WithdrawalFileNotCapable', $mysoc->country_code));
- }
- fclose($this->file);
- dolChmod($this->filename);
- return $result;
- }
- /**
- * Generate dynamically a RUM number for a customer bank account
- *
- * @param string $row_code_client Customer code (soc.code_client)
- * @param int $row_datec Creation date of bank account (rib.datec)
- * @param string $row_drum Id of customer bank account (rib.rowid)
- * @return string RUM number
- */
- public static function buildRumNumber($row_code_client, $row_datec, $row_drum)
- {
- global $langs;
- $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)
- // 3 char + '-' + 12 + '-' + id + '-' + code Must be lower than 32.
- return $pre.'-'.dol_print_date($row_datec, 'dayhourlogsmall').'-'.dol_trunc($row_drum.($row_code_client ? '-'.$row_code_client : ''), 13, 'right', 'UTF-8', 1);
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Write recipient of request (customer)
- *
- * @param int $rowid id of line
- * @param string $client_nom name of customer
- * @param string $rib_banque code of bank
- * @param string $rib_guichet code of bank office
- * @param string $rib_number bank account
- * @param float $amount amount
- * @param string $ref ref of invoice
- * @param int $facid id of invoice
- * @param string $rib_dom rib domiciliation
- * @param string $type 'direct-debit' or 'bank-transfer'
- * @return void
- * @see EnregDestinataireSEPA()
- */
- public function EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom = '', $type = 'direct-debit')
- {
- // phpcs:enable
- fputs($this->file, "06");
- fputs($this->file, "08"); // Prelevement ordinaire
- fputs($this->file, " "); // Zone Reservee B2
- fputs($this->file, $this->emetteur_ics); // ICS
- // Date d'echeance C1
- fputs($this->file, " ");
- fputs($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
- fputs($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
- // Raison Sociale Destinataire C2
- fputs($this->file, substr(strtoupper($client_nom)." ", 0, 24));
- // Domiciliation facultative D1
- $domiciliation = strtr($rib_dom, array(" " => "-", CHR(13) => " ", CHR(10) => ""));
- fputs($this->file, substr($domiciliation." ", 0, 24));
- // Zone Reservee D2
- fputs($this->file, substr(" ", 0, 8));
- // Code Guichet D3
- fputs($this->file, $rib_guichet);
- // Numero de compte D4
- fputs($this->file, substr("000000000000000".$rib_number, -11));
- // Zone E Montant
- $montant = (round($amount, 2) * 100);
- fputs($this->file, substr("000000000000000".$montant, -16));
- // Label F
- fputs($this->file, substr("*_".$ref."_RDVnet".$rowid." ", 0, 31));
- // Code etablissement G1
- fputs($this->file, $rib_banque);
- // Zone Reservee G2
- fputs($this->file, substr(" ", 0, 5));
- fputs($this->file, "\n");
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Write recipient (thirdparty concerned by request)
- *
- * @param string $row_code_client soc.code_client as code,
- * @param string $row_nom pl.client_nom AS name,
- * @param string $row_address soc.address AS adr,
- * @param string $row_zip soc.zip
- * @param string $row_town soc.town
- * @param string $row_country_code c.code AS country,
- * @param string $row_cb pl.code_banque AS cb, Not used for SEPA
- * @param string $row_cg pl.code_guichet AS cg, Not used for SEPA
- * @param string $row_cc pl.number AS cc, Not used for SEPA
- * @param string $row_somme pl.amount AS somme,
- * @param string $row_ref Invoice ref (f.ref)
- * @param string $row_idfac pf.fk_facture AS idfac,
- * @param string $row_iban rib.iban_prefix AS iban,
- * @param string $row_bic rib.bic AS bic,
- * @param string $row_datec rib.datec,
- * @param string $row_drum rib.rowid used to generate rum
- * @param string $row_rum rib.rum Rum defined on company bank account
- * @param string $type 'direct-debit' or 'bank-transfer'
- * @param string $row_comment A free text string for the Unstructured data field
- * @return string Return string with SEPA part DrctDbtTxInf
- * @see EnregDestinataire()
- */
- 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 = '')
- {
- // phpcs:enable
- global $conf;
- include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
- $CrLf = "\n";
- $Rowing = sprintf("%010d", $row_idfac);
- // Define value for RUM
- // Example: RUM-CustomerCode-CustomerBankAccountId-01424448606 (note: Date is the timestamp of the date of creation of CustomerBankAccountId)
- $Rum = (empty($row_rum) ? $this->buildRumNumber($row_code_client, $row_datec, $row_drum) : $row_rum);
- // Define date of RUM signature
- $DtOfSgntr = dol_print_date($row_datec, '%Y-%m-%d');
- if ($type != 'bank-transfer') {
- // SEPA Paiement Information of buyer for Direct Debit
- $XML_DEBITOR = '';
- $XML_DEBITOR .= ' <DrctDbtTxInf>'.$CrLf;
- $XML_DEBITOR .= ' <PmtId>'.$CrLf;
- // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
- $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
- $XML_DEBITOR .= ' </PmtId>'.$CrLf;
- $XML_DEBITOR .= ' <InstdAmt Ccy="EUR">'.round($row_somme, 2).'</InstdAmt>'.$CrLf;
- $XML_DEBITOR .= ' <DrctDbtTx>'.$CrLf;
- $XML_DEBITOR .= ' <MndtRltdInf>'.$CrLf;
- $XML_DEBITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
- $XML_DEBITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
- $XML_DEBITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
- $XML_DEBITOR .= ' </MndtRltdInf>'.$CrLf;
- $XML_DEBITOR .= ' </DrctDbtTx>'.$CrLf;
- $XML_DEBITOR .= ' <DbtrAgt>'.$CrLf;
- $XML_DEBITOR .= ' <FinInstnId>'.$CrLf;
- $XML_DEBITOR .= ' <BIC>'.$row_bic.'</BIC>'.$CrLf;
- $XML_DEBITOR .= ' </FinInstnId>'.$CrLf;
- $XML_DEBITOR .= ' </DbtrAgt>'.$CrLf;
- $XML_DEBITOR .= ' <Dbtr>'.$CrLf;
- $XML_DEBITOR .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))).'</Nm>'.$CrLf;
- $XML_DEBITOR .= ' <PstlAdr>'.$CrLf;
- $XML_DEBITOR .= ' <Ctry>'.$row_country_code.'</Ctry>'.$CrLf;
- $addressline1 = strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""));
- $addressline2 = strtr($row_zip.(($row_zip && $row_town) ? ' ' : (string) $row_town), array(CHR(13) => ", ", CHR(10) => ""));
- if (trim($addressline1)) {
- $XML_DEBITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- if (trim($addressline2)) {
- $XML_DEBITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- $XML_DEBITOR .= ' </PstlAdr>'.$CrLf;
- $XML_DEBITOR .= ' </Dbtr>'.$CrLf;
- $XML_DEBITOR .= ' <DbtrAcct>'.$CrLf;
- $XML_DEBITOR .= ' <Id>'.$CrLf;
- $XML_DEBITOR .= ' <IBAN>'.preg_replace('/\s/', '', $row_iban).'</IBAN>'.$CrLf;
- $XML_DEBITOR .= ' </Id>'.$CrLf;
- $XML_DEBITOR .= ' </DbtrAcct>'.$CrLf;
- $XML_DEBITOR .= ' <RmtInf>'.$CrLf;
- // A string with some information on payment - 140 max
- $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
- $XML_DEBITOR .= ' </RmtInf>'.$CrLf;
- $XML_DEBITOR .= ' </DrctDbtTxInf>'.$CrLf;
- return $XML_DEBITOR;
- } else {
- // SEPA Paiement Information of seller for Credit Transfer
- $XML_CREDITOR = '';
- $XML_CREDITOR .= ' <CdtTrfTxInf>'.$CrLf;
- $XML_CREDITOR .= ' <PmtId>'.$CrLf;
- // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
- $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
- $XML_CREDITOR .= ' </PmtId>'.$CrLf;
- if (!empty($this->sepa_xml_pti_in_ctti)) {
- $XML_CREDITOR .= ' <PmtTpInf>' . $CrLf;
- // Can be 'NORM' for normal or 'HIGH' for high priority level
- if (!empty($conf->global->PAYMENTBYBANKTRANSFER_FORCE_HIGH_PRIORITY)) {
- $instrprty = 'HIGH';
- } else {
- $instrprty = 'NORM';
- }
- $XML_CREDITOR .= ' <InstrPrty>'.$instrprty.'</InstrPrty>' . $CrLf;
- $XML_CREDITOR .= ' <SvcLvl>' . $CrLf;
- $XML_CREDITOR .= ' <Cd>SEPA</Cd>' . $CrLf;
- $XML_CREDITOR .= ' </SvcLvl>' . $CrLf;
- $XML_CREDITOR .= ' <CtgyPurp>' . $CrLf;
- $XML_CREDITOR .= ' <Cd>CORE</Cd>' . $CrLf;
- $XML_CREDITOR .= ' </CtgyPurp>' . $CrLf;
- $XML_CREDITOR .= ' </PmtTpInf>' . $CrLf;
- }
- $XML_CREDITOR .= ' <Amt>'.$CrLf;
- $XML_CREDITOR .= ' <InstdAmt Ccy="EUR">'.round($row_somme, 2).'</InstdAmt>'.$CrLf;
- $XML_CREDITOR .= ' </Amt>'.$CrLf;
- /*
- $XML_CREDITOR .= ' <DrctDbtTx>'.$CrLf;
- $XML_CREDITOR .= ' <MndtRltdInf>'.$CrLf;
- $XML_CREDITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
- $XML_CREDITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
- $XML_CREDITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
- $XML_CREDITOR .= ' </MndtRltdInf>'.$CrLf;
- $XML_CREDITOR .= ' </DrctDbtTx>'.$CrLf;
- */
- //$XML_CREDITOR .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf;
- $XML_CREDITOR .= ' <CdtrAgt>'.$CrLf;
- $XML_CREDITOR .= ' <FinInstnId>'.$CrLf;
- $XML_CREDITOR .= ' <BIC>'.$row_bic.'</BIC>'.$CrLf;
- $XML_CREDITOR .= ' </FinInstnId>'.$CrLf;
- $XML_CREDITOR .= ' </CdtrAgt>'.$CrLf;
- $XML_CREDITOR .= ' <Cdtr>'.$CrLf;
- $XML_CREDITOR .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))).'</Nm>'.$CrLf;
- $XML_CREDITOR .= ' <PstlAdr>'.$CrLf;
- $XML_CREDITOR .= ' <Ctry>'.$row_country_code.'</Ctry>'.$CrLf;
- $addressline1 = strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""));
- $addressline2 = strtr($row_zip.(($row_zip && $row_town) ? ' ' : (string) $row_town), array(CHR(13) => ", ", CHR(10) => ""));
- if (trim($addressline1)) {
- $XML_CREDITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- if (trim($addressline2)) {
- $XML_CREDITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- $XML_CREDITOR .= ' </PstlAdr>'.$CrLf;
- $XML_CREDITOR .= ' </Cdtr>'.$CrLf;
- $XML_CREDITOR .= ' <CdtrAcct>'.$CrLf;
- $XML_CREDITOR .= ' <Id>'.$CrLf;
- $XML_CREDITOR .= ' <IBAN>'.preg_replace('/\s/', '', $row_iban).'</IBAN>'.$CrLf;
- $XML_CREDITOR .= ' </Id>'.$CrLf;
- $XML_CREDITOR .= ' </CdtrAcct>'.$CrLf;
- $XML_CREDITOR .= ' <RmtInf>'.$CrLf;
- // A string with some information on payment - 140 max
- $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
- $XML_CREDITOR .= ' </RmtInf>'.$CrLf;
- $XML_CREDITOR .= ' </CdtTrfTxInf>'.$CrLf;
- return $XML_CREDITOR;
- }
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Write sender of request (me).
- *
- * @param string $type 'direct-debit' or 'bank-transfer'
- * @return void
- * @see EnregEmetteurSEPA()
- */
- public function EnregEmetteur($type = 'direct-debit')
- {
- // phpcs:enable
- fputs($this->file, "03");
- fputs($this->file, "08"); // Prelevement ordinaire
- fputs($this->file, " "); // Zone Reservee B2
- fputs($this->file, $this->emetteur_ics); // ICS
- // Date d'echeance C1
- fputs($this->file, " ");
- fputs($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
- fputs($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
- // Raison Sociale C2
- fputs($this->file, substr($this->raison_sociale." ", 0, 24));
- // Reference de la remise creancier D1 sur 7 caracteres
- fputs($this->file, substr($this->reference_remise." ", 0, 7));
- // Zone Reservee D1-2
- fputs($this->file, substr(" ", 0, 17));
- // Zone Reservee D2
- fputs($this->file, substr(" ", 0, 2));
- fputs($this->file, "E");
- fputs($this->file, substr(" ", 0, 5));
- // Code Guichet D3
- fputs($this->file, $this->emetteur_code_guichet);
- // Numero de compte D4
- fputs($this->file, substr("000000000000000".$this->emetteur_numero_compte, -11));
- // Zone Reservee E
- fputs($this->file, substr(" ", 0, 16));
- // Zone Reservee F
- fputs($this->file, substr(" ", 0, 31));
- // Code etablissement
- fputs($this->file, $this->emetteur_code_banque);
- // Zone Reservee G
- fputs($this->file, substr(" ", 0, 5));
- fputs($this->file, "\n");
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Write sender of request (me).
- * Note: The tag PmtInf is opened here but closed into caller
- *
- * @param Conf $configuration conf
- * @param int $ladate Date
- * @param int $nombre 0 or 1
- * @param float $total Total
- * @param string $CrLf End of line character
- * @param string $format FRST or RCUR or ALL
- * @param string $type 'direct-debit' or 'bank-transfer'
- * @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.
- * @return string String with SEPA Sender
- * @see EnregEmetteur()
- */
- public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit', $fk_bank_account = 0)
- {
- // phpcs:enable
- // SEPA INITIALISATION
- global $conf;
- // Clean parameters
- $dateTime_YMD = dol_print_date($ladate, '%Y%m%d');
- $dateTime_ETAD = dol_print_date($ladate, '%Y-%m-%d');
- $dateTime_YMDHMS = dol_print_date($ladate, '%Y-%m-%dT%H:%M:%S');
- // Clean params
- if (empty($fk_bank_account)) {
- $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
- }
- // Get data of bank account
- $account = new Account($this->db);
- if ($account->fetch($fk_bank_account) > 0) {
- $this->emetteur_code_banque = $account->code_banque;
- $this->emetteur_code_guichet = $account->code_guichet;
- $this->emetteur_numero_compte = $account->number;
- $this->emetteur_number_key = $account->cle_rib;
- $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
- $this->emetteur_iban = $account->iban;
- $this->emetteur_bic = $account->bic;
- $this->emetteur_ics = ($type == 'bank-transfer' ? $account->ics_transfer : $account->ics); // Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
- $this->raison_sociale = $account->proprio;
- }
- // Get pending payments
- $sql = "SELECT rowid, ref";
- $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as pb";
- $sql .= " WHERE pb.rowid = ".((int) $this->id);
- $resql = $this->db->query($sql);
- if ($resql) {
- $obj = $this->db->fetch_object($resql);
- $country = explode(':', $configuration->global->MAIN_INFO_SOCIETE_COUNTRY);
- $IdBon = sprintf("%05d", $obj->rowid);
- $RefBon = $obj->ref;
- if ($type != 'bank-transfer') {
- // SEPA Paiement Information of my company for Direct Debit
- $XML_SEPA_INFO = '';
- $XML_SEPA_INFO .= ' <PmtInf>'.$CrLf;
- $XML_SEPA_INFO .= ' <PmtInfId>'.('DD/'.$dateTime_YMD.'/ID'.$IdBon.'-'.$RefBon).'</PmtInfId>'.$CrLf;
- $XML_SEPA_INFO .= ' <PmtMtd>DD</PmtMtd>'.$CrLf;
- $XML_SEPA_INFO .= ' <NbOfTxs>'.$nombre.'</NbOfTxs>'.$CrLf;
- $XML_SEPA_INFO .= ' <CtrlSum>'.$total.'</CtrlSum>'.$CrLf;
- $XML_SEPA_INFO .= ' <PmtTpInf>'.$CrLf;
- $XML_SEPA_INFO .= ' <SvcLvl>'.$CrLf;
- $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>'.$CrLf;
- $XML_SEPA_INFO .= ' </SvcLvl>'.$CrLf;
- $XML_SEPA_INFO .= ' <LclInstrm>'.$CrLf;
- $XML_SEPA_INFO .= ' <Cd>CORE</Cd>'.$CrLf;
- $XML_SEPA_INFO .= ' </LclInstrm>'.$CrLf;
- $XML_SEPA_INFO .= ' <SeqTp>'.$format.'</SeqTp>'.$CrLf;
- $XML_SEPA_INFO .= ' </PmtTpInf>'.$CrLf;
- $XML_SEPA_INFO .= ' <ReqdColltnDt>'.$dateTime_ETAD.'</ReqdColltnDt>'.$CrLf;
- $XML_SEPA_INFO .= ' <Cdtr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
- $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
- $addressline1 = strtr($configuration->global->MAIN_INFO_SOCIETE_ADDRESS, array(CHR(13) => ", ", CHR(10) => ""));
- $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) => ""));
- if ($addressline1) {
- $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- if ($addressline2) {
- $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' </Cdtr>'.$CrLf;
- $XML_SEPA_INFO .= ' <CdtrAcct>'.$CrLf;
- $XML_SEPA_INFO .= ' <Id>'.$CrLf;
- $XML_SEPA_INFO .= ' <IBAN>'.preg_replace('/\s/', '', $this->emetteur_iban).'</IBAN>'.$CrLf;
- $XML_SEPA_INFO .= ' </Id>'.$CrLf;
- $XML_SEPA_INFO .= ' </CdtrAcct>'.$CrLf;
- $XML_SEPA_INFO .= ' <CdtrAgt>'.$CrLf;
- $XML_SEPA_INFO .= ' <FinInstnId>'.$CrLf;
- $XML_SEPA_INFO .= ' <BIC>'.$this->emetteur_bic.'</BIC>'.$CrLf;
- $XML_SEPA_INFO .= ' </FinInstnId>'.$CrLf;
- $XML_SEPA_INFO .= ' </CdtrAgt>'.$CrLf;
- /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
- $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
- $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ADDRESS), ' ')).'</AdrLine>'.$CrLf;
- $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;
- $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
- $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf; // Field "Responsible of fees". Must be SLEV
- $XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
- $XML_SEPA_INFO .= ' <Id>'.$CrLf;
- $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
- $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
- $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
- $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
- $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
- $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
- $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
- $XML_SEPA_INFO .= ' </Id>'.$CrLf;
- $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;
- } else {
- // SEPA Paiement Information of my company for Credit Transfer
- $XML_SEPA_INFO = '';
- $XML_SEPA_INFO .= ' <PmtInf>'.$CrLf;
- $XML_SEPA_INFO .= ' <PmtInfId>'.('TRF/'.$dateTime_YMD.'/ID'.$IdBon.'-'.$RefBon).'</PmtInfId>'.$CrLf;
- $XML_SEPA_INFO .= ' <PmtMtd>TRF</PmtMtd>'.$CrLf;
- //$XML_SEPA_INFO .= ' <BtchBookg>False</BtchBookg>'.$CrLf;
- $XML_SEPA_INFO .= ' <NbOfTxs>'.$nombre.'</NbOfTxs>'.$CrLf;
- $XML_SEPA_INFO .= ' <CtrlSum>'.$total.'</CtrlSum>'.$CrLf;
- 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.
- $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
- $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
- $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
- $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
- $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
- $XML_SEPA_INFO .= ' <Cd>CORE</Cd>' . $CrLf;
- $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
- $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
- $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
- }
- $XML_SEPA_INFO .= ' <ReqdExctnDt>'.dol_print_date($dateTime_ETAD, 'dayrfc').'</ReqdExctnDt>'.$CrLf;
- $XML_SEPA_INFO .= ' <Dbtr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
- $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
- $addressline1 = strtr($configuration->global->MAIN_INFO_SOCIETE_ADDRESS, array(CHR(13) => ", ", CHR(10) => ""));
- $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) => ""));
- if ($addressline1) {
- $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- if ($addressline2) {
- $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
- }
- $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' </Dbtr>'.$CrLf;
- $XML_SEPA_INFO .= ' <DbtrAcct>'.$CrLf;
- $XML_SEPA_INFO .= ' <Id>'.$CrLf;
- $XML_SEPA_INFO .= ' <IBAN>'.preg_replace('/\s/', '', $this->emetteur_iban).'</IBAN>'.$CrLf;
- $XML_SEPA_INFO .= ' </Id>'.$CrLf;
- $XML_SEPA_INFO .= ' </DbtrAcct>'.$CrLf;
- $XML_SEPA_INFO .= ' <DbtrAgt>'.$CrLf;
- $XML_SEPA_INFO .= ' <FinInstnId>'.$CrLf;
- $XML_SEPA_INFO .= ' <BIC>'.$this->emetteur_bic.'</BIC>'.$CrLf;
- $XML_SEPA_INFO .= ' </FinInstnId>'.$CrLf;
- $XML_SEPA_INFO .= ' </DbtrAgt>'.$CrLf;
- /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
- $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
- $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ADDRESS), ' ')).'</AdrLine>'.$CrLf;
- $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;
- $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
- $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
- $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf; // Field "Responsible of fees". Must be SLEV
- /*$XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
- $XML_SEPA_INFO .= ' <Id>'.$CrLf;
- $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
- $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
- $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
- $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
- $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
- $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
- $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
- $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
- $XML_SEPA_INFO .= ' </Id>'.$CrLf;
- $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;*/
- }
- } else {
- fputs($this->file, 'INCORRECT EMETTEUR '.$this->raison_sociale.$CrLf);
- $XML_SEPA_INFO = '';
- }
- return $XML_SEPA_INFO;
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Write end
- *
- * @param int $total total amount
- * @return void
- */
- public function EnregTotal($total)
- {
- // phpcs:enable
- fputs($this->file, "08");
- fputs($this->file, "08"); // Prelevement ordinaire
- fputs($this->file, " "); // Zone Reservee B2
- fputs($this->file, $this->emetteur_ics); // ICS
- // Reserve C1
- fputs($this->file, substr(" ", 0, 12));
- // Raison Sociale C2
- fputs($this->file, substr(" ", 0, 24));
- // D1
- fputs($this->file, substr(" ", 0, 24));
- // Zone Reservee D2
- fputs($this->file, substr(" ", 0, 8));
- // Code Guichet D3
- fputs($this->file, substr(" ", 0, 5));
- // Numero de compte D4
- fputs($this->file, substr(" ", 0, 11));
- // Zone E Montant
- $montant = ($total * 100);
- fputs($this->file, substr("000000000000000".$montant, -16));
- // Zone Reservee F
- fputs($this->file, substr(" ", 0, 31));
- // Code etablissement
- fputs($this->file, substr(" ", 0, 5));
- // Zone Reservee F
- fputs($this->file, substr(" ", 0, 5));
- fputs($this->file, "\n");
- }
- /**
- * Return status label of object
- *
- * @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
- * @return string Label
- */
- public function getLibStatut($mode = 0)
- {
- return $this->LibStatut($this->statut, $mode);
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Return status label for a status
- *
- * @param int $status Id status
- * @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
- * @return string Label
- */
- public function LibStatut($status, $mode = 0)
- {
- // phpcs:enable
- if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
- global $langs;
- //$langs->load("mymodule");
- $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
- $this->labelStatus[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
- $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
- $this->labelStatusShort[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
- if ($this->type == 'bank-transfer') {
- $this->labelStatus[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
- $this->labelStatusShort[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
- } else {
- $this->labelStatus[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
- $this->labelStatusShort[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
- }
- }
- $statusType = 'status1';
- if ($status == self::STATUS_TRANSFERED) {
- $statusType = 'status3';
- }
- if ($status == self::STATUS_CREDITED || $status == self::STATUS_DEBITED) {
- $statusType = 'status6';
- }
- return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Load indicators for dashboard (this->nbtodo and this->nbtodolate)
- *
- * @param User $user Objet user
- * @param string $mode Mode 'direct_debit' or 'credit_transfer'
- * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK
- */
- public function load_board($user, $mode)
- {
- // phpcs:enable
- global $conf, $langs;
- if ($user->socid) {
- return -1; // protection pour eviter appel par utilisateur externe
- }
- /*
- if ($mode == 'direct_debit') {
- $sql = "SELECT b.rowid, f.datedue as datefin";
- $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
- $sql .= " WHERE f.entity IN (".getEntity('facture').")";
- $sql .= " AND f.total_ttc > 0";
- } else {
- $sql = "SELECT b.rowid, f.datedue as datefin";
- $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
- $sql .= " WHERE f.entity IN (".getEntity('facture_fourn').")";
- $sql .= " AND f.total_ttc > 0";
- }
- $resql = $this->db->query($sql);
- if ($resql) {
- $langs->load("banks");
- $now = dol_now();
- $response = new WorkboardResponse();
- if ($mode == 'direct_debit') {
- $response->warning_delay = $conf->prelevement->warning_delay / 60 / 60 / 24;
- $response->label = $langs->trans("PendingDirectDebitToComplete");
- $response->labelShort = $langs->trans("PendingDirectDebitToCompleteShort");
- $response->url = DOL_URL_ROOT.'/compta/prelevement/index.php?leftmenu=checks&mainmenu=bank';
- } else {
- $response->warning_delay = $conf->paymentbybanktransfer->warning_delay / 60 / 60 / 24;
- $response->label = $langs->trans("PendingCreditTransferToComplete");
- $response->labelShort = $langs->trans("PendingCreditTransferToCompleteShort");
- $response->url = DOL_URL_ROOT.'/compta/paymentbybanktransfer/index.php?leftmenu=checks&mainmenu=bank';
- }
- $response->img = img_object('', "payment");
- while ($obj = $this->db->fetch_object($resql)) {
- $response->nbtodo++;
- if ($this->db->jdate($obj->datefin) < ($now - $conf->withdraw->warning_delay)) {
- $response->nbtodolate++;
- }
- }
- $response->nbtodo = 0;
- $response->nbtodolate = 0;
- // Return workboard only if quantity is not 0
- if ($response->nbtodo) {
- return $response;
- } else {
- return 0;
- }
- } else {
- dol_print_error($this->db);
- $this->error = $this->db->error();
- return -1;
- }
- */
- return 0;
- }
- /**
- * Return clicable link of object (with eventually picto)
- *
- * @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
- * @param array $arraydata Array of data
- * @return string HTML Code for Kanban thumb.
- */
- public function getKanbanView($option = '', $arraydata = null)
- {
- global $langs;
- $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
- $return = '<div class="box-flex-item box-flex-grow-zero">';
- $return .= '<div class="info-box info-box-sm">';
- $return .= '<span class="info-box-icon bg-infobox-action">';
- $return .= img_picto('', $this->picto);
- $return .= '</span>';
- $return .= '<div class="info-box-content">';
- $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
- $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
- if (property_exists($this, 'date_echeance')) {
- $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>';
- }
- if (property_exists($this, 'total')) {
- $return .= '<br><span class="opacitymedium">'.$langs->trans("Amount").'</span> : <span class="amount">'.price($this->total).'</span>';
- }
- if (method_exists($this, 'LibStatut')) {
- $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3).'</div>';
- }
- $return .= '</div>';
- $return .= '</div>';
- $return .= '</div>';
- return $return;
- }
- }
|