dolibarr 23.0.3
facture.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2014 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2014 Florian Henry <florian.henry@open-concept.pro>
7 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
29// Load Dolibarr environment
30require '../../main.inc.php';
31require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
32require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
33require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
35
44// Load translation files required by the page
45$langs->loadLangs(array('companies', 'bills', 'products', 'supplier_proposal'));
46
47$action = GETPOST('action', 'aZ');
48
49$id = GETPOSTINT('id');
50$ref = GETPOST('ref', 'alpha');
51
52// Security check
53$fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref : ''));
54$fieldtype = (!empty($ref) ? 'ref' : 'rowid');
55$socid = '';
56if (!empty($user->socid)) {
57 $socid = $user->socid;
58}
59
60// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
61$hookmanager->initHooks(array('productstatsinvoice'));
62$extrafields = new ExtraFields($db);
63
64// Fetch optionals attributes and labels
65$extrafields->fetch_name_optionals_label('facture');
66
67$search_array_options = $extrafields->getOptionalsFromPost('facture', '', 'search_');
68
69$showmessage = GETPOST('showmessage');
70
71// Load variable for pagination
72$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
73$sortfield = GETPOST('sortfield', 'aZ09comma');
74$sortorder = GETPOST('sortorder', 'aZ09comma');
75$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
76if (empty($page) || $page == -1) {
77 $page = 0;
78} // If $page is not defined, or '' or -1
79$offset = $limit * $page;
80$pageprev = $page - 1;
81$pagenext = $page + 1;
82if (!$sortorder) {
83 $sortorder = "DESC";
84}
85if (!$sortfield) {
86 $sortfield = "f.datef";
87}
88
89$option = '';
90
91$search_date_startday = GETPOSTINT('search_date_startday');
92if (!empty($search_date_startday)) {
93 $option .= '&search_date_startday='.$search_date_startday;
94}
95$search_date_startmonth = GETPOSTINT('search_date_startmonth');
96if (!empty($search_date_startmonth)) {
97 $option .= '&search_date_startmonth='.$search_date_startmonth;
98}
99$search_date_startyear = GETPOSTINT('search_date_startyear');
100if (!empty($search_date_startyear)) {
101 $option .= '&search_date_startyear='.$search_date_startyear;
102}
103$search_date_endday = GETPOSTINT('search_date_endday');
104if (!empty($search_date_endday)) {
105 $option .= '&search_date_endday='.$search_date_endday;
106}
107$search_date_endmonth = GETPOSTINT('search_date_endmonth');
108if (!empty($search_date_endmonth)) {
109 $option .= '&search_date_endmonth='.$search_date_endmonth;
110}
111$search_date_endyear = GETPOSTINT('search_date_endyear');
112if (!empty($search_date_endyear)) {
113 $option .= '&search_date_endyear='.$search_date_endyear;
114}
115$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear); // Use tzserver
116$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear);
117
118if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter', 'alpha')) {
119 $search_date_startday = '';
120 $search_date_startmonth = '';
121 $search_date_startyear = '';
122 $search_date_endday = '';
123 $search_date_endmonth = '';
124 $search_date_endyear = '';
125 $search_date_start = '';
126 $search_date_end = '';
127}
128
129$result = restrictedArea($user, 'produit|service', $fieldvalue, 'product&product', '', '', $fieldtype);
130
131
132/*
133 * View
134 */
135
136$invoicestatic = new Facture($db);
137$societestatic = new Societe($db);
138
139$form = new Form($db);
140$formother = new FormOther($db);
141
142if ($id > 0 || !empty($ref)) {
143 $product = new Product($db);
144 $result = $product->fetch($id, $ref);
145
146 $object = $product;
147
148 $parameters = array('id' => $id);
149 $reshook = $hookmanager->executeHooks('doActions', $parameters, $product, $action); // Note that $action and $object may have been modified by some hooks
150 if ($reshook < 0) {
151 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
152 }
153
154 $title = $langs->trans('ProductServiceCard');
155 $helpurl = '';
156 $shortlabel = dol_trunc($object->label, 16);
157 if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
158 $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('Referers');
159 $helpurl = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
160 }
161 if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
162 $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('Referers');
163 $helpurl = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
164 }
165
166 llxHeader('', $title, $helpurl, '', 0, 0, '', '', '', 'mod-product page-stats_facture');
167
168 if ($result > 0) {
169 $head = product_prepare_head($product);
170 $titre = $langs->trans("CardProduct".$product->type);
171 $picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product');
172 print dol_get_fiche_head($head, 'referers', $titre, -1, $picto);
173
174 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook
175 print $hookmanager->resPrint;
176 if ($reshook < 0) {
177 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
178 }
179
180 $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1&type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
181 $object->next_prev_filter = "(te.fk_product_type:=:".((int) $object->type).")";
182
183 $shownav = 1;
184 if ($user->socid && !in_array('product', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
185 $shownav = 0;
186 }
187
188 dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
189
190 print '<div class="fichecenter">';
191
192 print '<div class="underbanner clearboth"></div>';
193 print '<table class="border tableforfield centpercent">';
194
195 $nboflines = show_stats_for_company($product, $socid);
196
197 print "</table>";
198
199 print '</div>';
200 print '<div class="clearboth"></div>';
201
202 print dol_get_fiche_end();
203
204 if ($showmessage && $nboflines > 1) {
205 print '<span class="opacitymedium">'.$langs->trans("ClinkOnALinkOfColumn", $langs->transnoentitiesnoconv("Referers")).'</span>';
206 } elseif ($user->hasRight('facture', 'lire')) {
207 $sql = "SELECT DISTINCT s.nom as name, s.rowid as socid, s.code_client,";
208 $sql .= " f.ref, f.datef, f.paye, f.type, f.fk_statut as statut, f.rowid as facid,";
209 $sql .= " d.rowid, d.total_ht as total_ht, d.qty"; // We must keep the d.rowid here to not loose record because of the distinct used to ignore duplicate line when link on societe_commerciaux is used
210 if (!$user->hasRight('societe', 'client', 'voir')) {
211 $sql .= ", sc.fk_soc, sc.fk_user ";
212 }
213 // Add fields from extrafields
214 if (!empty($extrafields->attributes['facture']['label'])) {
215 foreach ($extrafields->attributes['facture']['label'] as $key => $val) {
216 $sql .= ($extrafields->attributes['facture']['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
217 }
218 }
219 // Add fields from hooks
220 $parameters = array();
221 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
222 $sql .= $hookmanager->resPrint;
223 $sql = preg_replace('/,\s*$/', '', $sql);
224
225 $sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
226 $sql .= ", ".MAIN_DB_PREFIX."facture as f";
227 if (isset($extrafields->attributes['facture']['label']) && is_array($extrafields->attributes['facture']['label']) && count($extrafields->attributes['facture']['label'])) {
228 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.'facture'."_extrafields as ef on (f.rowid = ef.fk_object)";
229 }
230 $sql .= ", ".MAIN_DB_PREFIX."facturedet as d";
231 if (!$user->hasRight('societe', 'client', 'voir')) {
232 $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
233 }
234 // Add table from hooks
235 $parameters = array();
236 $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook
237 $sql .= $hookmanager->resPrint;
238
239 $sql .= " WHERE f.fk_soc = s.rowid";
240 $sql .= " AND f.entity IN (".getEntity('invoice').")";
241 $sql .= " AND d.fk_facture = f.rowid";
242 $sql .= " AND d.fk_product = ".((int) $product->id);
243 if ($search_date_start) {
244 $sql .= " AND f.datef >= '".$db->idate($search_date_start)."'";
245 }
246 if ($search_date_end) {
247 $sql .= " AND f.datef <= '".$db->idate($search_date_end)."'";
248 }
249 if (!$user->hasRight('societe', 'client', 'voir')) {
250 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
251 }
252 if ($socid) {
253 $sql .= " AND f.fk_soc = ".((int) $socid);
254 }
255 // Add where from extra fields
256 $extrafieldsobjectkey = 'facture';
257 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
258 // Add where from hooks
259 $parameters = array();
260 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
261 $sql .= $hookmanager->resPrint;
262
263 // Add HAVING from hooks
264 $parameters = array();
265 $reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
266 if (empty($reshook)) {
267 $sql .= empty($hookmanager->resPrint) ? "" : " HAVING 1=1 ".$hookmanager->resPrint;
268 } else {
269 $sql = $hookmanager->resPrint;
270 }
271
272 $sql .= $db->order($sortfield, $sortorder);
273
274 // Calcul total qty and amount for global if full scan list
275 $total_ht = 0;
276 $total_qty = 0;
277
278 // Count total nb of records
279 $totalofrecords = '';
280 if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
281 $result = $db->query($sql);
282 $totalofrecords = $db->num_rows($result);
283 }
284
285 $sql .= $db->plimit($limit + 1, $offset);
286
287 $result = $db->query($sql);
288 if ($result) {
289 $num = $db->num_rows($result);
290
291 $option .= '&id='.$product->id;
292
293 if ($limit > 0 && $limit != $conf->liste_limit) {
294 $option .= '&limit='.((int) $limit);
295 }
296
297 // Add $param from extra fields
298 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
299 // Add $param from hooks
300 $parameters = array('param' => &$param);
301 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
302 $option .= $hookmanager->resPrint;
303
304 print '<form method="post" action="'.$_SERVER ['PHP_SELF'].'?id='.$product->id.'" name="search_form">'."\n";
305 print '<input type="hidden" name="token" value="'.newToken().'">';
306 if (!empty($sortfield)) {
307 print '<input type="hidden" name="sortfield" value="'.$sortfield.'"/>';
308 }
309 if (!empty($sortorder)) {
310 print '<input type="hidden" name="sortorder" value="'.$sortorder.'"/>';
311 }
312
313 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
314 print_barre_liste($langs->trans("CustomersInvoices"), $page, $_SERVER["PHP_SELF"], $option, $sortfield, $sortorder, '', $num, $totalofrecords, '', 0, '', '', $limit, 0, 0, 1);
315
316 if (!empty($page)) {
317 $option .= '&page='.urlencode((string) ($page));
318 }
319
320 print '<div class="liste_titre liste_titre_bydiv centpercent">';
321 print '<div class="divsearchfield">';
322 print $langs->trans('Period').' ('.$langs->trans("DateInvoice").') - ';
323 print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
324 print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
325 $parameters = array();
326 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
327 print $hookmanager->resPrint;
328
329 print '<div style="vertical-align: middle; display: inline-block">';
330 print '<input type="image" class="liste_titre" name="button_search" src="'.img_picto($langs->trans("Search"), 'search.png', '', 0, 1).'" value="'.dol_escape_htmltag($langs->trans("Search")).'" title="'.dol_escape_htmltag($langs->trans("Search")).'">';
331 print '<input type="image" class="liste_titre" name="button_removefilter" src="'.img_picto($langs->trans("Search"), 'searchclear.png', '', 0, 1).'" value="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'" title="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'">';
332 print '</div>';
333 print '</div>';
334 print '</div>';
335
336 $i = 0;
337 print '<div class="div-table-responsive">';
338 print '<table class="tagtable liste listwithfilterbefore" width="100%">';
339 print '<tr class="liste_titre">';
340 print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "s.rowid", "", $option, '', $sortfield, $sortorder);
341 print_liste_field_titre("Company", $_SERVER["PHP_SELF"], "s.nom", "", $option, '', $sortfield, $sortorder);
342 print_liste_field_titre("CustomerCode", $_SERVER["PHP_SELF"], "s.code_client", "", $option, '', $sortfield, $sortorder);
343 print_liste_field_titre("DateInvoice", $_SERVER["PHP_SELF"], "f.datef", "", $option, 'align="center"', $sortfield, $sortorder);
344 print_liste_field_titre("Qty", $_SERVER["PHP_SELF"], "d.qty", "", $option, 'align="center"', $sortfield, $sortorder);
345 print_liste_field_titre("AmountHT", $_SERVER["PHP_SELF"], "d.total_ht", "", $option, 'align="right"', $sortfield, $sortorder);
346 print_liste_field_titre("Status", $_SERVER["PHP_SELF"], "f.paye,f.fk_statut", "", $option, 'align="right"', $sortfield, $sortorder);
347 // Hook fields
348 $parameters = array('param' => $option, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
349 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
350 print $hookmanager->resPrint;
351 print "</tr>\n";
352
353 if ($num > 0) {
354 while ($i < min($num, $limit)) {
355 $objp = $db->fetch_object($result);
356
357 if ($objp->type == Facture::TYPE_CREDIT_NOTE) {
358 $objp->qty = -($objp->qty);
359 }
360
361 $total_ht += $objp->total_ht;
362 $total_qty += $objp->qty;
363
364 $invoicestatic->id = $objp->facid;
365 $invoicestatic->ref = $objp->ref;
366 $societestatic->fetch($objp->socid);
367 $paiement = $invoicestatic->getSommePaiement();
368
369 print '<tr class="oddeven">';
370 print '<td>';
371 print $invoicestatic->getNomUrl(1);
372 print "</td>\n";
373 print '<td>'.$societestatic->getNomUrl(1).'</td>';
374 print "<td>".$objp->code_client."</td>\n";
375 print '<td class="center">';
376 print dol_print_date($db->jdate($objp->datef), 'dayhour')."</td>";
377 print '<td class="center">'.$objp->qty."</td>\n";
378 print '<td class="right">'.price($objp->total_ht)."</td>\n";
379 print '<td class="right">'.$invoicestatic->LibStatut($objp->paye, $objp->statut, 5, $paiement, $objp->type).'</td>';
380 // Fields from hook
381 $parameters = array();
382 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
383 print $hookmanager->resPrint;
384 print "</tr>\n";
385 $i++;
386 }
387 }
388 print '<tr class="liste_total">';
389 if ($num < $limit && empty($offset)) {
390 print '<td>'.$langs->trans("Total").'</td>';
391 } else {
392 print '<td>'.$form->textwithpicto($langs->trans("Total"), $langs->trans("Totalforthispage")).'</td>';
393 }
394 print '<td colspan="3"></td>';
395 print '<td class="center">'.$total_qty.'</td>';
396 print '<td class="right">'.price($total_ht).'</td>';
397 print '<td></td>';
398 print "</table>";
399 print '</div>';
400 print '</form>';
401 } else {
402 dol_print_error($db);
403 }
404 $db->free($result);
405 }
406 }
407} else {
409}
410
411// End of page
412llxFooter();
413$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to manage standard extra fields.
Class to manage invoices.
const TYPE_CREDIT_NOTE
Credit note invoice.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are here.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage third parties objects (customers, suppliers, prospects...)
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $selectlimitsuffix=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
product_prepare_head($object)
Prepare array with list of tabs.
show_stats_for_company($product, $socid)
Show stats for a product.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.