Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.52% covered (success)
95.52%
64 / 67
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
StockOutputFinishService
95.52% covered (success)
95.52%
64 / 67
50.00% covered (danger)
50.00%
2 / 4
15
0.00% covered (danger)
0.00%
0 / 1
 processOutputFinish
94.29% covered (success)
94.29%
33 / 35
0.00% covered (danger)
0.00%
0 / 1
7.01
 allProductsSeparated
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 allProductsCoveredByPickingOrders
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
2.00
 processInvoiceLog
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3namespace Domain\StockIO\Services\V2;
4
5use App\Models\PickingOrder\PickingOrder;
6use App\Models\PickingOrder\PickingOrderProduct;
7use App\Models\StockIO\StockIO;
8use App\Models\User;
9
10use Domain\PickingOrder\Enums\PickingOrderStatusEnum;
11use Domain\Request\DTOs\RequestLogStoreDTO;
12use Domain\Request\Enums\RequestLogOperationEnum;
13use Domain\Request\Services\RequestLogStoreService;
14use Domain\Shared\Enums\SectorEnum;
15use Domain\StockIO\Enums\StockProductStatusEnum;
16use Domain\StockIO\Enums\StockStatusEnum;
17use Domain\StockIO\Services\StockIOFinishService;
18use Exception;
19use Illuminate\Support\Collection;
20use Throwable;
21
22class StockOutputFinishService
23{
24    private array $stockIOs;
25
26    /**
27     * @throws Exception
28     * @throws Throwable
29     */
30    public function processOutputFinish(PickingOrder $pickingOrder, User $user): void
31    {
32        $this->stockIOs = [];
33        $pickingOrder->stockIOProducts
34            ->map(fn ($stockIOProduct) => $stockIOProduct->stockIO)
35            ->filter()
36            ->unique('id')
37            ->each(function (StockIO $stockIO) use ($pickingOrder, $user) {
38                if (! $stockIO->isOutput()) {
39                    return;
40                }
41
42                $doesntExistUnfinishedPickingOrders = $stockIO->pickingOrders()
43                    ->whereNotIn('status', [
44                        PickingOrderStatusEnum::CONCLUDED->value,
45                        PickingOrderStatusEnum::SEPARATED->value,
46                        PickingOrderStatusEnum::SEPARATED_PARTIAL->value,
47                        PickingOrderStatusEnum::CANCELED->value,
48                    ])
49                    ->where('id', '!=', $pickingOrder->getKey())
50                    ->doesntExist();
51
52                if (! $doesntExistUnfinishedPickingOrders) {
53                    return;
54                }
55
56                $statuses = $stockIO->stockIOProducts()
57                    ->where('status', '<>', StockProductStatusEnum::CANCELED->value)
58                    ->pluck('status');
59
60                if ($statuses->isEmpty()) {
61                    return;
62                }
63
64                if ($this->allProductsSeparated($statuses) && $this->allProductsCoveredByPickingOrders($stockIO)) {
65                    (new StockIOFinishService())->finish($stockIO);
66                } else {
67                    $stockIO->setAttribute(
68                        'status',
69                        $stockIO->sector === SectorEnum::EXPEDITION
70                            ? StockStatusEnum::STARTED
71                            : StockStatusEnum::SEPARATED_PARTIAL
72                    );
73                    $stockIO->save();
74                }
75
76                $this->processInvoiceLog($stockIO, $pickingOrder, $user);
77            });
78    }
79
80    private function allProductsSeparated(Collection $statuses): bool
81    {
82        return $statuses->every(function ($status) {
83            $value = $status instanceof StockProductStatusEnum ? $status->value : (int) $status;
84
85            return $value === StockProductStatusEnum::SEPARATED->value;
86        });
87    }
88
89    private function allProductsCoveredByPickingOrders(StockIO $stockIO): bool
90    {
91        $products = $stockIO->stockIOProducts()
92            ->where('status', '<>', StockProductStatusEnum::CANCELED->value)
93            ->get(['id', 'amount']);
94
95        if ($products->isEmpty()) {
96            return false;
97        }
98
99        $coveredAmounts = PickingOrderProduct::query()
100            ->join('picking_orders', 'picking_orders.id', '=', 'picking_order_products.picking_order_id')
101            ->whereIn('picking_order_products.stock_io_product_id', $products->pluck('id'))
102            ->where('picking_orders.status', '<>', PickingOrderStatusEnum::CANCELED->value)
103            ->where('picking_order_products.status', '<>', PickingOrderStatusEnum::CANCELED->value)
104            ->selectRaw('picking_order_products.stock_io_product_id, SUM(picking_order_products.amount) as total')
105            ->groupBy('picking_order_products.stock_io_product_id')
106            ->pluck('total', 'stock_io_product_id');
107
108        return $products->every(function ($product) use ($coveredAmounts) {
109            $covered = (float) ($coveredAmounts[$product->getKey()] ?? 0);
110
111            return round($covered, 2) >= round((float) $product->getAttribute('amount'), 2);
112        });
113    }
114
115    /**
116     * @param StockIO $stockIO
117     * @param PickingOrder $pickingOrder
118     * @param User $user
119     */
120    private function processInvoiceLog(StockIO $stockIO, PickingOrder $pickingOrder, User $user): void
121    {
122        if($this->stockIOs == [] || !in_array($stockIO->getKey(), $this->stockIOs)) {
123            $requestLogStoreDTO = new RequestLogStoreDTO([
124                'request'     => $stockIO->request ? $stockIO->request : null,
125                'stockIO'     => $stockIO,
126                'operation'   => RequestLogOperationEnum::PICKING_ORDER_CONCLUDED,
127                'user'        => $user,
128                'detail'      => $pickingOrder->toJson(),
129                'observation' => "Tarefa de separação concluída: ". $pickingOrder->getKey(),
130            ]);
131
132            (new RequestLogStoreService())->store($requestLogStoreDTO, $user);
133
134            $this->stockIOs[] = $stockIO->getKey();
135        }
136    }
137}