diff --git a/htdocs/compta/facture/class/factureligne.class.php b/htdocs/compta/facture/class/factureligne.class.php index da8919e97f5..2bcde94a7a9 100644 --- a/htdocs/compta/facture/class/factureligne.class.php +++ b/htdocs/compta/facture/class/factureligne.class.php @@ -1070,4 +1070,38 @@ class FactureLigne extends CommonInvoiceLine return $cumulated_percent; } } + + /** + * Determines if we are using situation invoices. + * If so, determines if we are using the new mode (2) or legacy mode (1). + * + * Legacy mode means invoice line fields store the state of the cycle at the current + * situation (a cumulative value) rather than the delta between the previous situation + * and the current one. In that case, we need a ratio to convert those values. + * + * New mode = the values on the line already represent the delta between the previous + * state and the current state, so we don't need a conversion (we return 1). + * + * @return float + */ + public function getSituationRatio() + { + if (getDolGlobalInt('INVOICE_USE_SITUATION') === 1) { + // in legacy mode, the situation invoice line stores the (cumulative) state of the + // cycle at the current situation. To get the delta, we need to subtract the + // state at the previous situation (if applicable). + $prevProgress = $this->get_prev_progress($this->fk_facture); + + if ($this->situation_percent == 0) { + // should not happen + return 0; + } + + return ($this->situation_percent - $prevProgress) / $this->situation_percent; + } + // new mode (INVOICE_USE_SITUATION == 2): + // no ratio needed (data stored on line is already a delta) + // or not a situation invoice: no ratio needed either + return 1; + } } diff --git a/htdocs/compta/journal/sellsjournal.php b/htdocs/compta/journal/sellsjournal.php index 22474c15227..48beaa1933e 100644 --- a/htdocs/compta/journal/sellsjournal.php +++ b/htdocs/compta/journal/sellsjournal.php @@ -203,12 +203,22 @@ if ($result) { $line->fetch($obj->id); // id of line $prev_progress = 0; if ($obj->situation_cycle_ref > 0) { // It is a situation invoice + $prev_progress = $line->get_prev_progress($obj->rowid); // id on invoice + if (getDolGlobalInt('INVOICE_USE_SITUATION') === 1) { + // backward compat: old behavior => line's situation_percent was cumulative + // (it reflected the line's progress state, not the line progress delta) + $progressDelta = $obj->situation_percent - $prev_progress; + $progressState = $obj->situation_percent; + } else { + $progressDelta = $obj->situation_percent; + $progressState = $prev_progress + $progressDelta; + } + // Avoid divide by 0 - if ($obj->situation_percent == 0) { + if ($progressState == 0) { $situation_ratio = 0; } else { - $prev_progress = $line->get_prev_progress($obj->rowid); // id on invoice - $situation_ratio = ($obj->situation_percent - $prev_progress) / $obj->situation_percent; + $situation_ratio = $progressDelta / $progressState; } } else { $situation_ratio = 1; diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 8073d8c3dff..3e569f5d3d2 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -2456,15 +2456,31 @@ function pdf_getlineprogress($object, $i, $outputlangs, $hidedetails = 0, $hookm return ''; } if (empty($hidedetails) || $hidedetails > 1) { - if (getDolGlobalString('SITUATION_DISPLAY_DIFF_ON_PDF')) { + // 2 = situation_percent is non-cumulative (delta of current situation) + // 1 = (old mode): situation_percent is cumulative (state at situation) + $isCumulative = getDolGlobalInt('INVOICE_USE_SITUATION') === 1; + $showDelta = (bool) getDolGlobalInt('SITUATION_DISPLAY_DIFF_ON_PDF'); + + if ($isCumulative xor $showDelta) { + // Either: + // - old mode and we want to show a total or + // - new mode and we want to show a delta + $result = $object->lines[$i]->situation_percent; + } else { + // Either: + // - old mode but we want to show a delta or + // - new mode but we want to show a total $prev_progress = 0; if (method_exists($object->lines[$i], 'get_prev_progress')) { $prev_progress = $object->lines[$i]->get_prev_progress($object->id); } - $result = round($object->lines[$i]->situation_percent - $prev_progress, 1).'%'; - } else { - $result = round($object->lines[$i]->situation_percent, 1).'%'; + $result = $isCumulative ? + // old mode: we need to compute the delta (total - sum of previous) + $object->lines[$i]->situation_percent - $prev_progress : + // new mode: we need to compute the total (sum of previous + delta) + $prev_progress + $object->lines[$i]->situation_percent; } + $result = round($result, 1).'%'; } } return $result; @@ -2510,17 +2526,9 @@ function pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails = 0) } elseif (empty($hidedetails) || $hidedetails > 1) { $total_ht = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ht : $object->lines[$i]->total_ht); if (!empty($object->lines[$i]->situation_percent) && $object->lines[$i]->situation_percent > 0) { - // TODO Remove this. The total should be saved correctly in database instead of being modified here. - $prev_progress = 0; - $progress = 1; - if (method_exists($object->lines[$i], 'get_prev_progress')) { - $prev_progress = $object->lines[$i]->get_prev_progress($object->id); - $progress = ($object->lines[$i]->situation_percent - $prev_progress) / 100; - } - $result .= price($sign * ($total_ht / ($object->lines[$i]->situation_percent / 100)) * $progress, 0, $outputlangs); - } else { - $result .= price($sign * $total_ht, 0, $outputlangs); + $total_ht *= $object->lines[$i]->getSituationRatio(); } + $result .= price($sign * $total_ht, 0, $outputlangs); } } return $result; @@ -2566,17 +2574,9 @@ function pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails = 0) } elseif (empty($hidedetails) || $hidedetails > 1) { $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ttc : $object->lines[$i]->total_ttc); if (isset($object->lines[$i]->situation_percent) && $object->lines[$i]->situation_percent > 0) { - // TODO Remove this. The total should be saved correctly in database instead of being modified here. - $prev_progress = 0; - $progress = 1; - if (method_exists($object->lines[$i], 'get_prev_progress')) { - $prev_progress = $object->lines[$i]->get_prev_progress($object->id); - $progress = ($object->lines[$i]->situation_percent - $prev_progress) / 100; - } - $result .= price($sign * ($total_ttc / ($object->lines[$i]->situation_percent / 100)) * $progress, 0, $outputlangs); - } else { - $result .= price($sign * $total_ttc, 0, $outputlangs); + $total_ttc *= $object->lines[$i]->getSituationRatio(); } + $result .= price($sign * $total_ttc, 0, $outputlangs); } } return $result;