feat: implement staff management and subscription system
- Added StaffController for managing clinic staff, including listing, creating, updating, and toggling staff status. - Created ClinicStaff entity and repository for staff data handling. - Developed SubscriptionController to manage subscription plans and periods, including trial subscriptions. - Introduced SubscriptionPlan, SubscriptionPeriod, and ClinicSubscription entities for subscription management. - Implemented SubscriptionService for handling subscription logic, including trial activation and subscription creation from payments. - Added necessary repositories for subscription entities to facilitate data access and manipulation.
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace App\Subscription\Service;
|
||||
|
||||
use App\Config\Repository\SiteConfigRepository;
|
||||
use App\Payment\Entity\Payment;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Exception\AppException;
|
||||
use App\Subscription\Entity\ClinicSubscription;
|
||||
use App\Subscription\Repository\ClinicSubscriptionRepository;
|
||||
use App\Subscription\Repository\SubscriptionPeriodRepository;
|
||||
use App\Subscription\Repository\SubscriptionPlanRepository;
|
||||
|
||||
class SubscriptionService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClinicSubscriptionRepository $subscriptionRepo,
|
||||
private readonly SubscriptionPlanRepository $planRepo,
|
||||
private readonly SubscriptionPeriodRepository $periodRepo,
|
||||
private readonly SiteConfigRepository $configRepo,
|
||||
) {}
|
||||
|
||||
public function getActiveSubscription(string $entityType, int $entityId): ?ClinicSubscription
|
||||
{
|
||||
return $this->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 calculateExpiresAt(?int $currentExpiresAt, int $durationMonths): int
|
||||
{
|
||||
$base = max($currentExpiresAt ?? 0, time());
|
||||
return $base + $durationMonths * 30 * 86400;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user