- 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.
132 lines
5.0 KiB
PHP
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']);
|
|
}
|
|
}
|