Files
portal-api/app/Http/Controllers/admin/OrderController.php
T
2025-07-24 16:18:27 +07:00

411 lines
15 KiB
PHP

<?php
namespace App\Http\Controllers\admin;
use App\Http\Controllers\Controller;
use App\Http\Helpers\Helper;
use App\Http\Requests\OrderRequest;
use App\Http\Requests\UpdateOrderRequest;
use App\Jobs\Hosting\CreateHostingJobs;
use App\Jobs\VirtualMachine\Create\CreateVMJobs;
use App\Jobs\VirtualMachine\Upgrade\UpgradeVirtualMachine;
use App\Models\Customer;
use App\Models\Discount;
use App\Models\Log;
use App\Models\Order;
use App\Models\Os;
use App\Models\Payment;
use App\Models\Type;
use App\Repositories\Addon\AddonRepositoryInterface;
use App\Repositories\Hosting\HostingRepositoryInterface;
use App\Repositories\Invoice\InvoiceRepositoryInterface;
use App\Repositories\InvoiceItem\InvoiceItemRepositoryInterface;
use App\Repositories\Log\LogRepositoryInterface;
use App\Repositories\Module\Hosting\HostingRepositoryInterface as HostingHostingRepositoryInterface;
use App\Repositories\Module\HostingServer\HostingServerRepositoryInterface;
use App\Repositories\Module\IpAddress\IpAddressRepositoryInterface;
use App\Repositories\Module\Vmware\VmwareRepositoryInterface;
use App\Repositories\Order\OrderRepositoryInterface;
use App\Repositories\Os\OsRepositoryInterface;
use App\Repositories\VPS\VPSRepositoryInterface;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
class OrderController extends Controller
{
public function __construct(
public OrderRepositoryInterface $orderRepository,
public HostingRepositoryInterface $hostingRepository,
public VPSRepositoryInterface $vPSRepository,
public InvoiceRepositoryInterface $invoiceRepository,
public InvoiceItemRepositoryInterface $invoiceItemRepository,
public HostingHostingRepositoryInterface $moduleHostingRepository,
public VmwareRepositoryInterface $moduleVmwareRepository,
public HostingServerRepositoryInterface $moduleHostingServerRepository,
public OsRepositoryInterface $osRepository,
public IpAddressRepositoryInterface $ipAddressRepository,
public AddonRepositoryInterface $addonRepository,
public LogRepositoryInterface $logRepository
) {}
public function index(Request $request)
{
$orders = $this->orderRepository->filter($request->merge(['page' => $request->get('page', 1)])->all(), ['payment', 'customer', 'invoice']);
$title = 'List all orders';
return view('admin.order.index', compact('title', 'orders'));
}
// Tính billing
private function calculateBillingDetails($billing)
{
$months = match ($billing) {
2 => 1,
3 => 3,
4 => 6,
5 => 12,
default => 0
};
return [
'next_due_date' => $months ? Carbon::today()->addMonths($months)->timestamp : null,
'next_invoice' => $months ? Carbon::today()->addMonths($months)->timestamp : null,
'billing' => $months ?: 1
];
}
public function store(OrderRequest $request)
{
$request->validated();
$total = 0;
$product_item = [];
$relid_data = [];
foreach ($request->product as $key => $item) {
$product = null;
//get product item by type product
$relid_data[$key]['type'] = $item['type'];
$product = match ((int) $item['type']) {
3 => $this->hostingRepository->find($item['product_id']),
4 => $this->vPSRepository->find($item['product_id']),
default => null
};
if (!$product) {
throw new Exception("Sản phẩm không hợp lệ.");
}
$message = $product->name;
$billing = 0;
//Data product item with module auto create
$relid_data[$key]['data'] = [
'customer_id' => $request->customer_id,
'status' => 0,
'name' => $item['domain']
];
//billing data
$billingDetails = $this->calculateBillingDetails($item['billing']);
$relid_data[$key]['data'] = array_merge($relid_data[$key]['data'], $billingDetails);
//First pay for bill
$price_select = $item['price_custom'] ?
$item['price_custom'] :
$product->price_sale ?? $product->price;
$relid_data[$key]['data']['first_payment'] = $price_select * $billingDetails['billing'];
//next_pay
$relid_data[$key]['data']['next_payment'] = ($item['price_custom'] ?? $product->price) * $billingDetails['billing'];
//invoice item
$generalCode = Helper::generateUniqueCode();
$product_item[$key] = [
'customer_id' => $request->customer_id,
'type_id' => $item['type'],
'product_id' => $item['product_id'],
'description' => $message,
'amount' => $price_select,
'billing' => $item['billing'],
'tax' => 1,
'due_date' => Carbon::today()->hour(23)->minute(59)->second(59)->timestamp,
'code' => $generalCode
];
$relid_data[$key]['code'] = $generalCode;
if ($item['quantity'] > 1) {
for ($i = 1; $i < $item['quantity']; $i++) {
$newCode = Helper::generateUniqueCode();
$product_item[] = array_merge($product_item[$key], ['code' => $newCode]);
$relid_data[] = array_merge($relid_data[$key], ['code' => $newCode]);
}
}
if ($item['price_custom']) {
$total += $item['quantity'] * $item['price_custom'];
} else {
$price = ($product->price_sale ? $product->price_sale : null) ?? $product->price;
$total += $item['quantity'] * $price * $billingDetails['billing'];;
}
}
$order_item = [
'order_num' => Helper::generateUniqueCode(),
'customer_id' => $request->customer_id,
'date' => Carbon::today()->timestamp,
'invoice_id' => 0,
'discount_id' => $request->discount_id ?? 0,
'amount' => $total + ($total * (10 / 100)),
'payment_id' => $request->payment_id,
'user_id' => auth()->guard('admins')->user()->id,
'status' => $request->status,
'client_ip' => $request->getClientIp()
];
$invoice_data = [
'date' => Carbon::today()->timestamp,
'due_date' => Carbon::today()->hour(23)->minute(59)->second(59)->timestamp,
'date_paid' => (int)$request->status === 1 ? Carbon::today()->timestamp : null,
'sub_total' => $total,
'tax' => $total * (10 / 100),
'total' => $total + ($total * (10 / 100)),
'payment_id' => $request->payment_id,
'customer_id' => $request->create_invoice ? $request->customer_id : 0,
'status' => $request->status
];
DB::beginTransaction();
try {
$invoice = $this->invoiceRepository->create($invoice_data);
$product_item = array_map(function ($array) use ($invoice) {
$array['invoice_id'] = $invoice->id;
return $array;
}, $product_item);
if ($request->create_invoice) {
$order_item['invoice_id'] = $invoice->id;
}
$order = $this->orderRepository->create($order_item);
//append order_id to relid data
$relid_data = array_map(function ($array) use ($order) {
$array['data']['order_id'] = $order->id;
return $array;
}, $relid_data);
$relid = [];
//insert + get id for item auto created by module
foreach ($relid_data as $item) {
$code = $item['code'];
switch ($item['type']) {
case 3:
$relid_id = $this->moduleHostingRepository->create($item['data']);
$relid[$code] = $relid_id->id;
break;
case 4:
$item['data']['status'] = 2;
$relid_id = $this->moduleVmwareRepository->create($item['data']);
$relid[$code] = $relid_id->id;
break;
}
}
$product_item = array_filter(array_map(function ($array) use ($relid) {
if (isset($relid[$array['code']])) {
$array['relid'] = $relid[$array['code']];
unset($array['code']);
return $array;
}
return null;
}, $product_item));
$this->invoiceItemRepository->insert($product_item);
$last_id = $this->invoiceItemRepository->filter(['limit' => count($product_item)], [], [], ['id'])->pluck('id')->toArray();
$order->orderItem()->sync($last_id);
DB::commit();
} catch (Exception $error) {
DB::rollBack();
return back()->withErrors($error->getMessage());
}
return redirect()->route('admin.order.edit', ['id' => $order]);
}
public function create()
{
$title = 'Add new Order for Customer';
$customer = Customer::select('id', 'firstname', 'lastname')->where('status', 1)->get();
$payment = Payment::select('id', 'name')->where('status', 1)->get();
$discount = Discount::select('id', 'code', 'save', 'type')->where('status', 1)->get();
$type = Type::select('id', 'name')->where('status', 1)->get();
return view('admin.order.add', compact('title', 'customer', 'payment', 'discount', 'type'));
}
public function edit(int $id = 0)
{
$order = $this->orderRepository->findWithRelationships($id, ['orderItem', 'user', 'customer.invoiceItem.type', 'payment', 'discount', 'invoice.invoiceItem']);
if (!$order) {
return redirect()->route('admin.order.index')->withErrors('Can\'t find a order by order id #' . $id);
}
$title = 'View Manage Order';
$order->orderItem->transform(function ($item) {
$item->status = $this->invoiceItemRepository->findServiceStatus($item->relid, $item->type_id);
return $item;
});
return view('admin.order.edit', compact('title', 'order'));
}
public function update(int $id, UpdateOrderRequest $request)
{
$order = $this->orderRepository->findWithRelationships($id, ['invoice', 'orderItem']);
if (!$order) {
return redirect()->route('admin.order.index')->withErrors('Invalid request');
}
$status = match ($request->action) {
"accept" => 1,
"cancel" => 2,
default => 0
};
try {
DB::beginTransaction();
$this->orderRepository->update($id, ['status' => $status]);
if ($status === 1 && $request->module == 1) {
$jobs = [];
$addon = [];
$product = 0;
foreach ($order->orderItem as $key => $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:
$product = $this->moduleVmwareRepository->find($item->relid);
if ($product && $product->os_id) {
$os = $this->osRepository->findWithRelationships($product->os_id, ['osGroup']);
if (! $os || ! $os->osGroup->isNotEmpty()) break;
$ip_address = $this->ipAddressRepository->filter([
'module_host_id' => $os->osGroup->module_host_id,
'status' => 0
]);
if (count($ip_address) > 0) {
$this->moduleVmwareRepository->update($item->relid, [
'module_ipaddress_id' => $ip_address->first()->id,
]);
$this->ipAddressRepository->update($ip_address->first()->id, [
'status' => 1
]);
$jobs[] = new CreateVMJobs($product->id);
}
}
break;
default:
break;
}
}
if (count($order->orderItem) === count($addon)) {
dispatch(new UpgradeVirtualMachine($product, $addon, $order->id))->delay(now()->addSeconds(10));
}
if (count($jobs)) {
foreach ($jobs as $item) {
dispatch($item)->delay(now()->addSeconds(10));
}
}
}
DB::commit();
} catch (Exception $error) {
DB::rollBack();
return back()->withErrors($error->getMessage());
}
return back()->with('success', 'Order Set to ' . $request->action . ' success');
}
public function destroy(Request $request)
{
$validator = Validator::make($request->all(), [
'order' => 'numeric|required'
]);
if ($validator->fails()) {
return back()->withErrors('Can\'t find order');
}
$order = Order::with('Invoice', 'Invoice.InvoiceItem')->find($request->order);
if (!$order) {
return back()->withErrors('Invalid request');
}
if ($order->Invoice) {
$order->Invoice->delete();
if ($order->Invoice->InvoiceItem->count()) {
foreach ($order->Invoice->InvoiceItem->all() as $item) {
$item->delete();
}
}
}
$order->delete();
return back()->with('success', 'Delete Success');
}
}