Additional Changes
This commit is contained in:
@@ -15,37 +15,65 @@ use Modules\MaterialLogistics\Models\PurchaseOrder;
|
||||
use Modules\MaterialLogistics\Models\Warehouse;
|
||||
use Modules\MaterialLogistics\Services\DocumentNumberService;
|
||||
use Modules\ProjectManagement\Models\Project;
|
||||
use Modules\ProjectManagement\Services\ProjectWorkflowService;
|
||||
|
||||
class PurchaseOrderController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$purchaseOrders = PurchaseOrder::with([
|
||||
$query = PurchaseOrder::with([
|
||||
'requester:id,ulid,name',
|
||||
'approver:id,ulid,name',
|
||||
'project:id,ulid,name,code',
|
||||
'requisitions:id,ulid,document_number',
|
||||
'items:id,purchase_order_id,quantity,unit_cost'
|
||||
])
|
||||
->latest()
|
||||
->paginate(20);
|
||||
]);
|
||||
|
||||
if ($request->filled('project_ulid')) {
|
||||
$project = Project::where('ulid', $request->project_ulid)->first();
|
||||
if ($project) {
|
||||
$query->where('project_id', $project->id);
|
||||
}
|
||||
}
|
||||
|
||||
$purchaseOrders = $query->latest()->paginate(20);
|
||||
|
||||
return Inertia::render('MaterialLogistics::PurchaseOrders/Index', [
|
||||
'purchaseOrders' => $purchaseOrders,
|
||||
'projects' => Project::active()->select('id', 'ulid', 'name', 'code')->get(),
|
||||
'warehouses' => Warehouse::active()->select('id', 'ulid', 'name', 'code')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
public function create(Request $request)
|
||||
{
|
||||
$selectedProject = null;
|
||||
$budgetAnalysis = null;
|
||||
|
||||
if ($request->filled('project_ulid')) {
|
||||
$selectedProject = Project::where('ulid', $request->project_ulid)->firstOrFail();
|
||||
$workflowService = new ProjectWorkflowService();
|
||||
if (!$workflowService->canCreatePurchaseOrder($selectedProject)) {
|
||||
return redirect()->back()->with('error', 'Cannot create Purchase Order: Project does not have approved Material Requisitions.');
|
||||
}
|
||||
$budgetAnalysis = $workflowService->getBudgetAnalysis($selectedProject);
|
||||
}
|
||||
|
||||
$materials = Material::select('id', 'ulid', 'name', 'unit', 'unit_cost')
|
||||
->where('status', 'active')
|
||||
->orderBy('name')
|
||||
->get();
|
||||
$approvedRequisitions = MaterialRequisition::with(['items.material:id,ulid,name,unit,sku', 'requester:id,name'])
|
||||
|
||||
// Filter approved requisitions by project if selected
|
||||
$requisitionsQuery = MaterialRequisition::with(['items.material:id,ulid,name,unit,sku', 'requester:id,name'])
|
||||
->where('status', 'approved')
|
||||
->doesntHave('purchaseOrders')
|
||||
->orderByDesc('created_at')
|
||||
->get();
|
||||
->doesntHave('purchaseOrders');
|
||||
|
||||
if ($selectedProject) {
|
||||
$requisitionsQuery->where('project_id', $selectedProject->id);
|
||||
}
|
||||
|
||||
$approvedRequisitions = $requisitionsQuery->orderByDesc('created_at')->get();
|
||||
|
||||
// Find personnel with approve_po permission across the whole system
|
||||
$approverIds = \App\Models\User::permission('approve_po')
|
||||
@@ -57,22 +85,33 @@ class PurchaseOrderController extends Controller
|
||||
return back()->with('error', 'No approvers found in the system for Purchase Orders.');
|
||||
}
|
||||
|
||||
$warehousesQuery = Warehouse::active()
|
||||
->whereDoesntHave('project', function ($q) {
|
||||
$q->whereIn('status', ['closed', 'completed']);
|
||||
});
|
||||
|
||||
if ($selectedProject) {
|
||||
$warehousesQuery->where('project_id', $selectedProject->id);
|
||||
}
|
||||
|
||||
$warehouses = $warehousesQuery->with('project:id,ulid,name')
|
||||
->select('id', 'ulid', 'name', 'code', 'project_id')
|
||||
->get();
|
||||
|
||||
return Inertia::render('MaterialLogistics::PurchaseOrders/Form', [
|
||||
'materials' => $materials,
|
||||
'approvedRequisitions' => $approvedRequisitions,
|
||||
'warehouses' => Inertia::lazy(fn () => Warehouse::active()
|
||||
->whereDoesntHave('project', function ($q) {
|
||||
$q->whereIn('status', ['closed', 'completed']);
|
||||
})
|
||||
->with('project:id,ulid,name')
|
||||
->select('id', 'ulid', 'name', 'code', 'project_id')
|
||||
->get()),
|
||||
'projects' => Project::active()->select('id', 'ulid', 'name', 'code')->get(),
|
||||
'selectedProject' => $selectedProject,
|
||||
'budgetAnalysis' => $budgetAnalysis,
|
||||
'warehouses' => $warehouses,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'project_ulid' => 'required|string|exists:projects,ulid',
|
||||
'target_warehouse_ulid' => 'required|string',
|
||||
'supplier' => 'nullable|string|max:255',
|
||||
'notes' => 'nullable|string|max:1000',
|
||||
@@ -85,11 +124,23 @@ class PurchaseOrderController extends Controller
|
||||
'items.*.requisition_item_id' => 'nullable|integer',
|
||||
]);
|
||||
|
||||
$project = Project::where('ulid', $validated['project_ulid'])->firstOrFail();
|
||||
$targetWarehouse = Warehouse::where('ulid', $validated['target_warehouse_ulid'])->firstOrFail();
|
||||
|
||||
if ($targetWarehouse->project_id !== $project->id) {
|
||||
return redirect()->back()->with('error', 'Target warehouse does not belong to the selected project.');
|
||||
}
|
||||
|
||||
$workflowService = new ProjectWorkflowService();
|
||||
if (!$workflowService->canCreatePurchaseOrder($project)) {
|
||||
return redirect()->back()->with('error', 'Cannot create Purchase Order: Project workflow state does not permit PO creation.');
|
||||
}
|
||||
|
||||
$docService = new DocumentNumberService();
|
||||
|
||||
$po = DB::transaction(function () use ($validated, $targetWarehouse, $docService) {
|
||||
$po = DB::transaction(function () use ($validated, $project, $targetWarehouse, $docService) {
|
||||
$po = PurchaseOrder::create([
|
||||
'project_id' => $project->id,
|
||||
'target_warehouse_id' => $targetWarehouse->id,
|
||||
'document_number' => $docService->nextPoNumber(),
|
||||
'supplier' => $validated['supplier'] ?? null,
|
||||
@@ -127,7 +178,7 @@ class PurchaseOrderController extends Controller
|
||||
return redirect()->back()->with('error', 'Only draft POs can be edited.');
|
||||
}
|
||||
|
||||
$purchaseOrder->load('items.material:id,ulid,name,unit,unit_cost', 'requisitions:id,ulid,document_number', 'targetWarehouse:id,ulid,name,code');
|
||||
$purchaseOrder->load('items.material:id,ulid,name,unit,unit_cost', 'requisitions:id,ulid,document_number', 'targetWarehouse:id,ulid,name,code', 'project:id,ulid,name,code');
|
||||
|
||||
$materials = Material::select('id', 'ulid', 'name', 'unit', 'unit_cost')
|
||||
->where('status', 'active')
|
||||
@@ -144,17 +195,20 @@ class PurchaseOrderController extends Controller
|
||||
->orderByDesc('created_at')
|
||||
->get();
|
||||
|
||||
$budgetAnalysis = null;
|
||||
if ($purchaseOrder->project) {
|
||||
$workflowService = new ProjectWorkflowService();
|
||||
$budgetAnalysis = $workflowService->getBudgetAnalysis($purchaseOrder->project);
|
||||
}
|
||||
|
||||
return Inertia::render('MaterialLogistics::PurchaseOrders/Form', [
|
||||
'purchaseOrder' => $purchaseOrder,
|
||||
'materials' => $materials,
|
||||
'approvedRequisitions' => $approvedRequisitions,
|
||||
'warehouses' => Inertia::lazy(fn () => Warehouse::active()
|
||||
->whereDoesntHave('project', function ($q) {
|
||||
$q->whereIn('status', ['closed', 'completed']);
|
||||
})
|
||||
->with('project:id,ulid,name')
|
||||
->select('id', 'ulid', 'name', 'code', 'project_id')
|
||||
->get()),
|
||||
'projects' => Project::active()->select('id', 'ulid', 'name', 'code')->get(),
|
||||
'selectedProject' => $purchaseOrder->project,
|
||||
'budgetAnalysis' => $budgetAnalysis,
|
||||
'warehouses' => Warehouse::active()->with('project:id,ulid,name')->select('id', 'ulid', 'name', 'code', 'project_id')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -165,6 +219,7 @@ class PurchaseOrderController extends Controller
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'project_ulid' => 'required|string|exists:projects,ulid',
|
||||
'target_warehouse_ulid' => 'required|string',
|
||||
'supplier' => 'nullable|string|max:255',
|
||||
'notes' => 'nullable|string|max:1000',
|
||||
@@ -177,10 +232,21 @@ class PurchaseOrderController extends Controller
|
||||
'items.*.requisition_item_id' => 'nullable|integer',
|
||||
]);
|
||||
|
||||
$project = Project::where('ulid', $validated['project_ulid'])->firstOrFail();
|
||||
$targetWarehouse = Warehouse::where('ulid', $validated['target_warehouse_ulid'])->firstOrFail();
|
||||
|
||||
DB::transaction(function () use ($validated, $targetWarehouse, $purchaseOrder) {
|
||||
if ($targetWarehouse->project_id !== $project->id) {
|
||||
return redirect()->back()->with('error', 'Target warehouse does not belong to the selected project.');
|
||||
}
|
||||
|
||||
$workflowService = new ProjectWorkflowService();
|
||||
if (!$workflowService->canCreatePurchaseOrder($project)) {
|
||||
return redirect()->back()->with('error', 'Cannot update Purchase Order: Project workflow state does not permit PO updates.');
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($validated, $project, $targetWarehouse, $purchaseOrder) {
|
||||
$purchaseOrder->update([
|
||||
'project_id' => $project->id,
|
||||
'target_warehouse_id' => $targetWarehouse->id,
|
||||
'supplier' => $validated['supplier'] ?? null,
|
||||
'notes' => $validated['notes'] ?? null,
|
||||
@@ -215,6 +281,7 @@ class PurchaseOrderController extends Controller
|
||||
'targetWarehouse:id,ulid,name',
|
||||
'requester:id,ulid,name',
|
||||
'approver:id,ulid,name',
|
||||
'project:id,ulid,name,code',
|
||||
'items.material' => function ($query) {
|
||||
$query->select('id', 'ulid', 'name', 'unit', 'unit_cost', 'type')
|
||||
->with('components.component:id,name,unit');
|
||||
@@ -225,9 +292,16 @@ class PurchaseOrderController extends Controller
|
||||
|
||||
$warehouses = Warehouse::active()->select('id', 'ulid', 'name', 'code')->get();
|
||||
|
||||
$budgetAnalysis = null;
|
||||
if ($purchaseOrder->project) {
|
||||
$workflowService = new ProjectWorkflowService();
|
||||
$budgetAnalysis = $workflowService->getBudgetAnalysis($purchaseOrder->project);
|
||||
}
|
||||
|
||||
return Inertia::render('MaterialLogistics::PurchaseOrders/Show', [
|
||||
'purchaseOrder' => $purchaseOrder,
|
||||
'warehouses' => $warehouses,
|
||||
'budgetAnalysis' => $budgetAnalysis,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -307,15 +381,31 @@ class PurchaseOrderController extends Controller
|
||||
{
|
||||
$request->validate([
|
||||
'q' => 'nullable|string|max:100',
|
||||
'warehouse_ulid' => 'nullable|string',
|
||||
'project_ulid' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$query = PurchaseOrder::where('status', 'approved')
|
||||
$query = PurchaseOrder::whereIn('status', ['approved', 'delivered'])
|
||||
->with('items.material:id,ulid,name,unit,unit_cost');
|
||||
|
||||
if ($request->filled('q')) {
|
||||
$query->where('document_number', 'like', "%{$request->q}%");
|
||||
}
|
||||
|
||||
if ($request->filled('warehouse_ulid')) {
|
||||
$warehouse = Warehouse::where('ulid', $request->warehouse_ulid)->first();
|
||||
if ($warehouse) {
|
||||
$query->where('target_warehouse_id', $warehouse->id);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->filled('project_ulid')) {
|
||||
$project = Project::where('ulid', $request->project_ulid)->first();
|
||||
if ($project) {
|
||||
$query->where('project_id', $project->id);
|
||||
}
|
||||
}
|
||||
|
||||
$results = $query->select('id', 'ulid', 'document_number', 'supplier')
|
||||
->latest()
|
||||
->limit(20)
|
||||
|
||||
Reference in New Issue
Block a user