diff --git a/htdocs/blockedlog/README-fr.md b/htdocs/blockedlog/README-fr.md index e92bd5a09fe..a5d709ca7a7 100644 --- a/htdocs/blockedlog/README-fr.md +++ b/htdocs/blockedlog/README-fr.md @@ -4,7 +4,7 @@ LOG INALTERABLE ## Fonctionnalité Ce module trace, en temps réel, certains évènements métiers dans une log inaltérable (que vous ne pouvez pas modifier une fois enregistrés) de type blockchain. -Ce module est requis pour la compatibilité avec les exigences légales de certains pays (comme la France avec la loi Fincance 2016 - Norme NF535). +Ce module est requis pour la compatibilité avec les exigences légales de certains pays (comme la France avec la loi Finance 2016 - Norme NF525). **Les évènements tracés de manière inaltérables sont:** diff --git a/htdocs/blockedlog/README.md b/htdocs/blockedlog/README.md index ec3174fb847..7bd9b10787e 100644 --- a/htdocs/blockedlog/README.md +++ b/htdocs/blockedlog/README.md @@ -4,7 +4,7 @@ BLOCKED LOG ## Feature This module tracks, in real time, some events into a non reversible log (that you can't modify once recorded) into a block chain. -This module provides compatibility with requirements of laws of some countries (like France with the law Fincance 2016 - Norme NF535). +This module provides compatibility with requirements of laws of some countries (like France with the law Finance 2016 - Norme NF525). **The tracked events are:** diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 3ce88a4a588..2e2b2de1f46 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -80,8 +80,6 @@ if (isModEnabled('margin')) { } // General $Variables -$projectid = (GETPOST('projectid', 'int') ? GETPOST('projectid', 'int') : 0); - $id = (GETPOST('id', 'int') ? GETPOST('id', 'int') : GETPOST('facid', 'int')); // For backward compatibility $ref = GETPOST('ref', 'alpha'); $socid = GETPOST('socid', 'int'); @@ -100,6 +98,7 @@ $fac_rec = GETPOST('fac_rec', 'int'); $facid = GETPOST('facid', 'int'); $ref_client = GETPOST('ref_client', 'int'); $rank = (GETPOST('rank', 'int') > 0) ? GETPOST('rank', 'int') : -1; +$projectid = (GETPOST('projectid', 'int') ? GETPOST('projectid', 'int') : 0); // PDF $hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0)); @@ -3149,7 +3148,7 @@ if ($action == 'create') { print '
'; print ''; - print ''; + print ''; if ($soc->id > 0) { print ''."\n"; } @@ -3215,11 +3214,10 @@ if ($action == 'create') { $(\'input[name="force_fk_account"]\').val(\'1\'); $("#formtocreate").submit(); */ - // For company change, we must reuse data of comany, not input already done, so we call a GET with action=create, not a POST submit. - console.log("We have changed the company - Reload page"); - var socid = $(this).val(); - var fac_rec = $(\'#fac_rec\').val(); - window.location.href = "'.$_SERVER["PHP_SELF"].'?action=create&socid="+socid+"&fac_rec="+fac_rec; + // For company change, we must submit page with action=create instead of action=add + console.log("We have changed the company - Resubmit page"); + jQuery("#formtocreateaction").val("create"); + jQuery("#formtocreate").submit(); }); }); '; diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index ab0fbe2c0de..fd60a6a84a4 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -1793,11 +1793,11 @@ if ($resql) { $with_margin_info = false; if (isModEnabled('margin') && ( - !empty($arrayfields['total_pa']['checked']) - || !empty($arrayfields['total_margin']['checked']) - || !empty($arrayfields['total_margin_rate']['checked']) - || !empty($arrayfields['total_mark_rate']['checked']) - ) + !empty($arrayfields['total_pa']['checked']) + || !empty($arrayfields['total_margin']['checked']) + || !empty($arrayfields['total_margin_rate']['checked']) + || !empty($arrayfields['total_mark_rate']['checked']) + ) ) { $with_margin_info = true; } diff --git a/htdocs/install/repair.php b/htdocs/install/repair.php index 0d37f4d2dd7..c40f4a69e89 100644 --- a/htdocs/install/repair.php +++ b/htdocs/install/repair.php @@ -903,9 +903,8 @@ if ($ok && GETPOST('clean_product_stock_batch', 'alpha')) { $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch"; $sql .= " FROM ".MAIN_DB_PREFIX."product as p, ".MAIN_DB_PREFIX."product_stock as ps LEFT JOIN ".MAIN_DB_PREFIX."product_batch as pb ON ps.rowid = pb.fk_product_stock"; $sql .= " WHERE p.rowid = ps.fk_product"; - $sql .= " AND p.tobatch > 0"; $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel"; - $sql .= " HAVING reel != SUM(pb.qty) or SUM(pb.qty) IS NULL"; + $sql .= " HAVING (SUM(pb.qty) IS NOT NULL AND reel != SUM(pb.qty)) OR (SUM(pb.qty) IS NULL AND p.tobatch > 0)"; print $sql; $resql = $db->query($sql); if ($resql) { @@ -915,53 +914,73 @@ if ($ok && GETPOST('clean_product_stock_batch', 'alpha')) { $i = 0; while ($i < $num) { $obj = $db->fetch_object($resql); - print 'Product '.$obj->rowid.'-'.$obj->ref.' in warehouse '.$obj->fk_entrepot.' (product_stock id '.$obj->psrowid.'): '.$obj->reel.' (Stock product_stock.reel) != '.($obj->reelbatch ? $obj->reelbatch : '0').' (Stock batch sum product_batch)'; + print 'Product '.$obj->rowid.'-'.$obj->ref.' in warehouse id='.$obj->fk_entrepot.' (product_stock.id='.$obj->psrowid.'): '.$obj->reel.' (Stock product_stock.reel) != '.($obj->reelbatch ? $obj->reelbatch : '0').' (Stock batch sum product_batch)'; - // Fix + // Fix is required if ($obj->reel != $obj->reelbatch) { - if ($methodtofix == 'updatebatch') { - // Method 1 - print ' -> Insert qty '.($obj->reel - $obj->reelbatch).' with lot 000000 linked to fk_product_stock='.$obj->psrowid; + if (empty($obj->tobatch)) { + // If product is not a product that support batches, we can clean stock by deleting the product batch lines + print ' -> Delete qty '.$obj->reelbatch.' for any lot linked to fk_product_stock='.$obj->psrowid; + $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."product_batch"; + $sql2 .= " WHERE fk_product_stock = ".((int) $obj->psrowid); + print '
'.$sql2; + if (GETPOST('clean_product_stock_batch') == 'confirmed') { - $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."product_batch(fk_product_stock, batch, qty)"; - $sql2 .= "VALUES(".$obj->psrowid.", '000000', ".($obj->reel - $obj->reelbatch).")"; $resql2 = $db->query($sql2); if (!$resql2) { - // TODO If it fails, we must make update - //$sql2 ="UPDATE ".MAIN_DB_PREFIX."product_batch"; - //$sql2.=" SET ".$obj->psrowid.", '000000', ".($obj->reel - $obj->reelbatch).")"; - //$sql2.=" WHERE fk_product_stock = ".((int) $obj->psrowid) - } - } - } - if ($methodtofix == 'updatestock') { - // Method 2 - print ' -> Update qty of product_stock with qty = '.($obj->reelbatch ? ((float) $obj->reelbatch) : '0').' for ps.rowid = '.((int) $obj->psrowid); - if (GETPOST('clean_product_stock_batch') == 'confirmed') { - $error = 0; - - $db->begin(); - - $sql2 = "UPDATE ".MAIN_DB_PREFIX."product_stock"; - $sql2 .= " SET reel = ".($obj->reelbatch ? ((float) $obj->reelbatch) : '0')." WHERE rowid = ".((int) $obj->psrowid); - $resql2 = $db->query($sql2); - if ($resql2) { - // We update product_stock, so we must fill p.stock into product too. - $sql3 = 'UPDATE '.MAIN_DB_PREFIX.'product p SET p.stock= (SELECT SUM(ps.reel) FROM '.MAIN_DB_PREFIX.'product_stock ps WHERE ps.fk_product = p.rowid)'; - $resql3 = $db->query($sql3); - if (!$resql3) { - $error++; - dol_print_error($db); - } - } else { $error++; dol_print_error($db); } + } + } else { + if ($methodtofix == 'updatebatch') { + // Method 1 + print ' -> Insert qty '.($obj->reel - $obj->reelbatch).' with lot 000000 linked to fk_product_stock='.$obj->psrowid; + $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."product_batch(fk_product_stock, batch, qty)"; + $sql2 .= "VALUES(".((int) $obj->psrowid).", '000000', ".((float) ($obj->reel - $obj->reelbatch)).")"; + print '
'.$sql2; - if (!$error) { - $db->commit(); - } else { - $db->rollback(); + if (GETPOST('clean_product_stock_batch') == 'confirmed') { + $resql2 = $db->query($sql2); + if (!$resql2) { + // TODO If it fails, we must make update + //$sql2 ="UPDATE ".MAIN_DB_PREFIX."product_batch"; + //$sql2.=" SET ".$obj->psrowid.", '000000', ".($obj->reel - $obj->reelbatch).")"; + //$sql2.=" WHERE fk_product_stock = ".((int) $obj->psrowid) + } + } + } + if ($methodtofix == 'updatestock') { + // Method 2 + print ' -> Update qty of product_stock with qty = '.($obj->reelbatch ? ((float) $obj->reelbatch) : '0').' for ps.rowid = '.((int) $obj->psrowid); + $sql2 = "UPDATE ".MAIN_DB_PREFIX."product_stock"; + $sql2 .= " SET reel = ".($obj->reelbatch ? ((float) $obj->reelbatch) : '0')." WHERE rowid = ".((int) $obj->psrowid); + print '
'.$sql2; + + if (GETPOST('clean_product_stock_batch') == 'confirmed') { + $error = 0; + + $db->begin(); + + $resql2 = $db->query($sql2); + if ($resql2) { + // We update product_stock, so we must fill p.stock into product too. + $sql3 = 'UPDATE '.MAIN_DB_PREFIX.'product p SET p.stock= (SELECT SUM(ps.reel) FROM '.MAIN_DB_PREFIX.'product_stock ps WHERE ps.fk_product = p.rowid)'; + $resql3 = $db->query($sql3); + if (!$resql3) { + $error++; + dol_print_error($db); + } + } else { + $error++; + dol_print_error($db); + } + + if (!$error) { + $db->commit(); + } else { + $db->rollback(); + } } } } diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index 5d262f54200..164bfc3911c 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -308,7 +308,7 @@ ErrorExistingPermission = Permission %s for object %s already exis ErrorFieldExist=The value for %s already exist ErrorEqualModule=Module invalid in %s ErrorFieldValue=Value for %s is incorrect -ErrorCoherenceMenu=%s is required when % equal LEFT +ErrorCoherenceMenu=%s is required when %s is 'left' # Warnings WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup. diff --git a/htdocs/langs/en_US/interventions.lang b/htdocs/langs/en_US/interventions.lang index 4119973d6dd..b92474e7f91 100644 --- a/htdocs/langs/en_US/interventions.lang +++ b/htdocs/langs/en_US/interventions.lang @@ -50,7 +50,7 @@ UseDateWithoutHourOnFichinter=Hides hours and minutes off the date field for int InterventionStatistics=Statistics of interventions NbOfinterventions=No. of intervention cards NumberOfInterventionsByMonth=No. of intervention cards by month (date of validation) -AmountOfInteventionNotIncludedByDefault=Amount of intervention is not included by default into profit (in most cases, timesheets are used to count time spent). Add option PROJECT_INCLUDE_INTERVENTION_AMOUNT_IN_PROFIT to 1 into home-setup-other to include them. +AmountOfInteventionNotIncludedByDefault=Amount of intervention is not included by default into profit (in most cases, timesheets are used to count time spent). You can use PROJECT_ELEMENTS_FOR_ADD_MARGIN and PROJECT_ELEMENTS_FOR_MINUS_MARGIN option into home-setup-other to complete list of element included into profit. InterId=Intervention id InterRef=Intervention ref. InterDateCreation=Date creation intervention diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 3b911a4c2c7..9bd1a202245 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -1277,7 +1277,7 @@ if (!empty($arrayfields['p.stock']['checked'])) { print_liste_field_titre($arrayfields['p.stock']['label'], $_SERVER["PHP_SELF"], "p.stock", "", $param, '', $sortfield, $sortorder, 'right '); } if (!empty($arrayfields['stock_virtual']['checked'])) { - print_liste_field_titre($arrayfields['stock_virtual']['label'], $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder, 'right '); + print_liste_field_titre($arrayfields['stock_virtual']['label'], $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder, 'right ', 'VirtualStockDesc'); } if (!empty($arrayfields['p.tobatch']['checked'])) { print_liste_field_titre($arrayfields['p.tobatch']['label'], $_SERVER["PHP_SELF"], "p.tobatch", "", $param, '', $sortfield, $sortorder, 'center '); @@ -1854,7 +1854,7 @@ while ($i < $imaxinloop) { } if ($usercancreadprice) { if ($product_static->stock_reel < 0) { print ''; } - print price(price2num($product_static->stock_reel, 'MS')); + print price(price2num($product_static->stock_reel, 'MS'), 0, $langs, 1, 0); if ($product_static->stock_reel < 0) { print ''; } } } @@ -1872,7 +1872,7 @@ while ($i < $imaxinloop) { } if ($usercancreadprice) { if ($product_static->stock_theorique < 0) { print ''; } - print price(price2num($product_static->stock_theorique, 'MS')); + print price(price2num($product_static->stock_theorique, 'MS'), 0, $langs, 1, 0); if ($product_static->stock_theorique < 0) { print ''; } } } diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php index 9946e7a9077..22c475ab337 100644 --- a/htdocs/product/reassort.php +++ b/htdocs/product/reassort.php @@ -493,7 +493,7 @@ if ($resql) { print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' '; } if ($objp->stock_physique < 0) { print ''; } - print price2num($objp->stock_physique, 'MS'); + print price(price2num($objp->stock_physique, 'MS'), 0, $langs, 1, 0); if ($objp->stock_physique < 0) { print ''; } print ''; @@ -502,7 +502,7 @@ if ($resql) { if ($nb_warehouse > 1) { foreach ($warehouses_list as &$wh) { print ''; - print empty($product->stock_warehouse[$wh['id']]->real) ? '0' : $product->stock_warehouse[$wh['id']]->real; + print price(empty($product->stock_warehouse[$wh['id']]->real) ? 0 : $product->stock_warehouse[$wh['id']]->real, 0, $langs, 1, 0); print ''; } } @@ -511,11 +511,11 @@ if ($resql) { // Virtual stock if ($virtualdiffersfromphysical) { print ''; - if ($objp->seuil_stock_alerte != '' && ($product->stock_theorique < $objp->seuil_stock_alerte)) { + if ($objp->seuil_stock_alerte != '' && ($product->stock_theorique < (float) $objp->seuil_stock_alerte)) { print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' '; } if ($objp->stock_physique < 0) { print ''; } - print price2num($product->stock_theorique, 'MS'); + print price2num($product->stock_theorique, 'MS', 0, $langs, 1, 0); if ($objp->stock_physique < 0) { print ''; } print ''; } diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 8f548685631..935275bfe54 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -475,7 +475,7 @@ $listofreferent = array( 'table'=>'fichinter', 'datefieldname'=>'date_valid', 'disableamount'=>0, - 'margin'=>'minus', + 'margin'=>'', 'urlnew'=>DOL_URL_ROOT.'/fichinter/card.php?action=create&origin=project&originid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id), 'lang'=>'interventions', 'buttonnew'=>'AddIntervention', @@ -585,9 +585,9 @@ $listofreferent = array( 'name'=>"MouvementStockAssociated", 'title'=>"ListMouvementStockProject", 'class'=>'MouvementStock', - 'margin'=>'minus', 'table'=>'stock_mouvement', 'datefieldname'=>'datem', + 'margin'=>'minus', 'disableamount'=>0, 'test'=>!empty($conf->stock->enabled) && $user->hasRight('stock', 'mouvement', 'lire') && !empty($conf->global->STOCK_MOVEMENT_INTO_PROJECT_OVERVIEW)), 'salaries'=>array( @@ -752,6 +752,7 @@ $total_revenue_ht = 0; $balance_ht = 0; $balance_ttc = 0; +// Loop on each element type (proposal, sale order, invoices, ...) foreach ($listofreferent as $key => $value) { $parameters = array( 'total_revenue_ht' =>& $total_revenue_ht, @@ -787,6 +788,7 @@ foreach ($listofreferent as $key => $value) { $total_ht = 0; $total_ttc = 0; + // Loop on each object for the current element type $num = count($elementarray); for ($i = 0; $i < $num; $i++) { $tmp = explode('_', $elementarray[$i]); @@ -871,7 +873,7 @@ foreach ($listofreferent as $key => $value) { $defaultvat = get_default_tva($mysoc, $mysoc); $total_ttc_by_line = price2num($total_ht_by_line * (1 + ($defaultvat / 100)), 'MT'); } elseif ($key == 'loan') { - $total_ttc_by_line = $total_ht_by_line; // For loan there is actually no taxe managed in Dolibarr + $total_ttc_by_line = $total_ht_by_line; // For loan there is actually no taxe managed in Dolibarr } else { $total_ttc_by_line = $element->total_ttc; } @@ -892,19 +894,14 @@ foreach ($listofreferent as $key => $value) { } // Each element with at least one line is output - $qualifiedforfinalprofit = true; - if ($key == 'intervention' && empty($conf->global->PROJECT_INCLUDE_INTERVENTION_AMOUNT_IN_PROFIT)) { - $qualifiedforfinalprofit = false; - } - //var_dump($key.' '.$qualifiedforfinalprofit); // Calculate margin - if ($qualifiedforfinalprofit) { - if ($margin == 'add') { + if ($margin) { + if ($margin === 'add') { $total_revenue_ht += $total_ht; } - if ($margin != "add") { // Revert sign + if ($margin === "minus") { // Revert sign $total_ht = -$total_ht; $total_ttc = -$total_ttc; } @@ -920,24 +917,24 @@ foreach ($listofreferent as $key => $value) { print ''.$i.''; // Amount HT print ''; - if ($key == 'intervention' && !$qualifiedforfinalprofit) { + if ($key == 'intervention' && !$margin) { print ''.$form->textwithpicto($langs->trans("NA"), $langs->trans("AmountOfInteventionNotIncludedByDefault")).''; } else { - print price($total_ht); if ($key == 'propal') { print ''.$form->textwithpicto('', $langs->trans("SignedOnly")).''; } + print price($total_ht); } print ''; // Amount TTC print ''; - if ($key == 'intervention' && !$qualifiedforfinalprofit) { + if ($key == 'intervention' && !$margin) { print ''.$form->textwithpicto($langs->trans("NA"), $langs->trans("AmountOfInteventionNotIncludedByDefault")).''; } else { - print price($total_ttc); if ($key == 'propal') { print ''.$form->textwithpicto('', $langs->trans("SignedOnly")).''; } + print price($total_ttc); } print ''; print '';