Test Failed
Branch main (fda838)
by Rafael
50:22
created

AccountingCustomerController   F

Complexity

Total Complexity 365

Size/Duplication

Total Lines 2268
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1554
dl 0
loc 2268
rs 0.8
c 2
b 0
f 0
wmc 365

4 Methods

Rating   Name   Duplication   Size   Complexity  
F index() 0 724 119
F lines() 0 559 89
F list() 0 798 141
F card() 0 159 16

How to fix   Complexity   

Complex Class

Complex classes like AccountingCustomerController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AccountingCustomerController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* Copyright (C) 2013-2016  Olivier Geffroy         <[email protected]>
4
 * Copyright (C) 2013-2024	Alexandre Spangaro	    <[email protected]>
5
 * Copyright (C) 2014-2015	Ari Elbaz (elarifr)	    <[email protected]>
6
 * Copyright (C) 2013-2021	Florian Henry		    <[email protected]>
7
 * Copyright (C) 2014	  	Juanjo Menent		    <[email protected]>
8
 * Copyright (C) 2015       Jean-François Ferry     <[email protected]>
9
 * Copyright (C) 2016	  	Laurent Destailleur     <[email protected]>
10
 * Copyright (C) 2021      	Gauthier VERDOL         <[email protected]>
11
 * Copyright (C) 2024       Rafael San José         <[email protected]>
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 3 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25
 */
26
27
namespace DoliModules\Accounting\Controller;
28
29
global $conf;
30
global $db;
31
global $user;
32
global $hookmanager;
33
global $user;
34
global $menumanager;
35
global $langs;
36
global $mysoc;
37
38
// Load Dolibarr environment
39
require BASE_PATH . '/main.inc.php';
40
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
41
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php';
42
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php';
43
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
44
require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
45
require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
46
require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
47
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
48
49
use DoliCore\Base\DolibarrController;
50
use DoliModules\Accounting\Model\AccountingAccount;
51
52
class AccountingCustomerController extends DolibarrController
0 ignored issues
show
Deprecated Code introduced by
The class DoliCore\Base\DolibarrController has been deprecated: This class is only needed for compatibility with Dolibarr. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

52
class AccountingCustomerController extends /** @scrutinizer ignore-deprecated */ DolibarrController
Loading history...
53
{
54
    /**
55
     * \file    htdocs/accountancy/customer/card.php
56
     * \ingroup Accountancy (Double entries)
57
     * \brief   Card customer ventilation
58
     */
59
    public function card()
60
    {
61
        global $conf;
62
        global $db;
63
        global $user;
64
        global $hookmanager;
65
        global $user;
66
        global $menumanager;
67
        global $langs;
68
        global $mysoc;
69
70
// Load translation files required by the page
71
        $langs->loadLangs(array("bills", "accountancy"));
72
73
        $action = GETPOST('action', 'aZ09');
74
        $cancel = GETPOST('cancel', 'alpha');
75
        $backtopage = GETPOST('backtopage', 'alpha');
76
77
        $codeventil = GETPOSTINT('codeventil');
78
        $id = GETPOSTINT('id');
79
80
// Security check
81
        if (!isModEnabled('accounting')) {
82
            accessforbidden();
83
        }
84
        if ($user->socid > 0) {
85
            accessforbidden();
86
        }
87
        if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
88
            accessforbidden();
89
        }
90
91
92
93
        /*
94
         * Actions
95
         */
96
97
        if ($action == 'ventil' && $user->hasRight('accounting', 'bind', 'write')) {
98
            if (!$cancel) {
99
                if ($codeventil < 0) {
100
                    $codeventil = 0;
101
                }
102
103
                $sql = " UPDATE " . MAIN_DB_PREFIX . "facturedet";
104
                $sql .= " SET fk_code_ventilation = " . ((int) $codeventil);
105
                $sql .= " WHERE rowid = " . ((int) $id);
106
107
                $resql = $db->query($sql);
108
                if (!$resql) {
109
                    setEventMessages($db->lasterror(), null, 'errors');
110
                } else {
111
                    setEventMessages($langs->trans("RecordModifiedSuccessfully"), null, 'mesgs');
112
                    if ($backtopage) {
113
                        header("Location: " . $backtopage);
114
                        exit();
115
                    }
116
                }
117
            } else {
118
                header("Location: ./lines.php");
119
                exit();
120
            }
121
        }
122
123
124
        /*
125
         * View
126
         */
127
        $help_url = 'EN:Module_Double_Entry_Accounting|FR:Module_Comptabilit&eacute;_en_Partie_Double#Liaisons_comptables';
128
129
        llxHeader("", $langs->trans('FicheVentilation'), $help_url);
130
131
        if ($cancel == $langs->trans("Cancel")) {
132
            $action = '';
133
        }
134
135
        /*
136
         * Create
137
         */
138
        $form = new Form($db);
0 ignored issues
show
Bug introduced by
The type DoliModules\Accounting\Controller\Form was not found. Did you mean Form? If so, make sure to prefix the type with \.
Loading history...
139
        $facture_static = new Facture($db);
140
        $formaccounting = new FormAccounting($db);
0 ignored issues
show
Bug introduced by
The type DoliModules\Accounting\Controller\FormAccounting was not found. Did you mean FormAccounting? If so, make sure to prefix the type with \.
Loading history...
141
142
        if (!empty($id)) {
143
            $sql = "SELECT f.ref, f.rowid as facid, l.fk_product, l.description, l.price,";
144
            $sql .= " l.qty, l.rowid, l.tva_tx, l.remise_percent, l.subprice,";
145
            if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
146
                $sql .= " ppe.accountancy_code_sell as code_sell,";
147
            } else {
148
                $sql .= " p.accountancy_code_sell as code_sell,";
149
            }
150
            $sql .= " l.fk_code_ventilation, aa.account_number, aa.label";
151
            $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as l";
152
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = l.fk_product";
153
            if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
154
                $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
155
            }
156
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON l.fk_code_ventilation = aa.rowid";
157
            $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = l.fk_facture";
158
            $sql .= " WHERE f.fk_statut > 0 AND l.rowid = " . ((int) $id);
159
            $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
160
161
            dol_syslog("/accounting/customer/card.php", LOG_DEBUG);
162
            $result = $db->query($sql);
163
164
            if ($result) {
165
                $num_lines = $db->num_rows($result);
166
                $i = 0;
167
168
                if ($num_lines) {
169
                    $objp = $db->fetch_object($result);
170
171
                    print '<form action="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '" method="post">' . "\n";
172
                    print '<input type="hidden" name="token" value="' . newToken() . '">';
173
                    print '<input type="hidden" name="action" value="ventil">';
174
                    print '<input type="hidden" name="backtopage" value="' . dol_escape_htmltag($backtopage) . '">';
175
176
                    print load_fiche_titre($langs->trans('CustomersVentilation'), '', 'title_accountancy');
177
178
                    print dol_get_fiche_head();
179
180
                    print '<table class="border centpercent">';
181
182
                    // Ref facture
183
                    print '<tr><td>' . $langs->trans("Invoice") . '</td>';
184
                    $facture_static->ref = $objp->ref;
185
                    $facture_static->id = $objp->facid;
186
                    print '<td>' . $facture_static->getNomUrl(1) . '</td>';
187
                    print '</tr>';
188
189
                    print '<tr><td width="20%">' . $langs->trans("Line") . '</td>';
190
                    print '<td>' . nl2br($objp->description) . '</td></tr>';
191
                    print '<tr><td width="20%">' . $langs->trans("Account") . '</td><td>';
192
                    print $formaccounting->select_account($objp->fk_code_ventilation, 'codeventil', 1);
193
                    print '</td></tr>';
194
                    print '</table>';
195
196
                    print dol_get_fiche_end();
197
198
                    print '<div class="center">';
199
                    print '<input class="button button-save" type="submit" value="' . $langs->trans("Save") . '">';
200
                    print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
201
                    print '<input class="button button-cancel" type="submit" name="cancel" value="' . $langs->trans("Cancel") . '">';
202
                    print '</div>';
203
204
                    print '</form>';
205
                } else {
206
                    print "Error";
207
                }
208
            } else {
209
                print "Error";
210
            }
211
        } else {
212
            print "Error ID incorrect";
213
        }
214
215
// End of page
216
        llxFooter();
217
        $db->close();
218
    }
219
220
    /**
221
     * \file    htdocs/accountancy/customer/index.php
222
     * \ingroup Accountancy (Double entries)
223
     * \brief   Home customer journalization page
224
     */
225
    public function index()
226
    {
227
        global $conf;
228
        global $db;
229
        global $user;
230
        global $hookmanager;
231
        global $user;
232
        global $menumanager;
233
        global $langs;
234
        global $mysoc;
235
236
// Load translation files required by the page
237
        $langs->loadLangs(["compta", "bills", "other", "accountancy"]);
238
239
        $validatemonth = GETPOSTINT('validatemonth');
240
        $validateyear = GETPOSTINT('validateyear');
241
242
// Security check
243
        if (!isModEnabled('accounting')) {
244
            accessforbidden();
245
        }
246
        if ($user->socid > 0) {
247
            accessforbidden();
248
        }
249
        if (!$user->hasRight('accounting', 'bind', 'write')) {
250
            accessforbidden();
251
        }
252
253
        $accountingAccount = new AccountingAccount($db);
254
255
        $month_start = getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1);
256
        if (GETPOSTINT("year")) {
257
            $year_start = GETPOSTINT("year");
258
        } else {
259
            $year_start = dol_print_date(dol_now(), '%Y');
260
            if (dol_print_date(dol_now(), '%m') < $month_start) {
261
                $year_start--; // If current month is lower that starting fiscal month, we start last year
262
            }
263
        }
264
        $year_end = $year_start + 1;
265
        $month_end = $month_start - 1;
266
        if ($month_end < 1) {
267
            $month_end = 12;
268
            $year_end--;
269
        }
270
        $search_date_start = dol_mktime(0, 0, 0, $month_start, 1, $year_start);
271
        $search_date_end = dol_get_last_day($year_end, $month_end);
272
        $year_current = $year_start;
273
274
// Validate History
275
        $action = GETPOST('action', 'aZ09');
276
277
        $chartaccountcode = dol_getIdFromCode($db, getDolGlobalInt('CHARTOFACCOUNTS'), 'accounting_system', 'rowid', 'pcg_version');
278
279
// Security check
280
        if (!isModEnabled('accounting')) {
281
            accessforbidden();
282
        }
283
        if ($user->socid > 0) {
284
            accessforbidden();
285
        }
286
        if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
287
            accessforbidden();
288
        }
289
290
291
        /*
292
         * Actions
293
         */
294
295
        if (($action == 'clean' || $action == 'validatehistory') && $user->hasRight('accounting', 'bind', 'write')) {
296
            // Clean database by removing binding done on non existing or no more existing accounts
297
            $db->begin();
298
            $sql1 = "UPDATE " . $db->prefix() . "facturedet as fd";
299
            $sql1 .= " SET fk_code_ventilation = 0";
300
            $sql1 .= ' WHERE fd.fk_code_ventilation NOT IN';
301
            $sql1 .= '	(SELECT accnt.rowid ';
302
            $sql1 .= '	FROM ' . $db->prefix() . 'accounting_account as accnt';
303
            $sql1 .= '	INNER JOIN ' . $db->prefix() . 'accounting_system as syst';
304
            $sql1 .= "	ON accnt.fk_pcg_version = syst.pcg_version AND syst.rowid = " . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . " AND accnt.entity = " . ((int) $conf->entity) . ")";
305
            $sql1 .= " AND fd.fk_facture IN (SELECT rowid FROM " . $db->prefix() . "facture WHERE entity = " . ((int) $conf->entity) . ")";
306
            $sql1 .= " AND fk_code_ventilation <> 0";
307
308
            dol_syslog("htdocs/accountancy/customer/index.php fixaccountancycode", LOG_DEBUG);
309
            $resql1 = $db->query($sql1);
310
            if (!$resql1) {
311
                $error++;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $error seems to be never defined.
Loading history...
312
                $db->rollback();
313
                setEventMessages($db->lasterror(), null, 'errors');
314
            } else {
315
                $db->commit();
316
            }
317
            // End clean database
318
        }
319
320
        if ($action == 'validatehistory') {
321
            $error = 0;
322
            $nbbinddone = 0;
323
            $nbbindfailed = 0;
324
            $notpossible = 0;
325
326
            $db->begin();
327
328
            // Now make the binding. Bind automatically only for product with a dedicated account that exists into chart of account, others need a manual bind
329
            // Customer Invoice lines (must be same request than into page list.php for manual binding)
330
            $sql = "SELECT f.rowid as facid, f.ref as ref, f.datef, f.type as ftype, f.situation_cycle_ref, f.fk_facture_source,";
331
            $sql .= " l.rowid, l.fk_product, l.description, l.total_ht, l.fk_code_ventilation, l.product_type as type_l, l.situation_percent, l.tva_tx as tva_tx_line, l.vat_src_code,";
332
            $sql .= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.tva_tx as tva_tx_prod,";
333
            if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
334
                $sql .= " ppe.accountancy_code_sell as code_sell, ppe.accountancy_code_sell_intra as code_sell_intra, ppe.accountancy_code_sell_export as code_sell_export,";
335
            } else {
336
                $sql .= " p.accountancy_code_sell as code_sell, p.accountancy_code_sell_intra as code_sell_intra, p.accountancy_code_sell_export as code_sell_export,";
337
            }
338
            $sql .= " aa.rowid as aarowid, aa2.rowid as aarowid_intra, aa3.rowid as aarowid_export, aa4.rowid as aarowid_thirdparty,";
339
            $sql .= " co.code as country_code, co.label as country_label,";
340
            $sql .= " s.tva_intra,";
341
            if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
342
                $sql .= " spe.accountancy_code_sell as company_code_sell";  // accounting code for product but stored on thirdparty
343
            } else {
344
                $sql .= " s.accountancy_code_sell as company_code_sell";    // accounting code for product but stored on thirdparty
345
            }
346
            $sql .= " FROM " . $db->prefix() . "facture as f";
347
            $sql .= " INNER JOIN " . $db->prefix() . "societe as s ON s.rowid = f.fk_soc";
348
            if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
349
                $sql .= " LEFT JOIN " . $db->prefix() . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity);
350
            }
351
            $sql .= " LEFT JOIN " . $db->prefix() . "c_country as co ON co.rowid = s.fk_pays ";
352
            $sql .= " INNER JOIN " . $db->prefix() . "facturedet as l ON f.rowid = l.fk_facture";   // the main table
353
            $sql .= " LEFT JOIN " . $db->prefix() . "product as p ON p.rowid = l.fk_product";
354
            if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
