2
0
forked from Wavyzz/dolibarr

A serious rewrite of a lot of code to have the module batch number

stable.
This commit is contained in:
Laurent Destailleur
2015-04-12 17:08:14 +02:00
parent 6502d1c269
commit 8ebad7a395
14 changed files with 551 additions and 59 deletions

View File

@@ -136,7 +136,7 @@ class Facture extends CommonInvoice
var $specimen;
var $fac_rec;
//Incoterms
var $fk_incoterms;
var $location_incoterms;
@@ -559,7 +559,7 @@ class Facture extends CommonInvoice
$action='create';
// Actions on extra fields (by external module or standard code)
// FIXME le hook fait double emploi avec le trigger !!
// TODO le hook fait double emploi avec le trigger !!
$hookmanager->initHooks(array('invoicedao'));
$parameters=array('invoiceid'=>$this->id);
$reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
@@ -1040,9 +1040,9 @@ class Facture extends CommonInvoice
//Incoterms
$this->fk_incoterms = $obj->fk_incoterms;
$this->location_incoterms = $obj->location_incoterms;
$this->location_incoterms = $obj->location_incoterms;
$this->libelle_incoterms = $obj->libelle_incoterms;
if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1;
// Retreive all extrafield for invoice
@@ -3607,7 +3607,7 @@ class Facture extends CommonInvoice
$this->db->commit();
return 1;
} else {
$this->error = $this->db->error();
$this->error = $this->db->lasterror();
dol_syslog(get_class($this) . "::update Error setFinal " . $sql, LOG_ERR);
$this->db->rollback();
return -1;
@@ -3630,7 +3630,7 @@ class Facture extends CommonInvoice
$last = $res['max(situation_counter)'];
return ($last == $this->situation_counter);
} else {
$this->error = $this->db->error();
$this->error = $this->db->lasterror();
dol_syslog(get_class($this) . "::select Error " . $this->error, LOG_ERR);
$this->db->rollback();
return -1;

View File

@@ -93,7 +93,8 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->product->enabled', __HANDLER__, 'left', 2801__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/card.php?leftmenu=product&action=create&type=0', 'NewProduct', 1, 'products', '$user->rights->produit->creer', '', 2, 0, __ENTITY__);
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->product->enabled', __HANDLER__, 'left', 2802__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/list.php?leftmenu=product&type=0', 'List', 1, 'products', '$user->rights->produit->lire', '', 2, 1, __ENTITY__);
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->product->enabled', __HANDLER__, 'left', 2803__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/reassort.php?type=0', 'Stocks', 1, 'products', '$user->rights->produit->lire && $user->rights->stock->lire', '', 2, 4, __ENTITY__);
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->propal->enabled', __HANDLER__, 'left', 2804__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/popuprop.php?leftmenu=stats&type=0', 'Statistics', 1, 'main', '$user->rights->produit->lire', '', 2, 5, __ENTITY__);
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->productbatch->enabled', __HANDLER__, 'left', 2805__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/reassortlot.php?type=0', 'StocksByLotSerial', 1, 'products', '$user->rights->produit->lire && $user->rights->stock->lire', '', 2, 5, __ENTITY__);
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->propal->enabled', __HANDLER__, 'left', 2804__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/popuprop.php?leftmenu=stats&type=0', 'Statistics', 1, 'main', '$user->rights->produit->lire', '', 2, 6, __ENTITY__);
-- Product - Services
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->service->enabled', __HANDLER__, 'left', 2900__+MAX_llx_menu__, 'products', 'service', 3__+MAX_llx_menu__, '/product/index.php?leftmenu=service&type=1', 'Services', 0, 'products', '$user->rights->service->lire', '', 2, 1, __ENTITY__);
insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->service->enabled', __HANDLER__, 'left', 2901__+MAX_llx_menu__, 'products', '', 2900__+MAX_llx_menu__, '/product/card.php?leftmenu=service&action=create&type=1', 'NewService', 1, 'products', '$user->rights->service->creer', '', 2, 0, __ENTITY__);

View File

