Completed
Push — master ( 753652...d0e0e5 )
by Dmitry
04:54
created

CartFinisher::exchangeMoney()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 0
cts 11
cp 0
rs 9.8666
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 6
1
<?php
2
/**
3
 * Finance module for HiPanel
4
 *
5
 * @link      https://github.com/hiqdev/hipanel-module-finance
6
 * @package   hipanel-module-finance
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2019, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\modules\finance\cart;
12
13
use hipanel\modules\finance\models\Bill;
14
use hiqdev\yii2\cart\NotPurchasableException;
15
use hiqdev\yii2\cart\ShoppingCart;
16
use Yii;
17
use yii\base\BaseObject;
18
19
class CartFinisher extends BaseObject
20
{
21
    /**
22
     * @var ShoppingCart
23
     */
24
    public $cart;
25
26
    /**
27
     * @var string|null
28
     */
29
    public $exchangeFromCurrency;
30
31
    /**
32
     * @var PurchaseStrategyInterface[]
33
     */
34
    protected $purchasers = [];
35
36
    /**
37
     * @var AbstractPurchase[] array of successful purchases
38
     */
39
    protected $_success = [];
40
41
    /**
42
     * @var ErrorPurchaseException[] array of failed purchases
43
     */
44
    protected $_error = [];
45
46
    /**
47
     * @var PendingPurchaseException[] array of purchases that are pending
48
     */
49
    protected $_pending = [];
50
51
    /**
52
     * Getter for array of successful purchases.
53
     * @return AbstractPurchase[]
54
     */
55
    public function getSuccess()
56
    {
57
        return $this->_success;
58
    }
59
60
    /**
61
     * Getter for array of failed purchases.
62
     * @return ErrorPurchaseException[]
63
     */
64
    public function getError()
65
    {
66
        return $this->_error;
67
    }
68
69
    /**
70
     * Getter for array of failed purchases.
71
     * @return PendingPurchaseException[]
72
     */
73
    public function getPending()
74
    {
75
        return $this->_pending;
76
    }
77
78
    /**
79
     * Runs the purchase.
80
     * Purchases the positions in the [[cart]].
81
     */
82
    public function run()
83
    {
84
        if ($this->cart->isEmpty) {
85
            return;
86
        }
87
88
        $this->ensureCanBeFinished();
89
        $this->createPurchasers();
90
        $this->exchangeMoney();
91
92
        foreach ($this->purchasers as $purchaser) {
93
            $purchaser->run();
94
95
            $this->_success = array_merge($this->_success, $purchaser->getSuccessPurchases());
96
            foreach ($purchaser->getSuccessPurchases() as $purchase) {
97
                $this->cart->remove($purchase->position);
98
            }
99
            $this->_pending = array_merge($this->_pending, $purchaser->getPendingPurchaseExceptions());
100
            foreach ($purchaser->getPendingPurchaseExceptions() as $exception) {
101
                $this->cart->remove($exception->position);
102
            }
103
            $this->_error = array_merge($this->_error, $purchaser->getErrorPurchaseExceptions());
104
        }
105
    }
106
107
    protected function ensureCanBeFinished()
108
    {
109
        /** @var PositionPurchasabilityValidatorInterface[] $validators */
110
        $validators = [];
111
112
        foreach ($this->cart->positions as $position) {
113
            $purchase = $position->getPurchaseModel();
114
115
            foreach ($purchase->getPurchasabilityRules() as $validator) {
116
                if (!isset($validators[$validator])) {
117
                    $validators[$validator] = Yii::createObject($validator);
118
                }
119
            }
120
        }
121
122
        try {
123
            foreach ($validators as $validator) {
124
                $validator->validate($this->cart->positions);
125
            }
126
        } catch (NotPurchasableException $e) {
127
            $e->resolve();
128
        }
129
    }
130
131
    protected function createPurchasers()
132
    {
133
        foreach ($this->cart->positions as $position) {
134
            if ($position instanceof BatchPurchasablePositionInterface) {
135
                $purchaser = $this->getPurchaser(get_class($position), $position->getBatchPurchaseStrategyClass());
136
            } else {
137
                $purchaser = $this->getPurchaser(get_class($position), OneByOnePurchaseStrategy::class);
138
            }
139
140
            $purchaser->addPosition($position);
141
        }
142
    }
143
144
    /**
145
     * @param string $positionClass
146
     * @param string $purchaserClass
147
     * @return PurchaseStrategyInterface
148
     */
149
    protected function getPurchaser($positionClass, $purchaserClass)
150
    {
151
        if (!isset($this->purchasers[$positionClass])) {
152
            $this->purchasers[$positionClass] = new $purchaserClass($this->cart);
153
        }
154
155
        return $this->purchasers[$positionClass];
156
    }
157
158
    private function exchangeMoney(): void
159
    {
160
        if ($this->exchangeFromCurrency === null) {
161
            return;
162
        }
163
164
        Bill::perform('create-exchange', [
165
            'from' => $this->exchangeFromCurrency,
166
            'to' => $this->cart->getCurrency(),
167
            'buySum' => $this->cart->getTotal(),
168
        ]);
169
    }
170
}
171