Files
portal-api/app/Http/Controllers/frontend/ServiceController_renew.php
T
2026-01-27 17:24:48 +07:00

159 lines
7.1 KiB
PHP

/**
* Renew VPS Service
*/
public function renew(Request $request)
{
try {
$user = customer();
if (!$user) {
return redirect()->route('user.login')->with('error', __('Vui lòng đăng nhập.'));
}
// 1. Validate Input
$validator = FacadesValidator::make($request->all(), [
'product_id' => 'required|string',
'plan' => 'required',
'months' => 'nullable|integer|min:2|max:60'
]);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput()->with('error', __('Dữ liệu không hợp lệ.'));
}
$vmware_id = $this->sanitizeInput($request->product_id);
$plan = $request->input('plan');
$months = $plan === 'other' ? (int)$request->input('months') : (int)$plan;
if ($months < 2) {
return redirect()->back()->with('error', __('Thời hạn gia hạn tối thiểu là 2 tháng.'));
}
// 2. Find Service & Verify Ownership
$vm = ModuleVmware::where('vmware_id', $vmware_id)
->where('customer_id', $user->id)
->first();
if (!$vm) {
return redirect()->back()->with('error', __('Không tìm thấy dịch vụ hoặc bạn không có quyền truy cập.'));
}
// 3. Calculate Price based on Original Order/InvoiceItem
// Strategy: Find the InvoiceItem from the Order associated with this VM.
// If multiple items, try to match type VPS (4).
$order = Order::find($vm->order_id);
if (!$order) {
// Fallback if order missing (rare)
// Try finding by invoice_id if stored on VM? ModuleVmware has next_invoice but not current_invoice.
return redirect()->back()->with('error', __('Không tìm thấy đơn hàng gốc của dịch vụ này.'));
}
// Find InvoiceItem
// Order has relationship to Invoice (order->invoice)
// Or Order has orderItems (which are InvoiceItems)
$invoiceItem = null;
if ($order->invoice) {
// Try finding item in the invoice related to this order
// Note: The modal uses $invoice->invoiceItem->first(). We should try to be specific.
// We don't have a direct link from ModuleVmware to InvoiceItem.
// But ModuleVmware links to Order, which links to items.
// Let's take the first item of type 4 (VPS) from the order's invoice.
$invoiceItem = $order->invoice->invoiceItem->where('type_id', 4)->first();
if (!$invoiceItem) {
$invoiceItem = $order->invoice->invoiceItem->first();
}
}
if (!$invoiceItem) {
// Extreme fallback or failure
return redirect()->back()->with('error', __('Không tìm thấy thông tin giá của dịch vụ.'));
}
// Calculate Unit Price (Monthly)
// 'amount' in InvoiceItem is total price for 'months' duration.
$billing_months = $invoiceItem->months > 0 ? $invoiceItem->months : 1;
if ($invoiceItem->amount <= 0) {
// If amount is 0 (free?), unit price is 0.
$base_unit_price = 0;
} else {
$base_unit_price = $invoiceItem->amount / $billing_months;
}
// Calculate Addons Unit Price
$addons_unit_price = 0;
if ($invoiceItem->addons && $invoiceItem->addons->count() > 0) {
foreach ($invoiceItem->addons as $addonPivot) {
// Try to find price. Assuming Addon model has current price.
// Ideally we should use the price stored in pivot if available, but pivot structure is unknown.
// We'll use the Addon catalog price as fallback or primary if pivot doesn't store it.
// $addonPivot->addonItems returns the Addon model.
if ($addonPivot->addonItems) {
$addons_unit_price += $addonPivot->addonItems->price;
}
}
}
$total_unit_price = $base_unit_price + $addons_unit_price;
$total_cost = $total_unit_price * $months;
// 4. Check Balance
if ($user->credit < $total_cost) {
return redirect()->back()->with('error', __('Số dư tài khoản không đủ để gia hạn (Cần: :amount). Vui lòng nạp thêm tiền.', ['amount' => number_format($total_cost) . ' VNĐ']));
}
// 5. Process Renewal
DB::beginTransaction();
try {
// Deduct Credit
$user->decrement('credit', $total_cost);
// Create Renewal Invoice (Paid) - Optional but good for history
$newInvoice = Invoice::create([
'customer_id' => $user->id,
'status' => 1, // Paid
'date' => now(),
'due_date' => now(),
'total' => $total_cost,
'payment_method' => 'credit_balance', // or similar
'description' => "Gia hạn dịch vụ VPS #{$vm->name} ({$months} tháng)"
]);
// Update VM Expiry
// If current expiry is in the past, renew from NOW? Or from expiry?
// Usually from expiry if it's recent grace period. If long expired, maybe from now.
// Let's simply add to next_due_date.
$current_due = $vm->next_due_date ? \Carbon\Carbon::parse($vm->next_due_date) : now();
if ($current_due->isPast()) {
// If expired, maybe we should start from today?
// Or just extend the gap. User usually pays for the gap.
// Let's extend from current_due to maintain billing cycle.
}
$new_due_date = $current_due->copy()->addMonths($months);
$vm->update([
'next_due_date' => $new_due_date,
'status' => 1, // Ensure active if it was suspended
]);
// Log or Notify (Optional)
DB::commit();
// Clear cache
Cache::forget("vm_info_{$vm->vmware_id}");
return redirect()->back()->with('success', __('Gia hạn dịch vụ thành công! Hạn sử dụng mới: :date', ['date' => $new_due_date->format('d/m/Y')]));
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
} catch (\Exception $e) {
Log::error("Error renewing VM: " . $e->getMessage());
return redirect()->back()->with('error', __('Có lỗi xảy ra khi gia hạn dịch vụ. Vui lòng thử lại sau.'));
}
}