Some checks failed
Main Confidence / confidence (push) Failing after 52s
Add Customer Health decision card to tenant & workspace detail pages (spec 245). What I changed: - Render a decision-first Customer Health card on tenant and workspace detail pages. - Reuse `WorkspaceHealthSummaryQuery` and preserve `window` query param. - Update attention widget link text to "Review health details" and include `?window=`. - Add/adjust tests to cover new behavior and explainability. - Run Pint formatting. Compare URL: https://git.cloudarix.de/ahmido/TenantAtlas/compare/dev...245-customer-health-score Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #283
158 lines
5.7 KiB
PHP
158 lines
5.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\Finding;
|
|
use App\Models\OperationRun;
|
|
use App\Models\PlatformUser;
|
|
use App\Models\ProductUsageEvent;
|
|
use App\Models\ProviderConnection;
|
|
use App\Models\ReviewPack;
|
|
use App\Models\Tenant;
|
|
use App\Models\Workspace;
|
|
use App\Support\Auth\PlatformCapabilities;
|
|
use App\Support\OperationRunOutcome;
|
|
use App\Support\OperationRunStatus;
|
|
use App\Support\ProductTelemetry\ProductUsageEventCatalog;
|
|
use App\Support\Providers\ProviderConsentStatus;
|
|
use App\Support\Providers\ProviderVerificationStatus;
|
|
use App\Support\System\SystemDirectoryLinks;
|
|
use App\Support\SystemConsole\SystemConsoleWindow;
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function (): void {
|
|
CarbonImmutable::setTestNow(CarbonImmutable::parse('2026-04-27 12:00:00'));
|
|
});
|
|
|
|
afterEach(function (): void {
|
|
CarbonImmutable::setTestNow();
|
|
});
|
|
|
|
it('renders a decision-first customer health card on the tenant detail page before diagnostics', function (): void {
|
|
$fixture = createCustomerHealthDecisionFixture('Tenant Decision Workspace');
|
|
$platformUser = createDirectoryPlatformUser();
|
|
|
|
$response = $this->actingAs($platformUser, 'platform')
|
|
->get(SystemDirectoryLinks::tenantDetail($fixture['tenant']).'?window='.SystemConsoleWindow::LastWeek)
|
|
->assertSuccessful()
|
|
->assertSee('Customer health decision')
|
|
->assertSee('Overall health')
|
|
->assertSee('Reason')
|
|
->assertSee('Impact')
|
|
->assertSee('Recommended next action')
|
|
->assertSee('Top driver: Provider connection health')
|
|
->assertSee('Default provider consent or verification is blocking reliable tenant management.')
|
|
->assertSee('Review connectivity signals below and confirm the default provider consent and verification state.')
|
|
->assertSee('Last 7 days');
|
|
|
|
$html = $response->getContent();
|
|
$decisionPosition = strpos($html, 'Customer health decision');
|
|
$diagnosticsPosition = strpos($html, 'Connectivity signals');
|
|
|
|
expect($decisionPosition)->not->toBeFalse()
|
|
->and($diagnosticsPosition)->not->toBeFalse()
|
|
->and($decisionPosition)->toBeLessThan($diagnosticsPosition);
|
|
});
|
|
|
|
it('renders a decision-first customer health card on the workspace detail page before tenant diagnostics', function (): void {
|
|
$fixture = createCustomerHealthDecisionFixture('Workspace Decision Workspace');
|
|
$platformUser = createDirectoryPlatformUser();
|
|
|
|
$response = $this->actingAs($platformUser, 'platform')
|
|
->get(SystemDirectoryLinks::workspaceDetail($fixture['workspace']).'?window='.SystemConsoleWindow::LastWeek)
|
|
->assertSuccessful()
|
|
->assertSee('Customer health decision')
|
|
->assertSee('Overall health')
|
|
->assertSee('Reason')
|
|
->assertSee('Impact')
|
|
->assertSee('Recommended next action')
|
|
->assertSee('Top driver: Provider connection health')
|
|
->assertSee('Default provider consent or verification is blocking reliable tenant management.')
|
|
->assertSee('Open the affected tenant below and review the default provider connection state.')
|
|
->assertSee('Last 7 days');
|
|
|
|
$html = $response->getContent();
|
|
$decisionPosition = strpos($html, 'Customer health decision');
|
|
$diagnosticsPosition = strpos($html, 'Tenants summary');
|
|
|
|
expect($decisionPosition)->not->toBeFalse()
|
|
->and($diagnosticsPosition)->not->toBeFalse()
|
|
->and($decisionPosition)->toBeLessThan($diagnosticsPosition);
|
|
});
|
|
|
|
function createDirectoryPlatformUser(): PlatformUser
|
|
{
|
|
return PlatformUser::factory()->create([
|
|
'capabilities' => [
|
|
PlatformCapabilities::ACCESS_SYSTEM_PANEL,
|
|
PlatformCapabilities::DIRECTORY_VIEW,
|
|
],
|
|
'is_active' => true,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return array{workspace: Workspace, tenant: Tenant}
|
|
*/
|
|
function createCustomerHealthDecisionFixture(string $workspaceName): array
|
|
{
|
|
$workspace = Workspace::factory()->create(['name' => $workspaceName]);
|
|
$tenant = Tenant::factory()->for($workspace)->create([
|
|
'name' => $workspaceName.' Tenant',
|
|
'status' => Tenant::STATUS_ACTIVE,
|
|
]);
|
|
|
|
ProviderConnection::factory()
|
|
->for($tenant)
|
|
->create([
|
|
'workspace_id' => (int) $workspace->getKey(),
|
|
'is_default' => true,
|
|
'is_enabled' => true,
|
|
'consent_status' => ProviderConsentStatus::Granted->value,
|
|
'verification_status' => ProviderVerificationStatus::Blocked->value,
|
|
]);
|
|
|
|
ReviewPack::factory()
|
|
->for($tenant)
|
|
->ready()
|
|
->create([
|
|
'workspace_id' => (int) $workspace->getKey(),
|
|
'created_at' => now()->subDays(3),
|
|
'generated_at' => now()->subDays(3),
|
|
'expires_at' => now()->addDays(30),
|
|
]);
|
|
|
|
ProductUsageEvent::factory()
|
|
->for($tenant)
|
|
->forEvent(ProductUsageEventCatalog::ONBOARDING_CHECKPOINT_COMPLETED)
|
|
->create([
|
|
'workspace_id' => (int) $workspace->getKey(),
|
|
'occurred_at' => now()->subDays(3),
|
|
]);
|
|
|
|
OperationRun::factory()
|
|
->forTenant($tenant)
|
|
->create([
|
|
'workspace_id' => (int) $workspace->getKey(),
|
|
'status' => OperationRunStatus::Completed->value,
|
|
'outcome' => OperationRunOutcome::Succeeded->value,
|
|
'created_at' => now()->subDays(3),
|
|
'started_at' => now()->subDays(3)->subMinutes(5),
|
|
'completed_at' => now()->subDays(3),
|
|
]);
|
|
|
|
Finding::factory()
|
|
->for($tenant)
|
|
->closed()
|
|
->create([
|
|
'severity' => Finding::SEVERITY_LOW,
|
|
]);
|
|
|
|
return [
|
|
'workspace' => $workspace,
|
|
'tenant' => $tenant,
|
|
];
|
|
} |