Upgraded brick/math to latest version

This commit is contained in:
Jan Böhmer 2026-05-19 21:17:45 +02:00
parent 506d5f8173
commit 527c42c227
11 changed files with 58 additions and 56 deletions

View file

@ -17,7 +17,7 @@
"api-platform/json-api": "^4.0.0", "api-platform/json-api": "^4.0.0",
"api-platform/symfony": "^4.0.0", "api-platform/symfony": "^4.0.0",
"beberlei/doctrineextensions": "^1.2", "beberlei/doctrineextensions": "^1.2",
"brick/math": "^0.14.8", "brick/math": "^0.17.0",
"brick/schema": "^0.2.0", "brick/schema": "^0.2.0",
"composer/ca-bundle": "^1.5", "composer/ca-bundle": "^1.5",
"composer/package-versions-deprecated": "^1.11.99.5", "composer/package-versions-deprecated": "^1.11.99.5",

56
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "f7dc75ebd6fa0d9c496a32ea984fa4a5", "content-hash": "d6bda397c505e1e6d540c814a2368fbb",
"packages": [ "packages": [
{ {
"name": "amphp/amp", "name": "amphp/amp",
@ -2342,23 +2342,22 @@
}, },
{ {
"name": "brick/math", "name": "brick/math",
"version": "0.14.8", "version": "0.17.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/brick/math.git", "url": "https://github.com/brick/math.git",
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" "reference": "6aef71a9fbbd1ee7be0e313cd627f8e6f7125a5b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", "url": "https://api.github.com/repos/brick/math/zipball/6aef71a9fbbd1ee7be0e313cd627f8e6f7125a5b",
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", "reference": "6aef71a9fbbd1ee7be0e313cd627f8e6f7125a5b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^8.2" "php": "^8.2"
}, },
"require-dev": { "require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpstan/phpstan": "2.1.22", "phpstan/phpstan": "2.1.22",
"phpunit/phpunit": "^11.5" "phpunit/phpunit": "^11.5"
}, },
@ -2390,7 +2389,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/brick/math/issues", "issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.14.8" "source": "https://github.com/brick/math/tree/0.17.1"
}, },
"funding": [ "funding": [
{ {
@ -2398,7 +2397,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2026-02-10T14:33:43+00:00" "time": "2026-04-19T20:55:20+00:00"
}, },
{ {
"name": "brick/schema", "name": "brick/schema",
@ -4637,16 +4636,16 @@
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.10.0", "version": "7.10.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/guzzle.git", "url": "https://github.com/guzzle/guzzle.git",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" "reference": "b777df1776c667e287664dda75b0298ad8ae3a14"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b777df1776c667e287664dda75b0298ad8ae3a14",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", "reference": "b777df1776c667e287664dda75b0298ad8ae3a14",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4664,8 +4663,9 @@
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*", "ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2", "guzzle/client-integration-tests": "3.0.2",
"guzzlehttp/test-server": "^0.3.2",
"php-http/message-factory": "^1.1", "php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.39 || ^9.6.20", "phpunit/phpunit": "^8.5.52 || ^9.6.34",
"psr/log": "^1.1 || ^2.0 || ^3.0" "psr/log": "^1.1 || ^2.0 || ^3.0"
}, },
"suggest": { "suggest": {
@ -4743,7 +4743,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/guzzle/issues", "issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.10.0" "source": "https://github.com/guzzle/guzzle/tree/7.10.1"
}, },
"funding": [ "funding": [
{ {
@ -4759,20 +4759,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-08-23T22:36:01+00:00" "time": "2026-05-19T18:01:31+00:00"
}, },
{ {
"name": "guzzlehttp/promises", "name": "guzzlehttp/promises",
"version": "2.3.0", "version": "2.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/promises.git", "url": "https://github.com/guzzle/promises.git",
"reference": "481557b130ef3790cf82b713667b43030dc9c957" "reference": "d2d8dfae4757f384d630fdffc2d8d6618d8f4c5e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", "url": "https://api.github.com/repos/guzzle/promises/zipball/d2d8dfae4757f384d630fdffc2d8d6618d8f4c5e",
"reference": "481557b130ef3790cf82b713667b43030dc9c957", "reference": "d2d8dfae4757f384d630fdffc2d8d6618d8f4c5e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4780,7 +4780,7 @@
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.44 || ^9.6.25" "phpunit/phpunit": "^8.5.52 || ^9.6.34"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -4826,7 +4826,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/promises/issues", "issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.3.0" "source": "https://github.com/guzzle/promises/tree/2.3.1"
}, },
"funding": [ "funding": [
{ {
@ -4842,20 +4842,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-08-22T14:34:08+00:00" "time": "2026-05-19T18:30:48+00:00"
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.9.1", "version": "2.10.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "3780f78d6f2854cb327944a22c7b0617852ab7e9" "reference": "d5ddaf5743c42a61cb6100f83dc9d5a2bafe75ca"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/3780f78d6f2854cb327944a22c7b0617852ab7e9", "url": "https://api.github.com/repos/guzzle/psr7/zipball/d5ddaf5743c42a61cb6100f83dc9d5a2bafe75ca",
"reference": "3780f78d6f2854cb327944a22c7b0617852ab7e9", "reference": "d5ddaf5743c42a61cb6100f83dc9d5a2bafe75ca",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4943,7 +4943,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.9.1" "source": "https://github.com/guzzle/psr7/tree/2.10.0"
}, },
"funding": [ "funding": [
{ {
@ -4959,7 +4959,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-05-19T15:17:22+00:00" "time": "2026-05-19T17:32:11+00:00"
}, },
{ {
"name": "hshn/base64-encoded-file", "name": "hshn/base64-encoded-file",

View file

@ -37,6 +37,7 @@ use App\Services\EntityURLGenerator;
use App\Services\Formatters\AmountFormatter; use App\Services\Formatters\AmountFormatter;
use App\Services\Formatters\MoneyFormatter; use App\Services\Formatters\MoneyFormatter;
use App\Services\ProjectSystem\ProjectBuildHelper; use App\Services\ProjectSystem\ProjectBuildHelper;
use Brick\Math\BigDecimal;
use Brick\Math\RoundingMode; use Brick\Math\RoundingMode;
use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
@ -93,14 +94,14 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
return htmlspecialchars($this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit())); return htmlspecialchars($this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit()));
}, },
]) ])
->add('partId', TextColumn::class, [ ->add('partId', TextColumn::class, [
'label' => $this->translator->trans('project.bom.part_id'), 'label' => $this->translator->trans('project.bom.part_id'),
'visible' => true, 'visible' => true,
'orderField' => 'part.id', 'orderField' => 'part.id',
'render' => function ($value, ProjectBOMEntry $context) { 'render' => function ($value, ProjectBOMEntry $context) {
return $context->getPart() instanceof Part ? (string) $context->getPart()->getId() : ''; return $context->getPart() instanceof Part ? (string) $context->getPart()->getId() : '';
}, },
]) ])
->add('name', TextColumn::class, [ ->add('name', TextColumn::class, [
'label' => $this->translator->trans('part.table.name'), 'label' => $this->translator->trans('part.table.name'),
'orderField' => 'NATSORT(part.name)', 'orderField' => 'NATSORT(part.name)',
@ -161,7 +162,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
'label' => $this->translator->trans('part.table.manufacturingStatus'), 'label' => $this->translator->trans('part.table.manufacturingStatus'),
'data' => static fn(ProjectBOMEntry $context): ?ManufacturingStatus => $context->getPart()?->getManufacturingStatus(), 'data' => static fn(ProjectBOMEntry $context): ?ManufacturingStatus => $context->getPart()?->getManufacturingStatus(),
'orderField' => 'part.manufacturing_status', 'orderField' => 'part.manufacturing_status',
'class' => ManufacturingStatus::class, 'class' => ManufacturingStatus::class,
'render' => function (?ManufacturingStatus $status, ProjectBOMEntry $context): string { 'render' => function (?ManufacturingStatus $status, ProjectBOMEntry $context): string {
if ($status === null) { if ($status === null) {
return ''; return '';
@ -212,7 +213,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
'visible' => false, 'visible' => false,
'render' => function ($value, ProjectBOMEntry $context) { 'render' => function ($value, ProjectBOMEntry $context) {
$price = $this->projectBuildHelper->getEntryUnitPrice($context); $price = $this->projectBuildHelper->getEntryUnitPrice($context);
return $this->moneyFormatter->format($price->toScale(2, RoundingMode::UP)->toFloat(), null, 2, true); return $this->moneyFormatter->format($price->toScale(2, RoundingMode::Up)->toFloat(), null, 2, true);
}, },
]) ])
->add('ext_price', TextColumn::class, [ ->add('ext_price', TextColumn::class, [
@ -221,7 +222,8 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
'render' => function ($value, ProjectBOMEntry $context) { 'render' => function ($value, ProjectBOMEntry $context) {
$price = $this->projectBuildHelper->getEntryUnitPrice($context); $price = $this->projectBuildHelper->getEntryUnitPrice($context);
return $this->moneyFormatter->format( return $this->moneyFormatter->format(
$price->multipliedBy($context->getQuantity())->toScale(2, RoundingMode::UP)->toFloat(), $price->multipliedBy(BigDecimal::fromFloatShortest($context->getQuantity()))
->toScale(2, RoundingMode::Up)->toFloat(),
null, null,
2, 2,
true true

View file

@ -44,7 +44,7 @@ class BigDecimalType extends Type
return BigDecimal::of($value); return BigDecimal::of(is_float($value) ? BigDecimal::fromFloatShortest($value) : $value);
} }
/** /**

View file

@ -204,7 +204,7 @@ class Currency extends AbstractStructuralDBElement
return null; return null;
} }
return BigDecimal::one()->dividedBy($tmp, $tmp->getScale(), RoundingMode::HALF_UP); return BigDecimal::one()->dividedBy($tmp, $tmp->getScale(), RoundingMode::HalfUp);
} }
/** /**

View file

@ -195,10 +195,10 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface
#[SerializedName('price_per_unit')] #[SerializedName('price_per_unit')]
public function getPricePerUnit(float|string|BigDecimal $multiplier = 1.0): BigDecimal public function getPricePerUnit(float|string|BigDecimal $multiplier = 1.0): BigDecimal
{ {
$tmp = BigDecimal::of($multiplier); $tmp = is_float($multiplier) ? BigDecimal::fromFloatShortest($multiplier) : BigDecimal::of($multiplier);
$tmp = $tmp->multipliedBy($this->price); $tmp = $tmp->multipliedBy($this->price);
return $tmp->dividedBy($this->price_related_quantity, static::PRICE_PRECISION, RoundingMode::HALF_UP); return $tmp->dividedBy(BigDecimal::fromFloatShortest($this->price_related_quantity), static::PRICE_PRECISION, RoundingMode::HalfUp);
} }
/** /**
@ -317,7 +317,7 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface
*/ */
public function setPrice(BigDecimal $new_price): self public function setPrice(BigDecimal $new_price): self
{ {
$tmp = $new_price->toScale(self::PRICE_PRECISION, RoundingMode::HALF_UP); $tmp = $new_price->toScale(self::PRICE_PRECISION, RoundingMode::HalfUp);
//Only change the object, if the value changes, so that doctrine does not detect it as changed. //Only change the object, if the value changes, so that doctrine does not detect it as changed.
if ((string) $tmp !== (string) $this->price) { if ((string) $tmp !== (string) $this->price) {
$this->price = $tmp; $this->price = $tmp;

View file

@ -286,7 +286,7 @@ class PKPartImporter
//Partkeepr stores the price per item, we need to convert it to the price per packaging unit //Partkeepr stores the price per item, we need to convert it to the price per packaging unit
$price_per_item = BigDecimal::of($partdistributor['price']); $price_per_item = BigDecimal::of($partdistributor['price']);
$packaging_unit = (float) ($partdistributor['packagingUnit'] ?? 1); $packaging_unit = (float) ($partdistributor['packagingUnit'] ?? 1);
$pricedetail->setPrice($price_per_item->multipliedBy($packaging_unit)); $pricedetail->setPrice($price_per_item->multipliedBy(BigDecimal::fromFloatShortest($packaging_unit)));
$pricedetail->setPriceRelatedQuantity($packaging_unit); $pricedetail->setPriceRelatedQuantity($packaging_unit);
//We have to set the minimum discount quantity to the packaging unit (PartKeepr does not know this concept) //We have to set the minimum discount quantity to the packaging unit (PartKeepr does not know this concept)
//But in Part-DB the minimum discount qty have to be unique across a orderdetail //But in Part-DB the minimum discount qty have to be unique across a orderdetail

View file

@ -222,7 +222,7 @@ class TimeTravel
if (isset($metadata->fieldMappings[$field])) { if (isset($metadata->fieldMappings[$field])) {
//We need to convert the string to a BigDecimal first //We need to convert the string to a BigDecimal first
if (!$data instanceof BigDecimal && ('big_decimal' === $metadata->getFieldMapping($field)->type)) { if (!$data instanceof BigDecimal && ('big_decimal' === $metadata->getFieldMapping($field)->type)) {
$data = BigDecimal::of($data); $data = is_float($data) ? BigDecimal::fromFloatShortest($data) : BigDecimal::of($data);
} }
if (!$data instanceof \DateTimeInterface if (!$data instanceof \DateTimeInterface

View file

@ -170,7 +170,7 @@ class PricedetailHelper
return null; return null;
} }
return $avg->dividedBy($count, Pricedetail::PRICE_PRECISION, RoundingMode::HALF_UP); return $avg->dividedBy($count, Pricedetail::PRICE_PRECISION, RoundingMode::HalfUp);
} }
/** /**
@ -213,6 +213,6 @@ class PricedetailHelper
$val_target = $val_base->multipliedBy($targetCurrency->getInverseExchangeRate()); $val_target = $val_base->multipliedBy($targetCurrency->getInverseExchangeRate());
} }
return $val_target->toScale(Pricedetail::PRICE_PRECISION, RoundingMode::HALF_UP); return $val_target->toScale(Pricedetail::PRICE_PRECISION, RoundingMode::HalfUp);
} }
} }

View file

@ -190,7 +190,7 @@ final readonly class ProjectBuildHelper
continue; continue;
} }
$has_price = true; $has_price = true;
$total = $total->plus($unit_price->multipliedBy($entry->getQuantity())->multipliedBy($number_of_builds)); $total = $total->plus($unit_price->multipliedBy(BigDecimal::fromFloatShortest($entry->getQuantity()))->multipliedBy($number_of_builds));
} }
return $has_price ? $total : null; return $has_price ? $total : null;
@ -206,7 +206,7 @@ final readonly class ProjectBuildHelper
if ($total === null) { if ($total === null) {
return null; return null;
} }
return $total->dividedBy($number_of_builds, 10, RoundingMode::HALF_UP); return $total->dividedBy($number_of_builds, 10, RoundingMode::HalfUp);
} }
/** /**
@ -215,7 +215,7 @@ final readonly class ProjectBuildHelper
public function roundedTotalBuildPrice(Project $project, int $number_of_builds = 1, ?Currency $currency = null): ?BigDecimal public function roundedTotalBuildPrice(Project $project, int $number_of_builds = 1, ?Currency $currency = null): ?BigDecimal
{ {
return $this->calculateTotalBuildPrice($project, $number_of_builds, $currency) return $this->calculateTotalBuildPrice($project, $number_of_builds, $currency)
?->toScale(2, RoundingMode::UP); ?->toScale(2, RoundingMode::Up);
} }
/** /**
@ -224,7 +224,7 @@ final readonly class ProjectBuildHelper
public function roundedUnitBuildPrice(Project $project, int $number_of_builds = 1, ?Currency $currency = null): ?BigDecimal public function roundedUnitBuildPrice(Project $project, int $number_of_builds = 1, ?Currency $currency = null): ?BigDecimal
{ {
return $this->calculateUnitBuildPrice($project, $number_of_builds, $currency) return $this->calculateUnitBuildPrice($project, $number_of_builds, $currency)
?->toScale(2, RoundingMode::UP); ?->toScale(2, RoundingMode::Up);
} }
/** /**

View file

@ -44,15 +44,15 @@ class ExchangeRateUpdater
try { try {
//Try it in the direction QUOTE/BASE first, as most providers provide rates in this direction //Try it in the direction QUOTE/BASE first, as most providers provide rates in this direction
$rate = $this->swap->latest($currency->getIsoCode().'/'.$this->localizationSettings->baseCurrency); $rate = $this->swap->latest($currency->getIsoCode().'/'.$this->localizationSettings->baseCurrency);
$effective_rate = BigDecimal::of($rate->getValue()); $effective_rate = BigDecimal::fromFloatShortest($rate->getValue());
} catch (UnsupportedCurrencyPairException|UnsupportedExchangeQueryException $exception) { } catch (UnsupportedCurrencyPairException|UnsupportedExchangeQueryException $exception) {
//Otherwise try to get it inverse and calculate it ourselfes, from the format "BASE/QUOTE" //Otherwise try to get it inverse and calculate it ourselfes, from the format "BASE/QUOTE"
$rate = $this->swap->latest($this->localizationSettings->baseCurrency.'/'.$currency->getIsoCode()); $rate = $this->swap->latest($this->localizationSettings->baseCurrency.'/'.$currency->getIsoCode());
//The rate says how many quote units are worth one base unit //The rate says how many quote units are worth one base unit
//So we need to invert it to get the exchange rate //So we need to invert it to get the exchange rate
$rate_bd = BigDecimal::of($rate->getValue()); $rate_bd = BigDecimal::fromFloatShortest($rate->getValue());
$effective_rate = BigDecimal::one()->dividedBy($rate_bd, Currency::PRICE_SCALE, RoundingMode::HALF_UP); $effective_rate = BigDecimal::one()->dividedBy($rate_bd, Currency::PRICE_SCALE, RoundingMode::HalfUp);
} }
$currency->setExchangeRate($effective_rate); $currency->setExchangeRate($effective_rate);