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

Account::addline()   F

Complexity

Conditions 18
Paths 540

Size

Total Lines 103
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 68
nc 540
nop 13
dl 0
loc 103
rs 1.3388
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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