dolibarr  20.0.0-beta
sellsjournal.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2007-2010 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2007-2010 Jean Heimburger <jean@tiaris.info>
4  * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
5  * Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
6  * Copyright (C) 2013 Christophe Battarel <christophe.battarel@altairis.fr>
7  * Copyright (C) 2013-2023 Alexandre Spangaro <aspangaro@easya.solutions>
8  * Copyright (C) 2013-2016 Florian Henry <florian.henry@open-concept.pro>
9  * Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
10  * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
11  * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
12  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program. If not, see <https://www.gnu.org/licenses/>.
26  */
27 
34 // Load Dolibarr environment
35 require '../../main.inc.php';
36 require_once DOL_DOCUMENT_ROOT.'/core/lib/report.lib.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
39 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
40 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
41 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
42 require_once DOL_DOCUMENT_ROOT.'/societe/class/client.class.php';
43 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php';
44 
45 // Load translation files required by the page
46 $langs->loadLangs(array("commercial", "compta", "bills", "other", "accountancy", "errors"));
47 
48 $id_journal = GETPOSTINT('id_journal');
49 $action = GETPOST('action', 'aZ09');
50 
51 $date_startmonth = GETPOST('date_startmonth');
52 $date_startday = GETPOST('date_startday');
53 $date_startyear = GETPOST('date_startyear');
54 $date_endmonth = GETPOST('date_endmonth');
55 $date_endday = GETPOST('date_endday');
56 $date_endyear = GETPOST('date_endyear');
57 $in_bookkeeping = GETPOST('in_bookkeeping');
58 if ($in_bookkeeping == '') {
59  $in_bookkeeping = 'notyet';
60 }
61 
62 $now = dol_now();
63 
64 $hookmanager->initHooks(array('sellsjournal'));
65 $parameters = array();
66 
67 // Security check
68 if (!isModEnabled('accounting')) {
70 }
71 if ($user->socid > 0) {
73 }
74 if (!$user->hasRight('accounting', 'bind', 'write')) {
76 }
77 
78 $error = 0;
79 
80 
81 /*
82  * Actions
83  */
84 
85 $reshook = $hookmanager->executeHooks('doActions', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
86 
87 $accountingaccount = new AccountingAccount($db);
88 
89 // Get information of journal
90 $accountingjournalstatic = new AccountingJournal($db);
91 $accountingjournalstatic->fetch($id_journal);
92 $journal = $accountingjournalstatic->code;
93 $journal_label = $accountingjournalstatic->label;
94 
95 $date_start = dol_mktime(0, 0, 0, $date_startmonth, $date_startday, $date_startyear);
96 $date_end = dol_mktime(23, 59, 59, $date_endmonth, $date_endday, $date_endyear);
97 
98 if (empty($date_startmonth)) {
99  // Period by default on transfer
100  $dates = getDefaultDatesForTransfer();
101  $date_start = $dates['date_start'];
102  $pastmonthyear = $dates['pastmonthyear'];
103  $pastmonth = $dates['pastmonth'];
104 }
105 if (empty($date_endmonth)) {
106  // Period by default on transfer
107  $dates = getDefaultDatesForTransfer();
108  $date_end = $dates['date_end'];
109  $pastmonthyear = $dates['pastmonthyear'];
110  $pastmonth = $dates['pastmonth'];
111 }
112 if (getDolGlobalString('ACCOUNTANCY_JOURNAL_USE_CURRENT_MONTH')) {
113  $pastmonth += 1;
114 }
115 
116 if (!GETPOSTISSET('date_startmonth') && (empty($date_start) || empty($date_end))) { // We define date_start and date_end, only if we did not submit the form
117  $date_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
118  $date_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
119 }
120 
121 $sql = "SELECT f.rowid, f.ref, f.type, f.situation_cycle_ref, f.datef as df, f.ref_client, f.date_lim_reglement as dlr, f.close_code, f.retained_warranty, f.revenuestamp,";
122 $sql .= " fd.rowid as fdid, fd.description, fd.product_type, fd.total_ht, fd.total_tva, fd.total_localtax1, fd.total_localtax2, fd.tva_tx, fd.total_ttc, fd.situation_percent, fd.vat_src_code, fd.info_bits,";
123 $sql .= " s.rowid as socid, s.nom as name, s.code_client, s.code_fournisseur,";
124 if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
125  $sql .= " spe.accountancy_code_customer as code_compta,";
126  $sql .= " spe.accountancy_code_supplier as code_compta_fournisseur,";
127 } else {
128  $sql .= " s.code_compta as code_compta,";
129  $sql .= " s.code_compta_fournisseur,";
130 }
131 $sql .= " p.rowid as pid, p.ref as pref, aa.rowid as fk_compte, aa.account_number as compte, aa.label as label_compte,";
132 if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
133  $sql .= " ppe.accountancy_code_sell";
134 } else {
135  $sql .= " p.accountancy_code_sell";
136 }
137 $parameters = array();
138 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
139 $sql .= $hookmanager->resPrint;
140 $sql .= " FROM ".MAIN_DB_PREFIX."facturedet as fd";
141 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = fd.fk_product";
142 if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
143  $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
144 }
145 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa ON aa.rowid = fd.fk_code_ventilation";
146 $sql .= " JOIN ".MAIN_DB_PREFIX."facture as f ON f.rowid = fd.fk_facture";
147 $sql .= " JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = f.fk_soc";
148 if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
149  $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity);
150 }
151 $parameters = array();
152 $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters); // Note that $action and $object may have been modified by hook
153 $sql .= $hookmanager->resPrint;
154 $sql .= " WHERE fd.fk_code_ventilation > 0";
155 $sql .= " AND f.entity IN (".getEntity('invoice', 0).')'; // We don't share object for accountancy, we use source object sharing
156 $sql .= " AND f.fk_statut > 0";
157 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) { // Non common setup
158  $sql .= " AND f.type IN (".Facture::TYPE_STANDARD.",".Facture::TYPE_REPLACEMENT.",".Facture::TYPE_CREDIT_NOTE.",".Facture::TYPE_SITUATION.")";
159 } else {
160  $sql .= " AND f.type IN (".Facture::TYPE_STANDARD.",".Facture::TYPE_REPLACEMENT.",".Facture::TYPE_CREDIT_NOTE.",".Facture::TYPE_DEPOSIT.",".Facture::TYPE_SITUATION.")";
161 }
162 $sql .= " AND fd.product_type IN (0,1)";
163 if ($date_start && $date_end) {
164  $sql .= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'";
165 }
166 // Define begin binding date
167 if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
168  $sql .= " AND f.datef >= '".$db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING'))."'";
169 }
170 // Already in bookkeeping or not
171 if ($in_bookkeeping == 'already') {
172  $sql .= " AND f.rowid IN (SELECT fk_doc FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='customer_invoice')";
173  // $sql .= " AND fd.rowid IN (SELECT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab WHERE ab.doc_type='customer_invoice')"; // Useless, we save one line for all products with same account
174 }
175 if ($in_bookkeeping == 'notyet') {
176  $sql .= " AND f.rowid NOT IN (SELECT fk_doc FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='customer_invoice')";
177  // $sql .= " AND fd.rowid NOT IN (SELECT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab WHERE ab.doc_type='customer_invoice')"; // Useless, we save one line for all products with same account
178 }
179 $parameters = array();
180 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
181 $sql .= $hookmanager->resPrint;
182 $sql .= " ORDER BY f.datef, f.ref";
183 //print $sql;
184 
185 dol_syslog('accountancy/journal/sellsjournal.php', LOG_DEBUG);
186 $result = $db->query($sql);
187 if ($result) {
188  $tabfac = array();
189  $tabht = array();
190  $tabtva = array();
191  $def_tva = array();
192  $tabwarranty = array();
193  $tabrevenuestamp = array();
194  $tabttc = array();
195  $tablocaltax1 = array();
196  $tablocaltax2 = array();
197  $tabcompany = array();
198  $vatdata_cache = array();
199 
200  $num = $db->num_rows($result);
201 
202  // Variables
203  $cptcli = getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER', 'NotDefined');
204  $cpttva = getDolGlobalString('ACCOUNTING_VAT_SOLD_ACCOUNT', 'NotDefined');
205 
206  $i = 0;
207  while ($i < $num) {
208  $obj = $db->fetch_object($result);
209 
210  // Controls
211  $compta_soc = (!empty($obj->code_compta)) ? $obj->code_compta : $cptcli;
212 
213  $compta_prod = $obj->compte;
214  if (empty($compta_prod)) {
215  if ($obj->product_type == 0) {
216  $compta_prod = getDolGlobalString('ACCOUNTING_PRODUCT_SOLD_ACCOUNT', 'NotDefined');
217  } else {
218  $compta_prod = getDolGlobalString('ACCOUNTING_SERVICE_SOLD_ACCOUNT', 'NotDefined');
219  }
220  }
221 
222  //$compta_revenuestamp = getDolGlobalString('ACCOUNTING_REVENUESTAMP_SOLD_ACCOUNT', 'NotDefined');
223 
224  $tax_id = $obj->tva_tx . ($obj->vat_src_code ? ' (' . $obj->vat_src_code . ')' : '');
225  if (array_key_exists($tax_id, $vatdata_cache)) {
226  $vatdata = $vatdata_cache[$tax_id];
227  } else {
228  $vatdata = getTaxesFromId($tax_id, $mysoc, $mysoc, 0);
229  $vatdata_cache[$tax_id] = $vatdata;
230  }
231  $compta_tva = (!empty($vatdata['accountancy_code_sell']) ? $vatdata['accountancy_code_sell'] : $cpttva);
232  $compta_localtax1 = (!empty($vatdata['accountancy_code_sell']) ? $vatdata['accountancy_code_sell'] : $cpttva);
233  $compta_localtax2 = (!empty($vatdata['accountancy_code_sell']) ? $vatdata['accountancy_code_sell'] : $cpttva);
234 
235  // Define the array to store the detail of each vat rate and code for lines
236  if (price2num($obj->tva_tx) || !empty($obj->vat_src_code)) {
237  $def_tva[$obj->rowid][$compta_tva][vatrate($obj->tva_tx).($obj->vat_src_code ? ' ('.$obj->vat_src_code.')' : '')] = (vatrate($obj->tva_tx).($obj->vat_src_code ? ' ('.$obj->vat_src_code.')' : ''));
238  }
239 
240  // Create a compensation rate for situation invoice.
241  $situation_ratio = 1;
242  if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
243  if ($obj->situation_cycle_ref) {
244  // Avoid divide by 0
245  if ($obj->situation_percent == 0) {
246  $situation_ratio = 0;
247  } else {
248  $line = new FactureLigne($db);
249  $line->fetch($obj->fdid);
250 
251  // Situation invoices handling
252  $prev_progress = $line->get_prev_progress($obj->rowid);
253 
254  $situation_ratio = ($obj->situation_percent - $prev_progress) / $obj->situation_percent;
255  }
256  }
257  }
258 
259  $revenuestamp = (float) price2num($obj->revenuestamp, 'MT');
260 
261  // Invoice lines
262  $tabfac[$obj->rowid]["date"] = $db->jdate($obj->df);
263  $tabfac[$obj->rowid]["datereg"] = $db->jdate($obj->dlr);
264  $tabfac[$obj->rowid]["ref"] = $obj->ref;
265  $tabfac[$obj->rowid]["type"] = $obj->type;
266  $tabfac[$obj->rowid]["description"] = $obj->label_compte;
267  $tabfac[$obj->rowid]["close_code"] = $obj->close_code; // close_code = 'replaced' for replacement invoices (not used in most european countries)
268  $tabfac[$obj->rowid]["revenuestamp"] = $revenuestamp;
269  //$tabfac[$obj->rowid]["fk_facturedet"] = $obj->fdid;
270 
271  // Avoid warnings
272  if (!isset($tabttc[$obj->rowid][$compta_soc])) {
273  $tabttc[$obj->rowid][$compta_soc] = 0;
274  }
275  if (!isset($tabht[$obj->rowid][$compta_prod])) {
276  $tabht[$obj->rowid][$compta_prod] = 0;
277  }
278  if (!isset($tabtva[$obj->rowid][$compta_tva])) {
279  $tabtva[$obj->rowid][$compta_tva] = 0;
280  }
281  if (!isset($tablocaltax1[$obj->rowid][$compta_localtax1])) {
282  $tablocaltax1[$obj->rowid][$compta_localtax1] = 0;
283  }
284  if (!isset($tablocaltax2[$obj->rowid][$compta_localtax2])) {
285  $tablocaltax2[$obj->rowid][$compta_localtax2] = 0;
286  }
287 
288  // Compensation of data for invoice situation by using $situation_ratio. This works (nearly) for invoice that was not correctly recorded
289  // but it may introduces an error for situation invoices that were correctly saved. There is still rounding problem that differs between
290  // real data we should have stored and result obtained with a compensation.
291  // It also seems that credit notes on situation invoices are correctly saved (but it depends on the version used in fact).
292  // For credit notes, we hope to have situation_ratio = 1 so the compensation has no effect to avoid introducing troubles with credit notes.
293  if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
294  $total_ttc = $obj->total_ttc * $situation_ratio;
295  } else {
296  $total_ttc = $obj->total_ttc;
297  }
298 
299  // Move a part of the retained warrenty into the account of warranty
300  if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && $obj->retained_warranty > 0) {
301  $retained_warranty = (float) price2num($total_ttc * $obj->retained_warranty / 100, 'MT'); // Calculate the amount of warrenty for this line (using the percent value)
302  $tabwarranty[$obj->rowid][$compta_soc] += $retained_warranty;
303  $total_ttc -= $retained_warranty;
304  }
305 
306  $tabttc[$obj->rowid][$compta_soc] += $total_ttc;
307  $tabht[$obj->rowid][$compta_prod] += $obj->total_ht * $situation_ratio;
308  $tva_npr = ((($obj->info_bits & 1) == 1) ? 1 : 0);
309  if (!$tva_npr) { // We ignore line if VAT is a NPR
310  $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva * $situation_ratio;
311  }
312  $tablocaltax1[$obj->rowid][$compta_localtax1] += $obj->total_localtax1 * $situation_ratio;
313  $tablocaltax2[$obj->rowid][$compta_localtax2] += $obj->total_localtax2 * $situation_ratio;
314 
315  $compta_revenuestamp = 'NotDefined';
316  if (!empty($revenuestamp)) {
317  $sqlrevenuestamp = "SELECT accountancy_code_sell FROM ".MAIN_DB_PREFIX."c_revenuestamp";
318  $sqlrevenuestamp .= " WHERE fk_pays = ".((int) $mysoc->country_id);
319  $sqlrevenuestamp .= " AND taux = ".((float) $revenuestamp);
320  $sqlrevenuestamp .= " AND active = 1";
321  $resqlrevenuestamp = $db->query($sqlrevenuestamp);
322 
323  if ($resqlrevenuestamp) {
324  $num_rows_revenuestamp = $db->num_rows($resqlrevenuestamp);
325  if ($num_rows_revenuestamp > 1) {
326  dol_print_error($db, 'Failed 2 or more lines for the revenue stamp of your country. Check the dictionary of revenue stamp.');
327  } else {
328  $objrevenuestamp = $db->fetch_object($resqlrevenuestamp);
329  if ($objrevenuestamp) {
330  $compta_revenuestamp = $objrevenuestamp->accountancy_code_sell;
331  }
332  }
333  }
334  }
335 
336  if (empty($tabrevenuestamp[$obj->rowid][$compta_revenuestamp]) && !empty($revenuestamp)) {
337  // The revenue stamp was never seen for this invoice id=$obj->rowid
338  $tabttc[$obj->rowid][$compta_soc] += $obj->revenuestamp;
339  $tabrevenuestamp[$obj->rowid][$compta_revenuestamp] = $obj->revenuestamp;
340  }
341 
342  $tabcompany[$obj->rowid] = array(
343  'id' => $obj->socid,
344  'name' => $obj->name,
345  'code_client' => $obj->code_client,
346  'code_compta' => $compta_soc
347  );
348 
349  $i++;
350  }
351 
352  // After the loop on each line
353 } else {
354  dol_print_error($db);
355 }
356 
357 // Check for too many invoices first.
358 if (count($tabfac) > 10000) {
359  $error++;
360  setEventMessages("TooManyInvoicesToProcessPleaseUseAMoreSelectiveFilter", null, 'errors');
361 }
362 
363 $errorforinvoice = array();
364 
365 /*
366 // Old way, 1 query for each invoice
367 // Loop on all invoices to detect lines without binded code (fk_code_ventilation <= 0)
368 foreach ($tabfac as $key => $val) { // Loop on each invoice
369  $sql = "SELECT COUNT(fd.rowid) as nb";
370  $sql .= " FROM ".MAIN_DB_PREFIX."facturedet as fd";
371  $sql .= " WHERE fd.product_type <= 2 AND fd.fk_code_ventilation <= 0";
372  $sql .= " AND fd.total_ttc <> 0 AND fk_facture = ".((int) $key);
373  $resql = $db->query($sql);
374  if ($resql) {
375  $obj = $db->fetch_object($resql);
376  if ($obj->nb > 0) {
377  $errorforinvoice[$key] = 'somelinesarenotbound';
378  }
379  } else {
380  dol_print_error($db);
381  }
382 }
383 */
384 // New way, single query, load all unbound lines
385 
386 $sql = "
387 SELECT
388  fk_facture,
389  COUNT(fd.rowid) as nb
390 FROM
391  ".MAIN_DB_PREFIX."facturedet as fd
392 WHERE
393  fd.product_type <= 2
394  AND fd.fk_code_ventilation <= 0
395  AND fd.total_ttc <> 0
396  AND fk_facture IN (".$db->sanitize(implode(",", array_keys($tabfac))).")
397 GROUP BY fk_facture
398 ";
399 $resql = $db->query($sql);
400 
401 $num = $db->num_rows($resql);
402 $i = 0;
403 while ($i < $num) {
404  $obj = $db->fetch_object($resql);
405  if ($obj->nb > 0) {
406  $errorforinvoice[$obj->fk_facture_fourn] = 'somelinesarenotbound';
407  }
408  $i++;
409 }
410 //var_dump($errorforinvoice);exit;
411 
412 // Bookkeeping Write
413 if ($action == 'writebookkeeping' && !$error) {
414  $now = dol_now();
415  $error = 0;
416 
417  $companystatic = new Societe($db);
418  $invoicestatic = new Facture($db);
419  $accountingaccountcustomer = new AccountingAccount($db);
420 
421  $accountingaccountcustomer->fetch(null, getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER'), true);
422 
423  $accountingaccountcustomerwarranty = new AccountingAccount($db);
424 
425  $accountingaccountcustomerwarranty->fetch(null, getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY'), true);
426 
427  foreach ($tabfac as $key => $val) { // Loop on each invoice
428  $errorforline = 0;
429 
430  $totalcredit = 0;
431  $totaldebit = 0;
432 
433  $db->begin();
434 
435  $companystatic->id = $tabcompany[$key]['id'];
436  $companystatic->name = $tabcompany[$key]['name'];
437  $companystatic->code_compta = $tabcompany[$key]['code_compta'];
438  $companystatic->code_compta_client = $tabcompany[$key]['code_compta'];
439  $companystatic->code_client = $tabcompany[$key]['code_client'];
440  $companystatic->client = 3;
441 
442  $invoicestatic->id = $key;
443  $invoicestatic->ref = (string) $val["ref"];
444  $invoicestatic->type = $val["type"];
445  $invoicestatic->close_code = $val["close_code"];
446 
447  $date = dol_print_date($val["date"], 'day');
448 
449  // Is it a replaced invoice ? 0=not a replaced invoice, 1=replaced invoice not yet dispatched, 2=replaced invoice dispatched
450  $replacedinvoice = 0;
451  if ($invoicestatic->close_code == Facture::CLOSECODE_REPLACED) {
452  $replacedinvoice = 1;
453  $alreadydispatched = $invoicestatic->getVentilExportCompta(); // Test if replaced invoice already into bookkeeping.
454  if ($alreadydispatched) {
455  $replacedinvoice = 2;
456  }
457  }
458 
459  // If not already into bookkeeping, we won't add it. If yes, do nothing (should not happen because creating replacement not possible if invoice is accounted)
460  if ($replacedinvoice == 1) {
461  $db->rollback();
462  continue;
463  }
464 
465  // Error if some lines are not binded/ready to be journalized
466  if (isset($errorforinvoice[$key]) && $errorforinvoice[$key] == 'somelinesarenotbound') {
467  $error++;
468  $errorforline++;
469  setEventMessages($langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $val['ref']), null, 'errors');
470  }
471 
472  // Warranty
473  if (!$errorforline && getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
474  if (isset($tabwaranty[$key]) && is_array($tabwarranty[$key])) {
475  foreach ($tabwarranty[$key] as $k => $mt) {
476  $bookkeeping = new BookKeeping($db);
477  $bookkeeping->doc_date = $val["date"];
478  $bookkeeping->date_lim_reglement = $val["datereg"];
479  $bookkeeping->doc_ref = $val["ref"];
480  $bookkeeping->date_creation = $now;
481  $bookkeeping->doc_type = 'customer_invoice';
482  $bookkeeping->fk_doc = $key;
483  $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
484  $bookkeeping->thirdparty_code = $companystatic->code_client;
485 
486  $bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
487  $bookkeeping->subledger_label = $tabcompany[$key]['name'];
488 
489  $bookkeeping->numero_compte = getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY');
490  $bookkeeping->label_compte = $accountingaccountcustomerwarranty->label;
491 
492  $bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("Retainedwarranty");
493  $bookkeeping->montant = $mt;
494  $bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
495  $bookkeeping->debit = ($mt >= 0) ? $mt : 0;
496  $bookkeeping->credit = ($mt < 0) ? -$mt : 0;
497  $bookkeeping->code_journal = $journal;
498  $bookkeeping->journal_label = $langs->transnoentities($journal_label);
499  $bookkeeping->fk_user_author = $user->id;
500  $bookkeeping->entity = $conf->entity;
501 
502  $totaldebit += $bookkeeping->debit;
503  $totalcredit += $bookkeeping->credit;
504 
505  $result = $bookkeeping->create($user);
506  if ($result < 0) {
507  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
508  $error++;
509  $errorforline++;
510  $errorforinvoice[$key] = 'alreadyjournalized';
511  //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
512  } else {
513  $error++;
514  $errorforline++;
515  $errorforinvoice[$key] = 'other';
516  setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
517  }
518  }
519  }
520  }
521  }
522 
523  // Thirdparty
524  if (!$errorforline) {
525  foreach ($tabttc[$key] as $k => $mt) {
526  $bookkeeping = new BookKeeping($db);
527  $bookkeeping->doc_date = $val["date"];
528  $bookkeeping->date_lim_reglement = $val["datereg"];
529  $bookkeeping->doc_ref = $val["ref"];
530  $bookkeeping->date_creation = $now;
531  $bookkeeping->doc_type = 'customer_invoice';
532  $bookkeeping->fk_doc = $key;
533  $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
534  $bookkeeping->thirdparty_code = $companystatic->code_client;
535 
536  $bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
537  $bookkeeping->subledger_label = $tabcompany[$key]['name'];
538 
539  $bookkeeping->numero_compte = getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER');
540  $bookkeeping->label_compte = $accountingaccountcustomer->label;
541 
542  $bookkeeping->label_operation = dol_trunc($companystatic->name, 16).' - '.$invoicestatic->ref.' - '.$langs->trans("SubledgerAccount");
543  $bookkeeping->montant = $mt;
544  $bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
545  $bookkeeping->debit = ($mt >= 0) ? $mt : 0;
546  $bookkeeping->credit = ($mt < 0) ? -$mt : 0;
547  $bookkeeping->code_journal = $journal;
548  $bookkeeping->journal_label = $langs->transnoentities($journal_label);
549  $bookkeeping->fk_user_author = $user->id;
550  $bookkeeping->entity = $conf->entity;
551 
552  $totaldebit += $bookkeeping->debit;
553  $totalcredit += $bookkeeping->credit;
554 
555  $result = $bookkeeping->create($user);
556  if ($result < 0) {
557  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
558  $error++;
559  $errorforline++;
560  $errorforinvoice[$key] = 'alreadyjournalized';
561  //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
562  } else {
563  $error++;
564  $errorforline++;
565  $errorforinvoice[$key] = 'other';
566  setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
567  }
568  } else {
569  if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && getDolGlobalInt('ACCOUNTING_ENABLE_AUTOLETTERING')) {
570  require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php';
571  $lettering_static = new Lettering($db);
572 
573  $nb_lettering = $lettering_static->bookkeepingLettering(array($bookkeeping->id));
574  }
575  }
576  }
577  }
578 
579  // Product / Service
580  if (!$errorforline) {
581  foreach ($tabht[$key] as $k => $mt) {
582  $resultfetch = $accountingaccount->fetch(null, $k, true); // TODO Use a cache
583  $label_account = $accountingaccount->label;
584 
585  // get compte id and label
586  if ($resultfetch > 0) {
587  $bookkeeping = new BookKeeping($db);
588  $bookkeeping->doc_date = $val["date"];
589  $bookkeeping->date_lim_reglement = $val["datereg"];
590  $bookkeeping->doc_ref = $val["ref"];
591  $bookkeeping->date_creation = $now;
592  $bookkeeping->doc_type = 'customer_invoice';
593  $bookkeeping->fk_doc = $key;
594  $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
595  $bookkeeping->thirdparty_code = $companystatic->code_client;
596 
597  if (getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_USE_AUXILIARY_ON_DEPOSIT')) {
598  if ($k == getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT')) {
599  $bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
600  $bookkeeping->subledger_label = $tabcompany[$key]['name'];
601  } else {
602  $bookkeeping->subledger_account = '';
603  $bookkeeping->subledger_label = '';
604  }
605  } else {
606  $bookkeeping->subledger_account = '';
607  $bookkeeping->subledger_label = '';
608  }
609 
610  $bookkeeping->numero_compte = $k;
611  $bookkeeping->label_compte = $label_account;
612 
613  $bookkeeping->label_operation = dol_trunc($companystatic->name, 16).' - '.$invoicestatic->ref.' - '.$label_account;
614  $bookkeeping->montant = $mt;
615  $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
616  $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
617  $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
618  $bookkeeping->code_journal = $journal;
619  $bookkeeping->journal_label = $langs->transnoentities($journal_label);
620  $bookkeeping->fk_user_author = $user->id;
621  $bookkeeping->entity = $conf->entity;
622 
623  $totaldebit += $bookkeeping->debit;
624  $totalcredit += $bookkeeping->credit;
625 
626  $result = $bookkeeping->create($user);
627  if ($result < 0) {
628  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
629  $error++;
630  $errorforline++;
631  $errorforinvoice[$key] = 'alreadyjournalized';
632  //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
633  } else {
634  $error++;
635  $errorforline++;
636  $errorforinvoice[$key] = 'other';
637  setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
638  }
639  }
640  }
641  }
642  }
643 
644  // VAT
645  if (!$errorforline) {
646  $listoftax = array(0, 1, 2);
647  foreach ($listoftax as $numtax) {
648  $arrayofvat = $tabtva;
649  if ($numtax == 1) {
650  $arrayofvat = $tablocaltax1;
651  }
652  if ($numtax == 2) {
653  $arrayofvat = $tablocaltax2;
654  }
655 
656  foreach ($arrayofvat[$key] as $k => $mt) {
657  if ($mt) {
658  $accountingaccount->fetch(null, $k, true); // TODO Use a cache for label
659  $label_account = $accountingaccount->label;
660 
661  $bookkeeping = new BookKeeping($db);
662  $bookkeeping->doc_date = $val["date"];
663  $bookkeeping->date_lim_reglement = $val["datereg"];
664  $bookkeeping->doc_ref = $val["ref"];
665  $bookkeeping->date_creation = $now;
666  $bookkeeping->doc_type = 'customer_invoice';
667  $bookkeeping->fk_doc = $key;
668  $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
669  $bookkeeping->thirdparty_code = $companystatic->code_client;
670 
671  $bookkeeping->subledger_account = '';
672  $bookkeeping->subledger_label = '';
673 
674  $bookkeeping->numero_compte = $k;
675  $bookkeeping->label_compte = $label_account;
676 
677 
678  $bookkeeping->label_operation = dol_trunc($companystatic->name, 16).' - '.$invoicestatic->ref;
679  $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
680  $bookkeeping->label_operation .= ' - '.$langs->trans("Taxes").' '.$tmpvatrate.' %';
681  $bookkeeping->label_operation .= ($numtax ? ' - Localtax '.$numtax : '');
682 
683  $bookkeeping->montant = $mt;
684  $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
685  $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
686  $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
687  $bookkeeping->code_journal = $journal;
688  $bookkeeping->journal_label = $langs->transnoentities($journal_label);
689  $bookkeeping->fk_user_author = $user->id;
690  $bookkeeping->entity = $conf->entity;
691 
692  $totaldebit += $bookkeeping->debit;
693  $totalcredit += $bookkeeping->credit;
694 
695  $result = $bookkeeping->create($user);
696  if ($result < 0) {
697  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
698  $error++;
699  $errorforline++;
700  $errorforinvoice[$key] = 'alreadyjournalized';
701  //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
702  } else {
703  $error++;
704  $errorforline++;
705  $errorforinvoice[$key] = 'other';
706  setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
707  }
708  }
709  }
710  }
711  }
712  }
713 
714  // Revenue stamp
715  if (!$errorforline) {
716  if (isset($tabrevenuestamp[$key]) && is_array($tabrevenuestamp[$key])) {
717  foreach ($tabrevenuestamp[$key] as $k => $mt) {
718  if ($mt) {
719  $accountingaccount->fetch(null, $k, true); // TODO Use a cache for label
720  $label_account = $accountingaccount->label;
721 
722  $bookkeeping = new BookKeeping($db);
723  $bookkeeping->doc_date = $val["date"];
724  $bookkeeping->date_lim_reglement = $val["datereg"];
725  $bookkeeping->doc_ref = $val["ref"];
726  $bookkeeping->date_creation = $now;
727  $bookkeeping->doc_type = 'customer_invoice';
728  $bookkeeping->fk_doc = $key;
729  $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
730  $bookkeeping->thirdparty_code = $companystatic->code_client;
731 
732  $bookkeeping->subledger_account = '';
733  $bookkeeping->subledger_label = '';
734 
735  $bookkeeping->numero_compte = $k;
736  $bookkeeping->label_compte = $label_account;
737 
738  $bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("RevenueStamp");
739  $bookkeeping->montant = $mt;
740  $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
741  $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
742  $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
743  $bookkeeping->code_journal = $journal;
744  $bookkeeping->journal_label = $langs->transnoentities($journal_label);
745  $bookkeeping->fk_user_author = $user->id;
746  $bookkeeping->entity = $conf->entity;
747 
748  $totaldebit += $bookkeeping->debit;
749  $totalcredit += $bookkeeping->credit;
750 
751  $result = $bookkeeping->create($user);
752  if ($result < 0) {
753  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
754  $error++;
755  $errorforline++;
756  $errorforinvoice[$key] = 'alreadyjournalized';
757  //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
758  } else {
759  $error++;
760  $errorforline++;
761  $errorforinvoice[$key] = 'other';
762  setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
763  }
764  }
765  }
766  }
767  }
768  }
769 
770  // Protection against a bug on lines before
771  if (!$errorforline && (price2num($totaldebit, 'MT') != price2num($totalcredit, 'MT'))) {
772  $error++;
773  $errorforline++;
774  $errorforinvoice[$key] = 'amountsnotbalanced';
775  setEventMessages('We Tried to insert a non balanced transaction in book for '.$invoicestatic->ref.'. Canceled. Surely a bug.', null, 'errors');
776  }
777 
778  if (!$errorforline) {
779  $db->commit();
780  } else {
781  $db->rollback();
782 
783  if ($error >= 10) {
784  setEventMessages($langs->trans("ErrorTooManyErrorsProcessStopped"), null, 'errors');
785  break; // Break in the foreach
786  }
787  }
788  }
789 
790  $tabpay = $tabfac;
791 
792  if (empty($error) && count($tabpay) > 0) {
793  setEventMessages($langs->trans("GeneralLedgerIsWritten"), null, 'mesgs');
794  } elseif (count($tabpay) == $error) {
795  setEventMessages($langs->trans("NoNewRecordSaved"), null, 'warnings');
796  } else {
797  setEventMessages($langs->trans("GeneralLedgerSomeRecordWasNotRecorded"), null, 'warnings');
798  }
799 
800  $action = '';
801 
802  // Must reload data, so we make a redirect
803  if (count($tabpay) != $error) {
804  $param = 'id_journal='.$id_journal;
805  $param .= '&date_startday='.$date_startday;
806  $param .= '&date_startmonth='.$date_startmonth;
807  $param .= '&date_startyear='.$date_startyear;
808  $param .= '&date_endday='.$date_endday;
809  $param .= '&date_endmonth='.$date_endmonth;
810  $param .= '&date_endyear='.$date_endyear;
811  $param .= '&in_bookkeeping='.$in_bookkeeping;
812  header("Location: ".$_SERVER['PHP_SELF'].($param ? '?'.$param : ''));
813  exit;
814  }
815 }
816 
817 
818 
819 /*
820  * View
821  */
822 
823 $form = new Form($db);
824 
825 // Export
826 if ($action == 'exportcsv' && !$error) { // ISO and not UTF8 !
827  // Note that to have the button to get this feature enabled, you must enable ACCOUNTING_ENABLE_EXPORT_DRAFT_JOURNAL
828  $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
829 
830  $filename = 'journal';
831  $type_export = 'journal';
832  include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php';
833 
834  $companystatic = new Client($db);
835  $invoicestatic = new Facture($db);
836 
837  foreach ($tabfac as $key => $val) {
838  $companystatic->id = $tabcompany[$key]['id'];
839  $companystatic->name = $tabcompany[$key]['name'];
840  $companystatic->code_compta = $tabcompany[$key]['code_compta']; // deprecated
841  $companystatic->code_compta_client = $tabcompany[$key]['code_compta'];
842  $companystatic->code_client = $tabcompany[$key]['code_client'];
843  $companystatic->client = 3;
844 
845  $invoicestatic->id = $key;
846  $invoicestatic->ref = (string) $val["ref"];
847  $invoicestatic->type = $val["type"];
848  $invoicestatic->close_code = $val["close_code"];
849 
850  $date = dol_print_date($val["date"], 'day');
851 
852  // Is it a replaced invoice ? 0=not a replaced invoice, 1=replaced invoice not yet dispatched, 2=replaced invoice dispatched
853  $replacedinvoice = 0;
854  if ($invoicestatic->close_code == Facture::CLOSECODE_REPLACED) {
855  $replacedinvoice = 1;
856  $alreadydispatched = $invoicestatic->getVentilExportCompta(); // Test if replaced invoice already into bookkeeping.
857  if ($alreadydispatched) {
858  $replacedinvoice = 2;
859  }
860  }
861 
862  // If not already into bookkeeping, we won't add it. If yes, do nothing (should not happen because creating replacement not possible if invoice is accounted)
863  if ($replacedinvoice == 1) {
864  continue;
865  }
866 
867  // Warranty
868  if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && isset($tabwarranty[$key])) {
869  foreach ($tabwarranty[$key] as $k => $mt) {
870  //if ($mt) {
871  print '"'.$key.'"'.$sep;
872  print '"'.$date.'"'.$sep;
873  print '"'.$val["ref"].'"'.$sep;
874  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
875  print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
876  print '"'.length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY')).'"'.$sep;
877  print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
878  print '"'.$langs->trans("Thirdparty").'"'.$sep;
879  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("Retainedwarranty").'"'.$sep;
880  print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
881  print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
882  print '"'.$journal.'"';
883  print "\n";
884  //}
885  }
886  }
887 
888  // Third party
889  foreach ($tabttc[$key] as $k => $mt) {
890  //if ($mt) {
891  print '"'.$key.'"'.$sep;
892  print '"'.$date.'"'.$sep;
893  print '"'.$val["ref"].'"'.$sep;
894  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
895  print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
896  print '"'.length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER')).'"'.$sep;
897  print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
898  print '"'.$langs->trans("Thirdparty").'"'.$sep;
899  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("Thirdparty").'"'.$sep;
900  print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
901  print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
902  print '"'.$journal.'"';
903  print "\n";
904  //}
905  }
906 
907  // Product / Service
908  foreach ($tabht[$key] as $k => $mt) {
909  $accountingaccount = new AccountingAccount($db);
910  $accountingaccount->fetch(null, $k, true);
911  //if ($mt) {
912  print '"'.$key.'"'.$sep;
913  print '"'.$date.'"'.$sep;
914  print '"'.$val["ref"].'"'.$sep;
915  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
916  print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
917  print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
918  print '""'.$sep;
919  print '"'.mb_convert_encoding(dol_trunc($accountingaccount->label, 32), 'ISO-8859-1').'"'.$sep;
920  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.dol_trunc($accountingaccount->label, 32).'"'.$sep;
921  print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
922  print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
923  print '"'.$journal.'"';
924  print "\n";
925  //}
926  }
927 
928  // VAT
929  $listoftax = array(0, 1, 2);
930  foreach ($listoftax as $numtax) {
931  $arrayofvat = $tabtva;
932  if ($numtax == 1) {
933  $arrayofvat = $tablocaltax1;
934  }
935  if ($numtax == 2) {
936  $arrayofvat = $tablocaltax2;
937  }
938 
939  foreach ($arrayofvat[$key] as $k => $mt) {
940  if ($mt) {
941  print '"'.$key.'"'.$sep;
942  print '"'.$date.'"'.$sep;
943  print '"'.$val["ref"].'"'.$sep;
944  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
945  print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
946  print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
947  print '""'.$sep;
948  print '"'.$langs->trans("VAT").' - '.implode(', ', $def_tva[$key][$k]).' %"'.$sep;
949  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("VAT").implode(', ', $def_tva[$key][$k]).' %'.($numtax ? ' - Localtax '.$numtax : '').'"'.$sep;
950  print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
951  print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
952  print '"'.$journal.'"';
953  print "\n";
954  }
955  }
956  }
957 
958  // Revenue stamp
959  if (isset($tabrevenuestamp[$key])) {
960  foreach ($tabrevenuestamp[$key] as $k => $mt) {
961  //if ($mt) {
962  print '"'.$key.'"'.$sep;
963  print '"'.$date.'"'.$sep;
964  print '"'.$val["ref"].'"'.$sep;
965  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
966  print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
967  print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
968  print '""'.$sep;
969  print '"'.$langs->trans("RevenueStamp").'"'.$sep;
970  print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("RevenueStamp").'"'.$sep;
971  print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
972  print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
973  print '"'.$journal.'"';
974  print "\n";
975  //}
976  }
977  }
978  }
979 }
980 
981 
982 
983 if (empty($action) || $action == 'view') {
984  $title = $langs->trans("GenerationOfAccountingEntries").' - '.$accountingjournalstatic->getNomUrl(0, 2, 1, '', 1);
985 
986  llxHeader('', dol_string_nohtmltag($title));
987 
988  $nom = $title;
989  $nomlink = '';
990  $periodlink = '';
991  $exportlink = '';
992  $builddate = dol_now();
993  $description = $langs->trans("DescJournalOnlyBindedVisible").'<br>';
994  if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
995  $description .= $langs->trans("DepositsAreNotIncluded");
996  } else {
997  $description .= $langs->trans("DepositsAreIncluded");
998  }
999 
1000  $listofchoices = array('notyet' => $langs->trans("NotYetInGeneralLedger"), 'already' => $langs->trans("AlreadyInGeneralLedger"));
1001  $period = $form->selectDate($date_start ? $date_start : -1, 'date_start', 0, 0, 0, '', 1, 0).' - '.$form->selectDate($date_end ? $date_end : -1, 'date_end', 0, 0, 0, '', 1, 0);
1002  $period .= ' - '.$langs->trans("JournalizationInLedgerStatus").' '.$form->selectarray('in_bookkeeping', $listofchoices, $in_bookkeeping, 1);
1003 
1004  $varlink = 'id_journal='.$id_journal;
1005 
1006  journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''), '', $varlink);
1007 
1008  if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') != 'blockedonclosed') {
1009  // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed)
1010  // Fiscal period test
1011  $sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_fiscalyear WHERE entity = ".((int) $conf->entity);
1012  $resql = $db->query($sql);
1013  if ($resql) {
1014  $obj = $db->fetch_object($resql);
1015  if ($obj->nb == 0) {
1016  print '<br><div class="warning">'.img_warning().' '.$langs->trans("TheFiscalPeriodIsNotDefined");
1017  $desc = ' : '.$langs->trans("AccountancyAreaDescFiscalPeriod", 4, '{link}');
1018  $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("FiscalPeriod").'</strong>', $desc);
1019  print $desc;
1020  print '</div>';
1021  }
1022  } else {
1023  dol_print_error($db);
1024  }
1025  }
1026 
1027  // Button to write into Ledger
1028  $acctCustomerNotConfigured = in_array(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER'), ['','-1']);
1029  if ($acctCustomerNotConfigured) {
1030  print '<br><div class="warning">'.img_warning().' '.$langs->trans("SomeMandatoryStepsOfSetupWereNotDone");
1031  $desc = ' : '.$langs->trans("AccountancyAreaDescMisc", 4, '{link}');
1032  $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuDefaultAccounts").'</strong>', $desc);
1033  print $desc;
1034  print '</div>';
1035  }
1036  print '<br><div class="tabsAction tabsActionNoBottom centerimp">';
1037  if (getDolGlobalString('ACCOUNTING_ENABLE_EXPORT_DRAFT_JOURNAL') && $in_bookkeeping == 'notyet') {
1038  print '<input type="button" class="butAction" name="exportcsv" value="'.$langs->trans("ExportDraftJournal").'" onclick="launch_export();" />';
1039  }
1040  if ($acctCustomerNotConfigured) {
1041  print '<input type="button" class="butActionRefused classfortooltip" title="'.dol_escape_htmltag($langs->trans("SomeMandatoryStepsOfSetupWereNotDone")).'" value="'.$langs->trans("WriteBookKeeping").'" />';
1042  } else {
1043  if ($in_bookkeeping == 'notyet') {
1044  print '<input type="button" class="butAction" name="writebookkeeping" value="'.$langs->trans("WriteBookKeeping").'" onclick="writebookkeeping();" />';
1045  } else {
1046  print '<a href="#" class="butActionRefused classfortooltip" name="writebookkeeping">'.$langs->trans("WriteBookKeeping").'</a>';
1047  }
1048  }
1049  print '</div>';
1050 
1051  // TODO Avoid using js. We can use a direct link with $param
1052  print '
1053  <script type="text/javascript">
1054  function launch_export() {
1055  $("div.fiche form input[name=\"action\"]").val("exportcsv");
1056  $("div.fiche form input[type=\"submit\"]").click();
1057  $("div.fiche form input[name=\"action\"]").val("");
1058  }
1059  function writebookkeeping() {
1060  console.log("click on writebookkeeping");
1061  $("div.fiche form input[name=\"action\"]").val("writebookkeeping");
1062  $("div.fiche form input[type=\"submit\"]").click();
1063  $("div.fiche form input[name=\"action\"]").val("");
1064  }
1065  </script>';
1066 
1067  /*
1068  * Show result array
1069  */
1070  print '<br>';
1071 
1072  print '<div class="div-table-responsive">';
1073  print "<table class=\"noborder\" width=\"100%\">";
1074  print "<tr class=\"liste_titre\">";
1075  print "<td>".$langs->trans("Date")."</td>";
1076  print "<td>".$langs->trans("Piece").' ('.$langs->trans("InvoiceRef").")</td>";
1077  print "<td>".$langs->trans("AccountAccounting")."</td>";
1078  print "<td>".$langs->trans("SubledgerAccount")."</td>";
1079  print "<td>".$langs->trans("LabelOperation")."</td>";
1080  print '<td class="center">'.$langs->trans("AccountingDebit")."</td>";
1081  print '<td class="center">'.$langs->trans("AccountingCredit")."</td>";
1082  print "</tr>\n";
1083 
1084  $i = 0;
1085 
1086  $companystatic = new Client($db);
1087  $invoicestatic = new Facture($db);
1088 
1089  foreach ($tabfac as $key => $val) {
1090  $companystatic->id = $tabcompany[$key]['id'];
1091  $companystatic->name = $tabcompany[$key]['name'];
1092  $companystatic->code_compta = $tabcompany[$key]['code_compta'];
1093  $companystatic->code_compta_client = $tabcompany[$key]['code_compta'];
1094  $companystatic->code_client = $tabcompany[$key]['code_client'];
1095  $companystatic->client = 3;
1096 
1097  $invoicestatic->id = $key;
1098  $invoicestatic->ref = (string) $val["ref"];
1099  $invoicestatic->type = $val["type"];
1100  $invoicestatic->close_code = $val["close_code"];
1101 
1102  $date = dol_print_date($val["date"], 'day');
1103 
1104  // Is it a replaced invoice ? 0=not a replaced invoice, 1=replaced invoice not yet dispatched, 2=replaced invoice dispatched
1105  $replacedinvoice = 0;
1106  if ($invoicestatic->close_code == Facture::CLOSECODE_REPLACED) {
1107  $replacedinvoice = 1;
1108  $alreadydispatched = $invoicestatic->getVentilExportCompta(); // Test if replaced invoice already into bookkeeping.
1109  if ($alreadydispatched) {
1110  $replacedinvoice = 2;
1111  }
1112  }
1113 
1114  // If not already into bookkeeping, we won't add it, if yes, add the counterpart ???.
1115  if ($replacedinvoice == 1) {
1116  print '<tr class="oddeven">';
1117  print "<!-- Replaced invoice -->";
1118  print "<td>".$date."</td>";
1119  print "<td><strike>".$invoicestatic->getNomUrl(1)."</strike></td>";
1120  // Account
1121  print "<td>";
1122  print $langs->trans("Replaced");
1123  print '</td>';
1124  // Subledger account
1125  print "<td>";
1126  print '</td>';
1127  print "<td>";
1128  print "</td>";
1129  print '<td class="right"></td>';
1130  print '<td class="right"></td>';
1131  print "</tr>";
1132 
1133  $i++;
1134  continue;
1135  }
1136  if (isset($errorforinvoice[$key]) && $errorforinvoice[$key] == 'somelinesarenotbound') {
1137  print '<tr class="oddeven">';
1138  print "<!-- Some lines are not bound -->";
1139  print "<td>".$date."</td>";
1140  print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1141  // Account
1142  print "<td>";
1143  print '<span class="error">'.$langs->trans('ErrorInvoiceContainsLinesNotYetBoundedShort', $val['ref']).'</span>';
1144  print '</td>';
1145  // Subledger account
1146  print "<td>";
1147  print '</td>';
1148  print "<td>";
1149  print "</td>";
1150  print '<td class="right"></td>';
1151  print '<td class="right"></td>';
1152  print "</tr>";
1153 
1154  $i++;
1155  }
1156 
1157  // Warranty
1158  if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && isset($tabwarranty[$key]) && is_array($tabwarranty[$key])) {
1159  foreach ($tabwarranty[$key] as $k => $mt) {
1160  print '<tr class="oddeven">';
1161  print "<!-- Thirdparty warranty -->";
1162  print "<td>" . $date . "</td>";
1163  print "<td>" . $invoicestatic->getNomUrl(1) . "</td>";
1164  // Account
1165  print "<td>";
1166  $accountoshow = length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY'));
1167  if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1168  print '<span class="error">' . $langs->trans("MainAccountForRetainedWarrantyNotDefined") . '</span>';
1169  } else {
1170  print $accountoshow;
1171  }
1172  print '</td>';
1173  // Subledger account
1174  print "<td>";
1175  $accountoshow = length_accounta($k);
1176  if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1177  print '<span class="error">' . $langs->trans("ThirdpartyAccountNotDefined") . '</span>';
1178  } else {
1179  print $accountoshow;
1180  }
1181  print '</td>';
1182  print "<td>" . $companystatic->getNomUrl(0, 'customer', 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("Retainedwarranty") . "</td>";
1183  print '<td class="right nowraponall amount">' . ($mt >= 0 ? price($mt) : '') . "</td>";
1184  print '<td class="right nowraponall amount">' . ($mt < 0 ? price(-$mt) : '') . "</td>";
1185  print "</tr>";
1186  }
1187  }
1188 
1189  // Third party
1190  foreach ($tabttc[$key] as $k => $mt) {
1191  print '<tr class="oddeven">';
1192  print "<!-- Thirdparty -->";
1193  print "<td>".$date."</td>";
1194  print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1195  // Account
1196  print "<td>";
1197  $accountoshow = length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER'));
1198  if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1199  print '<span class="error">'.$langs->trans("MainAccountForCustomersNotDefined").'</span>';
1200  } else {
1201  print $accountoshow;
1202  }
1203  print '</td>';
1204  // Subledger account
1205  print "<td>";
1206  $accountoshow = length_accounta($k);
1207  if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1208  print '<span class="error">'.$langs->trans("ThirdpartyAccountNotDefined").'</span>';
1209  } else {
1210  print $accountoshow;
1211  }
1212  print '</td>';
1213  print "<td>".$companystatic->getNomUrl(0, 'customer', 16).' - '.$invoicestatic->ref.' - '.$langs->trans("SubledgerAccount")."</td>";
1214  print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
1215  print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
1216  print "</tr>";
1217 
1218  $i++;
1219  }
1220 
1221  // Product / Service
1222  foreach ($tabht[$key] as $k => $mt) {
1223  $accountingaccount = new AccountingAccount($db);
1224  $accountingaccount->fetch(null, $k, true);
1225 
1226  print '<tr class="oddeven">';
1227  print "<!-- Product -->";
1228  print "<td>".$date."</td>";
1229  print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1230  // Account
1231  print "<td>";
1232  $accountoshow = length_accountg($k);
1233  if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1234  print '<span class="error">'.$langs->trans("ProductNotDefined").'</span>';
1235  } else {
1236  print $accountoshow;
1237  }
1238  print "</td>";
1239  // Subledger account
1240  print "<td>";
1241  if (getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_USE_AUXILIARY_ON_DEPOSIT')) {
1242  if ($k == getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT')) {
1243  print length_accounta($tabcompany[$key]['code_compta']);
1244  }
1245  } elseif (($accountoshow == "") || $accountoshow == 'NotDefined') {
1246  print '<span class="error">' . $langs->trans("ThirdpartyAccountNotDefined") . '</span>';
1247  }
1248  print '</td>';
1249  $companystatic->id = $tabcompany[$key]['id'];
1250  $companystatic->name = $tabcompany[$key]['name'];
1251  print "<td>".$companystatic->getNomUrl(0, 'customer', 16).' - '.$invoicestatic->ref.' - '.$accountingaccount->label."</td>";
1252  print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
1253  print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
1254  print "</tr>";
1255 
1256  $i++;
1257  }
1258 
1259  // VAT
1260  $listoftax = array(0, 1, 2);
1261  foreach ($listoftax as $numtax) {
1262  $arrayofvat = $tabtva;
1263  if ($numtax == 1) {
1264  $arrayofvat = $tablocaltax1;
1265  }
1266  if ($numtax == 2) {
1267  $arrayofvat = $tablocaltax2;
1268  }
1269 
1270  // $key is id of invoice
1271  foreach ($arrayofvat[$key] as $k => $mt) {
1272  if ($mt) {
1273  print '<tr class="oddeven">';
1274  print "<!-- VAT -->";
1275  print "<td>".$date."</td>";
1276  print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1277  // Account
1278  print "<td>";
1279  $accountoshow = length_accountg($k);
1280  if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1281  print '<span class="error">'.$langs->trans("VATAccountNotDefined").' ('.$langs->trans("AccountingJournalType2").')</span>';
1282  } else {
1283  print $accountoshow;
1284  }
1285  print "</td>";
1286  // Subledger account
1287  print "<td>";
1288  print '</td>';
1289  print "<td>".$companystatic->getNomUrl(0, 'customer', 16).' - '.$invoicestatic->ref;
1290  // $def_tva is array[invoiceid][accountancy_code_sell_of_vat_rate_found][vatrate]=vatrate
1291  //var_dump($arrayofvat[$key]); //var_dump($key); //var_dump($k);
1292  $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
1293  print ' - '.$langs->trans("Taxes").' '.$tmpvatrate.' %';
1294  print($numtax ? ' - Localtax '.$numtax : '');
1295  print "</td>";
1296  print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
1297  print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
1298  print "</tr>";
1299 
1300  $i++;
1301  }
1302  }
1303  }
1304 
1305  // Revenue stamp
1306  if (isset($tabrevenuestamp[$key]) && is_array($tabrevenuestamp[$key])) {
1307  foreach ($tabrevenuestamp[$key] as $k => $mt) {
1308  print '<tr class="oddeven">';
1309  print "<!-- Thirdparty revenuestamp -->";
1310  print "<td>" . $date . "</td>";
1311  print "<td>" . $invoicestatic->getNomUrl(1) . "</td>";
1312  // Account
1313  print "<td>";
1314  $accountoshow = length_accountg($k);
1315  if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1316  print '<span class="error">' . $langs->trans("MainAccountForRevenueStampSaleNotDefined") . '</span>';
1317  } else {
1318  print $accountoshow;
1319  }
1320  print '</td>';
1321  // Subledger account
1322  print "<td>";
1323  print '</td>';
1324  print "<td>" . $companystatic->getNomUrl(0, 'customer', 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("RevenueStamp") . "</td>";
1325  print '<td class="right nowraponall amount">' . ($mt < 0 ? price(-$mt) : '') . "</td>";
1326  print '<td class="right nowraponall amount">' . ($mt >= 0 ? price($mt) : '') . "</td>";
1327  print "</tr>";
1328  }
1329  }
1330  }
1331 
1332  if (!$i) {
1333  print '<tr class="oddeven"><td colspan="7"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
1334  }
1335 
1336  print "</table>";
1337  print '</div>';
1338 
1339  // End of page
1340  llxFooter();
1341 }
1342 
1343 $db->close();
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
journalHead($nom, $variant, $period, $periodlink, $description, $builddate, $exportlink='', $moreparam=array(), $calcmode='', $varlink='', $moreoptions=array())
Show header of a page used to transfer/dispatch data in accounting.
getDefaultDatesForTransfer()
Return Default dates for transfer based on periodicity option in accountancy setup.
length_accounta($accounta)
Return Auxiliary accounting account of thirdparties with defined length.
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:55
llxFooter()
Empty footer.
Definition: wrapper.php:69
Class to manage accounting accounts.
Class to manage accounting journals.
Class to manage Ledger (General Ledger and Subledger)
Class to manage customers or prospects.
Class to manage invoices.
const TYPE_REPLACEMENT
Replacement invoice.
const TYPE_SITUATION
Situation invoice.
const TYPE_DEPOSIT
Deposit invoice.
const TYPE_CREDIT_NOTE
Credit note invoice.
Class to manage invoice lines.
Class to manage generation of HTML components Only common components must be here.
Class Lettering.
Class to manage third parties objects (customers, suppliers, prospects...)
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition: date.lib.php:595
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition: date.lib.php:614
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
div float
Buy price without taxes.
Definition: style.css.php:960
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.