changes of invoice and shipment

This commit is contained in:
divya abdar
2025-12-23 00:30:18 +05:30
parent 044bfe5563
commit 7fa03688aa
6 changed files with 196 additions and 40 deletions

View File

@@ -26,15 +26,13 @@ class AdminInvoiceController extends Controller
// ------------------------------------------------------------- // -------------------------------------------------------------
public function popup($id) 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) {
$shipment = \App\Models\Shipment::whereHas('items', function ($q) use ($invoice) { $q->where('order_id', $invoice->order_id);
$q->where('order_id', $invoice->order_id); })->first();
})
->first();
return view('admin.popup_invoice', compact('invoice', 'shipment')); return view('admin.popup_invoice', compact('invoice', 'shipment'));
} }
// ------------------------------------------------------------- // -------------------------------------------------------------
@@ -145,6 +143,22 @@ class AdminInvoiceController extends Controller
$invoice->update(['pdf_path' => 'invoices/' . $fileName]); $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) // INSTALLMENTS (ADD/DELETE)
// ------------------------------------------------------------- // -------------------------------------------------------------

Binary file not shown.

View File

@@ -550,46 +550,71 @@
</div> </div>
</div> </div>
<!-- ============================ @php
SIMPLIFIED INVOICE SUMMARY $totalAmount = $invoice->final_amount;
============================ --> $gstAmount = $invoice->gst_amount;
<div class="summary-container"> $totalPayable = $invoice->final_amount_with_gst;
<div class="row justify-content-center">
<div class="col-lg-8"> $paidAmount = $invoice->totalPaid();
<!-- Subtotal --> $remaining = $invoice->remainingAmount();
<div class="amount-row mb-2"> @endphp
<span>Subtotal Amount</span>
<span class="fw-bold">{{ number_format($invoice->final_amount,2) }}</span> <div class="summary-container">
</div> <div class="row justify-content-center">
<div class="col-lg-8">
<!-- GST -->
<div class="amount-row mb-2"> <div class="amount-row">
<span>GST Amount</span> <span>Total Amount</span>
<span class="fw-bold text-danger">{{ number_format($invoice->gst_amount, 2) }}</span> <span class="fw-bold">{{ number_format($totalAmount,2) }}</span>
</div>
<!-- Total Payable -->
<div class="amount-row mb-2 pt-2 border-top">
<span class="fw-bold">Total Payable Amount</span>
<span class="fw-bold text-success fs-5">{{ number_format($invoice->final_amount_with_gst,2) }}</span>
</div>
</div>
</div>
</div> </div>
<div class="amount-row">
<span>GST Amount</span>
<span class="fw-bold text-danger">
+ {{ number_format($gstAmount,2) }}
</span>
</div>
<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>
<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>
</div>
</div>
</div>
<!-- ============================ <!-- ============================
FOOTER DOWNLOAD & SHARE FOOTER DOWNLOAD & SHARE
============================ --> ============================ -->
<div class="mt-4 pt-3 border-top text-center"> <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 <i class="fas fa-download me-1"></i> Download PDF
</a> </a>
<button class="btn btn-success" onclick="shareInvoice()"> <button class="btn btn-success" onclick="shareInvoice()">
<i class="fas fa-share me-1"></i> Share <i class="fas fa-share me-1"></i> Share
</button> </button>
@endif
</div> </div>
</div> </div>
</div> </div>
@@ -599,12 +624,12 @@
<!-- ============================ <!-- ============================
SHARE SCRIPT SHARE SCRIPT
============================ --> ============================ -->
<script> <script>
function shareInvoice() { function shareInvoice() {
const shareData = { const shareData = {
title: "Invoice {{ $invoice->invoice_number }}", title: "Invoice {{ $invoice->invoice_number }}",
text: "Sharing 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) { if (navigator.share) {
@@ -614,6 +639,7 @@
alert("Link copied! Sharing not supported on this browser."); alert("Link copied! Sharing not supported on this browser.");
} }
} }
</script> </script>
</body> </body>
</html> </html>

View File

