feat(doctors): add activity start date field with Persian calendar in admin panel
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
# افزودن فیلد «تاریخ شروع فعالیت» (سال تجربه) در پنل ادمین با تقویم شمسی
|
||||
|
||||
## پروژه
|
||||
|
||||
`clinicpro` (Admin SPA + کمی backend/docs). سایت عمومی `nobat724_front` تغییری لازم ندارد (توضیح در «نکات مهم»).
|
||||
|
||||
## زمینه
|
||||
|
||||
هر پزشک باید «سال تجربه» داشته باشد. این عدد در backend از فیلد `activity_time` (تاریخ شروع کار، بهصورت Unix timestamp) محاسبه میشود و همهچیزِ backend و سایت عمومی از قبل آماده است:
|
||||
|
||||
- `Doctor::$activityTime` (ستون `activity_time`, `integer`, nullable) + `getExperience()` که سال تجربه را حساب میکند.
|
||||
- `toDetailArray()` هم `experience` (عدد سال) و هم `activity_time` (رشتهٔ timestamp) را برمیگرداند.
|
||||
- endpointهای `POST /api/v1/doctor` و `PATCH /api/v1/doctor/{uuid}` کلید `activity_time` را در بدنه میپذیرند (`hydrate...` → `setActivityTime((int) $data['activity_time'])`).
|
||||
- سایت عمومی در `nobat724_front/components/doctor/detailDoctor/Title.js` از قبل `{doctor?.experience} سال تجربه` را نشان میدهد.
|
||||
|
||||
مشکل این است که **پنل ادمین (Admin SPA) هیچ فیلدی برای ستکردن این تاریخ ندارد**، پس `activity_time` همیشه `null` میماند، `getExperience()` صفر برمیگرداند و در صفحهٔ عمومی «۰ سال تجربه» نمایش داده میشود (مثال: `/doctor/fbc11068-dd01-4c0c-9dab-ab86c38061ca`).
|
||||
|
||||
## مشکل / هدف
|
||||
|
||||
در فرمهای پزشک در Admin SPA یک فیلد «تاریخ شروع فعالیت» با **تقویم شمسی** اضافه شود که ترتیب انتخاب آن **سال → ماه → روز** باشد. این کامپوننت از قبل در پروژه وجود دارد: `PersianDatePicker` با prop `enableYearPicker`. مقدار انتخابشده باید به Unix timestamp (ثانیه) تبدیل و در کلید `activity_time` به API ارسال شود؛ و هنگام ویرایش، `activity_time` موجود باید به تاریخ برای نمایش در picker تبدیل شود.
|
||||
|
||||
## فایلهای مرتبط
|
||||
|
||||
| فایل | نقش |
|
||||
|------|-----|
|
||||
| `clinicpro/assets/admin/pages/DoctorDetailPage.tsx` | صفحهٔ اصلی ویرایش پزشک (هم ادمین هم پروفایل خود پزشک via `DoctorProfilePage`) — فرم ویرایش اینجاست |
|
||||
| `clinicpro/assets/admin/pages/DoctorFormPage.tsx` | فرم «افزودن پزشک جدید» (POST) |
|
||||
| `clinicpro/assets/admin/components/ui/PersianDatePicker.tsx` | تقویم شمسی موجود؛ prop `enableYearPicker` = ترتیب سال→ماه→روز |
|
||||
| `clinicpro/assets/admin/lib/utils.ts` | `toDate()`، `toGregorianDate()`، `formatDate()` برای تبدیل تاریخ |
|
||||
| `clinicpro/src/Doctor/Controller/DoctorController.php` | annotationهای `OA\Property` بدنهٔ create/update (فاقد `activity_time`) |
|
||||
| `clinicpro/docs/api/doctor.md` | مستندات request body (فاقد `activity_time`) |
|
||||
|
||||
## وضعیت فعلی
|
||||
|
||||
### backend (آماده — فقط annotation/doc ناقص)
|
||||
|
||||
```php
|
||||
// src/Doctor/Entity/Doctor.php
|
||||
public function getExperience(): int
|
||||
{
|
||||
if ($this->activityTime === null) {
|
||||
return 0;
|
||||
}
|
||||
return max(0, (int)((time() - $this->activityTime) / (365.25 * 24 * 3600)));
|
||||
}
|
||||
|
||||
// src/Doctor/Controller/DoctorController.php (hydrate مشترک create/update)
|
||||
if (array_key_exists('activity_time', $data)) $doctor->setActivityTime((int) $data['activity_time']);
|
||||
```
|
||||
|
||||
### کامپوننت تقویم (قرارداد ورودی/خروجی)
|
||||
|
||||
```tsx
|
||||
// PersianDatePicker.tsx
|
||||
interface Props {
|
||||
value: string; // YYYY-MM-DD میلادی
|
||||
onChange: (v: string) => void;
|
||||
placeholder?: string;
|
||||
height?: number;
|
||||
minWidth?: number;
|
||||
enableYearPicker?: boolean; // سال→ماه→روز
|
||||
}
|
||||
```
|
||||
|
||||
مقدار picker یک رشتهٔ **میلادی `YYYY-MM-DD`** است (نمایش داخلیاش شمسی است). نمونهٔ استفادهٔ موجود در `RepresentationProfilePage.tsx`:
|
||||
|
||||
```tsx
|
||||
<PersianDatePicker value={birthDate} onChange={setBirthDate} placeholder="تاریخ تولد" enableYearPicker />
|
||||
```
|
||||
|
||||
### فرم ویرایش پزشک — `DoctorDetailPage.tsx` (وضعیت فعلی، بدون فیلد تاریخ)
|
||||
|
||||
```tsx
|
||||
// interface (خط ~44)
|
||||
experience: number; activity_time: string | null; medical_system_code: string | null;
|
||||
|
||||
// zod schema (خط ~2191)
|
||||
const editSchema = z.object({
|
||||
name: z.string().min(2, 'نام حداقل ۲ کاراکتر'),
|
||||
gender: z.enum(['man', 'woman']).optional().or(z.literal('')),
|
||||
degree: z.string().optional().or(z.literal('')),
|
||||
medical_system_code: z.string().max(30).optional().or(z.literal('')),
|
||||
// ... activity_time نیست
|
||||
});
|
||||
|
||||
// reset مقادیر هنگام لود (خط ~2383)
|
||||
reset({
|
||||
name: doctor.name,
|
||||
gender: (doctor.gender as any) ?? '',
|
||||
degree: doctor.degree ?? '',
|
||||
medical_system_code: doctor.medical_system_code ?? '',
|
||||
// ... activity_time نیست
|
||||
});
|
||||
|
||||
// ارسال PATCH (خط ~2415)
|
||||
mutationFn: (body: EditForm) => api.patch<ApiResponse<any>>(`/api/v1/doctor/${uuid}`, {
|
||||
title: body.name,
|
||||
gender: editGender || undefined,
|
||||
degree: body.degree || undefined,
|
||||
medical_system_code: body.medical_system_code || undefined,
|
||||
info: body.info || undefined,
|
||||
// ... activity_time نیست
|
||||
}),
|
||||
|
||||
// JSX فرم — بعد از grid «درجه تحصیلی / کد نظام پزشکی» (خط ~2878)
|
||||
```
|
||||
|
||||
### فرم ساخت پزشک — `DoctorFormPage.tsx` (خط ~282)
|
||||
|
||||
```tsx
|
||||
mutationFn: (values: FormValues) =>
|
||||
api.post<ApiResponse<{ uuid: string }>>(createDoctorEndpoint, {
|
||||
// ...
|
||||
gender: gender || undefined,
|
||||
degree: values.degree || undefined,
|
||||
medical_system_code: values.medical_system_code || undefined,
|
||||
info: values.info || undefined,
|
||||
// ... activity_time نیست
|
||||
}),
|
||||
```
|
||||
|
||||
## وظایف
|
||||
|
||||
### ۱. افزودن فیلد تاریخ به فرم ویرایش `DoctorDetailPage.tsx` (اصلی)
|
||||
|
||||
state جدا برای تاریخ نگهدار (مثل الگوی `editGender`) تا نیازی به دستزدن به zod نباشد:
|
||||
|
||||
```tsx
|
||||
const [editActivityDate, setEditActivityDate] = useState(''); // YYYY-MM-DD میلادی یا ''
|
||||
```
|
||||
|
||||
هنگام لود در `useEffect`/`reset` مقدار اولیه را از `activity_time` (ثانیه) بساز:
|
||||
|
||||
```tsx
|
||||
setEditActivityDate(
|
||||
doctor.activity_time ? toGregorianDate(toDate(Number(doctor.activity_time))!) : ''
|
||||
);
|
||||
```
|
||||
|
||||
(از `../lib/utils` → `toDate`, `toGregorianDate` را import کن اگر نیستند.)
|
||||
|
||||
در JSX، بعد از grid «درجه تحصیلی / کد نظام پزشکی» (خط ~۲۸۷۸) یک `EditField` اضافه کن:
|
||||
|
||||
```tsx
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<EditField label="تاریخ شروع فعالیت">
|
||||
<PersianDatePicker
|
||||
value={editActivityDate}
|
||||
onChange={setEditActivityDate}
|
||||
placeholder="انتخاب تاریخ"
|
||||
enableYearPicker
|
||||
minWidth={200}
|
||||
/>
|
||||
</EditField>
|
||||
</div>
|
||||
```
|
||||
|
||||
در `updateMut` کلید `activity_time` را اضافه کن (تبدیل به ثانیه؛ خالی → `null` تا پاک شود):
|
||||
|
||||
```tsx
|
||||
activity_time: editActivityDate
|
||||
? Math.floor(new Date(`${editActivityDate}T12:00:00`).getTime() / 1000)
|
||||
: null,
|
||||
```
|
||||
|
||||
> نکته: backend فقط وقتی کلید `activity_time` در بدنه **باشد** آن را ست میکند؛ ارسال `null` باعث `setActivityTime((int) null) = 0` میشود. اگر میخواهی «پاککردن» واقعی (بازگشت به null) پشتیبانی شود، ببین وظیفهٔ ۳ (backend باید `null` را جدا از عدد مدیریت کند). در غیر این صورت وقتی خالی است اصلاً کلید را نفرست:
|
||||
> ```tsx
|
||||
> ...(editActivityDate ? { activity_time: Math.floor(new Date(`${editActivityDate}T12:00:00`).getTime()/1000) } : {}),
|
||||
> ```
|
||||
> رویکرد دوم (نفرستادن هنگام خالی) سادهتر و بدون تغییر backend است — همان را استفاده کن مگر پاککردن لازم باشد.
|
||||
|
||||
همچنین (اختیاری ولی مفید): در بخش نمایش، کارت `experience` از قبل هست (`InfoCard ... label="سابقه (سال)"`); میتوانی زیرش تاریخ شروع را با `formatDate(doctor.activity_time)` نشان دهی.
|
||||
|
||||
### ۲. افزودن همان فیلد به فرم ساخت `DoctorFormPage.tsx`
|
||||
|
||||
- `const [activityDate, setActivityDate] = useState('')`
|
||||
- در JSX کنار سایر فیلدهای «اطلاعات حرفهای» یک `PersianDatePicker ... enableYearPicker` با همان الگو.
|
||||
- در بدنهٔ `api.post(createDoctorEndpoint, {...})` هنگام مقدار داشتن، `activity_time` را به ثانیه اضافه کن (همان تبدیل وظیفهٔ ۱).
|
||||
|
||||
### ۳. (فقط اگر «پاککردن» لازم است) اصلاح hydrate در backend
|
||||
|
||||
اگر تصمیم گرفتی ارسال `null` را پشتیبانی کنی، در `DoctorController` جایی که `activity_time` hydrate میشود مقدار `null` را جدا مدیریت کن تا به `0` تبدیل نشود:
|
||||
|
||||
```php
|
||||
if (array_key_exists('activity_time', $data)) {
|
||||
$doctor->setActivityTime($data['activity_time'] !== null ? (int) $data['activity_time'] : null);
|
||||
}
|
||||
```
|
||||
|
||||
اگر رویکرد «نفرستادن هنگام خالی» را انتخاب کردی، این وظیفه لازم نیست.
|
||||
|
||||
### ۴. بهروزرسانی annotation و مستندات API
|
||||
|
||||
- در `DoctorController` به بدنهٔ **هر دو** endpoint (create ~خط ۶۳ و update ~خط ۲۷۱) این property را اضافه کن:
|
||||
```php
|
||||
new OA\Property(property: 'activity_time', type: 'integer', nullable: true, description: 'Unix timestamp (ثانیه) تاریخ شروع فعالیت؛ مبنای محاسبهٔ سال تجربه'),
|
||||
```
|
||||
- در `clinicpro/docs/api/doctor.md`: به جدول request body هر دو endpoint (POST و PATCH) ردیف `activity_time` (integer, Unix seconds, nullable) را اضافه کن و توضیح بده که `experience` در پاسخ از همین فیلد محاسبه میشود.
|
||||
|
||||
## نکات مهم
|
||||
|
||||
- **تقویم موجود را استفاده کن، جدید نساز:** `PersianDatePicker` با `enableYearPicker` دقیقاً ترتیب سال→ماه→روز را میدهد (همان که کاربر گفت «قبلاً این تقویم را نوشتی»). از `PersianDateInput` (که native `type=date` میلادی است) استفاده **نکن**.
|
||||
- **قرارداد مقدار picker میلادی است** (`YYYY-MM-DD`)؛ نمایش داخلی خودش شمسی است. تبدیل به/از Unix timestamp سمت فرم انجام میشود.
|
||||
- **واحد timestamp ثانیه است** (نه میلیثانیه) — `getExperience()` با `time()` (ثانیه) کار میکند. حتماً `/1000` بزن.
|
||||
- برای ثبات در برابر timezone از `T12:00:00` (ظهر) هنگام ساخت `Date` استفاده کن تا با تبدیل شمسی یکروز-جابهجایی رخ ندهد (الگوی موجود در `utils.toDate`).
|
||||
- `DoctorProfilePage` صرفاً `<DoctorDetailPage isOwnProfile />` است؛ با اصلاح `DoctorDetailPage` هر دو مسیر (ادمین و پروفایل خود پزشک) پوشش داده میشوند.
|
||||
- **سایت عمومی تغییری لازم ندارد:** `Title.js` از قبل `doctor.experience` را رندر میکند؛ بهمحض ستشدن `activity_time`، مقدار درست نمایش داده میشود. (اختیاری: اگر خواستی وقتی `experience === 0` عبارت «۰ سال تجربه» نمایش داده نشود، این یک تغییر کوچک نمایشی در `nobat724_front` است، خارج از این پرامپت.)
|
||||
- بعد از تغییر TSX: `ddev exec npx tsc --noEmit --project tsconfig.json` و `ddev exec yarn dev` برای build.
|
||||
- بعد از تغییر annotation کنترلر: `ddev exec php bin/console cache:clear` و طبق قانون پروژه `docs/api/doctor.md` را در همین session بهروز کن.
|
||||
@@ -22,12 +22,13 @@ import 'leaflet/dist/leaflet.css';
|
||||
import { api, ApiError } from '../lib/api';
|
||||
import { useAuthStore } from '../stores/authStore';
|
||||
import type { ApiResponse } from '../lib/api';
|
||||
import { formatNumber, iranMobileOptionalSchema } from '../lib/utils';
|
||||
import { formatNumber, iranMobileOptionalSchema, toDate, toGregorianDate } from '../lib/utils';
|
||||
import MobileInput from '../components/ui/MobileInput';
|
||||
import Modal from '../components/ui/Modal';
|
||||
import ConfirmDialog from '../components/ui/ConfirmDialog';
|
||||
import NotificationMobileCard from '../components/ui/NotificationMobileCard';
|
||||
import GlobalSearchableSelect from '../components/ui/SearchableSelect';
|
||||
import PersianDatePicker from '../components/ui/PersianDatePicker';
|
||||
|
||||
// Fix leaflet default marker icons
|
||||
delete (L.Icon.Default.prototype as any)._getIconUrl;
|
||||
@@ -2338,6 +2339,7 @@ export default function DoctorDetailPage({ isOwnProfile = false }: { isOwnProfil
|
||||
const [editingAddr, setEditingAddr] = useState<AddressData | null>(null);
|
||||
const [deletingAddrId, setDeletingAddrId] = useState<string | null>(null);
|
||||
const [editGender, setEditGender] = useState<'man' | 'woman' | ''>('');
|
||||
const [editActivityDate, setEditActivityDate] = useState('');
|
||||
|
||||
// ── Queries ──
|
||||
|
||||
@@ -2396,6 +2398,9 @@ export default function DoctorDetailPage({ isOwnProfile = false }: { isOwnProfil
|
||||
social_linkedin: doctor.social_media?.linkedin ?? '',
|
||||
});
|
||||
setEditGender((doctor.gender as any) ?? '');
|
||||
setEditActivityDate(
|
||||
doctor.activity_time ? toGregorianDate(toDate(Number(doctor.activity_time))!) : ''
|
||||
);
|
||||
}
|
||||
}, [doctor, reset]);
|
||||
|
||||
@@ -2419,6 +2424,9 @@ export default function DoctorDetailPage({ isOwnProfile = false }: { isOwnProfil
|
||||
medical_system_code: body.medical_system_code || undefined,
|
||||
mobile_number: body.mobile_number || undefined,
|
||||
info: body.info || undefined,
|
||||
...(editActivityDate
|
||||
? { activity_time: Math.floor(new Date(`${editActivityDate}T12:00:00`).getTime() / 1000) }
|
||||
: {}),
|
||||
specialties: body.specialties ?? [],
|
||||
doctor_services: body.services ?? [],
|
||||
social_media: {
|
||||
@@ -2877,6 +2885,18 @@ export default function DoctorDetailPage({ isOwnProfile = false }: { isOwnProfil
|
||||
</EditField>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<EditField label="تاریخ شروع فعالیت" hint="مبنای محاسبهٔ سال تجربه">
|
||||
<PersianDatePicker
|
||||
value={editActivityDate}
|
||||
onChange={setEditActivityDate}
|
||||
placeholder="انتخاب تاریخ"
|
||||
enableYearPicker
|
||||
minWidth={200}
|
||||
/>
|
||||
</EditField>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<EditField label="بیوگرافی">
|
||||
<textarea rows={3} className="cp-textarea" placeholder="معرفی کوتاهی از پزشک..." {...register('info')} style={{ resize: 'none' }} />
|
||||
|
||||
@@ -14,6 +14,7 @@ import { api } from '../lib/api';
|
||||
import type { ApiResponse } from '../lib/api';
|
||||
import SearchableSelect from '../components/ui/SearchableSelect';
|
||||
import MobileInput from '../components/ui/MobileInput';
|
||||
import PersianDatePicker from '../components/ui/PersianDatePicker';
|
||||
import { iranMobileSchema } from '../lib/utils';
|
||||
import { useAuthStore } from '../stores/authStore';
|
||||
|
||||
@@ -261,6 +262,7 @@ export default function DoctorFormPage() {
|
||||
primaryRole === 'representation' ? '/api/v1/representation/doctor' : '/api/v1/admin/doctors';
|
||||
const [selectedSpecialties, setSelectedSpecialties] = useState<number[]>([]);
|
||||
const [gender, setGender] = useState<'man' | 'woman' | ''>('');
|
||||
const [activityDate, setActivityDate] = useState('');
|
||||
|
||||
const specialtiesQ = useQuery({
|
||||
queryKey: ['specialties-list'],
|
||||
@@ -286,6 +288,9 @@ export default function DoctorFormPage() {
|
||||
degree: values.degree || undefined,
|
||||
medical_system_code: values.medical_system_code || undefined,
|
||||
info: values.info || undefined,
|
||||
...(activityDate
|
||||
? { activity_time: Math.floor(new Date(`${activityDate}T12:00:00`).getTime() / 1000) }
|
||||
: {}),
|
||||
specialties: selectedSpecialties,
|
||||
}),
|
||||
onSuccess: (res) => {
|
||||
@@ -369,6 +374,18 @@ export default function DoctorFormPage() {
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<Field label="تاریخ شروع فعالیت">
|
||||
<PersianDatePicker
|
||||
value={activityDate}
|
||||
onChange={setActivityDate}
|
||||
placeholder="انتخاب تاریخ"
|
||||
enableYearPicker
|
||||
minWidth={200}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<Field label="بیوگرافی">
|
||||
<textarea rows={3} className="cp-textarea" placeholder="معرفی کوتاهی از پزشک..." {...register('info')} style={{ resize: 'none' }} />
|
||||
|
||||
@@ -295,6 +295,9 @@ Delete a user.
|
||||
|-------|------|----------|-------------|
|
||||
| `mobile` | string | ✅ | موبایل ورود؛ باید فرمت معتبر موبایل ایران داشته باشد (`^09\d{9}$`) — ارقام فارسی/عربی به انگلیسی نرمال میشوند |
|
||||
| `name` | string | ✅ | نام پزشک |
|
||||
| `gender` / `degree` / `medical_system_code` / `info` | string | ❌ | اطلاعات حرفهای |
|
||||
| `activity_time` | integer | ❌ | Unix timestamp (ثانیه) تاریخ شروع فعالیت؛ مبنای محاسبهٔ سال تجربه |
|
||||
| `specialties` | integer[] | ❌ | آرایهٔ IDهای تخصص |
|
||||
|
||||
#### Errors
|
||||
| Code | HTTP | Description |
|
||||
|
||||
@@ -34,6 +34,7 @@ Create a doctor profile for the authenticated user.
|
||||
| `info` | string | ❌ | Bio/description |
|
||||
| `specialties` | integer[] | ❌ | Array of specialty IDs |
|
||||
| `doctor_services` | integer[] | ❌ | Array of doctor service IDs |
|
||||
| `activity_time` | integer | ❌ | Unix timestamp (ثانیه) تاریخ شروع فعالیت؛ مبنای محاسبهٔ `experience` (سال تجربه) در پاسخ |
|
||||
|
||||
### Response `201`
|
||||
```json
|
||||
|
||||
@@ -349,6 +349,7 @@ Get yearly earnings dashboard for a representation.
|
||||
| `mobile` | string | ✅ |
|
||||
| `name` | string | ✅ |
|
||||
| `gender` / `degree` / `medical_system_code` / `info` | string | ❌ |
|
||||
| `activity_time` | integer (Unix ts، تاریخ شروع فعالیت) | ❌ |
|
||||
| `specialties` | integer[] | ❌ |
|
||||
|
||||
#### Response `201`
|
||||
|
||||
@@ -418,6 +418,7 @@ class AdminApiController extends BaseController
|
||||
if (!empty($data['medical_system_code'])) $doctor->setMedicalSystemCode($data['medical_system_code']);
|
||||
if (!empty($data['info'])) $doctor->setInfo($data['info']);
|
||||
if (!empty($data['mobile_number'])) $doctor->setMobileNumber($data['mobile_number']);
|
||||
if (!empty($data['activity_time'])) $doctor->setActivityTime((int) $data['activity_time']);
|
||||
|
||||
if (!empty($data['specialties']) && is_array($data['specialties'])) {
|
||||
foreach ($data['specialties'] as $id) {
|
||||
|
||||
@@ -61,6 +61,7 @@ class DoctorController extends BaseController
|
||||
new OA\Property(property: 'medical_system_code', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'degree', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'info', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'activity_time', type: 'integer', nullable: true, description: 'Unix timestamp (seconds) of career start date; basis for years-of-experience'),
|
||||
new OA\Property(
|
||||
property: 'specialties',
|
||||
type: 'array',
|
||||
@@ -269,6 +270,7 @@ class DoctorController extends BaseController
|
||||
new OA\Property(property: 'medical_system_code', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'degree', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'info', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'activity_time', type: 'integer', nullable: true, description: 'Unix timestamp (seconds) of career start date; basis for years-of-experience'),
|
||||
new OA\Property(
|
||||
property: 'specialties',
|
||||
type: 'array',
|
||||
|
||||
@@ -242,6 +242,7 @@ class RepresentationActionController extends BaseController
|
||||
new OA\Property(property: 'gender', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'degree', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'medical_system_code', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'activity_time', type: 'integer', nullable: true, description: 'Unix timestamp (seconds) of career start date; basis for years-of-experience'),
|
||||
new OA\Property(property: 'specialties', type: 'array', items: new OA\Items(type: 'integer'), nullable: true),
|
||||
]
|
||||
)
|
||||
@@ -284,6 +285,7 @@ class RepresentationActionController extends BaseController
|
||||
if (!empty($data['medical_system_code'])) $doctor->setMedicalSystemCode($data['medical_system_code']);
|
||||
if (!empty($data['info'])) $doctor->setInfo($data['info']);
|
||||
if (!empty($data['mobile_number'])) $doctor->setMobileNumber($data['mobile_number']);
|
||||
if (!empty($data['activity_time'])) $doctor->setActivityTime((int) $data['activity_time']);
|
||||
|
||||
if (!empty($data['specialties']) && is_array($data['specialties'])) {
|
||||
foreach ($data['specialties'] as $id) {
|
||||
|
||||
Reference in New Issue
Block a user