Kaynağa Gözat

project link requirement by plan & project requirement list

moell 1 yıl önce
ebeveyn
işleme
79368856f1

+ 16 - 2
app/Http/Controllers/API/ProjectController.php

@@ -4,10 +4,12 @@ namespace App\Http\Controllers\API;
 
 use App\Http\Controllers\Controller;
 use App\Http\Requests\API\Project\CreateOrUpdateRequest;
+use App\Http\Requests\API\Project\LinkRequirementByPlanRequest;
 use App\Http\Requests\API\Project\LinkRequirementRequest;
 use App\Http\Requests\API\Project\PostponeRequest;
 use App\Http\Requests\API\Project\UnlinkRequirementRequest;
 use App\Http\Resources\API\PlanResource;
+use App\Http\Resources\API\ProjectRequirementResource;
 use App\Http\Resources\API\ProjectResource;
 use App\Http\Resources\API\RequirementResource;
 use App\Models\Enums\ProjectStatus;
@@ -19,7 +21,6 @@ use App\Models\ProjectRequirement;
 use App\Models\Requirement;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
-use function MongoDB\BSON\toJSON;
 
 class ProjectController extends Controller
 {
@@ -219,10 +220,19 @@ class ProjectController extends Controller
         return $this->noContent();
     }
 
-    public function linkRequirementByPlan(string $id)
+    public function linkRequirementByPlan(LinkRequirementByPlanRequest $request, string $id)
     {
         $project = Project::findOrFail($id);
 
+        $plan = Plan::findOrFail($request->plan_id);
+
+        foreach ($plan->requirements as $requirement) {
+            ProjectRequirement::query()->firstOrCreate([
+                'project_id' => $project->id, 'requirement_id' => $requirement->id,
+            ]);
+        }
+
+        return $this->noContent();
     }
 
     public function plan(string $id)
@@ -234,7 +244,11 @@ class ProjectController extends Controller
 
     public function requirement(string $id)
     {
+        $project = Project::findOrFail($id);
+
+        $requirements = $project->requirements()->with(['createdBy'])->simplePaginate();
 
+        return ProjectRequirementResource::collection($requirements);
     }
 
     public function notLinkAssetRequirement(string $id)

+ 28 - 0
app/Http/Requests/API/Project/LinkRequirementByPlanRequest.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests\API\Project;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class LinkRequirementByPlanRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     */
+    public function authorize(): bool
+    {
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
+     */
+    public function rules(): array
+    {
+        return [
+            'plan_id' => 'required',
+        ];
+    }
+}

+ 25 - 0
app/Http/Resources/API/ProjectRequirementResource.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Http\Resources\API;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class ProjectRequirementResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id' => $this->id,
+            'priority' => $this->priority,
+            'title' => $this->title,
+            'created_by' => new UserProfileResource($this->createdBy),
+            'status' => $this->status,
+        ];
+    }
+}

+ 23 - 0
app/Http/Resources/API/UserProfileResource.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace App\Http\Resources\API;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class UserProfileResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id' => $this->id,
+            'name' => $this->name,
+            'username' => $this->username,
+        ];
+    }
+}

+ 11 - 1
app/Models/Plan.php

@@ -10,8 +10,18 @@ class Plan extends Model
     use HasFactory;
 
     protected $fillable = [
-        'title'
+        'title',
+        'asset_id',
+        'parent_id',
+        'begin',
+        'end',
+        'description',
     ];
 
     public $timestamps = false;
+
+    public function requirements()
+    {
+        return $this->belongsToMany(Requirement::class, 'plan_requirement', 'plan_id', 'requirement_id');
+    }
 }

+ 20 - 0
app/Models/PlanRequirement.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class PlanRequirement extends Model
+{
+    use HasFactory;
+
+    protected $table = 'plan_requirement';
+
+    protected $fillable = [
+        'plan_id',
+        'requirement_id',
+    ];
+
+    public $timestamps = false;
+}

+ 5 - 0
app/Models/Project.php

@@ -29,4 +29,9 @@ class Project extends Model
     {
         return $this->belongsToMany(Asset::class, 'project_asset');
     }
+
+    public function requirements(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
+    {
+        return $this->belongsToMany(Requirement::class, 'project_requirement');
+    }
 }

+ 5 - 0
app/Models/Requirement.php

@@ -25,4 +25,9 @@ class Requirement extends Model
     protected $casts = [
         'mailto' => 'array',
     ];
+
+    public function createdBy(): \Illuminate\Database\Eloquent\Relations\BelongsTo
+    {
+        return $this->belongsTo(User::class, 'created_by');
+    }
 }

+ 6 - 0
database/factories/PlanFactory.php

@@ -2,6 +2,8 @@
 
 namespace Database\Factories;
 
