Passed
Push — master ( 81c528...9000e8 )
by Dmitry
03:50
created

Aggregator::aggregateCharges()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.016

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 1
dl 0
loc 16
ccs 9
cts 10
cp 0.9
crap 4.016
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 1
                $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
    /**
80
     * @param BillInterface $first
81
     * @param BillInterface $other
82
     * @return BillInterface
83
     */
84 1
    protected function aggregateBill(BillInterface $first, BillInterface $other): BillInterface
85
    {
86 1
        return new Bill(
87 1
            $this->aggregateId($first, $other),
88 1
            $first->getType(),
89 1
            $first->getTime(),
90 1
            $this->aggregateSum($first, $other),
91 1
            $this->aggregateQuantity($first, $other),
92 1
            $first->getCustomer(),
93 1
            $first->getTarget(),
94 1
            $first->getPlan(),
95 1
            array_merge($first->getCharges(), $other->getCharges())
96
        );
97
    }
98
99
    /**
100
     * @param BillInterface $first
101
     * @param BillInterface $other
102
     * @return string|int|null
103
     */
104 1
    protected function aggregateId(BillInterface $first, BillInterface $other)
105
    {
106 1
        if ($first->getId() === null) {
0 ignored issues
show
introduced by
The condition $first->getId() === null is always false.
Loading history...
107 1
            return $other->getId();
108
        }
109
        if ($other->getId() === null) {
0 ignored issues
show
introduced by
The condition $other->getId() === null is always false.
Loading history...
110
            return $first->getId();
111
        }
112
        if ($first->getId() === $other->getId()) {
113
            return $other->getId();
114
        }
115
116
        throw new AggregationException('cannot aggregate bills with different IDs');
117
    }
118
119
    /**
120
     * @param BillInterface $first
121
     * @param BillInterface $other
122
     * @return Money
123
     */
124 1
    protected function aggregateSum(BillInterface $first, BillInterface $other): Money
125
    {
126 1
        return $first->getSum()->add($other->getSum());
127
    }
128
129
    /**
130
     * @param BillInterface $first
131
     * @param BillInterface $other
132
     * @return QuantityInterface
133
     */
134 1
    protected function aggregateQuantity(BillInterface $first, BillInterface $other): QuantityInterface
135
    {
136 1
        if ($first->getQuantity()->isConvertible($other->getQuantity()->getUnit())) {
137 1
            return $first->getQuantity()->add($other->getQuantity());
138
        }
139
140
        return $first->getQuantity();
141
    }
142
}
143