Reader::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 10
dl 0
loc 12
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace Spryker\Zed\PriceProduct\Business\Model;
9
10
use Generated\Shared\Transfer\MoneyValueTransfer;
11
use Generated\Shared\Transfer\PriceProductCriteriaTransfer;
12
use Generated\Shared\Transfer\PriceProductDimensionTransfer;
13
use Generated\Shared\Transfer\PriceProductFilterIdentifierTransfer;
14
use Generated\Shared\Transfer\PriceProductFilterTransfer;
15
use Generated\Shared\Transfer\PriceProductTransfer;
16
use Spryker\Service\PriceProduct\PriceProductServiceInterface;
17
use Spryker\Zed\PriceProduct\Business\Model\PriceType\PriceProductTypeReaderInterface;
18
use Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductAbstractReaderInterface;
19
use Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductConcreteReaderInterface;
20
use Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductExpanderInterface;
21
use Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductMapperInterface;
22
use Spryker\Zed\PriceProduct\Dependency\Facade\PriceProductToProductFacadeInterface;
23
use Spryker\Zed\PriceProduct\Persistence\PriceProductRepositoryInterface;
24
use Spryker\Zed\PriceProduct\PriceProductConfig;
25
26
class Reader implements ReaderInterface
27
{
28
    /**
29
     * @var string|null
30
     */
31
    protected static $priceModeIdentifierForNetType;
32
33
    /**
34
     * @var array<\Generated\Shared\Transfer\PriceProductTransfer>
35
     */
36
    protected static $resolvedPriceProductTransferCollection = [];
37
38
    /**
39
     * @var string
40
     */
41
    protected const FIELD_PRICE_PAIR_ABSTRACTS = 'abstracts';
42
43
    /**
44
     * @var string
45
     */
46
    protected const FIELD_PRICE_PAIR_CONCRETES = 'concretes';
47
48
    /**
49
     * @param \Spryker\Zed\PriceProduct\Dependency\Facade\PriceProductToProductFacadeInterface $productFacade
50
     * @param \Spryker\Zed\PriceProduct\Business\Model\PriceType\PriceProductTypeReaderInterface $priceProductTypeReader
51
     * @param \Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductConcreteReaderInterface $priceProductConcreteReader
52
     * @param \Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductAbstractReaderInterface $priceProductAbstractReader
53
     * @param \Spryker\Zed\PriceProduct\Business\Model\PriceProductCriteriaBuilderInterface $priceProductCriteriaBuilder
54
     * @param \Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductMapperInterface $priceProductMapper
55
     * @param \Spryker\Zed\PriceProduct\PriceProductConfig $config
56
     * @param \Spryker\Service\PriceProduct\PriceProductServiceInterface $priceProductService
57
     * @param \Spryker\Zed\PriceProduct\Persistence\PriceProductRepositoryInterface $priceProductRepository
58
     * @param \Spryker\Zed\PriceProduct\Business\Model\Product\PriceProductExpanderInterface $priceProductExpander
59
     */
60
    public function __construct(
61
        protected PriceProductToProductFacadeInterface $productFacade,
62
        protected PriceProductTypeReaderInterface $priceProductTypeReader,
63
        protected PriceProductConcreteReaderInterface $priceProductConcreteReader,
64
        protected PriceProductAbstractReaderInterface $priceProductAbstractReader,
65
        protected PriceProductCriteriaBuilderInterface $priceProductCriteriaBuilder,
66
        protected PriceProductMapperInterface $priceProductMapper,
67
        protected PriceProductConfig $config,
68
        protected PriceProductServiceInterface $priceProductService,
69
        protected PriceProductRepositoryInterface $priceProductRepository,
70
        protected PriceProductExpanderInterface $priceProductExpander
71
    ) {
72
    }
73
74
    /**
75
     * @param string $sku
76
     * @param string|null $priceTypeName
77
     *
78
     * @return int|null
79
     */
80
    public function findPriceBySku($sku, $priceTypeName = null)
81
    {
82
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaWithDefaultValues($priceTypeName);
83
84
        $priceProductTransfer = $this->findProductPrice($sku, $priceProductCriteriaTransfer);
85
86
        if ($priceProductTransfer === null) {
87
            return null;
88
        }
89
90
        /** @var \Generated\Shared\Transfer\MoneyValueTransfer $moneyValueTransfer */
91
        $moneyValueTransfer = $priceProductTransfer->requireMoneyValue()->getMoneyValue();
92
        /** @var string $priceMode */
93
        $priceMode = $priceProductCriteriaTransfer->requirePriceMode()->getPriceMode();
94
95
        return $this->getPriceByPriceMode($moneyValueTransfer, $priceMode);
96
    }
97
98
    /**
99
     * @param \Generated\Shared\Transfer\PriceProductFilterTransfer $priceProductFilterTransfer
100
     *
101
     * @return int|null
102
     */
103
    public function findPriceFor(PriceProductFilterTransfer $priceProductFilterTransfer)
104
    {
105
        $priceProductTransfer = $this->findPriceProductFor($priceProductFilterTransfer);
106
107
        if ($priceProductTransfer === null) {
108
            return null;
109
        }
110
111
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaFromFilter($priceProductFilterTransfer);
112
113
        /** @var \Generated\Shared\Transfer\MoneyValueTransfer $moneyValueTransfer */
114
        $moneyValueTransfer = $priceProductTransfer->requireMoneyValue()->getMoneyValue();
115
        /** @var string $priceMode */
116
        $priceMode = $priceProductCriteriaTransfer->requirePriceMode()->getPriceMode();
117
118
        return $this->getPriceByPriceMode($moneyValueTransfer, $priceMode);
119
    }
120
121
    /**
122
     * @param \Generated\Shared\Transfer\PriceProductFilterTransfer $priceProductFilterTransfer
123
     *
124
     * @return \Generated\Shared\Transfer\PriceProductTransfer|null
125
     */
126
    public function findPriceProductFor(PriceProductFilterTransfer $priceProductFilterTransfer): ?PriceProductTransfer
127
    {
128
        $priceProductFilterTransfer->requireSku();
129
130
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaFromFilter($priceProductFilterTransfer);
131
132
        /** @var string $sku */
133
        $sku = $priceProductFilterTransfer->requireSku()->getSku();
134
135
        return $this->findProductPrice($sku, $priceProductCriteriaTransfer);
136
    }
137
138
    /**
139
     * @param int $idProductConcrete
140
     * @param int $idProductAbstract
141
     * @param \Generated\Shared\Transfer\PriceProductCriteriaTransfer|null $priceProductCriteriaTransfer
142
     *
143
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
144
     */
145
    public function findProductConcretePrices(
146
        int $idProductConcrete,
147
        int $idProductAbstract,
148
        ?PriceProductCriteriaTransfer $priceProductCriteriaTransfer = null
149
    ): array {
150
        $concretePriceProductTransfers = $this->priceProductConcreteReader
151
            ->findProductConcretePricesById($idProductConcrete, $priceProductCriteriaTransfer);
152
153
        if ($priceProductCriteriaTransfer !== null && $priceProductCriteriaTransfer->getOnlyConcretePrices()) {
154
            return $concretePriceProductTransfers;
155
        }
156
157
        $abstractPriceProductTransfers = $this->priceProductAbstractReader
158
            ->findProductAbstractPricesById($idProductAbstract, $priceProductCriteriaTransfer);
159
160
        return $this->mergeConcreteAndAbstractPrices($abstractPriceProductTransfers, $concretePriceProductTransfers);
161
    }
162
163
    /**
164
     * @param string $sku
165
     * @param string|null $priceTypeName
166
     *
167
     * @return bool
168
     */
169
    public function hasValidPrice($sku, $priceTypeName = null)
170
    {
171
        $priceTypeName = $this->priceProductTypeReader->handleDefaultPriceType($priceTypeName);
172
173
        if (!$this->priceProductTypeReader->hasPriceType($priceTypeName)) {
174
            return false;
175
        }
176
177
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaWithDefaultValues();
178
179
        return $this->isValidPrice($sku, $priceProductCriteriaTransfer);
180
    }
181
182
    /**
183
     * @param \Generated\Shared\Transfer\PriceProductFilterTransfer $priceProductFilterTransfer
184
     *
185
     * @return bool
186
     */
187
    public function hasValidPriceFor(PriceProductFilterTransfer $priceProductFilterTransfer)
188
    {
189
        $priceProductFilterTransfer->requireSku();
190
191
        $priceTypeName = $this->priceProductTypeReader->handleDefaultPriceType(
192
            $priceProductFilterTransfer->getPriceTypeName(),
193
        );
194
195
        if (!$this->priceProductTypeReader->hasPriceType($priceTypeName)) {
196
            return false;
197
        }
198
199
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaFromFilter($priceProductFilterTransfer);
200
201
        /** @var string $sku */
202
        $sku = $priceProductFilterTransfer->requireSku()->getSku();
203
204
        return $this->isValidPrice($sku, $priceProductCriteriaTransfer);
205
    }
206
207
    /**
208
     * @param string $sku
209
     * @param string $priceTypeName
210
     * @param string $currencyIsoCode
211
     *
212
     * @return int
213
     */
214
    public function getProductPriceIdBySku($sku, $priceTypeName, $currencyIsoCode)
215
    {
216
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaWithDefaultValues();
217
218
        if ($this->priceProductConcreteReader->hasPriceForProductConcrete($sku, $priceProductCriteriaTransfer)) {
219
            /** @var int $idPriceProduct */
220
            $idPriceProduct = $this->priceProductConcreteReader->findPriceProductId($sku, $priceProductCriteriaTransfer);
221
222
            return $idPriceProduct;
223
        }
224
225
        if (!$this->priceProductAbstractReader->hasPriceForProductAbstract($sku, $priceProductCriteriaTransfer)) {
226
            $sku = $this->productFacade->getAbstractSkuFromProductConcrete($sku);
227
        }
228
229
        /** @var int $idPriceProduct */
230
        $idPriceProduct = $this->priceProductAbstractReader->findPriceProductId($sku, $priceProductCriteriaTransfer);
231
232
        return $idPriceProduct;
233
    }
234
235
    /**
236
     * @param string $sku
237
     * @param \Generated\Shared\Transfer\PriceProductDimensionTransfer|null $priceProductDimensionTransfer
238
     *
239
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
240
     */
241
    public function findPricesBySkuForCurrentStore(
242
        string $sku,
243
        ?PriceProductDimensionTransfer $priceProductDimensionTransfer = null
244
    ): array {
245
        $priceProductDimensionTransfer = $this->getPriceProductDimensionTransfer($priceProductDimensionTransfer);
246
247
        $abstractPriceProductTransfers = $this->priceProductAbstractReader
248
            ->findProductAbstractPricesBySkuForCurrentStore($sku, $priceProductDimensionTransfer);
249
250
        $concretePriceProductTransfers = $this->priceProductConcreteReader
251
            ->findProductConcretePricesBySkuForCurrentStore($sku, $priceProductDimensionTransfer);
252
253
        if (!$concretePriceProductTransfers) {
254
            return $abstractPriceProductTransfers;
255
        }
256
257
        if (!$abstractPriceProductTransfers) {
258
            return $concretePriceProductTransfers;
259
        }
260
261
        return $this->mergeConcreteAndAbstractPrices($abstractPriceProductTransfers, $concretePriceProductTransfers);
262
    }
263
264
    /**
265
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $abstractPriceProductTransfers
266
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $concretePriceProductTransfers
267
     *
268
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
269
     */
270
    protected function mergeConcreteAndAbstractPrices(
271
        array $abstractPriceProductTransfers,
272
        array $concretePriceProductTransfers
273
    ) {
274
        $priceProductTransfers = [];
275
        foreach ($abstractPriceProductTransfers as $priceProductAbstractTransfer) {
276
            $abstractKey = $this->buildPriceProductIdentifier($priceProductAbstractTransfer);
277
278
            $priceProductTransfers = $this->mergeConcreteProduct(
279
                $concretePriceProductTransfers,
280
                $abstractKey,
281
                $priceProductAbstractTransfer,
282
                $priceProductTransfers,
283
            );
284
285
            if (!isset($priceProductTransfers[$abstractKey])) {
286
                $priceProductTransfers[$abstractKey] = $priceProductAbstractTransfer;
287
            }
288
        }
289
290
        return $this->addConcreteNotMergedPrices($concretePriceProductTransfers, $priceProductTransfers);
291
    }
292
293
    /**
294
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $concretePriceProductTransfers
295
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $priceProductTransfers
296
     *
297
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
298
     */
299
    protected function addConcreteNotMergedPrices(array $concretePriceProductTransfers, array $priceProductTransfers)
300
    {
301
        foreach ($concretePriceProductTransfers as $priceProductConcreteTransfer) {
302
            $concreteKey = $this->buildPriceProductIdentifier($priceProductConcreteTransfer);
303
304
            if (isset($priceProductTransfers[$concreteKey])) {
305
                continue;
306
            }
307
308
            $priceProductTransfers[$concreteKey] = $priceProductConcreteTransfer;
309
        }
310
311
        return $priceProductTransfers;
312
    }
313
314
    /**
315
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $concretePriceProductTransfers
316
     * @param string $abstractKey
317
     * @param \Generated\Shared\Transfer\PriceProductTransfer $priceProductAbstractTransfer
318
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $priceProductTransfers
319
     *
320
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
321
     */
322
    protected function mergeConcreteProduct(
323
        array $concretePriceProductTransfers,
324
        $abstractKey,
325
        PriceProductTransfer $priceProductAbstractTransfer,
326
        array $priceProductTransfers
327
    ) {
328
        foreach ($concretePriceProductTransfers as $priceProductConcreteTransfer) {
329
            $concreteKey = $this->buildPriceProductIdentifier($priceProductConcreteTransfer);
330
331
            if ($abstractKey !== $concreteKey) {
332
                continue;
333
            }
334
335
            $priceProductTransfers[$concreteKey] = $this->resolveConcreteProductPrice(
336
                $priceProductAbstractTransfer,
337
                $priceProductConcreteTransfer,
338
            );
339
        }
340
341
        if (!isset($priceProductTransfers[$abstractKey])) {
342
            /** @var \Generated\Shared\Transfer\PriceProductDimensionTransfer $priceDimensionTransfer */
343
            $priceDimensionTransfer = $priceProductAbstractTransfer->requirePriceDimension()->getPriceDimension();
344
            /** @var \Generated\Shared\Transfer\MoneyValueTransfer $moneyValueTransfer */
345
            $moneyValueTransfer = $priceProductAbstractTransfer->requireMoneyValue()->getMoneyValue();
346
            $priceDimensionTransfer->setIdPriceProductDefault(null);
347
            $moneyValueTransfer->setIdEntity(null);
348
            $priceProductTransfers[$abstractKey] = $priceProductAbstractTransfer->setPriceDimension($priceDimensionTransfer)
349
                ->setMoneyValue($moneyValueTransfer);
350
        }
351
352
        return $priceProductTransfers;
353
    }
354
355
    /**
356
     * @param \Generated\Shared\Transfer\PriceProductTransfer $priceProductAbstractTransfer
357
     * @param \Generated\Shared\Transfer\PriceProductTransfer $priceProductConcreteTransfer
358
     *
359
     * @return \Generated\Shared\Transfer\PriceProductTransfer
360
     */
361
    protected function resolveConcreteProductPrice(
362
        PriceProductTransfer $priceProductAbstractTransfer,
363
        PriceProductTransfer $priceProductConcreteTransfer
364
    ) {
365
        /** @var \Generated\Shared\Transfer\MoneyValueTransfer $abstractMoneyValueTransfer */
366
        $abstractMoneyValueTransfer = $priceProductAbstractTransfer->requireMoneyValue()->getMoneyValue();
367
        /** @var \Generated\Shared\Transfer\MoneyValueTransfer $concreteMoneyValueTransfer */
368
        $concreteMoneyValueTransfer = $priceProductConcreteTransfer->requireMoneyValue()->getMoneyValue();
369
370
        if ($concreteMoneyValueTransfer->getGrossAmount() === null) {
371
            $concreteMoneyValueTransfer->setGrossAmount($abstractMoneyValueTransfer->getGrossAmount());
372
        }
373
374
        if ($concreteMoneyValueTransfer->getNetAmount() === null) {
375
            $concreteMoneyValueTransfer->setNetAmount($abstractMoneyValueTransfer->getNetAmount());
376
        }
377
378
        return $priceProductConcreteTransfer;
379
    }
380
381
    /**
382
     * @param string $sku
383
     * @param \Generated\Shared\Transfer\PriceProductCriteriaTransfer $priceProductCriteriaTransfer
384
     *
385
     * @return \Generated\Shared\Transfer\PriceProductTransfer|null
386
     */
387
    protected function findProductPrice(string $sku, PriceProductCriteriaTransfer $priceProductCriteriaTransfer): ?PriceProductTransfer
388
    {
389
        $priceProductConcreteTransfers = $this->priceProductConcreteReader
390
            ->findProductConcretePricesBySkuAndCriteria($sku, $priceProductCriteriaTransfer);
391
392
        if ($this->productFacade->hasProductConcrete($sku)) {
393
            $sku = $this->productFacade->getAbstractSkuFromProductConcrete($sku);
394
        }
395
396
        $priceProductAbstractTransfers = $this->priceProductAbstractReader
397
            ->findProductAbstractPricesBySkuAndCriteria($sku, $priceProductCriteriaTransfer);
398
399
        if (!$priceProductConcreteTransfers) {
400
            return $this->priceProductService
401
                ->resolveProductPriceByPriceProductCriteria($priceProductAbstractTransfers, $priceProductCriteriaTransfer);
402
        }
403
404
        $priceProductTransfers = $this->priceProductService
405
            ->mergeConcreteAndAbstractPrices($priceProductAbstractTransfers, $priceProductConcreteTransfers);
406
407
        return $this->priceProductService
408
            ->resolveProductPriceByPriceProductCriteria($priceProductTransfers, $priceProductCriteriaTransfer);
409
    }
410
411
    /**
412
     * @param \Generated\Shared\Transfer\MoneyValueTransfer $moneyValueTransfer
413
     * @param string $priceMode
414
     *
415
     * @return int|null
416
     */
417
    protected function getPriceByPriceMode(MoneyValueTransfer $moneyValueTransfer, string $priceMode): ?int
418
    {
419
        if ($priceMode === $this->priceProductMapper->getNetPriceModeIdentifier()) {
420
            return $moneyValueTransfer->getNetAmount();
421
        }
422
423
        return $moneyValueTransfer->getGrossAmount();
424
    }
425
426
    /**
427
     * @param string $sku
428
     * @param \Generated\Shared\Transfer\PriceProductCriteriaTransfer $priceProductCriteriaTransfer
429
     *
430
     * @return bool
431
     */
432
    protected function isValidPrice($sku, PriceProductCriteriaTransfer $priceProductCriteriaTransfer)
433
    {
434
        if ($this->priceProductConcreteReader->hasPriceForProductConcrete($sku, $priceProductCriteriaTransfer)) {
435
            return true;
436
        }
437
438
        $abstractSku = $this->productFacade->getAbstractSkuFromProductConcrete($sku);
439
        if ($this->priceProductAbstractReader->hasPriceForProductAbstract($abstractSku, $priceProductCriteriaTransfer)) {
440
            return true;
441
        }
442
443
        return false;
444
    }
445
446
    /**
447
     * @param \Generated\Shared\Transfer\PriceProductDimensionTransfer|null $priceProductDimensionTransfer
448
     *
449
     * @return \Generated\Shared\Transfer\PriceProductDimensionTransfer
450
     */
451
    protected function getPriceProductDimensionTransfer(?PriceProductDimensionTransfer $priceProductDimensionTransfer = null): PriceProductDimensionTransfer
452
    {
453
        if (!$priceProductDimensionTransfer) {
454
            $priceProductDimensionTransfer = (new PriceProductDimensionTransfer())
455
                ->setType($this->config->getPriceDimensionDefault());
456
        }
457
458
        return $priceProductDimensionTransfer;
459
    }
460
461
    /**
462
     * @param int $idProductConcrete
463
     * @param int $idProductAbstract
464
     * @param \Generated\Shared\Transfer\PriceProductCriteriaTransfer|null $priceProductCriteriaTransfer
465
     *
466
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
467
     */
468
    public function findProductConcretePricesWithoutPriceExtraction(
469
        int $idProductConcrete,
470
        int $idProductAbstract,
471
        ?PriceProductCriteriaTransfer $priceProductCriteriaTransfer = null
472
    ): array {
473
        $concretePriceProductTransfers = $this->priceProductConcreteReader
474
            ->findProductConcretePricesWithoutPriceExtraction($idProductConcrete, $priceProductCriteriaTransfer);
475
476
        if ($priceProductCriteriaTransfer !== null && $priceProductCriteriaTransfer->getOnlyConcretePrices()) {
477
            return $concretePriceProductTransfers;
478
        }
479
480
        $abstractPriceProductTransfers = $this->priceProductAbstractReader
481
            ->findProductAbstractPricesWithoutPriceExtraction($idProductAbstract, $priceProductCriteriaTransfer);
482
483
        return $this->mergeConcreteAndAbstractPrices($abstractPriceProductTransfers, $concretePriceProductTransfers);
484
    }
485
486
    /**
487
     * @param \Generated\Shared\Transfer\PriceProductTransfer $priceProductTransfer
488
     *
489
     * @return string
490
     */
491
    protected function buildPriceProductIdentifier(PriceProductTransfer $priceProductTransfer): string
492
    {
493
        /** @var \Generated\Shared\Transfer\MoneyValueTransfer $moneyValueTransfer */
494
        $moneyValueTransfer = $priceProductTransfer->requireMoneyValue()->getMoneyValue();
495
        /** @var \Generated\Shared\Transfer\PriceTypeTransfer $priceTypeTransfer */
496
        $priceTypeTransfer = $priceProductTransfer->requirePriceType()->getPriceType();
497
498
        return implode(
499
            '-',
500
            [
501
                $moneyValueTransfer->getFkStore(),
502
                $moneyValueTransfer->getFkCurrency(),
503
                $priceTypeTransfer->getName(),
504
                $priceTypeTransfer->getPriceModeConfiguration(),
505
            ],
506
        );
507
    }
508
509
    /**
510
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
511
     *
512
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
513
     */
514
    public function getValidPrices(array $priceProductFilterTransfers): array
515
    {
516
        if (count($priceProductFilterTransfers) === 0) {
517
            return [];
518
        }
519
        $priceProductFilterTransfers = $this->filterPriceProductFilterTransfersWithoutExistingPriceType($priceProductFilterTransfers);
520
        if (!$priceProductFilterTransfers) {
521
            return [];
522
        }
523
524
        $concretePricesBySku = $this->findPricesForConcreteProducts($priceProductFilterTransfers);
525
        $abstractPricesBySku = $this->findPricesForAbstractProducts(
526
            $this->getProductConcreteSkus($priceProductFilterTransfers),
527
            $priceProductFilterTransfers,
528
        );
529
530
        return $this->resolveProductPrices(
531
            $this->mergeIndexedPriceProductTransfers($abstractPricesBySku, $concretePricesBySku),
532
            $priceProductFilterTransfers,
533
        );
534
    }
535
536
    /**
537
     * @param array<array<\Generated\Shared\Transfer\PriceProductTransfer>> $indexedAbstractPriceProductTransfers
538
     * @param array<array<\Generated\Shared\Transfer\PriceProductTransfer>> $indexedConcretePriceProductTransfers
539
     *
540
     * @return array<array<\Generated\Shared\Transfer\PriceProductTransfer>>
541
     */
542
    protected function mergeIndexedPriceProductTransfers(array $indexedAbstractPriceProductTransfers, array $indexedConcretePriceProductTransfers): array
543
    {
544
        $mergedPriceProductTransfers = [];
545
546
        foreach ($indexedAbstractPriceProductTransfers as $sku => $abstractPriceProductTransfers) {
547
            $mergedPriceProductTransfers[$sku] = $this->priceProductService->mergeConcreteAndAbstractPrices(
548
                $abstractPriceProductTransfers,
549
                $indexedConcretePriceProductTransfers[$sku] ?? [],
550
            );
551
        }
552
553
        foreach ($indexedConcretePriceProductTransfers as $sku => $concretePriceProductTransfers) {
554
            $mergedPriceProductTransfers[$sku] = $this->priceProductService->mergeConcreteAndAbstractPrices(
555
                $indexedAbstractPriceProductTransfers[$sku] ?? [],
556
                $concretePriceProductTransfers,
557
            );
558
        }
559
560
        return $mergedPriceProductTransfers;
561
    }
562
563
    /**
564
     * @param array<array<\Generated\Shared\Transfer\PriceProductTransfer>> $priceProductTransfers
565
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
566
     *
567
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
568
     */
569
    protected function resolveProductPrices(array $priceProductTransfers, array $priceProductFilterTransfers): array
570
    {
571
        $priceProductCriteriaTransfers = $this
572
            ->priceProductCriteriaBuilder
573
            ->buildCriteriaTransfersFromFilterTransfers($priceProductFilterTransfers);
574
575
        $resolvedPriceProductTransfers = [];
576
        foreach ($priceProductCriteriaTransfers as $index => $priceProductCriteriaTransfer) {
577
            $priceProductFilterTransfer = $this->fillPriceProductFilterIdentifier($priceProductFilterTransfers[$index]);
578
            $resolvedItemPrice = $this->resolveProductPriceByPriceProductCriteria(
579
                $priceProductFilterTransfer->getIdentifierOrFail(),
580
                $priceProductTransfers,
581
                $priceProductCriteriaTransfer,
582
            );
583
584
            if ($resolvedItemPrice) {
585
                $resolvedPriceProductTransfers[] = $resolvedItemPrice;
586
            }
587
        }
588
589
        return $resolvedPriceProductTransfers;
590
    }
591
592
    /**
593
     * @param string $priceProductCriteriaIdentifier
594
     * @param array<array<\Generated\Shared\Transfer\PriceProductTransfer>> $priceProductTransfers
595
     * @param \Generated\Shared\Transfer\PriceProductCriteriaTransfer $priceProductCriteriaTransfer
596
     *
597
     * @return \Generated\Shared\Transfer\PriceProductTransfer|null
598
     */
599
    protected function resolveProductPriceByPriceProductCriteria(
600
        string $priceProductCriteriaIdentifier,
601
        array $priceProductTransfers,
602
        PriceProductCriteriaTransfer $priceProductCriteriaTransfer
603
    ): ?PriceProductTransfer {
604
        if (!isset(static::$resolvedPriceProductTransferCollection[$priceProductCriteriaIdentifier])) {
605
            /** @var \Generated\Shared\Transfer\PriceProductTransfer $priceProductTransfer */
606
            $priceProductTransfer = $this->priceProductService->resolveProductPriceByPriceProductCriteria(
607
                $priceProductTransfers[$priceProductCriteriaIdentifier],
608
                $priceProductCriteriaTransfer,
609
            );
610
            static::$resolvedPriceProductTransferCollection[$priceProductCriteriaIdentifier] = $priceProductTransfer;
611
        }
612
613
        return static::$resolvedPriceProductTransferCollection[$priceProductCriteriaIdentifier];
614
    }
615
616
    /**
617
     * @return string
618
     */
619
    protected function getPriceModeIdentifierForNetType(): string
620
    {
621
        if (static::$priceModeIdentifierForNetType === null) {
622
            static::$priceModeIdentifierForNetType = $this->config->getPriceModeIdentifierForNetType();
623
        }
624
625
        return static::$priceModeIdentifierForNetType;
626
    }
627
628
    /**
629
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
630
     *
631
     * @return array<array<\Generated\Shared\Transfer\PriceProductTransfer>>
632
     */
633
    protected function findPricesForConcreteProducts(array $priceProductFilterTransfers): array
634
    {
635
        $priceProductFilterTransfer = $this->getCommonPriceProductFilterTransfer($priceProductFilterTransfers);
636
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaFromFilter($priceProductFilterTransfer);
637
        $productConcreteSkus = array_map(function (PriceProductFilterTransfer $priceProductFilterTransfer) {
638
            /** @var string $sku */
639
            $sku = $priceProductFilterTransfer->getSku();
640
641
            return $sku;
642
        }, $priceProductFilterTransfers);
643
644
        $concretePriceProductTransfers = $this->priceProductConcreteReader->getProductConcretePricesByConcreteSkusAndCriteria(
645
            $productConcreteSkus,
646
            $priceProductCriteriaTransfer,
647
        );
648
649
        return $this->groupPriceProductTransfersByFilter($priceProductFilterTransfers, $concretePriceProductTransfers);
650
    }
651
652
    /**
653
     * @param array<string> $productConcreteSkus
654
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
655
     *
656
     * @return array<array<\Generated\Shared\Transfer\PriceProductTransfer>>
657
     */
658
    protected function findPricesForAbstractProducts(array $productConcreteSkus, array $priceProductFilterTransfers): array
659
    {
660
        $priceProductFilterTransfer = $this->getCommonPriceProductFilterTransfer($priceProductFilterTransfers);
661
        $priceProductCriteriaTransfer = $this->priceProductCriteriaBuilder->buildCriteriaFromFilter($priceProductFilterTransfer);
662
663
        $priceProductTransfers = $this->priceProductAbstractReader->getProductAbstractPricesByConcreteSkusAndCriteria(
664
            $productConcreteSkus,
665
            $priceProductCriteriaTransfer,
666
        );
667
668
        return $this->groupPriceProductTransfersByFilter($priceProductFilterTransfers, $priceProductTransfers);
669
    }
670
671
    /**
672
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
673
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $priceProductTransfers
674
     *
675
     * @return array<array<\Generated\Shared\Transfer\PriceProductTransfer>>
676
     */
677
    protected function groupPriceProductTransfersByFilter(array $priceProductFilterTransfers, array $priceProductTransfers): array
678
    {
679
        $priceProductTransfersGroupedByFilterIdentifier = [];
680
681
        foreach ($priceProductFilterTransfers as $priceProductFilterTransfer) {
682
            $priceProductFilterTransfer = $this->fillPriceProductFilterIdentifier($priceProductFilterTransfer);
683
            $priceProductFilterIdentifier = $priceProductFilterTransfer->getIdentifierOrFail();
684
            $priceProductTransfersGroupedByFilterIdentifier[$priceProductFilterIdentifier] = $this->priceProductService->resolveProductPricesByPriceProductFilter(
685
                $priceProductTransfers,
686
                $priceProductFilterTransfer,
687
            );
688
        }
689
690
        return $priceProductTransfersGroupedByFilterIdentifier;
691
    }
692
693
    /**
694
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
695
     *
696
     * @return array<string>
697
     */
698
    protected function getProductConcreteSkus(array $priceProductFilterTransfers): array
699
    {
700
        $productConcreteSkus = [];
701
702
        foreach ($priceProductFilterTransfers as $priceProductFilterTransfer) {
703
            /** @var string $sku */
704
            $sku = $priceProductFilterTransfer->getSku();
705
706
            $productConcreteSkus[] = $sku;
707
        }
708
709
        return $productConcreteSkus;
710
    }
711
712
    /**
713
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
714
     *
715
     * @return array<\Generated\Shared\Transfer\PriceProductFilterTransfer>
716
     */
717
    protected function getPriceProductFilterTransfersBySku(array $priceProductFilterTransfers): array
718
    {
719
        $priceProductFilterTransfersBySku = [];
720
        foreach ($priceProductFilterTransfers as $priceProductFilterTransfer) {
721
            $priceProductFilterTransfersBySku[$priceProductFilterTransfer->getSku()] = $priceProductFilterTransfer;
722
        }
723
724
        return $priceProductFilterTransfersBySku;
725
    }
726
727
    /**
728
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
729
     *
730
     * @return \Generated\Shared\Transfer\PriceProductFilterTransfer
731
     */
732
    protected function getCommonPriceProductFilterTransfer(array $priceProductFilterTransfers): PriceProductFilterTransfer
733
    {
734
        /** @var \Generated\Shared\Transfer\PriceProductFilterTransfer $priceProductFilterTransfer */
735
        $priceProductFilterTransfer = array_shift($priceProductFilterTransfers);
736
737
        return $priceProductFilterTransfer;
738
    }
739
740
    /**
741
     * @param array<\Generated\Shared\Transfer\PriceProductFilterTransfer> $priceProductFilterTransfers
742
     *
743
     * @return array<\Generated\Shared\Transfer\PriceProductFilterTransfer>
744
     */
745
    protected function filterPriceProductFilterTransfersWithoutExistingPriceType(array $priceProductFilterTransfers): array
746
    {
747
        $filteredPriceProductFilterTransfers = [];
748
        foreach ($priceProductFilterTransfers as $priceProductFilterTransfer) {
749
            $priceTypeName = $this->priceProductTypeReader->handleDefaultPriceType(
750
                $priceProductFilterTransfer->getPriceTypeName(),
751
            );
752
            if ($this->priceProductTypeReader->hasPriceType($priceTypeName)) {
753
                $filteredPriceProductFilterTransfers[] = $priceProductFilterTransfer;
754
            }
755
        }
756
757
        return $filteredPriceProductFilterTransfers;
758
    }
759
760
    /**
761
     * @param \Generated\Shared\Transfer\PriceProductFilterTransfer $priceProductFilterTransfer
762
     *
763
     * @return string
764
     */
765
    protected function buildPriceProductFilterIdentifier(PriceProductFilterTransfer $priceProductFilterTransfer): string
766
    {
767
        $priceProductFilterIdentifierTransfer = (new PriceProductFilterIdentifierTransfer())->fromArray(
768
            $priceProductFilterTransfer->toArray(),
769
            true,
770
        );
771
        $priceProductFilterIdentifierTransfer->setQuantity((int)$priceProductFilterTransfer->getQuantity());
772
773
        return md5(json_encode($priceProductFilterIdentifierTransfer->toArray(), JSON_THROW_ON_ERROR));
774
    }
775
776
    /**
777
     * @param \Generated\Shared\Transfer\PriceProductFilterTransfer $priceProductFilterTransfer
778
     *
779
     * @return \Generated\Shared\Transfer\PriceProductFilterTransfer
780
     */
781
    protected function fillPriceProductFilterIdentifier(PriceProductFilterTransfer $priceProductFilterTransfer): PriceProductFilterTransfer
782
    {
783
        if ($priceProductFilterTransfer->getIdentifier() !== null) {
784
            return $priceProductFilterTransfer;
785
        }
786
787
        return $priceProductFilterTransfer->setIdentifier(
788
            $this->buildPriceProductFilterIdentifier($priceProductFilterTransfer),
789
        );
790
    }
791
792
    /**
793
     * @param \Generated\Shared\Transfer\PriceProductCriteriaTransfer $priceProductCriteriaTransfer
794
     *
795
     * @return array<int, array<\Generated\Shared\Transfer\PriceProductTransfer>>
796
     */
797
    public function findProductConcretePricesWithoutPriceExtractionByConcreteAbstractMap(PriceProductCriteriaTransfer $priceProductCriteriaTransfer): array
798
    {
799
        $productConcreteToProductAbstractIdMap = $priceProductCriteriaTransfer->getProductConcreteToAbstractIdMaps();
800
        $productAbstractToProductConcreteIdMap = $this->mapProductAbstractToProductConcreteId($productConcreteToProductAbstractIdMap);
801
        $priceProductTransfers = $this->getProductPriceTransfers($productConcreteToProductAbstractIdMap, $priceProductCriteriaTransfer);
802
        $priceProductConcreteProductAbstractPairs = $this->pairPriceProductsTransfersByConcreteToAbstractRelation(
803
            $priceProductTransfers,
804
            $productAbstractToProductConcreteIdMap,
805
        );
806
807
        $priceProductTransfersResult = [];
808
        foreach ($priceProductConcreteProductAbstractPairs as $idProductConcrete => $priceProductPair) {
809
            $priceProductTransfersResult[(int)$idProductConcrete] = $this->mergeConcreteAndAbstractPrices(
810
                $priceProductPair[static::FIELD_PRICE_PAIR_ABSTRACTS],
811
                $priceProductPair[static::FIELD_PRICE_PAIR_CONCRETES],
812
            );
813
        }
814
815
        return $priceProductTransfersResult;
816
    }
817
818
    /**
819
     * @param array<int, int> $productConcreteToProductAbstractIdMap
820
     * @param \Generated\Shared\Transfer\PriceProductCriteriaTransfer $priceProductCriteriaTransfer
821
     *
822
     * @return array<\Generated\Shared\Transfer\PriceProductTransfer>
823
     */
824
    protected function getProductPriceTransfers(
825
        array $productConcreteToProductAbstractIdMap,
826
        PriceProductCriteriaTransfer $priceProductCriteriaTransfer
827
    ): array {
828
        $productAbstractIds = array_unique(array_values($productConcreteToProductAbstractIdMap));
829
        $productConcreteIds = array_keys($productConcreteToProductAbstractIdMap);
830
831
        $priceProductTransfers = $this->priceProductRepository->findProductPricesByConcreteIdsOrAbstractIds(
832
            $productConcreteIds,
833
            $productAbstractIds,
834
            $priceProductCriteriaTransfer,
835
        );
836
837
        return $this->priceProductExpander->expandPriceProductTransfers($priceProductTransfers);
838
    }
839
840
    /**
841
     * @param array<int, int> $productConcreteToProductAbstractIdMap
842
     *
843
     * @return array<int, array<int>>
844
     */
845
    protected function mapProductAbstractToProductConcreteId(array $productConcreteToProductAbstractIdMap): array
846
    {
847
        $productAbstractToProductConcreteIdMap = [];
848
        foreach ($productConcreteToProductAbstractIdMap as $idProductConcrete => $idProductAbstract) {
849
            $productAbstractToProductConcreteIdMap[$idProductAbstract] = $productAbstractToProductConcreteIdMap[$idProductAbstract] ?? [];
850
            $productAbstractToProductConcreteIdMap[$idProductAbstract][] = $idProductConcrete;
851
        }
852
853
        return $productAbstractToProductConcreteIdMap;
854
    }
855
856
    /**
857
     * @param array<\Generated\Shared\Transfer\PriceProductTransfer> $priceProductTransfers
858
     * @param array<int, array<int>> $productAbstractToProductConcreteIdMap
859
     *
860
     * @return array<int|string, array<string, array<int, \Generated\Shared\Transfer\PriceProductTransfer>>>
861
     */
862
    protected function pairPriceProductsTransfersByConcreteToAbstractRelation(
863
        array $priceProductTransfers,
864
        array $productAbstractToProductConcreteIdMap
865
    ): array {
866
        $pairStructure = [
867
            static::FIELD_PRICE_PAIR_ABSTRACTS => [],
868
            static::FIELD_PRICE_PAIR_CONCRETES => [],
869
        ];
870
        $priceProductConcreteProductAbstractPairs = [];
871
872
        foreach ($priceProductTransfers as $priceProductTransfer) {
873
            $idProductAbstract = $priceProductTransfer->getIdProductAbstract();
874
            $idProductConcrete = $priceProductTransfer->getIdProduct();
875
876
            if (!$idProductAbstract || empty($productAbstractToProductConcreteIdMap[$idProductAbstract])) {
877
                $priceProductConcreteProductAbstractPairs[$idProductConcrete] ??= $pairStructure;
878
                $priceProductConcreteProductAbstractPairs[$idProductConcrete][static::FIELD_PRICE_PAIR_CONCRETES][] = $priceProductTransfer;
879
880
                continue;
881
            }
882
883
            foreach ($productAbstractToProductConcreteIdMap[$idProductAbstract] as $idProductConcreteRelated) {
884
                $priceProductConcreteProductAbstractPairs[$idProductConcreteRelated] ??= $pairStructure;
885
                $priceProductConcreteProductAbstractPairs[$idProductConcreteRelated][static::FIELD_PRICE_PAIR_ABSTRACTS][] = $priceProductTransfer;
886
            }
887
        }
888
889
        return $priceProductConcreteProductAbstractPairs;
890
    }
891
}
892