@@ -1055,14 +1055,19 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
$newmenu->add("/product/index.php?leftmenu=product&type=0", $langs->trans("Products"), 0, $user->rights->produit->lire, '', $mainmenu, 'product');
$newmenu->add("/product/card.php?leftmenu=product&action=create&type=0", $langs->trans("NewProduct"), 1, $user->rights->produit->creer);
$newmenu->add("/product/list.php?leftmenu=product&type=0", $langs->trans("List"), 1, $user->rights->produit->lire);
if (! empty($conf->propal->enabled))
{
$newmenu->add("/product/popuprop.php?leftmenu=stats&type=0", $langs->trans("Statistics"), 1, $user->rights->produit->lire && $user->rights->propale->lire);
}
if (! empty($conf->stock->enabled))
{
$newmenu->add("/product/reassort.php?type=0", $langs->trans("Stocks"), 1, $user->rights->produit->lire && $user->rights->stock->lire);
}
if (! empty($conf->stock->enabled))
{
$langs->load("stocks");
$newmenu->add("/product/reassortlot.php?type=0", $langs->trans("StocksByLotSerial"), 1, $user->rights->produit->lire && $user->rights->stock->lire);
}
if (! empty($conf->propal->enabled))
{
$newmenu->add("/product/popuprop.php?leftmenu=stats&type=0", $langs->trans("Statistics"), 1, $user->rights->produit->lire && $user->rights->propale->lire);
}
}
// Services

View File

@@ -16,6 +16,7 @@ CancelSending=Cancel sending
DeleteSending=Delete sending
Stock=Stock
Stocks=Stocks
StocksByLotSerial=Stock by lot/serial
Movement=Movement
Movements=Movements
ErrorWarehouseRefRequired=Warehouse reference name is required

View File

@@ -1,6 +1,6 @@
<?php
/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2005-2014 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
@@ -840,6 +840,8 @@ else
else $title=$langs->trans("NewProduct");
print_fiche_titre($title);
dol_fiche_head('');
print '<table class="border" width="100%">';
print '<tr>';
$tmpcode='';
@@ -1058,6 +1060,8 @@ else
print '<br>';
//}
dol_fiche_end();
print '<div class="center"><input type="submit" class="button" value="'.$langs->trans("Create").'"></div>';
print '</form>';

View File

