Add PaymentRepository::findByUser/countByUser and a paginated my/payments endpoint that returns the authenticated user's own payments (derived from the token, never a userId in the URL). Public dashboard's transactions tab can now list payments instead of hitting a nonexistent route. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.8 KiB
افزودن endpoint لیست پرداختهای کاربر لاگینشده (GET /api/v1/my/payments)
پروژه
clinicpro (Backend). این پرامپت اول اجرا شود.
Cross-repo: سایت عمومی (
nobat724_front) این endpoint را در تب «تراکنشها»ی داشبورد مصرف میکند. پرامپت همتای frontend:nobat724_front/.claude/prompt/fix-dashboard-uuid-and-lists.md
زمینه
داشبورد کاربر در سایت عمومی تب «تراکنشها» دارد که request.getMyPayments(userId) را صدا میزند → GET /api/v1/payment/my-payments/{userId}. اما چنین routeای در backend وجود ندارد (تأییدشده با debug:router): تنها endpointهای پرداخت، GET /api/v1/payment/{uuid} (تک پرداخت) و GET /api/v1/admin/payments (ادمین) هستند. در نتیجه تب تراکنشها همیشه 404 میگیرد.
Payment به user (پرداختکننده) لینک دارد و toArray() دارد، ولی PaymentRepository متد findByUser ندارد.
مشکل / هدف
یک endpoint عمومی-برای-کاربر بساز: GET /api/v1/my/payments که پرداختهای خودِ کاربر لاگینشده را (از روی توکن، نه از روی userId در URL) بهصورت لیست برمیگرداند. الگو دقیقاً مثل MyAppointmentsController و قرارداد پاسخ مثل بقیهی listهای کاربر.
فایلهای مرتبط
| فایل | نقش |
|---|---|
src/Payment/Controller/PaymentController.php |
افزودن متد myPayments() (یا کنترلر MyPaymentsController جدید) |
src/Payment/Repository/PaymentRepository.php |
افزودن findByUser(User $user, ?string $status, int $page, int $limit) |
src/Payment/Entity/Payment.php |
getUser(), toArray() موجود |
src/Appointment/Controller/MyAppointmentsController.php |
مرجع الگو (CurrentUser, paginated) |
docs/api/payment.md |
مستندسازی endpoint جدید |
وضعیت فعلی (کد واقعی)
PaymentRepository — بدون findByUser
public function findByUuid(string $uuid): ?Payment { ... }
public function findByOrderId(string $orderId): ?Payment { ... }
public function save(Payment $entity, bool $flush = true): void { ... }
Payment — لینک user + toArray
#[ORM\JoinColumn(name: 'user_id', ...)] private User $user;
public function getUser(): User { return $this->user; }
public function getOrderId(): string { ... }
public function getAmountRials(): int { ... }
public function getStatus(): string { ... }
public function toArray(): array { ... } // شکل پرداخت
route ناموجود که فرانت صدا میزند
GET /api/v1/payment/my-payments/{userId} → 404 (وجود ندارد)
وظایف
۱. findByUser در PaymentRepository
/** @return Payment[] */
public function findByUser(User $user, ?string $status = null, int $page = 1, int $limit = 20): array
{
$qb = $this->createQueryBuilder('p')
->where('p.user = :user')->setParameter('user', $user)
->orderBy('p.createdAt', 'DESC')
->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit);
if ($status !== null) {
$qb->andWhere('p.status = :status')->setParameter('status', $status);
}
return $qb->getQuery()->getResult();
}
public function countByUser(User $user, ?string $status = null): int
{
$qb = $this->createQueryBuilder('p')->select('COUNT(p.id)')
->where('p.user = :user')->setParameter('user', $user);
if ($status !== null) {
$qb->andWhere('p.status = :status')->setParameter('status', $status);
}
return (int) $qb->getQuery()->getSingleScalarResult();
}
از
Userبهجایuser_idدر DQL استفاده کن (App\Auth\Entity\Userرا import کن). status اختیاری (pending/paid/failed/...).
۲. endpoint GET /api/v1/my/payments
در PaymentController (یا کنترلر جدید MyPaymentsController همسبک با MyAppointmentsController):
#[Route('/api/v1/my/payments', methods: ['GET'])]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function myPayments(Request $request, #[CurrentUser] User $user): JsonResponse
{
$page = max(1, (int) $request->query->get('page', 1));
$limit = min(100, max(1, (int) $request->query->get('limit', 20)));
$status = $request->query->get('status');
$items = array_map(
fn(Payment $p) => $p->toArray(),
$this->paymentRepo->findByUser($user, $status, $page, $limit)
);
$total = $this->paymentRepo->countByUser($user, $status);
return $this->paginated($items, $total, $page, $limit);
}
از
paginated()استفاده کن (نه success تودرتو) تا فرانت items را ازdataو total را ازmeta.totalRecordsبخواند — همخوان با بقیهی listها. کاربر فقط پرداختهای خودش را میبیند (از#[CurrentUser]؛ هیچ userId از URL گرفته نمیشود).
۳. مطمئن شو route عمومی/auth درست است
/api/v1/my/paymentsزیر فایروال^/apiباIS_AUTHENTICATED_FULLYمیافتد (نیاز به whitelist عمومی ندارد چون کاربر لاگین است). نیازی به تغییرsecurity.yamlنیست. تأیید کن باdebug:router.
۴. مستندسازی
در docs/api/payment.md: endpoint GET /api/v1/my/payments با permission، query params (page, limit, status)، و نمونهی پاسخ paginated واقعی (items + meta).
نکات مهم
- هیچ migration لازم نیست (فقط query + route).
- امنیت: هرگز
userIdاز URL نگیر؛ فقط#[CurrentUser]. کاربر نباید پرداخت دیگران را ببیند. - پاسخها از
BaseController؛ این endpoint بایدpaginated()بدهد (نهsuccess(['data'=>...])) — فرانتdata(آرایه) وmeta.totalRecordsمیخواند. toArray()پرداخت شکل واقعی را میدهد؛ اگر فیلدی برای نمایش لازم است (مبلغ، وضعیت، تاریخ، نوع، order_id، appointment_uuid) و درtoArrayنیست، اضافه کن.- تست:
ddev exec php -lروی فایلهای تغییر یافتهddev exec php bin/console cache:clearddev exec php bin/console debug:router | grep "my/payments"- با توکن یک کاربر (مثلاً
09210651788که یک پرداخت آزمایشی دارد):GET /api/v1/my/payments→ ۲۰۰ با لیست پرداختهای همان کاربر؛ بدون توکن → ۴۰۱. docs/api/payment.mdبهروز شود.