30 require
'../../main.inc.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';
37 $langs->loadLangs(array(
'bills',
'products',
'stocks'));
41 $action =
GETPOST(
'action',
'aZ09');
42 $confirm =
GETPOST(
'confirm',
'alpha');
43 $cancel =
GETPOST(
'cancel',
'alpha');
48 if (!empty($user->socid)) $socid = $user->socid;
49 $fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref :
''));
50 $fieldtype = (!empty($ref) ?
'ref' :
'rowid');
51 $result =
restrictedArea($user,
'produit|service', $fieldvalue,
'product&product',
'',
'', $fieldtype);
55 if ($id > 0 || !empty($ref))
57 $result = $object->fetch($id, $ref);
58 $objectid = $object->id;
67 if ($cancel) $action =
'';
70 if ($action ==
'add_prod' && ($user->rights->produit->creer || $user->rights->service->creer))
73 $maxprod =
GETPOST(
"max_prod",
'int');
75 for ($i = 0; $i < $maxprod; $i++)
80 if ($object->add_sousproduit($id,
GETPOST(
"prod_id_".$i,
'int'), $qty,
GETPOST(
"prod_incdec_".$i,
'int')) > 0)
87 if ($object->error ==
"isFatherOfThis") {
88 setEventMessages($langs->trans(
"ErrorAssociationIsFatherOfThis"), null,
'errors');
94 if ($object->del_sousproduit($id,
GETPOST(
"prod_id_".$i,
'int')) > 0)
107 header(
"Location: ".
$_SERVER[
"PHP_SELF"].
'?id='.$object->id);
110 } elseif ($action ===
'save_composed_product')
112 $TProduct =
GETPOST(
'TProduct',
'array');
113 if (!empty($TProduct))
115 foreach ($TProduct as $id_product => $row)
117 if ($row[
'qty'] > 0) $object->update_sousproduit($id, $id_product, $row[
'qty'], isset($row[
'incdec']) ? 1 : 0);
118 else $object->del_sousproduit($id, $id_product);
131 $productstatic =
new Product($db);
132 $form =
new Form($db);
135 if ($action ==
'search')
137 $current_lang = $langs->getDefaultLang();
139 $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,';
140 $sql .=
' p.fk_product_type, p.tms as datem, p.tobatch';
141 if (!empty($conf->global->MAIN_MULTILANGS)) $sql .=
', pl.label as labelm, pl.description as descriptionm';
142 $sql .=
' FROM '.MAIN_DB_PREFIX.
'product as p';
143 $sql .=
' LEFT JOIN '.MAIN_DB_PREFIX.
'categorie_product as cp ON p.rowid = cp.fk_product';
144 if (!empty($conf->global->MAIN_MULTILANGS)) $sql .=
" LEFT JOIN ".MAIN_DB_PREFIX.
"product_lang as pl ON pl.fk_product = p.rowid AND lang='".($current_lang).
"'";
145 $sql .=
' WHERE p.entity IN ('.getEntity(
'product').
')';
149 $params = array(
'p.ref',
'p.label',
'p.description',
'p.note');
151 if (!empty($conf->global->MAIN_MULTILANGS))
153 $params[] =
'pl.label';
154 $params[] =
'pl.description';
155 $params[] =
'pl.note';
157 if (!empty($conf->barcode->enabled)) {
158 $params[] =
'p.barcode';
162 if (!empty($conf->categorie->enabled) && !empty($parent) && $parent != -1)
164 $sql .=
" AND cp.fk_categorie ='".$db->escape($parent).
"'";
166 $sql .=
" ORDER BY p.ref ASC";
168 $resql = $db->query($sql);
171 $title = $langs->trans(
'ProductServiceCard');
173 $shortlabel =
dol_trunc($object->label, 16);
176 $title = $langs->trans(
'Product').
" ".$shortlabel.
" - ".$langs->trans(
'AssociatedProducts');
177 $helpurl =
'EN:Module_Products|FR:Module_Produits|ES:Módulo_Productos';
181 $title = $langs->trans(
'Service').
" ".$shortlabel.
" - ".$langs->trans(
'AssociatedProducts');
182 $helpurl =
'EN:Module_Services_En|FR:Module_Services|ES:Módulo_Servicios';
188 $titre = $langs->trans(
"CardProduct".$object->type);
193 if ($id > 0 || !empty($ref))
198 if ($user->rights->produit->lire || $user->rights->service->lire)
200 $linkback =
'<a href="'.DOL_URL_ROOT.
'/product/list.php?restore_lastsearch_values=1">'.$langs->trans(
"BackToList").
'</a>';
203 if ($user->socid && !in_array(
'product', explode(
',', $conf->global->MAIN_MODULES_FOR_EXTERNAL))) $shownav = 0;
205 dol_banner_tab($object,
'ref', $linkback, $shownav,
'ref',
'',
'',
'', 0,
'',
'', 0);
207 if ($object->type !=
Product::TYPE_SERVICE || !empty($conf->global->STOCK_SUPPORTS_SERVICES) || empty($conf->global->PRODUIT_MULTIPRICES))
209 print '<div class="fichecenter">';
210 print '<div class="underbanner clearboth"></div>';
212 print '<table class="border centpercent tableforfield">';
217 print '<tr><td class="titlefield">'.$langs->trans(
"Nature").
'</td><td>';
218 print $object->getLibFinished();
222 if (empty($conf->global->PRODUIT_MULTIPRICES))
225 print '<tr><td class="titlefield">'.$langs->trans(
"SellingPrice").
'</td><td>';
226 if ($object->price_base_type ==
'TTC')
228 print price($object->price_ttc).
' '.$langs->trans($object->price_base_type);
230 print price($object->price).
' '.$langs->trans($object->price_base_type ? $object->price_base_type :
'HT');
235 print '<tr><td>'.$langs->trans(
"MinPrice").
'</td><td>';
236 if ($object->price_base_type ==
'TTC')
238 print price($object->price_min_ttc).
' '.$langs->trans($object->price_base_type);
240 print price($object->price_min).
' '.$langs->trans($object->price_base_type ? $object->price_base_type :
'HT');
253 $prodsfather = $object->getFather();
254 $object->get_sousproduits_arbo();
255 $prods_arbo = $object->get_arbo_each_prod();
257 $nbofsubsubproducts = count($prods_arbo);
258 $prodschild = $object->getChildsArbo($id, 1);
259 $nbofsubproducts = count($prodschild);
262 print '<div class="fichecenter">';
266 print '<table class="liste">';
267 print
'<tr class="liste_titre">';
268 print
'<td>'.$langs->trans(
'ParentProducts').
'</td>';
269 print
'<td>'.$langs->trans(
'Label').
'</td>';
270 print
'<td>'.$langs->trans(
'Qty').
'</td>';
272 if (count($prodsfather) > 0)
274 foreach ($prodsfather as $value)
276 $idprod = $value[
"id"];
277 $productstatic->id = $idprod;
278 $productstatic->type = $value[
"fk_product_type"];
279 $productstatic->ref = $value[
'ref'];
280 $productstatic->label = $value[
'label'];
281 $productstatic->entity = $value[
'entity'];
283 print
'<tr class="oddeven">';
284 print
'<td>'.$productstatic->getNomUrl(1,
'composition').
'</td>';
285 print
'<td>'.$productstatic->label.
'</td>';
286 print
'<td>'.$value[
'qty'].
'</td>';
290 print
'<tr class="oddeven">';
291 print
'<td colspan="3" class="opacitymedium">'.$langs->trans(
"None").
'</td>';
300 print
'<div class="fichecenter">';
302 $atleastonenotdefined = 0;
305 print
'<form name="formComposedProduct" action="'.$_SERVER[
'PHP_SELF'].
'" method="post">';
306 print
'<input type="hidden" name="token" value="'.newToken().
'" />';
307 print
'<input type="hidden" name="action" value="save_composed_product" />';
308 print
'<input type="hidden" name="id" value="'.$id.
'" />';
310 print
'<table class="liste">';
312 print
'<tr class="liste_titre">';
313 print
'<td>'.$langs->trans(
'ComposedProduct').
'</td>';
314 print
'<td>'.$langs->trans(
'Label').
'</td>';
315 print
'<td class="right" colspan="2">'.$langs->trans(
'MinSupplierPrice').
'</td>';
316 print
'<td class="right" colspan="2">'.$langs->trans(
'MinCustomerPrice').
'</td>';
317 if (!empty($conf->stock->enabled)) print
'<td class="right">'.$langs->trans(
'Stock').
'</td>';
318 print
'<td class="center">'.$langs->trans(
'Qty').
'</td>';
319 print
'<td class="center">'.$langs->trans(
'ComposedProductIncDecStock').
'</td>';
323 if (count($prods_arbo)) {
324 foreach ($prods_arbo as $value) {
325 $productstatic->fetch($value[
'id']);
327 if ($value[
'level'] <= 1) {
328 print
'<tr class="oddeven">';
331 $nb_of_subproduct = $value[
'nb'];
333 print
'<td>'.$productstatic->getNomUrl(1,
'composition').
'</td>';
334 print
'<td>'.$productstatic->label.
'</td>';
337 print
'<td class="right">';
338 if ($product_fourn->find_min_price_product_fournisseur($productstatic->id) > 0)
340 print $langs->trans(
"BuyingPriceMinShort").
': ';
341 if ($product_fourn->product_fourn_price_id > 0) print $product_fourn->display_price_product_fournisseur(0, 0);
342 else { print $langs->trans(
"NotDefined"); $notdefined++; $atleastonenotdefined++; }
347 $fourn_unitprice = (!empty($product_fourn->fourn_unitprice) ? $product_fourn->fourn_unitprice : 0);
348 $fourn_remise_percent = (!empty($product_fourn->fourn_remise_percent) ? $product_fourn->fourn_remise_percent : 0);
349 $fourn_remise = (!empty($product_fourn->fourn_remise) ? $product_fourn->fourn_remise : 0);
351 $unitline =
price2num(($fourn_unitprice * (1 - ($fourn_remise_percent / 100)) - $fourn_remise),
'MU');
352 $totalline =
price2num($value[
'nb'] * ($fourn_unitprice * (1 - ($fourn_remise_percent / 100)) - $fourn_remise),
'MT');
353 $total += $totalline;
355 print
'<td class="right">';
356 print ($notdefined ?
'' : ($value[
'nb'] > 1 ? $value[
'nb'].
'x' :
'').
price($unitline,
'',
'', 0, 0, -1, $conf->currency));
360 $pricesell = $productstatic->price;
361 if (!empty($conf->global->PRODUIT_MULTIPRICES))
363 $pricesell =
'Variable';
365 $totallinesell =
price2num($value[
'nb'] * ($pricesell),
'MT');
366 $totalsell += $totallinesell;
368 print
'<td class="right" colspan="2">';
369 print ($notdefined ?
'' : ($value[
'nb'] > 1 ? $value[
'nb'].
'x' :
''));
370 if (is_numeric($pricesell)) print
price($pricesell,
'',
'', 0, 0, -1, $conf->currency);
371 else print $langs->trans($pricesell);
375 if (!empty($conf->stock->enabled)) print
'<td class="right">'.$value[
'stock'].
'</td>';
378 if ($user->rights->produit->creer || $user->rights->service->creer)
380 print
'<td class="center"><input type="text" value="'.$nb_of_subproduct.
'" name="TProduct['.$productstatic->id.
'][qty]" size="4" class="right" /></td>';
381 print
'<td class="center"><input type="checkbox" name="TProduct['.$productstatic->id.
'][incdec]" value="1" '.($value[
'incdec'] == 1 ?
'checked' :
'').
' /></td>';
383 print
'<td>'.$nb_of_subproduct.
'</td>';
384 print
'<td>'.($value[
'incdec'] == 1 ?
'x' :
'').
'</td>';
390 if (empty($conf->global->PRODUCT_SHOW_SUB_SUB_PRODUCTS)) $hide =
' hideobject';
392 print
'<tr class="oddeven'.$hide.
'" id="sub-'.$value[
'id_parent'].
'">';
395 $productstatic->ref = $value[
'ref'];
397 for ($i = 0; $i < $value[
'level']; $i++) print
' ';
398 print $productstatic->getNomUrl(1,
'composition').
'</td>';
399 print
'<td>'.$productstatic->label.
'</td>';
402 print
'<td> </td>';
403 print
'<td> </td>';
405 print
'<td> </td>';
406 print
'<td> </td>';
408 if (!empty($conf->stock->enabled)) print
'<td></td>';
409 print
'<td class="center">'.$value[
'nb'].
'</td>';
410 print
'<td> </td>';
416 print
'<tr class="liste_total">';
417 print
'<td class="liste_total"></td>';
418 print
'<td class="liste_total"></td>';
421 print
'<td class="liste_total right">';
422 print $langs->trans(
"TotalBuyingPriceMinShort");
425 print
'<td class="liste_total right">';
426 if ($atleastonenotdefined) print $langs->trans(
"Unknown").
' ('.$langs->trans(
"SomeSubProductHaveNoPrices").
')';
427 print ($atleastonenotdefined ?
'' :
price($total,
'',
'', 0, 0, -1, $conf->currency));
431 print
'<td class="liste_total right">';
432 print $langs->trans(
"TotalSellingPriceMinShort");
435 print
'<td class="liste_total right">';
436 if ($atleastonenotdefined) print $langs->trans(
"Unknown").
' ('.$langs->trans(
"SomeSubProductHaveNoPrices").
')';
437 print ($atleastonenotdefined ?
'' :
price($totalsell,
'',
'', 0, 0, -1, $conf->currency));
441 if (!empty($conf->stock->enabled)) print
'<td class="liste_total right"> </td>';
443 print
'<td class="right" colspan="2">';
444 if ($user->rights->produit->creer || $user->rights->service->creer)
446 print
'<input type="submit" class="button button-save" value="'.$langs->trans(
"Save").
'">';
452 if (!empty($conf->stock->enabled)) $colspan++;
454 print
'<tr class="oddeven">';
455 print
'<td colspan="'.$colspan.
'" class="opacitymedium">'.$langs->trans(
"None").
'</td>';
471 if ((empty($action) || $action ==
'view' || $action ==
'edit' || $action ==
'search' || $action ==
're-edit') && ($user->rights->produit->creer || $user->rights->service->creer))
476 if (!empty($conf->categorie->enabled)) $rowspan++;
479 print
'<form action="'.DOL_URL_ROOT.
'/product/composition/card.php?id='.$id.
'" method="POST">';
480 print
'<input type="hidden" name="action" value="search">';
481 print
'<input type="hidden" name="id" value="'.$id.
'">';
482 print
'<div class="inline-block">';
483 print
'<input type="hidden" name="token" value="'.newToken().
'">';
484 print $langs->trans(
"KeywordFilter").
': ';
485 print
'<input type="text" name="key" value="'.$key.
'"> ';
487 if (!empty($conf->categorie->enabled))
489 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
490 print
'<div class="inline-block">'.$langs->trans(
"CategoryFilter").
': ';
491 print $form->select_all_categories(Categorie::TYPE_PRODUCT, $parent,
'parent').
' </div>';
494 print
'<div class="inline-block">';
495 print
'<input type="submit" class="button" value="'.$langs->trans(
"Search").
'">';
502 if ($action ==
'search')
505 print
'<form action="'.DOL_URL_ROOT.
'/product/composition/card.php?id='.$id.
'" method="post">';
506 print
'<input type="hidden" name="token" value="'.newToken().
'">';
507 print
'<input type="hidden" name="action" value="add_prod">';
508 print
'<input type="hidden" name="id" value="'.$id.
'">';
509 print
'<table class="noborder centpercent">';
510 print
'<tr class="liste_titre">';
511 print
'<th class="liste_titre">'.$langs->trans(
"ComposedProduct").
'</td>';
512 print
'<th class="liste_titre">'.$langs->trans(
"Label").
'</td>';
514 print
'<th class="liste_titre right">'.$langs->trans(
"Qty").
'</td>';
515 print
'<th class="center">'.$langs->trans(
'ComposedProductIncDecStock').
'</th>';
519 $num = $db->num_rows(
$resql);
522 if ($num == 0) print
'<tr><td colspan="4">'.$langs->trans(
"NoMatchFound").
'</td></tr>';
526 while ($i < min($num, $MAX))
528 $objp = $db->fetch_object(
$resql);
529 if ($objp->rowid != $id)
533 $prod_arbo->id = $objp->rowid;
538 $prod_arbo->get_sousproduits_arbo();
540 $prods_arbo = $prod_arbo->get_arbo_each_prod();
541 if (count($prods_arbo) > 0)
543 foreach ($prods_arbo as $key => $value)
545 if ($value[1] == $id)
559 print
'<tr class="oddeven">';
561 $productstatic->id = $objp->rowid;
562 $productstatic->ref = $objp->ref;
563 $productstatic->label = $objp->label;
564 $productstatic->type = $objp->type;
565 $productstatic->entity = $objp->entity;
566 $productstatic->status_batch = $objp->tobatch;
568 print
'<td>'.$productstatic->getNomUrl(1,
'', 24).
'</td>';
569 $labeltoshow = $objp->label;
570 if ($conf->global->MAIN_MULTILANGS && $objp->labelm) $labeltoshow = $objp->labelm;
572 print
'<td>'.$labeltoshow.
'</td>';
575 if ($object->is_sousproduit($id, $objp->rowid))
578 $qty = $object->is_sousproduit_qty;
579 $incdec = $object->is_sousproduit_incdec;
589 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>';
592 print
'<td class="center">';
593 if ($qty) print
'<input type="checkbox" name="prod_incdec_'.$i.
'" value="1" '.($incdec ?
'checked' :
'').
'>';
596 print
'<input type="checkbox" name="prod_incdec_'.$i.
'" value="1" checked>';
606 print
'<tr class="oddeven">';
607 print
'<td><span class="opacitymedium">'.$langs->trans(
"More").
'...</span></td>';
617 print
'<input type="hidden" name="max_prod" value="'.$i.
'">';
621 print
'<br><div class="center">';
622 print
'<input type="submit" class="button" name="save" value="'.$langs->trans(
"Add").
'/'.$langs->trans(
"Update").
'">';
623 print
' ';
624 print
'<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans(
"Cancel").
'">';
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Class to manage products or services.
const TYPE_ASSEMBLYKIT
Advanced feature: assembly kit.
const TYPE_STOCKKIT
Advanced feature: stock kit.
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete= 'resolve')
Convert a html select field into an ajax combobox.
const TYPE_SERVICE
Service.
const TYPE_PRODUCT
Regular product.
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...
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
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 '...
restrictedArea($user, $features, $objectid=0, $tableandshare= '', $feature2= '', $dbt_keyfield= 'fk_soc', $dbt_select= 'rowid', $isdraft=0)
Check permissions of a user to show a page and an object.
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...
print $_SERVER["PHP_SELF"]
Edit parameters.
dol_get_fiche_head($links=array(), $active= '', $title= '', $notab=0, $picto= '', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limittoshow=0, $moretabssuffix= '')
Show tabs of a record.
print
Draft customers invoices.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
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 '...' 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.
Class to manage predefined suppliers products.
product_prepare_head($object)
Prepare array with list of tabs.