@@ -741,6 +741,13 @@
margin: 1vh auto !important; margin: 1vh auto !important;
} }
/* UPDATED: Shipment Order Details Modal - ALSO EDGE-TO-EDGE */
.modal-xl.edge-to-edge.order-details-modal {
max-width: 95vw !important;
width: 95vw !important;
margin: 1vh auto !important;
}
.shipment-details-header { .shipment-details-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white; color: white;
@@ -1135,6 +1142,12 @@
margin: 2vh auto !important; margin: 2vh auto !important;
} }
.modal-xl.edge-to-edge.order-details-modal {
max-width: 96vw !important;
width: 96vw !important;
margin: 2vh auto !important;
}
.shipment-totals-row { .shipment-totals-row {
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
gap: 15px; gap: 15px;
@@ -1148,6 +1161,12 @@
margin: 2.5vh auto !important; margin: 2.5vh auto !important;
} }
.modal-xl.edge-to-edge.order-details-modal {
max-width: 95vw !important;
width: 95vw !important;
margin: 2.5vh auto !important;
}
.shipment-details-body { .shipment-details-body {
padding: 20px 25px; padding: 20px 25px;
} }
@@ -1176,6 +1195,14 @@
max-height: 100vh !important; max-height: 100vh !important;
} }
.modal-xl.edge-to-edge.order-details-modal {
max-width: 100vw !important;
width: 100vw !important;
margin: 0 !important;
height: 100vh !important;
max-height: 100vh !important;
}
.shipment-details-body { .shipment-details-body {
padding: 15px 20px; padding: 15px 20px;
} }
@@ -1210,6 +1237,15 @@
.shipment-total-value { .shipment-total-value {
font-size: 16px; font-size: 16px;
} }
/* Order details modal specific responsive styles */
.order-details-content {
padding: 15px;
}
.order-details-table {
min-width: 1000px;
}
} }
@media (max-width: 576px) { @media (max-width: 576px) {
@@ -1224,10 +1260,42 @@
overflow-y: auto; overflow-y: auto;
} }
.modal-xl.edge-to-edge.order-details-modal .modal-content {
border-radius: 0;
height: 100vh;
overflow-y: auto;
}
.shipment-details-header { .shipment-details-header {
padding: 20px 25px 15px; padding: 20px 25px 15px;
border-radius: 0; border-radius: 0;
} }
.order-details-header {
padding: 20px 15px 10px;
border-radius: 0;
}
.order-details-body {
padding: 15px;
}
}
@media (max-width: 480px) {
.modal-xl.edge-to-edge,
.modal-xl.edge-to-edge.order-details-modal {
margin: 0 !important;
padding: 0 !important;
}
.modal-content {
border-radius: 0 !important;
}
.shipment-details-body,
.order-details-body {
padding: 10px 15px;
}
} }
</style> </style>
@@ -1849,7 +1917,11 @@ function openShipmentDetails(id) {
html += ` html += `
<tr> <tr>
<td class="fw-bold"> <td class="fw-bold">
${order.order_id} <a href="javascript:void(0)"
class="text-primary fw-bold"
onclick="openShipmentOrderDetails(${order.id})">
${order.order_id}
</a>
</td> </td>
<td>${order.origin || 'N/A'}</td> <td>${order.origin || 'N/A'}</td>
<td>${order.destination || 'N/A'}</td> <td>${order.destination || 'N/A'}</td>
@@ -1962,6 +2034,46 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
}); });
}); });
function openShipmentOrderDetails(orderId) {
const modal = new bootstrap.Modal(
document.getElementById('shipmentOrderDetailsModal')
);
const body = document.getElementById('shipmentOrderDetailsBody');
body.innerHTML = "<p class='text-center text-muted'>Loading...</p>";
modal.show();
fetch(`/admin/orders/view/${orderId}`)
.then(res => res.text())
.then(html => {
body.innerHTML = html;
})
.catch(() => {
body.innerHTML =
"<p class='text-danger text-center'>Failed to load order details.</p>";
});
}
</script> </script>
<!-- SHIPMENT ORDER DETAILS MODAL - UPDATED TO EDGE-TO-EDGE -->
<div class="modal fade" id="shipmentOrderDetailsModal" tabindex="-1">
<div class="modal-dialog modal-xl edge-to-edge order-details-modal modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header shipment-details-header order-details-header">
<h5 class="modal-title fw-bold"><i class="bi bi-file-text me-2"></i>Order Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body shipment-details-body order-details-body" id="shipmentOrderDetailsBody">
<p class="text-center text-muted">Loading order details...</p>
</div>
</div>
</div>
</div>
@endsection @endsection

View File

@@ -219,7 +219,11 @@ Route::prefix('admin')
Route::post('/invoices/{id}/installment', [AdminInvoiceController::class, 'storeInstallment']) Route::post('/invoices/{id}/installment', [AdminInvoiceController::class, 'storeInstallment'])
->name('admin.invoice.installment.store'); ->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']) Route::delete('/installment/{id}', [AdminInvoiceController::class, 'deleteInstallment'])
->name('admin.invoice.installment.delete'); ->name('admin.invoice.installment.delete');