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