کلینیکهای من
diff --git a/docs/api/dashboard.md b/docs/api/dashboard.md
index 30c314d7..8baac33b 100644
--- a/docs/api/dashboard.md
+++ b/docs/api/dashboard.md
@@ -36,7 +36,18 @@ Returns stats and today's schedule for the authenticated clinic owner.
"pending_invitations": 2,
"sms_wallet_balance": 50000,
"unique_patients_count": 34,
- "revenue_period_rials": 12500000
+ "total_patients": 210,
+ "revenue_period_rials": 12500000,
+ "today_payments_rials": 5225000,
+ "week_payments_rials": 560000200
+ },
+ "charts": {
+ "revenue_by_day": [
+ { "label": "۷ خرداد", "amount_rials": 3200000 }
+ ],
+ "appointments_by_day": [
+ { "label": "۷ خرداد", "count": 9 }
+ ]
},
"period": { "from": 1717200000, "to": 1719792000 },
"today_appointments": [
@@ -62,7 +73,10 @@ Returns stats and today's schedule for the authenticated clinic owner.
**Field notes:**
- `sms_wallet_balance` — current SMS wallet balance in Rials (0 if wallet not yet created)
- `unique_patients_count` — distinct patients with at least one session in the `from`–`to` period
+- `total_patients` — distinct patients ever (no period filter)
- `revenue_period_rials` — sum of `final_price_rials` from all patient sessions in the period
+- `today_payments_rials` / `week_payments_rials` — revenue for today / the last 7 days
+- `charts.revenue_by_day` / `charts.appointments_by_day` — last 7 days series (Jalali day label); revenue drives the «میزان درآمد» area chart, appointments the «نمودار تعداد مراجعین» bar chart
- `today_appointments` — up to 5 records, ordered by `slot_start ASC`
- `doctors` — all doctors belonging to this clinic; each includes their appointment count for today
@@ -106,7 +120,14 @@ Returns stats and today's schedule for the authenticated doctor.
"total_ratings": 34,
"sms_wallet_balance": 25000,
"unique_patients_count": 18,
- "revenue_period_rials": 6800000
+ "total_patients": 140,
+ "revenue_period_rials": 6800000,
+ "today_payments_rials": 5225000,
+ "week_payments_rials": 42000000
+ },
+ "charts": {
+ "revenue_by_day": [ { "label": "۷ خرداد", "amount_rials": 3200000 } ],
+ "appointments_by_day": [ { "label": "۷ خرداد", "count": 4 } ]
},
"period": { "from": 1717200000, "to": 1719792000 },
"today_appointments": [
diff --git a/src/Dashboard/Controller/DashboardController.php b/src/Dashboard/Controller/DashboardController.php
index 5e889b1f..67543841 100644
--- a/src/Dashboard/Controller/DashboardController.php
+++ b/src/Dashboard/Controller/DashboardController.php
@@ -132,6 +132,17 @@ class DashboardController extends BaseController
$smsBalance = $this->smsWalletService->getBalance('clinic', $clinicId);
$uniquePatients = $this->patientRecordRepo->countUnique('clinic', $clinicId, $from, $to);
$revenuePeriod = $this->patientSessionRepo->sumRevenue('clinic', $clinicId, $from, $to);
+ $totalPatients = $this->patientRecordRepo->countUnique('clinic', $clinicId, 0, time());
+
+ $rev = $this->revenueDaily('clinic', $clinicId);
+ $apptByDay = $this->appointmentsDaily(function (int $ds, int $de) use ($clinicId): int {
+ return (int) $this->em->createQuery('
+ SELECT COUNT(a.id) FROM App\Appointment\Entity\Appointment a
+ JOIN App\Doctor\Entity\Doctor d WITH a.doctor = d
+ JOIN App\Clinic\Entity\Clinic c WITH d MEMBER OF c.doctors
+ WHERE c.id = :clinicId AND a.slotStart >= :s AND a.slotStart <= :e
+ ')->setParameters(['clinicId' => $clinicId, 's' => $ds, 'e' => $de])->getSingleScalarResult();
+ });
return $this->success([
'clinic' => [
@@ -147,7 +158,14 @@ class DashboardController extends BaseController
'pending_invitations' => $pendingInvitations,
'sms_wallet_balance' => $smsBalance,
'unique_patients_count' => $uniquePatients,
+ 'total_patients' => $totalPatients,
'revenue_period_rials' => $revenuePeriod,
+ 'today_payments_rials' => $rev['today_payments_rials'],
+ 'week_payments_rials' => $rev['week_payments_rials'],
+ ],
+ 'charts' => [
+ 'revenue_by_day' => $rev['revenue'],
+ 'appointments_by_day' => $apptByDay,
],
'period' => ['from' => $from, 'to' => $to],
'today_appointments' => $todayAppts,
@@ -227,6 +245,15 @@ class DashboardController extends BaseController
$smsBalance = $this->smsWalletService->getBalance('doctor', $doctorId);
$uniquePatients = $this->patientRecordRepo->countUnique('doctor', $doctorId, $from, $to);
$revenuePeriod = $this->patientSessionRepo->sumRevenue('doctor', $doctorId, $from, $to);
+ $totalPatients = $this->patientRecordRepo->countUnique('doctor', $doctorId, 0, time());
+
+ $rev = $this->revenueDaily('doctor', $doctorId);
+ $apptByDay = $this->appointmentsDaily(function (int $ds, int $de) use ($doctor): int {
+ return (int) $this->em->createQuery('
+ SELECT COUNT(a.id) FROM App\Appointment\Entity\Appointment a
+ WHERE a.doctor = :d AND a.slotStart >= :s AND a.slotStart <= :e
+ ')->setParameters(['d' => $doctor, 's' => $ds, 'e' => $de])->getSingleScalarResult();
+ });
return $this->success([
'doctor' => [
@@ -242,7 +269,14 @@ class DashboardController extends BaseController
'total_ratings' => (int) ($ratingRow['total'] ?? 0),
'sms_wallet_balance' => $smsBalance,
'unique_patients_count' => $uniquePatients,
+ 'total_patients' => $totalPatients,
'revenue_period_rials' => $revenuePeriod,
+ 'today_payments_rials' => $rev['today_payments_rials'],
+ 'week_payments_rials' => $rev['week_payments_rials'],
+ ],
+ 'charts' => [
+ 'revenue_by_day' => $rev['revenue'],
+ 'appointments_by_day' => $apptByDay,
],
'period' => ['from' => $from, 'to' => $to],
'today_appointments' => $todayAppts,
@@ -250,6 +284,44 @@ class DashboardController extends BaseController
]);
}
+ /**
+ * سری ۷ روز اخیر درآمد (بر اساس PatientSession) + پرداختی امروز و هفته.
+ * @return array{revenue: array, today_payments_rials:int, week_payments_rials:int}
+ */
+ private function revenueDaily(string $entityType, int $entityId): array
+ {
+ $fmt = new \IntlDateFormatter('fa_IR@calendar=persian', \IntlDateFormatter::NONE, \IntlDateFormatter::NONE, 'Asia/Tehran', \IntlDateFormatter::TRADITIONAL, 'd MMMM');
+ $series = [];
+ $todayPay = 0;
+ $weekPay = 0;
+ for ($i = 6; $i >= 0; $i--) {
+ $ds = strtotime('today midnight') - $i * 86400;
+ $de = $ds + 86399;
+ $rev = (int) $this->patientSessionRepo->sumRevenue($entityType, $entityId, $ds, $de);
+ $series[] = ['label' => $fmt->format($ds), 'amount_rials' => $rev];
+ $weekPay += $rev;
+ if ($i === 0) { $todayPay = $rev; }
+ }
+ return ['revenue' => $series, 'today_payments_rials' => $todayPay, 'week_payments_rials' => $weekPay];
+ }
+
+ /**
+ * سری ۷ روز اخیر تعداد نوبت با شمارندهی دلخواه (doctor/clinic).
+ * @param callable(int $dayStart, int $dayEnd): int $counter
+ * @return array
+ */
+ private function appointmentsDaily(callable $counter): array
+ {
+ $fmt = new \IntlDateFormatter('fa_IR@calendar=persian', \IntlDateFormatter::NONE, \IntlDateFormatter::NONE, 'Asia/Tehran', \IntlDateFormatter::TRADITIONAL, 'd MMMM');
+ $series = [];
+ for ($i = 6; $i >= 0; $i--) {
+ $ds = strtotime('today midnight') - $i * 86400;
+ $de = $ds + 86399;
+ $series[] = ['label' => $fmt->format($ds), 'count' => $counter($ds, $de)];
+ }
+ return $series;
+ }
+
// ── Secretary Dashboard ──────────────────────────────────────────────────
#[Route('/api/v1/dashboard/secretary', methods: ['GET'])]