浏览代码

Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into develop

Laurent Destailleur 2 年之前
父节点
当前提交
80b6e78679

+ 2 - 2
htdocs/bom/bom_card.php

@@ -573,7 +573,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
 
 
 	if (!empty($object->table_element_line)) {
 	if (!empty($object->table_element_line)) {
 		// Products
 		// Products
-		$res = $object->fetchLinesbytypeproduct(0);
+		$res = $object->fetchLinesbytypeproduct(0);		// Load all lines products into ->lines
 		$object->calculateCosts();
 		$object->calculateCosts();
 
 
 		print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product');
 		print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product');
@@ -622,7 +622,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
 
 
 		// Services
 		// Services
 		$filtertype = 1;
 		$filtertype = 1;
-		$res = $object->fetchLinesbytypeproduct(1);
+		$res = $object->fetchLinesbytypeproduct(1);		// Load all lines services into ->lines
 		$object->calculateCosts();
 		$object->calculateCosts();
 
 
 		print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service');
 		print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service');

+ 16 - 5
htdocs/bom/class/bom.class.php

@@ -1425,21 +1425,32 @@ class BOM extends CommonObject
 						}
 						}
 					}
 					}
 				} else {
 				} else {
-					//Convert qty to hour
-					$unit = measuringUnitString($line->fk_unit, '', '', 1);
-					$qty = convertDurationtoHour($line->qty, $unit);
+					// Convert qty of line into hours
+					$unitforline = measuringUnitString($line->fk_unit, '', '', 1);
+					$qtyhourforline = convertDurationtoHour($line->qty, $unitforline);
 
 
 					if (isModEnabled('workstation') && !empty($tmpproduct->fk_default_workstation)) {
 					if (isModEnabled('workstation') && !empty($tmpproduct->fk_default_workstation)) {
 						$workstation = new Workstation($this->db);
 						$workstation = new Workstation($this->db);
 						$res = $workstation->fetch($tmpproduct->fk_default_workstation);
 						$res = $workstation->fetch($tmpproduct->fk_default_workstation);
 
 
-						if ($res > 0) $line->total_cost = price2num($qty * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated), 'MT');
+						if ($res > 0) $line->total_cost = price2num($qtyhourforline * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated), 'MT');
 						else {
 						else {
 							$this->error = $workstation->error;
 							$this->error = $workstation->error;
 								return -3;
 								return -3;
 						}
 						}
 					} else {
 					} else {
-						$line->total_cost = price2num($qty * $tmpproduct->cost_price, 'MT');
+						$defaultdurationofservice = $tmpproduct->duration;
+						$reg = array();
+						$qtyhourservice = 0;
+						if (preg_match('/^(\d+)([a-z]+)$/', $defaultdurationofservice, $reg)) {
+							$qtyhourservice = convertDurationtoHour($reg[1], $reg[2]);
+						}
+
+						if ($qtyhourservice) {
+							$line->total_cost = price2num($qtyhourforline / $qtyhourservice * $tmpproduct->cost_price, 'MT');
+						} else {
+							$line->total_cost = price2num($line->qty * $tmpproduct->cost_price, 'MT');
+						}
 					}
 					}
 
 
 					$this->total_cost += $line->total_cost;
 					$this->total_cost += $line->total_cost;

+ 12 - 3
htdocs/bom/tpl/objectline_view.tpl.php

@@ -78,10 +78,14 @@ $objectline = new BOMLine($object->db);
 $coldisplay = 0;
 $coldisplay = 0;
 print "<!-- BEGIN PHP TEMPLATE objectline_view.tpl.php -->\n";
 print "<!-- BEGIN PHP TEMPLATE objectline_view.tpl.php -->\n";
 print '<tr id="row-'.$line->id.'" class="drag drop oddeven" '.$domData.' >';
 print '<tr id="row-'.$line->id.'" class="drag drop oddeven" '.$domData.' >';
