Files
portal-api/app/Support/BillingCycleCatalog.php
T

123 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support;
use App\Enums\Product\ProductBillingCycle;
use App\Models\Setting;
final class BillingCycleCatalog
{
public const SETTING_KEY = 'custom_billing_months';
public const CODE_PREFIX = 'months_';
public const MAX_MONTHS = 600;
/**
* @return list<string>
*/
public static function builtInCodes(): array
{
return array_values(array_map(
fn (ProductBillingCycle $cycle) => $cycle->value,
array_filter(ProductBillingCycle::cases(), fn (ProductBillingCycle $cycle) => $cycle->months() > 0)
));
}
/**
* @return list<int>
*/
public static function builtInMonths(): array
{
return array_values(array_filter(array_map(
fn (ProductBillingCycle $cycle) => $cycle->months(),
ProductBillingCycle::cases()
)));
}
/**
* @return list<int>
*/
public static function customMonths(): array
{
$saved = json_decode((string) Setting::where('key', self::SETTING_KEY)->value('value'), true);
return self::normalizeMonths(is_array($saved) ? $saved : []);
}
/**
* @param array<int, mixed> $months
* @return list<int>
*/
public static function saveCustomMonths(array $months): array
{
$normalized = self::normalizeMonths($months);
Setting::updateOrCreate(['key' => self::SETTING_KEY], ['value' => json_encode($normalized)]);
return $normalized;
}
/**
* @return list<string>
*/
public static function codes(): array
{
$codes = [...self::builtInCodes(), ...array_map(self::codeFor(...), self::customMonths())];
usort($codes, fn (string $a, string $b) => self::monthsFor($a) <=> self::monthsFor($b));
return $codes;
}
public static function codeFor(int $months): string
{
return self::CODE_PREFIX . $months;
}
public static function monthsFor(?string $code): ?int
{
if ($code === null || $code === '') {
return null;
}
$builtIn = ProductBillingCycle::tryFrom($code);
if ($builtIn) {
return $builtIn->months();
}
return preg_match('/^' . self::CODE_PREFIX . '(\d{1,3})$/', $code, $m) && (int) $m[1] > 0
? (int) $m[1]
: null;
}
public static function labelForMonths(int $months): string
{
return $months > 0 && $months % 12 === 0 ? ($months / 12) . ' năm' : $months . ' tháng';
}
public static function labelForCode(?string $code): ?string
{
$months = self::monthsFor($code);
return $months ? self::labelForMonths($months) : null;
}
/**
* @param array<int, mixed> $months
* @return list<int>
*/
private static function normalizeMonths(array $months): array
{
$valid = array_filter(
array_map('intval', $months),
fn (int $m) => $m >= 1 && $m <= self::MAX_MONTHS && !in_array($m, self::builtInMonths(), true)
);
$unique = array_values(array_unique($valid));
sort($unique);
return $unique;
}
}