Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
51.95% covered (warning)
51.95%
40 / 77
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ItemTransferService
51.95% covered (warning)
51.95%
40 / 77
20.00% covered (danger)
20.00%
1 / 5
27.98
0.00% covered (danger)
0.00%
0 / 1
 transferItem
55.88% covered (warning)
55.88%
19 / 34
0.00% covered (danger)
0.00%
0 / 1
9.09
 populateItemToTransferDTO
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 generatePickingOrder
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
2
 processPickingProductStatus
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
2.15
 storePickedItemTaskProgress
80.00% covered (warning)
80.00%
12 / 15
0.00% covered (danger)
0.00%
0 / 1
2.03
1<?php
2
3namespace Domain\Item\Services;
4
5use Exception;
6use Throwable;
7
8use Illuminate\Support\Facades\DB;
9
10use App\Models\Item\Item;
11use App\Models\PickedItem;
12use App\Models\PickingOrder\PickingOrder;
13use App\Models\PickingOrder\PickingOrderProduct;
14use App\Models\User;
15use App\Models\Transferable\Transferable;
16use App\Models\StockIO\StockIO;
17use App\Models\StockIO\StockIOProduct;
18
19use Domain\PickingOrder\DTOs\PickingOrderDTO;
20use Domain\PickingOrder\Enums\PickingOrderStatusEnum;
21use Domain\PickingOrder\Enums\PickingOrderTypeEnum;
22use Domain\PickingOrder\Services\V2\PickingOrderStoreService;
23use Domain\Transferable\Services\TransferableTransferItemService;
24use Domain\Transferable\DTOs\TransferItemDTO;
25use Domain\Transaction\Enums\TransactionTypeEnum;
26use Domain\StockIO\Exceptions\StockIOException;
27use Domain\Shared\Enums\SectorEnum;
28use Domain\Transaction\Enums\TransactionTransferReasonEnum;
29
30readonly class ItemTransferService
31{
32    /**
33     * @param Item $item
34     * @param Transferable $from ,
35     * @param Transferable $to ,
36     * @param float $amount
37     * @param PickingOrderProduct|null $pickingOrderProduct
38     * @param User $user
39     * @return void
40     * @throws Throwable
41     */
42    public function transferItem(
43        Item $item,
44        Transferable $from,
45        Transferable $to,
46        float $amount,
47        PickingOrderProduct|null $pickingOrderProduct,
48        User $user
49    ): void {
50        try {
51            DB::beginTransaction();
52
53            $stockIO = $item->itemable;
54
55            if (!$stockIO instanceof StockIO ) {
56                throw new StockIOException(
57                    __('The sender is not a StockIO.')
58                );
59            }
60
61            if (is_null($pickingOrderProduct)) {
62                $pickingOrder = $this->generatePickingOrder(
63                    $stockIO,
64                    $item,
65                    $user,
66                    $amount
67                );
68
69                $pickingOrderProducts = $pickingOrder->pickingOrderProduct;
70            }
71
72            $itemToTransferDTO = $this->populateItemToTransferDTO($item, $amount);
73
74            $transferredItem = (new TransferableTransferItemService)->transferOne(
75                $itemToTransferDTO,
76                $from->transferable,
77                $to->transferable,
78                TransactionTypeEnum::STORE,
79                TransactionTransferReasonEnum::REALLOCATION->value,
80                $user,
81                null,
82                SectorEnum::WAREHOUSE->value
83            );
84
85            if ($pickingOrderProduct) {
86                $this->storePickedItemTaskProgress($pickingOrderProduct, $transferredItem, $amount);
87                $this->processPickingProductStatus($pickingOrderProduct);
88            } else {
89                foreach ($pickingOrderProducts as $pickingProduct) {
90                    $this->processPickingProductStatus($pickingProduct);
91                }
92            }
93
94            DB::commit();
95        } catch (Throwable $throwable) {
96            DB::rollBack();
97            throw $throwable;
98        }
99    }
100
101    /**
102     * @param Item $itemToTransfer
103     * @param float $amount
104     * @param array $readingLogDTOs
105     * @return TransferItemDTO
106     */
107    private function populateItemToTransferDTO(
108        Item $itemToTransfer,
109        float $amount,
110        array $readingLogDTOs = []
111    ): TransferItemDTO {
112
113        return new TransferItemDTO([
114            'item'         => $itemToTransfer,
115            'amount'       => $amount,
116            'reading_logs' => $readingLogDTOs,
117        ]);
118
119    }
120
121    /**
122     * @param StockIO $stockIO
123     * @param Item $item
124     * @param User $user
125     * @param float $amount
126     * @return PickingOrder
127     * @throws Exception|Throwable
128     */
129    private function generatePickingOrder(StockIO $stockIO, Item $item, User $user, float $amount): PickingOrder
130    {
131        $stockIOProduct = StockIOProduct::query()
132            ->where('stock_io_id', $stockIO->getKey())
133            ->where('product_id', $item->product->getKey())
134            ->first();
135
136        $product = [];
137        array_push($product, [
138                'id'     => $stockIOProduct->getKey(),
139                'type'   => PickingOrderTypeEnum::INDIVIDUAL,
140                'amount' => $amount
141        ]);
142
143        $pickingOrderDto = new PickingOrderDTO([
144            'responsible'       => $user,
145            'urgent'            => false,
146            'type'              => PickingOrderTypeEnum::INDIVIDUAL,
147            'stock_io_products' => $product
148        ]);
149
150        return (new PickingOrderStoreService())->store($pickingOrderDto, $user);
151    }
152
153    private function processPickingProductStatus(PickingOrderProduct $pickingProduct)
154    {
155        $sumPickedItems = $pickingProduct
156            ->pickedItems()
157            ->sum('picked_items.amount');
158
159        if ($sumPickedItems == $pickingProduct->getAttribute('amount')) {
160            $pickingProduct->setAttribute('status', PickingOrderStatusEnum::CONCLUDED);
161            $pickingProduct->save();
162        }
163    }
164
165    private function storePickedItemTaskProgress(
166        PickingOrderProduct $pickingOrderProduct,
167        Item $item,
168        float $amount
169    ): void {
170        $pickedItem = PickedItem::query()
171            ->where('stock_io_product_id', $pickingOrderProduct->getAttribute('stock_io_product_id'))
172            ->where('item_id', $item->getKey())
173            ->where('picking_order_product_id', $pickingOrderProduct->getKey())
174            ->first();
175
176        if ($pickedItem) {
177            $pickedItem->setAttribute('amount', round((float) $pickedItem->getAttribute('amount') + $amount, 2));
178            $pickedItem->save();
179
180            return;
181        }
182
183        $pickedItem = new PickedItem();
184        $pickedItem->setAttribute('amount', $amount);
185        $pickedItem->item()->associate($item);
186        $pickedItem->stockIOProduct()->associate($pickingOrderProduct->stockIOProduct);
187        $pickedItem->pickingOrderProduct()->associate($pickingOrderProduct);
188        $pickedItem->save();
189    }
190}