chore: update document approval workflow and bug fixes

This commit is contained in:
2026-05-25 13:05:20 +08:00
parent d573c02893
commit 39a8e1d4cd
910 changed files with 49994 additions and 1010 deletions

View File

@@ -0,0 +1,133 @@
<?php
namespace Modules\TaskManagement\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Modules\MasterData\Models\Material;
use Modules\MaterialLogistics\Models\PurchaseOrder;
use Modules\ProjectManagement\Models\Project;
use Modules\ProjectManagement\Models\Task;
use Modules\ProjectManagement\Models\TaskMaterial;
class TaskMaterialController extends Controller
{
public function store(Request $request, Project $project, Task $task)
{
$validated = $request->validate([
'material_id' => 'required|string',
'purchase_order_id' => 'nullable|string',
'planned_qty' => 'required|numeric|min:0.01',
'actual_qty' => 'nullable|numeric|min:0',
'notes' => 'nullable|string|max:500',
]);
$material = Material::where('ulid', $validated['material_id'])->firstOrFail();
$poId = null;
if (!empty($validated['purchase_order_id'])) {
$po = PurchaseOrder::where('ulid', $validated['purchase_order_id'])->firstOrFail();
if ($po->status !== 'approved') {
return back()->with('error', 'Only materials from approved Purchase Orders can be assigned.');
}
if (!$po->items()->where('material_id', $material->id)->exists()) {
return back()->with('error', 'This material is not part of the selected Purchase Order.');
}
$poId = $po->id;
}
// Prevent duplicate material per task
if ($task->taskMaterials()->where('material_id', $material->id)->exists()) {
return back()->with('error', 'This material is already assigned to this task.');
}
$task->taskMaterials()->create([
'material_id' => $material->id,
'purchase_order_id' => $poId,
'planned_qty' => $validated['planned_qty'],
'actual_qty' => $validated['actual_qty'] ?? 0,
'unit_cost' => $material->unit_cost,
'notes' => $validated['notes'] ?? null,
]);
$project->load('tasks.taskMaterials');
$project->recalculateCapitalization();
return back()->with('success', 'Material added to task.');
}
public function storeBulk(Request $request, Project $project, Task $task)
{
$validated = $request->validate([
'purchase_order_id' => 'nullable|string',
'materials' => 'required|array|min:1',
'materials.*.material_id' => 'required|string',
'materials.*.planned_qty' => 'required|numeric|min:0.01',
]);
$poId = null;
if (!empty($validated['purchase_order_id'])) {
$po = PurchaseOrder::where('ulid', $validated['purchase_order_id'])->firstOrFail();
if ($po->status !== 'approved') {
return back()->with('error', 'Only materials from approved Purchase Orders can be assigned.');
}
$poId = $po->id;
}
$added = 0;
foreach ($validated['materials'] as $entry) {
$material = Material::where('ulid', $entry['material_id'])->firstOrFail();
if ($task->taskMaterials()->where('material_id', $material->id)->exists()) {
continue;
}
$task->taskMaterials()->create([
'material_id' => $material->id,
'purchase_order_id' => $poId,
'planned_qty' => $entry['planned_qty'],
'actual_qty' => 0,
'unit_cost' => $material->unit_cost,
]);
$added++;
}
$project->load('tasks.taskMaterials');
$project->recalculateCapitalization();
return back()->with('success', "{$added} material(s) added to task.");
}
public function update(Request $request, Project $project, Task $task, TaskMaterial $taskMaterial)
{
$validated = $request->validate([
'planned_qty' => 'nullable|numeric|min:0',
'actual_qty' => 'nullable|numeric|min:0',
'notes' => 'nullable|string|max:500',
]);
$taskMaterial->update(array_filter($validated, fn ($v) => $v !== null));
$project->load('tasks.taskMaterials');
$project->recalculateCapitalization();
return back()->with('success', 'Task material updated.');
}
public function destroy(Project $project, Task $task, TaskMaterial $taskMaterial)
{
$taskMaterial->delete();
$project->load('tasks.taskMaterials');
$project->recalculateCapitalization();
return back()->with('success', 'Material removed from task.');
}
}