Rebuild the /admin/insurance-pricing contracts UI to the Figma "مدیریت بیمه" design and inject the coverage/franchise/ceiling fields the design omitted. Backend: - Add contract-level `kind` column to TenantInsurance (basic|supplementary), defaulting to the catalog type; migration Version20260715093358. - POST/PATCH /billing/tenant-insurances now accept effective_from, effective_to, kind; PATCH also toggles is_active without clobbering the user-set effective_to (unlike DELETE/deactivate). - List returns the latest version of every insurance (active + inactive) via TenantInsuranceRepository::findLatestByTenant, for the فعال/غیرفعال toggle. Frontend: - New InsuranceModal (ui/Modal + SearchableSelect + PersianDateInput) with the seven fields; submit "ثبت بیمه". - TenantInsuranceContracts rebuilt: header + search box, desktop table (ردیف/نام/کد/نوع/وضعیت/عملیات) and mobile cards, status toggle -> PATCH. - utils: isoToUnix/unixToIso helpers for contract dates. Tests: TenantInsuranceContractApiTest (create/edit/toggle/list, 5 cases), InsuranceModal + TenantInsuranceContracts vitest suites, docs/api updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
102 lines
3.3 KiB
PHP
102 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Insurance\Repository;
|
|
|
|
use App\Insurance\Entity\TenantInsurance;
|
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|
use Doctrine\Persistence\ManagerRegistry;
|
|
|
|
class TenantInsuranceRepository extends ServiceEntityRepository
|
|
{
|
|
public function __construct(ManagerRegistry $registry)
|
|
{
|
|
parent::__construct($registry, TenantInsurance::class);
|
|
}
|
|
|
|
/** @return TenantInsurance[] */
|
|
public function findActiveByTenant(string $entityType, int $entityId): array
|
|
{
|
|
return $this->createQueryBuilder('t')
|
|
->where('t.entityType = :type')
|
|
->andWhere('t.entityId = :id')
|
|
->andWhere('t.isActive = true')
|
|
->setParameter('type', $entityType)
|
|
->setParameter('id', $entityId)
|
|
->orderBy('t.insuranceId', 'ASC')
|
|
->getQuery()
|
|
->getResult();
|
|
}
|
|
|
|
/**
|
|
* Latest version of every insurance the tenant has a contract with, active or not.
|
|
* The management UI shows one row per insurance with a فعال/غیرفعال toggle, so both
|
|
* states must be returned; older versions are collapsed to the newest.
|
|
*
|
|
* @return TenantInsurance[]
|
|
*/
|
|
public function findLatestByTenant(string $entityType, int $entityId): array
|
|
{
|
|
$rows = $this->createQueryBuilder('t')
|
|
->where('t.entityType = :type')
|
|
->andWhere('t.entityId = :id')
|
|
->setParameter('type', $entityType)
|
|
->setParameter('id', $entityId)
|
|
->orderBy('t.insuranceId', 'ASC')
|
|
->addOrderBy('t.version', 'DESC')
|
|
->getQuery()
|
|
->getResult();
|
|
|
|
$latest = [];
|
|
foreach ($rows as $row) {
|
|
$latest[$row->getInsuranceId()] ??= $row;
|
|
}
|
|
|
|
return array_values($latest);
|
|
}
|
|
|
|
public function findByUuid(string $uuid): ?TenantInsurance
|
|
{
|
|
return $this->findOneBy(['uuid' => $uuid]);
|
|
}
|
|
|
|
public function findActiveContract(string $entityType, int $entityId, int $insuranceId): ?TenantInsurance
|
|
{
|
|
return $this->createQueryBuilder('t')
|
|
->where('t.entityType = :type')
|
|
->andWhere('t.entityId = :id')
|
|
->andWhere('t.insuranceId = :ins')
|
|
->andWhere('t.isActive = true')
|
|
->setParameter('type', $entityType)
|
|
->setParameter('id', $entityId)
|
|
->setParameter('ins', $insuranceId)
|
|
->orderBy('t.version', 'DESC')
|
|
->setMaxResults(1)
|
|
->getQuery()
|
|
->getOneOrNullResult();
|
|
}
|
|
|
|
public function latestVersion(string $entityType, int $entityId, int $insuranceId): int
|
|
{
|
|
$max = $this->createQueryBuilder('t')
|
|
->select('MAX(t.version)')
|
|
->where('t.entityType = :type')
|
|
->andWhere('t.entityId = :id')
|
|
->andWhere('t.insuranceId = :ins')
|
|
->setParameter('type', $entityType)
|
|
->setParameter('id', $entityId)
|
|
->setParameter('ins', $insuranceId)
|
|
->getQuery()
|
|
->getSingleScalarResult();
|
|
|
|
return (int) ($max ?? 0);
|
|
}
|
|
|
|
public function save(TenantInsurance $entity, bool $flush = true): void
|
|
{
|
|
$this->getEntityManager()->persist($entity);
|
|
if ($flush) {
|
|
$this->getEntityManager()->flush();
|
|
}
|
|
}
|
|
}
|