355
                $sql .= " LEFT JOIN " . $db->prefix() . "product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
356
            }
357
            $alias_societe_perentity = !getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED') ? "s" : "spe";
358
            $alias_product_perentity = !getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED') ? "p" : "ppe";
359
            $sql .= " LEFT JOIN " . $db->prefix() . "accounting_account as aa  ON " . $db->sanitize($alias_product_perentity) . ".accountancy_code_sell = aa.account_number         AND aa.active = 1  AND aa.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa.entity = " . $conf->entity;
360
            $sql .= " LEFT JOIN " . $db->prefix() . "accounting_account as aa2 ON " . $db->sanitize($alias_product_perentity) . ".accountancy_code_sell_intra = aa2.account_number  AND aa2.active = 1 AND aa2.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa2.entity = " . $conf->entity;
361
            $sql .= " LEFT JOIN " . $db->prefix() . "accounting_account as aa3 ON " . $db->sanitize($alias_product_perentity) . ".accountancy_code_sell_export = aa3.account_number AND aa3.active = 1 AND aa3.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa3.entity = " . $conf->entity;
362
            $sql .= " LEFT JOIN " . $db->prefix() . "accounting_account as aa4 ON " . $db->sanitize($alias_societe_perentity) . ".accountancy_code_sell = aa4.account_number        AND aa4.active = 1 AND aa4.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa4.entity = " . $conf->entity;
363
            $sql .= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0";
364
            $sql .= " AND l.product_type <= 2";
365
            $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
366
            if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
367
                $sql .= " AND f.datef >= '" . $db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) . "'";
368
            }
369
            if ($validatemonth && $validateyear) {
370
                $sql .= dolSqlDateFilter('f.datef', 0, $validatemonth, $validateyear);
371
            }
372
373
            dol_syslog('htdocs/accountancy/customer/index.php');
374
375
            $result = $db->query($sql);
376
            if (!$result) {
377
                $error++;
378
                setEventMessages($db->lasterror(), null, 'errors');
379
            } else {
380
                $num_lines = $db->num_rows($result);
381
382
                $facture_static = new Facture($db);
383
384
                $isSellerInEEC = isInEEC($mysoc);
385
386
                $thirdpartystatic = new Societe($db);
0 ignored issues
show
Bug introduced by
The type DoliModules\Accounting\Controller\Societe was not found. Did you mean Societe? If so, make sure to prefix the type with \.
Loading history...
387
                $facture_static = new Facture($db);
388
                $facture_static_det = new FactureLigne($db);
389
                $product_static = new Product($db);
0 ignored issues
show
Bug introduced by
The type DoliModules\Accounting\Controller\Product was not found. Did you mean Product? If so, make sure to prefix the type with \.
Loading history...
390
391
                $i = 0;
392
                while ($i < min($num_lines, 10000)) {   // No more than 10000 at once
393
                    $objp = $db->fetch_object($result);
394
395
                    $thirdpartystatic->id = !empty($objp->socid) ? $objp->socid : 0;
396
                    $thirdpartystatic->name = !empty($objp->name) ? $objp->name : "";
397
                    $thirdpartystatic->client = !empty($objp->client) ? $objp->client : "";
398
                    $thirdpartystatic->fournisseur = !empty($objp->fournisseur) ? $objp->fournisseur : "";
399
                    $thirdpartystatic->code_client = !empty($objp->code_client) ? $objp->code_client : "";
400
                    $thirdpartystatic->code_compta_client = !empty($objp->code_compta_client) ? $objp->code_compta_client : "";
401
                    $thirdpartystatic->code_fournisseur = !empty($objp->code_fournisseur) ? $objp->code_fournisseur : "";
402
                    $thirdpartystatic->code_compta_fournisseur = !empty($objp->code_compta_fournisseur) ? $objp->code_compta_fournisseur : "";
403
                    $thirdpartystatic->email = !empty($objp->email) ? $objp->email : "";
404
                    $thirdpartystatic->country_code = !empty($objp->country_code) ? $objp->country_code : "";
405
                    $thirdpartystatic->tva_intra = !empty($objp->tva_intra) ? $objp->tva_intra : "";
406
                    $thirdpartystatic->code_compta_product = !empty($objp->company_code_sell) ? $objp->company_code_sell : "";      // The accounting account for product stored on thirdparty object (for level3 suggestion)
407
408
                    $product_static->ref = $objp->product_ref;
409
                    $product_static->id = $objp->product_id;
410
                    $product_static->type = $objp->type;
411
                    $product_static->label = $objp->product_label;
412
                    $product_static->status = !empty($objp->status) ? $objp->status : 0;
413
                    $product_static->status_buy = !empty($objp->status_buy) ? $objp->status_buy : 0;
414
                    $product_static->accountancy_code_sell = $objp->code_sell;
415
                    $product_static->accountancy_code_sell_intra = $objp->code_sell_intra;
416
                    $product_static->accountancy_code_sell_export = $objp->code_sell_export;
417
                    $product_static->accountancy_code_buy = !empty($objp->code_buy) ? $objp->code_buy : "";
418
                    $product_static->accountancy_code_buy_intra = !empty($objp->code_buy_intra) ? $objp->code_buy_intra : "";
419
                    $product_static->accountancy_code_buy_export = !empty($objp->code_buy_export) ? $objp->code_buy_export : "";
420
                    $product_static->tva_tx = $objp->tva_tx_prod;
421
422
                    $facture_static->ref = $objp->ref;
423
                    $facture_static->id = $objp->facid;
424
                    $facture_static->type = $objp->ftype;
425
                    $facture_static->date = $db->jdate($objp->datef);
426
                    $facture_static->fk_facture_source = $objp->fk_facture_source;
427
428
                    $facture_static_det->id = $objp->rowid;
429
                    $facture_static_det->total_ht = $objp->total_ht;
430
                    $facture_static_det->tva_tx = $objp->tva_tx_line;
431
                    $facture_static_det->vat_src_code = $objp->vat_src_code;
432
                    $facture_static_det->product_type = $objp->type_l;
433
                    $facture_static_det->desc = $objp->description;
434
435
                    $accountingAccountArray = [
436
                        'dom' => $objp->aarowid,
437
                        'intra' => $objp->aarowid_intra,
438
                        'export' => $objp->aarowid_export,
439
                        'thirdparty' => $objp->aarowid_thirdparty,
440
                    ];
441
442
                    $code_sell_p_notset = '';
443
                    $code_sell_t_notset = '';
444
445
                    $suggestedid = 0;
446
447
                    $return = $accountingAccount->getAccountingCodeToBind($thirdpartystatic, $mysoc, $product_static, $facture_static, $facture_static_det, $accountingAccountArray, 'customer');
448
                    if (!is_array($return) && $return < 0) {
449
                        setEventMessage($accountingAccount->error, 'errors');
450
                    } else {
451
                        $suggestedid = $return['suggestedid'];
452
                        $suggestedaccountingaccountfor = $return['suggestedaccountingaccountfor'];
453
454
                        if (!empty($suggestedid) && $suggestedaccountingaccountfor != '' && $suggestedaccountingaccountfor != 'eecwithoutvatnumber') {
455
                            $suggestedid = $return['suggestedid'];
456
                        } else {
457
                            $suggestedid = 0;
458
                        }
459
                    }
460
461
                    if ($suggestedid > 0) {
462
                        $sqlupdate = "UPDATE " . MAIN_DB_PREFIX . "facturedet";
463
                        $sqlupdate .= " SET fk_code_ventilation = " . ((int) $suggestedid);
464
                        $sqlupdate .= " WHERE fk_code_ventilation <= 0 AND product_type <= 2 AND rowid = " . ((int) $facture_static_det->id);
465
466
                        $resqlupdate = $db->query($sqlupdate);
467
                        if (!$resqlupdate) {
468
                            $error++;
469
                            setEventMessages($db->lasterror(), null, 'errors');
470
                            $nbbindfailed++;
471
                            break;
472
                        } else {
473
                            $nbbinddone++;
474
                        }
475
                    } else {
476
                        $notpossible++;
477
                        $nbbindfailed++;
478
                    }
479
480
                    $i++;
481
                }
482
                if ($num_lines > 10000) {
483
                    $notpossible += ($num_lines - 10000);
484
                }
485
            }
486
487
            if ($error) {
488
                $db->rollback();
489
            } else {
490
                $db->commit();
491
                setEventMessages($langs->trans('AutomaticBindingDone', $nbbinddone, $notpossible), null, ($notpossible ? 'warnings' : 'mesgs'));
492
                if ($nbbindfailed) {
493
                    setEventMessages($langs->trans('DoManualBindingForFailedRecord', $nbbindfailed), null, 'warnings');
494
                }
495
            }
496
        }
497
498
499
        /*
500
         * View
501
         */
502
        $help_url = 'EN:Module_Double_Entry_Accounting|FR:Module_Comptabilit&eacute;_en_Partie_Double#Liaisons_comptables';
503
504
        llxHeader('', $langs->trans("CustomersVentilation"), $help_url);
505
506
        $textprevyear = '<a href="' . $_SERVER['PHP_SELF'] . '?year=' . ($year_current - 1) . '">' . img_previous() . '</a>';
507
        $textnextyear = '&nbsp;<a href="' . $_SERVER['PHP_SELF'] . '?year=' . ($year_current + 1) . '">' . img_next() . '</a>';
508
509
510
        print load_fiche_titre($langs->trans("CustomersVentilation") . " " . $textprevyear . " " . $langs->trans("Year") . " " . $year_start . " " . $textnextyear, '', 'title_accountancy');
511
512
        print '<span class="opacitymedium">' . $langs->trans("DescVentilCustomer") . '</span><br>';
513
        print '<span class="opacitymedium hideonsmartphone">' . $langs->trans("DescVentilMore", $langs->transnoentitiesnoconv("ValidateHistory"), $langs->transnoentitiesnoconv("ToBind")) . '<br>';
514
        print '</span><br>';
515
516
        if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
517
            print info_admin($langs->trans("SorryThisModuleIsNotCompatibleWithTheExperimentalFeatureOfSituationInvoices"));
518
            print "<br>";
519
        }
520
521
        $y = $year_current;
522
523
        $buttonbind = '<a class="button small" href="' . $_SERVER['PHP_SELF'] . '?action=validatehistory&token=' . newToken() . '">' . img_picto($langs->trans("ValidateHistory"), 'link', 'class="pictofixedwidth fa-color-unset"') . $langs->trans("ValidateHistory") . '</a>';
524
525
        print_barre_liste(img_picto('', 'unlink', 'class="paddingright fa-color-unset"') . $langs->trans("OverviewOfAmountOfLinesNotBound"), '', '', '', '', '', '', -1, '', '', 0, '', '', 0, 1, 1, 0, $buttonbind);
526
//print load_fiche_titre($langs->trans("OverviewOfAmountOfLinesNotBound"), $buttonbind, '');
527
528
        print '<div class="div-table-responsive-no-min">';
529
        print '<table class="noborder centpercent">';
530
        print '<tr class="liste_titre"><td class="minwidth100">' . $langs->trans("Account") . '</td>';
531
        print '<td>' . $langs->trans("Label") . '</td>';
532
        for ($i = 1; $i <= 12; $i++) {
533
            $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
534
            if ($j > 12) {
535
                $j -= 12;
536
            }
537
            $cursormonth = $j;
538
            if ($cursormonth > 12) {
539
                $cursormonth -= 12;
540
            }
541
            $cursoryear = ($cursormonth < getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1)) ? $y + 1 : $y;
542
            $tmp = dol_getdate(dol_get_last_day($cursoryear, $cursormonth, 'gmt'), false, 'gmt');
543
544
            print '<td width="60" class="right">';
545
            if (!empty($tmp['mday'])) {
546
                $param = 'search_date_startday=1&search_date_startmonth=' . $cursormonth . '&search_date_startyear=' . $cursoryear;
547
                $param .= '&search_date_endday=' . $tmp['mday'] . '&search_date_endmonth=' . $tmp['mon'] . '&search_date_endyear=' . $tmp['year'];
548
                print '<a href="' . DOL_URL_ROOT . '/accountancy/customer/list.php?' . $param . '">';
549
            }
550
            print $langs->trans('MonthShort' . str_pad((int) $j, 2, '0', STR_PAD_LEFT));
551
            if (!empty($tmp['mday'])) {
552
                print '</a>';
553
            }
554
            print '</td>';
555
        }
556
        print '<td width="60" class="right"><b>' . $langs->trans("Total") . '</b></td></tr>';
557
558
        $sql = "SELECT " . $db->ifsql('aa.account_number IS NULL', "'tobind'", 'aa.account_number') . " AS codecomptable,";
559
        $sql .= "  " . $db->ifsql('aa.label IS NULL', "'tobind'", 'aa.label') . " AS intitule,";
560
        for ($i = 1; $i <= 12; $i++) {
561
            $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
562
            if ($j > 12) {
563
                $j -= 12;
564
            }
565
            $sql .= "  SUM(" . $db->ifsql("MONTH(f.datef) = " . ((int) $j), "fd.total_ht", "0") . ") AS month" . str_pad((int) $j, 2, "0", STR_PAD_LEFT) . ",";
566
        }
567
        $sql .= "  SUM(fd.total_ht) as total";
568
        $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd";
569
        $sql .= "  LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture";
570
        $sql .= "  LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.rowid = fd.fk_code_ventilation";
571
        $sql .= " WHERE f.datef >= '" . $db->idate($search_date_start) . "'";
572
        $sql .= "  AND f.datef <= '" . $db->idate($search_date_end) . "'";
573
// Define begin binding date
574
        if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
575
            $sql .= " AND f.datef >= '" . $db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) . "'";
576
        }
577
        $sql .= " AND f.fk_statut > 0";
578
        $sql .= " AND fd.product_type <= 2";
579
        $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
580
        $sql .= " AND aa.account_number IS NULL";
581
        if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
582
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")";
583
        } else {
584
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")";
585
        }
586
        $sql .= " GROUP BY fd.fk_code_ventilation,aa.account_number,aa.label";
587
588
        dol_syslog('htdocs/accountancy/customer/index.php', LOG_DEBUG);
589
        $resql = $db->query($sql);
590
        if ($resql) {
591
            $num = $db->num_rows($resql);
592
593
            while ($row = $db->fetch_row($resql)) {
594
                // TODO When INVOICE_USE_SITUATION = 1, values here are wrong. There is no compensation on bad stored amounts
595
                //$situation_ratio = 1;
596
                //if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
597
                //}
598
599
                print '<tr class="oddeven">';
600
                print '<td>';
601
                if ($row[0] == 'tobind') {
602
                    print '<span class="opacitymedium">' . $langs->trans("Unknown") . '</span>';
603
                } else {
604
                    print length_accountg($row[0]);
605
                }
606
                print '</td>';
607
                print '<td>';
608
                if ($row[0] == 'tobind') {
609
                    $startmonth = getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1);
610
                    if ($startmonth > 12) {
611
                        $startmonth -= 12;
612
                    }
613
                    $startyear = ($startmonth < getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1)) ? $y + 1 : $y;
614
                    $endmonth = getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) + 11;
