Fix debug creation of shipment with virtual product.

This commit is contained in:
Laurent Destailleur 2020-11-16 16:31:05 +01:00
parent 548a25b005
commit 6bbeb6d3a0
8 changed files with 80 additions and 45 deletions

View File

@ -2014,7 +2014,7 @@ class Commande extends CommonOrder
$sql .= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,';
$sql .= ' l.fk_unit,';
$sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
$sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tobatch as product_tobatch,';
$sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch,';
$sql .= ' p.weight, p.weight_units, p.volume, p.volume_units';
$sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as l';
$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)';
@ -2077,6 +2077,8 @@ class Commande extends CommonOrder
$line->libelle = $objp->product_label;
$line->product_label = $objp->product_label;
$line->product_desc = $objp->product_desc;
$line->product_tosell = $objp->product_tosell;
$line->product_tobuy = $objp->product_tobuy;
$line->product_tobatch = $objp->product_tobatch;
$line->fk_product_type = $objp->fk_product_type; // Produit ou service
$line->fk_unit = $objp->fk_unit;

View File

@ -62,6 +62,11 @@ abstract class CommonObject
*/
public $error;
/**
* @var string Error string that is hidden but can be used to store complementatry technical code.
*/
public $errorhidden;
/**
* @var string[] Array of error strings
*/

View File

@ -3190,7 +3190,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
'1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
'accountancy', 'account', 'accountline', 'action', 'add', 'address', 'bank_account', 'barcode', 'bank', 'bill', 'bookmark', 'bom', 'building',
'cash-register', 'category', 'check', 'clock', 'close_title', 'company', 'contact', 'contract', 'cubes',
'delete', 'dolly', 'dollyrevert', 'donation', 'edit', 'ellipsis-h', 'email', 'external-link-alt', 'external-link-square-alt',
'delete', 'dolly', 'dollyrevert', 'donation', 'edit', 'ellipsis-h', 'email', 'eraser', 'external-link-alt', 'external-link-square-alt',
'filter', 'file-code', 'file-export', 'file-import', 'file-upload', 'folder', 'folder-open', 'globe', 'globe-americas', 'grip', 'grip_title', 'group',
'help', 'holiday',
'intervention', 'label', 'language', 'list', 'listlight', 'lot',

View File

@ -90,16 +90,6 @@ function product_prepare_head($object)
$h++;
}
$head[$h][0] = DOL_URL_ROOT."/product/stats/card.php?id=".$object->id;
$head[$h][1] = $langs->trans('Statistics');
$head[$h][2] = 'stats';
$h++;
$head[$h][0] = DOL_URL_ROOT."/product/stats/facture.php?showmessage=1&id=".$object->id;
$head[$h][1] = $langs->trans('Referers');
$head[$h][2] = 'referers';
$h++;
if (!empty($conf->variants->enabled) && ($object->isProduct() || $object->isService())) {
global $db;
@ -149,6 +139,16 @@ function product_prepare_head($object)
}
}
$head[$h][0] = DOL_URL_ROOT."/product/stats/facture.php?showmessage=1&id=".$object->id;
$head[$h][1] = $langs->trans('Referers');
$head[$h][2] = 'referers';
$h++;
$head[$h][0] = DOL_URL_ROOT."/product/stats/card.php?id=".$object->id;
$head[$h][1] = $langs->trans('Statistics');
$head[$h][2] = 'stats';
$h++;
// Show more tabs from modules
// Entries must be declared in modules descriptor with line
// $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab

View File

