Files
econom/tests/Feature/ReportManagementTest.php
brusnitsyn fb2e6c58e3
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
first commit
2026-04-06 00:06:00 +09:00

342 lines
11 KiB
PHP

<?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'));
});