feat(service): custom product, lịch sử giám sát VM và mã hoá response theo phiên
- Dịch vụ custom: bảng custom_products + services.custom_product_id; createService nhận
custom{} thay product_id, giá = đơn giá tháng x số tháng chu kỳ (1/3/6/12/24/36),
gia hạn tính theo cùng đơn giá, ServiceClientDetailResource trả custom_product và specs.
- Giám sát VM: GET v1/system/vm-metrics/history gom lịch sử về tối đa 240 điểm;
lỗi lấy dung lượng đĩa không còn làm hỏng cả thẻ metrics.
- SealResponse: AES-256-GCM theo khoá phiên do proxy Next cấp qua header x-seal-key
(HMAC của session id). Client opt-in bằng x-seal; chi tiết dịch vụ, mật khẩu VM và
console ticket luôn được mã hoá. Body gửi lên dạng {enc} được giải mã trước validate;
khoá lệch trả 428 để client lấy khoá mới. Đây là che mắt DevTools, không phải bảo mật
chống chính chủ tài khoản.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
8108e8fe53
commit
6315a392c0
@@ -4,6 +4,7 @@ namespace App\Services\Customer;
|
||||
|
||||
use App\Helpers\OrderHelper;
|
||||
use App\Models\Customer;
|
||||
use App\Models\CustomProduct;
|
||||
use App\Models\ModuleVmware;
|
||||
use App\Models\Order;
|
||||
use App\Models\Product;
|
||||
@@ -88,9 +89,13 @@ class CustomerServiceProvisioningService
|
||||
return DB::transaction(function () use ($customer, $service, $data) {
|
||||
$vmFields = ['virtual_machine_id', 'os_id', 'vm_cpu', 'vm_ram_mb', 'vm_disk_gb', 'vm_ip', 'vm_dns', 'vm_user', 'vm_password', 'vm_port'];
|
||||
|
||||
$service->fill(collect($data)->except(['price', 'billing_cycle', ...$vmFields])->all());
|
||||
$service->fill(collect($data)->except(['price', 'billing_cycle', 'product_id', ...$vmFields])->all());
|
||||
$service->save();
|
||||
|
||||
if (!empty($data['product_id']) && (int) $data['product_id'] !== $service->product_id) {
|
||||
$this->replaceProduct($service, Product::findOrFail($data['product_id']));
|
||||
}
|
||||
|
||||
if (!empty($data['virtual_machine_id'])) {
|
||||
$this->assignVirtualMachine($service, $customer, (int) $data['virtual_machine_id']);
|
||||
}
|
||||
@@ -142,6 +147,12 @@ class CustomerServiceProvisioningService
|
||||
});
|
||||
}
|
||||
|
||||
private function replaceProduct(Service $service, Product $product): void
|
||||
{
|
||||
$service->update(['product_id' => $product->id, 'custom_product_id' => null, 'type' => $product->product_type]);
|
||||
$service->orderItem?->update(['product_id' => $product->id]);
|
||||
}
|
||||
|
||||
private function assignVirtualMachine(Service $service, Customer $customer, int $virtualMachineId): void
|
||||
{
|
||||
$vm = VirtualMachines::with('datacenter')->findOrFail($virtualMachineId);
|
||||
@@ -194,9 +205,10 @@ class CustomerServiceProvisioningService
|
||||
{
|
||||
$customer = $this->resolveCustomer($uuid);
|
||||
|
||||
$product = Product::find($data['product_id']);
|
||||
$custom = $data['custom'] ?? null;
|
||||
$product = $custom ? null : Product::find($data['product_id']);
|
||||
abort_if(
|
||||
$product->product_type === 'vps' && empty($data['virtual_machine_id']),
|
||||
$product?->product_type === 'vps' && empty($data['virtual_machine_id']),
|
||||
422,
|
||||
'VPS service requires a virtual_machine_id',
|
||||
);
|
||||
@@ -204,9 +216,13 @@ class CustomerServiceProvisioningService
|
||||
$billingCycle = $data['billing_cycle'] ?? 'monthly';
|
||||
$months = OrderHelper::cycleToMonths($billingCycle);
|
||||
|
||||
$listPrice = $this->orderRecorder->listPrice($product, $billingCycle, $data['server_name'] ?? null);
|
||||
abort_if($custom && !in_array($months, CustomProduct::CYCLE_MONTHS, true), 422, 'Chu kỳ không hợp lệ cho sản phẩm custom.');
|
||||
|
||||
$listPrice = $custom
|
||||
? (int) round((float) $custom['unit_price']) * $months
|
||||
: $this->orderRecorder->listPrice($product, $billingCycle, $data['server_name'] ?? null);
|
||||
abort_if(
|
||||
!isset($data['price']) && $listPrice === null && $product->product_type === 'domain',
|
||||
!isset($data['price']) && $listPrice === null && $product?->product_type === 'domain',
|
||||
422,
|
||||
'Tên miền không có giá trong bảng giá tên miền, vui lòng nhập giá.',
|
||||
);
|
||||
@@ -236,7 +252,9 @@ class CustomerServiceProvisioningService
|
||||
),
|
||||
);
|
||||
|
||||
return DB::transaction(function () use ($customer, $product, $data, $billingCycle, $months, $basePrice, $paidAmount, $paymentStatus, $paymentMethod, $clientIp) {
|
||||
return DB::transaction(function () use ($customer, $product, $custom, $data, $billingCycle, $months, $basePrice, $paidAmount, $paymentStatus, $paymentMethod, $clientIp) {
|
||||
$customProduct = $custom ? CustomProduct::create($custom) : null;
|
||||
|
||||
['order' => $order, 'orderItem' => $orderItem, 'invoice' => $invoice] = $this->orderRecorder->create(
|
||||
$customer->id,
|
||||
$product,
|
||||
@@ -247,6 +265,7 @@ class CustomerServiceProvisioningService
|
||||
paymentMethod: $paymentMethod,
|
||||
clientIp: $clientIp,
|
||||
amountPaid: $paidAmount,
|
||||
label: $customProduct?->name,
|
||||
);
|
||||
|
||||
// Ngày bắt đầu/hết hạn dùng chung cho cả module_vmware (next_due_date/next_invoice) và services.
|
||||
@@ -289,7 +308,8 @@ class CustomerServiceProvisioningService
|
||||
? ['customer_id' => $customer->id, 'vm_id' => $vmId]
|
||||
: [
|
||||
'customer_id' => $customer->id,
|
||||
'product_id' => $product->id,
|
||||
'product_id' => $product?->id,
|
||||
'custom_product_id' => $customProduct?->id,
|
||||
'vm_id' => null,
|
||||
'server_name' => $data['server_name'] ?? null,
|
||||
];
|
||||
@@ -298,7 +318,9 @@ class CustomerServiceProvisioningService
|
||||
|
||||
$service = Service::updateOrCreate($serviceLookup, [
|
||||
'customer_id' => $customer->id,
|
||||
'product_id' => $product->id,
|
||||
'product_id' => $product?->id,
|
||||
'custom_product_id' => $customProduct?->id,
|
||||
'type' => $customProduct?->category,
|
||||
'vm_id' => $vmId,
|
||||
'order_item_id' => $orderItem->id,
|
||||
'invoice_id' => $invoice->id,
|
||||
@@ -317,7 +339,7 @@ class CustomerServiceProvisioningService
|
||||
ModuleVmware::where('id', $vmId)->update(['service_id' => $service->id]);
|
||||
}
|
||||
|
||||
return $service->load(['product', 'vmware.os.osGroup']);
|
||||
return $service->load(['product', 'customProduct', 'vmware.os.osGroup']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user