From fa832e8a0df70ba9734bff4f2dd423d64325d971 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 27 Apr 2023 12:37:42 +0200 Subject: [PATCH 1/3] Fix missing date in popup --- htdocs/compta/paymentbybanktransfer/index.php | 8 ++++++-- htdocs/fourn/class/fournisseur.facture.class.php | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/paymentbybanktransfer/index.php b/htdocs/compta/paymentbybanktransfer/index.php index 7331aee48fa..adab830546a 100644 --- a/htdocs/compta/paymentbybanktransfer/index.php +++ b/htdocs/compta/paymentbybanktransfer/index.php @@ -101,7 +101,7 @@ print '
'; /* * 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 .= " 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,"; @@ -141,9 +141,13 @@ if ($resql) { $invoicestatic->id = $obj->rowid; $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->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(); $thirdpartystatic->id = $obj->socid; diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index bc0c7b9e232..ca81a778fee 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -2782,6 +2782,9 @@ class FactureFournisseur extends CommonInvoice if (!empty($this->date)) { $label .= '
'.$langs->trans('Date').': '.dol_print_date($this->date, 'day'); } + if (!empty($this->date_echeance)) { + $label .= '
'.$langs->trans('DateDue').': '.dol_print_date($this->date_echeance, 'day'); + } if (!empty($this->total_ht)) { $label .= '
'.$langs->trans('AmountHT').': '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency); } From 44b5b4fde951b7475c6552c23a43daf6d86d293d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 27 Apr 2023 12:53:50 +0200 Subject: [PATCH 2/3] Fix look and feel v17 --- htdocs/compta/paiement/cheque/index.php | 6 ++++++ htdocs/compta/paymentbybanktransfer/index.php | 2 +- htdocs/compta/prelevement/create.php | 20 +++++-------------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/htdocs/compta/paiement/cheque/index.php b/htdocs/compta/paiement/cheque/index.php index 394de095104..33c4d37c45d 100644 --- a/htdocs/compta/paiement/cheque/index.php +++ b/htdocs/compta/paiement/cheque/index.php @@ -127,6 +127,8 @@ if ($resql) { print ''.$langs->trans("Status").''; print "\n"; + $num = $db->num_rows($resql); + while ($objp = $db->fetch_object($resql)) { $checkdepositstatic->id = $objp->rowid; $checkdepositstatic->ref = ($objp->ref ? $objp->ref : $objp->rowid); @@ -152,6 +154,10 @@ if ($resql) { print ''; } + if (empty($num)) { + print ''.$langs->trans("None").''; + } + print ""; print ''; diff --git a/htdocs/compta/paymentbybanktransfer/index.php b/htdocs/compta/paymentbybanktransfer/index.php index adab830546a..ab26fe4c498 100644 --- a/htdocs/compta/paymentbybanktransfer/index.php +++ b/htdocs/compta/paymentbybanktransfer/index.php @@ -134,7 +134,7 @@ if ($resql) { print '
'; print ''; print ''; - print ''; + print ''; if ($num) { while ($i < $num && $i < 20) { $obj = $db->fetch_object($resql); diff --git a/htdocs/compta/prelevement/create.php b/htdocs/compta/prelevement/create.php index 7c91bfcca8e..deb48fd98e9 100644 --- a/htdocs/compta/prelevement/create.php +++ b/htdocs/compta/prelevement/create.php @@ -183,8 +183,6 @@ if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'pr } $massactionbutton = $form->selectMassAction('', $arrayofmassactions); -llxHeader('', $langs->trans("NewStandingOrder")); - if (prelevement_check_config($type) < 0) { $langs->load("errors"); $modulenametoshow = "Withdraw"; @@ -195,21 +193,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"); if ($type == 'bank-transfer') { $title = $langs->trans("NewPaymentByBankTransfer"); } +llxHeader('', $title); + print load_fiche_titre($title); print dol_get_fiche_head(); @@ -221,12 +211,12 @@ if ($nb < 0) { } print '
'.$langs->trans("SupplierInvoiceWaitingWithdraw").' ('.$num.')
'.$langs->trans("SupplierInvoiceWaitingWithdraw").' ('.$num.')
'; -$title = $langs->trans("NbOfInvoiceToWithdraw"); +$labeltoshow = $langs->trans("NbOfInvoiceToWithdraw"); if ($type == 'bank-transfer') { - $title = $langs->trans("NbOfInvoiceToPayByBankTransfer"); + $labeltoshow = $langs->trans("NbOfInvoiceToPayByBankTransfer"); } -print ''; +print ''; print ''; From 302c6a0ab993d767eb097cb8f846ca987fcb435f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 27 Apr 2023 14:02:59 +0200 Subject: [PATCH 3/3] Fix serious regression in creating MO. --- htdocs/bom/bom_card.php | 4 +- htdocs/bom/class/bom.class.php | 21 +++- htdocs/bom/tpl/objectline_view.tpl.php | 15 ++- htdocs/langs/en_US/mrp.lang | 2 +- htdocs/mrp/class/mo.class.php | 132 +++++++++++++++++++++++-- htdocs/mrp/mo_production.php | 5 + 6 files changed, 158 insertions(+), 21 deletions(-) diff --git a/htdocs/bom/bom_card.php b/htdocs/bom/bom_card.php index 9aa7d084ef1..64681ea098c 100644 --- a/htdocs/bom/bom_card.php +++ b/htdocs/bom/bom_card.php @@ -566,7 +566,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if (!empty($object->table_element_line)) { // Products - $res = $object->fetchLinesbytypeproduct(0); + $res = $object->fetchLinesbytypeproduct(0); // Load all lines products into ->lines $object->calculateCosts(); print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMProductsList'), '', 'product'); @@ -615,7 +615,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Services $filtertype = 1; - $res = $object->fetchLinesbytypeproduct(1); + $res = $object->fetchLinesbytypeproduct(1); // Load all lines services into ->lines $object->calculateCosts(); print ($res == 0 && $object->status >= $object::STATUS_VALIDATED) ? '' : load_fiche_titre($langs->trans('BOMServicesList'), '', 'service'); diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index 1edf20c4472..5bc09528026 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -1391,21 +1391,32 @@ class BOM extends CommonObject } } } 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)) { $workstation = new Workstation($this->db); $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 { $this->error = $workstation->error; return -3; } } 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; diff --git a/htdocs/bom/tpl/objectline_view.tpl.php b/htdocs/bom/tpl/objectline_view.tpl.php index 95bbed79784..b921e23d64d 100644 --- a/htdocs/bom/tpl/objectline_view.tpl.php +++ b/htdocs/bom/tpl/objectline_view.tpl.php @@ -78,10 +78,14 @@ $objectline = new BOMLine($object->db); $coldisplay = 0; print "\n"; print ''; + +// Line nb if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { print ''; $coldisplay++; } + +// Product print ''; +// Qty print ''; } else { - //Unité + // Unit print ''; } } + +// Cost $total_cost = 0; $tmpbom->calculateCosts(); print ''; $this->total_cost += $line->total_cost; } elseif ($sub_bom_product->cost_price > 0) { - print ''; + print ''; $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 - print ''; + print ''; $total_cost.= $sub_bom_product->pmp * $sub_bom_line->qty * $line->qty; } 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'; diff --git a/htdocs/langs/en_US/mrp.lang b/htdocs/langs/en_US/mrp.lang index fffb9e571da..f8ee50b341b 100644 --- a/htdocs/langs/en_US/mrp.lang +++ b/htdocs/langs/en_US/mrp.lang @@ -83,7 +83,7 @@ ProductsToProduce=Products to produce UnitCost=Unit 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) -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. ErrorAVirtualProductCantBeUsedIntoABomOrMo=A kit can't be used into a BOM or a MO Workstation=Workstation diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index ecb82507738..096a1afe906 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -101,7 +101,7 @@ class Mo extends CommonObject '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), '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'), 'fk_product' => array('type'=>'integer:Product:product/class/product.class.php:0', 'label'=>'Product', 'enabled'=>'$conf->product->enabled', '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), @@ -255,26 +255,23 @@ class Mo extends CommonObject */ public function create(User $user, $notrigger = false) { - global $conf; - $error = 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'; $tmpproduct = new Product($this->db); $tmpproduct->fetch($this->fk_product); if ($tmpproduct->hasFatherOrChild(1) > 0) { $this->error = 'ErrorAVirtualProductCantBeUsedIntoABomOrMo'; $this->errors[] = $this->error; - $this->db->rollback(); return -1; } } + $this->db->begin(); + if ($this->fk_bom > 0) { // 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'; @@ -292,7 +289,7 @@ class Mo extends CommonObject } if (!$error) { - $result = $this->updateProduction($user, $notrigger); // Insert lines from BOM + $result = $this->createProduction($user, $notrigger); // Insert lines from BOM if ($result <= 0) { $error++; } @@ -612,6 +609,121 @@ class Mo extends CommonObject $error++; } + // Update the lines (the qty) to consume or to produce + $result = $this->updateProduction($user, $notrigger); + if ($result <= 0) { + $error++; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Erase and update the line 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 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; @@ -622,7 +734,7 @@ class Mo extends CommonObject } /** - * Erase and update the line to consume and to produce. + * 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 diff --git a/htdocs/mrp/mo_production.php b/htdocs/mrp/mo_production.php index 49bafee23c3..894a7156a13 100644 --- a/htdocs/mrp/mo_production.php +++ b/htdocs/mrp/mo_production.php @@ -168,6 +168,11 @@ if (empty($reshook)) { $moline->origin_type = 'free'; // free consume line $moline->position = 0; + // Is it a product or a service ? + $tmpproduct = new Product($db); + $tmpproduct->fetch($moline->fk_product); + $moline->disable_stock_change = ($tmpproduct->type == Product::TYPE_SERVICE ? 1 : 0); + $resultline = $moline->create($user, false); // Never use triggers here if ($resultline <= 0) { $error++;
'.$title.'
'.$labeltoshow.''; print $nb; print '
'.($i + 1).''; print '
'; $coldisplay++; @@ -113,6 +117,7 @@ if (!empty($extrafields)) { print '
'; $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 @@ -142,7 +147,7 @@ if ($filtertype != 1) { echo $line->efficiency; print ''; $coldisplay++; @@ -166,6 +171,8 @@ if ($filtertype != 1) { print ''; @@ -312,10 +319,12 @@ if ($resql) { print ''.price(price2num($sub_bom_line->total_cost, 'MT')).''.price(price2num($sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty, 'MT')).''; + print ''.price(price2num($sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty, 'MT')).''.price(price2num($sub_bom_product->pmp * $sub_bom_line->qty * $line->qty, 'MT')).''; + print ''.price(price2num($sub_bom_product->pmp * $sub_bom_line->qty * $line->qty, 'MT')).'