update email template
This commit is contained in:
@@ -5,6 +5,7 @@ namespace App\Services;
|
||||
use App\Enums\Invoice\InvoiceStatus;
|
||||
use App\Enums\Order\OrderStatus;
|
||||
use App\Enums\TransactionStatus;
|
||||
use App\Helpers\OrderHelper;
|
||||
use App\Jobs\Hosting\ProvisionHostingAccountJob;
|
||||
use App\Jobs\VirtualMachine\Action\VMJobs;
|
||||
use App\Jobs\VirtualMachine\Create\CreateVirtualMachineJob;
|
||||
@@ -28,23 +29,34 @@ class InvoicePaymentService
|
||||
throw new \InvalidArgumentException('Hóa đơn không thuộc tài khoản này.');
|
||||
}
|
||||
|
||||
// Balance/status are re-checked below under row locks — this is just a fast
|
||||
// fail-fast path so we don't open a transaction for an already-paid invoice.
|
||||
if ((int) $invoice->status === InvoiceStatus::PAID->value) {
|
||||
return $invoice->fresh(['order.orderItems.product', 'services', 'customer']);
|
||||
}
|
||||
|
||||
if (! in_array((int) $invoice->status, [InvoiceStatus::UNPAID->value, InvoiceStatus::OVERDUE->value], true)) {
|
||||
throw new \InvalidArgumentException('Hóa đơn không ở trạng thái có thể thanh toán.');
|
||||
}
|
||||
|
||||
if ((int) $customer->total < (int) $invoice->total) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Số dư không đủ. Hiện có: %s VNĐ, cần: %s VNĐ.',
|
||||
number_format((int) $customer->total),
|
||||
number_format((int) $invoice->total)
|
||||
));
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($invoice, $customer, $method) {
|
||||
// Lock both rows so two concurrent payment requests for the same invoice/customer
|
||||
// (double-click, retry) cannot both pass the balance check before either commits.
|
||||
$invoice = Invoice::where('id', $invoice->id)->lockForUpdate()->firstOrFail();
|
||||
$customer = Customer::where('id', $customer->id)->lockForUpdate()->firstOrFail();
|
||||
|
||||
if ((int) $invoice->status === InvoiceStatus::PAID->value) {
|
||||
return $invoice->fresh(['order.orderItems.product', 'services', 'customer']);
|
||||
}
|
||||
|
||||
if (! in_array((int) $invoice->status, [InvoiceStatus::UNPAID->value, InvoiceStatus::OVERDUE->value], true)) {
|
||||
throw new \InvalidArgumentException('Hóa đơn không ở trạng thái có thể thanh toán.');
|
||||
}
|
||||
|
||||
if ((int) $customer->total < (int) $invoice->total) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Số dư không đủ. Hiện có: %s VNĐ, cần: %s VNĐ.',
|
||||
number_format((int) $customer->total),
|
||||
number_format((int) $invoice->total)
|
||||
));
|
||||
}
|
||||
|
||||
$customer->decrement('total', (int) $invoice->total);
|
||||
|
||||
$invoice->update([
|
||||
@@ -128,12 +140,13 @@ class InvoicePaymentService
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) $order->status !== OrderStatus::ACTIVE->value) {
|
||||
$order->update([
|
||||
'status' => OrderStatus::ACTIVE->value,
|
||||
'payment_method' => $invoice->payment_method,
|
||||
]);
|
||||
}
|
||||
// payment_method/paid_at always mirror the invoice that was just paid, even if the
|
||||
// order's status doesn't change (e.g. it's already ACTIVE from an earlier payment).
|
||||
$order->update([
|
||||
'status' => OrderStatus::ACTIVE->value,
|
||||
'payment_method' => $invoice->payment_method,
|
||||
'paid_at' => $invoice->paid_at,
|
||||
]);
|
||||
|
||||
foreach ($order->orderItems as $item) {
|
||||
$isHostingProvision = ! $item->os_id
|
||||
@@ -150,7 +163,7 @@ class InvoicePaymentService
|
||||
'status' => ($item->os_id || $isHostingProvision) ? 'pending' : 'active',
|
||||
'auto_renew' => false,
|
||||
'started_at' => now(),
|
||||
'expires_at' => now()->addMonths($item->months ?: $this->cycleToMonths($item->billing_cycle)),
|
||||
'expires_at' => now()->addMonths($item->months ?: OrderHelper::cycleToMonths($item->billing_cycle)),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -177,10 +190,13 @@ class InvoicePaymentService
|
||||
return;
|
||||
}
|
||||
|
||||
if ($invoice->order && (int) $invoice->order->status !== OrderStatus::ACTIVE->value) {
|
||||
if ($invoice->order) {
|
||||
// Same rule as activateOrder(): payment_method/paid_at always mirror the invoice
|
||||
// that was just paid, regardless of whether the order's status actually changes.
|
||||
$invoice->order->update([
|
||||
'status' => OrderStatus::ACTIVE->value,
|
||||
'payment_method' => $invoice->payment_method,
|
||||
'paid_at' => $invoice->paid_at,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -239,16 +255,4 @@ class InvoicePaymentService
|
||||
}
|
||||
}
|
||||
|
||||
private function cycleToMonths(?string $cycle): int
|
||||
{
|
||||
return match ($cycle) {
|
||||
'monthly' => 1,
|
||||
'quarterly' => 3,
|
||||
'semi_annually' => 6,
|
||||
'annually' => 12,
|
||||
'biennially' => 24,
|
||||
'triennially' => 36,
|
||||
default => 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user