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
@@ -266,12 +266,11 @@ class TransactionController extends Controller
'type' => 'deposit',
'public_code' => $t->public_code,
'trans' => $t->trans,
'description' => 'Nạp tiền vào tài khoản',
'description' => $t->typeLabel(),
'amount' => (float) $t->amount,
'status' => $t->status,
'status_label' => TransactionStatus::from((int) $t->status)->label(),
'reference_id' => null,
'reference_num'=> null,
'detail_key' => $t->uuid,
'created_at' => $t->created_at?->toISOString(),
]);
@@ -287,8 +286,7 @@ class TransactionController extends Controller
'amount' => (float) $inv->total,
'status' => $inv->status,
'status_label' => \App\Enums\Invoice\InvoiceStatus::tryFrom((int) $inv->status)?->label() ?? '-',
'reference_id' => $inv->order?->id,
'reference_num'=> $inv->order?->order_num,
'detail_key' => $inv->order?->order_num,
'created_at' => $inv->created_at?->toISOString(),
]);
@@ -303,6 +301,37 @@ class TransactionController extends Controller
]);
}
public function getClientTransactionDetail(Request $request, string $uuid): JsonResponse
{
$transaction = Transaction::query()
->where('uuid', $uuid)
->where('customer_id', $request->user()->id)
->first();
if (! $transaction) {
return response()->json(['error' => true, 'message' => 'Giao dịch không tồn tại'], 404);
}
return response()->json([
'error' => false,
'data' => [
'uuid' => $transaction->uuid,
'public_code' => $transaction->public_code,
'trans' => $transaction->trans,
'type' => $transaction->type,
'type_label' => $transaction->typeLabel(),
'direction' => $transaction->direction,
'amount' => (int) $transaction->amount,
'received_amount' => $transaction->received_amount !== null ? (int) $transaction->received_amount : null,
'status' => (int) $transaction->status,
'status_label' => TransactionStatus::from((int) $transaction->status)->label(),
'has_proof' => $transaction->proof_image !== null,
'created_at' => $transaction->created_at?->toISOString(),
'updated_at' => $transaction->updated_at?->toISOString(),
],
]);
}
public function getByPublicCode(Request $request)
{
$code = $request->query('code');