- Lịch sử thanh toán hoá đơn trả thêm `method` (tự động gia hạn / số dư / admin / chuyển khoản / hoàn tiền), bỏ đuôi `(method)` khỏi ghi chú - `DnsServer::panelUrl()` = https://<domain>/ dùng cho email cấp hosting và nút Plesk của khách - Order item trả thêm `uuid`/`type` của dịch vụ để FE dẫn tới trang quản lý - Yêu cầu huỷ dịch vụ, chứng chỉ SSL, lịch sử gia hạn, đổi mật khẩu hosting cho khách Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
95 lines
3.2 KiB
PHP
95 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Api\ServiceClient;
|
|
|
|
use App\Models\DnsDomain;
|
|
use App\Models\Service;
|
|
use App\Repositories\Api\ServiceClient\ServiceClientRepositoryInterface;
|
|
|
|
class ServiceClientService
|
|
{
|
|
protected $serviceClientRepository;
|
|
|
|
public function __construct(ServiceClientRepositoryInterface $serviceClientRepository)
|
|
{
|
|
$this->serviceClientRepository = $serviceClientRepository;
|
|
}
|
|
|
|
/**
|
|
* Lấy danh sách dịch vụ đang hoạt động
|
|
*/
|
|
public function getActiveServices(int $customerId, ?string $productType = null, ?int $limit = 10, ?string $group = null)
|
|
{
|
|
return $this->serviceClientRepository->getActiveServices($customerId, $productType, $limit, $group);
|
|
}
|
|
|
|
/**
|
|
* @return array{vps: int, server: int, hosting: int, domain: int}
|
|
*/
|
|
public function countByType(int $customerId): array
|
|
{
|
|
$counts = Service::query()
|
|
->where('customer_id', $customerId)
|
|
->whereNotIn('status', ['cancelled', 'terminated'])
|
|
->selectRaw('type, COUNT(*) as total')
|
|
->groupBy('type')
|
|
->pluck('total', 'type');
|
|
|
|
return [
|
|
'vps' => (int) $counts->get('vps', 0),
|
|
'server' => (int) $counts->get('server', 0),
|
|
'hosting' => (int) $counts->get('hosting', 0),
|
|
'domain' => (int) $counts->get('domain', 0) + $this->countZonesWithoutService($customerId),
|
|
];
|
|
}
|
|
|
|
private function countZonesWithoutService(int $customerId): int
|
|
{
|
|
$serviceDomains = Service::query()
|
|
->where('customer_id', $customerId)
|
|
->where('type', 'domain')
|
|
->whereNotIn('status', ['cancelled', 'terminated'])
|
|
->pluck('server_name')
|
|
->map(fn ($name) => mb_strtolower(trim((string) $name)));
|
|
|
|
return DnsDomain::query()
|
|
->whereHas('customer', fn ($query) => $query->where('customers.id', $customerId))
|
|
->where('is_created', '!=', DnsDomain::STATUS_CANCELLED)
|
|
->pluck('domain_name')
|
|
->map(fn ($name) => mb_strtolower(trim((string) $name)))
|
|
->unique()
|
|
->diff($serviceDomains)
|
|
->count();
|
|
}
|
|
|
|
/**
|
|
* @param iterable<Service> $services
|
|
*/
|
|
public function attachDnsRecordCounts(iterable $services, int $customerId): void
|
|
{
|
|
$counts = DnsDomain::query()
|
|
->withCount('ns')
|
|
->whereHas('customer', fn ($query) => $query->where('customers.id', $customerId))
|
|
->get(['id', 'domain_name'])
|
|
->mapWithKeys(fn (DnsDomain $domain) => [
|
|
mb_strtolower(trim($domain->domain_name)) => (int) $domain->ns_count,
|
|
]);
|
|
|
|
foreach ($services as $service) {
|
|
if ($service->type === 'domain') {
|
|
$service->setAttribute('dns_records_count', $counts->get(mb_strtolower(trim((string) $service->server_name))));
|
|
}
|
|
}
|
|
}
|
|
|
|
public function findActiveBySlug(string $slug)
|
|
{
|
|
return $this->serviceClientRepository->findActiveBySlug($slug);
|
|
}
|
|
|
|
public function getDetailService(string $uuid, int $customerId)
|
|
{
|
|
return $this->serviceClientRepository->getDetailService($uuid, $customerId);
|
|
}
|
|
}
|