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