Skip to content

Commit

Permalink
Fix allocation bugs (moneyphp#526)
Browse files Browse the repository at this point in the history
* fix allocation bugs
- fixes moneyphp#492
- replaces moneyphp#509

* include missing new line
  • Loading branch information
frederikbosch authored Dec 6, 2018
1 parent 42e55ab commit fb16a55
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 15 deletions.
16 changes: 8 additions & 8 deletions spec/MoneySpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,15 @@ function it_allocates_amount(Calculator $calculator)
return (int) floor($args[0] * $args[1] / $args[2]);
});

$calculator->subtract(Argument::type('numeric'), Argument::type('int'))->will(function ($args) {
$calculator->subtract(Argument::type('numeric'), Argument::type('numeric'))->will(function ($args) {
return (string) $args[0] - $args[1];
});

$calculator->add(Argument::type('numeric'), Argument::type('int'))->will(function ($args) {
$calculator->add(Argument::type('numeric'), Argument::type('numeric'))->will(function ($args) {
return (string) ($args[0] + $args[1]);
});

$calculator->compare(Argument::type('numeric'), Argument::type('int'))->will(function ($args) {
$calculator->compare(Argument::type('numeric'), Argument::type('numeric'))->will(function ($args) {
return ($args[0] < $args[1]) ? -1 : (($args[0] > $args[1]) ? 1 : 0);
});

Expand All @@ -307,15 +307,15 @@ function it_allocates_amount_to_n_targets(Calculator $calculator)
return (int) floor($args[0] * $args[1] / $args[2]);
});

$calculator->subtract(Argument::type('numeric'), Argument::type('int'))->will(function ($args) {
return $args[0] - $args[1];
$calculator->subtract(Argument::type('numeric'), Argument::type('numeric'))->will(function ($args) {
return (string)($args[0] - $args[1]);
});

$calculator->add(Argument::type('numeric'), Argument::type('int'))->will(function ($args) {
return $args[0] + $args[1];
$calculator->add(Argument::type('numeric'), Argument::type('numeric'))->will(function ($args) {
return (string)($args[0] + $args[1]);
});

$calculator->compare(Argument::type('numeric'), Argument::type('int'))->will(function ($args) {
$calculator->compare(Argument::type('numeric'), Argument::type('numeric'))->will(function ($args) {
return ($args[0] < $args[1]) ? -1 : (($args[0] > $args[1]) ? 1 : 0);
});

Expand Down
21 changes: 14 additions & 7 deletions src/Money.php
Original file line number Diff line number Diff line change
Expand Up @@ -381,19 +381,26 @@ public function allocate(array $ratios)
if ($ratio < 0) {
throw new \InvalidArgumentException('Cannot allocate to none, ratio must be zero or positive');
}

$share = $this->getCalculator()->share($this->amount, $ratio, $total);
$results[] = $this->newInstance($share);
$remainder = $this->getCalculator()->subtract($remainder, $share);
}

for ($i = 0; $this->getCalculator()->compare($remainder, 0) > 0; ++$i) {
if (!$ratios[$i]) {
continue;
}
if ($this->getCalculator()->compare($remainder, '0') === 0) {
return $results;
}

$fractions = array_map(function ($ratio) use ($total) {
$share = ($ratio / $total) * $this->amount;

return $share - floor($share);
}, $ratios);

$results[$i]->amount = (string) $this->getCalculator()->add($results[$i]->amount, 1);
$remainder = $this->getCalculator()->subtract($remainder, 1);
while ($this->getCalculator()->compare($remainder, '0') > 0) {
$index = !empty($fractions) ? array_keys($fractions, max($fractions))[0] : 0;
$results[$index]->amount = $this->getCalculator()->add($results[$index]->amount, '1');
$remainder = $this->getCalculator()->subtract($remainder, '1');
unset($fractions[$index]);
}

return $results;
Expand Down
3 changes: 3 additions & 0 deletions tests/MoneyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,9 @@ public function allocationExamples()
[0, [0, 0, 1], [0, 0, 0]],
[2, [1, 1, 1], [1, 1, 0]],
[1, [1, 1], [1, 0]],
[1, [0.33, 0.66], [0, 1]],
[101, [3, 7], [30, 71]],
[101, [7, 3], [71, 30]],
];
}

Expand Down

0 comments on commit fb16a55

Please sign in to comment.