dolibarr  20.0.0-beta
card.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2020 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5  * Copyright (C) 2005-2018 Regis Houssin <regis.houssin@inodbox.com>
6  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
7  * Copyright (C) 2011-2014 Juanjo Menent <jmenent@2byte.es>
8  * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
9  * Copyright (C) 2023 Benjamin Falière <benjamin.faliere@altairis.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  */
24 
31 // Load Dolibarr environment
32 require '../../main.inc.php';
33 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
35 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
37 
38 // Load translation files required by the page
39 $langs->loadLangs(array('bills', 'products', 'stocks'));
40 
41 $id = GETPOSTINT('id');
42 $ref = GETPOST('ref', 'alpha');
43 $action = GETPOST('action', 'aZ09');
44 $confirm = GETPOST('confirm', 'alpha');
45 $cancel = GETPOST('cancel', 'alpha');
46 $key = GETPOST('key');
47 $parent = GETPOST('parent');
48 
49 // Security check
50 if (!empty($user->socid)) {
51  $socid = $user->socid;
52 }
53 $fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref : ''));
54 $fieldtype = (!empty($ref) ? 'ref' : 'rowid');
55 
56 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
57 $hookmanager->initHooks(array('productcompositioncard', 'globalcard'));
58 
59 $object = new Product($db);
60 $objectid = 0;
61 if ($id > 0 || !empty($ref)) {
62  $result = $object->fetch($id, $ref);
63  $objectid = $object->id;
64  $id = $object->id;
65 }
66 
67 $result = restrictedArea($user, 'produit|service', $fieldvalue, 'product&product', '', '', $fieldtype);
68 
69 if ($object->id > 0) {
70  if ($object->type == $object::TYPE_PRODUCT) {
71  restrictedArea($user, 'produit', $object->id, 'product&product', '', '');
72  }
73  if ($object->type == $object::TYPE_SERVICE) {
74  restrictedArea($user, 'service', $object->id, 'product&product', '', '');
75  }
76 } else {
77  restrictedArea($user, 'produit|service', $fieldvalue, 'product&product', '', '', $fieldtype);
78 }
79 $usercanread = (($object->type == Product::TYPE_PRODUCT && $user->hasRight('produit', 'lire')) || ($object->type == Product::TYPE_SERVICE && $user->hasRight('service', 'lire')));
80 $usercancreate = (($object->type == Product::TYPE_PRODUCT && $user->hasRight('produit', 'creer')) || ($object->type == Product::TYPE_SERVICE && $user->hasRight('service', 'creer')));
81 $usercandelete = (($object->type == Product::TYPE_PRODUCT && $user->hasRight('produit', 'supprimer')) || ($object->type == Product::TYPE_SERVICE && $user->hasRight('service', 'supprimer')));
82 
83 
84 /*
85  * Actions
86  */
87 
88 if ($cancel) {
89  $action = '';
90 }
91 
92 $reshook = $hookmanager->executeHooks('doActions', [], $object, $action); // Note that $action and $object may have been modified by some hooks
93 if ($reshook < 0) {
94  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
95 }
96 
97 if (empty($reshook)) {
98  // Add subproduct to product
99  if ($action == 'add_prod' && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
100  $error = 0;
101  $maxprod = GETPOSTINT("max_prod");
102 
103  for ($i = 0; $i < $maxprod; $i++) {
104  $qty = price2num(GETPOST("prod_qty_" . $i, 'alpha'), 'MS');
105  if ($qty > 0) {
106  if ($object->add_sousproduit($id, GETPOSTINT("prod_id_" . $i), $qty, GETPOSTINT("prod_incdec_" . $i)) > 0) {
107  //var_dump($i.' '.GETPOST("prod_id_".$i, 'int'), $qty, GETPOST("prod_incdec_".$i, 'int'));
108  $action = 'edit';
109  } else {
110  $error++;
111  $action = 're-edit';
112  if ($object->error == "isFatherOfThis") {
113  setEventMessages($langs->trans("ErrorAssociationIsFatherOfThis"), null, 'errors');
114  } else {
115  setEventMessages($object->error, $object->errors, 'errors');
116  }
117  }
118  } else {
119  if ($object->del_sousproduit($id, GETPOSTINT("prod_id_" . $i)) > 0) {
120  $action = 'edit';
121  } else {
122  $error++;
123  $action = 're-edit';
124  setEventMessages($object->error, $object->errors, 'errors');
125  }
126  }
127  }
128 
129  if (!$error) {
130  header("Location: " . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
131  exit;
132  }
133  } elseif ($action === 'save_composed_product') {
134  $TProduct = GETPOST('TProduct', 'array');
135  if (!empty($TProduct)) {
136  foreach ($TProduct as $id_product => $row) {
137  if ($row['qty'] > 0) {
138  $object->update_sousproduit($id, $id_product, $row['qty'], isset($row['incdec']) ? 1 : 0);
139  } else {
140  $object->del_sousproduit($id, $id_product);
141  }
142  }
143  setEventMessages('RecordSaved', null);
144  }
145  $action = '';
146  header("Location: " . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
147  exit;
148  }
149 }
150 
151 /*
152  * View
153  */
154 
155 $form = new Form($db);
156 $formproduct = new FormProduct($db);
157 $product_fourn = new ProductFournisseur($db);
158 $productstatic = new Product($db);
159 
160 // action recherche des produits par mot-cle et/ou par categorie
161 if ($action == 'search') {
162  $current_lang = $langs->getDefaultLang();
163 
164  $sql = 'SELECT DISTINCT p.rowid, p.ref, p.label, p.fk_product_type as type, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
165  $sql .= ' p.fk_product_type, p.tms as datem, p.tobatch';
166  $sql .= ', p.tosell as status, p.tobuy as status_buy';
167  if (getDolGlobalInt('MAIN_MULTILANGS')) {
168  $sql .= ', pl.label as labelm, pl.description as descriptionm';
169  }
170 
171  $parameters = array();
172  $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
173  $sql .= $hookmanager->resPrint;
174 
175  $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
176  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_product as cp ON p.rowid = cp.fk_product';
177  if (getDolGlobalInt('MAIN_MULTILANGS')) {
178  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND lang='".($current_lang)."'";
179  }
180  $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
181 
182  $parameters = array();
183  $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
184  $sql .= $hookmanager->resPrint;
185 
186  if ($key != "") {
187  // For natural search
188  $params = array('p.ref', 'p.label', 'p.description', 'p.note');
189  // multilang
190  if (getDolGlobalInt('MAIN_MULTILANGS')) {
191  $params[] = 'pl.label';
192  $params[] = 'pl.description';
193  $params[] = 'pl.note';
194  }
195  if (isModEnabled('barcode')) {
196  $params[] = 'p.barcode';
197  }
198  $sql .= natural_search($params, $key);
199  }
200  if (isModEnabled('category') && !empty($parent) && $parent != -1) {
201  $sql .= " AND cp.fk_categorie ='".$db->escape($parent)."'";
202  }
203  $sql .= " ORDER BY p.ref ASC";
204 
205  $resql = $db->query($sql);
206 }
207 
208 $title = $langs->trans('ProductServiceCard');
209 $help_url = '';
210 $shortlabel = dol_trunc($object->label, 16);
211 if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
212  $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('AssociatedProducts');
213  $help_url = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos|DE:Modul_Produkte';
214 }
215 if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
216  $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('AssociatedProducts');
217  $help_url = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios|DE:Modul_Leistungen';
218 }
219 
220 llxHeader('', $title, $help_url);
221 
223 
224 $titre = $langs->trans("CardProduct".$object->type);
225 $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
226 
227 print dol_get_fiche_head($head, 'subproduct', $titre, -1, $picto);
228 
229 
230 if ($id > 0 || !empty($ref)) {
231  /*
232  * Product card
233  */
234  if ($user->hasRight('produit', 'lire') || $user->hasRight('service', 'lire')) {
235  $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1&type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
236 
237  $shownav = 1;
238  if ($user->socid && !in_array('product', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
239  $shownav = 0;
240  }
241 
242  dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref', '');
243 
244  if ($object->type != Product::TYPE_SERVICE || getDolGlobalString('STOCK_SUPPORTS_SERVICES') || !getDolGlobalString('PRODUIT_MULTIPRICES')) {
245  print '<div class="fichecenter">';
246  print '<div class="fichehalfleft">';
247  print '<div class="underbanner clearboth"></div>';
248 
249  print '<table class="border centpercent tableforfield">';
250 
251  // Type
252  if (isModEnabled("product") && isModEnabled("service")) {
253  $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
254  print '<tr><td class="titlefield">';
255  print (!getDolGlobalString('PRODUCT_DENY_CHANGE_PRODUCT_TYPE')) ? $form->editfieldkey("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat) : $langs->trans('Type');
256  print '</td><td>';
257  print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat);
258  print '</td></tr>';
259  }
260 
261  print '</table>';
262 
263  print '</div><div class="fichehalfright">';
264  print '<div class="underbanner clearboth"></div>';
265 
266  print '<table class="border centpercent tableforfield">';
267 
268  // Nature
269  if ($object->type != Product::TYPE_SERVICE) {
270  if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) {
271  print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
272  print $object->getLibFinished();
273  //print $formproduct->selectProductNature('finished', $object->finished);
274  print '</td></tr>';
275  }
276  }
277 
278  if (!getDolGlobalString('PRODUIT_MULTIPRICES')) {
279  // Price
280  print '<tr><td class="titlefield">'.$langs->trans("SellingPrice").'</td><td>';
281  if ($object->price_base_type == 'TTC') {
282  print price($object->price_ttc).' '.$langs->trans($object->price_base_type);
283  } else {
284  print price($object->price).' '.$langs->trans($object->price_base_type ? $object->price_base_type : 'HT');
285  }
286  print '</td></tr>';
287 
288  // Price minimum
289  print '<tr><td>'.$langs->trans("MinPrice").'</td><td>';
290  if ($object->price_base_type == 'TTC') {
291  print price($object->price_min_ttc).' '.$langs->trans($object->price_base_type);
292  } else {
293  print price($object->price_min).' '.$langs->trans($object->price_base_type ? $object->price_base_type : 'HT');
294  }
295  print '</td></tr>';
296  }
297 
298  print '</table>';
299  print '</div>';
300  print '</div>';
301  }
302 
303  print dol_get_fiche_end();
304 
305 
306  print '<br><br>';
307 
308  $prodsfather = $object->getFather(); // Parent Products
309  $object->get_sousproduits_arbo(); // Load $object->sousprods
310  $parent_label = $object->label;
311  $prods_arbo = $object->get_arbo_each_prod();
312 
313  $tmpid = $id;
314  if (!empty($conf->use_javascript_ajax)) {
315  $nboflines = $prods_arbo;
316  $table_element_line='product_association';
317 
318  include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
319  }
320  $id = $tmpid;
321 
322  $nbofsubsubproducts = count($prods_arbo); // This include sub sub product into nb
323  $prodschild = $object->getChildsArbo($id, 1);
324  $nbofsubproducts = count($prodschild); // This include only first level of children
325 
326 
327  print '<div class="fichecenter">';
328 
329  print load_fiche_titre($langs->trans("ProductParentList"), '', '');
330 
331  print '<table class="liste">';
332  print '<tr class="liste_titre">';
333  print '<td>'.$langs->trans('ParentProducts').'</td>';
334  print '<td>'.$langs->trans('Label').'</td>';
335  print '<td class="right">'.$langs->trans('Qty').'</td>';
336  print '</td>';
337  if (count($prodsfather) > 0) {
338  foreach ($prodsfather as $value) {
339  $idprod = $value["id"];
340  $productstatic->id = $idprod; // $value["id"];
341  $productstatic->type = $value["fk_product_type"];
342  $productstatic->ref = $value['ref'];
343  $productstatic->label = $value['label'];
344  $productstatic->entity = $value['entity'];
345  $productstatic->status = $value['status'];
346  $productstatic->status_buy = $value['status_buy'];
347 
348  print '<tr class="oddeven">';
349  print '<td>'.$productstatic->getNomUrl(1, 'composition').'</td>';
350  print '<td>'.dol_escape_htmltag($productstatic->label).'</td>';
351  print '<td class="right">'.dol_escape_htmltag($value['qty']).'</td>';
352  print '</tr>';
353  }
354  } else {
355  print '<tr class="oddeven">';
356  print '<td colspan="3"><span class="opacitymedium">'.$langs->trans("None").'</span></td>';
357  print '</tr>';
358  }
359  print '</table>';
360  print '</div>';
361 
362  print '<br>'."\n";
363 
364 
365  print '<div class="fichecenter">';
366 
367  $atleastonenotdefined = 0;
368  print load_fiche_titre($langs->trans("ProductAssociationList"), '', '');
369 
370  print '<form name="formComposedProduct" action="'.$_SERVER['PHP_SELF'].'" method="post">';
371  print '<input type="hidden" name="token" value="'.newToken().'" />';
372  print '<input type="hidden" name="action" value="save_composed_product" />';
373  print '<input type="hidden" name="id" value="'.$id.'" />';
374 
375  print '<table id="tablelines" class="ui-sortable liste nobottom">';
376 
377  print '<tr class="liste_titre nodrag nodrop">';
378  // Rank
379  print '<td>'.$langs->trans('Position').'</td>';
380  // Product ref
381  print '<td>'.$langs->trans('ComposedProduct').'</td>';
382  // Product label
383  print '<td>'.$langs->trans('Label').'</td>';
384  // Min supplier price
385  print '<td class="right" colspan="2">'.$langs->trans('MinSupplierPrice').'</td>';
386  // Min customer price
387  print '<td class="right" colspan="2">'.$langs->trans('MinCustomerPrice').'</td>';
388  // Stock
389  if (isModEnabled('stock')) {
390  print '<td class="right">'.$langs->trans('Stock').'</td>';
391  }
392  // Hook fields
393  $parameters = array();
394  $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
395  print $hookmanager->resPrint;
396  // Qty in kit
397  print '<td class="right">'.$langs->trans('Qty').'</td>';
398  // Stoc inc/dev
399  print '<td class="center">'.$langs->trans('ComposedProductIncDecStock').'</td>';
400  // Move
401  print '<td class="linecolmove" style="width: 10px"></td>';
402  print '</tr>'."\n";
403 
404  $totalsell = 0;
405  $total = 0;
406  if (count($prods_arbo)) {
407  foreach ($prods_arbo as $value) {
408  $productstatic->fetch($value['id']);
409 
410  if ($value['level'] <= 1) {
411  print '<tr id="'.$object->sousprods[$parent_label][$value['id']][6].'" class="drag drop oddeven level1">';
412 
413  // Rank
414  print '<td>'.$object->sousprods[$parent_label][$value['id']][7].'</td>';
415 
416  $notdefined = 0;
417  $nb_of_subproduct = $value['nb'];
418 
419  // Product ref
420  print '<td>'.$productstatic->getNomUrl(1, 'composition').'</td>';
421 
422  // Product label
423  print '<td title="'.dol_escape_htmltag($productstatic->label).'" class="tdoverflowmax150">'.dol_escape_htmltag($productstatic->label).'</td>';
424 
425  // Best buying price
426  print '<td class="right">';
427  if ($product_fourn->find_min_price_product_fournisseur($productstatic->id) > 0) {
428  print $langs->trans("BuyingPriceMinShort").': ';
429  if ($product_fourn->product_fourn_price_id > 0) {
430  print $product_fourn->display_price_product_fournisseur(0, 0);
431  } else {
432  print $langs->trans("NotDefined");
433  $notdefined++;
434  $atleastonenotdefined++;
435  }
436  }
437  print '</td>';
438 
439  // For avoid a non-numeric value
440  $fourn_unitprice = (!empty($product_fourn->fourn_unitprice) ? $product_fourn->fourn_unitprice : 0);
441  $fourn_remise_percent = (!empty($product_fourn->fourn_remise_percent) ? $product_fourn->fourn_remise_percent : 0);
442  $fourn_remise = (!empty($product_fourn->fourn_remise) ? $product_fourn->fourn_remise : 0);
443 
444  $unitline = price2num(($fourn_unitprice * (1 - ($fourn_remise_percent / 100)) - $fourn_remise), 'MU');
445  $totalline = price2num($value['nb'] * ($fourn_unitprice * (1 - ($fourn_remise_percent / 100)) - $fourn_remise), 'MT');
446  $total += $totalline;
447 
448  print '<td class="right nowraponall">';
449  print($notdefined ? '' : ($value['nb'] > 1 ? $value['nb'].'x ' : '').'<span class="amount">'.price($unitline, 0, '', 0, 0, -1, $conf->currency)).'</span>';
450  print '</td>';
451 
452  // Best selling price
453  $pricesell = $productstatic->price;
454  if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
455  $pricesell = 'Variable';
456  } else {
457  $totallinesell = price2num($value['nb'] * ($pricesell), 'MT');
458  $totalsell += $totallinesell;
459  }
460  print '<td class="right" colspan="2">';
461  print($notdefined ? '' : ($value['nb'] > 1 ? $value['nb'].'x ' : ''));
462  if (is_numeric($pricesell)) {
463  print '<span class="amount">'.price($pricesell, 0, '', 0, 0, -1, $conf->currency).'</span>';
464  } else {
465  print '<span class="opacitymedium">'.$langs->trans($pricesell).'</span>';
466  }
467  print '</td>';
468 
469  // Stock
470  if (isModEnabled('stock')) {
471  print '<td class="right">'.$value['stock'].'</td>'; // Real stock
472  }
473 
474  // Hook fields
475  $parameters = array();
476  $reshook=$hookmanager->executeHooks('printFieldListValue', $parameters, $productstatic); // Note that $action and $object may have been modified by hook
477  print $hookmanager->resPrint;
478 
479  // Qty + IncDec
480  if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) {
481  print '<td class="center"><input type="text" value="'.$nb_of_subproduct.'" name="TProduct['.$productstatic->id.'][qty]" class="right width40" /></td>';
482  print '<td class="center"><input type="checkbox" name="TProduct['.$productstatic->id.'][incdec]" value="1" '.($value['incdec'] == 1 ? 'checked' : '').' /></td>';
483  } else {
484  print '<td>'.$nb_of_subproduct.'</td>';
485  print '<td>'.($value['incdec'] == 1 ? 'x' : '').'</td>';
486  }
487 
488  // Move action
489  print '<td class="linecolmove tdlineupdown center"></td>';
490 
491  print '</tr>'."\n";
492  } else {
493  $hide = '';
494  if (!getDolGlobalString('PRODUCT_SHOW_SUB_SUB_PRODUCTS')) {
495  $hide = ' hideobject'; // By default, we do not show this. It makes screen very difficult to understand
496  }
497 
498  print '<tr class="oddeven'.$hide.'" id="sub-'.$value['id_parent'].'" data-ignoreidfordnd=1>';
499 
500  //$productstatic->ref=$value['label'];
501  $productstatic->ref = $value['ref'];
502 
503  // Rankd
504  print '<td></td>';
505 
506  // Product ref
507  print '<td>';
508  for ($i = 0; $i < $value['level']; $i++) {
509  print ' &nbsp; &nbsp; '; // Add indentation
510  }
511  print $productstatic->getNomUrl(1, 'composition');
512  print '</td>';
513 
514  // Product label
515  print '<td>'.dol_escape_htmltag($productstatic->label).'</td>';
516 
517  // Best buying price
518  print '<td>&nbsp;</td>';
519  print '<td>&nbsp;</td>';
520  // Best selling price
521  print '<td>&nbsp;</td>';
522  print '<td>&nbsp;</td>';
523 
524  // Stock
525  if (isModEnabled('stock')) {
526  print '<td></td>'; // Real stock
527  }
528 
529  // Hook fields
530  $parameters = array();
531  $reshook=$hookmanager->executeHooks('printFieldListValue', $parameters, $productstatic); // Note that $action and $object may have been modified by hook
532  print $hookmanager->resPrint;
533 
534  // Qty in kit
535  print '<td class="right">'.dol_escape_htmltag($value['nb']).'</td>';
536 
537  // Inc/dec
538  print '<td>&nbsp;</td>';
539 
540  // Action move
541  print '<td>&nbsp;</td>';
542 
543  print '</tr>'."\n";
544  }
545  }
546 
547 
548  // Total
549 
550  print '<tr class="liste_total">';
551 
552  // Rank
553  print '<td></td>';
554 
555  // Product ref
556  print '<td class="liste_total"></td>';
557 
558  // Product label
559  print '<td class="liste_total"></td>';
560 
561  // Minimum buying price
562  print '<td class="liste_total right">';
563  print $langs->trans("TotalBuyingPriceMinShort");
564  print '</td>';
565 
566  print '<td class="liste_total right">';
567  if ($atleastonenotdefined) {
568  print $langs->trans("Unknown").' ('.$langs->trans("SomeSubProductHaveNoPrices").')';
569  }
570  print($atleastonenotdefined ? '' : price($total, 0, '', 0, 0, -1, $conf->currency));
571  print '</td>';
572 
573  // Minimum selling price
574  print '<td class="liste_total right">';
575  print $langs->trans("TotalSellingPriceMinShort");
576  print '</td>';
577 
578  print '<td class="liste_total right">';
579  if ($atleastonenotdefined) {
580  print $langs->trans("Unknown").' ('.$langs->trans("SomeSubProductHaveNoPrices").')';
581  }
582  print($atleastonenotdefined ? '' : price($totalsell, 0, '', 0, 0, -1, $conf->currency));
583  print '</td>';
584 
585  // Stock
586  if (isModEnabled('stock')) {
587  print '<td class="liste_total right">&nbsp;</td>';
588  }
589 
590  print '<td></td>';
591 
592  print '<td class="center">';
593  if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) {
594  print '<input type="submit" class="button button-save" value="'.$langs->trans("Save").'">';
595  }
596  print '</td>';
597 
598  print '<td></td>';
599 
600  print '</tr>'."\n";
601  } else {
602  $colspan = 10;
603  if (isModEnabled('stock')) {
604  $colspan++;
605  }
606 
607  print '<tr class="oddeven">';
608  print '<td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("None").'</span></td>';
609  print '</tr>';
610  }
611 
612  print '</table>';
613 
614  /*if($user->rights->produit->creer || $user->hasRight('service', 'creer')) {
615  print '<input type="submit" class="button button-save" value="'.$langs->trans("Save").'">';
616  }*/
617 
618  print '</form>';
619  print '</div>';
620 
621 
622 
623  // Form with product to add
624  if ((empty($action) || $action == 'view' || $action == 'edit' || $action == 'search' || $action == 're-edit') && ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer'))) {
625  print '<br>';
626 
627  $rowspan = 1;
628  if (isModEnabled('category')) {
629  $rowspan++;
630  }
631 
632  print load_fiche_titre($langs->trans("ProductToAddSearch"), '', '');
633  print '<form action="'.DOL_URL_ROOT.'/product/composition/card.php?id='.$id.'" method="POST">';
634  print '<input type="hidden" name="action" value="search">';
635  print '<input type="hidden" name="id" value="'.$id.'">';
636  print '<div class="inline-block">';
637  print '<input type="hidden" name="token" value="'.newToken().'">';
638  print $langs->trans("KeywordFilter").': ';
639  print '<input type="text" name="key" value="'.$key.'"> &nbsp; ';
640  print '</div>';
641  if (isModEnabled('category')) {
642  require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
643  print '<div class="inline-block">'.$langs->trans("CategoryFilter").': ';
644  print $form->select_all_categories(Categorie::TYPE_PRODUCT, $parent, 'parent').' &nbsp; </div>';
645  print ajax_combobox('parent');
646  }
647  print '<div class="inline-block">';
648  print '<input type="submit" class="button small" value="'.$langs->trans("Search").'">';
649  print '</div>';
650  print '</form>';
651  }
652 
653 
654  // List of products
655  if ($action == 'search') {
656  print '<br>';
657  print '<form action="'.DOL_URL_ROOT.'/product/composition/card.php?id='.$id.'" method="post">';
658  print '<input type="hidden" name="token" value="'.newToken().'">';
659  print '<input type="hidden" name="action" value="add_prod">';
660  print '<input type="hidden" name="id" value="'.$id.'">';
661 
662  print '<table class="noborder centpercent">';
663  print '<tr class="liste_titre">';
664  print '<th class="liste_titre">'.$langs->trans("ComposedProduct").'</td>';
665  print '<th class="liste_titre">'.$langs->trans("Label").'</td>';
666  //print '<th class="liste_titre center">'.$langs->trans("IsInPackage").'</td>';
667  print '<th class="liste_titre right">'.$langs->trans("Qty").'</td>';
668  print '<th class="center">'.$langs->trans('ComposedProductIncDecStock').'</th>';
669  print '</tr>';
670  if ($resql) {
671  $num = $db->num_rows($resql);
672  $i = 0;
673 
674  if ($num == 0) {
675  print '<tr><td colspan="4">'.$langs->trans("NoMatchFound").'</td></tr>';
676  }
677 
678  $MAX = 100;
679 
680  while ($i < min($num, $MAX)) {
681  $objp = $db->fetch_object($resql);
682  if ($objp->rowid != $id) {
683  // check if a product is not already a parent product of this one
684  $prod_arbo = new Product($db);
685  $prod_arbo->id = $objp->rowid;
686  // This type is not supported (not required to have virtual products working).
687  if (getDolGlobalString('PRODUCT_USE_DEPRECATED_ASSEMBLY_AND_STOCK_KIT_TYPE')) {
688  if ($prod_arbo->type == 2 || $prod_arbo->type == 3) {
689  $is_pere = 0;
690  $prod_arbo->get_sousproduits_arbo();
691  // associations sousproduits
692  $prods_arbo = $prod_arbo->get_arbo_each_prod();
693  if (count($prods_arbo) > 0) {
694  foreach ($prods_arbo as $key => $value) {
695  if ($value[1] == $id) {
696  $is_pere = 1;
697  }
698  }
699  }
700  if ($is_pere == 1) {
701  $i++;
702  continue;
703  }
704  }
705  }
706 
707  print "\n";
708  print '<tr class="oddeven">';
709 
710  $productstatic->id = $objp->rowid;
711  $productstatic->ref = $objp->ref;
712  $productstatic->label = $objp->label;
713  $productstatic->type = $objp->type;
714  $productstatic->entity = $objp->entity;
715  $productstatic->status = $objp->status;
716  $productstatic->status_buy = $objp->status_buy;
717  $productstatic->status_batch = $objp->tobatch;
718 
719  print '<td>'.$productstatic->getNomUrl(1, '', 24).'</td>';
720  $labeltoshow = $objp->label;
721  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($objp->labelm)) {
722  $labeltoshow = $objp->labelm;
723  }
724 
725  print '<td>'.$labeltoshow.'</td>';
726 
727 
728  if ($object->is_sousproduit($id, $objp->rowid)) {
729  //$addchecked = ' checked';
730  $qty = $object->is_sousproduit_qty;
731  $incdec = $object->is_sousproduit_incdec;
732  } else {
733  //$addchecked = '';
734  $qty = 0;
735  $incdec = 0;
736  }
737  // Contained into package
738  /*print '<td class="center"><input type="hidden" name="prod_id_'.$i.'" value="'.$objp->rowid.'">';
739  print '<input type="checkbox" '.$addchecked.'name="prod_id_chk'.$i.'" value="'.$objp->rowid.'"></td>';*/
740  // Qty
741  print '<td class="right"><input type="hidden" name="prod_id_'.$i.'" value="'.$objp->rowid.'"><input type="text" size="2" name="prod_qty_'.$i.'" value="'.($qty ? $qty : '').'"></td>';
742 
743  // Inc Dec
744  print '<td class="center">';
745  if ($qty) {
746  print '<input type="checkbox" name="prod_incdec_'.$i.'" value="1" '.($incdec ? 'checked' : '').'>';
747  } else {
748  // TODO Hide field and show it when setting a qty
749  print '<input type="checkbox" name="prod_incdec_'.$i.'" value="1" checked>';
750  //print '<input type="checkbox" disabled name="prod_incdec_'.$i.'" value="1" checked>';
751  }
752  print '</td>';
753 
754  print '</tr>';
755  }
756  $i++;
757  }
758  if ($num > $MAX) {
759  print '<tr class="oddeven">';
760  print '<td><span class="opacitymedium">'.$langs->trans("More").'...</span></td>';
761  print '<td></td>';
762  print '<td></td>';
763  print '<td></td>';
764  print '</tr>';
765  }
766  } else {
767  dol_print_error($db);
768  }
769  print '</table>';
770  print '<input type="hidden" name="max_prod" value="'.$i.'">';
771 
772  if ($num > 0) {
773  print '<div class="center">';
774  print '<input type="submit" class="button button-save" name="save" value="'.$langs->trans("Add").'/'.$langs->trans("Update").'">';
775  print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
776  print '</div>';
777  }
778 
779  print '</form>';
780  }
781  }
782 }
783 
784 // End of page
785 llxFooter();
786 $db->close();
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:456
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:55
llxFooter()
Empty footer.
Definition: wrapper.php:69
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
$parameters
Actions.
Definition: card.php:84
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
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)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
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.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
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.
Definition: product.lib.php:37
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.