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