Passed
Branch develop (b13600)
by
unknown
108:30
created

Account::replaceThirdparty()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 3
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
/* Copyright (C) 2001-2007	Rodolphe Quiedeville	<[email protected]>
3
 * Copyright (C) 2003		Jean-Louis Bergamo		<[email protected]>
4
 * Copyright (C) 2004-2012	Laurent Destailleur		<[email protected]>
5
 * Copyright (C) 2004		Christophe Combelles	<[email protected]>
6
 * Copyright (C) 2005-2010	Regis Houssin			<[email protected]>
7
 * Copyright (C) 2013		Florian Henry			<[email protected]>
8
 * Copyright (C) 2015-2016	Marcos García			<[email protected]>
9
 * Copyright (C) 2015-2017	Alexandre Spangaro		<[email protected]>
10
 * Copyright (C) 2016		Ferran Marcet   		<[email protected]>
11
 * Copyright (C) 2019		JC Prieto				<[email protected]><[email protected]>
12
 * Copyright (C) 2022-2023  Frédéric France         <[email protected]>
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 3 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26
 */
27
28
/**
29
 *	\file       htdocs/compta/bank/class/account.class.php
30
 *	\ingroup    bank
31
 *	\brief      File of class to manage bank accounts
32
 */
33
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
34
35
36
/**
37
 *	Class to manage bank accounts
38
 */