@@ -3202,7 +3202,8 @@ class Product extends CommonObject
/**
* Load information about stock of a product into stock_reel, stock_warehouse[] (including stock_warehouse[idwarehouse]->detail_batch for batch products)
*
* @return int < 0 if KO, > 0 if OK
* @return int < 0 if KO, > 0 if OK
* @see load_virtual_stock, getBatchInfo
*/
function load_stock()
{
@@ -3250,9 +3251,10 @@ class Product extends CommonObject
}
/**
* Load information about virtual stock of a product
* Load information about objects that are delat between physical and virtual stock of a product
*
* @return int < 0 if KO, > 0 if OK
* @return int < 0 if KO, > 0 if OK
* @see load_stock, getBatchInfo
*/
function load_virtual_stock()
{
@@ -3308,6 +3310,44 @@ class Product extends CommonObject
}
}
/**
* Load existing information about a serial
*
* @param string $batch
* @return array Array with record into product_batch
* @see load_stock, load_virtual_stock
*/
function loadBatchInfo($batch)
{
$result=array();
$sql = "SELECT pb.batch, pb.eatby, pb.sellby, SUM(pb.qty) FROM ".MAIN_DB_PREFIX."product_batch as pb, ".MAIN_DB_PREFIX."product_stock as ps";
$sql.= " WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".$this->id." AND pb.batch = '".$this->db->escape($batch)."'";
$sql.= " GROUP BY pb.batch, pb.eatby, pb.sellby";
dol_syslog(get_class($this)."::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
$num = $this->db->num_rows($resql);
$i=0;
while ($i < $num)
{
$obj = $this->db->fetch_object($resql);
$result[]=array('batch'=>$batch, 'eatby'=>$this->db->jdate($obj->eatby), 'sellby'=>$this->db->jdate($obj->sellby), 'qty'=>$obj->qty);
$i++;
}
return $result;
}
else
{
dol_print_error($this->db);
$this->db->rollback();
return array();
}
}
/**
* Move an uploaded file described into $file array into target directory $sdir.
*

View File

@@ -1,6 +1,6 @@
<?php
/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2014 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2014 Charles-Fr BENKE <charles.fr@benke.fr>
*

View File

@@ -102,13 +102,12 @@ $title=$langs->trans("ProductsAndServices");
$sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,';
$sql.= ' p.fk_product_type, p.tms as datem,';
$sql.= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte,';
$sql.= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
$sql.= ' SUM(s.reel) as stock_physique';
$sql .= ', p.desiredstock';
$sql.= ' FROM ('.MAIN_DB_PREFIX.'product as p';
$sql.= ' FROM '.MAIN_DB_PREFIX.'product as p';
$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s on p.rowid = s.fk_product';
// We'll need this table joined to the select in order to filter by categ
if ($search_categ) $sql.= ", ".MAIN_DB_PREFIX."categorie_product as cp";
$sql.= ') LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s on p.rowid = s.fk_product';
$sql.= " WHERE p.entity IN (".getEntity('product', 1).")";
if ($search_categ) $sql.= " AND p.rowid = cp.fk_product"; // Join for the needed table to filter by categ
if ($sall)
@@ -156,9 +155,7 @@ if ($search_categ)
$sql .= " AND cp.fk_categorie = ".$db->escape($search_categ);
}
$sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
$sql.= " p.fk_product_type, p.tms,";
$sql.= " p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte";
$sql .= ", p.desiredstock";
$sql.= " p.fk_product_type, p.tms, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock";
if ($toolowstock) $sql.= " HAVING SUM(".$db->ifsql('s.reel IS NULL', '0', 's.reel').") < p.seuil_stock_alerte"; // Not used yet
$sql.= $db->order($sortfield,$sortorder);
$sql.= $db->plimit($limit + 1, $offset);
@@ -247,19 +244,19 @@ if ($resql)
print_liste_field_titre($langs->trans("DesiredStock"), $_SERVER["PHP_SELF"], "p.desiredstock",$param,"",'align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("PhysicalStock"), $_SERVER["PHP_SELF"], "stock_physique",$param,"",'align="right"',$sortfield,$sortorder);
// TODO Add info of running suppliers/customers orders
//print_liste_field_titre($langs->trans("TheoreticalStock"),"reassort.php", "stock_theorique",$param,"",'align="right"',$sortfield,$sortorder);
//print_liste_field_titre($langs->trans("TheoreticalStock"),$_SERVER["PHP_SELF"], "stock_theorique",$param,"",'align="right"',$sortfield,$sortorder);
print '<td class="liste_titre">&nbsp;</td>';
print_liste_field_titre($langs->trans("Sell"),"reassort.php", "p.tosell",$param,"",'align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Buy"),"reassort.php", "p.tobuy",$param,"",'align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Sell"),$_SERVER["PHP_SELF"], "p.tosell",$param,"",'align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Buy"),$_SERVER["PHP_SELF"], "p.tobuy",$param,"",'align="right"',$sortfield,$sortorder);
print "</tr>\n";
// Lignes des champs de filtre
print '<tr class="liste_titre">';
print '<td class="liste_titre">';
print '<input class="flat" type="text" name="sref" value="'.$sref.'">';
print '<input class="flat" type="text" name="sref" size="6" value="'.$sref.'">';
print '</td>';
print '<td class="liste_titre">';
print '<input class="flat" type="text" name="snom" value="'.$snom.'">';
print '<input class="flat" type="text" name="snom" size="8" value="'.$snom.'">';
print '</td>';
if (! empty($conf->service->enabled) && $type == 1)
{
@@ -267,6 +264,7 @@ if ($resql)
print '&nbsp;';
print '</td>';
}
// Lot/Serial
print '<td class="liste_titre">&nbsp;</td>';
print '<td class="liste_titre" align="right">&nbsp;</td>';
print '<td class="liste_titre">&nbsp;</td>';

View File

@@ -0,0 +1,388 @@
<?php
/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
*
* 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/>.
*/
/**
* \file htdocs/product/reassortlot.php
* \ingroup produit
* \brief Page to list stocks
*/
require '../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
$langs->load("products");
$langs->load("stocks");
$langs->load("productbatch");
// Security check
if ($user->societe_id) $socid=$user->societe_id;
$result=restrictedArea($user,'produit|service');
$action=GETPOST('action','alpha');
$sref=GETPOST("sref");
$snom=GETPOST("snom");
$sall=GETPOST("sall");
$type=GETPOST("type","int");
$sbarcode=GETPOST("sbarcode");
$search_batch=GETPOST('search_batch');
$catid=GETPOST('catid','int');
$toolowstock=GETPOST('toolowstock');
$tosell = GETPOST("tosell");
$tobuy = GETPOST("tobuy");
$fourn_id = GETPOST("fourn_id",'int');
$sortfield = GETPOST("sortfield",'alpha');
$sortorder = GETPOST("sortorder",'alpha');
$page = GETPOST("page",'int');
if (! $sortfield) $sortfield="stock_physique";
if (! $sortorder) $sortorder="ASC";
$limit = $conf->liste_limit;
$offset = $limit * $page ;
// Load sale and categ filters
$search_sale = GETPOST("search_sale");
$search_categ = GETPOST("search_categ");
// Get object canvas (By default, this is not defined, so standard usage of dolibarr)
$canvas=GETPOST("canvas");
$objcanvas=null;
if (! empty($canvas))
{
require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
$objcanvas = new Canvas($db,$action);
$objcanvas->getCanvas('product','list',$canvas);
}
if (! empty($_POST["button_removefilter_x"]))
{
$sref="";
$snom="";
$sall="";
$search_sale="";
$search_categ="";
$type="";
$catid='';
$toolowstock='';
}
/*
* Actions
*/
// None
/*
* View
*/
$htmlother=new FormOther($db);
$title=$langs->trans("ProductsAndServices");
$sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,';
$sql.= ' p.fk_product_type, p.tms as datem,';
$sql.= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
$sql.= ' s.fk_entrepot,';
$sql.= ' pb.batch, pb.eatby, pb.sellby,';
$sql.= ' SUM(pb.qty) as stock_physique';
$sql.= ' FROM '.MAIN_DB_PREFIX.'product as p';
$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s on p.rowid = s.fk_product';
$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_batch as pb on pb.fk_product_stock = s.rowid';
// We'll need this table joined to the select in order to filter by categ
if ($search_categ) $sql.= ", ".MAIN_DB_PREFIX."categorie_product as cp";
$sql.= " WHERE p.entity IN (".getEntity('product', 1).")";
if ($search_categ) $sql.= " AND p.rowid = cp.fk_product"; // Join for the needed table to filter by categ
if ($sall)
{
$sql.= " AND (p.ref LIKE '%".$db->escape($sall)."%' OR p.label LIKE '%".$db->escape($sall)."%' OR p.description LIKE '%".$db->escape($sall)."%' OR p.note LIKE '%".$db->escape($sall)."%')";
}
// if the type is not 1, we show all products (type = 0,2,3)
if (dol_strlen($type))
{
if ($type==1)
{
$sql.= " AND p.fk_product_type = '1'";
}
else
{
$sql.= " AND p.fk_product_type <> '1'";
}
}
if ($sref) $sql.= " AND p.ref LIKE '%".$sref."%'";
if ($sbarcode) $sql.= " AND p.barcode LIKE '%".$sbarcode."%'";
if ($snom) $sql.= " AND p.label LIKE '%".$db->escape($snom)."%'";
if (! empty($tosell))
{
$sql.= " AND p.tosell = ".$tosell;
}
if (! empty($tobuy))
{
$sql.= " AND p.tobuy = ".$tobuy;
}
if (! empty($canvas))
{
$sql.= " AND p.canvas = '".$db->escape($canvas)."'";
}
if($catid)
{
$sql.= " AND cp.fk_categorie = ".$catid;
}
if ($fourn_id > 0)
{
$sql.= " AND p.rowid = pf.fk_product AND pf.fk_soc = ".$fourn_id;
}
// Insert categ filter
if ($search_categ)
{
$sql .= " AND cp.fk_categorie = ".$db->escape($search_categ);
}
if ($search_batch)
{
$sql .= " AND pb.batch LIKE '%".$db->escape($search_batch)."%'";
}
$sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
$sql.= " p.fk_product_type, p.tms, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,";
$sql.= " s.fk_entrepot,";
$sql.= " pb.batch, pb.eatby, pb.sellby";
if ($toolowstock) $sql.= " HAVING SUM(".$db->ifsql('s.reel IS NULL', '0', 's.reel').") < p.seuil_stock_alerte"; // Not used yet
$sql.= $db->order($sortfield,$sortorder);
$sql.= $db->plimit($limit + 1, $offset);
$resql = $db->query($sql);
if ($resql)
{
$num = $db->num_rows($resql);
$i = 0;
if ($num == 1 && ($sall or $snom or $sref))
{
$objp = $db->fetch_object($resql);
header("Location: card.php?id=$objp->rowid");
exit;
}
$helpurl='';
$helpurl='EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
if (isset($type))
{
if ($type==1) { $texte = $langs->trans("Services"); }
else { $texte = $langs->trans("Products"); }
} else {
$texte = $langs->trans("ProductsAndServices");
}
$texte.=' ('.$langs->trans("StocksByLotSerial").')';
llxHeader("",$title,$helpurl,$texte);
if ($sref || $snom || $sall || GETPOST('search'))
{
print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=".$sref."&snom=".$snom."&amp;sall=".$sall."&amp;tosell=".$tosell."&amp;tobuy=".$tobuy, $sortfield, $sortorder,'',$num);
}
else
{
print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&amp;type=$type":""), $sortfield, $sortorder,'',$num);
}
if (! empty($catid))
{
print "<div id='ways'>";
$c = new Categorie($db);
$c->fetch($catid);
$ways = $c->print_all_ways(' &gt; ','product/reassortlot.php');
print " &gt; ".$ways[0]."<br>\n";
print "</div><br>";
}
print '<form action="'. $_SERVER["PHP_SELF"] .'" method="post" name="formulaire">';
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
print '<input type="hidden" name="type" value="'.$type.'">';
print '<table class="liste" width="100%">';
// Filter on categories
$moreforfilter='';
if (! empty($conf->categorie->enabled))
{
$moreforfilter.=$langs->trans('Categories'). ': ';
$moreforfilter.=$htmlother->select_categories(0,$search_categ,'search_categ');
$moreforfilter.=' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ';
}
//$moreforfilter.=$langs->trans("StockTooLow").' <input type="checkbox" name="toolowstock" value="1"'.($toolowstock?' checked="checked"':'').'>';
if ($moreforfilter)
{
print '<tr class="liste_titre">';
print '<td class="liste_titre" colspan="11">';
print $moreforfilter;
print '</td></tr>';
}
$param="&tosell=$tosell&tobuy=$tobuy".(isset($type)?"&type=$type":"")."&fourn_id=$fourn_id&snom=$snom&sref=$sref&batch=$batch&eatby=$eatby&sellby=$sellby";
// Lignes des titres
print "<tr class=\"liste_titre\">";
print_liste_field_titre($langs->trans("Ref"), $_SERVER["PHP_SELF"], "p.ref",$param,"","",$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Label"), $_SERVER["PHP_SELF"], "p.label",$param,"","",$sortfield,$sortorder);
if (! empty($conf->service->enabled) && $type == 1) print_liste_field_titre($langs->trans("Duration"), $_SERVER["PHP_SELF"], "p.duration",$param,"",'align="center"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Warehouse"), $_SERVER["PHP_SELF"], "",$param,"",'',$sortfield,$sortorder);
//print_liste_field_titre($langs->trans("DesiredStock"), $_SERVER["PHP_SELF"], "p.desiredstock",$param,"",'align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Batch"), $_SERVER["PHP_SELF"], "pb.batch",$param,"",'align="center"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("l_eatby"), $_SERVER["PHP_SELF"], "pb.eatby",$param,"",'align="center"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("l_sellby"), $_SERVER["PHP_SELF"], "pb.sellby",$param,"",'align="center"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("PhysicalStock"), $_SERVER["PHP_SELF"], "stock_physique",$param,"",'align="right"',$sortfield,$sortorder);
// TODO Add info of running suppliers/customers orders
//print_liste_field_titre($langs->trans("TheoreticalStock"),$_SERVER["PHP_SELF"], "stock_theorique",$param,"",'align="right"',$sortfield,$sortorder);
print '<td class="liste_titre">&nbsp;</td>';
print_liste_field_titre($langs->trans("Sell"),$_SERVER["PHP_SELF"], "p.tosell",$param,"",'align="right"',$sortfield,$sortorder);
print_liste_field_titre($langs->trans("Buy"),$_SERVER["PHP_SELF"], "p.tobuy",$param,"",'align="right"',$sortfield,$sortorder);
print "</tr>\n";
// Lignes des champs de filtre
print '<tr class="liste_titre">';
print '<td class="liste_titre">';
print '<input class="flat" type="text" name="sref" size="6" value="'.$sref.'">';
print '</td>';
print '<td class="liste_titre">';
print '<input class="flat" type="text" name="snom" size="8" value="'.$snom.'">';
print '</td>';
if (! empty($conf->service->enabled) && $type == 1)
{
print '<td class="liste_titre">';
print '&nbsp;';
print '</td>';
}
print '<td class="liste_titre">&nbsp;</td>';
print '<td class="liste_titre" align="center"><input class="flat" type="text" name="search_batch" size="6" value="'.$search_batch.'"></td>';
print '<td class="liste_titre" align="right">&nbsp;</td>';
print '<td class="liste_titre">&nbsp;</td>';
print '<td class="liste_titre">&nbsp;</td>';
print '<td class="liste_titre">&nbsp;</td>';
print '<td class="liste_titre">&nbsp;</td>';
print '<td class="liste_titre" align="right">';
print '<input type="image" class="liste_titre" name="button_search" src="'.img_picto($langs->trans("Search"),'search.png','','',1).'" alt="'.$langs->trans("Search").'">';
print '<input type="image" class="liste_titre" name="button_removefilter" src="'.img_picto($langs->trans("Search"),'searchclear.png','','',1).'" alt="'.$langs->trans("RemoveFilter").'">';
print '</td>';
print '</tr>';
$product_static=new Product($db);
$warehousetmp=new Entrepot($db);
$var=True;
while ($i < min($num,$limit))
{
$objp = $db->fetch_object($resql);
// Multilangs
if (! empty($conf->global->MAIN_MULTILANGS)) // si l'option est active
{
$sql = "SELECT label";
$sql.= " FROM ".MAIN_DB_PREFIX."product_lang";
$sql.= " WHERE fk_product=".$objp->rowid;
$sql.= " AND lang='". $langs->getDefaultLang() ."'";
$sql.= " LIMIT 1";
$result = $db->query($sql);
if ($result)
{
$objtp = $db->fetch_object($result);
if (! empty($objtp->label)) $objp->label = $objtp->label;
}
}
$var=!$var;
print '<tr '.$bc[$var].'><td class="nowrap">';
$product_static->ref=$objp->ref;
$product_static->id=$objp->rowid;
$product_static->label = $objp->label;
$product_static->type=$objp->fk_product_type;
print $product_static->getNomUrl(1,'',16);
//if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow"));
print '</td>';
print '<td>'.$objp->label.'</td>';
if (! empty($conf->service->enabled) && $type == 1)
{
print '<td align="center">';
if (preg_match('/([0-9]+)y/i',$objp->duration,$regs)) print $regs[1].' '.$langs->trans("DurationYear");
elseif (preg_match('/([0-9]+)m/i',$objp->duration,$regs)) print $regs[1].' '.$langs->trans("DurationMonth");
elseif (preg_match('/([0-9]+)d/i',$objp->duration,$regs)) print $regs[1].' '.$langs->trans("DurationDay");
else print $objp->duration;
print '</td>';
}
//print '<td align="right">'.$objp->stock_theorique.'</td>';
//print '<td align="right">'.$objp->seuil_stock_alerte.'</td>';
//print '<td align="right">'.$objp->desiredstock.'</td>';
// Warehouse
print '<td>';
$warehousetmp->fetch($obj->fk_entrepot);
print $warehousetmp->getNomUrl(1);
print '</td>';
print '<td align="center">'.$objp->batch.'</td>';
print '<td align="center">'.dol_print_date($db->jdate($objp->eatby), 'day').'</td>';
print '<td align="center">'.dol_print_date($db->jdate($objp->sellby), 'day').'</td>';
print '<td align="right">';
//if ($objp->seuil_stock_alerte && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' ';
print $objp->stock_physique;
print '</td>';
print '<td align="right"><a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?idproduct='.$product_static->id.'&search_batch='.$objp->batch.'">'.$langs->trans("Movements").'</a></td>';
print '<td align="right" class="nowrap">'.$product_static->LibStatut($objp->statut,5,0).'</td>';
print '<td align="right" class="nowrap">'.$product_static->LibStatut($objp->tobuy,5,1).'</td>';
print "</tr>\n";
$i++;
}
print "</table>";
print '</form>';
if ($num > $conf->liste_limit)
{
if ($sref || $snom || $sall || GETPOST('search'))
{
print_barre_liste('', $page, "reassort.php", "&sref=".$sref."&snom=".$snom."&amp;sall=".$sall."&amp;tosell=".$tosell."&amp;tobuy=".$tobuy, $sortfield, $sortorder,'',$num, 0, '');
}
else
{
print_barre_liste('', $page, "reassort.php", "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&amp;type=$type":"")."&amp;tosell=".$tosell."&amp;tobuy=".$tobuy, $sortfield, $sortorder,'',$num, 0, '');
}
}
$db->free($resql);
}
else
{
dol_print_error($db);
}
llxFooter();
$db->close();

View File

@@ -76,7 +76,7 @@ class MouvementStock extends CommonObject
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
$error = 0;
dol_syslog(get_class($this)."::_create start userid=$user->id, fk_product=$fk_product, warehouse=$entrepot_id, qty=$qty, type=$type, price=$price, label=$label, inventorycode=$inventorycode");
dol_syslog(get_class($this)."::_create start userid=$user->id, fk_product=$fk_product, warehouse=$entrepot_id, qty=$qty, type=$type, price=$price, label=$label, inventorycode=$inventorycode, datem=".$datem.", eatby=".$eatby.", sellby=".$sellby.", batch=".$batch.", skip_batch=".$skip_batch);
// Clean parameters
if (empty($price)) $price=0;
@@ -101,7 +101,7 @@ class MouvementStock extends CommonObject
$this->qty = $qty;
$this->type = $type;
$this->db->begin();
$mvid = 0;
$product = new Product($this->db);
$result=$product->fetch($fk_product);
@@ -110,6 +110,9 @@ class MouvementStock extends CommonObject
dol_print_error('',"Failed to fetch product");
return -1;
}
$this->db->begin();
$product->load_stock();
// Test if product require batch data. If yes, and there is not, we throw an error.
@@ -137,17 +140,17 @@ class MouvementStock extends CommonObject
while ($i < $num)
{
$obj = $this->db->fetch_object($resql);
if ($obj->eatby != $eatby)
if ($this->db->jdate($obj->eatby) != $eatby)
{
$this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $obj->eatby, $eatby);
dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $obj->eatby, $eatby));
$this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->eatby), $eatby);
dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->eatby), $eatby));
$this->db->rollback();
return -3;
}
if ($obj->sellby != $sellby)
if ($this->db->jdate($obj->sellby) != $sellby)
{
$this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $obj->sellby, $sellby);
dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $obj->sellby, $sellby));
$this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->sellby), $sellby);
dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->sellby), $sellby));
$this->db->rollback();
return -3;
}
@@ -162,6 +165,16 @@ class MouvementStock extends CommonObject
}
}
// TODO Check qty is ok for stock move.
if (! empty($conf->productbatch->enabled) && $product->hasbatch() && ! $skip_batch)
{
}
else
{
}
// Define if we must make the stock change (If product type is a service or if stock is used also for services)
$movestock=0;
if ($product->type != Product::TYPE_SERVICE || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) $movestock=1;
@@ -176,8 +189,6 @@ class MouvementStock extends CommonObject
$fk_origin = 0;
}
$mvid = 0;
$sql = "INSERT INTO ".MAIN_DB_PREFIX."stock_mouvement(";
$sql.= " datem, fk_product, batch, eatby, sellby,";
$sql.= " fk_entrepot, value, type_mouvement, fk_user_author, label, inventorycode, price, fk_origin, origintype";

