Files
ladill-queue/app/Services/Qms/PlanService.php
T
isaacclad 8be3eaeb4b
Deploy Ladill Queue / deploy (push) Successful in 33s
Add branch count control to Queue plans page.
Match Care/Frontdesk: branches stepper next to billing period, live
totals, and checkout charges for the selected seat count.
2026-07-16 09:36:36 +00:00

124 lines
3.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Services\Qms;
use App\Models\Branch;
use App\Models\Organization;
use Carbon\Carbon;
class PlanService
{
public function planKey(Organization $organization): string
{
$settings = $organization->settings ?? [];
$plan = (string) ($settings['plan'] ?? 'free');
if (in_array($plan, ['pro', 'enterprise'], true) && ! empty($settings['plan_expires_at'])) {
if (Carbon::parse($settings['plan_expires_at'])->isPast()) {
return 'free';
}
}
return array_key_exists($plan, config('qms.plans', [])) ? $plan : 'free';
}
public function plan(Organization $organization): string
{
return $this->planKey($organization);
}
public function isPro(Organization $organization): bool
{
return $this->planKey($organization) === 'pro';
}
public function isEnterprise(Organization $organization): bool
{
return $this->planKey($organization) === 'enterprise';
}
public function hasPaidPlan(Organization $organization): bool
{
return in_array($this->planKey($organization), ['pro', 'enterprise'], true);
}
public function activeBranchCount(Organization $organization): int
{
return Branch::query()
->where('organization_id', $organization->id)
->where('is_active', true)
->count();
}
public function maxBranches(Organization $organization): ?int
{
return config('qms.plans.'.$this->planKey($organization).'.max_branches');
}
public function maxQueues(Organization $organization): ?int
{
return config('qms.plans.'.$this->planKey($organization).'.max_queues');
}
public function canAddBranch(Organization $organization, int $currentCount): bool
{
$max = $this->maxBranches($organization);
return $max === null || $currentCount < $max;
}
public function canAddQueue(Organization $organization, int $currentCount): bool
{
$max = $this->maxQueues($organization);
return $max === null || $currentCount < $max;
}
public function proPricePerBranchMinor(): int
{
return (int) config(
'qms.plans.pro.price_minor_per_branch',
config('qms.plans.pro.price_minor', 249000)
);
}
public function proPriceMinor(Organization $organization): int
{
return $this->priceForBranches('pro', $this->activeBranchCount($organization));
}
public function enterprisePricePerBranchMinor(): int
{
return (int) config('qms.plans.enterprise.price_minor_per_branch', 449000);
}
public function enterprisePriceMinor(Organization $organization): int
{
return $this->priceForBranches('enterprise', $this->activeBranchCount($organization));
}
/** Fixed branch count × per-branch rate (checkout when the user picks seats). */
public function priceForBranches(string $plan, int $branches): int
{
$branches = max(1, $branches);
$rate = $plan === 'enterprise'
? $this->enterprisePricePerBranchMinor()
: $this->proPricePerBranchMinor();
return $branches * $rate;
}
public function resolveCheckoutBranches(Organization $organization, int $requested): int
{
$branches = max(1, min(999, $requested));
$active = max(1, $this->activeBranchCount($organization));
return max($branches, $active);
}
public function canSubscribeEnterprise(Organization $organization): bool
{
return $this->activeBranchCount($organization) >= (int) config('qms.enterprise.min_branches', 2);
}
}