feat(issues): incidencias enriquecidas (tareas/comentarios/fotos/verificación) + tabla Rappasoft + logo
Web: - IssueTask + IssueComment (modelos, migraciones, soft-deletes, campos de sync). Issue gana tasks()/comments() y accessor de % de avance derivado de tareas. - IssueDetail (página): checklist con asignado/fecha límite/progreso, hilo de comentarios con foto por comentario, galería de fotos de la incidencia y flujo de verificación open→in_review→resolved/closed (+reabrir) con notas. - Creación/edición en páginas propias (IssueForm), sin modal; al guardar redirige al detalle. Rutas projects.issues.create/edit/show. - Listado con tabla Rappasoft (IssueTable): filtros por estado/prioridad, búsqueda, barra de progreso y acciones por fila gateadas por permisos; IssueManager queda como contenedor (cabecera + stats) que embebe la tabla. - Seguridad: pertenencia al proyecto + permisos por acción (view/create/edit/delete issues, upload/delete media) en todos los componentes. API móvil (offline): - /sync: issue_task.create/update y issue_comment.create (idempotente, LWW). - /media: parent_entity issue_task / issue_comment. - bundle + tombstones incluyen issue_tasks / issue_comments. - openapi.yaml + MOBILE_SYNC_PROTOCOL.md actualizados. Tests: MobileApiTest 23 passing (+5); IssuesTablePageTest (3) smoke de la tabla. Branding: logo RTE International — MAI Group (public/images/logo-rte.png) en login y navegación; application-logo pasa de SVG por defecto a <img>. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Livewire\IssueManager;
|
||||
use App\Livewire\IssueTable;
|
||||
use App\Models\Issue;
|
||||
use App\Models\Project;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Tests\TestCase;
|
||||
|
||||
class IssuesTablePageTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private function memberWithIssue(): array
|
||||
{
|
||||
foreach (['view issues', 'create issues', 'edit issues', 'delete issues'] as $p) {
|
||||
Permission::findOrCreate($p);
|
||||
}
|
||||
|
||||
$user = User::factory()->create();
|
||||
$user->givePermissionTo(['view issues', 'edit issues', 'delete issues']);
|
||||
|
||||
$project = Project::create([
|
||||
'reference' => 'TBL-1',
|
||||
'name' => 'Proyecto Tabla',
|
||||
'address' => 'Calle Falsa 123',
|
||||
'lat' => 40.0,
|
||||
'lng' => -3.0,
|
||||
'start_date' => now()->toDateString(),
|
||||
'end_date_estimated' => now()->addMonths(6)->toDateString(),
|
||||
'status' => 'in_progress',
|
||||
'created_by' => $user->id,
|
||||
]);
|
||||
$project->users()->attach($user->id, ['role_in_project' => 'supervisor']);
|
||||
|
||||
$issue = Issue::create([
|
||||
'project_id' => $project->id,
|
||||
'title' => 'Grieta en muro',
|
||||
'status' => 'open',
|
||||
'priority' => 'high',
|
||||
'reported_by' => $user->id,
|
||||
]);
|
||||
|
||||
return [$user, $project, $issue];
|
||||
}
|
||||
|
||||
public function test_issue_manager_renders_stats_and_table(): void
|
||||
{
|
||||
[$user, $project, $issue] = $this->memberWithIssue();
|
||||
|
||||
Livewire::actingAs($user)
|
||||
->test(IssueManager::class, ['project' => $project])
|
||||
->assertOk()
|
||||
->assertSee('Incidencias del proyecto')
|
||||
->assertSeeLivewire(IssueTable::class);
|
||||
}
|
||||
|
||||
public function test_issue_table_lists_and_resolves_an_issue(): void
|
||||
{
|
||||
[$user, $project, $issue] = $this->memberWithIssue();
|
||||
|
||||
Livewire::actingAs($user)
|
||||
->test(IssueTable::class, ['projectId' => $project->id])
|
||||
->assertOk()
|
||||
->assertSee('Grieta en muro')
|
||||
->call('resolve', $issue->id);
|
||||
|
||||
$this->assertEquals('resolved', $issue->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_issue_table_forbidden_for_non_member(): void
|
||||
{
|
||||
[, $project] = $this->memberWithIssue();
|
||||
|
||||
$outsider = User::factory()->create();
|
||||
$outsider->givePermissionTo('view issues');
|
||||
|
||||
Livewire::actingAs($outsider)
|
||||
->test(IssueTable::class, ['projectId' => $project->id])
|
||||
->assertForbidden();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user