subscriptionRepo->findActive($entityType, $entityId); } public function hasFeature(string $entityType, int $entityId, string $feature): bool { $subscription = $this->getActiveSubscription($entityType, $entityId); if ($subscription === null) { return false; } return $subscription->getPlan()->hasFeature($feature); } public function getSecretaryLimit(string $entityType, int $entityId): int { $subscription = $this->getActiveSubscription($entityType, $entityId); if ($subscription === null) { return 1; } return $subscription->getPlan()->getMaxSecretaries(); } public function hasUsedTrial(string $entityType, int $entityId): bool { return $this->subscriptionRepo->hasUsedTrial($entityType, $entityId); } public function activateTrial(string $entityType, int $entityId): ClinicSubscription { if ($this->hasUsedTrial($entityType, $entityId)) { throw new AppException(ErrorCodes::ERR_TRIAL_ALREADY_USED, null, 422); } $trialEnabled = $this->configRepo->get('trial_enabled'); if ($trialEnabled === '0') { throw new AppException(ErrorCodes::ERR_TRIAL_DISABLED, null, 422); } $basicPlan = $this->planRepo->findByName('basic'); if ($basicPlan === null) { throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, null, 500); } $trialPeriod = $this->periodRepo->findTrialPeriodForPlan($basicPlan); if ($trialPeriod === null) { throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, null, 500); } $expiresAt = $this->calculateExpiresAt(null, $trialPeriod->getDurationMonths()); $subscription = new ClinicSubscription( $entityType, $entityId, $basicPlan, $trialPeriod, true, $expiresAt, null ); $this->subscriptionRepo->save($subscription); return $subscription; } public function createFromPayment(Payment $payment, string $entityType, int $entityId, string $periodUuid): ClinicSubscription { $period = $this->periodRepo->findByUuid($periodUuid); if ($period === null) { throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, null, 404); } $currentSub = $this->getActiveSubscription($entityType, $entityId); $currentExpires = $currentSub?->getExpiresAt(); $expiresAt = $this->calculateExpiresAt($currentExpires, $period->getDurationMonths()); $subscription = new ClinicSubscription( $entityType, $entityId, $period->getPlan(), $period, false, $expiresAt, $payment ); $this->subscriptionRepo->save($subscription); return $subscription; } /** حذف اشتراکِ ساخته‌شده از یک پرداخت (هنگام استرداد/برگشت وجه). */ public function deleteByPayment(\App\Payment\Entity\Payment $payment): void { $subscription = $this->subscriptionRepo->findByPayment($payment); if ($subscription !== null) { $this->subscriptionRepo->remove($subscription); } } public function calculateExpiresAt(?int $currentExpiresAt, int $durationMonths): int { $base = max($currentExpiresAt ?? 0, time()); return $base + $durationMonths * 30 * 86400; } }