excel import
This commit is contained in:
@@ -13,6 +13,11 @@ use App\Models\User;
|
||||
use PDF;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use App\Exports\OrdersExport;
|
||||
use App\Imports\OrderItemsPreviewImport;
|
||||
|
||||
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
|
||||
class AdminOrderController extends Controller
|
||||
{
|
||||
@@ -36,44 +41,6 @@ class AdminOrderController extends Controller
|
||||
return view('admin.orders_create', compact('markList'));
|
||||
}
|
||||
|
||||
// public function store(Request $request)
|
||||
// {
|
||||
// $data = $request->validate([
|
||||
// 'mark_no' => 'required|string',
|
||||
// 'origin' => 'nullable|string',
|
||||
// 'destination' => 'nullable|string',
|
||||
// 'ctn' => 'nullable|numeric',
|
||||
// 'qty' => 'nullable|numeric',
|
||||
// 'ttl_qty' => 'nullable|numeric',
|
||||
// 'ttl_amount' => 'nullable|numeric',
|
||||
// 'cbm' => 'nullable|numeric',
|
||||
// 'ttl_cbm' => 'nullable|numeric',
|
||||
// 'kg' => 'nullable|numeric',
|
||||
// 'ttl_kg' => 'nullable|numeric',
|
||||
// ]);
|
||||
|
||||
// $order = Order::create([
|
||||
// 'order_id' => $this->generateOrderId(),
|
||||
// 'mark_no' => $data['mark_no'],
|
||||
// 'origin' => $data['origin'] ?? null,
|
||||
// 'destination'=> $data['destination'] ?? null,
|
||||
// 'ctn' => $data['ctn'] ?? 0,
|
||||
// 'qty' => $data['qty'] ?? 0,
|
||||
// 'ttl_qty' => $data['ttl_qty'] ?? 0,
|
||||
// 'ttl_amount' => $data['ttl_amount'] ?? 0,
|
||||
// 'cbm' => $data['cbm'] ?? 0,
|
||||
// 'ttl_cbm' => $data['ttl_cbm'] ?? 0,
|
||||
// 'kg' => $data['kg'] ?? 0,
|
||||
// 'ttl_kg' => $data['ttl_kg'] ?? 0,
|
||||
// 'status' => 'pending',
|
||||
// ]);
|
||||
|
||||
// $this->createInvoice($order);
|
||||
|
||||
// return redirect()->route('admin.orders.show', $order->id)
|
||||
// ->with('success', 'Order created successfully.');
|
||||
// }
|
||||
|
||||
/* ---------------------------
|
||||
* SHOW / POPUP
|
||||
* ---------------------------*/
|
||||
@@ -723,4 +690,36 @@ class AdminOrderController extends Controller
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function uploadExcelPreview(Request $request)
|
||||
{
|
||||
try {
|
||||
$request->validate([
|
||||
'excel' => 'required|file|mimes:xlsx,xls'
|
||||
]);
|
||||
|
||||
$import = new OrderItemsPreviewImport();
|
||||
Excel::import($import, $request->file('excel'));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'items' => $import->rows
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Invalid Excel file format'
|
||||
], 422);
|
||||
} catch (\Throwable $e) {
|
||||
\Log::error($e);
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Server error'
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
26
app/Imports/OrderItemsPreviewImport.php
Normal file
26
app/Imports/OrderItemsPreviewImport.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace App\Imports;
|
||||
|
||||
use Maatwebsite\Excel\Concerns\ToCollection;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class OrderItemsPreviewImport implements ToCollection
|
||||
{
|
||||
public array $rows = [];
|
||||
|
||||
public function collection(Collection $collection)
|
||||
{
|
||||
$header = $collection->first()->map(fn ($h) => strtolower(trim($h)))->toArray();
|
||||
|
||||
foreach ($collection->skip(1) as $row) {
|
||||
$item = [];
|
||||
foreach ($header as $i => $key) {
|
||||
$item[$key] = $row[$i] ?? null;
|
||||
}
|
||||
|
||||
if (!empty($item['description'])) {
|
||||
$this->rows[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1214,6 +1214,7 @@ body, .container-fluid {
|
||||
<th>#</th>
|
||||
<th>Order ID</th>
|
||||
<th>Mark No</th>
|
||||
<th>Date</th>
|
||||
<th>Origin</th>
|
||||
<th>Destination</th>
|
||||
<th>Total CTN</th>
|
||||
@@ -1225,7 +1226,6 @@ body, .container-fluid {
|
||||
<th>Total KG</th>
|
||||
<th>Total TTL KG</th>
|
||||
<th>Status</th>
|
||||
<th>Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -1441,6 +1441,13 @@ body, .container-fluid {
|
||||
<button type="submit" class="btn btn-info" id="addItemBtn">
|
||||
<i class="bi bi-plus-circle"></i> Add Item
|
||||
</button>
|
||||
|
||||
<input type="file" id="excelInput" accept=".xlsx,.xls" hidden>
|
||||
|
||||
<button type="button" class="btn btn-outline-success" id="uploadExcelBtn">
|
||||
<i class="bi bi-file-earmark-excel"></i> Upload Excel
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1918,6 +1925,75 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
e.target.closest('tr').remove();
|
||||
reindexRows();
|
||||
});
|
||||
|
||||
// ===== EXCEL UPLOAD LOGIC =====
|
||||
const uploadExcelBtn = document.getElementById('uploadExcelBtn');
|
||||
const excelInput = document.getElementById('excelInput');
|
||||
|
||||
if (uploadExcelBtn && excelInput) {
|
||||
|
||||
uploadExcelBtn.addEventListener('click', () => excelInput.click());
|
||||
|
||||
excelInput.addEventListener('change', function () {
|
||||
const file = this.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('excel', file);
|
||||
formData.append('_token', '{{ csrf_token() }}');
|
||||
|
||||
fetch('{{ route("admin.orders.upload.excel.preview") }}', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(async res => {
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.success) {
|
||||
alert('Invalid Excel file');
|
||||
return;
|
||||
}
|
||||
populateItemsTable(res.items);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('Excel upload failed');
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function populateItemsTable(items) {
|
||||
itemsTableBody.innerHTML = '';
|
||||
|
||||
items.forEach((item, index) => {
|
||||
addRow(index);
|
||||
const row = itemsTableBody.children[index];
|
||||
|
||||
row.querySelector('[data-field="description"]').value = item.description ?? '';
|
||||
row.querySelector('[data-field="ctn"]').value = item.ctn ?? '';
|
||||
row.querySelector('[data-field="qty"]').value = item.qty ?? '';
|
||||
row.querySelector('[data-field="ttl_qty"]').value = item.ttl_qty ?? '';
|
||||
row.querySelector('[data-field="unit"]').value = item.unit ?? '';
|
||||
row.querySelector('[data-field="price"]').value = item.price ?? '';
|
||||
row.querySelector('[data-field="ttl_amount"]').value = item.ttl_amount ?? '';
|
||||
row.querySelector('[data-field="cbm"]').value = item.cbm ?? '';
|
||||
row.querySelector('[data-field="ttl_cbm"]').value = item.ttl_cbm ?? '';
|
||||
row.querySelector('[data-field="kg"]').value = item.kg ?? '';
|
||||
row.querySelector('[data-field="ttl_kg"]').value = item.ttl_kg ?? '';
|
||||
row.querySelector('[data-field="shop_no"]').value = item.shop_no ?? '';
|
||||
});
|
||||
|
||||
reindexRows();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -160,6 +160,12 @@ Route::prefix('admin')
|
||||
Route::delete('/orders/{id}/delete', [AdminOrderController::class, 'destroy'])
|
||||
->name('admin.orders.destroy');
|
||||
|
||||
|
||||
Route::post('/orders/upload-excel-preview',
|
||||
[AdminOrderController::class, 'uploadExcelPreview']
|
||||
)->name('admin.orders.upload.excel.preview');
|
||||
|
||||
|
||||
// ---------------------------
|
||||
// SHIPMENTS (FIXED ROUTES)
|
||||
// ---------------------------
|
||||
|
||||
Reference in New Issue
Block a user