first commit
This commit is contained in:
341
tests/Feature/ReportManagementTest.php
Normal file
341
tests/Feature/ReportManagementTest.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\TeamRole;
|
||||
use App\Models\Department;
|
||||
use App\Models\DepartmentProfile;
|
||||
use App\Models\MedicationExpenseRow;
|
||||
use App\Models\MedicationExpenseValue;
|
||||
use App\Models\ReportPeriod;
|
||||
use App\Models\ServiceCatalog;
|
||||
use App\Models\ServiceEntry;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('authenticated users can open the report periods page', function () {
|
||||
$user = User::factory()->create();
|
||||
ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
'year' => 2026,
|
||||
'month' => 2,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->get(route('reports.periods.index', ['current_team' => $user->currentTeam]));
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('reports/periods/Index')
|
||||
->where('periods.0.label', 'Февраль 2026'));
|
||||
});
|
||||
|
||||
test('authenticated users can create a report period scoped to their team', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->post(route('reports.periods.store', ['current_team' => $user->currentTeam]), [
|
||||
'year' => 2026,
|
||||
'month' => 2,
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('reports.periods.index', ['current_team' => $user->currentTeam]));
|
||||
|
||||
$this->assertDatabaseHas('report_periods', [
|
||||
'team_id' => $user->currentTeam->id,
|
||||
'year' => 2026,
|
||||
'month' => 2,
|
||||
'status' => 'draft',
|
||||
]);
|
||||
});
|
||||
|
||||
test('report periods must be unique within a team', function () {
|
||||
$user = User::factory()->create();
|
||||
ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
'year' => 2026,
|
||||
'month' => 2,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from(route('reports.periods.index', ['current_team' => $user->currentTeam]))
|
||||
->post(route('reports.periods.store', ['current_team' => $user->currentTeam]), [
|
||||
'year' => 2026,
|
||||
'month' => 2,
|
||||
]);
|
||||
|
||||
$response->assertSessionHasErrors('month');
|
||||
});
|
||||
|
||||
test('authenticated users can approve a period', function () {
|
||||
$user = User::factory()->create();
|
||||
$period = ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->patch(route('reports.periods.approve', [
|
||||
'current_team' => $user->currentTeam,
|
||||
'report_period' => $period,
|
||||
]));
|
||||
|
||||
$response->assertRedirect(route('reports.periods.index', ['current_team' => $user->currentTeam]));
|
||||
|
||||
expect($period->fresh()->status->value)->toBe('approved');
|
||||
});
|
||||
|
||||
test('approved periods can not be edited through services or medication forms', function () {
|
||||
$user = User::factory()->create();
|
||||
$providerDepartment = Department::factory()->create();
|
||||
$recipientDepartment = Department::factory()->create();
|
||||
$serviceCatalog = ServiceCatalog::factory()->create();
|
||||
$period = ReportPeriod::factory()->approved()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
]);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->post(route('reports.operations.store', ['current_team' => $user->currentTeam]), [
|
||||
'report_period_id' => $period->id,
|
||||
'provider_department_id' => $providerDepartment->id,
|
||||
'service_catalog_id' => $serviceCatalog->id,
|
||||
'entries' => [
|
||||
$recipientDepartment->id => [
|
||||
'quantity' => 100,
|
||||
'unit_price' => 15.50,
|
||||
],
|
||||
],
|
||||
])
|
||||
->assertStatus(422);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->post(route('reports.medication-expenses.store', ['current_team' => $user->currentTeam]), [
|
||||
'report_period_id' => $period->id,
|
||||
'department_id' => $providerDepartment->id,
|
||||
'values' => [
|
||||
'oms' => [
|
||||
'alcohol' => 10,
|
||||
],
|
||||
],
|
||||
])
|
||||
->assertStatus(422);
|
||||
});
|
||||
|
||||
test('authenticated users can store service entries', function () {
|
||||
$user = User::factory()->create();
|
||||
$providerDepartment = Department::factory()->create();
|
||||
$recipientDepartment = Department::factory()->create();
|
||||
$period = ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
]);
|
||||
$serviceCatalog = ServiceCatalog::factory()->create([
|
||||
'default_price' => 15.50,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->post(route('reports.operations.store', ['current_team' => $user->currentTeam]), [
|
||||
'report_period_id' => $period->id,
|
||||
'provider_department_id' => $providerDepartment->id,
|
||||
'service_catalog_id' => $serviceCatalog->id,
|
||||
'entries' => [
|
||||
$recipientDepartment->id => [
|
||||
'quantity' => 2471,
|
||||
'unit_price' => 15.50,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
|
||||
$this->assertDatabaseHas('service_entries', [
|
||||
'report_period_id' => $period->id,
|
||||
'service_catalog_id' => $serviceCatalog->id,
|
||||
'provider_department_id' => $providerDepartment->id,
|
||||
'recipient_department_id' => $recipientDepartment->id,
|
||||
'quantity' => 2471.00,
|
||||
'unit_price' => 15.50,
|
||||
]);
|
||||
});
|
||||
|
||||
test('authenticated users can store medication expense values', function () {
|
||||
$user = User::factory()->create();
|
||||
$department = Department::factory()->create();
|
||||
$period = ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->post(route('reports.medication-expenses.store', ['current_team' => $user->currentTeam]), [
|
||||
'report_period_id' => $period->id,
|
||||
'department_id' => $department->id,
|
||||
'values' => [
|
||||
'oms' => [
|
||||
'alcohol' => 120.5,
|
||||
'dressing' => 30.75,
|
||||
],
|
||||
'budget' => [
|
||||
'medicines' => 80,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
|
||||
$row = MedicationExpenseRow::query()
|
||||
->where('report_period_id', $period->id)
|
||||
->where('department_id', $department->id)
|
||||
->first();
|
||||
|
||||
expect($row)->not->toBeNull();
|
||||
|
||||
$this->assertDatabaseHas('medication_expense_values', [
|
||||
'medication_expense_row_id' => $row->id,
|
||||
'funding_source' => 'oms',
|
||||
'expense_category' => 'alcohol',
|
||||
'amount' => 120.50,
|
||||
]);
|
||||
});
|
||||
|
||||
test('report pages are isolated per team', function () {
|
||||
$user = User::factory()->create();
|
||||
$otherTeam = Team::factory()->create();
|
||||
$user->teams()->attach($otherTeam, ['role' => TeamRole::Member->value]);
|
||||
|
||||
ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
'year' => 2026,
|
||||
'month' => 2,
|
||||
]);
|
||||
ReportPeriod::factory()->create([
|
||||
'team_id' => $otherTeam->id,
|
||||
'year' => 2026,
|
||||
'month' => 3,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->get(route('reports.periods.index', ['current_team' => $user->currentTeam]));
|
||||
|
||||
$response->assertInertia(fn (Assert $page) => $page
|
||||
->where('periods', fn (array $periods) => count($periods) === 1
|
||||
&& $periods[0]['label'] === 'Февраль 2026'));
|
||||
});
|
||||
|
||||
test('non team members can not access report routes', function () {
|
||||
$user = User::factory()->create();
|
||||
$foreignTeam = Team::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('reports.periods.index', ['current_team' => $foreignTeam]))
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
test('analysis page renders data from services and medication modules', function () {
|
||||
$user = User::factory()->create();
|
||||
$profile = DepartmentProfile::factory()->create([
|
||||
'name' => 'Клинический профиль',
|
||||
]);
|
||||
$department = Department::factory()->create([
|
||||
'name' => 'Гематологическое',
|
||||
'department_profile_id' => $profile->id,
|
||||
]);
|
||||
$period = ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
'year' => 2026,
|
||||
'month' => 2,
|
||||
]);
|
||||
$serviceCatalog = ServiceCatalog::factory()->create([
|
||||
'code' => 'kdl_plan',
|
||||
'name' => 'КДЛ плановая служба',
|
||||
'sort_order' => 1,
|
||||
'default_price' => 15.50,
|
||||
]);
|
||||
$providerDepartment = Department::factory()->create([
|
||||
'name' => 'Яяя лаборатория',
|
||||
]);
|
||||
|
||||
ServiceEntry::factory()->create([
|
||||
'report_period_id' => $period->id,
|
||||
'service_catalog_id' => $serviceCatalog->id,
|
||||
'provider_department_id' => $providerDepartment->id,
|
||||
'recipient_department_id' => $department->id,
|
||||
'quantity' => 2471,
|
||||
'unit_price' => 15.50,
|
||||
]);
|
||||
|
||||
$row = MedicationExpenseRow::factory()->create([
|
||||
'report_period_id' => $period->id,
|
||||
'department_id' => $department->id,
|
||||
]);
|
||||
|
||||
MedicationExpenseValue::factory()->create([
|
||||
'medication_expense_row_id' => $row->id,
|
||||
'funding_source' => 'oms',
|
||||
'expense_category' => 'medicines',
|
||||
'amount' => 1000,
|
||||
]);
|
||||
MedicationExpenseValue::factory()->create([
|
||||
'medication_expense_row_id' => $row->id,
|
||||
'funding_source' => 'budget',
|
||||
'expense_category' => 'dressing',
|
||||
'amount' => 150,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->get(route('reports.analysis.index', [
|
||||
'current_team' => $user->currentTeam,
|
||||
'period' => $period->id,
|
||||
]));
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('reports/analysis/Index')
|
||||
->where('period.label', 'Февраль 2026')
|
||||
->where('rows.0.department.name', 'Гематологическое')
|
||||
->where('rows.0.services.kdl_plan.quantity', 2471.0)
|
||||
->where('rows.0.services.kdl_plan.amount', 38300.5)
|
||||
->where('rows.0.serviceTotals.total_amount', 38300.5)
|
||||
->where('rows.0.expense.total_expense', 1150.0)
|
||||
->where('rows.0.expense.without_budget_total', 1000.0));
|
||||
});
|
||||
|
||||
test('operations and medication entry pages render for authenticated team members', function () {
|
||||
$user = User::factory()->create();
|
||||
$period = ReportPeriod::factory()->create([
|
||||
'team_id' => $user->currentTeam->id,
|
||||
]);
|
||||
$department = Department::factory()->create();
|
||||
ServiceCatalog::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('reports.operations.index', [
|
||||
'current_team' => $user->currentTeam,
|
||||
'period' => $period->id,
|
||||
'provider_department' => $department->id,
|
||||
]))
|
||||
->assertOk()
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('reports/operations/Index'));
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('reports.medication-expenses.index', [
|
||||
'current_team' => $user->currentTeam,
|
||||
'period' => $period->id,
|
||||
'department' => $department->id,
|
||||
]))
|
||||
->assertOk()
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('reports/medication-expenses/Index'));
|
||||
});
|
||||
Reference in New Issue
Block a user