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