112 if (
$object->code_compta_client ==
'411CUSTCODE') {
113 $object->code_compta_client =
'';
116 if (
$object->code_compta_fournisseur ==
'401SUPPCODE') {
117 $object->code_compta_fournisseur =
'';
123 $sql =
"SELECT DISTINCT bk.rowid, bk.doc_date, bk.doc_type, bk.doc_ref, bk.subledger_account, ";
124 $sql .=
" bk.numero_compte , bk.label_compte, bk.debit , bk.credit, bk.montant ";
125 $sql .=
" , bk.sens , bk.code_journal , bk.piece_num, bk.date_lettering, bu.url_id , bu.type ";
126 $sql .=
" FROM ".MAIN_DB_PREFIX.
"accounting_bookkeeping as bk";
127 $sql .=
" LEFT JOIN ".MAIN_DB_PREFIX.
"bank_url as bu ON(bk.fk_doc = bu.fk_bank AND bu.type IN ('payment', 'payment_supplier') ) ";
129 if (
$object->code_compta_client !=
"") {
130 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_client).
"' ";
132 if (
$object->code_compta_client !=
"" &&
$object->code_compta_fournisseur !=
"") {
135 if (
$object->code_compta_fournisseur !=
"") {
136 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_fournisseur).
"' ";
139 $sql .=
" ) AND (bk.date_lettering ='' OR bk.date_lettering IS NULL) ";
140 $sql .=
" AND (bk.lettering_code != '' OR bk.lettering_code IS NULL) ";
141 $sql .=
' AND bk.date_validated IS NULL ';
142 $sql .= $this->db->order(
'bk.doc_date',
'DESC');
146 $resql = $this->db->query($sql);
148 $num = $this->db->num_rows($resql);
150 while ($obj = $this->db->fetch_object($resql)) {
154 if ($obj->type ==
'payment_supplier') {
155 $sql =
'SELECT DISTINCT bk.rowid, facf.ref, facf.ref_supplier, payf.fk_bank, facf.rowid as fact_id';
156 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn facf ";
157 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"paiementfourn_facturefourn as payfacf ON payfacf.fk_facturefourn=facf.rowid";
158 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"paiementfourn as payf ON payfacf.fk_paiementfourn=payf.rowid";
159 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"accounting_bookkeeping as bk ON (bk.fk_doc = payf.fk_bank AND bk.code_journal='".$this->db->escape($obj->code_journal).
"')";
160 $sql .=
" WHERE payfacf.fk_paiementfourn = '".$this->db->escape($obj->url_id).
"' ";
161 $sql .=
" AND facf.entity = " . (int)
$conf->entity;
162 $sql .=
" AND code_journal IN (SELECT code FROM ".MAIN_DB_PREFIX.
"accounting_journal WHERE nature=4 AND entity=" . (int)
$conf->entity .
") ";
164 if (
$object->code_compta_client !=
"") {
165 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_client).
"' ";
167 if (
$object->code_compta_client !=
"" &&
$object->code_compta_fournisseur !=
"") {
170 if (
$object->code_compta_fournisseur !=
"") {
171 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_fournisseur).
"' ";
175 $resql2 = $this->db->query($sql);
177 while ($obj2 = $this->db->fetch_object($resql2)) {
178 $ids[$obj2->rowid] = $obj2->rowid;
179 $ids_fact[] = $obj2->fact_id;
181 $this->db->free($resql2);
183 $this->errors[] = $this->db->lasterror;
186 if (count($ids_fact)) {
187 $sql =
'SELECT bk.rowid, facf.ref, facf.ref_supplier ';
188 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn facf ";
189 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"accounting_bookkeeping as bk ON( bk.fk_doc = facf.rowid AND facf.rowid IN (".$this->db->sanitize(implode(
',', $ids_fact)).
"))";
190 $sql .=
" WHERE bk.code_journal IN (SELECT code FROM ".MAIN_DB_PREFIX.
"accounting_journal WHERE nature=3 AND entity=". (int)
$conf->entity.
") ";
191 $sql .=
" AND facf.entity = " . (int)
$conf->entity;
193 if (
$object->code_compta_client !=
"") {
194 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_client).
"' ";
196 if (
$object->code_compta_client !=
"" &&
$object->code_compta_fournisseur !=
"") {
199 if (
$object->code_compta_fournisseur !=
"") {
200 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_fournisseur).
"' ";
204 $resql2 = $this->db->query($sql);
206 while ($obj2 = $this->db->fetch_object($resql2)) {
207 $ids[$obj2->rowid] = $obj2->rowid;
209 $this->db->free($resql2);
211 $this->errors[] = $this->db->lasterror;
215 } elseif ($obj->type ==
'payment') {
216 $sql =
'SELECT DISTINCT bk.rowid, fac.ref, fac.ref, pay.fk_bank, fac.rowid as fact_id';
217 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture fac ";
218 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"paiement_facture as payfac ON payfac.fk_facture=fac.rowid";
219 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"paiement as pay ON payfac.fk_paiement=pay.rowid";
220 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"accounting_bookkeeping as bk ON (bk.fk_doc = pay.fk_bank AND bk.code_journal='".$this->db->escape($obj->code_journal).
"')";
221 $sql .=
" WHERE payfac.fk_paiement = '".$this->db->escape($obj->url_id).
"' ";
222 $sql .=
" AND bk.code_journal IN (SELECT code FROM ".MAIN_DB_PREFIX.
"accounting_journal WHERE nature=4 AND entity=". (int)
$conf->entity.
") ";
223 $sql .=
" AND fac.entity IN (".getEntity(
'invoice', 0).
")";
225 if (
$object->code_compta_client !=
"") {
226 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_client).
"' ";
228 if (
$object->code_compta_client !=
"" &&
$object->code_compta_fournisseur !=
"") {
231 if (
$object->code_compta_fournisseur !=
"") {
232 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_fournisseur).
"' ";
236 $resql2 = $this->db->query($sql);
238 while ($obj2 = $this->db->fetch_object($resql2)) {
239 $ids[$obj2->rowid] = $obj2->rowid;
240 $ids_fact[] = $obj2->fact_id;
243 $this->errors[] = $this->db->lasterror;
246 if (count($ids_fact)) {
247 $sql =
'SELECT bk.rowid, fac.ref, fac.ref_supplier ';
248 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture fac ";
249 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"accounting_bookkeeping as bk ON( bk.fk_doc = fac.rowid AND fac.rowid IN (".$this->db->sanitize(implode(
',', $ids_fact)).
"))";
250 $sql .=
" WHERE code_journal IN (SELECT code FROM ".MAIN_DB_PREFIX.
"accounting_journal WHERE nature=2 AND entity=". (int)
$conf->entity.
") ";
251 $sql .=
" AND fac.entity IN (".getEntity(
'invoice', 0).
")";
253 if (
$object->code_compta_client !=
"") {
254 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_client).
"' ";
256 if (
$object->code_compta_client !=
"" &&
$object->code_compta_fournisseur !=
"") {
259 if (
$object->code_compta_fournisseur !=
"") {
260 $sql .=
" bk.subledger_account = '".$this->db->escape(
$object->code_compta_fournisseur).
"' ";
264 $resql2 = $this->db->query($sql);
266 while ($obj2 = $this->db->fetch_object($resql2)) {
267 $ids[$obj2->rowid] = $obj2->rowid;
269 $this->db->free($resql2);
271 $this->errors[] = $this->db->lasterror;
277 if (count($ids) > 1) {
281 $this->db->free($resql);
284 foreach ($this->errors as $errmsg) {
286 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
309 $letter = str_pad(
"",
getDolGlobalInt(
'ACCOUNTING_LETTERING_NBLETTERS', 3), $partial ?
'a' :
'A');
314 $idlist = implode(
',', array_map(
'intval', $ids));
315 $sql =
"SELECT ab.lettering_code, GROUP_CONCAT(DISTINCT ab.rowid SEPARATOR ',') AS bookkeeping_ids";
316 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS ab";
317 $sql .=
" WHERE ab.rowid IN (" . $this->db->sanitize($idlist) .
")";
318 $sql .=
" GROUP BY ab.lettering_code";
319 $sql .=
" ORDER BY ab.lettering_code DESC";
321 dol_syslog(__METHOD__ .
" - Check partial / normal lettering case", LOG_DEBUG);
322 $resql = $this->db->query($sql);
324 while ($obj = $this->db->fetch_object($resql)) {
325 if (empty($obj->lettering_code)) {
330 if ($partial && preg_match(
'/^[A-Z]+$/', $obj->lettering_code)) {
331 if (!empty($obj->bookkeeping_ids)) {
332 $ids = array_diff($ids, explode(
',', $obj->bookkeeping_ids));
334 } elseif (!$partial && preg_match(
'/^[a-z]+$/', $obj->lettering_code)) {
336 $sql2 =
"UPDATE " . MAIN_DB_PREFIX .
"accounting_bookkeeping SET";
337 $sql2 .=
" matching_general = 0";
338 $sql2 .=
", lettering_code = NULL";
339 $sql2 .=
", date_lettering = NULL";
340 $sql2 .=
" WHERE entity IN (" .
getEntity(
'accountancy') .
")";
341 $sql2 .=
" AND lettering_code = '" . $this->db->escape($obj->lettering_code) .
"'";
343 dol_syslog(__METHOD__ .
" - Remove partial lettering", LOG_DEBUG);
344 $resql2 = $this->db->query($sql2);
346 $this->errors[] =
'Error' . $this->db->lasterror();
352 $this->db->free($resql);
354 $this->errors[] =
'Error' . $this->db->lasterror();
358 if (!$error && !empty($ids)) {
360 $idlist = implode(
',', array_map(
'intval', $ids));
361 $sql =
"SELECT DISTINCT ab2.lettering_code";
362 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS ab";
363 $sql .=
" LEFT JOIN " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS ab2 ON ab2.subledger_account = ab.subledger_account";
364 $sql .=
" WHERE ab.rowid IN (" . $this->db->sanitize($idlist) .
")";
365 $sql .=
" AND ab2.lettering_code != ''";
366 $sql .=
" AND ab2.matching_general = 0";
367 $sql .=
" ORDER BY ab2.lettering_code DESC";
369 dol_syslog(__METHOD__ .
" - Get next code", LOG_DEBUG);
370 $resql = $this->db->query($sql);
372 while ($obj = $this->db->fetch_object($resql)) {
373 if (!empty($obj->lettering_code) &&
374 (($partial && preg_match(
'/^[a-z]+$/', $obj->lettering_code)) ||
375 (!$partial && preg_match(
'/^[A-Z]+$/', $obj->lettering_code)))
377 $letter = $obj->lettering_code;
382 $this->db->free($resql);
384 $this->errors[] =
'Error' . $this->db->lasterror();
389 if (!$error && !$partial) {
390 $idlist = implode(
',', array_map(
'intval', $ids));
391 $sql =
"SELECT SUM(ABS(debit)) as deb, SUM(ABS(credit)) as cred";
392 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping";
393 $sql .=
" WHERE rowid IN (" . $this->db->sanitize($idlist) .
")";
394 $sql .=
" AND lettering_code IS NULL";
395 $sql .=
" AND subledger_account != ''";
397 dol_syslog(__METHOD__ .
" - Test amount integrity", LOG_DEBUG);
398 $resql = $this->db->query($sql);
400 if ($obj = $this->db->fetch_object($resql)) {
401 if (!(round(abs($obj->deb), 2) === round(abs($obj->cred), 2))) {
402 $this->errors[] = $langs->trans(
'ErrorMatchingUnbalanced',
price(
price2num(abs($obj->deb),
'MT')),
price(
price2num(abs($obj->cred),
'MT')));
406 $this->db->free($resql);
408 $this->errors[] =
'SQL Error message: ' . $this->db->lasterror();
415 $idlist = implode(
',', array_map(
'intval', $ids));
416 $sql =
"UPDATE " . MAIN_DB_PREFIX .
"accounting_bookkeeping SET";
417 $sql .=
" lettering_code='" . $this->db->escape($letter) .
"'";
418 $sql .=
", date_lettering = '" . $this->db->idate($now) .
"'";
419 $sql .=
", matching_general = 0";
420 $sql .=
" WHERE rowid IN (" . $this->db->sanitize($idlist) .
")";
421 $sql .=
" AND lettering_code IS NULL";
422 $sql .=
" AND subledger_account != ''";
424 dol_syslog(__METHOD__ .
" - Update lettering code", LOG_DEBUG);
425 $resql = $this->db->query($sql);
428 $this->errors[] =
"Error " . $this->db->lasterror();
430 $affected_rows = $this->db->affected_rows($resql);
437 $this->db->rollback();
438 foreach ($this->errors as $errmsg) {
439 dol_syslog(get_class($this) .
"::update " . $errmsg, LOG_ERR);
440 $this->error .= ($this->error ?
', ' . $errmsg : $errmsg);
445 return $affected_rows;
526 global
$conf, $langs;
533 $letter = str_pad(
"",
getDolGlobalInt(
'ACCOUNTING_LETTERING_NBLETTERS', 3), $partial ?
'a' :
'A');
537 $idlist = implode(
',', array_map(
'intval', $ids));
538 $sql =
"SELECT DISTINCT numero_compte";
539 $sql .=
" FROM " . $this->db->prefix() .
"accounting_bookkeeping AS ab";
540 $sql .=
" LEFT JOIN (";
541 $sql .=
" SELECT aa.rowid, aa.account_number";
542 $sql .=
" FROM " . $this->db->prefix() .
"accounting_account AS aa";
543 $sql .=
" INNER JOIN " . $this->db->prefix() .
"accounting_system AS asys ON asys.pcg_version = aa.fk_pcg_version";
544 $sql .=
" WHERE asys.rowid = ".(int) $pcgId.
" AND aa.reconcilable";
545 $sql .=
" ) AS reconciliable_accounts ON reconciliable_accounts.account_number = ab.numero_compte";
546 $sql .=
" WHERE ab.rowid IN (" . $this->db->sanitize($idlist) .
")";
547 $sql .=
" AND reconciliable_accounts.rowid IS NULL";
549 $resql = $this->db->query($sql);
551 while ($obj = $this->db->fetch_object($resql)) {
552 $this->errors[] = $langs->trans(
553 'ErrorAccountNotReconcilable',
555 dol_buildpath(
'accountancy/admin/account.php', 1) .
'?search_account=' . $obj->numero_compte,
556 $langs->transnoentitiesnoconv(
'Chartofaccounts')
560 $this->db->free($resql);
562 $this->errors[] =
'Error' . $this->db->lasterror();
567 $idlist = implode(
',', array_map(
'intval', $ids));
568 $sql =
"SELECT fy.rowid, fy.date_start, fy.date_end, COUNT(DISTINCT fy.rowid) AS nb_fiscalyears";
569 $sql .=
" FROM " . $this->db->prefix() .
"accounting_bookkeeping AS ab";
570 $sql .=
" INNER JOIN " . $this->db->prefix() .
"accounting_fiscalyear AS fy";
571 $sql .=
" ON ab.doc_date BETWEEN fy.date_start AND fy.date_end";
572 $sql .=
" AND fy.entity = " . (int)
$conf->entity;
573 $sql .=
" WHERE ab.rowid IN (" . $this->db->sanitize($idlist) .
")";
574 $sql .=
" GROUP BY fy.rowid, fy.date_start, fy.date_end";
576 dol_syslog(__METHOD__ .
" - Get fiscal year", LOG_DEBUG);
577 $resql = $this->db->query($sql);
579 $this->errors[] =
'Error ' . $this->db->lasterror();
583 $fiscalYearRows = [];
584 while ($obj = $this->db->fetch_object($resql)) {
585 $fiscalYearRows[] = $obj;
587 $this->db->free($resql);
590 if (empty($fiscalYearRows)) {
591 $this->errors[] = $langs->trans(
'ErrorFiscalYearNotFound');
596 if (count($fiscalYearRows) > 1) {
597 $periods = array_map(
607 $this->errors[] = $langs->transnoentitiesnoconv(
'ErrorMatchingCrossFiscalYear', implode(
', ', $periods));
611 $fiscalYear = $fiscalYearRows[0];
612 $fiscalYearStart = $this->db->jdate($fiscalYear->date_start);
613 $fiscalYearEnd = $this->db->jdate($fiscalYear->date_end);
618 $idlist = implode(
',', array_map(
'intval', $ids));
619 $sql =
"SELECT ab.lettering_code, GROUP_CONCAT(DISTINCT ab.rowid SEPARATOR ',') AS bookkeeping_ids";
620 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS ab";
621 $sql .=
" WHERE ab.rowid IN (" . $this->db->sanitize($idlist) .
")";
622 $sql .=
" GROUP BY ab.lettering_code";
623 $sql .=
" ORDER BY ab.lettering_code DESC";
625 dol_syslog(__METHOD__ .
" - Check partial / normal lettering case", LOG_DEBUG);
626 $resql = $this->db->query($sql);
628 while ($obj = $this->db->fetch_object($resql)) {
629 if (empty($obj->lettering_code)) {
634 if ($partial && preg_match(
'/^[A-Z]+$/', $obj->lettering_code)) {
635 if (!empty($obj->bookkeeping_ids)) {
636 $ids = array_diff($ids, explode(
',', $obj->bookkeeping_ids));
638 } elseif (!$partial && preg_match(
'/^[a-z]+$/', $obj->lettering_code)) {
640 $sql2 =
"UPDATE " . MAIN_DB_PREFIX .
"accounting_bookkeeping SET";
641 $sql2 .=
" matching_general = 1";
642 $sql2 .=
", lettering_code = NULL";
643 $sql2 .=
", date_lettering = NULL";
644 $sql2 .=
" WHERE entity IN (" .
getEntity(
'accountancy') .
")";
645 $sql2 .=
" AND lettering_code = '" . $this->db->escape($obj->lettering_code) .
"'";
647 dol_syslog(__METHOD__ .
" - Remove partial lettering", LOG_DEBUG);
648 $resql2 = $this->db->query($sql2);
650 $this->errors[] =
'Error' . $this->db->lasterror();
656 $this->db->free($resql);
658 $this->errors[] =
'Error' . $this->db->lasterror();
662 if (!$error && !empty($ids)) {
664 $idlist = implode(
',', array_map(
'intval', $ids));
665 $sql =
"SELECT DISTINCT ab2.lettering_code";
666 $sql .=
" FROM " . $this->db->prefix() .
"accounting_bookkeeping AS ab";
667 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"accounting_bookkeeping AS ab2 ON ab2.numero_compte = ab.numero_compte";
668 $sql .=
" WHERE ab.rowid IN (" . $this->db->sanitize($idlist) .
")";
669 $sql .=
" AND ab2.lettering_code != ''";
670 $sql .=
" AND ab2.matching_general = 1";
671 $sql .=
" AND ab2.doc_date BETWEEN '" . $this->db->idate($fiscalYearStart) .
"' AND '" . $this->db->idate($fiscalYearEnd) .
"'";
672 $sql .=
" ORDER BY ab2.lettering_code DESC";
674 dol_syslog(__METHOD__ .
" - Get next code", LOG_DEBUG);
675 $resql = $this->db->query($sql);
677 while ($obj = $this->db->fetch_object($resql)) {
678 if (!empty($obj->lettering_code) &&
679 (($partial && preg_match(
'/^[a-z]+$/', $obj->lettering_code)) ||
680 (!$partial && preg_match(
'/^[A-Z]+$/', $obj->lettering_code)))
682 $letter = $obj->lettering_code;
687 $this->db->free($resql);
689 $this->errors[] =
'Error' . $this->db->lasterror();
694 if (!$error && !$partial) {
695 $idlist = implode(
',', array_map(
'intval', $ids));
696 $sql =
"SELECT SUM(ABS(debit)) as deb, SUM(ABS(credit)) as cred";
697 $sql .=
" FROM " . $this->db->prefix() .
"accounting_bookkeeping";
698 $sql .=
" WHERE rowid IN (" . $this->db->sanitize($idlist) .
")";
699 $sql .=
" AND lettering_code IS NULL";
701 dol_syslog(__METHOD__ .
" - Test amount integrity", LOG_DEBUG);
702 $resql = $this->db->query($sql);
704 if ($obj = $this->db->fetch_object($resql)) {
705 if (!(round(abs($obj->deb), 2) === round(abs($obj->cred), 2))) {
706 $this->errors[] = $langs->trans(
'ErrorMatchingUnbalanced',
price(
price2num(abs($obj->deb),
'MT')),
price(
price2num(abs($obj->cred),
'MT')));
710 $this->db->free($resql);
712 $this->errors[] =
'SQL Error message: ' . $this->db->lasterror();
719 $idlist = implode(
',', array_map(
'intval', $ids));
720 $sql =
"UPDATE " . $this->db->prefix() .
"accounting_bookkeeping SET";
721 $sql .=
" lettering_code='" . $this->db->escape($letter) .
"'";
722 $sql .=
", date_lettering = '" . $this->db->idate($now) .
"'";
723 $sql .=
", matching_general = 1";
724 $sql .=
" WHERE rowid IN (" . $this->db->sanitize($idlist) .
")";
725 $sql .=
" AND lettering_code IS NULL";
727 dol_syslog(__METHOD__ .
" - Update general lettering code", LOG_DEBUG);
728 $resql = $this->db->query($sql);
731 $this->errors[] =
"Error " . $this->db->lasterror();
733 $affected_rows = $this->db->affected_rows($resql);
740 $this->db->rollback();
741 foreach ($this->errors as $errmsg) {
742 dol_syslog(get_class($this) .
"::update " . $errmsg, LOG_ERR);
743 $this->error .= ($this->error ?
', ' . $errmsg : $errmsg);
748 return $affected_rows;
766 $idlist = implode(
',', array_map(
'intval', $ids));
767 $sql =
"SELECT DISTINCT ab.lettering_code, ab.numero_compte, fy.date_start, fy.date_end";
768 $sql .=
" FROM " . $this->db->prefix() .
"accounting_bookkeeping AS ab";
769 $sql .=
" INNER JOIN " . $this->db->prefix() .
"accounting_fiscalyear AS fy";
770 $sql .=
" ON ab.doc_date BETWEEN fy.date_start AND fy.date_end";
771 $sql .=
" AND fy.entity = " . (int)
$conf->entity;
772 $sql .=
" WHERE ab.rowid IN (" . $this->db->sanitize($idlist) .
")";
773 $sql .=
" AND ab.matching_general = 1";
774 $sql .=
" AND ab.lettering_code IS NOT NULL AND ab.lettering_code != ''";
776 dol_syslog(__METHOD__ .
" - Collect lettering groups to delete", LOG_DEBUG);
777 $resql = $this->db->query($sql);
779 $this->errors[] =
'Error ' . $this->db->lasterror();
784 while ($obj = $this->db->fetch_object($resql)) {
786 'code' => $obj->lettering_code,
787 'compte' => $obj->numero_compte,
788 'date_start' => $obj->date_start,
789 'date_end' => $obj->date_end,
792 $this->db->free($resql);
794 if (empty($groups)) {
800 foreach ($groups as $group) {
801 $sql =
"UPDATE " . $this->db->prefix() .
"accounting_bookkeeping SET";
802 $sql .=
" lettering_code = NULL";
803 $sql .=
", date_lettering = NULL";
804 $sql .=
", matching_general = 0";
805 $sql .=
" WHERE numero_compte = '" . $this->db->escape($group[
'compte']) .
"'";
806 $sql .=
" AND lettering_code = '" . $this->db->escape($group[
'code']) .
"'";
807 $sql .=
" AND matching_general = 1";
808 $sql .=
" AND doc_date BETWEEN '" . $this->db->escape($group[
'date_start']) .
"' AND '" . $this->db->escape($group[
'date_end']) .
"'";
810 dol_syslog(__METHOD__ .
" - Delete gl matching group " . $group[
'code'] .
"/" . $group[
'compte'], LOG_DEBUG);
811 $resql = $this->db->query($sql);
814 $this->errors[] =
'Error ' . $this->db->lasterror();
817 $affected += $this->db->affected_rows($resql);
821 foreach ($this->errors as $errmsg) {
822 dol_syslog(get_class($this) .
"::deleteGeneralMatching " . $errmsg, LOG_ERR);
823 $this->error .= ($this->error ?
', ' . $errmsg : $errmsg);
842 $this->errors = array();
845 $bookkeeping_ids = is_array($bookkeeping_ids) ? $bookkeeping_ids : array();
850 if (!is_array($grouped_lines)) {
854 foreach ($grouped_lines as $lines) {
857 $do_it = !$unlettering;
858 $lettering_code =
null;
859 $piece_num_lines = array();
860 $bookkeeping_lines = array();
861 foreach ($lines as $line_infos) {
862 $bookkeeping_lines[$line_infos[
'id']] = $line_infos[
'id'];
863 $piece_num_lines[$line_infos[
'piece_num']] = $line_infos[
'piece_num'];
864 $total += ($line_infos[
'credit'] > 0 ? $line_infos[
'credit'] : -$line_infos[
'debit']);
868 if (isset($lettering_code) && $lettering_code != $line_infos[
'lettering_code']) {
869 $this->errors[] = $langs->trans(
'AccountancyErrorMismatchLetteringCode');
873 if (!isset($lettering_code)) {
874 $lettering_code = (
string) $line_infos[
'lettering_code'];
876 if (!empty($line_infos[
'lettering_code'])) {
879 } elseif (!empty($line_infos[
'lettering_code'])) {
885 if (!$group_error && !$unlettering &&
price2num($total) != 0) {
886 $this->errors[] = $langs->trans(
'AccountancyErrorMismatchBalanceAmount', $total);
891 if (!$group_error && $do_it) {
899 } elseif ($result > 0) {
905 $this->errors[] = $langs->trans(
'AccountancyErrorLetteringBookkeeping', implode(
', ', $piece_num_lines));
911 return -2 - $nb_lettering;
913 return $nb_lettering;
924 public function getLinkedLines($bookkeeping_ids, $only_has_subledger_account =
true)
926 global
$conf, $langs;
927 $this->errors = array();
930 $bookkeeping_ids = is_array($bookkeeping_ids) ? $bookkeeping_ids : array();
933 $sql =
"SELECT DISTINCT ab.doc_type, ab.fk_doc";
934 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS ab";
935 $sql .=
" WHERE ab.entity IN (" .
getEntity(
'accountancy') .
")";
936 $sql .=
" AND ab.fk_doc > 0";
937 if (!empty($bookkeeping_ids)) {
939 $sql .=
" AND EXISTS (";
940 $sql .=
" SELECT rowid";
941 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS pn";
942 $sql .=
" WHERE pn.entity IN (" .
getEntity(
'accountancy') .
")";
943 $sql .=
" AND pn.rowid IN (" . $this->db->sanitize(implode(
',', $bookkeeping_ids)) .
")";
944 $sql .=
" AND pn.piece_num = ab.piece_num";
947 if ($only_has_subledger_account) {
948 $sql .=
" AND ab.subledger_account != ''";
951 dol_syslog(__METHOD__ .
" - Get all bookkeeping lines", LOG_DEBUG);
952 $resql = $this->db->query($sql);
954 $this->errors[] =
"Error " . $this->db->lasterror();
958 $bookkeeping_lines_by_type = array();
959 while ($obj = $this->db->fetch_object($resql)) {
960 $bookkeeping_lines_by_type[$obj->doc_type][$obj->fk_doc] = $obj->fk_doc;
962 $this->db->free($resql);
964 if (empty($bookkeeping_lines_by_type)) {
968 if (!empty($bookkeeping_lines_by_type[
'bank'])) {
970 if (!is_array($new_bookkeeping_lines_by_type)) {
973 foreach ($new_bookkeeping_lines_by_type as $doc_type => $fk_docs) {
974 foreach ($fk_docs as $fk_doc) {
975 $bookkeeping_lines_by_type[$doc_type][$fk_doc] = $fk_doc;
980 $grouped_lines = array();
981 foreach (self::$doc_type_infos as $doc_type => $doc_type_info) {
982 if (empty($bookkeeping_lines_by_type[$doc_type]) || !is_array($bookkeeping_lines_by_type[$doc_type])) {
988 if (!is_array($doc_grouped)) {
993 foreach ($doc_grouped as $doc_ids) {
995 if (!is_array($bank_ids)) {
1000 $sql =
"SELECT DISTINCT ab.rowid, ab.piece_num, ab.debit, ab.credit, ab.lettering_code";
1001 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS ab";
1002 $sql .=
" WHERE ab.entity IN (" .
getEntity(
'accountancy') .
")";
1004 if (!empty($bank_ids)) {
1005 $sql .=
" EXISTS (";
1006 $sql .=
" SELECT bpn.rowid";
1007 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS bpn";
1008 $sql .=
" WHERE bpn.entity IN (" .
getEntity(
'accountancy') .
")";
1009 $sql .=
" AND bpn.doc_type = 'bank'";
1010 $sql .=
" AND bpn.fk_doc IN (" . $this->db->sanitize(implode(
',', $bank_ids)) .
")";
1011 $sql .=
" AND bpn.piece_num = ab.piece_num";
1014 $sql .=
" EXISTS (";
1015 $sql .=
" SELECT dpn.rowid";
1016 $sql .=
" FROM " . MAIN_DB_PREFIX .
"accounting_bookkeeping AS dpn";
1017 $sql .=
" WHERE dpn.entity IN (" .
getEntity(
'accountancy') .
")";
1018 $sql .=
" AND dpn.doc_type = '" . $this->db->escape($doc_type) .
"'";
1019 $sql .=
" AND dpn.fk_doc IN (" . $this->db->sanitize(implode(
',', $doc_ids)) .
")";
1020 $sql .=
" AND dpn.piece_num = ab.piece_num";
1023 if ($only_has_subledger_account) {
1024 $sql .=
" AND ab.subledger_account != ''";
1027 dol_syslog(__METHOD__ .
" - Get all bookkeeping lines linked", LOG_DEBUG);
1028 $resql = $this->db->query($sql);
1030 $this->errors[] =
"Error " . $this->db->lasterror();
1035 while ($obj = $this->db->fetch_object($resql)) {
1036 $group[$obj->rowid] = array(
1037 'id' => $obj->rowid,
1038 'piece_num' => $obj->piece_num,
1039 'debit' => $obj->debit,
1040 'credit' => $obj->credit,
1041 'lettering_code' => $obj->lettering_code,
1044 $this->db->free($resql);
1046 if (!empty($group)) {
1047 $grouped_lines[] = $group;
1052 return $grouped_lines;
1063 dol_syslog(__METHOD__ .
" - bank_ids=".json_encode($bank_ids), LOG_DEBUG);
1066 $bank_ids = is_array($bank_ids) ? $bank_ids : array();
1068 if (empty($bank_ids)) {
1072 $bookkeeping_lines_by_type = array();
1073 foreach (self::$doc_type_infos as $doc_type => $doc_type_info) {
1075 $sql =
"SELECT DISTINCT dp." . $this->db->sanitize($doc_type_info[
'doc_payment_table_fk_doc']) .
" AS fk_doc";
1076 $sql .=
" FROM " . MAIN_DB_PREFIX . $this->db->sanitize($doc_type_info[
'payment_table']) .
" AS p";
1077 $sql .=
" LEFT JOIN " . MAIN_DB_PREFIX . $this->db->sanitize($doc_type_info[
'doc_payment_table']) .
" AS dp ON dp." . $this->db->sanitize($doc_type_info[
'doc_payment_table_fk_payment']) .
" = p.rowid";
1078 $sql .=
" WHERE p." . $this->db->sanitize($doc_type_info[
'payment_table_fk_bank']) .
" IN (" . $this->db->sanitize(implode(
',', $bank_ids)) .
")";
1079 $sql .=
" AND dp." . $this->db->sanitize($doc_type_info[
'doc_payment_table_fk_doc']) .
" > 0";
1081 dol_syslog(__METHOD__ .
" - Get all fk_doc by doc_type from list of bank ids for '" . $doc_type .
"'", LOG_DEBUG);
1082 $resql = $this->db->query($sql);
1084 $this->errors[] =
"Error " . $this->db->lasterror();
1088 while ($obj = $this->db->fetch_object($resql)) {
1089 $bookkeeping_lines_by_type[$doc_type][$obj->fk_doc] = $obj->fk_doc;
1091 $this->db->free($resql);
1094 return $bookkeeping_lines_by_type;
1108 dol_syslog(__METHOD__ .
" - bank_ids=".json_encode($document_ids) .
", doc_type=$doc_type", LOG_DEBUG);
1111 $document_ids = is_array($document_ids) ? $document_ids : array();
1113 $document_ids = array_filter($document_ids);
1115 $doc_type = trim($doc_type);
1117 if (empty($document_ids)) {
1120 if (!is_array(self::$doc_type_infos[$doc_type])) {
1121 $langs->load(
'errors');
1122 $this->errors[] = $langs->trans(
'ErrorBadParameters');
1126 $doc_type_info = self::$doc_type_infos[$doc_type];
1127 $bank_ids = array();
1130 $sql =
"SELECT DISTINCT p." . $this->db->sanitize($doc_type_info[
'payment_table_fk_bank']) .
" AS fk_doc";
1131 $sql .=
" FROM " . MAIN_DB_PREFIX . $this->db->sanitize($doc_type_info[
'payment_table']) .
" AS p";
1132 $sql .=
" LEFT JOIN " . MAIN_DB_PREFIX . $this->db->sanitize($doc_type_info[
'doc_payment_table']) .
" AS dp ON dp." . $this->db->sanitize($doc_type_info[
'doc_payment_table_fk_payment']) .
" = p.rowid";
1134 $sql .=
" WHERE dp." . $this->db->sanitize($doc_type_info[
'doc_payment_table_fk_doc']) .
" IN (" . $this->db->sanitize(implode(
',', $document_ids)) .
")";
1135 $sql .=
" AND p." . $this->db->sanitize($doc_type_info[
'payment_table_fk_bank']) .
" > 0";
1137 dol_syslog(__METHOD__ .
" - Get all bank ids from list of document ids of a type '" . $doc_type .
"'", LOG_DEBUG);
1138 $resql = $this->db->query($sql);
1140 $this->errors[] =
"Error " . $this->db->lasterror();
1144 while ($obj = $this->db->fetch_object($resql)) {
1145 $bank_ids[$obj->fk_doc] = $obj->fk_doc;
1147 $this->db->free($resql);
1164 $document_ids = is_array($document_ids) ? $document_ids : array();
1165 $doc_type = trim($doc_type);
1167 $document_ids = array_filter($document_ids);
1169 if (empty($document_ids)) {
1173 if (!is_array(self::$doc_type_infos[$doc_type])) {
1174 $langs->load(
'errors');
1175 $this->errors[] = $langs->trans(
'ErrorBadParameters');
1179 $doc_type_info = self::$doc_type_infos[$doc_type];
1182 $current_document_ids = array();
1183 $link_by_element = array();
1184 $element_by_link = array();
1185 foreach ($doc_type_info[
'linked_info'] as $linked_info) {
1186 if (empty($linked_info[
'fk_line_link'])) {
1187 $sql =
"SELECT DISTINCT tl2.".$this->db->sanitize($linked_info[
'fk_link']).
" AS fk_link, tl2.".$this->db->sanitize($linked_info[
'fk_doc']).
" AS fk_doc";
1188 $sql .=
" FROM ".MAIN_DB_PREFIX.$this->db->sanitize($linked_info[
'table']).
" AS tl";
1189 $sql .=
" LEFT JOIN ".MAIN_DB_PREFIX.$this->db->sanitize($linked_info[
'table']).
" AS tl2 ON tl2.".$this->db->sanitize($linked_info[
'fk_link']).
" = tl.".$this->db->sanitize($linked_info[
'fk_link']);
1190 $sql .=
" WHERE tl.".$this->db->sanitize($linked_info[
'fk_doc']).
" IN (".$this->db->sanitize(implode(
',', $document_ids)).
")";
1192 $sql =
"SELECT DISTINCT tl2.fk_link, tl2.fk_doc";
1195 $sql .=
" SELECT DISTINCT " . $this->db->ifsql(
"tll.".$this->db->sanitize($linked_info[
'fk_table_link_line_parent']).
" IS NOT NULL",
"tll.".$this->db->sanitize($linked_info[
'fk_table_link_line_parent']),
"tl.".$this->db->sanitize($linked_info[
'fk_link'])).
" AS fk_link, tl.".$this->db->sanitize($linked_info[
'fk_doc']).
" AS fk_doc";
1196 $sql .=
" FROM " . MAIN_DB_PREFIX .$this->db->sanitize($linked_info[
'table']).
" AS tl";
1198 $sql .=
" LEFT JOIN " . MAIN_DB_PREFIX . $this->db->sanitize($linked_info[
'table_link_line']) .
" AS tll ON tll.".$this->db->sanitize($linked_info[
'fk_table_link_line']) .
" = tl.".$this->db->sanitize($linked_info[
'fk_line_link']);
1200 $sql .=
" LEFT JOIN (";
1202 $sql .=
" SELECT DISTINCT " . $this->db->ifsql(
"tll.".$this->db->sanitize($linked_info[
'fk_table_link_line_parent']).
" IS NOT NULL",
"tll.".$this->db->sanitize($linked_info[
'fk_table_link_line_parent']),
"tl.".$this->db->sanitize($linked_info[
'fk_link'])).
" AS fk_link, tl.".$this->db->sanitize($linked_info[
'fk_doc']).
" AS fk_doc";
1203 $sql .=
" FROM " . MAIN_DB_PREFIX .$this->db->sanitize($linked_info[
'table']).
" AS tl";
1205 $sql .=
" LEFT JOIN " . MAIN_DB_PREFIX . $this->db->sanitize($linked_info[
'table_link_line']) .
" AS tll ON tll.".$this->db->sanitize($linked_info[
'fk_table_link_line']) .
" = tl.".$this->db->sanitize($linked_info[
'fk_line_link']);
1206 $sql .=
") AS tl2 ON tl2.fk_link = tl.fk_link";
1207 $sql .=
" WHERE tl.fk_doc IN (" . $this->db->sanitize(implode(
',', $document_ids)) .
")";
1208 $sql .=
" AND tl2.fk_doc IS NOT NULL";
1211 dol_syslog(__METHOD__ .
" - Get document lines", LOG_DEBUG);
1212 $resql = $this->db->query($sql);
1214 $this->errors[] =
"Error " . $this->db->lasterror();
1218 $is_fk_link_is_also_fk_doc = !empty($linked_info[
'is_fk_link_is_also_fk_doc']);
1219 while ($obj = $this->db->fetch_object($resql)) {
1220 $current_document_ids[$obj->fk_doc] = $obj->fk_doc;
1222 $link_key = (
string) $linked_info[
'prefix'] . (
string) $obj->fk_link;
1223 $element_by_link[$link_key][$obj->fk_doc] = $obj->fk_doc;
1224 $link_by_element[(int) $obj->fk_doc][$link_key] = $link_key;
1225 if ($is_fk_link_is_also_fk_doc) {
1226 $element_by_link[$link_key][$obj->fk_link] = $obj->fk_link;
1227 $link_by_element[(int) $obj->fk_link][$link_key] = $link_key;
1230 $this->db->free($resql);
1233 if (count(array_diff($document_ids, $current_document_ids))) {
1249 public function getGroupElements(&$link_by_element, &$element_by_link, $link_key =
'', &$current_group = array())
1251 $grouped_elements = array();
1252 if (!empty($link_key) && !isset($element_by_link[$link_key])) {
1254 return $grouped_elements;
1258 if (empty($link_key)) {
1260 $save_link_by_element = $link_by_element;
1261 $save_element_by_link = $element_by_link;
1264 $save_link_by_element =
null;
1265 $save_element_by_link =
null;
1270 $current_link_key = !empty($link_key) ? $link_key : array_keys($element_by_link)[0];
1271 $element_ids = $element_by_link[$current_link_key];
1272 unset($element_by_link[$current_link_key]);
1274 foreach ($element_ids as $element_id) {
1276 if (!isset($link_by_element[$element_id])) {
1281 $current_group[$element_id] = $element_id;
1284 $link_keys = $link_by_element[$element_id];
1285 unset($link_by_element[$element_id]);
1288 foreach ($link_keys as $key) {
1289 $this->
getGroupElements($link_by_element, $element_by_link, (
string) $key, $current_group);
1293 if (empty($link_key)) {
1295 $grouped_elements[] = $current_group;
1296 $current_group = array();
1298 }
while (!empty($element_by_link) && empty($link_key));
1300 if (empty($link_key)) {
1302 $link_by_element = $save_link_by_element;
1303 $element_by_link = $save_element_by_link;
1306 return $grouped_elements;