Completed
Push — master ( 1f7668...7ed0a5 )
by Andrii
03:21
created

Discount::multiply()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 3
rs 10
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\charge\modifiers\addons;
12
13
use hiqdev\php\billing\charge\ChargeInterface;
14
use hiqdev\php\billing\charge\modifiers\AddonInterface;
15
use hiqdev\php\billing\formula\FormulaSemanticsError;
16
use Money\Currencies\ISOCurrencies;
17
use Money\Currency;
18
use Money\Money;
19
use Money\Parser\DecimalMoneyParser;
20
21
/**
22
 * Discount addon.
23
 *
24
 * @author Andrii Vasyliev <[email protected]>
25
 */
26
class Discount implements AddonInterface
27
{
28
    protected static $name = 'discount';
29
30
    /**
31
     * @var string|Money
32
     */
33
    protected $value;
34
35
    protected $moneyParser;
36
37 26
    public function __construct($value)
38
    {
39 26
        $this->moneyParser = new DecimalMoneyParser(new ISOCurrencies());
40 26
        $this->value = $this->ensureValidValue($value);
41 26
    }
42
43 11
    public function getValue()
44
    {
45 11
        return $this->value;
46
    }
47
48 12
    public function isAbsolute()
49
    {
50 12
        return $this->value instanceof Money;
51
    }
52
53 8
    public function isRelative()
54
    {
55 8
        return !$this->isAbsolute();
56
    }
57
58 26
    public function ensureValidValue($value)
59
    {
60 26
        if ($value instanceof static) {
61
            return $value->getValue();
62
        }
63
64 26
        if ($value instanceof Money) {
65 8
            return $value;
66
        }
67
68 24
        if (is_numeric($value)) {
69 10
            return (string) $value;
70
        }
71
72 20
        if (is_string($value) && preg_match('/^(\d{1,5}(\.\d+)?)%$/', $value, $ms)) {
73 18
            return $ms[1];
74
        }
75
76 16
        if (is_string($value) && preg_match('/^(\d{1,5}(\.\d+)?) ([A-Z]{3})$/', $value, $ms)) {
77 16
            return $this->moneyParser->parse($ms[1], new Currency($ms[3]));
78
        }
79
80 4
        $name = static::$name;
81 4
        throw new FormulaSemanticsError("invalid $name value: $value");
82
    }
83
84 8
    public function multiply($multiplier)
85
    {
86 8
        if (!is_numeric($multiplier)) {
87 3
            throw new FormulaSemanticsError('multiplier for discount must be numeric');
88
        }
89
90 5
        return new static($this->isAbsolute() ? $this->value->multiply($multiplier) : $this->value*$multiplier);
91
    }
92
93 11
    public function add($addend)
94
    {
95 11
        if (!$addend instanceof self) {
96 7
            $addend = new self($addend);
97
        }
98 7
        $this->ensureSameType($addend, 'addend');
99
100 5
        if ($this->isAbsolute()) {
101 3
            $sum = $this->value->add($addend->getValue());
0 ignored issues
show
Bug introduced by
It seems like $addend->getValue() can also be of type string; however, parameter $addend of Money\Money::add() does only seem to accept Money\Money, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
            $sum = $this->value->add(/** @scrutinizer ignore-type */ $addend->getValue());
Loading history...
102
        } else {
103 3
            $sum = $this->value + $addend->getValue();
104
        }
105
106 5
        return new static($sum);
107
    }
108
109 1
    public function compare($other)
110
    {
111 1
        if (!$other instanceof self) {
112 1
            $other = new self($other);
113
        }
114 1
        $this->ensureSameType($other, 'comparison argument');
115
116 1
        if ($this->isAbsolute()) {
117 1
            return $this->value->compare($other->getValue());
0 ignored issues
show
Bug introduced by
It seems like $other->getValue() can also be of type string; however, parameter $other of Money\Money::compare() does only seem to accept Money\Money, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
            return $this->value->compare(/** @scrutinizer ignore-type */ $other->getValue());
Loading history...
118
        } else {
119 1
            return $this->value - $other->getValue();
120
        }
121
    }
122
123 8
    public function ensureSameType(self $other, $name)
124
    {
125 8
        if ($this->isRelative() && !$other->isRelative()) {
126 1
            throw new FormulaSemanticsError("$name must be relative");
127
        }
128 7
        if ($this->isAbsolute() && !$other->isAbsolute()) {
129 1
            throw new FormulaSemanticsError("$name must be absolute");
130
        }
131 6
    }
132
133 4
    public function calculateSum(ChargeInterface $charge): Money
134
    {
135 4
        return $this->value instanceof Money
136 2
            ? $this->value->multiply($charge->getUsage()->getQuantity())
137 4
            : $charge->getSum()->multiply($this->value * 0.01)
138
        ;
139
    }
140
}
141