+
+// Line nb
 if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
 if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
 	print '<td class="linecolnum center">'.($i + 1).'</td>';
 	print '<td class="linecolnum center">'.($i + 1).'</td>';
 	$coldisplay++;
 	$coldisplay++;
 }
 }
+
+// Product
 print '<td class="linecoldescription minwidth300imp">';
 print '<td class="linecoldescription minwidth300imp">';
 print '<div id="line_'.$line->id.'"></div>';
 print '<div id="line_'.$line->id.'"></div>';
 $coldisplay++;
 $coldisplay++;
@@ -113,6 +117,7 @@ if (!empty($extrafields)) {
 
 
 print '</td>';
 print '</td>';
 
 
+// Qty
 print '<td class="linecolqty nowrap right">';
 print '<td class="linecolqty nowrap right">';
 $coldisplay++;
 $coldisplay++;
 echo price($line->qty, 0, '', 0, 0); // Yes, it is a quantity, not a price, but we just want the formating role of function price
 echo price($line->qty, 0, '', 0, 0); // Yes, it is a quantity, not a price, but we just want the formating role of function price
@@ -142,7 +147,7 @@ if ($filtertype != 1) {
 	echo $line->efficiency;
 	echo $line->efficiency;
 	print '</td>';
 	print '</td>';
 } else {
 } else {
-	//Unité
+	// Unit
 	print '<td class="linecolunit nowrap right">';
 	print '<td class="linecolunit nowrap right">';
 	$coldisplay++;
 	$coldisplay++;
 
 
@@ -166,6 +171,8 @@ if ($filtertype != 1) {
 		print '</td>';
 		print '</td>';
 	}
 	}
 }
 }
+
+// Cost
 $total_cost = 0;
 $total_cost = 0;
 $tmpbom->calculateCosts();
 $tmpbom->calculateCosts();
 print '<td id="costline_'.$line->id.'" class="linecolcost nowrap right">';
 print '<td id="costline_'.$line->id.'" class="linecolcost nowrap right">';