615
                    if ($endmonth > 12) {
616
                        $endmonth -= 12;
617
                    }
618
                    $endyear = ($endmonth < getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1)) ? $y + 1 : $y;
619
                    print $langs->trans("UseMenuToSetBindindManualy", DOL_URL_ROOT . '/accountancy/customer/list.php?search_date_startday=1&search_date_startmonth=' . ((int) $startmonth) . '&search_date_startyear=' . ((int) $startyear) . '&search_date_endday=&search_date_endmonth=' . ((int) $endmonth) . '&search_date_endyear=' . ((int) $endyear), $langs->transnoentitiesnoconv("ToBind"));
620
                } else {
621
                    print $row[1];
622
                }
623
                print '</td>';
624
                for ($i = 2; $i <= 13; $i++) {
625
                    $cursormonth = (getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) + $i - 2);
626
                    if ($cursormonth > 12) {
627
                        $cursormonth -= 12;
628
                    }
629
                    $cursoryear = ($cursormonth < getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1)) ? $y + 1 : $y;
630
                    $tmp = dol_getdate(dol_get_last_day($cursoryear, $cursormonth, 'gmt'), false, 'gmt');
631
632
                    print '<td class="right nowraponall amount">';
633
                    print price($row[$i]);
634
                    // Add link to make binding
635
                    if (!empty(price2num($row[$i]))) {
636
                        print '<a href="' . $_SERVER['PHP_SELF'] . '?action=validatehistory&year=' . $y . '&validatemonth=' . ((int) $cursormonth) . '&validateyear=' . ((int) $cursoryear) . '&token=' . newToken() . '">';
637
                        print img_picto($langs->trans("ValidateHistory") . ' (' . $langs->trans('Month' . str_pad($cursormonth, 2, '0', STR_PAD_LEFT)) . ' ' . $cursoryear . ')', 'link', 'class="marginleft2"');
638
                        print '</a>';
639
                    }
640
                    print '</td>';
641
                }
642
                print '<td class="right nowraponall amount"><b>' . price($row[14]) . '</b></td>';
643
                print '</tr>';
644
            }
645
            $db->free($resql);
646
647
            if ($num == 0) {
648
                print '<tr class="oddeven"><td colspan="16">';
649
                print '<span class="opacitymedium">' . $langs->trans("NoRecordFound") . '</span>';
650
                print '</td></tr>';
651
            }
652
        } else {
653
            print $db->lasterror(); // Show last sql error
654
        }
655
        print "</table>\n";
656
        print '</div>';
657
658
659
        print '<br>';
660
661
662
        print_barre_liste(img_picto('', 'link', 'class="paddingright fa-color-unset"') . $langs->trans("OverviewOfAmountOfLinesBound"), '', '', '', '', '', '', -1, '', '', 0, '', '', 0, 1, 1);
663
//print load_fiche_titre($langs->trans("OverviewOfAmountOfLinesBound"), '', '');
664
665
        print '<div class="div-table-responsive-no-min">';
666
        print '<table class="noborder centpercent">';
667
        print '<tr class="liste_titre"><td class="minwidth100">' . $langs->trans("Account") . '</td>';
668
        print '<td>' . $langs->trans("Label") . '</td>';
669
        for ($i = 1; $i <= 12; $i++) {
670
            $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
671
            if ($j > 12) {
672
                $j -= 12;
673
            }
674
            $cursormonth = $j;
675
            if ($cursormonth > 12) {
676
                $cursormonth -= 12;
677
            }
678
            $cursoryear = ($cursormonth < getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1)) ? $y + 1 : $y;
679
            $tmp = dol_getdate(dol_get_last_day($cursoryear, $cursormonth, 'gmt'), false, 'gmt');
680
681
            print '<td width="60" class="right">';
682
            if (!empty($tmp['mday'])) {
683
                $param = 'search_date_startday=1&search_date_startmonth=' . $cursormonth . '&search_date_startyear=' . $cursoryear;
684
                $param .= '&search_date_endday=' . $tmp['mday'] . '&search_date_endmonth=' . $tmp['mon'] . '&search_date_endyear=' . $tmp['year'];
685
                print '<a href="' . DOL_URL_ROOT . '/accountancy/customer/lines.php?' . $param . '">';
686
            }
687
            print $langs->trans('MonthShort' . str_pad((int) $j, 2, '0', STR_PAD_LEFT));
688
            if (!empty($tmp['mday'])) {
689
                print '</a>';
690
            }
691
            print '</td>';
692
        }
693
        print '<td width="60" class="right"><b>' . $langs->trans("Total") . '</b></td></tr>';
694
695
        $sql = "SELECT " . $db->ifsql('aa.account_number IS NULL', "'tobind'", 'aa.account_number') . " AS codecomptable,";
696
        $sql .= "  " . $db->ifsql('aa.label IS NULL', "'tobind'", 'aa.label') . " AS intitule,";
697
        for ($i = 1; $i <= 12; $i++) {
698
            $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
699
            if ($j > 12) {
700
                $j -= 12;
701
            }
702
            $sql .= "  SUM(" . $db->ifsql("MONTH(f.datef) = " . ((int) $j), "fd.total_ht", "0") . ") AS month" . str_pad((int) $j, 2, "0", STR_PAD_LEFT) . ",";
703
        }
704
        $sql .= "  SUM(fd.total_ht) as total";
705
        $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd";
706
        $sql .= "  LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture";
707
        $sql .= "  LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.rowid = fd.fk_code_ventilation";
708
        $sql .= " WHERE f.datef >= '" . $db->idate($search_date_start) . "'";
709
        $sql .= "  AND f.datef <= '" . $db->idate($search_date_end) . "'";
710
// Define begin binding date
711
        if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
712
            $sql .= " AND f.datef >= '" . $db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) . "'";
713
        }
714
        $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
715
        $sql .= " AND f.fk_statut > 0";
716
        $sql .= " AND fd.product_type <= 2";
717
        if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
718
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . ", " . Facture::TYPE_REPLACEMENT . ", " . Facture::TYPE_CREDIT_NOTE . ", " . Facture::TYPE_SITUATION . ")";
719
        } else {
720
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . ", " . Facture::TYPE_REPLACEMENT . ", " . Facture::TYPE_CREDIT_NOTE . ", " . Facture::TYPE_DEPOSIT . ", " . Facture::TYPE_SITUATION . ")";
721
        }
722
        $sql .= " AND aa.account_number IS NOT NULL";
723
        $sql .= " GROUP BY fd.fk_code_ventilation,aa.account_number,aa.label";
724
        $sql .= ' ORDER BY aa.account_number';
725
726
        dol_syslog('htdocs/accountancy/customer/index.php');
727
        $resql = $db->query($sql);
728
        if ($resql) {
729
            $num = $db->num_rows($resql);
730
731
            while ($row = $db->fetch_row($resql)) {
732
                // TODO When INVOICE_USE_SITUATION = 1, values here are wrong. There is no compensation on bad stored amounts
733
                //$situation_ratio = 1;
734
                //if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
735
                //}
736
737
                print '<tr class="oddeven">';
738
                print '<td>';
739
                if ($row[0] == 'tobind') {
740
                    print $langs->trans("Unknown");
741
                } else {
742
                    print length_accountg($row[0]);
743
                }
744
                print '</td>';
745
746
                print '<td>';
747
                if ($row[0] == 'tobind') {
748
                    print $langs->trans("UseMenuToSetBindindManualy", DOL_URL_ROOT . '/accountancy/customer/list.php?search_year=' . ((int) $y), $langs->transnoentitiesnoconv("ToBind"));
749
                } else {
750
                    print $row[1];
751
                }
752
                print '</td>';
753
754
                for ($i = 2; $i <= 13; $i++) {
755
                    $cursormonth = (getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) + $i - 2);
756
                    if ($cursormonth > 12) {
757
                        $cursormonth -= 12;
758
                    }
759
                    $cursoryear = ($cursormonth < getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1)) ? $y + 1 : $y;
760
                    $tmp = dol_getdate(dol_get_last_day($cursoryear, $cursormonth, 'gmt'), false, 'gmt');
761
762
                    print '<td class="right nowraponall amount">';
763
                    print price($row[$i]);
764
                    print '</td>';
765
                }
766
                print '<td class="right nowraponall amount"><b>' . price($row[14]) . '</b></td>';
767
                print '</tr>';
768
            }
769
            $db->free($resql);
770
771
            if ($num == 0) {
772
                print '<tr class="oddeven"><td colspan="16">';
773
                print '<span class="opacitymedium">' . $langs->trans("NoRecordFound") . '</span>';
774
                print '</td></tr>';
775
            }
776
        } else {
777
            print $db->lasterror(); // Show last sql error
778
        }
779
        print "</table>\n";
780
        print '</div>';
781
782
783
        if (getDolGlobalString('SHOW_TOTAL_OF_PREVIOUS_LISTS_IN_LIN_PAGE')) { // This part of code looks strange. Why showing a report that should rely on result of this step ?
784
            print '<br>';
785
            print '<br>';
786
787
            print_barre_liste($langs->trans("OtherInfo"), '', '', '', '', '', '', -1, '', '', 0, '', '', 0, 1, 1);
788
            //print load_fiche_titre($langs->trans("OtherInfo"), '', '');
789
790
            print '<div class="div-table-responsive-no-min">';
791
            print '<table class="noborder centpercent">';
792
            print '<tr class="liste_titre"><td lass="left">' . $langs->trans("TotalVente") . '</td>';
793
            for ($i = 1; $i <= 12; $i++) {
794
                $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
795
                if ($j > 12) {
796
                    $j -= 12;
797
                }
798
                print '<td width="60" class="right">' . $langs->trans('MonthShort' . str_pad((int) $j, 2, '0', STR_PAD_LEFT)) . '</td>';
799
            }
800
            print '<td width="60" class="right"><b>' . $langs->trans("Total") . '</b></td></tr>';
801
802
            $sql = "SELECT '" . $db->escape($langs->trans("TotalVente")) . "' AS total,";
803
            for ($i = 1; $i <= 12; $i++) {
804
                $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
805
                if ($j > 12) {
806
                    $j -= 12;
807
                }
808
                $sql .= "  SUM(" . $db->ifsql("MONTH(f.datef) = " . ((int) $j), "fd.total_ht", "0") . ") AS month" . str_pad((int) $j, 2, "0", STR_PAD_LEFT) . ",";
809
            }
810
            $sql .= "  SUM(fd.total_ht) as total";
811
            $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd";
812
            $sql .= "  LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture";
813
            $sql .= " WHERE f.datef >= '" . $db->idate($search_date_start) . "'";
814
            $sql .= "  AND f.datef <= '" . $db->idate($search_date_end) . "'";
815
            // Define begin binding date
816
            if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
817
                $sql .= " AND f.datef >= '" . $db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) . "'";
818
            }
819
            $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
820
            $sql .= " AND f.fk_statut > 0";
821
            $sql .= " AND fd.product_type <= 2";
822
            if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
823
                $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . ", " . Facture::TYPE_REPLACEMENT . ", " . Facture::TYPE_CREDIT_NOTE . ", " . Facture::TYPE_SITUATION . ")";
824
            } else {
825
                $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . ", " . Facture::TYPE_REPLACEMENT . ", " . Facture::TYPE_CREDIT_NOTE . ", " . Facture::TYPE_DEPOSIT . ", " . Facture::TYPE_SITUATION . ")";
826
            }
827
828
            dol_syslog('htdocs/accountancy/customer/index.php');
829
            $resql = $db->query($sql);
830
            if ($resql) {
831
                $num = $db->num_rows($resql);
832
833
                while ($row = $db->fetch_row($resql)) {
834
                    print '<tr><td>' . $row[0] . '</td>';
835
                    for ($i = 1; $i <= 12; $i++) {
836
                        print '<td class="right nowraponall amount">' . price($row[$i]) . '</td>';
837
                    }
838
                    print '<td class="right nowraponall amount"><b>' . price($row[13]) . '</b></td>';
839
                    print '</tr>';
840
                }
841
                $db->free($resql);
842
            } else {
843
                print $db->lasterror(); // Show last sql error
844
            }
845
            print "</table>\n";
846
            print '</div>';
847
848
            if (isModEnabled('margin')) {
849
                print "<br>\n";
850
                print '<div class="div-table-responsive-no-min">';
851
                print '<table class="noborder centpercent">';
852
                print '<tr class="liste_titre"><td>' . $langs->trans("TotalMarge") . '</td>';
853
                for ($i = 1; $i <= 12; $i++) {
854
                    $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
855
                    if ($j > 12) {
856
                        $j -= 12;
857
                    }
858
                    print '<td width="60" class="right">' . $langs->trans('MonthShort' . str_pad((int) $j, 2, '0', STR_PAD_LEFT)) . '</td>';
859
                }
860
                print '<td width="60" class="right"><b>' . $langs->trans("Total") . '</b></td></tr>';
861
862
                if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
863
                    // With old situation invoice setup
864
                    $sql = "SELECT '" . $db->escape($langs->trans("Vide")) . "' AS marge,";
865
                    for ($i = 1; $i <= 12; $i++) {
866
                        $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
867
                        if ($j > 12) {
868
                            $j -= 12;
869
                        }
870
                        $sql .= " SUM(" . $db->ifsql(
871
                                "MONTH(f.datef) = " . ((int) $j),
872
                                " (" . $db->ifsql(
873
                                    "fd.total_ht < 0",
874
                                    " (-1 * (abs(fd.total_ht) - (fd.buy_price_ht * fd.qty * (fd.situation_percent / 100))))",   // TODO This is bugged, we must use the percent for the invoice and fd.situation_percent is cumulated percent !
875
                                    "  (fd.total_ht - (fd.buy_price_ht * fd.qty * (fd.situation_percent / 100)))"
876
                                ) . ")",
877
                                0
878
                            ) . ") AS month" . str_pad((int) $j, 2, '0', STR_PAD_LEFT) . ",";
879
                    }
880
                    $sql .= "  SUM(" . $db->ifsql(
881
                            "fd.total_ht < 0",
882
                            " (-1 * (abs(fd.total_ht) - (fd.buy_price_ht * fd.qty * (fd.situation_percent / 100))))",   // TODO This is bugged, we must use the percent for the invoice and fd.situation_percent is cumulated percent !
883
                            "  (fd.total_ht - (fd.buy_price_ht * fd.qty * (fd.situation_percent / 100)))"
884
                        ) . ") as total";
885
                } else {
886
                    $sql = "SELECT '" . $db->escape($langs->trans("Vide")) . "' AS marge,";
887
                    for ($i = 1; $i <= 12; $i++) {
888
                        $j = $i + getDolGlobalInt('SOCIETE_FISCAL_MONTH_START', 1) - 1;
889
                        if ($j > 12) {
890
                            $j -= 12;
891
                        }
892
                        $sql .= " SUM(" . $db->ifsql(
893
                                "MONTH(f.datef) = " . ((int) $j),
894
                                " (" . $db->ifsql(
895
                                    "fd.total_ht < 0",
896
                                    " (-1 * (abs(fd.total_ht) - (fd.buy_price_ht * fd.qty)))",
897
                                    "  (fd.total_ht - (fd.buy_price_ht * fd.qty))"
898
                                ) . ")",
899
                                0
900
                            ) . ") AS month" . str_pad((int) $j, 2, '0', STR_PAD_LEFT) . ",";
901
                    }
902
                    $sql .= "  SUM(" . $db->ifsql(
903
                            "fd.total_ht < 0",
904
                            " (-1 * (abs(fd.total_ht) - (fd.buy_price_ht * fd.qty)))",
905
                            "  (fd.total_ht - (fd.buy_price_ht * fd.qty))"
906
                        ) . ") as total";
907
                }
