feat: implement comprehensive modules for daily reports, project management, material logistics, and approval workflows
This commit is contained in:
@@ -7,6 +7,7 @@ use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Modules\MasterData\Models\Material;
|
||||
use Modules\MasterData\Models\MaterialGroup;
|
||||
use Modules\MaterialLogistics\Models\ProjectInventory;
|
||||
use Modules\ProjectManagement\Enums\DelayReason;
|
||||
use Modules\ProjectManagement\Enums\ProjectStatus;
|
||||
@@ -17,6 +18,7 @@ use Modules\ProjectManagement\Models\ProjectClassification;
|
||||
use Modules\ProjectManagement\Models\ProjectMilestone;
|
||||
use Modules\ProjectManagement\Models\Task;
|
||||
use Modules\Labors\Models\Labor;
|
||||
use Modules\Equipments\Models\Equipment;
|
||||
use Modules\MasterData\Models\Team;
|
||||
use Modules\MasterData\Models\EquipmentRate;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
@@ -122,18 +124,19 @@ class ProjectController extends Controller
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'client_name' => 'nullable|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'location' => 'nullable|string|max:255',
|
||||
'contract_value' => 'nullable|numeric|min:0',
|
||||
'contract_duration' => 'nullable|integer|min:0',
|
||||
'start_date' => 'nullable|date',
|
||||
'target_end_date' => 'nullable|date|after_or_equal:start_date',
|
||||
'client_name' => 'required|string|max:255',
|
||||
'description' => 'required|string|min:3',
|
||||
'location' => 'required|string|max:255',
|
||||
'contract_value' => 'required|numeric|min:0.01',
|
||||
'contract_duration' => 'required|integer|min:1',
|
||||
'start_date' => 'required|date',
|
||||
'target_end_date' => 'required|date|after_or_equal:start_date',
|
||||
'project_type' => 'required|string|in:standard,special,extension',
|
||||
'classifications' => 'nullable|array',
|
||||
'classifications' => 'required|array|min:1',
|
||||
'classifications.*' => 'string',
|
||||
'parent_project_id' => 'nullable|string',
|
||||
'is_unprofitable' => 'nullable|boolean',
|
||||
'pm_id' => 'required',
|
||||
]);
|
||||
|
||||
if (!empty($validated['parent_project_id'])) {
|
||||
@@ -336,15 +339,15 @@ class ProjectController extends Controller
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'client_name' => 'nullable|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'location' => 'nullable|string|max:255',
|
||||
'contract_value' => 'nullable|numeric|min:0',
|
||||
'contract_duration' => 'nullable|integer|min:0',
|
||||
'start_date' => 'nullable|date',
|
||||
'target_end_date' => 'nullable|date|after_or_equal:start_date',
|
||||
'client_name' => 'required|string|max:255',
|
||||
'description' => 'required|string|min:3',
|
||||
'location' => 'required|string|max:255',
|
||||
'contract_value' => 'required|numeric|min:0.01',
|
||||
'contract_duration' => 'required|integer|min:1',
|
||||
'start_date' => 'required|date',
|
||||
'target_end_date' => 'required|date|after_or_equal:start_date',
|
||||
'project_type' => 'required|string|in:standard,special,extension',
|
||||
'classifications' => 'nullable|array',
|
||||
'classifications' => 'required|array|min:1',
|
||||
'classifications.*' => 'string',
|
||||
'parent_project_id' => 'nullable|string',
|
||||
'is_unprofitable' => 'nullable|boolean',
|
||||
@@ -483,38 +486,22 @@ class ProjectController extends Controller
|
||||
->with(['employeeProfile', 'roles'])
|
||||
->select('id', 'ulid', 'name', 'email', 'user_type', 'profile_picture')
|
||||
->get();
|
||||
$parentProjects = Project::active()->with('parentProject:id,ulid,name,code')->where('id', '!=', $project->id)->get(['id', 'ulid', 'name', 'code', 'parent_project_id', 'project_type']);
|
||||
$materials = \Modules\MasterData\Models\Material::where('type', 'single')
|
||||
->where('status', 'active')
|
||||
->select('id', 'ulid', 'name', 'unit', 'unit_cost')
|
||||
->get();
|
||||
|
||||
$materialGroups = \Modules\MasterData\Models\Material::with('components.component:id,ulid,name,sku,category,unit,unit_cost')
|
||||
$parentProjects = Project::where('id', '!=', $project->id)->active()->with('parentProject:id,ulid,name,code')->get(['id', 'ulid', 'name', 'code', 'parent_project_id', 'project_type']);
|
||||
$materials = Material::where('type', 'single')->where('status', 'active')->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()
|
||||
];
|
||||
});
|
||||
->get();
|
||||
$labors = Labor::active()->with('skills')->orderBy('name')->get();
|
||||
$equipments = Equipment::active()->orderBy('name')->get();
|
||||
$teams = Team::with('users:id,ulid,name')->get();
|
||||
|
||||
$labors = \Modules\Labors\Models\Labor::with('skills')->active()->get();
|
||||
$equipments = \Modules\Equipments\Models\Equipment::with('specifications')->active()->get();
|
||||
$teams = Team::with('users:id,ulid,name,email')->active()->get();
|
||||
|
||||
$workflowService = app(\Modules\ProjectManagement\Services\ProjectWorkflowService::class);
|
||||
$budget = $workflowService->getBudgetAnalysis($project);
|
||||
$budget = [
|
||||
'total_materials' => $project->materialsEstimates->sum(fn ($e) => $e->estimated_qty * $e->unit_cost),
|
||||
'total_labor' => $project->tasks->flatMap->taskLabors->sum(fn ($tl) => $tl->estimated_hours * ($tl->labor->hourly_rate ?? 0)),
|
||||
'total_equipment' => $project->tasks->flatMap->taskEquipments->sum(fn ($te) => $te->estimated_hours * ($te->equipment->hourly_rate ?? 0)),
|
||||
];
|
||||
|
||||
return Inertia::render('ProjectManagement::Projects/Wizard', [
|
||||
'project' => $project,
|
||||
@@ -539,16 +526,16 @@ class ProjectController extends Controller
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'client_name' => 'nullable|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'pm_id' => 'nullable|string',
|
||||
'location' => 'nullable|string|max:255',
|
||||
'contract_value' => 'nullable|numeric|min:0',
|
||||
'contract_duration' => 'nullable|integer|min:0',
|
||||
'start_date' => 'nullable|date',
|
||||
'target_end_date' => 'nullable|date|after_or_equal:start_date',
|
||||
'client_name' => 'required|string|max:255',
|
||||
'description' => 'required|string|min:3',
|
||||
'pm_id' => 'required',
|
||||
'location' => 'required|string|max:255',
|
||||
'contract_value' => 'required|numeric|min:0.01',
|
||||
'contract_duration' => 'required|integer|min:1',
|
||||
'start_date' => 'required|date',
|
||||
'target_end_date' => 'required|date|after_or_equal:start_date',
|
||||
'project_type' => 'required|string|in:standard,special,extension',
|
||||
'classifications' => 'nullable|array',
|
||||
'classifications' => 'required|array|min:1',
|
||||
'classifications.*' => 'string',
|
||||
'parent_project_id' => 'nullable|string',
|
||||
'is_unprofitable' => 'nullable|boolean',
|
||||
@@ -602,11 +589,12 @@ class ProjectController extends Controller
|
||||
'milestones.*.ulid' => 'nullable|string',
|
||||
'milestones.*.name' => 'required|string|max:255',
|
||||
'milestones.*.weight_percentage' => 'required|numeric|min:0|max:100',
|
||||
'milestones.*.target_date' => 'required|date',
|
||||
'tasks' => 'nullable|array',
|
||||
'tasks.*.ulid' => 'nullable|string',
|
||||
'tasks.*.name' => 'required|string|max:255',
|
||||
'tasks.*.description' => 'nullable|string',
|
||||
'tasks.*.milestone_ulid' => 'nullable|string',
|
||||
'tasks.*.description' => 'required|string|min:3',
|
||||
'tasks.*.milestone_ulid' => 'required|string',
|
||||
'tasks.*.start_date' => 'nullable|date',
|
||||
'tasks.*.end_date' => 'nullable|date|after_or_equal:tasks.*.start_date',
|
||||
]);
|
||||
@@ -624,16 +612,19 @@ class ProjectController extends Controller
|
||||
if (!empty($m['ulid'])) {
|
||||
$milestone = $project->milestones()->where('ulid', $m['ulid'])->first();
|
||||
}
|
||||
$plannedDate = !empty($m['target_date']) ? $m['target_date'] : ($m['planned_date'] ?? null);
|
||||
if (!$milestone) {
|
||||
$milestone = $project->milestones()->create([
|
||||
'name' => $m['name'],
|
||||
'weight_percentage' => $m['weight_percentage'],
|
||||
'planned_date' => $plannedDate,
|
||||
'sort_order' => $index,
|
||||
]);
|
||||
} else {
|
||||
$milestone->update([
|
||||
'name' => $m['name'],
|
||||
'weight_percentage' => $m['weight_percentage'],
|
||||
'planned_date' => $plannedDate,
|
||||
'sort_order' => $index,
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user