diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php index 97e9895686f..a0e37026ff8 100644 --- a/htdocs/core/class/html.formprojet.class.php +++ b/htdocs/core/class/html.formprojet.class.php @@ -464,7 +464,7 @@ class FormProjets if ($table_element == 'projet_task') return ''; // Special cas of element we never link to a project (already always done) $linkedtothirdparty=false; - if (! in_array($table_element, array('don','expensereport_det','expensereport','loan'))) $linkedtothirdparty=true; + if (! in_array($table_element, array('don','expensereport_det','expensereport','loan','stock_mouvement'))) $linkedtothirdparty=true; $sqlfilter=''; $projectkey="fk_projet"; @@ -503,6 +503,10 @@ class FormProjets case "fichinter": $sql = "SELECT t.rowid, t.ref"; break; + case 'stock_mouvement': + $sql = 'SELECT t.rowid, t.label as ref'; + $projectkey='fk_origin'; + break; default: $sql = "SELECT t.rowid, t.ref"; break; @@ -516,7 +520,7 @@ class FormProjets if (is_numeric($socid)) $sql.= " AND t.fk_soc=".$socid; else $sql.= " AND t.fk_soc IN (".$socid.")"; } - if (! in_array($table_element, array('expensereport_det'))) $sql.= ' AND t.entity IN ('.getEntity('project',1).')'; + if (! in_array($table_element, array('expensereport_det','stock_mouvement'))) $sql.= ' AND t.entity IN ('.getEntity('project',1).')'; if ($linkedtothirdparty) $sql.=" AND s.rowid = t.fk_soc"; if ($sqlfilter) $sql.= " AND ".$sqlfilter; $sql.= " ORDER BY ref DESC"; diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index f7a77db4821..cfced089c3a 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -22,6 +22,8 @@ Movements=Movements ErrorWarehouseRefRequired=Warehouse reference name is required ListOfWarehouses=List of warehouses ListOfStockMovements=List of stock movements +StockMovementForId=Movement ID %d +ListMouvementStockProject=List of stock movements associated to project StocksArea=Warehouses area Location=Location LocationSummary=Short name location diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 32ffbeead05..51fca3d8487 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -3520,20 +3520,23 @@ class Product extends CommonObject * @param string $label Label of stock movement * @param double $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 $inventorycode Inventory code + * @param string $origin_element Origin element type + * @param int $origin_id Origin id of element * @return int <0 if KO, >0 if OK */ - function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='') + function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null) { if ($id_entrepot) { $this->db->begin(); require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php'; - + $op[0] = "+".trim($nbpiece); $op[1] = "-".trim($nbpiece); $movementstock=new MouvementStock($this->db); + $movementstock->setOrigin($origin_element, $origin_id); $result=$movementstock->_create($user,$this->id,$id_entrepot,$op[$movement],$movement,$price,$label,$inventorycode); if ($result >= 0) @@ -3565,9 +3568,11 @@ class Product extends CommonObject * @param date $dluo sell-by date * @param string $lot Lot number * @param string $inventorycode Inventory code + * @param string $origin_element Origin element type + * @param int $origin_id Origin id of element * @return int <0 if KO, >0 if OK */ - function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='',$lot='', $inventorycode='') + function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='',$lot='', $inventorycode='', $origin_element='', $origin_id=null) { if ($id_entrepot) { @@ -3579,6 +3584,7 @@ class Product extends CommonObject $op[1] = "-".trim($nbpiece); $movementstock=new MouvementStock($this->db); + $movementstock->setOrigin($origin_element, $origin_id); $result=$movementstock->_create($user,$this->id,$id_entrepot,$op[$movement],$movement,$price,$label,$inventorycode,'',$dlc,$dluo,$lot); if ($result >= 0) diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index dee344b6a5b..e6631d4b716 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -893,6 +893,33 @@ class MouvementStock extends CommonObject return ''; } + + /** + * Set attribute origin to object + * + * @param string $origin_element type of element + * @param int $origin_id id of element + * + * @return void + */ + function setOrigin($origin_element, $origin_id) + { + if (!empty($origin_element) && $origin_id > 0) + { + $origin=''; + if ($origin_element == 'project') + { + if (!class_exists('Project')) require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + $origin = new Project($this->db); + } + + if (!empty($origin)) + { + $this->origin = $origin; + $this->origin->id = $origin_id; + } + } + } /** @@ -911,4 +938,89 @@ class MouvementStock extends CommonObject // There is no specific properties. All data into insert are provided as method parameter. } + + /** + * Return a link (with optionaly the picto) + * Use this->id,this->lastname, this->firstname + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to + * @param integer $notooltip 1=Disable tooltip + * @param int $maxlen Max length of visible user name + * @param string $morecss Add more css on link + * @return string String with URL + */ + function getNomUrl($withpicto=0, $option='', $notooltip=0, $maxlen=24, $morecss='') + { + global $langs, $conf, $db; + + $result = ''; + $companylink = ''; + + $label = '' . $langs->trans("Movement") . ' '.$this->id.''; + $label.= '
'; + $label.= '' . $langs->trans('Label') . ': ' . $this->label; + $label.= '
' . $langs->trans('Qty') . ': ' .$this->qty; + $label.= '
'; + + $link = 'id . $linkend; + return $result; + } + + /** + * Return label statut + * + * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto + * @return string Label of status + */ + function getLibStatut($mode=0) + { + return $this->LibStatut($mode); + } + + /** + * Renvoi le libelle d'un status donne + * + * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto + * @return string Label of status + */ + function LibStatut($mode=0) + { + global $langs; + + if ($mode == 0) + { + return $langs->trans('StatusNotApplicable'); + } + if ($mode == 1) + { + return $langs->trans('StatusNotApplicable'); + } + if ($mode == 2) + { + return img_picto($langs->trans('StatusNotApplicable'),'statut9').' '.$langs->trans('StatusNotApplicable'); + } + if ($mode == 3) + { + return img_picto($langs->trans('StatusNotApplicable'),'statut9'); + } + if ($mode == 4) + { + return img_picto($langs->trans('StatusNotApplicable'),'statut9').' '.$langs->trans('StatusNotApplicable'); + } + if ($mode == 5) + { + return $langs->trans('StatusNotApplicable').' '.img_picto($langs->trans('StatusNotApplicable'),'statut9'); + } + } } diff --git a/htdocs/product/stock/mouvement.php b/htdocs/product/stock/mouvement.php index 8e6775e2e6e..a5daa87a510 100644 --- a/htdocs/product/stock/mouvement.php +++ b/htdocs/product/stock/mouvement.php @@ -34,6 +34,11 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/stock.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +if (! empty($conf->projet->enabled)) +{ + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; +} $langs->load("products"); $langs->load("stocks"); @@ -43,6 +48,7 @@ if (! empty($conf->productbatch->enabled)) $langs->load("productbatch"); $result=restrictedArea($user,'stock'); $id=GETPOST('id','int'); +$msid=GETPOST('msid','int'); $product_id=GETPOST("product_id"); $action=GETPOST('action'); $cancel=GETPOST('cancel'); @@ -156,6 +162,15 @@ if ($action == "correct_stock") if (! $error) { + $origin_element = ''; + $origin_id = null; + + if (GETPOST('projectid', 'int')) + { + $origin_element = 'project'; + $origin_id = GETPOST('projectid', 'int'); + } + if ($product->hasbatch()) { $batch=GETPOST('batch_number'); @@ -173,7 +188,9 @@ if ($action == "correct_stock") GETPOST("label",'san_alpha'), GETPOST('unitprice'), $eatby,$sellby,$batch, - GETPOST('inventorycode') + GETPOST('inventorycode'), + $origin_element, + $origin_id ); // We do not change value of stock for a correction } else @@ -185,7 +202,9 @@ if ($action == "correct_stock") GETPOST("mouvement"), GETPOST("label",'san_alpha'), GETPOST('unitprice'), - GETPOST('inventorycode') + GETPOST('inventorycode'), + $origin_element, + $origin_id ); // We do not change value of stock for a correction } @@ -392,6 +411,7 @@ $userstatic=new User($db); $form=new Form($db); $formother=new FormOther($db); $formproduct=new FormProduct($db); +if (!empty($conf->projet->enabled)) $formproject=new FormProjets($db); $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.fk_product_type as type, p.entity,"; $sql.= " e.label as stock, e.rowid as entrepot_id, e.lieu,"; @@ -412,6 +432,7 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON m.fk_user_author = u.rowid"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lot as pl ON m.batch = pl.batch AND m.fk_product = pl.fk_product"; $sql.= " WHERE m.fk_product = p.rowid"; +if ($msid > 0) $sql .= " AND m.rowid = ".$msid; $sql.= " AND m.fk_entrepot = e.rowid"; $sql.= " AND e.entity IN (".getEntity('stock', 1).")"; if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) $sql.= " AND p.fk_product_type = 0"; @@ -492,8 +513,12 @@ if ($resql) $i = 0; $help_url='EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks'; - $texte = $langs->trans("ListOfStockMovements"); - if ($id) $texte.=' ('.$langs->trans("ForThisWarehouse").')'; + if ($msid) $texte = $langs->trans('StockMovementForId', $msid); + else + { + $texte = $langs->trans("ListOfStockMovements"); + if ($id) $texte.=' ('.$langs->trans("ForThisWarehouse").')'; + } llxHeader("",$texte,$help_url); /* diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php index 6bcf98e96c1..158440c5855 100644 --- a/htdocs/product/stock/product.php +++ b/htdocs/product/stock/product.php @@ -37,6 +37,11 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productstockentrepot.class.php'; if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php'; +if (! empty($conf->projet->enabled)) +{ + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; +} $langs->load("products"); $langs->load("orders"); @@ -220,6 +225,15 @@ if ($action == "correct_stock" && ! $cancel) $priceunit=price2num(GETPOST("unitprice")); if (is_numeric(GETPOST("nbpiece")) && $id) { + $origin_element = ''; + $origin_id = null; + + if (GETPOST('projectid', 'int')) + { + $origin_element = 'project'; + $origin_id = GETPOST('projectid', 'int'); + } + if (empty($object)) { $object = new Product($db); $result=$object->fetch($id); @@ -236,7 +250,9 @@ if ($action == "correct_stock" && ! $cancel) $d_eatby, $d_sellby, $batchnumber, - GETPOST('inventorycode') + GETPOST('inventorycode'), + $origin_element, + $origin_id ); // We do not change value of stock for a correction } else @@ -248,7 +264,9 @@ if ($action == "correct_stock" && ! $cancel) GETPOST("mouvement"), GETPOST("label"), $priceunit, - GETPOST('inventorycode') + GETPOST('inventorycode'), + $origin_element, + $origin_id ); // We do not change value of stock for a correction } @@ -490,7 +508,7 @@ if ($action == 'updateline' && GETPOST('save') == $langs->trans('Save')) $form = new Form($db); $formproduct=new FormProduct($db); - +if (! empty($conf->projet->enabled)) $formproject=new FormProjets($db); if ($id > 0 || $ref) { diff --git a/htdocs/product/stock/tpl/stockcorrection.tpl.php b/htdocs/product/stock/tpl/stockcorrection.tpl.php index ac37566457f..d08cf334671 100644 --- a/htdocs/product/stock/tpl/stockcorrection.tpl.php +++ b/htdocs/product/stock/tpl/stockcorrection.tpl.php @@ -77,7 +77,14 @@ // Purchase price print ''; print ''.$langs->trans("UnitPurchaseValue").''; - print ''; + print ''; + if (! empty($conf->projet->enabled)) + { + print ''.$langs->trans('Project').''; + print ''; + $formproject->select_projects(); + print ''; + } print ''; // Serial / Eat-by date diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 4a0c12c040e..edd4c6eed12 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -496,6 +496,10 @@ class Project extends CommonObject { $sql = "SELECT DISTINCT pt.rowid, ptt.fk_user FROM " . MAIN_DB_PREFIX . "projet_task as pt, " . MAIN_DB_PREFIX . "projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet=" . $this->id; } + elseif ($type == 'stock_mouvement') + { + $sql = 'SELECT ms.rowid, ms.fk_user_author as fk_user FROM ' . MAIN_DB_PREFIX . 'stock_mouvement as ms WHERE ms.origintype = "project" AND ms.fk_origin = ' . $this->id . ' AND ms.type_mouvement = 1'; + } else { $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . $tablename." WHERE fk_projet=" . $this->id; diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index cd7cdba7ec4..87a5509cd38 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -48,6 +48,7 @@ if (! empty($conf->expensereport->enabled)) require_once DOL_DOCUMENT_ROOT.'/exp if (! empty($conf->agenda->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; if (! empty($conf->don->enabled)) require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php'; if (! empty($conf->loan->enabled)) require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php'; +if (! empty($conf->stock->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; $langs->load("projects"); $langs->load("companies"); @@ -397,6 +398,15 @@ $listofreferent=array( 'buttonnew'=>'AddTimeSpent', 'testnew'=>$user->rights->projet->creer, 'test'=>($conf->projet->enabled && $user->rights->projet->lire && empty($conf->global->PROJECT_HIDE_TASKS))), +'stock_mouvement'=>array( + 'name'=>"MouvementStockAssociated", + 'title'=>"ListMouvementStockProject", + 'class'=>'MouvementStock', + 'margin'=>'minus', + 'table'=>'stock_mouvement', + 'datefieldname'=>'datem', + 'disableamount'=>0, + 'test'=>$conf->stock->enabled && $user->rights->stock->mouvement->lire), /* No need for this, available on dedicated tab "Agenda/Events" 'agenda'=>array( 'name'=>"Agenda", @@ -483,6 +493,7 @@ $langs->load("bills"); $langs->load("orders"); $langs->load("proposals"); $langs->load("margins"); +if (!empty($conf->stock->enabled)) $langs->load('stocks'); print load_fiche_titre($langs->trans("Profit"), '', 'title_accountancy'); @@ -529,6 +540,7 @@ foreach ($listofreferent as $key => $value) // Special cases if ($tablename != 'expensereport_det' && method_exists($element, 'fetch_thirdparty')) $element->fetch_thirdparty(); if ($tablename == 'don') $total_ht_by_line=$element->amount; + elseif ($tablename == 'stock_mouvement') $total_ht_by_line=$element->price*abs($element->qty); elseif ($tablename == 'projet_task') { if ($idofelementuser) @@ -553,6 +565,7 @@ foreach ($listofreferent as $key => $value) if ($qualifiedfortotal) $total_ht = $total_ht + $total_ht_by_line; if ($tablename == 'don') $total_ttc_by_line=$element->amount; + elseif ($tablename == 'stock_mouvement') $total_ttc_by_line=$element->price*abs($element->qty); elseif ($tablename == 'projet_task') { $defaultvat = get_default_tva($mysoc, $mysoc); @@ -601,6 +614,9 @@ foreach ($listofreferent as $key => $value) case 'Contrat': $newclassname = 'Contract'; break; + case 'MouvementStock': + $newclassname = 'StockMovement'; + break; default: $newclassname = $classname; } @@ -717,7 +733,7 @@ foreach ($listofreferent as $key => $value) // Thirdparty or user print ''; if (in_array($tablename, array('projet_task')) && $key == 'project_task') print ''; // if $key == 'project_task', we don't want details per user - elseif (in_array($tablename, array('expensereport_det','don','projet_task'))) print $langs->trans("User"); + elseif (in_array($tablename, array('expensereport_det','don','projet_task','stock_mouvement'))) print $langs->trans("User"); else print $langs->trans("ThirdParty"); print ''; // Amount HT @@ -800,7 +816,7 @@ foreach ($listofreferent as $key => $value) print ""; // Remove link print ''; - if ($tablename != 'projet_task') + if ($tablename != 'projet_task' && $tablename != 'stock_mouvement') { print '' . img_picto($langs->trans('Unlink'), 'editdelete') . ''; } @@ -848,6 +864,7 @@ foreach ($listofreferent as $key => $value) // Date or TimeSpent $date=''; $total_time_by_line = null; if ($tablename == 'expensereport_det') $date = $element->date; // No draft status on lines + elseif ($tablename == 'stock_mouvement') $date = $element->datem; elseif (! empty($element->status) || ! empty($element->statut) || ! empty($element->fk_status)) { if ($tablename=='don') $date = $element->datedon; @@ -889,7 +906,7 @@ foreach ($listofreferent as $key => $value) $tmpuser->fetch($expensereport->fk_user_author); print $tmpuser->getNomUrl(1,'',48); } - else if ($tablename == 'don') + else if ($tablename == 'don' || $tablename == 'stock_mouvement') { if ($element->fk_user_author > 0) { @@ -911,6 +928,7 @@ foreach ($listofreferent as $key => $value) $total_ht_by_line=null; $othermessage=''; if ($tablename == 'don') $total_ht_by_line=$element->amount; + elseif ($tablename == 'stock_mouvement') $total_ht_by_line=$element->price*abs($element->qty); elseif (in_array($tablename, array('projet_task'))) { if (! empty($conf->salaries->enabled)) @@ -950,6 +968,7 @@ foreach ($listofreferent as $key => $value) { $total_ttc_by_line=null; if ($tablename == 'don') $total_ttc_by_line=$element->amount; + elseif ($tablename == 'stock_mouvement') $total_ttc_by_line=$element->price*abs($element->qty); elseif ($tablename == 'projet_task') { if (! empty($conf->salaries->enabled)) @@ -998,6 +1017,10 @@ foreach ($listofreferent as $key => $value) print $element->progress.' %'; } } + else if ($tablename == 'stock_mouvement') + { + print $element->getLibStatut(3); + } else { print $element->getLibStatut(5);