feat(billing): renewals, coupons, VAT numbering, billing cycles and invoice payment tracking

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-19 16:37:56 +07:00
co-authored by Claude Sonnet 5.5
parent ea9a53f742
commit 25f23d541e
134 changed files with 4926 additions and 185 deletions
@@ -3,7 +3,6 @@
namespace App\Services\Customer;
use App\Helpers\OrderHelper;
use App\Mail\ServiceRenewalReminderMail;
use App\Models\Customer;
use App\Models\ModuleVmware;
use App\Models\Order;
@@ -21,7 +20,6 @@ use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
class CustomerServiceProvisioningService
@@ -43,6 +41,7 @@ class CustomerServiceProvisioningService
['customer_uuid' => $uuid],
[
'product',
'product.pricings' => fn ($query) => $query->where('is_active', 1)->select('id', 'product_id', 'billing_cycle'),
'orderItem',
'invoice',
'vmware.os.osGroup',
@@ -186,22 +185,6 @@ class CustomerServiceProvisioningService
$service->update(['vm_id' => $vmId]);
}
/**
* Gửi email nhắc gia hạn dịch vụ cho khách hàng.
*/
public function notifyRenewal(string $uuid, int $serviceId): void
{
$customer = $this->resolveCustomer($uuid);
$service = Service::where('customer_id', $customer->id)->where('id', $serviceId)
->with(['product', 'orderItem'])
->first();
abort_if(!$service, 404, 'Không tìm thấy dịch vụ');
abort_if(!$customer->email, 422, 'Khách hàng chưa có email');
Mail::to($customer->email)->send(new ServiceRenewalReminderMail($customer, $service));
}
/**
* Create a service for a customer. For VPS products, accepts a
* `virtual_machine_id` from the vCenter inventory and auto-creates the