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