refactor(parser): normalize percentage value handling

Refactor percentage value parsing to use a dedicated method for better readability and maintainability.
Add tests to ensure legacy overflow percentages are normalized correctly.
This commit is contained in:
Jérémy Munsch 2026-10-06 15:46:22 +02:00
parent e72b570823
commit dc836f911a
Signed by: forge-joniko
GPG key ID: D7EFE2F5CB6CC0E4
2 changed files with 72 additions and 10 deletions

View file

@ -117,8 +117,8 @@ final readonly class IncoCompositionParser
return new FreshProduceAndNuts(
reference: $refFnl,
portion: $porFnl,
freshFnlPercentage: new PercentageValue(self::getString($row, 'POURCENT_FNL_FRAIS', 'pourcent_fnl_frais')),
fruitsPercentage: new PercentageValue(self::getString($row, 'POURCENT_FRUITS', 'pourcent_fruits')),
freshFnlPercentage: self::toPercentageValue($row, 'POURCENT_FNL_FRAIS', 'pourcent_fnl_frais'),
fruitsPercentage: self::toPercentageValue($row, 'POURCENT_FRUITS', 'pourcent_fruits'),
);
}
@ -128,14 +128,14 @@ final readonly class IncoCompositionParser
public static function toReferenceIntakes(array $row): ReferenceIntakes
{
return new ReferenceIntakes(
energyE14: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_E14_P', 'pourcent_apport_ref_e14_p')),
energyKj: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_KJO_P', 'pourcent_apport_ref_kjo_p')),
fat: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_FAT_P', 'pourcent_apport_ref_fat_p')),
saturatedFat: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_FATSAT_P', 'pourcent_apport_ref_fatsat_p')),
carbohydrates: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_CHOVAL_P', 'pourcent_apport_ref_choval_p')),
sugars: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_SUGAR_P', 'pourcent_apport_ref_sugar_p')),
protein: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_PRO_P', 'pourcent_apport_ref_pro_p')),
salt: new PercentageValue(self::getString($row, 'POURCENT_APPORT_REF_SALTEQ_P', 'pourcent_apport_ref_salteq_p')),
energyE14: self::toPercentageValue($row, 'POURCENT_APPORT_REF_E14_P', 'pourcent_apport_ref_e14_p'),
energyKj: self::toPercentageValue($row, 'POURCENT_APPORT_REF_KJO_P', 'pourcent_apport_ref_kjo_p'),
fat: self::toPercentageValue($row, 'POURCENT_APPORT_REF_FAT_P', 'pourcent_apport_ref_fat_p'),
saturatedFat: self::toPercentageValue($row, 'POURCENT_APPORT_REF_FATSAT_P', 'pourcent_apport_ref_fatsat_p'),
carbohydrates: self::toPercentageValue($row, 'POURCENT_APPORT_REF_CHOVAL_P', 'pourcent_apport_ref_choval_p'),
sugars: self::toPercentageValue($row, 'POURCENT_APPORT_REF_SUGAR_P', 'pourcent_apport_ref_sugar_p'),
protein: self::toPercentageValue($row, 'POURCENT_APPORT_REF_PRO_P', 'pourcent_apport_ref_pro_p'),
salt: self::toPercentageValue($row, 'POURCENT_APPORT_REF_SALTEQ_P', 'pourcent_apport_ref_salteq_p'),
portionAmount: self::getString($row, 'APPORT_PORT', 'apport_port', '100g'),
);
}
@ -345,4 +345,47 @@ final readonly class IncoCompositionParser
return is_scalar($val) ? (string) $val : $default;
}
/**
* @param array<string, mixed> $row
*/
private static function toPercentageValue(array $row, string $key, string $fallbackKey = ''): PercentageValue
{
return new PercentageValue(
self::normalizeLegacyOverflowPercentage(
self::getString($row, $key, $fallbackKey)
)
);
}
private static function normalizeLegacyOverflowPercentage(string $value): string
{
$trimmed = trim($value);
if ($trimmed === '') {
return $value;
}
$numericCandidate = str_replace(',', '.', $trimmed);
if (! is_numeric($numericCandidate)) {
return $value;
}
$numeric = (float) $numericCandidate;
if ($numeric <= 100.0) {
return $value;
}
$normalized = $numeric / 10.0;
return self::toCompactNumericString($normalized);
}
private static function toCompactNumericString(float $value): string
{
if (fmod($value, 1.0) === 0.0) {
return (string) (int) $value;
}
return rtrim(rtrim(number_format($value, 6, '.', ''), '0'), '.');
}
}

View file

@ -145,6 +145,25 @@ describe('IncoCompositionParser', function (): void {
->and($score->grade)->toBe('B');
});
it('normalizes legacy overflow percentages by dividing by 10', function (): void {
$row = [
'POURCENT_APPORT_REF_PRO_P' => '130',
'POURCENT_APPORT_REF_FAT_P' => '105',
'POURCENT_APPORT_REF_E14_P' => '10',
'POURCENT_APPORT_REF_KJO_P' => '10',
'POURCENT_APPORT_REF_FATSAT_P' => '14',
'POURCENT_APPORT_REF_CHOVAL_P' => '6',
'POURCENT_APPORT_REF_SUGAR_P' => '1',
'POURCENT_APPORT_REF_SALTEQ_P' => '18',
'APPORT_PORT' => '100g',
];
$intakes = IncoCompositionParser::toReferenceIntakes($row);
expect($intakes->protein->value)->toBe('13')
->and($intakes->fat->value)->toBe('10.5');
});
it('parses minerals, vitamins, fatty acids, amino acids, and special compounds', function (): void {
$row = [
'NUT_CA' => '120',