2
0
forked from Wavyzz/dolibarr

New add shipping and dispatching from/to multiple warehouses

Add select2 to warehouse selectors
Ship customer orderline from multiple warehouses
Dispatch client orderline to multiple warehouses
This commit is contained in:
fappels
2015-12-18 18:00:31 +01:00
parent 4fcedc92c9
commit 7fc8007571
8 changed files with 483 additions and 193 deletions

View File

@@ -21,6 +21,7 @@
/**
* addLineBatch
* @deprecated replaced by addDispatchLine and moved to module folder and file fourn/js/lib_dispatch.js
*
* @param index int number of produt. 0 = first product line
*/

View File

@@ -7,7 +7,7 @@
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
* Copyright (C) 2014 Francis Appels <francis.appels@yahoo.com>
* Copyright (C) 2014-2015 Francis Appels <francis.appels@yahoo.com>
*
* 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
@@ -90,20 +90,6 @@ $permissiondellink=$user->rights->expedition->livraison->creer; // Used by the i
* Actions
*/
$warehousecanbeselectedlater=1;
if (($action == 'create') || ($action == 'add'))
{
if (! empty($conf->productbatch->enabled))
{
if (! (GETPOST('entrepot_id','int') > 0))
{
$langs->load("errors");
setEventMessages($langs->trans("WarehouseMustBeSelectedAtFirstStepWhenProductBatchModuleOn"), null, 'errors');
header("Location: ".DOL_URL_ROOT.'/expedition/shipment.php?id='.$origin_id);
exit;
}
}
}
// Set incoterm
if ($action == 'set_incoterms' && !empty($conf->incoterm->enabled))
@@ -157,6 +143,7 @@ if (empty($reshook))
$object->location_incoterms = GETPOST('location_incoterms', 'alpha');
$batch_line = array();
$stockLine = array();
$num=count($objectsrc->lines);
$totalqty=0;
@@ -170,6 +157,7 @@ if (empty($reshook))
$j=0;
$batch="batchl".$i."_0";
$stockLocation="ent1".$i."_0";
$qty = "qtyl".$i;
if (isset($_POST[$batch]))
@@ -196,6 +184,22 @@ if (empty($reshook))
$totalqty+=$subtotalqty;
}
else if (isset($_POST[$stockLocation]))
{
//shipment line from multiple stock locations
$qty .= '_'.$j;
while (isset($_POST[$stockLocation]))
{
// save sub line of warehouse
$stockLine[$i][$j]['qty']=GETPOST($qty,'int');
$stockLine[$i][$j]['warehouse_id']=GETPOST($stockLocation,'int');
$stockLine[$i][$j]['ix_l']=GETPOST($idl,'int');
$j++;
$stockLocation="ent1".$i."_".$j;
$qty = "qtyl".$i.'_'.$j;
}
}
else
{
//shipment line for product with no batch management
@@ -214,6 +218,22 @@ if (empty($reshook))
if (! isset($batch_line[$i]))
{
// not batch mode
if (isset($stockLine[$i]))
{
//shipment from multiple stock locations
for($j = 0; $j < count($stockLine[$i]); $j++)
{
if ($stockLine[$i][$j]['qty']>0)
{
$ret=$object->addline($stockLine[$i][$j]['warehouse_id'], $stockLine[$i][$j]['ix_l'], $stockLine[$i][$j]['qty']);
if ($ret < 0)
{
setEventMessages($object->error, $object->errors, 'errors');
$error++;
}
}
}
}
if (GETPOST($qty,'int') > 0 || (GETPOST($qty,'int') == 0 && $conf->global->SHIPMENT_GETS_ALL_ORDER_PRODUCTS))
{
$ent = "entl".$i;
@@ -773,20 +793,22 @@ if ($action == 'create')
print '</td>';
$quantityAsked = $line->qty;
if ($line->product_type == 1 && empty($conf->global->STOCK_SUPPORTS_SERVICES))
{
$quantityToBeDelivered = 0;
}
else
{
$quantityToBeDelivered = $quantityAsked - $quantityDelivered;
}
$warehouse_id = GETPOST('entrepot_id','int');
$defaultqty=0;
$warehouseObject = null;
if ($warehouse_id > 0)
{
//var_dump($product);
$stock = $product->stock_warehouse[$warehouse_id]->real;
$stock+=0; // Convertit en numerique
$defaultqty=min($quantityToBeDelivered, $stock);
if (($line->product_type == 1 && empty($conf->global->STOCK_SUPPORTS_SERVICES)) || $defaultqty < 0) $defaultqty=0;
}
//ship from preselected location
$stock = + $product->stock_warehouse[$warehouse_id]->real; // Convert to number
$deliverableQty=min($quantityToBeDelivered, $stock);
if (empty($conf->productbatch->enabled) || ! ($product->hasbatch() && is_object($product->stock_warehouse[$warehouse_id])))
{
// Quantity to send
@@ -794,7 +816,7 @@ if ($action == 'create')
if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES))
{
print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
print '<input name="qtyl'.$indiceAsked.'" id="qtyl'.$indiceAsked.'" type="text" size="4" value="'.$defaultqty.'">';
print '<input name="qtyl'.$indiceAsked.'" id="qtyl'.$indiceAsked.'" type="text" size="4" value="'.$deliverableQty.'">';
}
else print $langs->trans("NA");
print '</td>';
@@ -865,9 +887,10 @@ if ($action == 'create')
foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch)
{
//var_dump($dbatch);
$substock=$dbatch->qty +0 ; // To get a numeric
$batchStock = + $dbatch->qty; // To get a numeric
$deliverableQty = min($quantityToBeDelivered,$batchStock);
print '<tr><td colspan="3" ></td><td align="center">';
print '<input name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.($substock > 0 ? min($defaultqty,$substock) : '0').'">';
print '<input name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.$deliverableQty.'">';
print '</td>';
print '<td align="left">';
@@ -877,10 +900,10 @@ if ($action == 'create')
print '<!-- Show details of lot -->';
print '<input name="batchl'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$dbatch->id.'">';
print $langs->trans("DetailBatchFormat", $dbatch->batch, dol_print_date($dbatch->eatby,"day"), dol_print_date($dbatch->sellby,"day"), $dbatch->qty);
if ($defaultqty<=0) {
$defaultqty=0;
} else {
$defaultqty -= min($defaultqty,$substock);
$quantityToBeDelivered -= $deliverableQty;
if ($quantityToBeDelivered < 0)
{
$quantityToBeDelivered = 0;
}
$subj++;
}
@@ -895,7 +918,136 @@ if ($action == 'create')
print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $staticwarehouse->libelle);
}
}
}
else
{
// ship from multiple locations
if (empty($conf->productbatch->enabled) || ! $product->hasbatch())
{
print '<td></td><td></td></tr>'; // end line and start a new one for each warehouse
print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
$subj=0;
foreach ($product->stock_warehouse as $warehouse_id=>$stock_warehouse) {
$warehouseObject=new Entrepot($db);
$warehouseObject->fetch($warehouse_id);
if ($stock_warehouse->real > 0) {
$stock = + $stock_warehouse->real; // Convert it to number
$deliverableQty = min($quantityToBeDelivered,$stock);
// Quantity to send
print '<tr><td colspan="3" ></td><td align="center">';
if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES))
{
print '<input name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'" type="text" size="4" value="'.$deliverableQty.'">';
print '<input name="ent1'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$warehouse_id.'">';
}
else print $langs->trans("NA");
print '</td>';
// Stock
if (! empty($conf->stock->enabled))
{
print '<td align="left">';
if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES))
{
print $warehouseObject->getNomUrl(0).' / ';
print '<!-- Show details of stock -->';
print $stock;
}
else
{
print $langs->trans("Service");
}
print '</td>';
}
$quantityToBeDelivered -= $deliverableQty;
if ($quantityToBeDelivered < 0)
{
$quantityToBeDelivered = 0;
}
$subj++;
print "</tr>\n";
}
}
// Show subproducts of product
if (! empty($conf->global->PRODUIT_SOUSPRODUITS) && $line->fk_product > 0)
{
$product->get_sousproduits_arbo();
$prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
if(count($prods_arbo) > 0)
{
foreach($prods_arbo as $key => $value)
{
//print $value[0];
$img='';
if ($value['stock'] < $value['stock_alert'])
{
$img=img_warning($langs->trans("StockTooLow"));
}
print "<tr ".$bc[$var]."><td>&nbsp; &nbsp; &nbsp; ->
<a href=\"".DOL_URL_ROOT."/product/card.php?id=".$value['id']."\">".$value['fullpath']."
</a> (".$value['nb'].")</td><td align=\"center\"> ".$value['nb_total']."</td><td>&nbsp</td><td>&nbsp</td>
<td align=\"center\">".$value['stock']." ".$img."</td></tr>";
}
}
}
}
else
{
print '<td></td><td></td></tr>'; // end line and start a new one for lot/serial
$subj=0;
print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
foreach ($product->stock_warehouse as $warehouse_id=>$stock_warehouse) {
$warehouseObject=new Entrepot($db);
$warehouseObject->fetch($warehouse_id);
if (($stock_warehouse->real > 0) && (count($stock_warehouse->detail_batch))) {
foreach ($stock_warehouse->detail_batch as $dbatch)
{
//var_dump($dbatch);
$batchStock = + $dbatch->qty; // To get a numeric
$deliverableQty = min($quantityToBeDelivered,$batchStock);
print '<tr><td colspan="3" ></td><td align="center">';
print '<input name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.$deliverableQty.'">';
print '</td>';
print '<td align="left">';
print $warehouseObject->getNomUrl(0).' / ';
print '<!-- Show details of lot -->';
print '<input name="batchl'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$dbatch->id.'">';
print $langs->trans("DetailBatchFormat", $dbatch->batch, dol_print_date($dbatch->eatby,"day"), dol_print_date($dbatch->sellby,"day"), $dbatch->qty);
$quantityToBeDelivered -= $deliverableQty;
if ($quantityToBeDelivered < 0)
{
$quantityToBeDelivered = 0;
}
//dol_syslog('deliverableQty = '.$deliverableQty.' batchStock = '.$batchStock);
$subj++;
}
}
}
}
if ($subj == 0)
{
print '<tr><td colspan="3" ></td><td align="center">';
print '<input name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="0" disabled="disabled"> ';
print '</td>';
print '<td align="left">';
if ($warehouseObject)
{
print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->libelle);
}
else
{
print img_warning().' '.$langs->trans("StockTooLow");
}
}
}
$indiceAsked++;
}

