chore: update document approval workflow and bug fixes
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\MaterialLogistics\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Modules\MaterialLogistics\Models\InventoryMovement;
|
||||
use Modules\MaterialLogistics\Models\Warehouse;
|
||||
|
||||
class WarehouseController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Warehouse::query();
|
||||
|
||||
if ($search = $request->search) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('code', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
$warehouses = $query->withCount('stock')
|
||||
->latest()
|
||||
->paginate(15)
|
||||
->withQueryString()
|
||||
->through(fn ($w) => $w->append(['total_value', 'item_count']));
|
||||
|
||||
return Inertia::render('MaterialLogistics::Warehouses/Index', [
|
||||
'warehouses' => $warehouses,
|
||||
'filters' => $request->only(['search']),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return Inertia::render('MaterialLogistics::Warehouses/Form');
|
||||
}
|
||||
|
||||
public function show(Request $request, Warehouse $warehouse)
|
||||
{
|
||||
// Paginated stock with search & category filter
|
||||
$stockQuery = $warehouse->stock()->with([
|
||||
'material:id,ulid,name,sku,unit,category,type',
|
||||
'material.components.component:id,name,unit'
|
||||
]);
|
||||
|
||||
if ($search = $request->search) {
|
||||
$stockQuery->whereHas('material', fn ($q) =>
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('sku', 'like', "%{$search}%")
|
||||
);
|
||||
}
|
||||
if ($category = $request->category) {
|
||||
$stockQuery->whereHas('material', fn ($q) => $q->where('category', $category));
|
||||
}
|
||||
|
||||
$stock = $stockQuery->paginate(25)->withQueryString();
|
||||
|
||||
// Append is_low_stock to each stock item
|
||||
$stock->getCollection()->each(fn ($s) => $s->append('is_low_stock'));
|
||||
|
||||
// Summary stats from full warehouse stock (not filtered)
|
||||
$allStock = $warehouse->stock()->with('material:id,category')->get();
|
||||
$summary = [
|
||||
'total_items' => $allStock->count(),
|
||||
'total_value' => $allStock->sum(fn ($s) => (float) $s->quantity * (float) $s->unit_cost),
|
||||
'categories' => $allStock->pluck('material.category')->filter()->unique()->count(),
|
||||
'low_stock_count' => $allStock->filter(fn ($s) => $s->is_low_stock)->count(),
|
||||
];
|
||||
|
||||
// Distinct categories for filter dropdown
|
||||
$categories = $allStock->pluck('material.category')
|
||||
->filter()
|
||||
->unique()
|
||||
->sort()
|
||||
->values();
|
||||
|
||||
// Recent movements for this warehouse
|
||||
$movements = InventoryMovement::forWarehouse($warehouse->id)
|
||||
->with(['material:id,ulid,name,sku,unit', 'performer:id,name'])
|
||||
->latest()
|
||||
->paginate(15, ['*'], 'movements_page')
|
||||
->withQueryString();
|
||||
|
||||
return Inertia::render('MaterialLogistics::Warehouses/Show', [
|
||||
'warehouse' => $warehouse,
|
||||
'stock' => $stock,
|
||||
'summary' => $summary,
|
||||
'categories' => $categories,
|
||||
'movements' => $movements,
|
||||
'filters' => $request->only(['search', 'category']),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'code' => 'required|string|max:20|unique:warehouses',
|
||||
'address' => 'nullable|string',
|
||||
'type' => 'required|in:main,yard,staging',
|
||||
]);
|
||||
|
||||
Warehouse::create($validated);
|
||||
|
||||
return redirect()->route('warehouses.index')->with('success', 'Warehouse created.');
|
||||
}
|
||||
|
||||
public function edit(Warehouse $warehouse)
|
||||
{
|
||||
return Inertia::render('MaterialLogistics::Warehouses/Form', [
|
||||
'warehouse' => $warehouse,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, Warehouse $warehouse)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'code' => "required|string|max:20|unique:warehouses,code,{$warehouse->id}",
|
||||
'address' => 'nullable|string',
|
||||
'type' => 'required|in:main,yard,staging',
|
||||
'status' => 'nullable|in:active,inactive',
|
||||
]);
|
||||
|
||||
$warehouse->update($validated);
|
||||
|
||||
return redirect()->route('warehouses.index')->with('success', 'Warehouse updated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON API: warehouse stock for selects and dispatching.
|
||||
*/
|
||||
public function stockSummary(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'warehouse_ulid' => 'required|string',
|
||||
]);
|
||||
|
||||
$warehouse = Warehouse::where('ulid', $request->warehouse_ulid)->firstOrFail();
|
||||
|
||||
$stock = $warehouse->stock()
|
||||
->with([
|
||||
'material:id,ulid,name,sku,unit,category,type',
|
||||
'material.components.component:id,name,unit'
|
||||
])
|
||||
->where('quantity', '>', 0)
|
||||
->get()
|
||||
->map(fn ($s) => [
|
||||
'material' => $s->material,
|
||||
'quantity' => $s->quantity,
|
||||
'reserved_qty' => $s->reserved_qty,
|
||||
'available_qty' => $s->available_qty,
|
||||
'unit_cost' => $s->unit_cost,
|
||||
]);
|
||||
|
||||
return response()->json($stock);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user