Completed
Push — master ( fb64b4...3f626a )
by Dmitry
03:31
created

SaleRepository   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 15
eloc 55
dl 0
loc 110
ccs 0
cts 59
cp 0
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A findId() 0 15 2
A findByOrder() 0 3 1
A save() 0 11 2
B findByAction() 0 29 7
A buildTargetCond() 0 14 2
A joinPlans() 0 9 1
1
<?php
2
/**
3
 * API for Billing
4
 *
5
 * @link      https://github.com/hiqdev/billing-hiapi
6
 * @package   billing-hiapi
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\billing\hiapi\sale;
12
13
use hiqdev\php\billing\action\ActionInterface;
14
use hiqdev\php\billing\customer\CustomerInterface;
15
use hiqdev\php\billing\order\OrderInterface;
16
use hiqdev\php\billing\plan\PlanInterface;
17
use hiqdev\php\billing\sale\Sale;
18
use hiqdev\php\billing\sale\SaleInterface;
19
use hiqdev\php\billing\sale\SaleRepositoryInterface;
20
use hiqdev\yii\DataMapper\expressions\CallExpression;
21
use hiqdev\yii\DataMapper\expressions\HstoreExpression;
22
use hiqdev\yii\DataMapper\models\relations\Bucket;
23
use hiqdev\yii\DataMapper\query\Specification;
24
use hiqdev\yii\DataMapper\repositories\BaseRepository;
25
use yii\db\Query;
26
27
class SaleRepository extends BaseRepository implements SaleRepositoryInterface
28
{
29
    /** {@inheritdoc} */
30
    public $queryClass = SaleQuery::class;
31
32
    public function findId(SaleInterface $sale)
33
    {
34
        if ($sale->hasId()) {
35
            return $sale->getId();
36
        }
37
        $hstore = new HstoreExpression(array_filter([
38
            'buyer'     => $sale->getCustomer()->getLogin(),
39
            'buyer_id'  => $sale->getCustomer()->getId(),
40
            'object_id' => $sale->getTarget()->getId(),
41
            'tariff_id' => $sale->getPlan()->getId(),
42
        ]));
43
        $call = new CallExpression('sale_id', [$hstore]);
44
        $command = (new Query())->select($call);
45
46
        return $command->scalar($this->db);
47
    }
48
49
    /**
50
     * @param OrderInterface $order
51
     * @return Sale[]|SaleInterface[]
52
     */
53
    public function findByOrder(OrderInterface $order)
54
    {
55
        return array_map([$this, 'findByAction'], $order->getActions());
56
    }
57
58
    /**
59
     * Used to find a sale by action target.
60
     *
61
     * @param ActionInterface $action
62
     * @return SaleInterface|false
63
     */
64
    public function findByAction(ActionInterface $action)
65
    {
66
        $type = $action->getTarget()->getType();
67
        if ($type === null) {
0 ignored issues
show
introduced by
The condition $type === null is always false.
Loading history...
68
            // When action target type is not set, then action can be applied to any target.
69
            // It means we can not find exact sale, so return null.
70
            // Used at lest for:
71
            //  - temporary actions, when in-memory action is matched against an in-memory plan.
72
            return false;
73
        }
74
75
        if ($type === 'certificate') {
76
            $target_id = new CallExpression('class_id', ['certificate']);
77
        } elseif ($type === 'domain' || $type === 'feature') {
78
            $target_id = new CallExpression('class_id', ['zone']);
79
        } elseif ($type === 'server') {
80
            $target_id = $action->getTarget()->getId();
81
        } elseif ($type === 'serverConfig') {
82
            $target_id = $action->getTarget()->getId();
83
        } else {
84
            throw new \Exception('not implemented for: ' . $type);
85
        }
86
87
        $spec = $this->createSpecification()
88
            /// XXX how to pass if we want with prices into joinPlans?
89
            ->with('plans')
90
            ->where($this->buildTargetCond($target_id, $action->getCustomer()));
91
92
        return $this->findOne($spec);
93
    }
94
95
    protected function buildTargetCond($target_id, CustomerInterface $client)
96
    {
97
        $client_id = $client->getId();
98
        if ($client_id) {
99
            $seller_id = null;
100
        } else {
101
            $seller_id = $client->getSeller()->getId();
102
            $client_id = $seller_id;
103
        }
104
105
        return array_filter([
106
            'target-id'     => $target_id,
107
            'customer-id'   => $client_id,
108
            'seller-id'     => $seller_id,
109
        ]);
110
    }
111
112
    protected function joinPlans(&$rows)
113
    {
114
        $bucket = Bucket::fromRows($rows, 'plan-id');
115
        $spec = $this->createSpecification()
116
            ->with('prices')
117
            ->where(['id' => $bucket->getKeys()]);
118
        $raw_plans = $this->getRepository(PlanInterface::class)->queryAll($spec);
119
        $bucket->fill($raw_plans, 'id');
120
        $bucket->pourOneToOne($rows, 'plan');
121
    }
122
123
    /**
124
     * @param SaleInterface $sale
125
     */
126
    public function save(SaleInterface $sale)
127
    {
128
        $hstore = new HstoreExpression([
129
            'object_id'     => $sale->getTarget()->getId(),
130
            'contact_id'    => $sale->getCustomer()->getId(),
131
            'tariff_id'     => $sale->getPlan() ? $sale->getPlan()->getId() : null,
132
            'time'          => $sale->getTime()->format('c'),
133
        ]);
134
        $call = new CallExpression('sale_object', [$hstore]);
135
        $command = (new Query())->select($call);
136
        $sale->setId($command->scalar($this->db));
137
    }
138
}
139