908
                $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd";
909
                $sql .= "  LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture";
910
                $sql .= " WHERE f.datef >= '" . $db->idate($search_date_start) . "'";
911
                $sql .= "  AND f.datef <= '" . $db->idate($search_date_end) . "'";
912
                // Define begin binding date
913
                if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
914
                    $sql .= " AND f.datef >= '" . $db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) . "'";
915
                }
916
                $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
917
                $sql .= " AND f.fk_statut > 0";
918
                $sql .= " AND fd.product_type <= 2";
919
                if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
920
                    $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . ", " . Facture::TYPE_REPLACEMENT . ", " . Facture::TYPE_CREDIT_NOTE . ", " . Facture::TYPE_SITUATION . ")";
921
                } else {
922
                    $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . ", " . Facture::TYPE_REPLACEMENT . ", " . Facture::TYPE_CREDIT_NOTE . ", " . Facture::TYPE_DEPOSIT . ", " . Facture::TYPE_SITUATION . ")";
923
                }
924
                dol_syslog('htdocs/accountancy/customer/index.php');
925
                $resql = $db->query($sql);
926
                if ($resql) {
927
                    $num = $db->num_rows($resql);
928
929
                    while ($row = $db->fetch_row($resql)) {
930
                        print '<tr><td>' . $row[0] . '</td>';
931
                        for ($i = 1; $i <= 12; $i++) {
932
                            print '<td class="right nowraponall amount">' . price(price2num($row[$i])) . '</td>';
933
                        }
934
                        print '<td class="right nowraponall amount"><b>' . price(price2num($row[13])) . '</b></td>';
935
                        print '</tr>';
936
                    }
937
                    $db->free($resql);
938
                } else {
939
                    print $db->lasterror(); // Show last sql error
940
                }
941
                print "</table>\n";
942
                print '</div>';
943
            }
944
        }
945
946
// End of page
947
        llxFooter();
948
        $db->close();
949
    }
950
951
    /**
952
     * \file        htdocs/accountancy/customer/lines.php
953
     * \ingroup     Accountancy (Double entries)
954
     * \brief       Page of detail of the lines of ventilation of invoices customers
955
     */
956
    public function lines()
957
    {
958
        global $conf;
959
        global $db;
960
        global $user;
961
        global $hookmanager;
962
        global $user;
963
        global $menumanager;
964
        global $langs;
965
        global $mysoc;
966
967
// Load translation files required by the page
968
        $langs->loadLangs(["bills", "compta", "accountancy", "productbatch", "products"]);
969
970
        $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
971
972
        $account_parent = GETPOST('account_parent');
973
        $changeaccount = GETPOST('changeaccount');
974
// Search Getpost
975
        $search_societe = GETPOST('search_societe', 'alpha');
976
        $search_lineid = GETPOSTINT('search_lineid');
977
        $search_ref = GETPOST('search_ref', 'alpha');
978
        $search_invoice = GETPOST('search_invoice', 'alpha');
979
        $search_label = GETPOST('search_label', 'alpha');
980
        $search_desc = GETPOST('search_desc', 'alpha');
981
        $search_amount = GETPOST('search_amount', 'alpha');
982
        $search_account = GETPOST('search_account', 'alpha');
983
        $search_vat = GETPOST('search_vat', 'alpha');
984
        $search_date_startday = GETPOSTINT('search_date_startday');
985
        $search_date_startmonth = GETPOSTINT('search_date_startmonth');
986
        $search_date_startyear = GETPOSTINT('search_date_startyear');
987
        $search_date_endday = GETPOSTINT('search_date_endday');
988
        $search_date_endmonth = GETPOSTINT('search_date_endmonth');
989
        $search_date_endyear = GETPOSTINT('search_date_endyear');
990
        $search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear);   // Use tzserver
991
        $search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear);
992
        $search_country = GETPOST('search_country', 'alpha');
993
        $search_tvaintra = GETPOST('search_tvaintra', 'alpha');
994
995
// Load variable for pagination
996
        $limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : getDolGlobalString('ACCOUNTING_LIMIT_LIST_VENTILATION', $conf->liste_limit);
997
        $sortfield = GETPOST('sortfield', 'aZ09comma');
998
        $sortorder = GETPOST('sortorder', 'aZ09comma');
999
        $page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
1000
        if (empty($page) || $page < 0) {
1001
            $page = 0;
1002
        }
1003
        $offset = $limit * $page;
1004
        $pageprev = $page - 1;
1005
        $pagenext = $page + 1;
1006
        if (!$sortfield) {
1007
            $sortfield = "f.datef, f.ref, fd.rowid";
1008
        }
1009
        if (!$sortorder) {
1010
            if (getDolGlobalInt('ACCOUNTING_LIST_SORT_VENTILATION_DONE') > 0) {
1011
                $sortorder = "DESC";
1012
            } else {
1013
                $sortorder = "ASC";
1014
            }
1015
        }
1016
1017
// Security check
1018
        if (!isModEnabled('accounting')) {
1019
            accessforbidden();
1020
        }
1021
        if ($user->socid > 0) {
1022
            accessforbidden();
1023
        }
1024
        if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
1025
            accessforbidden();
1026
        }
1027
1028
1029
        $formaccounting = new FormAccounting($db);
1030
1031
1032
        /*
1033
         * Actions
1034
         */
1035
1036
// Purge search criteria
1037
        if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
1038
            $search_societe = '';
1039
            $search_lineid = '';
1040
            $search_ref = '';
1041
            $search_invoice = '';
1042
            $search_label = '';
1043
            $search_desc = '';
1044
            $search_amount = '';
1045
            $search_account = '';
1046
            $search_vat = '';
1047
            $search_date_startday = '';
1048
            $search_date_startmonth = '';
1049
            $search_date_startyear = '';
1050
            $search_date_endday = '';
1051
            $search_date_endmonth = '';
1052
            $search_date_endyear = '';
1053
            $search_date_start = '';
1054
            $search_date_end = '';
1055
            $search_country = '';
1056
            $search_tvaintra = '';
1057
        }
1058
1059
        if (is_array($changeaccount) && count($changeaccount) > 0 && $user->hasRight('accounting', 'bind', 'write')) {
1060
            $error = 0;
1061
1062
            if (!(GETPOSTINT('account_parent') >= 0)) {
1063
                $error++;
1064
                setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Account")), null, 'errors');
1065
            }
1066
1067
            if (!$error) {
1068
                $db->begin();
1069
1070
                $sql1 = "UPDATE " . MAIN_DB_PREFIX . "facturedet";
1071
                $sql1 .= " SET fk_code_ventilation = " . (GETPOSTINT('account_parent') > 0 ? GETPOSTINT('account_parent') : 0);
1072
                $sql1 .= ' WHERE rowid IN (' . $db->sanitize(implode(',', $changeaccount)) . ')';
1073
1074
                dol_syslog('accountancy/customer/lines.php::changeaccount sql= ' . $sql1);
1075
                $resql1 = $db->query($sql1);
1076
                if (!$resql1) {
1077
                    $error++;
1078
                    setEventMessages($db->lasterror(), null, 'errors');
1079
                }
1080
                if (!$error) {
1081
                    $db->commit();
1082
                    setEventMessages($langs->trans("Save"), null, 'mesgs');
1083
                } else {
1084
                    $db->rollback();
1085
                    setEventMessages($db->lasterror(), null, 'errors');
1086
                }
1087
1088
                $account_parent = ''; // Protection to avoid to mass apply it a second time
1089
            }
1090
        }
1091
1092
        if (GETPOST('sortfield') == 'f.datef, f.ref, fd.rowid') {
1093
            $value = (GETPOST('sortorder') == 'asc,asc,asc' ? 0 : 1);
1094
            require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
1095
            $res = dolibarr_set_const($db, "ACCOUNTING_LIST_SORT_VENTILATION_DONE", $value, 'yesno', 0, '', $conf->entity);
1096
        }
1097
1098
1099
        /*
1100
         * View
1101
         */
1102
1103
        $form = new Form($db);
1104
        $formother = new FormOther($db);
0 ignored issues
show
Bug introduced by
The type DoliModules\Accounting\Controller\FormOther was not found. Did you mean FormOther? If so, make sure to prefix the type with \.
Loading history...
1105
1106
        $help_url = 'EN:Module_Double_Entry_Accounting|FR:Module_Comptabilit&eacute;_en_Partie_Double#Liaisons_comptables';
1107
1108
        llxHeader('', $langs->trans("CustomersVentilation") . ' - ' . $langs->trans("Dispatched"), $help_url);
1109
1110
        print '<script type="text/javascript">
1111
			$(function () {
1112
				$(\'#select-all\').click(function(event) {
1113
				    // Iterate each checkbox
1114
				    $(\':checkbox\').each(function() {
1115
				    	this.checked = true;
1116
				    });
1117
			    });
1118
			    $(\'#unselect-all\').click(function(event) {
1119
				    // Iterate each checkbox
1120
				    $(\':checkbox\').each(function() {
1121
				    	this.checked = false;
1122
				    });
1123
			    });
1124
			});
1125
			 </script>';
1126
1127
        /*
1128
         * Customer Invoice lines
1129
         */
1130
        $sql = "SELECT f.rowid as facid, f.ref as ref, f.type as ftype, f.situation_cycle_ref, f.datef, f.ref_client,";
1131
        $sql .= " fd.rowid, fd.description, fd.product_type as line_type, fd.total_ht, fd.total_tva, fd.tva_tx, fd.vat_src_code, fd.total_ttc, fd.situation_percent,";
1132
        $sql .= " s.rowid as socid, s.nom as name, s.code_client,";
1133
        if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
1134
            $sql .= " spe.accountancy_code_customer as code_compta_client,";
1135
            $sql .= " spe.accountancy_code_supplier as code_compta_fournisseur,";
1136
        } else {
1137
            $sql .= " s.code_compta as code_compta_client,";
1138
            $sql .= " s.code_compta_fournisseur,";
1139
        }
1140
        $sql .= " p.rowid as product_id, p.fk_product_type as product_type, p.ref as product_ref, p.label as product_label, p.tobuy, p.tosell,";
1141
        if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
1142
            $sql .= " ppe.accountancy_code_sell, ppe.accountancy_code_sell_intra, ppe.accountancy_code_sell_export,";
1143
        } else {
1144
            $sql .= " p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export,";
1145
        }
1146
        $sql .= " aa.rowid as fk_compte, aa.account_number, aa.label as label_account, aa.labelshort as labelshort_account,";
1147
        $sql .= " fd.situation_percent,";
1148
        $sql .= " co.code as country_code, co.label as country,";
1149
        $sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1150
        $parameters = [];
1151
        $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
1152
        $sql .= $hookmanager->resPrint;
1153
        $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd";
1154
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = fd.fk_product";
1155
        if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
1156
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
1157
        }
1158
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.rowid = fd.fk_code_ventilation";
1159
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture";
1160
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid = f.fk_soc";
1161
        if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
1162
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity);
1163
        }
1164
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as co ON co.rowid = s.fk_pays ";
1165
        $sql .= " WHERE fd.fk_code_ventilation > 0";
1166
        $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
1167
        $sql .= " AND f.fk_statut > 0";
1168
        if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
1169
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")";
1170
        } else {
1171
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")";
1172
        }
1173
// Add search filter like
1174
        if ($search_societe) {
1175
            $sql .= natural_search('s.nom', $search_societe);
1176
        }
1177
        if ($search_lineid) {
1178
            $sql .= natural_search("fd.rowid", $search_lineid, 1);
1179
        }
1180
        if (strlen(trim($search_invoice))) {
1181
            $sql .= natural_search("f.ref", $search_invoice);
1182
        }
1183
        if (strlen(trim($search_ref))) {
1184
            $sql .= natural_search("p.ref", $search_ref);
1185
        }
1186
        if (strlen(trim($search_label))) {
1187
            $sql .= natural_search("p.label", $search_label);
1188
        }
1189
        if (strlen(trim($search_desc))) {
1190
            $sql .= natural_search("fd.description", $search_desc);
1191
        }
1192
        if (strlen(trim($search_amount))) {
1193
            $sql .= natural_search("fd.total_ht", $search_amount, 1);
1194
        }
1195
        if (strlen(trim($search_account))) {
1196
            $sql .= natural_search("aa.account_number", $search_account);
1197
        }
1198
        if (strlen(trim($search_vat))) {
1199
            $sql .= natural_search("fd.tva_tx", price2num($search_vat), 1);
1200
        }
1201
        if ($search_date_start) {
1202
            $sql .= " AND f.datef >= '" . $db->idate($search_date_start) . "'";
1203
        }
1204
        if ($search_date_end) {
1205
            $sql .= " AND f.datef <= '" . $db->idate($search_date_end) . "'";
1206
        }
