Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
65.96% covered (warning)
65.96%
31 / 47
14.29% covered (danger)
14.29%
1 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
TransferTaskPullProductService
65.96% covered (warning)
65.96%
31 / 47
14.29% covered (danger)
14.29%
1 / 7
28.40
0.00% covered (danger)
0.00%
0 / 1
 pull
69.23% covered (warning)
69.23%
9 / 13
0.00% covered (danger)
0.00%
0 / 1
3.26
 transfer
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 checkStockAvailability
20.00% covered (danger)
20.00%
1 / 5
0.00% covered (danger)
0.00%
0 / 1
7.61
 findAddressItem
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 storePickedItem
69.23% covered (warning)
69.23%
9 / 13
0.00% covered (danger)
0.00%
0 / 1
3.26
 checkTransferTaskStatus
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
4.25
 getAmountPickedTransferTaskProductsItem
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Domain\TransferTask\Services;
4
5use App\Models\Address\Address;
6use App\Models\Item\Item;
7use App\Models\TransferTask\PickedTransferTaskProduct;
8use App\Models\User;
9use App\Helper\AppHelper;
10use Domain\Transferable\Exceptions\CantTransferItemException;
11use Domain\TransferTask\DTOs\TransferTaskPickProductDTO;
12use Domain\TransferTask\Enums\PickedTransferTaskProductStatusEnum;
13use Domain\TransferTask\Exceptions\PickedTransferTaskProductStatusException;
14use Domain\TransferTask\Exceptions\TransferTaskStatusException;
15use Illuminate\Database\Eloquent\Builder;
16use Illuminate\Support\Facades\DB;
17use Illuminate\Support\ItemNotFoundException;
18use Throwable;
19
20readonly class TransferTaskPullProductService
21{
22    /**
23     * @param TransferTaskPickProductDTO $transferTaskProductDTO
24     * @param Address $sender
25     * @param User $user
26     * @return void
27     * @throws Throwable
28     */
29    public function pull(TransferTaskPickProductDTO $transferTaskProductDTO, Address $sender, User $user): void
30    {
31        try {
32            DB::beginTransaction();
33
34            if ($transferTaskProductDTO->transferTaskProduct->isPicked()) {
35                throw new CantTransferItemException(__('Product is already picked'));
36            }
37
38            $this->checkTransferTaskStatus($transferTaskProductDTO);
39
40            $this->storePickedItem(
41                $transferTaskProductDTO,
42                $this->transfer($transferTaskProductDTO, $sender),
43                $user
44            );
45
46            DB::commit();
47        } catch (Throwable $throwable) {
48            DB::rollBack();
49            throw $throwable;
50        }
51    }
52
53    /**
54     * @param TransferTaskPickProductDTO $transferTaskProductDTO
55     * @param Address $sender
56     * @return Item
57     */
58    private function transfer(TransferTaskPickProductDTO $transferTaskProductDTO, Address $sender): Item
59    {
60        $itemOnAddress = $this->findAddressItem($sender, $transferTaskProductDTO);
61        $this->checkStockAvailability($itemOnAddress, $transferTaskProductDTO->amount);
62
63        return $itemOnAddress;
64
65    }
66
67    /**
68     * @param Item $addressItem
69     * @param float $amount
70     * @return void
71     */
72    private function checkStockAvailability(Item $addressItem, float $amount): void
73    {
74        if ($addressItem->isAmountExceeded($amount)){
75            if($addressItem->pickTransferTaskProducts->where('status', PickedTransferTaskProductStatusEnum::TRANSFERRING)
76                                              ->sum('amount') > 0){
77                throw new CantTransferItemException(__('The quantity you are trying to transfer exceeds the available amount. Part of the item is already reserved for another transfer.'));                                                   
78            } else {
79                throw new CantTransferItemException(__('The amount you are trying to transfer exceeds the available amount in the item'));
80            }            
81        }
82    }
83
84    /**
85     * @param Address $address
86     * @param TransferTaskPickProductDTO $transferTaskProductDTO
87     * @return Item
88     */
89    private function findAddressItem(Address $address, TransferTaskPickProductDTO $transferTaskProductDTO): Item
90    {
91
92        $itemToTransfer = $address->findItemByProductionOrder($transferTaskProductDTO->transferTaskProduct->product, $transferTaskProductDTO->productionOrder);
93
94        if (!$itemToTransfer) {
95            throw new ItemNotFoundException(__('Product is not part of this address'));
96        }
97
98        return $itemToTransfer;
99    }
100
101    /**
102     * @param TransferTaskPickProductDTO $transferTaskPickProductDTO
103     * @param Item $item
104     * @param User $user
105     * @return void
106     */
107    private function storePickedItem(TransferTaskPickProductDTO $transferTaskPickProductDTO, Item $item, User $user): void
108    {
109        $pickedTransferTaskProduct = $transferTaskPickProductDTO->transferTaskProduct->pickedTransferTaskProduct()
110            ->whereHas('item', function (Builder $builder) use ($transferTaskPickProductDTO) {
111                $builder->whereHas('integration', function (Builder $builder) use ($transferTaskPickProductDTO) {
112                    $builder->where('parameters->production_order', $transferTaskPickProductDTO->productionOrder);
113                });
114            })
115            ->first();
116
117        if ($pickedTransferTaskProduct) {
118            if ($pickedTransferTaskProduct->isPicked()) {
119                throw new PickedTransferTaskProductStatusException(__('Item is already picked'));
120            }
121            
122            $pickedTransferTaskProduct->setAttribute('amount', round($pickedTransferTaskProduct->getAttribute('amount') + $transferTaskPickProductDTO->amount, 2));
123            $pickedTransferTaskProduct->save();
124        } else {
125            (new PickedTransferTaskProductStoreService())->store($transferTaskPickProductDTO, $item, $user);
126        }
127    }
128
129
130    /**
131     * @param TransferTaskPickProductDTO $transferTaskProductDTO
132     * @return void
133     */
134    private function checkTransferTaskStatus(TransferTaskPickProductDTO $transferTaskProductDTO): void
135    {
136        $transferTask = $transferTaskProductDTO->transferTaskProduct->transferTask;
137        if ($transferTask->isPending()) {
138            $transferTask->start();
139            $transferTask->save();
140        }
141
142        if ($transferTask->isCanceled()) {
143            throw new TransferTaskStatusException(__('Task is canceled'));
144        }
145
146        if ($transferTask->isConcluded()) {
147            throw new TransferTaskStatusException(__('Task is concluded'));
148        }
149    }
150
151    private function getAmountPickedTransferTaskProductsItem(Item $item): float
152    {
153        return round(DB::table('picked_transfer_task_products')->where('item_id', $item->getKey())->sum('amount'), 2);
154    }
155}