Skip to content

Commit 0fe1c2a

Browse files
feat: add stock in managment
1 parent 8b23bda commit 0fe1c2a

17 files changed

Lines changed: 1678 additions & 0 deletions
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Ingredients;
4+
5+
use App\Http\Concerns\ExtractsFilters;
6+
use App\Http\Controllers\Controller;
7+
use App\Http\Requests\Ingredients\IngredientStockIn\StoreIngredientStockInRequest;
8+
use App\Http\Requests\Ingredients\IngredientStockIn\UpdateIngredientStockInRequest;
9+
use App\Models\IngredientStockIn;
10+
use App\Services\AccessControlService;
11+
use App\Services\IngredientStockInService;
12+
use Illuminate\Http\RedirectResponse;
13+
use Illuminate\Http\Request;
14+
use Inertia\Inertia;
15+
use Inertia\Response;
16+
17+
class IngredientStockInController extends Controller
18+
{
19+
use ExtractsFilters;
20+
21+
public function __construct(
22+
private IngredientStockInService $stockInService,
23+
private AccessControlService $accessControl,
24+
) {}
25+
26+
public function index(Request $request): Response
27+
{
28+
$filters = $this->extractFilters($request, ['search', 'warehouse_id', 'status', 'source', 'per_page']);
29+
$scope = $this->accessControl->resolveSessionScope($request);
30+
31+
return Inertia::render('ingredient-stock-ins/index',
32+
$this->stockInService->getIndexData($filters, $scope));
33+
}
34+
35+
public function create(Request $request): Response
36+
{
37+
$scope = $this->accessControl->resolveSessionScope($request);
38+
return Inertia::render('ingredient-stock-ins/create',
39+
$this->stockInService->getCreateData($request->string('warehouse_id', '')->toString(), $scope));
40+
}
41+
42+
public function store(StoreIngredientStockInRequest $request): RedirectResponse
43+
{
44+
$stockIn = $this->stockInService->createStockIn($request->validated(), $request->user()->id);
45+
46+
return redirect()->route('ingredient-stock-ins.show', $stockIn)
47+
->with('success', 'Stock in record created successfully.');
48+
}
49+
50+
public function show(IngredientStockIn $ingredientStockIn): Response
51+
{
52+
return Inertia::render('ingredient-stock-ins/show',
53+
$this->stockInService->getShowData($ingredientStockIn));
54+
}
55+
56+
public function edit(Request $request, IngredientStockIn $ingredientStockIn): Response
57+
{
58+
$scope = $this->accessControl->resolveSessionScope($request);
59+
return Inertia::render('ingredient-stock-ins/edit',
60+
$this->stockInService->getEditData($ingredientStockIn, $scope));
61+
}
62+
63+
public function update(UpdateIngredientStockInRequest $request, IngredientStockIn $ingredientStockIn): RedirectResponse
64+
{
65+
$this->stockInService->updateStockIn($ingredientStockIn, $request->validated());
66+
67+
return redirect()->route('ingredient-stock-ins.show', $ingredientStockIn)
68+
->with('success', 'Stock in record updated successfully.');
69+
}
70+
71+
public function destroy(IngredientStockIn $ingredientStockIn): RedirectResponse
72+
{
73+
$this->stockInService->deleteStockIn($ingredientStockIn);
74+
75+
return redirect()->route('ingredient-stock-ins.index')
76+
->with('success', 'Stock in record deleted successfully.');
77+
}
78+
79+
public function approve(Request $request, IngredientStockIn $ingredientStockIn): RedirectResponse
80+
{
81+
$this->stockInService->approve($ingredientStockIn, $request->user()->id);
82+
83+
return redirect()->route('ingredient-stock-ins.show', $ingredientStockIn)
84+
->with('success', 'Stock in approved. Stock has been added.');
85+
}
86+
87+
public function cancel(Request $request, IngredientStockIn $ingredientStockIn): RedirectResponse
88+
{
89+
$this->stockInService->cancel($ingredientStockIn);
90+
91+
return back()->with('success', 'Stock in record cancelled.');
92+
}
93+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Ingredients\IngredientStockIn;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
use Illuminate\Validation\Rule;
7+
8+
class StoreIngredientStockInRequest extends FormRequest
9+
{
10+
public function authorize(): bool
11+
{
12+
return true;
13+
}
14+
15+
public function rules(): array
16+
{
17+
return [
18+
'warehouse_id' => ['required', 'integer', 'exists:warehouses,id'],
19+
'stock_in_date' => ['required', 'date'],
20+
'source' => ['required', Rule::in(['purchase', 'return', 'correction', 'donation', 'other'])],
21+
'remarks' => ['nullable', 'string', 'max:2000'],
22+
23+
'items' => ['required', 'array', 'min:1'],
24+
'items.*.ingredient_id' => ['required', 'integer', 'exists:ingredients,id'],
25+
'items.*.ingredient_batch_id' => ['nullable', 'integer', 'exists:ingredient_batches,id'],
26+
'items.*.quantity' => ['required', 'numeric', 'min:0.0001'],
27+
'items.*.unit_cost' => ['nullable', 'numeric', 'min:0'],
28+
];
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Ingredients\IngredientStockIn;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
use Illuminate\Validation\Rule;
7+
8+
class UpdateIngredientStockInRequest extends FormRequest
9+
{
10+
public function authorize(): bool
11+
{
12+
return true;
13+
}
14+
15+
public function rules(): array
16+
{
17+
return [
18+
'warehouse_id' => ['required', 'integer', 'exists:warehouses,id'],
19+
'stock_in_date' => ['required', 'date'],
20+
'source' => ['required', Rule::in(['purchase', 'return', 'correction', 'donation', 'other'])],
21+
'remarks' => ['nullable', 'string', 'max:2000'],
22+
23+
'items' => ['required', 'array', 'min:1'],
24+
'items.*.ingredient_id' => ['required', 'integer', 'exists:ingredients,id'],
25+
'items.*.ingredient_batch_id' => ['nullable', 'integer', 'exists:ingredient_batches,id'],
26+
'items.*.quantity' => ['required', 'numeric', 'min:0.0001'],
27+
'items.*.unit_cost' => ['nullable', 'numeric', 'min:0'],
28+
];
29+
}
30+
}

app/Models/IngredientStockIn.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
7+
use Illuminate\Database\Eloquent\Relations\HasMany;
8+
use Illuminate\Database\Eloquent\Relations\MorphMany;
9+
10+
class IngredientStockIn extends Model
11+
{
12+
protected $fillable = [
13+
'stock_in_no',
14+
'warehouse_id',
15+
'stock_in_date',
16+
'source',
17+
'status',
18+
'remarks',
19+
'created_by',
20+
'approved_by',
21+
'approved_at',
22+
];
23+
24+
protected function casts(): array
25+
{
26+
return [
27+
'stock_in_date' => 'date',
28+
'approved_at' => 'datetime',
29+
];
30+
}
31+
32+
public function warehouse(): BelongsTo
33+
{
34+
return $this->belongsTo(Warehouse::class);
35+
}
36+
37+
public function items(): HasMany
38+
{
39+
return $this->hasMany(IngredientStockInItem::class);
40+
}
41+
42+
public function createdBy(): BelongsTo
43+
{
44+
return $this->belongsTo(User::class, 'created_by');
45+
}
46+
47+
public function approvedBy(): BelongsTo
48+
{
49+
return $this->belongsTo(User::class, 'approved_by');
50+
}
51+
52+
public function inventoryTransactions(): MorphMany
53+
{
54+
return $this->morphMany(IngredientInventoryTransaction::class, 'reference');
55+
}
56+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
7+
8+
class IngredientStockInItem extends Model
9+
{
10+
protected $fillable = [
11+
'ingredient_stock_in_id',
12+
'ingredient_id',
13+
'ingredient_batch_id',
14+
'quantity',
15+
'unit_cost',
16+
'total_cost',
17+
];
18+
19+
protected function casts(): array
20+
{
21+
return [
22+
'quantity' => 'decimal:4',
23+
'unit_cost' => 'decimal:6',
24+
'total_cost' => 'decimal:4',
25+
];
26+
}
27+
28+
public function stockIn(): BelongsTo
29+
{
30+
return $this->belongsTo(IngredientStockIn::class, 'ingredient_stock_in_id');
31+
}
32+
33+
public function ingredient(): BelongsTo
34+
{
35+
return $this->belongsTo(Ingredient::class);
36+
}
37+
38+
public function batch(): BelongsTo
39+
{
40+
return $this->belongsTo(IngredientBatch::class, 'ingredient_batch_id');
41+
}
42+
}

0 commit comments

Comments
 (0)