1207
        if (strlen(trim($search_country))) {
1208
            $arrayofcode = getCountriesInEEC();
1209
            $country_code_in_EEC = $country_code_in_EEC_without_me = '';
1210
            foreach ($arrayofcode as $key => $value) {
1211
                $country_code_in_EEC .= ($country_code_in_EEC ? "," : "") . "'" . $value . "'";
1212
                if ($value != $mysoc->country_code) {
1213
                    $country_code_in_EEC_without_me .= ($country_code_in_EEC_without_me ? "," : "") . "'" . $value . "'";
1214
                }
1215
            }
1216
            if ($search_country == 'special_allnotme') {
1217
                $sql .= " AND co.code <> '" . $db->escape($mysoc->country_code) . "'";
1218
            } elseif ($search_country == 'special_eec') {
1219
                $sql .= " AND co.code IN (" . $db->sanitize($country_code_in_EEC, 1) . ")";
1220
            } elseif ($search_country == 'special_eecnotme') {
1221
                $sql .= " AND co.code IN (" . $db->sanitize($country_code_in_EEC_without_me, 1) . ")";
1222
            } elseif ($search_country == 'special_noteec') {
1223
                $sql .= " AND co.code NOT IN (" . $db->sanitize($country_code_in_EEC, 1) . ")";
1224
            } else {
1225
                $sql .= natural_search("co.code", $search_country);
1226
            }
1227
        }
1228
        if (strlen(trim($search_tvaintra))) {
1229
            $sql .= natural_search("s.tva_intra", $search_tvaintra);
1230
        }
1231
        $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
1232
        $sql .= $db->order($sortfield, $sortorder);
1233
1234
// Count total nb of records
1235
        $nbtotalofrecords = '';
1236
        if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
1237
            $result = $db->query($sql);
1238
            $nbtotalofrecords = $db->num_rows($result);
1239
            if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
1240
                $page = 0;
1241
                $offset = 0;
1242
            }
1243
        }
1244
1245
        $sql .= $db->plimit($limit + 1, $offset);
1246
1247
        dol_syslog("/accountancy/customer/lines.php", LOG_DEBUG);
1248
        $result = $db->query($sql);
1249
        if ($result) {
1250
            $num_lines = $db->num_rows($result);
1251
            $i = 0;
1252
1253
            $param = '';
1254
            if (!empty($contextpage) && $contextpage != $_SERVER['PHP_SELF']) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $contextpage seems to never exist and therefore empty should always be true.
Loading history...
1255
                $param .= '&contextpage=' . urlencode($contextpage);
1256
            }
1257
            if ($limit > 0 && $limit != $conf->liste_limit) {
1258
                $param .= '&limit=' . ((int) $limit);
1259
            }
1260
            if ($search_societe) {
1261
                $param .= "&search_societe=" . urlencode($search_societe);
1262
            }
1263
            if ($search_invoice) {
1264
                $param .= "&search_invoice=" . urlencode($search_invoice);
1265
            }
1266
            if ($search_ref) {
1267
                $param .= "&search_ref=" . urlencode($search_ref);
1268
            }
1269
            if ($search_label) {
1270
                $param .= "&search_label=" . urlencode($search_label);
1271
            }
1272
            if ($search_desc) {
1273
                $param .= "&search_desc=" . urlencode($search_desc);
1274
            }
1275
            if ($search_account) {
1276
                $param .= "&search_account=" . urlencode($search_account);
1277
            }
1278
            if ($search_vat) {
1279
                $param .= "&search_vat=" . urlencode($search_vat);
1280
            }
1281
            if ($search_date_startday) {
1282
                $param .= '&search_date_startday=' . urlencode((string) ($search_date_startday));
1283
            }
1284
            if ($search_date_startmonth) {
1285
                $param .= '&search_date_startmonth=' . urlencode((string) ($search_date_startmonth));
1286
            }
1287
            if ($search_date_startyear) {
1288
                $param .= '&search_date_startyear=' . urlencode((string) ($search_date_startyear));
1289
            }
1290
            if ($search_date_endday) {
1291
                $param .= '&search_date_endday=' . urlencode((string) ($search_date_endday));
1292
            }
1293
            if ($search_date_endmonth) {
1294
                $param .= '&search_date_endmonth=' . urlencode((string) ($search_date_endmonth));
1295
            }
1296
            if ($search_date_endyear) {
1297
                $param .= '&search_date_endyear=' . urlencode((string) ($search_date_endyear));
1298
            }
1299
            if ($search_country) {
1300
                $param .= "&search_country=" . urlencode($search_country);
1301
            }
1302
            if ($search_tvaintra) {
1303
                $param .= "&search_tvaintra=" . urlencode($search_tvaintra);
1304
            }
1305
1306
            print '<form action="' . $_SERVER['PHP_SELF'] . '" method="post">' . "\n";
1307
            print '<input type="hidden" name="action" value="ventil">';
1308
            if ($optioncss != '') {
1309
                print '<input type="hidden" name="optioncss" value="' . $optioncss . '">';
1310
            }
1311
            print '<input type="hidden" name="token" value="' . newToken() . '">';
1312
            print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
1313
            print '<input type="hidden" name="sortfield" value="' . $sortfield . '">';
1314
            print '<input type="hidden" name="sortorder" value="' . $sortorder . '">';
1315
            print '<input type="hidden" name="page" value="' . $page . '">';
1316
1317
            // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1318
            print_barre_liste($langs->trans("InvoiceLinesDone"), $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, '', $num_lines, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit);
1319
            print '<span class="opacitymedium">' . $langs->trans("DescVentilDoneCustomer") . '</span><br>';
1320
1321
            print '<br><div class="inline-block divButAction paddingbottom">' . $langs->trans("ChangeAccount") . ' ';
1322
            print $formaccounting->select_account($account_parent, 'account_parent', 2, [], 0, 0, 'maxwidth300 maxwidthonsmartphone valignmiddle');
1323
            print '<input type="submit" class="button small valignmiddle" value="' . $langs->trans("ChangeBinding") . '"/></div>';
1324
1325
            $moreforfilter = '';
1326
1327
            print '<div class="div-table-responsive">';
1328
            print '<table class="tagtable liste' . ($moreforfilter ? " listwithfilterbefore" : "") . '">' . "\n";
1329
1330
            print '<tr class="liste_titre_filter">';
1331
            print '<td class="liste_titre"><input type="text" class="flat maxwidth25" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '"></td>';
1332
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
1333
            print '<td class="liste_titre center">';
1334
            print '<div class="nowrapfordate">';
1335
            print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
1336
            print '</div>';
1337
            print '<div class="nowrapfordate">';
1338
            print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
1339
            print '</div>';
1340
            print '</td>';
1341
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_ref" value="' . dol_escape_htmltag($search_ref) . '"></td>';
1342
            //print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_label" value="' . dol_escape_htmltag($search_label) . '"></td>';
1343
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_desc" value="' . dol_escape_htmltag($search_desc) . '"></td>';
1344
            print '<td class="liste_titre right"><input type="text" class="right flat maxwidth50" name="search_amount" value="' . dol_escape_htmltag($search_amount) . '"></td>';
1345
            print '<td class="liste_titre right"><input type="text" class="right flat maxwidth50" placeholder="%" name="search_vat" size="1" value="' . dol_escape_htmltag($search_vat) . '"></td>';
1346
            print '<td class="liste_titre"><input type="text" class="flat maxwidth75imp" name="search_societe" value="' . dol_escape_htmltag($search_societe) . '"></td>';
1347
            print '<td class="liste_titre">';
1348
            print $form->select_country($search_country, 'search_country', '', 0, 'maxwidth150', 'code2', 1, 0, 1);
1349
            //print '<input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '">';
1350
            print '</td>';
1351
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_tvaintra" value="' . dol_escape_htmltag($search_tvaintra) . '"></td>';
1352
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_account" value="' . dol_escape_htmltag($search_account) . '"></td>';
1353
            print '<td class="liste_titre center">';
1354
            $searchpicto = $form->showFilterButtons();
1355
            print $searchpicto;
1356
            print "</td></tr>\n";
1357
1358
            print '<tr class="liste_titre">';
1359
            print_liste_field_titre("LineId", $_SERVER['PHP_SELF'], "fd.rowid", "", $param, '', $sortfield, $sortorder);
1360
            print_liste_field_titre("Invoice", $_SERVER['PHP_SELF'], "f.ref", "", $param, '', $sortfield, $sortorder);
1361
            print_liste_field_titre("Date", $_SERVER['PHP_SELF'], "f.datef, f.ref, fd.rowid", "", $param, '', $sortfield, $sortorder, 'center ');
1362
            print_liste_field_titre("ProductRef", $_SERVER['PHP_SELF'], "p.ref", "", $param, '', $sortfield, $sortorder);
1363
            //print_liste_field_titre("ProductLabel", $_SERVER['PHP_SELF'], "p.label", "", $param, '', $sortfield, $sortorder);
1364
            print_liste_field_titre("ProductDescription", $_SERVER['PHP_SELF'], "fd.description", "", $param, '', $sortfield, $sortorder);
1365
            print_liste_field_titre("Amount", $_SERVER['PHP_SELF'], "fd.total_ht", "", $param, '', $sortfield, $sortorder, 'right ');
1366
            print_liste_field_titre("VATRate", $_SERVER['PHP_SELF'], "fd.tva_tx", "", $param, '', $sortfield, $sortorder, 'right ');
1367
            print_liste_field_titre("ThirdParty", $_SERVER['PHP_SELF'], "s.nom", "", $param, '', $sortfield, $sortorder);
1368
            print_liste_field_titre("Country", $_SERVER['PHP_SELF'], "co.label", "", $param, '', $sortfield, $sortorder);
1369
            print_liste_field_titre("VATIntra", $_SERVER['PHP_SELF'], "s.tva_intra", "", $param, '', $sortfield, $sortorder);
1370
            print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "aa.account_number", "", $param, '', $sortfield, $sortorder);
1371
            $checkpicto = $form->showCheckAddButtons();
1372
            print_liste_field_titre($checkpicto, '', '', '', '', '', '', '', 'center ');
1373
            print "</tr>\n";
1374
1375
            $thirdpartystatic = new Societe($db);
1376
            $facturestatic = new Facture($db);
1377
            $productstatic = new Product($db);
1378
            $accountingaccountstatic = new AccountingAccount($db);
1379
1380
            $i = 0;
1381
            while ($i < min($num_lines, $limit)) {
1382
                $objp = $db->fetch_object($result);
1383
1384
                $facturestatic->ref = $objp->ref;
1385
                $facturestatic->id = $objp->facid;
1386
                $facturestatic->type = $objp->ftype;
1387
1388
                $thirdpartystatic->id = $objp->socid;
1389
                $thirdpartystatic->name = $objp->name;
1390
                $thirdpartystatic->client = $objp->client;
1391
                $thirdpartystatic->fournisseur = $objp->fournisseur;
1392
                $thirdpartystatic->code_client = $objp->code_client;
1393
                $thirdpartystatic->code_compta_client = $objp->code_compta_client;
1394
                $thirdpartystatic->code_fournisseur = $objp->code_fournisseur;
1395
                $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur;
1396
                $thirdpartystatic->email = $objp->email;
1397
                $thirdpartystatic->country_code = $objp->country_code;
1398
1399
                $productstatic->ref = $objp->product_ref;
1400
                $productstatic->id = $objp->product_id;
1401
                $productstatic->label = $objp->product_label;
1402
                $productstatic->type = $objp->line_type;
1403
                $productstatic->status = $objp->tosell;
1404
                $productstatic->status_buy = $objp->tobuy;
1405
                $productstatic->accountancy_code_sell = $objp->accountancy_code_sell;
1406
                $productstatic->accountancy_code_sell_intra = $objp->accountancy_code_sell_intra;
1407
                $productstatic->accountancy_code_sell_export = $objp->accountancy_code_sell_export;
1408
1409
                $accountingaccountstatic->rowid = $objp->fk_compte;
1410
                $accountingaccountstatic->label = $objp->label_account;
1411
                $accountingaccountstatic->labelshort = $objp->labelshort_account;
1412
                $accountingaccountstatic->account_number = $objp->account_number;
1413
1414
                print '<tr class="oddeven">';
1415
1416
                // Line id
1417
                print '<td>' . $objp->rowid . '</td>';
1418
1419
                // Ref Invoice
1420
                print '<td class="nowraponall">' . $facturestatic->getNomUrl(1) . '</td>';
1421
1422
                // Date invoice
1423
                print '<td class="center">' . dol_print_date($db->jdate($objp->datef), 'day') . '</td>';
1424
1425
                // Ref Product
1426
                print '<td class="tdoverflowmax100">';
1427
                if ($productstatic->id > 0) {
1428
                    print $productstatic->getNomUrl(1);
1429
                }
1430
                if ($productstatic->id > 0 && $objp->product_label) {
1431
                    print '<br>';
1432
                }
1433
                if ($objp->product_label) {
1434
                    print '<span class="opacitymedium">' . $objp->product_label . '</span>';
1435
                }
1436
                print '</td>';
1437
1438
                print '<td class="tdoverflowonsmartphone small">';
1439
                $text = dolGetFirstLineOfText(dol_string_nohtmltag($objp->description, 1));
1440
                $trunclength = getDolGlobalInt('ACCOUNTING_LENGTH_DESCRIPTION', 32);
1441
                print $form->textwithtooltip(dol_trunc($text, $trunclength), $objp->description);
1442
                print '</td>';
1443
1444
                // Amount
1445
                print '<td class="right nowraponall amount">';
1446
1447
                // Create a compensation rate for old situation invoice feature.
1448
                $situation_ratio = 1;
1449
                if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
1450
                    if ($objp->situation_cycle_ref) {
1451
                        // Avoid divide by 0
1452
                        if ($objp->situation_percent == 0) {
1453
                            $situation_ratio = 0;
1454
                        } else {
1455
                            $line = new FactureLigne($db);
1456
                            $line->fetch($objp->rowid);
1457
1458
                            // Situation invoices handling
1459
                            $prev_progress = $line->get_prev_progress($objp->facid);
1460
1461
                            $situation_ratio = ($objp->situation_percent - $prev_progress) / $objp->situation_percent;
1462
                        }
1463
                    }
1464
                    print price($objp->total_ht * $situation_ratio);
1465
                } else {
1466
                    print price($objp->total_ht);
1467
                }
1468
                print '</td>';
1469
1470
                // Vat rate
1471
                print '<td class="right">' . vatrate($objp->tva_tx . ($objp->vat_src_code ? ' (' . $objp->vat_src_code . ')' : '')) . '</td>';
1472
1473
                // Thirdparty
1474
                print '<td class="tdoverflowmax100">' . $thirdpartystatic->getNomUrl(1, 'customer') . '</td>';
1475
1476
                // Country
1477
                print '<td>';
1478
                if ($objp->country_code) {
1479
                    print $langs->trans("Country" . $objp->country_code) . ' (' . $objp->country_code . ')';
1480
                }
1481
                print '</td>';
1482
1483
                print '<td class="tdoverflowmax80" title="' . dol_escape_htmltag($objp->tva_intra) . '">' . dol_escape_htmltag($objp->tva_intra) . '</td>';
