33 require
'../../main.inc.php';
34 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
35 require_once DOL_DOCUMENT_ROOT.
'/product/class/product.class.php';
36 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
37 require_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
38 require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
39 require_once DOL_DOCUMENT_ROOT.
'/product/class/html.formproduct.class.php';
40 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productstockentrepot.class.php';
41 if (!empty($conf->productbatch->enabled)) {
42 require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
44 if (!empty($conf->projet->enabled)) {
45 require_once DOL_DOCUMENT_ROOT.
'/core/class/html.formprojet.class.php';
46 require_once DOL_DOCUMENT_ROOT.
'/projet/class/project.class.php';
49 if (!empty($conf->variants->enabled)) {
50 require_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductAttribute.class.php';
51 require_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductAttributeValue.class.php';
52 require_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
53 require_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
57 $langs->loadlangs(array(
'products',
'suppliers',
'orders',
'bills',
'stocks',
'sendings',
'margins'));
58 if (!empty($conf->productbatch->enabled)) $langs->load(
"productbatch");
60 $backtopage =
GETPOST(
'backtopage',
'alpha');
61 $action =
GETPOST(
'action',
'aZ09');
62 $cancel =
GETPOST(
'cancel',
'alpha');
66 $stocklimit =
GETPOST(
'seuil_stock_alerte');
67 $desiredstock =
GETPOST(
'desiredstock');
68 $cancel =
GETPOST(
'cancel',
'alpha');
69 $fieldid = isset($_GET[
"ref"]) ?
'ref' :
'rowid';
72 $pdluoid =
GETPOST(
'pdluoid',
'int');
73 $batchnumber =
GETPOST(
'batch_number',
'san_alpha');
74 if (!empty($batchnumber)) {
75 $batchnumber = trim($batchnumber);
79 if ($user->socid) $socid = $user->socid;
80 $result =
restrictedArea($user,
'produit&stock', $id,
'product&product',
'',
'', $fieldid);
87 $extrafields->fetch_name_optionals_label($object->table_element);
89 if ($id > 0 || !empty($ref))
91 $result = $object->fetch($id, $ref);
94 if (empty($id) && !empty($object->id)) $id = $object->id;
96 $modulepart =
'product';
99 $canvas = !empty($object->canvas) ? $object->canvas :
GETPOST(
"canvas");
103 require_once DOL_DOCUMENT_ROOT.
'/core/class/canvas.class.php';
104 $objcanvas =
new Canvas($db, $action);
105 $objcanvas->getCanvas(
'stockproduct',
'card', $canvas);
109 $hookmanager->initHooks(array(
'stockproductcard',
'globalcard'));
118 if ($cancel) $action =
'';
120 $parameters = array(
'id'=>$id,
'ref'=>$ref,
'objcanvas'=>$objcanvas);
121 $reshook = $hookmanager->executeHooks(
'doActions', $parameters, $object, $action);
122 if ($reshook < 0)
setEventMessages($hookmanager->error, $hookmanager->errors,
'errors');
124 if ($action ==
'addlimitstockwarehouse' && !empty($user->rights->produit->creer))
126 $seuil_stock_alerte =
GETPOST(
'seuil_stock_alerte');
127 $desiredstock =
GETPOST(
'desiredstock');
130 if ($seuil_stock_alerte ==
'') {
131 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"StockLimit")), null,
'errors');
134 if ($desiredstock ==
'') {
135 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"DesiredStock")), null,
'errors');
141 if ($pse->fetch(0, $id,
GETPOST(
'fk_entrepot',
'int')) > 0) {
143 $pse->seuil_stock_alerte = $seuil_stock_alerte;
144 $pse->desiredstock = $desiredstock;
145 if ($pse->update($user) > 0)
setEventMessages($langs->trans(
'ProductStockWarehouseUpdated'), null,
'mesgs');
148 $pse->fk_entrepot =
GETPOST(
'fk_entrepot',
'int');
149 $pse->fk_product = $id;
150 $pse->seuil_stock_alerte =
GETPOST(
'seuil_stock_alerte');
151 $pse->desiredstock =
GETPOST(
'desiredstock');
152 if ($pse->create($user) > 0)
setEventMessages($langs->trans(
'ProductStockWarehouseCreated'), null,
'mesgs');
156 header(
"Location: ".
$_SERVER[
"PHP_SELF"].
"?id=".$id);
160 if ($action ==
'delete_productstockwarehouse' && !empty($user->rights->produit->creer))
164 $pse->fetch(
GETPOST(
'fk_productstockwarehouse',
'int'));
165 if ($pse->delete($user) > 0)
setEventMessages($langs->trans(
'ProductStockWarehouseDeleted'), null,
'mesgs');
171 if ($action ==
'setseuil_stock_alerte' && !empty($user->rights->produit->creer))
174 $result = $object->fetch($id);
175 $object->seuil_stock_alerte = $stocklimit;
176 $result = $object->update($object->id, $user, 0,
'update');
185 if ($action ==
'setdesiredstock' && !empty($user->rights->produit->creer))
188 $result = $object->fetch($id);
189 $object->desiredstock = $desiredstock;
190 $result = $object->update($object->id, $user, 0,
'update');
198 if ($action ==
"correct_stock" && !$cancel)
200 if (!(
GETPOST(
"id_entrepot",
'int') > 0))
202 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Warehouse")), null,
'errors');
204 $action =
'correction';
208 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"NumberOfUnit")), null,
'errors');
210 $action =
'correction';
213 if (!empty($conf->productbatch->enabled))
216 $result = $object->fetch($id);
218 if ($object->hasbatch() && !$batchnumber)
220 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"batch_number")), null,
'errors');
222 $action =
'correction';
229 if (is_numeric($nbpiece) && $nbpiece != 0 && $id) {
230 $origin_element =
'';
233 if (
GETPOST(
'projectid',
'int')) {
234 $origin_element =
'project';
235 $origin_id =
GETPOST(
'projectid',
'int');
238 if (empty($object)) {
240 $result = $object->fetch($id);
243 $disablestockchangeforsubproduct = 0;
244 if (
GETPOST(
'disablesubproductstockchange')) {
245 $disablestockchangeforsubproduct = 1;
248 if ($object->hasbatch()) {
249 $result = $object->correct_stock_batch(
254 GETPOST(
"label",
'alphanohtml'),
259 GETPOST(
'inventorycode',
'alphanohtml'),
262 $disablestockchangeforsubproduct
265 $result = $object->correct_stock(
270 GETPOST(
"label",
'alphanohtml'),
272 GETPOST(
'inventorycode',
'alphanohtml'),
275 $disablestockchangeforsubproduct
281 header(
"Location: ".$backtopage);
284 header(
"Location: ".
$_SERVER[
"PHP_SELF"].
"?id=".$object->id);
289 $action =
'correction';
296 if ($action ==
"transfert_stock" && !$cancel)
298 if (!(
GETPOST(
"id_entrepot",
'int') > 0) || !(
GETPOST(
"id_entrepot_destination",
'int') > 0))
300 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Warehouse")), null,
'errors');
302 $action =
'transfert';
304 if (!
GETPOST(
"nbpiece",
'int'))
306 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"NumberOfUnit")), null,
'errors');
308 $action =
'transfert';
310 if (
GETPOST(
"id_entrepot",
'int') ==
GETPOST(
"id_entrepot_destination",
'int'))
312 setEventMessages($langs->trans(
"ErrorSrcAndTargetWarehouseMustDiffers"), null,
'errors');
314 $action =
'transfert';
316 if (!empty($conf->productbatch->enabled))
319 $result = $object->fetch($id);
321 if ($object->hasbatch() && !$batchnumber)
323 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"batch_number")), null,
'errors');
325 $action =
'transfert';
334 $result = $object->fetch($id);
338 $object->load_stock(
'novirtual');
342 if (isset($object->pmp)) $pricesrc = $object->pmp;
343 $pricedest = $pricesrc;
347 if ($object->hasbatch())
353 $result = $pdluo->fetch($pdluoid);
356 $srcwarehouseid = $pdluo->warehouseid;
357 $batch = $pdluo->batch;
358 $eatby = $pdluo->eatby;
359 $sellby = $pdluo->sellby;
365 $srcwarehouseid =
GETPOST(
'id_entrepot',
'int');
366 $batch = $batchnumber;
376 $result1 = $object->correct_stock_batch(
381 GETPOST(
"label",
'alphanohtml'),
383 $eatby, $sellby, $batch,
384 GETPOST(
'inventorycode',
'alphanohtml')
386 if ($result1 < 0) $error++;
391 $result2 = $object->correct_stock_batch(
393 GETPOST(
"id_entrepot_destination",
'int'),
396 GETPOST(
"label",
'alphanohtml'),
398 $eatby, $sellby, $batch,
399 GETPOST(
'inventorycode',
'alphanohtml')
401 if ($result2 < 0) $error++;
407 $result1 = $object->correct_stock(
412 GETPOST(
"label",
'alphanohtml'),
414 GETPOST(
'inventorycode',
'alphanohtml')
416 if ($result1 < 0) $error++;
421 $result2 = $object->correct_stock(
423 GETPOST(
"id_entrepot_destination",
'int'),
426 GETPOST(
"label",
'alphanohtml'),
428 GETPOST(
'inventorycode',
'alphanohtml')
430 if ($result2 < 0) $error++;
435 if (!$error && $result1 >= 0 && $result2 >= 0)
441 header(
"Location: ".$backtopage);
444 header(
"Location: product.php?id=".$object->id);
450 $action =
'transfert';
457 if ($action ==
'updateline' &&
GETPOST(
'save') == $langs->trans(
"Save"))
460 $result = $pdluo->fetch(
GETPOST(
'pdluoid',
'int'));
466 if ((!
GETPOST(
"sellby")) && (!
GETPOST(
"eatby")) && (!$batchnumber)) {
467 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"atleast1batchfield")), null,
'errors');
469 $d_eatby =
dol_mktime(0, 0, 0, $_POST[
'eatbymonth'], $_POST[
'eatbyday'], $_POST[
'eatbyyear']);
470 $d_sellby =
dol_mktime(0, 0, 0, $_POST[
'sellbymonth'], $_POST[
'sellbyday'], $_POST[
'sellbyyear']);
471 $pdluo->batch = $batchnumber;
472 $pdluo->eatby = $d_eatby;
473 $pdluo->sellby = $d_sellby;
474 $result = $pdluo->update($user);
481 setEventMessages($langs->trans(
'BatchInformationNotfound'), null,
'errors');
486 header(
"Location: product.php?id=".$id);
496 $form =
new Form($db);
498 if (!empty($conf->projet->enabled)) $formproject =
new FormProjets($db);
503 $result = $object->fetch($id, $ref);
505 $variants = $object->hasVariants();
507 $object->load_stock();
509 $title = $langs->trans(
'ProductServiceCard');
511 $shortlabel =
dol_trunc($object->label, 16);
514 $title = $langs->trans(
'Product').
" ".$shortlabel.
" - ".$langs->trans(
'Stock');
515 $helpurl =
'EN:Module_Products|FR:Module_Produits|ES:Módulo_Productos';
519 $title = $langs->trans(
'Service').
" ".$shortlabel.
" - ".$langs->trans(
'Stock');
520 $helpurl =
'EN:Module_Services_En|FR:Module_Services|ES:Módulo_Servicios';
528 $titre = $langs->trans(
"CardProduct".$object->type);
535 $linkback =
'<a href="'.DOL_URL_ROOT.
'/product/list.php?restore_lastsearch_values=1">'.$langs->trans(
"BackToList").
'</a>';
538 if ($user->socid && !in_array(
'stock', explode(
',', $conf->global->MAIN_MODULES_FOR_EXTERNAL))) $shownav = 0;
543 print '<div class="fichecenter">';
545 print '<div class="fichehalfleft">';
546 print '<div class="underbanner clearboth"></div>';
548 print '<table class="border tableforfield centpercent">';
550 if ($conf->productbatch->enabled) {
551 print '<tr><td class="titlefield">'.$langs->trans(
"ManageLotSerial").
'</td><td>';
552 print $object->getLibStatut(0, 2);
558 $textdesc = $langs->trans(
"CostPriceDescription");
559 $textdesc .=
"<br>".$langs->trans(
"CostPriceUsage");
560 $text = $form->textwithpicto($langs->trans(
"CostPrice"), $textdesc, 1,
'help',
'');
561 print $form->editfieldkey($text,
'cost_price', $object->cost_price, $object, $usercancreate,
'amount:6');
562 print '</td><td colspan="2">';
563 print $form->editfieldval($text,
'cost_price', $object->cost_price, $object, $usercancreate,
'amount:6');
567 print '<tr><td class="titlefield">'.$form->textwithpicto($langs->trans(
"AverageUnitPricePMPShort"), $langs->trans(
"AverageUnitPricePMPDesc")).
'</td>';
569 if ($object->pmp > 0)
print price($object->pmp).
' '.$langs->trans(
"HT");
574 print '<tr><td>'.$langs->trans(
"BuyingPriceMin").
'</td>';
577 if ($product_fourn->find_min_price_product_fournisseur($object->id) > 0) {
578 if ($product_fourn->product_fourn_price_id > 0)
print $product_fourn->display_price_product_fournisseur();
579 else print $langs->trans(
"NotDefined");
583 if (empty($conf->global->PRODUIT_MULTIPRICES)) {
585 print '<tr><td>'.$langs->trans(
"SellingPrice").
'</td><td>';
586 if ($object->price_base_type ==
'TTC') {
587 print price($object->price_ttc).
' '.$langs->trans($object->price_base_type);
589 print price($object->price).
' '.$langs->trans($object->price_base_type);
594 print '<tr><td>'.$langs->trans(
"MinPrice").
'</td><td>';
595 if ($object->price_base_type ==
'TTC') {
596 print price($object->price_min_ttc).
' '.$langs->trans($object->price_base_type);
598 print price($object->price_min).
' '.$langs->trans($object->price_base_type);
603 print '<tr><td>'.$langs->trans(
"SellingPrice").
'</td><td>';
604 print $langs->trans(
"Variable");
608 print '<tr><td>'.$langs->trans(
"MinPrice").
'</td><td>';
609 print $langs->trans(
"Variable");
614 $parameters = array();
615 $reshook = $hookmanager->executeHooks(
'formObjectOptions', $parameters, $object, $action);
616 print $hookmanager->resPrint;
621 print '<div class="fichehalfright"><div class="ficheaddleft"><div class="underbanner clearboth"></div>';
623 print '<table class="border tableforfield centpercent">';
626 print '<tr><td>'.$form->editfieldkey($form->textwithpicto($langs->trans(
"StockLimit"), $langs->trans(
"StockLimitDesc"), 1),
'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer).
'</td><td>';
627 print $form->editfieldval(
"StockLimit",
'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer,
'string');
631 print '<tr><td>'.$form->editfieldkey($form->textwithpicto($langs->trans(
"DesiredStock"), $langs->trans(
"DesiredStockDesc"), 1),
'desiredstock', $object->desiredstock, $object, $user->rights->produit->creer);
633 print $form->editfieldval(
"DesiredStock",
'desiredstock', $object->desiredstock, $object, $user->rights->produit->creer,
'string');
637 $text_stock_options = $langs->trans(
"RealStockDesc").
'<br>';
638 $text_stock_options .= $langs->trans(
"RealStockWillAutomaticallyWhen").
'<br>';
639 $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE) ?
'- '.$langs->trans(
"DeStockOnShipment").
'<br>' :
'');
640 $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) ?
'- '.$langs->trans(
"DeStockOnValidateOrder").
'<br>' :
'');
641 $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_BILL) ?
'- '.$langs->trans(
"DeStockOnBill").
'<br>' :
'');
642 $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) ?
'- '.$langs->trans(
"ReStockOnBill").
'<br>' :
'');
643 $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER) ?
'- '.$langs->trans(
"ReStockOnValidateOrder").
'<br>' :
'');
644 $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) ?
'- '.$langs->trans(
"ReStockOnDispatchOrder").
'<br>' :
'');
645 $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE) ?
'- '.$langs->trans(
"StockOnReception").
'<br>' :
'');
648 print $form->textwithpicto($langs->trans(
"PhysicalStock"), $text_stock_options, 1);
650 print '<td>'.price2num($object->stock_reel,
'MS');
651 if ($object->seuil_stock_alerte !=
'' && ($object->stock_reel < $object->seuil_stock_alerte))
print ' '.img_warning($langs->trans(
"StockLowerThanLimit", $object->seuil_stock_alerte));
653 print ' <a href="'.DOL_URL_ROOT.
'/product/stock/stockatdate.php?productid='.$object->id.
'">'.$langs->trans(
"StockAtDate").
'</a>';
657 $stocktheo =
price2num($object->stock_theorique,
'MS');
660 $helpondiff =
'<strong>'.$langs->trans(
"StockDiffPhysicTeoric").
':</strong><br>';
662 if (!empty($conf->commande->enabled)) {
663 if ($found) $helpondiff .=
'<br>';
else $found = 1;
664 $helpondiff .= $langs->trans(
"ProductQtyInCustomersOrdersRunning").
': '.$object->stats_commande[
'qty'];
665 $result = $object->load_stats_commande(0,
'0', 1);
667 $helpondiff .=
' ('.$langs->trans(
"ProductQtyInDraft").
': '.$object->stats_commande[
'qty'].
')';
671 if (!empty($conf->expedition->enabled)) {
672 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
673 $filterShipmentStatus =
'';
674 if (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) {
676 } elseif (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) {
679 if ($found) $helpondiff .=
'<br>';
else $found = 1;
680 $result = $object->load_stats_sending(0,
'2', 1, $filterShipmentStatus);
681 $helpondiff .= $langs->trans(
"ProductQtyInShipmentAlreadySent").
': '.$object->stats_expedition[
'qty'];
685 if (!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled))
687 if ($found) $helpondiff .=
'<br>';
else $found = 1;
688 $result = $object->load_stats_commande_fournisseur(0,
'3,4', 1);
689 $helpondiff .= $langs->trans(
"ProductQtyInSuppliersOrdersRunning").
': '.$object->stats_commande_fournisseur[
'qty'];
690 $result = $object->load_stats_commande_fournisseur(0,
'0,1,2', 1);
692 $helpondiff .=
' ('.$langs->trans(
"ProductQtyInDraftOrWaitingApproved").
': '.$object->stats_commande_fournisseur[
'qty'].
')';
696 if (!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) {
697 if ($found) $helpondiff .=
'<br>';
else $found = 1;
698 $helpondiff .= $langs->trans(
"ProductQtyInSuppliersShipmentAlreadyRecevied").
': '.$object->stats_reception[
'qty'];
702 if (!empty($conf->mrp->enabled)) {
703 if ($found) $helpondiff .=
'<br>';
else $found = 1;
704 $helpondiff .= $langs->trans(
"ProductQtyToConsumeByMO").
': '.$object->stats_mrptoconsume[
'qty'].
'<br>';
705 $helpondiff .= $langs->trans(
"ProductQtyToProduceByMO").
': '.$object->stats_mrptoproduce[
'qty'];
711 print $form->textwithpicto($langs->trans(
"VirtualStock"), $langs->trans(
"VirtualStockDesc"));
715 print $form->textwithpicto((empty($stocktheo) ? 0 : $stocktheo), $helpondiff);
716 if ($object->seuil_stock_alerte !=
'' && ($object->stock_theorique < $object->seuil_stock_alerte))
print ' '.img_warning($langs->trans(
"StockLowerThanLimit", $object->seuil_stock_alerte));
717 print ' <a href="'.DOL_URL_ROOT.
'/product/stock/stockatdate.php?mode=future&productid='.$object->id.
'">'.$langs->trans(
"VirtualStockAtDate").
'</a>';
722 if (!empty($user->rights->stock->mouvement->lire))
724 $sql =
"SELECT max(m.datem) as datem";
725 $sql .=
" FROM ".MAIN_DB_PREFIX.
"stock_mouvement as m";
726 $sql .=
" WHERE m.fk_product = ".((int) $object->id);
727 $resqlbis = $db->query($sql);
729 $obj = $db->fetch_object($resqlbis);
730 $lastmovementdate = $db->jdate($obj->datem);
734 print '<tr><td class="tdtop">'.$langs->trans(
"LastMovement").
'</td><td>';
735 if ($lastmovementdate) {
737 print ' <a href="'.DOL_URL_ROOT.
'/product/stock/movement_list.php?idproduct='.$object->id.
'">'.$langs->trans(
"FullList").
'</a>';
739 print '<a href="'.DOL_URL_ROOT.
'/product/stock/movement_list.php?idproduct='.$object->id.
'">'.$langs->trans(
"None").
'</a>';
750 print '<div style="clear:both"></div>';
757 if ($action ==
"correction")
759 include DOL_DOCUMENT_ROOT.
'/product/stock/tpl/stockcorrection.tpl.php';
764 if ($action ==
"transfert")
766 include DOL_DOCUMENT_ROOT.
'/product/stock/tpl/stocktransfer.tpl.php';
776 $parameters = array();
778 $reshook = $hookmanager->executeHooks(
'addMoreActionsButtons', $parameters, $object, $action);
781 if (empty($action) && $object->id)
783 print "<div class=\"tabsAction\">\n";
785 if ($user->rights->stock->mouvement->creer)
787 if (!$variants || !empty($conf->global->VARIANT_ALLOW_STOCK_MOVEMENT_ON_VARIANT_PARENT)) {
788 print '<a class="butAction" href="'.$_SERVER[
"PHP_SELF"].
'?id='.$object->id.
'&action=correction">'.$langs->trans(
"CorrectStock").
'</a>';
790 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans(
"ActionAvailableOnVariantProductOnly").
'">'.$langs->trans(
"CorrectStock").
'</a>';
793 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans(
"NotEnoughPermissions").
'">'.$langs->trans(
"CorrectStock").
'</a>';
797 if ($user->rights->stock->mouvement->creer)
799 if (!$variants || !empty($conf->global->VARIANT_ALLOW_STOCK_MOVEMENT_ON_VARIANT_PARENT)) {
800 print '<a class="butAction" href="'.$_SERVER[
"PHP_SELF"].
'?id='.$object->id.
'&action=transfert">'.$langs->trans(
"TransferStock").
'</a>';
802 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans(
"ActionAvailableOnVariantProductOnly").
'">'.$langs->trans(
"TransferStock").
'</a>';
805 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans(
"NotEnoughPermissions").
'">'.$langs->trans(
"CorrectStock").
'</a>';
818 print '<div class="div-table-responsive">';
819 print '<table class="noborder centpercent">';
821 print '<tr class="liste_titre">';
822 print '<td colspan="4">'.$langs->trans(
"Warehouse").
'</td>';
823 print '<td class="right">'.$langs->trans(
"NumberOfUnit").
'</td>';
824 print '<td class="right">'.$form->textwithpicto($langs->trans(
"AverageUnitPricePMPShort"), $langs->trans(
"AverageUnitPricePMPDesc")).
'</td>';
825 print '<td class="right">'.$langs->trans(
"EstimatedStockValueShort").
'</td>';
826 print '<td class="right">'.$langs->trans(
"SellPriceMin").
'</td>';
827 print '<td class="right">'.$langs->trans(
"EstimatedStockValueSellShort").
'</td>';
829 if ((!empty($conf->productbatch->enabled)) && $object->hasbatch()) {
831 print '<tr class="liste_titre"><td width="10%"></td>';
832 print '<td class="right" width="10%">'.$langs->trans(
"batch_number").
'</td>';
833 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
835 print '<td class="center" width="10%">'.$langs->trans(
"EatByDate").
'</td>';
837 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
839 print '<td class="center" width="10%">'.$langs->trans(
"SellByDate").
'</td>';
841 print '<td colspan="'.$colspan.
'"></td>';
849 $sql =
"SELECT e.rowid, e.ref, e.lieu, e.fk_parent, e.statut, ps.reel, ps.rowid as product_stock_id, p.pmp";
850 $sql .=
" FROM ".MAIN_DB_PREFIX.
"entrepot as e,";
851 $sql .=
" ".MAIN_DB_PREFIX.
"product_stock as ps";
852 $sql .=
" LEFT JOIN ".MAIN_DB_PREFIX.
"product as p ON p.rowid = ps.fk_product";
853 $sql .=
" WHERE ps.reel != 0";
854 $sql .=
" AND ps.fk_entrepot = e.rowid";
855 $sql .=
" AND e.entity IN (".getEntity(
'stock').
")";
856 $sql .=
" AND ps.fk_product = ".$object->id;
857 $sql .=
" ORDER BY e.ref";
859 $entrepotstatic =
new Entrepot($db);
863 $totalvalue = $totalvaluesell = 0;
865 $resql = $db->query($sql);
867 $num = $db->num_rows(
$resql);
868 $total = $totalwithpmp;
872 $obj = $db->fetch_object(
$resql);
874 $entrepotstatic->id = $obj->rowid;
875 $entrepotstatic->ref = $obj->ref;
876 $entrepotstatic->label = $obj->ref;
877 $entrepotstatic->lieu = $obj->lieu;
878 $entrepotstatic->fk_parent = $obj->fk_parent;
879 $entrepotstatic->statut = $obj->statut;
881 $stock_real =
price2num($obj->reel,
'MS');
882 print '<tr class="oddeven">';
883 print '<td colspan="4">'.$entrepotstatic->getNomUrl(1).
'</td>';
884 print '<td class="right">'.$stock_real.($stock_real < 0 ?
' '.img_warning() :
'').
'</td>';
886 print '<td class="right">'.(price2num($object->pmp) ?
price2num($object->pmp,
'MU') :
'').
'</td>';
888 print '<td class="right">'.(price2num($object->pmp) ?
price(
price2num($object->pmp * $obj->reel,
'MT')) :
'').
'</td>';
890 print '<td class="right">';
891 if (empty($conf->global->PRODUIT_MULTIPRICES))
print price(
price2num($object->price,
'MU'), 1);
892 else print $langs->trans(
"Variable");
895 print '<td class="right">';
896 if (empty($conf->global->PRODUIT_MULTIPRICES))
print price(
price2num($object->price * $obj->reel,
'MT'), 1).
'</td>';
897 else print $langs->trans(
"Variable");
899 $total += $obj->reel;
900 if (
price2num($object->pmp)) $totalwithpmp += $obj->reel;
901 $totalvalue = $totalvalue + ($object->pmp * $obj->reel);
902 $totalvaluesell = $totalvaluesell + ($object->price * $obj->reel);
904 if ((!empty($conf->productbatch->enabled)) && $object->hasbatch()) {
907 foreach ($details as $pdluo) {
908 $product_lot_static->id = $pdluo->lotid;
909 $product_lot_static->batch = $pdluo->batch;
910 $product_lot_static->eatby = $pdluo->eatby;
911 $product_lot_static->sellby = $pdluo->sellby;
913 if ($action ==
'editline' &&
GETPOST(
'lineid',
'int') == $pdluo->id) {
915 print '<td colspan="9">';
916 print '<form action="'.$_SERVER[
"PHP_SELF"].
'" method="POST">';
917 print '<input type="hidden" name="token" value="'.newToken().
'">';
918 print '<input type="hidden" name="pdluoid" value="'.$pdluo->id.
'"><input type="hidden" name="action" value="updateline"><input type="hidden" name="id" value="'.$id.
'"><table class="noborder centpercent"><tr><td width="10%"></td>';
919 print '<td class="right" width="10%"><input type="text" name="batch_number" value="'.$pdluo->batch.
'"></td>';
920 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
921 print '<td class="center" width="10%">';
922 print $form->selectDate($pdluo->eatby,
'eatby',
'',
'', 1,
'', 1, 0);
925 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
926 print '<td class="center" width="10%">';
927 print $form->selectDate($pdluo->sellby,
'sellby',
'',
'', 1,
'', 1, 0);
930 print '<td class="right" colspan="3">'.$pdluo->qty.($pdluo->qty < 0 ?
' '.img_warning() :
'').
'</td>';
931 print '<td colspan="4"><input type="submit" class="button button-save" id="savelinebutton marginbottomonly" name="save" value="'.$langs->trans(
"Save").
'">';
932 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="Cancel" value="'.$langs->trans(
"Cancel").
'"></td></tr>';
937 print "\n".
'<tr><td class="right">';
938 print img_picto($langs->trans(
"Tranfer"),
'uparrow',
'class="hideonsmartphone"').
' ';
939 print '<a href="'.$_SERVER[
"PHP_SELF"].
'?id='.$object->id.
'&id_entrepot='.$entrepotstatic->id.
'&action=transfert&pdluoid='.$pdluo->id.
'">'.$langs->trans(
"TransferStock").
'</a>';
944 print '<td class="right">';
945 print $product_lot_static->getNomUrl(1);
948 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
950 print '<td class="center">'.dol_print_date($pdluo->eatby,
'day').
'</td>';
952 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
954 print '<td class="center">'.dol_print_date($pdluo->sellby,
'day').
'</td>';
956 print '<td class="right" colspan="'.$colspan.
'">'.$pdluo->qty.($pdluo->qty < 0 ?
' '.img_warning() :
'').
'</td>';
957 print '<td colspan="4"></td>';
967 print '<tr class="liste_total"><td class="right liste_total" colspan="4">'.$langs->trans(
"Total").
':</td>';
968 print '<td class="liste_total right">'.price2num($total,
'MS').
'</td>';
969 print '<td class="liste_total right">';
973 print '<td class="liste_total right">';
976 print '<td class="liste_total right">';
977 if (empty($conf->global->PRODUIT_MULTIPRICES))
print ($total ?
price($totalvaluesell / $total, 1) :
' ');
978 else print $langs->trans(
"Variable");
981 print '<td class="liste_total right">';
982 if (empty($conf->global->PRODUIT_MULTIPRICES))
print price(
price2num($totalvaluesell,
'MT'), 1);
983 else print $langs->trans(
"Variable");
990 if (!empty($conf->global->STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE)) {
994 if (!empty($user->rights->produit->creer)) {
995 print '<form action="'.$_SERVER[
"PHP_SELF"].
'" method="POST">';
996 print '<input type="hidden" name="token" value="'.newToken().
'">';
997 print '<input type="hidden" name="action" value="addlimitstockwarehouse">';
998 print '<input type="hidden" name="id" value="'.$id.
'">';
1000 print '<table class="noborder centpercent">';
1001 if (!empty($user->rights->produit->creer)) {
1002 print '<tr class="liste_titre"><td width="40%">'.$formproduct->selectWarehouses(
'',
'fk_entrepot').
'</td>';
1003 print '<td class="right"><input name="seuil_stock_alerte" type="text" placeholder="'.$langs->trans(
"StockLimit").
'" /></td>';
1004 print '<td class="right"><input name="desiredstock" type="text" placeholder="'.$langs->trans(
"DesiredStock").
'" /></td>';
1005 print '<td class="right"><input type="submit" value="'.$langs->trans(
"Save").
'" class="button button-save" /></td>';
1008 print '<tr class="liste_titre"><td width="40%">'.$langs->trans(
"Warehouse").
'</td>';
1009 print '<td class="right">'.$langs->trans(
"StockLimit").
'</td>';
1010 print '<td class="right">'.$langs->trans(
"DesiredStock").
'</td>';
1015 $lines = $pse->fetchAll($id);
1017 if (!empty($lines)) {
1019 foreach ($lines as $line) {
1021 $ent->fetch($line[
'fk_entrepot']);
1022 print '<tr class="oddeven"><td width="40%">'.$ent->getNomUrl(3).
'</td>';
1023 print '<td class="right">'.$line[
'seuil_stock_alerte'].
'</td>';
1024 print '<td class="right">'.$line[
'desiredstock'].
'</td>';
1025 if (!empty($user->rights->produit->creer)) {
1026 print '<td class="right"><a href="'.$_SERVER[
'PHP_SELF'].
'?id='.$id.
'&fk_productstockwarehouse='.$line[
'id'].
'&action=delete_productstockwarehouse&token='.
newToken().
'">'.
img_delete().
'</a></td>';
1034 if (!empty($user->rights->produit->creer)) {
1040 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1041 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1042 $prodstatic =
new Product($db);
1045 $productCombinations = $prodcomb->fetchAllByFkProductParent($object->id);
1047 print '<form method="POST" action="'.$_SERVER[
"PHP_SELF"].
'">';
1048 print '<input type="hidden" name="token" value="'.newToken().
'">';
1049 print '<input type="hidden" name="action" value="massaction">';
1050 print '<input type="hidden" name="id" value="'.$id.
'">';
1051 print '<input type="hidden" name="backtopage" value="'.$backtopage.
'">';
1054 $title = $langs->trans(
"ProductCombinations");
1058 print '<div class="div-table-responsive">';
1060 <table
class=
"liste">
1061 <tr
class=
"liste_titre">
1062 <td
class=
"liste_titre"><?php echo $langs->trans(
'Product') ?></td>
1063 <td
class=
"liste_titre"><?php echo $langs->trans(
'Combination') ?></td>
1064 <td
class=
"liste_titre center"><?php echo $langs->trans(
'OnSell') ?></td>
1065 <td
class=
"liste_titre center"><?php echo $langs->trans(
'OnBuy') ?></td>
1066 <td
class=
"liste_titre right"><?php echo $langs->trans(
'Stock') ?></td>
1067 <td
class=
"liste_titre"></td>
1071 if (count($productCombinations))
1074 foreach ($productCombinations as $currcomb)
1076 $prodstatic->fetch($currcomb->fk_product_child);
1077 $prodstatic->load_stock();
1078 $stock_total += $prodstatic->stock_reel;
1080 <tr
class=
"oddeven">
1081 <td><?php echo $prodstatic->getNomUrl(1) ?></td>
1085 $productCombination2ValuePairs = $comb2val->fetchByFkCombination($currcomb->id);
1086 $iMax = count($productCombination2ValuePairs);
1088 for ($i = 0; $i < $iMax; $i++) {
1091 if ($i !== ($iMax - 1)) {
1096 <td style=
"text-align: center;"><?php echo $prodstatic->getLibStatut(2, 0) ?></td>
1097 <td style=
"text-align: center;"><?php echo $prodstatic->getLibStatut(2, 1) ?></td>
1098 <td
class=
"right"><?php echo $prodstatic->stock_reel ?></td>
1100 <a
class=
"paddingleft paddingright" href=
"<?php echo dol_buildpath('/product/stock/product.php?id='.$currcomb->fk_product_child, 2) ?>"><?php echo
img_edit() ?></a>
1108 print '<tr class="liste_total">';
1109 print '<td colspan="4" class="left">'.$langs->trans(
"Total").
'</td>';
1110 print '<td class="right">'.$stock_total.
'</td>';
1114 print '<tr><td colspan="8"><span class="opacitymedium">'.$langs->trans(
"None").
'</span></td></tr>';
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Class ProductStockEntrepot.
img_edit($titlealt= 'default', $float=0, $other= '')
Show logo editer/modifier fiche.
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
Class with list of lots and properties.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm= 'auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
Class to manage products or services.
dol_htmlentities($string, $flags=null, $encoding= 'UTF-8', $double_encode=false)
Replace htmlentities functions.
const TYPE_SERVICE
Service.
const TYPE_PRODUCT
Regular product.
const STATUS_CLOSED
Closed status.
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.
print_barre_liste($titre, $page, $file, $options= '', $sortfield= '', $sortorder= '', $morehtmlcenter= '', $num=-1, $totalnboflines= '', $picto= 'generic', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow= '')
Print a title with navigation controls for pagination.
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 '...
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
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.
Class ProductCombination Used to represent a product combination.
const STATUS_VALIDATED
Validated status.
print $_SERVER["PHP_SELF"]
Edit parameters.
static findAll($db, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
dol_get_fiche_head($links=array(), $active= '', $title= '', $notab=0, $picto= '', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limittoshow=0, $moretabssuffix= '')
Show tabs of a record.
Manage record for batch number management.
print
Draft customers invoices.
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Class ProductCombination2ValuePair Used to represent the relation between a product combination...
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...
newToken()
Return the value of token currently saved into session with name 'newtoken'.
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.
img_delete($titlealt= 'default', $other= 'class="pictodelete"', $morecss= '')
Show delete logo.
Class to manage predefined suppliers products.
product_prepare_head($object)
Prepare array with list of tabs.
Class to manage warehouses.