SalesRepository   F
last analyzed

Complexity

Total Complexity 85

Size/Duplication

Total Lines 884
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 350
dl 0
loc 884
rs 2
c 0
b 0
f 0
wmc 85

37 Methods

Rating   Name   Duplication   Size   Complexity  
A getLatestSalesOrderTotalsSubQuerySql() 0 11 1
A getSalesOrderItemsByOrderIds() 0 9 1
A getSalesOrderEntity() 0 26 2
A isSearchByAllFilterFieldSet() 0 9 3
A getOmsOrderItemStates() 0 8 1
A setMissingCustomer() 0 8 2
A setShippingAddress() 0 15 2
A findCustomerOrderIdByOrderReference() 0 11 1
A applySalesOrderFilters() 0 22 5
A applySorting() 0 12 3
A getCurrencyIsoCodesBySalesOrderIds() 0 14 2
A setOrderTotals() 0 15 2
A setBillingAddress() 0 9 1
A getMappedSalesOrderTotalsBySalesOrderIds() 0 18 1
A getSalesExpensesBySalesExpenseCollectionDeleteCriteria() 0 18 2
A applyFilterToQuery() 0 13 4
A countUniqueProductsForOrder() 0 10 1
A expandSalesOrdersWithSalesOrderItems() 0 17 3
A createOrderTransfer() 0 12 1
A expandSalesOrdersWithSalesExpenses() 0 17 3
A applyPagination() 0 30 5
A getOrderCollection() 0 36 3
A getOrderItems() 0 20 1
A setOrderExpenses() 0 11 2
A getCustomerOrderListByCustomerReference() 0 24 3
A buildSearchOrdersQuery() 0 21 4
A hydrateAddressTransferFromEntity() 0 8 1
A getSalesOrderDetails() 0 5 1
A appySalesExpenseCollectionDeleteCriteriaFilters() 0 13 3
A searchOrders() 0 21 2
A preparePagination() 0 23 1
A findOrderAddressByIdOrderAddress() 0 13 2
A setOrderFilters() 0 13 4
A createOrderAddressTransfer() 0 3 1
A findOrderWithoutItems() 0 16 2
A getTotalCustomerOrderCount() 0 12 2
B setOrderItemFilters() 0 38 7

How to fix   Complexity   

Complex Class

Complex classes like SalesRepository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SalesRepository, and based on these observations, apply Extract Interface, too.

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\Sales\Persistence;
9
10
use ArrayObject;
11
use Generated\Shared\Transfer\AddressTransfer;
12
use Generated\Shared\Transfer\ExpenseTransfer;
13
use Generated\Shared\Transfer\FilterTransfer;
14
use Generated\Shared\Transfer\OrderCollectionTransfer;
15
use Generated\Shared\Transfer\OrderCriteriaTransfer;
16
use Generated\Shared\Transfer\OrderFilterTransfer;
17
use Generated\Shared\Transfer\OrderItemFilterTransfer;
18
use Generated\Shared\Transfer\OrderListRequestTransfer;
19
use Generated\Shared\Transfer\OrderListTransfer;
20
use Generated\Shared\Transfer\OrderTransfer;
21
use Generated\Shared\Transfer\PaginationTransfer;
22
use Generated\Shared\Transfer\SalesExpenseCollectionDeleteCriteriaTransfer;
23
use Generated\Shared\Transfer\TaxTotalTransfer;
24
use Generated\Shared\Transfer\TotalsTransfer;
25
use Orm\Zed\Oms\Persistence\Map\SpyOmsOrderItemStateTableMap;
26
use Orm\Zed\Sales\Persistence\Map\SpySalesOrderTableMap;
27
use Orm\Zed\Sales\Persistence\Map\SpySalesOrderTotalsTableMap;
28
use Orm\Zed\Sales\Persistence\SpySalesExpenseQuery;
29
use Orm\Zed\Sales\Persistence\SpySalesOrder;
30
use Orm\Zed\Sales\Persistence\SpySalesOrderAddress;
31
use Orm\Zed\Sales\Persistence\SpySalesOrderItemQuery;
32
use Orm\Zed\Sales\Persistence\SpySalesOrderQuery;
33
use Propel\Runtime\ActiveQuery\Criteria;
34
use Propel\Runtime\ActiveQuery\ModelCriteria;
35
use Spryker\Zed\Kernel\Persistence\AbstractRepository;
36
use Spryker\Zed\Propel\PropelFilterCriteria;
37
use Spryker\Zed\Sales\Business\Exception\InvalidSalesOrderException;
38
use Spryker\Zed\Sales\Persistence\Propel\QueryBuilder\OrderSearchFilterFieldQueryBuilder;
39
40
/**
41
 * @method \Spryker\Zed\Sales\Persistence\SalesPersistenceFactory getFactory()
42
 */