1484
1485
                print '<td>';
1486
                print $accountingaccountstatic->getNomUrl(0, 1, 1, '', 1);
1487
                print ' <a class="editfielda" href="./card.php?id=' . $objp->rowid . '&backtopage=' . urlencode($_SERVER['PHP_SELF'] . ($param ? '?' . $param : '')) . '">';
1488
                print img_edit();
1489
                print '</a></td>';
1490
1491
                print '<td class="center"><input type="checkbox" class="checkforaction" name="changeaccount[]" value="' . $objp->rowid . '"/></td>';
1492
1493
                print '</tr>';
1494
                $i++;
1495
            }
1496
            if ($num_lines == 0) {
1497
                print '<tr><td colspan="12"><span class="opacitymedium">' . $langs->trans("NoRecordFound") . '</span></td></tr>';
1498
            }
1499
1500
            print '</table>';
1501
            print "</div>";
1502
1503
            if ($nbtotalofrecords > $limit) {
1504
                print_barre_liste('', $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, '', $num_lines, $nbtotalofrecords, '', 0, '', '', $limit, 1);
1505
            }
1506
1507
            print '</form>';
1508
        } else {
1509
            print $db->lasterror();
1510
        }
1511
1512
// End of page
1513
        llxFooter();
1514
        $db->close();
1515
    }
1516
1517
    /**
1518
     * \file        htdocs/accountancy/customer/list.php
1519
     * \ingroup     Accountancy (Double entries)
1520
     * \brief       Ventilation page from customers invoices
1521
     */
1522
    public function list()
1523
    {
1524
        global $conf;
1525
        global $db;
1526
        global $user;
1527
        global $hookmanager;
1528
        global $user;
1529
        global $menumanager;
1530
        global $langs;
1531
        global $mysoc;
1532
1533
// Load translation files required by the page
1534
        $langs->loadLangs(["bills", "companies", "compta", "accountancy", "other", "productbatch", "products"]);
1535
1536
        $action = GETPOST('action', 'aZ09');
1537
        $massaction = GETPOST('massaction', 'alpha');
1538
        $confirm = GETPOST('confirm', 'alpha');
1539
        $toselect = GETPOST('toselect', 'array');
1540
        $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'accountancycustomerlist'; // To manage different context of search
1541
        $optioncss = GETPOST('optioncss', 'alpha');
1542
1543
        $default_account = GETPOSTINT('default_account');
1544
1545
// Select Box
1546
        $mesCasesCochees = GETPOST('toselect', 'array');
1547
1548
// Search Getpost
1549
        $search_societe = GETPOST('search_societe', 'alpha');
1550
        $search_lineid = GETPOSTINT('search_lineid');
1551
        $search_ref = GETPOST('search_ref', 'alpha');
1552
        $search_invoice = GETPOST('search_invoice', 'alpha');
1553
        $search_label = GETPOST('search_label', 'alpha');
1554
        $search_desc = GETPOST('search_desc', 'alpha');
1555
        $search_amount = GETPOST('search_amount', 'alpha');
1556
        $search_account = GETPOST('search_account', 'alpha');
1557
        $search_vat = GETPOST('search_vat', 'alpha');
1558
        $search_date_startday = GETPOSTINT('search_date_startday');
1559
        $search_date_startmonth = GETPOSTINT('search_date_startmonth');
1560
        $search_date_startyear = GETPOSTINT('search_date_startyear');
1561
        $search_date_endday = GETPOSTINT('search_date_endday');
1562
        $search_date_endmonth = GETPOSTINT('search_date_endmonth');
1563
        $search_date_endyear = GETPOSTINT('search_date_endyear');
1564
        $search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear);   // Use tzserver
1565
        $search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear);
1566
        $search_country = GETPOST('search_country', 'alpha');
1567
        $search_tvaintra = GETPOST('search_tvaintra', 'alpha');
1568
1569
// Define begin binding date
1570
        if (empty($search_date_start) && getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
1571
            $search_date_start = $db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING'));
1572
        }
1573
1574
// Load variable for pagination
1575
        $limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : getDolGlobalString('ACCOUNTING_LIMIT_LIST_VENTILATION', $conf->liste_limit);
1576
        $sortfield = GETPOST('sortfield', 'aZ09comma');
1577
        $sortorder = GETPOST('sortorder', 'aZ09comma');
1578
        $page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
1579
        if (empty($page) || $page < 0) {
1580
            $page = 0;
1581
        }
1582
        $offset = $limit * $page;
1583
        $pageprev = $page - 1;
1584
        $pagenext = $page + 1;
1585
        if (!$sortfield) {
1586
            $sortfield = "f.datef, f.ref, l.rowid";
1587
        }
1588
        if (!$sortorder) {
1589
            if (getDolGlobalInt('ACCOUNTING_LIST_SORT_VENTILATION_TODO') > 0) {
1590
                $sortorder = "DESC";
1591
            } else {
1592
                $sortorder = "ASC";
1593
            }
1594
        }
1595
1596
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
1597
        $hookmanager->initHooks(['accountancycustomerlist']);
1598
1599
        $formaccounting = new FormAccounting($db);
1600
        $accountingAccount = new AccountingAccount($db);
1601
1602
        $chartaccountcode = dol_getIdFromCode($db, getDolGlobalInt('CHARTOFACCOUNTS'), 'accounting_system', 'rowid', 'pcg_version');
1603
1604
// Security check
1605
        if (!isModEnabled('accounting')) {
1606
            accessforbidden();
1607
        }
1608
        if ($user->socid > 0) {
1609
            accessforbidden();
1610
        }
1611
        if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
1612
            accessforbidden();
1613
        }
1614
1615
1616
        /*
1617
         * Actions
1618
         */
1619
1620
        if (GETPOST('cancel', 'alpha')) {
1621
            $action = 'list';
1622
            $massaction = '';
1623
        }
1624
        if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
1625
            $massaction = '';
1626
        }
1627
1628
        $parameters = [];
1629
        $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $object does not exist. Did you maybe mean $objectclass?
Loading history...
1630
        if ($reshook < 0) {
1631
            setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1632
        }
1633
1634
        if (empty($reshook)) {
1635
            // Purge search criteria
1636
            if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All test are required to be compatible with all browsers
1637
                $search_societe = '';
1638
                $search_lineid = '';
1639
                $search_ref = '';
1640
                $search_invoice = '';
1641
                $search_label = '';
1642
                $search_desc = '';
1643
                $search_amount = '';
1644
                $search_account = '';
1645
                $search_vat = '';
1646
                $search_date_startday = '';
1647
                $search_date_startmonth = '';
1648
                $search_date_startyear = '';
1649
                $search_date_endday = '';
1650
                $search_date_endmonth = '';
1651
                $search_date_endyear = '';
1652
                $search_date_start = '';
1653
                $search_date_end = '';
1654
                $search_country = '';
1655
                $search_tvaintra = '';
1656
            }
1657
1658
            // Mass actions
1659
            $objectclass = 'AccountingAccount';
1660
            $permissiontoread = $user->hasRight('accounting', 'read');
1661
            $permissiontodelete = $user->hasRight('accounting', 'delete');
1662
            $uploaddir = $conf->accounting->dir_output;
1663
            include DOL_DOCUMENT_ROOT . '/core/actions_massactions.inc.php';
1664
        }
1665
1666
1667
        if ($massaction == 'ventil' && $user->hasRight('accounting', 'bind', 'write')) {
1668
            $msg = '';
1669
1670
            //print '<div><span style="color:red">' . $langs->trans("Processing") . '...</span></div>';
1671
            if (!empty($mesCasesCochees)) {
1672
                $msg = '<div>' . $langs->trans("SelectedLines") . ': ' . count($mesCasesCochees) . '</div>';
1673
                $msg .= '<div class="detail">';
1674
                $cpt = 0;
1675
                $ok = 0;
1676
                $ko = 0;
1677
1678
                foreach ($mesCasesCochees as $maLigneCochee) {
1679
                    $maLigneCourante = explode("_", $maLigneCochee);
1680
                    $monId = $maLigneCourante[0];
1681
                    $monCompte = GETPOST('codeventil' . $monId);
1682
1683
                    if ($monCompte <= 0) {
1684
                        $msg .= '<div><span style="color:red">' . $langs->trans("Lineofinvoice") . ' ' . $monId . ' - ' . $langs->trans("NoAccountSelected") . '</span></div>';
1685
                        $ko++;
1686
                    } else {
1687
                        $sql = " UPDATE " . MAIN_DB_PREFIX . "facturedet";
1688
                        $sql .= " SET fk_code_ventilation = " . ((int) $monCompte);
1689
                        $sql .= " WHERE rowid = " . ((int) $monId);
1690
1691
                        $accountventilated = new AccountingAccount($db);
1692
                        $accountventilated->fetch($monCompte, '', 1);
1693
1694
                        dol_syslog("accountancy/customer/list.php", LOG_DEBUG);
1695
                        if ($db->query($sql)) {
1696
                            $msg .= '<div><span style="color:green">' . $langs->trans("Lineofinvoice") . ' ' . $monId . ' - ' . $langs->trans("VentilatedinAccount") . ' : ' . length_accountg($accountventilated->account_number) . '</span></div>';
1697
                            $ok++;
1698
                        } else {
1699
                            $msg .= '<div><span style="color:red">' . $langs->trans("ErrorDB") . ' : ' . $langs->trans("Lineofinvoice") . ' ' . $monId . ' - ' . $langs->trans("NotVentilatedinAccount") . ' : ' . length_accountg($accountventilated->account_number) . '<br> <pre>' . $sql . '</pre></span></div>';
1700
                            $ko++;
1701
                        }
1702
                    }
1703
1704
                    $cpt++;
1705
                }
1706
                $msg .= '</div>';
1707
                $msg .= '<div>' . $langs->trans("EndProcessing") . '</div>';
1708
            }
1709
        }
1710
1711
        if (GETPOST('sortfield') == 'f.datef, f.ref, l.rowid') {
1712
            $value = (GETPOST('sortorder') == 'asc,asc,asc' ? 0 : 1);
1713
            require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
1714
            $res = dolibarr_set_const($db, "ACCOUNTING_LIST_SORT_VENTILATION_TODO", $value, 'yesno', 0, '', $conf->entity);
1715
        }
1716
1717
1718
        /*
1719
         * View
1720
         */
1721
1722
        $form = new Form($db);
1723
        $formother = new FormOther($db);
1724
1725
        $help_url = 'EN:Module_Double_Entry_Accounting|FR:Module_Comptabilit&eacute;_en_Partie_Double#Liaisons_comptables';
1726
1727
        llxHeader('', $langs->trans("CustomersVentilation"), $help_url);
1728
1729
        if (empty($chartaccountcode)) {
1730
            print $langs->trans("ErrorChartOfAccountSystemNotSelected");
1731
            // End of page
1732
            llxFooter();
1733
            $db->close();
1734
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1735
        }
1736
1737
// Customer Invoice lines
1738
        $sql = "SELECT f.rowid as facid, f.ref, f.datef, f.type as ftype, f.situation_cycle_ref, f.fk_facture_source,";
1739
        $sql .= " l.rowid, l.fk_product, l.description, l.total_ht, l.situation_percent, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line, l.vat_src_code,";
1740
        $sql .= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.tva_tx as tva_tx_prod,";
1741
        if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
1742
            $sql .= " ppe.accountancy_code_sell as code_sell, ppe.accountancy_code_sell_intra as code_sell_intra, ppe.accountancy_code_sell_export as code_sell_export,";
1743
            $sql .= " ppe.accountancy_code_buy as code_buy, ppe.accountancy_code_buy_intra as code_buy_intra, ppe.accountancy_code_buy_export as code_buy_export,";
1744
        } else {
1745
            $sql .= " p.accountancy_code_sell as code_sell, p.accountancy_code_sell_intra as code_sell_intra, p.accountancy_code_sell_export as code_sell_export,";
1746
            $sql .= " p.accountancy_code_buy as code_buy, p.accountancy_code_buy_intra as code_buy_intra, p.accountancy_code_buy_export as code_buy_export,";
1747
        }
1748
        $sql .= " p.tosell as status, p.tobuy as status_buy,";
1749
        $sql .= " aa.rowid as aarowid, aa2.rowid as aarowid_intra, aa3.rowid as aarowid_export, aa4.rowid as aarowid_thirdparty,";
1750
        $sql .= " co.code as country_code, co.label as country_label,";
1751
        $sql .= " s.rowid as socid, s.nom as name, s.tva_intra, s.email, s.town, s.zip, s.fk_pays, s.client, s.fournisseur, s.code_client, s.code_fournisseur,";
1752
        if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
1753
            $sql .= " spe.accountancy_code_customer as code_compta_client,";
1754
            $sql .= " spe.accountancy_code_supplier as code_compta_fournisseur,";
1755
            $sql .= " spe.accountancy_code_sell as company_code_sell";
1756
        } else {
1757
            $sql .= " s.code_compta as code_compta_client,";
1758
            $sql .= " s.code_compta_fournisseur,";
1759
            $sql .= " s.accountancy_code_sell as company_code_sell";
1760
        }
1761
        $parameters = [];
1762
        $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
1763
        $sql .= $hookmanager->resPrint;
1764
        $sql .= " FROM " . MAIN_DB_PREFIX . "facture as f";
1765
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid = f.fk_soc";
1766
        if (getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED')) {
1767
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_perentity as spe ON spe.fk_soc = s.rowid AND spe.entity = " . ((int) $conf->entity);
1768
        }
1769
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as co ON co.rowid = s.fk_pays ";
1770
        $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "facturedet as l ON f.rowid = l.fk_facture";
1771
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = l.fk_product";
1772
        if (getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) {
1773
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
1774
        }
1775
        $alias_societe_perentity = !getDolGlobalString('MAIN_COMPANY_PERENTITY_SHARED') ? "s" : "spe";
1776
        $alias_product_perentity = !getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED') ? "p" : "ppe";
1777
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa  ON " . $alias_product_perentity . ".accountancy_code_sell = aa.account_number         AND aa.active = 1  AND aa.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa.entity = " . $conf->entity;
1778
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa2 ON " . $alias_product_perentity . ".accountancy_code_sell_intra = aa2.account_number  AND aa2.active = 1 AND aa2.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa2.entity = " . $conf->entity;
1779
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa3 ON " . $alias_product_perentity . ".accountancy_code_sell_export = aa3.account_number AND aa3.active = 1 AND aa3.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa3.entity = " . $conf->entity;
1780
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa4 ON " . $alias_societe_perentity . ".accountancy_code_sell = aa4.account_number        AND aa4.active = 1 AND aa4.fk_pcg_version = '" . $db->escape($chartaccountcode) . "' AND aa4.entity = " . $conf->entity;
1781
1782
        $sql .= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0";
