feat: khởi tạo/huỷ domain Plesk qua job, gửi mail hoá đơn qua queue, đính kèm triển khai

- ProvisionDnsDomainJob/SuspendDnsDomainJob: tạo domain admin lên Plesk, huỷ = suspend (is_created=3)
- Khách xem zone DNS được gán ở /dich-vu/domain, quản lý bản ghi A/AAAA/CNAME/TXT/MX/SRV
- send-mail hoá đơn đẩy SendInvoiceMailJob, preview + sửa nội dung, ghi mail.order_id
- invoice_attachments.type (payment_proof/deployment)
- CacheService xoá theo SCAN pattern, Redis không persistent mặc định
- Backfill transactions.public_code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-11 09:56:18 +07:00
co-authored by Claude Opus 5.5
parent 30898ea46f
commit 94614d9cb3
55 changed files with 1190 additions and 236 deletions
@@ -2,6 +2,7 @@
namespace App\Http\Resources\Api\Client\Service;
use App\Models\DnsDomain;
use App\Models\ModuleHostingPleskClient;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
@@ -27,6 +28,18 @@ class ServiceClientDetailResource extends JsonResource
];
}
private function resolveDnsZone(): ?DnsDomain
{
if ($this->type !== 'domain' || !$this->server_name) {
return null;
}
return DnsDomain::query()
->whereRaw('LOWER(domain_name) = ?', [mb_strtolower(trim($this->server_name))])
->whereHas('customer', fn ($query) => $query->where('customers.id', $this->customer_id))
->first(['id', 'is_created']);
}
/**
* Transform the resource into an array.
*
@@ -72,6 +85,8 @@ class ServiceClientDetailResource extends JsonResource
$product = $orderItem?->product;
$hosting = $this->resource->hostingAccount;
$pleskCredentials = $hosting ? $this->resolvePleskCredentials($hosting) : null;
$dnsZone = $this->resolveDnsZone();
$dnsCancelled = $dnsZone !== null && (int) $dnsZone->is_created === DnsDomain::STATUS_CANCELLED;
return [
'id' => $this->id,
@@ -115,6 +130,8 @@ class ServiceClientDetailResource extends JsonResource
'password' => $pleskCredentials['password'] ?? null,
'status' => $hosting->status,
] : null,
'dns_domain_id' => $dnsZone && !$dnsCancelled ? $dnsZone->id : null,
'dns_cancelled' => $dnsCancelled,
];
}
}