- Add SendSmsMessage class for encapsulating SMS message data. - Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS. - Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates. - Develop SendSmsHandler for handling SMS sending messages. - Create SmsService to manage SMS dispatching and logging. - Add UserProfileController for managing user profiles with CRUD operations. - Implement UserProfile entity and repository for user profile data management. - Update symfony.lock and bootstrap.php for project dependencies and environment setup.
165 lines
5.6 KiB
Markdown
165 lines
5.6 KiB
Markdown
# نکات پیادهسازی — تسک ۱۲: ماژول امتیاز و نظرات
|
|
|
|
## ⚠ تناقض نام فیلدها: API vs DB (بسیار مهم!)
|
|
|
|
فیلدهایی که **کلاینت ارسال میکند** با نام فیلدهای **پایگاه داده** متفاوت هستند:
|
|
|
|
| نام در Request (API) | نام در DB (Drupal field) | توضیح |
|
|
|---------------------|------------------------|-------|
|
|
| `correct_diagnosis` | `accuracy_of_diagnosis` | دقت تشخیص |
|
|
| `doctor_skill` | `doctor_expertise` | مهارت پزشک |
|
|
| `behavior_doctor` | `doctor_behavior` | برخورد پزشک |
|
|
| `office_cleaning` | `clinic_cleanliness` | نظافت مطب |
|
|
| `time_in_office` | `waiting_time_at_clinic` | زمان انتظار |
|
|
| `doctor` | `doctor_id` | شناسه دکتر (integer) |
|
|
| `rate` | `starts` | امتیاز ستارهای (DECIMAL 10,2) |
|
|
|
|
**در Symfony باید:**
|
|
- ورودی را با نامهای API دریافت کن (`correct_diagnosis`, ...)
|
|
- در Entity و DB با نامهای Drupal ذخیره کن (`accuracy_of_diagnosis`, ...)
|
|
|
|
## نمونه واقعی Request — POST /api/v1/clinicpro/rate
|
|
```json
|
|
{
|
|
"correct_diagnosis": 100,
|
|
"doctor_skill": 100,
|
|
"behavior_doctor": 100,
|
|
"office_cleaning": 100,
|
|
"time_in_office": 100,
|
|
"doctor": 1,
|
|
"rate": 2
|
|
}
|
|
```
|
|
|
|
## نمونه واقعی Request — PATCH /api/v1/clinicpro/rate/{uuid}
|
|
```json
|
|
{
|
|
"correct_diagnosis": 50,
|
|
"doctor_skill": 60,
|
|
"behavior_doctor": 70,
|
|
"office_cleaning": 80,
|
|
"time_in_office": 90,
|
|
"doctor": 1,
|
|
"rate": 2
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## سیستم امتیازدهی وزنی
|
|
|
|
Rating در Drupal **5 معیار جداگانه** دارد که هر کدام مقدار 0-100 میگیرند
|
|
و با وزنهای متفاوت محاسبه میشوند:
|
|
|
|
```php
|
|
$weights = [
|
|
"doctor_behavior" => 1.5, // behavior_doctor در API
|
|
"accuracy_of_diagnosis" => 3.0, // correct_diagnosis در API
|
|
"waiting_time_at_clinic" => 1.0, // time_in_office در API
|
|
"doctor_expertise" => 2.0, // doctor_skill در API
|
|
"clinic_cleanliness" => 1.0, // office_cleaning در API
|
|
];
|
|
|
|
// فرمول محاسبه:
|
|
$weightedAverage = SUM(value * weight) / SUM(weights); // از 100
|
|
$stars = ($weightedAverage / 100) * 5; // از 5
|
|
```
|
|
|
|
### پیادهسازی calculateDoctorRating در Symfony
|
|
```php
|
|
public function calculateRating(array $apiScores): array
|
|
{
|
|
// نگاشت نامهای API به نامهای DB
|
|
$mapped = [
|
|
'accuracy_of_diagnosis' => $apiScores['correct_diagnosis'] ?? 0,
|
|
'doctor_expertise' => $apiScores['doctor_skill'] ?? 0,
|
|
'doctor_behavior' => $apiScores['behavior_doctor'] ?? 0,
|
|
'clinic_cleanliness' => $apiScores['office_cleaning'] ?? 0,
|
|
'waiting_time_at_clinic' => $apiScores['time_in_office'] ?? 0,
|
|
];
|
|
|
|
$weights = [
|
|
'doctor_behavior' => 1.5,
|
|
'accuracy_of_diagnosis' => 3.0,
|
|
'waiting_time_at_clinic' => 1.0,
|
|
'doctor_expertise' => 2.0,
|
|
'clinic_cleanliness' => 1.0,
|
|
];
|
|
|
|
$totalScore = 0.0;
|
|
$totalWeight = 0.0;
|
|
|
|
foreach ($weights as $key => $weight) {
|
|
$totalScore += $mapped[$key] * $weight;
|
|
$totalWeight += $weight;
|
|
}
|
|
|
|
$weightedAverage = $totalWeight > 0 ? $totalScore / $totalWeight : 0;
|
|
$stars = ($weightedAverage / 100) * 5;
|
|
|
|
return [
|
|
'percent' => round($weightedAverage, 1),
|
|
'starts' => round(min(5.0, max(0.0, $stars)), 2),
|
|
// ⚠️ نام فیلد DB: "starts" است نه "stars"!
|
|
];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## آمار دکتر — GET /api/v1/clinicpro-comment/doctor-rate/{doctorUuid}
|
|
|
|
```
|
|
URL: /api/v1/clinicpro-comment/doctor-rate/{uuid_دکتر}
|
|
Auth: عمومی (بدون احراز هویت)
|
|
```
|
|
|
|
```json
|
|
{
|
|
"average_stars": 4.3,
|
|
"total_rates": 87,
|
|
"averages": {
|
|
"average_doctor_behavior": 82.1,
|
|
"average_accuracy_of_diagnosis": 88.5,
|
|
"average_waiting_time_at_clinic": 65.3,
|
|
"average_doctor_expertise": 90.2,
|
|
"average_clinic_cleanliness": 78.4
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## تأیید نظرات
|
|
نظرات با `approved=0` ذخیره میشوند.
|
|
ادمین آنها را از `GET /api/v1/clinicpro/unverified-comments/{doctorId}` میبیند.
|
|
سپس با `PATCH /api/v1/clinicpro/unverified-comments/{commentId}` تأیید میکند.
|
|
|
|
---
|
|
|
|
## اعتبارسنجی مقادیر Rating
|
|
هر معیار باید بین 0 تا 100 باشد:
|
|
```php
|
|
#[Assert\Range(min: 0, max: 100)]
|
|
```
|
|
|
|
---
|
|
|
|
## مجوزها
|
|
```
|
|
POST /api/v1/clinicpro/rate → احراز هویتشده
|
|
PATCH /api/v1/clinicpro/rate/{uuid} → owner (هر کاربر فقط یک امتیاز برای هر دکتر)
|
|
DELETE /api/v1/rate/doctor/{uuid} → ROLE_ADMIN
|
|
GET /api/v1/clinicpro/rate/{uuid} → owner (امتیاز کاربر برای دکتر مشخص)
|
|
GET /api/v1/clinicpro-comment/doctor-rate/{uuid} → عمومی (آمار کلی دکتر)
|
|
POST /api/v1/clinicpro/comment → احراز هویتشده
|
|
PATCH /api/v1/clinicpro/comment/{uuid} → owner یا ROLE_ADMIN
|
|
DELETE /api/v1/clinicpro/comment/{uuid} → owner یا ROLE_ADMIN
|
|
GET /api/v1/clinicpro/comment/{uuid} → احراز هویتشده
|
|
GET /api/v1/clinicpro/comments/{doctorId} → احراز هویتشده (فقط approved)
|
|
GET /api/v1/clinicpro/unverified-comments/{doctorId} → ROLE_ADMIN
|
|
PATCH /api/v1/clinicpro/unverified-comments/{id} → ROLE_ADMIN (تأیید/رد نظر)
|
|
POST /api/v1/clinicpro/like → احراز هویتشده
|
|
PATCH /api/v1/clinicpro/like/{uuid} → owner
|
|
```
|