excel import
This commit is contained in:
@@ -13,6 +13,11 @@ use App\Models\User;
|
|||||||
use PDF;
|
use PDF;
|
||||||
use Maatwebsite\Excel\Facades\Excel;
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
use App\Exports\OrdersExport;
|
use App\Exports\OrdersExport;
|
||||||
|
use App\Imports\OrderItemsPreviewImport;
|
||||||
|
|
||||||
|
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
|
||||||
class AdminOrderController extends Controller
|
class AdminOrderController extends Controller
|
||||||
{
|
{
|
||||||
@@ -36,44 +41,6 @@ class AdminOrderController extends Controller
|
|||||||
return view('admin.orders_create', compact('markList'));
|
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
|
* 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>#</th>
|
||||||
<th>Order ID</th>
|
<th>Order ID</th>
|
||||||
<th>Mark No</th>
|
<th>Mark No</th>
|
||||||
|
<th>Date</th>
|
||||||
<th>Origin</th>
|
<th>Origin</th>
|
||||||
<th>Destination</th>
|
<th>Destination</th>
|
||||||
<th>Total CTN</th>
|
<th>Total CTN</th>
|
||||||
@@ -1225,7 +1226,6 @@ body, .container-fluid {
|
|||||||
<th>Total KG</th>
|
<th>Total KG</th>
|
||||||
<th>Total TTL KG</th>
|
<th>Total TTL KG</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Date</th>
|
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -1441,6 +1441,13 @@ body, .container-fluid {
|
|||||||
<button type="submit" class="btn btn-info" id="addItemBtn">
|
<button type="submit" class="btn btn-info" id="addItemBtn">
|
||||||
<i class="bi bi-plus-circle"></i> Add Item
|
<i class="bi bi-plus-circle"></i> Add Item
|
||||||
</button>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -1918,6 +1925,75 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
e.target.closest('tr').remove();
|
e.target.closest('tr').remove();
|
||||||
reindexRows();
|
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>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,12 @@ Route::prefix('admin')
|
|||||||
Route::delete('/orders/{id}/delete', [AdminOrderController::class, 'destroy'])
|
Route::delete('/orders/{id}/delete', [AdminOrderController::class, 'destroy'])
|
||||||
->name('admin.orders.destroy');
|
->name('admin.orders.destroy');
|
||||||
|
|
||||||
|
|
||||||
|
Route::post('/orders/upload-excel-preview',
|
||||||
|
[AdminOrderController::class, 'uploadExcelPreview']
|
||||||
|
)->name('admin.orders.upload.excel.preview');
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// SHIPMENTS (FIXED ROUTES)
|
// SHIPMENTS (FIXED ROUTES)
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user