feat: add payments summary endpoint and UI redesign for MyPaymentsPage

- Implemented a new API endpoint `/api/v1/my/billing/payments/summary` to provide a financial summary of payments with filters for national code, status, and date range.
- Updated the InvoiceRepository to aggregate totals for paid and unsettled invoices.
- Created a new hook `usePaymentsSummary` to fetch summary data in the frontend.
- Redesigned the MyPaymentsPage to align with the ClaimsPage structure, incorporating a design system, summary statistics, and improved filtering options.
- Added tests for the new payments summary endpoint to ensure correct functionality and filtering behavior.
This commit is contained in:
hamed
2026-07-19 10:12:01 +03:30
parent 7ebc04fc3f
commit 5c8fe8ece4
11 changed files with 735 additions and 129 deletions
+39 -7
View File
@@ -168,18 +168,50 @@ class BillingController extends BaseController
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
}
$filters = [
$page = max(1, (int) $request->query->get('page', 1));
$limit = min(100, max(1, (int) $request->query->get('limit', 20)));
$result = $this->invoiceService->tenantInvoiceList(
$entityType,
$entityId,
$this->paymentFilters($request),
$page,
$limit,
);
return $this->paginated($result['items'], $result['total'], $page, $limit);
}
/**
* خلاصه‌ی مالی همان مجموعه‌ی فیلترشده‌ی listPayments — برای کارت‌های آمار.
* پاسخ: { total_rials, paid_rials, unsettled_rials, invoices_count }.
*/
#[Route('/api/v1/my/billing/payments/summary', methods: ['GET'])]
public function paymentsSummary(Request $request, #[CurrentUser] User $user): JsonResponse
{
[$entityType, $entityId] = $this->resolveEntity($user);
if ($entityId === null) {
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
}
return $this->success(
$this->invoiceService->tenantInvoiceSummary($entityType, $entityId, $this->paymentFilters($request)),
);
}
/**
* فیلترهای مشترک لیست پرداخت‌ها و خلاصه‌ی آن؛ یک منبع تا دو نما واگرا نشوند.
*
* @return array{national_code:?string,status:?string,from:?string,to:?string}
*/
private function paymentFilters(Request $request): array
{
return [
'national_code' => $request->query->get('national_code') ?: null,
'status' => $request->query->get('status') ?: null,
'from' => $request->query->get('from') ?: null,
'to' => $request->query->get('to') ?: null,
];
$page = max(1, (int) $request->query->get('page', 1));
$limit = min(100, max(1, (int) $request->query->get('limit', 20)));
$result = $this->invoiceService->tenantInvoiceList($entityType, $entityId, $filters, $page, $limit);
return $this->paginated($result['items'], $result['total'], $page, $limit);
}
/**