feat: Add IT Support catalog and related migrations, seeders, and email templates

- Created migration to add 'group_label' to 'product_type_fields' table.
- Implemented ItSupportCatalogSeeder to populate IT Support features and tiers.
- Added ProductCategorySeeder for initial product categories.
- Developed ProductMockupSeeder for mockup products in various categories.
- Introduced ProductTypeFieldSeeder to define fields for different product types.
- Created email templates for VPS service information and service renewal reminders.
This commit is contained in:
baodev0
2026-08-26 16:19:38 +07:00
parent 382b7c0ef8
commit c917e3bf5e
47 changed files with 2992 additions and 1759 deletions
+83
View File
@@ -11,14 +11,17 @@ use App\Http\Helpers\Helper;
use App\Jobs\Hosting\CreateHostingJobs;
use App\Jobs\Mail\Customer\OrderCreatedJob;
use App\Jobs\VirtualMachine\Create\CreateVirtualMachineJob;
use App\Jobs\VirtualMachine\Upgrade\UpgradeVirtualMachine;
use App\Models\Customer;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Payment;
use App\Models\Transaction;
use App\Repositories\Addon\AddonRepositoryInterface;
use App\Repositories\Invoice\InvoiceRepositoryInterface;
use App\Repositories\InvoiceItem\InvoiceItemRepositoryInterface;
use App\Repositories\Module\Hosting\HostingRepositoryInterface as ModuleHostingRepositoryInterface;
use App\Repositories\Module\HostingServer\HostingServerRepositoryInterface;
use App\Repositories\Module\Vmware\VmwareRepositoryInterface;
use App\Repositories\Order\OrderRepositoryInterface;
use Carbon\Carbon;
@@ -34,8 +37,88 @@ class OrderService
private readonly InvoiceItemRepositoryInterface $invoiceItemRepository,
private readonly ModuleHostingRepositoryInterface $moduleHostingRepository,
private readonly VmwareRepositoryInterface $moduleVmwareRepository,
private readonly HostingServerRepositoryInterface $moduleHostingServerRepository,
private readonly AddonRepositoryInterface $addonRepository,
) {}
/**
* Xác nhận đơn hàng (status=1). Nếu $provisionModules, chạy thêm logic
* cấp phát hosting/VM/addon dựa trên các order item (module=1 từ FE).
*/
public function confirmOrder(Order $order, bool $provisionModules): void
{
DB::transaction(function () use ($order, $provisionModules) {
$this->orderRepository->update($order->id, ['status' => 1]);
if ($provisionModules) {
$this->provisionOrderItems($order);
}
});
}
public function setStatus(Order $order, int $status): void
{
$this->orderRepository->update($order->id, ['status' => $status]);
}
/**
* Xoá đơn hàng cùng hóa đơn và các dòng hóa đơn liên quan.
*/
public function deleteOrder(Order $order): void
{
DB::transaction(function () use ($order) {
if ($order->invoice) {
$order->invoice->invoiceItem()->delete();
$order->invoice->delete();
}
$order->delete();
});
}
private function provisionOrderItems(Order $order): void
{
$jobs = [];
$addon = [];
$product = 0;
foreach ($order->orderItem as $item) {
switch ((int) $item->type_id) {
case 1:
$itemData = $this->addonRepository->find($item->relid);
if ($itemData) {
$price = match ((int) $item->billing) {
2 => $item->amount / 1,
3 => $item->amount / 3,
4 => $item->amount / 6,
5 => $item->amount / 12,
default => 0
};
$addon[strtolower($itemData->name)] = (int) $price / $itemData->price;
$product = $item->parent_id;
}
break;
case 3:
$hostingServer = $this->moduleHostingServerRepository->get_active();
if ($hostingServer) {
$this->moduleHostingRepository->update($item->relid, ['module_server_id' => $hostingServer->first()->id]);
$jobs[] = new CreateHostingJobs($item->relid);
}
break;
// case 4 (VPS/Cloud): xử lý bởi CreateVirtualMachineJob, đã dispatch
// ngay lúc tạo đơn trong createOrder() — không provision lại ở đây.
}
}
if (count($order->orderItem) === count($addon)) {
dispatch(new UpgradeVirtualMachine($product, $addon, $order->id))->delay(now()->addSeconds(10));
}
foreach ($jobs as $item) {
dispatch($item)->delay(now()->addSeconds(10));
}
}
public function createOrder(array $data): Order
{
$customer = Customer::find($data['customer_id']);