View File

@@ -378,25 +378,39 @@ class Expedition extends CommonObject
function create_line_batch($line_ext)
{
$error = 0;
$stockLocationQty = array(); // associated array with batch qty in stock location
if ($this->create_line(($line_ext->entrepot_id?$line_ext->entrepot_id:'null'),$line_ext->origin_line_id,$line_ext->qty) < 0)
$tab=$line_ext->detail_batch;
// create stockLocation Qty array
foreach ($tab as $detbatch)
{
if ($detbatch->entrepot_id)
{
$stockLocationQty[$detbatch->entrepot_id] += $detbatch->dluo_qty;
}
}
// create shipment lines
foreach ($stockLocationQty as $stockLocation => $qty)
{
if ($this->create_line($stockLocation,$line_ext->origin_line_id,$qty) < 0)
{
$error++;
}
if (! $error)
else
{
// create shipment batch lines for stockLocation
$line_id= $this->db->last_insert_id(MAIN_DB_PREFIX."expeditiondet");
$tab=$line_ext->detail_batch;
foreach ($tab as $detbatch)
{
if ($detbatch->entrepot_id == $stockLocation){
if (! ($detbatch->create($line_id) >0)) // Create an expeditionlinebatch
{
$error++;
}
}
}
}
}
if (! $error) return 1;
else return -1;
@@ -1278,8 +1292,10 @@ class Expedition extends CommonObject
$this->total_localtax1+= $tabprice[9];
$this->total_localtax2+= $tabprice[10];
if ($originline != $obj->fk_origin_line)
{
$line->detail_batch = array();
}
// Eat-by date
if (! empty($conf->productbatch->enabled) && $obj->line_id > 0)
{

View File

@@ -721,10 +721,7 @@ if ($id > 0 || ! empty($ref))
if (! empty($conf->stock->enabled))
{
$warehousecanbeselectedlater=1;
if (! empty($conf->productbatch->enabled)) $warehousecanbeselectedlater=0;
print '<td'.($warehousecanbeselectedlater?'':' class="fieldrequired"').'>'.$langs->trans("WarehouseSource").'</td>';
print '<td>'.$langs->trans("WarehouseSource").'</td>';
print '<td>';
print $formproduct->selectWarehouses(! empty($commande->warehouse_id)?$commande->warehouse_id:-1,'entrepot_id','',1);
if (count($formproduct->cache_warehouses) <= 0)

View File

@@ -33,6 +33,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
if (! empty($conf->projet->enabled)) require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
$langs->load('orders');
@@ -130,17 +131,17 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner)
$pos=0;
foreach($_POST as $key => $value)
{
if (preg_match('/^product_([0-9]+)$/i', $key, $reg)) // without batch module enabled
if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) // without batch module enabled
{
$pos++;
//$numline=$reg[1] + 1; // line of product
//$numline=$reg[2] + 1; // line of product
$numline=$pos;
$prod = "product_".$reg[1];
$qty = "qty_".$reg[1];
$ent = "entrepot_".$reg[1];
$pu = "pu_".$reg[1]; // This is unit price including discount
$fk_commandefourndet = "fk_commandefourndet_".$reg[1];
$prod = "product_".$reg[1].'_'.$reg[2];
$qty = "qty_".$reg[1].'_'.$reg[2];
$ent = "entrepot_".$reg[1].'_'.$reg[2];
$pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
$fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2];
if (GETPOST($qty) > 0) // We ask to move a qty
{
@@ -163,14 +164,14 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner)
}
}
}
if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) // with batch module enabled
if (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) // with batch module enabled
{
$pos++;
//eat-by date dispatch
//$numline=$reg[2] + 1; // line of product
$numline=$pos;
$prod = 'product_'.$reg[1].'_'.$reg[2];
$prod = 'product_batch_'.$reg[1].'_'.$reg[2];
$qty = 'qty_'.$reg[1].'_'.$reg[2];
$ent = 'entrepot_'.$reg[1].'_'.$reg[2];
$pu = 'pu_'.$reg[1].'_'.$reg[2];
@@ -191,7 +192,7 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner)
$error++;
}
if (! ($_POST[$lot] || $dDLUO || $dDLC))
if (! (GETPOST($lot, 'alpha') || $dDLUO || $dDLC))
{
dol_syslog('No dispatch for line '.$key.' as serial/eat-by/sellby date are not set');
$text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').' ' .($numline).'-'.($reg[1]+1);
@@ -245,19 +246,13 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner)
*/
$form = new Form($db);
$formproduct = new FormProduct($db);
$warehouse_static = new Entrepot($db);
$supplierorderdispatch = new CommandeFournisseurDispatch($db);
$help_url='EN:CommandeFournisseur';
if (!empty($conf->productbatch->enabled))
{
llxHeader('',$langs->trans("OrderCard"),$help_url,'',0,0,array('/core/js/lib_batch.js'));
}
else
{
llxHeader('',$langs->trans("OrderCard"),$help_url);
}
llxHeader('',$langs->trans("OrderCard"),$help_url,'',0,0,array('/fourn/js/lib_dispatch.js'));
$now=dol_now();
@@ -425,7 +420,7 @@ if ($id > 0 || ! empty($ref))
$nbfreeproduct=0;
$nbproduct=0;
$var=true;
$var=false;
while ($i < $num)
{
$objp = $db->fetch_object($resql);
@@ -449,13 +444,7 @@ if ($id > 0 || ! empty($ref))
// To show detail cref and description value, we must make calculation by cref
//print ($objp->cref?' ('.$objp->cref.')':'');
//if ($objp->description) print '<br>'.nl2br($objp->description);
if ((empty($conf->productbatch->enabled)) || $objp->tobatch==0)
{
$suffix='_'.$i;
} else {
$suffix='_0_'.$i;
}
print "\n";
print '<!-- Line '.$suffix.' -->'."\n";
@@ -489,6 +478,7 @@ if ($id > 0 || ! empty($ref))
print "</td>";
}
$var=!$var;
$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');
@@ -500,15 +490,19 @@ if ($id > 0 || ! empty($ref))
if (! empty($conf->productbatch->enabled) && $objp->tobatch==1)
{
print '<td align="right">'.img_picto($langs->trans('AddDispatchBatchLine'),'split.png','onClick="addLineBatch('.$i.')"').'</td>'; // Dispatch column
$type = 'batch';
print '<td align="right">'.img_picto($langs->trans('AddDispatchBatchLine'),'split.png','onClick="addDispatchLine('.$i.',\''.$type.'\')"').'</td>'; // Dispatch column
print '<td></td>'; // Warehouse column
print '</tr>';
print '<tr '.$bc[$var].' name="dluo'.$suffix.'">';
print '<tr '.$bc[$var].' name="'.$type.$suffix.'">';
print '<td>';
print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
print '<input name="pu'.$suffix.'" type="hidden" value="'.$up_ht_disc.'"><!-- This is a up including discount -->';
// hidden fields for js function
print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $products_dispatched[$objp->rowid].'">';
print '</td>';
print '<td>';
@@ -524,15 +518,24 @@ if ($id > 0 || ! empty($ref))
print '</td>';
print '<td colspan="2">&nbsp</td>'; // Qty ordered + qty already dispatached
}
// Dispatch
print '<td align="right">';
if (empty($conf->productbatch->enabled) || $objp->tobatch!=1)
else
{
$type = 'dispatch';
print '<td align="right">'.img_picto($langs->trans('AddStockLocationLine'),'split.png','onClick="addDispatchLine('.$i.',\''.$type.'\')"').'</td>'; // Dispatch column
print '<td></td>';
print '</tr>';
print '<tr '.$bc[$var].' name="'.$type.$suffix.'">';
print '<td colspan="6">';
print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
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 -->';
// hidden fields for js function
print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $products_dispatched[$objp->rowid].'">';
print '</td>';
}
// Dispatch
print '<td align="right">';
print '<input id="qty'.$suffix.'" name="qty'.$suffix.'" type="text" size="8" value="'.(GETPOST('qty'.$suffix)!='' ? GETPOST('qty'.$suffix) : $remaintodispatch).'">';
print '</td>';
@@ -540,11 +543,11 @@ if ($id > 0 || ! empty($ref))
print '<td align="right">';
if (count($listwarehouses)>1)
{
print $form->selectarray("entrepot".$suffix, $listwarehouses, GETPOST("entrepot".$suffix), 1, 0, 0, '', 0, 0, $disabled);
print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix), "entrepot".$suffix,'',1,0,$objp->fk_product);
}
elseif (count($listwarehouses)==1)
{
print $form->selectarray("entrepot".$suffix, $listwarehouses, GETPOST("entrepot".$suffix), 0, 0, 0, '', 0, 0, $disabled);
print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix), "entrepot".$suffix,'',0,0,$objp->fk_product);
}
else
{

View File

@@ -0,0 +1,77 @@
// Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
// Copyright (C) 2015 Francis Appels <francis.appels@z-application.com>
//
// 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
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// or see http://www.gnu.org/
//
// \file htdocs/core/js/lib_dispatch.js
// \brief File that include javascript functions used dispatch.php
//
/**
* addDispatchLine
* Adds new table row for dispatching to multiple stock locations
*
* @param index int index of produt line. 0 = first product line
* @param type string type of dispatch (batch = batch dispatch, dispatch = non batch dispatch)
*/
function addDispatchLine(index,type)
{
var $row = $("tr[name='"+type+'_0_'+index+"']").clone(true), // clone first batch line to jQuery object
nbrTrs = $("tr[name^='"+type+"_'][name$='_"+index+"']").length, // position of line for batch
qtyOrdered = parseFloat($("#qty_ordered_"+(nbrTrs - 1)+"_"+index).val()),
qty = parseFloat($("#qty_"+(nbrTrs - 1)+"_"+index).val()),
qtyDispatched;
if (type === 'batch')
{
qtyDispatched = parseFloat($("#qty_dispatched_"+(nbrTrs - 1)+"_"+index).val()) + 1;
}
else
{
qtyDispatched = parseFloat($("#qty_dispatched_"+(nbrTrs - 1)+"_"+index).val()) + qty;
}
if (qtyDispatched < qtyOrdered)
{
//replace tr suffix nbr
$row.html($row.html().replace(/_0_/g,"_"+nbrTrs+"_"));
//create new select2 to avoid duplicate id of cloned one
$row.find("select[name='"+'entrepot_'+nbrTrs+'_'+index+"']").select2();
// TODO find solution to copy selected option to new select
// TODO find solution to keep new tr's after page refresh
//clear value
$row.find("input[name^='qty']").val('');
//change name of new row
$row.attr('name',type+'_'+nbrTrs+'_'+index);
//insert new row before last row
$("tr[name^='"+type+"_'][name$='_"+index+"']:last").after($row);
//remove cloned select2 with duplicate id.
$("#s2id_entrepot_"+nbrTrs+'_'+index).detach();
/* Suffix of lines are: _ trs.length _ index */
$("#qty_"+nbrTrs+"_"+index).focus();
$("#qty_dispatched_"+(nbrTrs)+"_"+index).val(qtyDispatched);
if (type === 'batch')
{
$("#qty_"+(nbrTrs)+"_"+index).val(qty-1);
$("#qty_"+(nbrTrs-1)+"_"+index).val(1);
}
else
{
$("#qty_"+nbrTrs+"_"+index).val(qtyOrdered - qtyDispatched);
}
}
}

View File

@@ -52,24 +52,49 @@ class FormProduct
* If fk_product is not 0, we do not use cache
*
* @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
* @param string $batch Add quantity of batch stock in label for product with batch name batch, batch name precedes batch_id. Nothing if ''.
* @param int $fk_product_batch Add quantity of batch stock in label for product with batch id fk_product_batch. Nothing if 0.
* @param boolean $sumStock sum total stock of a warehouse, default true
* @return int Nb of loaded lines, 0 if already loaded, <0 if KO
*/
function loadWarehouses($fk_product=0)
function loadWarehouses($fk_product=0, $batch = '', $fk_product_batch=0, $sumStock = true)
{
global $conf, $langs;
if (empty($fk_product) && count($this->cache_warehouses)) return 0; // Cache already loaded and we do not want a list with information specific to a product
$sql = "SELECT e.rowid, e.label";
if ($fk_product) $sql.= ", ps.reel";
$sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e";
if ($fk_product)
if (!empty($fk_product))
{
if (!empty($fk_product_batch) || !empty($batch))
{
$sql.= ", pb.qty as stock";
}
else
{
$sql.= ", ps.reel as stock";
}
}
else if ($sumStock)
{
$sql.= ", sum(ps.reel) as stock";
}
$sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_entrepot = e.rowid";
if (!empty($fk_product))
{
$sql.= " AND ps.fk_product = '".$fk_product."'";
if (!empty($batch))
{
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_batch as pb on pb.fk_product_stock = ps.rowid AND pb.batch = '".$batch."'";
} else if (!empty($fk_product_batch))
{
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_batch as pb on pb.fk_product_stock = ps.rowid AND pb.rowid = '".$fk_product_batch."'";
}
}
$sql.= " WHERE e.entity IN (".getEntity('stock', 1).")";
$sql.= " AND e.statut = 1";
if ($sumStock && empty($fk_product)) $sql.= " GROUP BY e.rowid, e.label, e.description";
$sql.= " ORDER BY e.label";
dol_syslog(get_class($this).'::loadWarehouses', LOG_DEBUG);
@@ -81,10 +106,11 @@ class FormProduct
while ($i < $num)
{
$obj = $this->db->fetch_object($resql);
if ($sumStock) $obj->stock = price2num($obj->stock,5);
$this->cache_warehouses[$obj->rowid]['id'] =$obj->rowid;
$this->cache_warehouses[$obj->rowid]['label']=$obj->label;
if ($fk_product) $this->cache_warehouses[$obj->rowid]['stock']=$obj->reel;
$this->cache_warehouses[$obj->rowid]['description'] = $obj->description;
$this->cache_warehouses[$obj->rowid]['stock'] = $obj->stock;
$i++;
}
return $num;
@@ -106,18 +132,31 @@ class FormProduct
* @param int $disabled 1=Select is disabled
* @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
* @param string $empty_label Empty label if needed (only if $empty=1)
* @param int $showstock 1=show stock count
* @param int $forcecombo force combo iso ajax select2
* @param array $events events to add to select2
* @return string HTML select
*/
function selectWarehouses($selected='',$htmlname='idwarehouse',$filtertype='',$empty=0,$disabled=0,$fk_product=0,$empty_label='')
function selectWarehouses($selected='',$htmlname='idwarehouse',$filtertype='',$empty=0,$disabled=0,$fk_product=0,$empty_label='', $showstock=0, $forcecombo=0, $events=array())
{
global $langs,$user;
global $conf,$langs,$user;
dol_syslog(get_class($this)."::selectWarehouses $selected, $htmlname, $filtertype, $empty, $disabled, $fk_product",LOG_DEBUG);
$out='';
$this->loadWarehouses($fk_product);
$nbofwarehouses=count($this->cache_warehouses);
$out='<select class="flat"'.($disabled?' disabled':'').' id="'.$htmlname.'" name="'.($htmlname.($disabled?'_disabled':'')).'">';
if ($conf->use_javascript_ajax && ! $forcecombo)
{
include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
$comboenhancement = ajax_combobox($htmlname, $events);
$out.= $comboenhancement;
$nodatarole=($comboenhancement?' data-role="none"':'');
}
$out.='<select class="flat"'.($disabled?' disabled':'').' id="'.$htmlname.'" name="'.($htmlname.($disabled?'_disabled':'')).'"'.$nodatarole.'>';
if ($empty) $out.='<option value="-1">'.($empty_label?$empty_label:'&nbsp;').'</option>';
foreach($this->cache_warehouses as $id => $arraytypes)
{
@@ -125,7 +164,7 @@ class FormProduct
if ($selected == $id || ($selected == 'ifone' && $nbofwarehouses == 1)) $out.=' selected';
$out.='>';
$out.=$arraytypes['label'];
if ($fk_product) $out.=' ('.$langs->trans("Stock").': '.($arraytypes['stock']>0?$arraytypes['stock']:'?').')';
if (($fk_product || ($showstock > 0)) && ($arraytypes['stock'] != 0)) $out.='('.$langs->trans("Stock").':'.$arraytypes['stock'].')';
$out.='</option>';
}
$out.='</select>';

View File

@@ -57,7 +57,7 @@ $form=new Form($db);
$warehouse=new Entrepot($db);
$sql = "SELECT e.rowid, e.label as ref, e.statut, e.lieu, e.address, e.zip, e.town, e.fk_pays,";
$sql.= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue";
$sql.= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue, SUM(ps.reel) as stockqty";
$sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps ON e.rowid = ps.fk_entrepot";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON ps.fk_product = p.rowid";
@@ -94,6 +94,7 @@ if ($result)
print "<tr class=\"liste_titre\">";
print_liste_field_titre($langs->trans("Ref"),$_SERVER["PHP_SELF"], "e.label","","","",$sortfield,$sortorder);
print_liste_field_titre($langs->trans("LocationSummary"),$_SERVER["PHP_SELF"], "e.lieu","","","",$sortfield,$sortorder);
print_liste_field_titre($langs->trans("PhysicalStock"), $_SERVER["PHP_SELF"], "stockqty",'','','align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("EstimatedStockValue"), $_SERVER["PHP_SELF"], "e.valo_pmp",'','','align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("EstimatedStockValueSell"), $_SERVER["PHP_SELF"], "",'','','align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Status"),$_SERVER["PHP_SELF"], "e.statut",'','','align="right"',$sortfield,$sortorder);
@@ -111,7 +112,7 @@ if ($result)
print '<input class="flat" type="text" name="search_label" size="10" value="'.dol_escape_htmltag($search_label).'">';
print '</td>';
print '<td class="liste_titre" colspan="2">';
print '<td class="liste_titre" colspan="3">';
print '</td>';
print '<td class="liste_titre" align="right">';
@@ -128,7 +129,7 @@ if ($result)
if ($num)
{
$entrepot=new Entrepot($db);
$total = $totalsell = 0;
$total = $totalsell = $totalStock = 0;
$var=false;
while ($i < min($num,$limit))
{
@@ -140,6 +141,8 @@ if ($result)
print '<td>' . $entrepot->getNomUrl(1) . '</td>';
// Location
print '<td>'.$objp->lieu.'</td>';
// Stock qty
print '<td align="right">'.price2num($objp->stockqty,5).'</td>';
// PMP value
print '<td align="right">';
if (price2num($objp->estimatedvalue,'MT')) print price(price2num($objp->estimatedvalue,'MT'),1);
@@ -163,6 +166,7 @@ if ($result)
$total += price2num($objp->estimatedvalue,'MU');
$totalsell += price2num($objp->sellvalue,'MU');
$totalStock += $objp->stockqty;
$var=!$var;
$i++;
@@ -170,6 +174,7 @@ if ($result)
print '<tr class="liste_total">';
print '<td colspan="2" align="right">'.$langs->trans("Total").'</td>';
print '<td align="right">'.price2num($totalStock,5).'</td>';
print '<td align="right">'.price(price2num($total,'MT'),1,$langs,0,0,-1,$conf->currency).'</td>';
print '<td align="right">';
if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($totalsell,'MT'),1,$langs,0,0,-1,$conf->currency);