2
0
forked from Wavyzz/dolibarr

Several fix in warehouse stock change (rounding, api rest)

This commit is contained in:
Laurent Destailleur
2016-11-18 16:34:03 +01:00
parent 0b3765dd9a
commit 7ac96da0d4
8 changed files with 573 additions and 40 deletions

View File

@@ -93,13 +93,31 @@ class DolibarrApi
// Remove linkedObjects. We should already have linkedObjectIds that avoid huge responses
unset($object->linkedObjects);
unset($object->lignes); // should be lines
unset($object->lignes); // should be ->lines
unset($object->oldline);
unset($object->error);
unset($object->errors);
unset($object->ref_previous);
unset($object->ref_next);
unset($object->ref_int);
unset($object->projet); // Should be fk_project
unset($object->project); // Should be fk_project
unset($object->author); // Should be fk_user_author
unset($object->statuts);
unset($object->statuts_short);
unset($object->statuts_logo);
unset($object->statuts_long);
unset($object->element);
unset($object->fk_element);
unset($object->table_element);
unset($object->table_element_line);
unset($object->picto);
// Remove the $oldcopy property because it is not supported by the JSON
// encoder. The following error is generated when trying to serialize
// it: "Error encoding/decoding JSON: Type is not supported"

View File

@@ -151,7 +151,7 @@ class Categories extends DolibarrApi
$obj = $db->fetch_object($result);
$category_static = new Categorie($db);
if($category_static->fetch($obj->rowid)) {
$obj_ret[] = parent::_cleanObjectDatas($category_static);
$obj_ret[] = $this->_cleanObjectDatas($category_static);
}
$i++;
}
@@ -237,7 +237,7 @@ class Categories extends DolibarrApi
$obj = $db->fetch_object($result);
$category_static = new Categorie($db);
if($category_static->fetch($obj->rowid)) {
$obj_ret[] = parent::_cleanObjectDatas($category_static);
$obj_ret[] = $this->_cleanObjectDatas($category_static);
}
$i++;
}
@@ -339,6 +339,26 @@ class Categories extends DolibarrApi
);
}
/**
* Clean sensible object datas
*
* @param object $object Object to clean
* @return array Array of cleaned object properties
*
* @todo use an array for properties to clean
*
*/
function _cleanObjectDatas($object) {
$object = parent::_cleanObjectDatas($object);
// Remove the subscriptions because they are handled as a subresource.
//unset($object->subscriptions);
return $object;
}
/**
* Validate fields before create or update object
*

View File

@@ -3488,7 +3488,7 @@ function price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerou
* @param string $rounding ''=No rounding
* 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT)
* 'MT'=Round to Max for totals with Tax (MAIN_MAX_DECIMALS_TOT)
* 'MS'=Round to Max Shown (MAIN_MAX_DECIMALS_SHOWN)
* 'MS'=Round to Max for stock quantity (MAIN_MAX_DECIMALS_STOCK)
* @param int $alreadysqlnb Put 1 if you know that content is already universal format number
* @return string Amount with universal numeric format (Example: '99.99999') or unchanged text if conversion fails.
*
@@ -3538,7 +3538,7 @@ function price2num($amount,$rounding='',$alreadysqlnb=0)
$nbofdectoround='';
if ($rounding == 'MU') $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_UNIT;
elseif ($rounding == 'MT') $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_TOT;
elseif ($rounding == 'MS') $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_SHOWN;
elseif ($rounding == 'MS') $nbofdectoround=empty($conf->global->MAIN_MAX_DECIMALS_STOCK)?5:$conf->global->MAIN_MAX_DECIMALS_STOCK;
elseif (is_numeric($rounding)) $nbofdectoround=$rounding; // For admin info page
//print "RR".$amount.' - '.$nbofdectoround.'<br>';
if (dol_strlen($nbofdectoround)) $amount = round($amount,$nbofdectoround); // $nbofdectoround can be 0.

View File

@@ -332,7 +332,8 @@ else
// Nb of products
print '<tr><td>'.$langs->trans("NumberOfProducts").'</td><td>';
print empty($calcproducts['nb'])?'0':$calcproducts['nb'];
$valtoshow=price2num($calcproducts['nb'], 'MS');
print empty($valtoshow)?'0':$valtoshow;
print "</td></tr>";
print '</table>';
@@ -485,13 +486,19 @@ else
$productstatic->entity=$objp->entity;
print $productstatic->getNomUrl(1,'stock',16);
print '</td>';
// Label
print '<td>'.$objp->produit.'</td>';
print '<td align="right">'.$objp->value.'</td>';
print '<td align="right">';
$valtoshow=price2num($objp->value, 'MS');
print empty($valtoshow)?'0':$valtoshow;
print '</td>';
$totalunit+=$objp->value;
// Price buy PMP
print '<td align="right">'.price(price2num($objp->ppmp,'MU')).'</td>';
// Total PMP
print '<td align="right">'.price(price2num($objp->ppmp*$objp->value,'MT')).'</td>';
$totalvalue+=price2num($objp->ppmp*$objp->value,'MT');
@@ -530,7 +537,10 @@ else
$db->free($resql);
print '<tr class="liste_total"><td class="liste_total" colspan="2">'.$langs->trans("Total").'</td>';
print '<td class="liste_total" align="right">'.$totalunit.'</td>';
print '<td class="liste_total" align="right">';
$valtoshow=price2num($totalunit, 'MS');
print empty($valtoshow)?'0':$valtoshow;
print '</td>';
print '<td class="liste_total">&nbsp;</td>';
print '<td class="liste_total" align="right">'.price(price2num($totalvalue,'MT')).'</td>';
if (empty($conf->global->PRODUIT_MULTIPRICES))

View File

@@ -0,0 +1,349 @@
<?php
/* Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
*
* 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/>.
*/
use Luracast\Restler\RestException;
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
/**
* API class for stock movements
*
* @access protected
* @class DolibarrApiAccess {@requires user,external}
*/
class StockMovements extends DolibarrApi
{
/**
* @var array $FIELDS Mandatory fields, checked when create and update object
*/
static $FIELDS = array(
'product_id',
'warehouse_id',
'qty'
);
/**
* @var MouvmeentStock $stockmovement {@type MouvementStock}
*/
public $stockmovement;
/**
* Constructor
*/
function __construct()
{
global $db, $conf;
$this->db = $db;
$this->stockmovement = new MouvementStock($this->db);
}
/**
* Get properties of a stock movement object
*
* Return an array with stock movement informations
*
* @param int $id ID of movement
* @return array|mixed data without useless information
*
* @throws RestException
*/
/*
function get($id)
{
if(! DolibarrApiAccess::$user->rights->stock->lire) {
throw new RestException(401);
}
$result = $this->stockmovement->fetch($id);
if( ! $result ) {
throw new RestException(404, 'warehouse not found');
}
if( ! DolibarrApi::_checkAccessToResource('warehouse',$this->stockmovement->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
return $this->_cleanObjectDatas($this->stockmovement);
}*/
/**
* Get a list of stock movement
*
* @param string $sortfield Sort field
* @param string $sortorder Sort order
* @param int $limit Limit for list
* @param int $page Page number
* @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.product_id:=:1) and (t.date_creation:<:'20160101')"
* @return array Array of warehouse objects
*
* @throws RestException
*/
function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $sqlfilters = '') {
global $db, $conf;
$obj_ret = array();
if(! DolibarrApiAccess::$user->rights->stock->lire) {
throw new RestException(401);
}
$sql = "SELECT t.rowid";
$sql.= " FROM ".MAIN_DB_PREFIX."stock_mouvement as t";
//$sql.= ' WHERE t.entity IN ('.getEntity('stock', 1).')';
$sql.= ' WHERE 1 = 1';
// Add sql filters
if ($sqlfilters)
{
if (! DolibarrApi::_checkFilters($sqlfilters))
{
throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
}
$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
$sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
}
$sql.= $db->order($sortfield, $sortorder);
if ($limit) {
if ($page < 0)
{
$page = 0;
}
$offset = $limit * $page;
$sql.= $db->plimit($limit + 1, $offset);
}
$result = $db->query($sql);
if ($result)
{
$i=0;
$num = $db->num_rows($result);
while ($i < min($num, ($limit <= 0 ? $num : $limit)))
{
$obj = $db->fetch_object($result);
$stockmovement_static = new MouvementStock($db);
if($stockmovement_static->fetch($obj->rowid)) {
$obj_ret[] = $this->_cleanObjectDatas($stockmovement_static);
}
$i++;
}
}
else {
throw new RestException(503, 'Error when retrieve stock movement list : '.$stockmovement_static->error);
}
if( ! count($obj_ret)) {
throw new RestException(404, 'No stock movement found');
}
return $obj_ret;
}
/*
* @param int $product_id Id product id {@min 1}
* @param int $warehouse_id Id warehouse {@min 1}
* @param float $qty Qty to add (Use negative value for a stock decrease) {@min 0} {@message qty must be higher than 0}
* @param string $lot Lot
* @param string $movementcode Movement code {@example INV123}
* @param string $movementlabel Movement label {@example Inventory number 123}
* @param string $price To update AWP (Average Weighted Price) when you make a stock increase (qty must be higher then 0).
*/
/**
* Create stock movement object.
* You can use the following message to test this RES API:
* { "product_id": 1, "warehouse_id": 1, "qty": 1, "lot": "", "movementcode": "INV123", "movementlabel": "Inventory 123", "price": 0 }
*
* @param array $request_data Request data
* @return int ID of stock movement
*/
//function post($product_id, $warehouse_id, $qty, $lot='', $movementcode='', $movementlabel='', $price=0)
function post($request_data = NULL)
{
if(! DolibarrApiAccess::$user->rights->stock->creer) {
throw new RestException(401);
}
// Check mandatory fields
//$result = $this->_validate($request_data);
foreach($request_data as $field => $value) {
//$this->stockmovement->$field = $value;
if ($field == 'product_id') $product_id = $value;
if ($field == 'warehouse_id') $warehouse_id = $value;
if ($field == 'qty') $qty = $value;
if ($field == 'lot') $lot = $value;
if ($field == 'movementcode') $movementcode = $value;
if ($field == 'movementlabel') $movementlabel = $value;
if ($field == 'price') $price = $value;
}
// Type increase or decrease
if ($qty >= 0) $type = 3;
else $type = 2;
if($this->stockmovement->_create(DolibarrApiAccess::$user, $product_id, $warehouse_id, $qty, $type, $price, $movementlabel, $movementcode, '', '', '', $lot) <= 0) {
throw new RestException(503, 'Error when create stock movement : '.$this->stockmovement->error);
}
return $this->stockmovement->id;
}
/**
* Update stock movement
*
* @param int $id Id of warehouse to update
* @param array $request_data Datas
* @return int
*/
/*
function put($id, $request_data = NULL)
{
if(! DolibarrApiAccess::$user->rights->stock->creer) {
throw new RestException(401);
}
$result = $this->stockmovement->fetch($id);
if( ! $result ) {
throw new RestException(404, 'stock movement not found');
}
if( ! DolibarrApi::_checkAccessToResource('stock',$this->stockmovement->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
foreach($request_data as $field => $value) {
$this->stockmovement->$field = $value;
}
if($this->stockmovement->update($id, DolibarrApiAccess::$user))
return $this->get ($id);
return false;
}*/
/**
* Delete stock movement
*
* @param int $id Stock movement ID
* @return array
*/
/*
function delete($id)
{
if(! DolibarrApiAccess::$user->rights->stock->supprimer) {
throw new RestException(401);
}
$result = $this->stockmovement->fetch($id);
if( ! $result ) {
throw new RestException(404, 'stock movement not found');
}
if( ! DolibarrApi::_checkAccessToResource('stock',$this->stockmovement->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
if (! $this->stockmovement->delete(DolibarrApiAccess::$user)) {
throw new RestException(401,'error when delete stock movement');
}
return array(
'success' => array(
'code' => 200,
'message' => 'Warehouse deleted'
)
);
}*/
/**
* Clean sensible object datas
*
* @param object $object Object to clean
* @return array Array of cleaned object properties
*
* @todo use an array for properties to clean
*
*/
function _cleanObjectDatas($object) {
$object = parent::_cleanObjectDatas($object);
// Remove useless data
unset($object->civility_id);
unset($object->firstname);
unset($object->lastname);
unset($object->name);
unset($object->location_incoterms);
unset($object->libelle_incoterms);
unset($object->fk_incoterms);
unset($object->lines);
unset($object->total_ht);
unset($object->total_ttc);
unset($object->total_tva);
unset($object->total_localtax1);
unset($object->total_localtax2);
unset($object->note);
unset($object->note_private);
unset($object->note_public);
unset($object->shipping_method_id);
unset($object->fk_account);
unset($object->modelpdf);
unset($object->fk_delivery_address);
unset($object->cond_reglement);
unset($object->cond_reglement_id);
unset($object->mode_reglement_id);
unset($object->barcode_type_coder);
unset($object->barcode_type_label);
unset($object->barcode_type_code);
unset($object->barcode_type);
unset($object->country_code);
unset($object->country_id);
unset($object->country);
unset($object->thirdparty);
unset($object->contact);
unset($object->contact_id);
unset($object->user);
unset($object->fk_project);
unset($object->project);
//unset($object->eatby); Filled correctly in read mode
//unset($object->sellby); Filled correctly in read mode
return $object;
}
/**
* Validate fields before create or update object
*
* @param array|null $data Data to validate
* @return array
*
* @throws RestException
*/
function _validate($data)
{
$stockmovement = array();
foreach (Warehouses::$FIELDS as $field) {
if (!isset($data[$field]))
throw new RestException(400, "$field field missing");
$stockmovement[$field] = $data[$field];
}
return $stockmovement;
}
}

