1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* Copyright (C) 2014-2017 Olivier Geffroy <[email protected]> |
4
|
|
|
* Copyright (C) 2015-2022 Alexandre Spangaro <[email protected]> |
5
|
|
|
* Copyright (C) 2015-2020 Florian Henry <[email protected]> |
6
|
|
|
* Copyright (C) 2018-2024 Frédéric France <[email protected]> |
7
|
|
|
* Copyright (C) 2024 MDW <[email protected]> |
8
|
|
|
* Copyright (C) 2024 Rafael San José <[email protected]> |
9
|
|
|
* |
10
|
|
|
* This program is free software; you can redistribute it and/or modify |
11
|
|
|
* it under the terms of the GNU General Public License as published by |
12
|
|
|
* the Free Software Foundation; either version 3 of the License, or |
13
|
|
|
* (at your option) any later version. |
14
|
|
|
* |
15
|
|
|
* This program is distributed in the hope that it will be useful, |
16
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
17
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18
|
|
|
* GNU General Public License for more details. |
19
|
|
|
* |
20
|
|
|
* You should have received a copy of the GNU General Public License |
21
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
namespace Dolibarr\Code\Accountancy\Classes; |
25
|
|
|
|
26
|
|
|
use Dolibarr\Code\Accountancy\Classes\AccountingAccount; |
27
|
|
|
use Dolibarr\Code\Accountancy\Classes\AccountingJournal; |
28
|
|
|
use Dolibarr\Code\Accountancy\Classes\BookKeepingLine; |
29
|
|
|
use Dolibarr\Code\User\Classes\User; |
30
|
|
|
use Dolibarr\Core\Base\CommonObject; |
31
|
|
|
use Dolibarr\Core\Base\CommonObjectLine; |
32
|
|
|
use DoliDB; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* \file htdocs/accountancy/class/bookkeeping.class.php |
36
|
|
|
* \ingroup Accountancy (Double entries) |
37
|
|
|
* \brief File of class to manage Ledger (General Ledger and Subledger) |
38
|
|
|
*/ |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Class to manage Ledger (General Ledger and Subledger) |
42
|
|
|
*/ |
43
|
|
|
class BookKeeping extends CommonObject |
44
|
|
|
{ |
45
|
|
|
/** |
46
|
|
|
* @var string Id to identify managed objects |
47
|
|
|
*/ |
48
|
|
|
public $element = 'accountingbookkeeping'; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var string Name of table without prefix where object is stored |
52
|
|
|
*/ |
53
|
|
|
public $table_element = 'accounting_bookkeeping'; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var int Entity |
57
|
|
|
*/ |
58
|
|
|
public $entity; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var BookKeepingLine[] Lines |
62
|
|
|
*/ |
63
|
|
|
public $lines = array(); |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var int ID |
67
|
|
|
*/ |
68
|
|
|
public $id; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var int Date of source document, in db date NOT NULL |
72
|
|
|
*/ |
73
|
|
|
public $doc_date; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @var int Deadline for payment |
77
|
|
|
*/ |
78
|
|
|
public $date_lim_reglement; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var string doc_type |
82
|
|
|
*/ |
83
|
|
|
public $doc_type; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @var string doc_ref |
87
|
|
|
*/ |
88
|
|
|
public $doc_ref; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @var int ID |
92
|
|
|
*/ |
93
|
|
|
public $fk_doc; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @var int ID |
97
|
|
|
*/ |
98
|
|
|
public $fk_docdet; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @var string thirdparty code |
102
|
|
|
*/ |
103
|
|
|
public $thirdparty_code; |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @var string subledger account |
107
|
|
|
*/ |
108
|
|
|
public $subledger_account; |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @var string subledger label |
112
|
|
|
*/ |
113
|
|
|
public $subledger_label; |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @var string doc_type |
117
|
|
|
*/ |
118
|
|
|
public $numero_compte; |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @var string label compte |
122
|
|
|
*/ |
123
|
|
|
public $label_compte; |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* @var string label operation |
127
|
|
|
*/ |
128
|
|
|
public $label_operation; |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* @var float FEC:Debit |
132
|
|
|
*/ |
133
|
|
|
public $debit; |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @var float FEC:Credit |
137
|
|
|
*/ |
138
|
|
|
public $credit; |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* @var float FEC:Amount (Not necessary) |
142
|
|
|
* @deprecated No more used (we have info into debit/credit and sens) |
143
|
|
|
*/ |
144
|
|
|
public $montant; |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* @var float FEC:Amount (Not necessary) |
148
|
|
|
* @deprecated No more used (we have info into debit/credit and sens) |
149
|
|
|
*/ |
150
|
|
|
public $amount; |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* @var string FEC:Sens (Not necessary) |
154
|
|
|
*/ |
155
|
|
|
public $sens; |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* @var int ID |
159
|
|
|
*/ |
160
|
|
|
public $fk_user_author; |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* @var string key for import |
164
|
|
|
*/ |
165
|
|
|
public $import_key; |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* @var string code journal |
169
|
|
|
*/ |
170
|
|
|
public $code_journal; |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @var string label journal |
174
|
|
|
*/ |
175
|
|
|
public $journal_label; |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* @var int accounting transaction id |
179
|
|
|
*/ |
180
|
|
|
public $piece_num; |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* @var BookKeepingLine[] Movement line array |
184
|
|
|
*/ |
185
|
|
|
public $linesmvt = array(); |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* @var BookKeepingLine[] export line array |
189
|
|
|
*/ |
190
|
|
|
public $linesexport = array(); |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* @var integer|string date of movement validated & lock |
194
|
|
|
*/ |
195
|
|
|
public $date_validation; |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* @var integer|string date of movement who are noticed like exported |
199
|
|
|
*/ |
200
|
|
|
public $date_export; |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png |
204
|
|
|
*/ |
205
|
|
|
public $picto = 'generic'; |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* @var string[] SQL filter used for check if the bookkeeping record can be created/inserted/modified/deleted (cached) |
209
|
|
|
*/ |
210
|
|
|
public static $can_modify_bookkeeping_sql_cached; |
211
|
|
|
|
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* Constructor |
215
|
|
|
* |
216
|
|
|
* @param DoliDB $db Database handler |
217
|
|
|
*/ |
218
|
|
|
public function __construct(DoliDB $db) |
219
|
|
|
{ |
220
|
|
|
$this->db = $db; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Create object into database |
225
|
|
|
* |
226
|
|
|
* @param User $user User that creates |
227
|
|
|
* @param int $notrigger false=launch triggers after, true=disable triggers |
228
|
|
|
* @return int Return integer <0 if KO, Id of created object if OK |
229
|
|
|
*/ |
230
|
|
|
public function create(User $user, $notrigger = 0) |
231
|
|
|
{ |
232
|
|
|
global $conf, $langs; |
233
|
|
|
|
234
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
235
|
|
|
|
236
|
|
|
$error = 0; |
237
|
|
|
|
238
|
|
|
// Clean parameters</center> |
239
|
|
|
if (isset($this->doc_type)) { |
240
|
|
|
$this->doc_type = trim($this->doc_type); |
241
|
|
|
} |
242
|
|
|
if (isset($this->doc_ref)) { |
243
|
|
|
$this->doc_ref = trim($this->doc_ref); |
244
|
|
|
} |
245
|
|
|
if (isset($this->fk_doc)) { |
246
|
|
|
$this->fk_doc = (int) $this->fk_doc; |
247
|
|
|
} |
248
|
|
|
if (isset($this->fk_docdet)) { |
249
|
|
|
$this->fk_docdet = (int) $this->fk_docdet; |
250
|
|
|
} |
251
|
|
|
if (isset($this->thirdparty_code)) { |
252
|
|
|
$this->thirdparty_code = trim($this->thirdparty_code); |
253
|
|
|
} |
254
|
|
|
if (isset($this->subledger_account)) { |
255
|
|
|
$this->subledger_account = trim($this->subledger_account); |
256
|
|
|
} |
257
|
|
|
if (isset($this->subledger_label)) { |
258
|
|
|
$this->subledger_label = trim($this->subledger_label); |
259
|
|
|
} |
260
|
|
|
if (isset($this->numero_compte)) { |
261
|
|
|
$this->numero_compte = trim($this->numero_compte); |
262
|
|
|
} |
263
|
|
|
if (isset($this->label_compte)) { |
264
|
|
|
$this->label_compte = trim($this->label_compte); |
265
|
|
|
} |
266
|
|
|
if (isset($this->label_operation)) { |
267
|
|
|
$this->label_operation = trim($this->label_operation); |
268
|
|
|
} |
269
|
|
|
if (isset($this->debit)) { |
270
|
|
|
$this->debit = (float) $this->debit; |
271
|
|
|
} |
272
|
|
|
if (isset($this->credit)) { |
273
|
|
|
$this->credit = (float) $this->credit; |
274
|
|
|
} |
275
|
|
|
if (isset($this->montant)) { |
276
|
|
|
$this->montant = (float) $this->montant; |
277
|
|
|
} |
278
|
|
|
if (isset($this->amount)) { |
279
|
|
|
$this->amount = (float) $this->amount; |
280
|
|
|
} |
281
|
|
|
if (isset($this->sens)) { |
282
|
|
|
$this->sens = trim($this->sens); |
283
|
|
|
} |
284
|
|
|
if (isset($this->import_key)) { |
285
|
|
|
$this->import_key = trim($this->import_key); |
286
|
|
|
} |
287
|
|
|
if (isset($this->code_journal)) { |
288
|
|
|
$this->code_journal = trim($this->code_journal); |
289
|
|
|
} |
290
|
|
|
if (isset($this->journal_label)) { |
291
|
|
|
$this->journal_label = trim($this->journal_label); |
292
|
|
|
} |
293
|
|
|
if (isset($this->piece_num)) { |
294
|
|
|
$this->piece_num = (int) $this->piece_num; |
295
|
|
|
} |
296
|
|
|
if (empty($this->debit)) { |
297
|
|
|
$this->debit = 0.0; |
298
|
|
|
} |
299
|
|
|
if (empty($this->credit)) { |
300
|
|
|
$this->credit = 0.0; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
$result = $this->validBookkeepingDate($this->doc_date); |
304
|
|
|
if ($result < 0) { |
305
|
|
|
return -1; |
306
|
|
|
} elseif ($result == 0) { |
307
|
|
|
if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') { |
308
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod'); |
309
|
|
|
} else { |
310
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod'); |
311
|
|
|
} |
312
|
|
|
return -1; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
// Check parameters |
316
|
|
|
if (($this->numero_compte == "") || $this->numero_compte == '-1' || $this->numero_compte == 'NotDefined') { |
317
|
|
|
$langs->loadLangs(array("errors")); |
318
|
|
|
if (in_array($this->doc_type, array('bank', 'expense_report'))) { |
319
|
|
|
$this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForBankLine', $this->fk_docdet, $this->doc_type); |
320
|
|
|
} else { |
321
|
|
|
//$this->errors[]=$langs->trans('ErrorFieldAccountNotDefinedForInvoiceLine', $this->doc_ref, $this->label_compte); |
322
|
|
|
$mesg = $this->doc_ref . ', ' . $langs->trans("AccountAccounting") . ': ' . ($this->numero_compte != -1 ? $this->numero_compte : $langs->trans("Unknown")); |
323
|
|
|
if ($this->subledger_account && $this->subledger_account != $this->numero_compte) { |
324
|
|
|
$mesg .= ', ' . $langs->trans("SubledgerAccount") . ': ' . $this->subledger_account; |
325
|
|
|
} |
326
|
|
|
$this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForLine', $mesg); |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
return -1; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
$this->db->begin(); |
333
|
|
|
|
334
|
|
|
$this->piece_num = 0; |
335
|
|
|
|
336
|
|
|
// First check if line not yet already in bookkeeping. |
337
|
|
|
// Note that we must include 'doc_type - fk_doc - numero_compte - label' to be sure to have unicity of line (because we may have several lines |
338
|
|
|
// with same doc_type, fk_doc, numero_compte for 1 invoice line when using localtaxes with same account) |
339
|
|
|
// WARNING: This is not reliable, label may have been modified. This is just a small protection. |
340
|
|
|
// The page that make transfer make the test on couple (doc_type - fk_doc) only. |
341
|
|
|
$sql = "SELECT count(*) as nb"; |
342
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element; |
343
|
|
|
$sql .= " WHERE doc_type = '" . $this->db->escape($this->doc_type) . "'"; |
344
|
|
|
$sql .= " AND fk_doc = " . ((int) $this->fk_doc); |
345
|
|
|
if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) { |
346
|
|
|
// DO NOT USE THIS IN PRODUCTION. This will generate a lot of trouble into reports and will corrupt database (by generating duplicate entries. |
347
|
|
|
$sql .= " AND fk_docdet = " . ((int) $this->fk_docdet); // This field can be 0 if record is for several lines |
348
|
|
|
} |
349
|
|
|
$sql .= " AND numero_compte = '" . $this->db->escape($this->numero_compte) . "'"; |
350
|
|
|
$sql .= " AND label_operation = '" . $this->db->escape($this->label_operation) . "'"; |
351
|
|
|
$sql .= " AND entity = " . $conf->entity; // Do not use getEntity for accounting features |
352
|
|
|
|
353
|
|
|
$resql = $this->db->query($sql); |
354
|
|
|
|
355
|
|
|
if ($resql) { |
356
|
|
|
$row = $this->db->fetch_object($resql); |
357
|
|
|
if ($row->nb == 0) { // Not already into bookkeeping |
358
|
|
|
// Check to know if piece_num already exists for data we try to insert to reuse the same value |
359
|
|
|
$sqlnum = "SELECT piece_num"; |
360
|
|
|
$sqlnum .= " FROM " . MAIN_DB_PREFIX . $this->table_element; |
361
|
|
|
$sqlnum .= " WHERE doc_type = '" . $this->db->escape($this->doc_type) . "'"; // For example doc_type = 'bank' |
362
|
|
|
$sqlnum .= " AND fk_doc = " . ((int) $this->fk_doc); |
363
|
|
|
if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) { |
364
|
|
|
// fk_docdet is rowid into llx_bank or llx_facturedet or llx_facturefourndet, or ... |
365
|
|
|
$sqlnum .= " AND fk_docdet = " . ((int) $this->fk_docdet); |
366
|
|
|
} |
367
|
|
|
$sqlnum .= " AND doc_ref = '" . $this->db->escape($this->doc_ref) . "'"; // ref of source object |
368
|
|
|
$sqlnum .= " AND entity = " . $conf->entity; // Do not use getEntity for accounting features |
369
|
|
|
|
370
|
|
|
dol_syslog(get_only_class($this) . ":: create sqlnum=" . $sqlnum, LOG_DEBUG); |
371
|
|
|
$resqlnum = $this->db->query($sqlnum); |
372
|
|
|
if ($resqlnum) { |
373
|
|
|
$objnum = $this->db->fetch_object($resqlnum); |
374
|
|
|
$this->piece_num = $objnum->piece_num; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
dol_syslog(get_only_class($this) . "::create this->piece_num=" . $this->piece_num, LOG_DEBUG); |
378
|
|
|
if (empty($this->piece_num)) { |
379
|
|
|
$sqlnum = "SELECT MAX(piece_num)+1 as maxpiecenum"; |
380
|
|
|
$sqlnum .= " FROM " . MAIN_DB_PREFIX . $this->table_element; |
381
|
|
|
$sqlnum .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
382
|
|
|
|
383
|
|
|
$resqlnum = $this->db->query($sqlnum); |
384
|
|
|
if ($resqlnum) { |
385
|
|
|
$objnum = $this->db->fetch_object($resqlnum); |
386
|
|
|
$this->piece_num = $objnum->maxpiecenum; |
387
|
|
|
} |
388
|
|
|
dol_syslog(get_only_class($this) . ":: create now this->piece_num=" . $this->piece_num, LOG_DEBUG); |
389
|
|
|
} |
390
|
|
|
if (empty($this->piece_num)) { |
391
|
|
|
$this->piece_num = 1; |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
$now = dol_now(); |
395
|
|
|
|
396
|
|
|
$sql = "INSERT INTO " . MAIN_DB_PREFIX . $this->table_element . " ("; |
397
|
|
|
$sql .= "doc_date"; |
398
|
|
|
$sql .= ", date_lim_reglement"; |
399
|
|
|
$sql .= ", doc_type"; |
400
|
|
|
$sql .= ", doc_ref"; |
401
|
|
|
$sql .= ", fk_doc"; |
402
|
|
|
$sql .= ", fk_docdet"; |
403
|
|
|
$sql .= ", thirdparty_code"; |
404
|
|
|
$sql .= ", subledger_account"; |
405
|
|
|
$sql .= ", subledger_label"; |
406
|
|
|
$sql .= ", numero_compte"; |
407
|
|
|
$sql .= ", label_compte"; |
408
|
|
|
$sql .= ", label_operation"; |
409
|
|
|
$sql .= ", debit"; |
410
|
|
|
$sql .= ", credit"; |
411
|
|
|
$sql .= ", montant"; |
412
|
|
|
$sql .= ", sens"; |
413
|
|
|
$sql .= ", fk_user_author"; |
414
|
|
|
$sql .= ", date_creation"; |
415
|
|
|
$sql .= ", code_journal"; |
416
|
|
|
$sql .= ", journal_label"; |
417
|
|
|
$sql .= ", piece_num"; |
418
|
|
|
$sql .= ', entity'; |
419
|
|
|
$sql .= ") VALUES ("; |
420
|
|
|
$sql .= "'" . $this->db->idate($this->doc_date) . "'"; |
421
|
|
|
$sql .= ", " . (!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'" . $this->db->idate($this->date_lim_reglement) . "'"); |
422
|
|
|
$sql .= ", '" . $this->db->escape($this->doc_type) . "'"; |
423
|
|
|
$sql .= ", '" . $this->db->escape($this->doc_ref) . "'"; |
424
|
|
|
$sql .= ", " . ((int) $this->fk_doc); |
425
|
|
|
$sql .= ", " . ((int) $this->fk_docdet); |
426
|
|
|
$sql .= ", " . (!empty($this->thirdparty_code) ? ("'" . $this->db->escape($this->thirdparty_code) . "'") : "NULL"); |
427
|
|
|
$sql .= ", " . (!empty($this->subledger_account) ? ("'" . $this->db->escape($this->subledger_account) . "'") : "NULL"); |
428
|
|
|
$sql .= ", " . (!empty($this->subledger_label) ? ("'" . $this->db->escape($this->subledger_label) . "'") : "NULL"); |
429
|
|
|
$sql .= ", '" . $this->db->escape($this->numero_compte) . "'"; |
430
|
|
|
$sql .= ", " . (!empty($this->label_compte) ? ("'" . $this->db->escape($this->label_compte) . "'") : "NULL"); |
431
|
|
|
$sql .= ", '" . $this->db->escape($this->label_operation) . "'"; |
432
|
|
|
$sql .= ", " . ((float) $this->debit); |
433
|
|
|
$sql .= ", " . ((float) $this->credit); |
434
|
|
|
$sql .= ", " . ((float) $this->montant); |
435
|
|
|
$sql .= ", " . (!empty($this->sens) ? ("'" . $this->db->escape($this->sens) . "'") : "NULL"); |
436
|
|
|
$sql .= ", '" . $this->db->escape($this->fk_user_author) . "'"; |
437
|
|
|
$sql .= ", '" . $this->db->idate($now) . "'"; |
438
|
|
|
$sql .= ", '" . $this->db->escape($this->code_journal) . "'"; |
439
|
|
|
$sql .= ", " . (!empty($this->journal_label) ? ("'" . $this->db->escape($this->journal_label) . "'") : "NULL"); |
440
|
|
|
$sql .= ", " . ((int) $this->piece_num); |
441
|
|
|
$sql .= ", " . (!isset($this->entity) ? $conf->entity : $this->entity); |
442
|
|
|
$sql .= ")"; |
443
|
|
|
|
444
|
|
|
$resql = $this->db->query($sql); |
445
|
|
|
if ($resql) { |
446
|
|
|
$id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); |
447
|
|
|
|
448
|
|
|
if ($id > 0) { |
449
|
|
|
$this->id = $id; |
450
|
|
|
$result = 0; |
451
|
|
|
} else { |
452
|
|
|
$result = -2; |
453
|
|
|
$error++; |
454
|
|
|
$this->errors[] = 'Error Create Error ' . $result . ' lecture ID'; |
455
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
456
|
|
|
} |
457
|
|
|
} else { |
458
|
|
|
$result = -1; |
459
|
|
|
$error++; |
460
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
461
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
462
|
|
|
} |
463
|
|
|
} else { // Already exists |
464
|
|
|
$result = -3; |
465
|
|
|
$error++; |
466
|
|
|
$this->error = 'BookkeepingRecordAlreadyExists'; |
467
|
|
|
dol_syslog(__METHOD__ . ' ' . $this->error, LOG_WARNING); |
468
|
|
|
} |
469
|
|
|
} else { |
470
|
|
|
$result = -5; |
471
|
|
|
$error++; |
472
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
473
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
// Uncomment this and change MYOBJECT to your own tag if you |
477
|
|
|
// want this action to call a trigger. |
478
|
|
|
//if (! $error && ! $notrigger) { |
479
|
|
|
|
480
|
|
|
// // Call triggers |
481
|
|
|
// $result=$this->call_trigger('MYOBJECT_CREATE',$user); |
482
|
|
|
// if ($result < 0) $error++; |
483
|
|
|
// // End call triggers |
484
|
|
|
//} |
485
|
|
|
|
486
|
|
|
// Commit or rollback |
487
|
|
|
if ($error) { |
488
|
|
|
$this->db->rollback(); |
489
|
|
|
return -1 * $error; |
490
|
|
|
} else { |
491
|
|
|
$this->db->commit(); |
492
|
|
|
return $result; |
493
|
|
|
} |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
/** |
497
|
|
|
* Return a link to the object card (with optionally the picto) |
498
|
|
|
* |
499
|
|
|
* @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) |
500
|
|
|
* @param string $option On what the link point to ('nolink', ...) |
501
|
|
|
* @param int $notooltip 1=Disable tooltip |
502
|
|
|
* @param string $morecss Add more css on link |
503
|
|
|
* @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking |
504
|
|
|
* @return string String with URL |
505
|
|
|
*/ |
506
|
|
|
public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) |
507
|
|
|
{ |
508
|
|
|
global $db, $conf, $langs; |
509
|
|
|
global $dolibarr_main_authentication, $dolibarr_main_demo; |
510
|
|
|
global $menumanager, $hookmanager; |
511
|
|
|
|
512
|
|
|
if (!empty($conf->dol_no_mouse_hover)) { |
513
|
|
|
$notooltip = 1; // Force disable tooltips |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
$result = ''; |
517
|
|
|
$companylink = ''; |
518
|
|
|
|
519
|
|
|
$label = '<u>' . $langs->trans("Transaction") . '</u>'; |
520
|
|
|
$label .= '<br>'; |
521
|
|
|
$label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->piece_num; |
522
|
|
|
|
523
|
|
|
$url = constant('BASE_URL') . '/accountancy/bookkeeping/card.php?piece_num=' . $this->piece_num; |
524
|
|
|
|
525
|
|
|
if ($option != 'nolink') { |
526
|
|
|
// Add param to save lastsearch_values or not |
527
|
|
|
$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); |
528
|
|
|
if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { |
529
|
|
|
$add_save_lastsearch_values = 1; |
530
|
|
|
} |
531
|
|
|
if ($add_save_lastsearch_values) { |
532
|
|
|
$url .= '&save_lastsearch_values=1'; |
533
|
|
|
} |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
$linkclose = ''; |
537
|
|
|
if (empty($notooltip)) { |
538
|
|
|
if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) { |
539
|
|
|
$label = $langs->trans("ShowTransaction"); |
540
|
|
|
$linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"'; |
541
|
|
|
} |
542
|
|
|
$linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"'; |
543
|
|
|
$linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"'; |
544
|
|
|
} else { |
545
|
|
|
$linkclose = ($morecss ? ' class="' . $morecss . '"' : ''); |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
$linkstart = '<a href="' . $url . '"'; |
549
|
|
|
$linkstart .= $linkclose . '>'; |
550
|
|
|
$linkend = '</a>'; |
551
|
|
|
|
552
|
|
|
$result .= $linkstart; |
553
|
|
|
if ($withpicto) { |
554
|
|
|
$result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); |
555
|
|
|
} |
556
|
|
|
if ($withpicto != 2) { |
557
|
|
|
$result .= $this->piece_num; |
558
|
|
|
} |
559
|
|
|
$result .= $linkend; |
560
|
|
|
//if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); |
561
|
|
|
|
562
|
|
|
global $action; |
563
|
|
|
$hookmanager->initHooks(array($this->element . 'dao')); |
564
|
|
|
$parameters = array('id' => $this->id, 'getnomurl' => &$result); |
565
|
|
|
$reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks |
566
|
|
|
if ($reshook > 0) { |
567
|
|
|
$result = $hookmanager->resPrint; |
568
|
|
|
} else { |
569
|
|
|
$result .= $hookmanager->resPrint; |
570
|
|
|
} |
571
|
|
|
return $result; |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
/** |
575
|
|
|
* Create object into database |
576
|
|
|
* |
577
|
|
|
* @param User $user User that creates |
578
|
|
|
* @param int $notrigger false=launch triggers after, true=disable triggers |
579
|
|
|
* @param string $mode Mode |
580
|
|
|
* @return int Return integer <0 if KO, Id of created object if OK |
581
|
|
|
*/ |
582
|
|
|
public function createStd(User $user, $notrigger = 0, $mode = '') |
583
|
|
|
{ |
584
|
|
|
global $conf, $langs; |
585
|
|
|
|
586
|
|
|
$langs->loadLangs(array("accountancy", "bills", "compta")); |
587
|
|
|
|
588
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
589
|
|
|
|
590
|
|
|
$error = 0; |
591
|
|
|
|
592
|
|
|
// Clean parameters |
593
|
|
|
if (isset($this->doc_type)) { |
594
|
|
|
$this->doc_type = trim($this->doc_type); |
595
|
|
|
} |
596
|
|
|
if (isset($this->doc_ref)) { |
597
|
|
|
$this->doc_ref = trim($this->doc_ref); |
598
|
|
|
} |
599
|
|
|
if (isset($this->fk_doc)) { |
600
|
|
|
$this->fk_doc = (int) $this->fk_doc; |
601
|
|
|
} |
602
|
|
|
if (isset($this->fk_docdet)) { |
603
|
|
|
$this->fk_docdet = (int) $this->fk_docdet; |
604
|
|
|
} |
605
|
|
|
if (isset($this->thirdparty_code)) { |
606
|
|
|
$this->thirdparty_code = trim($this->thirdparty_code); |
607
|
|
|
} |
608
|
|
|
if (isset($this->subledger_account)) { |
609
|
|
|
$this->subledger_account = trim($this->subledger_account); |
610
|
|
|
} |
611
|
|
|
if (isset($this->subledger_label)) { |
612
|
|
|
$this->subledger_label = trim($this->subledger_label); |
613
|
|
|
} |
614
|
|
|
if (isset($this->numero_compte)) { |
615
|
|
|
$this->numero_compte = trim($this->numero_compte); |
616
|
|
|
} |
617
|
|
|
if (isset($this->label_compte)) { |
618
|
|
|
$this->label_compte = trim($this->label_compte); |
619
|
|
|
} |
620
|
|
|
if (isset($this->label_operation)) { |
621
|
|
|
$this->label_operation = trim($this->label_operation); |
622
|
|
|
} |
623
|
|
|
if (isset($this->sens)) { |
624
|
|
|
$this->sens = trim($this->sens); |
625
|
|
|
} |
626
|
|
|
if (isset($this->import_key)) { |
627
|
|
|
$this->import_key = trim($this->import_key); |
628
|
|
|
} |
629
|
|
|
if (isset($this->code_journal)) { |
630
|
|
|
$this->code_journal = trim($this->code_journal); |
631
|
|
|
} |
632
|
|
|
if (isset($this->journal_label)) { |
633
|
|
|
$this->journal_label = trim($this->journal_label); |
634
|
|
|
} |
635
|
|
|
if (isset($this->piece_num)) { |
636
|
|
|
$this->piece_num = (int) $this->piece_num; |
637
|
|
|
} |
638
|
|
|
if (empty($this->debit)) { |
639
|
|
|
$this->debit = 0; |
640
|
|
|
} |
641
|
|
|
if (empty($this->credit)) { |
642
|
|
|
$this->credit = 0; |
643
|
|
|
} |
644
|
|
|
if (empty($this->montant)) { |
645
|
|
|
$this->montant = 0; |
646
|
|
|
} |
647
|
|
|
|
648
|
|
|
$result = $this->validBookkeepingDate($this->doc_date); |
649
|
|
|
if ($result < 0) { |
650
|
|
|
return -1; |
651
|
|
|
} elseif ($result == 0) { |
652
|
|
|
if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') { |
653
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod'); |
654
|
|
|
} else { |
655
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod'); |
656
|
|
|
} |
657
|
|
|
return -1; |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
$this->debit = (float) price2num($this->debit, 'MT'); |
661
|
|
|
$this->credit = (float) price2num($this->credit, 'MT'); |
662
|
|
|
$this->montant = (float) price2num($this->montant, 'MT'); |
663
|
|
|
|
664
|
|
|
$now = dol_now(); |
665
|
|
|
|
666
|
|
|
// Check parameters |
667
|
|
|
$this->journal_label = $langs->trans($this->journal_label); |
668
|
|
|
|
669
|
|
|
// Insert request |
670
|
|
|
$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . $mode . ' ('; |
671
|
|
|
$sql .= 'doc_date,'; |
672
|
|
|
$sql .= 'date_lim_reglement,'; |
673
|
|
|
$sql .= 'doc_type,'; |
674
|
|
|
$sql .= 'doc_ref,'; |
675
|
|
|
$sql .= 'fk_doc,'; |
676
|
|
|
$sql .= 'fk_docdet,'; |
677
|
|
|
$sql .= 'thirdparty_code,'; |
678
|
|
|
$sql .= 'subledger_account,'; |
679
|
|
|
$sql .= 'subledger_label,'; |
680
|
|
|
$sql .= 'numero_compte,'; |
681
|
|
|
$sql .= 'label_compte,'; |
682
|
|
|
$sql .= 'label_operation,'; |
683
|
|
|
$sql .= 'debit,'; |
684
|
|
|
$sql .= 'credit,'; |
685
|
|
|
$sql .= 'montant,'; |
686
|
|
|
$sql .= 'sens,'; |
687
|
|
|
$sql .= 'fk_user_author,'; |
688
|
|
|
$sql .= 'date_creation,'; |
689
|
|
|
$sql .= 'code_journal,'; |
690
|
|
|
$sql .= 'journal_label,'; |
691
|
|
|
$sql .= 'piece_num,'; |
692
|
|
|
$sql .= 'entity'; |
693
|
|
|
$sql .= ') VALUES ('; |
694
|
|
|
$sql .= ' ' . (!isset($this->doc_date) || dol_strlen($this->doc_date) == 0 ? 'NULL' : "'" . $this->db->idate($this->doc_date) . "'") . ','; |
695
|
|
|
$sql .= ' ' . (!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'" . $this->db->idate($this->date_lim_reglement) . "'") . ','; |
696
|
|
|
$sql .= ' ' . (!isset($this->doc_type) ? 'NULL' : "'" . $this->db->escape($this->doc_type) . "'") . ','; |
697
|
|
|
$sql .= ' ' . (!isset($this->doc_ref) ? 'NULL' : "'" . $this->db->escape($this->doc_ref) . "'") . ','; |
698
|
|
|
$sql .= ' ' . (empty($this->fk_doc) ? '0' : (int) $this->fk_doc) . ','; |
699
|
|
|
$sql .= ' ' . (empty($this->fk_docdet) ? '0' : (int) $this->fk_docdet) . ','; |
700
|
|
|
$sql .= ' ' . (!isset($this->thirdparty_code) ? 'NULL' : "'" . $this->db->escape($this->thirdparty_code) . "'") . ','; |
701
|
|
|
$sql .= ' ' . (!isset($this->subledger_account) ? 'NULL' : "'" . $this->db->escape($this->subledger_account) . "'") . ','; |
702
|
|
|
$sql .= ' ' . (!isset($this->subledger_label) ? 'NULL' : "'" . $this->db->escape($this->subledger_label) . "'") . ','; |
703
|
|
|
$sql .= ' ' . (!isset($this->numero_compte) ? 'NULL' : "'" . $this->db->escape($this->numero_compte) . "'") . ','; |
704
|
|
|
$sql .= ' ' . (!isset($this->label_compte) ? 'NULL' : "'" . $this->db->escape($this->label_compte) . "'") . ','; |
705
|
|
|
$sql .= ' ' . (!isset($this->label_operation) ? 'NULL' : "'" . $this->db->escape($this->label_operation) . "'") . ','; |
706
|
|
|
$sql .= ' ' . (!isset($this->debit) ? 'NULL' : $this->debit) . ','; |
707
|
|
|
$sql .= ' ' . (!isset($this->credit) ? 'NULL' : $this->credit) . ','; |
708
|
|
|
$sql .= ' ' . (!isset($this->montant) ? 'NULL' : $this->montant) . ','; |
709
|
|
|
$sql .= ' ' . (!isset($this->sens) ? 'NULL' : "'" . $this->db->escape($this->sens) . "'") . ','; |
710
|
|
|
$sql .= ' ' . ((int) $user->id) . ','; |
711
|
|
|
$sql .= ' ' . "'" . $this->db->idate($now) . "',"; |
712
|
|
|
$sql .= ' ' . (empty($this->code_journal) ? 'NULL' : "'" . $this->db->escape($this->code_journal) . "'") . ','; |
713
|
|
|
$sql .= ' ' . (empty($this->journal_label) ? 'NULL' : "'" . $this->db->escape($this->journal_label) . "'") . ','; |
714
|
|
|
$sql .= ' ' . (empty($this->piece_num) ? 'NULL' : $this->db->escape($this->piece_num)) . ','; |
715
|
|
|
$sql .= ' ' . (!isset($this->entity) ? $conf->entity : $this->entity); |
716
|
|
|
$sql .= ')'; |
717
|
|
|
|
718
|
|
|
$this->db->begin(); |
719
|
|
|
|
720
|
|
|
$resql = $this->db->query($sql); |
721
|
|
|
if (!$resql) { |
722
|
|
|
$error++; |
723
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
724
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
725
|
|
|
} |
726
|
|
|
|
727
|
|
|
if (!$error) { |
728
|
|
|
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element . $mode); |
729
|
|
|
} |
730
|
|
|
|
731
|
|
|
// Commit or rollback |
732
|
|
|
if ($error) { |
733
|
|
|
$this->db->rollback(); |
734
|
|
|
|
735
|
|
|
return -1 * $error; |
736
|
|
|
} else { |
737
|
|
|
$this->db->commit(); |
738
|
|
|
|
739
|
|
|
return $this->id; |
740
|
|
|
} |
741
|
|
|
} |
742
|
|
|
|
743
|
|
|
/** |
744
|
|
|
* Load object in memory from the database |
745
|
|
|
* |
746
|
|
|
* @param int $id Id object |
747
|
|
|
* @param string|null $ref Ref |
748
|
|
|
* @param string $mode Mode ('' or 'tmp_') |
749
|
|
|
* @return int Return integer <0 if KO, 0 if not found, >0 if OK |
750
|
|
|
*/ |
751
|
|
|
public function fetch($id, $ref = null, $mode = '') |
752
|
|
|
{ |
753
|
|
|
global $conf; |
754
|
|
|
|
755
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
756
|
|
|
|
757
|
|
|
$sql = 'SELECT'; |
758
|
|
|
$sql .= ' t.rowid,'; |
759
|
|
|
$sql .= " t.doc_date,"; |
760
|
|
|
$sql .= " t.date_lim_reglement,"; |
761
|
|
|
$sql .= " t.doc_type,"; |
762
|
|
|
$sql .= " t.doc_ref,"; |
763
|
|
|
$sql .= " t.fk_doc,"; |
764
|
|
|
$sql .= " t.fk_docdet,"; |
765
|
|
|
$sql .= " t.thirdparty_code,"; |
766
|
|
|
$sql .= " t.subledger_account,"; |
767
|
|
|
$sql .= " t.subledger_label,"; |
768
|
|
|
$sql .= " t.numero_compte,"; |
769
|
|
|
$sql .= " t.label_compte,"; |
770
|
|
|
$sql .= " t.label_operation,"; |
771
|
|
|
$sql .= " t.debit,"; |
772
|
|
|
$sql .= " t.credit,"; |
773
|
|
|
$sql .= " t.montant as amount,"; |
774
|
|
|
$sql .= " t.sens,"; |
775
|
|
|
$sql .= " t.fk_user_author,"; |
776
|
|
|
$sql .= " t.import_key,"; |
777
|
|
|
$sql .= " t.code_journal,"; |
778
|
|
|
$sql .= " t.journal_label,"; |
779
|
|
|
$sql .= " t.piece_num,"; |
780
|
|
|
$sql .= " t.date_creation,"; |
781
|
|
|
// In llx_accounting_bookkeeping_tmp, field date_export doesn't exist |
782
|
|
|
if ($mode != "_tmp") { |
783
|
|
|
$sql .= " t.date_export,"; |
784
|
|
|
} |
785
|
|
|
$sql .= " t.date_validated as date_validation"; |
786
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . $mode . ' as t'; |
787
|
|
|
$sql .= ' WHERE 1 = 1'; |
788
|
|
|
$sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
789
|
|
|
if (null !== $ref) { |
790
|
|
|
$sql .= " AND t.rowid = " . ((int) $ref); |
791
|
|
|
} else { |
792
|
|
|
$sql .= " AND t.rowid = " . ((int) $id); |
793
|
|
|
} |
794
|
|
|
|
795
|
|
|
$resql = $this->db->query($sql); |
796
|
|
|
if ($resql) { |
797
|
|
|
$numrows = $this->db->num_rows($resql); |
798
|
|
|
if ($numrows) { |
799
|
|
|
$obj = $this->db->fetch_object($resql); |
800
|
|
|
|
801
|
|
|
$this->id = $obj->rowid; |
802
|
|
|
|
803
|
|
|
$this->doc_date = $this->db->jdate($obj->doc_date); |
|
|
|
|
804
|
|
|
$this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement); |
|
|
|
|
805
|
|
|
$this->doc_type = $obj->doc_type; |
806
|
|
|
$this->doc_ref = $obj->doc_ref; |
807
|
|
|
$this->fk_doc = $obj->fk_doc; |
808
|
|
|
$this->fk_docdet = $obj->fk_docdet; |
809
|
|
|
$this->thirdparty_code = $obj->thirdparty_code; |
810
|
|
|
$this->subledger_account = $obj->subledger_account; |
811
|
|
|
$this->subledger_label = $obj->subledger_label; |
812
|
|
|
$this->numero_compte = $obj->numero_compte; |
813
|
|
|
$this->label_compte = $obj->label_compte; |
814
|
|
|
$this->label_operation = $obj->label_operation; |
815
|
|
|
$this->debit = $obj->debit; |
816
|
|
|
$this->credit = $obj->credit; |
817
|
|
|
$this->montant = $obj->amount; |
|
|
|
|
818
|
|
|
$this->amount = $obj->amount; |
|
|
|
|
819
|
|
|
$this->sens = $obj->sens; |
820
|
|
|
$this->fk_user_author = $obj->fk_user_author; |
821
|
|
|
$this->import_key = $obj->import_key; |
822
|
|
|
$this->code_journal = $obj->code_journal; |
823
|
|
|
$this->journal_label = $obj->journal_label; |
824
|
|
|
$this->piece_num = $obj->piece_num; |
825
|
|
|
$this->date_creation = $this->db->jdate($obj->date_creation); |
826
|
|
|
$this->date_export = $this->db->jdate($obj->date_export); |
827
|
|
|
$this->date_validation = isset($obj->date_validation) ? $this->db->jdate($obj->date_validation) : ''; |
828
|
|
|
} |
829
|
|
|
$this->db->free($resql); |
830
|
|
|
|
831
|
|
|
if ($numrows) { |
832
|
|
|
return 1; |
833
|
|
|
} else { |
834
|
|
|
return 0; |
835
|
|
|
} |
836
|
|
|
} else { |
837
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
838
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
839
|
|
|
|
840
|
|
|
return -1; |
841
|
|
|
} |
842
|
|
|
} |
843
|
|
|
|
844
|
|
|
|
845
|
|
|
/** |
846
|
|
|
* Load object in memory from the database in ->lines. Or just make a simple count if $countonly=1. |
847
|
|
|
* |
848
|
|
|
* @param string $sortorder Sort Order |
849
|
|
|
* @param string $sortfield Sort field |
850
|
|
|
* @param int $limit limit |
851
|
|
|
* @param int $offset offset limit |
852
|
|
|
* @param array $filter filter array |
853
|
|
|
* @param string $filtermode filter mode (AND or OR) |
854
|
|
|
* @param int $option option (0: general account or 1: subaccount) |
855
|
|
|
* @param int $countonly Do not fill the $object->lines, return only the count. |
856
|
|
|
* @return int Return integer <0 if KO, Number of lines if OK |
857
|
|
|
*/ |
858
|
|
|
public function fetchAllByAccount($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0, $countonly = 0) |
859
|
|
|
{ |
860
|
|
|
global $conf; |
861
|
|
|
|
862
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
863
|
|
|
|
864
|
|
|
$this->lines = array(); |
865
|
|
|
$num = 0; |
866
|
|
|
|
867
|
|
|
$sql = 'SELECT'; |
868
|
|
|
if ($countonly) { |
869
|
|
|
$sql .= ' COUNT(t.rowid) as nb'; |
870
|
|
|
} else { |
871
|
|
|
$sql .= ' t.rowid,'; |
872
|
|
|
$sql .= " t.doc_date,"; |
873
|
|
|
$sql .= " t.doc_type,"; |
874
|
|
|
$sql .= " t.doc_ref,"; |
875
|
|
|
$sql .= " t.fk_doc,"; |
876
|
|
|
$sql .= " t.fk_docdet,"; |
877
|
|
|
$sql .= " t.thirdparty_code,"; |
878
|
|
|
$sql .= " t.subledger_account,"; |
879
|
|
|
$sql .= " t.subledger_label,"; |
880
|
|
|
$sql .= " t.numero_compte,"; |
881
|
|
|
$sql .= " t.label_compte,"; |
882
|
|
|
$sql .= " t.label_operation,"; |
883
|
|
|
$sql .= " t.debit,"; |
884
|
|
|
$sql .= " t.credit,"; |
885
|
|
|
$sql .= " t.montant as amount,"; |
886
|
|
|
$sql .= " t.sens,"; |
887
|
|
|
$sql .= " t.multicurrency_amount,"; |
888
|
|
|
$sql .= " t.multicurrency_code,"; |
889
|
|
|
$sql .= " t.lettering_code,"; |
890
|
|
|
$sql .= " t.date_lettering,"; |
891
|
|
|
$sql .= " t.fk_user_author,"; |
892
|
|
|
$sql .= " t.import_key,"; |
893
|
|
|
$sql .= " t.code_journal,"; |
894
|
|
|
$sql .= " t.journal_label,"; |
895
|
|
|
$sql .= " t.piece_num,"; |
896
|
|
|
$sql .= " t.date_creation,"; |
897
|
|
|
$sql .= " t.date_export,"; |
898
|
|
|
$sql .= " t.date_validated as date_validation,"; |
899
|
|
|
$sql .= " t.date_lim_reglement,"; |
900
|
|
|
$sql .= " t.import_key"; |
901
|
|
|
} |
902
|
|
|
// Manage filter |
903
|
|
|
$sqlwhere = array(); |
904
|
|
|
if (count($filter) > 0) { |
905
|
|
|
foreach ($filter as $key => $value) { |
906
|
|
|
if ($key == 't.doc_date>=') { |
907
|
|
|
$sqlwhere[] = "t.doc_date >= '" . $this->db->idate($value) . "'"; |
908
|
|
|
} elseif ($key == 't.doc_date<=') { |
909
|
|
|
$sqlwhere[] = "t.doc_date <= '" . $this->db->idate($value) . "'"; |
910
|
|
|
} elseif ($key == 't.doc_date>') { |
911
|
|
|
$sqlwhere[] = "t.doc_date > '" . $this->db->idate($value) . "'"; |
912
|
|
|
} elseif ($key == 't.doc_date<') { |
913
|
|
|
$sqlwhere[] = "t.doc_date < '" . $this->db->idate($value) . "'"; |
914
|
|
|
} elseif ($key == 't.numero_compte>=') { |
915
|
|
|
$sqlwhere[] = "t.numero_compte >= '" . $this->db->escape($value) . "'"; |
916
|
|
|
} elseif ($key == 't.numero_compte<=') { |
917
|
|
|
$sqlwhere[] = "t.numero_compte <= '" . $this->db->escape($value) . "'"; |
918
|
|
|
} elseif ($key == 't.subledger_account>=') { |
919
|
|
|
$sqlwhere[] = "t.subledger_account >= '" . $this->db->escape($value) . "'"; |
920
|
|
|
} elseif ($key == 't.subledger_account<=') { |
921
|
|
|
$sqlwhere[] = "t.subledger_account <= '" . $this->db->escape($value) . "'"; |
922
|
|
|
} elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') { |
923
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . ' = ' . ((int) $value); |
924
|
|
|
} elseif ($key == 't.subledger_account' || $key == 't.numero_compte') { |
925
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . ' LIKE \'' . $this->db->escape($this->db->escapeforlike($value)) . '%\''; |
926
|
|
|
} elseif ($key == 't.date_creation>=') { |
927
|
|
|
$sqlwhere[] = 't.date_creation >= \'' . $this->db->idate($value) . '\''; |
928
|
|
|
} elseif ($key == 't.date_creation<=') { |
929
|
|
|
$sqlwhere[] = 't.date_creation <= \'' . $this->db->idate($value) . '\''; |
930
|
|
|
} elseif ($key == 't.date_export>=') { |
931
|
|
|
$sqlwhere[] = 't.date_export >= \'' . $this->db->idate($value) . '\''; |
932
|
|
|
} elseif ($key == 't.date_export<=') { |
933
|
|
|
$sqlwhere[] = 't.date_export <= \'' . $this->db->idate($value) . '\''; |
934
|
|
|
} elseif ($key == 't.date_validated>=') { |
935
|
|
|
$sqlwhere[] = 't.date_validated >= \'' . $this->db->idate($value) . '\''; |
936
|
|
|
} elseif ($key == 't.date_validated<=') { |
937
|
|
|
$sqlwhere[] = 't.date_validated <= \'' . $this->db->idate($value) . '\''; |
938
|
|
|
} elseif ($key == 't.date_lim_reglement>=') { |
939
|
|
|
$sqlwhere[] = 't.date_lim_reglement>=\'' . $this->db->idate($value) . '\''; |
940
|
|
|
} elseif ($key == 't.date_lim_reglement<=') { |
941
|
|
|
$sqlwhere[] = 't.date_lim_reglement<=\'' . $this->db->idate($value) . '\''; |
942
|
|
|
} elseif ($key == 't.credit' || $key == 't.debit') { |
943
|
|
|
$sqlwhere[] = natural_search($key, $value, 1, 1); |
944
|
|
|
} elseif ($key == 't.reconciled_option') { |
945
|
|
|
$sqlwhere[] = 't.lettering_code IS NULL'; |
946
|
|
|
} elseif ($key == 't.code_journal' && !empty($value)) { |
947
|
|
|
if (is_array($value)) { |
948
|
|
|
$sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1); |
949
|
|
|
} else { |
950
|
|
|
$sqlwhere[] = natural_search("t.code_journal", $value, 3, 1); |
951
|
|
|
} |
952
|
|
|
} elseif ($key == 't.search_accounting_code_in' && !empty($value)) { |
953
|
|
|
$sqlwhere[] = 't.numero_compte IN (' . $this->db->sanitize($value, 1) . ')'; |
954
|
|
|
} else { |
955
|
|
|
$sqlwhere[] = natural_search($key, $value, 0, 1); |
956
|
|
|
} |
957
|
|
|
} |
958
|
|
|
} |
959
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; |
960
|
|
|
$sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features |
961
|
|
|
if (count($sqlwhere) > 0) { |
962
|
|
|
$sql .= " AND " . implode(" " . $this->db->sanitize($filtermode) . " ", $sqlwhere); |
963
|
|
|
} |
964
|
|
|
// Filter by ledger account or subledger account |
965
|
|
|
if (!empty($option)) { |
966
|
|
|
$sql .= " AND t.subledger_account IS NOT NULL"; |
967
|
|
|
$sql .= " AND t.subledger_account <> ''"; |
968
|
|
|
$sortfield = 't.subledger_account' . ($sortfield ? ',' . $sortfield : ''); |
969
|
|
|
$sortorder = 'ASC' . ($sortfield ? ',' . $sortfield : ''); |
970
|
|
|
} else { |
971
|
|
|
$sortfield = 't.numero_compte' . ($sortfield ? ',' . $sortfield : ''); |
972
|
|
|
$sortorder = 'ASC' . ($sortorder ? ',' . $sortorder : ''); |
973
|
|
|
} |
974
|
|
|
|
975
|
|
|
if (!$countonly) { |
976
|
|
|
$sql .= $this->db->order($sortfield, $sortorder); |
977
|
|
|
if (!empty($limit)) { |
978
|
|
|
$sql .= $this->db->plimit($limit + 1, $offset); |
979
|
|
|
} |
980
|
|
|
} |
981
|
|
|
|
982
|
|
|
$resql = $this->db->query($sql); |
983
|
|
|
if ($resql) { |
984
|
|
|
if ($countonly) { |
985
|
|
|
$obj = $this->db->fetch_object($resql); |
986
|
|
|
if ($obj) { |
987
|
|
|
$num = $obj->nb; |
988
|
|
|
} |
989
|
|
|
} else { |
990
|
|
|
$num = $this->db->num_rows($resql); |
991
|
|
|
|
992
|
|
|
$i = 0; |
993
|
|
|
while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) { |
994
|
|
|
$line = new BookKeepingLine($this->db); |
995
|
|
|
|
996
|
|
|
$line->id = $obj->rowid; |
997
|
|
|
|
998
|
|
|
$line->doc_date = $this->db->jdate($obj->doc_date); |
999
|
|
|
$line->doc_type = $obj->doc_type; |
1000
|
|
|
$line->doc_ref = $obj->doc_ref; |
1001
|
|
|
$line->fk_doc = $obj->fk_doc; |
1002
|
|
|
$line->fk_docdet = $obj->fk_docdet; |
1003
|
|
|
$line->thirdparty_code = $obj->thirdparty_code; |
1004
|
|
|
$line->subledger_account = $obj->subledger_account; |
1005
|
|
|
$line->subledger_label = $obj->subledger_label; |
1006
|
|
|
$line->numero_compte = $obj->numero_compte; |
1007
|
|
|
$line->label_compte = $obj->label_compte; |
1008
|
|
|
$line->label_operation = $obj->label_operation; |
1009
|
|
|
$line->debit = $obj->debit; |
1010
|
|
|
$line->credit = $obj->credit; |
1011
|
|
|
$line->montant = $obj->amount; // deprecated |
|
|
|
|
1012
|
|
|
$line->amount = $obj->amount; |
1013
|
|
|
$line->sens = $obj->sens; |
1014
|
|
|
$line->multicurrency_amount = $obj->multicurrency_amount; |
1015
|
|
|
$line->multicurrency_code = $obj->multicurrency_code; |
1016
|
|
|
$line->lettering_code = $obj->lettering_code; |
1017
|
|
|
$line->date_lettering = $obj->date_lettering; |
1018
|
|
|
$line->fk_user_author = $obj->fk_user_author; |
1019
|
|
|
$line->import_key = $obj->import_key; |
1020
|
|
|
$line->code_journal = $obj->code_journal; |
1021
|
|
|
$line->journal_label = $obj->journal_label; |
1022
|
|
|
$line->piece_num = $obj->piece_num; |
1023
|
|
|
$line->date_creation = $this->db->jdate($obj->date_creation); |
1024
|
|
|
$line->date_export = $this->db->jdate($obj->date_export); |
1025
|
|
|
$line->date_validation = $this->db->jdate($obj->date_validation); |
1026
|
|
|
// Due date |
1027
|
|
|
$line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement); |
1028
|
|
|
$line->import_key = $obj->import_key; |
1029
|
|
|
|
1030
|
|
|
$this->lines[] = $line; |
1031
|
|
|
|
1032
|
|
|
$i++; |
1033
|
|
|
} |
1034
|
|
|
} |
1035
|
|
|
$this->db->free($resql); |
1036
|
|
|
|
1037
|
|
|
return $num; |
1038
|
|
|
} else { |
1039
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
1040
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1041
|
|
|
|
1042
|
|
|
return -1; |
1043
|
|
|
} |
1044
|
|
|
} |
1045
|
|
|
|
1046
|
|
|
/** |
1047
|
|
|
* Load object in memory from the database |
1048
|
|
|
* |
1049
|
|
|
* @param string $sortorder Sort Order |
1050
|
|
|
* @param string $sortfield Sort field |
1051
|
|
|
* @param int $limit Limit |
1052
|
|
|
* @param int $offset Offset limit |
1053
|
|
|
* @param string|array $filter Filter array |
1054
|
|
|
* @param string $filtermode Filter mode (AND or OR) |
1055
|
|
|
* @param int $showAlreadyExportMovements Show movements when field 'date_export' is not empty (0:No / 1:Yes (Default)) |
1056
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1057
|
|
|
*/ |
1058
|
|
|
public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $showAlreadyExportMovements = 1) |
1059
|
|
|
{ |
1060
|
|
|
global $conf; |
1061
|
|
|
|
1062
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
1063
|
|
|
|
1064
|
|
|
$sql = 'SELECT'; |
1065
|
|
|
$sql .= ' t.rowid,'; |
1066
|
|
|
$sql .= " t.doc_date,"; |
1067
|
|
|
$sql .= " t.doc_type,"; |
1068
|
|
|
$sql .= " t.doc_ref,"; |
1069
|
|
|
$sql .= " t.fk_doc,"; |
1070
|
|
|
$sql .= " t.fk_docdet,"; |
1071
|
|
|
$sql .= " t.thirdparty_code,"; |
1072
|
|
|
$sql .= " t.subledger_account,"; |
1073
|
|
|
$sql .= " t.subledger_label,"; |
1074
|
|
|
$sql .= " t.numero_compte,"; |
1075
|
|
|
$sql .= " t.label_compte,"; |
1076
|
|
|
$sql .= " t.label_operation,"; |
1077
|
|
|
$sql .= " t.debit,"; |
1078
|
|
|
$sql .= " t.credit,"; |
1079
|
|
|
$sql .= " t.lettering_code,"; |
1080
|
|
|
$sql .= " t.date_lettering,"; |
1081
|
|
|
$sql .= " t.montant as amount,"; |
1082
|
|
|
$sql .= " t.sens,"; |
1083
|
|
|
$sql .= " t.fk_user_author,"; |
1084
|
|
|
$sql .= " t.import_key,"; |
1085
|
|
|
$sql .= " t.code_journal,"; |
1086
|
|
|
$sql .= " t.journal_label,"; |
1087
|
|
|
$sql .= " t.piece_num,"; |
1088
|
|
|
$sql .= " t.date_creation,"; |
1089
|
|
|
$sql .= " t.date_lim_reglement,"; |
1090
|
|
|
$sql .= " t.tms as date_modification,"; |
1091
|
|
|
$sql .= " t.date_export,"; |
1092
|
|
|
$sql .= " t.date_validated as date_validation"; |
1093
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; |
1094
|
|
|
|
1095
|
|
|
$sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features |
1096
|
|
|
if ($showAlreadyExportMovements == 0) { |
1097
|
|
|
$sql .= " AND t.date_export IS NULL"; |
1098
|
|
|
} |
1099
|
|
|
|
1100
|
|
|
// Manage filter |
1101
|
|
|
if (is_array($filter)) { // deprecated, use $filter = USF syntax |
1102
|
|
|
$sqlwhere = array(); |
1103
|
|
|
if (count($filter) > 0) { |
1104
|
|
|
foreach ($filter as $key => $value) { |
1105
|
|
|
if ($key == 't.doc_date') { |
1106
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . ' = \'' . $this->db->idate($value) . '\''; |
1107
|
|
|
} elseif ($key == 't.doc_date>=') { |
1108
|
|
|
$sqlwhere[] = "t.doc_date >= '" . $this->db->idate($value) . "'"; |
1109
|
|
|
} elseif ($key == 't.doc_date<=') { |
1110
|
|
|
$sqlwhere[] = "t.doc_date <= '" . $this->db->idate($value) . "'"; |
1111
|
|
|
} elseif ($key == 't.doc_date>') { |
1112
|
|
|
$sqlwhere[] = "t.doc_date > '" . $this->db->idate($value) . "'"; |
1113
|
|
|
} elseif ($key == 't.doc_date<') { |
1114
|
|
|
$sqlwhere[] = "t.doc_date < '" . $this->db->idate($value) . "'"; |
1115
|
|
|
} elseif ($key == 't.numero_compte>=') { |
1116
|
|
|
$sqlwhere[] = "t.numero_compte >= '" . $this->db->escape($value) . "'"; |
1117
|
|
|
} elseif ($key == 't.numero_compte<=') { |
1118
|
|
|
$sqlwhere[] = "t.numero_compte <= '" . $this->db->escape($value) . "'"; |
1119
|
|
|
} elseif ($key == 't.subledger_account>=') { |
1120
|
|
|
$sqlwhere[] = "t.subledger_account >= '" . $this->db->escape($value) . "'"; |
1121
|
|
|
} elseif ($key == 't.subledger_account<=') { |
1122
|
|
|
$sqlwhere[] = "t.subledger_account <= '" . $this->db->escape($value) . "'"; |
1123
|
|
|
} elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') { |
1124
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . ' = ' . ((int) $value); |
1125
|
|
|
} elseif ($key == 't.subledger_account' || $key == 't.numero_compte') { |
1126
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . ' LIKE \'' . $this->db->escape($value) . '%\''; |
1127
|
|
|
} elseif ($key == 't.date_creation>=') { |
1128
|
|
|
$sqlwhere[] = 't.date_creation >= \'' . $this->db->idate($value) . '\''; |
1129
|
|
|
} elseif ($key == 't.date_creation<=') { |
1130
|
|
|
$sqlwhere[] = 't.date_creation <= \'' . $this->db->idate($value) . '\''; |
1131
|
|
|
} elseif ($key == 't.tms>=') { |
1132
|
|
|
$sqlwhere[] = 't.tms >= \'' . $this->db->idate($value) . '\''; |
1133
|
|
|
} elseif ($key == 't.tms<=') { |
1134
|
|
|
$sqlwhere[] = 't.tms <= \'' . $this->db->idate($value) . '\''; |
1135
|
|
|
} elseif ($key == 't.date_export>=') { |
1136
|
|
|
$sqlwhere[] = 't.date_export >= \'' . $this->db->idate($value) . '\''; |
1137
|
|
|
} elseif ($key == 't.date_export<=') { |
1138
|
|
|
$sqlwhere[] = 't.date_export <= \'' . $this->db->idate($value) . '\''; |
1139
|
|
|
} elseif ($key == 't.date_validated>=') { |
1140
|
|
|
$sqlwhere[] = 't.date_validated >= \'' . $this->db->idate($value) . '\''; |
1141
|
|
|
} elseif ($key == 't.date_validated<=') { |
1142
|
|
|
$sqlwhere[] = 't.date_validated <= \'' . $this->db->idate($value) . '\''; |
1143
|
|
|
} elseif ($key == 't.credit' || $key == 't.debit') { |
1144
|
|
|
$sqlwhere[] = natural_search($key, $value, 1, 1); |
1145
|
|
|
} elseif ($key == 't.code_journal' && !empty($value)) { |
1146
|
|
|
if (is_array($value)) { |
1147
|
|
|
$sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1); |
1148
|
|
|
} else { |
1149
|
|
|
$sqlwhere[] = natural_search("t.code_journal", $value, 3, 1); |
1150
|
|
|
} |
1151
|
|
|
} else { |
1152
|
|
|
$sqlwhere[] = natural_search($key, $value, 0, 1); |
1153
|
|
|
} |
1154
|
|
|
} |
1155
|
|
|
} |
1156
|
|
|
if (count($sqlwhere) > 0) { |
1157
|
|
|
$sql .= ' AND ' . implode(" " . $this->db->sanitize($filtermode) . " ", $sqlwhere); |
1158
|
|
|
} |
1159
|
|
|
|
1160
|
|
|
$filter = ''; |
1161
|
|
|
} |
1162
|
|
|
|
1163
|
|
|
// Manage filter |
1164
|
|
|
$errormessage = ''; |
1165
|
|
|
$sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage); |
1166
|
|
|
if ($errormessage) { |
1167
|
|
|
$this->errors[] = $errormessage; |
1168
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1169
|
|
|
return -1; |
1170
|
|
|
} |
1171
|
|
|
|
1172
|
|
|
if (!empty($sortfield)) { |
1173
|
|
|
$sql .= $this->db->order($sortfield, $sortorder); |
1174
|
|
|
} |
1175
|
|
|
if (!empty($limit)) { |
1176
|
|
|
$sql .= $this->db->plimit($limit + 1, $offset); |
1177
|
|
|
} |
1178
|
|
|
$this->lines = array(); |
1179
|
|
|
|
1180
|
|
|
$resql = $this->db->query($sql); |
1181
|
|
|
if ($resql) { |
1182
|
|
|
$num = $this->db->num_rows($resql); |
1183
|
|
|
|
1184
|
|
|
$i = 0; |
1185
|
|
|
while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) { |
1186
|
|
|
$line = new BookKeepingLine($this->db); |
1187
|
|
|
|
1188
|
|
|
$line->id = $obj->rowid; |
1189
|
|
|
|
1190
|
|
|
$line->doc_date = $this->db->jdate($obj->doc_date); |
1191
|
|
|
$line->doc_type = $obj->doc_type; |
1192
|
|
|
$line->doc_ref = $obj->doc_ref; |
1193
|
|
|
$line->fk_doc = $obj->fk_doc; |
1194
|
|
|
$line->fk_docdet = $obj->fk_docdet; |
1195
|
|
|
$line->thirdparty_code = $obj->thirdparty_code; |
1196
|
|
|
$line->subledger_account = $obj->subledger_account; |
1197
|
|
|
$line->subledger_label = $obj->subledger_label; |
1198
|
|
|
$line->numero_compte = $obj->numero_compte; |
1199
|
|
|
$line->label_compte = $obj->label_compte; |
1200
|
|
|
$line->label_operation = $obj->label_operation; |
1201
|
|
|
$line->debit = $obj->debit; |
1202
|
|
|
$line->credit = $obj->credit; |
1203
|
|
|
$line->montant = $obj->amount; // deprecated |
|
|
|
|
1204
|
|
|
$line->amount = $obj->amount; |
1205
|
|
|
$line->sens = $obj->sens; |
1206
|
|
|
$line->lettering_code = $obj->lettering_code; |
1207
|
|
|
$line->date_lettering = $obj->date_lettering; |
1208
|
|
|
$line->fk_user_author = $obj->fk_user_author; |
1209
|
|
|
$line->import_key = $obj->import_key; |
1210
|
|
|
$line->code_journal = $obj->code_journal; |
1211
|
|
|
$line->journal_label = $obj->journal_label; |
1212
|
|
|
$line->piece_num = $obj->piece_num; |
1213
|
|
|
$line->date_creation = $this->db->jdate($obj->date_creation); |
1214
|
|
|
$line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement); |
1215
|
|
|
$line->date_modification = $this->db->jdate($obj->date_modification); |
1216
|
|
|
$line->date_export = $this->db->jdate($obj->date_export); |
1217
|
|
|
$line->date_validation = $this->db->jdate($obj->date_validation); |
1218
|
|
|
|
1219
|
|
|
$this->lines[] = $line; |
1220
|
|
|
|
1221
|
|
|
$i++; |
1222
|
|
|
} |
1223
|
|
|
$this->db->free($resql); |
1224
|
|
|
|
1225
|
|
|
return $num; |
1226
|
|
|
} else { |
1227
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
1228
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1229
|
|
|
return -1; |
1230
|
|
|
} |
1231
|
|
|
} |
1232
|
|
|
|
1233
|
|
|
/** |
1234
|
|
|
* Load object in memory from the database |
1235
|
|
|
* |
1236
|
|
|
* @param string $sortorder Sort Order |
1237
|
|
|
* @param string $sortfield Sort field |
1238
|
|
|
* @param int $limit Limit |
1239
|
|
|
* @param int $offset Offset limit |
1240
|
|
|
* @param string|array $filter Filter |
1241
|
|
|
* @param string $filtermode Filter mode (AND or OR) |
1242
|
|
|
* @param int $option option (0: aggregate by general account or 1: aggreegate by subaccount) |
1243
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1244
|
|
|
*/ |
1245
|
|
|
public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $option = 0) |
1246
|
|
|
{ |
1247
|
|
|
global $conf; |
1248
|
|
|
|
1249
|
|
|
$this->lines = array(); |
1250
|
|
|
|
1251
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
1252
|
|
|
|
1253
|
|
|
$sql = 'SELECT'; |
1254
|
|
|
$sql .= " t.numero_compte,"; |
1255
|
|
|
if (!empty($option)) { |
1256
|
|
|
$sql .= " t.subledger_account,"; |
1257
|
|
|
$sql .= " t.subledger_label,"; |
1258
|
|
|
} |
1259
|
|
|
$sql .= " SUM(t.debit) as debit,"; |
1260
|
|
|
$sql .= " SUM(t.credit) as credit"; |
1261
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; |
1262
|
|
|
$sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features |
1263
|
|
|
|
1264
|
|
|
// Manage filter |
1265
|
|
|
if (is_array($filter)) { |
1266
|
|
|
$sqlwhere = array(); |
1267
|
|
|
if (count($filter) > 0) { |
1268
|
|
|
foreach ($filter as $key => $value) { |
1269
|
|
|
if ($key == 't.doc_date') { |
1270
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . " = '" . $this->db->idate($value) . "'"; |
1271
|
|
|
} elseif ($key == 't.doc_date>=') { |
1272
|
|
|
$sqlwhere[] = "t.doc_date >= '" . $this->db->idate($value) . "'"; |
1273
|
|
|
} elseif ($key == 't.doc_date<=') { |
1274
|
|
|
$sqlwhere[] = "t.doc_date <= '" . $this->db->idate($value) . "'"; |
1275
|
|
|
} elseif ($key == 't.doc_date>') { |
1276
|
|
|
$sqlwhere[] = "t.doc_date > '" . $this->db->idate($value) . "'"; |
1277
|
|
|
} elseif ($key == 't.doc_date<') { |
1278
|
|
|
$sqlwhere[] = "t.doc_date < '" . $this->db->idate($value) . "'"; |
1279
|
|
|
} elseif ($key == 't.numero_compte>=') { |
1280
|
|
|
$sqlwhere[] = "t.numero_compte >= '" . $this->db->escape($value) . "'"; |
1281
|
|
|
} elseif ($key == 't.numero_compte<=') { |
1282
|
|
|
$sqlwhere[] = "t.numero_compte <= '" . $this->db->escape($value) . "'"; |
1283
|
|
|
} elseif ($key == 't.subledger_account>=') { |
1284
|
|
|
$sqlwhere[] = "t.subledger_account >= '" . $this->db->escape($value) . "'"; |
1285
|
|
|
} elseif ($key == 't.subledger_account<=') { |
1286
|
|
|
$sqlwhere[] = "t.subledger_account <= '" . $this->db->escape($value) . "'"; |
1287
|
|
|
} elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') { |
1288
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . " = " . ((int) $value); |
1289
|
|
|
} elseif ($key == 't.subledger_account' || $key == 't.numero_compte') { |
1290
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . " LIKE '" . $this->db->escape($value) . "%'"; |
1291
|
|
|
} elseif ($key == 't.subledger_label') { |
1292
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . " LIKE '" . $this->db->escape($value) . "%'"; |
1293
|
|
|
} elseif ($key == 't.code_journal' && !empty($value)) { |
1294
|
|
|
if (is_array($value)) { |
1295
|
|
|
$sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1); |
1296
|
|
|
} else { |
1297
|
|
|
$sqlwhere[] = natural_search("t.code_journal", $value, 3, 1); |
1298
|
|
|
} |
1299
|
|
|
} elseif ($key == 't.reconciled_option') { |
1300
|
|
|
$sqlwhere[] = 't.lettering_code IS NULL'; |
1301
|
|
|
} else { |
1302
|
|
|
$sqlwhere[] = $this->db->sanitize($key) . " LIKE '%" . $this->db->escape($this->db->escapeforlike($value)) . "%'"; |
1303
|
|
|
} |
1304
|
|
|
} |
1305
|
|
|
} |
1306
|
|
|
if (count($sqlwhere) > 0) { |
1307
|
|
|
$sql .= " AND " . implode(" " . $this->db->sanitize($filtermode) . " ", $sqlwhere); |
1308
|
|
|
} |
1309
|
|
|
|
1310
|
|
|
$filter = ''; |
1311
|
|
|
} |
1312
|
|
|
|
1313
|
|
|
// Manage filter |
1314
|
|
|
$errormessage = ''; |
1315
|
|
|
$sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage); |
1316
|
|
|
if ($errormessage) { |
1317
|
|
|
$this->errors[] = $errormessage; |
1318
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1319
|
|
|
return -1; |
1320
|
|
|
} |
1321
|
|
|
|
1322
|
|
|
if (!empty($option)) { |
1323
|
|
|
$sql .= " AND t.subledger_account IS NOT NULL"; |
1324
|
|
|
$sql .= " AND t.subledger_account <> ''"; |
1325
|
|
|
$sql .= " GROUP BY t.numero_compte, t.subledger_account, t.subledger_label"; |
1326
|
|
|
$sortfield = 't.subledger_account' . ($sortfield ? ',' . $sortfield : ''); |
1327
|
|
|
$sortorder = 'ASC' . ($sortfield ? ',' . $sortfield : ''); |
1328
|
|
|
} else { |
1329
|
|
|
$sql .= ' GROUP BY t.numero_compte'; |
1330
|
|
|
$sortfield = 't.numero_compte' . ($sortfield ? ',' . $sortfield : ''); |
1331
|
|
|
$sortorder = 'ASC' . ($sortorder ? ',' . $sortorder : ''); |
1332
|
|
|
} |
1333
|
|
|
|
1334
|
|
|
if (!empty($sortfield)) { |
1335
|
|
|
$sql .= $this->db->order($sortfield, $sortorder); |
1336
|
|
|
} |
1337
|
|
|
if (!empty($limit)) { |
1338
|
|
|
$sql .= $this->db->plimit($limit + 1, $offset); |
1339
|
|
|
} |
1340
|
|
|
|
1341
|
|
|
//print $sql; |
1342
|
|
|
$resql = $this->db->query($sql); |
1343
|
|
|
|
1344
|
|
|
if ($resql) { |
1345
|
|
|
$num = $this->db->num_rows($resql); |
1346
|
|
|
|
1347
|
|
|
$i = 0; |
1348
|
|
|
while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) { |
1349
|
|
|
$line = new BookKeepingLine($this->db); |
1350
|
|
|
|
1351
|
|
|
$line->numero_compte = $obj->numero_compte; |
1352
|
|
|
//$line->label_compte = $obj->label_compte; |
1353
|
|
|
if (!empty($option)) { |
1354
|
|
|
$line->subledger_account = $obj->subledger_account; |
1355
|
|
|
$line->subledger_label = $obj->subledger_label; |
1356
|
|
|
} |
1357
|
|
|
$line->debit = $obj->debit; |
1358
|
|
|
$line->credit = $obj->credit; |
1359
|
|
|
|
1360
|
|
|
$this->lines[] = $line; |
1361
|
|
|
|
1362
|
|
|
$i++; |
1363
|
|
|
} |
1364
|
|
|
$this->db->free($resql); |
1365
|
|
|
|
1366
|
|
|
return $num; |
1367
|
|
|
} else { |
1368
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
1369
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1370
|
|
|
|
1371
|
|
|
return -1; |
1372
|
|
|
} |
1373
|
|
|
} |
1374
|
|
|
|
1375
|
|
|
/** |
1376
|
|
|
* Update object into database |
1377
|
|
|
* |
1378
|
|
|
* @param User $user User that modifies |
1379
|
|
|
* @param int $notrigger false=launch triggers after, true=disable triggers |
1380
|
|
|
* @param string $mode Mode ('' or _tmp') |
1381
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1382
|
|
|
*/ |
1383
|
|
|
public function update(User $user, $notrigger = 0, $mode = '') |
1384
|
|
|
{ |
1385
|
|
|
global $langs; |
1386
|
|
|
$error = 0; |
1387
|
|
|
|
1388
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
1389
|
|
|
|
1390
|
|
|
// Clean parameters |
1391
|
|
|
if (isset($this->doc_type)) { |
1392
|
|
|
$this->doc_type = trim($this->doc_type); |
1393
|
|
|
} |
1394
|
|
|
if (isset($this->doc_ref)) { |
1395
|
|
|
$this->doc_ref = trim($this->doc_ref); |
1396
|
|
|
} |
1397
|
|
|
if (isset($this->fk_doc)) { |
1398
|
|
|
$this->fk_doc = (int) $this->fk_doc; |
1399
|
|
|
} |
1400
|
|
|
if (isset($this->fk_docdet)) { |
1401
|
|
|
$this->fk_docdet = (int) $this->fk_docdet; |
1402
|
|
|
} |
1403
|
|
|
if (isset($this->thirdparty_code)) { |
1404
|
|
|
$this->thirdparty_code = trim($this->thirdparty_code); |
1405
|
|
|
} |
1406
|
|
|
if (isset($this->subledger_account)) { |
1407
|
|
|
$this->subledger_account = trim($this->subledger_account); |
1408
|
|
|
} |
1409
|
|
|
if (isset($this->subledger_label)) { |
1410
|
|
|
$this->subledger_label = trim($this->subledger_label); |
1411
|
|
|
} |
1412
|
|
|
if (isset($this->numero_compte)) { |
1413
|
|
|
$this->numero_compte = trim($this->numero_compte); |
1414
|
|
|
} |
1415
|
|
|
if (isset($this->label_compte)) { |
1416
|
|
|
$this->label_compte = trim($this->label_compte); |
1417
|
|
|
} |
1418
|
|
|
if (isset($this->label_operation)) { |
1419
|
|
|
$this->label_operation = trim($this->label_operation); |
1420
|
|
|
} |
1421
|
|
|
if (isset($this->sens)) { |
1422
|
|
|
$this->sens = trim($this->sens); |
1423
|
|
|
} |
1424
|
|
|
if (isset($this->import_key)) { |
1425
|
|
|
$this->import_key = trim($this->import_key); |
1426
|
|
|
} |
1427
|
|
|
if (isset($this->code_journal)) { |
1428
|
|
|
$this->code_journal = trim($this->code_journal); |
1429
|
|
|
} |
1430
|
|
|
if (isset($this->journal_label)) { |
1431
|
|
|
$this->journal_label = trim($this->journal_label); |
1432
|
|
|
} |
1433
|
|
|
if (isset($this->piece_num)) { |
1434
|
|
|
$this->piece_num = (int) $this->piece_num; |
1435
|
|
|
} |
1436
|
|
|
|
1437
|
|
|
$result = $this->canModifyBookkeeping($this->id, $mode); |
1438
|
|
|
if ($result < 0) { |
1439
|
|
|
return -1; |
1440
|
|
|
} elseif ($result == 0) { |
1441
|
|
|
if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') { |
1442
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod'); |
1443
|
|
|
} else { |
1444
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod'); |
1445
|
|
|
} |
1446
|
|
|
return -1; |
1447
|
|
|
} |
1448
|
|
|
|
1449
|
|
|
$this->debit = (float) price2num($this->debit, 'MT'); |
1450
|
|
|
$this->credit = (float) price2num($this->credit, 'MT'); |
1451
|
|
|
$this->montant = (float) price2num($this->montant, 'MT'); |
1452
|
|
|
|
1453
|
|
|
// Check parameters |
1454
|
|
|
// Put here code to add a control on parameters values |
1455
|
|
|
|
1456
|
|
|
// Update request |
1457
|
|
|
$sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . $mode . ' SET'; |
1458
|
|
|
$sql .= ' doc_date = ' . (!isset($this->doc_date) || dol_strlen($this->doc_date) != 0 ? "'" . $this->db->idate($this->doc_date) . "'" : 'null') . ','; |
1459
|
|
|
$sql .= ' doc_type = ' . (isset($this->doc_type) ? "'" . $this->db->escape($this->doc_type) . "'" : "null") . ','; |
1460
|
|
|
$sql .= ' doc_ref = ' . (isset($this->doc_ref) ? "'" . $this->db->escape($this->doc_ref) . "'" : "null") . ','; |
1461
|
|
|
$sql .= ' fk_doc = ' . (isset($this->fk_doc) ? $this->fk_doc : "null") . ','; |
1462
|
|
|
$sql .= ' fk_docdet = ' . (isset($this->fk_docdet) ? $this->fk_docdet : "null") . ','; |
1463
|
|
|
$sql .= ' thirdparty_code = ' . (isset($this->thirdparty_code) ? "'" . $this->db->escape($this->thirdparty_code) . "'" : "null") . ','; |
1464
|
|
|
$sql .= ' subledger_account = ' . (isset($this->subledger_account) ? "'" . $this->db->escape($this->subledger_account) . "'" : "null") . ','; |
1465
|
|
|
$sql .= ' subledger_label = ' . (isset($this->subledger_label) ? "'" . $this->db->escape($this->subledger_label) . "'" : "null") . ','; |
1466
|
|
|
$sql .= ' numero_compte = ' . (isset($this->numero_compte) ? "'" . $this->db->escape($this->numero_compte) . "'" : "null") . ','; |
1467
|
|
|
$sql .= ' label_compte = ' . (isset($this->label_compte) ? "'" . $this->db->escape($this->label_compte) . "'" : "null") . ','; |
1468
|
|
|
$sql .= ' label_operation = ' . (isset($this->label_operation) ? "'" . $this->db->escape($this->label_operation) . "'" : "null") . ','; |
1469
|
|
|
$sql .= ' debit = ' . (isset($this->debit) ? $this->debit : "null") . ','; |
1470
|
|
|
$sql .= ' credit = ' . (isset($this->credit) ? $this->credit : "null") . ','; |
1471
|
|
|
$sql .= ' montant = ' . (isset($this->montant) ? $this->montant : "null") . ','; |
1472
|
|
|
$sql .= ' sens = ' . (isset($this->sens) ? "'" . $this->db->escape($this->sens) . "'" : "null") . ','; |
1473
|
|
|
$sql .= ' fk_user_author = ' . (isset($this->fk_user_author) ? $this->fk_user_author : "null") . ','; |
1474
|
|
|
$sql .= ' import_key = ' . (isset($this->import_key) ? "'" . $this->db->escape($this->import_key) . "'" : "null") . ','; |
1475
|
|
|
$sql .= ' code_journal = ' . (isset($this->code_journal) ? "'" . $this->db->escape($this->code_journal) . "'" : "null") . ','; |
1476
|
|
|
$sql .= ' journal_label = ' . (isset($this->journal_label) ? "'" . $this->db->escape($this->journal_label) . "'" : "null") . ','; |
1477
|
|
|
$sql .= ' piece_num = ' . (isset($this->piece_num) ? $this->piece_num : "null"); |
1478
|
|
|
$sql .= ' WHERE rowid=' . ((int) $this->id); |
1479
|
|
|
|
1480
|
|
|
$this->db->begin(); |
1481
|
|
|
|
1482
|
|
|
$resql = $this->db->query($sql); |
1483
|
|
|
if (!$resql) { |
1484
|
|
|
$error++; |
1485
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
1486
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1487
|
|
|
} |
1488
|
|
|
|
1489
|
|
|
// Uncomment this and change MYOBJECT to your own tag if you |
1490
|
|
|
// want this action calls a trigger. |
1491
|
|
|
//if (! $error && ! $notrigger) { |
1492
|
|
|
|
1493
|
|
|
// // Call triggers |
1494
|
|
|
// $result=$this->call_trigger('MYOBJECT_MODIFY',$user); |
1495
|
|
|
// if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail} |
1496
|
|
|
// // End call triggers |
1497
|
|
|
//} |
1498
|
|
|
|
1499
|
|
|
// Commit or rollback |
1500
|
|
|
if ($error) { |
1501
|
|
|
$this->db->rollback(); |
1502
|
|
|
|
1503
|
|
|
return -1 * $error; |
1504
|
|
|
} else { |
1505
|
|
|
$this->db->commit(); |
1506
|
|
|
|
1507
|
|
|
return 1; |
1508
|
|
|
} |
1509
|
|
|
} |
1510
|
|
|
|
1511
|
|
|
/** |
1512
|
|
|
* Update accounting movement |
1513
|
|
|
* |
1514
|
|
|
* @param string $piece_num Piece num |
1515
|
|
|
* @param string $field Field |
1516
|
|
|
* @param string $value Value |
1517
|
|
|
* @param string $mode Mode ('' or _tmp') |
1518
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1519
|
|
|
*/ |
1520
|
|
|
public function updateByMvt($piece_num = '', $field = '', $value = '', $mode = '') |
1521
|
|
|
{ |
1522
|
|
|
$error = 0; |
1523
|
|
|
|
1524
|
|
|
$sql_filter = $this->getCanModifyBookkeepingSQL(); |
1525
|
|
|
if (!isset($sql_filter)) { |
1526
|
|
|
return -1; |
1527
|
|
|
} |
1528
|
|
|
|
1529
|
|
|
$this->db->begin(); |
1530
|
|
|
|
1531
|
|
|
$sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . $mode; |
1532
|
|
|
$sql .= " SET " . $this->db->sanitize($field) . " = " . (is_numeric($value) ? ((float) $value) : "'" . $this->db->escape($value) . "'"); |
1533
|
|
|
$sql .= " WHERE piece_num = " . ((int) $piece_num); |
1534
|
|
|
$sql .= $sql_filter; |
1535
|
|
|
|
1536
|
|
|
$resql = $this->db->query($sql); |
1537
|
|
|
|
1538
|
|
|
if (!$resql) { |
1539
|
|
|
$error++; |
1540
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
1541
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1542
|
|
|
} |
1543
|
|
|
if ($error) { |
1544
|
|
|
$this->db->rollback(); |
1545
|
|
|
|
1546
|
|
|
return -1 * $error; |
1547
|
|
|
} else { |
1548
|
|
|
$this->db->commit(); |
1549
|
|
|
|
1550
|
|
|
return 1; |
1551
|
|
|
} |
1552
|
|
|
} |
1553
|
|
|
|
1554
|
|
|
/** |
1555
|
|
|
* Delete object in database |
1556
|
|
|
* |
1557
|
|
|
* @param User $user User that deletes |
1558
|
|
|
* @param int $notrigger 0=launch triggers after, 1=disable triggers |
1559
|
|
|
* @param string $mode Mode ('' or 'tmp_') |
1560
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1561
|
|
|
*/ |
1562
|
|
|
public function delete(User $user, $notrigger = 0, $mode = '') |
1563
|
|
|
{ |
1564
|
|
|
global $langs; |
1565
|
|
|
|
1566
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
1567
|
|
|
|
1568
|
|
|
$result = $this->canModifyBookkeeping($this->id, $mode); |
1569
|
|
|
if ($result < 0) { |
1570
|
|
|
return -1; |
1571
|
|
|
} elseif ($result == 0) { |
1572
|
|
|
if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') { |
1573
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod'); |
1574
|
|
|
} else { |
1575
|
|
|
$this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod'); |
1576
|
|
|
} |
1577
|
|
|
return -1; |
1578
|
|
|
} |
1579
|
|
|
|
1580
|
|
|
$error = 0; |
1581
|
|
|
|
1582
|
|
|
$this->db->begin(); |
1583
|
|
|
|
1584
|
|
|
// Uncomment this and change MYOBJECT to your own tag if you |
1585
|
|
|
// want this action calls a trigger. |
1586
|
|
|
//if (! $error && ! $notrigger) { |
1587
|
|
|
|
1588
|
|
|
// // Call triggers |
1589
|
|
|
// $result=$this->call_trigger('MYOBJECT_DELETE',$user); |
1590
|
|
|
// if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail} |
1591
|
|
|
// // End call triggers |
1592
|
|
|
//} |
1593
|
|
|
|
1594
|
|
|
if (!$error) { |
1595
|
|
|
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . $mode; |
1596
|
|
|
$sql .= ' WHERE rowid=' . ((int) $this->id); |
1597
|
|
|
|
1598
|
|
|
$resql = $this->db->query($sql); |
1599
|
|
|
if (!$resql) { |
1600
|
|
|
$error++; |
1601
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
1602
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1603
|
|
|
} |
1604
|
|
|
} |
1605
|
|
|
|
1606
|
|
|
// Commit or rollback |
1607
|
|
|
if ($error) { |
1608
|
|
|
$this->db->rollback(); |
1609
|
|
|
|
1610
|
|
|
return -1 * $error; |
1611
|
|
|
} else { |
1612
|
|
|
$this->db->commit(); |
1613
|
|
|
|
1614
|
|
|
return 1; |
1615
|
|
|
} |
1616
|
|
|
} |
1617
|
|
|
|
1618
|
|
|
/** |
1619
|
|
|
* Delete bookkeeping by importkey |
1620
|
|
|
* |
1621
|
|
|
* @param string $importkey Import key |
1622
|
|
|
* @param string $mode Mode |
1623
|
|
|
* @return int Result |
1624
|
|
|
*/ |
1625
|
|
|
public function deleteByImportkey($importkey, $mode = '') |
1626
|
|
|
{ |
1627
|
|
|
$this->db->begin(); |
1628
|
|
|
|
1629
|
|
|
$sql_filter = $this->getCanModifyBookkeepingSQL(); |
1630
|
|
|
if (!isset($sql_filter)) { |
1631
|
|
|
return -1; |
1632
|
|
|
} |
1633
|
|
|
|
1634
|
|
|
// first check if line not yet in bookkeeping |
1635
|
|
|
$sql = "DELETE"; |
1636
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode; |
1637
|
|
|
$sql .= " WHERE import_key = '" . $this->db->escape($importkey) . "'"; |
1638
|
|
|
$sql .= $sql_filter; |
1639
|
|
|
|
1640
|
|
|
$resql = $this->db->query($sql); |
1641
|
|
|
|
1642
|
|
|
if (!$resql) { |
1643
|
|
|
$this->errors[] = "Error " . $this->db->lasterror(); |
1644
|
|
|
dol_syslog(get_only_class($this) . "::delete Error " . $this->db->lasterror(), LOG_ERR); |
1645
|
|
|
$this->db->rollback(); |
1646
|
|
|
return -1; |
1647
|
|
|
} |
1648
|
|
|
|
1649
|
|
|
$this->db->commit(); |
1650
|
|
|
return 1; |
1651
|
|
|
} |
1652
|
|
|
|
1653
|
|
|
/** |
1654
|
|
|
* Delete bookkeeping by year |
1655
|
|
|
* |
1656
|
|
|
* @param int $delyear Year to delete |
1657
|
|
|
* @param string $journal Journal to delete |
1658
|
|
|
* @param string $mode Mode |
1659
|
|
|
* @param int $delmonth Month |
1660
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1661
|
|
|
*/ |
1662
|
|
|
public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0) |
1663
|
|
|
{ |
1664
|
|
|
global $conf, $langs; |
1665
|
|
|
|
1666
|
|
|
if (empty($delyear) && empty($journal)) { |
1667
|
|
|
$this->error = 'ErrorOneFieldRequired'; |
1668
|
|
|
return -1; |
1669
|
|
|
} |
1670
|
|
|
if (!empty($delmonth) && empty($delyear)) { |
1671
|
|
|
$this->error = 'YearRequiredIfMonthDefined'; |
1672
|
|
|
return -2; |
1673
|
|
|
} |
1674
|
|
|
|
1675
|
|
|
$sql_filter = $this->getCanModifyBookkeepingSQL(); |
1676
|
|
|
if (!isset($sql_filter)) { |
1677
|
|
|
return -1; |
1678
|
|
|
} |
1679
|
|
|
|
1680
|
|
|
$this->db->begin(); |
1681
|
|
|
|
1682
|
|
|
// Delete record in bookkeeping |
1683
|
|
|
$sql = "DELETE"; |
1684
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode; |
1685
|
|
|
$sql .= " WHERE 1 = 1"; |
1686
|
|
|
$sql .= dolSqlDateFilter('doc_date', 0, $delmonth, $delyear); |
1687
|
|
|
if (!empty($journal)) { |
1688
|
|
|
$sql .= " AND code_journal = '" . $this->db->escape($journal) . "'"; |
1689
|
|
|
} |
1690
|
|
|
$sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
1691
|
|
|
// Exclusion of validated entries at the time of deletion |
1692
|
|
|
$sql .= " AND date_validated IS NULL"; |
1693
|
|
|
$sql .= $sql_filter; |
1694
|
|
|
|
1695
|
|
|
// TODO: In a future we must forbid deletion if record is inside a closed fiscal period. |
1696
|
|
|
|
1697
|
|
|
$resql = $this->db->query($sql); |
1698
|
|
|
|
1699
|
|
|
if (!$resql) { |
1700
|
|
|
$this->errors[] = "Error " . $this->db->lasterror(); |
1701
|
|
|
foreach ($this->errors as $errmsg) { |
1702
|
|
|
dol_syslog(get_only_class($this) . "::delete " . $errmsg, LOG_ERR); |
1703
|
|
|
$this->error .= ($this->error ? ', ' . $errmsg : $errmsg); |
1704
|
|
|
} |
1705
|
|
|
$this->db->rollback(); |
1706
|
|
|
return -1; |
1707
|
|
|
} |
1708
|
|
|
|
1709
|
|
|
$this->db->commit(); |
1710
|
|
|
return 1; |
1711
|
|
|
} |
1712
|
|
|
|
1713
|
|
|
/** |
1714
|
|
|
* Delete bookkeeping by piece number |
1715
|
|
|
* |
1716
|
|
|
* @param int $piecenum Piecenum to delete |
1717
|
|
|
* @param string $mode Mode ('' or '_tmp') |
1718
|
|
|
* @return int Result |
1719
|
|
|
*/ |
1720
|
|
|
public function deleteMvtNum($piecenum, $mode = '') |
1721
|
|
|
{ |
1722
|
|
|
global $conf; |
1723
|
|
|
|
1724
|
|
|
$sql_filter = $this->getCanModifyBookkeepingSQL(); |
1725
|
|
|
if (!isset($sql_filter)) { |
1726
|
|
|
return -1; |
1727
|
|
|
} |
1728
|
|
|
|
1729
|
|
|
$this->db->begin(); |
1730
|
|
|
|
1731
|
|
|
// first check if line not yet in bookkeeping |
1732
|
|
|
$sql = "DELETE"; |
1733
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode; |
1734
|
|
|
$sql .= " WHERE piece_num = " . (int) $piecenum; |
1735
|
|
|
$sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion |
1736
|
|
|
$sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
1737
|
|
|
$sql .= $sql_filter; |
1738
|
|
|
|
1739
|
|
|
$resql = $this->db->query($sql); |
1740
|
|
|
|
1741
|
|
|
if (!$resql) { |
1742
|
|
|
$this->errors[] = "Error " . $this->db->lasterror(); |
1743
|
|
|
foreach ($this->errors as $errmsg) { |
1744
|
|
|
dol_syslog(get_only_class($this) . "::delete " . $errmsg, LOG_ERR); |
1745
|
|
|
$this->error .= ($this->error ? ', ' . $errmsg : $errmsg); |
1746
|
|
|
} |
1747
|
|
|
$this->db->rollback(); |
1748
|
|
|
return -1; |
1749
|
|
|
} |
1750
|
|
|
|
1751
|
|
|
$this->db->commit(); |
1752
|
|
|
return 1; |
1753
|
|
|
} |
1754
|
|
|
|
1755
|
|
|
/** |
1756
|
|
|
* Load an object from its id and create a new one in database |
1757
|
|
|
* |
1758
|
|
|
* @param User $user User making the clone |
1759
|
|
|
* @param int $fromid Id of object to clone |
1760
|
|
|
* @return int New id of clone |
1761
|
|
|
*/ |
1762
|
|
|
public function createFromClone(User $user, $fromid) |
1763
|
|
|
{ |
1764
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
1765
|
|
|
|
1766
|
|
|
$error = 0; |
1767
|
|
|
$object = new BookKeeping($this->db); |
1768
|
|
|
|
1769
|
|
|
$this->db->begin(); |
1770
|
|
|
|
1771
|
|
|
// Load source object |
1772
|
|
|
$object->fetch($fromid); |
1773
|
|
|
// Reset object |
1774
|
|
|
$object->id = 0; |
1775
|
|
|
|
1776
|
|
|
// Clear fields |
1777
|
|
|
// ... |
1778
|
|
|
|
1779
|
|
|
// Create clone |
1780
|
|
|
$object->context['createfromclone'] = 'createfromclone'; |
1781
|
|
|
$result = $object->create($user); |
1782
|
|
|
|
1783
|
|
|
// Other options |
1784
|
|
|
if ($result < 0) { |
1785
|
|
|
$error++; |
1786
|
|
|
$this->errors = $object->errors; |
1787
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
1788
|
|
|
} |
1789
|
|
|
|
1790
|
|
|
unset($object->context['createfromclone']); |
1791
|
|
|
|
1792
|
|
|
// End |
1793
|
|
|
if (!$error) { |
1794
|
|
|
$this->db->commit(); |
1795
|
|
|
|
1796
|
|
|
return $object->id; |
1797
|
|
|
} else { |
1798
|
|
|
$this->db->rollback(); |
1799
|
|
|
|
1800
|
|
|
return -1; |
1801
|
|
|
} |
1802
|
|
|
} |
1803
|
|
|
|
1804
|
|
|
/** |
1805
|
|
|
* Initialise object with example values |
1806
|
|
|
* Id must be 0 if object instance is a specimen |
1807
|
|
|
* |
1808
|
|
|
* @return int |
1809
|
|
|
*/ |
1810
|
|
|
public function initAsSpecimen() |
1811
|
|
|
{ |
1812
|
|
|
global $user; |
1813
|
|
|
|
1814
|
|
|
$now = dol_now(); |
1815
|
|
|
|
1816
|
|
|
$this->id = 0; |
1817
|
|
|
$this->doc_date = $now; |
1818
|
|
|
$this->doc_type = ''; |
1819
|
|
|
$this->doc_ref = ''; |
1820
|
|
|
$this->fk_doc = 0; |
1821
|
|
|
$this->fk_docdet = 0; |
1822
|
|
|
$this->thirdparty_code = 'CU001'; |
1823
|
|
|
$this->subledger_account = '41100001'; |
1824
|
|
|
$this->subledger_label = 'My customer company'; |
1825
|
|
|
$this->numero_compte = '411'; |
1826
|
|
|
$this->label_compte = 'Customer'; |
1827
|
|
|
$this->label_operation = 'Sales of pea'; |
1828
|
|
|
$this->debit = 99.9; |
1829
|
|
|
$this->credit = 0.0; |
1830
|
|
|
$this->amount = 0.0; |
|
|
|
|
1831
|
|
|
$this->sens = 'D'; |
1832
|
|
|
$this->fk_user_author = $user->id; |
1833
|
|
|
$this->import_key = '20201027'; |
1834
|
|
|
$this->code_journal = 'VT'; |
1835
|
|
|
$this->journal_label = 'Journal de vente'; |
1836
|
|
|
$this->piece_num = 1234; |
1837
|
|
|
$this->date_creation = $now; |
1838
|
|
|
|
1839
|
|
|
return 1; |
1840
|
|
|
} |
1841
|
|
|
|
1842
|
|
|
/** |
1843
|
|
|
* Load an accounting document into memory from database |
1844
|
|
|
* |
1845
|
|
|
* @param int $piecenum Accounting document to get |
1846
|
|
|
* @param string $mode Mode |
1847
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1848
|
|
|
*/ |
1849
|
|
|
public function fetchPerMvt($piecenum, $mode = '') |
1850
|
|
|
{ |
1851
|
|
|
global $conf; |
1852
|
|
|
|
1853
|
|
|
$sql = "SELECT piece_num, doc_date, code_journal, journal_label, doc_ref, doc_type,"; |
1854
|
|
|
$sql .= " date_creation, tms as date_modification, date_validated as date_validation, date_lim_reglement, import_key"; |
1855
|
|
|
// In llx_accounting_bookkeeping_tmp, field date_export doesn't exist |
1856
|
|
|
if ($mode != "_tmp") { |
1857
|
|
|
$sql .= ", date_export"; |
1858
|
|
|
} |
1859
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode; |
1860
|
|
|
$sql .= " WHERE piece_num = " . ((int) $piecenum); |
1861
|
|
|
$sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
1862
|
|
|
|
1863
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
1864
|
|
|
$result = $this->db->query($sql); |
1865
|
|
|
if ($result) { |
1866
|
|
|
$obj = $this->db->fetch_object($result); |
1867
|
|
|
|
1868
|
|
|
$this->piece_num = $obj->piece_num; |
1869
|
|
|
$this->code_journal = $obj->code_journal; |
1870
|
|
|
$this->journal_label = $obj->journal_label; |
1871
|
|
|
$this->doc_date = $this->db->jdate($obj->doc_date); |
|
|
|
|
1872
|
|
|
$this->doc_ref = $obj->doc_ref; |
1873
|
|
|
$this->doc_type = $obj->doc_type; |
1874
|
|
|
$this->date_creation = $this->db->jdate($obj->date_creation); |
1875
|
|
|
$this->date_modification = $this->db->jdate($obj->date_modification); |
1876
|
|
|
if ($mode != "_tmp") { |
1877
|
|
|
$this->date_export = $this->db->jdate($obj->date_export); |
1878
|
|
|
} |
1879
|
|
|
$this->date_validation = $this->db->jdate($obj->date_validation); |
1880
|
|
|
$this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement); |
|
|
|
|
1881
|
|
|
$this->import_key = $obj->import_key; |
1882
|
|
|
} else { |
1883
|
|
|
$this->error = "Error " . $this->db->lasterror(); |
1884
|
|
|
dol_syslog(__METHOD__ . $this->error, LOG_ERR); |
1885
|
|
|
return -1; |
1886
|
|
|
} |
1887
|
|
|
|
1888
|
|
|
return 1; |
1889
|
|
|
} |
1890
|
|
|
|
1891
|
|
|
/** |
1892
|
|
|
* Return next movement number |
1893
|
|
|
* |
1894
|
|
|
* @param string $mode Mode |
1895
|
|
|
* @return int<1, max>|-1 Return next movement number or -1 if error |
1896
|
|
|
*/ |
1897
|
|
|
public function getNextNumMvt($mode = '') |
1898
|
|
|
{ |
1899
|
|
|
global $conf; |
1900
|
|
|
|
1901
|
|
|
$sql = "SELECT MAX(piece_num)+1 as max FROM " . MAIN_DB_PREFIX . $this->table_element . $mode; |
1902
|
|
|
$sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
1903
|
|
|
|
1904
|
|
|
dol_syslog(get_only_class($this) . "::getNextNumMvt", LOG_DEBUG); |
1905
|
|
|
|
1906
|
|
|
$result = $this->db->query($sql); |
1907
|
|
|
|
1908
|
|
|
if ($result) { |
1909
|
|
|
$obj = $this->db->fetch_object($result); |
1910
|
|
|
if ($obj) { |
1911
|
|
|
$result = $obj->max; |
1912
|
|
|
} |
1913
|
|
|
if (empty($result)) { |
1914
|
|
|
$result = 1; |
1915
|
|
|
} |
1916
|
|
|
return $result; |
1917
|
|
|
} else { |
1918
|
|
|
$this->error = "Error " . $this->db->lasterror(); |
1919
|
|
|
dol_syslog(get_only_class($this) . "::getNextNumMvt " . $this->error, LOG_ERR); |
1920
|
|
|
return -1; |
1921
|
|
|
} |
1922
|
|
|
} |
1923
|
|
|
|
1924
|
|
|
/** |
1925
|
|
|
* Load all accounting lines related to a given transaction ID $piecenum |
1926
|
|
|
* |
1927
|
|
|
* @param int $piecenum Id of line to get |
1928
|
|
|
* @param string $mode Mode ('' or '_tmp') |
1929
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
1930
|
|
|
*/ |
1931
|
|
|
public function fetchAllPerMvt($piecenum, $mode = '') |
1932
|
|
|
{ |
1933
|
|
|
global $conf; |
1934
|
|
|
|
1935
|
|
|
$sql = "SELECT rowid, doc_date, doc_type,"; |
1936
|
|
|
$sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,"; |
1937
|
|
|
$sql .= " numero_compte, label_compte, label_operation, debit, credit,"; |
1938
|
|
|
$sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, journal_label, piece_num,"; |
1939
|
|
|
$sql .= " date_creation, tms as date_modification, date_validated as date_validation"; |
1940
|
|
|
// In llx_accounting_bookkeeping_tmp, field date_export doesn't exist |
1941
|
|
|
if ($mode != "_tmp") { |
1942
|
|
|
$sql .= ", date_export"; |
1943
|
|
|
} |
1944
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . $mode; |
1945
|
|
|
$sql .= " WHERE piece_num = " . ((int) $piecenum); |
1946
|
|
|
$sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
1947
|
|
|
|
1948
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
1949
|
|
|
$result = $this->db->query($sql); |
1950
|
|
|
if ($result) { |
1951
|
|
|
while ($obj = $this->db->fetch_object($result)) { |
1952
|
|
|
$line = new BookKeepingLine($this->db); |
1953
|
|
|
|
1954
|
|
|
$line->id = $obj->rowid; |
1955
|
|
|
|
1956
|
|
|
$line->doc_date = $this->db->jdate($obj->doc_date); |
1957
|
|
|
$line->doc_type = $obj->doc_type; |
1958
|
|
|
$line->doc_ref = $obj->doc_ref; |
1959
|
|
|
$line->fk_doc = $obj->fk_doc; |
1960
|
|
|
$line->fk_docdet = $obj->fk_docdet; |
1961
|
|
|
$line->thirdparty_code = $obj->thirdparty_code; |
1962
|
|
|
$line->subledger_account = $obj->subledger_account; |
1963
|
|
|
$line->subledger_label = $obj->subledger_label; |
1964
|
|
|
$line->numero_compte = $obj->numero_compte; |
1965
|
|
|
$line->label_compte = $obj->label_compte; |
1966
|
|
|
$line->label_operation = $obj->label_operation; |
1967
|
|
|
$line->debit = $obj->debit; |
1968
|
|
|
$line->credit = $obj->credit; |
1969
|
|
|
$line->montant = $obj->amount; |
|
|
|
|
1970
|
|
|
$line->amount = $obj->amount; |
1971
|
|
|
$line->sens = $obj->sens; |
1972
|
|
|
$line->code_journal = $obj->code_journal; |
1973
|
|
|
$line->journal_label = $obj->journal_label; |
1974
|
|
|
$line->piece_num = $obj->piece_num; |
1975
|
|
|
$line->date_creation = $obj->date_creation; |
1976
|
|
|
$line->date_modification = $obj->date_modification; |
1977
|
|
|
if ($mode != "_tmp") { |
1978
|
|
|
$line->date_export = $obj->date_export; |
1979
|
|
|
} |
1980
|
|
|
$line->date_validation = $obj->date_validation; |
1981
|
|
|
|
1982
|
|
|
$this->linesmvt[] = $line; |
1983
|
|
|
} |
1984
|
|
|
} else { |
1985
|
|
|
$this->error = "Error " . $this->db->lasterror(); |
1986
|
|
|
dol_syslog(__METHOD__ . $this->error, LOG_ERR); |
1987
|
|
|
return -1; |
1988
|
|
|
} |
1989
|
|
|
|
1990
|
|
|
return 1; |
1991
|
|
|
} |
1992
|
|
|
|
1993
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
1994
|
|
|
/** |
1995
|
|
|
* Export bookkeeping |
1996
|
|
|
* |
1997
|
|
|
* @param string $model Model |
1998
|
|
|
* @return int Result |
1999
|
|
|
*/ |
2000
|
|
|
public function export_bookkeeping($model = 'ebp') |
2001
|
|
|
{ |
2002
|
|
|
// phpcs:enable |
2003
|
|
|
global $conf; |
2004
|
|
|
|
2005
|
|
|
$sql = "SELECT rowid, doc_date, doc_type,"; |
2006
|
|
|
$sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,"; |
2007
|
|
|
$sql .= " numero_compte, label_compte, label_operation, debit, credit,"; |
2008
|
|
|
$sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,"; |
2009
|
|
|
$sql .= " date_validated as date_validation"; |
2010
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element; |
2011
|
|
|
$sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
2012
|
|
|
|
2013
|
|
|
dol_syslog(get_only_class($this) . "::export_bookkeeping", LOG_DEBUG); |
2014
|
|
|
|
2015
|
|
|
$resql = $this->db->query($sql); |
2016
|
|
|
|
2017
|
|
|
if ($resql) { |
2018
|
|
|
$this->linesexport = array(); |
2019
|
|
|
|
2020
|
|
|
$num = $this->db->num_rows($resql); |
2021
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2022
|
|
|
$line = new BookKeepingLine($this->db); |
2023
|
|
|
|
2024
|
|
|
$line->id = $obj->rowid; |
2025
|
|
|
|
2026
|
|
|
$line->doc_date = $this->db->jdate($obj->doc_date); |
2027
|
|
|
$line->doc_type = $obj->doc_type; |
2028
|
|
|
$line->doc_ref = $obj->doc_ref; |
2029
|
|
|
$line->fk_doc = $obj->fk_doc; |
2030
|
|
|
$line->fk_docdet = $obj->fk_docdet; |
2031
|
|
|
$line->thirdparty_code = $obj->thirdparty_code; |
2032
|
|
|
$line->subledger_account = $obj->subledger_account; |
2033
|
|
|
$line->subledger_label = $obj->subledger_label; |
2034
|
|
|
$line->numero_compte = $obj->numero_compte; |
2035
|
|
|
$line->label_compte = $obj->label_compte; |
2036
|
|
|
$line->label_operation = $obj->label_operation; |
2037
|
|
|
$line->debit = $obj->debit; |
2038
|
|
|
$line->credit = $obj->credit; |
2039
|
|
|
$line->montant = $obj->amount; |
|
|
|
|
2040
|
|
|
$line->amount = $obj->amount; |
2041
|
|
|
$line->sens = $obj->sens; |
2042
|
|
|
$line->code_journal = $obj->code_journal; |
2043
|
|
|
$line->piece_num = $obj->piece_num; |
2044
|
|
|
$line->date_validation = $obj->date_validation; |
2045
|
|
|
|
2046
|
|
|
$this->linesexport[] = $line; |
2047
|
|
|
} |
2048
|
|
|
$this->db->free($resql); |
2049
|
|
|
|
2050
|
|
|
return $num; |
2051
|
|
|
} else { |
2052
|
|
|
$this->error = "Error " . $this->db->lasterror(); |
2053
|
|
|
dol_syslog(get_only_class($this) . "::export_bookkeeping " . $this->error, LOG_ERR); |
2054
|
|
|
return -1; |
2055
|
|
|
} |
2056
|
|
|
} |
2057
|
|
|
|
2058
|
|
|
/** |
2059
|
|
|
* Transform transaction |
2060
|
|
|
* |
2061
|
|
|
* @param int $direction If 0: tmp => real, if 1: real => tmp |
2062
|
|
|
* @param string $piece_num Piece num = Transaction ref |
2063
|
|
|
* @return int int Return integer <0 if KO, >0 if OK |
2064
|
|
|
*/ |
2065
|
|
|
public function transformTransaction($direction = 0, $piece_num = '') |
2066
|
|
|
{ |
2067
|
|
|
global $conf; |
2068
|
|
|
|
2069
|
|
|
$error = 0; |
2070
|
|
|
|
2071
|
|
|
$sql_filter = $this->getCanModifyBookkeepingSQL(); |
2072
|
|
|
|
2073
|
|
|
if (!isset($sql_filter)) { |
2074
|
|
|
return -1; |
2075
|
|
|
} |
2076
|
|
|
|
2077
|
|
|
$this->db->begin(); |
2078
|
|
|
|
2079
|
|
|
if ($direction == 0) { |
2080
|
|
|
$next_piecenum = $this->getNextNumMvt(); |
2081
|
|
|
$now = dol_now(); |
2082
|
|
|
|
2083
|
|
|
if ($next_piecenum < 0) { |
2084
|
|
|
$error++; |
2085
|
|
|
} |
2086
|
|
|
|
2087
|
|
|
if (!$error) { |
2088
|
|
|
// Delete if there is an empty line |
2089
|
|
|
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity) . " AND numero_compte IS NULL AND debit = 0 AND credit = 0"; |
2090
|
|
|
$resql = $this->db->query($sql); |
2091
|
|
|
if (!$resql) { |
2092
|
|
|
$error++; |
2093
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2094
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2095
|
|
|
} |
2096
|
|
|
} |
2097
|
|
|
|
2098
|
|
|
if (!$error) { |
2099
|
|
|
$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . ' (doc_date, doc_type,'; |
2100
|
|
|
$sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,'; |
2101
|
|
|
$sql .= ' numero_compte, label_compte, label_operation, debit, credit,'; |
2102
|
|
|
$sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num, date_creation)'; |
2103
|
|
|
$sql .= ' SELECT doc_date, doc_type,'; |
2104
|
|
|
$sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,'; |
2105
|
|
|
$sql .= ' numero_compte, label_compte, label_operation, debit, credit,'; |
2106
|
|
|
$sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, ' . ((int) $next_piecenum) . ", '" . $this->db->idate($now) . "'"; |
2107
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND numero_compte IS NOT NULL AND entity = ' . ((int) $conf->entity); |
2108
|
|
|
$sql .= $sql_filter; |
2109
|
|
|
$resql = $this->db->query($sql); |
2110
|
|
|
if (!$resql) { |
2111
|
|
|
$error++; |
2112
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2113
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2114
|
|
|
} |
2115
|
|
|
} |
2116
|
|
|
|
2117
|
|
|
if (!$error) { |
2118
|
|
|
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity); |
2119
|
|
|
$resql = $this->db->query($sql); |
2120
|
|
|
if (!$resql) { |
2121
|
|
|
$error++; |
2122
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2123
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2124
|
|
|
} |
2125
|
|
|
} |
2126
|
|
|
} elseif ($direction == 1) { |
2127
|
|
|
if (!$error) { |
2128
|
|
|
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity); |
2129
|
|
|
$resql = $this->db->query($sql); |
2130
|
|
|
if (!$resql) { |
2131
|
|
|
$error++; |
2132
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2133
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2134
|
|
|
} |
2135
|
|
|
} |
2136
|
|
|
|
2137
|
|
|
if (!$error) { |
2138
|
|
|
$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '_tmp (doc_date, doc_type,'; |
2139
|
|
|
$sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,'; |
2140
|
|
|
$sql .= ' numero_compte, label_compte, label_operation, debit, credit,'; |
2141
|
|
|
$sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num)'; |
2142
|
|
|
$sql .= ' SELECT doc_date, doc_type,'; |
2143
|
|
|
$sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,'; |
2144
|
|
|
$sql .= ' numero_compte, label_compte, label_operation, debit, credit,'; |
2145
|
|
|
$sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num'; |
2146
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity); |
2147
|
|
|
$sql .= $sql_filter; |
2148
|
|
|
$resql = $this->db->query($sql); |
2149
|
|
|
if (!$resql) { |
2150
|
|
|
$error++; |
2151
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2152
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2153
|
|
|
} |
2154
|
|
|
} |
2155
|
|
|
|
2156
|
|
|
if (!$error) { |
2157
|
|
|
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . '_tmp WHERE piece_num = ' . ((int) $piece_num) . ' AND entity = ' . ((int) $conf->entity); |
2158
|
|
|
$sql .= $sql_filter; |
2159
|
|
|
$resql = $this->db->query($sql); |
2160
|
|
|
if (!$resql) { |
2161
|
|
|
$error++; |
2162
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2163
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2164
|
|
|
} |
2165
|
|
|
} |
2166
|
|
|
} |
2167
|
|
|
if (!$error) { |
2168
|
|
|
$this->db->commit(); |
2169
|
|
|
return 1; |
2170
|
|
|
} else { |
2171
|
|
|
$this->db->rollback(); |
2172
|
|
|
return -1; |
2173
|
|
|
} |
2174
|
|
|
/* |
2175
|
|
|
$sql = "DELETE FROM "; |
2176
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab"; |
2177
|
|
|
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte"; |
2178
|
|
|
$sql .= " AND aa.active = 1"; |
2179
|
|
|
$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version"; |
2180
|
|
|
$sql .= " AND asy.rowid = " . ((int) $pcgver); |
2181
|
|
|
$sql .= " AND ab.entity IN (" . getEntity('accountancy') . ")"; |
2182
|
|
|
$sql .= " ORDER BY account_number ASC"; |
2183
|
|
|
*/ |
2184
|
|
|
} |
2185
|
|
|
|
2186
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
2187
|
|
|
/** |
2188
|
|
|
* Return list of accounts with label by chart of accounts |
2189
|
|
|
* |
2190
|
|
|
* @param string $selectid Preselected chart of accounts |
2191
|
|
|
* @param string $htmlname Name of field in html form |
2192
|
|
|
* @param int $showempty Add an empty field |
2193
|
|
|
* @param array $event Event options |
2194
|
|
|
* @param int $select_in Value is a aa.rowid (0 default) or aa.account_number (1) |
2195
|
|
|
* @param int $select_out Set value returned by select 0=rowid (default), 1=account_number |
2196
|
|
|
* @param string $aabase Set accounting_account base class to display empty=all or from 1 to 8 will display only account beginning by this number |
2197
|
|
|
* @return string|int String with HTML select or -1 if KO |
2198
|
|
|
*/ |
2199
|
|
|
public function select_account($selectid, $htmlname = 'account', $showempty = 0, $event = array(), $select_in = 0, $select_out = 0, $aabase = '') |
2200
|
|
|
{ |
2201
|
|
|
// phpcs:enable |
2202
|
|
|
global $conf; |
2203
|
|
|
|
2204
|
|
|
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/accounting.lib.php'; |
2205
|
|
|
|
2206
|
|
|
$pcgver = getDolGlobalInt('CHARTOFACCOUNTS'); |
2207
|
|
|
|
2208
|
|
|
$sql = "SELECT DISTINCT ab.numero_compte as account_number, aa.label as label, aa.rowid as rowid, aa.fk_pcg_version"; |
2209
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab"; |
2210
|
|
|
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte"; |
2211
|
|
|
$sql .= " AND aa.active = 1"; |
2212
|
|
|
$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version"; |
2213
|
|
|
$sql .= " AND asy.rowid = " . ((int) $pcgver); |
2214
|
|
|
$sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
2215
|
|
|
$sql .= " ORDER BY account_number ASC"; |
2216
|
|
|
|
2217
|
|
|
dol_syslog(get_only_class($this) . "::select_account", LOG_DEBUG); |
2218
|
|
|
$resql = $this->db->query($sql); |
2219
|
|
|
|
2220
|
|
|
if (!$resql) { |
2221
|
|
|
$this->error = "Error " . $this->db->lasterror(); |
2222
|
|
|
dol_syslog(get_only_class($this) . "::select_account " . $this->error, LOG_ERR); |
2223
|
|
|
return "-1"; |
2224
|
|
|
} |
2225
|
|
|
|
2226
|
|
|
$out = ajax_combobox($htmlname, $event); |
2227
|
|
|
|
2228
|
|
|
$options = array(); |
2229
|
|
|
$selected = null; |
2230
|
|
|
|
2231
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2232
|
|
|
$label = length_accountg($obj->account_number) . ' - ' . $obj->label; |
2233
|
|
|
|
2234
|
|
|
$select_value_in = $obj->rowid; |
2235
|
|
|
$select_value_out = $obj->rowid; |
2236
|
|
|
|
2237
|
|
|
if ($select_in == 1) { |
2238
|
|
|
$select_value_in = $obj->account_number; |
2239
|
|
|
} |
2240
|
|
|
if ($select_out == 1) { |
2241
|
|
|
$select_value_out = $obj->account_number; |
2242
|
|
|
} |
2243
|
|
|
|
2244
|
|
|
// Remember guy's we store in database llx_facturedet the rowid of accounting_account and not the account_number |
2245
|
|
|
// Because same account_number can be share between different accounting_system and do have the same meaning |
2246
|
|
|
if (($selectid != '') && $selectid == $select_value_in) { |
2247
|
|
|
$selected = $select_value_out; |
2248
|
|
|
} |
2249
|
|
|
|
2250
|
|
|
$options[$select_value_out] = $label; |
2251
|
|
|
} |
2252
|
|
|
|
2253
|
|
|
$out .= Form::selectarray($htmlname, $options, $selected, $showempty, 0, 0, '', 0, 0, 0, '', 'maxwidth300'); |
2254
|
|
|
$this->db->free($resql); |
2255
|
|
|
return $out; |
2256
|
|
|
} |
2257
|
|
|
|
2258
|
|
|
/** |
2259
|
|
|
* Return id and description of a root accounting account. |
2260
|
|
|
* FIXME: This function takes the parent of parent to get the root account ! |
2261
|
|
|
* |
2262
|
|
|
* @param string $account Accounting account |
2263
|
|
|
* @return array|int Array with root account information (max 2 upper level), <0 if KO |
2264
|
|
|
*/ |
2265
|
|
|
public function getRootAccount($account = null) |
2266
|
|
|
{ |
2267
|
|
|
global $conf; |
2268
|
|
|
$pcgver = getDolGlobalInt('CHARTOFACCOUNTS'); |
2269
|
|
|
|
2270
|
|
|
$sql = "SELECT root.rowid, root.account_number, root.label as label,"; |
2271
|
|
|
$sql .= " parent.rowid as parent_rowid, parent.account_number as parent_account_number, parent.label as parent_label"; |
2272
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as aa"; |
2273
|
|
|
$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version"; |
2274
|
|
|
$sql .= " AND asy.rowid = " . ((int) $pcgver); |
2275
|
|
|
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1"; |
2276
|
|
|
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1"; |
2277
|
|
|
$sql .= " WHERE aa.account_number = '" . $this->db->escape($account) . "'"; |
2278
|
|
|
$sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
2279
|
|
|
|
2280
|
|
|
dol_syslog(get_only_class($this) . "::select_account", LOG_DEBUG); |
2281
|
|
|
$resql = $this->db->query($sql); |
2282
|
|
|
if ($resql) { |
2283
|
|
|
$obj = ''; |
2284
|
|
|
if ($this->db->num_rows($resql)) { |
2285
|
|
|
$obj = $this->db->fetch_object($resql); |
2286
|
|
|
} |
2287
|
|
|
|
2288
|
|
|
$result = array('id' => $obj->rowid, 'account_number' => $obj->account_number, 'label' => $obj->label); |
2289
|
|
|
return $result; |
2290
|
|
|
} else { |
2291
|
|
|
$this->error = "Error " . $this->db->lasterror(); |
2292
|
|
|
dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR); |
2293
|
|
|
|
2294
|
|
|
return -1; |
2295
|
|
|
} |
2296
|
|
|
} |
2297
|
|
|
|
2298
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
2299
|
|
|
/** |
2300
|
|
|
* Description of accounting account |
2301
|
|
|
* |
2302
|
|
|
* @param string $account Accounting account |
2303
|
|
|
* @return string|int Account desc or -1 if KO |
2304
|
|
|
*/ |
2305
|
|
|
public function get_compte_desc($account = null) |
2306
|
|
|
{ |
2307
|
|
|
// phpcs:enable |
2308
|
|
|
global $conf; |
2309
|
|
|
|
2310
|
|
|
$pcgver = getDolGlobalInt('CHARTOFACCOUNTS'); |
2311
|
|
|
$sql = "SELECT aa.account_number, aa.label, aa.rowid, aa.fk_pcg_version, cat.label as category"; |
2312
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as aa "; |
2313
|
|
|
$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version"; |
2314
|
|
|
$sql .= " AND aa.account_number = '" . $this->db->escape($account) . "'"; |
2315
|
|
|
$sql .= " AND asy.rowid = " . ((int) $pcgver); |
2316
|
|
|
$sql .= " AND aa.active = 1"; |
2317
|
|
|
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid"; |
2318
|
|
|
$sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features |
2319
|
|
|
|
2320
|
|
|
dol_syslog(get_only_class($this) . "::select_account", LOG_DEBUG); |
2321
|
|
|
$resql = $this->db->query($sql); |
2322
|
|
|
if ($resql) { |
2323
|
|
|
$obj = ''; |
2324
|
|
|
if ($this->db->num_rows($resql)) { |
2325
|
|
|
$obj = $this->db->fetch_object($resql); |
2326
|
|
|
} |
2327
|
|
|
if (empty($obj->category)) { |
2328
|
|
|
return $obj->label; |
2329
|
|
|
} else { |
2330
|
|
|
return $obj->label . ' (' . $obj->category . ')'; |
2331
|
|
|
} |
2332
|
|
|
} else { |
2333
|
|
|
$this->error = "Error " . $this->db->lasterror(); |
2334
|
|
|
dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR); |
2335
|
|
|
return "-1"; |
2336
|
|
|
} |
2337
|
|
|
} |
2338
|
|
|
|
2339
|
|
|
/** |
2340
|
|
|
* Get SQL string for check if the bookkeeping can be modified or deleted ? (cached) |
2341
|
|
|
* |
2342
|
|
|
* @param string $alias Bookkeeping alias table |
2343
|
|
|
* @param bool $force Force reload |
2344
|
|
|
* @return string|null SQL filter or null if error |
2345
|
|
|
*/ |
2346
|
|
|
public function getCanModifyBookkeepingSQL($alias = '', $force = false) |
2347
|
|
|
{ |
2348
|
|
|
global $conf; |
2349
|
|
|
|
2350
|
|
|
$alias = trim($alias); |
2351
|
|
|
$alias = !empty($alias) && strpos($alias, '.') < 0 ? $alias . "." : $alias; |
2352
|
|
|
|
2353
|
|
|
if (!isset(self::$can_modify_bookkeeping_sql_cached[$alias]) || $force) { |
2354
|
|
|
$result = $this->loadFiscalPeriods($force, 'active'); |
2355
|
|
|
if ($result < 0) { |
2356
|
|
|
return null; |
2357
|
|
|
} |
2358
|
|
|
|
2359
|
|
|
$sql_list = array(); |
2360
|
|
|
if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) { |
2361
|
|
|
foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) { |
2362
|
|
|
$sql_list[] = "('" . $this->db->idate($fiscal_period['date_start']) . "' <= " . $this->db->sanitize($alias) . "doc_date AND " . $this->db->sanitize($alias) . "doc_date <= '" . $this->db->idate($fiscal_period['date_end']) . "')"; |
2363
|
|
|
} |
2364
|
|
|
} |
2365
|
|
|
$sqlsanitized = implode(' OR ', $sql_list); |
2366
|
|
|
self::$can_modify_bookkeeping_sql_cached[$alias] = !empty($sql_list) ? " AND (" . $sqlsanitized . ")" : ""; |
2367
|
|
|
} |
2368
|
|
|
|
2369
|
|
|
return self::$can_modify_bookkeeping_sql_cached[$alias]; |
2370
|
|
|
} |
2371
|
|
|
|
2372
|
|
|
/** |
2373
|
|
|
* Is the bookkeeping can be modified or deleted ? |
2374
|
|
|
* |
2375
|
|
|
* @param int $id Bookkeeping ID |
2376
|
|
|
* @param string $mode Mode ('' or 'tmp_') |
2377
|
|
|
* @return int Return integer <0 if KO, == 0 if No, == 1 if Yes |
2378
|
|
|
*/ |
2379
|
|
|
public function canModifyBookkeeping($id, $mode = '') |
2380
|
|
|
{ |
2381
|
|
|
global $conf; |
2382
|
|
|
|
2383
|
|
|
if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') { |
2384
|
|
|
$result = $this->loadFiscalPeriods(false, 'closed'); |
2385
|
|
|
|
2386
|
|
|
if ($result < 0) { |
2387
|
|
|
return -1; |
2388
|
|
|
} |
2389
|
|
|
|
2390
|
|
|
$bookkeeping = new BookKeeping($this->db); |
2391
|
|
|
$result = $bookkeeping->fetch($id, null, $mode); |
2392
|
|
|
if ($result <= 0) { |
2393
|
|
|
return $result; |
2394
|
|
|
} |
2395
|
|
|
|
2396
|
|
|
if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) { |
2397
|
|
|
foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) { |
2398
|
|
|
if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) { |
2399
|
|
|
return 0; |
2400
|
|
|
} |
2401
|
|
|
} |
2402
|
|
|
} |
2403
|
|
|
|
2404
|
|
|
return 1; |
2405
|
|
|
} else { |
2406
|
|
|
$result = $this->loadFiscalPeriods(false, 'active'); |
2407
|
|
|
if ($result < 0) { |
2408
|
|
|
return -1; |
2409
|
|
|
} |
2410
|
|
|
|
2411
|
|
|
$bookkeeping = new BookKeeping($this->db); |
2412
|
|
|
$result = $bookkeeping->fetch($id, null, $mode); |
2413
|
|
|
|
2414
|
|
|
if ($result <= 0) { |
2415
|
|
|
return $result; |
2416
|
|
|
} |
2417
|
|
|
if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) { |
2418
|
|
|
foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) { |
2419
|
|
|
if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $bookkeeping->doc_date && (empty($fiscal_period['date_end']) || $bookkeeping->doc_date <= $fiscal_period['date_end'])) { |
2420
|
|
|
return 1; |
2421
|
|
|
} |
2422
|
|
|
} |
2423
|
|
|
} |
2424
|
|
|
|
2425
|
|
|
return 0; |
2426
|
|
|
} |
2427
|
|
|
} |
2428
|
|
|
|
2429
|
|
|
/** |
2430
|
|
|
* Is the bookkeeping date valid (on an open period or not on a closed period) ? |
2431
|
|
|
* |
2432
|
|
|
* @param int $date Bookkeeping date |
2433
|
|
|
* @return int Return integer <0 if KO, == 0 if No, == 1 if date is valid for a transfer |
2434
|
|
|
*/ |
2435
|
|
|
public function validBookkeepingDate($date) |
2436
|
|
|
{ |
2437
|
|
|
global $conf; |
2438
|
|
|
|
2439
|
|
|
if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') { |
2440
|
|
|
$result = $this->loadFiscalPeriods(false, 'closed'); |
2441
|
|
|
|
2442
|
|
|
if ($result < 0) { |
2443
|
|
|
return -1; |
2444
|
|
|
} |
2445
|
|
|
|
2446
|
|
|
if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) { |
2447
|
|
|
foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) { |
2448
|
|
|
if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) { |
2449
|
|
|
return 0; |
2450
|
|
|
} |
2451
|
|
|
} |
2452
|
|
|
} |
2453
|
|
|
|
2454
|
|
|
return 1; |
2455
|
|
|
} else { |
2456
|
|
|
$result = $this->loadFiscalPeriods(false, 'active'); |
2457
|
|
|
if ($result < 0) { |
2458
|
|
|
return -1; |
2459
|
|
|
} |
2460
|
|
|
|
2461
|
|
|
if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) { |
2462
|
|
|
foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) { |
2463
|
|
|
if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $date && (empty($fiscal_period['date_end']) || $date <= $fiscal_period['date_end'])) { |
2464
|
|
|
return 1; |
2465
|
|
|
} |
2466
|
|
|
} |
2467
|
|
|
} |
2468
|
|
|
|
2469
|
|
|
return 0; |
2470
|
|
|
} |
2471
|
|
|
} |
2472
|
|
|
|
2473
|
|
|
/** |
2474
|
|
|
* Load list of active fiscal period |
2475
|
|
|
* |
2476
|
|
|
* @param bool $force Force reload |
2477
|
|
|
* @param string $mode active or closed ? |
2478
|
|
|
* @return int Return integer <0 if KO, >0 if OK |
2479
|
|
|
*/ |
2480
|
|
|
public function loadFiscalPeriods($force = false, $mode = 'active') |
2481
|
|
|
{ |
2482
|
|
|
global $conf; |
2483
|
|
|
|
2484
|
|
|
if ($mode == 'active') { |
2485
|
|
|
if (!isset($conf->cache['active_fiscal_period_cached']) || $force) { |
2486
|
|
|
$sql = "SELECT date_start, date_end"; |
2487
|
|
|
$sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear"; |
2488
|
|
|
$sql .= " WHERE entity = " . ((int) $conf->entity); |
2489
|
|
|
$sql .= " AND statut = 0"; |
2490
|
|
|
|
2491
|
|
|
$resql = $this->db->query($sql); |
2492
|
|
|
if (!$resql) { |
2493
|
|
|
$this->errors[] = $this->db->lasterror(); |
2494
|
|
|
return -1; |
2495
|
|
|
} |
2496
|
|
|
|
2497
|
|
|
$list = array(); |
2498
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2499
|
|
|
$list[] = array( |
2500
|
|
|
'date_start' => $this->db->jdate($obj->date_start), |
2501
|
|
|
'date_end' => $this->db->jdate($obj->date_end), |
2502
|
|
|
); |
2503
|
|
|
} |
2504
|
|
|
$conf->cache['active_fiscal_period_cached'] = $list; |
2505
|
|
|
} |
2506
|
|
|
} |
2507
|
|
|
if ($mode == 'closed') { |
2508
|
|
|
if (!isset($conf->cache['closed_fiscal_period_cached']) || $force) { |
2509
|
|
|
$sql = "SELECT date_start, date_end"; |
2510
|
|
|
$sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear"; |
2511
|
|
|
$sql .= " WHERE entity = " . ((int) $conf->entity); |
2512
|
|
|
$sql .= " AND statut = 1"; |
2513
|
|
|
|
2514
|
|
|
$resql = $this->db->query($sql); |
2515
|
|
|
if (!$resql) { |
2516
|
|
|
$this->errors[] = $this->db->lasterror(); |
2517
|
|
|
return -1; |
2518
|
|
|
} |
2519
|
|
|
|
2520
|
|
|
$list = array(); |
2521
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2522
|
|
|
$list[] = array( |
2523
|
|
|
'date_start' => $this->db->jdate($obj->date_start), |
2524
|
|
|
'date_end' => $this->db->jdate($obj->date_end), |
2525
|
|
|
); |
2526
|
|
|
} |
2527
|
|
|
$conf->cache['closed_fiscal_period_cached'] = $list; |
2528
|
|
|
} |
2529
|
|
|
} |
2530
|
|
|
|
2531
|
|
|
return 1; |
2532
|
|
|
} |
2533
|
|
|
|
2534
|
|
|
/** |
2535
|
|
|
* Get list of fiscal period |
2536
|
|
|
* |
2537
|
|
|
* @param string $filter Filter |
2538
|
|
|
* @return array<array{id:int,label:string,date_start:string,date_end:string,status:int}>|int Return integer <0 if KO, Fiscal periods : [[id, date_start, date_end, label], ...] |
2539
|
|
|
*/ |
2540
|
|
|
public function getFiscalPeriods($filter = '') |
2541
|
|
|
{ |
2542
|
|
|
global $conf; |
2543
|
|
|
$list = array(); |
2544
|
|
|
|
2545
|
|
|
$sql = "SELECT rowid, label, date_start, date_end, statut"; |
2546
|
|
|
$sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear"; |
2547
|
|
|
$sql .= " WHERE entity = " . ((int) $conf->entity); |
2548
|
|
|
if (!empty($filter)) { |
2549
|
|
|
$sql .= " AND (" . $this->db->sanitize($filter, 1, 1, 1) . ')'; |
2550
|
|
|
} |
2551
|
|
|
$sql .= $this->db->order('date_start', 'ASC'); |
2552
|
|
|
|
2553
|
|
|
$resql = $this->db->query($sql); |
2554
|
|
|
if (!$resql) { |
2555
|
|
|
$this->errors[] = $this->db->lasterror(); |
2556
|
|
|
return -1; |
2557
|
|
|
} |
2558
|
|
|
|
2559
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2560
|
|
|
$list[$obj->rowid] = array( |
2561
|
|
|
'id' => (int) $obj->rowid, |
2562
|
|
|
'label' => $obj->label, |
2563
|
|
|
'date_start' => $this->db->jdate($obj->date_start), |
2564
|
|
|
'date_end' => $this->db->jdate($obj->date_end), |
2565
|
|
|
'status' => (int) $obj->statut, |
2566
|
|
|
); |
2567
|
|
|
} |
2568
|
|
|
|
2569
|
|
|
return $list; |
2570
|
|
|
} |
2571
|
|
|
|
2572
|
|
|
/** |
2573
|
|
|
* Get list of count by month into the fiscal period |
2574
|
|
|
* |
2575
|
|
|
* @param int $date_start Date start |
2576
|
|
|
* @param int $date_end Date end |
2577
|
|
|
* @return array|int Return integer <0 if KO, Fiscal periods : [[id, date_start, date_end, label], ...] |
2578
|
|
|
*/ |
2579
|
|
|
public function getCountByMonthForFiscalPeriod($date_start, $date_end) |
2580
|
|
|
{ |
2581
|
|
|
$total = 0; |
2582
|
|
|
$list = array(); |
2583
|
|
|
|
2584
|
|
|
$sql = "SELECT YEAR(b.doc_date) as year"; |
2585
|
|
|
for ($i = 1; $i <= 12; $i++) { |
2586
|
|
|
$sql .= ", SUM(" . $this->db->ifsql("MONTH(b.doc_date) = " . ((int) $i), "1", "0") . ") AS month" . ((int) $i); |
2587
|
|
|
} |
2588
|
|
|
$sql .= ", COUNT(b.rowid) as total"; |
2589
|
|
|
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as b"; |
2590
|
|
|
$sql .= " WHERE b.doc_date >= '" . $this->db->idate($date_start) . "'"; |
2591
|
|
|
$sql .= " AND b.doc_date <= '" . $this->db->idate($date_end) . "'"; |
2592
|
|
|
$sql .= " AND b.entity IN (" . getEntity('bookkeeping', 0) . ")"; // We don't share object for accountancy |
2593
|
|
|
|
2594
|
|
|
// Get count for each month into the fiscal period |
2595
|
|
|
if (getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) { |
2596
|
|
|
// TODO Analyse is done by finding record not into a closed period |
2597
|
|
|
// Loop on each closed period |
2598
|
|
|
$sql .= " AND b.doc_date BETWEEN 0 AND 0"; |
2599
|
|
|
} else { |
2600
|
|
|
// Analyse closed record using the unitary flag/date on each record |
2601
|
|
|
$sql .= " AND date_validated IS NULL"; |
2602
|
|
|
} |
2603
|
|
|
|
2604
|
|
|
$sql .= " GROUP BY YEAR(b.doc_date)"; |
2605
|
|
|
$sql .= $this->db->order("year", 'ASC'); |
2606
|
|
|
|
2607
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
2608
|
|
|
$resql = $this->db->query($sql); |
2609
|
|
|
if (!$resql) { |
2610
|
|
|
$this->errors[] = $this->db->lasterror(); |
2611
|
|
|
return -1; |
2612
|
|
|
} |
2613
|
|
|
|
2614
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2615
|
|
|
$total += (int) $obj->total; |
2616
|
|
|
$year_list = array( |
2617
|
|
|
'year' => (int) $obj->year, |
2618
|
|
|
'count' => array(), |
2619
|
|
|
'total' => (int) $obj->total, |
2620
|
|
|
); |
2621
|
|
|
for ($i = 1; $i <= 12; $i++) { |
2622
|
|
|
$year_list['count'][$i] = (int) $obj->{'month' . $i}; |
2623
|
|
|
} |
2624
|
|
|
|
2625
|
|
|
$list[] = $year_list; |
2626
|
|
|
} |
2627
|
|
|
|
2628
|
|
|
$this->db->free($resql); |
2629
|
|
|
|
2630
|
|
|
return array( |
2631
|
|
|
'total' => $total, |
2632
|
|
|
'list' => $list, |
2633
|
|
|
); |
2634
|
|
|
} |
2635
|
|
|
|
2636
|
|
|
/** |
2637
|
|
|
* Validate all movement between the specified dates |
2638
|
|
|
* |
2639
|
|
|
* @param int $date_start Date start |
2640
|
|
|
* @param int $date_end Date end |
2641
|
|
|
* @return int int Return integer <0 if KO, >0 if OK |
2642
|
|
|
*/ |
2643
|
|
|
public function validateMovementForFiscalPeriod($date_start, $date_end) |
2644
|
|
|
{ |
2645
|
|
|
global $conf; |
2646
|
|
|
|
2647
|
|
|
$now = dol_now(); |
2648
|
|
|
|
2649
|
|
|
// Specify as export : update field date_validated on selected month/year |
2650
|
|
|
$sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping"; |
2651
|
|
|
$sql .= " SET date_validated = '" . $this->db->idate($now) . "'"; |
2652
|
|
|
$sql .= " WHERE entity = " . ((int) $conf->entity); |
2653
|
|
|
$sql .= " AND DATE(doc_date) >= '" . $this->db->idate($date_start) . "'"; |
2654
|
|
|
$sql .= " AND DATE(doc_date) <= '" . $this->db->idate($date_end) . "'"; |
2655
|
|
|
$sql .= " AND date_validated IS NULL"; |
2656
|
|
|
|
2657
|
|
|
dol_syslog(__METHOD__, LOG_DEBUG); |
2658
|
|
|
$resql = $this->db->query($sql); |
2659
|
|
|
if (!$resql) { |
2660
|
|
|
$this->errors[] = $this->db->lasterror(); |
2661
|
|
|
return -1; |
2662
|
|
|
} |
2663
|
|
|
|
2664
|
|
|
return 1; |
2665
|
|
|
} |
2666
|
|
|
|
2667
|
|
|
/** |
2668
|
|
|
* Define accounting result |
2669
|
|
|
* |
2670
|
|
|
* @param int $date_start Date start |
2671
|
|
|
* @param int $date_end Date end |
2672
|
|
|
* @return string Accounting result |
2673
|
|
|
*/ |
2674
|
|
|
public function accountingResult($date_start, $date_end) |
2675
|
|
|
{ |
2676
|
|
|
global $conf; |
2677
|
|
|
|
2678
|
|
|
$this->db->begin(); |
2679
|
|
|
|
2680
|
|
|
$income_statement_amount = 0; |
2681
|
|
|
|
2682
|
|
|
if (getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) { |
2683
|
|
|
$accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen'); |
2684
|
|
|
|
2685
|
|
|
$pcg_type_filter = array(); |
2686
|
|
|
foreach ($accounting_groups_used_for_income_statement as $item) { |
2687
|
|
|
$pcg_type_filter[] = "'" . $this->db->escape($item) . "'"; |
2688
|
|
|
} |
2689
|
|
|
|
2690
|
|
|
$sql = 'SELECT'; |
2691
|
|
|
$sql .= " t.numero_compte,"; |
2692
|
|
|
$sql .= " aa.pcg_type,"; |
2693
|
|
|
$sql .= " (SUM(t.credit) - SUM(t.debit)) as accounting_result"; |
2694
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; |
2695
|
|
|
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte'; |
2696
|
|
|
$sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features |
2697
|
|
|
$sql .= " AND aa.entity = " . ((int) $conf->entity); |
2698
|
|
|
$sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')'; |
2699
|
|
|
$sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')'; |
2700
|
|
|
$sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'"; |
2701
|
|
|
$sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'"; |
2702
|
|
|
$sql .= ' GROUP BY t.numero_compte, aa.pcg_type'; |
2703
|
|
|
|
2704
|
|
|
$resql = $this->db->query($sql); |
2705
|
|
|
if (!$resql) { |
2706
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2707
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2708
|
|
|
} else { |
2709
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2710
|
|
|
$income_statement_amount += $obj->accounting_result; |
2711
|
|
|
} |
2712
|
|
|
} |
2713
|
|
|
} |
2714
|
|
|
|
2715
|
|
|
return (string) $income_statement_amount; |
2716
|
|
|
} |
2717
|
|
|
|
2718
|
|
|
/** |
2719
|
|
|
* Close fiscal period |
2720
|
|
|
* |
2721
|
|
|
* @param int $fiscal_period_id Fiscal year ID |
2722
|
|
|
* @param int $new_fiscal_period_id New fiscal year ID |
2723
|
|
|
* @param bool $separate_auxiliary_account Separate auxiliary account |
2724
|
|
|
* @param bool $generate_bookkeeping_records Generate closure bookkeeping records |
2725
|
|
|
* @return int int Return integer <0 if KO, >0 if OK |
2726
|
|
|
*/ |
2727
|
|
|
public function closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account = false, $generate_bookkeeping_records = true) |
2728
|
|
|
{ |
2729
|
|
|
global $conf, $langs, $user; |
2730
|
|
|
|
2731
|
|
|
// Current fiscal period |
2732
|
|
|
$fiscal_period_id = max(0, $fiscal_period_id); |
2733
|
|
|
if (empty($fiscal_period_id)) { |
2734
|
|
|
$langs->load('errors'); |
2735
|
|
|
$this->errors[] = $langs->trans('ErrorBadParameters'); |
2736
|
|
|
return -1; |
2737
|
|
|
} |
2738
|
|
|
$fiscal_period = new Fiscalyear($this->db); |
2739
|
|
|
$result = $fiscal_period->fetch($fiscal_period_id); |
2740
|
|
|
if ($result < 0) { |
2741
|
|
|
$this->error = $fiscal_period->error; |
2742
|
|
|
$this->errors = $fiscal_period->errors; |
2743
|
|
|
return -1; |
2744
|
|
|
} elseif (empty($fiscal_period->id)) { |
2745
|
|
|
$langs->loadLangs(array('errors', 'compta')); |
2746
|
|
|
$this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')'; |
2747
|
|
|
return -1; |
2748
|
|
|
} |
2749
|
|
|
|
2750
|
|
|
// New fiscal period |
2751
|
|
|
$new_fiscal_period_id = max(0, $new_fiscal_period_id); |
2752
|
|
|
if (empty($new_fiscal_period_id)) { |
2753
|
|
|
$langs->load('errors'); |
2754
|
|
|
$this->errors[] = $langs->trans('ErrorBadParameters'); |
2755
|
|
|
return -1; |
2756
|
|
|
} |
2757
|
|
|
$new_fiscal_period = new Fiscalyear($this->db); |
2758
|
|
|
$result = $new_fiscal_period->fetch($new_fiscal_period_id); |
2759
|
|
|
if ($result < 0) { |
2760
|
|
|
$this->error = $new_fiscal_period->error; |
2761
|
|
|
$this->errors = $new_fiscal_period->errors; |
2762
|
|
|
return -1; |
2763
|
|
|
} elseif (empty($new_fiscal_period->id)) { |
2764
|
|
|
$langs->loadLangs(array('errors', 'compta')); |
2765
|
|
|
$this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')'; |
2766
|
|
|
return -1; |
2767
|
|
|
} |
2768
|
|
|
|
2769
|
|
|
$error = 0; |
2770
|
|
|
$this->db->begin(); |
2771
|
|
|
|
2772
|
|
|
$fiscal_period->statut = Fiscalyear::STATUS_CLOSED; |
2773
|
|
|
$fiscal_period->status = Fiscalyear::STATUS_CLOSED; // Actually not used |
2774
|
|
|
$result = $fiscal_period->update($user); |
2775
|
|
|
if ($result < 0) { |
2776
|
|
|
$this->error = $fiscal_period->error; |
2777
|
|
|
$this->errors = $fiscal_period->errors; |
2778
|
|
|
$error++; |
2779
|
|
|
} |
2780
|
|
|
|
2781
|
|
|
if (!$error && !empty($generate_bookkeeping_records)) { |
2782
|
|
|
$journal_id = max(0, getDolGlobalString('ACCOUNTING_CLOSURE_DEFAULT_JOURNAL')); |
2783
|
|
|
if (empty($journal_id)) { |
2784
|
|
|
$langs->loadLangs(array('errors', 'accountancy')); |
2785
|
|
|
$this->errors[] = $langs->trans('ErrorBadParameters') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')'; |
2786
|
|
|
$error++; |
2787
|
|
|
} |
2788
|
|
|
|
2789
|
|
|
// Fetch journal |
2790
|
|
|
if (!$error) { |
2791
|
|
|
$journal = new AccountingJournal($this->db); |
2792
|
|
|
$result = $journal->fetch($journal_id); |
2793
|
|
|
if ($result < 0) { |
2794
|
|
|
$this->error = $journal->error; |
2795
|
|
|
$this->errors = $journal->errors; |
2796
|
|
|
$error++; |
2797
|
|
|
} elseif ($result == 0) { |
2798
|
|
|
$langs->loadLangs(array('errors', 'accountancy')); |
2799
|
|
|
$this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')'; |
2800
|
|
|
$error++; |
2801
|
|
|
} |
2802
|
|
|
} |
2803
|
|
|
|
2804
|
|
|
if (!$error) { |
2805
|
|
|
$accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen'); |
2806
|
|
|
$accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen'); |
2807
|
|
|
|
2808
|
|
|
$pcg_type_filter = array(); |
2809
|
|
|
$tmp = array_merge($accounting_groups_used_for_balance_sheet_account, $accounting_groups_used_for_income_statement); |
2810
|
|
|
foreach ($tmp as $item) { |
2811
|
|
|
$pcg_type_filter[] = "'" . $this->db->escape($item) . "'"; |
2812
|
|
|
} |
2813
|
|
|
|
2814
|
|
|
$sql = 'SELECT'; |
2815
|
|
|
$sql .= " t.numero_compte,"; |
2816
|
|
|
$sql .= " t.label_compte,"; |
2817
|
|
|
if ($separate_auxiliary_account) { |
2818
|
|
|
$sql .= " t.subledger_account,"; |
2819
|
|
|
$sql .= " t.subledger_label,"; |
2820
|
|
|
} |
2821
|
|
|
$sql .= " aa.pcg_type,"; |
2822
|
|
|
$sql .= " (SUM(t.credit) - SUM(t.debit)) as opening_balance"; |
2823
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; |
2824
|
|
|
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte'; |
2825
|
|
|
$sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features |
2826
|
|
|
$sql .= " AND aa.entity = " . ((int) $conf->entity); |
2827
|
|
|
$sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')'; |
2828
|
|
|
$sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')'; |
2829
|
|
|
$sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'"; |
2830
|
|
|
$sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'"; |
2831
|
|
|
$sql .= ' GROUP BY t.numero_compte, t.label_compte, aa.pcg_type'; |
2832
|
|
|
if ($separate_auxiliary_account) { |
2833
|
|
|
$sql .= ' ,t.subledger_account, t.subledger_label'; |
2834
|
|
|
} |
2835
|
|
|
$sql .= $this->db->order("t.numero_compte", "ASC"); |
2836
|
|
|
|
2837
|
|
|
$resql = $this->db->query($sql); |
2838
|
|
|
if (!$resql) { |
2839
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
2840
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
2841
|
|
|
|
2842
|
|
|
$error++; |
2843
|
|
|
} else { |
2844
|
|
|
$now = dol_now(); |
2845
|
|
|
$income_statement_amount = 0; |
2846
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
2847
|
|
|
if (in_array($obj->pcg_type, $accounting_groups_used_for_income_statement)) { |
2848
|
|
|
$income_statement_amount += $obj->opening_balance; |
2849
|
|
|
} else { |
2850
|
|
|
// Insert bookkeeping record for balance sheet account |
2851
|
|
|
$mt = $obj->opening_balance; |
2852
|
|
|
|
2853
|
|
|
$bookkeeping = new BookKeeping($this->db); |
2854
|
|
|
$bookkeeping->doc_date = $new_fiscal_period->date_start; |
2855
|
|
|
$bookkeeping->date_lim_reglement = 0; |
2856
|
|
|
$bookkeeping->doc_ref = $new_fiscal_period->label; |
2857
|
|
|
$bookkeeping->date_creation = $now; |
2858
|
|
|
$bookkeeping->doc_type = 'closure'; |
2859
|
|
|
$bookkeeping->fk_doc = $new_fiscal_period->id; |
2860
|
|
|
$bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add |
2861
|
|
|
$bookkeeping->thirdparty_code = ''; |
2862
|
|
|
|
2863
|
|
|
if ($separate_auxiliary_account) { |
2864
|
|
|
$bookkeeping->subledger_account = $obj->subledger_account; |
2865
|
|
|
$bookkeeping->subledger_label = $obj->subledger_label; |
2866
|
|
|
} else { |
2867
|
|
|
$bookkeeping->subledger_account = ''; |
2868
|
|
|
$bookkeeping->subledger_label = ''; |
2869
|
|
|
} |
2870
|
|
|
|
2871
|
|
|
$bookkeeping->numero_compte = $obj->numero_compte; |
2872
|
|
|
$bookkeeping->label_compte = $obj->label_compte; |
2873
|
|
|
|
2874
|
|
|
$bookkeeping->label_operation = $new_fiscal_period->label; |
2875
|
|
|
$bookkeeping->montant = $mt; |
|
|
|
|
2876
|
|
|
$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D'; |
2877
|
|
|
$bookkeeping->debit = ($mt < 0) ? -$mt : 0; |
2878
|
|
|
$bookkeeping->credit = ($mt >= 0) ? $mt : 0; |
2879
|
|
|
$bookkeeping->code_journal = $journal->code; |
2880
|
|
|
$bookkeeping->journal_label = $langs->transnoentities($journal->label); |
2881
|
|
|
$bookkeeping->fk_user_author = $user->id; |
2882
|
|
|
$bookkeeping->entity = $conf->entity; |
2883
|
|
|
|
2884
|
|
|
$result = $bookkeeping->create($user); |
2885
|
|
|
if ($result < 0) { |
2886
|
|
|
$this->error = $bookkeeping->error; |
2887
|
|
|
$this->errors = $bookkeeping->errors; |
2888
|
|
|
$error++; |
2889
|
|
|
break; |
2890
|
|
|
} |
2891
|
|
|
} |
2892
|
|
|
} |
2893
|
|
|
|
2894
|
|
|
// Insert bookkeeping record for income statement |
2895
|
|
|
if (!$error && $income_statement_amount != 0) { |
2896
|
|
|
$mt = $income_statement_amount; |
2897
|
|
|
$accountingaccount = new AccountingAccount($this->db); |
2898
|
|
|
$accountingaccount->fetch(null, getDolGlobalString($income_statement_amount < 0 ? 'ACCOUNTING_RESULT_LOSS' : 'ACCOUNTING_RESULT_PROFIT'), true); |
2899
|
|
|
|
2900
|
|
|
$bookkeeping = new BookKeeping($this->db); |
2901
|
|
|
$bookkeeping->doc_date = $new_fiscal_period->date_start; |
2902
|
|
|
$bookkeeping->date_lim_reglement = 0; |
2903
|
|
|
$bookkeeping->doc_ref = $new_fiscal_period->label; |
2904
|
|
|
$bookkeeping->date_creation = $now; |
2905
|
|
|
$bookkeeping->doc_type = 'closure'; |
2906
|
|
|
$bookkeeping->fk_doc = $new_fiscal_period->id; |
2907
|
|
|
$bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add |
2908
|
|
|
$bookkeeping->thirdparty_code = ''; |
2909
|
|
|
|
2910
|
|
|
if ($separate_auxiliary_account) { |
2911
|
|
|
$bookkeeping->subledger_label = ''; |
2912
|
|
|
$bookkeeping->subledger_account = $obj->subledger_account; |
2913
|
|
|
$bookkeeping->subledger_label = $obj->subledger_label; |
2914
|
|
|
} else { |
2915
|
|
|
$bookkeeping->subledger_account = ''; |
2916
|
|
|
$bookkeeping->subledger_label = ''; |
2917
|
|
|
} |
2918
|
|
|
|
2919
|
|
|
$bookkeeping->numero_compte = $accountingaccount->account_number; |
2920
|
|
|
$bookkeeping->label_compte = $accountingaccount->label; |
2921
|
|
|
|
2922
|
|
|
$bookkeeping->label_operation = $new_fiscal_period->label; |
2923
|
|
|
$bookkeeping->montant = $mt; |
2924
|
|
|
$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D'; |
2925
|
|
|
$bookkeeping->debit = ($mt < 0) ? -$mt : 0; |
2926
|
|
|
$bookkeeping->credit = ($mt >= 0) ? $mt : 0; |
2927
|
|
|
$bookkeeping->code_journal = $journal->code; |
2928
|
|
|
$bookkeeping->journal_label = $langs->transnoentities($journal->label); |
2929
|
|
|
$bookkeeping->fk_user_author = $user->id; |
2930
|
|
|
$bookkeeping->entity = $conf->entity; |
2931
|
|
|
|
2932
|
|
|
$result = $bookkeeping->create($user); |
2933
|
|
|
if ($result < 0) { |
2934
|
|
|
$this->error = $bookkeeping->error; |
2935
|
|
|
$this->errors = $bookkeeping->errors; |
2936
|
|
|
$error++; |
2937
|
|
|
} |
2938
|
|
|
} |
2939
|
|
|
$this->db->free($resql); |
2940
|
|
|
} |
2941
|
|
|
} |
2942
|
|
|
} |
2943
|
|
|
|
2944
|
|
|
if ($error) { |
2945
|
|
|
$this->db->rollback(); |
2946
|
|
|
return -1; |
2947
|
|
|
} else { |
2948
|
|
|
$this->db->commit(); |
2949
|
|
|
return 1; |
2950
|
|
|
} |
2951
|
|
|
} |
2952
|
|
|
|
2953
|
|
|
/** |
2954
|
|
|
* Insert accounting reversal into the inventory journal of the new fiscal period |
2955
|
|
|
* |
2956
|
|
|
* @param int $fiscal_period_id Fiscal year ID |
2957
|
|
|
* @param int $inventory_journal_id Inventory journal ID |
2958
|
|
|
* @param int $new_fiscal_period_id New fiscal year ID |
2959
|
|
|
* @param int $date_start Date start |
2960
|
|
|
* @param int $date_end Date end |
2961
|
|
|
* @return int int Return integer <0 if KO, >0 if OK |
2962
|
|
|
*/ |
2963
|
|
|
public function insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end) |
2964
|
|
|
{ |
2965
|
|
|
global $conf, $langs, $user; |
2966
|
|
|
|
2967
|
|
|
// Current fiscal period |
2968
|
|
|
$fiscal_period_id = max(0, $fiscal_period_id); |
2969
|
|
|
if (empty($fiscal_period_id)) { |
2970
|
|
|
$langs->load('errors'); |
2971
|
|
|
$this->errors[] = $langs->trans('ErrorBadParameters'); |
2972
|
|
|
return -1; |
2973
|
|
|
} |
2974
|
|
|
$fiscal_period = new Fiscalyear($this->db); |
2975
|
|
|
$result = $fiscal_period->fetch($fiscal_period_id); |
2976
|
|
|
if ($result < 0) { |
2977
|
|
|
$this->error = $fiscal_period->error; |
2978
|
|
|
$this->errors = $fiscal_period->errors; |
2979
|
|
|
return -1; |
2980
|
|
|
} elseif (empty($fiscal_period->id)) { |
2981
|
|
|
$langs->loadLangs(array('errors', 'compta')); |
2982
|
|
|
$this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')'; |
2983
|
|
|
return -1; |
2984
|
|
|
} |
2985
|
|
|
|
2986
|
|
|
// New fiscal period |
2987
|
|
|
$new_fiscal_period_id = max(0, $new_fiscal_period_id); |
2988
|
|
|
if (empty($new_fiscal_period_id)) { |
2989
|
|
|
$langs->load('errors'); |
2990
|
|
|
$this->errors[] = $langs->trans('ErrorBadParameters'); |
2991
|
|
|
return -1; |
2992
|
|
|
} |
2993
|
|
|
$new_fiscal_period = new Fiscalyear($this->db); |
2994
|
|
|
$result = $new_fiscal_period->fetch($new_fiscal_period_id); |
2995
|
|
|
if ($result < 0) { |
2996
|
|
|
$this->error = $new_fiscal_period->error; |
2997
|
|
|
$this->errors = $new_fiscal_period->errors; |
2998
|
|
|
return -1; |
2999
|
|
|
} elseif (empty($new_fiscal_period->id)) { |
3000
|
|
|
$langs->loadLangs(array('errors', 'compta')); |
3001
|
|
|
$this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')'; |
3002
|
|
|
return -1; |
3003
|
|
|
} |
3004
|
|
|
|
3005
|
|
|
// Inventory journal |
3006
|
|
|
$inventory_journal_id = max(0, $inventory_journal_id); |
3007
|
|
|
if (empty($inventory_journal_id)) { |
3008
|
|
|
$langs->load('errors'); |
3009
|
|
|
$this->errors[] = $langs->trans('ErrorBadParameters'); |
3010
|
|
|
return -1; |
3011
|
|
|
} |
3012
|
|
|
// Fetch journal |
3013
|
|
|
$inventory_journal = new AccountingJournal($this->db); |
3014
|
|
|
$result = $inventory_journal->fetch($inventory_journal_id); |
3015
|
|
|
if ($result < 0) { |
3016
|
|
|
$this->error = $inventory_journal->error; |
3017
|
|
|
$this->errors = $inventory_journal->errors; |
3018
|
|
|
return -1; |
3019
|
|
|
} elseif ($result == 0) { |
3020
|
|
|
$langs->loadLangs(array('errors', 'accountancy')); |
3021
|
|
|
$this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('InventoryJournal'); |
3022
|
|
|
return -1; |
3023
|
|
|
} |
3024
|
|
|
|
3025
|
|
|
$error = 0; |
3026
|
|
|
$this->db->begin(); |
3027
|
|
|
|
3028
|
|
|
$sql = 'SELECT t.rowid'; |
3029
|
|
|
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; |
3030
|
|
|
$sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features |
3031
|
|
|
$sql .= " AND code_journal = '" . $this->db->escape($inventory_journal->code) . "'"; |
3032
|
|
|
$sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'"; |
3033
|
|
|
$sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'"; |
3034
|
|
|
$sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'"; |
3035
|
|
|
$sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'"; |
3036
|
|
|
|
3037
|
|
|
$resql = $this->db->query($sql); |
3038
|
|
|
if (!$resql) { |
3039
|
|
|
$this->errors[] = 'Error ' . $this->db->lasterror(); |
3040
|
|
|
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); |
3041
|
|
|
|
3042
|
|
|
$error++; |
3043
|
|
|
} else { |
3044
|
|
|
$now = dol_now(); |
3045
|
|
|
while ($obj = $this->db->fetch_object($resql)) { |
3046
|
|
|
$bookkeeping = new BookKeeping($this->db); |
3047
|
|
|
$result = $bookkeeping->fetch($obj->rowid); |
3048
|
|
|
if ($result < 0) { |
3049
|
|
|
$this->error = $inventory_journal->error; |
3050
|
|
|
$this->errors = $inventory_journal->errors; |
3051
|
|
|
$error++; |
3052
|
|
|
break; |
3053
|
|
|
} elseif ($result == 0) { |
3054
|
|
|
$langs->loadLangs(array('errors', 'accountancy')); |
3055
|
|
|
$this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('LineId') . ': ' . $obj->rowid; |
3056
|
|
|
$error++; |
3057
|
|
|
break; |
3058
|
|
|
} |
3059
|
|
|
|
3060
|
|
|
$bookkeeping->id = 0; |
3061
|
|
|
$bookkeeping->doc_date = $new_fiscal_period->date_start; |
3062
|
|
|
$bookkeeping->doc_ref = $new_fiscal_period->label; |
3063
|
|
|
$bookkeeping->date_creation = $now; |
3064
|
|
|
$bookkeeping->doc_type = 'accounting_reversal'; |
3065
|
|
|
$bookkeeping->fk_doc = $new_fiscal_period->id; |
3066
|
|
|
$bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add |
3067
|
|
|
|
3068
|
|
|
$bookkeeping->montant = -$bookkeeping->montant; |
|
|
|
|
3069
|
|
|
$bookkeeping->sens = ($bookkeeping->montant >= 0) ? 'C' : 'D'; |
|
|
|
|
3070
|
|
|
$old_debit = $bookkeeping->debit; |
3071
|
|
|
$bookkeeping->debit = $bookkeeping->credit; |
3072
|
|
|
$bookkeeping->credit = $old_debit; |
3073
|
|
|
|
3074
|
|
|
$bookkeeping->fk_user_author = $user->id; |
3075
|
|
|
$bookkeeping->entity = $conf->entity; |
3076
|
|
|
|
3077
|
|
|
$result = $bookkeeping->create($user); |
3078
|
|
|
if ($result < 0) { |
3079
|
|
|
$this->error = $bookkeeping->error; |
3080
|
|
|
$this->errors = $bookkeeping->errors; |
3081
|
|
|
$error++; |
3082
|
|
|
break; |
3083
|
|
|
} |
3084
|
|
|
} |
3085
|
|
|
$this->db->free($resql); |
3086
|
|
|
} |
3087
|
|
|
|
3088
|
|
|
if ($error) { |
3089
|
|
|
$this->db->rollback(); |
3090
|
|
|
return -1; |
3091
|
|
|
} else { |
3092
|
|
|
$this->db->commit(); |
3093
|
|
|
return 1; |
3094
|
|
|
} |
3095
|
|
|
} |
3096
|
|
|
} |
3097
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.