Merge branch 'dev' of http://103.248.30.24:3000/kent-logistics/Kent-logistics-Laravel into dev
This commit is contained in:
@@ -6,10 +6,11 @@ use App\Models\Order;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class OrdersExport implements FromCollection, WithHeadings
|
class OrdersExport implements FromCollection, WithHeadings
|
||||||
{
|
{
|
||||||
protected $request;
|
protected Request $request;
|
||||||
|
|
||||||
public function __construct(Request $request)
|
public function __construct(Request $request)
|
||||||
{
|
{
|
||||||
@@ -18,61 +19,99 @@ class OrdersExport implements FromCollection, WithHeadings
|
|||||||
|
|
||||||
private function buildQuery()
|
private function buildQuery()
|
||||||
{
|
{
|
||||||
$query = Order::with(['markList', 'invoice', 'shipments']);
|
$query = Order::query()->with([
|
||||||
|
'markList',
|
||||||
|
'invoice',
|
||||||
|
'shipments',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// SEARCH
|
||||||
if ($this->request->filled('search')) {
|
if ($this->request->filled('search')) {
|
||||||
$search = $this->request->search;
|
$search = trim($this->request->search);
|
||||||
$query->where(function($q) use ($search) {
|
|
||||||
$q->where('order_id', 'like', "%{$search}%")
|
$query->where(function ($q) use ($search) {
|
||||||
->orWhereHas('markList', function($q2) use ($search) {
|
$q->where('orders.order_id', 'like', "%{$search}%")
|
||||||
|
->orWhereHas('markList', function ($q2) use ($search) {
|
||||||
$q2->where('company_name', 'like', "%{$search}%")
|
$q2->where('company_name', 'like', "%{$search}%")
|
||||||
->orWhere('customer_id', 'like', "%{$search}%");
|
->orWhere('customer_id', 'like', "%{$search}%")
|
||||||
|
->orWhere('origin', 'like', "%{$search}%")
|
||||||
|
->orWhere('destination', 'like', "%{$search}%");
|
||||||
})
|
})
|
||||||
->orWhereHas('invoice', function($q3) use ($search) {
|
->orWhereHas('invoice', function ($q3) use ($search) {
|
||||||
$q3->where('invoice_number', 'like', "%{$search}%");
|
$q3->where('invoice_number', 'like', "%{$search}%");
|
||||||
|
})
|
||||||
|
->orWhereHas('shipments', function ($q4) use ($search) {
|
||||||
|
// ✅ FIXED
|
||||||
|
$q4->where('shipments.shipment_id', 'like', "%{$search}%");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// INVOICE STATUS
|
||||||
|
// INVOICE STATUS (FIXED)
|
||||||
if ($this->request->filled('status')) {
|
if ($this->request->filled('status')) {
|
||||||
$query->whereHas('invoice', function($q) {
|
$query->where(function ($q) {
|
||||||
$q->where('status', $this->request->status);
|
$q->whereHas('invoice', function ($q2) {
|
||||||
|
$q2->where('status', $this->request->status);
|
||||||
|
})
|
||||||
|
->orWhereDoesntHave('invoice');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// SHIPMENT STATUS (FIXED)
|
||||||
if ($this->request->filled('shipment')) {
|
if ($this->request->filled('shipment')) {
|
||||||
$query->whereHas('shipments', function($q) {
|
$query->where(function ($q) {
|
||||||
$q->where('status', $this->request->shipment);
|
$q->whereHas('shipments', function ($q2) {
|
||||||
|
$q2->where('status', $this->request->shipment);
|
||||||
|
})
|
||||||
|
->orWhereDoesntHave('shipments');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query->latest('id');
|
|
||||||
|
// DATE RANGE
|
||||||
|
if ($this->request->filled('from_date')) {
|
||||||
|
$query->whereDate('orders.created_at', '>=', $this->request->from_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->request->filled('to_date')) {
|
||||||
|
$query->whereDate('orders.created_at', '<=', $this->request->to_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->latest('orders.id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function collection()
|
public function collection()
|
||||||
{
|
{
|
||||||
$orders = $this->buildQuery()->get();
|
return $this->buildQuery()->get()->map(function ($order) {
|
||||||
|
|
||||||
// Map to simple array rows suitable for Excel
|
|
||||||
return $orders->map(function($order) {
|
|
||||||
$mark = $order->markList;
|
$mark = $order->markList;
|
||||||
$invoice = $order->invoice;
|
$invoice = $order->invoice;
|
||||||
$shipment = $order->shipments->first() ?? null;
|
$shipment = $order->shipments->first();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'Order ID' => $order->order_id,
|
'Order ID' => $order->order_id ?? '-',
|
||||||
'Shipment ID' => $shipment->shipment_id ?? '-',
|
'Shipment ID' => $shipment?->shipment_id ?? '-',
|
||||||
'Customer ID' => $mark->customer_id ?? '-',
|
'Customer ID' => $mark?->customer_id ?? '-',
|
||||||
'Company' => $mark->company_name ?? '-',
|
'Company' => $mark?->company_name ?? '-',
|
||||||
'Origin' => $mark->origin ?? $order->origin ?? '-',
|
'Origin' => $mark?->origin ?? $order->origin ?? '-',
|
||||||
'Destination' => $mark->destination ?? $order->destination ?? '-',
|
'Destination' => $mark?->destination ?? $order->destination ?? '-',
|
||||||
'Order Date' => $order->created_at ? $order->created_at->format('d-m-Y') : '-',
|
'Order Date' => $order->created_at
|
||||||
'Invoice No' => $invoice->invoice_number ?? '-',
|
? $order->created_at->format('d-m-Y')
|
||||||
'Invoice Date' => $invoice?->invoice_date ? \Carbon\Carbon::parse($invoice->invoice_date)->format('d-m-Y') : '-',
|
: '-',
|
||||||
'Amount' => $invoice?->final_amount ? number_format($invoice->final_amount, 2) : '-',
|
'Invoice No' => $invoice?->invoice_number ?? '-',
|
||||||
'Amount + GST' => $invoice?->final_amount_with_gst ? number_format($invoice->final_amount_with_gst, 2) : '-',
|
'Invoice Date' => $invoice?->invoice_date
|
||||||
'Invoice Status' => $invoice->status ? ucfirst($invoice->status) : 'Pending',
|
? Carbon::parse($invoice->invoice_date)->format('d-m-Y')
|
||||||
'Shipment Status' => $shipment?->status ? ucfirst(str_replace('_', ' ', $shipment->status)) : 'Pending',
|
: '-',
|
||||||
|
'Amount' => $invoice?->final_amount !== null
|
||||||
|
? number_format($invoice->final_amount, 2)
|
||||||
|
: '0.00',
|
||||||
|
'Amount + GST' => $invoice?->final_amount_with_gst !== null
|
||||||
|
? number_format($invoice->final_amount_with_gst, 2)
|
||||||
|
: '0.00',
|
||||||
|
'Invoice Status' => ucfirst($invoice?->status ?? 'pending'),
|
||||||
|
'Shipment Status' => ucfirst(str_replace('_', ' ', $shipment?->status ?? 'pending')),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,6 +365,128 @@ class AdminOrderController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function see($id)
|
||||||
|
{
|
||||||
|
$order = Order::with([
|
||||||
|
'markList',
|
||||||
|
'items',
|
||||||
|
'invoice.items',
|
||||||
|
'shipments' => function ($q) use ($id) {
|
||||||
|
$q->whereHas('orders', function ($oq) use ($id) {
|
||||||
|
$oq->where('orders.id', $id)
|
||||||
|
->whereNull('orders.deleted_at');
|
||||||
|
})->with([
|
||||||
|
'orders' => function ($oq) use ($id) {
|
||||||
|
$oq->where('orders.id', $id)
|
||||||
|
->whereNull('orders.deleted_at')
|
||||||
|
->with('items');
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
])->findOrFail($id);
|
||||||
|
|
||||||
|
/* ---------------- ORDER DATA ---------------- */
|
||||||
|
$orderData = [
|
||||||
|
'order_id' => $order->order_id,
|
||||||
|
'status' => $order->status,
|
||||||
|
'totals' => [
|
||||||
|
'ctn' => $order->ctn,
|
||||||
|
'qty' => $order->qty,
|
||||||
|
'ttl_qty' => $order->ttl_qty,
|
||||||
|
'cbm' => $order->cbm,
|
||||||
|
'ttl_cbm' => $order->ttl_cbm,
|
||||||
|
'kg' => $order->kg,
|
||||||
|
'ttl_kg' => $order->ttl_kg,
|
||||||
|
'amount' => $order->ttl_amount,
|
||||||
|
],
|
||||||
|
'items' => $order->items,
|
||||||
|
];
|
||||||
|
|
||||||
|
/* ---------------- SHIPMENTS DATA ---------------- */
|
||||||
|
$shipmentsData = [];
|
||||||
|
|
||||||
|
foreach ($order->shipments as $shipment) {
|
||||||
|
|
||||||
|
$shipmentOrders = [];
|
||||||
|
$totals = [
|
||||||
|
'ctn' => 0, 'qty' => 0, 'ttl_qty' => 0,
|
||||||
|
'cbm' => 0, 'ttl_cbm' => 0,
|
||||||
|
'kg' => 0, 'ttl_kg' => 0,
|
||||||
|
'amount' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($shipment->orders as $shipOrder) {
|
||||||
|
foreach ($shipOrder->items as $item) {
|
||||||
|
|
||||||
|
$shipmentOrders[] = [
|
||||||
|
'order_id' => $shipOrder->order_id,
|
||||||
|
'origin' => $shipOrder->origin,
|
||||||
|
'destination' => $shipOrder->destination,
|
||||||
|
'description' => $item->description,
|
||||||
|
'ctn' => $item->ctn,
|
||||||
|
'qty' => $item->qty,
|
||||||
|
'ttl_qty' => $item->ttl_qty,
|
||||||
|
'amount' => $item->ttl_amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$totals['ctn'] += $item->ctn;
|
||||||
|
$totals['qty'] += $item->qty;
|
||||||
|
$totals['ttl_qty'] += $item->ttl_qty;
|
||||||
|
$totals['cbm'] += $item->cbm;
|
||||||
|
$totals['ttl_cbm'] += $item->ttl_cbm;
|
||||||
|
$totals['kg'] += $item->kg;
|
||||||
|
$totals['ttl_kg'] += $item->ttl_kg;
|
||||||
|
$totals['amount'] += $item->ttl_amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($shipmentOrders)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$shipmentsData[] = [
|
||||||
|
'shipment_id' => $shipment->shipment_id,
|
||||||
|
'status' => $shipment->status,
|
||||||
|
'date' => $shipment->shipment_date,
|
||||||
|
'total_orders' => 1,
|
||||||
|
'orders' => $shipmentOrders,
|
||||||
|
'totals' => $totals,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- INVOICE DATA ---------------- */
|
||||||
|
$invoiceData = null;
|
||||||
|
if ($order->invoice) {
|
||||||
|
$invoice = $order->invoice;
|
||||||
|
$invoiceData = [
|
||||||
|
'invoice_no' => $invoice->invoice_number,
|
||||||
|
'status' => $invoice->status,
|
||||||
|
'invoice_date' => $invoice->invoice_date,
|
||||||
|
'due_date' => $invoice->due_date,
|
||||||
|
'customer' => [
|
||||||
|
'name' => $invoice->customer_name,
|
||||||
|
'mobile' => $invoice->customer_mobile,
|
||||||
|
'email' => $invoice->customer_email,
|
||||||
|
'address' => $invoice->customer_address,
|
||||||
|
'pincode' => $invoice->pincode,
|
||||||
|
],
|
||||||
|
'items' => $invoice->items,
|
||||||
|
'summary' => [
|
||||||
|
'amount' => $invoice->final_amount,
|
||||||
|
'cgst' => 0,
|
||||||
|
'sgst' => 0,
|
||||||
|
'total' => $invoice->final_amount_with_gst,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('admin.see_order', compact(
|
||||||
|
'order',
|
||||||
|
'orderData',
|
||||||
|
'shipmentsData',
|
||||||
|
'invoiceData'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function resetTemp()
|
public function resetTemp()
|
||||||
@@ -392,71 +514,125 @@ class AdminOrderController extends Controller
|
|||||||
|
|
||||||
private function buildOrdersQueryFromRequest(Request $request)
|
private function buildOrdersQueryFromRequest(Request $request)
|
||||||
{
|
{
|
||||||
$query = Order::with(['markList', 'invoice', 'shipments']);
|
$query = Order::query()
|
||||||
|
->with(['markList', 'invoice', 'shipments']);
|
||||||
|
|
||||||
// Search across order_id, markList.company_name, markList.customer_id, invoice.invoice_number
|
/* ----------------------------------
|
||||||
|
| SEARCH FILTER
|
||||||
|
|----------------------------------*/
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$search = $request->search;
|
$search = trim($request->search);
|
||||||
$query->where(function($q) use ($search) {
|
|
||||||
$q->where('order_id', 'like', "%{$search}%")
|
$query->where(function ($q) use ($search) {
|
||||||
->orWhereHas('markList', function($q2) use ($search) {
|
$q->where('orders.order_id', 'like', "%{$search}%")
|
||||||
|
|
||||||
|
->orWhereHas('markList', function ($q2) use ($search) {
|
||||||
$q2->where('company_name', 'like', "%{$search}%")
|
$q2->where('company_name', 'like', "%{$search}%")
|
||||||
->orWhere('customer_id', 'like', "%{$search}%");
|
->orWhere('customer_id', 'like', "%{$search}%")
|
||||||
|
->orWhere('origin', 'like', "%{$search}%")
|
||||||
|
->orWhere('destination', 'like', "%{$search}%");
|
||||||
})
|
})
|
||||||
->orWhereHas('invoice', function($q3) use ($search) {
|
|
||||||
|
->orWhereHas('invoice', function ($q3) use ($search) {
|
||||||
$q3->where('invoice_number', 'like', "%{$search}%");
|
$q3->where('invoice_number', 'like', "%{$search}%");
|
||||||
|
})
|
||||||
|
|
||||||
|
->orWhereHas('shipments', function ($q4) use ($search) {
|
||||||
|
// ✅ VERY IMPORTANT: table name added
|
||||||
|
$q4->where('shipments.shipment_id', 'like', "%{$search}%");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoice status filter
|
/* ----------------------------------
|
||||||
|
| INVOICE STATUS FILTER
|
||||||
|
|----------------------------------*/
|
||||||
if ($request->filled('status')) {
|
if ($request->filled('status')) {
|
||||||
$query->whereHas('invoice', function($q) use ($request) {
|
$query->where(function ($q) use ($request) {
|
||||||
$q->where('status', $request->status);
|
$q->whereHas('invoice', function ($q2) use ($request) {
|
||||||
|
$q2->where('status', $request->status);
|
||||||
|
})
|
||||||
|
->orWhereDoesntHave('invoice');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shipment status filter
|
/* ----------------------------------
|
||||||
|
| SHIPMENT STATUS FILTER
|
||||||
|
|----------------------------------*/
|
||||||
if ($request->filled('shipment')) {
|
if ($request->filled('shipment')) {
|
||||||
$query->whereHas('shipments', function($q) use ($request) {
|
$query->where(function ($q) use ($request) {
|
||||||
$q->where('status', $request->shipment);
|
$q->whereHas('shipments', function ($q2) use ($request) {
|
||||||
|
$q2->where('status', $request->shipment);
|
||||||
|
})
|
||||||
|
->orWhereDoesntHave('shipments');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// optional ordering
|
/* ----------------------------------
|
||||||
$query->latest('id');
|
| DATE RANGE FILTER (🔥 FIXED)
|
||||||
|
|----------------------------------*/
|
||||||
return $query;
|
if ($request->filled('from_date')) {
|
||||||
|
$query->whereDate('orders.created_at', '>=', $request->from_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('to_date')) {
|
||||||
|
$query->whereDate('orders.created_at', '<=', $request->to_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->latest('orders.id');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function downloadPdf(Request $request)
|
public function downloadPdf(Request $request)
|
||||||
{
|
{
|
||||||
// Build same filtered query used for table
|
// Build same filtered query used for table
|
||||||
$query = $this->buildOrdersQueryFromRequest($request);
|
// $query = $this->buildOrdersQueryFromRequest($request);
|
||||||
|
|
||||||
$orders = $query->get();
|
// $orders = $query->get();
|
||||||
|
|
||||||
|
// // optional: pass filters to view for header
|
||||||
|
// $filters = [
|
||||||
|
// 'search' => $request->search ?? null,
|
||||||
|
// 'status' => $request->status ?? null,
|
||||||
|
// 'shipment' => $request->shipment ?? null,
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $pdf = PDF::loadView('admin.orders.pdf', compact('orders', 'filters'))
|
||||||
|
// ->setPaper('a4', 'landscape'); // adjust if needed
|
||||||
|
|
||||||
|
// $fileName = 'orders-report'
|
||||||
|
// . ($filters['status'] ? "-{$filters['status']}" : '')
|
||||||
|
// . '-' . date('Y-m-d') . '.pdf';
|
||||||
|
|
||||||
|
// return $pdf->download($fileName);
|
||||||
|
$orders = $this->buildOrdersQueryFromRequest($request)->get();
|
||||||
|
|
||||||
// optional: pass filters to view for header
|
|
||||||
$filters = [
|
$filters = [
|
||||||
'search' => $request->search ?? null,
|
'search' => $request->search,
|
||||||
'status' => $request->status ?? null,
|
'status' => $request->status,
|
||||||
'shipment' => $request->shipment ?? null,
|
'shipment' => $request->shipment,
|
||||||
|
'from' => $request->from_date,
|
||||||
|
'to' => $request->to_date,
|
||||||
];
|
];
|
||||||
|
|
||||||
$pdf = PDF::loadView('admin.orders.pdf', compact('orders', 'filters'))
|
$pdf = PDF::loadView('admin.orders.pdf', compact('orders', 'filters'))
|
||||||
->setPaper('a4', 'landscape'); // adjust if needed
|
->setPaper('a4', 'landscape');
|
||||||
|
|
||||||
$fileName = 'orders-report'
|
return $pdf->download(
|
||||||
. ($filters['status'] ? "-{$filters['status']}" : '')
|
'orders-report-' . now()->format('Y-m-d') . '.pdf'
|
||||||
. '-' . date('Y-m-d') . '.pdf';
|
);
|
||||||
|
|
||||||
return $pdf->download($fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function downloadExcel(Request $request)
|
public function downloadExcel(Request $request)
|
||||||
{
|
{
|
||||||
// pass request to OrdersExport which will build Filtered query internally
|
// pass request to OrdersExport which will build Filtered query internally
|
||||||
return Excel::download(new OrdersExport($request), 'orders-report-' . date('Y-m-d') . '.xlsx');
|
// return Excel::download(new OrdersExport($request), 'orders-report-' . date('Y-m-d') . '.xlsx');
|
||||||
|
return Excel::download(
|
||||||
|
new OrdersExport($request),
|
||||||
|
'orders-report-' . now()->format('Y-m-d') . '.xlsx'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/reverb": "^1.6",
|
"laravel/reverb": "^1.6",
|
||||||
"laravel/tinker": "^2.10.1",
|
"laravel/tinker": "^2.10.1",
|
||||||
"maatwebsite/excel": "^1.1",
|
"maatwebsite/excel": "^3.1",
|
||||||
"mpdf/mpdf": "^8.2",
|
"mpdf/mpdf": "^8.2",
|
||||||
"php-open-source-saver/jwt-auth": "2.8",
|
"php-open-source-saver/jwt-auth": "2.8",
|
||||||
"spatie/laravel-permission": "^6.23"
|
"spatie/laravel-permission": "^6.23"
|
||||||
|
|||||||
556
composer.lock
generated
556
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "0e6764a0918bf6d36999c1623fbd2efb",
|
"content-hash": "e0736d5bff7a8cfda1aa3e5e13b94eec",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "barryvdh/laravel-dompdf",
|
"name": "barryvdh/laravel-dompdf",
|
||||||
@@ -342,6 +342,162 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-01-03T16:18:33+00:00"
|
"time": "2025-01-03T16:18:33+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "composer/pcre",
|
||||||
|
"version": "3.3.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/pcre.git",
|
||||||
|
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||||
|
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.4 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"phpstan/phpstan": "<1.11.10"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.12 || ^2",
|
||||||
|
"phpstan/phpstan-strict-rules": "^1 || ^2",
|
||||||
|
"phpunit/phpunit": "^8 || ^9"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"phpstan": {
|
||||||
|
"includes": [
|
||||||
|
"extension.neon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\Pcre\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "j.boggiano@seld.be",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
|
||||||
|
"keywords": [
|
||||||
|
"PCRE",
|
||||||
|
"preg",
|
||||||
|
"regex",
|
||||||
|
"regular expression"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/composer/pcre/issues",
|
||||||
|
"source": "https://github.com/composer/pcre/tree/3.3.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-11-12T16:29:46+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "composer/semver",
|
||||||
|
"version": "3.4.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/semver.git",
|
||||||
|
"reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
|
||||||
|
"reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.11",
|
||||||
|
"symfony/phpunit-bridge": "^3 || ^7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\Semver\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nils Adermann",
|
||||||
|
"email": "naderman@naderman.de",
|
||||||
|
"homepage": "http://www.naderman.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "j.boggiano@seld.be",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rob Bast",
|
||||||
|
"email": "rob.bast@gmail.com",
|
||||||
|
"homepage": "http://robbast.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Semver library that offers utilities, version constraint parsing and validation.",
|
||||||
|
"keywords": [
|
||||||
|
"semantic",
|
||||||
|
"semver",
|
||||||
|
"validation",
|
||||||
|
"versioning"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||||
|
"issues": "https://github.com/composer/semver/issues",
|
||||||
|
"source": "https://github.com/composer/semver/tree/3.4.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-08-20T19:15:30+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "dflydev/dot-access-data",
|
"name": "dflydev/dot-access-data",
|
||||||
"version": "v3.0.3",
|
"version": "v3.0.3",
|
||||||
@@ -917,6 +1073,67 @@
|
|||||||
},
|
},
|
||||||
"time": "2023-08-08T05:53:35+00:00"
|
"time": "2023-08-08T05:53:35+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ezyang/htmlpurifier",
|
||||||
|
"version": "v4.19.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||||
|
"reference": "b287d2a16aceffbf6e0295559b39662612b77fcf"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf",
|
||||||
|
"reference": "b287d2a16aceffbf6e0295559b39662612b77fcf",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"cerdic/css-tidy": "^1.7 || ^2.0",
|
||||||
|
"simpletest/simpletest": "dev-master"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.",
|
||||||
|
"ext-bcmath": "Used for unit conversion and imagecrash protection",
|
||||||
|
"ext-iconv": "Converts text to and from non-UTF-8 encodings",
|
||||||
|
"ext-tidy": "Used for pretty-printing HTML"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"library/HTMLPurifier.composer.php"
|
||||||
|
],
|
||||||
|
"psr-0": {
|
||||||
|
"HTMLPurifier": "library/"
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/library/HTMLPurifier/Language/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Edward Z. Yang",
|
||||||
|
"email": "admin@htmlpurifier.org",
|
||||||
|
"homepage": "http://ezyang.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Standards compliant HTML filter written in PHP",
|
||||||
|
"homepage": "http://htmlpurifier.org/",
|
||||||
|
"keywords": [
|
||||||
|
"html"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/ezyang/htmlpurifier/issues",
|
||||||
|
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0"
|
||||||
|
},
|
||||||
|
"time": "2025-10-17T16:34:55+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "fruitcake/php-cors",
|
"name": "fruitcake/php-cors",
|
||||||
"version": "v1.4.0",
|
"version": "v1.4.0",
|
||||||
@@ -2582,48 +2799,58 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maatwebsite/excel",
|
"name": "maatwebsite/excel",
|
||||||
"version": "v1.1.5",
|
"version": "3.1.67",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Maatwebsite/Laravel-Excel.git",
|
"url": "https://github.com/SpartnerNL/Laravel-Excel.git",
|
||||||
"reference": "0c67aba8387726458d42461eae91a3415593bbc4"
|
"reference": "e508e34a502a3acc3329b464dad257378a7edb4d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Maatwebsite/Laravel-Excel/zipball/0c67aba8387726458d42461eae91a3415593bbc4",
|
"url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/e508e34a502a3acc3329b464dad257378a7edb4d",
|
||||||
"reference": "0c67aba8387726458d42461eae91a3415593bbc4",
|
"reference": "e508e34a502a3acc3329b464dad257378a7edb4d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.0",
|
"composer/semver": "^3.3",
|
||||||
"phpoffice/phpexcel": "~1.8.0"
|
"ext-json": "*",
|
||||||
|
"illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0",
|
||||||
|
"php": "^7.0||^8.0",
|
||||||
|
"phpoffice/phpspreadsheet": "^1.30.0",
|
||||||
|
"psr/simple-cache": "^1.0||^2.0||^3.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mockery/mockery": "~0.9",
|
"laravel/scout": "^7.0||^8.0||^9.0||^10.0",
|
||||||
"orchestra/testbench": "~2.2.0@dev",
|
"orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0",
|
||||||
"phpunit/phpunit": "~4.0"
|
"predis/predis": "^1.1"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"extra": {
|
||||||
"psr-0": {
|
"laravel": {
|
||||||
"Maatwebsite\\Excel\\": "src/"
|
"aliases": {
|
||||||
|
"Excel": "Maatwebsite\\Excel\\Facades\\Excel"
|
||||||
},
|
},
|
||||||
"classmap": [
|
"providers": [
|
||||||
"src/Maatwebsite/Excel",
|
"Maatwebsite\\Excel\\ExcelServiceProvider"
|
||||||
"tests/TestCase.php"
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Maatwebsite\\Excel\\": "src/"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": [
|
"license": [
|
||||||
"LGPL"
|
"MIT"
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Maatwebsite.nl",
|
"name": "Patrick Brouwers",
|
||||||
"email": "patrick@maatwebsite.nl"
|
"email": "patrick@spartner.nl"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "An eloquent way of importing and exporting Excel and CSV in Laravel 4 with the power of PHPExcel",
|
"description": "Supercharged Excel exports and imports in Laravel",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"PHPExcel",
|
"PHPExcel",
|
||||||
"batch",
|
"batch",
|
||||||
@@ -2631,13 +2858,210 @@
|
|||||||
"excel",
|
"excel",
|
||||||
"export",
|
"export",
|
||||||
"import",
|
"import",
|
||||||
"laravel"
|
"laravel",
|
||||||
|
"php",
|
||||||
|
"phpspreadsheet"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/Maatwebsite/Laravel-Excel/issues",
|
"issues": "https://github.com/SpartnerNL/Laravel-Excel/issues",
|
||||||
"source": "https://github.com/Maatwebsite/Laravel-Excel/tree/master"
|
"source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.67"
|
||||||
},
|
},
|
||||||
"time": "2014-07-10T09:06:07+00:00"
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://laravel-excel.com/commercial-support",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/patrickbrouwers",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-08-26T09:13:16+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maennchen/zipstream-php",
|
||||||
|
"version": "3.1.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/maennchen/ZipStream-PHP.git",
|
||||||
|
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f",
|
||||||
|
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-zlib": "*",
|
||||||
|
"php-64bit": "^8.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"brianium/paratest": "^7.7",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.16",
|
||||||
|
"guzzlehttp/guzzle": "^7.5",
|
||||||
|
"mikey179/vfsstream": "^1.6",
|
||||||
|
"php-coveralls/php-coveralls": "^2.5",
|
||||||
|
"phpunit/phpunit": "^11.0",
|
||||||
|
"vimeo/psalm": "^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"guzzlehttp/psr7": "^2.4",
|
||||||
|
"psr/http-message": "^2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"ZipStream\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Paul Duncan",
|
||||||
|
"email": "pabs@pablotron.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonatan Männchen",
|
||||||
|
"email": "jonatan@maennchen.ch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jesse Donat",
|
||||||
|
"email": "donatj@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "András Kolesár",
|
||||||
|
"email": "kolesar@kolesar.hu"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
|
||||||
|
"keywords": [
|
||||||
|
"stream",
|
||||||
|
"zip"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
|
||||||
|
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/maennchen",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-01-27T12:07:53+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "markbaker/complex",
|
||||||
|
"version": "3.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MarkBaker/PHPComplex.git",
|
||||||
|
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
||||||
|
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Complex\\": "classes/src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"email": "mark@lange.demon.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Class for working with complex numbers",
|
||||||
|
"homepage": "https://github.com/MarkBaker/PHPComplex",
|
||||||
|
"keywords": [
|
||||||
|
"complex",
|
||||||
|
"mathematics"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
|
||||||
|
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
|
||||||
|
},
|
||||||
|
"time": "2022-12-06T16:21:08+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "markbaker/matrix",
|
||||||
|
"version": "3.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MarkBaker/PHPMatrix.git",
|
||||||
|
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
|
||||||
|
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpdocumentor/phpdocumentor": "2.*",
|
||||||
|
"phploc/phploc": "^4.0",
|
||||||
|
"phpmd/phpmd": "2.*",
|
||||||
|
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
||||||
|
"sebastian/phpcpd": "^4.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Matrix\\": "classes/src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"email": "mark@demon-angel.eu"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Class for working with matrices",
|
||||||
|
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
||||||
|
"keywords": [
|
||||||
|
"mathematics",
|
||||||
|
"matrix",
|
||||||
|
"vector"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
|
||||||
|
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
|
||||||
|
},
|
||||||
|
"time": "2022-12-02T22:17:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "masterminds/html5",
|
"name": "masterminds/html5",
|
||||||
@@ -3756,66 +4180,110 @@
|
|||||||
"time": "2025-02-10T21:11:16+00:00"
|
"time": "2025-02-10T21:11:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpoffice/phpexcel",
|
"name": "phpoffice/phpspreadsheet",
|
||||||
"version": "1.8.1",
|
"version": "1.30.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHPOffice/PHPExcel.git",
|
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
||||||
"reference": "372c7cbb695a6f6f1e62649381aeaa37e7e70b32"
|
"reference": "fa8257a579ec623473eabfe49731de5967306c4c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHPOffice/PHPExcel/zipball/372c7cbb695a6f6f1e62649381aeaa37e7e70b32",
|
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fa8257a579ec623473eabfe49731de5967306c4c",
|
||||||
"reference": "372c7cbb695a6f6f1e62649381aeaa37e7e70b32",
|
"reference": "fa8257a579ec623473eabfe49731de5967306c4c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"composer/pcre": "^1||^2||^3",
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
|
"ext-xmlreader": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"php": ">=5.2.0"
|
"ext-zip": "*",
|
||||||
|
"ext-zlib": "*",
|
||||||
|
"ezyang/htmlpurifier": "^4.15",
|
||||||
|
"maennchen/zipstream-php": "^2.1 || ^3.0",
|
||||||
|
"markbaker/complex": "^3.0",
|
||||||
|
"markbaker/matrix": "^3.0",
|
||||||
|
"php": ">=7.4.0 <8.5.0",
|
||||||
|
"psr/http-client": "^1.0",
|
||||||
|
"psr/http-factory": "^1.0",
|
||||||
|
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "dev-main",
|
||||||
|
"dompdf/dompdf": "^1.0 || ^2.0 || ^3.0",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.2",
|
||||||
|
"mitoteam/jpgraph": "^10.3",
|
||||||
|
"mpdf/mpdf": "^8.1.1",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpstan/phpstan": "^1.1",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0",
|
||||||
|
"phpunit/phpunit": "^8.5 || ^9.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.7",
|
||||||
|
"tecnickcom/tcpdf": "^6.5"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"ext-intl": "PHP Internationalization Functions",
|
||||||
|
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
|
||||||
|
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-4": {
|
||||||
"PHPExcel": "Classes/"
|
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": [
|
"license": [
|
||||||
"LGPL"
|
"MIT"
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Maarten Balliauw",
|
"name": "Maarten Balliauw",
|
||||||
"homepage": "http://blog.maartenballiauw.be"
|
"homepage": "https://blog.maartenballiauw.be"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Mark Baker"
|
"name": "Mark Baker",
|
||||||
|
"homepage": "https://markbakeruk.net"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Franck Lefevre",
|
"name": "Franck Lefevre",
|
||||||
"homepage": "http://blog.rootslabs.net"
|
"homepage": "https://rootslabs.net"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Erik Tilt"
|
"name": "Erik Tilt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Adrien Crivelli"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
||||||
"homepage": "http://phpexcel.codeplex.com",
|
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"OpenXML",
|
"OpenXML",
|
||||||
"excel",
|
"excel",
|
||||||
|
"gnumeric",
|
||||||
|
"ods",
|
||||||
"php",
|
"php",
|
||||||
"spreadsheet",
|
"spreadsheet",
|
||||||
"xls",
|
"xls",
|
||||||
"xlsx"
|
"xlsx"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/PHPOffice/PHPExcel/issues",
|
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
||||||
"source": "https://github.com/PHPOffice/PHPExcel/tree/master"
|
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.30.1"
|
||||||
},
|
},
|
||||||
"abandoned": "phpoffice/phpspreadsheet",
|
"time": "2025-10-26T16:01:04+00:00"
|
||||||
"time": "2015-05-01T07:00:55+00:00"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpoption/phpoption",
|
"name": "phpoption/phpoption",
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
@extends('admin.layouts.app')
|
@extends('admin.layouts.app')
|
||||||
|
|
||||||
@section('page-title', 'Orders')
|
@section('page-title', 'Orders')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<style>
|
<style>
|
||||||
/* ===== GLOBAL RESPONSIVE STYLES ===== */
|
/* ===== GLOBAL RESPONSIVE STYLES ===== */
|
||||||
html, body {
|
html, body {
|
||||||
overflow-x: hidden !important;
|
overflow-x: hidden !important;
|
||||||
@@ -553,6 +553,29 @@
|
|||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-range {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-input {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 1px solid var(--border-light);
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
background: white;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
min-width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.filter-bar {
|
.filter-bar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -563,38 +586,60 @@
|
|||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-select {
|
.filter-select,
|
||||||
|
.date-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-range {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
.pagination-container {
|
.pagination-container {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="orders-container">
|
<div class="orders-container">
|
||||||
<div class="orders-title">
|
<div class="orders-title">
|
||||||
<i class="fas fa-box-open"></i> Orders Management
|
<i class="fas fa-box-open"></i> Orders Management
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Stats Cards -->
|
<!-- Stats Cards -->
|
||||||
<div class="stats-container">
|
<div class="stats-container">
|
||||||
|
@php
|
||||||
|
$totalOrders = $orders->count();
|
||||||
|
$paidInvoices = $orders->filter(function($order) {
|
||||||
|
$status = $order->invoice?->status ?? 'pending';
|
||||||
|
return strtolower($status) === 'paid';
|
||||||
|
})->count();
|
||||||
|
$pendingInvoices = $orders->filter(function($order) {
|
||||||
|
$status = $order->invoice?->status ?? 'pending';
|
||||||
|
return strtolower($status) === 'pending';
|
||||||
|
})->count();
|
||||||
|
$overdueInvoices = $orders->filter(function($order) {
|
||||||
|
$status = $order->invoice?->status ?? 'pending';
|
||||||
|
return strtolower($status) === 'overdue';
|
||||||
|
})->count();
|
||||||
|
@endphp
|
||||||
|
|
||||||
<div class="stat-card total">
|
<div class="stat-card total">
|
||||||
<div class="stat-value">{{ $orders->count() }}</div>
|
<div class="stat-value">{{ $totalOrders }}</div>
|
||||||
<div class="stat-label">Total Orders</div>
|
<div class="stat-label">Total Orders</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card paid">
|
<div class="stat-card paid">
|
||||||
<div class="stat-value">{{ $orders->where('invoice.status', 'paid')->count() }}</div>
|
<div class="stat-value">{{ $paidInvoices }}</div>
|
||||||
<div class="stat-label">Paid Invoices</div>
|
<div class="stat-label">Paid Invoices</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card pending">
|
<div class="stat-card pending">
|
||||||
<div class="stat-value">{{ $orders->where('invoice.status', 'pending')->count() }}</div>
|
<div class="stat-value">{{ $pendingInvoices }}</div>
|
||||||
<div class="stat-label">Pending Invoices</div>
|
<div class="stat-label">Pending Invoices</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card overdue">
|
<div class="stat-card overdue">
|
||||||
<div class="stat-value">{{ $orders->where('invoice.status', 'overdue')->count() }}</div>
|
<div class="stat-value">{{ $overdueInvoices }}</div>
|
||||||
<div class="stat-label">Overdue Invoices</div>
|
<div class="stat-label">Overdue Invoices</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -617,12 +662,14 @@
|
|||||||
<i class="fas fa-search search-icon"></i>
|
<i class="fas fa-search search-icon"></i>
|
||||||
<input type="text" class="search-input" placeholder="Search orders..." id="searchInput">
|
<input type="text" class="search-input" placeholder="Search orders..." id="searchInput">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<select class="filter-select" id="statusFilter">
|
<select class="filter-select" id="statusFilter">
|
||||||
<option value="">All Status</option>
|
<option value="">All Invoice Status</option>
|
||||||
<option value="paid">Paid</option>
|
<option value="paid">Paid</option>
|
||||||
<option value="pending">Pending</option>
|
<option value="pending">Pending</option>
|
||||||
<option value="overdue">Overdue</option>
|
<option value="overdue">Overdue</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select class="filter-select" id="shipmentFilter">
|
<select class="filter-select" id="shipmentFilter">
|
||||||
<option value="">All Shipments</option>
|
<option value="">All Shipments</option>
|
||||||
<option value="pending">Pending</option>
|
<option value="pending">Pending</option>
|
||||||
@@ -630,6 +677,13 @@
|
|||||||
<option value="dispatched">Dispatched</option>
|
<option value="dispatched">Dispatched</option>
|
||||||
<option value="delivered">Delivered</option>
|
<option value="delivered">Delivered</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<div class="date-range">
|
||||||
|
<span class="date-label">From:</span>
|
||||||
|
<input type="date" class="date-input" id="fromDate">
|
||||||
|
<span class="date-label">To:</span>
|
||||||
|
<input type="date" class="date-input" id="toDate">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(isset($orders) && $orders->count() > 0)
|
@if(isset($orders) && $orders->count() > 0)
|
||||||
@@ -660,20 +714,23 @@
|
|||||||
$mark = $order->markList ?? null;
|
$mark = $order->markList ?? null;
|
||||||
$invoice = $order->invoice ?? null;
|
$invoice = $order->invoice ?? null;
|
||||||
$shipment = $order->shipments->first() ?? null;
|
$shipment = $order->shipments->first() ?? null;
|
||||||
$invoiceStatus = strtolower($invoice->status ?? '');
|
|
||||||
$shipmentStatus = strtolower(str_replace('_', ' ', $shipment->status ?? ''));
|
// Normalized status values for consistent CSS classes
|
||||||
|
$invoiceStatus = strtolower($invoice?->status ?? 'pending');
|
||||||
|
$shipmentStatus = strtolower($shipment?->status ?? 'pending');
|
||||||
|
$shipmentStatusForCss = str_replace([' ', '-'], '_', $shipmentStatus);
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $order->order_id ?? '-' }}</td>
|
<td>{{ $order->order_id ?? '-' }}</td>
|
||||||
<td>{{ $shipment->shipment_id ?? '-' }}</td>
|
<td>{{ $shipment?->shipment_id ?? '-' }}</td>
|
||||||
<td>{{ $mark->customer_id ?? '-' }}</td>
|
<td>{{ $mark?->customer_id ?? '-' }}</td>
|
||||||
<td>{{ $mark->company_name ?? '-' }}</td>
|
<td>{{ $mark?->company_name ?? '-' }}</td>
|
||||||
<td>{{ $mark->origin ?? $order->origin ?? '-' }}</td>
|
<td>{{ $mark?->origin ?? $order->origin ?? '-' }}</td>
|
||||||
<td>{{ $mark->destination ?? $order->destination ?? '-' }}</td>
|
<td>{{ $mark?->destination ?? $order->destination ?? '-' }}</td>
|
||||||
<td>{{ $order->created_at ? $order->created_at->format('d-m-Y') : '-' }}</td>
|
<td>{{ $order->created_at ? $order->created_at->format('d-m-Y') : '-' }}</td>
|
||||||
|
|
||||||
<td>{{ $invoice->invoice_number ?? '-' }}</td>
|
<td>{{ $invoice?->invoice_number ?? '-' }}</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{{ $invoice?->invoice_date ? date('d-m-Y', strtotime($invoice->invoice_date)) : '-' }}
|
{{ $invoice?->invoice_date ? date('d-m-Y', strtotime($invoice->invoice_date)) : '-' }}
|
||||||
@@ -688,27 +745,19 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@if($invoice?->status)
|
|
||||||
<span class="status-badge status-{{ $invoiceStatus }}">
|
<span class="status-badge status-{{ $invoiceStatus }}">
|
||||||
{{ ucfirst($invoice->status) }}
|
{{ ucfirst($invoiceStatus) }}
|
||||||
</span>
|
</span>
|
||||||
@else
|
|
||||||
<span class="status-badge status-pending">Pending</span>
|
|
||||||
@endif
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@if($shipment?->status)
|
<span class="status-badge ship-{{ $shipmentStatusForCss }}">
|
||||||
<span class="status-badge ship-{{ str_replace(' ', '_', $shipmentStatus) }}">
|
|
||||||
{{ ucfirst($shipmentStatus) }}
|
{{ ucfirst($shipmentStatus) }}
|
||||||
</span>
|
</span>
|
||||||
@else
|
|
||||||
<span class="status-badge ship-pending">Pending</span>
|
|
||||||
@endif
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{{ route('admin.orders.show', $order->id) }}" title="View Details">
|
<a href="{{ route('admin.orders.see', $order->id) }}" title="View Details">
|
||||||
<i class="fas fa-eye action-btn"></i>
|
<i class="fas fa-eye action-btn"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@@ -744,17 +793,14 @@
|
|||||||
<p class="text-muted">There are currently no orders in the system.</p>
|
<p class="text-muted">There are currently no orders in the system.</p>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Pagination state
|
// Pagination state
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
const itemsPerPage = 10;
|
const itemsPerPage = 10;
|
||||||
let allOrders = @json($orders);
|
let allOrders = @json($orders);
|
||||||
let filteredOrders = [...allOrders];
|
let filteredOrders = [...allOrders];
|
||||||
console.log('ORDERS SAMPLE:', allOrders[0]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Status icon helper functions
|
// Status icon helper functions
|
||||||
function getInvoiceStatusIcon(status) {
|
function getInvoiceStatusIcon(status) {
|
||||||
@@ -785,26 +831,96 @@ console.log('ORDERS SAMPLE:', allOrders[0]);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Date validation
|
||||||
|
function isValidDate(dateString) {
|
||||||
|
if (!dateString) return false;
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date instanceof Date && !isNaN(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date comparison helper - FIXED to properly handle order date
|
||||||
|
function isDateBetween(dateToCheck, fromDate, toDate) {
|
||||||
|
if (!dateToCheck) return true; // If no date to check, don't filter it out
|
||||||
|
|
||||||
|
// Parse the date to check (order date)
|
||||||
|
const checkDate = new Date(dateToCheck);
|
||||||
|
if (!isValidDate(checkDate)) return true;
|
||||||
|
|
||||||
|
// Set time to beginning of day for comparison
|
||||||
|
checkDate.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Check from date
|
||||||
|
if (fromDate && isValidDate(fromDate)) {
|
||||||
|
const from = new Date(fromDate);
|
||||||
|
from.setHours(0, 0, 0, 0);
|
||||||
|
if (checkDate < from) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to date
|
||||||
|
if (toDate && isValidDate(toDate)) {
|
||||||
|
const to = new Date(toDate);
|
||||||
|
to.setHours(23, 59, 59, 999);
|
||||||
|
if (checkDate > to) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to check if an order matches all filters
|
||||||
|
function orderMatchesFilters(order, searchTerm, statusFilter, shipmentFilter, fromDate, toDate) {
|
||||||
|
// Search term matching across multiple fields
|
||||||
|
let matchesSearch = true;
|
||||||
|
if (searchTerm) {
|
||||||
|
const searchFields = [
|
||||||
|
order.order_id?.toString().toLowerCase(),
|
||||||
|
order.shipments?.[0]?.shipment_id?.toString().toLowerCase(),
|
||||||
|
order.markList?.customer_id?.toString().toLowerCase(),
|
||||||
|
order.markList?.company_name?.toString().toLowerCase(),
|
||||||
|
order.invoice?.invoice_number?.toString().toLowerCase(),
|
||||||
|
order.markList?.origin?.toString().toLowerCase(),
|
||||||
|
order.markList?.destination?.toString().toLowerCase()
|
||||||
|
];
|
||||||
|
matchesSearch = searchFields.some(field => field && field.includes(searchTerm.toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoice status filter with safe access and normalization
|
||||||
|
const invoiceStatus = (order.invoice?.status || 'pending').toLowerCase();
|
||||||
|
const matchesStatus = !statusFilter || invoiceStatus === statusFilter;
|
||||||
|
|
||||||
|
// Shipment status filter with safe access and normalization
|
||||||
|
const shipmentStatus = (order.shipments?.[0]?.status || 'pending').toLowerCase();
|
||||||
|
const matchesShipment = !shipmentFilter || shipmentStatus === shipmentFilter;
|
||||||
|
|
||||||
|
// Date range filter - using order date (created_at)
|
||||||
|
const orderDate = order.created_at;
|
||||||
|
const matchesDate = isDateBetween(orderDate, fromDate, toDate);
|
||||||
|
|
||||||
|
return matchesSearch && matchesStatus && matchesShipment && matchesDate;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize pagination and filters
|
// Initialize pagination and filters
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Set today as default "to" date
|
||||||
renderTable();
|
renderTable();
|
||||||
updatePaginationControls();
|
updatePaginationControls();
|
||||||
|
|
||||||
// Bind pagination events
|
// Pagination events
|
||||||
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage);
|
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage);
|
||||||
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage);
|
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage);
|
||||||
|
|
||||||
// Bind filter events
|
// Filter events
|
||||||
document.getElementById('searchInput').addEventListener('input', handleSearch);
|
document.getElementById('searchInput').addEventListener('input', handleFilter);
|
||||||
document.getElementById('statusFilter').addEventListener('change', handleFilter);
|
document.getElementById('statusFilter').addEventListener('change', handleFilter);
|
||||||
document.getElementById('shipmentFilter').addEventListener('change', handleFilter);
|
document.getElementById('shipmentFilter').addEventListener('change', handleFilter);
|
||||||
|
document.getElementById('fromDate').addEventListener('change', handleFilter);
|
||||||
|
document.getElementById('toDate').addEventListener('change', handleFilter);
|
||||||
|
|
||||||
// Bind download events
|
// Download buttons
|
||||||
document.getElementById('downloadPdf').addEventListener('click', downloadPdf);
|
document.getElementById('downloadPdf').addEventListener('click', downloadPdf);
|
||||||
document.getElementById('downloadExcel').addEventListener('click', downloadExcel);
|
document.getElementById('downloadExcel').addEventListener('click', downloadExcel);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Download Functions
|
// Download Functions with ALL filter parameters
|
||||||
function downloadPdf() {
|
function downloadPdf() {
|
||||||
if (filteredOrders.length === 0) {
|
if (filteredOrders.length === 0) {
|
||||||
showNotification('No data available to download', 'warning');
|
showNotification('No data available to download', 'warning');
|
||||||
@@ -813,25 +929,26 @@ console.log('ORDERS SAMPLE:', allOrders[0]);
|
|||||||
|
|
||||||
showNotification('Preparing PDF download...', 'info');
|
showNotification('Preparing PDF download...', 'info');
|
||||||
|
|
||||||
// Get current filters for the download
|
// Get all current filters
|
||||||
const searchTerm = document.getElementById('searchInput').value;
|
const searchTerm = document.getElementById('searchInput').value;
|
||||||
const statusFilter = document.getElementById('statusFilter').value;
|
const statusFilter = document.getElementById('statusFilter').value;
|
||||||
const shipmentFilter = document.getElementById('shipmentFilter').value;
|
const shipmentFilter = document.getElementById('shipmentFilter').value;
|
||||||
|
const fromDate = document.getElementById('fromDate').value;
|
||||||
|
const toDate = document.getElementById('toDate').value;
|
||||||
|
|
||||||
// Create download URL with filters
|
// Create download URL with all filters - ALWAYS include all filters
|
||||||
let downloadUrl = "{{ route('admin.orders.download.pdf') }}";
|
let downloadUrl = "{{ route('admin.orders.download.pdf') }}";
|
||||||
let params = new URLSearchParams();
|
let params = new URLSearchParams();
|
||||||
|
|
||||||
if (searchTerm) params.append('search', searchTerm);
|
// Always append all parameters, even if empty
|
||||||
if (statusFilter) params.append('status', statusFilter);
|
params.append('search', searchTerm || '');
|
||||||
if (shipmentFilter) params.append('shipment', shipmentFilter);
|
params.append('status', statusFilter || '');
|
||||||
|
params.append('shipment', shipmentFilter || '');
|
||||||
|
params.append('from_date', fromDate || '');
|
||||||
|
params.append('to_date', toDate || '');
|
||||||
|
|
||||||
if (params.toString()) {
|
// Trigger download with all parameters
|
||||||
downloadUrl += '?' + params.toString();
|
window.location.href = downloadUrl + '?' + params.toString();
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger download
|
|
||||||
window.location.href = downloadUrl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadExcel() {
|
function downloadExcel() {
|
||||||
@@ -842,120 +959,49 @@ console.log('ORDERS SAMPLE:', allOrders[0]);
|
|||||||
|
|
||||||
showNotification('Preparing Excel download...', 'info');
|
showNotification('Preparing Excel download...', 'info');
|
||||||
|
|
||||||
// Get current filters for the download
|
// Get all current filters
|
||||||
const searchTerm = document.getElementById('searchInput').value;
|
const searchTerm = document.getElementById('searchInput').value;
|
||||||
const statusFilter = document.getElementById('statusFilter').value;
|
const statusFilter = document.getElementById('statusFilter').value;
|
||||||
const shipmentFilter = document.getElementById('shipmentFilter').value;
|
const shipmentFilter = document.getElementById('shipmentFilter').value;
|
||||||
|
const fromDate = document.getElementById('fromDate').value;
|
||||||
|
const toDate = document.getElementById('toDate').value;
|
||||||
|
|
||||||
// Create download URL with filters
|
// Create download URL with all filters - ALWAYS include all filters
|
||||||
let downloadUrl = "{{ route('admin.orders.download.excel') }}";
|
let downloadUrl = "{{ route('admin.orders.download.excel') }}";
|
||||||
let params = new URLSearchParams();
|
let params = new URLSearchParams();
|
||||||
|
|
||||||
if (searchTerm) params.append('search', searchTerm);
|
// Always append all parameters, even if empty
|
||||||
if (statusFilter) params.append('status', statusFilter);
|
params.append('search', searchTerm || '');
|
||||||
if (shipmentFilter) params.append('shipment', shipmentFilter);
|
params.append('status', statusFilter || '');
|
||||||
|
params.append('shipment', shipmentFilter || '');
|
||||||
|
params.append('from_date', fromDate || '');
|
||||||
|
params.append('to_date', toDate || '');
|
||||||
|
|
||||||
if (params.toString()) {
|
// Trigger download with all parameters
|
||||||
downloadUrl += '?' + params.toString();
|
window.location.href = downloadUrl + '?' + params.toString();
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger download
|
|
||||||
window.location.href = downloadUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notification function
|
|
||||||
function showNotification(message, type = 'info') {
|
|
||||||
// Remove existing notification
|
|
||||||
const existingNotification = document.querySelector('.download-notification');
|
|
||||||
if (existingNotification) {
|
|
||||||
existingNotification.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
const notification = document.createElement('div');
|
|
||||||
notification.className = `download-notification alert alert-${type}`;
|
|
||||||
notification.style.cssText = `
|
|
||||||
position: fixed;
|
|
||||||
top: 20px;
|
|
||||||
right: 20px;
|
|
||||||
z-index: 10000;
|
|
||||||
padding: 12px 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: white;
|
|
||||||
font-weight: 500;
|
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
||||||
animation: slideIn 0.3s ease;
|
|
||||||
`;
|
|
||||||
|
|
||||||
if (type === 'info') {
|
|
||||||
notification.style.background = 'linear-gradient(135deg, #3b82f6, #1d4ed8)';
|
|
||||||
} else if (type === 'warning') {
|
|
||||||
notification.style.background = 'linear-gradient(135deg, #f59e0b, #d97706)';
|
|
||||||
} else if (type === 'success') {
|
|
||||||
notification.style.background = 'linear-gradient(135deg, #10b981, #059669)';
|
|
||||||
}
|
|
||||||
|
|
||||||
notification.textContent = message;
|
|
||||||
document.body.appendChild(notification);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
notification.style.animation = 'slideOut 0.3s ease';
|
|
||||||
setTimeout(() => notification.remove(), 300);
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add CSS for notifications
|
|
||||||
const style = document.createElement('style');
|
|
||||||
style.textContent = `
|
|
||||||
@keyframes slideIn {
|
|
||||||
from { transform: translateX(100%); opacity: 0; }
|
|
||||||
to { transform: translateX(0); opacity: 1; }
|
|
||||||
}
|
|
||||||
@keyframes slideOut {
|
|
||||||
from { transform: translateX(0); opacity: 1; }
|
|
||||||
to { transform: translateX(100%); opacity: 0; }
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
document.head.appendChild(style);
|
|
||||||
|
|
||||||
// Search functionality
|
|
||||||
function handleSearch(e) {
|
|
||||||
const searchTerm = e.target.value.toLowerCase();
|
|
||||||
filterOrders();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter functionality
|
// Filter functionality
|
||||||
function handleFilter() {
|
function handleFilter() {
|
||||||
filterOrders();
|
const searchTerm = document.getElementById('searchInput').value;
|
||||||
}
|
|
||||||
|
|
||||||
function filterOrders() {
|
|
||||||
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
|
|
||||||
const statusFilter = document.getElementById('statusFilter').value;
|
const statusFilter = document.getElementById('statusFilter').value;
|
||||||
const shipmentFilter = document.getElementById('shipmentFilter').value;
|
const shipmentFilter = document.getElementById('shipmentFilter').value;
|
||||||
|
const fromDate = document.getElementById('fromDate').value;
|
||||||
|
const toDate = document.getElementById('toDate').value;
|
||||||
|
|
||||||
filteredOrders = allOrders.filter(order => {
|
// Apply all filters
|
||||||
const matchesSearch = !searchTerm ||
|
filteredOrders = allOrders.filter(order =>
|
||||||
order.order_id?.toLowerCase().includes(searchTerm) ||
|
orderMatchesFilters(order, searchTerm, statusFilter, shipmentFilter, fromDate, toDate)
|
||||||
order.mark_list?.company_name?.toLowerCase().includes(searchTerm) ||
|
);
|
||||||
order.invoice?.invoice_number?.toLowerCase().includes(searchTerm);
|
|
||||||
|
|
||||||
|
|
||||||
const matchesStatus = !statusFilter ||
|
|
||||||
(order.invoice?.status && order.invoice.status.toLowerCase() === statusFilter);
|
|
||||||
|
|
||||||
const matchesShipment = !shipmentFilter ||
|
|
||||||
(order.shipments?.[0]?.status && order.shipments[0].status.toLowerCase() === shipmentFilter);
|
|
||||||
|
|
||||||
return matchesSearch && matchesStatus && matchesShipment;
|
|
||||||
});
|
|
||||||
|
|
||||||
currentPage = 1;
|
currentPage = 1;
|
||||||
renderTable();
|
renderTable();
|
||||||
updatePaginationControls();
|
updatePaginationControls();
|
||||||
|
|
||||||
// Update download buttons state
|
// Update download buttons state
|
||||||
document.getElementById('downloadPdf').disabled = filteredOrders.length === 0;
|
const hasResults = filteredOrders.length > 0;
|
||||||
document.getElementById('downloadExcel').disabled = filteredOrders.length === 0;
|
document.getElementById('downloadPdf').disabled = !hasResults;
|
||||||
|
document.getElementById('downloadExcel').disabled = !hasResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination Functions
|
// Pagination Functions
|
||||||
@@ -1053,11 +1099,14 @@ console.log('ORDERS SAMPLE:', allOrders[0]);
|
|||||||
const paginatedItems = filteredOrders.slice(startIndex, endIndex);
|
const paginatedItems = filteredOrders.slice(startIndex, endIndex);
|
||||||
|
|
||||||
paginatedItems.forEach(order => {
|
paginatedItems.forEach(order => {
|
||||||
const mark = order.mark_list || null;
|
const mark = order.markList || null;
|
||||||
const invoice = order.invoice || null;
|
const invoice = order.invoice || null;
|
||||||
const shipment = order.shipments?.[0] || null;
|
const shipment = order.shipments?.[0] || null;
|
||||||
const invoiceStatus = (invoice?.status || '').toLowerCase();
|
|
||||||
const shipmentStatus = (shipment?.status || '').toLowerCase().replace('_', ' ');
|
// Normalized status values matching Blade logic
|
||||||
|
const invoiceStatus = (invoice?.status || 'pending').toLowerCase();
|
||||||
|
const shipmentStatus = (shipment?.status || 'pending').toLowerCase();
|
||||||
|
const shipmentStatusForCss = shipmentStatus.replace(/[ -]/g, '_');
|
||||||
|
|
||||||
const row = document.createElement('tr');
|
const row = document.createElement('tr');
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
@@ -1073,19 +1122,13 @@ console.log('ORDERS SAMPLE:', allOrders[0]);
|
|||||||
<td>${invoice?.final_amount ? '₹' + Number(invoice.final_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '-'}</td>
|
<td>${invoice?.final_amount ? '₹' + Number(invoice.final_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '-'}</td>
|
||||||
<td>${invoice?.final_amount_with_gst ? '₹' + Number(invoice.final_amount_with_gst).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '-'}</td>
|
<td>${invoice?.final_amount_with_gst ? '₹' + Number(invoice.final_amount_with_gst).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '-'}</td>
|
||||||
<td>
|
<td>
|
||||||
${invoice?.status
|
<span class="status-badge status-${invoiceStatus}">${getInvoiceStatusIcon(invoiceStatus)}${invoiceStatus.charAt(0).toUpperCase() + invoiceStatus.slice(1)}</span>
|
||||||
? `<span class="status-badge status-${invoiceStatus}">${getInvoiceStatusIcon(invoiceStatus)}${invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)}</span>`
|
|
||||||
: '<span class="status-badge status-pending"><i class="fas fa-clock status-icon"></i>Pending</span>'
|
|
||||||
}
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
${shipment?.status
|
<span class="status-badge ship-${shipmentStatusForCss}">${getShipmentStatusIcon(shipmentStatusForCss)}${shipmentStatus.charAt(0).toUpperCase() + shipmentStatus.slice(1)}</span>
|
||||||
? `<span class="status-badge ship-${shipmentStatus.replace(' ', '_')}">${getShipmentStatusIcon(shipmentStatus.replace(' ', '_'))}${shipment.status.charAt(0).toUpperCase() + shipment.status.slice(1)}</span>`
|
|
||||||
: '<span class="status-badge ship-pending"><i class="fas fa-clock status-icon"></i>Pending</span>'
|
|
||||||
}
|
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="/admin/orders/${order.id}" title="View Details">
|
<a href="/admin/orders/${order.id}/see" title="View Details">
|
||||||
<i class="fas fa-eye action-btn"></i>
|
<i class="fas fa-eye action-btn"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@@ -1093,6 +1136,60 @@ console.log('ORDERS SAMPLE:', allOrders[0]);
|
|||||||
tbody.appendChild(row);
|
tbody.appendChild(row);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
|
||||||
|
|
||||||
@endsection
|
// Notification function
|
||||||
|
function showNotification(message, type = 'info') {
|
||||||
|
// Remove existing notification
|
||||||
|
const existingNotification = document.querySelector('.download-notification');
|
||||||
|
if (existingNotification) {
|
||||||
|
existingNotification.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
const notification = document.createElement('div');
|
||||||
|
notification.className = `download-notification alert alert-${type}`;
|
||||||
|
notification.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
z-index: 10000;
|
||||||
|
padding: 12px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||||
|
animation: slideIn 0.3s ease;
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (type === 'info') {
|
||||||
|
notification.style.background = 'linear-gradient(135deg, #3b82f6, #1d4ed8)';
|
||||||
|
} else if (type === 'warning') {
|
||||||
|
notification.style.background = 'linear-gradient(135deg, #f59e0b, #d97706)';
|
||||||
|
} else if (type === 'success') {
|
||||||
|
notification.style.background = 'linear-gradient(135deg, #10b981, #059669)';
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.textContent = message;
|
||||||
|
document.body.appendChild(notification);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.style.animation = 'slideOut 0.3s ease';
|
||||||
|
setTimeout(() => notification.remove(), 300);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add CSS for notifications
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
@keyframes slideIn {
|
||||||
|
from { transform: translateX(100%); opacity: 0; }
|
||||||
|
to { transform: translateX(0); opacity: 1; }
|
||||||
|
}
|
||||||
|
@keyframes slideOut {
|
||||||
|
from { transform: translateX(0); opacity: 1; }
|
||||||
|
to { transform: translateX(100%); opacity: 0; }
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@endsection
|
||||||
@@ -11,17 +11,18 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h3>Orders Report</h3>
|
|
||||||
|
|
||||||
@if(!empty($filters))
|
<h3>Orders Report</h3>
|
||||||
|
|
||||||
|
@if(!empty($filters))
|
||||||
<p>
|
<p>
|
||||||
@if($filters['search']) Search: <strong>{{ $filters['search'] }}</strong> @endif
|
@if(!empty($filters['search'])) Search: <strong>{{ $filters['search'] }}</strong> @endif
|
||||||
@if($filters['status']) | Status: <strong>{{ ucfirst($filters['status']) }}</strong> @endif
|
@if(!empty($filters['status'])) | Status: <strong>{{ ucfirst($filters['status']) }}</strong> @endif
|
||||||
@if($filters['shipment']) | Shipment: <strong>{{ ucfirst($filters['shipment']) }}</strong> @endif
|
@if(!empty($filters['shipment'])) | Shipment: <strong>{{ ucfirst($filters['shipment']) }}</strong> @endif
|
||||||
</p>
|
</p>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Order ID</th>
|
<th>Order ID</th>
|
||||||
@@ -42,29 +43,32 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@forelse($orders as $order)
|
@forelse($orders as $order)
|
||||||
@php
|
@php
|
||||||
$mark = $order->markList ?? null;
|
$mark = $order->markList;
|
||||||
$invoice = $order->invoice ?? null;
|
$invoice = $order->invoice;
|
||||||
$shipment = $order->shipments->first() ?? null;
|
$shipment = $order->shipments->first();
|
||||||
@endphp
|
@endphp
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $order->order_id }}</td>
|
<td>{{ $order->order_id }}</td>
|
||||||
<td>{{ $shipment->shipment_id ?? '-' }}</td>
|
<td>{{ $shipment?->shipment_id ?? '-' }}</td>
|
||||||
<td>{{ $mark->customer_id ?? '-' }}</td>
|
<td>{{ $mark?->customer_id ?? '-' }}</td>
|
||||||
<td>{{ $mark->company_name ?? '-' }}</td>
|
<td>{{ $mark?->company_name ?? '-' }}</td>
|
||||||
<td>{{ $mark->origin ?? $order->origin ?? '-' }}</td>
|
<td>{{ $mark?->origin ?? $order->origin ?? '-' }}</td>
|
||||||
<td>{{ $mark->destination ?? $order->destination ?? '-' }}</td>
|
<td>{{ $mark?->destination ?? $order->destination ?? '-' }}</td>
|
||||||
<td>{{ $order->created_at ? $order->created_at->format('d-m-Y') : '-' }}</td>
|
<td>{{ $order->created_at?->format('d-m-Y') ?? '-' }}</td>
|
||||||
<td>{{ $invoice->invoice_number ?? '-' }}</td>
|
<td>{{ $invoice?->invoice_number ?? '-' }}</td>
|
||||||
<td>{{ $invoice?->invoice_date ? \Carbon\Carbon::parse($invoice->invoice_date)->format('d-m-Y') : '-' }}</td>
|
<td>{{ $invoice?->invoice_date ? \Carbon\Carbon::parse($invoice->invoice_date)->format('d-m-Y') : '-' }}</td>
|
||||||
<td>{{ $invoice?->final_amount ? number_format($invoice->final_amount, 2) : '-' }}</td>
|
<td>{{ $invoice?->final_amount !== null ? number_format($invoice->final_amount, 2) : '-' }}</td>
|
||||||
<td>{{ $invoice?->final_amount_with_gst ? number_format($invoice->final_amount_with_gst, 2) : '-' }}</td>
|
<td>{{ $invoice?->final_amount_with_gst !== null ? number_format($invoice->final_amount_with_gst, 2) : '-' }}</td>
|
||||||
<td>{{ $invoice->status ? ucfirst($invoice->status) : 'Pending' }}</td>
|
<td>{{ ucfirst($invoice?->status ?? 'Pending') }}</td>
|
||||||
<td>{{ $shipment?->status ? ucfirst(str_replace('_',' ',$shipment->status)) : 'Pending' }}</td>
|
<td>{{ ucfirst(str_replace('_',' ', $shipment?->status ?? 'Pending')) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr><td colspan="13" style="text-align:center">No orders found</td></tr>
|
<tr>
|
||||||
|
<td colspan="13" style="text-align:center">No orders found</td>
|
||||||
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
1370
resources/views/admin/see_order.blade.php
Normal file
1370
resources/views/admin/see_order.blade.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -133,6 +133,10 @@ Route::prefix('admin')
|
|||||||
Route::get('/orders/view/{id}', [AdminOrderController::class, 'popup'])
|
Route::get('/orders/view/{id}', [AdminOrderController::class, 'popup'])
|
||||||
->name('admin.orders.popup');
|
->name('admin.orders.popup');
|
||||||
|
|
||||||
|
// Route::get('/orders/{id}', [AdminOrderController::class, 'view'])
|
||||||
|
// ->name('admin.orders.view');
|
||||||
|
Route::get('/orders/{order:order_id}/see', [AdminOrderController::class, 'see'])
|
||||||
|
->name('admin.orders.see');
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// ORDERS (FIXED ROUTES)
|
// ORDERS (FIXED ROUTES)
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user