Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
31.91% |
15 / 47 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
| StockOutputFinishService | |
31.91% |
15 / 47 |
|
0.00% |
0 / 3 |
49.19 | |
0.00% |
0 / 1 |
| processOutputFinish | |
57.69% |
15 / 26 |
|
0.00% |
0 / 1 |
10.71 | |||
| allProductsSeparated | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| allProductsCoveredByPickingOrders | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
6 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace Domain\StockIO\Services; |
| 4 | |
| 5 | use App\Models\PickingOrder\PickingOrderProduct; |
| 6 | use App\Models\PickingOrder\PickingOrder; |
| 7 | use App\Models\StockIO\StockIO; |
| 8 | use Domain\PickingOrder\Enums\PickingOrderStatusEnum; |
| 9 | use Domain\Shared\Enums\SectorEnum; |
| 10 | use Domain\StockIO\Enums\StockProductStatusEnum; |
| 11 | use Domain\StockIO\Enums\StockStatusEnum; |
| 12 | use Illuminate\Support\Collection; |
| 13 | |
| 14 | readonly class StockOutputFinishService |
| 15 | { |
| 16 | public function processOutputFinish(PickingOrder $pickingOrder): void |
| 17 | { |
| 18 | $output = $pickingOrder->stockIO; |
| 19 | |
| 20 | if (!$output?->isOutput()) { |
| 21 | return; |
| 22 | } |
| 23 | |
| 24 | $doesntExistUnfinishedPickingOrders = $output->pickingOrders() |
| 25 | ->whereNotIn('status', [ |
| 26 | PickingOrderStatusEnum::CONCLUDED->value, |
| 27 | PickingOrderStatusEnum::SEPARATED->value, |
| 28 | PickingOrderStatusEnum::CANCELED->value, |
| 29 | ]) |
| 30 | ->where('id', '!=', $pickingOrder->getKey()) |
| 31 | ->doesntExist(); |
| 32 | |
| 33 | $statuses = $output->stockIOProducts() |
| 34 | ->where('status', '<>', StockProductStatusEnum::CANCELED->value) |
| 35 | ->pluck('status'); |
| 36 | |
| 37 | if (!$doesntExistUnfinishedPickingOrders || !$statuses->isEmpty()) { |
| 38 | return; |
| 39 | } |
| 40 | |
| 41 | if ($this->allProductsSeparated($statuses) && $this->allProductsCoveredByPickingOrders($output)) { |
| 42 | (new StockIOFinishService())->finish($output); |
| 43 | |
| 44 | return; |
| 45 | } |
| 46 | |
| 47 | $output->setAttribute( |
| 48 | 'status', |
| 49 | $output->isRequest() |
| 50 | ? StockStatusEnum::SEPARATED_PARTIAL |
| 51 | : StockStatusEnum::STARTED |
| 52 | ); |
| 53 | $output->save(); |
| 54 | } |
| 55 | |
| 56 | private function allProductsSeparated(Collection $statuses): bool |
| 57 | { |
| 58 | return $statuses->every(function ($status) { |
| 59 | $value = $status instanceof StockProductStatusEnum ? $status->value : (int) $status; |
| 60 | |
| 61 | return $value === StockProductStatusEnum::SEPARATED->value; |
| 62 | }); |
| 63 | } |
| 64 | |
| 65 | private function allProductsCoveredByPickingOrders(StockIO $output): bool |
| 66 | { |
| 67 | $products = $output->stockIOProducts() |
| 68 | ->where('status', '<>', StockProductStatusEnum::CANCELED->value) |
| 69 | ->get(['id', 'amount']); |
| 70 | |
| 71 | if ($products->isEmpty()) { |
| 72 | return false; |
| 73 | } |
| 74 | |
| 75 | $coveredAmounts = PickingOrderProduct::query() |
| 76 | ->join('picking_orders', 'picking_orders.id', '=', 'picking_order_products.picking_order_id') |
| 77 | ->whereIn('picking_order_products.stock_io_product_id', $products->pluck('id')) |
| 78 | ->where('picking_orders.status', '<>', PickingOrderStatusEnum::CANCELED->value) |
| 79 | ->where('picking_order_products.status', '<>', PickingOrderStatusEnum::CANCELED->value) |
| 80 | ->selectRaw('picking_order_products.stock_io_product_id, SUM(picking_order_products.amount) as total') |
| 81 | ->groupBy('picking_order_products.stock_io_product_id') |
| 82 | ->pluck('total', 'stock_io_product_id'); |
| 83 | |
| 84 | return $products->every(function ($product) use ($coveredAmounts) { |
| 85 | $covered = (float) ($coveredAmounts[$product->getKey()] ?? 0); |
| 86 | |
| 87 | return round($covered, 2) >= round((float) $product->getAttribute('amount'), 2); |
| 88 | }); |
| 89 | } |
| 90 | } |