1783
        $sql .= " AND l.product_type <= 2";
1784
// Add search filter like
1785
        if ($search_societe) {
1786
            $sql .= natural_search('s.nom', $search_societe);
1787
        }
1788
        if ($search_lineid) {
1789
            $sql .= natural_search("l.rowid", $search_lineid, 1);
1790
        }
1791
        if (strlen(trim($search_invoice))) {
1792
            $sql .= natural_search("f.ref", $search_invoice);
1793
        }
1794
        if (strlen(trim($search_ref))) {
1795
            $sql .= natural_search("p.ref", $search_ref);
1796
        }
1797
        if (strlen(trim($search_label))) {
1798
            $sql .= natural_search("p.label", $search_label);
1799
        }
1800
        if (strlen(trim($search_desc))) {
1801
            $sql .= natural_search("l.description", $search_desc);
1802
        }
1803
        if (strlen(trim($search_amount))) {
1804
            $sql .= natural_search("l.total_ht", $search_amount, 1);
1805
        }
1806
        if (strlen(trim($search_account))) {
1807
            $sql .= natural_search("aa.account_number", $search_account);
1808
        }
1809
        if (strlen(trim($search_vat))) {
1810
            $sql .= natural_search("l.tva_tx", price2num($search_vat), 1);
1811
        }
1812
        if ($search_date_start) {
1813
            $sql .= " AND f.datef >= '" . $db->idate($search_date_start) . "'";
1814
        }
1815
        if ($search_date_end) {
1816
            $sql .= " AND f.datef <= '" . $db->idate($search_date_end) . "'";
1817
        }
1818
        if (strlen(trim($search_country))) {
1819
            $arrayofcode = getCountriesInEEC();
1820
            $country_code_in_EEC = $country_code_in_EEC_without_me = '';
1821
            foreach ($arrayofcode as $key => $value) {
1822
                $country_code_in_EEC .= ($country_code_in_EEC ? "," : "") . "'" . $value . "'";
1823
                if ($value != $mysoc->country_code) {
1824
                    $country_code_in_EEC_without_me .= ($country_code_in_EEC_without_me ? "," : "") . "'" . $value . "'";
1825
                }
1826
            }
1827
            if ($search_country == 'special_allnotme') {
1828
                $sql .= " AND co.code <> '" . $db->escape($mysoc->country_code) . "'";
1829
            } elseif ($search_country == 'special_eec') {
1830
                $sql .= " AND co.code IN (" . $db->sanitize($country_code_in_EEC, 1) . ")";
1831
            } elseif ($search_country == 'special_eecnotme') {
1832
                $sql .= " AND co.code IN (" . $db->sanitize($country_code_in_EEC_without_me, 1) . ")";
1833
            } elseif ($search_country == 'special_noteec') {
1834
                $sql .= " AND co.code NOT IN (" . $db->sanitize($country_code_in_EEC, 1) . ")";
1835
            } else {
1836
                $sql .= natural_search("co.code", $search_country);
1837
            }
1838
        }
1839
        if (strlen(trim($search_tvaintra))) {
1840
            $sql .= natural_search("s.tva_intra", $search_tvaintra);
1841
        }
1842
        if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
1843
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")";
1844
        } else {
1845
            $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")";
1846
        }
1847
        $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy
1848
1849
// Add where from hooks
1850
        $parameters = [];
1851
        $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
1852
        $sql .= $hookmanager->resPrint;
1853
1854
        $sql .= $db->order($sortfield, $sortorder);
1855
1856
// Count total nb of records
1857
        $nbtotalofrecords = '';
1858
        if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
1859
            $result = $db->query($sql);
1860
            $nbtotalofrecords = $db->num_rows($result);
1861
            if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
1862
                $page = 0;
1863
                $offset = 0;
1864
            }
1865
        }
1866
1867
        $sql .= $db->plimit($limit + 1, $offset);
1868
1869
        dol_syslog("accountancy/customer/list.php", LOG_DEBUG);
1870
// MAX_JOIN_SIZE can be very low (ex: 300000) on some limited configurations (ex: https://www.online.net/fr/hosting/online-perso)
1871
// This big SELECT command may exceed the MAX_JOIN_SIZE limit => Therefore we use SQL_BIG_SELECTS=1 to disable the MAX_JOIN_SIZE security
1872
        if ($db->type == 'mysqli') {
1873
            $db->query("SET SQL_BIG_SELECTS=1");
1874
        }
1875
1876
        $result = $db->query($sql);
