Files
clinicpro/tests/Dashboard/DashboardChartPeriodTest.php
T
hamed 62a9fd87c3 feat: Implement Jalali calendar support for dashboard charts
- Added support for Jalali calendar in the dashboard, allowing charts to display data based on the current Jalali month and year.
- Updated the API to return `patients_year`, `patients_month`, and `revenue_year` parameters for the dashboard charts.
- Refactored the dashboard controller to handle Jalali date calculations and queries.
- Modified the frontend components to utilize the new Jalali date parameters and reflect changes in the UI.
- Removed the status column from the NewAppointmentsTable as status management is now handled on the appointments page.
- Added tests to ensure the correct functioning of the new Jalali chart period features.
2026-07-18 21:44:01 +03:30

132 lines
5.0 KiB
PHP

<?php
namespace App\Tests\Dashboard;
use App\Appointment\Entity\Appointment;
use App\Clinic\Entity\Clinic;
use App\Doctor\Entity\Doctor;
use App\Tests\ApiTestCase;
/**
* GET /api/v1/dashboard/{clinic,doctor} — chart series periods.
*
* «نمودار تعداد بیماران» is one Jalali month (day-by-day) and «میزان درآمد» is
* one Jalali year (month-by-month); both default to the current Jalali period
* and are overridable via patients_year / patients_month / revenue_year.
*/
class DashboardChartPeriodTest extends ApiTestCase
{
/** @return array{0:int, 1:int} [jalaliYear, jalaliMonth] */
private function currentJalali(): array
{
$cal = \IntlCalendar::createInstance(new \DateTimeZone('Asia/Tehran'), 'fa_IR@calendar=persian');
return [$cal->get(\IntlCalendar::FIELD_YEAR), $cal->get(\IntlCalendar::FIELD_MONTH) + 1];
}
private function jalaliMonthLength(int $year, int $month): int
{
$cal = \IntlCalendar::createInstance(new \DateTimeZone('Asia/Tehran'), 'fa_IR@calendar=persian');
$cal->set(\IntlCalendar::FIELD_YEAR, $year);
$cal->set(\IntlCalendar::FIELD_MONTH, $month - 1);
$cal->set(\IntlCalendar::FIELD_DAY_OF_MONTH, 1);
return $cal->getActualMaximum(\IntlCalendar::FIELD_DAY_OF_MONTH);
}
private function clinicWithDoctor(): array
{
$clinicOwner = $this->createUser(['ROLE_CLINIC']);
$clinic = new Clinic($clinicOwner);
$clinic->setName('کلینیک نمودار');
$docOwner = $this->createUser(['ROLE_DOCTOR']);
$doctor = new Doctor($docOwner, 'حمیدی');
$clinic->getDoctors()->add($doctor);
$this->em->persist($doctor);
$this->em->persist($clinic);
$this->em->flush();
return [$clinicOwner, $doctor];
}
public function testClinicChartsDefaultToCurrentJalaliPeriod(): void
{
[$owner] = $this->clinicWithDoctor();
[$year, $month] = $this->currentJalali();
$res = $this->authJson('GET', '/api/v1/dashboard/clinic', $owner);
self::assertSame(200, $this->responseCode());
self::assertSame(
['patients_year' => $year, 'patients_month' => $month, 'revenue_year' => $year],
$res['data']['charts_period']
);
self::assertCount($this->jalaliMonthLength($year, $month), $res['data']['charts']['appointments_by_day']);
self::assertCount(12, $res['data']['charts']['revenue_by_month']);
}
public function testClinicChartsHonourRequestedPeriod(): void
{
[$owner] = $this->clinicWithDoctor();
// اسفند ۱۴۰۳ سال کبیسه است → ۳۰ روز
$res = $this->authJson('GET', '/api/v1/dashboard/clinic?patients_year=1403&patients_month=12&revenue_year=1402', $owner);
self::assertSame(200, $this->responseCode());
self::assertSame(
['patients_year' => 1403, 'patients_month' => 12, 'revenue_year' => 1402],
$res['data']['charts_period']
);
self::assertCount(30, $res['data']['charts']['appointments_by_day']);
}
public function testTodayAppointmentIsCountedOnItsJalaliDay(): void
{
[$owner, $doctor] = $this->clinicWithDoctor();
$patient = $this->createUser(['ROLE_USER']);
$start = time();
$this->em->persist(new Appointment($doctor, $patient, $start, $start + 1_800));
$this->em->flush();
$res = $this->authJson('GET', '/api/v1/dashboard/clinic', $owner);
$days = $res['data']['charts']['appointments_by_day'];
$cal = \IntlCalendar::createInstance(new \DateTimeZone('Asia/Tehran'), 'fa_IR@calendar=persian');
$todayIndex = $cal->get(\IntlCalendar::FIELD_DAY_OF_MONTH) - 1;
self::assertGreaterThanOrEqual(1, $days[$todayIndex]['count'], 'today\'s slot must land on today\'s bar');
}
public function testOutOfRangeParamsAreClamped(): void
{
[$owner] = $this->clinicWithDoctor();
[$year] = $this->currentJalali();
$res = $this->authJson('GET', '/api/v1/dashboard/clinic?patients_month=99&patients_year=9999&revenue_year=0', $owner);
self::assertSame(200, $this->responseCode());
$period = $res['data']['charts_period'];
self::assertSame(12, $period['patients_month']);
self::assertSame(1500, $period['patients_year']);
// revenue_year=0 is falsy → falls back to the current Jalali year
self::assertSame($year, $period['revenue_year']);
}
public function testDoctorChartsUseSameJalaliPeriod(): void
{
$owner = $this->createUser(['ROLE_DOCTOR']);
$doctor = new Doctor($owner, 'حمیدی');
$this->em->persist($doctor);
$this->em->flush();
$res = $this->authJson('GET', '/api/v1/dashboard/doctor?patients_year=1403&patients_month=1', $owner);
self::assertSame(200, $this->responseCode());
self::assertSame(1403, $res['data']['charts_period']['patients_year']);
self::assertCount(31, $res['data']['charts']['appointments_by_day']);
}
}