diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 6eb61c0f983..3f6c9d956a5 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -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; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 3020c53f83d..7c3b368ae14 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -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 */ diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 85b930ae654..76ed140870f 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -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', diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index 09232fbd012..909e51dc6d7 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -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 diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 5fa0ebe26ea..2cef2c39320 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -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 ''.$langs->trans("QtyToShip"); if (empty($conf->productbatch->enabled)) { - print '
'.$langs->trans("Fill").''; + print '
'.$langs->trans("Fill").''; print ' / '; } else { print '
'; } - print ''.$langs->trans("Reset").''; + print ''.img_picto($langs->trans("Reset"), 'eraser').''; print ''; 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 ''."\n"; + print ''."\n"; print ''."\n"; // Product label @@ -1125,13 +1125,16 @@ if ($action == 'create') //var_dump($product->stock_warehouse[1]); print ''; - print ''; // ancre pour retourner sur la ligne + print ''; // 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 ''; + // 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; diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index abc59080912..6c2faa0624d 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -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; diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 59d34f728b1..292690020b9 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -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() { diff --git a/htdocs/product/stats/commande.php b/htdocs/product/stats/commande.php index 4bedbd3d2ba..f89305b4d95 100644 --- a/htdocs/product/stats/commande.php +++ b/htdocs/product/stats/commande.php @@ -170,6 +170,7 @@ if ($id > 0 || !empty($ref)) if (!empty($search_year)) $option .= '&search_year='.urlencode($search_year); print '
'."\n"; + print ''; if (!empty($sortfield)) print ''; if (!empty($sortorder))