Details
-
Type:
Bug
-
Status: Open
-
Priority:
Major
-
Resolution: Unresolved
-
Affects Version/s: None
-
Fix Version/s: 5.13.0-b2
-
Component/s: None
-
Labels:None
Description
Credits to BW on discord for bringing to our attention
To reproduce
- update a currency to use a format with a comma decimal separator (ex. 1234,56)
- create an invoice with that currency, unit price anything but lets say 4
- download the invoice and see the unit price column shows 4,0000.00
To resolve, in app/models/currencies.php around line 400 replace
// Format the currency
switch ($formats[$currency][$company_id]->format) {
// Values with decimal separator
case '#,###.##':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ',' : ''),
$decimals,
'.'
);
break;
case '#.###,##':
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', $with_separator ? '.' : ''),
$decimals,
','
);
break;
case '# ###.##':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ' ' : ''),
$decimals,
'.'
);
break;
case '# ###,##':
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', $with_separator ? ' ' : ''),
$decimals,
','
);
break;
case '#,##,###.##':
$value = number_format($value, $decimals, '.', '');
// If value over 1000 need to format specially
if ($with_separator && $value >= 1000) {
$thousandths_length = strlen($value) - ($decimals + 2);
$temp_val = $value;
$value = substr($temp_val, -($decimals + 1)); // hold decimals
// format value
for ($j = 0, $i = $thousandths_length; $i >= 0; $i--, $j++) {
// Thousandths place
if ($j < 3) {
$value = $temp_val[$i] . $value;
} else {
// All others
$value = $temp_val[$i] . (($j + 3) % 2 == 0 ? ',' : '') . $value;
}
}
}
$value = $this->truncateDecimal($value, $decimals, '.');
break;
// Values with no decimal separator (unless explicitly given)
case '# ###':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ' ' : ''),
$decimals,
'.'
);
break;
case '#.###':
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', $with_separator ? '.' : ''),
$decimals,
','
);
break;
case '#,###':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ',' : ''),
$decimals,
'.'
);
break;
case '####.##':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', ''),
$decimals,
'.'
);
break;
case '####,##':
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', ''),
$decimals,
','
);
break;
default:
return $value; // format was unrecognized, return the value as-is
}
// Remove non-significant decimals
if ($significant_decimals) {
$value = preg_replace('/(\.[0-9]+?)0*$/', '$1', $value);
// Force at leas 2 decimals
if (strpos($value, '.') === false) {
$value .= '.00';
} else {
$decimals = strlen(substr(strrchr($value, '.'), 1));
if ($decimals < 2) {
$value .= str_repeat('0', 2 - $decimals);
}
}
}
With
// Format the currency
$decimal_separator = '.';
switch ($formats[$currency][$company_id]->format) {
// Values with decimal separator
case '#,###.##':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ',' : ''),
$decimals,
'.'
);
break;
case '#.###,##':
$decimal_separator = ',';
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', $with_separator ? '.' : ''),
$decimals,
','
);
break;
case '# ###.##':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ' ' : ''),
$decimals,
'.'
);
break;
case '# ###,##':
$decimal_separator = ',';
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', $with_separator ? ' ' : ''),
$decimals,
','
);
break;
case '#,##,###.##':
$value = number_format($value, $decimals, '.', '');
// If value over 1000 need to format specially
if ($with_separator && $value >= 1000) {
$thousandths_length = strlen($value) - ($decimals + 2);
$temp_val = $value;
$value = substr($temp_val, -($decimals + 1)); // hold decimals
// format value
for ($j = 0, $i = $thousandths_length; $i >= 0; $i--, $j++) {
// Thousandths place
if ($j < 3) {
$value = $temp_val[$i] . $value;
} else {
// All others
$value = $temp_val[$i] . (($j + 3) % 2 == 0 ? ',' : '') . $value;
}
}
}
$value = $this->truncateDecimal($value, $decimals, '.');
break;
// Values with no decimal separator (unless explicitly given)
case '# ###':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ' ' : ''),
$decimals,
'.'
);
break;
case '#.###':
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', $with_separator ? '.' : ''),
$decimals,
','
);
break;
case '#,###':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', $with_separator ? ',' : ''),
$decimals,
'.'
);
break;
case '####.##':
$value = $this->truncateDecimal(
number_format($value, $decimals, '.', ''),
$decimals,
'.'
);
break;
case '####,##':
$decimal_separator = ',';
$value = $this->truncateDecimal(
number_format($value, $decimals, ',', ''),
$decimals,
','
);
break;
default:
return $value; // format was unrecognized, return the value as-is
}
// Remove non-significant decimals
if ($significant_decimals) {
$value = preg_replace('/(\\' . $decimal_separator . '[0-9]+?)0*$/', '$1', $value);
// Force at leas 2 decimals
if (strpos($value, $decimal_separator) === false) {
$value .= $decimal_separator . '00';
} else {
$decimals = strlen(substr(strrchr($value, $decimal_separator), 1));
if ($decimals < 2) {
$value .= str_repeat('0', 2 - $decimals);
}
}
}
Activity
| Field | Original Value | New Value |
|---|---|---|
| Comment | [ Credits to BW on discord for bringing to our attention ] |
| Description |
To reproduce
- update a currency to use a format with a comma decimal separator (ex. 1234,56) - create an invoice with that currency, unit price anything but lets say 4 - download the invoice and see the unit price column shows 4,0000.00 To resolve, in app/models/currencies.php around line 400 replace {code:java} // Format the currency switch ($formats[$currency][$company_id]->format) { // Values with decimal separator case '#,###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '#.###,##': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '# ###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '# ###,##': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? ' ' : ''), $decimals, ',' ); break; case '#,##,###.##': $value = number_format($value, $decimals, '.', ''); // If value over 1000 need to format specially if ($with_separator && $value >= 1000) { $thousandths_length = strlen($value) - ($decimals + 2); $temp_val = $value; $value = substr($temp_val, -($decimals + 1)); // hold decimals // format value for ($j = 0, $i = $thousandths_length; $i >= 0; $i--, $j++) { // Thousandths place if ($j < 3) { $value = $temp_val[$i] . $value; } else { // All others $value = $temp_val[$i] . (($j + 3) % 2 == 0 ? ',' : '') . $value; } } } $value = $this->truncateDecimal($value, $decimals, '.'); break; // Values with no decimal separator (unless explicitly given) case '# ###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '#.###': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '#,###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '####.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', ''), $decimals, '.' ); break; case '####,##': $value = $this->truncateDecimal( number_format($value, $decimals, ',', ''), $decimals, ',' ); break; default: return $value; // format was unrecognized, return the value as-is } // Remove non-significant decimals if ($significant_decimals) { $value = preg_replace('/(\.[0-9]+?)0*$/', '$1', $value); // Force at leas 2 decimals if (strpos($value, '.') === false) { $value .= '.00'; } else { $decimals = strlen(substr(strrchr($value, '.'), 1)); if ($decimals < 2) { $value .= str_repeat('0', 2 - $decimals); } } } {code} With {code:java} // Format the currency $decimal_separator = '.'; switch ($formats[$currency][$company_id]->format) { // Values with decimal separator case '#,###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '#.###,##': $decimal_separator = ','; $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '# ###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '# ###,##': $decimal_separator = ','; $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? ' ' : ''), $decimals, ',' ); break; case '#,##,###.##': $value = number_format($value, $decimals, '.', ''); // If value over 1000 need to format specially if ($with_separator && $value >= 1000) { $thousandths_length = strlen($value) - ($decimals + 2); $temp_val = $value; $value = substr($temp_val, -($decimals + 1)); // hold decimals // format value for ($j = 0, $i = $thousandths_length; $i >= 0; $i--, $j++) { // Thousandths place if ($j < 3) { $value = $temp_val[$i] . $value; } else { // All others $value = $temp_val[$i] . (($j + 3) % 2 == 0 ? ',' : '') . $value; } } } $value = $this->truncateDecimal($value, $decimals, '.'); break; // Values with no decimal separator (unless explicitly given) case '# ###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '#.###': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '#,###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '####.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', ''), $decimals, '.' ); break; case '####,##': $decimal_separator = ','; $value = $this->truncateDecimal( number_format($value, $decimals, ',', ''), $decimals, ',' ); break; default: return $value; // format was unrecognized, return the value as-is } // Remove non-significant decimals if ($significant_decimals) { $value = preg_replace('/(\\' . $decimal_separator . '[0-9]+?)0*$/', '$1', $value); // Force at leas 2 decimals if (strpos($value, $decimal_separator) === false) { $value .= $decimal_separator . '00'; } else { $decimals = strlen(substr(strrchr($value, $decimal_separator), 1)); if ($decimals < 2) { $value .= str_repeat('0', 2 - $decimals); } } } {code} |
Credits to BW on discord for bringing to our attention
To reproduce - update a currency to use a format with a comma decimal separator (ex. 1234,56) - create an invoice with that currency, unit price anything but lets say 4 - download the invoice and see the unit price column shows 4,0000.00 To resolve, in app/models/currencies.php around line 400 replace {code:java} // Format the currency switch ($formats[$currency][$company_id]->format) { // Values with decimal separator case '#,###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '#.###,##': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '# ###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '# ###,##': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? ' ' : ''), $decimals, ',' ); break; case '#,##,###.##': $value = number_format($value, $decimals, '.', ''); // If value over 1000 need to format specially if ($with_separator && $value >= 1000) { $thousandths_length = strlen($value) - ($decimals + 2); $temp_val = $value; $value = substr($temp_val, -($decimals + 1)); // hold decimals // format value for ($j = 0, $i = $thousandths_length; $i >= 0; $i--, $j++) { // Thousandths place if ($j < 3) { $value = $temp_val[$i] . $value; } else { // All others $value = $temp_val[$i] . (($j + 3) % 2 == 0 ? ',' : '') . $value; } } } $value = $this->truncateDecimal($value, $decimals, '.'); break; // Values with no decimal separator (unless explicitly given) case '# ###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '#.###': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '#,###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '####.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', ''), $decimals, '.' ); break; case '####,##': $value = $this->truncateDecimal( number_format($value, $decimals, ',', ''), $decimals, ',' ); break; default: return $value; // format was unrecognized, return the value as-is } // Remove non-significant decimals if ($significant_decimals) { $value = preg_replace('/(\.[0-9]+?)0*$/', '$1', $value); // Force at leas 2 decimals if (strpos($value, '.') === false) { $value .= '.00'; } else { $decimals = strlen(substr(strrchr($value, '.'), 1)); if ($decimals < 2) { $value .= str_repeat('0', 2 - $decimals); } } } {code} With {code:java} // Format the currency $decimal_separator = '.'; switch ($formats[$currency][$company_id]->format) { // Values with decimal separator case '#,###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '#.###,##': $decimal_separator = ','; $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '# ###.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '# ###,##': $decimal_separator = ','; $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? ' ' : ''), $decimals, ',' ); break; case '#,##,###.##': $value = number_format($value, $decimals, '.', ''); // If value over 1000 need to format specially if ($with_separator && $value >= 1000) { $thousandths_length = strlen($value) - ($decimals + 2); $temp_val = $value; $value = substr($temp_val, -($decimals + 1)); // hold decimals // format value for ($j = 0, $i = $thousandths_length; $i >= 0; $i--, $j++) { // Thousandths place if ($j < 3) { $value = $temp_val[$i] . $value; } else { // All others $value = $temp_val[$i] . (($j + 3) % 2 == 0 ? ',' : '') . $value; } } } $value = $this->truncateDecimal($value, $decimals, '.'); break; // Values with no decimal separator (unless explicitly given) case '# ###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ' ' : ''), $decimals, '.' ); break; case '#.###': $value = $this->truncateDecimal( number_format($value, $decimals, ',', $with_separator ? '.' : ''), $decimals, ',' ); break; case '#,###': $value = $this->truncateDecimal( number_format($value, $decimals, '.', $with_separator ? ',' : ''), $decimals, '.' ); break; case '####.##': $value = $this->truncateDecimal( number_format($value, $decimals, '.', ''), $decimals, '.' ); break; case '####,##': $decimal_separator = ','; $value = $this->truncateDecimal( number_format($value, $decimals, ',', ''), $decimals, ',' ); break; default: return $value; // format was unrecognized, return the value as-is } // Remove non-significant decimals if ($significant_decimals) { $value = preg_replace('/(\\' . $decimal_separator . '[0-9]+?)0*$/', '$1', $value); // Force at leas 2 decimals if (strpos($value, $decimal_separator) === false) { $value .= $decimal_separator . '00'; } else { $decimals = strlen(substr(strrchr($value, $decimal_separator), 1)); if ($decimals < 2) { $value .= str_repeat('0', 2 - $decimals); } } } {code} |