43
class SalesRepository extends AbstractRepository implements SalesRepositoryInterface
44
{
45
    /**
46
     * @var string
47
     */
48
    protected const ID_SALES_ORDER = 'id_sales_order';
49
50
    /**
51
     * @var string
52
     */
53
    protected const COL_MAX_CREATED_AT = 'max_created_at';
54
55
    /**
56
     * @var string
57
     */
58
    protected const COL_FK_SALES_ORDER = 'fk_sales_order';
59
60
    /**
61
     * @var string
62
     */
63
    protected const ALIAS_LATEST_TOTALS = 'latest_totals';
64
65
    /**
66
     * @var array<string, string>
67
     */
68
    protected const SORT_KEYS_MAP = [
69
        'createdAt' => SpySalesOrderTableMap::COL_CREATED_AT,
70
        'updatedAt' => SpySalesOrderTableMap::COL_UPDATED_AT,
71
    ];
72
73
    /**
74
     * @param string $customerReference
75
     * @param string $orderReference
76
     *
77
     * @return int|null
78
     */
79
    public function findCustomerOrderIdByOrderReference(string $customerReference, string $orderReference): ?int
80
    {
81
        /** @var int|null $idSalesOrder */
82
        $idSalesOrder = $this->getFactory()
83
            ->createSalesOrderQuery()
84
            ->filterByCustomerReference($customerReference)
85
            ->filterByOrderReference($orderReference)
86
            ->select([static::ID_SALES_ORDER])
87
            ->findOne();
88
89
        return $idSalesOrder;
90
    }
91
92
    /**
93
     * @param int $idOrderAddress
94
     *
95
     * @return \Generated\Shared\Transfer\AddressTransfer|null
96
     */
97
    public function findOrderAddressByIdOrderAddress(int $idOrderAddress): ?AddressTransfer
98
    {
99
        $addressEntity = $this->getFactory()
100
            ->createSalesOrderAddressQuery()
101
            ->leftJoinWithCountry()
102
            ->filterByIdSalesOrderAddress($idOrderAddress)
103
            ->findOne();
104
105
        if ($addressEntity === null) {
106
            return null;
107
        }
108
109
        return $this->hydrateAddressTransferFromEntity($this->createOrderAddressTransfer(), $addressEntity);
110
    }
111
112
    /**
113
     * @module Oms
114
     *
115
     * @param \Generated\Shared\Transfer\OrderItemFilterTransfer $orderItemFilterTransfer
116
     *
117
     * @return array<\Generated\Shared\Transfer\ItemTransfer>
118
     */
119
    public function getOrderItems(OrderItemFilterTransfer $orderItemFilterTransfer): array
120
    {
121
        $salesOrderItemQuery = $this->getFactory()
122
            ->createSalesOrderItemQuery()
123
            ->innerJoinWithOrder()
124
            ->leftJoinWithProcess()
125
            ->leftJoinWithState();
126
127
        $salesOrderItemQuery = $this->setOrderItemFilters($salesOrderItemQuery, $orderItemFilterTransfer);
128
129
        $salesOrderItemQuery = $this->buildQueryFromCriteria(
130
            $salesOrderItemQuery,
131
            $orderItemFilterTransfer->getFilter(),
132
        );
133
134
        $salesOrderItemQuery->setFormatter(ModelCriteria::FORMAT_OBJECT);
135
136
        return $this->getFactory()
137
            ->createSalesOrderItemMapper()
138
            ->mapSalesOrderItemEntityCollectionToOrderItemTransfers($salesOrderItemQuery->find());
139
    }
140
141
    /**
142
     * @param array<int> $salesOrderIds
143
     *
144
     * @return array<string>
145
     */
146
    public function getCurrencyIsoCodesBySalesOrderIds(array $salesOrderIds): array
147
    {
148
        if (!$salesOrderIds) {
149
            return [];
150
        }
151
152
        /** @var \Propel\Runtime\Collection\ObjectCollection $currencyIsoCodes */
153
        $currencyIsoCodes = $this->getFactory()
154
            ->createSalesOrderQuery()
155
            ->filterByIdSalesOrder_In($salesOrderIds)
156
            ->select([static::ID_SALES_ORDER, SpySalesOrderTableMap::COL_CURRENCY_ISO_CODE])
157
            ->find();
158
159
        return $currencyIsoCodes->toKeyValue(static::ID_SALES_ORDER, SpySalesOrderTableMap::COL_CURRENCY_ISO_CODE);
160
    }
161
162
    /**
163
     * @param \Generated\Shared\Transfer\OrderListTransfer $orderListTransfer
164
     *
165
     * @return \Generated\Shared\Transfer\OrderListTransfer
166
     */
167
    public function searchOrders(OrderListTransfer $orderListTransfer): OrderListTransfer
168
    {
169
        $orderListTransfer
170
            ->requireFormat();
171
172
        $salesOrderQuery = $this->getFactory()
173
            ->createSalesOrderQuery()
174
            ->groupByIdSalesOrder()
175
            ->setIgnoreCase(true);
176
177
        $salesOrderQuery = $this->buildSearchOrdersQuery($salesOrderQuery, $orderListTransfer);
178
179
        if ($orderListTransfer->getPagination()) {
180
            $salesOrderQuery = $this->preparePagination($salesOrderQuery, $orderListTransfer->getPaginationOrFail());
181
        }
182
183
        $orderTransfers = $this->getFactory()
184
            ->createSalesOrderMapper()
185
            ->mapSalesOrderEntityCollectionToOrderTransfers($salesOrderQuery->find());
186
187
        return $orderListTransfer->setOrders(new ArrayObject($orderTransfers));
188
    }
189
190
    /**
191
     * @param array<int> $salesOrderIds
192
     *
193
     * @return array<\Generated\Shared\Transfer\ItemTransfer>
194
     */
195
    public function getSalesOrderItemsByOrderIds(array $salesOrderIds): array
196
    {
197
        $salesOrderItemQuery = $this->getFactory()
198
            ->createSalesOrderItemQuery()
199
            ->filterByFkSalesOrder_In($salesOrderIds);
200
201
        return $this->getFactory()
202
            ->createSalesOrderItemMapper()
203
            ->mapSalesOrderItemEntityCollectionToOrderItemTransfers($salesOrderItemQuery->find());
204
    }
205
206
    /**
207
     * @param array<int> $salesOrderIds
208
     *
209
     * @return array<\Generated\Shared\Transfer\TotalsTransfer>
210
     */
211
    public function getMappedSalesOrderTotalsBySalesOrderIds(array $salesOrderIds): array
212
    {
213
        $salesOrderTotalsSubQuerySql = $this->getLatestSalesOrderTotalsSubQuerySql($salesOrderIds);
214
        $salesOrderTotalsQuery = $this->getFactory()
215
            ->getSalesOrderTotalsPropelQuery()
216
            ->addAlias(static::ALIAS_LATEST_TOTALS, sprintf('(%s)', $salesOrderTotalsSubQuerySql))
217
            ->addJoin(
218
                [SpySalesOrderTotalsTableMap::COL_FK_SALES_ORDER, SpySalesOrderTotalsTableMap::COL_CREATED_AT],
219
                [sprintf('%s.%s', static::ALIAS_LATEST_TOTALS, static::COL_FK_SALES_ORDER), sprintf('%s.%s', static::ALIAS_LATEST_TOTALS, static::COL_MAX_CREATED_AT)],
220
                Criteria::INNER_JOIN,
221
            )
222
            ->filterByFkSalesOrder_In($salesOrderIds)
223
            ->groupByFkSalesOrder()
224
            ->orderByCreatedAt();
225
226
        return $this->getFactory()
227
            ->createSalesOrderMapper()
228
            ->mapSalesOrderTotalsEntityCollectionToMappedOrderTotalsByIdSalesOrder($salesOrderTotalsQuery->find());
229
    }
230
231
    /**
232
     * @param array<int> $salesOrderIds
233
     *
234
     * @return string
235
     */
236
    protected function getLatestSalesOrderTotalsSubQuerySql(array $salesOrderIds): string
237
    {
238
        $params = [];
239
        $salesOrderTotalsSubQuery = $this->getFactory()
240
            ->getSalesOrderTotalsPropelQuery()
241
            ->withColumn(sprintf('MAX(%s)', SpySalesOrderTotalsTableMap::COL_CREATED_AT), static::COL_MAX_CREATED_AT)
242
            ->select([static::COL_FK_SALES_ORDER, static::COL_MAX_CREATED_AT])
243
            ->filterByFkSalesOrder_In($salesOrderIds)
244
            ->groupByFkSalesOrder();
245
246
        return $salesOrderTotalsSubQuery->createSelectSql($params);
247
    }
248
249
    /**
250
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrderQuery $salesOrderQuery
251
     * @param \Generated\Shared\Transfer\OrderListTransfer $orderListTransfer
252
     *
253
     * @return \Orm\Zed\Sales\Persistence\SpySalesOrderQuery
254
     */
255
    protected function buildSearchOrdersQuery(
256
        SpySalesOrderQuery $salesOrderQuery,
257
        OrderListTransfer $orderListTransfer
258
    ): SpySalesOrderQuery {
259
        $salesOrderQuery = $this->getFactory()
260
            ->createOrderSearchFilterFieldQueryBuilder()
261
            ->addSalesOrderQueryFilters($salesOrderQuery, $orderListTransfer);
262
263
        $queryJoinCollectionTransfer = $orderListTransfer->getQueryJoins();
264
265
        if ($queryJoinCollectionTransfer && $queryJoinCollectionTransfer->getQueryJoins()->count()) {
266
            $salesOrderQuery = $this->getFactory()
267
                ->createOrderSearchQueryJoinQueryBuilder()
268
                ->addSalesOrderQueryFilters($salesOrderQuery, $queryJoinCollectionTransfer);
269
        }
270
271
        if ($this->isSearchByAllFilterFieldSet($orderListTransfer->getFilterFields())) {
272
            $salesOrderQuery->where([OrderSearchFilterFieldQueryBuilder::CONDITION_GROUP_ALL]);
273
        }
274
275
        return $salesOrderQuery;
276
    }
277
278
    /**
279
     * @param \Propel\Runtime\ActiveQuery\ModelCriteria $query
280
     * @param \Generated\Shared\Transfer\PaginationTransfer $paginationTransfer
281
     *
282
     * @return \Propel\Runtime\ActiveQuery\ModelCriteria
283
     */
284
    protected function preparePagination(
285
        ModelCriteria $query,
286
        PaginationTransfer $paginationTransfer
287
    ): ModelCriteria {
288
        $page = $paginationTransfer
289
            ->requirePage()
290
            ->getPage();
291
292
        $maxPerPage = $paginationTransfer
293
            ->requireMaxPerPage()
294
            ->getMaxPerPage();
295
296
        $propelModelPager = $query->paginate($page, $maxPerPage);
297
298
        $paginationTransfer->setNbResults($propelModelPager->getNbResults())
299
            ->setFirstIndex($propelModelPager->getFirstIndex())
300
            ->setLastIndex($propelModelPager->getLastIndex())
301
            ->setFirstPage($propelModelPager->getFirstPage())
302
            ->setLastPage($propelModelPager->getLastPage())
303
            ->setNextPage($propelModelPager->getNextPage())
304
            ->setPreviousPage($propelModelPager->getPreviousPage());
305
306
        return $propelModelPager->getQuery();
307
    }
308
309
    /**
310
     * @param \Generated\Shared\Transfer\AddressTransfer $addressTransfer
311
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrderAddress $addressEntity
312
     *
313
     * @return \Generated\Shared\Transfer\AddressTransfer
314
     */
315
    protected function hydrateAddressTransferFromEntity(
316
        AddressTransfer $addressTransfer,
317
        SpySalesOrderAddress $addressEntity
318
    ): AddressTransfer {
319
        $addressTransfer->fromArray($addressEntity->toArray(), true);
320
        $addressTransfer->setIso2Code($addressEntity->getCountry()->getIso2Code());
321
322
        return $addressTransfer;
323
    }
324
325
    /**
326
     * @return \Generated\Shared\Transfer\AddressTransfer
327
     */
328
    protected function createOrderAddressTransfer(): AddressTransfer
329
    {
330
        return new AddressTransfer();
331
    }
332
333
    /**
334
     * @param \Generated\Shared\Transfer\OrderListRequestTransfer $orderListRequestTransfer
335
     *
336
     * @return \Generated\Shared\Transfer\OrderListTransfer
337
     */
338
    public function getCustomerOrderListByCustomerReference(OrderListRequestTransfer $orderListRequestTransfer): OrderListTransfer
339
    {
340
        $orderListQuery = $this->getFactory()
341
            ->createSalesOrderQuery()
342
            ->filterByCustomerReference($orderListRequestTransfer->getCustomerReference());
343
344
        if ($orderListRequestTransfer->getOrderReferences()) {
345
            $orderListQuery->filterByOrderReference_In($orderListRequestTransfer->getOrderReferences());
346
        }
347
348
        $ordersCount = $orderListQuery->count();
349
        if (!$ordersCount) {
350
            return new OrderListTransfer();
351
        }
352
353
        $orderListQuery = $this->applyFilterToQuery($orderListQuery, $orderListRequestTransfer->getFilter());
354
355
        $orderListTransfer = $this->getFactory()
356
            ->createSalesOrderMapper()
357
            ->mapSalesOrderEntitiesToOrderListTransfer($orderListQuery->find()->getArrayCopy(), new OrderListTransfer());
358
359
        $orderListTransfer->setPagination((new PaginationTransfer())->setNbResults($ordersCount));
360
361
        return $orderListTransfer;
362
    }
363
364
    /**
365
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrderQuery $orderListQuery
366
     * @param \Generated\Shared\Transfer\FilterTransfer|null $filterTransfer
367
     *
368
     * @return \Orm\Zed\Sales\Persistence\SpySalesOrderQuery
369
     */
370
    protected function applyFilterToQuery(SpySalesOrderQuery $orderListQuery, ?FilterTransfer $filterTransfer): SpySalesOrderQuery
371
    {
372
        if ($filterTransfer) {
373
            if ($filterTransfer->getOrderBy() && isset(static::SORT_KEYS_MAP[$filterTransfer->getOrderBy()])) {
374
                $filterTransfer->setOrderBy(static::SORT_KEYS_MAP[$filterTransfer->getOrderBy()]);
375
            }
376
377
            $orderListQuery->mergeWith(
378
                (new PropelFilterCriteria($filterTransfer))->toCriteria(),
379
            );
380
        }
381
382
        return $orderListQuery;
383
    }
384
385
    /**
386
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrderItemQuery $salesOrderItemQuery
387
     * @param \Generated\Shared\Transfer\OrderItemFilterTransfer $orderItemFilterTransfer
388
     *
389
     * @return \Orm\Zed\Sales\Persistence\SpySalesOrderItemQuery
390
     */
391
    protected function setOrderItemFilters(
392
        SpySalesOrderItemQuery $salesOrderItemQuery,
393
        OrderItemFilterTransfer $orderItemFilterTransfer
394
    ): SpySalesOrderItemQuery {
395
        if ($orderItemFilterTransfer->getSalesOrderItemIds()) {
396
            $salesOrderItemQuery->filterByIdSalesOrderItem_In(array_unique($orderItemFilterTransfer->getSalesOrderItemIds()));
397
        }
398
399
        if ($orderItemFilterTransfer->getSalesOrderItemUuids()) {
400
            $salesOrderItemQuery->filterByUuid_In(array_unique($orderItemFilterTransfer->getSalesOrderItemUuids()));
401
        }
402
403
        if ($orderItemFilterTransfer->getSalesOrderIds()) {
404
            $salesOrderItemQuery->filterByFkSalesOrder_In(array_unique($orderItemFilterTransfer->getSalesOrderIds()));
405
        }
406
407
        if ($orderItemFilterTransfer->getCustomerReferences()) {
408
            $salesOrderItemQuery
409
                ->useOrderQuery()
410
                    ->filterByCustomerReference_In(array_unique($orderItemFilterTransfer->getCustomerReferences()))
411
                ->endUse();
412
        }
413
414
        if ($orderItemFilterTransfer->getOrderReferences()) {
415
            $salesOrderItemQuery
416
                ->useOrderQuery()
417
                    ->filterByOrderReference_In(array_unique($orderItemFilterTransfer->getOrderReferences()))
418
                ->endUse();
419
        }
420
421
        if ($orderItemFilterTransfer->getItemStates()) {
422
            $salesOrderItemQuery
423
                ->useStateQuery()
424
                    ->filterByName_In(array_unique($orderItemFilterTransfer->getItemStates()))
425
                ->endUse();
426
        }
427
428
        return $salesOrderItemQuery;
429
    }
430
431
    /**
432
     * @param \ArrayObject<int, \Generated\Shared\Transfer\FilterFieldTransfer> $filterFieldTransfers
433
     *
434
     * @return bool
435
     */
436
    protected function isSearchByAllFilterFieldSet(ArrayObject $filterFieldTransfers): bool
437
    {
438
        foreach ($filterFieldTransfers as $filterFieldTransfer) {
439
            if ($filterFieldTransfer->getType() === OrderSearchFilterFieldQueryBuilder::SEARCH_TYPE_ALL) {
440
                return true;
441
            }
442
        }
443
444
        return false;
445
    }
446
447
    /**
448
     * @param \Generated\Shared\Transfer\OrderFilterTransfer $orderFilterTransfer
449
     *
450
     * @return \Generated\Shared\Transfer\OrderTransfer
451
     */
452
    public function getSalesOrderDetails(OrderFilterTransfer $orderFilterTransfer): OrderTransfer
453
    {
454
        $orderEntity = $this->getSalesOrderEntity($orderFilterTransfer);
455
456
        return $this->createOrderTransfer($orderEntity);
457
    }
458
459
    /**
460
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
461
     *
462
     * @return int
463
     */
464
    public function getTotalCustomerOrderCount(OrderTransfer $orderTransfer): int
465
    {
466
        $customerReference = $orderTransfer->getCustomerReference();
467
468
        if ($customerReference === null) {
469
            return 0;
470
        }
471
472
        return $this->getFactory()
473
            ->createSalesOrderQuery()
474
            ->filterByCustomerReference($customerReference)
475
            ->count();
476
    }
477
478
    /**
479
     * @param int $idSalesOrder
480
     *
481
     * @return int
482
     */
483
    public function countUniqueProductsForOrder(int $idSalesOrder): int
484
    {
485
        return (int)$this->getFactory()
486
            ->createSalesOrderItemQuery()
487
            ->filterByFkSalesOrder($idSalesOrder)
488
            ->withColumn('COUNT(*)', 'Count')
489
            ->select(['Count'])
490
            ->groupBySku()
491
            ->orderBy('Count')
492
            ->count();
493
    }
494
495
    /**
496
     * @param \Generated\Shared\Transfer\OrderCriteriaTransfer $orderCriteriaTransfer
497
     *
498
     * @return \Generated\Shared\Transfer\OrderCollectionTransfer
499
     */
500
    public function getOrderCollection(OrderCriteriaTransfer $orderCriteriaTransfer): OrderCollectionTransfer
501
    {
502
        $orderCollectionTransfer = new OrderCollectionTransfer();
503
504
        $salesOrderQuery = $this->getFactory()
505
            ->createSalesOrderQuery()
506
            ->leftJoinWith('SpySalesOrder.BillingAddress billingAddress')
507
            ->leftJoinWith('billingAddress.Country billingCountry')
508
            ->leftJoinWith('SpySalesOrder.ShippingAddress shippingAddress')
509
            ->leftJoinWith('shippingAddress.Country shippingCountry');
510
        $salesOrderQuery = $this->applySalesOrderFilters($salesOrderQuery, $orderCriteriaTransfer);
511
512
        /** @var \ArrayObject<array-key, \Generated\Shared\Transfer\SortTransfer> $sortTransfers */
513
        $sortTransfers = $orderCriteriaTransfer->getSortCollection();
514
        $salesOrderQuery = $this->applySorting($salesOrderQuery, $sortTransfers);
515
516
        $paginationTransfer = $orderCriteriaTransfer->getPagination();
517
        if ($paginationTransfer) {
518
            $salesOrderQuery = $this->applyPagination($salesOrderQuery, $paginationTransfer);
519
            $orderCollectionTransfer->setPagination($paginationTransfer);
520
        }
521
522
        $salesOrderEntitiesIndexedByIdSalesOrder = $salesOrderQuery->find()
523
            ->getArrayCopy('IdSalesOrder');
524
        $salesOrderEntitiesIndexedByIdSalesOrder = $this->expandSalesOrdersWithSalesOrderItems(
525
            $salesOrderEntitiesIndexedByIdSalesOrder,
526
        );
527
        $salesOrderEntitiesIndexedByIdSalesOrder = $this->expandSalesOrdersWithSalesExpenses(
528
            $salesOrderEntitiesIndexedByIdSalesOrder,
529
        );
530
531
        foreach ($salesOrderEntitiesIndexedByIdSalesOrder as $salesOrderEntity) {
532
            $orderCollectionTransfer->addOrder($this->createOrderTransfer($salesOrderEntity));
533
        }
534
535
        return $orderCollectionTransfer;
536
    }
537
538
    /**
539
     * @param \Generated\Shared\Transfer\OrderFilterTransfer $orderFilterTransfer
540
     *
541
     * @return \Generated\Shared\Transfer\OrderTransfer|null
542
     */
543
    public function findOrderWithoutItems(OrderFilterTransfer $orderFilterTransfer): ?OrderTransfer
544
    {
545
        $orderFilterTransfer->requireSalesOrderId();
546
547
        $salesOrderEntity = $this->getFactory()
548
            ->createSalesOrderQuery()
549
            ->filterByIdSalesOrder($orderFilterTransfer->getSalesOrderId())
550
            ->findOne();
551
552
        if ($salesOrderEntity === null) {
553
            return null;
554
        }
555
556
        return $this->getFactory()
557
            ->createSalesOrderMapper()
558
            ->mapSalesOrderEntityToSalesOrderTransfer($salesOrderEntity, new OrderTransfer());
559
    }
560
561
    /**
562
     * @param \Generated\Shared\Transfer\SalesExpenseCollectionDeleteCriteriaTransfer $salesExpenseCollectionDeleteCriteriaTransfer
563
     *
564
     * @return list<\Generated\Shared\Transfer\ExpenseTransfer>
565
     */
566
    public function getSalesExpensesBySalesExpenseCollectionDeleteCriteria(
567
        SalesExpenseCollectionDeleteCriteriaTransfer $salesExpenseCollectionDeleteCriteriaTransfer
568
    ): array {
569
        $salesExpenseQuery = $this->getFactory()->createSalesExpenseQuery();
570
        $salesExpenseQuery = $this->appySalesExpenseCollectionDeleteCriteriaFilters(
571
            $salesExpenseQuery,
572
            $salesExpenseCollectionDeleteCriteriaTransfer,
573
        );
574
575
        $salesExpenseEntities = $salesExpenseQuery->find();
576
577
        if ($salesExpenseEntities->count() === 0) {
578
            return [];
579
        }
580
581
        return $this->getFactory()
582
            ->createSalesExpenseMapper()
583
            ->mapSalesExpenseEntitiesToExpenseTransfers($salesExpenseEntities, []);
584
    }
585
586
    /**
587
     * @return list<string>
588
     */
589
    public function getOmsOrderItemStates(): array
590
    {
591
        return $this->getFactory()
592
            ->getOmsOrderItemStatePropelQuery()
593
            ->select([SpyOmsOrderItemStateTableMap::COL_NAME])
594
            ->orderBy(SpyOmsOrderItemStateTableMap::COL_ID_OMS_ORDER_ITEM_STATE)
595
            ->find()
596
            ->getData();
597
    }
598
599
    /**
600
     * @param \Generated\Shared\Transfer\OrderFilterTransfer $orderFilterTransfer
601
     *
602
     * @throws \Spryker\Zed\Sales\Business\Exception\InvalidSalesOrderException
603
     *
604
     * @return \Orm\Zed\Sales\Persistence\SpySalesOrder
605
     */
606
    protected function getSalesOrderEntity(OrderFilterTransfer $orderFilterTransfer): SpySalesOrder
607
    {
608
        $salesOrderQuery = $this->getFactory()->createSalesOrderQuery()
609
            ->setModelAlias('order')
610
            ->innerJoinWith('order.BillingAddress billingAddress')
611
            ->innerJoinWith('billingAddress.Country billingCountry')
612
            ->leftJoinWith('order.ShippingAddress shippingAddress')
613
            ->leftJoinWith('shippingAddress.Country shippingCountry');
614
        $salesOrderQuery = $this->setOrderFilters($salesOrderQuery, $orderFilterTransfer);
615
        $salesOrderQuery = $this->buildQueryFromCriteria(
616
            $salesOrderQuery,
617
            $orderFilterTransfer->getFilter(),
618
        );
619
        $salesOrderQuery->setFormatter(ModelCriteria::FORMAT_OBJECT);
620
        $orderEntity = $salesOrderQuery->findOne();
621
622
        if ($orderEntity === null) {
623
            throw new InvalidSalesOrderException(
624
                sprintf(
625
                    'Order could not be found for ID %s',
626
                    $orderFilterTransfer->getSalesOrderId(),
627
                ),
628
            );
629
        }
630
631
        return $orderEntity;
632
    }
633
634
    /**
635
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrder $salesOrderEntity
636
     *
637
     * @return \Generated\Shared\Transfer\OrderTransfer
638
     */
639
    protected function createOrderTransfer(SpySalesOrder $salesOrderEntity): OrderTransfer
640
    {
641
        $orderTransfer = $this->getFactory()
642
            ->createSalesOrderMapper()
643
            ->mapSalesOrderEntityToSalesOrderTransfer($salesOrderEntity, new OrderTransfer());
644
        $orderTransfer = $this->setOrderTotals($salesOrderEntity, $orderTransfer);
645
        $orderTransfer = $this->setBillingAddress($salesOrderEntity, $orderTransfer);
646
        $orderTransfer = $this->setShippingAddress($salesOrderEntity, $orderTransfer);
647
        $orderTransfer = $this->setOrderExpenses($salesOrderEntity, $orderTransfer);
648
        $orderTransfer = $this->setMissingCustomer($salesOrderEntity, $orderTransfer);
649
650
        return $orderTransfer;
651
    }
652
653
    /**
654
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrderQuery $salesOrderQuery
655
     * @param \Generated\Shared\Transfer\OrderFilterTransfer $orderFilterTransfer
656
     *
657
     * @return \Orm\Zed\Sales\Persistence\SpySalesOrderQuery
658
     */
659
    protected function setOrderFilters(SpySalesOrderQuery $salesOrderQuery, OrderFilterTransfer $orderFilterTransfer): SpySalesOrderQuery
660
    {
661
        if ($orderFilterTransfer->getSalesOrderId()) {
662
            $salesOrderQuery->filterByIdSalesOrder($orderFilterTransfer->getSalesOrderId());
663
        }
664
        if ($orderFilterTransfer->getCustomerReference()) {
665
            $salesOrderQuery->filterByCustomerReference($orderFilterTransfer->getCustomerReference());
666
        }
667
        if ($orderFilterTransfer->getOrderReference()) {
668
            $salesOrderQuery->filterByOrderReference($orderFilterTransfer->getOrderReference());
669
        }
670
671
        return $salesOrderQuery;
672
    }
673
674
    /**
675
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrder $orderEntity
676
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
677
     *
678
     * @return \Generated\Shared\Transfer\OrderTransfer
679
     */
680
    protected function setOrderTotals(SpySalesOrder $orderEntity, OrderTransfer $orderTransfer): OrderTransfer
681
    {
682
        $salesOrderTotalsEntity = $orderEntity->getLastOrderTotals();
683
684
        if (!$salesOrderTotalsEntity) {
685
            return $orderTransfer;
686
        }
687
688
        $totalsTransfer = $this->getFactory()
689
            ->createSalesOrderTotalsMapper()
690
            ->mapSalesOrderTotalsTransfer($salesOrderTotalsEntity, new TotalsTransfer(), new TaxTotalTransfer());
691
692
        $orderTransfer->setTotals($totalsTransfer);
693
694
        return $orderTransfer;
695
    }
696
697
    /**
698
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrder $orderEntity
699
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
700
     *
701
     * @return \Generated\Shared\Transfer\OrderTransfer
702
     */
703
    protected function setBillingAddress(SpySalesOrder $orderEntity, OrderTransfer $orderTransfer): OrderTransfer
704
    {
705
        $billingAddressTransfer = $this->getFactory()
706
            ->createSalesOrderAddressMapper()
707
            ->mapAddressEntityToAddressTransfer(new AddressTransfer(), $orderEntity->getBillingAddress());
708
709
        $orderTransfer->setBillingAddress($billingAddressTransfer);
710
711
        return $orderTransfer;
712
    }
713
714
    /**
715
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrder $orderEntity
716
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
717
     *
718
     * @return \Generated\Shared\Transfer\OrderTransfer
719
     */
720
    protected function setShippingAddress(SpySalesOrder $orderEntity, OrderTransfer $orderTransfer): OrderTransfer
721
    {
722
        $orderShippingAddressEntity = $orderEntity->getShippingAddress();
723
724
        if ($orderShippingAddressEntity === null) {
725
            return $orderTransfer;
726
        }
727
728
        $shippingAddressTransfer = $this->getFactory()
729
            ->createSalesOrderAddressMapper()
730
            ->mapAddressEntityToAddressTransfer(new AddressTransfer(), $orderShippingAddressEntity);
731
732
        $orderTransfer->setShippingAddress($shippingAddressTransfer);
733
734
        return $orderTransfer;
735
    }
736
737
    /**
738
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrder $orderEntity
739
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
740
     *
741
     * @return \Generated\Shared\Transfer\OrderTransfer
742
     */
743
    protected function setOrderExpenses(SpySalesOrder $orderEntity, OrderTransfer $orderTransfer): OrderTransfer
744
    {
745
        foreach ($orderEntity->getExpenses(new Criteria()) as $expenseEntity) {
746
            $expenseTransfer = $this->getFactory()
747
                ->createSalesExpenseMapper()
748
                ->mapExpenseEntityToSalesExpenseTransfer(new ExpenseTransfer(), $expenseEntity);
749
750
            $orderTransfer->addExpense($expenseTransfer);
751
        }
752
753
        return $orderTransfer;
754
    }
755
756
    /**
757
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrder $orderEntity
758
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
759
     *
760
     * @return \Generated\Shared\Transfer\OrderTransfer
761
     */
762
    protected function setMissingCustomer(SpySalesOrder $orderEntity, OrderTransfer $orderTransfer): OrderTransfer
763
    {
764
        if (!$orderEntity->getCustomer()) {
765
            $orderTransfer->setCustomerReference(null);
766
            $orderTransfer->setFkCustomer(null);
767
        }
768
769
        return $orderTransfer;
770
    }
771
772
    /**
773
     * @param \Orm\Zed\Sales\Persistence\SpySalesOrderQuery $salesOrderQuery
774
     * @param \Generated\Shared\Transfer\OrderCriteriaTransfer $orderCriteriaTransfer
775
     *
776
     * @return \Orm\Zed\Sales\Persistence\SpySalesOrderQuery
777
     */
778
    protected function applySalesOrderFilters(
779
        SpySalesOrderQuery $salesOrderQuery,
780
        OrderCriteriaTransfer $orderCriteriaTransfer
781
    ): SpySalesOrderQuery {
782
        $orderConditionsTransfer = $orderCriteriaTransfer->getOrderConditions();
783
        if ($orderConditionsTransfer === null) {
784
            return $salesOrderQuery;
785
        }
786
787
        if ($orderConditionsTransfer->getSalesOrderIds() !== []) {
788
            $salesOrderQuery->filterByIdSalesOrder_In($orderConditionsTransfer->getSalesOrderIds());
789
        }
790
791
        if ($orderConditionsTransfer->getOrderReferences() !== []) {
792
            $salesOrderQuery->filterByOrderReference_In($orderConditionsTransfer->getOrderReferences());
793
        }
794
795
        if ($orderConditionsTransfer->getCustomerReferences() !== []) {
796
            $salesOrderQuery->filterByCustomerReference_In($orderConditionsTransfer->getCustomerReferences());
797
        }
798
799
        return $salesOrderQuery;
800
    }
801
802
    /**
803
     * @param \Propel\Runtime\ActiveQuery\ModelCriteria $modelCriteria
804
     * @param \ArrayObject<array-key, \Generated\Shared\Transfer\SortTransfer> $sortTransfers
805
     *
806
     * @return \Propel\Runtime\ActiveQuery\ModelCriteria
807
     */
808
    protected function applySorting(
809
        ModelCriteria $modelCriteria,
810
        ArrayObject $sortTransfers
811
    ): ModelCriteria {
812
        foreach ($sortTransfers as $sortTransfer) {
813
            $modelCriteria->orderBy(
814
                $sortTransfer->getFieldOrFail(),
815
                $sortTransfer->getIsAscending() ? Criteria::ASC : Criteria::DESC,
816
            );
817
        }
818
819
        return $modelCriteria;
820
    }
821
822
    /**
823
     * @param \Propel\Runtime\ActiveQuery\ModelCriteria $modelCriteria
824
     * @param \Generated\Shared\Transfer\PaginationTransfer $paginationTransfer
825
     *
826
     * @return \Propel\Runtime\ActiveQuery\ModelCriteria
827
     */
828
    protected function applyPagination(
829
        ModelCriteria $modelCriteria,
830
        PaginationTransfer $paginationTransfer
831
    ): ModelCriteria {
832
        if ($paginationTransfer->getOffset() !== null && $paginationTransfer->getLimit() !== null) {
833
            $paginationTransfer->setNbResults($modelCriteria->count());
834
835
            return $modelCriteria
836
                ->offset($paginationTransfer->getOffsetOrFail())
837
                ->setLimit($paginationTransfer->getLimitOrFail());
838
        }
839
840
        if ($paginationTransfer->getPage() !== null && $paginationTransfer->getMaxPerPage()) {
841
            $propelModelPager = $modelCriteria->paginate(
842
                $paginationTransfer->getPageOrFail(),
843
                $paginationTransfer->getMaxPerPageOrFail(),
844
            );
845
846
            $paginationTransfer->setNbResults($propelModelPager->getNbResults())
847
                ->setFirstIndex($propelModelPager->getFirstIndex())
848
                ->setLastIndex($propelModelPager->getLastIndex())
849
                ->setFirstPage($propelModelPager->getFirstPage())
850
                ->setLastPage($propelModelPager->getLastPage())
851
                ->setNextPage($propelModelPager->getNextPage())
852
                ->setPreviousPage($propelModelPager->getPreviousPage());
853
854
            return $propelModelPager->getQuery();
855
        }
856
857
        return $modelCriteria;
858
    }
859
860
    /**
861
     * @param array<int, \Orm\Zed\Sales\Persistence\SpySalesOrder> $salesOrderEntitiesIndexedByIdSalesOrder
862
     *
863
     * @return array<int, \Orm\Zed\Sales\Persistence\SpySalesOrder>
864
     */
865
    protected function expandSalesOrdersWithSalesOrderItems(array $salesOrderEntitiesIndexedByIdSalesOrder): array
866
    {
867
        $salesOrderItemEntities = $this->getFactory()
868
            ->createSalesOrderItemQuery()
869
            ->filterByFkSalesOrder_In(array_keys($salesOrderEntitiesIndexedByIdSalesOrder))
870
            ->find();
871
872
        foreach ($salesOrderItemEntities as $salesOrderItemEntity) {
873
            $idSalesOrder = $salesOrderItemEntity->getFkSalesOrder();
874
            if (!isset($salesOrderEntitiesIndexedByIdSalesOrder[$idSalesOrder])) {
875
                continue;
876
            }
877
878
            $salesOrderEntitiesIndexedByIdSalesOrder[$idSalesOrder]->addItem($salesOrderItemEntity);
879
        }
880
881
        return $salesOrderEntitiesIndexedByIdSalesOrder;
882
    }
883
884
    /**
885
     * @param array<int, \Orm\Zed\Sales\Persistence\SpySalesOrder> $salesOrderEntitiesIndexedByIdSalesOrder
886
     *
887
     * @return array<int, \Orm\Zed\Sales\Persistence\SpySalesOrder>
888
     */
889
    protected function expandSalesOrdersWithSalesExpenses(array $salesOrderEntitiesIndexedByIdSalesOrder): array
890
    {
891
        $salesExpenseEntities = $this->getFactory()
892
            ->createSalesExpenseQuery()
893
            ->filterByFkSalesOrder_In(array_keys($salesOrderEntitiesIndexedByIdSalesOrder))
894
            ->find();
895
896
        foreach ($salesExpenseEntities as $salesExpenseEntity) {
897
            $idSalesOrder = $salesExpenseEntity->getFkSalesOrder();
898
            if (!isset($salesOrderEntitiesIndexedByIdSalesOrder[$idSalesOrder])) {
899
                continue;
900
            }
901
902
            $salesOrderEntitiesIndexedByIdSalesOrder[$idSalesOrder]->addExpense($salesExpenseEntity);
903
        }
904
905
        return $salesOrderEntitiesIndexedByIdSalesOrder;
906
    }
907
908
    /**
909
     * @param \Orm\Zed\Sales\Persistence\SpySalesExpenseQuery $salesExpenseQuery
910
     * @param \Generated\Shared\Transfer\SalesExpenseCollectionDeleteCriteriaTransfer $salesExpenseCollectionDeleteCriteriaTransfer
911
     *
912
     * @return \Orm\Zed\Sales\Persistence\SpySalesExpenseQuery
913
     */
914
    protected function appySalesExpenseCollectionDeleteCriteriaFilters(
915
        SpySalesExpenseQuery $salesExpenseQuery,
916
        SalesExpenseCollectionDeleteCriteriaTransfer $salesExpenseCollectionDeleteCriteriaTransfer
917
    ): SpySalesExpenseQuery {
918
        if ($salesExpenseCollectionDeleteCriteriaTransfer->getSalesOrderIds()) {
919
            $salesExpenseQuery->filterByFkSalesOrder_In($salesExpenseCollectionDeleteCriteriaTransfer->getSalesOrderIds());
920
        }
921
922
        if ($salesExpenseCollectionDeleteCriteriaTransfer->getTypes()) {
923
            $salesExpenseQuery->filterByType_In($salesExpenseCollectionDeleteCriteriaTransfer->getTypes());
924
        }
925
926
        return $salesExpenseQuery;
927
    }
928
}
929