feat: implement comprehensive material and product stock management logic in CuttingService

This commit is contained in:
Yoga Pangestu 2026-06-13 14:03:12 +07:00
parent 1e2d81a86d
commit 837c930c4f

View File

@ -93,7 +93,6 @@ public function getInProgressCuttings(User $user): Collection
});
}
/**
* @return Collection<int, RawMaterial>
*/
@ -226,6 +225,9 @@ public function create(array $validated, User $user): Cutting
$cutting->results()->create($resultData);
}
$cutting->load('materials.rawMaterialPrice.rawMaterial');
$this->deductMaterialStock($cutting);
return $cutting;
});
}
@ -242,6 +244,12 @@ public function update(Cutting $cutting, array $validated): void
}
DB::transaction(function () use ($cutting, $validated): void {
$cutting->load(['materials.rawMaterialPrice.rawMaterial', 'results']);
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
$this->reverseTotalMaterialStock($cutting);
}
$cutting->materials()->delete();
$cutting->results()->delete();
@ -259,6 +267,11 @@ public function update(Cutting $cutting, array $validated): void
$cutting->results()->create($resultData);
}
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
$cutting->load('materials.rawMaterialPrice.rawMaterial');
$this->deductMaterialStock($cutting);
}
if ($cutting->status === CuttingStatus::REJECTED) {
$cutting->rejection()?->delete();
}
@ -274,6 +287,9 @@ public function delete(Cutting $cutting): void
}
DB::transaction(function () use ($cutting): void {
$cutting->load(['materials.rawMaterialPrice.rawMaterial']);
$this->reverseTotalMaterialStock($cutting);
$cutting->materials()->delete();
$cutting->results()->delete();
$cutting->delete();
@ -292,19 +308,18 @@ public function transitionStatus(Cutting $cutting, CuttingStatus $status, User $
$cutting->load(['materials', 'results']);
if ($status === CuttingStatus::COMPLETED) {
$this->applyMaterialStockOnComplete($cutting);
}
if ($status === CuttingStatus::VERIFIED) {
$this->applyRemainingMaterialStock($cutting);
$this->applyProductStockOnVerify($cutting);
}
if ($status === CuttingStatus::REJECTED) {
$this->reverseMaterialStock($cutting);
$this->reverseProductStock($cutting);
$this->storeRejection($cutting, $reason, $user);
}
if ($status === CuttingStatus::IN_PROGRESS && $cutting->status === CuttingStatus::REJECTED) {
$this->deductMaterialStock($cutting);
$cutting->rejection()?->delete();
}
@ -407,7 +422,7 @@ private function buildResults(array $results): array
->all();
}
private function applyMaterialStockOnComplete(Cutting $cutting): void
private function deductMaterialStock(Cutting $cutting): void
{
foreach ($cutting->materials as $material) {
$totalTaken = (float) $material->material_usage + (float) $material->remaining_material;
@ -426,9 +441,26 @@ private function applyMaterialStockOnComplete(Cutting $cutting): void
}
$price->decrement('stock', $totalTaken);
}
}
private function reverseTotalMaterialStock(Cutting $cutting): void
{
foreach ($cutting->materials as $material) {
$totalTaken = (float) $material->material_usage + (float) $material->remaining_material;
RawMaterialPrice::query()
->whereKey($material->raw_material_price_id)
->increment('stock', $totalTaken);
}
}
private function applyRemainingMaterialStock(Cutting $cutting): void
{
foreach ($cutting->materials as $material) {
if ((float) $material->remaining_material > 0) {
$price->increment('stock', $material->remaining_material);
RawMaterialPrice::query()
->whereKey($material->raw_material_price_id)
->increment('stock', $material->remaining_material);
}
}
}
@ -455,6 +487,19 @@ private function applyProductStockOnVerify(Cutting $cutting): void
}
}
private function reverseProductStock(Cutting $cutting): void
{
foreach ($cutting->results as $result) {
if ($result->warehouse_stock < 1) {
continue;
}
ProductVariant::query()
->whereKey($result->product_variant_id)
->decrement('stock', $result->warehouse_stock);
}
}
private function storeRejection(Cutting $cutting, ?string $reason, User $user): void
{
if ($reason === null || trim($reason) === '') {