Maxi debug and enhancement of module batch.

This commit is contained in:
Laurent Destailleur 2015-02-11 22:54:06 +01:00
parent 7869bc0d7f
commit 179cbbd187
17 changed files with 412 additions and 243 deletions

View File

@ -77,7 +77,7 @@ class PaymentSocialContribution extends CommonObject
// Validate parametres // Validate parametres
if (! $this->datepaye) if (! $this->datepaye)
{ {
$this->error='ErrorBadValueForParameter'; $this->error='ErrorBadValueForParameterCreatePaymentSocialContrib';
return -1; return -1;
} }

View File

@ -111,7 +111,7 @@ class Events // extends CommonObject
$this->description=trim($this->description); $this->description=trim($this->description);
// Check parameters // Check parameters
if (empty($this->description)) { $this->error='ErrorBadValueForParameter'; return -1; } if (empty($this->description)) { $this->error='ErrorBadValueForParameterCreateEventDesc'; return -1; }
// Insert request // Insert request
$sql = "INSERT INTO ".MAIN_DB_PREFIX."events("; $sql = "INSERT INTO ".MAIN_DB_PREFIX."events(";

View File

@ -19,11 +19,15 @@
// \brief File that include javascript functions used when dispatching batch-enabled product // \brief File that include javascript functions used when dispatching batch-enabled product
// //
function AddLineBatch(index) { /**
* @param index int number of produt. 0 = first product line
*/
function addLineBatch(index)
{
var nme = 'dluo_0_'+index; var nme = 'dluo_0_'+index;
$row=$("tr[name='"+nme+"']").clone(true); $row=$("tr[name='"+nme+"']").clone(true);
$row.find("input[name^='qty']").val(''); $row.find("input[name^='qty']").val('');
var trs = $("tr[name^='dluo_'][name$='_"+index+"']"); var trs = $("tr[name^='dluo_'][name$='_"+index+"']"); /* trs.length = position of line for batch */
var newrow=$row.html().replace(/_0_/g,"_"+(trs.length)+"_"); var newrow=$row.html().replace(/_0_/g,"_"+(trs.length)+"_");
$row.html(newrow); $row.html(newrow);
//clear value //clear value
@ -31,4 +35,13 @@ function AddLineBatch(index) {
//change name of row //change name of row
$row.attr('name','dluo_'+trs.length+'_'+index); $row.attr('name','dluo_'+trs.length+'_'+index);
$("tr[name^='dluo_'][name$='_"+index+"']:last").after($row); $("tr[name^='dluo_'][name$='_"+index+"']:last").after($row);
/* Suffix of lines are: _ trs.length _ index */
jQuery("#lot_number_"+trs.length+"_"+index).focus();
nb = jQuery("#qty_"+(trs.length - 1)+"_"+index).val();
if (nb > 0)
{
jQuery("#qty_"+(trs.length - 1)+"_"+index).val(1);
jQuery("#qty_"+trs.length+"_"+index).val(nb - 1);
}
} }

View File

@ -1270,7 +1270,7 @@ class CommandeFournisseur extends CommonOrder
/** /**
* Add a product into a stock warehouse. * Save a receiving into the tracking table of receiving (commande_fournisseur_dispatch) and add product into stock warehouse.
* *
* @param User $user User object making change * @param User $user User object making change
* @param int $product Id of product to dispatch * @param int $product Id of product to dispatch
@ -1283,7 +1283,7 @@ class CommandeFournisseur extends CommonOrder
* @param string $batch Lot number * @param string $batch Lot number
* @return int <0 if KO, >0 if OK * @return int <0 if KO, >0 if OK
*/ */
function DispatchProduct($user, $product, $qty, $entrepot, $price=0, $comment='', $eatby='', $sellby='', $batch='') function dispatchProduct($user, $product, $qty, $entrepot, $price=0, $comment='', $eatby='', $sellby='', $batch='')
{ {
global $conf; global $conf;
$error = 0; $error = 0;
@ -1292,12 +1292,12 @@ class CommandeFournisseur extends CommonOrder
// Check parameters // Check parameters
if ($entrepot <= 0 || $qty <= 0) if ($entrepot <= 0 || $qty <= 0)
{ {
$this->error='BadValueForParameter'; $this->error='BadValueForParameterWarehouseOrQty';
return -1; return -1;
} }
$dispatchstatus = 1; $dispatchstatus = 1;
if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) $dispatchstatus = 0; // Setting status will be done manually to 1 if this option is on if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) $dispatchstatus = 0; // Setting dispatch status (a validation step after receiving products) will be done manually to 1 if this option is on
$now=dol_now(); $now=dol_now();
@ -1306,10 +1306,12 @@ class CommandeFournisseur extends CommonOrder
$this->db->begin(); $this->db->begin();
$sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur_dispatch"; $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur_dispatch";
$sql.= " (fk_commande, fk_product, qty, fk_entrepot, fk_user, datec, status, comment) VALUES"; $sql.= " (fk_commande, fk_product, qty, fk_entrepot, fk_user, datec, status, comment, eatby, sellby, batch) VALUES";
$sql.= " ('".$this->id."','".$product."','".$qty."',".($entrepot>0?"'".$entrepot."'":"null").",'".$user->id."','".$this->db->idate($now)."', ".$dispatchstatus.", '".$this->db->escape($comment)."')"; $sql.= " ('".$this->id."','".$product."','".$qty."',".($entrepot>0?"'".$entrepot."'":"null").",'".$user->id."','".$this->db->idate($now)."', ".$dispatchstatus.", '".$this->db->escape($comment)."', ";
$sql.= ($eatby?"'".$this->db->idate($eatby)."'":"null").", ".($sellby?"'".$this->db->idate($sellby)."'":"null").", ".($batch?"'".$batch."'":"null");
$sql.= ")";
dol_syslog(get_class($this)."::DispatchProduct", LOG_DEBUG); dol_syslog(get_class($this)."::dispatchProduct", LOG_DEBUG);
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
if ($resql) if ($resql)
{ {
@ -1329,7 +1331,7 @@ class CommandeFournisseur extends CommonOrder
$this->db->commit(); $this->db->commit();
} }
else else
{ {
$this->error=$this->db->lasterror(); $this->error=$this->db->lasterror();
$error++; $error++;
} }
@ -1337,6 +1339,7 @@ class CommandeFournisseur extends CommonOrder
// Si module stock gere et que incrementation faite depuis un dispatching en stock // Si module stock gere et que incrementation faite depuis un dispatching en stock
if (!$error && $entrepot > 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) if (!$error && $entrepot > 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER))
{ {
$mouv = new MouvementStock($this->db); $mouv = new MouvementStock($this->db);
if ($product > 0) if ($product > 0)
{ {
@ -1346,7 +1349,7 @@ class CommandeFournisseur extends CommonOrder
if ($result < 0) if ($result < 0)
{ {
$this->error=$mouv->error; $this->error=$mouv->error;
dol_syslog(get_class($this)."::DispatchProduct ".$this->error, LOG_ERR); dol_syslog(get_class($this)."::dispatchProduct ".$this->error, LOG_ERR);
$error++; $error++;
} }
} }

View File

@ -4,7 +4,7 @@
* Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com> * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2005-2009 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2014 C<EFBFBD>dric Gross <c.gross@kreiz-it.fr> * Copyright (C) 2014 Cedric Gross <c.gross@kreiz-it.fr>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -24,7 +24,7 @@
/** /**
* \file htdocs/fourn/commande/dispatch.php * \file htdocs/fourn/commande/dispatch.php
* \ingroup commande * \ingroup commande
* \brief Fiche de ventilation des commandes fournisseurs * \brief Page to dispatch receiving
*/ */
require '../../main.inc.php'; require '../../main.inc.php';
@ -63,6 +63,7 @@ $mesg='';
/* /*
* Actions * Actions
*/ */
if ($_POST["action"] == 'dispatch' && $user->rights->fournisseur->commande->receptionner) if ($_POST["action"] == 'dispatch' && $user->rights->fournisseur->commande->receptionner)
{ {
$commande = new CommandeFournisseur($db); $commande = new CommandeFournisseur($db);
@ -74,7 +75,7 @@ if ($_POST["action"] == 'dispatch' && $user->rights->fournisseur->commande->rece
foreach($_POST as $key => $value) foreach($_POST as $key => $value)
{ {
if ( preg_match('/^product_([0-9]+)$/i', $key, $reg) ) if (preg_match('/^product_([0-9]+)$/i', $key, $reg))
{ {
$prod = "product_".$reg[1]; $prod = "product_".$reg[1];
$qty = "qty_".$reg[1]; $qty = "qty_".$reg[1];
@ -82,7 +83,7 @@ if ($_POST["action"] == 'dispatch' && $user->rights->fournisseur->commande->rece
$pu = "pu_".$reg[1]; // This is unit price including discount $pu = "pu_".$reg[1]; // This is unit price including discount
if (GETPOST($ent,'int') > 0) if (GETPOST($ent,'int') > 0)
{ {
$result = $commande->DispatchProduct($user, GETPOST($prod,'int'),GETPOST($qty), GETPOST($ent,'int'), GETPOST($pu), GETPOST("comment")); $result = $commande->dispatchProduct($user, GETPOST($prod,'int'),GETPOST($qty), GETPOST($ent,'int'), GETPOST($pu), GETPOST("comment"));
if ($result < 0) if ($result < 0)
{ {
setEventMessages($commande->error, $commande->errors, 'errors'); setEventMessages($commande->error, $commande->errors, 'errors');
@ -115,23 +116,26 @@ if ($_POST["action"] == 'dispatch' && $user->rights->fournisseur->commande->rece
setEventMessage($langs->trans('ErrorFieldRequired',$text), 'errors'); setEventMessage($langs->trans('ErrorFieldRequired',$text), 'errors');
$error++; $error++;
} }
if (!((GETPOST($qty) > 0 ) && ( $_POST[$lot] or $dDLUO or $dDLC) ))
if (! $error)
{ {
dol_syslog('No dispatch for line '.$key.' as qty is not set or eat-by date are not set'); if (! ((GETPOST($qty) > 0) && ($_POST[$lot] || $dDLUO || $dDLC)))
$text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').'' .($reg[1]-1);
setEventMessage($langs->trans('ErrorFieldRequired',$text), 'errors');
$error++;
}
else
{
$result = $commande->DispatchProduct($user, GETPOST($prod,'int'),GETPOST($qty), GETPOST($ent,'int'), GETPOST($pu), GETPOST("comment"), $dDLC, $dDLUO, GETPOST($lot));
if ($result < 0)
{ {
setEventMessages($commande->error, $commande->errors, 'errors'); dol_syslog('No dispatch for line '.$key.' as qty is not set or eat-by date are not set');
$text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').'' .($reg[1]-1);
setEventMessage($langs->trans('ErrorFieldRequired',$text), 'errors');
$error++; $error++;
} }
else
{
$result = $commande->dispatchProduct($user, GETPOST($prod,'int'), GETPOST($qty), GETPOST($ent,'int'), GETPOST($pu), GETPOST("comment"), $dDLC, $dDLUO, GETPOST($lot));
if ($result < 0)
{
setEventMessages($commande->error, $commande->errors, 'errors');
$error++;
}
}
} }
} }
} }
@ -168,13 +172,14 @@ if ($_POST["action"] == 'dispatch' && $user->rights->fournisseur->commande->rece
* View * View
*/ */
$help_url='EN:CommandeFournisseur';
if (!empty($conf->productbatch->enabled)) if (!empty($conf->productbatch->enabled))
{ {
llxHeader('',$langs->trans("OrderCard"),"CommandeFournisseur",'',0,0,array('/core/js/lib_batch.js')); llxHeader('',$langs->trans("OrderCard"),$help_url,'',0,0,array('/core/js/lib_batch.js'));
} }
else else
{ {
llxHeader('',$langs->trans("OrderCard"),"CommandeFournisseur"); llxHeader('',$langs->trans("OrderCard"),$help_url);
} }
$form = new Form($db); $form = new Form($db);
@ -310,20 +315,25 @@ if ($id > 0 || ! empty($ref))
if ($num) if ($num)
{ {
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
print '<td colspan="4" width="40%">'.$langs->trans("Description").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td></td>';
print '<td></td>';
print '<td></td>';
print '<td align="right">'.$langs->trans("QtyOrdered").'</td>'; print '<td align="right">'.$langs->trans("QtyOrdered").'</td>';
print '<td align="right">'.$langs->trans("QtyDispatched").'</td>'; print '<td align="right">'.$langs->trans("QtyDispatchedShort").'</td>';
print '<td align="right">'.$langs->trans("QtyDelivered").'</td>'; print '<td align="right">'.$langs->trans("QtyToDispatchShort").'</td>';
print '<td align="right">'.$langs->trans("Warehouse").'</td>'; print '<td align="right">'.$langs->trans("Warehouse").'</td>';
print "</tr>\n"; print "</tr>\n";
if (!empty($conf->productbatch->enabled)) {
if (! empty($conf->productbatch->enabled))
{
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
print '<td width="5%">&nbsp;</td>'; print '<td></td>';
print '<td>'.$langs->trans("batch_number").'</td>';
print '<td>'.$langs->trans("l_eatby").'</td>'; print '<td>'.$langs->trans("l_eatby").'</td>';
print '<td>'.$langs->trans("l_sellby").'</td>'; print '<td>'.$langs->trans("l_sellby").'</td>';
print '<td>'.$langs->trans("batch_number").'</td>'; print '<td colspan="4">&nbsp;</td>';
print '<td colspan="4" width="50%">&nbsp;</td>';
print "</tr>\n"; print "</tr>\n";
} }
@ -346,19 +356,47 @@ if ($id > 0 || ! empty($ref))
{ {
$remaintodispatch=($objp->qty - (empty($products_dispatched[$objp->fk_product])?0:$products_dispatched[$objp->fk_product])); // Calculation of dispatched $remaintodispatch=($objp->qty - (empty($products_dispatched[$objp->fk_product])?0:$products_dispatched[$objp->fk_product])); // Calculation of dispatched
if ($remaintodispatch < 0) $remaintodispatch=0; if ($remaintodispatch < 0) $remaintodispatch=0;
if ($remaintodispatch)
if ($remaintodispatch || empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED))
{ {
$nbproduct++; $nbproduct++;
$var=!$var; $var=!$var;
print "<tr ".$bc[$var].">"; print "<tr ".$bc[$var].">";
print '<td colspan="4">';
print '<a href="'.DOL_URL_ROOT.'/product/fournisseurs.php?id='.$objp->fk_product.'">'.img_object($langs->trans("ShowProduct"),'product').' '.$objp->ref.'</a>'; $linktoprod='<a href="'.DOL_URL_ROOT.'/product/fournisseurs.php?id='.$objp->fk_product.'">'.img_object($langs->trans("ShowProduct"),'product').' '.$objp->ref.'</a>';
print ' - '.$objp->label."\n"; $linktoprod.=' - '.$objp->label."\n";
if (! empty($conf->productbatch->enabled))
{
if ($objp->tobatch)
{
print '<td colspan="4">';
print $linktoprod;
print "</td>";
}
else
{
print '<td>';
print $linktoprod;
print "</td>";
print '<td colspan="3">';
print $langs->trans("ProductDoesNotUseBatchSerial");
print '</td>';
}
}
else
{
print '<td>';
print $linktoprod;
print "</td>";
}
// To show detail cref and description value, we must make calculation by cref // To show detail cref and description value, we must make calculation by cref
//print ($objp->cref?' ('.$objp->cref.')':''); //print ($objp->cref?' ('.$objp->cref.')':'');
//if ($objp->description) print '<br>'.nl2br($objp->description); //if ($objp->description) print '<br>'.nl2br($objp->description);
if ((empty($conf->productbatch->enabled)) || $objp->tobatch==0) { if ((empty($conf->productbatch->enabled)) || $objp->tobatch==0)
{
$suffix='_'.$i; $suffix='_'.$i;
} else { } else {
$suffix='_0_'.$i; $suffix='_0_'.$i;
@ -367,32 +405,44 @@ if ($id > 0 || ! empty($ref))
$up_ht_disc=$objp->subprice; $up_ht_disc=$objp->subprice;
if (! empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) $up_ht_disc=price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU'); if (! empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) $up_ht_disc=price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
print "</td>\n"; // Qty ordered
print '<td align="right">'.$objp->qty.'</td>'; print '<td align="right">'.$objp->qty.'</td>';
// Already dispatched
print '<td align="right">'.$products_dispatched[$objp->fk_product].'</td>'; print '<td align="right">'.$products_dispatched[$objp->fk_product].'</td>';
if ( !(empty($conf->productbatch->enabled)) && $objp->tobatch==1) { if (! empty($conf->productbatch->enabled) && $objp->tobatch==1)
print '<td colspan="2" align="center">'.img_picto_common($langs->trans('AddDispatchBatchLine'),'treemenu/plustop2.gif','onClick="AddLineBatch('.$i.')"').'</td>'; {
print '<td align="right">'.img_picto($langs->trans('AddDispatchBatchLine'),'split.png','onClick="addLineBatch('.$i.')"').'</td>'; // Dispatch column
print '<td></td>'; // Warehouse column
print '</tr>'; print '</tr>';
print '<tr '.$bc[$var].' name="dluo'.$suffix.'"><td width="5%">';
print '<tr '.$bc[$var].' name="dluo'.$suffix.'">';
print '<td>';
print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">'; print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
print '<input name="pu'.$suffix.'" type="hidden" value="'.$up_ht_disc.'"><!-- This is a up including discount -->'; print '<input name="pu'.$suffix.'" type="hidden" value="'.$up_ht_disc.'"><!-- This is a up including discount -->';
print '</td><td>';
$form->select_date('','dlc'.$suffix,'','',1,"");
print '</td><td>';
$form->select_date('','dluo'.$suffix,'','',1,"");
print '</td><td>';
print '<input type="text" name="lot_number'.$suffix.'" size="40" value="">';
print '</td>'; print '</td>';
print '<td colspan="2">&nbsp</td>'; print '<td>';
} else { print '<input type="text" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" size="40" value="">';
print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">'; print '</td>';
print '<input name="pu'.$suffix.'" type="hidden" value="'.$up_ht_disc.'"><!-- This is a up including discount -->'; print '<td>';
$form->select_date('','dlc'.$suffix,'','',1,"");
print '</td>';
print '<td>';
$form->select_date('','dluo'.$suffix,'','',1,"");
print '</td>';
print '<td colspan="2">&nbsp</td>'; // Qty ordered + qty already dispatached
} }
// Dispatch // Dispatch
print '<td align="right"><input name="qty'.$suffix.'" type="text" size="8" value="'.($remaintodispatch).'"></td>'; print '<td align="right">';
if (empty($conf->productbatch->enabled) || $objp->tobatch!=1)
{
print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
print '<input name="pu'.$suffix.'" type="hidden" value="'.$up_ht_disc.'"><!-- This is a up including discount -->';
}
print '<input id="qty'.$suffix.'" name="qty'.$suffix.'" type="text" size="8" value="'.($remaintodispatch).'">';
print '</td>';
// Warehouse // Warehouse
print '<td align="right">'; print '<td align="right">';
@ -409,6 +459,7 @@ if ($id > 0 || ! empty($ref))
print $langs->trans("NoWarehouseDefined"); print $langs->trans("NoWarehouseDefined");
} }
print "</td>\n"; print "</td>\n";
print "</tr>\n"; print "</tr>\n";
} }
} }
@ -430,11 +481,13 @@ if ($id > 0 || ! empty($ref))
print '<input type="text" size="60" maxlength="128" name="comment" value="'; print '<input type="text" size="60" maxlength="128" name="comment" value="';
print $_POST["comment"]?GETPOST("comment"):$langs->trans("DispatchSupplierOrder",$commande->ref); print $_POST["comment"]?GETPOST("comment"):$langs->trans("DispatchSupplierOrder",$commande->ref);
// print ' / '.$commande->ref_supplier; // Not yet available // print ' / '.$commande->ref_supplier; // Not yet available
print '" class="flat"><br><br>'; print '" class="flat"> &nbsp; ';
print '<div class="center"><input type="submit" class="button" value="'.$langs->trans("DispatchVerb").'"'; //print '<div class="center">';
print '<input type="submit" class="button" value="'.$langs->trans("DispatchVerb").'"';
if (count($listwarehouses) <= 0) print ' disabled="disabled"'; if (count($listwarehouses) <= 0) print ' disabled="disabled"';
print '></div>'; print '>';
//print '</div>';
} }
if (! $nbproduct && $nbfreeproduct) if (! $nbproduct && $nbfreeproduct)
{ {
@ -449,7 +502,7 @@ if ($id > 0 || ! empty($ref))
// List of already dispatching // List of already dispatching
$sql = "SELECT p.ref, p.label,"; $sql = "SELECT p.ref, p.label,";
$sql.= " e.rowid as warehouse_id, e.label as entrepot,"; $sql.= " e.rowid as warehouse_id, e.label as entrepot,";
$sql.= " cfd.rowid, cfd.fk_product, cfd.qty, cfd.comment, cfd.status"; $sql.= " cfd.rowid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status";
$sql.= " FROM ".MAIN_DB_PREFIX."product as p,"; $sql.= " FROM ".MAIN_DB_PREFIX."product as p,";
$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd"; $sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
@ -473,6 +526,12 @@ if ($id > 0 || ! empty($ref))
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Description").'</td>'; print '<td>'.$langs->trans("Description").'</td>';
if (! empty($conf->productbatch->enabled))
{
print '<td>'.$langs->trans("batch_number").'</td>';
print '<td>'.$langs->trans("l_eatby").'</td>';
print '<td>'.$langs->trans("l_sellby").'</td>';
}
print '<td align="right">'.$langs->trans("QtyDispatched").'</td>'; print '<td align="right">'.$langs->trans("QtyDispatched").'</td>';
print '<td></td>'; print '<td></td>';
print '<td>'.$langs->trans("Warehouse").'</td>'; print '<td>'.$langs->trans("Warehouse").'</td>';
@ -491,6 +550,13 @@ if ($id > 0 || ! empty($ref))
print ' - '.$objp->label; print ' - '.$objp->label;
print "</td>\n"; print "</td>\n";
if (! empty($conf->productbatch->enabled))
{
print '<td>'.$objp->batch.'</td>';
print '<td>'.dol_print_date($db->jdate($objp->eatby),'day').'</td>';
print '<td>'.dol_print_date($db->jdate($objp->sellby),'day').'</td>';
}
// Qty // Qty
print '<td align="right">'.$objp->qty.'</td>'; print '<td align="right">'.$objp->qty.'</td>';
print '<td>&nbsp;</td>'; print '<td>&nbsp;</td>';

View File

@ -105,6 +105,8 @@ ALTER TABLE llx_product_fournisseur_price ADD COLUMN delivery_time_days integer;
ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN comment varchar(255); ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN comment varchar(255);
ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN status integer; ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN status integer;
ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN tms timestamp; ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN tms timestamp;
ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN eatby date DEFAULT NULL;
ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN sellby date DEFAULT NULL;
ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN batch varchar(30) DEFAULT NULL;

View File

@ -14,6 +14,9 @@
-- You should have received a copy of the GNU General Public License -- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>. -- along with this program. If not, see <http://www.gnu.org/licenses/>.
-- --
-- This table is just an history table to track all receiving done for a
-- particular supplier order. A movement with same information is also done
-- into stock_movement so this table may be useless.
-- =================================================================== -- ===================================================================
create table llx_commande_fournisseur_dispatch create table llx_commande_fournisseur_dispatch
@ -25,6 +28,9 @@ create table llx_commande_fournisseur_dispatch
fk_entrepot integer, fk_entrepot integer,
fk_user integer, fk_user integer,
comment varchar(255), -- comment on movement comment varchar(255), -- comment on movement
eatby date DEFAULT NULL,
sellby date DEFAULT NULL,
batch varchar(30) DEFAULT NULL,
status integer, status integer,
datec datetime, datec datetime,
tms timestamp tms timestamp

View File

@ -158,6 +158,8 @@ ErrorPriceExpression21=Empty result '%s'
ErrorPriceExpression22=Negative result '%s' ErrorPriceExpression22=Negative result '%s'
ErrorPriceExpressionInternal=Internal error '%s' ErrorPriceExpressionInternal=Internal error '%s'
ErrorPriceExpressionUnknown=Unknown error '%s' ErrorPriceExpressionUnknown=Unknown error '%s'
ErrorSrcAndTargetWarehouseMustDiffers=Source and target warehouses must differs
ErrorTryToMakeMoveOnProductRequiringBatchData=Error, trying to make a stock movement without batch/serial information, on a product requiring batch/serial information
# Warnings # Warnings
WarningMandatorySetupNotComplete=Mandatory setup parameters are not yet defined WarningMandatorySetupNotComplete=Mandatory setup parameters are not yet defined

View File

@ -1,9 +1,9 @@
# ProductBATCH language file - en_US - ProductBATCH # ProductBATCH language file - en_US - ProductBATCH
ManageLotSerial=Manage batch/serial ManageLotSerial=Use batch/serial number
ProductStatusOnBatch=Managed ProductStatusOnBatch=Yes (Batch/serial required)
ProductStatusNotOnBatch=Not Managed ProductStatusNotOnBatch=No (Batch/serial not used)
ProductStatusOnBatchShort=Managed ProductStatusOnBatchShort=Yes
ProductStatusNotOnBatchShort=Not Managed ProductStatusNotOnBatchShort=No
Batch=Batch/Serial Batch=Batch/Serial
atleast1batchfield=Eat-by date or Sell-by date or Batch number atleast1batchfield=Eat-by date or Sell-by date or Batch number
batch_number=Batch/Serial number batch_number=Batch/Serial number
@ -18,3 +18,4 @@ printQty=Qty: %d
AddDispatchBatchLine=Add a line for Shelf Life dispatching AddDispatchBatchLine=Add a line for Shelf Life dispatching
BatchDefaultNumber=Undefined BatchDefaultNumber=Undefined
WhenProductBatchModuleOnOptionAreForced=When module Batch/Serial is on, increase/decrease stock mode is forced to last choice and can't be edited. Other options can be defined as you want. WhenProductBatchModuleOnOptionAreForced=When module Batch/Serial is on, increase/decrease stock mode is forced to last choice and can't be edited. Other options can be defined as you want.
ProductDoesNotUseBatchSerial=This product does not use batch/serial number

View File

@ -48,6 +48,8 @@ PMPValueShort=WAP
EnhancedValueOfWarehouses=Warehouses value EnhancedValueOfWarehouses=Warehouses value
UserWarehouseAutoCreate=Create a warehouse automatically when creating a user UserWarehouseAutoCreate=Create a warehouse automatically when creating a user
QtyDispatched=Quantity dispatched QtyDispatched=Quantity dispatched
QtyDispatchedShort=Qty dispatched
QtyToDispatchShort=Qty to dispatch
OrderDispatch=Stock dispatching OrderDispatch=Stock dispatching
RuleForStockManagementDecrease=Rule for stock management decrease RuleForStockManagementDecrease=Rule for stock management decrease
RuleForStockManagementIncrease=Rule for stock management increase RuleForStockManagementIncrease=Rule for stock management increase
@ -125,3 +127,4 @@ StockMustBeEnoughForShipment= Stock level must be enough to add product/service
MovementLabel=Label of movement MovementLabel=Label of movement
InventoryCode=Inventory code InventoryCode=Inventory code
IsInPackage=Contained into package IsInPackage=Contained into package
ShowWarehouse=Show warehouse

View File

@ -122,4 +122,3 @@ RuleForStockAvailability=Règles d'exigence sur les stocks
StockMustBeEnoughForInvoice=Le niveau de stock doit être suffisant pour ajouter un produit/service dans une facture StockMustBeEnoughForInvoice=Le niveau de stock doit être suffisant pour ajouter un produit/service dans une facture
StockMustBeEnoughForOrder=Le niveau de stock doit être suffisant pour ajouter un produit/service dans une commande StockMustBeEnoughForOrder=Le niveau de stock doit être suffisant pour ajouter un produit/service dans une commande
StockMustBeEnoughForShipment= Le niveau de stock doit être suffisant pour ajouter un produit/service dans une expédition StockMustBeEnoughForShipment= Le niveau de stock doit être suffisant pour ajouter un produit/service dans une expédition

View File

@ -3057,6 +3057,51 @@ class Product extends CommonObject
} }
} }
/**
* Adjust stock in a warehouse for product with batch number
*
* @param User $user user asking change
* @param int $id_entrepot id of warehouse
* @param double $nbpiece nb of units
* @param int $movement 0 = add, 1 = remove
* @param string $label Label of stock movement
* @param double $price Price to use for stock eval
* @param date $dlc eat-by date
* @param date $dluo sell-by date
* @param string $lot Lot number
* @param string $inventorycode Inventory code
* @return int <0 if KO, >0 if OK
*/
function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='',$lot='', $inventorycode='')
{
if ($id_entrepot)
{
$this->db->begin();
require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
$op[0] = "+".trim($nbpiece);
$op[1] = "-".trim($nbpiece);
$movementstock=new MouvementStock($this->db);
$result=$movementstock->_create($user,$this->id,$id_entrepot,$op[$movement],$movement,$price,$label,$inventorycode,'',$dlc,$dluo,$lot);
if ($result >= 0)
{
$this->db->commit();
return 1;
}
else
{
$this->error=$movementstock->error;
$this->errors=$movementstock->errors;
$this->db->rollback();
return -1;
}
}
}
/** /**
* Load information about stock of a product into stock_warehouse[] and stock_reel * Load information about stock of a product into stock_warehouse[] and stock_reel
* *
@ -3646,48 +3691,6 @@ class Product extends CommonObject
return ($this->status_batch == 1 ? true : false); return ($this->status_batch == 1 ? true : false);
} }
/**
* Adjust stock in a warehouse for product with batch number
*
* @param User $user user asking change
* @param int $id_entrepot id of warehouse
* @param double $nbpiece nb of units
* @param int $movement 0 = add, 1 = remove
* @param string $label Label of stock movement
* @param double $price Price to use for stock eval
* @param date $dlc eat-by date
* @param date $dluo sell-by date
* @param string $lot Lot number
* @param string $inventorycode Inventory code
* @return int <0 if KO, >0 if OK
*/
function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='',$lot='', $inventorycode='')
{
if ($id_entrepot)
{
$this->db->begin();
require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
$op[0] = "+".trim($nbpiece);
$op[1] = "-".trim($nbpiece);
$movementstock=new MouvementStock($this->db);
$result=$movementstock->_create($user,$this->id,$id_entrepot,$op[$movement],$movement,$price,$label,$inventorycode,'',$dlc,$dluo,$lot);
if ($result >= 0)
{
$this->db->commit();
return 1;
}
else
{
$this->error=$movementstock->error;
$this->db->rollback();
return -1;
}
}
}
/** /**
* Return minimum product recommended price * Return minimum product recommended price

View File

@ -87,13 +87,12 @@ class Productbatch extends CommonObject
$sql.= "import_key"; $sql.= "import_key";
$sql.= ") VALUES ("; $sql.= ") VALUES (";
$sql.= " ".(! isset($this->fk_product_stock)?'NULL':$this->fk_product_stock).","; $sql.= " ".(! isset($this->fk_product_stock)?'NULL':$this->fk_product_stock).",";
$sql.= " ".(! isset($this->sellby) || dol_strlen($this->sellby)==0?'NULL':$this->db->idate($this->sellby)).","; $sql.= " ".(! isset($this->sellby) || dol_strlen($this->sellby)==0?'NULL':"'".$this->db->idate($this->sellby)."'").",";
$sql.= " ".(! isset($this->eatby) || dol_strlen($this->eatby)==0?'NULL':$this->db->idate($this->eatby)).","; $sql.= " ".(! isset($this->eatby) || dol_strlen($this->eatby)==0?'NULL':"'".$this->db->idate($this->eatby)."'").",";
$sql.= " ".(! isset($this->batch)?'NULL':"'".$this->db->escape($this->batch)."'").","; $sql.= " ".(! isset($this->batch)?'NULL':"'".$this->db->escape($this->batch)."'").",";
$sql.= " ".(! isset($this->qty)?'NULL':$this->qty).","; $sql.= " ".(! isset($this->qty)?'NULL':$this->qty).",";
$sql.= " ".(! isset($this->import_key)?'NULL':"'".$this->db->escape($this->import_key)."'").""; $sql.= " ".(! isset($this->import_key)?'NULL':"'".$this->db->escape($this->import_key)."'")."";
$sql.= ")"; $sql.= ")";
$this->db->begin(); $this->db->begin();
@ -122,11 +121,6 @@ class Productbatch extends CommonObject
// Commit or rollback // Commit or rollback
if ($error) if ($error)
{ {
foreach($this->errors as $errmsg)
{
dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
$this->error.=($this->error?', '.$errmsg:$errmsg);
}
$this->db->rollback(); $this->db->rollback();
return -1*$error; return -1*$error;
} }

View File

@ -510,6 +510,7 @@ class Entrepot extends CommonObject
function getNomUrl($withpicto=0,$option='') function getNomUrl($withpicto=0,$option='')
{ {
global $langs; global $langs;
$langs->load("stocks");
$result=''; $result='';
$label = '<u>' . $langs->trans("ShowWarehouse").'</u>'; $label = '<u>' . $langs->trans("ShowWarehouse").'</u>';

View File

@ -95,6 +95,19 @@ class MouvementStock extends CommonObject
} }
$product->load_stock(); $product->load_stock();
// Test if product require batch data. If yes, and there is not, we throw an error.
if ($product->hasbatch() && ! $skip_sellby)
{
if (empty($batch) && empty($eatby) && empty($sellby))
{
$this->errors[]="ErrorTryToMakeMoveOnProductRequiringBatchData";
dol_syslog("Try to make a movement of a product with status_batch on without any batch data");
$this->db->rollback();
return -2;
}
}
// Define if we must make the stock change (If product type is a service or if stock is used also for services) // Define if we must make the stock change (If product type is a service or if stock is used also for services)
$movestock=0; $movestock=0;
if ($product->type != 1 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) $movestock=1; if ($product->type != 1 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) $movestock=1;
@ -250,7 +263,7 @@ class MouvementStock extends CommonObject
// Update detail stock for sell-by date // Update detail stock for sell-by date
if (($product->hasbatch()) && (! $error) && (! $skip_sellby)) if (($product->hasbatch()) && (! $error) && (! $skip_sellby))
{ {
$param_batch=array('fk_product_stock' =>$fk_product_stock, 'eatby'=>$eatby,'sellby'=>$sellby,'batchnumber'=>$batch); $param_batch=array('fk_product_stock' =>$fk_product_stock, 'eatby'=>$eatby, 'sellby'=>$sellby, 'batchnumber'=>$batch);
$result=$this->_create_batch($param_batch, $qty); $result=$this->_create_batch($param_batch, $qty);
if ($result<0) $error++; if ($result<0) $error++;
} }
@ -462,10 +475,13 @@ class MouvementStock extends CommonObject
* @param int $qty Quantity of product with batch number * @param int $qty Quantity of product with batch number
* @return int <0 if KO, else return productbatch id * @return int <0 if KO, else return productbatch id
*/ */
function _create_batch($dluo, $qty ) { function _create_batch($dluo, $qty )
$pdluo=New Productbatch($this->db); {
$pdluo=new Productbatch($this->db);
//Try to find an existing record with batch same batch number or id $result=0;
// Try to find an existing record with batch same batch number or id
if (is_numeric($dluo)) { if (is_numeric($dluo)) {
$result=$pdluo->fetch($dluo); $result=$pdluo->fetch($dluo);
} else if (is_array($dluo)) { } else if (is_array($dluo)) {
@ -481,25 +497,34 @@ class MouvementStock extends CommonObject
} }
} else { } else {
dol_syslog(get_class($this)."::_create_batch error invalid param dluo".$error, LOG_ERR); dol_syslog(get_class($this)."::_create_batch error invalid param dluo".$error, LOG_ERR);
$result = -1; $result = -1;
} }
//batch record found so we update it //batch record found so we update it
if ($result>0) { if ($result>0)
if ($pdluo->id >0) { {
if ($pdluo->id >0)
{
$pdluo->qty +=$qty; $pdluo->qty +=$qty;
if ($pdluo->qty == 0) { if ($pdluo->qty == 0) {
$result=$pdluo->delete(0,1); $result=$pdluo->delete(0,1);
} else { } else {
$result=$pdluo->update(0,1); $result=$pdluo->update(0,1);
} }
} else { }
else
{
$pdluo->fk_product_stock=$vfk_product_stock; $pdluo->fk_product_stock=$vfk_product_stock;
$pdluo->qty = $qty; $pdluo->qty = $qty;
$pdluo->eatby = $veatby; $pdluo->eatby = $veatby;
$pdluo->sellby = $vsellby; $pdluo->sellby = $vsellby;
$pdluo->batch = $vbatchnumber; $pdluo->batch = $vbatchnumber;
$result=$pdluo->create(0,1); $result=$pdluo->create(0,1);
if ($result < 0)
{
$this->error=$pdluo->error;
$this->errors=$pdluo->errors;
}
} }
return $result; return $result;
} else { } else {

View File

@ -78,10 +78,10 @@ if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter")) // Both
* Actions * Actions
*/ */
if ($cancel) $action=''; if ($cancel) $action=''; // Protection to avoid action for all cancel buttons
// Correct stock // Correct stock
if ($action == "correct_stock" && ! $_POST["cancel"]) if ($action == "correct_stock")
{ {
if (is_numeric($_POST["nbpiece"]) && $product_id) if (is_numeric($_POST["nbpiece"]) && $product_id)
{ {

View File

@ -47,13 +47,17 @@ if (! empty($conf->productbatch->enabled)) $langs->load("productbatch");
$action=GETPOST("action"); $action=GETPOST("action");
$cancel=GETPOST('cancel'); $cancel=GETPOST('cancel');
// Security check
$id=GETPOST('id', 'int'); $id=GETPOST('id', 'int');
$ref=GETPOST('ref', 'alpha'); $ref=GETPOST('ref', 'alpha');
$stocklimit = GETPOST('stocklimit'); $stocklimit = GETPOST('stocklimit');
$desiredstock = GETPOST('desiredstock'); $desiredstock = GETPOST('desiredstock');
$cancel = GETPOST('cancel'); $cancel = GETPOST('cancel');
$fieldid = isset($_GET["ref"])?'ref':'rowid'; $fieldid = isset($_GET["ref"])?'ref':'rowid';
$d_eatby=dol_mktime(12, 0, 0, $_POST['eatbymonth'], $_POST['eatbyday'], $_POST['eatbyyear']);
$d_sellby=dol_mktime(12, 0, 0, $_POST['sellbymonth'], $_POST['sellbyday'], $_POST['sellbyyear']);
$pdluoid=GETPOST('pdluoid','int');
// Security check
if ($user->societe_id) $socid=$user->societe_id; if ($user->societe_id) $socid=$user->societe_id;
$result=restrictedArea($user,'produit&stock',$id,'product&product','','',$fieldid); $result=restrictedArea($user,'produit&stock',$id,'product&product','','',$fieldid);
@ -128,8 +132,6 @@ if ($action == "correct_stock" && ! $cancel)
} }
if ($product->hasbatch()) if ($product->hasbatch())
{ {
$d_eatby=dol_mktime(12, 0, 0, $_POST['eatbymonth'], $_POST['eatbyday'], $_POST['eatbyyear']);
$d_sellby=dol_mktime(12, 0, 0, $_POST['sellbymonth'], $_POST['sellbyday'], $_POST['sellbyyear']);
$result=$product->correct_stock_batch( $result=$product->correct_stock_batch(
$user, $user,
GETPOST("id_entrepot"), GETPOST("id_entrepot"),
@ -185,91 +187,116 @@ if ($action == "transfert_stock" && ! $cancel)
$error++; $error++;
$action='transfert'; $action='transfert';
} }
if (GETPOST("id_entrepot_source",'int') == GETPOST("id_entrepot_destination",'int'))
{
setEventMessage($langs->trans("ErrorSrcAndTargetWarehouseMustDiffers"), 'errors');
$error++;
$action='transfert';
}
if (! $error) if (! $error)
{ {
if (GETPOST("id_entrepot_source",'int') <> GETPOST("id_entrepot_destination",'int')) if ($id)
{ {
if (GETPOST("nbpiece",'int') && $id) $product = new Product($db);
$result=$product->fetch($id);
$db->begin();
$product->load_stock(); // Load array product->stock_warehouse
// Define value of products moved
$pricesrc=0;
//if (isset($product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp)) $pricesrc=$product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp;
if (isset($product->pmp)) $pricesrc=$product->pmp;
$pricedest=$pricesrc;
if ($product->hasbatch())
{ {
$product = new Product($db); $pdluo = new Productbatch($db);
$result=$product->fetch($id);
$db->begin(); if ($pdluoid > 0)
$product->load_stock(); // Load array product->stock_warehouse
// Define value of products moved
$pricesrc=0;
//if (isset($product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp)) $pricesrc=$product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp;
if (isset($product->pmp)) $pricesrc=$product->pmp;
$pricedest=$pricesrc;
$pdluoid=GETPOST('pdluoid','int');
if ($pdluoid>0)
{ {
$pdluo = new Productbatch($db); $result=$pdluo->fetch($pdluoid);
$result=$pdluo->fetch($pdluoid); if ($result)
{
if ($result>0 && $pdluo->id) $srcwarehouseid=$pdluo->warehouseid;
{ $batch=$pdluo->batch;
// Remove stock $eatby=$pdluo->eatby;
$result1=$product->correct_stock_batch( $sellby=$pdluo->sellby;
$user, }
$pdluo->warehouseid, else
GETPOST("nbpiece",'int'), {
1, setEventMessages($pdluo->error, $pdluo->errors, 'errors');
GETPOST("label",'san_alpha'), $error++;
$pricesrc, }
$pdluo->eatby,$pdluo->sellby,$pdluo->batch
);
// Add stock
$result2=$product->correct_stock_batch(
$user,
GETPOST("id_entrepot_destination",'int'),
GETPOST("nbpiece",'int'),
0,
GETPOST("label",'san_alpha'),
$pricedest,
$pdluo->eatby,$pdluo->sellby,$pdluo->batch
);
}
} }
else else
{ {
// Remove stock $srcwarehouseid=GETPOST('id_entrepot_source','int');
$result1=$product->correct_stock( $batch=GETPOST('batch_number');
$user, $eatby=$d_eatby;
GETPOST("id_entrepot_source"), $sellby=$d_sellby;
GETPOST("nbpiece"), }
1,
GETPOST("label"),
$pricesrc
);
// Add stock if (! $error)
$result2=$product->correct_stock(
$user,
GETPOST("id_entrepot_destination"),
GETPOST("nbpiece"),
0,
GETPOST("label"),
$pricedest
);
}
if ($result1 >= 0 && $result2 >= 0)
{ {
$db->commit(); // Remove stock
header("Location: product.php?id=".$product->id); $result1=$product->correct_stock_batch(
exit; $user,
} $srcwarehouseid,
else GETPOST("nbpiece",'int'),
{ 1,
setEventMessage($product->error, 'errors'); GETPOST("label",'san_alpha'),
$db->rollback(); $pricesrc,
$eatby,$sellby,$batch
);
// Add stock
$result2=$product->correct_stock_batch(
$user,
GETPOST("id_entrepot_destination",'int'),
GETPOST("nbpiece",'int'),
0,
GETPOST("label",'san_alpha'),
$pricedest,
$eatby,$sellby,$batch
);
} }
} }
else
{
// Remove stock
$result1=$product->correct_stock(
$user,
GETPOST("id_entrepot_source"),
GETPOST("nbpiece"),
1,
GETPOST("label"),
$pricesrc
);
// Add stock
$result2=$product->correct_stock(
$user,
GETPOST("id_entrepot_destination"),
GETPOST("nbpiece"),
0,
GETPOST("label"),
$pricedest
);
}
if (! $error && $result1 >= 0 && $result2 >= 0)
{
$db->commit();
header("Location: product.php?id=".$product->id);
exit;
}
else
{
setEventMessages($product->error, $product->errors, 'errors');
$db->rollback();
$action='transfert';
}
} }
} }
} }
@ -578,14 +605,15 @@ if ($id > 0 || $ref)
print '<td width="20%" class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td><td width="20%"><input class="flat" name="nbpiece" id="nbpiece" size="10" value="'.GETPOST("nbpiece").'"></td>'; print '<td width="20%" class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td><td width="20%"><input class="flat" name="nbpiece" id="nbpiece" size="10" value="'.GETPOST("nbpiece").'"></td>';
print '</tr>'; print '</tr>';
// Label // Purchase price
print '<tr>'; print '<tr>';
print '<td width="20%" colspan="2">'.$langs->trans("UnitPurchaseValue").'</td>'; print '<td width="20%" colspan="2">'.$langs->trans("UnitPurchaseValue").'</td>';
print '<td colspan="4"><input class="flat" name="price" id="unitprice" size="10" value="'.GETPOST("unitprice").'"></td>'; print '<td colspan="4"><input class="flat" name="price" id="unitprice" size="10" value="'.GETPOST("unitprice").'"></td>';
print '</tr>'; print '</tr>';
//eat-by date // Eat-by date
if ((! empty($conf->productbatch->enabled)) && $product->hasbatch()) { if ((! empty($conf->productbatch->enabled)) && $product->hasbatch())
{
print '<tr>'; print '<tr>';
print '<td colspan="2">'.$langs->trans("batch_number").'</td><td colspan="4">'; print '<td colspan="2">'.$langs->trans("batch_number").'</td><td colspan="4">';
print '<input type="text" name="batch_number" size="40" value="'.GETPOST("batch_number").'">'; print '<input type="text" name="batch_number" size="40" value="'.GETPOST("batch_number").'">';
@ -627,9 +655,10 @@ if ($id > 0 || $ref)
{ {
$pdluoid=GETPOST('pdluoid','int'); $pdluoid=GETPOST('pdluoid','int');
$pdluo = new Productbatch($db);
if ($pdluoid > 0) if ($pdluoid > 0)
{ {
$pdluo = new Productbatch($db);
$result=$pdluo->fetch($pdluoid); $result=$pdluo->fetch($pdluoid);
if ($result > 0) if ($result > 0)
@ -653,25 +682,43 @@ if ($id > 0 || $ref)
print '<table class="border" width="100%">'; print '<table class="border" width="100%">';
print '<tr>'; print '<tr>';
print '<td width="20%" class="fieldrequired">'.$langs->trans("WarehouseSource").'</td><td width="20%">'; print '<td width="15%" class="fieldrequired">'.$langs->trans("WarehouseSource").'</td><td width="15%">';
if ($pdluoid) if ($pdluoid)
{ {
print $formproduct->selectWarehouses($pdluo->warehouseid,'id_entrepot_source','',1,1); print $formproduct->selectWarehouses($pdluo->warehouseid,'id_entrepot_source','',1,1);
} }
else else
{ {
print $formproduct->selectWarehouses((GETPOST("dwid")?GETPOT("dwid",'int'):(GETPOST('id_entrepot')?GETPOST('id_entrepot_source','int'):'ifone')),'id_entrepot_source','',1); print $formproduct->selectWarehouses((GETPOST("dwid")?GETPOT("dwid",'int'):(GETPOST('id_entrepot_source')?GETPOST('id_entrepot_source','int'):'ifone')),'id_entrepot_source','',1);
} }
print '</td>'; print '</td>';
print '<td width="20%" class="fieldrequired">'.$langs->trans("WarehouseTarget").'</td><td width="20%">'; print '<td width="15%" class="fieldrequired">'.$langs->trans("WarehouseTarget").'</td><td width="15%">';
print $formproduct->selectWarehouses(GETPOST('id_entrepot_destination'),'id_entrepot_destination','',1); print $formproduct->selectWarehouses(GETPOST('id_entrepot_destination'),'id_entrepot_destination','',1);
print '</td>'; print '</td>';
print '<td width="20%" class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td><td width="20%"><input type="text" class="flat" name="nbpiece" size="10" value="'.dol_escape_htmltag(GETPOST("nbpiece")).'"></td>'; print '<td width="15%" class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td><td width="15%"><input type="text" class="flat" name="nbpiece" size="10" value="'.dol_escape_htmltag(GETPOST("nbpiece")).'"></td>';
print '</tr>'; print '</tr>';
// Eat-by date
if ((! empty($conf->productbatch->enabled)) && $product->hasbatch())
{
print '<tr>';
print '<td>'.$langs->trans("batch_number").'</td><td colspan="5">';
print '<input type="text" name="batch_number" size="40"'.($pdluoid > 0 ? ' disabled="true"':'').' value="'.(GETPOST('batch_number')?GETPOST('batch_number'):$pdluo->batch).'">'; // If form was opened for a specific pdluoid, field is disabled
print '</td>';
print '</tr><tr>';
print '<td>'.$langs->trans("l_eatby").'</td><td>';
print $form->select_date(($d_eatby?$d_eatby:$pdluo->eatby),'eatby','','',1,"", 1, 0, 1, ($pdluoid > 0 ? 1 : 0)); // If form was opened for a specific pdluoid, field is disabled
print '</td>';
print '<td>'.$langs->trans("l_sellby").'</td><td>';
print $form->select_date(($d_sellby?$d_sellby:$pdluo->sellby),'sellby','','',1,"", 1, 0, 1, ($pdluoid > 0 ? 1 : 0)); // If form was opened for a specific pdluoid, field is disabled
print '</td>';
print '<td colspan="2"></td>';
print '</tr>';
}
// Label // Label
print '<tr>'; print '<tr>';
print '<td width="20%">'.$langs->trans("LabelMovement").'</td>'; print '<td width="15%">'.$langs->trans("MovementLabel").'</td>';
print '<td colspan="5">'; print '<td colspan="5">';
print '<input type="text" name="label" size="80" value="'.dol_escape_htmltag(GETPOST("label")).'">'; print '<input type="text" name="label" size="80" value="'.dol_escape_htmltag(GETPOST("label")).'">';
print '</td>'; print '</td>';
@ -699,9 +746,9 @@ if ($id > 0 || $ref)
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
print '<input type="hidden" name="action" value="create_stock">'; print '<input type="hidden" name="action" value="create_stock">';
print '<table class="border" width="100%"><tr>'; print '<table class="border" width="100%"><tr>';
print '<td width="20%">'.$langs->trans("Warehouse").'</td><td width="40%">'; print '<td width="15%">'.$langs->trans("Warehouse").'</td><td width="40%">';
print $formproduct->selectWarehouses('','id_entrepot','',1); print $formproduct->selectWarehouses('','id_entrepot','',1);
print '</td><td width="20%">'.$langs->trans("NumberOfUnit").'</td><td width="20%"><input name="nbpiece" size="10" value=""></td></tr>'; print '</td><td width="15%">'.$langs->trans("NumberOfUnit").'</td><td width="15%"><input name="nbpiece" size="10" value=""></td></tr>';
print '<tr><td colspan="4" align="center"><input type="submit" class="button" value="'.$langs->trans('Save').'">&nbsp;'; print '<tr><td colspan="4" align="center"><input type="submit" class="button" value="'.$langs->trans('Save').'">&nbsp;';
print '<input type="submit" class="button" name="cancel" value="'.$langs->trans('Cancel').'"></td></tr>'; print '<input type="submit" class="button" name="cancel" value="'.$langs->trans('Cancel').'"></td></tr>';
print '</table>'; print '</table>';
@ -731,7 +778,8 @@ if (empty($action) && $product->id)
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$product->id.'&amp;action=correction">'.$langs->trans("StockCorrection").'</a>'; print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$product->id.'&amp;action=correction">'.$langs->trans("StockCorrection").'</a>';
} }
if (($user->rights->stock->mouvement->creer) && !$product->hasbatch()) //if (($user->rights->stock->mouvement->creer) && ! $product->hasbatch())
if (($user->rights->stock->mouvement->creer))
{ {
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$product->id.'&amp;action=transfert">'.$langs->trans("StockMovement").'</a>'; print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$product->id.'&amp;action=transfert">'.$langs->trans("StockMovement").'</a>';
} }
@ -753,7 +801,8 @@ print '<td align="right">'.$langs->trans("EstimatedStockValueShort").'</td>';
print '<td align="right">'.$langs->trans("SellPriceMin").'</td>'; print '<td align="right">'.$langs->trans("SellPriceMin").'</td>';
print '<td align="right">'.$langs->trans("EstimatedStockValueSellShort").'</td>'; print '<td align="right">'.$langs->trans("EstimatedStockValueSellShort").'</td>';
print '</tr>'; print '</tr>';
if ( (! empty($conf->productbatch->enabled)) && $product->hasbatch()) { if ((! empty($conf->productbatch->enabled)) && $product->hasbatch())
{
print '<tr class="liste_titre"><td width="10%"></td>'; print '<tr class="liste_titre"><td width="10%"></td>';
print '<td align="right" width="10%">'.$langs->trans("batch_number").'</td>'; print '<td align="right" width="10%">'.$langs->trans("batch_number").'</td>';
print '<td align="right" width="10%">'.$langs->trans("l_eatby").'</td>'; print '<td align="right" width="10%">'.$langs->trans("l_eatby").'</td>';
@ -798,7 +847,7 @@ if ($resql)
print '<td align="right">'; print '<td align="right">';
if (empty($conf->global->PRODUIT_MULTI_PRICES)) print price(price2num($product->price,'MU'),1); if (empty($conf->global->PRODUIT_MULTI_PRICES)) print price(price2num($product->price,'MU'),1);
else print $langs->trans("Variable"); else print $langs->trans("Variable");
print '</td>'; // Ditto : Show PMP from movement or from product print '</td>';
// Value sell // Value sell
print '<td align="right">'; print '<td align="right">';
if (empty($conf->global->PRODUIT_MULTI_PRICES)) print price(price2num($product->price*$obj->reel,'MT'),1).'</td>'; // Ditto : Show PMP from movement or from product if (empty($conf->global->PRODUIT_MULTI_PRICES)) print price(price2num($product->price*$obj->reel,'MT'),1).'</td>'; // Ditto : Show PMP from movement or from product
@ -835,8 +884,10 @@ if ($resql)
{ {
print "\n".'<tr><td align="right">'; print "\n".'<tr><td align="right">';
print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$product->id.'&amp;action=transfert&amp;pdluoid='.$pdluo->id.'">'.$langs->trans("StockMovement").'</a>'; print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$product->id.'&amp;action=transfert&amp;pdluoid='.$pdluo->id.'">'.$langs->trans("StockMovement").'</a>';
print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&amp;action=editline&amp;lineid='.$pdluo->id.'#'.$pdluo->id.'">'; // Disabled, because edition of stock content must use the "Correct stock menu".
print img_edit().'</a></td>'; // Do not use this, or data will be wrong (bad tracking of movement label, inventory code, ...
//print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&amp;action=editline&amp;lineid='.$pdluo->id.'#'.$pdluo->id.'">';
//print img_edit().'</a></td>';
print '<td align="right">'.$pdluo->batch.'</td>'; print '<td align="right">'.$pdluo->batch.'</td>';
print '<td align="right">'. dol_print_date($pdluo->eatby,'day') .'</td>'; print '<td align="right">'. dol_print_date($pdluo->eatby,'day') .'</td>';
print '<td align="right">'. dol_print_date($pdluo->sellby,'day') .'</td>'; print '<td align="right">'. dol_print_date($pdluo->sellby,'day') .'</td>';