Passed
Push — master ( 364662...9798b7 )
by Andrii
02:56
created

Aggregator::aggregateCharges()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.128

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 1
dl 0
loc 16
ccs 8
cts 10
cp 0.8
crap 4.128
rs 9.9332
c 0
b 0
f 0
1
<?php
2
/**
3
 * PHP Billing Library
4
 *
5
 * @link      https://github.com/hiqdev/php-billing
6
 * @package   php-billing
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\php\billing\tools;
12
13
use hiqdev\php\billing\bill\Bill;
14
use hiqdev\php\billing\bill\BillInterface;
15
use hiqdev\php\billing\charge\AggregationException;
16
use hiqdev\php\billing\charge\ChargeInterface;
17
use hiqdev\php\billing\charge\GeneralizerInterface;
18
use hiqdev\php\units\QuantityInterface;
19
use Money\Money;
20
21
/**
22
 * @author Andrii Vasyliev <[email protected]>
23
 */
24
class Aggregator implements AggregatorInterface
25
{
26
    /**
27
     * @var GeneralizerInterface
28
     */
29
    protected $generalizer;
30
31 1
    public function __construct(GeneralizerInterface $generalizer)
32
    {
33 1
        $this->generalizer = $generalizer;
34 1
    }
35
36
    /**
37
     * Aggregates given Charges to Bills. Then aggregates them again with DB.
38
     * @param ChargeInterface[]|ChargeInterface[][] $charges
39
     * @return BillInterface[]
40
     */
41 1
    public function aggregateCharges(array $charges): array
42
    {
43 1
        $bills = [];
44 1
        foreach ($charges as $charge) {
45 1
            if (is_array($charge)) {
46
                $others = $this->aggregateCharges($charge);
47 1
            } elseif ($charge instanceof ChargeInterface) {
48 1
                $others = [$this->generalizer->createBill($charge)];
49
            } else {
50
                throw new AggregationException('Not a Charge given to Aggregator');
51
            }
52
53 1
            $bills = $this->aggregateBills($bills, $others);
54
        }
55
56 1
        return $bills;
57
    }
58
59
    /**
60
     * Aggregate arrays of bills.
61
     * @param BillInterface[] $bills
62
     * @param BillInterface[] $others
63
     * @return BillInterface[]
64
     */
65 1
    protected function aggregateBills(array $bills, array $others): array
66
    {
67 1
        foreach ($others as $bill) {
68 1
            $uid = $bill->getUniqueString();
69 1
            if (empty($bills[$uid])) {
70 1
                $bills[$uid] = $bill;
71
            } else {
72 1
                $bills[$uid] = $this->aggregateBill($bills[$uid], $bill);
73
            }
74
        }
75
76 1
        return $bills;
77
    }
78
79 1
    protected function aggregateBill(BillInterface $first, BillInterface $other): BillInterface
80
    {
81 1
        return new Bill(
82 1
            $this->aggregateId($first, $other),
83 1
            $first->getType(),
84 1
            $first->getTime(),
85 1
            $this->aggregateSum($first, $other),
86 1
            $this->aggregateQuantity($first, $other),
87 1
            $first->getCustomer(),
88 1
            $first->getTarget(),
89 1
            $first->getPlan(),
90 1
            array_merge($first->getCharges(), $other->getCharges())
91
        );
92
    }
93
94
    /**
95
     * @return string|int|null
96
     */
97 1
    protected function aggregateId(BillInterface $first, BillInterface $other)
98
    {
99 1
        if ($first->getId() === null) {
0 ignored issues
show
introduced by
The condition $first->getId() === null is always false.
Loading history...
100 1
            return $other->getId();
101
        }
102
        if ($other->getId() === null) {
0 ignored issues
show
introduced by
The condition $other->getId() === null is always false.
Loading history...
103
            return $first->getId();
104
        }
105
        if ($first->getId() === $other->getId()) {
106
            return $other->getId();
107
        }
108
109
        throw new AggregationException('cannot aggregate bills with different IDs');
110
    }
111
112 1
    protected function aggregateSum(BillInterface $first, BillInterface $other): Money
113
    {
114 1
        return $first->getSum()->add($other->getSum());
115
    }
116
117 1
    protected function aggregateQuantity(BillInterface $first, BillInterface $other): QuantityInterface
118
    {
119 1
        if ($first->getQuantity()->isConvertible($other->getQuantity()->getUnit())) {
120 1
            return $first->getQuantity()->add($other->getQuantity());
121
        }
122
123
        return $first->getQuantity();
124
    }
125
}
126