feat(claims): enhance claims filtering with insurance, date range, and patient search

This commit is contained in:
hamed
2026-06-24 06:19:25 +03:30
parent 69beb7b944
commit 91fb55258a
5 changed files with 196 additions and 17 deletions
+24 -5
View File
@@ -59,13 +59,18 @@ class BillingController extends BaseController
$sessionIds[] = $d['patient_session_id'];
}
}
$sessionDates = $this->sessionRepo->datesForIds(array_values(array_unique($sessionIds)));
$uniqueSessionIds = array_values(array_unique($sessionIds));
$sessionDates = $this->sessionRepo->datesForIds($uniqueSessionIds);
$patientInfo = $this->sessionRepo->patientInfoForIds($uniqueSessionIds);
return array_map(function (Claim $claim) use ($itemDetails, $sessionDates) {
return array_map(function (Claim $claim) use ($itemDetails, $sessionDates, $patientInfo) {
$data = $claim->toArray();
$data['insurance_name'] = $this->insuranceRepo->find($claim->getInsuranceId())?->getName();
$data['items'] = array_map(function (array $item) use ($itemDetails, $sessionDates) {
$patientName = null;
$patientMobile = null;
$data['items'] = array_map(function (array $item) use ($itemDetails, $sessionDates, $patientInfo, &$patientName, &$patientMobile) {
$detail = $itemDetails[$item['invoice_item_id']] ?? null;
$sessionId = $detail['patient_session_id'] ?? null;
$item['title'] = $detail['title'] ?? null;
@@ -73,9 +78,17 @@ class BillingController extends BaseController
$item['quantity'] = $detail['quantity'] ?? 1;
$item['total_rials'] = $detail['total_rials'] ?? null;
$item['visit_date'] = $sessionId !== null ? ($sessionDates[$sessionId] ?? null) : null;
if ($patientName === null && $sessionId !== null && isset($patientInfo[$sessionId])) {
$patientName = $patientInfo[$sessionId]['name'];
$patientMobile = $patientInfo[$sessionId]['mobile'];
}
return $item;
}, $data['items']);
$data['patient_name'] = $patientName;
$data['patient_mobile'] = $patientMobile;
return $data;
}, $claims);
}
@@ -164,8 +177,14 @@ class BillingController extends BaseController
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
}
$status = $request->query->get('status') ?: null;
$claims = $this->claimRepo->findByTenant($entityType, $entityId, $status);
$filters = [
'status' => $request->query->get('status') ?: null,
'insurance_id' => $request->query->get('insurance_id') ?: null,
'from' => $request->query->get('from') ?: null,
'to' => $request->query->get('to') ?: null,
'q' => $request->query->get('q') ?: null,
];
$claims = $this->claimRepo->findByTenant($entityType, $entityId, $filters);
return $this->success(['data' => $this->enrichClaims($claims)]);
}
+33 -4
View File
@@ -18,8 +18,11 @@ class ClaimRepository extends ServiceEntityRepository
return $this->findOneBy(['uuid' => $uuid]);
}
/** @return Claim[] */
public function findByTenant(string $entityType, int $entityId, ?string $status = null): array
/**
* @param array{status?:?string, insurance_id?:?int, from?:?int, to?:?int, q?:?string} $filters
* @return Claim[]
*/
public function findByTenant(string $entityType, int $entityId, array $filters = []): array
{
$qb = $this->createQueryBuilder('c')
->where('c.entityType = :type')
@@ -28,8 +31,34 @@ class ClaimRepository extends ServiceEntityRepository
->setParameter('id', $entityId)
->orderBy('c.id', 'DESC');
if ($status !== null) {
$qb->andWhere('c.status = :status')->setParameter('status', $status);
if (!empty($filters['status'])) {
$qb->andWhere('c.status = :status')->setParameter('status', $filters['status']);
}
if (!empty($filters['insurance_id'])) {
$qb->andWhere('c.insuranceId = :insId')->setParameter('insId', (int) $filters['insurance_id']);
}
if (!empty($filters['from'])) {
$qb->andWhere('c.createdAt >= :from')->setParameter('from', (int) $filters['from']);
}
if (!empty($filters['to'])) {
$qb->andWhere('c.createdAt <= :to')->setParameter('to', (int) $filters['to']);
}
// فیلتر بیمار: مطالباتی که آیتم‌شان به صورتحساب پرونده‌ی همان کاربر اشاره دارد (موبایل/کدملی/نام).
if (!empty($filters['q'])) {
$q = trim((string) $filters['q']);
$qb->andWhere(
'EXISTS (' .
'SELECT 1 FROM App\Billing\Entity\ClaimItem ci2 ' .
'JOIN App\Billing\Entity\InvoiceItem ii2 WITH ii2.id = ci2.invoiceItemId ' .
'JOIN App\Billing\Entity\Invoice inv2 WITH inv2 = ii2.invoice ' .
'JOIN App\Patient\Entity\PatientRecord pr2 WITH pr2.id = inv2.patientRecordId ' .
'JOIN App\Auth\Entity\User u2 WITH u2 = pr2.user ' .
'WHERE ci2.claim = c AND (' .
'u2.mobileNumber LIKE :q OR u2.nationalCode LIKE :q OR u2.realName LIKE :q' .
')' .
')'
)->setParameter('q', '%' . $q . '%');
}
return $qb->getQuery()->getResult();
@@ -89,4 +89,31 @@ class PatientSessionRepository extends ServiceEntityRepository
}
return $out;
}
/**
* نام و موبایل بیمار هر مراجعه — کلیددار بر اساس id جلسه.
* @param int[] $ids
* @return array<int, array{name: ?string, mobile: ?string}>
*/
public function patientInfoForIds(array $ids): array
{
if ($ids === []) {
return [];
}
$rows = $this->createQueryBuilder('s')
->select('s.id AS id', 'u.realName AS name', 'u.mobileNumber AS mobile')
->join('s.record', 'r')
->join('r.user', 'u')
->where('s.id IN (:ids)')
->setParameter('ids', $ids)
->getQuery()
->getArrayResult();
$out = [];
foreach ($rows as $r) {
$out[(int) $r['id']] = ['name' => $r['name'], 'mobile' => $r['mobile']];
}
return $out;
}
}