@@ -312,10 +319,12 @@ if ($resql) {
 			print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'"><span class="amount">'.price(price2num($sub_bom_line->total_cost, 'MT')).'</span></td>';
 			print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'"><span class="amount">'.price(price2num($sub_bom_line->total_cost, 'MT')).'</span></td>';
 			$this->total_cost += $line->total_cost;
 			$this->total_cost += $line->total_cost;
 		} elseif ($sub_bom_product->cost_price > 0) {
 		} elseif ($sub_bom_product->cost_price > 0) {
-			print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'"><span class="amount">'.price(price2num($sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty, 'MT')).'</span></td>';
+			print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'">';
+			print '<span class="amount">'.price(price2num($sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty, 'MT')).'</span></td>';
 			$total_cost+= $sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty;
 			$total_cost+= $sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty;
 		} elseif ($sub_bom_product->pmp > 0) {	// PMP if cost price isn't defined
 		} elseif ($sub_bom_product->pmp > 0) {	// PMP if cost price isn't defined
-			print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'"><span class="amount">'.price(price2num($sub_bom_product->pmp * $sub_bom_line->qty * $line->qty, 'MT')).'</span></td>';
+			print '<td class="linecolcost nowrap right" id="sub_bom_cost_'.$sub_bom_line->id.'">';
+			print '<span class="amount">'.price(price2num($sub_bom_product->pmp * $sub_bom_line->qty * $line->qty, 'MT')).'</span></td>';
 			$total_cost.= $sub_bom_product->pmp * $sub_bom_line->qty * $line->qty;
 			$total_cost.= $sub_bom_product->pmp * $sub_bom_line->qty * $line->qty;
 		} else {	// Minimum purchase price if cost price and PMP aren't defined
 		} else {	// Minimum purchase price if cost price and PMP aren't defined
 			$sql_supplier_price = 'SELECT MIN(price) AS min_price, quantity AS qty FROM '.MAIN_DB_PREFIX.'product_fournisseur_price';
 			$sql_supplier_price = 'SELECT MIN(price) AS min_price, quantity AS qty FROM '.MAIN_DB_PREFIX.'product_fournisseur_price';

+ 5 - 3
htdocs/compta/paiement/cheque/index.php

@@ -123,7 +123,7 @@ $max = 10;
 
 
 foreach ($arrayofpaymentmodetomanage as $val) {
 foreach ($arrayofpaymentmodetomanage as $val) {
 	$sql = "SELECT bc.rowid, bc.date_bordereau as db, bc.amount, bc.ref as ref,";
 	$sql = "SELECT bc.rowid, bc.date_bordereau as db, bc.amount, bc.ref as ref,";
-	$sql .= " bc.statut, bc.nbcheque, bc.type,";
+	$sql .= " bc.statut as status, bc.nbcheque, bc.type,";
 	$sql .= " ba.ref as bref, ba.label, ba.rowid as bid, ba.number, ba.currency_code, ba.account_number, ba.fk_accountancy_journal,";
 	$sql .= " ba.ref as bref, ba.label, ba.rowid as bid, ba.number, ba.currency_code, ba.account_number, ba.fk_accountancy_journal,";
 	$sql .= " aj.code";
 	$sql .= " aj.code";
 	$sql .= " FROM ".MAIN_DB_PREFIX."bordereau_cheque as bc, ".MAIN_DB_PREFIX."bank_account as ba";
 	$sql .= " FROM ".MAIN_DB_PREFIX."bordereau_cheque as bc, ".MAIN_DB_PREFIX."bank_account as ba";
@@ -160,7 +160,8 @@ foreach ($arrayofpaymentmodetomanage as $val) {
 
 
 			$checkdepositstatic->id = $objp->rowid;
 			$checkdepositstatic->id = $objp->rowid;
 			$checkdepositstatic->ref = ($objp->ref ? $objp->ref : $objp->rowid);
 			$checkdepositstatic->ref = ($objp->ref ? $objp->ref : $objp->rowid);
-			$checkdepositstatic->statut = $objp->statut;
+			$checkdepositstatic->statut = $objp->status;
+			$checkdepositstatic->status = $objp->status;
 
 
 			$accountstatic->id = $objp->bid;
 			$accountstatic->id = $objp->bid;
 			$accountstatic->ref = $objp->bref;
 			$accountstatic->ref = $objp->bref;
@@ -178,13 +179,14 @@ foreach ($arrayofpaymentmodetomanage as $val) {
 			print '<td class="nowraponall">'.$accountstatic->getNomUrl(1).'</td>';
 			print '<td class="nowraponall">'.$accountstatic->getNomUrl(1).'</td>';
 			print '<td class="right">'.$objp->nbcheque.'</td>';
 			print '<td class="right">'.$objp->nbcheque.'</td>';
 			print '<td class="right"><span class="amount">'.price($objp->amount).'</span></td>';
 			print '<td class="right"><span class="amount">'.price($objp->amount).'</span></td>';
-			print '<td class="right">'.$checkdepositstatic->LibStatut($objp->statut, 3).'</td>';
+			print '<td class="right">'.$checkdepositstatic->LibStatut($objp->status, 3).'</td>';
 
 
 			print '</tr>';
 			print '</tr>';
 		}
 		}
 		if ($i == 0) {
 		if ($i == 0) {
 			print '<tr><td colspan="6"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
 			print '<tr><td colspan="6"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
 		}
 		}
+
 		print "</table>";
 		print "</table>";
 		print '</div>';
 		print '</div>';
 
 

+ 7 - 3
htdocs/compta/paymentbybanktransfer/index.php

@@ -101,7 +101,7 @@ print '</span></td></tr></table></div><br>';
 /*
 /*
  * Invoices waiting for withdraw
  * Invoices waiting for withdraw
  */
  */
-$sql = "SELECT f.ref, f.rowid, f.total_ttc, f.fk_statut, f.paye, f.type,";
+$sql = "SELECT f.ref, f.rowid, f.total_ttc, f.fk_statut, f.paye, f.type, f.datef, f.date_lim_reglement,";
 $sql .= " pfd.date_demande, pfd.amount,";
 $sql .= " pfd.date_demande, pfd.amount,";
 $sql .= " s.nom as name, s.email, s.rowid as socid, s.tva_intra, s.siren as idprof1, s.siret as idprof2, s.ape as idprof3, s.idprof4, s.idprof5, s.idprof6";
 $sql .= " s.nom as name, s.email, s.rowid as socid, s.tva_intra, s.siren as idprof1, s.siret as idprof2, s.ape as idprof3, s.idprof4, s.idprof5, s.idprof6";
 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f,";
 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f,";
@@ -134,16 +134,20 @@ if ($resql) {
 	print '<div class="div-table-responsive-no-min">';
 	print '<div class="div-table-responsive-no-min">';
 	print '<table class="noborder centpercent">';
 	print '<table class="noborder centpercent">';
 	print '<tr class="liste_titre">';
 	print '<tr class="liste_titre">';
-	print '<th colspan="5">'.$langs->trans("SupplierInvoiceWaitingWithdraw").' ('.$num.')</th></tr>';
+	print '<th colspan="5">'.$langs->trans("SupplierInvoiceWaitingWithdraw").' <span class="opacitymedium">('.$num.')</span></th></tr>';
 	if ($num) {
 	if ($num) {
 		while ($i < $num && $i < 20) {
 		while ($i < $num && $i < 20) {
 			$obj = $db->fetch_object($resql);
 			$obj = $db->fetch_object($resql);
 
 
 			$invoicestatic->id = $obj->rowid;
 			$invoicestatic->id = $obj->rowid;
 			$invoicestatic->ref = $obj->ref;
 			$invoicestatic->ref = $obj->ref;
-			$invoicestatic->statut = $obj->fk_statut;
+			$invoicestatic->status = $obj->fk_statut;
+			$invoicestatic->statut = $obj->fk_statut;	// For backward comaptibility
 			$invoicestatic->paye = $obj->paye;
 			$invoicestatic->paye = $obj->paye;
 			$invoicestatic->type = $obj->type;
 			$invoicestatic->type = $obj->type;
+			$invoicestatic->date = $db->jdate($obj->datef);
+			$invoicestatic->date_echeance = $db->jdate($obj->date_lim_reglement);
+			$invoicestatic->total_ttc = $obj->total_ttc;
 			$alreadypayed = $invoicestatic->getSommePaiement();
 			$alreadypayed = $invoicestatic->getSommePaiement();
 
 
 			$thirdpartystatic->id = $obj->socid;
 			$thirdpartystatic->id = $obj->socid;

+ 5 - 15
htdocs/compta/prelevement/create.php

@@ -185,8 +185,6 @@ if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'pr
 }
 }
 $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
 $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
 
 
-llxHeader('', $langs->trans("NewStandingOrder"));
-
 if (prelevement_check_config($type) < 0) {
 if (prelevement_check_config($type) < 0) {
 	$langs->load("errors");
 	$langs->load("errors");
 	$modulenametoshow = "Withdraw";
 	$modulenametoshow = "Withdraw";
@@ -197,21 +195,13 @@ if (prelevement_check_config($type) < 0) {
 }
 }
 
 
 
 
-/*$h=0;
-$head[$h][0] = DOL_URL_ROOT.'/compta/prelevement/create.php';
-$head[$h][1] = $langs->trans("NewStandingOrder");
-$head[$h][2] = 'payment';
-$hselected = 'payment';
-$h++;
-
-print dol_get_fiche_head($head, $hselected, $langs->trans("StandingOrders"), 0, 'payment');
-*/
-
 $title = $langs->trans("NewStandingOrder");
 $title = $langs->trans("NewStandingOrder");
 if ($type == 'bank-transfer') {
 if ($type == 'bank-transfer') {
 	$title = $langs->trans("NewPaymentByBankTransfer");
 	$title = $langs->trans("NewPaymentByBankTransfer");
 }
 }
 
 
+llxHeader('', $title);
+
 print load_fiche_titre($title);
 print load_fiche_titre($title);
 
 
 print dol_get_fiche_head();
 print dol_get_fiche_head();
@@ -223,12 +213,12 @@ if ($nb < 0) {
 }
 }
 print '<table class="border centpercent tableforfield">';
 print '<table class="border centpercent tableforfield">';
 
 
-$title = $langs->trans("NbOfInvoiceToWithdraw");
+$labeltoshow = $langs->trans("NbOfInvoiceToWithdraw");
 if ($type == 'bank-transfer') {
 if ($type == 'bank-transfer') {
-	$title = $langs->trans("NbOfInvoiceToPayByBankTransfer");
+	$labeltoshow = $langs->trans("NbOfInvoiceToPayByBankTransfer");
 }
 }
 
 
-print '<tr><td class="titlefield">'.$title.'</td>';
+print '<tr><td class="titlefield">'.$labeltoshow.'</td>';
 print '<td class="nowraponall">';
 print '<td class="nowraponall">';
 print dol_escape_htmltag($nb);
 print dol_escape_htmltag($nb);
 print '</td></tr>';
 print '</td></tr>';

+ 3 - 0
htdocs/fourn/class/fournisseur.facture.class.php

@@ -2765,6 +2765,9 @@ class FactureFournisseur extends CommonInvoice
 		if (!empty($this->date)) {
 		if (!empty($this->date)) {
 			$datas['date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
 			$datas['date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
 		}
 		}
+		if (!empty($this->date_echeance)) {
+			$datas['date_echeance'] = '<br><b>'.$langs->trans('DateDue').':</b> '.dol_print_date($this->date_echeance, 'day');
+		}
 		if (!empty($this->total_ht)) {
 		if (!empty($this->total_ht)) {
 			$datas['amountht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
 			$datas['amountht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
 		}
 		}

+ 1 - 1
htdocs/langs/en_US/mrp.lang

@@ -83,7 +83,7 @@ ProductsToProduce=Products to produce
 UnitCost=Unit cost
 UnitCost=Unit cost
 TotalCost=Total cost
 TotalCost=Total cost
 BOMTotalCost=The cost to produce this BOM based on cost of each quantity and product to consume (use Cost price if defined, else Average Weighted Price if defined, else the Best purchase price)
 BOMTotalCost=The cost to produce this BOM based on cost of each quantity and product to consume (use Cost price if defined, else Average Weighted Price if defined, else the Best purchase price)
-BOMTotalCostService=If the "Workstation" module is activated and a workstation is defined by default on the line, then the calculation is "quantity (converted into hours) x workstation ahr", otherwise "quantity (converted into hours) x cost price of the service"
+BOMTotalCostService=If the "Workstation" module is activated and a workstation is defined by default on the line, then the calculation is "quantity (converted into hours) x workstation ahr", otherwise "quantity x cost price of the service"
 GoOnTabProductionToProduceFirst=You must first have started the production to close a Manufacturing Order (See tab '%s'). But you can Cancel it.
 GoOnTabProductionToProduceFirst=You must first have started the production to close a Manufacturing Order (See tab '%s'). But you can Cancel it.
 ErrorAVirtualProductCantBeUsedIntoABomOrMo=A kit can't be used into a BOM or a MO
 ErrorAVirtualProductCantBeUsedIntoABomOrMo=A kit can't be used into a BOM or a MO
 Workstation=Workstation
 Workstation=Workstation

+ 1 - 1
htdocs/langs/en_US/withdrawals.lang

@@ -56,7 +56,7 @@ TransData=Transmission date
 TransMetod=Transmission method
 TransMetod=Transmission method
 Send=Send
 Send=Send
 Lines=Lines
 Lines=Lines
-StandingOrderReject=Issue a rejection
+StandingOrderReject=Record a rejection
 WithdrawsRefused=Direct debit refused
 WithdrawsRefused=Direct debit refused
 WithdrawalRefused=Withdrawal refused
 WithdrawalRefused=Withdrawal refused
 CreditTransfersRefused=Credit transfers refused
 CreditTransfersRefused=Credit transfers refused

+ 121 - 9
htdocs/mrp/class/mo.class.php

@@ -98,7 +98,7 @@ class Mo extends CommonObject
 		'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
 		'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
 		'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'position'=>5, 'notnull'=>1, 'default'=>'1', 'index'=>1),
 		'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'position'=>5, 'notnull'=>1, 'default'=>'1', 'index'=>1),
 		'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>4, 'position'=>10, 'notnull'=>1, 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object", 'showoncombobox'=>'1', 'noteditable'=>1),
 		'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>4, 'position'=>10, 'notnull'=>1, 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object", 'showoncombobox'=>'1', 'noteditable'=>1),
-		'fk_bom' => array('type'=>'integer:Bom:bom/class/bom.class.php:0:(t.status:=:1)', 'filter'=>'active=1', 'label'=>'BOM', 'enabled'=>'$conf->bom->enabled', 'visible'=>1, 'position'=>33, 'notnull'=>-1, 'index'=>1, 'comment'=>"Original BOM", 'css'=>'minwidth100 maxwidth300', 'csslist'=>'nowraponall', 'picto'=>'bom'),
+		'fk_bom' => array('type'=>'integer:Bom:bom/class/bom.class.php:0:(t.status:=:1)', 'filter'=>'active=1', 'label'=>'BOM', 'enabled'=>'$conf->bom->enabled', 'visible'=>1, 'position'=>33, 'notnull'=>-1, 'index'=>1, 'comment'=>"Original BOM", 'css'=>'minwidth100 maxwidth500', 'csslist'=>'tdoverflowmax150', 'picto'=>'bom'),
 		'mrptype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>1, 'position'=>34, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing', 1=>'Disassemble'), 'css'=>'minwidth150', 'csslist'=>'minwidth150 center'),
 		'mrptype' => array('type'=>'integer', 'label'=>'Type', 'enabled'=>1, 'visible'=>1, 'position'=>34, 'notnull'=>1, 'default'=>'0', 'arrayofkeyval'=>array(0=>'Manufacturing', 1=>'Disassemble'), 'css'=>'minwidth150', 'csslist'=>'minwidth150 center'),
 		'fk_product' => array('type'=>'integer:Product:product/class/product.class.php:0', 'label'=>'Product', 'enabled'=>'isModEnabled("product")', 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'comment'=>"Product to produce", 'css'=>'maxwidth300', 'csslist'=>'tdoverflowmax100', 'picto'=>'product'),
 		'fk_product' => array('type'=>'integer:Product:product/class/product.class.php:0', 'label'=>'Product', 'enabled'=>'isModEnabled("product")', 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'comment'=>"Product to produce", 'css'=>'maxwidth300', 'csslist'=>'tdoverflowmax100', 'picto'=>'product'),
 		'qty' => array('type'=>'real', 'label'=>'QtyToProduce', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'notnull'=>1, 'comment'=>"Qty to produce", 'css'=>'width75', 'default'=>1, 'isameasure'=>1),
 		'qty' => array('type'=>'real', 'label'=>'QtyToProduce', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'notnull'=>1, 'comment'=>"Qty to produce", 'css'=>'width75', 'default'=>1, 'isameasure'=>1),
@@ -283,26 +283,23 @@ class Mo extends CommonObject
 	 */
 	 */
 	public function create(User $user, $notrigger = false)
 	public function create(User $user, $notrigger = false)
 	{
 	{
-		global $conf;
-
 		$error = 0;
 		$error = 0;
 		$idcreated = 0;
 		$idcreated = 0;
 
 
-		$this->db->begin();
-
-		// Check that product is not a kit/virtual product
-		if (empty($conf->global->ALLOW_USE_KITS_INTO_BOM_AND_MO) && $this->fk_product > 0) {
+		// If kits feature is enabled and we don't allow kits into BOM and MO, we check that the product is not a kit/virtual product
+		if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && !getDolGlobalString('ALLOW_USE_KITS_INTO_BOM_AND_MO') && $this->fk_product > 0) {
 			include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
 			include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
 			$tmpproduct = new Product($this->db);
 			$tmpproduct = new Product($this->db);
 			$tmpproduct->fetch($this->fk_product);
 			$tmpproduct->fetch($this->fk_product);
 			if ($tmpproduct->hasFatherOrChild(1) > 0) {
 			if ($tmpproduct->hasFatherOrChild(1) > 0) {
 				$this->error = 'ErrorAVirtualProductCantBeUsedIntoABomOrMo';
 				$this->error = 'ErrorAVirtualProductCantBeUsedIntoABomOrMo';
 				$this->errors[] = $this->error;
 				$this->errors[] = $this->error;
-				$this->db->rollback();
 				return -1;
 				return -1;
 			}
 			}
 		}
 		}
 
 
+		$this->db->begin();
+
 		if ($this->fk_bom > 0) {
 		if ($this->fk_bom > 0) {
 			// If there is a nown BOM, we force the type of MO to the type of BOM
 			// If there is a nown BOM, we force the type of MO to the type of BOM
 			include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
 			include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
@@ -320,7 +317,7 @@ class Mo extends CommonObject
 		}
 		}
 
 
 		if (!$error) {
 		if (!$error) {
-			$result = $this->updateProduction($user, $notrigger);	// Insert lines from BOM
+			$result = $this->createProduction($user, $notrigger);	// Insert lines from BOM
 			if ($result <= 0) {
 			if ($result <= 0) {
 				$error++;
 				$error++;
 			}
 			}
@@ -640,6 +637,12 @@ class Mo extends CommonObject
 			$error++;
 			$error++;
 		}
 		}
 
 
+		// Update the lines (the qty) to consume or to produce
+		$result = $this->updateProduction($user, $notrigger);
+		if ($result <= 0) {
+			$error++;
+		}
+
 		if (!$error) {
 		if (!$error) {
 			$this->db->commit();
 			$this->db->commit();
 			return 1;
 			return 1;
@@ -649,6 +652,7 @@ class Mo extends CommonObject
 		}
 		}
 	}
 	}
 
 
+
 	/**
 	/**
 	 * Erase and update the line to consume and to produce.
 	 * Erase and update the line to consume and to produce.
 	 *
 	 *
@@ -656,6 +660,114 @@ class Mo extends CommonObject
 	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
 	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
 	 * @return int             <0 if KO, >0 if OK
 	 * @return int             <0 if KO, >0 if OK
 	 */
 	 */
+	public function createProduction(User $user, $notrigger = true)
+	{
+		$error = 0;
+		$role = "";
+
+		if ($this->status != self::STATUS_DRAFT) {
+			return -1;
+		}
+
+		$this->db->begin();
+
+		// Insert lines in mrp_production table from BOM data
+		if (!$error) {
+			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.'mrp_production WHERE fk_mo = '.((int) $this->id);
+			$this->db->query($sql);
+
+			$moline = new MoLine($this->db);
+
+			// Line to produce
+			$moline->fk_mo = $this->id;
+			$moline->qty = $this->qty;
+			$moline->fk_product = $this->fk_product;
+			$moline->position = 1;
+
+			if ($this->fk_bom > 0) {	// If a BOM is defined, we know what to produce.
+				include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
+				$bom = new Bom($this->db);
+				$bom->fetch($this->fk_bom);
+				if ($bom->bomtype == 1) {
+					$role = 'toproduce';
+					$moline->role = 'toconsume';
+				} else {
+					$role = 'toconsume';
+					$moline->role = 'toproduce';
+				}
+			} else {
+				if ($this->mrptype == 1) {
+					$moline->role = 'toconsume';
+				} else {
+					$moline->role = 'toproduce';
+				}
+			}
+
+			$resultline = $moline->create($user, false); // Never use triggers here
+			if ($resultline <= 0) {
+				$error++;
+				$this->error = $moline->error;
+				$this->errors = $moline->errors;
+				dol_print_error($this->db, $moline->error, $moline->errors);
+			}
+
+			if ($this->fk_bom > 0) {	// If a BOM is defined, we know what to consume.
+				if ($bom->id > 0) {
+					// Lines to consume
+					if (!$error) {
+						foreach ($bom->lines as $line) {
+							$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 {
+								$moline->qty = price2num(($line->qty / ( !empty($bom->qty) ? $bom->qty : 1 ) ) * $this->qty / ( !empty($line->efficiency) ? $line->efficiency : 1 ), 'MS'); // Calculate with Qty to produce and  more presition
+							}
+							if ($moline->qty <= 0) {
+								$error++;
+								$this->error = "BadValueForquantityToConsume";
+								break;
+							} else {
+								$moline->fk_product = $line->fk_product;
+								$moline->role = $role;
+								$moline->position = $line->position;
+								$moline->qty_frozen = $line->qty_frozen;
+								$moline->disable_stock_change = $line->disable_stock_change;
+
+								$resultline = $moline->create($user, false); // Never use triggers here
+								if ($resultline <= 0) {
+									$error++;
+									$this->error = $moline->error;
+									$this->errors = $moline->errors;
+									dol_print_error($this->db, $moline->error, $moline->errors);
+									break;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+
+		if (!$error) {
+			$this->db->commit();
+			return 1;
+		} else {
+			$this->db->rollback();
+			return -1;
+		}
+	}
+
+	/**
+	 * Update quantities in lines to consume and to produce.
+	 *
+	 * @param  User $user      User that modifies
+	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
+	 * @return int             <0 if KO, >0 if OK
+	 */
 	public function updateProduction(User $user, $notrigger = true)
 	public function updateProduction(User $user, $notrigger = true)
 	{
 	{
 		$error = 0;
 		$error = 0;

+ 8 - 3
htdocs/mrp/mo_production.php

@@ -169,10 +169,14 @@ if (empty($reshook)) {
 		$moline->origin_type = 'free'; // free consume line
 		$moline->origin_type = 'free'; // free consume line
 		$moline->position = 0;
 		$moline->position = 0;
 
 
+		// Is it a product or a service ?
 		if (!empty($moline->fk_product)) {
 		if (!empty($moline->fk_product)) {
-			$product = new Product($db);
-			$product->fetch($moline->fk_product);
-			if ($product->type == Product::TYPE_SERVICE) $moline->fk_default_workstation = $product->fk_default_workstation;
+			$tmpproduct = new Product($db);
+			$tmpproduct->fetch($moline->fk_product);
+			if ($tmpproduct->type == Product::TYPE_SERVICE) {
+				$moline->fk_default_workstation = $tmpproduct->fk_default_workstation;
+			}
+			$moline->disable_stock_change = ($tmpproduct->type == Product::TYPE_SERVICE ? 1 : 0);
 		}
 		}
 
 
 		$resultline = $moline->create($user, false); // Never use triggers here
 		$resultline = $moline->create($user, false); // Never use triggers here
@@ -184,6 +188,7 @@ if (empty($reshook)) {
 		$action = '';
 		$action = '';
 		// Redirect to refresh the tab information
 		// Redirect to refresh the tab information
 		header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
 		header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
+		exit;
 	}
 	}
 
 
 	if (in_array($action, array('confirm_consumeorproduce', 'confirm_consumeandproduceall')) && $permissiontoproduce) {
 	if (in_array($action, array('confirm_consumeorproduce', 'confirm_consumeandproduceall')) && $permissiontoproduce) {