changes
This commit is contained in:
@@ -26,13 +26,11 @@ class AdminInvoiceController extends Controller
|
||||
// -------------------------------------------------------------
|
||||
public function popup($id)
|
||||
{
|
||||
$invoice = Invoice::with(['items', 'order'])->findOrFail($id);
|
||||
$invoice = Invoice::with(['items', 'order', 'installments'])->findOrFail($id);
|
||||
|
||||
// Find actual Shipment record
|
||||
$shipment = \App\Models\Shipment::whereHas('items', function ($q) use ($invoice) {
|
||||
$q->where('order_id', $invoice->order_id);
|
||||
})
|
||||
->first();
|
||||
})->first();
|
||||
|
||||
return view('admin.popup_invoice', compact('invoice', 'shipment'));
|
||||
}
|
||||
@@ -145,6 +143,22 @@ class AdminInvoiceController extends Controller
|
||||
$invoice->update(['pdf_path' => 'invoices/' . $fileName]);
|
||||
}
|
||||
|
||||
public function downloadInvoice($id)
|
||||
{
|
||||
$invoice = Invoice::findOrFail($id);
|
||||
|
||||
// Generate PDF if missing
|
||||
if (
|
||||
!$invoice->pdf_path ||
|
||||
!file_exists(public_path($invoice->pdf_path))
|
||||
) {
|
||||
$this->generateInvoicePDF($invoice);
|
||||
$invoice->refresh();
|
||||
}
|
||||
|
||||
return response()->download(public_path($invoice->pdf_path));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// INSTALLMENTS (ADD/DELETE)
|
||||
// -------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
* ---------------------------*/
|
||||
@@ -580,7 +547,7 @@ class AdminOrderController extends Controller
|
||||
'ttl_cbm' => $total_ttl_cbm,
|
||||
'kg' => $total_kg,
|
||||
'ttl_kg' => $total_ttl_kg,
|
||||
'status' => 'pending',
|
||||
'status' => 'order_placed',
|
||||
]);
|
||||
|
||||
// 6) order items
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,11 @@ class ShipmentController extends Controller
|
||||
$usedOrderIds = ShipmentItem::pluck('order_id')->toArray();
|
||||
|
||||
// 2) Load available orders (not used in any shipment)
|
||||
$availableOrders = Order::whereNotIn('id', $usedOrderIds)->get();
|
||||
$availableOrders = Order::whereNotIn('id', $usedOrderIds)
|
||||
->where('status', '!=', 'order_placed')
|
||||
->get();
|
||||
|
||||
|
||||
|
||||
// 3) Load all shipments for listing
|
||||
$shipments = Shipment::latest()->get();
|
||||
@@ -65,6 +69,16 @@ class ShipmentController extends Controller
|
||||
// CALCULATE TOTALS
|
||||
// -----------------------------
|
||||
$orders = Order::whereIn('id', $request->order_ids)->get();
|
||||
foreach ($orders as $order) {
|
||||
if ($order->status === 'order_placed') {
|
||||
return back()->with(
|
||||
'error',
|
||||
"Order {$order->order_id} is not ready for shipment"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$total_ctn = $orders->sum('ctn');
|
||||
$total_qty = $orders->sum('qty');
|
||||
@@ -82,7 +96,7 @@ class ShipmentController extends Controller
|
||||
'shipment_id' => $newShipmentId,
|
||||
'origin' => $request->origin,
|
||||
'destination' => $request->destination,
|
||||
'status' => Shipment::STATUS_PENDING,
|
||||
'status' => Shipment::STATUS_SHIPMENT_READY,
|
||||
'shipment_date' => $request->shipment_date,
|
||||
|
||||
'total_ctn' => $total_ctn,
|
||||
@@ -141,23 +155,29 @@ class ShipmentController extends Controller
|
||||
'status' => 'required|string'
|
||||
]);
|
||||
|
||||
// 1) Update shipment status
|
||||
$shipment = Shipment::findOrFail($request->shipment_id);
|
||||
$shipment->status = $request->status;
|
||||
$shipment->save();
|
||||
|
||||
// 2) Update ALL related orders' status
|
||||
// ✅ Sync shipment status to orders ONLY after shipment exists
|
||||
foreach ($shipment->orders as $order) {
|
||||
$order->status = $shipment->status; // status is string: pending, in_transit, dispatched, delivered
|
||||
|
||||
// Prevent rollback or overwrite
|
||||
if ($order->status === 'delivered') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$order->status = $shipment->status;
|
||||
$order->save();
|
||||
}
|
||||
|
||||
return redirect()->back()->with(
|
||||
'success',
|
||||
"Shipment status updated to {$shipment->statusLabel()} and related orders updated."
|
||||
"Shipment status updated to {$shipment->statusLabel()}."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update shipment details
|
||||
*/
|
||||
@@ -266,11 +286,23 @@ public function addOrders(Request $request, Shipment $shipment)
|
||||
'order_ids' => 'required|array|min:1',
|
||||
]);
|
||||
|
||||
// फक्त न वापरलेले orders घ्या
|
||||
$orders = Order::whereIn('id', $request->order_ids)->get();
|
||||
|
||||
foreach ($orders as $order) {
|
||||
// pivot मध्ये insert
|
||||
|
||||
if ($order->status === 'order_placed') {
|
||||
return back()->with(
|
||||
'error',
|
||||
"Order {$order->order_id} is not ready for shipment"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Prevent duplicates
|
||||
if (ShipmentItem::where('order_id', $order->id)->exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ShipmentItem::create([
|
||||
'shipment_id' => $shipment->id,
|
||||
'order_id' => $order->id,
|
||||
@@ -282,23 +314,25 @@ public function addOrders(Request $request, Shipment $shipment)
|
||||
]);
|
||||
}
|
||||
|
||||
// totals
|
||||
// Recalculate totals
|
||||
$orderIds = ShipmentItem::where('shipment_id', $shipment->id)->pluck('order_id');
|
||||
$allOrders = Order::whereIn('id', $orderIds)->get();
|
||||
|
||||
$shipment->total_ctn = $allOrders->sum('ctn');
|
||||
$shipment->total_qty = $allOrders->sum('qty');
|
||||
$shipment->total_ttl_qty = $allOrders->sum('ttl_qty');
|
||||
$shipment->total_cbm = $allOrders->sum('cbm');
|
||||
$shipment->total_ttl_cbm = $allOrders->sum('ttl_cbm');
|
||||
$shipment->total_kg = $allOrders->sum('kg');
|
||||
$shipment->total_ttl_kg = $allOrders->sum('ttl_kg');
|
||||
$shipment->total_amount = $allOrders->sum('ttl_amount');
|
||||
$shipment->save();
|
||||
$shipment->update([
|
||||
'total_ctn' => $allOrders->sum('ctn'),
|
||||
'total_qty' => $allOrders->sum('qty'),
|
||||
'total_ttl_qty' => $allOrders->sum('ttl_qty'),
|
||||
'total_cbm' => $allOrders->sum('cbm'),
|
||||
'total_ttl_cbm' => $allOrders->sum('ttl_cbm'),
|
||||
'total_kg' => $allOrders->sum('kg'),
|
||||
'total_ttl_kg' => $allOrders->sum('ttl_kg'),
|
||||
'total_amount' => $allOrders->sum('ttl_amount'),
|
||||
]);
|
||||
|
||||
return redirect()
|
||||
->route('admin.shipments.dummy', $shipment->id)
|
||||
->with('success', 'Orders added to shipment successfully.');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -289,6 +289,44 @@ public function invoiceDetails($invoice_id)
|
||||
]);
|
||||
}
|
||||
|
||||
public function confirmOrder($order_id)
|
||||
{
|
||||
$user = JWTAuth::parseToken()->authenticate();
|
||||
|
||||
if (! $user) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Unauthorized'
|
||||
], 401);
|
||||
}
|
||||
|
||||
$order = $user->orders()
|
||||
->where('order_id', $order_id)
|
||||
->first();
|
||||
|
||||
if (! $order) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Order not found'
|
||||
], 404);
|
||||
}
|
||||
|
||||
// 🚫 Only allow confirm from order_placed
|
||||
if ($order->status !== 'order_placed') {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Order cannot be confirmed'
|
||||
], 422);
|
||||
}
|
||||
|
||||
$order->status = 'order_confirmed';
|
||||
$order->save();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Order confirmed successfully'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,5 +64,25 @@ class Order extends Model
|
||||
}
|
||||
|
||||
|
||||
const STATUS_LABELS = [
|
||||
'order_placed' => 'Order Placed',
|
||||
'order_confirmed' => 'Order Confirmed',
|
||||
'supplier_warehouse' => 'Supplier Warehouse',
|
||||
'consolidate_warehouse'=> 'Consolidate Warehouse',
|
||||
'export_custom' => 'Export Custom',
|
||||
'international_transit'=> 'International Transit',
|
||||
'arrived_india' => 'Arrived at India',
|
||||
'import_custom' => 'Import Custom',
|
||||
'warehouse' => 'Warehouse',
|
||||
'domestic_distribution'=> 'Domestic Distribution',
|
||||
'out_for_delivery' => 'Out for Delivery',
|
||||
'delivered' => 'Delivered',
|
||||
];
|
||||
|
||||
public function getStatusLabelAttribute()
|
||||
{
|
||||
return self::STATUS_LABELS[$this->status]
|
||||
?? ucfirst(str_replace('_', ' ', $this->status));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,25 +45,6 @@ class Shipment extends Model
|
||||
return $this->belongsToMany(Order::class, 'shipment_items', 'shipment_id', 'order_id');
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// STATUS CONSTANTS
|
||||
// ---------------------------
|
||||
|
||||
const STATUS_PENDING = 'pending';
|
||||
const STATUS_IN_TRANSIT = 'in_transit';
|
||||
const STATUS_DISPATCHED = 'dispatched';
|
||||
const STATUS_DELIVERED = 'delivered';
|
||||
|
||||
public static function statusOptions()
|
||||
{
|
||||
return [
|
||||
self::STATUS_PENDING => 'Pending',
|
||||
self::STATUS_IN_TRANSIT => 'In Transit',
|
||||
self::STATUS_DISPATCHED => 'Dispatched',
|
||||
self::STATUS_DELIVERED => 'Delivered',
|
||||
];
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// HELPERS
|
||||
// ---------------------------
|
||||
@@ -73,8 +54,38 @@ class Shipment extends Model
|
||||
return $this->items()->count();
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// STATUS CONSTANTS (LOGISTICS FLOW)
|
||||
// ---------------------------
|
||||
const STATUS_SHIPMENT_READY = 'shipment_ready';
|
||||
const STATUS_EXPORT_CUSTOM = 'export_custom';
|
||||
const STATUS_INTERNATIONAL_TRANSIT= 'international_transit';
|
||||
const STATUS_ARRIVED_INDIA = 'arrived_india';
|
||||
const STATUS_IMPORT_CUSTOM = 'import_custom';
|
||||
const STATUS_WAREHOUSE = 'warehouse';
|
||||
const STATUS_DOMESTIC_DISTRIBUTION= 'domestic_distribution';
|
||||
const STATUS_OUT_FOR_DELIVERY = 'out_for_delivery';
|
||||
const STATUS_DELIVERED = 'delivered';
|
||||
|
||||
public static function statusOptions()
|
||||
{
|
||||
return [
|
||||
self::STATUS_SHIPMENT_READY => 'Shipment Ready',
|
||||
self::STATUS_EXPORT_CUSTOM => 'Export Custom',
|
||||
self::STATUS_INTERNATIONAL_TRANSIT => 'International Transit',
|
||||
self::STATUS_ARRIVED_INDIA => 'Arrived at India',
|
||||
self::STATUS_IMPORT_CUSTOM => 'Import Custom',
|
||||
self::STATUS_WAREHOUSE => 'Warehouse',
|
||||
self::STATUS_DOMESTIC_DISTRIBUTION => 'Domestic Distribution',
|
||||
self::STATUS_OUT_FOR_DELIVERY => 'Out for Delivery',
|
||||
self::STATUS_DELIVERED => 'Delivered',
|
||||
];
|
||||
}
|
||||
|
||||
public function statusLabel()
|
||||
{
|
||||
return self::statusOptions()[$this->status] ?? ucfirst($this->status);
|
||||
return self::statusOptions()[$this->status]
|
||||
?? ucfirst(str_replace('_', ' ', $this->status));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
BIN
public/invoices/invoice-INV-2025-000031.pdf
Normal file
BIN
public/invoices/invoice-INV-2025-000031.pdf
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/invoices/invoice-INV-2025-000044.pdf
Normal file
BIN
public/invoices/invoice-INV-2025-000044.pdf
Normal file
Binary file not shown.
BIN
public/invoices/invoice-INV-2025-000046.pdf
Normal file
BIN
public/invoices/invoice-INV-2025-000046.pdf
Normal file
Binary file not shown.
@@ -1284,6 +1284,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>
|
||||
@@ -1295,7 +1296,6 @@ body, .container-fluid {
|
||||
<th>Total KG</th>
|
||||
<th>Total TTL KG</th>
|
||||
<th>Status</th>
|
||||
<th>Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -1351,10 +1351,75 @@ body, .container-fluid {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination Controls -->
|
||||
<div class="pagination-container">
|
||||
<div class="pagination-info" id="pageInfo">
|
||||
Showing 1 to 10 of {{ $orders->count() }} entries
|
||||
<td>{{ $order->mark_no }}</td>
|
||||
<td>{{ $order->origin }}</td>
|
||||
<td>{{ $order->destination }}</td>
|
||||
<td>{{ $order->ctn }}</td>
|
||||
<td>{{ $order->qty }}</td>
|
||||
<td>{{ $order->ttl_qty }}</td>
|
||||
<td>₹{{ number_format($order->ttl_amount, 2) }}</td>
|
||||
<td>{{ $order->cbm }}</td>
|
||||
<td>{{ $order->ttl_cbm }}</td>
|
||||
<td>{{ $order->kg }}</td>
|
||||
<td>{{ $order->ttl_kg }}</td>
|
||||
<td>
|
||||
@php
|
||||
// Badge color mapping
|
||||
$badgeMap = [
|
||||
'order_placed' => 'secondary',
|
||||
'order_confirmed' => 'info',
|
||||
'supplier_warehouse' => 'warning',
|
||||
'consolidate_warehouse' => 'warning',
|
||||
'export_custom' => 'primary',
|
||||
'international_transit' => 'primary',
|
||||
'arrived_india' => 'info',
|
||||
'import_custom' => 'info',
|
||||
'warehouse' => 'dark',
|
||||
'domestic_distribution' => 'primary',
|
||||
'out_for_delivery' => 'success',
|
||||
'delivered' => 'success',
|
||||
];
|
||||
|
||||
// Icon mapping
|
||||
$iconMap = [
|
||||
'order_placed' => 'bi-clock-fill',
|
||||
'order_confirmed' => 'bi-check-circle',
|
||||
'supplier_warehouse' => 'bi-box-seam',
|
||||
'consolidate_warehouse' => 'bi-boxes',
|
||||
'export_custom' => 'bi-upload',
|
||||
'international_transit' => 'bi-truck',
|
||||
'arrived_india' => 'bi-geo-alt',
|
||||
'import_custom' => 'bi-download',
|
||||
'warehouse' => 'bi-building',
|
||||
'domestic_distribution' => 'bi-diagram-3',
|
||||
'out_for_delivery' => 'bi-truck-flatbed',
|
||||
'delivered' => 'bi-check-circle-fill',
|
||||
];
|
||||
|
||||
$badgeClass = $badgeMap[$order->status] ?? 'secondary';
|
||||
$iconClass = $iconMap[$order->status] ?? 'bi-info-circle';
|
||||
@endphp
|
||||
|
||||
<span class="badge bg-{{ $badgeClass }}">
|
||||
<i class="bi {{ $iconClass }} status-icon"></i>
|
||||
{{ $order->status_label }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>{{ $order->created_at->format('d-m-Y') }}</td>
|
||||
<td>
|
||||
<a href="{{ route('admin.orders.show', $order->id) }}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-eye"></i> View
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="16" class="text-muted">No orders found</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination-controls">
|
||||
<button class="pagination-img-btn" id="prevPageBtn" title="Previous page">
|
||||
@@ -1490,6 +1555,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>
|
||||
@@ -1951,6 +2023,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>
|
||||
|
||||
|
||||
@@ -33,6 +33,97 @@ body {
|
||||
100% { opacity: 1; transform: translateY(0) scale(1); }
|
||||
}
|
||||
|
||||
/* --------------------------------------------------
|
||||
INVOICE PREVIEW RESPONSIVE FIXES
|
||||
-------------------------------------------------- */
|
||||
.invoice-preview-wrapper {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.invoice-preview-wrapper * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Override any fixed width styles that might be in popup_invoice */
|
||||
#invoicePreview,
|
||||
.invoice-container,
|
||||
.invoice-wrapper {
|
||||
max-width: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* Responsive table fixes for invoice */
|
||||
.invoice-preview-wrapper table {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
table-layout: auto !important;
|
||||
}
|
||||
|
||||
.invoice-preview-wrapper .table-responsive {
|
||||
overflow-x: auto !important;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* Ensure all elements scale properly */
|
||||
.invoice-preview-wrapper .row,
|
||||
.invoice-preview-wrapper .col,
|
||||
.invoice-preview-wrapper [class*="col-"] {
|
||||
flex: 1 1 auto !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
/* Force responsive behavior for print-style elements */
|
||||
@media (max-width: 1200px) {
|
||||
.invoice-preview-wrapper {
|
||||
font-size: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.invoice-preview-wrapper {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.invoice-preview-wrapper {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
.invoice-preview-wrapper table th,
|
||||
.invoice-preview-wrapper table td {
|
||||
padding: 0.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.invoice-preview-wrapper {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.invoice-preview-wrapper .d-flex {
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
.invoice-preview-wrapper .text-end,
|
||||
.invoice-preview-wrapper .text-start {
|
||||
text-align: center !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent any fixed pixel widths */
|
||||
.invoice-preview-wrapper [style*="width:"]:not([style*="width:100%"]):not([style*="width:auto"]) {
|
||||
width: auto !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.invoice-preview-wrapper [style*="min-width"] {
|
||||
min-width: 0 !important;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------
|
||||
COMPACT CARD DESIGN
|
||||
-------------------------------------------------- */
|
||||
@@ -332,6 +423,30 @@ body {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.invoice-preview-wrapper {
|
||||
max-width: 100% !important;
|
||||
width: 100% !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.invoice-preview-wrapper * {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.glass-card {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid #000 !important;
|
||||
}
|
||||
|
||||
.card-header-compact {
|
||||
background: #000 !important;
|
||||
color: #fff !important;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Main Container -->
|
||||
@@ -344,7 +459,7 @@ body {
|
||||
<i class="fas fa-file-invoice me-2"></i>Invoice Overview
|
||||
</h4>
|
||||
</div>
|
||||
<div class="card-body-compact">
|
||||
<div class="card-body-compact invoice-preview-wrapper">
|
||||
@include('admin.popup_invoice', [
|
||||
'invoice' => $invoice,
|
||||
'shipment' => $shipment,
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
}
|
||||
|
||||
.id-container {
|
||||
margin-bottom: 1rem; /* Reduced from 1.5rem */
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.id-box {
|
||||
@@ -67,6 +67,9 @@
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
transition: all 0.3s ease;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.id-box:hover {
|
||||
@@ -82,34 +85,29 @@
|
||||
border-left: 4px solid var(--success);
|
||||
}
|
||||
|
||||
.id-box-accent {
|
||||
border-left: 4px solid var(--warning);
|
||||
}
|
||||
|
||||
.id-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: var(--border-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 0.5rem; /* Reduced from 0.75rem */
|
||||
font-size: 1rem;
|
||||
font-size: 1.2rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.id-icon-primary {
|
||||
background: rgba(52, 152, 219, 0.1);
|
||||
color: var(--secondary);
|
||||
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.id-icon-secondary {
|
||||
background: rgba(39, 174, 96, 0.1);
|
||||
color: var(--success);
|
||||
background: linear-gradient(135deg, #27ae60 0%, #219653 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.id-icon-accent {
|
||||
background: rgba(243, 156, 18, 0.1);
|
||||
color: var(--warning);
|
||||
.id-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.id-label {
|
||||
@@ -126,76 +124,87 @@
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
margin-bottom: 0;
|
||||
word-break: break-word;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.date-container {
|
||||
background: white;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 1rem; /* Reduced from 1.25rem */
|
||||
margin-bottom: 1rem; /* Reduced from 1.5rem */
|
||||
border: 1px solid #e9ecef;
|
||||
box-shadow: var(--box-shadow);
|
||||
}
|
||||
|
||||
.date-card {
|
||||
text-align: center;
|
||||
padding: 0.75rem;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.date-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 0.5rem; /* Reduced from 0.75rem */
|
||||
background: var(--secondary);
|
||||
/* Enhanced Date Section with Blue-Purple Gradient */
|
||||
.date-badge {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
background: linear-gradient(135deg, #3498db 0%, #9b59b6 100%);
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
min-width: 140px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.2);
|
||||
}
|
||||
|
||||
.date-label {
|
||||
font-size: 0.8rem;
|
||||
color: #6c757d;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
.date-badge:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(52, 152, 219, 0.3);
|
||||
}
|
||||
|
||||
.date-badge .badge-label {
|
||||
font-size: 0.7rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.date-value {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
padding: 0.5rem;
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.date-connector {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
margin-bottom: 0.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.date-connector i {
|
||||
background: var(--light);
|
||||
padding: 10px;
|
||||
.date-badge .badge-label i {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.date-badge .badge-value {
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.date-badge.due-date {
|
||||
background: linear-gradient(135deg, #3498db 0%, #9b59b6 100%);
|
||||
}
|
||||
|
||||
.date-badge.overdue {
|
||||
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.4); }
|
||||
70% { box-shadow: 0 0 0 6px rgba(231, 76, 60, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0); }
|
||||
}
|
||||
|
||||
.date-separator {
|
||||
color: #dee2e6;
|
||||
font-weight: 300;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.date-separator i {
|
||||
background: white;
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
color: var(--secondary);
|
||||
border: 2px solid #e9ecef;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: var(--border-radius);
|
||||
margin-bottom: 1rem; /* Reduced from 1.5rem */
|
||||
margin-bottom: 1rem;
|
||||
box-shadow: var(--box-shadow);
|
||||
}
|
||||
|
||||
@@ -228,27 +237,18 @@
|
||||
background-color: rgba(52, 152, 219, 0.03);
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
background: var(--light);
|
||||
border-left: 4px solid var(--secondary);
|
||||
}
|
||||
|
||||
.summary-header {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
/* Simplified Summary Section */
|
||||
.summary-container {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.amount-row {
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.75rem 0;
|
||||
}
|
||||
|
||||
.total-row {
|
||||
border-top: 2px solid #dee2e6;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
@@ -268,15 +268,20 @@
|
||||
|
||||
/* COMPACT HEADER STYLES */
|
||||
.compact-header {
|
||||
margin-bottom: 0.75rem; /* Reduced from default */
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.compact-header .invoice-title {
|
||||
margin-bottom: 0.25rem; /* Reduced gap */
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.compact-header .status-badge {
|
||||
margin-top: 0.25rem; /* Reduced gap */
|
||||
/* Date and status row */
|
||||
.date-status-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -284,10 +289,6 @@
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.date-connector {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
@@ -295,6 +296,55 @@
|
||||
.id-box {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.date-status-row {
|
||||
justify-content: flex-start;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.compact-header .col-md-6.text-end {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.date-badge {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.summary-container {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.date-status-row {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.date-separator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.date-badge {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.id-box {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.id-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -318,6 +368,24 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 text-end">
|
||||
<div class="date-status-row">
|
||||
<!-- Invoice Date -->
|
||||
<div class="date-badge">
|
||||
<div class="badge-label">
|
||||
<i class="fas fa-calendar-alt"></i> INVOICE DATE
|
||||
</div>
|
||||
<div class="badge-value">{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Due Date -->
|
||||
<div class="date-badge due-date @if($invoice->status == 'overdue') overdue @endif">
|
||||
<div class="badge-label">
|
||||
<i class="fas fa-clock"></i> DUE DATE
|
||||
</div>
|
||||
<div class="badge-value">{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Badge -->
|
||||
<span class="status-badge
|
||||
@if($invoice->status=='paid') bg-success
|
||||
@elseif($invoice->status=='overdue') bg-danger
|
||||
@@ -333,28 +401,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Three ID Boxes in One Row -->
|
||||
<!-- ============================
|
||||
ORDER & SHIPMENT ID BOXES
|
||||
============================ -->
|
||||
<div class="id-container">
|
||||
<div class="row">
|
||||
<!-- Invoice ID Box -->
|
||||
<div class="col-md-4 mb-3">
|
||||
<!-- Order ID Box -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="id-box id-box-primary">
|
||||
<div class="id-icon id-icon-primary">
|
||||
<i class="fas fa-receipt"></i>
|
||||
</div>
|
||||
<div class="id-label">Invoice ID</div>
|
||||
<div class="id-value">{{ $invoice->invoice_number }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order ID Box -->
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="id-box id-box-secondary">
|
||||
<div class="id-icon id-icon-secondary">
|
||||
<i class="fas fa-shopping-cart"></i>
|
||||
</div>
|
||||
<div class="id-label">Order ID</div>
|
||||
<div class="id-content">
|
||||
<div class="id-label">ORDER ID</div>
|
||||
<div class="id-value">
|
||||
@if($invoice->order && $invoice->order->order_id)
|
||||
{{ $invoice->order->order_id }}
|
||||
@@ -366,14 +427,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shipment ID Box -->
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="id-box id-box-accent">
|
||||
<div class="id-icon id-icon-accent">
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="id-box id-box-secondary">
|
||||
<div class="id-icon id-icon-secondary">
|
||||
<i class="fas fa-shipping-fast"></i>
|
||||
</div>
|
||||
<div class="id-label">Shipment ID</div>
|
||||
<div class="id-content">
|
||||
<div class="id-label">SHIPMENT ID</div>
|
||||
<div class="id-value">
|
||||
@php
|
||||
$shipmentId = 'N/A';
|
||||
@@ -392,38 +455,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================
|
||||
DATES SECTION
|
||||
============================ -->
|
||||
<div class="date-container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-5">
|
||||
<div class="date-card">
|
||||
<div class="date-icon">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</div>
|
||||
<div class="date-label">INVOICE DATE</div>
|
||||
<div class="date-value">{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="date-connector">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="date-card">
|
||||
<div class="date-icon">
|
||||
<i class="fas fa-clock"></i>
|
||||
</div>
|
||||
<div class="date-label">DUE DATE</div>
|
||||
<div class="date-value @if($invoice->status == 'overdue') text-danger @endif">
|
||||
{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================
|
||||
@@ -519,78 +550,71 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================
|
||||
FINAL SUMMARY
|
||||
============================ -->
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-6">
|
||||
<div class="card summary-card">
|
||||
<div class="card-header summary-header">
|
||||
<h6 class="mb-0 fw-bold">
|
||||
<i class="fas fa-calculator me-2"></i> Final Summary
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">Amount:</span>
|
||||
<span class="fw-bold text-dark">₹{{ number_format($invoice->final_amount,2) }}</span>
|
||||
@php
|
||||
$totalAmount = $invoice->final_amount;
|
||||
$gstAmount = $invoice->gst_amount;
|
||||
$totalPayable = $invoice->final_amount_with_gst;
|
||||
|
||||
$paidAmount = $invoice->totalPaid();
|
||||
$remaining = $invoice->remainingAmount();
|
||||
@endphp
|
||||
|
||||
<div class="summary-container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
|
||||
<div class="amount-row">
|
||||
<span>Total Amount</span>
|
||||
<span class="fw-bold">₹{{ number_format($totalAmount,2) }}</span>
|
||||
</div>
|
||||
|
||||
@if($invoice->tax_type === 'gst')
|
||||
{{-- CGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">CGST ({{ $invoice->cgst_percent ?? ($invoice->gst_percent/2) }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount/2, 2) }}</span>
|
||||
<div class="amount-row">
|
||||
<span>GST Amount</span>
|
||||
<span class="fw-bold text-danger">
|
||||
+ ₹{{ number_format($gstAmount,2) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{-- SGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">SGST ({{ $invoice->sgst_percent ?? ($invoice->gst_percent/2) }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount/2, 2) }}</span>
|
||||
<div class="amount-row border-top pt-2">
|
||||
<span class="fw-bold">Total Payable</span>
|
||||
<span class="fw-bold text-success">
|
||||
₹{{ number_format($totalPayable,2) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@elseif($invoice->tax_type === 'igst')
|
||||
{{-- IGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">IGST ({{ $invoice->igst_percent ?? $invoice->gst_percent }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount, 2) }}</span>
|
||||
<div class="amount-row">
|
||||
<span>Paid Amount</span>
|
||||
<span class="fw-bold text-primary">
|
||||
− ₹{{ number_format($paidAmount,2) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="amount-row border-top pt-2">
|
||||
<span class="fw-bold text-danger">Remaining Amount</span>
|
||||
<span class="fw-bold text-danger fs-5">
|
||||
₹{{ number_format($remaining,2) }}
|
||||
</span>
|
||||
</div>
|
||||
@else
|
||||
{{-- Default GST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">GST ({{ $invoice->gst_percent }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount, 2) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center pt-1">
|
||||
<span class="fw-bold text-dark">Total Payable:</span>
|
||||
<span class="fw-bold text-success">₹{{ number_format($invoice->final_amount_with_gst,2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ============================
|
||||
FOOTER — DOWNLOAD & SHARE
|
||||
============================ -->
|
||||
<div class="mt-4 pt-3 border-top text-center">
|
||||
@if($invoice->pdf_path)
|
||||
<a href="{{ asset($invoice->pdf_path) }}" class="btn btn-primary me-2" download>
|
||||
|
||||
<a href="{{ route('admin.invoices.download', $invoice->id) }}"
|
||||
class="btn btn-primary me-2">
|
||||
<i class="fas fa-download me-1"></i> Download PDF
|
||||
</a>
|
||||
|
||||
<button class="btn btn-success" onclick="shareInvoice()">
|
||||
<i class="fas fa-share me-1"></i> Share
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Footer Message -->
|
||||
<div class="mt-4 pt-3 border-top text-center text-muted">
|
||||
<p class="mb-1">Thank you for your business!</p>
|
||||
<p class="mb-0">For any inquiries, contact us at support@Kent Logistic</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -605,7 +629,7 @@
|
||||
const shareData = {
|
||||
title: "Invoice {{ $invoice->invoice_number }}",
|
||||
text: "Sharing invoice {{ $invoice->invoice_number }}",
|
||||
url: "{{ asset($invoice->pdf_path) }}"
|
||||
url: "{{ route('admin.invoices.download', $invoice->id) }}"
|
||||
};
|
||||
|
||||
if (navigator.share) {
|
||||
@@ -616,5 +640,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
||||
|
||||
@section('content')
|
||||
<style>
|
||||
|
||||
:root {
|
||||
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
@@ -20,10 +21,9 @@
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
|
||||
/* Main Container */
|
||||
/* Main Container - FLUID LIKE SHIPMENT PAGE */
|
||||
.staff-add-container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
right: -100px;
|
||||
}
|
||||
|
||||
/* Main Card */
|
||||
/* Main Card - FLUID BEHAVIOR */
|
||||
.staff-add-card {
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(10px);
|
||||
@@ -51,9 +51,10 @@
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Header Section */
|
||||
/* Header Section - FLUID SCALING */
|
||||
.staff-add-header {
|
||||
background: var(--primary-gradient);
|
||||
padding: 35px 40px;
|
||||
@@ -105,7 +106,7 @@
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Progress Steps */
|
||||
/* Progress Steps - FLUID ADJUSTMENTS */
|
||||
.progress-steps {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -207,7 +208,7 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Form Grid */
|
||||
/* Form Grid - ADAPTIVE LIKE SHIPMENT PAGE */
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
@@ -327,7 +328,7 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Permissions Section */
|
||||
/* Permissions Section - ADAPTIVE GRID */
|
||||
.permissions-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
@@ -585,7 +586,305 @@
|
||||
.strength-good { background: #38b2ac; }
|
||||
.strength-strong { background: #48bb78; }
|
||||
|
||||
/* Responsive Design */
|
||||
/* =========================================== */
|
||||
/* DESKTOP MEDIA QUERIES - LIKE SHIPMENT PAGE */
|
||||
/* =========================================== */
|
||||
|
||||
/* Base desktop - 992px+ */
|
||||
@media (min-width: 992px) {
|
||||
body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-stage {
|
||||
padding: 0 30px 30px;
|
||||
}
|
||||
|
||||
.staff-add-header {
|
||||
padding: 30px 30px;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.navigation-buttons {
|
||||
padding: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Large desktop - 1200px+ */
|
||||
@media (min-width: 1200px) {
|
||||
.staff-add-card {
|
||||
margin: 0 auto;
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.staff-add-header {
|
||||
padding: 35px 35px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
font-size: 42px;
|
||||
}
|
||||
|
||||
.progress-steps {
|
||||
padding: 30px 35px 0;
|
||||
}
|
||||
|
||||
.form-stage {
|
||||
padding: 0 35px 35px;
|
||||
}
|
||||
|
||||
.step-circle {
|
||||
width: 55px;
|
||||
height: 55px;
|
||||
}
|
||||
|
||||
.navigation-buttons {
|
||||
padding: 30px 35px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 14px 32px;
|
||||
min-width: 140px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra large desktop - 1440px+ */
|
||||
@media (min-width: 1440px) {
|
||||
.staff-add-card {
|
||||
max-width: 97%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 35px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.staff-add-header {
|
||||
padding: 40px 40px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 2.3rem;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
.progress-steps {
|
||||
padding: 35px 40px 0;
|
||||
}
|
||||
|
||||
.form-stage {
|
||||
padding: 0 40px 40px;
|
||||
}
|
||||
|
||||
.step-circle {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.step-label {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
padding: 16px 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.permission-group {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.permission-name {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.navigation-buttons {
|
||||
padding: 35px 40px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 16px 36px;
|
||||
min-width: 150px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
min-width: 180px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultra wide desktop - 1600px+ */
|
||||
@media (min-width: 1600px) {
|
||||
.staff-add-card {
|
||||
max-width: 98%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 35px;
|
||||
}
|
||||
|
||||
.staff-add-header {
|
||||
padding: 45px 45px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
font-size: 55px;
|
||||
}
|
||||
|
||||
.progress-steps {
|
||||
padding: 40px 45px 0;
|
||||
}
|
||||
|
||||
.form-stage {
|
||||
padding: 0 45px 45px;
|
||||
}
|
||||
|
||||
.step-circle {
|
||||
width: 65px;
|
||||
height: 65px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.step-label {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
padding: 18px 22px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.permission-group {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.navigation-buttons {
|
||||
padding: 40px 45px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 18px 40px;
|
||||
min-width: 160px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultra wide 4K+ screens - 1920px+ */
|
||||
@media (min-width: 1920px) {
|
||||
body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.staff-add-card {
|
||||
max-width: 99%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 45px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.staff-add-header {
|
||||
padding: 50px 50px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 2.7rem;
|
||||
}
|
||||
|
||||
.progress-steps {
|
||||
padding: 45px 50px 0;
|
||||
}
|
||||
|
||||
.form-stage {
|
||||
padding: 0 50px 50px;
|
||||
}
|
||||
|
||||
.navigation-buttons {
|
||||
padding: 45px 50px;
|
||||
}
|
||||
|
||||
.decorative-circle {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
top: -150px;
|
||||
right: -150px;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================== */
|
||||
/* MOBILE RESPONSIVE (UNCHANGED) */
|
||||
/* =========================================== */
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
padding: 15px;
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
|
||||
/* Compact Container */
|
||||
/* FLUID CONTAINER - LIKE SHIPMENT PAGE */
|
||||
.staff-edit-container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -33,6 +32,7 @@
|
||||
box-shadow: var(--shadow-lg);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.staff-edit-card::before {
|
||||
@@ -46,10 +46,10 @@
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* Compact Header */
|
||||
/* Fluid Header */
|
||||
.staff-header {
|
||||
background: var(--primary-gradient);
|
||||
padding: 25px;
|
||||
padding: 30px 25px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
@@ -102,7 +102,7 @@
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
/* Compact Form Sections */
|
||||
/* Fluid Form Sections */
|
||||
.form-section {
|
||||
padding: 25px;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.05);
|
||||
@@ -135,7 +135,7 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Compact Form Grid */
|
||||
/* ADAPTIVE FORM GRID - LIKE SHIPMENT PAGE */
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
@@ -160,7 +160,7 @@
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
/* Compact Form Inputs */
|
||||
/* Form Inputs */
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
@@ -189,7 +189,7 @@
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Compact Status Toggle */
|
||||
/* Status Toggle */
|
||||
.status-toggle {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
@@ -228,7 +228,7 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Compact Permissions Section */
|
||||
/* ADAPTIVE PERMISSIONS SECTION - LIKE SHIPMENT PAGE */
|
||||
.permissions-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||
@@ -337,7 +337,7 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Compact Error Messages */
|
||||
/* Error Messages */
|
||||
.error-container {
|
||||
background: linear-gradient(135deg, #fff5f5, #fed7d7);
|
||||
border: 1.5px solid #fc8181;
|
||||
@@ -377,7 +377,7 @@
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Compact Action Buttons */
|
||||
/* Action Buttons */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
@@ -448,7 +448,267 @@
|
||||
.strength-good { background: #38b2ac; }
|
||||
.strength-strong { background: #48bb78; }
|
||||
|
||||
/* Responsive Design */
|
||||
/* =========================================== */
|
||||
/* DESKTOP MEDIA QUERIES - LIKE SHIPMENT PAGE */
|
||||
/* =========================================== */
|
||||
|
||||
/* Base desktop - 992px+ */
|
||||
@media (min-width: 992px) {
|
||||
body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.staff-header {
|
||||
padding: 35px 30px;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Large desktop - 1200px+ */
|
||||
@media (min-width: 1200px) {
|
||||
.staff-edit-card {
|
||||
margin: 0 auto;
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.staff-header {
|
||||
padding: 40px 35px;
|
||||
}
|
||||
|
||||
.staff-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.staff-avatar {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.staff-avatar-initials {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
padding: 35px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 14px 28px;
|
||||
min-width: 140px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra large desktop - 1440px+ */
|
||||
@media (min-width: 1440px) {
|
||||
.staff-edit-card {
|
||||
max-width: 97%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 35px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.staff-header {
|
||||
padding: 45px 40px;
|
||||
}
|
||||
|
||||
.staff-title {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
.staff-avatar {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.staff-avatar-initials {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
padding: 14px 18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.section-icon {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.permission-group {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.permission-name {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 15px 32px;
|
||||
min-width: 150px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultra wide desktop - 1600px+ */
|
||||
@media (min-width: 1600px) {
|
||||
.staff-edit-card {
|
||||
max-width: 98%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 35px;
|
||||
}
|
||||
|
||||
.staff-header {
|
||||
padding: 50px 45px;
|
||||
}
|
||||
|
||||
.staff-title {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
|
||||
.staff-avatar {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
font-size: 44px;
|
||||
}
|
||||
|
||||
.staff-avatar-initials {
|
||||
font-size: 44px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
padding: 15px 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.section-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.permission-group {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 16px 36px;
|
||||
min-width: 160px;
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultra wide 4K+ screens - 1920px+ */
|
||||
@media (min-width: 1920px) {
|
||||
body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.staff-edit-card {
|
||||
max-width: 99%;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 45px;
|
||||
}
|
||||
|
||||
.permissions-container {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.staff-header {
|
||||
padding: 60px 50px;
|
||||
}
|
||||
|
||||
.staff-title {
|
||||
font-size: 2.6rem;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
padding: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================== */
|
||||
/* MOBILE RESPONSIVE (UNCHANGED) */
|
||||
/* =========================================== */
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
padding: 10px;
|
||||
@@ -521,7 +781,7 @@
|
||||
<div class="staff-edit-container">
|
||||
<!-- Main Card -->
|
||||
<div class="staff-edit-card">
|
||||
<!-- Compact Header -->
|
||||
<!-- Fluid Header -->
|
||||
<div class="staff-header">
|
||||
<div class="staff-avatar">
|
||||
<div class="staff-avatar-initials">
|
||||
|
||||
@@ -38,6 +38,7 @@ Route::middleware(['auth:api'])->group(function () {
|
||||
Route::get('/user/order/{order_id}/shipment', [UserOrderController::class, 'orderShipment']);
|
||||
Route::get('/user/order/{order_id}/invoice', [UserOrderController::class, 'orderInvoice']);
|
||||
Route::get('/user/order/{order_id}/track', [UserOrderController::class, 'trackOrder']);
|
||||
Route::post('/user/orders/{order_id}/confirm', [UserOrderController::class, 'confirmOrder']);
|
||||
|
||||
|
||||
// Invoice List
|
||||
|
||||
@@ -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)
|
||||
// ---------------------------
|
||||
@@ -223,6 +229,10 @@ Route::prefix('admin')
|
||||
Route::post('/invoices/{id}/installment', [AdminInvoiceController::class, 'storeInstallment'])
|
||||
->name('admin.invoice.installment.store');
|
||||
|
||||
Route::get(
|
||||
'/admin/invoices/{id}/download',
|
||||
[AdminInvoiceController::class, 'downloadInvoice']
|
||||
)->name('admin.invoices.download');
|
||||
|
||||
|
||||
Route::delete('/installment/{id}', [AdminInvoiceController::class, 'deleteInstallment'])
|
||||
|
||||
Reference in New Issue
Block a user