+use App\Models\Asset;
+use Carbon\Carbon;
 use Illuminate\Database\Eloquent\Factories\Factory;
 use Illuminate\Support\Facades\Auth;
 
@@ -20,6 +22,10 @@ class PlanFactory extends Factory
         return [
             'title' => fake()->title(),
             'company_id' => Auth::user()->company_id,
+            'asset_id' => Asset::factory(),
+            'begin' => Carbon::now()->toDateString(),
+            'end' => Carbon::now()->addDays(10)->toDateString(),
+            'description' => fake()->text(),
         ];
     }
 }

+ 1 - 1
database/factories/RequirementFactory.php

@@ -23,7 +23,7 @@ class RequirementFactory extends Factory
     {
         return [
             'title' => fake()->title(),
-            'asset_id' => Asset::factory()->create()->id,
+            'asset_id' => Asset::factory(),
             'status' => RequirementStatus::CHANGED->value,
             'requirement_group_id' => RequirementGroup::factory()->create()->id,
             'company_id' => Auth::user()->company_id,

+ 28 - 0
database/migrations/2024_01_24_122827_create_plan_requirement_table.php

@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('plan_requirement', function (Blueprint $table) {
+            $table->id();
+            $table->integer('plan_id')->index();
+            $table->integer('requirement_id')->index();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('plan_requirement');
+    }
+};

+ 36 - 0
database/migrations/2024_01_24_124223_add_fields_to_plan_table.php

@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('plans', function (Blueprint $table) {
+            $table->integer('asset_id');
+            $table->integer('parent_id')->default(0);
+            $table->date("begin")->nullable();
+            $table->date("end")->nullable();
+            $table->text("description")->nullable();
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('plans', function (Blueprint $table) {
+            $table->dropColumn([
+                'asset_id', 'parent_id', 'begin', 'end', 'description', 'deleted_at', 'created_at', 'udpated_at'
+            ]);
+        });
+    }
+};

+ 1 - 1
routes/api.php

@@ -42,7 +42,7 @@ Route::middleware(['auth:sanctum'])->group(function () {
         ->name("project.link-requirement");
     Route::patch("project/{project}/unlink-requirement", [API\ProjectController::class, "unlinkRequirement"])
         ->name("project.unlink-requirement");
-    Route::patch("project/{project}/link-requirement-by-plan/{project_requirement}", [API\ProjectController::class, "linkRequirementByPlan"])
+    Route::patch("project/{project}/link-requirement-by-plan", [API\ProjectController::class, "linkRequirementByPlan"])
         ->name("project.link-requirement-by-plan");
 
     Route::get("project/{project}/plan", [API\ProjectController::class, "plan"])

+ 53 - 0
tests/Feature/API/ProjectTest.php

@@ -5,6 +5,7 @@ namespace Tests\Feature\API;
 use App\Models\Asset;
 use App\Models\Enums\ProjectStatus;
 use App\Models\Plan;
+use App\Models\PlanRequirement;
 use App\Models\Project;
 use App\Models\ProjectAsset;
 use App\Models\ProjectPlan;
@@ -234,4 +235,56 @@ class ProjectTest extends TestCase
 
         $this->assertEquals(0, $count);
     }
+
+    public function test_project_link_requirement_by_plan(): void
+    {
+        $project = Project::factory()->create();
+
+        $plan = Plan::factory()->create();
+
+        $requirement = Requirement::factory()->make();
+        $requirement->asset_id = $plan->asset_id;
+        $requirement->save();
+
+        PlanRequirement::create([
+            'plan_id' => $plan->id,
+            'requirement_id' => $requirement->id,
+        ]);
+
+        $response = $this->patch(route('project.link-requirement-by-plan', ['project' => $project->id]), [
+            'plan_id' => $plan->id,
+        ]);
+
+        $response->assertStatus(204);
+
+        $count = ProjectRequirement::where([
+            'project_id' => $project->id,
+            'requirement_id' => $requirement->id,
+        ])->count();
+
+        $this->assertEquals(1, $count);
+    }
+
+    public function test_project_requirement_list(): void
+    {
+        $project = Project::factory()->create();
+
+        $requirements = Requirement::factory(30)->create();
+
+        foreach ($requirements as $requirement) {
+            ProjectRequirement::create([
+                'project_id' => $project->id,
+                'requirement_id' => $requirement->id,
+            ]);
+        }
+
+        $response = $this->get(route('project.requirement', ['project' => $project->id]));
+
+        dump($response->getContent());
+
+        $response->assertStatus(200)
+            ->assertJsonStructure($this->simplePaginateResponseStructure([
+                'id', 'title', 'created_by', 'status'
+            ]));
+    }
 }