feat: nạp tiền thủ công mã 30 phút, gia hạn trừ số dư, đồng bộ domain từ Plesk

- Nạp tiền: mã thanh toán sống 30 phút (ManualDepositDraft), khôi phục/huỷ mã, lệnh dọn mã hết hạn; total_pending chỉ tính giao dịch đã nộp chứng từ, admin duyệt/từ chối/xoá giao dịch
- Gia hạn dịch vụ: phát hành invoice gia hạn trên order gốc và trừ số dư ngay
- Đồng bộ domain từ Plesk theo server, ServiceOrderRecorder tạo order/invoice cho dịch vụ admin dựng
- Danh sách dịch vụ trả field theo loại (service_plan, dns_records_count), đếm dịch vụ theo loại

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-11 23:07:51 +07:00
co-authored by Claude Opus 5.5
parent 10af41c5cf
commit c5115b52dd
53 changed files with 1887 additions and 613 deletions
@@ -10,6 +10,7 @@ use App\Jobs\DnsManager\SyncDnsFromPlesk;
use App\Repositories\DnsManager\Domain\DnsDomainRepositoryInterface;
use App\Repositories\DnsManager\Record\DnsRecordRepositoryInterface;
use App\Services\ServerService;
use App\Services\Domain\CustomerDomainServiceSync;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -32,6 +33,7 @@ class DomainController extends Controller
private readonly DnsDomainRepositoryInterface $domainRepository,
private readonly DnsRecordRepositoryInterface $recordRepository,
private readonly ServerService $serverService,
private readonly CustomerDomainServiceSync $customerDomainServiceSync,
) {}
// ─── Domains ─────────────────────────────────────────────────────────────
@@ -114,7 +116,7 @@ class DomainController extends Controller
]);
if (!empty($request->customer_ids)) {
$domain->customer()->sync($request->customer_ids);
$this->customerDomainServiceSync->syncCustomers($domain, $request->customer_ids);
}
DB::commit();
@@ -153,6 +155,7 @@ class DomainController extends Controller
DB::beginTransaction();
try {
$previousDomainName = $domain->domain_name;
$this->domainRepository->update($id, $request->only([
'domain_name',
'dns_manager_server_id',
@@ -161,8 +164,19 @@ class DomainController extends Controller
]));
// Sync customers (empty array = detach all)
$freshDomain = $domain->fresh();
if ($request->has('customer_ids')) {
$domain->customer()->sync($request->customer_ids ?? []);
$this->customerDomainServiceSync->syncCustomers(
$freshDomain,
$request->customer_ids ?? [],
$previousDomainName,
);
} elseif ($previousDomainName !== $freshDomain->domain_name) {
$this->customerDomainServiceSync->syncCustomers(
$freshDomain,
$freshDomain->customer()->pluck('customers.id')->all(),
$previousDomainName,
);
}
DB::commit();
@@ -270,9 +284,13 @@ class DomainController extends Controller
// ─── Sync from Plesk ─────────────────────────────────────────────────────
public function syncDns(): JsonResponse
public function syncDns(Request $request): JsonResponse
{
dispatch(new SyncDnsFromPlesk());
$validated = $request->validate([
'dns_manager_server_id' => ['nullable', 'integer', 'exists:dns_manager_servers,id'],
]);
dispatch(new SyncDnsFromPlesk($validated['dns_manager_server_id'] ?? null));
return response()->json([
'error' => false,