View File

@@ -27,6 +27,7 @@ require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
$langs->load("stocks");
$langs->load("productbatch");
// Security check
$result=restrictedArea($user,'stock');
@@ -112,7 +113,7 @@ print '</div><div class="fichetwothirdright"><div class="ficheaddleft">';
$max=10;
$sql = "SELECT p.rowid, p.label as produit,";
$sql.= " e.label as stock, e.rowid as entrepot_id,";
$sql.= " m.value, m.datem";
$sql.= " m.value as qty, m.datem, m.batch, m.eatby, m.sellby";
$sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e";
$sql.= ", ".MAIN_DB_PREFIX."stock_mouvement as m";
$sql.= ", ".MAIN_DB_PREFIX."product as p";
@@ -133,6 +134,12 @@ if ($resql)
print "<tr class=\"liste_titre\">";
print '<td>'.$langs->trans("LastMovements",min($num,$max)).'</td>';
print '<td>'.$langs->trans("Product").'</td>';
if (! empty($conf->productbatch->enabled))
{
print '<td>'.$langs->trans("Batch").'</td>';
print '<td>'.$langs->trans("l_eatby").'</td>';
print '<td>'.$langs->trans("l_sellby").'</td>';
}
print '<td>'.$langs->trans("Warehouse").'</td>';
print '<td align="right"><a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php">'.$langs->trans("FullList").'</a></td>';
print "</tr>\n";
@@ -148,12 +155,18 @@ if ($resql)
print "<td><a href=\"../card.php?id=$objp->rowid\">";
print img_object($langs->trans("ShowProduct"),"product").' '.$objp->produit;
print "</a></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>';
}
print '<td><a href="card.php?id='.$objp->entrepot_id.'">';
print img_object($langs->trans("ShowWarehouse"),"stock").' '.$objp->stock;
print "</a></td>\n";
print '<td align="right">';
if ($objp->value > 0) print '+';
print $objp->value.'</td>';
if ($objp->qty > 0) print '+';
print $objp->qty.'</td>';
print "</tr>\n";
$i++;
}