View File

@@ -136,7 +136,7 @@ class Warehouses extends DolibarrApi
$obj = $db->fetch_object($result);
$warehouse_static = new Entrepot($db);
if($warehouse_static->fetch($obj->rowid)) {
$obj_ret[] = parent::_cleanObjectDatas($warehouse_static);
$obj_ret[] = $this->_cleanObjectDatas($warehouse_static);
}
$i++;
}
@@ -169,7 +169,7 @@ class Warehouses extends DolibarrApi
foreach($request_data as $field => $value) {
$this->warehouse->$field = $value;
}
if($this->warehouse->create(DolibarrApiAccess::$user) < 0) {
if($this->warehouse->create(DolibarrApiAccess::$user) <= 0) {
throw new RestException(503, 'Error when create warehouse : '.$this->warehouse->error);
}
return $this->warehouse->id;
@@ -193,7 +193,7 @@ class Warehouses extends DolibarrApi
throw new RestException(404, 'warehouse not found');
}
if( ! DolibarrApi::_checkAccessToResource('warehouse',$this->warehouse->id)) {
if( ! DolibarrApi::_checkAccessToResource('stock',$this->warehouse->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
@@ -223,7 +223,7 @@ class Warehouses extends DolibarrApi
throw new RestException(404, 'warehouse not found');
}
if( ! DolibarrApi::_checkAccessToResource('warehouse',$this->warehouse->id)) {
if( ! DolibarrApi::_checkAccessToResource('stock',$this->warehouse->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
@@ -239,6 +239,27 @@ class Warehouses extends DolibarrApi
);
}
/**
* Clean sensible object datas
*
* @param object $object Object to clean
* @return array Array of cleaned object properties
*
* @todo use an array for properties to clean
*
*/
function _cleanObjectDatas($object) {
$object = parent::_cleanObjectDatas($object);
// Remove the subscriptions because they are handled as a subresource.
//unset($object->subscriptions);
return $object;
}
/**
* Validate fields before create or update object
*

View File

@@ -30,10 +30,31 @@
*/
class MouvementStock extends CommonObject
{
var $product_id;
var $entrepot_id;
var $qty;
var $type;
/**
* @var string Id to identify managed objects
*/
public $element = 'stockmouvement';
/**
* @var string Name of table without prefix where object is stored
*/
public $table_element = 'stock_mouvement';
public $product_id;
public $warehouse_id;
public $qty;
public $type;
public $tms = '';
public $datem = '';
public $price;
public $fk_user_author;
public $label;
public $fk_origin;
public $origintype;
public $inventorycode;
public $batch;
/**
@@ -46,6 +67,7 @@ class MouvementStock extends CommonObject
$this->db = $db;
}
/**
* Add a movement of stock (in one direction only)
*
@@ -54,18 +76,18 @@ class MouvementStock extends CommonObject
* @param int $entrepot_id Id of warehouse
* @param int $qty Qty of movement (can be <0 or >0 depending on parameter type)
* @param int $type Direction of movement:
* 0=input (stock increase after stock transfert), 1=output (stock decrease after stock transfer),
* 0=input (stock increase by a stock transfer), 1=output (stock decrease after by a stock transfer),
* 2=output (stock decrease), 3=input (stock increase)
* Note that qty should be > 0 with 0 or 3, < 0 with 1 or 2.
* @param int $price Unit price HT of product, used to calculate average weighted price (PMP in french). If 0, average weighted price is not changed.
* @param string $label Label of stock movement
* @param string $inventorycode Inventory code
* @param string $datem Force date of movement
* @param date $eatby eat-by date
* @param date $sellby sell-by date
* @param date $eatby eat-by date. Will be used if lot does not exists yet and will be created.
* @param date $sellby sell-by date. Will be used if lot does not exists yet and will be created.
* @param string $batch batch number
* @param boolean $skip_batch If set to true, stock movement is done without impacting batch record
* @param int $id_product_batch Id product_batch (when skip_batch is flase and we already know which record of product_batch to use)
* @param int $id_product_batch Id product_batch (when skip_batch is false and we already know which record of product_batch to use)
* @return int <0 if KO, 0 if fk_product is null, >0 if OK
*/
function _create($user, $fk_product, $entrepot_id, $qty, $type, $price=0, $label='', $inventorycode='', $datem='',$eatby='',$sellby='',$batch='',$skip_batch=false, $id_product_batch=0)
@@ -75,7 +97,7 @@ class MouvementStock extends CommonObject
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.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, datem=".$datem.", eatby=".$eatby.", sellby=".$sellby.", batch=".$batch.", skip_batch=".$skip_batch);
dol_syslog(get_class($this)."::_create start userid=$user->id, fk_product=$fk_product, warehouse_id=$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;
@@ -90,7 +112,7 @@ class MouvementStock extends CommonObject
}
if ($sellby < 0)
{
$this->errors[]='ErrorBadValueForParameterEatBy';
$this->errors[]='ErrorBadValueForParameterSellBy';
return -1;
}
@@ -315,7 +337,7 @@ class MouvementStock extends CommonObject
$sql.= " '".$origintype."'";
$sql.= ")";
dol_syslog(get_class($this)."::_create", LOG_DEBUG);
dol_syslog(get_class($this)."::_create insert record into stock_mouvement", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
@@ -340,7 +362,7 @@ class MouvementStock extends CommonObject
$sql = "SELECT rowid, reel FROM ".MAIN_DB_PREFIX."product_stock";
$sql.= " WHERE fk_entrepot = ".$entrepot_id." AND fk_product = ".$fk_product; // This is a unique key
dol_syslog(get_class($this)."::_create", LOG_DEBUG);
dol_syslog(get_class($this)."::_create check if a record already exists in product_stock", LOG_DEBUG);
$resql=$this->db->query($sql);
if ($resql)
{
@@ -405,7 +427,7 @@ class MouvementStock extends CommonObject
$sql.= " (".$qty.", ".$entrepot_id.", ".$fk_product.")";
}
dol_syslog(get_class($this)."::_create", LOG_DEBUG);
dol_syslog(get_class($this)."::_create update stock value", LOG_DEBUG);
$resql=$this->db->query($sql);
if (! $resql)
{
@@ -444,7 +466,7 @@ class MouvementStock extends CommonObject
$sql.= " stock=(SELECT SUM(ps.reel) FROM ".MAIN_DB_PREFIX."product_stock as ps WHERE ps.fk_product = p.rowid)";
$sql.= " WHERE rowid = ".$fk_product;
dol_syslog(get_class($this)."::_create", LOG_DEBUG);
dol_syslog(get_class($this)."::_create update AWP", LOG_DEBUG);
$resql=$this->db->query($sql);
if (! $resql)
{
@@ -488,6 +510,96 @@ class MouvementStock extends CommonObject
}
/**
* Load object in memory from the database
*
* @param int $id Id object
*
* @return int <0 if KO, 0 if not found, >0 if OK
*/
public function fetch($id)
{
dol_syslog(__METHOD__, LOG_DEBUG);
$sql = 'SELECT';
$sql .= ' t.rowid,';
$sql .= " t.tms,";
$sql .= " t.datem,";
$sql .= " t.fk_product,";
$sql .= " t.fk_entrepot,";
$sql .= " t.value,";
$sql .= " t.price,";
$sql .= " t.type_mouvement,";
$sql .= " t.fk_user_author,";
$sql .= " t.label,";
$sql .= " t.fk_origin,";
$sql .= " t.origintype,";
$sql .= " t.inventorycode,";
$sql .= " t.batch,";
$sql .= " t.eatby,";
$sql .= " t.sellby";
$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
$sql.= ' WHERE 1 = 1';
//if (null !== $ref) {
//$sql .= ' AND t.ref = ' . '\'' . $ref . '\'';
//} else {
$sql .= ' AND t.rowid = ' . $id;
//}
$resql = $this->db->query($sql);
if ($resql) {
$numrows = $this->db->num_rows($resql);
if ($numrows) {
$obj = $this->db->fetch_object($resql);
$this->id = $obj->rowid;
$this->product_id = $obj->fk_product;
$this->warehouse_id = $obj->fk_entrepot;
$this->qty = $obj->value;
$this->type = $obj->type_mouvement;
$this->tms = $this->db->jdate($obj->tms);
$this->datem = $this->db->jdate($obj->datem);
$this->price = $obj->price;
$this->fk_user_author = $obj->fk_user_author;
$this->label = $obj->label;
$this->fk_origin = $obj->fk_origin;
$this->origintype = $obj->origintype;
$this->inventorycode = $obj->inventorycode;
$this->batch = $obj->batch;
$this->eatby = $this->db->jdate($obj->eatby);
$this->sellby = $this->db->jdate($obj->sellby);
}
// Retrieve all extrafields for invoice
// fetch optionals attributes and labels
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
$extrafields=new ExtraFields($this->db);
$extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
$this->fetch_optionals($this->id,$extralabels);
// $this->fetch_lines();
$this->db->free($resql);
if ($numrows) {
return 1;
} else {
return 0;
}
} else {
$this->errors[] = 'Error ' . $this->db->lasterror();
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
return - 1;
}
}
/**
* Create movement in database for all subproducts
*
@@ -592,8 +704,10 @@ class MouvementStock extends CommonObject
*
* @param int $id Id of product
* @return int <0 if KO, nb of subproducts if OK
* @deprecated A count($product->getChildsArbo($id,1)) is same. No reason to have this in this class.
*/
function nbOfSubProdcuts($id)
/*
function nbOfSubProducts($id)
{
$nbSP=0;
@@ -605,7 +719,7 @@ class MouvementStock extends CommonObject
$nbSP=$obj->nb;
}
return $nbSP;
}
}*/
/**
* Count number of product in stock before a specific date

View File

@@ -534,7 +534,8 @@ if ($resql)
// Nb of products
print '<tr><td>'.$langs->trans("NumberOfProducts").'</td><td>';
print empty($calcproducts['nb'])?'0':$calcproducts['nb'];
$valtoshow=price2num($calcproducts['nb'], 'MS');
print empty($valtoshow)?'0':$valtoshow;
print "</td></tr>";
print '</table>';