chore: update document approval workflow and bug fixes
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\MaterialLogistics\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Inertia\Inertia;
|
||||
use Modules\ApprovalWorkflow\Services\ApprovalService;
|
||||
use Modules\MasterData\Models\Material;
|
||||
use Modules\MaterialLogistics\Models\MaterialRequisition;
|
||||
use Modules\MasterData\Models\MaterialGroup;
|
||||
use Modules\MaterialLogistics\Services\DocumentNumberService;
|
||||
use Modules\ProjectManagement\Models\Project;
|
||||
|
||||
class MaterialRequisitionController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$requisitions = MaterialRequisition::with([
|
||||
'requester:id,ulid,name',
|
||||
'approver:id,ulid,name',
|
||||
'items:id,material_requisition_id,quantity,unit_cost' // Need items for frontend line total
|
||||
])
|
||||
->latest()
|
||||
->paginate(20);
|
||||
|
||||
return Inertia::render('MaterialLogistics::Requisitions/Index', [
|
||||
'requisitions' => $requisitions,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$materials = Material::select('id', 'ulid', 'name', 'unit', 'unit_cost', 'sku', 'category', 'status')
|
||||
->where('status', 'active')
|
||||
->orderBy('category')
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
$materialGroups = Material::with('components.component:id,ulid,name,sku,category,unit,unit_cost')
|
||||
->whereIn('type', ['kit', 'assembly'])
|
||||
->where('status', 'active')
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->map(function ($kit) {
|
||||
return [
|
||||
'id' => $kit->id,
|
||||
'ulid' => $kit->ulid,
|
||||
'name' => $kit->name,
|
||||
'description' => $kit->description ?? '',
|
||||
'status' => $kit->status,
|
||||
'materials' => $kit->components->map(function ($comp) {
|
||||
return array_merge($comp->component->toArray(), [
|
||||
'pivot' => ['quantity' => $comp->quantity]
|
||||
]);
|
||||
})->toArray()
|
||||
];
|
||||
});
|
||||
|
||||
return Inertia::render('MaterialLogistics::Requisitions/Form', [
|
||||
'materials' => $materials,
|
||||
'materialGroups' => $materialGroups,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'notes' => 'nullable|string|max:1000',
|
||||
'items' => 'required|array|min:1',
|
||||
'items.*.material_ulid' => 'required|string',
|
||||
'items.*.quantity' => 'required|numeric|min:0.01',
|
||||
'items.*.unit_cost' => 'required|numeric|min:0',
|
||||
]);
|
||||
|
||||
$docService = new DocumentNumberService();
|
||||
|
||||
$mr = DB::transaction(function () use ($validated, $docService) {
|
||||
$mr = MaterialRequisition::create([
|
||||
'document_number' => $docService->nextMrNumber(),
|
||||
'status' => 'draft',
|
||||
'requested_by' => auth()->id(),
|
||||
'notes' => $validated['notes'] ?? null,
|
||||
]);
|
||||
|
||||
foreach ($validated['items'] as $item) {
|
||||
$material = Material::where('ulid', $item['material_ulid'])->firstOrFail();
|
||||
$mr->items()->create([
|
||||
'material_id' => $material->id,
|
||||
'quantity' => $item['quantity'],
|
||||
'unit_cost' => $item['unit_cost'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $mr;
|
||||
});
|
||||
|
||||
return redirect()->route('requisitions.show', $mr)->with('success', 'Material Requisition created.');
|
||||
}
|
||||
|
||||
public function edit(MaterialRequisition $requisition)
|
||||
{
|
||||
if ($requisition->status !== 'draft') {
|
||||
return redirect()->back()->with('error', 'Only draft requisitions can be edited.');
|
||||
}
|
||||
|
||||
$requisition->load('items.material:id,ulid,name,unit,unit_cost');
|
||||
|
||||
$materials = Material::select('id', 'ulid', 'name', 'sku', 'category', 'unit', 'unit_cost', 'status')
|
||||
->where('status', 'active')
|
||||
->orderBy('category')
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
$materialGroups = Material::with('components.component:id,ulid,name,sku,category,unit,unit_cost')
|
||||
->whereIn('type', ['kit', 'assembly'])
|
||||
->where('status', 'active')
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->map(function ($kit) {
|
||||
return [
|
||||
'id' => $kit->id,
|
||||
'ulid' => $kit->ulid,
|
||||
'name' => $kit->name,
|
||||
'description' => $kit->description ?? '',
|
||||
'status' => $kit->status,
|
||||
'materials' => $kit->components->map(function ($comp) {
|
||||
return array_merge($comp->component->toArray(), [
|
||||
'pivot' => ['quantity' => $comp->quantity]
|
||||
]);
|
||||
})->toArray()
|
||||
];
|
||||
});
|
||||
|
||||
return Inertia::render('MaterialLogistics::Requisitions/Form', [
|
||||
'requisition' => $requisition,
|
||||
'materials' => $materials,
|
||||
'materialGroups' => $materialGroups,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, MaterialRequisition $requisition)
|
||||
{
|
||||
if ($requisition->status !== 'draft') {
|
||||
return redirect()->back()->with('error', 'Only draft requisitions can be updated.');
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'notes' => 'nullable|string|max:1000',
|
||||
'items' => 'required|array|min:1',
|
||||
'items.*.material_ulid' => 'required|string',
|
||||
'items.*.quantity' => 'required|numeric|min:0.01',
|
||||
'items.*.unit_cost' => 'required|numeric|min:0',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($validated, $requisition) {
|
||||
$requisition->update([
|
||||
'notes' => $validated['notes'] ?? null,
|
||||
]);
|
||||
|
||||
$requisition->items()->delete(); // remove old items
|
||||
|
||||
foreach ($validated['items'] as $item) {
|
||||
$material = Material::where('ulid', $item['material_ulid'])->firstOrFail();
|
||||
$requisition->items()->create([
|
||||
'material_id' => $material->id,
|
||||
'quantity' => $item['quantity'],
|
||||
'unit_cost' => $item['unit_cost'],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('requisitions.show', $requisition)->with('success', 'Material Requisition updated.');
|
||||
}
|
||||
|
||||
public function show(MaterialRequisition $requisition)
|
||||
{
|
||||
$requisition->load([
|
||||
'requester:id,ulid,name',
|
||||
'approver:id,ulid,name',
|
||||
'items.material' => function ($query) {
|
||||
$query->select('id', 'ulid', 'name', 'unit', 'unit_cost', 'type')
|
||||
->with('components.component:id,name,unit');
|
||||
},
|
||||
'approvalChains.steps.approver:id,ulid,name',
|
||||
]);
|
||||
|
||||
return Inertia::render('MaterialLogistics::Requisitions/Show', [
|
||||
'requisition' => $requisition,
|
||||
]);
|
||||
}
|
||||
|
||||
public function submitForApproval(MaterialRequisition $requisition)
|
||||
{
|
||||
if ($requisition->status !== 'draft') {
|
||||
return back()->with('error', 'Only draft requisitions can be submitted.');
|
||||
}
|
||||
|
||||
// Find personnel with approve_mr permission across the whole system
|
||||
$approverIds = \App\Models\User::permission('approve_mr')
|
||||
->pluck('id')
|
||||
->values()
|
||||
->toArray();
|
||||
|
||||
if (empty($approverIds)) {
|
||||
return back()->with('error', 'No approvers found in the system for Material Requests.');
|
||||
}
|
||||
|
||||
$approvalService = app(ApprovalService::class);
|
||||
$approvalService->createChain(
|
||||
$requisition,
|
||||
$approverIds,
|
||||
'material_requisition',
|
||||
auth()->id(),
|
||||
);
|
||||
|
||||
$requisition->update(['status' => 'submitted']);
|
||||
|
||||
return back()->with('success', 'Material Requisition submitted for approval.');
|
||||
}
|
||||
|
||||
public function downloadPdf(MaterialRequisition $requisition)
|
||||
{
|
||||
$requisition->load([
|
||||
'requester:id,name',
|
||||
'approver:id,name',
|
||||
'items.material:id,name,unit',
|
||||
'approvalChains.steps.approver:id,name',
|
||||
]);
|
||||
|
||||
// Global approver roles
|
||||
$approverDetails = [];
|
||||
if ($requisition->approvalChains->isNotEmpty()) {
|
||||
$chain = $requisition->approvalChains->first();
|
||||
foreach ($chain->steps as $step) {
|
||||
if ($step->status === 'approved' && $step->approver) {
|
||||
$approverDetails[] = [
|
||||
'name' => $step->approver->name,
|
||||
'role' => 'Approver',
|
||||
'date' => $step->acted_at?->format('M d, Y'),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($approverDetails) && $requisition->status === 'approved' && $requisition->approver) {
|
||||
$approverDetails[] = [
|
||||
'name' => $requisition->approver->name,
|
||||
'role' => 'Approver',
|
||||
'date' => $requisition->approved_at ? $requisition->approved_at->format('M d, Y') : null,
|
||||
];
|
||||
}
|
||||
|
||||
$pdf = Pdf::loadView('materiallogistics::pdf.material-requisition', [
|
||||
'requisition' => $requisition,
|
||||
'approverDetails' => $approverDetails,
|
||||
]);
|
||||
|
||||
return $pdf->download("MR-{$requisition->document_number}.pdf");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user