View File

@@ -1,6 +1,6 @@
<?php
/* Copyright (C) 2001-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2014 Regis Houssin <regis.houssin@capnetworks.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -51,6 +51,8 @@ $year = strftime("%Y",time());
* View
*/
$form=new Form($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.= " FROM ".MAIN_DB_PREFIX."entrepot as e";
@@ -118,7 +120,11 @@ if ($result)
// Selling value
print '<td align="right">';
if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($objp->sellvalue,'MT'),1);
else print $langs->trans("Variable");
else
{
$htmltext=$langs->trans("OptionMULTIPRICESIsOn");
print $form->textwithtooltip($langs->trans("Variable"),$htmltext);
}
print '</td>';
// Status
print '<td align="right">'.$entrepot->LibStatut($objp->statut,5).'</td>';
@@ -134,7 +140,14 @@ if ($result)
print '<tr class="liste_total">';
print '<td colspan="2" align="right">'.$langs->trans("Total").'</td>';
print '<td align="right">'.price(price2num($total,'MT'),1,$langs,0,0,-1,$conf->currency).'</td>';
print '<td align="right">'.price(price2num($totalsell,'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);
else
{
$htmltext=$langs->trans("OptionMULTIPRICESIsOn");
print $form->textwithtooltip($langs->trans("Variable"),$htmltext);
}
print '</td>';
print '<td align="right">&nbsp;</td>';
print "</tr>\n";
}

View File

@@ -107,7 +107,7 @@ if ($action == 'addline')
{
$producttmp=new Product($db);
$producttmp->fetch($id_product);
if ($producttmp->status_batch)
if ($producttmp->hasbatch())
{
if (empty($batch))
{
@@ -117,6 +117,21 @@ if ($action == 'addline')
}
}
// TODO Check qty is ok for stock move. Note qty may not be enough yet, but we make a check now to report a warning.
// What is important is to have qty when doing action 'createmovements'
if (! $error)
{
// Warning, don't forget lines already added into the $_SESSION['massstockmove']
if ($producttmp->hasbatch())
{
}
else
{
}
}
if (! $error)
{
if (count(array_keys($listofdata)) > 0) $id=max(array_keys($listofdata)) + 1;
@@ -214,12 +229,19 @@ if ($action == 'createmovements')
}
else
{
// FIXME Seach record into product_batch table from serial to use same value for dlc and dluo
// FIXME MAke field batch lot required.
/*var_dump($batch);
var_dump($product->stock_warehouse);
exit;*/
$arraybatchinfo=$product->loadBatchInfo($batch);
if (count($arraybatchinfo) > 0)
{
$firstrecord = array_shift($arraybatchinfo);
$dlc=$firstrecord['eatby'];
$dluo=$firstrecord['sellby'];
//var_dump($batch); var_dump($arraybatchinfo); var_dump($firstrecord); var_dump($dlc); var_dump($dluo); exit;
}
else
{
$dlc='';
$dluo='';
}
// Remove stock
$result1=$product->correct_stock_batch(
@@ -325,7 +347,6 @@ $param='';
print '<tr class="liste_titre">';
print getTitleFieldOfList($langs->trans('ProductRef'),0,$_SERVER["PHP_SELF"],'',$param,'','class="tagtd"',$sortfield,$sortorder);
print getTitleFieldOfList('');
if ($conf->productbatch->enabled)
{
print getTitleFieldOfList($langs->trans('Batch'),0,$_SERVER["PHP_SELF"],'',$param,'','class="tagtd"',$sortfield,$sortorder);
@@ -352,8 +373,6 @@ else
}
print $form->select_produits($id_product,'productid',$filtertype,$limit);
print '</td>';
print '<td>';
print '</td>';
// Batch number
if ($conf->productbatch->enabled)
{
@@ -386,12 +405,9 @@ foreach($listofdata as $key => $val)
$warehousestatict->fetch($val['id_tw']);
print '<tr '.$bc[$var].'>';
print '<td>'.$productstatic->getNomUrl(1).'</td>';
print '<td>';
$oldref=$productstatic->ref;
$productstatic->ref=$productstatic->label;
print $productstatic->getNomUrl(1);
$productstatic->ref=$oldref;
print ' - '.$productstatic->label;
print '</td>';
if ($conf->productbatch->enabled)
{

View File

@@ -432,7 +432,9 @@ if ($id > 0 || $ref)
// PMP
print '<tr><td>'.$langs->trans("AverageUnitPricePMP").'</td>';
print '<td>'.price($product->pmp).' '.$langs->trans("HT").'</td>';
print '<td>';
if ($product->pmp > 0) print price($product->pmp).' '.$langs->trans("HT");
print '</td>';
print '</tr>';
// Minimum Price