Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.89% covered (warning)
88.89%
40 / 45
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProductsItemsHandler
88.89% covered (warning)
88.89%
40 / 45
50.00% covered (danger)
50.00%
2 / 4
9.11
0.00% covered (danger)
0.00%
0 / 1
 setNext
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 handle
78.95% covered (warning)
78.95%
15 / 19
0.00% covered (danger)
0.00%
0 / 1
4.15
 deleteItemsUnlisted
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
1
 processMovementDate
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace Domain\Item\Services;
4
5use App\Models\Item\Item;
6use App\Models\User;
7use Domain\Item\DTOs\ItemDTO;
8use Domain\Item\DTOs\ItemsDTO;
9use Domain\Item\Enums\ItemSyncEnum;
10use Domain\Item\Interfaces\HasItemsInterface;
11use Domain\Item\Interfaces\ItemsHandlerInterface;
12use Domain\Shared\Integrations\Senior\Exceptions\IntegrationSoapSeniorException;
13use Illuminate\Database\Eloquent\Builder;
14use Illuminate\Support\Facades\DB;
15use Throwable;
16use function array_diff;
17use function array_map;
18
19/**
20 * Class ProductsItemsHandler
21 *
22 * This class implements the ItemsHandlerInterface and is responsible for handling products items.
23 */
24class ProductsItemsHandler implements ItemsHandlerInterface
25{
26    private ?ItemsHandlerInterface $nextHandler = null;
27
28    /**
29     * @param ItemsHandlerInterface $handler
30     * @return ItemsHandlerInterface
31     */
32    public function setNext(ItemsHandlerInterface $handler): ItemsHandlerInterface
33    {
34        $this->nextHandler = $handler;
35        return $handler;
36    }
37
38    /**
39     * @param ItemsDTO $itemsDTO
40     * @param HasItemsInterface $hasItems
41     * @param User $user
42     * @return void
43     * @throws Throwable
44     */
45    public function handle(ItemsDTO $itemsDTO, HasItemsInterface $hasItems, User $user): void
46    {
47        try {
48            DB::beginTransaction();
49
50            $this->deleteItemsUnlisted($itemsDTO, $hasItems, $user);
51
52            /** @var ItemDTO $productItemDTO */
53            foreach ($itemsDTO->products as $productItemDTO) {
54                /** @var Item|null $item */
55                $item = $hasItems->items()
56                    ->where('product_id', $productItemDTO->target->getKey())
57                    ->whereHas('integration', function (Builder $query) use ($productItemDTO) {
58                        $query->where('parameters->production_order', $productItemDTO->itemIntegrationDTO->productionOrder);
59                        $query->where('parameters->movement_date', $productItemDTO->itemIntegrationDTO->movementDate);
60                    })
61                    ->first();
62
63                if ($item) {
64                    (new ItemUpdateService())->update($productItemDTO, $item, $user);
65                } else {
66                    $item = (new ItemStoreService())->store($productItemDTO, $hasItems, $user);
67                }
68
69                $this->processMovementDate($item, $productItemDTO, $user);
70            }
71
72            $this->nextHandler?->handle($itemsDTO, $hasItems, $user);
73
74            DB::commit();
75        } catch (Throwable $throwable) {
76            DB::rollBack();
77            throw $throwable;
78        }
79    }
80
81    /**
82     * @param ItemsDTO $itemsDTO
83     * @param HasItemsInterface $hasItems
84     * @param User $user
85     * @return void
86     * @throws Throwable
87     */
88    private function deleteItemsUnlisted(ItemsDTO $itemsDTO, HasItemsInterface $hasItems, User $user): void
89    {
90        $itemsFiltered = collect(array_map(function (ItemDTO $itemDTO) {
91            return [
92                'targets' => $itemDTO->target->getKey(),
93                'production_order' => $itemDTO->itemIntegrationDTO->productionOrder,
94                'movement_date' => $itemDTO->itemIntegrationDTO->movementDate,
95            ];
96        }, $itemsDTO->products));
97
98        $missingProductIDs = array_diff(
99            $hasItems->items()->pluck('product_id')->toArray(),
100            $itemsFiltered->pluck('targets')->unique()->toArray()
101        );
102
103        $itemsToDelete = $hasItems->items()
104            ->whereHas('integration', function (Builder $query) use ($itemsFiltered) {
105                $query->whereIn('parameters->production_order', $itemsFiltered->pluck('production_order')->unique()->toArray());
106                $query->whereIn('parameters->movement_date', $itemsFiltered->pluck('movement_date')->unique()->toArray());
107            })
108            ->whereIn('product_id', $missingProductIDs)
109            ->get();
110
111        $itemsToDelete->each(function (Item $item) use ($user) {
112            (new ItemDeleteService())->delete($item, $user);
113        });
114    }
115
116    /**
117     * @param Item $item
118     * @param mixed $productItemDTO
119     * @param User $user
120     * @return void
121     * @throws Throwable
122     * @throws IntegrationSoapSeniorException
123     */
124    private function processMovementDate(Item $item, mixed $productItemDTO, User $user): void
125    {
126        $itemIntegration = $item->integration;
127        if (!isset($itemIntegration->getAttribute('parameters')['movement_date']) || $itemIntegration->getAttribute('sync') == ItemSyncEnum::SYNC_FAIL) {
128            (new ItemPopulateMovementDateService())->get($item, $productItemDTO->itemIntegrationDTO->productionOrder, $user);
129        }
130    }
131}