diff --git a/htdocs/install/mysql/migration/13.0.0-14.0.0.sql b/htdocs/install/mysql/migration/13.0.0-14.0.0.sql index eaad793b47f..2b8ef11801b 100644 --- a/htdocs/install/mysql/migration/13.0.0-14.0.0.sql +++ b/htdocs/install/mysql/migration/13.0.0-14.0.0.sql @@ -135,6 +135,9 @@ ALTER TABLE llx_menu ADD COLUMN prefix varchar(255) NULL AFTER titre; ALTER TABLE llx_chargesociales ADD COLUMN fk_user integer DEFAULT NULL; +ALTER TABLE llx_mrp_production ADD COLUMN origin_id integer AFTER fk_mo; +ALTER TABLE llx_mrp_production ADD COLUMN origin_type varchar(10) AFTER origin_id; + ALTER TABLE llx_fichinter ADD COLUMN last_main_doc varchar(255) AFTER model_pdf; ALTER TABLE llx_projet ADD COLUMN last_main_doc varchar(255) AFTER model_pdf; diff --git a/htdocs/install/mysql/tables/llx_mrp_production.sql b/htdocs/install/mysql/tables/llx_mrp_production.sql index 36129a54aea..a76e1f655ae 100644 --- a/htdocs/install/mysql/tables/llx_mrp_production.sql +++ b/htdocs/install/mysql/tables/llx_mrp_production.sql @@ -17,6 +17,8 @@ CREATE TABLE llx_mrp_production( rowid integer AUTO_INCREMENT PRIMARY KEY NOT NULL, fk_mo integer NOT NULL, + origin_id integer, + origin_type varchar(10), -- 'bom' bom production line or 'free' free production line added after Mo creation from bom position integer NOT NULL DEFAULT 0, fk_product integer NOT NULL, fk_warehouse integer, @@ -24,7 +26,7 @@ CREATE TABLE llx_mrp_production( qty_frozen smallint DEFAULT 0, disable_stock_change smallint DEFAULT 0, batch varchar(128), - role varchar(10), -- 'toconsume' or 'toproduce' (initialized at MO creation), 'consumed' or 'produced' (added after MO validation) + role varchar(10), -- 'toconsume' or 'toproduce' (initialized at MO creation), 'consumed' or 'produced' (added after MO validation) fk_mrp_production integer, -- if role = 'consumed', id of line with role 'toconsume', if role = 'produced' id of line with role 'toproduce' fk_stock_movement integer, -- id of stock movement when movements are validated date_creation datetime NOT NULL, diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index 121909eb28a..2ee97e9e22a 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -655,6 +655,8 @@ class Mo extends CommonObject $moline = new MoLine($this->db); $moline->fk_mo = $this->id; + $moline->origin_id = $line->id; + $moline->origin_type = 'bomline'; if ($line->qty_frozen) { $moline->qty = $line->qty; // Qty to consume does not depends on quantity to produce } else { @@ -1386,6 +1388,8 @@ class MoLine extends CommonObjectLine public $fields = array( 'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10), 'fk_mo' =>array('type'=>'integer', 'label'=>'Mo', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>15), + 'origin_id' =>array('type'=>'integer', 'label'=>'Origin', 'enabled'=>1, 'visible'=>-1, 'notnull'=>0, 'position'=>17), + 'origin_type' =>array('type'=>'varchar(10)', 'label'=>'Origin type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>0, 'position'=>18), 'position' =>array('type'=>'integer', 'label'=>'Position', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>20), 'fk_product' =>array('type'=>'integer', 'label'=>'Product', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>25), 'fk_warehouse' =>array('type'=>'integer', 'label'=>'Warehouse', 'enabled'=>1, 'visible'=>-1, 'position'=>30), @@ -1405,6 +1409,8 @@ class MoLine extends CommonObjectLine public $rowid; public $fk_mo; + public $origin_id; + public $origin_type; public $position; public $fk_product; public $fk_warehouse; @@ -1487,7 +1493,7 @@ class MoLine extends CommonObjectLine public function fetch($id, $ref = null) { $result = $this->fetchCommon($id, $ref); - if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines(); + return $result; } diff --git a/htdocs/mrp/mo_movements.php b/htdocs/mrp/mo_movements.php index b4dbed059bc..8a54a8b0cbd 100644 --- a/htdocs/mrp/mo_movements.php +++ b/htdocs/mrp/mo_movements.php @@ -119,7 +119,7 @@ $arrayfields = array( 'm.type_mouvement'=>array('label'=>$langs->trans("TypeMovement"), 'checked'=>1, 'position'=>48), 'origin'=>array('label'=>$langs->trans("Origin"), 'enabled'=>0, 'checked'=>0, 'position'=>50), 'm.value'=>array('label'=>$langs->trans("Qty"), 'checked'=>1, 'position'=>60), - 'm.price'=>array('label'=>$langs->trans("UnitPurchaseValue"), 'enabled'=>0, 'checked'=>0, 'position'=>62), + 'm.price'=>array('label'=>$langs->trans("UnitCost"), 'enabled'=>0, 'checked'=>0, 'position'=>62), //'m.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500), //'m.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500) ); @@ -139,7 +139,11 @@ $permissiontodelete = $user->rights->mrp->delete || ($permissiontoadd && isset($ $upload_dir = $conf->mrp->multidir_output[isset($object->entity) ? $object->entity : 1]; $permissiontoproduce = $permissiontoadd; +$permissiontoupdatecost = $user->rights->bom->write; // User who can define cost must have knowledge of pricing +if ($permissiontoupdatecost) { + $arrayfields['m.price']['enabled'] = 1; +} /* * Actions diff --git a/htdocs/mrp/mo_production.php b/htdocs/mrp/mo_production.php index c1b6fa64ec8..c519fb91260 100644 --- a/htdocs/mrp/mo_production.php +++ b/htdocs/mrp/mo_production.php @@ -34,6 +34,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; dol_include_once('/mrp/class/mo.class.php'); +dol_include_once('/bom/class/bom.class.php'); dol_include_once('/mrp/lib/mrp_mo.lib.php'); // Load translation files required by the page @@ -88,6 +89,7 @@ $permissiontodelete = $user->rights->mrp->delete || ($permissiontoadd && isset($ $upload_dir = $conf->mrp->multidir_output[isset($object->entity) ? $object->entity : 1]; $permissiontoproduce = $permissiontoadd; +$permissiontoupdatecost = $user->rights->bom->read; // User who can define cost must have knowledge of pricing /* @@ -150,6 +152,7 @@ if (empty($reshook)) $moline->qty = GETPOST('qtytoadd', 'int'); ; $moline->fk_product = GETPOST('productidtoadd', 'int'); $moline->role = 'toconsume'; + $moline->origin_type = 'free'; // free consume line $moline->position = 0; $resultline = $moline->create($user, false); // Never use triggers here @@ -168,7 +171,7 @@ if (empty($reshook)) $codemovement = GETPOST('inventorycode', 'alphanohtml'); $db->begin(); - + $pos = 0; // Process line to consume foreach ($object->lines as $line) { if ($line->role == 'toconsume') { @@ -199,7 +202,11 @@ if (empty($reshook)) // Record stock movement $id_product_batch = 0; $stockmove->origin = $object; - $idstockmove = $stockmove->livraison($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement); + if ($qtytoprocess >= 0) { + $idstockmove = $stockmove->livraison($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement); + } else { + $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement); + } if ($idstockmove < 0) { $error++; setEventMessages($stockmove->error, $stockmove->errors, 'errors'); @@ -207,7 +214,6 @@ if (empty($reshook)) } if (!$error) { - $pos = 0; // Record consumption $moline = new MoLine($db); $moline->fk_mo = $object->id; @@ -237,6 +243,7 @@ if (empty($reshook)) } // Process line to produce + $pos = 0; foreach ($object->lines as $line) { if ($line->role == 'toproduce') { $tmpproduct = new Product($db); @@ -245,36 +252,35 @@ if (empty($reshook)) $i = 1; while (GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i)) { $qtytoprocess = price2num(GETPOST('qtytoproduce-'.$line->id.'-'.$i)); + $pricetoprocess = GETPOST('pricetoproduce-'.$line->id.'-'.$i) ? price2num(GETPOST('pricetoproduce-'.$line->id.'-'.$i)) : 0; + // Check warehouse is set if we should have to + if (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i)) { // If there is a warehouse to set + if (!(GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0)) { // If there is no warehouse set. + $langs->load("errors"); + setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref), null, 'errors'); + $error++; + } + if (!empty($conf->productbatch->enabled) && $tmpproduct->status_batch && (!GETPOST('batchtoproduce-'.$line->id.'-'.$i))) { + $langs->load("errors"); + setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref), null, 'errors'); + $error++; + } + } + + $idstockmove = 0; + if (!$error && GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0) { + // Record stock movement + $id_product_batch = 0; + $stockmove->origin = $object; + $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i), $qtytoprocess, $pricetoprocess, $labelmovement, '', '', GETPOST('batchtoproduce-'.$line->id.'-'.$i), dol_now(), $id_product_batch, $codemovement); + if ($idstockmove < 0) { + $error++; + setEventMessages($stockmove->error, $stockmove->errors, 'errors'); + } + } if ($qtytoprocess != 0) { - // Check warehouse is set if we should have to - if (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i)) { // If there is a warehouse to set - if (!(GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0)) { // If there is no warehouse set. - $langs->load("errors"); - setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref), null, 'errors'); - $error++; - } - if (!empty($conf->productbatch->enabled) && $tmpproduct->status_batch && (!GETPOST('batchtoproduce-'.$line->id.'-'.$i))) { - $langs->load("errors"); - setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref), null, 'errors'); - $error++; - } - } - - $idstockmove = 0; - if (!$error && GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0) { - // Record stock movement - $id_product_batch = 0; - $stockmove->origin = $object; - $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, '', '', GETPOST('batchtoproduce-'.$line->id.'-'.$i), dol_now(), $id_product_batch, $codemovement); - if ($idstockmove < 0) { - $error++; - setEventMessages($stockmove->error, $stockmove->errors, 'errors'); - } - } - if (!$error) { - $pos = 0; // Record production $moline = new MoLine($db); $moline->fk_mo = $object->id; @@ -677,12 +683,23 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Show object lines $object->fetchLines(); + $bomcost = 0; + if ($object->fk_bom > 0) { + $bom = new Bom($db); + $res = $bom->fetch($object->fk_bom); + if ($res > 0) { + $bomcost = $bom->unit_cost; + } + } + + // consumtion + print '