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