@ -1047,7 +1047,7 @@ if ($action == 'create')
$i++;
}
print '});
jQuery("#autoreset").click(function() {';
jQuery("#autoreset").click(function() { console.log("Reset values to 0"); ';
$i = 0;
while ($i < $numAsked)
{
@ -1075,12 +1075,12 @@ if ($action == 'create')
print '<td class="center">'.$langs->trans("QtyToShip");
if (empty($conf->productbatch->enabled))
{
print '<br><a href="#" id="autofill">'.$langs->trans("Fill").'</a>';
print '<br><a href="#" id="autofill" class="opacitymedium link cursor cursorpointer">'.$langs->trans("Fill").'</a>';
print ' / ';
} else {
print '<br>';
}
print '<a href="#" id="autoreset">'.$langs->trans("Reset").'</a>';
print '<span id="autoreset" class="opacitymedium link cursor cursorpointer">'.img_picto($langs->trans("Reset"), 'eraser').'</span>';
print '</td>';
if (!empty($conf->stock->enabled))
{
@ -1114,7 +1114,7 @@ if ($action == 'create')
if (!empty($line->date_start)) $type = 1;
if (!empty($line->date_end)) $type = 1;
print '<!-- line '.$line->rowid.' for product -->'."\n";
print '<!-- line '.$line->id.' for product -->'."\n";
print '<tr class="oddeven">'."\n";
// Product label
@ -1125,13 +1125,16 @@ if ($action == 'create')
//var_dump($product->stock_warehouse[1]);
print '<td>';
print '<a name="'.$line->rowid.'"></a>'; // ancre pour retourner sur la ligne
print '<a name="'.$line->id.'"></a>'; // ancre pour retourner sur la ligne
// Show product and description
$product_static->type = $line->fk_product_type;
$product_static->id = $line->fk_product;
$product_static->ref = $line->ref;
$product_static->status = $line->product_tosell;
$product_static->status_buy = $line->product_tobuy;
$product_static->status_batch = $line->product_tobatch;
$text = $product_static->getNomUrl(1);
$text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
$description = ($conf->global->PRODUIT_DESC_IN_FORM ? '' : dol_htmlentitiesbr($line->desc));
@ -2048,7 +2051,7 @@ if ($action == 'create')
$sql .= ", ed.rowid as shipmentline_id, ed.qty as qty_shipped, ed.fk_expedition as expedition_id, ed.fk_origin_line, ed.fk_entrepot";
$sql .= ", e.rowid as shipment_id, e.ref as shipment_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_expedition";
//if ($conf->delivery_note->enabled) $sql .= ", l.rowid as livraison_id, l.ref as livraison_ref, l.date_delivery, ld.qty as qty_received";
$sql .= ', p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid, p.tobatch as product_tobatch';
$sql .= ', p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch';
$sql .= ', p.description as product_desc';
$sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
$sql .= ", ".MAIN_DB_PREFIX."expedition as e";
@ -2075,7 +2078,10 @@ if ($action == 'create')
if ($obj)
{
// $obj->rowid is rowid in $origin."det" table
$alreadysent[$obj->rowid][$obj->shipmentline_id] = array('shipment_ref'=>$obj->shipment_ref, 'shipment_id'=>$obj->shipment_id, 'warehouse'=>$obj->fk_entrepot, 'qty_shipped'=>$obj->qty_shipped, 'date_valid'=>$db->jdate($obj->date_valid), 'date_delivery'=>$db->jdate($obj->date_delivery));
$alreadysent[$obj->rowid][$obj->shipmentline_id] = array(
'shipment_ref'=>$obj->shipment_ref, 'shipment_id'=>$obj->shipment_id, 'warehouse'=>$obj->fk_entrepot, 'qty_shipped'=>$obj->qty_shipped,
'product_tosell'=>$obj->product_tosell, 'product_tobuy'=>$obj->product_tobuy, 'product_tobatch'=>$obj->product_tobatch,
'date_valid'=>$db->jdate($obj->date_valid), 'date_delivery'=>$db->jdate($obj->date_delivery));
}
$i++;
}
@ -2084,6 +2090,7 @@ if ($action == 'create')
}
print '<tbody>';
// Loop on each product to send/sent
for ($i = 0; $i < $num_prod; $i++)
{
@ -2119,6 +2126,8 @@ if ($action == 'create')
$product_static->type = $lines[$i]->fk_product_type;
$product_static->id = $lines[$i]->fk_product;
$product_static->ref = $lines[$i]->ref;
$product_static->status = $lines[$i]->product_tosell;
$product_static->status_buy = $lines[$i]->product_tobuy;
$product_static->status_batch = $lines[$i]->product_tobatch;
$product_static->weight = $lines[$i]->weight;

View File

@ -619,10 +619,8 @@ class Expedition extends CommonObject
// Tracking url
$this->getUrlTrackingStatus($obj->tracking_number);
/*
* Thirdparty
*/
$result = $this->fetch_thirdparty();
// Thirdparty
$result = $this->fetch_thirdparty(); // TODO Remove this
// Retrieve extrafields
$this->fetch_optionals();
@ -919,6 +917,7 @@ class Expedition extends CommonObject
$line->entrepot_id = $entrepot_id;
$line->origin_line_id = $id;
$line->fk_origin_line = $id;
$line->qty = $qty;
$orderline = new OrderLine($this->db);
@ -931,31 +930,37 @@ class Expedition extends CommonObject
{
$fk_product = $orderline->fk_product;
if (!($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS))
{
if (!($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS)) {
$langs->load("errors");
$this->error = $langs->trans("ErrorWarehouseRequiredIntoShipmentLine");
return -1;
}
if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT)
{
// Check must be done for stock of product into warehouse if $entrepot_id defined
if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT) {
$product = new Product($this->db);
$result = $product->fetch($fk_product);
$product->fetch($fk_product);
// Check must be done for stock of product into warehouse if $entrepot_id defined
if ($entrepot_id > 0) {
$product->load_stock('warehouseopen');
$product_stock = $product->stock_warehouse[$entrepot_id]->real;
} else $product_stock = $product->stock_reel;
} else {
$product_stock = $product->stock_reel;
}
$product_type = $product->type;
if ($product_type == 0 && $product_stock < $qty)
{
$langs->load("errors");
$this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnShipment', $product->ref);
$this->db->rollback();
return -3;
if ($product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
$isavirtualproduct = ($product->hasFatherOrChild(1) > 0);
// The product is qualified for a check of quantity (must be enough in stock to be added into shipment).
if (!$isavirtualproduct || empty($conf->global->PRODUIT_SOUSPRODUITS) || ($isavirtualproduct && empty($conf->global->STOCK_EXCLUDE_VIRTUAL_PRODUCTS))) { // If STOCK_EXCLUDE_VIRTUAL_PRODUCTS is set, we do not manage stock for kits/virtual products.
if ($product_stock < $qty) {
$langs->load("errors");
$this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnShipment', $product->ref);
$this->errorhidden = 'ErrorStockIsNotEnoughToAddProductOnShipment';
$this->db->rollback();
return -3;
}
}
}
}
}
@ -1576,7 +1581,7 @@ class Expedition extends CommonObject
$sql .= ", cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc, cd.rang";
$sql .= ", ed.rowid as line_id, ed.qty as qty_shipped, ed.fk_origin_line, ed.fk_entrepot";
$sql .= ", p.ref as product_ref, p.label as product_label, p.fk_product_type";
$sql .= ", p.weight, p.weight_units, p.length, p.length_units, p.surface, p.surface_units, p.volume, p.volume_units, p.tobatch as product_tobatch";
$sql .= ", p.weight, p.weight_units, p.length, p.length_units, p.surface, p.surface_units, p.volume, p.volume_units, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch";
$sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed, ".MAIN_DB_PREFIX."commandedet as cd";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = cd.fk_product";
$sql .= " WHERE ed.fk_expedition = ".$this->id;
@ -1638,6 +1643,8 @@ class Expedition extends CommonObject
$line->product_ref = $obj->product_ref;
$line->product_label = $obj->product_label;
$line->libelle = $obj->product_label; // TODO deprecated
$line->product_tosell = $obj->product_tosell;
$line->product_tobuy = $obj->product_tobuy;
$line->product_tobatch = $obj->product_tobatch;
$line->label = $obj->custom_label;
$line->description = $obj->description;

View File

@ -3807,11 +3807,11 @@ class Product extends CommonObject
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Verifie si c'est un sous-produit
* Check if it is a sub-product into a kit
*
* @param int $fk_parent Id du produit auquel le produit est lie
* @param int $fk_child Id du produit lie
* @return int < 0 si erreur, > 0 si ok
* @param int $fk_parent Id of parent kit product
* @param int $fk_child Id of child product
* @return int <0 if KO, >0 if OK
*/
public function is_sousproduit($fk_parent, $fk_child)
{
@ -3827,6 +3827,7 @@ class Product extends CommonObject
if ($num > 0) {
$obj = $this->db->fetch_object($result);
$this->is_sousproduit_qty = $obj->qty;
$this->is_sousproduit_incdec = $obj->incdec;
@ -4221,17 +4222,26 @@ class Product extends CommonObject
}
/**
* Return all parent products for current product (first level only)
* Count all parent and children products for current product (first level only)
*
* @return int Nb of father + child
* @param int $mode 0=Both parent and child, -1=Parents only, 1=Children only
* @return int Nb of father + child
* @see getFather(), get_sousproduits_arbo()
*/
public function hasFatherOrChild()
public function hasFatherOrChild($mode = 0)
{
$nb = 0;
$sql = "SELECT COUNT(pa.rowid) as nb";
$sql .= " FROM ".MAIN_DB_PREFIX."product_association as pa";
$sql .= " WHERE pa.fk_product_fils = ".$this->id." OR pa.fk_product_pere = ".$this->id;
if ($mode == 0) {
$sql .= " WHERE pa.fk_product_fils = ".$this->id." OR pa.fk_product_pere = ".$this->id;
} elseif ($mode == -1) {
$sql .= " WHERE pa.fk_product_fils = ".$this->id; // We are a child, so we found lines that link to parents (can have several parents)
} elseif ($mode == 1) {
$sql .= " WHERE pa.fk_product_pere = ".$this->id; // We are a parent, so we found lines that link to children (can have several children)
}
$resql = $this->db->query($sql);
if ($resql) {
$obj = $this->db->fetch_object($resql);
@ -4297,6 +4307,7 @@ class Product extends CommonObject
* Return all parent products for current product (first level only)
*
* @return array Array of product
* @see hasFatherOrChild()
*/
public function getFather()
{

View File

@ -170,6 +170,7 @@ if ($id > 0 || !empty($ref))
if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year);
print '<form method="post" action="'.$_SERVER ['PHP_SELF'].'?id='.$product->id.'" name="search_form">'."\n";
print '<input type="hidden" name="token" value="'.newToken().'">';
if (!empty($sortfield))
print '<input type="hidden" name="sortfield" value="'.$sortfield.'"/>';
if (!empty($sortorder))