39
class Account extends CommonObject
40
{
41
	/**
42
	 * @var string ID to identify managed object
43
	 */
44
	public $element = 'bank_account';
45
46
	/**
47
	 * @var string Name of table without prefix where object is stored
48
	 */
49
	public $table_element = 'bank_account';
50
51
	/**
52
	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
53
	 */
54
	public $picto = 'account';
55
56
	/**
57
	 * @var	int		Use id instead of rowid
58
	 * @deprecated
59
	 * @see $id
60
	 */
61
	public $rowid;
62
63
	/**
64
	 * Account Label
65
	 * @var string
66
	 */
67
	public $label;
68
69
	/**
70
	 * Bank account type. Check TYPE_ constants
71
	 * @var int
72
	 */
73
	public $courant;
74
75
	/**
76
	 * Bank account type. Check TYPE_ constants
77
	 * @var int
78
	 */
79
	public $type;
80
81
	/**
82
	 * Bank name
83
	 * @var string
84
	 */
85
	public $bank;
86
87
	/**
88
	 * Status
89
	 * @var int
90
	 */
91
	public $clos = self::STATUS_OPEN;
92
93
	/**
94
	 * Does it need to be conciliated?
95
	 * @var int
96
	 */
97
	public $rappro = 1;
98
99
	/**
100
	 * Webpage
101
	 * @var string
102
	 */
103
	public $url;
104
105
	/**
106
	 * Bank number. If in SEPA area, you should move to IBAN field
107
	 * @var string
108
	 */
109
	public $code_banque;
110
111
	/**
112
	 * Branch number. If in SEPA area, you should move to IBAN field
113
	 * @var string
114
	 */
115
	public $code_guichet;
116
117
	/**
118
	 * Account number. If in SEPA area, you should move to IBAN field
119
	 * @var string
120
	 */
121
	public $number;
122
123
	/**
124
	 * Bank account number control digit. If in SEPA area, you should move to IBAN field
125
	 * @var string
126
	 */
127
	public $cle_rib;
128
129
	/**
130
	 * BIC/Swift code
131
	 * @var string
132
	 */
133
	public $bic;
134
135
	/**
136
	 * IBAN number (International Bank Account Number). Stored into iban_prefix field into database (TODO Rename field in database)
137
	 * @var string
138
	 */
139
	public $iban;
140
141
	/**
142
	 * IBAN number
143
	 *
144
	 * @var string
145
	 * @deprecated see $iban
146
	 */
147
	public $iban_prefix;
148
149
	/**
150
	 * XML SEPA format: place Payment Type Information (PmtTpInf) in Credit Transfer Transaction Information (CdtTrfTxInf)
151
	 * @var int
152
	 */
153
	public $pti_in_ctti = 0;
154
155
	/**
156
	 * Name of account holder
157
	 * @var string
158
	 */
159
	public $proprio;
160
161
	/**
162
	 * Address of account holder
163
	 * @var string
164
	 */
165
	public $owner_address;
166
	public $owner_zip;
167
	public $owner_town;
168
	public $owner_country_id;
169
	public $owner_country_code;
170
171
	/**
172
	 * Address of the bank account
173
	 * @var string
174
	 */
175
	public $domiciliation;		// deprecated, use now address
176
	public $address;
177
	public $state_id;
178
	public $state_code;
179
	public $state;
180
181
	/**
182
	 * Variable containing all account types with their respective translated label.
183
	 * Defined in __construct
184
	 * @var array
185
	 */
186
	public $type_lib = array();
187
188
	/**
189
	 * Variable containing all account statuses with their respective translated label.
190
	 * Defined in __construct
191
	 * @var array
192
	 */
193
	public $status = array();
194
195
	/**
196
	 * Accountancy code
197
	 * @var string
198
	 */
199
	public $account_number;
200
201
	/**
202
	 * @var int ID
203
	 */
204
	public $fk_accountancy_journal;
205
	/**
206
	 * @var string	Label of journal
207
	 */
208
	public $accountancy_journal;
209
210
	/**
211
	 * Currency code
212
	 * @var string
213
	 */
214
	public $currency_code;
215
216
	/**
217
	 * Currency code
218
	 * @var string
219
	 * @deprecated Use currency_code instead
220
	 */
221
	public $account_currency_code;
222
223
	/**
224
	 * Authorized minimum balance
225
	 * @var float
226
	 */
227
	public $min_allowed;
228
229
	/**
230
	 * Desired minimum balance
231
	 * @var float
232
	 */
233
	public $min_desired;
234
235
	/**
236
	 * Notes
237
	 * @var string
238
	 */
239
	public $comment;
240
241
	/**
242
	 * Date of the initial balance. Used in Account::create
243
	 * @var int
244
	 */
245
	public $date_solde;
246
247
	/**
248
	 * Balance. Used in Account::create
249
	 * @var float
250
	 * @deprecated
251
	 * @see $balance
252
	 */
253
	public $solde;
254
255
	/**
256
	 * Balance. Used in Account::create
257
	 * @var float
258
	 */
259
	public $balance;
260
261
	/**
262
	 * Creditor Identifier CI. Some banks use different ICS for direct debit and bank tranfer
263
	 * @var string
264
	 */
265
	public $ics;
266
267
	/**
268
	 * Creditor Identifier for Bank Transfer.
269
	 * @var string
270
	 */
271
	public $ics_transfer;
272
273
274
275
	/**
276
	 *  'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
277
	 *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
278
	 *  'label' the translation key.
279
	 *  'enabled' is a condition when the field must be managed.
280
	 *  'position' is the sort order of field.
281
	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
282
	 *  '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)
283
	 *  'noteditable' says if field is not editable (1 or 0)
284
	 *  '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.
285
	 *  'index' if we want an index in database.
286
	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
287
	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
288
	 *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
289
	 *  'css' is the CSS style to use on field. For example: 'maxwidth200'
290
	 *  'help' is a string visible as a tooltip on field
291
	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
292
	 *  '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.
293
	 *  'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
294
	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
295
	 *
296
	 *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
297
	 */
298
299
	// BEGIN MODULEBUILDER PROPERTIES
300
	/**
301
	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
302
	 */
303
	public $fields = array(
304
		'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
305
		'ref' =>array('type'=>'varchar(12)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>25),
306
		'label' =>array('type'=>'varchar(30)', 'label'=>'Label', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>30),
307
		'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>35, 'index'=>1),
308
		'bank' =>array('type'=>'varchar(60)', 'label'=>'Bank', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
309
		'code_banque' =>array('type'=>'varchar(128)', 'label'=>'Code banque', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
310
		'code_guichet' =>array('type'=>'varchar(6)', 'label'=>'Code guichet', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
311
		'number' =>array('type'=>'varchar(255)', 'label'=>'Number', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
312
		'cle_rib' =>array('type'=>'varchar(5)', 'label'=>'Cle rib', 'enabled'=>1, 'visible'=>-1, 'position'=>60),
313
		'bic' =>array('type'=>'varchar(11)', 'label'=>'Bic', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
314
		'iban_prefix' =>array('type'=>'varchar(34)', 'label'=>'Iban prefix', 'enabled'=>1, 'visible'=>-1, 'position'=>70),
315
		'country_iban' =>array('type'=>'varchar(2)', 'label'=>'Country iban', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
316
		'cle_iban' =>array('type'=>'varchar(2)', 'label'=>'Cle iban', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
317
		'domiciliation' =>array('type'=>'varchar(255)', 'label'=>'Domiciliation', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
318
		'state_id' =>array('type'=>'integer', 'label'=>'StateId', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
319
		'fk_pays' =>array('type'=>'integer', 'label'=>'Country', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>95),
320
		'proprio' =>array('type'=>'varchar(60)', 'label'=>'Proprio', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
321
		'owner_address' =>array('type'=>'varchar(255)', 'label'=>'Owner address', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
322
		'owner_zip' =>array('type'=>'varchar(25)', 'label'=>'Owner zip', 'enabled'=>1, 'visible'=>-1, 'position'=>106),
323
		'owner_town' =>array('type'=>'varchar(50)', 'label'=>'Owner town', 'enabled'=>1, 'visible'=>-1, 'position'=>107),
324
		'owner_country_id' =>array('type'=>'integer', 'label'=>'Owner country', 'enabled'=>1, 'visible'=>-1, 'position'=>108),
325
		'courant' =>array('type'=>'smallint(6)', 'label'=>'Courant', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>110),
326
		'clos' =>array('type'=>'smallint(6)', 'label'=>'Clos', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>115),
327
		'rappro' =>array('type'=>'smallint(6)', 'label'=>'Rappro', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
328
		'url' =>array('type'=>'varchar(128)', 'label'=>'Url', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
329
		'account_number' =>array('type'=>'varchar(32)', 'label'=>'Account number', 'enabled'=>1, 'visible'=>-1, 'position'=>130),
330
		'fk_accountancy_journal' =>array('type'=>'integer', 'label'=>'Accountancy journal ID', 'enabled'=>1, 'visible'=>-1, 'position'=>132),
331
		'accountancy_journal' =>array('type'=>'varchar(20)', 'label'=>'Accountancy journal', 'enabled'=>1, 'visible'=>-1, 'position'=>135),
332
		'currency_code' =>array('type'=>'varchar(3)', 'label'=>'Currency code', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>140),
333
		'min_allowed' =>array('type'=>'integer', 'label'=>'Min allowed', 'enabled'=>1, 'visible'=>-1, 'position'=>145),
334
		'min_desired' =>array('type'=>'integer', 'label'=>'Min desired', 'enabled'=>1, 'visible'=>-1, 'position'=>150),
335
		'comment' =>array('type'=>'text', 'label'=>'Comment', 'enabled'=>1, 'visible'=>-1, 'position'=>155),
336
		'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>156),
337
		'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>157),
338
		'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
339
		'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>165),
340
		'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>170),
341
		'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>175),
342
		'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>180),
343
		'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
344
	);
345
	// END MODULEBUILDER PROPERTIES
346
347
	/**
348
	 * Current account
349
	 */
350
	const TYPE_CURRENT = 1;
351
	/**
352
	 * Cash account
353
	 */
354
	const TYPE_CASH = 2;
355
	/**
356
	 * Savings account
357
	 */
358
	const TYPE_SAVINGS = 0;
359
360
361
	const STATUS_OPEN = 0;
362
	const STATUS_CLOSED = 1;
363
364
365
	/**
366
	 *  Constructor
367
	 *
368
	 *  @param	DoliDB		$db		Database handler
369
	 */
370
	public function __construct(DoliDB $db)
371
	{
372
		global $langs;
373
374
		$this->db = $db;
375
376
		$this->solde = 0;
377
378
		$this->type_lib = array(
379
			self::TYPE_SAVINGS => $langs->trans("BankType0"),
380
			self::TYPE_CURRENT => $langs->trans("BankType1"),
381
			self::TYPE_CASH => $langs->trans("BankType2"),
382
		);
383
384
		$this->status = array(
385
			self::STATUS_OPEN => $langs->trans("StatusAccountOpened"),
386
			self::STATUS_CLOSED => $langs->trans("StatusAccountClosed")
387
		);
388
	}
389
390
	/**
391
	 * Shows the account number in the appropriate format
392
	 *
393
	 * @return string
394
	 */
395
	public function __toString()
396
	{
397
		$string = '';
398
		foreach ($this->getFieldsToShow() as $val) {
399
			if ($val == 'BankCode') {
400
				$string .= $this->code_banque.' ';
401
			} elseif ($val == 'BankAccountNumber') {
402
				$string .= $this->number.' ';
403
			} elseif ($val == 'DeskCode') {
404
				$string .= $this->code_guichet.' ';
405
			} elseif ($val == 'BankAccountNumberKey') {
406
				$string .= $this->cle_rib.' ';
407
			} elseif ($val == 'BIC') {
408
				$string .= $this->bic.' ';
409
			} elseif ($val == 'IBAN') {
410
				$string .= $this->iban.' ';
411
			}
412
		}
413
414
		return trim($string);
415
	}
416
417
418
	/**
419
	 *  Return if a bank account need to be conciliated
420
	 *
421
	 *  @return     int         1 if need to be concialiated, < 0 otherwise.
422
	 */
423
	public function canBeConciliated()
424
	{
425
		global $conf;
426
427
		if (empty($this->rappro)) {
428
			return -1;
429
		}
430
		if ($this->courant == Account::TYPE_CASH && empty($conf->global->BANK_CAN_RECONCILIATE_CASHACCOUNT)) {
431
			return -2;
432
		}
433
		if ($this->clos) {
434
			return -3;
435
		}
436
		return 1;
437
	}
438
439
440
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
441
	/**
442
	 *      Add a link between bank line record and its source
443
	 *
444
	 *      @param	int		$line_id    Id of bank entry
445
	 *      @param  int		$url_id     Id of object related to link
446
	 *      @param  string	$url        Url (deprecated, we use now 'url_id' and 'type' instead)
447
	 *      @param  string	$label      Link label
448
	 *      @param  string	$type       Type of link ('payment', 'company', 'member', ...)
449
	 *      @return int         		<0 if KO, id line if OK
450
	 */
451
	public function add_url_line($line_id, $url_id, $url, $label, $type)
452
	{
453
		// phpcs:enable
454
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."bank_url (";
455
		$sql .= "fk_bank";
456
		$sql .= ", url_id";
457
		$sql .= ", url";		// deprecated
458
		$sql .= ", label";
459
		$sql .= ", type";
460
		$sql .= ") VALUES (";
461
		$sql .= " ".((int) $line_id);
462
		$sql .= ", ".((int) $url_id);
463
		$sql .= ", '".$this->db->escape($url)."'";		// dperecated
464
		$sql .= ", '".$this->db->escape($label)."'";
465
		$sql .= ", '".$this->db->escape($type)."'";
466
		$sql .= ")";
467
468
		dol_syslog(get_class($this)."::add_url_line", LOG_DEBUG);
469
		if ($this->db->query($sql)) {
470
			$rowid = $this->db->last_insert_id(MAIN_DB_PREFIX."bank_url");
471
			return $rowid;
472
		} else {
473
			$this->error = $this->db->lasterror();
474
			return -1;
475
		}
476
	}
477
478
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
479
	/**
480
	 * 		TODO Move this into AccountLine
481
	 *      Return array with links from llx_bank_url
482
	 *
483
	 *      @param  int         $fk_bank    To search using bank transaction id
484
	 *      @param  int         $url_id     To search using link to
485
	 *      @param  string      $type       To search using type
486
	 *      @return array|int               Array of links array('url'=>, 'url_id'=>, 'label'=>, 'type'=> 'fk_bank'=> ) or -1 on error
487
	 */
488
	public function get_url($fk_bank = '', $url_id = '', $type = '')
489
	{
490
		// phpcs:enable
491
		$lines = array();
492
493
		// Check parameters
494
		if (!empty($fk_bank) && (!empty($url_id) || !empty($type))) {
495
			$this->error = "ErrorBadParameter";
496
			return -1;
497
		}
498
499
		$sql = "SELECT fk_bank, url_id, url, label, type";
500
		$sql .= " FROM ".MAIN_DB_PREFIX."bank_url";
501
		if ($fk_bank > 0) {
502
			$sql .= " WHERE fk_bank = ".((int) $fk_bank);
503
		} else {
504
			$sql .= " WHERE url_id = ".((int) $url_id)." AND type = '".$this->db->escape($type)."'";
505
		}
506
		$sql .= " ORDER BY type, label";
507
508
		dol_syslog(get_class($this)."::get_url", LOG_DEBUG);
509
		$result = $this->db->query($sql);
510
		if ($result) {
511
			$i = 0;
512
			$num = $this->db->num_rows($result);
513
			while ($i < $num) {
514
				$obj = $this->db->fetch_object($result);
515
				// Anciens liens (pour compatibilite)
516
				$lines[$i][0] = $obj->url;
517
				$lines[$i][1] = $obj->url_id;
518
				$lines[$i][2] = $obj->label;
519
				$lines[$i][3] = $obj->type;
520
				// Nouveaux liens
521
				$lines[$i]['url'] = $obj->url;
522
				$lines[$i]['url_id'] = $obj->url_id;
523
				$lines[$i]['label'] = $obj->label;
524
				$lines[$i]['type'] = $obj->type;
525
				$lines[$i]['fk_bank'] = $obj->fk_bank;
526
				$i++;
527
			}
528
		} else {
529
			dol_print_error($this->db);
530
		}
531
532
		return $lines;
533
	}
534
535
	/**
536
	 *  Add an entry into table ".MAIN_DB_PREFIX."bank
537
	 *
538
	 *  @param	int	        $date			Date operation
539
	 *  @param	string		$oper			'VIR','PRE','LIQ','VAD','CB','CHQ'...
540
	 *  @param	string		$label			Descripton
541
	 *  @param	float		$amount			Amount
542
	 *  @param	string		$num_chq		Numero cheque or transfer
543
	 *  @param	int  		$categorie		Category id (optionnal)
544
	 *  @param	User		$user			User that create
545
	 *  @param	string		$emetteur		Name of cheque writer
546
	 *  @param	string		$banque			Bank of cheque writer
547
	 *  @param	string		$accountancycode	When we record a free bank entry, we must provide accounting account if accountancy module is on.
548
	 *  @param	int			$datev			Date value
549
	 *  @param  string      $num_releve     Label of bank receipt for reconciliation
550
	 *  @param	float		$amount_main_currency	Amount
551
	 *  @return	int							Rowid of added entry, <0 if KO
552
	 */
553
	public function addline($date, $oper, $label, $amount, $num_chq, $categorie, User $user, $emetteur = '', $banque = '', $accountancycode = '', $datev = null, $num_releve = '', $amount_main_currency = null)
554
	{
555
		// Deprecation warning
556
		if (is_numeric($oper)) {
557
			dol_syslog(__METHOD__.": using numeric operations is deprecated", LOG_WARNING);
558
		}
559
560
		if (empty($this->id) && !empty($this->rowid)) {	// For backward compatibility
561
			$this->id = $this->rowid;
562
		}
563
564
		// Clean parameters
565
		$emetteur = trim($emetteur);
566
		$banque = trim($banque);
567
		$label = trim($label);
568
569
		$now = dol_now();
570
571
		if (is_numeric($oper)) {    // Clean operation to have a code instead of a rowid
572
			$sql = "SELECT code FROM ".MAIN_DB_PREFIX."c_paiement";
573
			$sql .= " WHERE id = ".((int) $oper);
574
			$sql .= " AND entity IN (".getEntity('c_paiement').")";
575
			$resql = $this->db->query($sql);
576
			if ($resql) {
577
				$obj = $this->db->fetch_object($resql);
578
				$oper = $obj->code;
579
			} else {
580
				dol_print_error($this->db, 'Failed to get payment type code');
581
				return -1;
582
			}
583
		}
584
585
		// Check parameters
586
		if (!$oper) {
587
			$this->error = "oper not defined";
588
			return -1;
589
		}
590
		if (!$this->id) {
591
			$this->error = "this->id not defined";
592
			return -2;
593
		}
594
		if ($this->courant == Account::TYPE_CASH && $oper != 'LIQ') {
595
			$this->error = "ErrorCashAccountAcceptsOnlyCashMoney";
596
			return -3;
597
		}
598
599
		$this->db->begin();
600
601
		if (is_null($datev) || empty($datev)) {
602
			$datev = $date;
603
		}
604
605
		$accline = new AccountLine($this->db);
606
		$accline->datec = $now;
607
		$accline->dateo = $date;
608
		$accline->datev = $datev;
609
		$accline->label = $label;
610
		$accline->amount = $amount;
611
		$accline->amount_main_currency = $amount_main_currency;
612
		$accline->fk_user_author = $user->id;
613
		$accline->fk_account = $this->id;
614
		$accline->fk_type = $oper;
615
		$accline->numero_compte = $accountancycode;
616
		$accline->num_releve = $num_releve;
617
618
		if ($num_chq) {
619
			$accline->num_chq = $num_chq;
620
		}
621
622
		if ($emetteur) {
623
			$accline->emetteur = $emetteur;
624
		}
625
626
		if ($banque) {
627
			$accline->bank_chq = $banque;
628
		}
629
630
		if ($accline->insert() > 0) {
631
			if ($categorie > 0) {
632
				$sql = "INSERT INTO ".MAIN_DB_PREFIX."bank_class(";
633
				$sql .= "lineid, fk_categ";
634
				$sql .= ") VALUES (";
635
				$sql .= ((int) $accline->id).", '".$this->db->escape($categorie)."'";
636
				$sql .= ")";
637
638
				$result = $this->db->query($sql);
639
				if (!$result) {
640
					$this->error = $this->db->lasterror();
641
					$this->db->rollback();
642
643
					return -4;
644
				}
645
			}
646
647
			$this->db->commit();
648
649
			return $accline->id;
650
		} else {
651
			$this->error = $accline->error;
652
			$this->errors = $accline->errors;
653
			$this->db->rollback();
654
655
			return -5;
656
		}
657
	}
658
659
	/**
660
	 *  Create bank account into database
661
	 *
662
	 *  @param	User	$user		Object user making creation
663
	 *  @param  int     $notrigger  1=Disable triggers
664
	 *  @return int        			< 0 if KO, > 0 if OK
665
	 */
666
	public function create(User $user, $notrigger = 0)
667
	{
668
		global $langs, $conf;
669
670
		$error = 0;
671
672
		// Clean parameters
673
		if (!$this->min_allowed) {
674
			$this->min_allowed = 0;
675
		}
676
		if (!$this->min_desired) {
677
			$this->min_desired = 0;
678
		}
679
680
		// Check parameters
681
		if (empty($this->country_id)) {
682
			$this->error = $langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Country"));
683
			dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
684
			return -1;
685
		}
686
		if (empty($this->ref)) {
687
			$this->error = $langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Ref"));
688
			dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
689
			return -1;
690
		}
691
		if (empty($this->date_solde)) {
692
			$this->error = $langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("DateInitialBalance"));
693
			dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
694
			return -1;
695
		}
696
697
		// Chargement librairie pour acces fonction controle RIB
698
		require_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php';
699
700
		$now = dol_now();
701
702
		$this->db->begin();
703
704
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."bank_account (";
705
		$sql .= "datec";
706
		$sql .= ", ref";
707
		$sql .= ", label";
708
		$sql .= ", entity";
709
		$sql .= ", account_number";
710
		$sql .= ", fk_accountancy_journal";
711
		$sql .= ", bank";
712
		$sql .= ", code_banque";
713
		$sql .= ", code_guichet";
714
		$sql .= ", number";
715
		$sql .= ", cle_rib";
716
		$sql .= ", bic";
717
		$sql .= ", iban_prefix";
718
		$sql .= ", domiciliation";
719
		$sql .= ", pti_in_ctti";
720
		$sql .= ", proprio";
721
		$sql .= ", owner_address";
722
		$sql .= ", owner_zip";
723
		$sql .= ", owner_town";
724
		$sql .= ", owner_country_id";
725
		$sql .= ", currency_code";
726
		$sql .= ", rappro";
727
		$sql .= ", min_allowed";
728
		$sql .= ", min_desired";
729
		$sql .= ", comment";
730
		$sql .= ", state_id";
731
		$sql .= ", fk_pays";
732
		$sql .= ", ics";
733
		$sql .= ", ics_transfer";
734
		$sql .= ") VALUES (";
735
		$sql .= "'".$this->db->idate($now)."'";
736
		$sql .= ", '".$this->db->escape($this->ref)."'";
737
		$sql .= ", '".$this->db->escape($this->label)."'";
738
		$sql .= ", ".((int) $conf->entity);
739
		$sql .= ", '".$this->db->escape($this->account_number)."'";
740
		$sql .= ", ".($this->fk_accountancy_journal > 0 ? ((int) $this->fk_accountancy_journal) : "null");
741
		$sql .= ", '".$this->db->escape($this->bank)."'";
742
		$sql .= ", '".$this->db->escape($this->code_banque)."'";
743
		$sql .= ", '".$this->db->escape($this->code_guichet)."'";
744
		$sql .= ", '".$this->db->escape($this->number)."'";
745
		$sql .= ", '".$this->db->escape($this->cle_rib)."'";
746
		$sql .= ", '".$this->db->escape($this->bic)."'";
747
		$sql .= ", '".$this->db->escape($this->iban)."'";
748
		$sql .= ", '".$this->db->escape($this->domiciliation)."'";
749
		$sql .= ", ".((int) $this->pti_in_ctti);
750
		$sql .= ", '".$this->db->escape($this->proprio)."'";
751
		$sql .= ", '".$this->db->escape($this->owner_address)."'";
752
		$sql .= ", '".$this->db->escape($this->owner_zip)."'";
753
		$sql .= ", '".$this->db->escape($this->owner_town)."'";
754
		$sql .= ", ".($this->owner_country_id > 0 ? ((int) $this->owner_country_id) : "null");
755
		$sql .= ", '".$this->db->escape($this->currency_code)."'";
756
		$sql .= ", ".((int) $this->rappro);
757
		$sql .= ", ".price2num($this->min_allowed, 'MT');
758
		$sql .= ", ".price2num($this->min_desired, 'MT');
759
		$sql .= ", '".$this->db->escape($this->comment)."'";
760
		$sql .= ", ".($this->state_id > 0 ? ((int) $this->state_id) : "null");
761
		$sql .= ", ".($this->country_id > 0 ? ((int) $this->country_id) : "null");
762
		$sql .= ", '".$this->db->escape($this->ics)."'";
763
		$sql .= ", '".$this->db->escape($this->ics_transfer)."'";
764
		$sql .= ")";
765
766
		dol_syslog(get_class($this)."::create", LOG_DEBUG);
767
		$resql = $this->db->query($sql);
768
		if ($resql) {
769
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."bank_account");
770
771
			$result = $this->update($user, 1);
772
			if ($result > 0) {
773
				$accline = new AccountLine($this->db);
774
				$accline->datec = $this->db->idate($now);
775
				$accline->label = '('.$langs->trans("InitialBankBalance").')';
776
				$accline->amount = price2num($this->solde);
777
				$accline->fk_user_author = $user->id;
778
				$accline->fk_account = $this->id;
779
				$accline->datev = $this->db->idate($this->date_solde);
780
				$accline->dateo = $this->db->idate($this->date_solde);
781
				$accline->fk_type = 'SOLD';
782
783
				if ($accline->insert() < 0) {
784
					$error++;
785
					$this->error = $accline->error;
786
					$this->errors = $accline->errors;
787
				}
788
789
				if (!$error) {
790
					$result = $this->insertExtraFields();
791
					if ($result < 0) {
792
						$error++;
793
					}
794
				}
795
796
				if (!$error && !$notrigger) {
797
					// Call trigger
798
					$result = $this->call_trigger('BANKACCOUNT_CREATE', $user);
799
					if ($result < 0) {
800
						$error++;
801
					}
802
					// End call triggers
803
				}
804
			} else {
805
				$error++;
806
			}
807
		} else {
808
			if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
809
				$this->error = $langs->trans("ErrorBankLabelAlreadyExists");
810
				$error++;
811
			} else {
812
				$this->error = $this->db->error()." sql=".$sql;
813
				$error++;
814
			}
815
		}
816
817
		if (!$error) {
818
			$this->db->commit();
819
			return $this->id;
820
		} else {
821
			$this->db->rollback();
822
			return -1 * $error;
823
		}
824
	}
825
826
	/**
827
	 *    	Update bank account card
828
	 *
829
	 *    	@param	User	$user       Object user making action
830
	 *      @param  int     $notrigger  1=Disable triggers
831
	 *		@return	int					<0 if KO, >0 if OK
832
	 */
833
	public function update(User $user, $notrigger = 0)
834
	{
835
		global $langs, $conf;
836
837
		$error = 0;
838
839
		$this->db->begin();
840
841
		// Check parameters
842
		if (empty($this->country_id)) {
843
			$this->error = $langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Country"));
844
			dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR);
845
			return -1;
846
		}
847
		if (empty($this->ref)) {
848
			$this->error = $langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Ref"));
849
			dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR);
850
			return -1;
851
		}
852
		if (!$this->label) {
853
			$this->label = "???";
854
		}
855
856
		$sql = "UPDATE ".MAIN_DB_PREFIX."bank_account SET ";
857
858
		$sql .= " ref   = '".$this->db->escape($this->ref)."'";
859
		$sql .= ",label = '".$this->db->escape($this->label)."'";
860
861
		$sql .= ",courant = ".((int) $this->courant);
862
		$sql .= ",clos = ".((int) $this->clos);
863
		$sql .= ",rappro = ".((int) $this->rappro);
864
		$sql .= ",url = ".($this->url ? "'".$this->db->escape($this->url)."'" : "null");
865
		$sql .= ",account_number = '".$this->db->escape($this->account_number)."'";
866
		$sql .= ",fk_accountancy_journal = ".($this->fk_accountancy_journal > 0 ? ((int) $this->fk_accountancy_journal) : "null");
867
		$sql .= ",bank  = '".$this->db->escape($this->bank)."'";
868
		$sql .= ",code_banque='".$this->db->escape($this->code_banque)."'";
869
		$sql .= ",code_guichet='".$this->db->escape($this->code_guichet)."'";
870
		$sql .= ",number='".$this->db->escape($this->number)."'";
871
		$sql .= ",cle_rib='".$this->db->escape($this->cle_rib)."'";
872
		$sql .= ",bic='".$this->db->escape($this->bic)."'";
873
		$sql .= ",iban_prefix = '".$this->db->escape($this->iban)."'";
874
		$sql .= ",domiciliation='".$this->db->escape($this->domiciliation)."'";
875
		$sql .= ",pti_in_ctti=".((int) $this->pti_in_ctti);
876
		$sql .= ",proprio = '".$this->db->escape($this->proprio)."'";
877
		$sql .= ",owner_address = '".$this->db->escape($this->owner_address)."'";
878
		$sql .= ",owner_zip = '".$this->db->escape($this->owner_zip)."'";
879
		$sql .= ",owner_town = '".$this->db->escape($this->owner_town)."'";
880
		$sql .= ",owner_country_id = ".($this->owner_country_id > 0 ? ((int) $this->owner_country_id) : "null");
881
882
		$sql .= ",currency_code = '".$this->db->escape($this->currency_code)."'";
883
884
		$sql .= ",min_allowed = ".($this->min_allowed != '' ? price2num($this->min_allowed) : "null");
885
		$sql .= ",min_desired = ".($this->min_desired != '' ? price2num($this->min_desired) : "null");
886
		$sql .= ",comment = '".$this->db->escape($this->comment)."'";
887
888
		$sql .= ",state_id = ".($this->state_id > 0 ? ((int) $this->state_id) : "null");
889
		$sql .= ",fk_pays = ".($this->country_id > 0 ? ((int) $this->country_id) : "null");
890
		$sql .= ",ics = '".$this->db->escape($this->ics)."'";
891
		$sql .= ",ics_transfer = '".$this->db->escape($this->ics_transfer)."'";
892
893
		$sql .= " WHERE rowid = ".((int) $this->id);
894
895
		dol_syslog(get_class($this)."::update", LOG_DEBUG);
896
		$result = $this->db->query($sql);
897
		if ($result) {
898
			// Actions on extra fields (by external module or standard code)
899
			if (!$error) {
900
				$result = $this->insertExtraFields();
901
				if ($result < 0) {
902
					$error++;
903
				}
904
			}
905
906
			if (!$error && !$notrigger) {
907
				// Call trigger
908
				$result = $this->call_trigger('BANKACCOUNT_MODIFY', $user);
909
				if ($result < 0) {
910
					$error++;
911
				}
912
				// End call triggers
913
			}
914
		} else {
915
			$error++;
916
			$this->error = $this->db->lasterror();
917
			dol_print_error($this->db);
918
		}
919
920
		if (!$error) {
921
			$this->db->commit();
922
			return $this->id;
923
		} else {
924
			$this->db->rollback();
925
			return -1 * $error;
926
		}
927
	}
928
929
930
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
931
	/**
932
	 *  Update BBAN (RIB) account fields
933
	 *
934
	 *  @param	User	$user       Object user making update
935
	 *	@return	int					<0 if KO, >0 if OK
936
	 */
937
	public function update_bban(User $user = null)
938
	{
939
		// phpcs:enable
940
		global $conf, $langs;
941
942
		// Load library to get BAN control function
943
		require_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php';
944
945
		dol_syslog(get_class($this)."::update_bban $this->code_banque,$this->code_guichet,$this->number,$this->cle_rib,$this->iban");
946
947
		// Check parameters
948
		if (!$this->ref) {
949
			$this->error = $langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->trans("Ref"));
950
			return -2;
951
		}
952
953
		$sql = "UPDATE ".MAIN_DB_PREFIX."bank_account SET ";
954
		$sql .= " bank  = '".$this->db->escape($this->bank)."'";
955
		$sql .= ",code_banque='".$this->db->escape($this->code_banque)."'";
956
		$sql .= ",code_guichet='".$this->db->escape($this->code_guichet)."'";
957
		$sql .= ",number='".$this->db->escape($this->number)."'";
958
		$sql .= ",cle_rib='".$this->db->escape($this->cle_rib)."'";
959
		$sql .= ",bic='".$this->db->escape($this->bic)."'";
960
		$sql .= ",iban_prefix = '".$this->db->escape($this->iban)."'";
961
		$sql .= ",domiciliation='".$this->db->escape($this->domiciliation)."'";
962
		$sql .= ",proprio = '".$this->db->escape($this->proprio)."'";
963
		$sql .= ",owner_address = '".$this->db->escape($this->owner_address)."'";
964
		$sql .= ",owner_zip = '".$this->db->escape($this->owner_zip)."'";
965
		$sql .= ",owner_town = '".$this->db->escape($this->owner_town)."'";
966
		$sql .= ",owner_country_id = ".($this->owner_country_id > 0 ? ((int) $this->owner_country_id) : "null");
967
		$sql .= ",state_id = ".($this->state_id > 0 ? $this->state_id : "null");
968
		$sql .= ",fk_pays = ".($this->country_id > 0 ? $this->country_id : "null");
969
		$sql .= " WHERE rowid = ".((int) $this->id);
970
		$sql .= " AND entity = ".((int) $conf->entity);
971
972
		dol_syslog(get_class($this)."::update_bban", LOG_DEBUG);
973
974
		$result = $this->db->query($sql);
975
		if ($result) {
976
			return 1;
977
		} else {
978
			$this->error = $this->db->lasterror();
979
			dol_print_error($this->db);
980
			return -1;
981
		}
982
	}
983
984
985
	/**
986
	 *      Load a bank account into memory from database
987
	 *
988
	 *      @param	int		$id      	Id of bank account to get
989
	 *      @param  string	$ref     	Ref of bank account to get
990
	 *      @return	int					<0 if KO, >0 if OK
991
	 */
992
	public function fetch($id, $ref = '')
993
	{
994
		global $conf;
995
996
		if (empty($id) && empty($ref)) {
997
			$this->error = "ErrorBadParameters";
998
			return -1;
999
		}
1000
1001
		$sql = "SELECT ba.rowid, ba.ref, ba.label, ba.bank, ba.number, ba.courant, ba.clos, ba.rappro, ba.url,";
1002
		$sql .= " ba.code_banque, ba.code_guichet, ba.cle_rib, ba.bic, ba.iban_prefix as iban,";
1003
		$sql .= " ba.domiciliation as address, ba.pti_in_ctti, ba.proprio, ba.owner_address, ba.owner_zip, ba.owner_town, ba.owner_country_id, ba.state_id, ba.fk_pays as country_id,";
1004
		$sql .= " ba.account_number, ba.fk_accountancy_journal, ba.currency_code,";
1005
		$sql .= " ba.min_allowed, ba.min_desired, ba.comment,";
1006
		$sql .= " ba.datec as date_creation, ba.tms as date_update, ba.ics, ba.ics_transfer,";
1007
		$sql .= ' c.code as country_code, c.label as country,';
1008
		$sql .= ' d.code_departement as state_code, d.nom as state,';
1009
		$sql .= ' aj.code as accountancy_journal';
1010
		$sql .= " FROM ".MAIN_DB_PREFIX."bank_account as ba";
1011
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_country as c ON ba.fk_pays = c.rowid';
1012
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_departements as d ON ba.state_id = d.rowid';
1013
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'accounting_journal as aj ON aj.rowid=ba.fk_accountancy_journal';
1014
		$sql .= " WHERE ba.entity IN (".getEntity($this->element).")";
1015
		if ($id) {
1016
			$sql .= " AND ba.rowid = ".((int) $id);
1017
		}
1018
		if ($ref) {
1019
			$sql .= " AND ba.ref = '".$this->db->escape($ref)."'";
1020
		}
1021
1022
		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1023
		$result = $this->db->query($sql);
1024
		if ($result) {
1025
			if ($this->db->num_rows($result)) {
1026
				$obj = $this->db->fetch_object($result);
1027
1028
				$this->id            = $obj->rowid;
1029
				$this->rowid         = $obj->rowid;
1030
				$this->ref           = $obj->ref;
1031
				$this->label         = $obj->label;
1032
				$this->type          = $obj->courant;
1033
				$this->courant       = $obj->courant;
1034
				$this->bank          = $obj->bank;
1035
				$this->clos          = $obj->clos;
1036
				$this->rappro        = $obj->rappro;
1037
				$this->url           = $obj->url;
1038
1039
				$this->code_banque   = $obj->code_banque;
1040
				$this->code_guichet  = $obj->code_guichet;
1041
				$this->number        = $obj->number;
1042
				$this->cle_rib       = $obj->cle_rib;
1043
				$this->bic           = $obj->bic;
1044
				$this->iban          = $obj->iban;
1045
				$this->domiciliation = $obj->address;
1046
				$this->address       = $obj->address;
1047
				$this->pti_in_ctti   = $obj->pti_in_ctti;
1048
				$this->proprio       = $obj->proprio;
1049
				$this->owner_address = $obj->owner_address;
1050
				$this->owner_zip     = $obj->owner_zip;
1051
				$this->owner_town    = $obj->owner_town;
1052
				$this->owner_country_id = $obj->owner_country_id;
1053
1054
				$this->state_id        = $obj->state_id;
1055
				$this->state_code      = $obj->state_code;
1056
				$this->state           = $obj->state;
1057
1058
				$this->country_id    = $obj->country_id;
1059
				$this->country_code  = $obj->country_code;
1060
				$this->country       = $obj->country;
1061
1062
				$this->account_number = $obj->account_number;
1063
				$this->fk_accountancy_journal = $obj->fk_accountancy_journal;
1064
				$this->accountancy_journal = $obj->accountancy_journal;
1065
1066
				$this->currency_code  = $obj->currency_code;
1067
				$this->account_currency_code = $obj->currency_code;
1068
				$this->min_allowed    = $obj->min_allowed;
1069
				$this->min_desired    = $obj->min_desired;
1070
				$this->comment        = $obj->comment;
1071
1072
				$this->date_creation  = $this->db->jdate($obj->date_creation);
1073
				$this->date_update    = $this->db->jdate($obj->date_update);
1074
1075
				$this->ics           = $obj->ics;
1076
				$this->ics_transfer  = $obj->ics_transfer;
1077
1078
				// Retrieve all extrafield
1079
				// fetch optionals attributes and labels
1080
				$this->fetch_optionals();
1081
1082
				return 1;
1083
			} else {
1084
				return 0;
1085
			}
1086
		} else {
1087
			$this->error = $this->db->lasterror();
1088
			$this->errors[] = $this->error;
1089
			return -1;
1090
		}
1091
	}
1092
1093
	/**
1094
	 * Sets object to supplied categories.
1095
	 *
1096
	 * Deletes object from existing categories not supplied.
1097
	 * Adds it to non existing supplied categories.
1098
	 * Existing categories are left untouch.
1099
	 *
1100
	 * @param 	int[]|int 	$categories 	Category or categories IDs
1101
	 * @return 	int							<0 if KO, >0 if OK
1102
	 */
1103
	public function setCategories($categories)
1104
	{
1105
		require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1106
		return parent::setCategoriesCommon($categories, Categorie::TYPE_ACCOUNT);
1107
	}
1108
1109
	/**
1110
	 *  Delete bank account from database
1111
	 *
1112
	 *	@param	User	$user	User deleting
1113
	 *  @return int             <0 if KO, >0 if OK
1114
	 */
1115
	public function delete(User $user = null)
1116
	{
1117
		$error = 0;
1118
1119
		$this->db->begin();
1120
1121
		// Delete link between tag and bank account
1122
		if (!$error) {
1123
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_account";
1124
			$sql .= " WHERE fk_account = ".((int) $this->id);
1125
1126
			$resql = $this->db->query($sql);
1127
			if (!$resql) {
1128
				$error++;
1129
				$this->error = "Error ".$this->db->lasterror();
1130
			}
1131
		}
1132
1133
		if (!$error) {
1134
			$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element;
1135
			$sql .= " WHERE rowid = ".((int) $this->id);
1136
1137
			dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1138
			$result = $this->db->query($sql);
1139
			if ($result) {
1140
				// Remove extrafields
1141
				if (!$error) {
1142
					$result = $this->deleteExtraFields();
1143
					if ($result < 0) {
1144
						$error++;
1145
						dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1146
					}
1147
				}
1148
			} else {
1149
				$error++;
1150
				$this->error = "Error ".$this->db->lasterror();
1151
			}
1152
		}
1153
1154
		if (!$error) {
1155
			$this->db->commit();
1156
			return 1;
1157
		} else {
1158
			$this->db->rollback();
1159
			return -1;
1160
		}
1161
	}
1162
1163
1164
	/**
1165
	 *  Return label of object status
1166
	 *
1167
	 *  @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
1168
	 *  @return     string        		    Label
1169
	 */
1170
	public function getLibStatut($mode = 0)
1171
	{
1172
		return $this->LibStatut($this->clos, $mode);
1173
	}
1174
1175
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1176
	/**
1177
	 *  Return label of given object status
1178
	 *
1179
	 *  @param	 int		$status        	Id status
1180
	 *  @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
1181
	 *  @return  string        			    Label
1182
	 */
1183
	public function LibStatut($status, $mode = 0)
1184
	{
1185
		// phpcs:enable
1186
		global $langs;
1187
		$langs->load('banks');
1188
1189
		if ($status == self::STATUS_OPEN) {
1190
			$label = $langs->transnoentitiesnoconv("StatusAccountOpened");
1191
			$labelshort = $langs->transnoentitiesnoconv("StatusAccountOpened");
1192
			$statusType = 'status4';
1193
		} else {
1194
			$label = $langs->transnoentitiesnoconv("StatusAccountClosed");
1195
			$labelshort = $langs->transnoentitiesnoconv("StatusAccountClosed");
1196
			$statusType = 'status5';
1197
		}
1198
1199
		return dolGetStatus($label, $labelshort, '', $statusType, $mode);
1200
	}
1201
1202
1203
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1204
	/**
1205
	 *    Renvoi si un compte peut etre supprimer ou non (sans mouvements)
1206
	 *
1207
	 *    @return     boolean     vrai si peut etre supprime, faux sinon
1208
	 */
1209
	public function can_be_deleted()
1210
	{
1211
		// phpcs:enable
1212
		$can_be_deleted = false;
1213
1214
		$sql = "SELECT COUNT(rowid) as nb";
1215
		$sql .= " FROM ".MAIN_DB_PREFIX."bank";
1216
		$sql .= " WHERE fk_account = ".((int) $this->id);
1217
1218
		$resql = $this->db->query($sql);
1219
		if ($resql) {
1220
			$obj = $this->db->fetch_object($resql);
1221
			if ($obj->nb <= 1) {
1222
				$can_be_deleted = true; // Juste le solde
1223
			}
1224
		} else {
1225
			dol_print_error($this->db);
1226
		}
1227
		return $can_be_deleted;
1228
	}
1229
1230
1231
	/**
1232
	 *   Return error
1233
	 *
1234
	 *   @return	string		Error string
1235
	 */
1236
	public function error()
1237
	{
1238
		return $this->error;
1239
	}
1240
1241
	/**
1242
	 * 	Return current sold
1243
	 *
1244
	 * 	@param	int		$option		1=Exclude future operation date (this is to exclude input made in advance and have real account sold)
1245
	 *	@param	int		$date_end	Date until we want to get bank account sold
1246
	 *	@param	string	$field		dateo or datev
1247
	 *	@return	int		current sold (value date <= today)
1248
	 */
1249
	public function solde($option = 0, $date_end = '', $field = 'dateo')
1250
	{
1251
		$solde = 0;
1252
1253
		$sql = "SELECT sum(amount) as amount";
1254
		$sql .= " FROM ".MAIN_DB_PREFIX."bank";
1255
		$sql .= " WHERE fk_account = ".((int) $this->id);
1256
		if ($option == 1) {
1257
			$sql .= " AND ".$this->db->escape($field)." <= '".(!empty($date_end) ? $this->db->idate($date_end) : $this->db->idate(dol_now()))."'";
1258
		}
1259
1260
		$resql = $this->db->query($sql);
1261
		if ($resql) {
1262
			if ($this->db->num_rows($resql)) {
1263
				$obj = $this->db->fetch_object($resql);
1264
				$solde = $obj->amount;
1265
			}
1266
			$this->db->free($resql);
1267
		} else {
1268
			$this->errors[] = $this->db->lasterror;
1269
			return -1;
1270
		}
1271
1272
		return price2num($solde, 'MU');
1273
	}
1274
1275
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1276
	/**
1277
	 *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
1278
	 *
1279
	 *      @param	User	$user        		Objet user
1280
	 *		@param	int		$filteraccountid	To get info for a particular account id
1281
	 *      @return WorkboardResponse|int 		<0 if KO, WorkboardResponse if OK
1282
	 */
1283
	public function load_board(User $user, $filteraccountid = 0)
1284
	{
1285
		// phpcs:enable
1286
		global $conf, $langs;
1287
1288
		if ($user->socid) {
1289
			return -1; // protection pour eviter appel par utilisateur externe
1290
		}
1291
1292
		$sql = "SELECT b.rowid, b.datev as datefin";
1293
		$sql .= " FROM ".MAIN_DB_PREFIX."bank as b,";
1294
		$sql .= " ".MAIN_DB_PREFIX."bank_account as ba";
1295
		$sql .= " WHERE b.rappro=0";
1296
		$sql .= " AND b.fk_account = ba.rowid";
1297
		$sql .= " AND ba.entity IN (".getEntity('bank_account').")";
1298
		$sql .= " AND (ba.rappro = 1 AND ba.courant != 2)"; // Compte rapprochable
1299
		$sql .= " AND clos = 0";
1300
		if ($filteraccountid) {
1301
			$sql .= " AND ba.rowid = ".((int) $filteraccountid);
1302
		}
1303
1304
		$resql = $this->db->query($sql);
1305
		if ($resql) {
1306
			$langs->load("banks");
1307
			$now = dol_now();
1308
1309
			require_once DOL_DOCUMENT_ROOT.'/core/class/workboardresponse.class.php';
1310
1311
			$response = new WorkboardResponse();
1312
			$response->warning_delay = $conf->bank->rappro->warning_delay / 60 / 60 / 24;
1313
			$response->label = $langs->trans("TransactionsToConciliate");
1314
			$response->labelShort = $langs->trans("TransactionsToConciliateShort");
1315
			$response->url = DOL_URL_ROOT.'/compta/bank/list.php?leftmenu=bank&amp;mainmenu=bank';
1316
			$response->img = img_object('', "payment");
1317
1318
			while ($obj = $this->db->fetch_object($resql)) {
1319
				$response->nbtodo++;
1320
				if ($this->db->jdate($obj->datefin) < ($now - $conf->bank->rappro->warning_delay)) {
1321
					$response->nbtodolate++;
1322
				}
1323
			}
1324
1325
			return $response;
1326
		} else {
1327
			dol_print_error($this->db);
1328
			$this->error = $this->db->error();
1329
			return -1;
1330
		}
1331
	}
1332
1333
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1334
	/**
1335
	 *      Charge indicateurs this->nb de tableau de bord
1336
	 *		@param		int			$filteraccountid	To get info for a particular account id
1337
	 *      @return     int         <0 if ko, >0 if ok
1338
	 */
1339
	public function load_state_board($filteraccountid = 0)
1340
	{
1341
		// phpcs:enable
1342
		global $user;
1343
1344
		if ($user->socid) {
1345
			return -1; // protection pour eviter appel par utilisateur externe
1346
		}
1347
1348
		$sql = "SELECT count(b.rowid) as nb";
1349
		$sql .= " FROM ".MAIN_DB_PREFIX."bank as b,";
1350
		$sql .= " ".MAIN_DB_PREFIX."bank_account as ba";
1351
		$sql .= " WHERE b.fk_account = ba.rowid";
1352
		$sql .= " AND ba.entity IN (".getEntity('bank_account').")";
1353
		$sql .= " AND (ba.rappro = 1 AND ba.courant != 2)"; // Compte rapprochable
1354
		$sql .= " AND clos = 0";
1355
		if ($filteraccountid) {
1356
			$sql .= " AND ba.rowid = ".((int) $filteraccountid);
1357
		}
1358
1359
		$resql = $this->db->query($sql);
1360
		if ($resql) {
1361
			while ($obj = $this->db->fetch_object($resql)) {
1362
				$this->nb["banklines"] = $obj->nb;
1363
			}
1364
			$this->db->free($resql);
1365
		} else {
1366
			dol_print_error($this->db);
1367
			$this->error = $this->db->error();
1368
			return -1;
1369
		}
1370
	}
1371
1372
1373
	/**
1374
	 *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
1375
	 *
1376
	 *      @return int     Nb of account we can reconciliate
1377
	 */
1378
	public function countAccountToReconcile()
1379
	{
1380
		global $db, $conf, $user;
1381
1382
		//Protection against external users
1383
		if ($user->socid) {
1384
			return 0;
1385
		}
1386
1387
		$nb = 0;
1388
1389
		$sql = "SELECT COUNT(ba.rowid) as nb";
1390
		$sql .= " FROM ".MAIN_DB_PREFIX."bank_account as ba";
1391
		$sql .= " WHERE ba.rappro > 0 and ba.clos = 0";
1392
		$sql .= " AND ba.entity IN (".getEntity('bank_account').")";
1393
		if (empty($conf->global->BANK_CAN_RECONCILIATE_CASHACCOUNT)) {
1394
			$sql .= " AND ba.courant != 2";
1395
		}
1396
		$resql = $this->db->query($sql);
1397
		if ($resql) {
1398
			$obj = $this->db->fetch_object($resql);
1399
			$nb = $obj->nb;
1400
		} else {
1401
			dol_print_error($this->db);
1402
		}
1403
1404
		return $nb;
1405
	}
1406
1407
	/**
1408
	 * getTooltipContentArray
1409
	 * @param array $params params to construct tooltip data
1410
	 * @since v18
1411
	 * @return array
1412
	 */
1413
	public function getTooltipContentArray($params)
1414
	{
1415
		global $langs;
1416
		include_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php';
1417
1418
		$datas = [];
1419
1420
		$nofetch = empty($params['nofetch']) ? false : true;
1421
		$pictos = img_picto('', $this->picto).' <u class="paddingrightnow">'.$langs->trans("BankAccount").'</u>';
1422
		if (isset($this->status)) {
1423
			$pictos .= ' '.$this->getLibStatut(5);
1424
		}
1425
		$datas['picto'] = $pictos;
1426
		$datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
1427
		$datas['accountnumber'] = '<br><b>'.$langs->trans('AccountNumber').':</b> '.$this->number;
1428
		$datas['iban'] = '<br><b>'.$langs->trans('IBAN').':</b> '.getIbanHumanReadable($this);
1429
		$datas['bic'] = '<br><b>'.$langs->trans('BIC').':</b> '.$this->bic;
1430
		$datas['accountcurrency'] = '<br><b>'.$langs->trans("AccountCurrency").':</b> '.$this->currency_code;
1431
1432
		if (isModEnabled('accounting')) {
1433
			include_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
1434
			$langs->load("accountancy");
1435
			$datas['accountaccounting'] = '<br><b>'.$langs->trans('AccountAccounting').':</b> '.length_accountg($this->account_number);
1436
			$datas['accountancyjournal'] = '<br><b>'.$langs->trans('AccountancyJournal').':</b> '.$this->accountancy_journal;
1437
		}
1438
		// show categories for this record only in ajax to not overload lists
1439
		if (isModEnabled('categorie') && !$nofetch) {
1440
			require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
1441
			$form = new Form($this->db);
1442
			$datas['categories'] = '<br>' . $form->showCategories($this->id, Categorie::TYPE_ACCOUNT, 1);
1443
		}
1444
1445
		return $datas;
1446
	}
1447
1448
	/**
1449
	 *  Return clicable name (with picto eventually)
1450
	 *
1451
	 *	@param	int		$withpicto					Include picto into link
1452
	 *  @param  string	$mode           			''=Link to card, 'transactions'=Link to transactions card
1453
	 *  @param  string  $option         			''=Show ref, 'reflabel'=Show ref+label
1454
	 *  @param  int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
1455
	 *  @param	int  	$notooltip		 			1=Disable tooltip
1456
	 *	@return	string								Chaine avec URL
1457
	 */
1458
	public function getNomUrl($withpicto = 0, $mode = '', $option = '', $save_lastsearch_value = -1, $notooltip = 0)
1459
	{
1460
		global $conf, $langs, $user;
1461
		include_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php';
1462
1463
		$result = '';
1464
		$classfortooltip = 'classfortooltip';
1465
		$dataparams = '';
1466
		$params = [
1467
			'id' => $this->id,
1468
			'objecttype' => $this->element,
1469
			'option' => $option,
1470
			'nofetch' => 1,
1471
		];
1472
		if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1473
			$classfortooltip = 'classforajaxtooltip';
1474
			$dataparams = ' data-params='.json_encode($params);
1475
		}
1476
		$label = implode($this->getTooltipContentArray($params));
1477
1478
		$linkclose = '"'.$dataparams.' title="'.dol_escape_htmltag($label, 1).'" class="'.$classfortooltip.'">';
1479
1480
		$url = DOL_URL_ROOT.'/compta/bank/card.php?id='.$this->id;
1481
		if ($mode == 'transactions') {
1482
			$url = DOL_URL_ROOT.'/compta/bank/bankentries_list.php?id='.$this->id;
1483
		} elseif ($mode == 'receipts') {
1484
			$url = DOL_URL_ROOT.'/compta/bank/releve.php?account='.$this->id;
1485
		}
1486
1487
		if ($option != 'nolink') {
1488
			// Add param to save lastsearch_values or not
1489
			$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1490
			if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1491
				$add_save_lastsearch_values = 1;
1492
			}
1493
			if ($add_save_lastsearch_values) {
1494
				$url .= '&save_lastsearch_values=1';
1495
			}
1496
		}
1497
1498
		$linkstart = '<a href="'.$url.$linkclose;
1499
		$linkend = '</a>';
1500
1501
		if ($option == 'nolink') {
1502
			$linkstart = '';
1503
			$linkend = '';
1504
		}
1505
1506
		$result .= $linkstart;
1507
		if ($withpicto) {
1508
			$result .= img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : $dataparams.' class="'.(($withpicto != 2) ? 'paddingright ' : '').$classfortooltip.'"'), 0, 0, $notooltip ? 0 : 1);
1509
		}
1510
		if ($withpicto != 2) {
1511
			$result .= $this->ref.($option == 'reflabel' && $this->label ? ' - '.$this->label : '');
1512
		}
1513
		$result .= $linkend;
1514
1515
		return $result;
1516
	}
1517
1518
1519
	// Method after here are common to Account and CompanyBankAccount
1520
1521
1522
	/**
1523
	 *     Return if an account has valid information for Direct debit payment
1524
	 *
1525
	 *     @return     int         1 if correct, <=0 if wrong
1526
	 */
1527
	public function verif()
1528
	{
1529
		require_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php';
1530
1531
		$this->error_number = 0;
1532
1533
		// Call function to check BAN
1534
1535
		if (!checkIbanForAccount($this)) {
1536
			$this->error_number = 12;
1537
			$this->error_message = 'IBANNotValid';
1538
		}
1539
		if (!checkSwiftForAccount($this)) {
1540
			$this->error_number = 12;
1541
			$this->error_message = 'SwiftNotValid';
1542
		}
1543
		/*if (! checkBanForAccount($this))
1544
		{
1545
			$this->error_number = 12;
1546
			$this->error_message = 'BANControlError';
1547
		}*/
1548
1549
		if ($this->error_number == 0) {
1550
			return 1;
1551
		} else {
1552
			return 0;
1553
		}
1554
	}
1555
1556
	/**
1557
	 * 	Return account country code
1558
	 *
1559
	 *	@return		string		country code
1560
	 */
1561
	public function getCountryCode()
1562
	{
1563
		global $mysoc;
1564
1565
		// We return country code of bank account
1566
		if (!empty($this->country_code)) {
1567
			return $this->country_code;
1568
		}
1569
1570
		// For backward compatibility, we try to guess country from other information
1571
		if (!empty($this->iban)) {
1572
			// If IBAN defined, we can know country of account from it
1573
			$reg = array();
1574
			if (preg_match("/^([a-zA-Z][a-zA-Z])/i", $this->iban, $reg)) {
1575
				return $reg[1];
1576
			}
1577
		}
1578
1579
		// If this class is linked to a third party
1580
		if (!empty($this->socid)) {
1581
			require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1582
			$company = new Societe($this->db);
1583
			$result = $company->fetch($this->socid);
1584
			if (!empty($company->country_code)) {
1585
				return $company->country_code;
1586
			}
1587
		}
1588
1589
		// We return country code of managed company
1590
		if (!empty($mysoc->country_code)) {
1591
			return $mysoc->country_code;
1592
		}
1593
1594
		return '';
1595
	}
1596
1597
	/**
1598
	 * Return if a bank account is defined with detailed information (bank code, desk code, number and key).
1599
	 * More information on codes used by countries on page http://en.wikipedia.org/wiki/Bank_code
1600
	 *
1601
	 * @return		int        0=No bank code need + Account number is enough
1602
	 *                         1=Need 2 fields for bank code: Bank, Desk (France, Spain, ...) + Account number and key
1603
	 *                         2=Need 1 field for bank code:  Bank only (Sort code for Great Britain, BSB for Australia) + Account number
1604
	 */
1605
	public function useDetailedBBAN()
1606
	{
1607
		$country_code = $this->getCountryCode();
1608
1609
		if (in_array($country_code, array('FR', 'ES', 'GA', 'IT', 'NC'))) {
1610
			return 1; // France, Spain, Gabon, ... - Not valid for CH
1611
		}
1612
		if (in_array($country_code, array('AD', 'AU', 'BE', 'CA', 'DE', 'DK', 'GR', 'GB', 'ID', 'IE', 'IR', 'KR', 'NL', 'NZ', 'UK', 'US'))) {
1613
			return 2; // Australia, England...
1614
		}
1615
		return 0;
1616
	}
1617
1618
	/**
1619
	 * Return 1 if IBAN / BIC is mandatory (otherwise option)
1620
	 *
1621
	 * @return		int        1 = mandatory / 0 = Not mandatory
1622
	 */
1623
	public function needIBAN()
1624
	{
1625
		global $conf;
1626
1627
		if (!empty($conf->global->MAIN_IBAN_IS_NEVER_MANDATORY)) {
1628
			return 0;
1629
		}
1630
1631
		$country_code = $this->getCountryCode();
1632
1633
		$country_code_in_EEC = array(
1634
				'AT', // Austria
1635
				'BE', // Belgium
1636
				'BG', // Bulgaria
1637
				'CY', // Cyprus
1638
				'CZ', // Czech republic
1639
				'DE', // Germany
1640
				'DK', // Danemark
1641
				'EE', // Estonia
1642
				'ES', // Spain
1643
				'FI', // Finland
1644
				'FR', // France
1645
				'GB', // United Kingdom
1646
				'GR', // Greece
1647
				'HR', // Croatia
1648
				'NL', // Holland
1649
				'HU', // Hungary
1650
				'IE', // Ireland
1651
				'IM', // Isle of Man - Included in UK
1652
				'IT', // Italy
1653
				'LT', // Lithuania
1654
				'LU', // Luxembourg
1655
				'LV', // Latvia
1656
				'MC', // Monaco - Included in France
1657
				'MT', // Malta
1658
				//'NO',	// Norway
1659
				'PL', // Poland
1660
				'PT', // Portugal
1661
				'RO', // Romania
1662
				'SE', // Sweden
1663
				'SK', // Slovakia
1664
				'SI', // Slovenia
1665
				'UK', // United Kingdom
1666
				//'CH',	// Switzerland - No. Swizerland in not in EEC
1667
		);
1668
1669
		if (in_array($country_code, $country_code_in_EEC)) {
1670
			return 1; // France, Spain, ...
1671
		}
1672
		return 0;
1673
	}
1674
1675
	/**
1676
	 *	Load miscellaneous information for tab "Info"
1677
	 *
1678
	 *	@param  int		$id		Id of object to load
1679
	 *	@return	void
1680
	 */
1681
	public function info($id)
1682
	{
1683
	}
1684
1685
	/**
1686
	 * Returns the fields in order that this bank account should show to the user
1687
	 * Will return an array with the following values:
1688
	 * - BankAccountNumber
1689
	 * - BankCode
1690
	 * - BankAccountNumberKey
1691
	 * - DeskCode
1692
	 *
1693
	 * Some countries show less or more bank account properties to the user
1694
	 *
1695
	 * @param  int     $includeibanbic         1=Return also key for IBAN and BIC
1696
	 * @return array                           Array of fields to show
1697
	 * @see useDetailedBBAN()
1698
	 */
1699
	public function getFieldsToShow($includeibanbic = 0)
1700
	{
1701
		//Get the required properties depending on the country
1702
		$detailedBBAN = $this->useDetailedBBAN();
1703
1704
		if ($detailedBBAN == 0) {
1705
			$fieldarray = array(
1706
					'BankAccountNumber'
1707
			);
1708
		} elseif ($detailedBBAN == 2) {
1709
			$fieldarray = array(
1710
					'BankCode',
1711
					'BankAccountNumber'
1712
			);
1713
		} else {
1714
			$fieldarray = self::getAccountNumberOrder();
1715
		}
1716
1717
		//if ($this->needIBAN()) {    // return always IBAN and BIC (this was old behaviour)
1718
		if ($includeibanbic) {
1719
			$fieldarray[] = 'IBAN';
1720
			$fieldarray[] = 'BIC';
1721
		}
1722
		//}
1723
1724
		//Get the order the properties are shown
1725
		return $fieldarray;
1726
	}
1727
1728
	/**
1729
	 * Returns the components of the bank account in order.
1730
	 * Will return an array with the following values:
1731
	 * - BankAccountNumber
1732
	 * - BankCode
1733
	 * - BankAccountNumberKey
1734
	 * - DeskCode
1735
	 *
1736
	 * @return array
1737
	 */
1738
	public static function getAccountNumberOrder()
1739
	{
1740
		global $conf;
1741
1742
		$fieldlists = array(
1743
				'BankCode',
1744
				'DeskCode',
1745
				'BankAccountNumber',
1746
				'BankAccountNumberKey'
1747
		);
1748
1749
		if (!empty($conf->global->BANK_SHOW_ORDER_OPTION)) {
1750
			if (is_numeric($conf->global->BANK_SHOW_ORDER_OPTION)) {
1751
				if ($conf->global->BANK_SHOW_ORDER_OPTION == '1') {
1752
					$fieldlists = array(
1753
						'BankCode',
1754
						'DeskCode',
1755
						'BankAccountNumberKey',
1756
						'BankAccountNumber'
1757
					);
1758
				}
1759
			} else {
1760
				//Replace the old AccountNumber key with the new BankAccountNumber key
1761
				$fieldlists = explode(
1762
					' ',
1763
					preg_replace('/ ?[^Bank]AccountNumber ?/', 'BankAccountNumber', $conf->global->BANK_SHOW_ORDER_OPTION)
1764
				);
1765
			}
1766
		}
1767
1768
		return $fieldlists;
1769
	}
1770
1771
1772
	/**
1773
	 *  Initialise an instance with random values.
1774
	 *  Used to build previews or test instances.
1775
	 *	id must be 0 if object instance is a specimen.
1776
	 *
1777
	 *  @return	void
1778
	 */
1779
	public function initAsSpecimen()
1780
	{
1781
		// Example of IBAN FR7630001007941234567890185
1782
		$this->specimen        = 1;
1783
		$this->ref             = 'MBA';
1784
		$this->label           = 'My Big Company Bank account';
1785
		$this->bank            = 'MyBank';
1786
		$this->courant         = Account::TYPE_CURRENT;
1787
		$this->clos            = Account::STATUS_OPEN;
1788
		$this->code_banque     = '30001';
1789
		$this->code_guichet    = '00794';
1790
		$this->number          = '12345678901';
1791
		$this->cle_rib         = '85';
1792
		$this->bic             = 'AA12';
1793
		$this->iban            = 'FR7630001007941234567890185';
1794
		$this->domiciliation   = 'Banque de France';
1795
		$this->proprio         = 'Owner';
1796
		$this->owner_address   = 'Owner address';
1797
		$this->owner_zip       = 'Owner zip';
1798
		$this->owner_town      = 'Owner town';
1799
		$this->owner_country_id = 'Owner country_id';
1800
		$this->country_id      = 1;
1801
	}
1802
1803
	/**
1804
	 * Function used to replace a thirdparty id with another one.
1805
	 *
1806
	 * @param DoliDB 	$dbs 			Database handler
1807
	 * @param int 		$origin_id 		Old thirdparty id
1808
	 * @param int 		$dest_id 		New thirdparty id
1809
	 * @return bool						True=SQL success, False=SQL error
1810
	 */
1811
	public static function replaceThirdparty($dbs, $origin_id, $dest_id)
1812
	{
1813
		$sql = "UPDATE ".MAIN_DB_PREFIX."bank_url SET url_id = ".((int) $dest_id)." WHERE url_id = ".((int) $origin_id)." AND type='company'";
1814
1815
		if ($dbs->query($sql)) {
1816
			return true;
1817
		} else {
1818
			//if ($ignoreerrors) return true; // TODO Not enough. If there is A-B on kept thirdparty and B-C on old one, we must get A-B-C after merge. Not A-B.
1819
			//$this->errors = $dbs->lasterror();
1820
			return false;
1821
		}
1822
	}
1823
1824
	/**
1825
	 *	Return clicable link of object (with eventually picto)
1826
	 *
1827
	 *	@param      string	    $option                 Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
1828
	 *  @param		array		$arraydata				Array of data
1829
	 *  @return		string								HTML Code for Kanban thumb.
1830
	 */
1831
	public function getKanbanView($option = '', $arraydata = null)
1832
	{
1833
		global $langs;
1834
		$return = '<div class="box-flex-item box-flex-grow-zero">';
1835
		$return .= '<div class="info-box info-box-sm">';
1836
		$return .= '<span class="info-box-icon bg-infobox-action">';
1837
		$return .= img_picto('', $this->picto);
1838
		$return .= '</span>';
1839
		$return .= '<div class="info-box-content">';
1840
		$return .= '<span class="info-box-ref">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
1841
1842
		if (property_exists($this, 'type_lib')) {
1843
			$return .= '<br><span class="info-box-label opacitymedium" title="'.$this->type_lib[$this->type].'">'.substr($this->type_lib[$this->type], 0, 24).'...</span>';
1844
		}
1845
		if (method_exists($this, 'solde')) {
1846
			$return .= '<br><a href="'.DOL_URL_ROOT.'/compta/bank/bankentries_list.php?id='.$this->id.'">';
1847
			$return .= '<span class="opacitymedium">'.$langs->trans("Balance").'</span> : <span class="amount">'.price($this->solde(1), 0, $langs, 1, -1, -1, $this->currency_code).'</span>';
1848
		}
1849
		if (method_exists($this, 'getLibStatut')) {
1850
			$return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(5).'</div>';
1851
		}
1852
		$return .= '</div>';
1853
		$return .= '</div>';
1854
		$return .= '</div>';
1855
		return $return;
1856
	}
1857
}
1858
1859
1860
/**
1861
 *	Class to manage bank transaction lines
1862
 */
1863
class AccountLine extends CommonObjectLine
1864
{
1865
	/**
1866
	 * @var string Error code (or message)
1867
	 */
1868
	public $error = '';
1869
1870
	/**
1871
	 * @var DoliDB Database handler.
1872
	 */
1873
	public $db;
1874
1875
	/**
1876
	 * @var string ID to identify managed object
1877
	 */
1878
	public $element = 'bank';
1879
1880
	/**
1881
	 * @var string Name of table without prefix where object is stored
1882
	 */
1883
	public $table_element = 'bank';
1884
1885
	/**
1886
	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
1887
	 */
1888
	public $picto = 'accountline';
1889
1890
	/**
1891
	 * @var int ID
1892
	 */
1893
	public $id;
1894
1895
	/**
1896
	 * @var string Ref
1897
	 */
1898
	public $ref;
1899
1900
	/**
1901
	 * Date creation record (datec)
1902
	 *
1903
	 * @var integer
1904
	 */
1905
	public $datec;
1906
1907
	/**
1908
	 * Date (dateo)
1909
	 *
1910
	 * @var integer
1911
	 */
1912
	public $dateo;
1913
1914
	/**
1915
	 * Date value (datev)
1916
	 *
1917
	 * @var integer
1918
	 */
1919
	public $datev;
1920
1921
	public $amount;					/* Amount of payment in the bank account currency */
1922
	public $amount_main_currency;	/* Amount in the currency of company if bank account use another currency */
1923
1924
	/**
1925
	 * @var int ID
1926
	 */
1927
	public $fk_user_author;
1928
1929
	/**
1930
	 * @var int ID
1931
	 */
1932
	public $fk_user_rappro;
1933
1934
	/**
1935
	 * @var int ID
1936
	 */
1937
	public $fk_type;
1938
1939
	/**
1940
	 * @var int ID of cheque receipt
1941
	 */
1942
	public $fk_bordereau;
1943
1944
	/**
1945
	 * @var int ID of bank account
1946
	 */
1947
	public $fk_account;
1948
1949
	/**
1950
	 * @var string		Ref of bank account
1951
	 */
1952
	public $bank_account_ref;
1953
1954
	/**
1955
	 * @var string		Label of bank account
1956
	 */
1957
	public $bank_account_label;
1958
1959
	/**
1960
	 * @var string		Bank account numero
1961
	 */
1962
	public $numero_compte;
1963
1964
	/**
1965
	 * @var string		Name of check issuer
1966
	 */
1967
	public $emetteur;
1968
1969
	public $rappro; // Is it conciliated
1970
	public $num_releve; // If conciliated, what is bank statement
1971
	public $num_chq; // Num of cheque
1972
	public $bank_chq; // Bank of cheque
1973
1974
	/**
1975
	 * @var string bank transaction lines label
1976
	 */
1977
	public $label;
1978
1979
	public $note;
1980
1981
1982
1983
	/**
1984
	 *  Constructor
1985
	 *
1986
	 *  @param	DoliDB	$db		Database handler
1987
	 */
1988
	public function __construct(DoliDB $db)
1989
	{
1990
		$this->db = $db;
1991
	}
1992
1993
	/**
1994
	 *  Load into memory content of a bank transaction line
1995
	 *
1996
	 *  @param		int		$rowid   	Id of bank transaction to load
1997
	 *  @param      string	$ref     	Ref of bank transaction to load
1998
	 *  @param      string	$num     	External num to load (ex: num of transaction for paypal fee)
1999
	 *	@return		int					<0 if KO, 0 if OK but not found, >0 if OK and found
2000
	 */
2001
	public function fetch($rowid, $ref = '', $num = '')
2002
	{
2003
		global $conf;
2004
2005
		// Check parameters
2006
		if (empty($rowid) && empty($ref) && empty($num)) {
2007
			return -1;
2008
		}
2009
2010
		$sql = "SELECT b.rowid, b.datec, b.datev, b.dateo, b.amount, b.label as label, b.fk_account,";
2011
		$sql .= " b.fk_user_author, b.fk_user_rappro,";
2012
		$sql .= " b.fk_type, b.num_releve, b.num_chq, b.rappro, b.note,";
2013
		$sql .= " b.fk_bordereau, b.banque, b.emetteur,";
2014
		//$sql.= " b.author"; // Is this used ?
2015
		$sql .= " ba.ref as bank_account_ref, ba.label as bank_account_label";
2016
		$sql .= " FROM ".MAIN_DB_PREFIX."bank as b,";
2017
		$sql .= " ".MAIN_DB_PREFIX."bank_account as ba";
2018
		$sql .= " WHERE b.fk_account = ba.rowid";
2019
		$sql .= " AND ba.entity IN (".getEntity('bank_account').")";
2020
		if ($num) {
2021
			$sql .= " AND b.num_chq='".$this->db->escape($num)."'";
2022
		} elseif ($ref) {
2023
			$sql .= " AND b.rowid='".$this->db->escape($ref)."'";
2024
		} else {
2025
			$sql .= " AND b.rowid = ".((int) $rowid);
2026
		}
2027
2028
		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
2029
		$result = $this->db->query($sql);
2030
		if ($result) {
2031
			$ret = 0;
2032
2033
			$obj = $this->db->fetch_object($result);
2034
			if ($obj) {
2035
				$this->id = $obj->rowid;
2036
				$this->rowid = $obj->rowid;
2037
				$this->ref = $obj->rowid;
2038
2039
				$this->datec = $obj->datec;
2040
				$this->datev = $obj->datev;
2041
				$this->dateo = $obj->dateo;
2042
				$this->amount = $obj->amount;
2043
				$this->label = $obj->label;
2044
				$this->note = $obj->note;
2045
2046
				$this->fk_user_author = $obj->fk_user_author;
2047
				$this->fk_user_rappro = $obj->fk_user_rappro;
2048
2049
				$this->fk_type = $obj->fk_type; // Type of transaction
2050
				$this->rappro = $obj->rappro;
2051
				$this->num_releve = $obj->num_releve;
2052
2053
				$this->num_chq = $obj->num_chq;
2054
				$this->bank_chq = $obj->banque;
2055
				$this->fk_bordereau = $obj->fk_bordereau;
2056
2057
				$this->fk_account = $obj->fk_account;
2058
				$this->bank_account_ref = $obj->bank_account_ref;
2059
				$this->bank_account_label = $obj->bank_account_label;
2060
2061
				// Retrieve all extrafield
2062
				// fetch optionals attributes and labels
2063
				$this->fetch_optionals();
2064
2065
				$ret = 1;
2066
			}
2067
			$this->db->free($result);
2068
			return $ret;
2069
		} else {
2070
			return -1;
2071
		}
2072
	}
2073
2074
	/**
2075
	 * Inserts a transaction to a bank account
2076
	 *
2077
	 * @return int <0 if KO, rowid of the line if OK
2078
	 */
2079
	public function insert()
2080
	{
2081
		$error = 0;
2082
2083
		$this->db->begin();
2084
2085
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."bank (";
2086
		$sql .= "datec";
2087
		$sql .= ", dateo";
2088
		$sql .= ", datev";
2089
		$sql .= ", label";
2090
		$sql .= ", amount";
2091
		$sql .= ", amount_main_currency";
2092
		$sql .= ", fk_user_author";
2093
		$sql .= ", num_chq";
2094
		$sql .= ", fk_account";
2095
		$sql .= ", fk_type";
2096
		$sql .= ", emetteur,banque";
2097
		$sql .= ", rappro";
2098
		$sql .= ", numero_compte";
2099
		$sql .= ", num_releve";
2100
		$sql .= ") VALUES (";
2101
		$sql .= "'".$this->db->idate($this->datec)."'";
2102
		$sql .= ", '".$this->db->idate($this->dateo)."'";
2103
		$sql .= ", '".$this->db->idate($this->datev)."'";
2104
		$sql .= ", '".$this->db->escape($this->label)."'";
2105
		$sql .= ", ".price2num($this->amount);
2106
		$sql .= ", ".(empty($this->amount_main_currency) ? "NULL" : price2num($this->amount_main_currency));
2107
		$sql .= ", ".($this->fk_user_author > 0 ? ((int) $this->fk_user_author) : "null");
2108
		$sql .= ", ".($this->num_chq ? "'".$this->db->escape($this->num_chq)."'" : "null");
2109
		$sql .= ", '".$this->db->escape($this->fk_account)."'";
2110
		$sql .= ", '".$this->db->escape($this->fk_type)."'";
2111
		$sql .= ", ".($this->emetteur ? "'".$this->db->escape($this->emetteur)."'" : "null");
2112
		$sql .= ", ".($this->bank_chq ? "'".$this->db->escape($this->bank_chq)."'" : "null");
2113
		$sql .= ", ".(int) $this->rappro;
2114
		$sql .= ", ".($this->numero_compte ? "'".$this->db->escape($this->numero_compte)."'" : "''");
2115
		$sql .= ", ".($this->num_releve ? "'".$this->db->escape($this->num_releve)."'" : "null");
2116
		$sql .= ")";
2117
2118
		dol_syslog(get_class($this)."::insert", LOG_DEBUG);
2119
		$resql = $this->db->query($sql);
2120
		if ($resql) {
2121
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'bank');
2122
			// Actions on extra fields (by external module or standard code)
2123
			$result = $this->insertExtraFields();
2124
			if ($result < 0) {
2125
				$error++;
2126
			}
2127
		} else {
2128
			$error++;
2129
			$this->error = $this->db->lasterror();
2130
			dol_print_error($this->db);
2131
		}
2132
2133
		if (!$error) {
2134
			$this->db->commit();
2135
			return $this->id;
2136
		} else {
2137
			$this->db->rollback();
2138
			return -1 * $error;
2139
		}
2140
	}
2141
2142
	/**
2143
	 *      Delete bank transaction record
2144
	 *
2145
	 *		@param	User	$user	User object that delete
2146
	 *      @return	int 			<0 if KO, >0 if OK
2147
	 */
2148
	public function delete(User $user = null)
2149
	{
2150
		global $conf;
2151
2152
		$nbko = 0;
2153
2154
		if ($this->rappro) {
2155
			// Protection to avoid any delete of consolidated lines
2156
			$this->error = "ErrorDeleteNotPossibleLineIsConsolidated";
2157
			return -1;
2158
		}
2159
2160
		$this->db->begin();
2161
2162
		// Protection to avoid any delete of accounted lines. Protection on by default
2163
		if (empty($conf->global->BANK_ALLOW_TRANSACTION_DELETION_EVEN_IF_IN_ACCOUNTING)) {
2164
			$sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping WHERE doc_type = 'bank' AND fk_doc = ".((int) $this->id);
2165
			$resql = $this->db->query($sql);
2166
			if ($resql) {
2167
				$obj = $this->db->fetch_object($resql);
2168
				if ($obj && $obj->nb) {
2169
					$this->error = 'ErrorRecordAlreadyInAccountingDeletionNotPossible';
2170
					$this->db->rollback();
2171
					return -1;
2172
				}
2173
			} else {
2174
				$this->error = $this->db->lasterror();
2175
				$this->db->rollback();
2176
				return -1;
2177
			}
2178
		}
2179
2180
		// Delete urls
2181
		$result = $this->delete_urls($user);
2182
		if ($result < 0) {
2183
			$nbko++;
2184
		}
2185
2186
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."bank_class WHERE lineid=".(int) $this->rowid;
2187
		dol_syslog(get_class($this)."::delete", LOG_DEBUG);
2188
		$result = $this->db->query($sql);
2189
		if (!$result) {
2190
			$nbko++;
2191
		}
2192
2193
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."bank_extrafields WHERE fk_object=".(int) $this->rowid;
2194
		$result = $this->db->query($sql);
2195
		if (!$result) {
2196
			$nbko++;
2197
		}
2198
2199
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."bank WHERE rowid=".(int) $this->rowid;
2200
		dol_syslog(get_class($this)."::delete", LOG_DEBUG);
2201
		$result = $this->db->query($sql);
2202
		if (!$result) {
2203
			$nbko++;
2204
		}
2205
2206
		if (!$nbko) {
2207
			$this->db->commit();
2208
			return 1;
2209
		} else {
2210
			$this->db->rollback();
2211
			return -$nbko;
2212
		}
2213
	}
2214
2215
2216
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2217
	/**
2218
	 *      Delete bank line records
2219
	 *
2220
	 *		@param	User	$user	User object that delete
2221
	 *      @return	int 			<0 if KO, >0 if OK
2222
	 */
2223
	public function delete_urls(User $user = null)
2224
	{
2225
		// phpcs:enable
2226
		$nbko = 0;
2227
2228
		if ($this->rappro) {
2229
			// Protection to avoid any delete of consolidated lines
2230
			$this->error = "ErrorDeleteNotPossibleLineIsConsolidated";
2231
			return -1;
2232
		}
2233
2234
		$this->db->begin();
2235
2236
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."bank_url WHERE fk_bank=".(int) $this->rowid;
2237
		dol_syslog(get_class($this)."::delete_urls", LOG_DEBUG);
2238
		$result = $this->db->query($sql);
2239
		if (!$result) {
2240
			$nbko++;
2241
		}
2242
2243
		if (!$nbko) {
2244
			$this->db->commit();
2245
			return 1;
2246
		} else {
2247
			$this->db->rollback();
2248
			return -$nbko;
2249
		}
2250
	}
2251
2252
2253
	/**
2254
	 *		Update bank account record in database
2255
	 *
2256
	 *		@param	User	$user			Object user making update
2257
	 *		@param 	int		$notrigger		0=Disable all triggers
2258
	 *		@return	int						<0 if KO, >0 if OK
2259
	 */
2260
	public function update(User $user, $notrigger = 0)
2261
	{
2262
		$this->db->begin();
2263
2264
		$sql = "UPDATE ".MAIN_DB_PREFIX."bank SET";
2265
		$sql .= " amount = ".price2num($this->amount).",";
2266
		$sql .= " datev='".$this->db->idate($this->datev)."',";
2267
		$sql .= " dateo='".$this->db->idate($this->dateo)."'";
2268
		$sql .= " WHERE rowid = ".((int) $this->rowid);
2269
2270
		dol_syslog(get_class($this)."::update", LOG_DEBUG);
2271
		$resql = $this->db->query($sql);
2272
		if ($resql) {
2273
			$this->db->commit();
2274
			return 1;
2275
		} else {
2276
			$this->db->rollback();
2277
			$this->error = $this->db->error();
2278
			return -1;
2279
		}
2280
	}
2281
2282
2283
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2284
	/**
2285
	 *	Update conciliation field
2286
	 *
2287
	 *	@param	User	$user			Objet user making update
2288
	 *	@param 	int		$cat			Category id
2289
	 *	@param	int		$conciliated	1=Set transaction to conciliated, 0=Keep transaction non conciliated
2290
	 *	@return	int						<0 if KO, >0 if OK
2291
	 */
2292
	public function update_conciliation(User $user, $cat, $conciliated = 1)
2293
	{
2294
		// phpcs:enable
2295
		global $conf, $langs;
2296
2297
		$this->db->begin();
2298
2299
		// Check statement field
2300
		if (!empty($conf->global->BANK_STATEMENT_REGEX_RULE)) {
2301
			if (!preg_match('/'.$conf->global->BANK_STATEMENT_REGEX_RULE.'/', $this->num_releve)) {
2302
				$this->errors[] = $langs->trans("ErrorBankStatementNameMustFollowRegex", $conf->global->BANK_STATEMENT_REGEX_RULE);
2303
				return -1;
2304
			}
2305
		}
2306
2307
		$sql = "UPDATE ".MAIN_DB_PREFIX."bank SET";
2308
		$sql .= " rappro = ".((int) $conciliated);
2309
		$sql .= ", num_releve = '".$this->db->escape($this->num_releve)."'";
2310
		if ($conciliated) {
2311
			$sql .= ", fk_user_rappro = ".$user->id;
2312
		}
2313
		$sql .= " WHERE rowid = ".((int) $this->id);
2314
2315
		dol_syslog(get_class($this)."::update_conciliation", LOG_DEBUG);
2316
		$resql = $this->db->query($sql);
2317
		if ($resql) {
2318
			if (!empty($cat)) {
2319
				$sql = "INSERT INTO ".MAIN_DB_PREFIX."bank_class (";
2320
				$sql .= "lineid";
2321
				$sql .= ", fk_categ";
2322
				$sql .= ") VALUES (";
2323
				$sql .= $this->id;
2324
				$sql .= ", ".((int) $cat);
2325
				$sql .= ")";
2326
2327
				dol_syslog(get_class($this)."::update_conciliation", LOG_DEBUG);
2328
				$this->db->query($sql);
2329
2330
				// No error check. Can fail if category already affected
2331
			}
2332
2333
			$this->rappro = 1;
2334
2335
			$this->db->commit();
2336
			return 1;
2337
		} else {
2338
			$this->db->rollback();
2339
			return -1;
2340
		}
2341
	}
2342
2343
2344
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2345
	/**
2346
	 * 	Increase/decrease value date of a rowid
2347
	 *
2348
	 *	@param	int		$rowid		Id of line
2349
	 *	@param	int		$sign		1 or -1
2350
	 *	@return	int					>0 if OK, 0 if KO
2351
	 */
2352
	public function datev_change($rowid, $sign = 1)
2353
	{
2354
		// phpcs:enable
2355
		$sql = "SELECT datev FROM ".MAIN_DB_PREFIX."bank WHERE rowid = ".((int) $rowid);
2356
		$resql = $this->db->query($sql);
2357
		if ($resql) {
2358
			$obj = $this->db->fetch_object($resql);
2359
			$newdate = $this->db->jdate($obj->datev) + (3600 * 24 * $sign);
2360
2361
			$sql = "UPDATE ".MAIN_DB_PREFIX."bank SET";
2362
			$sql .= " datev = '".$this->db->idate($newdate)."'";
2363
			$sql .= " WHERE rowid = ".((int) $rowid);
2364
2365
			$result = $this->db->query($sql);
2366
			if ($result) {
2367
				if ($this->db->affected_rows($result)) {
2368
					return 1;
2369
				}
2370
			} else {
2371
				dol_print_error($this->db);
2372
				return 0;
2373
			}
2374
		} else {
2375
			dol_print_error($this->db);
2376
		}
2377
		return 0;
2378
	}
2379
2380
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2381
	/**
2382
	 * 	Increase value date of a rowid
2383
	 *
2384
	 *	@param	int		$id		Id of line to change
2385
	 *	@return	int				>0 if OK, 0 if KO
2386
	 */
2387
	public function datev_next($id)
2388
	{
2389
		// phpcs:enable
2390
		return $this->datev_change($id, 1);
2391
	}
2392
2393
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2394
	/**
2395
	 * 	Decrease value date of a rowid
2396
	 *
2397
	 *	@param	int		$id		Id of line to change
2398
	 *	@return	int				>0 if OK, 0 if KO
2399
	 */
2400
	public function datev_previous($id)
2401
	{
2402
		// phpcs:enable
2403
		return $this->datev_change($id, -1);
2404
	}
2405
2406
2407
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2408
	/**
2409
	 * 	Increase/decrease operation date of a rowid
2410
	 *
2411
	 *	@param	int		$rowid		Id of line
2412
	 *	@param	int		$sign		1 or -1
2413
	 *	@return	int					>0 if OK, 0 if KO
2414
	 */
2415
	public function dateo_change($rowid, $sign = 1)
2416
	{
2417
		// phpcs:enable
2418
		$sql = "SELECT dateo FROM ".MAIN_DB_PREFIX."bank WHERE rowid = ".((int) $rowid);
2419
		$resql = $this->db->query($sql);
2420
		if ($resql) {
2421
			$obj = $this->db->fetch_object($resql);
2422
			$newdate = $this->db->jdate($obj->dateo) + (3600 * 24 * $sign);
2423
2424
			$sql = "UPDATE ".MAIN_DB_PREFIX."bank SET";
2425
			$sql .= " dateo = '".$this->db->idate($newdate)."'";
2426
			$sql .= " WHERE rowid = ".((int) $rowid);
2427
2428
			$result = $this->db->query($sql);
2429
			if ($result) {
2430
				if ($this->db->affected_rows($result)) {
2431
					return 1;
2432
				}
2433
			} else {
2434
				dol_print_error($this->db);
2435
				return 0;
2436
			}
2437
		} else {
2438
			dol_print_error($this->db);
2439
		}
2440
		return 0;
2441
	}
2442
2443
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2444
	/**
2445
	 * 	Increase operation date of a rowid
2446
	 *
2447
	 *	@param	int		$id		Id of line to change
2448
	 *	@return	int				>0 if OK, 0 if KO
2449
	 */
2450
	public function dateo_next($id)
2451
	{
2452
		// phpcs:enable
2453
		return $this->dateo_change($id, 1);
2454
	}
2455
2456
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2457
	/**
2458
	 * 	Decrease operation date of a rowid
2459
	 *
2460
	 *	@param	int		$id		Id of line to change
2461
	 *	@return	int				>0 if OK, 0 if KO
2462
	 */
2463
	public function dateo_previous($id)
2464
	{
2465
		// phpcs:enable
2466
		return $this->dateo_change($id, -1);
2467
	}
2468
2469
2470
	/**
2471
	 *	Load miscellaneous information for tab "Info"
2472
	 *
2473
	 *	@param  int		$id		Id of object to load
2474
	 *	@return	void
2475
	 */
2476
	public function info($id)
2477
	{
2478
		$sql = 'SELECT b.rowid, b.datec, b.tms as datem,';
2479
		$sql .= ' b.fk_user_author, b.fk_user_rappro';
2480
		$sql .= ' FROM '.MAIN_DB_PREFIX.'bank as b';
2481
		$sql .= ' WHERE b.rowid = '.((int) $id);
2482
2483
		$result = $this->db->query($sql);
2484
		if ($result) {
2485
			if ($this->db->num_rows($result)) {
2486
				$obj = $this->db->fetch_object($result);
2487
				$this->id = $obj->rowid;
2488
2489
				if ($obj->fk_user_author) {
2490
					$cuser = new User($this->db);
2491
					$cuser->fetch($obj->fk_user_author);
2492
					$this->user_creation = $cuser;
2493
				}
2494
				if ($obj->fk_user_rappro) {
2495
					$ruser = new User($this->db);
2496
					$ruser->fetch($obj->fk_user_rappro);
2497
					$this->user_rappro = $ruser;
2498
				}
2499
2500
				$this->date_creation     = $this->db->jdate($obj->datec);
2501
				$this->date_modification = $this->db->jdate($obj->datem);
2502
				//$this->date_rappro       = $obj->daterappro;    // Not yet managed
2503
			}
2504
			$this->db->free($result);
2505
		} else {
2506
			dol_print_error($this->db);
2507
		}
2508
	}
2509
2510
2511
	/**
2512
	 *    	Return clickable name (with picto eventually)
2513
	 *
2514
	 *		@param	int		$withpicto		0=No picto, 1=Include picto into link, 2=Only picto
2515
	 *		@param	int		$maxlen			Longueur max libelle
2516
	 *		@param	string	$option			Option ('', 'showall', 'showconciliated', 'showconciliatedandaccounted'). Options may be slow.
2517
	 * 		@param	int     $notooltip		1=Disable tooltip
2518
	 *		@return	string					Chaine avec URL
2519
	 */
2520
	public function getNomUrl($withpicto = 0, $maxlen = 0, $option = '', $notooltip = 0)
2521
	{
2522
		global $langs;
2523
2524
		$result = '';
2525
2526
		$label = img_picto('', $this->picto).' <u>'.$langs->trans("BankTransactionLine").'</u>:<br>';
2527
		$label .= '<b>'.$langs->trans("Ref").':</b> '.$this->ref;
2528
2529
		$linkstart = '<a href="'.DOL_URL_ROOT.'/compta/bank/line.php?rowid='.((int) $this->id).'&save_lastsearch_values=1" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
2530
		$linkend = '</a>';
2531
2532
		$result .= $linkstart;
2533
		if ($withpicto) {
2534
			$result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'account'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
2535
		}
2536
		if ($withpicto != 2) {
2537
			$result .= ($this->ref ? $this->ref : $this->id);
2538
		}
2539
		$result .= $linkend;
2540
2541
		if ($option == 'showall' || $option == 'showconciliated' || $option == 'showconciliatedandaccounted') {
2542
			$result .= ' <span class="opacitymedium">(';
2543
		}
2544
		if ($option == 'showall') {
2545
			$result .= $langs->trans("BankAccount").': ';
2546
			$accountstatic = new Account($this->db);
2547
			$accountstatic->id = $this->fk_account;
2548
			$accountstatic->ref = $this->bank_account_ref;
2549
			$accountstatic->label = $this->bank_account_label;
2550
			$result .= $accountstatic->getNomUrl(0).', ';
2551
		}
2552
		if ($option == 'showall' || $option == 'showconciliated' || $option == 'showconciliatedandaccounted') {
2553
			$result .= $langs->trans("BankLineConciliated").': ';
2554
			$result .= yn($this->rappro);
2555
		}
2556
		if ($option == 'showall' || $option == 'showconciliatedandaccounted') {
2557
			$sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping WHERE doc_type = 'bank' AND fk_doc = ".((int) $this->id);
2558
			$resql = $this->db->query($sql);
2559
			if ($resql) {
2560
				$obj = $this->db->fetch_object($resql);
2561
				if ($obj && $obj->nb) {
2562
					$result .= ' - '.$langs->trans("Accounted").': '.yn(1);
2563
				} else {
2564
					$result .= ' - '.$langs->trans("Accounted").': '.yn(0);
2565
				}
2566
			}
2567
		}
2568
		if ($option == 'showall' || $option == 'showconciliated' || $option == 'showconciliatedandaccounted') {
2569
			$result .= ')</span>';
2570
		}
2571
2572
		return $result;
2573
	}
2574
2575
2576
	/**
2577
	 *    Return label of status (activity, closed)
2578
	 *
2579
	 *    @param	int		$mode       0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long
2580
	 *    @return   string        		Libelle
2581
	 */
2582
	public function getLibStatut($mode = 0)
2583
	{
2584
		return $this->LibStatut($this->status, $mode);
2585
	}
2586
2587
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2588
	/**
2589
	 *  Renvoi le libelle d'un statut donne
2590
	 *
2591
	 *  @param	int		$status         Id statut
2592
	 *  @param	int		$mode           0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
2593
	 *  @return	string          		Libelle du statut
2594
	 */
2595
	public function LibStatut($status, $mode = 0)
2596
	{
2597
		// phpcs:enable
2598
		global $langs;
2599
		//$langs->load('companies');
2600
		/*
2601
		if ($mode == 0)
2602
		{
2603
			if ($status==0) return $langs->trans("ActivityCeased");
2604
			if ($status==1) return $langs->trans("InActivity");
2605
		}
2606
		if ($mode == 1)
2607
		{
2608
			if ($status==0) return $langs->trans("ActivityCeased");
2609
			if ($status==1) return $langs->trans("InActivity");
2610
		}
2611
		if ($mode == 2)
2612
		{
2613
			if ($status==0) return img_picto($langs->trans("ActivityCeased"),'statut5', 'class="pictostatus"').' '.$langs->trans("ActivityCeased");
2614
			if ($status==1) return img_picto($langs->trans("InActivity"),'statut4', 'class="pictostatus"').' '.$langs->trans("InActivity");
2615
		}
2616
		if ($mode == 3)
2617
		{
2618
			if ($status==0) return img_picto($langs->trans("ActivityCeased"),'statut5', 'class="pictostatus"');
2619
			if ($status==1) return img_picto($langs->trans("InActivity"),'statut4', 'class="pictostatus"');
2620
		}
2621
		if ($mode == 4)
2622
		{
2623
			if ($status==0) return img_picto($langs->trans("ActivityCeased"),'statut5', 'class="pictostatus"').' '.$langs->trans("ActivityCeased");
2624
			if ($status==1) return img_picto($langs->trans("InActivity"),'statut4', 'class="pictostatus"').' '.$langs->trans("InActivity");
2625
		}
2626
		if ($mode == 5)
2627
		{
2628
			if ($status==0) return $langs->trans("ActivityCeased").' '.img_picto($langs->trans("ActivityCeased"),'statut5', 'class="pictostatus"');
2629
			if ($status==1) return $langs->trans("InActivity").' '.img_picto($langs->trans("InActivity"),'statut4', 'class="pictostatus"');
2630
		}*/
2631
	}
2632
2633
2634
	/**
2635
	 *	Return if a bank line was dispatched into bookkeeping
2636
	 *
2637
	 *	@return     int         <0 if KO, 0=no, 1=yes
2638
	 */
2639
	public function getVentilExportCompta()
2640
	{
2641
		$alreadydispatched = 0;
2642
2643
		$type = 'bank';
2644
2645
		$sql = " SELECT COUNT(ab.rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='".$this->db->escape($type)."' AND ab.fk_doc = ".((int) $this->id);
2646
		$resql = $this->db->query($sql);
2647
		if ($resql) {
2648
			$obj = $this->db->fetch_object($resql);
2649
			if ($obj) {
2650
				$alreadydispatched = $obj->nb;
2651
			}
2652
		} else {
2653
			$this->error = $this->db->lasterror();
2654
			return -1;
2655
		}
2656
2657
		if ($alreadydispatched) {
2658
			return 1;
2659
		}
2660
		return 0;
2661
	}
2662
}
2663