dolibarr 21.0.0-alpha
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-2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
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
35require '../../main.inc.php';
36require_once DOL_DOCUMENT_ROOT.'/core/lib/report.lib.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
39require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
40require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
41require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
42require_once DOL_DOCUMENT_ROOT.'/societe/class/client.class.php';
43require_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');
58if ($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
68if (!isModEnabled('accounting')) {
70}
71if ($user->socid > 0) {
73}
74if (!$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 a 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
98if (empty($date_startmonth)) {
99 // Period by default on transfer
101 $date_start = $dates['date_start'];
102 $pastmonthyear = $dates['pastmonthyear'];
103 $pastmonth = $dates['pastmonth'];
104}
105if (empty($date_endmonth)) {
106 // Period by default on transfer
108 $date_end = $dates['date_end'];
109 $pastmonthyear = $dates['pastmonthyear'];
110 $pastmonth = $dates['pastmonth'];
111}
112if (getDolGlobalString('ACCOUNTANCY_JOURNAL_USE_CURRENT_MONTH')) {
113 $pastmonth += 1;
114}
115
116if (!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,";
124if (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,";
132if (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";
142if (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";
148if (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";
157if (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)";
163if ($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
167if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
168 $sql .= " AND f.datef >= '".$db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING'))."'";
169}
170// Already in bookkeeping or not
171if ($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}
175if ($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
185dol_syslog('accountancy/journal/sellsjournal.php', LOG_DEBUG);
186$result = $db->query($sql);
187if ($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 if (getDolGlobalInt('INVOICE_USE_SITUATION') == 2) {
311 $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva;
312 $tablocaltax1[$obj->rowid][$compta_localtax1] += $obj->total_localtax1;
313 $tablocaltax2[$obj->rowid][$compta_localtax2] += $obj->total_localtax2;
314 } else {
315 $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva * $situation_ratio;
316 $tablocaltax1[$obj->rowid][$compta_localtax1] += $obj->total_localtax1 * $situation_ratio;
317 $tablocaltax2[$obj->rowid][$compta_localtax2] += $obj->total_localtax2 * $situation_ratio;
318 }
319 }
320
321 $compta_revenuestamp = 'NotDefined';
322 if (!empty($revenuestamp)) {
323 $sqlrevenuestamp = "SELECT accountancy_code_sell FROM ".MAIN_DB_PREFIX."c_revenuestamp";
324 $sqlrevenuestamp .= " WHERE fk_pays = ".((int) $mysoc->country_id);
325 $sqlrevenuestamp .= " AND taux = ".((float) $revenuestamp);
326 $sqlrevenuestamp .= " AND active = 1";
327 $resqlrevenuestamp = $db->query($sqlrevenuestamp);
328
329 if ($resqlrevenuestamp) {
330 $num_rows_revenuestamp = $db->num_rows($resqlrevenuestamp);
331 if ($num_rows_revenuestamp > 1) {
332 dol_print_error($db, 'Failed 2 or more lines for the revenue stamp of your country. Check the dictionary of revenue stamp.');
333 } else {
334 $objrevenuestamp = $db->fetch_object($resqlrevenuestamp);
335 if ($objrevenuestamp) {
336 $compta_revenuestamp = $objrevenuestamp->accountancy_code_sell;
337 }
338 }
339 }
340 }
341
342 if (empty($tabrevenuestamp[$obj->rowid][$compta_revenuestamp]) && !empty($revenuestamp)) {
343 // The revenue stamp was never seen for this invoice id=$obj->rowid
344 $tabttc[$obj->rowid][$compta_soc] += $obj->revenuestamp;
345 $tabrevenuestamp[$obj->rowid][$compta_revenuestamp] = $obj->revenuestamp;
346 }
347
348 $tabcompany[$obj->rowid] = array(
349 'id' => $obj->socid,
350 'name' => $obj->name,
351 'code_client' => $obj->code_client,
352 'code_compta' => $compta_soc
353 );
354
355 $i++;
356
357 // Check for too many lines.
358 if ($i > getDolGlobalInt('ACCOUNTANCY_MAX_TOO_MANY_LINES_TO_PROCESS', 10000)) {
359 $error++;
360 setEventMessages("ErrorTooManyLinesToProcessPleaseUseAMoreSelectiveFilter", null, 'errors');
361 break;
362 }
363 }
364
365 // After the loop on each line
366} else {
367 dol_print_error($db);
368}
369
370
371$errorforinvoice = array();
372
373/*
374// Old way, 1 query for each invoice
375// Loop on all invoices to detect lines without binded code (fk_code_ventilation <= 0)
376foreach ($tabfac as $key => $val) { // Loop on each invoice
377 $sql = "SELECT COUNT(fd.rowid) as nb";
378 $sql .= " FROM ".MAIN_DB_PREFIX."facturedet as fd";
379 $sql .= " WHERE fd.product_type <= 2 AND fd.fk_code_ventilation <= 0";
380 $sql .= " AND fd.total_ttc <> 0 AND fk_facture = ".((int) $key);
381 $resql = $db->query($sql);
382 if ($resql) {
383 $obj = $db->fetch_object($resql);
384 if ($obj->nb > 0) {
385 $errorforinvoice[$key] = 'somelinesarenotbound';
386 }
387 } else {
388 dol_print_error($db);
389 }
390}
391*/
392// New way, single query, load all unbound lines
393
394$sql = "
395SELECT
396 fk_facture,
397 COUNT(fd.rowid) as nb
398FROM
399 ".MAIN_DB_PREFIX."facturedet as fd
400WHERE
401 fd.product_type <= 2
402 AND fd.fk_code_ventilation <= 0
403 AND fd.total_ttc <> 0
404 AND fk_facture IN (".$db->sanitize(implode(",", array_keys($tabfac))).")
405GROUP BY fk_facture
406";
407$resql = $db->query($sql);
408
409$num = $db->num_rows($resql);
410$i = 0;
411while ($i < $num) {
412 $obj = $db->fetch_object($resql);
413 if ($obj->nb > 0) {
414 $errorforinvoice[$obj->fk_facture_fourn] = 'somelinesarenotbound';
415 }
416 $i++;
417}
418//var_dump($errorforinvoice);exit;
419
420// Bookkeeping Write
421if ($action == 'writebookkeeping' && !$error) {
422 $now = dol_now();
423 $error = 0;
424
425 $companystatic = new Societe($db);
426 $invoicestatic = new Facture($db);
427
428 $accountingaccountcustomer = new AccountingAccount($db);
429 $accountingaccountcustomer->fetch(null, getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER'), true);
430
431 $accountingaccountcustomerwarranty = new AccountingAccount($db);
432 $accountingaccountcustomerwarranty->fetch(null, getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY'), true);
433
434 foreach ($tabfac as $key => $val) { // Loop on each invoice
435 $errorforline = 0;
436
437 $totalcredit = 0;
438 $totaldebit = 0;
439
440 $db->begin(); // We accept transaction into loop, so if we hang, we can continue transfer from the last error
441
442 $companystatic->id = $tabcompany[$key]['id'];
443 $companystatic->name = $tabcompany[$key]['name'];
444 $companystatic->code_compta = $tabcompany[$key]['code_compta'];
445 $companystatic->code_compta_client = $tabcompany[$key]['code_compta'];
446 $companystatic->code_client = $tabcompany[$key]['code_client'];
447 $companystatic->client = 3;
448
449 $invoicestatic->id = $key;
450 $invoicestatic->ref = (string) $val["ref"];
451 $invoicestatic->type = $val["type"];
452 $invoicestatic->close_code = $val["close_code"];
453
454 $date = dol_print_date($val["date"], 'day');
455
456 // Is it a replaced invoice? 0=not a replaced invoice, 1=replaced invoice not yet dispatched, 2=replaced invoice dispatched
457 $replacedinvoice = 0;
458 if ($invoicestatic->close_code == Facture::CLOSECODE_REPLACED) {
459 $replacedinvoice = 1;
460 $alreadydispatched = $invoicestatic->getVentilExportCompta(); // Test if replaced invoice already into bookkeeping.
461 if ($alreadydispatched) {
462 $replacedinvoice = 2;
463 }
464 }
465
466 // If not already into bookkeeping, we won't add it. If yes, do nothing (should not happen because creating a replacement is not possible if invoice is accounted)
467 if ($replacedinvoice == 1) {
468 $db->rollback();
469 continue;
470 }
471
472 // Error if some lines are not binded/ready to be journalized
473 if (isset($errorforinvoice[$key]) && $errorforinvoice[$key] == 'somelinesarenotbound') {
474 $error++;
475 $errorforline++;
476 setEventMessages($langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $val['ref']), null, 'errors');
477 }
478
479 // Warranty
480 if (!$errorforline && getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
481 if (isset($tabwaranty[$key]) && is_array($tabwarranty[$key])) {
482 foreach ($tabwarranty[$key] as $k => $mt) {
483 $bookkeeping = new BookKeeping($db);
484 $bookkeeping->doc_date = $val["date"];
485 $bookkeeping->date_lim_reglement = $val["datereg"];
486 $bookkeeping->doc_ref = $val["ref"];
487 $bookkeeping->date_creation = $now;
488 $bookkeeping->doc_type = 'customer_invoice';
489 $bookkeeping->fk_doc = $key;
490 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are the source of this record to add
491 $bookkeeping->thirdparty_code = $companystatic->code_client;
492
493 $bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
494 $bookkeeping->subledger_label = $tabcompany[$key]['name'];
495
496 $bookkeeping->numero_compte = getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY');
497 $bookkeeping->label_compte = $accountingaccountcustomerwarranty->label;
498
499 $bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("RetainedWarranty");
500 $bookkeeping->montant = $mt;
501 $bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
502 $bookkeeping->debit = ($mt >= 0) ? $mt : 0;
503 $bookkeeping->credit = ($mt < 0) ? -$mt : 0;
504 $bookkeeping->code_journal = $journal;
505 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
506 $bookkeeping->fk_user_author = $user->id;
507 $bookkeeping->entity = $conf->entity;
508
509 $totaldebit += $bookkeeping->debit;
510 $totalcredit += $bookkeeping->credit;
511
512 $result = $bookkeeping->create($user);
513 if ($result < 0) {
514 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
515 $error++;
516 $errorforline++;
517 $errorforinvoice[$key] = 'alreadyjournalized';
518 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
519 } else {
520 $error++;
521 $errorforline++;
522 $errorforinvoice[$key] = 'other';
523 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
524 }
525 }
526 }
527 }
528 }
529
530 // Thirdparty
531 if (!$errorforline) {
532 foreach ($tabttc[$key] as $k => $mt) {
533 $bookkeeping = new BookKeeping($db);
534 $bookkeeping->doc_date = $val["date"];
535 $bookkeeping->date_lim_reglement = $val["datereg"];
536 $bookkeeping->doc_ref = $val["ref"];
537 $bookkeeping->date_creation = $now;
538 $bookkeeping->doc_type = 'customer_invoice';
539 $bookkeeping->fk_doc = $key;
540 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
541 $bookkeeping->thirdparty_code = $companystatic->code_client;
542
543 $bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
544 $bookkeeping->subledger_label = $tabcompany[$key]['name'];
545
546 $bookkeeping->numero_compte = getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER');
547 $bookkeeping->label_compte = $accountingaccountcustomer->label;
548
549 $bookkeeping->label_operation = dol_trunc($companystatic->name, 16).' - '.$invoicestatic->ref.' - '.$langs->trans("SubledgerAccount");
550 $bookkeeping->montant = $mt;
551 $bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
552 $bookkeeping->debit = ($mt >= 0) ? $mt : 0;
553 $bookkeeping->credit = ($mt < 0) ? -$mt : 0;
554 $bookkeeping->code_journal = $journal;
555 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
556 $bookkeeping->fk_user_author = $user->id;
557 $bookkeeping->entity = $conf->entity;
558
559 $totaldebit += $bookkeeping->debit;
560 $totalcredit += $bookkeeping->credit;
561
562 $result = $bookkeeping->create($user);
563 if ($result < 0) {
564 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
565 $error++;
566 $errorforline++;
567 $errorforinvoice[$key] = 'alreadyjournalized';
568 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
569 } else {
570 $error++;
571 $errorforline++;
572 $errorforinvoice[$key] = 'other';
573 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
574 }
575 } else {
576 if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && getDolGlobalInt('ACCOUNTING_ENABLE_AUTOLETTERING')) {
577 require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php';
578 $lettering_static = new Lettering($db);
579
580 $nb_lettering = $lettering_static->bookkeepingLettering(array($bookkeeping->id));
581 }
582 }
583 }
584 }
585
586 // Product / Service
587 if (!$errorforline) {
588 foreach ($tabht[$key] as $k => $mt) {
589 if (empty($conf->cache['accountingaccountincurrententity'][$k])) {
590 $accountingaccount = new AccountingAccount($db);
591 $accountingaccount->fetch(0, $k, true);
592 $conf->cache['accountingaccountincurrententity'][$k] = $accountingaccount;
593 } else {
594 $accountingaccount = $conf->cache['accountingaccountincurrententity'][$k];
595 }
596
597 $label_account = $accountingaccount->label;
598
599 // get compte id and label
600 if ($accountingaccount->id > 0) {
601 $bookkeeping = new BookKeeping($db);
602 $bookkeeping->doc_date = $val["date"];
603 $bookkeeping->date_lim_reglement = $val["datereg"];
604 $bookkeeping->doc_ref = $val["ref"];
605 $bookkeeping->date_creation = $now;
606 $bookkeeping->doc_type = 'customer_invoice';
607 $bookkeeping->fk_doc = $key;
608 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
609 $bookkeeping->thirdparty_code = $companystatic->code_client;
610
611 if (getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_USE_AUXILIARY_ON_DEPOSIT')) {
612 if ($k == getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT')) {
613 $bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
614 $bookkeeping->subledger_label = $tabcompany[$key]['name'];
615 } else {
616 $bookkeeping->subledger_account = '';
617 $bookkeeping->subledger_label = '';
618 }
619 } else {
620 $bookkeeping->subledger_account = '';
621 $bookkeeping->subledger_label = '';
622 }
623
624 $bookkeeping->numero_compte = $k;
625 $bookkeeping->label_compte = $label_account;
626
627 $bookkeeping->label_operation = dol_trunc($companystatic->name, 16).' - '.$invoicestatic->ref.' - '.$label_account;
628 $bookkeeping->montant = $mt;
629 $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
630 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
631 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
632 $bookkeeping->code_journal = $journal;
633 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
634 $bookkeeping->fk_user_author = $user->id;
635 $bookkeeping->entity = $conf->entity;
636
637 $totaldebit += $bookkeeping->debit;
638 $totalcredit += $bookkeeping->credit;
639
640 $result = $bookkeeping->create($user);
641 if ($result < 0) {
642 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
643 $error++;
644 $errorforline++;
645 $errorforinvoice[$key] = 'alreadyjournalized';
646 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
647 } else {
648 $error++;
649 $errorforline++;
650 $errorforinvoice[$key] = 'other';
651 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
652 }
653 }
654 }
655 }
656 }
657
658 // VAT
659 if (!$errorforline) {
660 $listoftax = array(0, 1, 2);
661 foreach ($listoftax as $numtax) {
662 $arrayofvat = $tabtva;
663 if ($numtax == 1) {
664 $arrayofvat = $tablocaltax1;
665 }
666 if ($numtax == 2) {
667 $arrayofvat = $tablocaltax2;
668 }
669
670 foreach ($arrayofvat[$key] as $k => $mt) {
671 if ($mt) {
672 $accountingaccount->fetch(null, $k, true); // TODO Use a cache for label
673 $label_account = $accountingaccount->label;
674
675 $bookkeeping = new BookKeeping($db);
676 $bookkeeping->doc_date = $val["date"];
677 $bookkeeping->date_lim_reglement = $val["datereg"];
678 $bookkeeping->doc_ref = $val["ref"];
679 $bookkeeping->date_creation = $now;
680 $bookkeeping->doc_type = 'customer_invoice';
681 $bookkeeping->fk_doc = $key;
682 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
683 $bookkeeping->thirdparty_code = $companystatic->code_client;
684
685 $bookkeeping->subledger_account = '';
686 $bookkeeping->subledger_label = '';
687
688 $bookkeeping->numero_compte = $k;
689 $bookkeeping->label_compte = $label_account;
690
691
692 $bookkeeping->label_operation = dol_trunc($companystatic->name, 16).' - '.$invoicestatic->ref;
693 $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
694 $bookkeeping->label_operation .= ' - '.$langs->trans("Taxes").' '.$tmpvatrate.' %';
695 $bookkeeping->label_operation .= ($numtax ? ' - Localtax '.$numtax : '');
696
697 $bookkeeping->montant = $mt;
698 $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
699 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
700 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
701 $bookkeeping->code_journal = $journal;
702 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
703 $bookkeeping->fk_user_author = $user->id;
704 $bookkeeping->entity = $conf->entity;
705
706 $totaldebit += $bookkeeping->debit;
707 $totalcredit += $bookkeeping->credit;
708
709 $result = $bookkeeping->create($user);
710 if ($result < 0) {
711 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
712 $error++;
713 $errorforline++;
714 $errorforinvoice[$key] = 'alreadyjournalized';
715 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
716 } else {
717 $error++;
718 $errorforline++;
719 $errorforinvoice[$key] = 'other';
720 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
721 }
722 }
723 }
724 }
725 }
726 }
727
728 // Revenue stamp
729 if (!$errorforline) {
730 if (isset($tabrevenuestamp[$key]) && is_array($tabrevenuestamp[$key])) {
731 foreach ($tabrevenuestamp[$key] as $k => $mt) {
732 if ($mt) {
733 $accountingaccount->fetch(null, $k, true); // TODO Use a cache for label
734 $label_account = $accountingaccount->label;
735
736 $bookkeeping = new BookKeeping($db);
737 $bookkeeping->doc_date = $val["date"];
738 $bookkeeping->date_lim_reglement = $val["datereg"];
739 $bookkeeping->doc_ref = $val["ref"];
740 $bookkeeping->date_creation = $now;
741 $bookkeeping->doc_type = 'customer_invoice';
742 $bookkeeping->fk_doc = $key;
743 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
744 $bookkeeping->thirdparty_code = $companystatic->code_client;
745
746 $bookkeeping->subledger_account = '';
747 $bookkeeping->subledger_label = '';
748
749 $bookkeeping->numero_compte = $k;
750 $bookkeeping->label_compte = $label_account;
751
752 $bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("RevenueStamp");
753 $bookkeeping->montant = $mt;
754 $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
755 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
756 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
757 $bookkeeping->code_journal = $journal;
758 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
759 $bookkeeping->fk_user_author = $user->id;
760 $bookkeeping->entity = $conf->entity;
761
762 $totaldebit += $bookkeeping->debit;
763 $totalcredit += $bookkeeping->credit;
764
765 $result = $bookkeeping->create($user);
766 if ($result < 0) {
767 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
768 $error++;
769 $errorforline++;
770 $errorforinvoice[$key] = 'alreadyjournalized';
771 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
772 } else {
773 $error++;
774 $errorforline++;
775 $errorforinvoice[$key] = 'other';
776 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
777 }
778 }
779 }
780 }
781 }
782 }
783
784 // Protection against a bug on lines before
785 if (!$errorforline && (price2num($totaldebit, 'MT') != price2num($totalcredit, 'MT'))) {
786 $error++;
787 $errorforline++;
788 $errorforinvoice[$key] = 'amountsnotbalanced';
789 setEventMessages('We Tried to insert a non balanced transaction in book for '.$invoicestatic->ref.'. Canceled. Surely a bug.', null, 'errors');
790 }
791
792 if (!$errorforline) {
793 $db->commit();
794 } else {
795 $db->rollback();
796
797 if ($error >= 10) {
798 setEventMessages($langs->trans("ErrorTooManyErrorsProcessStopped"), null, 'errors');
799 break; // Break in the foreach
800 }
801 }
802 }
803
804 $tabpay = $tabfac;
805
806 if (empty($error) && count($tabpay) > 0) {
807 setEventMessages($langs->trans("GeneralLedgerIsWritten"), null, 'mesgs');
808 } elseif (count($tabpay) == $error) {
809 setEventMessages($langs->trans("NoNewRecordSaved"), null, 'warnings');
810 } else {
811 setEventMessages($langs->trans("GeneralLedgerSomeRecordWasNotRecorded"), null, 'warnings');
812 }
813
814 $action = '';
815
816 // Must reload data, so we make a redirect
817 if (count($tabpay) != $error) {
818 $param = 'id_journal='.$id_journal;
819 $param .= '&date_startday='.$date_startday;
820 $param .= '&date_startmonth='.$date_startmonth;
821 $param .= '&date_startyear='.$date_startyear;
822 $param .= '&date_endday='.$date_endday;
823 $param .= '&date_endmonth='.$date_endmonth;
824 $param .= '&date_endyear='.$date_endyear;
825 $param .= '&in_bookkeeping='.$in_bookkeeping;
826 header("Location: ".$_SERVER['PHP_SELF'].($param ? '?'.$param : ''));
827 exit;
828 }
829}
830
831
832
833/*
834 * View
835 */
836
837$form = new Form($db);
838
839// Export
840if ($action == 'exportcsv' && !$error) { // ISO and not UTF8 !
841 // Note that to have the button to get this feature enabled, you must enable ACCOUNTING_ENABLE_EXPORT_DRAFT_JOURNAL
842 $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
843
844 $filename = 'journal';
845 $type_export = 'journal';
846 include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php';
847
848 $companystatic = new Client($db);
849 $invoicestatic = new Facture($db);
850
851 foreach ($tabfac as $key => $val) {
852 $companystatic->id = $tabcompany[$key]['id'];
853 $companystatic->name = $tabcompany[$key]['name'];
854 $companystatic->code_compta = $tabcompany[$key]['code_compta']; // deprecated
855 $companystatic->code_compta_client = $tabcompany[$key]['code_compta'];
856 $companystatic->code_client = $tabcompany[$key]['code_client'];
857 $companystatic->client = 3;
858
859 $invoicestatic->id = $key;
860 $invoicestatic->ref = (string) $val["ref"];
861 $invoicestatic->type = $val["type"];
862 $invoicestatic->close_code = $val["close_code"];
863
864 $date = dol_print_date($val["date"], 'day');
865
866 // Is it a replaced invoice? 0=not a replaced invoice, 1=replaced invoice not yet dispatched, 2=replaced invoice dispatched
867 $replacedinvoice = 0;
868 if ($invoicestatic->close_code == Facture::CLOSECODE_REPLACED) {
869 $replacedinvoice = 1;
870 $alreadydispatched = $invoicestatic->getVentilExportCompta(); // Test if replaced invoice already into bookkeeping.
871 if ($alreadydispatched) {
872 $replacedinvoice = 2;
873 }
874 }
875
876 // 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)
877 if ($replacedinvoice == 1) {
878 continue;
879 }
880
881 // Warranty
882 if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && isset($tabwarranty[$key])) {
883 foreach ($tabwarranty[$key] as $k => $mt) {
884 //if ($mt) {
885 print '"'.$key.'"'.$sep;
886 print '"'.$date.'"'.$sep;
887 print '"'.$val["ref"].'"'.$sep;
888 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
889 print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
890 print '"'.length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY')).'"'.$sep;
891 print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
892 print '"'.$langs->trans("Thirdparty").'"'.$sep;
893 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("RetainedWarranty").'"'.$sep;
894 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
895 print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
896 print '"'.$journal.'"';
897 print "\n";
898 //}
899 }
900 }
901
902 // Third party
903 foreach ($tabttc[$key] as $k => $mt) {
904 //if ($mt) {
905 print '"'.$key.'"'.$sep;
906 print '"'.$date.'"'.$sep;
907 print '"'.$val["ref"].'"'.$sep;
908 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
909 print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
910 print '"'.length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER')).'"'.$sep;
911 print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
912 print '"'.$langs->trans("Thirdparty").'"'.$sep;
913 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("Thirdparty").'"'.$sep;
914 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
915 print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
916 print '"'.$journal.'"';
917 print "\n";
918 //}
919 }
920
921 // Product / Service
922 foreach ($tabht[$key] as $k => $mt) {
923 $accountingaccount = new AccountingAccount($db);
924 $accountingaccount->fetch(null, $k, true);
925 //if ($mt) {
926 print '"'.$key.'"'.$sep;
927 print '"'.$date.'"'.$sep;
928 print '"'.$val["ref"].'"'.$sep;
929 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
930 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
931 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
932 print '""'.$sep;
933 print '"'.mb_convert_encoding(dol_trunc($accountingaccount->label, 32), 'ISO-8859-1').'"'.$sep;
934 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.dol_trunc($accountingaccount->label, 32).'"'.$sep;
935 print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
936 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
937 print '"'.$journal.'"';
938 print "\n";
939 //}
940 }
941
942 // VAT
943 $listoftax = array(0, 1, 2);
944 foreach ($listoftax as $numtax) {
945 $arrayofvat = $tabtva;
946 if ($numtax == 1) {
947 $arrayofvat = $tablocaltax1;
948 }
949 if ($numtax == 2) {
950 $arrayofvat = $tablocaltax2;
951 }
952
953 foreach ($arrayofvat[$key] as $k => $mt) {
954 if ($mt) {
955 print '"'.$key.'"'.$sep;
956 print '"'.$date.'"'.$sep;
957 print '"'.$val["ref"].'"'.$sep;
958 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
959 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
960 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
961 print '""'.$sep;
962 print '"'.$langs->trans("VAT").' - '.implode(', ', $def_tva[$key][$k]).' %"'.$sep;
963 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;
964 print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
965 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
966 print '"'.$journal.'"';
967 print "\n";
968 }
969 }
970 }
971
972 // Revenue stamp
973 if (isset($tabrevenuestamp[$key])) {
974 foreach ($tabrevenuestamp[$key] as $k => $mt) {
975 //if ($mt) {
976 print '"'.$key.'"'.$sep;
977 print '"'.$date.'"'.$sep;
978 print '"'.$val["ref"].'"'.$sep;
979 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
980 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
981 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
982 print '""'.$sep;
983 print '"'.$langs->trans("RevenueStamp").'"'.$sep;
984 print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("RevenueStamp").'"'.$sep;
985 print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
986 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
987 print '"'.$journal.'"';
988 print "\n";
989 //}
990 }
991 }
992 }
993}
994
995
996
997if (empty($action) || $action == 'view') {
998 $title = $langs->trans("GenerationOfAccountingEntries").' - '.$accountingjournalstatic->getNomUrl(0, 2, 1, '', 1);
999 $help_url ='EN:Module_Double_Entry_Accounting|FR:Module_Comptabilit&eacute;_en_Partie_Double#G&eacute;n&eacute;ration_des_&eacute;critures_en_comptabilit&eacute;';
1000 llxHeader('', dol_string_nohtmltag($title), $help_url, '', 0, 0, '', '', '', 'mod-accountancy accountancy-generation page-sellsjournal');
1001
1002 $nom = $title;
1003 $nomlink = '';
1004 $periodlink = '';
1005 $exportlink = '';
1006 $builddate = dol_now();
1007 $description = $langs->trans("DescJournalOnlyBindedVisible").'<br>';
1008 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
1009 $description .= $langs->trans("DepositsAreNotIncluded");
1010 } else {
1011 $description .= $langs->trans("DepositsAreIncluded");
1012 }
1013
1014 $listofchoices = array('notyet' => $langs->trans("NotYetInGeneralLedger"), 'already' => $langs->trans("AlreadyInGeneralLedger"));
1015 $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);
1016 $period .= ' - '.$langs->trans("JournalizationInLedgerStatus").' '.$form->selectarray('in_bookkeeping', $listofchoices, $in_bookkeeping, 1);
1017
1018 $varlink = 'id_journal='.$id_journal;
1019
1020 journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''), '', $varlink);
1021
1022 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') != 'blockedonclosed') {
1023 // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed)
1024 // Fiscal period test
1025 $sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_fiscalyear WHERE entity = ".((int) $conf->entity);
1026 $resql = $db->query($sql);
1027 if ($resql) {
1028 $obj = $db->fetch_object($resql);
1029 if ($obj->nb == 0) {
1030 print '<br><div class="warning">'.img_warning().' '.$langs->trans("TheFiscalPeriodIsNotDefined");
1031 $desc = ' : '.$langs->trans("AccountancyAreaDescFiscalPeriod", 4, '{link}');
1032 $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("FiscalPeriod").'</strong>', $desc);
1033 print $desc;
1034 print '</div>';
1035 }
1036 } else {
1037 dol_print_error($db);
1038 }
1039 }
1040
1041 // Button to write into Ledger
1042 $acctCustomerNotConfigured = in_array(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER'), ['','-1']);
1043 if ($acctCustomerNotConfigured) {
1044 print '<br><div class="warning">'.img_warning().' '.$langs->trans("SomeMandatoryStepsOfSetupWereNotDone");
1045 $desc = ' : '.$langs->trans("AccountancyAreaDescMisc", 4, '{link}');
1046 $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuDefaultAccounts").'</strong>', $desc);
1047 print $desc;
1048 print '</div>';
1049 }
1050 print '<br><div class="tabsAction tabsActionNoBottom centerimp">';
1051 if (getDolGlobalString('ACCOUNTING_ENABLE_EXPORT_DRAFT_JOURNAL') && $in_bookkeeping == 'notyet') {
1052 print '<input type="button" class="butAction" name="exportcsv" value="'.$langs->trans("ExportDraftJournal").'" onclick="launch_export();" />';
1053 }
1054 if ($acctCustomerNotConfigured) {
1055 print '<input type="button" class="butActionRefused classfortooltip" title="'.dol_escape_htmltag($langs->trans("SomeMandatoryStepsOfSetupWereNotDone")).'" value="'.$langs->trans("WriteBookKeeping").'" />';
1056 } else {
1057 if ($in_bookkeeping == 'notyet') {
1058 print '<input type="button" class="butAction" name="writebookkeeping" value="'.$langs->trans("WriteBookKeeping").'" onclick="writebookkeeping();" />';
1059 } else {
1060 print '<a href="#" class="butActionRefused classfortooltip" name="writebookkeeping">'.$langs->trans("WriteBookKeeping").'</a>';
1061 }
1062 }
1063 print '</div>';
1064
1065 // TODO Avoid using js. We can use a direct link with $param
1066 print '
1067 <script type="text/javascript">
1068 function launch_export() {
1069 $("div.fiche form input[name=\"action\"]").val("exportcsv");
1070 $("div.fiche form input[type=\"submit\"]").click();
1071 $("div.fiche form input[name=\"action\"]").val("");
1072 }
1073 function writebookkeeping() {
1074 console.log("click on writebookkeeping");
1075 $("div.fiche form input[name=\"action\"]").val("writebookkeeping");
1076 $("div.fiche form input[type=\"submit\"]").click();
1077 $("div.fiche form input[name=\"action\"]").val("");
1078 }
1079 </script>';
1080
1081 /*
1082 * Show result array
1083 */
1084 print '<br>';
1085
1086 print '<div class="div-table-responsive">';
1087 print "<table class=\"noborder\" width=\"100%\">";
1088 print "<tr class=\"liste_titre\">";
1089 print "<td>".$langs->trans("Date")."</td>";
1090 print "<td>".$langs->trans("Piece").' ('.$langs->trans("InvoiceRef").")</td>";
1091 print "<td>".$langs->trans("AccountAccounting")."</td>";
1092 print "<td>".$langs->trans("SubledgerAccount")."</td>";
1093 print "<td>".$langs->trans("LabelOperation")."</td>";
1094 print '<td class="center">'.$langs->trans("AccountingDebit")."</td>";
1095 print '<td class="center">'.$langs->trans("AccountingCredit")."</td>";
1096 print "</tr>\n";
1097
1098 $i = 0;
1099
1100 $companystatic = new Client($db);
1101 $invoicestatic = new Facture($db);
1102
1103 foreach ($tabfac as $key => $val) {
1104 $companystatic->id = $tabcompany[$key]['id'];
1105 $companystatic->name = $tabcompany[$key]['name'];
1106 $companystatic->code_compta = $tabcompany[$key]['code_compta'];
1107 $companystatic->code_compta_client = $tabcompany[$key]['code_compta'];
1108 $companystatic->code_client = $tabcompany[$key]['code_client'];
1109 $companystatic->client = 3;
1110
1111 $invoicestatic->id = $key;
1112 $invoicestatic->ref = (string) $val["ref"];
1113 $invoicestatic->type = $val["type"];
1114 $invoicestatic->close_code = $val["close_code"];
1115
1116 $date = dol_print_date($val["date"], 'day');
1117
1118 // Is it a replaced invoice? 0=not a replaced invoice, 1=replaced invoice not yet dispatched, 2=replaced invoice dispatched
1119 $replacedinvoice = 0;
1120 if ($invoicestatic->close_code == Facture::CLOSECODE_REPLACED) {
1121 $replacedinvoice = 1;
1122 $alreadydispatched = $invoicestatic->getVentilExportCompta(); // Test if replaced invoice already into bookkeeping.
1123 if ($alreadydispatched) {
1124 $replacedinvoice = 2;
1125 }
1126 }
1127
1128 // If not already into bookkeeping, we won't add it, if yes, add the counterpart ???.
1129 if ($replacedinvoice == 1) {
1130 print '<tr class="oddeven">';
1131 print "<!-- Replaced invoice -->";
1132 print "<td>".$date."</td>";
1133 print "<td><strike>".$invoicestatic->getNomUrl(1)."</strike></td>";
1134 // Account
1135 print "<td>";
1136 print $langs->trans("Replaced");
1137 print '</td>';
1138 // Subledger account
1139 print "<td>";
1140 print '</td>';
1141 print "<td>";
1142 print "</td>";
1143 print '<td class="right"></td>';
1144 print '<td class="right"></td>';
1145 print "</tr>";
1146
1147 $i++;
1148 continue;
1149 }
1150 if (isset($errorforinvoice[$key]) && $errorforinvoice[$key] == 'somelinesarenotbound') {
1151 print '<tr class="oddeven">';
1152 print "<!-- Some lines are not bound -->";
1153 print "<td>".$date."</td>";
1154 print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1155 // Account
1156 print "<td>";
1157 print '<span class="error">'.$langs->trans('ErrorInvoiceContainsLinesNotYetBoundedShort', $val['ref']).'</span>';
1158 print '</td>';
1159 // Subledger account
1160 print "<td>";
1161 print '</td>';
1162 print "<td>";
1163 print "</td>";
1164 print '<td class="right"></td>';
1165 print '<td class="right"></td>';
1166 print "</tr>";
1167
1168 $i++;
1169 }
1170
1171 // Warranty
1172 if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && isset($tabwarranty[$key]) && is_array($tabwarranty[$key])) {
1173 foreach ($tabwarranty[$key] as $k => $mt) {
1174 print '<tr class="oddeven">';
1175 print "<!-- Thirdparty warranty -->";
1176 print "<td>" . $date . "</td>";
1177 print "<td>" . $invoicestatic->getNomUrl(1) . "</td>";
1178 // Account
1179 print "<td>";
1180 $accountoshow = length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY'));
1181 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1182 print '<span class="error">' . $langs->trans("MainAccountForRetainedWarrantyNotDefined") . '</span>';
1183 } else {
1184 print $accountoshow;
1185 }
1186 print '</td>';
1187 // Subledger account
1188 print "<td>";
1189 $accountoshow = length_accounta($k);
1190 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1191 print '<span class="error">' . $langs->trans("ThirdpartyAccountNotDefined") . '</span>';
1192 } else {
1193 print $accountoshow;
1194 }
1195 print '</td>';
1196 print "<td>" . $companystatic->getNomUrl(0, 'customer', 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("RetainedWarranty") . "</td>";
1197 print '<td class="right nowraponall amount">' . ($mt >= 0 ? price($mt) : '') . "</td>";
1198 print '<td class="right nowraponall amount">' . ($mt < 0 ? price(-$mt) : '') . "</td>";
1199 print "</tr>";
1200 }
1201 }
1202
1203 // Third party
1204 foreach ($tabttc[$key] as $k => $mt) {
1205 print '<tr class="oddeven">';
1206 print "<!-- Thirdparty -->";
1207 print "<td>".$date."</td>";
1208 print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1209 // Account
1210 print "<td>";
1211 $accountoshow = length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER'));
1212 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1213 print '<span class="error">'.$langs->trans("MainAccountForCustomersNotDefined").'</span>';
1214 } else {
1215 print $accountoshow;
1216 }
1217 print '</td>';
1218 // Subledger account
1219 print "<td>";
1220 $accountoshow = length_accounta($k);
1221 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1222 print '<span class="error">'.$langs->trans("ThirdpartyAccountNotDefined").'</span>';
1223 } else {
1224 print $accountoshow;
1225 }
1226 print '</td>';
1227 print "<td>".$companystatic->getNomUrl(0, 'customer', 16).' - '.$invoicestatic->ref.' - '.$langs->trans("SubledgerAccount")."</td>";
1228 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
1229 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
1230 print "</tr>";
1231
1232 $i++;
1233 }
1234
1235 // Product / Service
1236 foreach ($tabht[$key] as $k => $mt) {
1237 if (empty($conf->cache['accountingaccountincurrententity'][$k])) {
1238 $accountingaccount = new AccountingAccount($db);
1239 $accountingaccount->fetch(0, $k, true);
1240 $conf->cache['accountingaccountincurrententity'][$k] = $accountingaccount;
1241 } else {
1242 $accountingaccount = $conf->cache['accountingaccountincurrententity'][$k];
1243 }
1244
1245 print '<tr class="oddeven">';
1246 print "<!-- Product -->";
1247 print "<td>".$date."</td>";
1248 print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1249 // Account
1250 print "<td>";
1251 $accountoshow = length_accountg($k);
1252 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1253 print '<span class="error">'.$langs->trans("ProductNotDefined").'</span>';
1254 } else {
1255 print $accountoshow;
1256 }
1257 print "</td>";
1258 // Subledger account
1259 print "<td>";
1260 if (getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_USE_AUXILIARY_ON_DEPOSIT')) {
1261 if ($k == getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT')) {
1262 print length_accounta($tabcompany[$key]['code_compta']);
1263 }
1264 } elseif (($accountoshow == "") || $accountoshow == 'NotDefined') {
1265 print '<span class="error">' . $langs->trans("ThirdpartyAccountNotDefined") . '</span>';
1266 }
1267 print '</td>';
1268 $companystatic->id = $tabcompany[$key]['id'];
1269 $companystatic->name = $tabcompany[$key]['name'];
1270 print "<td>".$companystatic->getNomUrl(0, 'customer', 16).' - '.$invoicestatic->ref.' - '.$accountingaccount->label."</td>";
1271 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
1272 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
1273 print "</tr>";
1274
1275 $i++;
1276 }
1277
1278 // VAT
1279 $listoftax = array(0, 1, 2);
1280 foreach ($listoftax as $numtax) {
1281 $arrayofvat = $tabtva;
1282 if ($numtax == 1) {
1283 $arrayofvat = $tablocaltax1;
1284 }
1285 if ($numtax == 2) {
1286 $arrayofvat = $tablocaltax2;
1287 }
1288
1289 // $key is id of invoice
1290 foreach ($arrayofvat[$key] as $k => $mt) {
1291 if ($mt) {
1292 print '<tr class="oddeven">';
1293 print "<!-- VAT -->";
1294 print "<td>".$date."</td>";
1295 print "<td>".$invoicestatic->getNomUrl(1)."</td>";
1296 // Account
1297 print "<td>";
1298 $accountoshow = length_accountg($k);
1299 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1300 print '<span class="error">'.$langs->trans("VATAccountNotDefined").' ('.$langs->trans("AccountingJournalType2").')</span>';
1301 } else {
1302 print $accountoshow;
1303 }
1304 print "</td>";
1305 // Subledger account
1306 print "<td>";
1307 print '</td>';
1308 print "<td>".$companystatic->getNomUrl(0, 'customer', 16).' - '.$invoicestatic->ref;
1309 // $def_tva is array[invoiceid][accountancy_code_sell_of_vat_rate_found][vatrate]=vatrate
1310 //var_dump($arrayofvat[$key]); //var_dump($key); //var_dump($k);
1311 $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
1312 print ' - '.$langs->trans("Taxes").' '.$tmpvatrate.' %';
1313 print($numtax ? ' - Localtax '.$numtax : '');
1314 print "</td>";
1315 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
1316 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
1317 print "</tr>";
1318
1319 $i++;
1320 }
1321 }
1322 }
1323
1324 // Revenue stamp
1325 if (isset($tabrevenuestamp[$key]) && is_array($tabrevenuestamp[$key])) {
1326 foreach ($tabrevenuestamp[$key] as $k => $mt) {
1327 print '<tr class="oddeven">';
1328 print "<!-- Thirdparty revenuestamp -->";
1329 print "<td>" . $date . "</td>";
1330 print "<td>" . $invoicestatic->getNomUrl(1) . "</td>";
1331 // Account
1332 print "<td>";
1333 $accountoshow = length_accountg($k);
1334 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
1335 print '<span class="error">' . $langs->trans("MainAccountForRevenueStampSaleNotDefined") . '</span>';
1336 } else {
1337 print $accountoshow;
1338 }
1339 print '</td>';
1340 // Subledger account
1341 print "<td>";
1342 print '</td>';
1343 print "<td>" . $companystatic->getNomUrl(0, 'customer', 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("RevenueStamp") . "</td>";
1344 print '<td class="right nowraponall amount">' . ($mt < 0 ? price(-$mt) : '') . "</td>";
1345 print '<td class="right nowraponall amount">' . ($mt >= 0 ? price($mt) : '') . "</td>";
1346 print "</tr>";
1347 }
1348 }
1349 }
1350
1351 if (!$i) {
1352 print '<tr class="oddeven"><td colspan="7"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
1353 }
1354
1355 print "</table>";
1356 print '</div>';
1357
1358 // End of page
1359 llxFooter();
1360}
1361
1362$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($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:70
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...)
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:594
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition date.lib.php:613
llxFooter()
Footer empty.
Definition document.php:107
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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.