1877
        if ($result) {
1878
            $num_lines = $db->num_rows($result);
1879
            $i = 0;
1880
1881
            $arrayofselected = is_array($toselect) ? $toselect : [];
1882
1883
            $param = '';
1884
            if (!empty($contextpage) && $contextpage != $_SERVER['PHP_SELF']) {
1885
                $param .= '&contextpage=' . urlencode($contextpage);
1886
            }
1887
            if ($limit > 0 && $limit != $conf->liste_limit) {
1888
                $param .= '&limit=' . ((int) $limit);
1889
            }
1890
            if ($search_societe) {
1891
                $param .= '&search_societe=' . urlencode($search_societe);
1892
            }
1893
            if ($search_lineid) {
1894
                $param .= '&search_lineid=' . urlencode((string) ($search_lineid));
1895
            }
1896
            if ($search_date_startday) {
1897
                $param .= '&search_date_startday=' . urlencode((string) ($search_date_startday));
1898
            }
1899
            if ($search_date_startmonth) {
1900
                $param .= '&search_date_startmonth=' . urlencode((string) ($search_date_startmonth));
1901
            }
1902
            if ($search_date_startyear) {
1903
                $param .= '&search_date_startyear=' . urlencode((string) ($search_date_startyear));
1904
            }
1905
            if ($search_date_endday) {
1906
                $param .= '&search_date_endday=' . urlencode((string) ($search_date_endday));
1907
            }
1908
            if ($search_date_endmonth) {
1909
                $param .= '&search_date_endmonth=' . urlencode((string) ($search_date_endmonth));
1910
            }
1911
            if ($search_date_endyear) {
1912
                $param .= '&search_date_endyear=' . urlencode((string) ($search_date_endyear));
1913
            }
1914
            if ($search_invoice) {
1915
                $param .= '&search_invoice=' . urlencode($search_invoice);
1916
            }
1917
            if ($search_ref) {
1918
                $param .= '&search_ref=' . urlencode($search_ref);
1919
            }
1920
            if ($search_label) {
1921
                $param .= '&search_label=' . urlencode($search_label);
1922
            }
1923
            if ($search_desc) {
1924
                $param .= '&search_desc=' . urlencode($search_desc);
1925
            }
1926
            if ($search_amount) {
1927
                $param .= '&search_amount=' . urlencode($search_amount);
1928
            }
1929
            if ($search_vat) {
1930
                $param .= '&search_vat=' . urlencode($search_vat);
1931
            }
1932
            if ($search_country) {
1933
                $param .= "&search_country=" . urlencode($search_country);
1934
            }
1935
            if ($search_tvaintra) {
1936
                $param .= "&search_tvaintra=" . urlencode($search_tvaintra);
1937
            }
1938
1939
            $arrayofmassactions = [
1940
                'ventil' => img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans("Ventilate")
1941
                , 'set_default_account' => img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans("ConfirmPreselectAccount"),
1942
                //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"),
1943
                //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"),
1944
            ];
1945
            //if ($user->hasRight('mymodule', 'supprimer')) $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
1946
            //if (in_array($massaction, array('presend','predelete'))) $arrayofmassactions=array();
1947
            if ($massaction !== 'set_default_account') {
1948
                $massactionbutton = $form->selectMassAction('ventil', $arrayofmassactions, 1);
1949
            }
1950
1951
            print '<form action="' . $_SERVER['PHP_SELF'] . '" method="post">' . "\n";
1952
            print '<input type="hidden" name="action" value="ventil">';
1953
            if ($optioncss != '') {
1954
                print '<input type="hidden" name="optioncss" value="' . $optioncss . '">';
1955
            }
1956
            print '<input type="hidden" name="token" value="' . newToken() . '">';
1957
            print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
1958
            print '<input type="hidden" name="sortfield" value="' . $sortfield . '">';
1959
            print '<input type="hidden" name="sortorder" value="' . $sortorder . '">';
1960
            print '<input type="hidden" name="page" value="' . $page . '">';
1961
1962
            // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1963
            print_barre_liste($langs->trans("InvoiceLines"), $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, $massactionbutton, $num_lines, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit);
1964
1965
            if ($massaction == 'set_default_account') {
1966
                $formquestion = [];
1967
                $formquestion[] = [
1968
                    'type' => 'other',
1969
                    'name' => 'set_default_account',
1970
                    'label' => $langs->trans("AccountancyCode"),
1971
                    'value' => $formaccounting->select_account('', 'default_account', 1, [], 0, 0, 'maxwidth200 maxwidthonsmartphone', 'cachewithshowemptyone'),
1972
                ];
1973
                print $form->formconfirm($_SERVER['PHP_SELF'], $langs->trans("ConfirmPreselectAccount"), $langs->trans("ConfirmPreselectAccountQuestion", count($toselect)), "confirm_set_default_account", $formquestion, 1, 0, 200, 500, 1);
1974
            }
1975
1976
            print '<span class="opacitymedium">' . $langs->trans("DescVentilTodoCustomer") . '</span></br><br>';
1977
1978
            if (!empty($msg)) {
1979
                print $msg . '<br>';
1980
            }
1981
1982
            $moreforfilter = '';
1983
1984
            print '<div class="div-table-responsive">';
1985
            print '<table class="tagtable liste' . ($moreforfilter ? " listwithfilterbefore" : "") . '">' . "\n";
1986
1987
            // We add search filter
1988
            print '<tr class="liste_titre_filter">';
1989
            print '<td class="liste_titre"><input type="text" class="flat maxwidth25" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '"></td>';
1990
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
1991
            print '<td class="liste_titre center">';
1992
            print '<div class="nowrapfordate">';
1993
            print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
1994
            print '</div>';
1995
            print '<div class="nowrapfordate">';
1996
            print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
1997
            print '</div>';
1998
            print '</td>';
1999
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_ref" value="' . dol_escape_htmltag($search_ref) . '"></td>';
2000
            print '<td class="liste_titre"><input type="text" class="flat maxwidth100" name="search_desc" value="' . dol_escape_htmltag($search_desc) . '"></td>';
2001
            print '<td class="liste_titre right"><input type="text" class="flat maxwidth50 right" name="search_amount" value="' . dol_escape_htmltag($search_amount) . '"></td>';
2002
            print '<td class="liste_titre right"><input type="text" class="flat maxwidth50 right" name="search_vat" placeholder="%" size="1" value="' . dol_escape_htmltag($search_vat) . '"></td>';
2003
            print '<td class="liste_titre"><input type="text" class="flat maxwidth75imp" name="search_societe" value="' . dol_escape_htmltag($search_societe) . '"></td>';
2004
            print '<td class="liste_titre">';
2005
            print $form->select_country($search_country, 'search_country', '', 0, 'maxwidth100', 'code2', 1, 0, 1);
2006
            //print '<input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '">';
2007
            print '</td>';
2008
            print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_tvaintra" value="' . dol_escape_htmltag($search_tvaintra) . '"></td>';
2009
            print '<td class="liste_titre"></td>';
2010
            print '<td class="liste_titre"></td>';
2011
            print '<td class="center liste_titre">';
2012
            $searchpicto = $form->showFilterButtons();
2013
            print $searchpicto;
2014
            print '</td>';
2015
            print "</tr>\n";
2016
2017
            print '<tr class="liste_titre">';
2018
            print_liste_field_titre("LineId", $_SERVER['PHP_SELF'], "l.rowid", "", $param, '', $sortfield, $sortorder);
2019
            print_liste_field_titre("Invoice", $_SERVER['PHP_SELF'], "f.ref", "", $param, '', $sortfield, $sortorder);
2020
            print_liste_field_titre("Date", $_SERVER['PHP_SELF'], "f.datef, f.ref, l.rowid", "", $param, '', $sortfield, $sortorder, 'center ');
2021
            print_liste_field_titre("ProductRef", $_SERVER['PHP_SELF'], "p.ref", "", $param, '', $sortfield, $sortorder);
2022
            //print_liste_field_titre("ProductLabel", $_SERVER['PHP_SELF'], "p.label", "", $param, '', $sortfield, $sortorder);
2023
            print_liste_field_titre("ProductDescription", $_SERVER['PHP_SELF'], "l.description", "", $param, '', $sortfield, $sortorder);
2024
            print_liste_field_titre("Amount", $_SERVER['PHP_SELF'], "l.total_ht", "", $param, '', $sortfield, $sortorder, 'right maxwidth50 ');
2025
            print_liste_field_titre("VATRate", $_SERVER['PHP_SELF'], "l.tva_tx", "", $param, '', $sortfield, $sortorder, 'right ', '', 1);
2026
            print_liste_field_titre("ThirdParty", $_SERVER['PHP_SELF'], "s.nom", "", $param, '', $sortfield, $sortorder);
2027
            print_liste_field_titre("Country", $_SERVER['PHP_SELF'], "co.label", "", $param, '', $sortfield, $sortorder);
2028
            print_liste_field_titre("VATIntraShort", $_SERVER['PHP_SELF'], "s.tva_intra", "", $param, '', $sortfield, $sortorder);
2029
            print_liste_field_titre("DataUsedToSuggestAccount", '', '', '', '', '', '', '', 'nowraponall ');
2030
            print_liste_field_titre("AccountAccountingSuggest", '', '', '', '', '', '', '', 'center ');
2031
            $checkpicto = '';
2032
            if ($massactionbutton) {
2033
                $checkpicto = $form->showCheckAddButtons('checkforselect', 1);
2034
            }
2035
            print_liste_field_titre($checkpicto, '', '', '', '', '', '', '', 'center ');
2036
            print "</tr>\n";
2037
2038
            $thirdpartystatic = new Societe($db);
2039
            $facture_static = new Facture($db);
2040
            $facture_static_det = new FactureLigne($db);
2041
            $product_static = new Product($db);
2042
2043
2044
            $accountingaccount_codetotid_cache = [];
2045
2046
            while ($i < min($num_lines, $limit)) {
2047
                $objp = $db->fetch_object($result);
2048
2049
                // product_type: 0 = service, 1 = product
2050
                // if product does not exist we use the value of product_type provided in facturedet to define if this is a product or service
2051
                // issue : if we change product_type value in product DB it should differ from the value stored in facturedet DB !
2052
                $code_sell_l = '';
2053
                $code_sell_p = '';
2054
                $code_sell_t = '';
2055
2056
                $thirdpartystatic->id = $objp->socid;
2057
                $thirdpartystatic->name = $objp->name;
2058
                $thirdpartystatic->client = $objp->client;
2059
                $thirdpartystatic->fournisseur = $objp->fournisseur;
2060
                $thirdpartystatic->code_client = $objp->code_client;
2061
                $thirdpartystatic->code_compta = $objp->code_compta_client;     // For backward compatibility
2062
                $thirdpartystatic->code_compta_client = $objp->code_compta_client;
2063
                $thirdpartystatic->code_fournisseur = $objp->code_fournisseur;
2064
                $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur;
2065
                $thirdpartystatic->email = $objp->email;
2066
                $thirdpartystatic->country_code = $objp->country_code;
2067
                $thirdpartystatic->tva_intra = $objp->tva_intra;
2068
                $thirdpartystatic->code_compta_product = $objp->company_code_sell;      // The accounting account for product stored on thirdparty object (for level3 suggestion)
2069
2070
                $product_static->ref = $objp->product_ref;
2071
                $product_static->id = $objp->product_id;
2072
                $product_static->type = $objp->type;
2073
                $product_static->label = $objp->product_label;
2074
                $product_static->status = $objp->status;
2075
                $product_static->status_buy = $objp->status_buy;
2076
                $product_static->accountancy_code_sell = $objp->code_sell;
2077
                $product_static->accountancy_code_sell_intra = $objp->code_sell_intra;
2078
                $product_static->accountancy_code_sell_export = $objp->code_sell_export;
2079
                $product_static->accountancy_code_buy = $objp->code_buy;
2080
                $product_static->accountancy_code_buy_intra = $objp->code_buy_intra;
2081
                $product_static->accountancy_code_buy_export = $objp->code_buy_export;
2082
                $product_static->tva_tx = $objp->tva_tx_prod;
2083
2084
                $facture_static->ref = $objp->ref;
2085
                $facture_static->id = $objp->facid;
2086
                $facture_static->type = $objp->ftype;
2087
                $facture_static->date = $db->jdate($objp->datef);
2088
                $facture_static->fk_facture_source = $objp->fk_facture_source;
2089
2090
                $facture_static_det->id = $objp->rowid;
2091
                $facture_static_det->total_ht = $objp->total_ht;
2092
                $facture_static_det->tva_tx = $objp->tva_tx_line;
2093
                $facture_static_det->vat_src_code = $objp->vat_src_code;
2094
                $facture_static_det->product_type = $objp->type_l;
2095
                $facture_static_det->desc = $objp->description;
2096
2097
                $accountingAccountArray = [
2098
                    'dom' => $objp->aarowid,
2099
                    'intra' => $objp->aarowid_intra,
2100
                    'export' => $objp->aarowid_export,
2101
                    'thirdparty' => $objp->aarowid_thirdparty,
2102
                ];
2103
2104
                $code_sell_p_notset = '';
2105
                $code_sell_t_notset = '';
2106
2107
                $suggestedid = 0;
2108
2109
                $return = $accountingAccount->getAccountingCodeToBind($thirdpartystatic, $mysoc, $product_static, $facture_static, $facture_static_det, $accountingAccountArray, 'customer');
2110
                if (!is_array($return) && $return < 0) {
2111
                    setEventMessage($accountingAccount->error, 'errors');
2112
                } else {
2113
                    $suggestedid = $return['suggestedid'];
2114
                    $suggestedaccountingaccountfor = $return['suggestedaccountingaccountfor'];
2115
                    $suggestedaccountingaccountbydefaultfor = $return['suggestedaccountingaccountbydefaultfor'];
2116
                    $code_sell_l = $return['code_l'];
2117
                    $code_sell_p = $return['code_p'];
2118
                    $code_sell_t = $return['code_t'];
2119
                }
2120
                //var_dump($return);
2121
2122
                if (!empty($code_sell_p)) {
2123
                    // Value was defined previously
2124
                } else {
2125
                    $code_sell_p_notset = 'color:orange';
2126
                }
2127
                if (empty($code_sell_l) && empty($code_sell_p)) {
2128
                    $code_sell_p_notset = 'color:red';
2129
                }
2130
                if ($suggestedaccountingaccountfor == 'eecwithoutvatnumber' && empty($code_sell_p_notset)) {
2131
                    $code_sell_p_notset = 'color:orange';
2132
                }
2133
2134
                // $code_sell_l is now default code of product/service
2135
                // $code_sell_p is now code of product/service
2136
                // $code_sell_t is now code of thirdparty
2137
                //var_dump($code_sell_l.' - '.$code_sell_p.' - '.$code_sell_t.' -> '.$suggestedid.' ('.$suggestedaccountingaccountbydefaultfor.' '.$suggestedaccountingaccountfor.')');
2138
2139
                print '<tr class="oddeven">';
2140
2141
                // Line id
2142
                print '<td>' . $facture_static_det->id . '</td>';
2143
2144
                // Ref Invoice
2145
                print '<td class="nowraponall">' . $facture_static->getNomUrl(1) . '</td>';
2146
2147
                print '<td class="center">' . dol_print_date($facture_static->date, 'day') . '</td>';
2148
2149
                // Ref Product
2150
                print '<td class="tdoverflowmax100">';
2151
                if ($product_static->id > 0) {
2152
                    print $product_static->getNomUrl(1);
2153
                }
2154
                if ($product_static->label) {
2155
                    print '<br><span class="opacitymedium small">' . dol_escape_htmltag($product_static->label) . '</span>';
2156
                }
2157
                print '</td>';
2158
2159
                // Description of line
2160
                print '<td class="tdoverflowonsmartphone small">';
2161
                $text = dolGetFirstLineOfText(dol_string_nohtmltag($facture_static_det->desc, 1));
2162
                $trunclength = getDolGlobalInt('ACCOUNTING_LENGTH_DESCRIPTION', 32);
2163
                print $form->textwithtooltip(dol_trunc($text, $trunclength), $facture_static_det->desc);
2164
                print '</td>';
2165
2166
                // Amount
2167
                print '<td class="right nowraponall amount">';
2168
2169
                // Create a compensation rate for old situation invoice feature.
2170
                $situation_ratio = 1;
2171
                if (getDolGlobalInt('INVOICE_USE_SITUATION') == 1) {
2172
                    if ($objp->situation_cycle_ref) {
2173
                        // Avoid divide by 0
2174
                        if ($objp->situation_percent == 0) {
2175
                            $situation_ratio = 0;
2176
                        } else {
2177
                            $line = new FactureLigne($db);
2178
                            $line->fetch($objp->rowid);
2179
2180
                            // Situation invoices handling
2181
                            $prev_progress = $line->get_prev_progress($objp->facid);
2182
2183
                            $situation_ratio = ($objp->situation_percent - $prev_progress) / $objp->situation_percent;
2184
                        }
2185
                    }
2186
                    print price($objp->total_ht * $situation_ratio);
2187
                } else {
2188
                    print price($objp->total_ht);
2189
                }
2190
                print '</td>';
2191
2192
                // Vat rate
2193
                $code_vat_differ = '';
2194
                if ($product_static->tva_tx !== $facture_static_det->tva_tx && price2num($product_static->tva_tx) && price2num($facture_static_det->tva_tx)) {  // Note: having a vat rate of 0 is often the normal case when sells is intra b2b or to export
2195
                    $code_vat_differ = 'warning bold';
2196
                }
2197
                print '<td class="right' . ($code_vat_differ ? ' ' . $code_vat_differ : '') . '">';
2198
                print vatrate($facture_static_det->tva_tx . ($facture_static_det->vat_src_code ? ' (' . $facture_static_det->vat_src_code . ')' : ''));
2199
                print '</td>';
2200
2201
                // Thirdparty
2202
                print '<td class="tdoverflowmax100">' . $thirdpartystatic->getNomUrl(1, 'customer') . '</td>';
2203
2204
                // Country
2205
                $labelcountry = ($objp->country_code && ($langs->trans("Country" . $objp->country_code) != "Country" . $objp->country_code)) ? $langs->trans("Country" . $objp->country_code) : $objp->country_label;
2206
                print '<td class="tdoverflowmax100" title="' . dol_escape_htmltag($labelcountry) . '">';
2207
                print dol_escape_htmltag($labelcountry);
2208
                print '</td>';
2209
2210
                // VAT Num
2211
                print '<td class="tdoverflowmax80" title="' . dol_escape_htmltag($objp->tva_intra) . '">' . dol_escape_htmltag($objp->tva_intra) . '</td>';
2212
2213
                // Found accounts
2214
                print '<td class="small">';
2215
                // First show default account for any products
2216
                $s = '1. ' . (($facture_static_det->product_type == 1) ? $langs->trans("DefaultForService") : $langs->trans("DefaultForProduct")) . ': ';
2217
                $shelp = '';
2218
                $ttype = 'help';
2219
                if ($suggestedaccountingaccountbydefaultfor == 'eec') {
2220
                    $shelp .= $langs->trans("SaleEEC");
2221
                } elseif ($suggestedaccountingaccountbydefaultfor == 'eecwithvat') {
2222
                    $shelp = $langs->trans("SaleEECWithVAT");
2223
                } elseif ($suggestedaccountingaccountbydefaultfor == 'eecwithoutvatnumber') {
2224
                    $shelp = $langs->trans("SaleEECWithoutVATNumber");
2225
                    $ttype = 'warning';
2226
                } elseif ($suggestedaccountingaccountbydefaultfor == 'export') {
2227
                    $shelp .= $langs->trans("SaleExport");
2228
                }
2229
                $s .= ($code_sell_l > 0 ? length_accountg($code_sell_l) : '<span style="' . $code_sell_p_notset . '">' . $langs->trans("NotDefined") . '</span>');
2230
                print $form->textwithpicto($s, $shelp, 1, $ttype, '', 0, 2, '', 1);
2231
                // Now show account for product
2232
                if ($product_static->id > 0) {
2233
                    print '<br>';
2234
                    $s = '2. ' . (($facture_static_det->product_type == 1) ? $langs->trans("ThisService") : $langs->trans("ThisProduct")) . ': ';
2235
                    $shelp = '';
2236
                    $ttype = 'help';
2237
                    if ($suggestedaccountingaccountfor == 'eec') {
2238
                        $shelp = $langs->trans("SaleEEC");
2239
                    } elseif ($suggestedaccountingaccountfor == 'eecwithvat') {
2240
                        $shelp = $langs->trans("SaleEECWithVAT");
2241
                    } elseif ($suggestedaccountingaccountfor == 'eecwithoutvatnumber') {
2242
                        $shelp = $langs->trans("SaleEECWithoutVATNumber");
2243
                        $ttype = 'warning';
2244
                    } elseif ($suggestedaccountingaccountfor == 'export') {
2245
                        $shelp = $langs->trans("SaleExport");
2246
                    }
2247
                    $s .= (empty($code_sell_p) ? '<span style="' . $code_sell_p_notset . '">' . $langs->trans("NotDefined") . '</span>' : length_accountg($code_sell_p));
2248
                    print $form->textwithpicto($s, $shelp, 1, $ttype, '', 0, 2, '', 1);
2249
                } else {
2250
                    print '<br>';
2251
                    $s = '2. ' . (($objp->type_l == 1) ? $langs->trans("ThisService") : $langs->trans("ThisProduct")) . ': ';
2252
                    $shelp = '';
2253
                    $s .= $langs->trans("NotDefined");
2254
                    print $form->textwithpicto($s, $shelp, 1, 'help', '', 0, 2, '', 1);
2255
                }
2256
                if (getDolGlobalString('ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY')) {
2257
                    print '<br>';
2258
                    $s = '3. ' . (($facture_static_det->product_type == 1) ? $langs->trans("ServiceForThisThirdparty") : $langs->trans("ProductForThisThirdparty")) . ': ';
2259
                    $shelp = '';
2260
                    $s .= ($code_sell_t > 0 ? length_accountg($code_sell_t) : '<span style="' . $code_sell_t_notset . '">' . $langs->trans("NotDefined") . '</span>');
2261
                    print $form->textwithpicto($s, $shelp, 1, 'help', '', 0, 2, '', 1);
2262
                }
2263
                print '</td>';
2264
2265
                // Suggested accounting account
2266
                print '<td>';
2267
                print $formaccounting->select_account(($default_account > 0 && $confirm === 'yes' && in_array($objp->rowid . "_" . $i, $toselect)) ? $default_account : $suggestedid, 'codeventil' . $facture_static_det->id, 1, [], 0, 0, 'codeventil maxwidth150 maxwidthonsmartphone', 'cachewithshowemptyone');
2268
                print '</td>';
2269
2270
                // Column with checkbox
2271
                print '<td class="center">';
2272
                $ischecked = 0;
2273
                if (!empty($suggestedid) && $suggestedaccountingaccountfor != '' && $suggestedaccountingaccountfor != 'eecwithoutvatnumber') {
2274
                    $ischecked = 1;
2275
                }
2276
2277
                if (!empty($toselect)) {
2278
                    $ischecked = 0;
2279
                    if (in_array($objp->rowid . "_" . $i, $toselect)) {
2280
                        $ischecked = 1;
2281
                    }
2282
                }
2283
2284
                print '<input type="checkbox" class="flat checkforselect checkforselect' . $facture_static_det->id . '" name="toselect[]" value="' . $facture_static_det->id . "_" . $i . '"' . ($ischecked ? " checked" : "") . '/>';
2285
                print '</td>';
2286
2287
                print '</tr>';
2288
                $i++;
2289
            }
2290
            if ($num_lines == 0) {
2291
                print '<tr><td colspan="13"><span class="opacitymedium">' . $langs->trans("NoRecordFound") . '</span></td></tr>';
2292
            }
2293
2294
            print '</table>';
2295
            print "</div>";
2296
2297
            print '</form>';
2298
        } else {
2299
            print $db->error();
2300
        }
2301
        if ($db->type == 'mysqli') {
2302
            $db->query("SET SQL_BIG_SELECTS=0"); // Enable MAX_JOIN_SIZE limitation
2303
        }
2304
2305
// Add code to auto check the box when we select an account
2306
        print '<script type="text/javascript">
2307
jQuery(document).ready(function() {
2308
	jQuery(".codeventil").change(function() {
2309
		var s=$(this).attr("id").replace("codeventil", "")
2310
		console.log(s+" "+$(this).val());
2311
		if ($(this).val() == -1) jQuery(".checkforselect"+s).prop("checked", false);
2312
		else jQuery(".checkforselect"+s).prop("checked", true);
2313
	});
2314
});
2315
</script>';
2316
2317
// End of page
2318
        llxFooter();
2319
        $db->close();
2320
    }
2321
}
2322