Compare commits
10 Commits
dev
...
10af713fa1
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
10af713fa1 | ||
|
|
ebb263cd36 | ||
|
|
82d9c10130 | ||
|
|
cb24cf575b | ||
|
|
e4c07cb838 | ||
|
|
f38a5afdd7 | ||
|
|
9423c79c80 | ||
|
|
8a958b9c48 | ||
|
|
82882e859e | ||
|
|
2d28e7c1d5 |
@@ -9,6 +9,7 @@ use App\Models\InvoiceItem;
|
|||||||
use Mpdf\Mpdf;
|
use Mpdf\Mpdf;
|
||||||
use App\Models\InvoiceInstallment;
|
use App\Models\InvoiceInstallment;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
class AdminInvoiceController extends Controller
|
class AdminInvoiceController extends Controller
|
||||||
{
|
{
|
||||||
@@ -43,7 +44,14 @@ class AdminInvoiceController extends Controller
|
|||||||
$invoice = Invoice::with(['order.shipments'])->findOrFail($id);
|
$invoice = Invoice::with(['order.shipments'])->findOrFail($id);
|
||||||
$shipment = $invoice->order?->shipments?->first();
|
$shipment = $invoice->order?->shipments?->first();
|
||||||
|
|
||||||
return view('admin.invoice_edit', compact('invoice', 'shipment'));
|
// ADD THIS SECTION: Calculate customer's total due across all invoices
|
||||||
|
$customerTotalDue = Invoice::where('customer_id', $invoice->customer_id)
|
||||||
|
->where('status', '!=', 'cancelled')
|
||||||
|
->where('status', '!=', 'void')
|
||||||
|
->sum('final_amount_with_gst');
|
||||||
|
|
||||||
|
// Pass the new variable to the view
|
||||||
|
return view('admin.invoice_edit', compact('invoice', 'shipment', 'customerTotalDue'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
@@ -147,14 +155,9 @@ class AdminInvoiceController extends Controller
|
|||||||
{
|
{
|
||||||
$invoice = Invoice::findOrFail($id);
|
$invoice = Invoice::findOrFail($id);
|
||||||
|
|
||||||
// Generate PDF if missing
|
// ALWAYS regenerate to reflect latest HTML/CSS
|
||||||
if (
|
|
||||||
!$invoice->pdf_path ||
|
|
||||||
!file_exists(public_path($invoice->pdf_path))
|
|
||||||
) {
|
|
||||||
$this->generateInvoicePDF($invoice);
|
$this->generateInvoicePDF($invoice);
|
||||||
$invoice->refresh();
|
$invoice->refresh();
|
||||||
}
|
|
||||||
|
|
||||||
return response()->download(public_path($invoice->pdf_path));
|
return response()->download(public_path($invoice->pdf_path));
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -458,7 +458,7 @@ tr:hover td{ background:#fbfdff; }
|
|||||||
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
|
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Entry Details Modal (existing) ---------- */
|
/* ---------- Entry Details Modal (Enhanced) ---------- */
|
||||||
.modal-fade1 {
|
.modal-fade1 {
|
||||||
position:fixed;
|
position:fixed;
|
||||||
inset:0;
|
inset:0;
|
||||||
@@ -480,6 +480,9 @@ tr:hover td{ background:#fbfdff; }
|
|||||||
max-height:92vh;
|
max-height:92vh;
|
||||||
overflow:auto;
|
overflow:auto;
|
||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
#entryOrdersModal {
|
||||||
|
z-index: 1300;
|
||||||
}
|
}
|
||||||
#entryOrdersModal {
|
#entryOrdersModal {
|
||||||
z-index: 1300;
|
z-index: 1300;
|
||||||
@@ -504,6 +507,182 @@ tr:hover td{ background:#fbfdff; }
|
|||||||
.entry-summary-label{ font-size:12px; color:var(--muted); }
|
.entry-summary-label{ font-size:12px; color:var(--muted); }
|
||||||
.entry-summary-value{ font-size:18px; font-weight:700; color:#253047; margin-top:6px; }
|
.entry-summary-value{ font-size:18px; font-weight:700; color:#253047; margin-top:6px; }
|
||||||
|
|
||||||
|
/* Enhanced dropdown */
|
||||||
|
.installment-status-dropdown {
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 40px 10px 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1.5px solid #e3eaf6;
|
||||||
|
background: white;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="%236b7280" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installment-status-dropdown:hover {
|
||||||
|
border-color: #c2d1f0;
|
||||||
|
background-color: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installment-status-dropdown:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--accent);
|
||||||
|
box-shadow: 0 0 0 3px rgba(39, 109, 234, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status-specific dropdown options */
|
||||||
|
.installment-status-dropdown option {
|
||||||
|
padding: 12px !important;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installment-status-dropdown option[value="Pending"] {
|
||||||
|
color: #f59e0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installment-status-dropdown option[value="Loading"] {
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installment-status-dropdown option[value="Packed"] {
|
||||||
|
color: #8b5cf6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installment-status-dropdown option[value="Dispatched"] {
|
||||||
|
color: #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installment-status-dropdown option[value="Delivered"] {
|
||||||
|
color: #0c6b2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Entry Orders Modal (Enhanced) ---------- */
|
||||||
|
.entry-orders-modal .modal-box1 {
|
||||||
|
padding: 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 20px 60px rgba(18, 30, 60, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-orders-header {
|
||||||
|
background: linear-gradient(90deg, var(--primary-1), var(--primary-2));
|
||||||
|
padding: 24px 30px;
|
||||||
|
color: white;
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-orders-header h2 {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-orders-header .subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.9;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-orders-content {
|
||||||
|
padding: 30px;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Orders table in modal */
|
||||||
|
.orders-table-container {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #eef3fb;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-table th {
|
||||||
|
background: linear-gradient(90deg, #f8fbff, #f5f9ff);
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--primary-1);
|
||||||
|
border-bottom: 2px solid #eef3fb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-table td {
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-bottom: 1px solid #f1f6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-table tr:hover {
|
||||||
|
background: #fbfdff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-table tr:last-child td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Order ID with badge style */
|
||||||
|
.order-id-badge {
|
||||||
|
display: inline-block;
|
||||||
|
background: linear-gradient(90deg, #f0f7ff, #e6f0ff);
|
||||||
|
color: var(--primary-1);
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
border: 1px solid #dbe4f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Summary row */
|
||||||
|
.orders-summary-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: linear-gradient(90deg, #f8fbff, #f5f9ff);
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
border: 1px solid #eef3fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-summary-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-summary-value {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--primary-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-summary-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-top: 4px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
/* installment modal */
|
/* installment modal */
|
||||||
#installmentModal .modal-box1 { max-width:720px; min-width:380px; }
|
#installmentModal .modal-box1 { max-width:720px; min-width:380px; }
|
||||||
|
|
||||||
@@ -1110,6 +1289,38 @@ tr:hover td{ background:#fbfdff; }
|
|||||||
.pagination-container {
|
.pagination-container {
|
||||||
margin-right: 0 !important;
|
margin-right: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Responsive modals */
|
||||||
|
.entry-details-modal .modal-box1,
|
||||||
|
.entry-orders-modal .modal-box1 {
|
||||||
|
margin: 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-details-header,
|
||||||
|
.entry-orders-header {
|
||||||
|
padding: 18px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-details-content,
|
||||||
|
.entry-orders-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-summary-cards {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-summary-value {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-summary-row {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zoom out specific fix */
|
/* Zoom out specific fix */
|
||||||
@@ -1146,6 +1357,10 @@ tr:hover td{ background:#fbfdff; }
|
|||||||
.pagination-info {
|
.pagination-info {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entry-summary-cards {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prevent horizontal scroll on very small screens */
|
/* Prevent horizontal scroll on very small screens */
|
||||||
@@ -1178,6 +1393,7 @@ html, body {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="account-container">
|
<div class="account-container">
|
||||||
@@ -1415,37 +1631,64 @@ html, body {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ENTRY DETAILS MODAL -->
|
<!-- ENTRY DETAILS MODAL (Enhanced) -->
|
||||||
<div class="modal-fade1" id="entryDetailsModal">
|
<div class="modal-fade1 entry-details-modal" id="entryDetailsModal">
|
||||||
<div class="modal-box1 entry-details-modal">
|
<div class="modal-box1">
|
||||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
|
<div class="entry-details-header">
|
||||||
<div>
|
<h2>Entry Details</h2>
|
||||||
<h2 style="margin:0;font-size:20px;color:#223256;font-weight:800">Entry Details — <span id="entryDetailsId">-</span></h2>
|
<div class="subtitle">
|
||||||
<div style="font-size:13px;color:var(--muted)">Complete view of all installments for this entry.</div>
|
<span id="entryDetailsId">Loading...</span>
|
||||||
|
<span>• Complete view of all installments for this entry</span>
|
||||||
</div>
|
</div>
|
||||||
<div><button class="btn ghost" onclick="closeEntryDetailsModal()">Close</button></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="entry-details-content">
|
||||||
<div class="entry-summary-cards">
|
<div class="entry-summary-cards">
|
||||||
<div class="entry-summary-card">
|
<div class="entry-summary-card">
|
||||||
<div class="entry-summary-label">Original Amount</div>
|
<div class="entry-summary-label">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
||||||
|
</svg>
|
||||||
|
Original Amount
|
||||||
|
</div>
|
||||||
<div class="entry-summary-value" id="originalAmount">-</div>
|
<div class="entry-summary-value" id="originalAmount">-</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="entry-summary-card">
|
<div class="entry-summary-card">
|
||||||
<div class="entry-summary-label">Total Processed</div>
|
<div class="entry-summary-label">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
|
||||||
|
</svg>
|
||||||
|
Total Processed
|
||||||
|
</div>
|
||||||
<div class="entry-summary-value" id="totalProcessed">-</div>
|
<div class="entry-summary-value" id="totalProcessed">-</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="entry-summary-card">
|
<div class="entry-summary-card">
|
||||||
<div class="entry-summary-label">Pending Balance</div>
|
<div class="entry-summary-label">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>
|
||||||
|
</svg>
|
||||||
|
Pending Balance
|
||||||
|
</div>
|
||||||
<div class="entry-summary-value" id="pendingBalance">-</div>
|
<div class="entry-summary-value" id="pendingBalance">-</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="entry-summary-card">
|
<div class="entry-summary-card">
|
||||||
<div class="entry-summary-label">Total Installments</div>
|
<div class="entry-summary-label">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
||||||
|
</svg>
|
||||||
|
Total Installments
|
||||||
|
</div>
|
||||||
<div class="entry-summary-value" id="totalInstallments">-</div>
|
<div class="entry-summary-value" id="totalInstallments">-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="entry-installments-table" style="width:100%; border-collapse:collapse;">
|
<div style="margin-top: 30px;">
|
||||||
|
<h3 style="font-size: 18px; font-weight: 700; color: var(--primary-1); margin-bottom: 16px;">
|
||||||
|
Installment History
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="orders-table-container">
|
||||||
|
<table class="entry-installments-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Installment</th>
|
<th>Installment</th>
|
||||||
@@ -1460,36 +1703,40 @@ html, body {
|
|||||||
<tr><td colspan="6" class="empty-state">No installments yet</td></tr>
|
<tr><td colspan="6" class="empty-state">No installments yet</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="display:flex; justify-content: flex-end; gap:12px; margin-top:16px;">
|
<div style="padding: 20px 30px; border-top: 1px solid #eef3fb; display: flex; justify-content: space-between; align-items: center;">
|
||||||
<button type="button" class="btn ghost" onclick="closeEntryDetailsModal()">Close</button>
|
<button type="button" class="btn ghost" onclick="closeEntryDetailsModal()">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
@can('account.add_installment')
|
@can('account.add_installment')
|
||||||
<button type="button" class="btn" id="addInstallmentFromDetails">+ Add New Installment</button>
|
<button type="button" class="btn" id="addInstallmentFromDetails">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 6px;">
|
||||||
|
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
|
||||||
|
</svg>
|
||||||
|
Add New Installment
|
||||||
|
</button>
|
||||||
@endcan
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ENTRY ORDERS MODAL -->
|
<!-- ENTRY ORDERS MODAL (Enhanced) -->
|
||||||
<div class="modal-fade1" id="entryOrdersModal">
|
<div class="modal-fade1 entry-orders-modal" id="entryOrdersModal">
|
||||||
<div class="modal-box1" style="max-width: 1000px;">
|
<div class="modal-box1">
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;">
|
<div class="entry-orders-header">
|
||||||
<div>
|
<h2>Entry Orders</h2>
|
||||||
<h2 style="margin:0;font-size:20px;color:#223256;font-weight:800;">
|
<div class="subtitle">
|
||||||
Entry Orders
|
<span id="entryOrdersEntryNo-span">Loading...</span>
|
||||||
<span id="entryOrdersEntryNo-span" style="font-size:14px;color:#6b7280;margin-left:8px;"></span>
|
<span>• All orders associated with this entry</span>
|
||||||
</h2>
|
|
||||||
<div style="font-size:13px;color:#6f7b8f;">
|
|
||||||
All orders associated with this entry.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn ghost" type="button" onclick="closeEntryOrdersModal()">
|
|
||||||
Close
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="entry-orders-content">
|
||||||
<div class="orders-table-container">
|
<div class="orders-table-container">
|
||||||
<table class="orders-table" style="width:100%;border-collapse:collapse;font-size:13px;">
|
<table class="orders-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Order ID</th>
|
<th>Order ID</th>
|
||||||
@@ -1503,19 +1750,36 @@ html, body {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody id="entryOrdersTableBody">
|
<tbody id="entryOrdersTableBody">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="7" class="empty-state">No orders associated with this entry</td>
|
<td colspan="7" class="empty-state">Loading orders...</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="orders-summary-row">
|
||||||
|
<div class="orders-summary-item">
|
||||||
|
<div class="orders-summary-value" id="ordersTotalCount">0</div>
|
||||||
|
<div class="orders-summary-label">Total Orders</div>
|
||||||
|
</div>
|
||||||
|
<div class="orders-summary-item">
|
||||||
|
<div class="orders-summary-value" id="ordersTotalQuantity">0</div>
|
||||||
|
<div class="orders-summary-label">Total Quantity</div>
|
||||||
|
</div>
|
||||||
|
<div class="orders-summary-item">
|
||||||
|
<div class="orders-summary-value" id="ordersTotalAmount">₹0</div>
|
||||||
|
<div class="orders-summary-label">Total Amount</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="padding: 20px 30px; border-top: 1px solid #eef3fb; display: flex; justify-content: flex-end;">
|
||||||
|
<button class="btn ghost" type="button" onclick="closeEntryOrdersModal()">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Installment Modal -->
|
<!-- Installment Modal -->
|
||||||
<div class="modal-fade1" id="installmentModal">
|
<div class="modal-fade1" id="installmentModal">
|
||||||
<div class="modal-box1" style="max-width:720px;">
|
<div class="modal-box1" style="max-width:720px;">
|
||||||
@@ -2784,9 +3048,16 @@ async function submitEditEntry(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function openEntryOrdersModal(entryNo) {
|
function openEntryOrdersModal(entryNo) {
|
||||||
|
// Set entry number in header
|
||||||
document.getElementById('entryOrdersEntryNo-span').textContent = `(${entryNo})`;
|
document.getElementById('entryOrdersEntryNo-span').textContent = `(${entryNo})`;
|
||||||
|
|
||||||
|
// Reset summary values
|
||||||
|
document.getElementById('ordersTotalCount').textContent = '0';
|
||||||
|
document.getElementById('ordersTotalQuantity').textContent = '0';
|
||||||
|
document.getElementById('ordersTotalAmount').textContent = '₹0';
|
||||||
|
|
||||||
|
// table loading state
|
||||||
const tbody = document.getElementById('entryOrdersTableBody');
|
const tbody = document.getElementById('entryOrdersTableBody');
|
||||||
tbody.innerHTML = `
|
tbody.innerHTML = `
|
||||||
<tr>
|
<tr>
|
||||||
@@ -2794,6 +3065,7 @@ async function submitEditEntry(e) {
|
|||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// API call: /admin/account/entry-orders/{entryno}
|
||||||
jsonFetch(`/admin/account/entry-orders/${encodeURIComponent(entryNo)}`, {
|
jsonFetch(`/admin/account/entry-orders/${encodeURIComponent(entryNo)}`, {
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
})
|
})
|
||||||
@@ -2819,29 +3091,44 @@ async function submitEditEntry(e) {
|
|||||||
|
|
||||||
tbody.innerHTML = '';
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
|
let totalQuantity = 0;
|
||||||
|
let totalAmount = 0;
|
||||||
|
|
||||||
orders.forEach(order => {
|
orders.forEach(order => {
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
|
|
||||||
const amountValue =
|
const idString = (order.orderid ?? order.id ?? '').toString().trim();
|
||||||
order.ttl_amount ??
|
const numericId = parseInt(idString, 10);
|
||||||
order.ttlamount ??
|
const formattedId = isNaN(numericId)
|
||||||
order.total_amount ??
|
? escapeHtml(idString)
|
||||||
order.order_amount ??
|
: 'KNT-25-' + String(numericId).padStart(8, '0');
|
||||||
order.amount ??
|
|
||||||
0;
|
// Calculate values for summary
|
||||||
|
const quantity = Number(order.qty || order.order_qty || 0);
|
||||||
|
const amountValue = Number(order.ttl_amount ?? order.ttlamount ?? order.total_amount ?? order.order_amount ?? order.amount ?? 0);
|
||||||
|
|
||||||
|
totalQuantity += quantity;
|
||||||
|
totalAmount += amountValue;
|
||||||
|
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td>${escapeHtml(order.order_id)}</td>
|
<td>
|
||||||
<td>${escapeHtml(order.mark_no ?? '')}</td>
|
<span class="order-id-badge">${formattedId}</span>
|
||||||
|
</td>
|
||||||
|
<td>${escapeHtml(order.markno ?? order.mark_no ?? '')}</td>
|
||||||
<td>${escapeHtml(order.origin ?? '')}</td>
|
<td>${escapeHtml(order.origin ?? '')}</td>
|
||||||
<td>${escapeHtml(order.destination ?? '')}</td>
|
<td>${escapeHtml(order.destination ?? '')}</td>
|
||||||
<td>${escapeHtml(order.ctn ?? '')}</td>
|
<td>${escapeHtml(order.ctn ?? '')}</td>
|
||||||
<td>${escapeHtml(order.qty ?? '')}</td>
|
<td><strong>${quantity}</strong></td>
|
||||||
<td>${formatCurrency(amountValue)}</td>
|
<td><strong>${formatCurrency(amountValue)}</strong></td>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
tbody.appendChild(tr);
|
tbody.appendChild(tr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update summary
|
||||||
|
document.getElementById('ordersTotalCount').textContent = orders.length;
|
||||||
|
document.getElementById('ordersTotalQuantity').textContent = totalQuantity.toLocaleString();
|
||||||
|
document.getElementById('ordersTotalAmount').textContent = formatCurrency(totalAmount);
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
tbody.innerHTML = `
|
tbody.innerHTML = `
|
||||||
@@ -2852,8 +3139,7 @@ async function submitEditEntry(e) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('entryOrdersModal').classList.add('modal-open');
|
document.getElementById('entryOrdersModal').classList.add('modal-open');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function closeEntryOrdersModal() {
|
function closeEntryOrdersModal() {
|
||||||
document.getElementById('entryOrdersModal').classList.remove('modal-open');
|
document.getElementById('entryOrdersModal').classList.remove('modal-open');
|
||||||
@@ -2989,7 +3275,7 @@ function handleSearch(){
|
|||||||
updatePaginationControls();
|
updatePaginationControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Entry details & installments ---------- */
|
/* ---------- Entry details & installments (Enhanced) ---------- */
|
||||||
async function openEntryDetailsModal(entryNo) {
|
async function openEntryDetailsModal(entryNo) {
|
||||||
try {
|
try {
|
||||||
const res = await jsonFetch('/admin/account/entry/' + encodeURIComponent(entryNo));
|
const res = await jsonFetch('/admin/account/entry/' + encodeURIComponent(entryNo));
|
||||||
@@ -2999,58 +3285,109 @@ async function openEntryDetailsModal(entryNo) {
|
|||||||
const entry = res.entry;
|
const entry = res.entry;
|
||||||
currentEntry = entry;
|
currentEntry = entry;
|
||||||
|
|
||||||
|
// Set header info
|
||||||
document.getElementById('entryDetailsId').textContent = entry.entry_no;
|
document.getElementById('entryDetailsId').textContent = entry.entry_no;
|
||||||
document.getElementById('originalAmount').textContent = formatCurrency(entry.amount);
|
|
||||||
|
|
||||||
const totalProcessed = Number(entry.amount) - Number(entry.pending_amount);
|
// Calculate values
|
||||||
|
const originalAmount = Number(entry.amount || 0);
|
||||||
|
const pendingAmount = Number(entry.pending_amount || 0);
|
||||||
|
const totalProcessed = originalAmount - pendingAmount;
|
||||||
|
|
||||||
|
// Update summary cards
|
||||||
|
document.getElementById('originalAmount').textContent = formatCurrency(originalAmount);
|
||||||
document.getElementById('totalProcessed').textContent = formatCurrency(totalProcessed);
|
document.getElementById('totalProcessed').textContent = formatCurrency(totalProcessed);
|
||||||
|
document.getElementById('pendingBalance').textContent = formatCurrency(pendingAmount);
|
||||||
|
document.getElementById('totalInstallments').textContent = entry.installments?.length || 0;
|
||||||
|
|
||||||
document.getElementById('pendingBalance').textContent = formatCurrency(entry.pending_amount);
|
// Render installments table
|
||||||
document.getElementById('totalInstallments').textContent = entry.installments.length;
|
|
||||||
|
|
||||||
const tbody = document.getElementById('installmentsTableBody');
|
const tbody = document.getElementById('installmentsTableBody');
|
||||||
tbody.innerHTML = '';
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
|
if (!entry.installments || entry.installments.length === 0) {
|
||||||
|
tbody.innerHTML = `
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="empty-state">
|
||||||
|
<div style="padding: 30px; text-align: center;">
|
||||||
|
<div style="font-size: 48px; color: #eef3fb; margin-bottom: 16px;">📋</div>
|
||||||
|
<div style="font-size: 16px; color: #6f7b8f; font-weight: 500;">
|
||||||
|
No installments found for this entry
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 14px; color: #9ba5bb; margin-top: 8px;">
|
||||||
|
Add your first installment to get started
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
entry.installments.forEach((ins, idx) => {
|
entry.installments.forEach((ins, idx) => {
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
tr.innerHTML = `
|
|
||||||
<td>${idx === 0 ? 'Original Entry' : 'Installment ' + idx}</td>
|
|
||||||
<td>${escapeHtml(ins.proc_date)}</td>
|
|
||||||
<td>${escapeHtml(ins.description)}</td>
|
|
||||||
<td>${escapeHtml(ins.region)}</td>
|
|
||||||
<td>${formatCurrency(ins.amount)}</td>
|
|
||||||
|
|
||||||
|
// Determine installment label
|
||||||
|
let installmentLabel = 'Original Entry';
|
||||||
|
if (idx > 0) {
|
||||||
|
installmentLabel = `Installment ${idx}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status dropdown options with colors
|
||||||
|
const statusOptions = [
|
||||||
|
{ value: 'Pending', label: '⏳ Pending', color: '#f59e0b' },
|
||||||
|
{ value: 'Loading', label: '📦 Loading', color: '#3b82f6' },
|
||||||
|
{ value: 'Packed', label: '📦 Packed', color: '#8b5cf6' },
|
||||||
|
{ value: 'Dispatched', label: '🚚 Dispatched', color: '#10b981' },
|
||||||
|
{ value: 'Delivered', label: '✅ Delivered', color: '#0c6b2e' }
|
||||||
|
];
|
||||||
|
|
||||||
|
let statusOptionsHtml = '';
|
||||||
|
statusOptions.forEach(opt => {
|
||||||
|
const selected = ins.status === opt.value ? 'selected' : '';
|
||||||
|
statusOptionsHtml += `<option value="${opt.value}" ${selected} style="color: ${opt.color}; font-weight: 500;">${opt.label}</option>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
tr.innerHTML = `
|
||||||
|
<td>
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px;">
|
||||||
|
<div style="width: 32px; height: 32px; border-radius: 8px; background: linear-gradient(135deg, #f0f7ff, #e6f0ff); display: flex; align-items: center; justify-content: center; font-weight: 700; color: var(--primary-1);">
|
||||||
|
${idx + 1}
|
||||||
|
</div>
|
||||||
|
<span style="font-weight: 600;">${installmentLabel}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div style="display: flex; align-items: center; gap: 6px;">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
|
||||||
|
<line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/>
|
||||||
|
<line x1="3" y1="10" x2="21" y2="10"/>
|
||||||
|
</svg>
|
||||||
|
${escapeHtml(ins.proc_date || ins.date || '')}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>${escapeHtml(ins.description || '')}</td>
|
||||||
|
<td>
|
||||||
|
<span style="padding: 4px 8px; background: #f0f7ff; border-radius: 6px; font-size: 12px; font-weight: 600; color: var(--primary-1);">
|
||||||
|
${escapeHtml(ins.region || '')}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span style="font-weight: 700; color: var(--primary-1);">
|
||||||
|
${formatCurrency(ins.amount || 0)}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select class="installment-status-dropdown"
|
<select class="installment-status-dropdown"
|
||||||
data-id="${ins.id}"
|
data-id="${ins.id}"
|
||||||
onchange="updateInstallmentStatus(${ins.id}, this.value)">
|
onchange="updateInstallmentStatus(${ins.id}, this.value)"
|
||||||
<option value="Pending" ${ins.status === 'Pending' ? 'selected' : ''}
|
title="Update installment status">
|
||||||
style="color: #f59e0b; font-weight: 500; padding: 10px;">
|
${statusOptionsHtml}
|
||||||
⏳ Pending
|
|
||||||
</option>
|
|
||||||
<option value="Loading" ${ins.status === 'Loading' ? 'selected' : ''}
|
|
||||||
style="color: #3b82f6; font-weight: 500; padding: 10px;">
|
|
||||||
📦 Loading
|
|
||||||
</option>
|
|
||||||
<option value="Packed" ${ins.status === 'Packed' ? 'selected' : ''}
|
|
||||||
style="color: #8b5cf6; font-weight: 500; padding: 10px;">
|
|
||||||
📦 Packed
|
|
||||||
</option>
|
|
||||||
<option value="Dispatched" ${ins.status === 'Dispatched' ? 'selected' : ''}
|
|
||||||
style="color: #10b981; font-weight: 500; padding: 10px;">
|
|
||||||
🚚 Dispatched
|
|
||||||
</option>
|
|
||||||
<option value="Delivered" ${ins.status === 'Delivered' ? 'selected' : ''}
|
|
||||||
style="color: #0c6b2e; font-weight: 500; padding: 10px;">
|
|
||||||
✅ Delivered
|
|
||||||
</option>
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
`;
|
`;
|
||||||
tbody.appendChild(tr);
|
tbody.appendChild(tr);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show modal
|
||||||
document.getElementById('entryDetailsModal').classList.add('modal-open');
|
document.getElementById('entryDetailsModal').classList.add('modal-open');
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
@extends('admin.layouts.app')
|
@extends('admin.layouts.app')
|
||||||
|
|
||||||
@section('page-title', 'Customers')
|
@section('page-title', 'Customers')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Import Inter font */
|
/* Import Inter font */
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
||||||
|
|
||||||
@@ -700,9 +700,9 @@
|
|||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- Header - Removed gradient -->
|
<!-- Header - Removed gradient -->
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<h4 style="color: #2c3e50; font-weight: 700; font-family: 'Inter', sans-serif;">Customer List</h4>
|
<h4 style="color: #2c3e50; font-weight: 700; font-family: 'Inter', sans-serif;">Customer List</h4>
|
||||||
@@ -830,6 +830,7 @@
|
|||||||
<th class="table-header">Order Total</th>
|
<th class="table-header">Order Total</th>
|
||||||
<th class="table-header">Total Payable</th> {{-- NEW --}}
|
<th class="table-header">Total Payable</th> {{-- NEW --}}
|
||||||
<th class="table-header">Remaining</th> {{-- NEW --}}
|
<th class="table-header">Remaining</th> {{-- NEW --}}
|
||||||
|
<th class="table-header">Paid Amount</th>
|
||||||
<th class="table-header">Create Date</th>
|
<th class="table-header">Create Date</th>
|
||||||
<th class="table-header">Status</th>
|
<th class="table-header">Status</th>
|
||||||
<th class="table-header" width="100">Actions</th>
|
<th class="table-header" width="100">Actions</th>
|
||||||
@@ -907,8 +908,11 @@
|
|||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<td class="total-column">
|
||||||
|
<span class="fw-bold text-success">
|
||||||
|
₹{{ number_format($totalPaid, 2) }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
<!-- Create Date -->
|
<!-- Create Date -->
|
||||||
@@ -984,9 +988,9 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Add hover effects to table rows
|
// Add hover effects to table rows
|
||||||
const tableRows = document.querySelectorAll('.table tbody tr');
|
const tableRows = document.querySelectorAll('.table tbody tr');
|
||||||
@@ -1013,6 +1017,6 @@
|
|||||||
@endif
|
@endif
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -274,6 +274,30 @@ body {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-info-compact {
|
||||||
|
background: linear-gradient(135deg, #06b6d4 0%, #0ea5e9 100%);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(6, 182, 212, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-info-compact:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 20px rgba(6, 182, 212, 0.4);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-warning-compact {
|
||||||
|
background: var(--warning-gradient);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-warning-compact:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 20px rgba(245, 158, 11, 0.4);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------
|
/* --------------------------------------------------
|
||||||
COMPACT SUMMARY CARDS
|
COMPACT SUMMARY CARDS
|
||||||
-------------------------------------------------- */
|
-------------------------------------------------- */
|
||||||
@@ -316,7 +340,7 @@ body {
|
|||||||
-------------------------------------------------- */
|
-------------------------------------------------- */
|
||||||
.amount-breakdown-compact {
|
.amount-breakdown-compact {
|
||||||
background: white;
|
background: white;
|
||||||
padding: 1rem;
|
padding: 1.5rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: var(--shadow-soft);
|
box-shadow: var(--shadow-soft);
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
@@ -391,6 +415,15 @@ body {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------
|
||||||
|
HEADER ACTION BUTTONS
|
||||||
|
-------------------------------------------------- */
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------
|
/* --------------------------------------------------
|
||||||
RESPONSIVE DESIGN
|
RESPONSIVE DESIGN
|
||||||
-------------------------------------------------- */
|
-------------------------------------------------- */
|
||||||
@@ -422,6 +455,13 @@ body {
|
|||||||
.table-compact {
|
.table-compact {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
@@ -454,10 +494,21 @@ body {
|
|||||||
|
|
||||||
<!-- Invoice Preview Section -->
|
<!-- Invoice Preview Section -->
|
||||||
<div class="glass-card">
|
<div class="glass-card">
|
||||||
<div class="card-header-compact">
|
<div class="card-header-compact d-flex justify-content-between align-items-center">
|
||||||
<h4>
|
<h4>
|
||||||
<i class="fas fa-file-invoice me-2"></i>Invoice Overview
|
<i class="fas fa-file-invoice me-2"></i>Invoice Overview
|
||||||
</h4>
|
</h4>
|
||||||
|
<div class="header-actions">
|
||||||
|
<!-- Share Invoice -->
|
||||||
|
<button class="btn-info-compact btn-compact" id="shareInvoiceBtn">
|
||||||
|
<i class="fas fa-share-alt me-2"></i>Share Invoice
|
||||||
|
</button>
|
||||||
|
<!-- Download Invoice -->
|
||||||
|
<a href="{{ route('admin.invoices.download', $invoice->id) }}"
|
||||||
|
class="btn-warning-compact btn-compact" target="_blank">
|
||||||
|
<i class="fas fa-download me-2"></i>Download Invoice
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body-compact invoice-preview-wrapper">
|
<div class="card-body-compact invoice-preview-wrapper">
|
||||||
@include('admin.popup_invoice', [
|
@include('admin.popup_invoice', [
|
||||||
@@ -468,6 +519,89 @@ body {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Amount Breakdown -->
|
||||||
|
<div class="glass-card">
|
||||||
|
<div class="card-header-compact">
|
||||||
|
<h4>
|
||||||
|
<i class="fas fa-calculator me-2"></i>Amount Breakdown
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body-compact">
|
||||||
|
<div class="amount-breakdown-compact">
|
||||||
|
@php
|
||||||
|
$totalPaid = $invoice->installments->sum('amount');
|
||||||
|
$remaining = $invoice->final_amount_with_gst - $totalPaid;
|
||||||
|
|
||||||
|
// Calculate GST/IGST percentage dynamically
|
||||||
|
$taxPercentage = $invoice->tax_type === 'gst'
|
||||||
|
? ($invoice->cgst_percent + $invoice->sgst_percent)
|
||||||
|
: $invoice->igst_percent;
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="breakdown-row">
|
||||||
|
<span class="breakdown-label">Total Amount (Before Tax):</span>
|
||||||
|
<span class="breakdown-value">₹{{ number_format($invoice->final_amount, 2) }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="breakdown-row">
|
||||||
|
<span class="breakdown-label">
|
||||||
|
@if($invoice->tax_type === 'gst')
|
||||||
|
GST ({{ number_format($taxPercentage, 2) }}%)
|
||||||
|
@else
|
||||||
|
IGST ({{ number_format($taxPercentage, 2) }}%)
|
||||||
|
@endif:
|
||||||
|
</span>
|
||||||
|
<span class="breakdown-value text-warning">₹{{ number_format($invoice->gst_amount, 2) }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="breakdown-row" style="border-top: 2px solid #e2e8f0; padding-top: 0.75rem;">
|
||||||
|
<span class="breakdown-label fw-bold">Total Invoice Amount (Including GST):</span>
|
||||||
|
<span class="breakdown-value fw-bold text-dark">₹{{ number_format($invoice->final_amount_with_gst, 2) }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="breakdown-row">
|
||||||
|
<span class="breakdown-label text-success">Total Paid:</span>
|
||||||
|
<span class="breakdown-value fw-bold text-success" id="paidAmount">₹{{ number_format($totalPaid, 2) }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="breakdown-row" style="border-bottom: none;">
|
||||||
|
<span class="breakdown-label text-danger">Remaining:</span>
|
||||||
|
<span class="breakdown-value fw-bold text-danger" id="remainingAmount">₹{{ number_format($remaining, 2) }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- NEW: Customer's Total Amount Due Across All Invoices -->
|
||||||
|
<div class="breakdown-row" style="border-top: 2px solid #3b82f6; background: rgba(59, 130, 246, 0.05);">
|
||||||
|
<span class="breakdown-label fw-bold text-primary">
|
||||||
|
<i class="fas fa-users me-1"></i>Total Amount Due (Including Tax):
|
||||||
|
<small class="d-block text-muted" style="font-size: 0.75rem; font-weight: normal;">
|
||||||
|
</small>
|
||||||
|
</span>
|
||||||
|
<span class="breakdown-value fw-bold text-primary" style="font-size: 1.1rem;">
|
||||||
|
₹{{ number_format($customerTotalDue, 2) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Installment Summary -->
|
||||||
|
<div class="summary-grid-compact mt-3">
|
||||||
|
<div class="summary-card-compact total">
|
||||||
|
<div class="summary-value-compact text-success">₹{{ number_format($invoice->final_amount_with_gst, 2) }}</div>
|
||||||
|
<div class="summary-label-compact">Total Amount</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card-compact paid">
|
||||||
|
<div class="summary-value-compact text-primary">₹{{ number_format($totalPaid, 2) }}</div>
|
||||||
|
<div class="summary-label-compact">Total Paid</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card-compact remaining">
|
||||||
|
<div class="summary-value-compact text-warning">₹{{ number_format($remaining, 2) }}</div>
|
||||||
|
<div class="summary-label-compact">Remaining</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Edit Invoice Form -->
|
<!-- Edit Invoice Form -->
|
||||||
<div class="glass-card">
|
<div class="glass-card">
|
||||||
<div class="card-header-compact">
|
<div class="card-header-compact">
|
||||||
@@ -577,81 +711,6 @@ body {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php
|
|
||||||
$totalPaid = $invoice->installments->sum('amount');
|
|
||||||
$remaining = $invoice->final_amount_with_gst - $totalPaid;
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
<!-- Amount Breakdown -->
|
|
||||||
<div class="amount-breakdown-compact">
|
|
||||||
<h6 class="fw-bold mb-3 text-dark">
|
|
||||||
<i class="fas fa-calculator me-2"></i>Amount Breakdown
|
|
||||||
</h6>
|
|
||||||
|
|
||||||
<div class="breakdown-row">
|
|
||||||
<span class="breakdown-label">Total Amount (Before Tax):</span>
|
|
||||||
<span class="breakdown-value">₹{{ number_format($invoice->final_amount, 2) }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="breakdown-row">
|
|
||||||
<span class="breakdown-label">Tax Type:</span>
|
|
||||||
<span class="breakdown-value text-primary">
|
|
||||||
@if($invoice->tax_type === 'gst')
|
|
||||||
GST (CGST + SGST)
|
|
||||||
@else
|
|
||||||
IGST
|
|
||||||
@endif
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="breakdown-row">
|
|
||||||
<span class="breakdown-label">Tax Percentage:</span>
|
|
||||||
<span class="breakdown-value text-primary">
|
|
||||||
@if($invoice->tax_type === 'gst')
|
|
||||||
{{ $invoice->cgst_percent + $invoice->sgst_percent }}%
|
|
||||||
@else
|
|
||||||
{{ $invoice->igst_percent }}%
|
|
||||||
@endif
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="breakdown-row">
|
|
||||||
<span class="breakdown-label">GST Amount:</span>
|
|
||||||
<span class="breakdown-value text-warning">₹{{ number_format($invoice->gst_amount, 2) }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="breakdown-row" style="border-top: 2px solid #e2e8f0; padding-top: 0.75rem;">
|
|
||||||
<span class="breakdown-label fw-bold">Total Invoice Amount (Including GST):</span>
|
|
||||||
<span class="breakdown-value fw-bold text-dark">₹{{ number_format($invoice->final_amount_with_gst, 2) }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="breakdown-row">
|
|
||||||
<span class="breakdown-label text-success">Total Paid:</span>
|
|
||||||
<span class="breakdown-value fw-bold text-success" id="paidAmount">₹{{ number_format($totalPaid, 2) }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="breakdown-row" style="border-bottom: none;">
|
|
||||||
<span class="breakdown-label text-danger">Remaining:</span>
|
|
||||||
<span class="breakdown-value fw-bold text-danger" id="remainingAmount">₹{{ number_format($remaining, 2) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Installment Summary -->
|
|
||||||
<div class="summary-grid-compact">
|
|
||||||
<div class="summary-card-compact total">
|
|
||||||
<div class="summary-value-compact text-success">₹{{ number_format($invoice->final_amount_with_gst, 2) }}</div>
|
|
||||||
<div class="summary-label-compact">Total Amount</div>
|
|
||||||
</div>
|
|
||||||
<div class="summary-card-compact paid">
|
|
||||||
<div class="summary-value-compact text-primary">₹{{ number_format($totalPaid, 2) }}</div>
|
|
||||||
<div class="summary-label-compact">Total Paid</div>
|
|
||||||
</div>
|
|
||||||
<div class="summary-card-compact remaining">
|
|
||||||
<div class="summary-value-compact text-warning">₹{{ number_format($remaining, 2) }}</div>
|
|
||||||
<div class="summary-label-compact">Remaining</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Installment Management -->
|
<!-- Installment Management -->
|
||||||
<div class="glass-card">
|
<div class="glass-card">
|
||||||
<div class="card-header-compact d-flex justify-content-between align-items-center">
|
<div class="card-header-compact d-flex justify-content-between align-items-center">
|
||||||
@@ -736,6 +795,7 @@ body {
|
|||||||
<h6 class="fw-bold mb-2 text-dark">
|
<h6 class="fw-bold mb-2 text-dark">
|
||||||
<i class="fas fa-history me-2"></i>Installment History
|
<i class="fas fa-history me-2"></i>Installment History
|
||||||
</h6>
|
</h6>
|
||||||
|
@if($invoice->installments->count() > 0)
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table-compact">
|
<table class="table-compact">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -776,24 +836,87 @@ body {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@else
|
||||||
</div>
|
<div id="noInstallmentsMsg" class="text-center text-muted fw-bold py-4">
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Add this just above the table -->
|
|
||||||
<div id="noInstallmentsMsg" class="d-none text-center text-muted fw-bold py-4">
|
|
||||||
No installments found. Click "Add Installment" to create one.
|
No installments found. Click "Add Installment" to create one.
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table ...>
|
|
||||||
<tbody id="installmentTable">
|
|
||||||
@foreach($invoice->installments as $i)
|
|
||||||
...
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
// Share Invoice Functionality
|
||||||
|
const shareInvoiceBtn = document.getElementById('shareInvoiceBtn');
|
||||||
|
if (shareInvoiceBtn) {
|
||||||
|
shareInvoiceBtn.addEventListener('click', function() {
|
||||||
|
const shareUrl = window.location.href;
|
||||||
|
const invoiceNo = "{{ $invoice->invoice_no }}";
|
||||||
|
const message = `Invoice #${invoiceNo} - Total: ₹{{ number_format($invoice->final_amount_with_gst, 2) }}\nView: ${shareUrl}`;
|
||||||
|
|
||||||
|
if (navigator.share) {
|
||||||
|
navigator.share({
|
||||||
|
title: `Invoice #${invoiceNo}`,
|
||||||
|
text: `Invoice #${invoiceNo} - Total: ₹{{ number_format($invoice->final_amount_with_gst, 2) }}`,
|
||||||
|
url: shareUrl
|
||||||
|
}).catch(console.error);
|
||||||
|
} else if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(message)
|
||||||
|
.then(() => {
|
||||||
|
alert('Invoice link copied to clipboard!');
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('Failed to copy: ', err);
|
||||||
|
// Fallback to prompt
|
||||||
|
prompt('Copy this link to share:', shareUrl);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
prompt('Copy this link to share:', shareUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print Invoice Function
|
||||||
|
window.printInvoice = function() {
|
||||||
|
const printWindow = window.open('', '_blank');
|
||||||
|
const invoiceContent = document.querySelector('.invoice-preview-wrapper').innerHTML;
|
||||||
|
const printContent = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Invoice {{ $invoice->invoice_no }}</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||||
|
.invoice-container { max-width: 800px; margin: 0 auto; }
|
||||||
|
.text-end { text-align: right; }
|
||||||
|
.fw-bold { font-weight: bold; }
|
||||||
|
table { width: 100%; border-collapse: collapse; }
|
||||||
|
th, td { padding: 8px; border: 1px solid #ddd; }
|
||||||
|
th { background-color: #f8f9fa; }
|
||||||
|
.total-row { background-color: #f8f9fa; font-weight: bold; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="invoice-container">
|
||||||
|
${invoiceContent}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
window.print();
|
||||||
|
setTimeout(function() {
|
||||||
|
window.close();
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
<\/script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
printWindow.document.write(printContent);
|
||||||
|
printWindow.document.close();
|
||||||
|
};
|
||||||
|
|
||||||
// Toggle Installment Form
|
// Toggle Installment Form
|
||||||
const toggleBtn = document.getElementById("toggleInstallmentForm");
|
const toggleBtn = document.getElementById("toggleInstallmentForm");
|
||||||
const formBox = document.getElementById("installmentForm");
|
const formBox = document.getElementById("installmentForm");
|
||||||
@@ -814,6 +937,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
maximumFractionDigits: 2
|
maximumFractionDigits: 2
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (submitForm) {
|
||||||
submitForm.addEventListener("submit", function (e) {
|
submitForm.addEventListener("submit", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -839,9 +963,40 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const table = document.querySelector("#installmentTable");
|
const table = document.querySelector("#installmentTable");
|
||||||
const index = table.rows.length + 1;
|
const noInstallmentsMsg = document.getElementById("noInstallmentsMsg");
|
||||||
|
|
||||||
table.insertAdjacentHTML("beforeend", `
|
if (noInstallmentsMsg) {
|
||||||
|
noInstallmentsMsg.classList.add("d-none");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table) {
|
||||||
|
// Create table if it doesn't exist
|
||||||
|
const tableHTML = `
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table-compact">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Payment Method</th>
|
||||||
|
<th>Reference No</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="installmentTable">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
const parent = submitForm.closest('.card-body-compact');
|
||||||
|
parent.insertAdjacentHTML('beforeend', tableHTML);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTable = document.querySelector("#installmentTable");
|
||||||
|
const index = newTable.rows.length + 1;
|
||||||
|
|
||||||
|
newTable.insertAdjacentHTML("beforeend", `
|
||||||
<tr data-id="${data.installment.id}">
|
<tr data-id="${data.installment.id}">
|
||||||
<td class="fw-bold text-muted">${index}</td>
|
<td class="fw-bold text-muted">${index}</td>
|
||||||
<td>${data.installment.installment_date}</td>
|
<td>${data.installment.installment_date}</td>
|
||||||
@@ -860,15 +1015,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
</tr>
|
</tr>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Update all displayed values using GST fields!
|
// Update all displayed values
|
||||||
if (document.getElementById("paidAmount")) document.getElementById("paidAmount").textContent = formatINR(data.totalPaid);
|
if (document.getElementById("paidAmount")) document.getElementById("paidAmount").textContent = formatINR(data.totalPaid);
|
||||||
if (document.getElementById("remainingAmount")) document.getElementById("remainingAmount").textContent = formatINR(data.remaining);
|
if (document.getElementById("remainingAmount")) document.getElementById("remainingAmount").textContent = formatINR(data.remaining);
|
||||||
if (document.getElementById("baseAmount")) document.getElementById("baseAmount").textContent = formatINR(data.baseAmount);
|
|
||||||
if (document.getElementById("gstAmount")) document.getElementById("gstAmount").textContent = formatINR(data.gstAmount);
|
|
||||||
if (document.getElementById("totalInvoiceWithGst")) document.getElementById("totalInvoiceWithGst").textContent = formatINR(data.finalAmountWithGst);
|
|
||||||
if (document.getElementById("invoiceStatus")) document.getElementById("invoiceStatus").textContent = data.isCompleted ? "Paid" : "Pending";
|
|
||||||
|
|
||||||
// Update summary cards if used
|
// Update summary cards
|
||||||
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
|
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
|
||||||
if (paidCard) paidCard.textContent = formatINR(data.totalPaid);
|
if (paidCard) paidCard.textContent = formatINR(data.totalPaid);
|
||||||
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
|
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
|
||||||
@@ -890,6 +1041,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
alert("Something went wrong. Please try again.");
|
alert("Something went wrong. Please try again.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Delete Installment
|
// Delete Installment
|
||||||
document.addEventListener("click", function (e) {
|
document.addEventListener("click", function (e) {
|
||||||
@@ -911,15 +1063,27 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.status === "success") {
|
if (data.status === "success") {
|
||||||
row.style.opacity = "0";
|
row.style.opacity = "0";
|
||||||
setTimeout(() => row.remove(), 300);
|
setTimeout(() => {
|
||||||
|
row.remove();
|
||||||
|
|
||||||
// Update all displayed values using GST fields!
|
// Update row numbers
|
||||||
|
const rows = document.querySelectorAll("#installmentTable tr");
|
||||||
|
rows.forEach((row, index) => {
|
||||||
|
row.querySelector("td:first-child").textContent = index + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show no installments message if empty
|
||||||
|
if (rows.length === 0) {
|
||||||
|
const noInstallmentsMsg = document.getElementById("noInstallmentsMsg");
|
||||||
|
if (noInstallmentsMsg) {
|
||||||
|
noInstallmentsMsg.classList.remove("d-none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
// Update all displayed values
|
||||||
if (document.getElementById("paidAmount")) document.getElementById("paidAmount").textContent = formatINR(data.totalPaid);
|
if (document.getElementById("paidAmount")) document.getElementById("paidAmount").textContent = formatINR(data.totalPaid);
|
||||||
if (document.getElementById("remainingAmount")) document.getElementById("remainingAmount").textContent = formatINR(data.remaining);
|
if (document.getElementById("remainingAmount")) document.getElementById("remainingAmount").textContent = formatINR(data.remaining);
|
||||||
if (document.getElementById("baseAmount")) document.getElementById("baseAmount").textContent = formatINR(data.baseAmount);
|
|
||||||
if (document.getElementById("gstAmount")) document.getElementById("gstAmount").textContent = formatINR(data.gstAmount);
|
|
||||||
if (document.getElementById("totalInvoiceWithGst")) document.getElementById("totalInvoiceWithGst").textContent = formatINR(data.finalAmountWithGst);
|
|
||||||
if (document.getElementById("invoiceStatus")) document.getElementById("invoiceStatus").textContent = data.remaining === 0 ? "Paid" : "Pending";
|
|
||||||
|
|
||||||
// Update summary cards
|
// Update summary cards
|
||||||
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
|
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
|
||||||
@@ -927,7 +1091,15 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
|
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
|
||||||
if (remainingCard) remainingCard.textContent = formatINR(data.remaining);
|
if (remainingCard) remainingCard.textContent = formatINR(data.remaining);
|
||||||
|
|
||||||
|
// Show add installment button if there's remaining amount
|
||||||
|
if (data.remaining > 0 && !document.getElementById("toggleInstallmentForm")) {
|
||||||
|
const header = document.querySelector(".glass-card .card-header-compact");
|
||||||
|
header.innerHTML += `
|
||||||
|
<button id="toggleInstallmentForm" class="btn-primary-compact btn-compact">
|
||||||
|
<i class="fas fa-plus-circle me-2"></i>Add Installment
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
alert(data.message);
|
alert(data.message);
|
||||||
} else {
|
} else {
|
||||||
@@ -940,6 +1112,4 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
@@ -11,59 +11,67 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
.container {
|
|
||||||
|
.container {
|
||||||
max-width: 850px;
|
max-width: 850px;
|
||||||
margin: 24px auto 0 auto;
|
margin: 24px auto 0 auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 13px;
|
border-radius: 13px;
|
||||||
box-shadow: 0 2px 14px rgba(40,105,160,0.08);
|
box-shadow: 0 2px 14px rgba(40,105,160,0.08);
|
||||||
padding: 35px 32px 18px 32px;
|
padding: 35px 32px 18px 32px;
|
||||||
}
|
}
|
||||||
.header {
|
|
||||||
display: flex;
|
/* ================= HEADER FIX ================= */
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-start;
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden; /* clears floats */
|
||||||
border-bottom: 2px solid #E6EBF0;
|
border-bottom: 2px solid #E6EBF0;
|
||||||
padding-bottom: 13px;
|
padding-bottom: 13px;
|
||||||
}
|
}
|
||||||
.logo-company {
|
|
||||||
display: flex;
|
/* LEFT SIDE */
|
||||||
align-items: flex-start;
|
.logo-company {
|
||||||
}
|
float: left;
|
||||||
.logo {
|
width: 65%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RIGHT SIDE */
|
||||||
|
.invoice-details {
|
||||||
|
float: right;
|
||||||
|
width: 35%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo */
|
||||||
|
.logo {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
margin-right: 13px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
.company-details {
|
|
||||||
margin-top: 0;
|
/* Company text */
|
||||||
|
.company-details {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
line-height: 1.55;
|
||||||
.company-title {
|
}
|
||||||
|
|
||||||
|
.company-title {
|
||||||
font-size: 21px;
|
font-size: 21px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
.company-sub {
|
|
||||||
font-size: 16px;
|
/* Invoice */
|
||||||
margin-bottom: 8px;
|
.invoice-title {
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
.invoice-details {
|
|
||||||
text-align: right;
|
|
||||||
min-width: 220px;
|
|
||||||
}
|
|
||||||
.invoice-title {
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 23px;
|
font-size: 23px;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
.paid-label {
|
|
||||||
margin-top: 8px;
|
/* Paid / Status */
|
||||||
margin-bottom: 2px;
|
.paid-tag {
|
||||||
}
|
|
||||||
.paid-tag {
|
|
||||||
background: #23BF47;
|
background: #23BF47;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -72,8 +80,9 @@
|
|||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.paid-tag:before {
|
|
||||||
|
.paid-tag:before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 7px;
|
left: 7px;
|
||||||
@@ -82,99 +91,80 @@
|
|||||||
height: 10px;
|
height: 10px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
.paid-date {
|
|
||||||
|
.paid-date {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #23BF47;
|
color: #23BF47;
|
||||||
margin-top: 2px;
|
margin-top: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bill-section {
|
/* ================= REST ================= */
|
||||||
|
|
||||||
|
.bill-section {
|
||||||
background: #F3F7FB;
|
background: #F3F7FB;
|
||||||
border-radius: 11px;
|
border-radius: 11px;
|
||||||
padding: 20px 18px 13px 18px;
|
padding: 20px 18px 13px 18px;
|
||||||
margin: 28px 0 16px 0;
|
margin: 28px 0 16px 0;
|
||||||
box-shadow: 0 0px 0px #0000;
|
}
|
||||||
}
|
|
||||||
.bill-title {
|
.bill-title {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #23355D;
|
color: #23355D;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
letter-spacing: 0.3px;
|
}
|
||||||
}
|
|
||||||
.bill-details {
|
.bill-details {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
margin-bottom: 13px;
|
margin-bottom: 13px;
|
||||||
background: #fff;
|
}
|
||||||
border-radius: 10px;
|
|
||||||
overflow: hidden;
|
th {
|
||||||
}
|
|
||||||
th {
|
|
||||||
background: #F6F7F9;
|
background: #F6F7F9;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #6781A6;
|
color: #6781A6;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border: none;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
td {
|
|
||||||
|
td {
|
||||||
padding: 7px 0;
|
padding: 7px 0;
|
||||||
color: #222;
|
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
border: none;
|
color: #222;
|
||||||
text-align: left;
|
}
|
||||||
}
|
|
||||||
tbody tr:not(:last-child) td {
|
tbody tr:not(:last-child) td {
|
||||||
border-bottom: 1px solid #E6EBF0;
|
border-bottom: 1px solid #E6EBF0;
|
||||||
}
|
}
|
||||||
tbody tr:last-child td {
|
|
||||||
border-bottom: none;
|
.footer {
|
||||||
}
|
|
||||||
.totals-row td {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #23355D;
|
|
||||||
}
|
|
||||||
.gst-row td {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #23BF47;
|
|
||||||
}
|
|
||||||
.total-row td {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 17px;
|
|
||||||
color: #222;
|
|
||||||
}
|
|
||||||
.payment-info {
|
|
||||||
margin-top: 24px;
|
|
||||||
margin-bottom: 9px;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
.ref-number {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #6781A6;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
margin-top: 2px;
|
|
||||||
}
|
|
||||||
.footer {
|
|
||||||
border-top: 1.2px solid #E6EBF0;
|
border-top: 1.2px solid #E6EBF0;
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #888;
|
color: #888;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.footer strong {
|
.gst-row td {
|
||||||
color: #222;
|
color: #23BF47;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.total-row td {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 17px;
|
||||||
|
border-top: 2px solid #E6EBF0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -241,18 +231,47 @@
|
|||||||
<td>{{ number_format($item->ttl_amount, 0) }}</td>
|
<td>{{ number_format($item->ttl_amount, 0) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
{{-- SUBTOTAL --}}
|
||||||
<tr class="totals-row">
|
<tr class="totals-row">
|
||||||
<td colspan="3" style="text-align:right;">Subtotal:</td>
|
<td colspan="3" style="text-align:right;">total</td>
|
||||||
<td>{{ number_format($invoice->subtotal, 0) }}</td>
|
<td style="text-align:right;">
|
||||||
|
₹ {{ number_format($invoice->final_amount, 2) }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
{{-- TAX --}}
|
||||||
|
@if($invoice->tax_type === 'gst' && $invoice->gst_amount > 0)
|
||||||
|
|
||||||
<tr class="gst-row">
|
<tr class="gst-row">
|
||||||
<td colspan="3" style="text-align:right;">GST ({{ $invoice->gst_percent }}%):</td>
|
<td colspan="3" style="text-align:right;">
|
||||||
<td>{{ number_format($invoice->gst_amount, 0) }}</td>
|
GST ({{ $invoice->gst_percent }}%)
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right;">
|
||||||
|
₹ {{ number_format($invoice->gst_amount, 2) }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@elseif($invoice->tax_type === 'igst' && $invoice->gst_amount > 0)
|
||||||
|
|
||||||
|
<tr class="gst-row">
|
||||||
|
<td colspan="3" style="text-align:right;">
|
||||||
|
IGST ({{ $invoice->gst_percent }}%)
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right;">
|
||||||
|
₹ {{ number_format($invoice->gst_amount, 2) }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- TOTAL --}}
|
||||||
<tr class="total-row">
|
<tr class="total-row">
|
||||||
<td colspan="3" style="text-align:right;">Total:</td>
|
<td colspan="3" style="text-align:right;">Total Amount</td>
|
||||||
<td>{{ number_format($invoice->final_amount_with_gst, 0) }}</td>
|
<td style="text-align:right;">
|
||||||
|
₹ {{ number_format($invoice->final_amount_with_gst, 2) }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<!-- Payment Info & Reference -->
|
<!-- Payment Info & Reference -->
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
|
/* ALL YOUR EXISTING CSS STAYS HERE - EXCEPT GST TOTALS SECTION REMOVED */
|
||||||
:root {
|
:root {
|
||||||
--primary: #2c3e50;
|
--primary: #2c3e50;
|
||||||
--secondary: #3498db;
|
--secondary: #3498db;
|
||||||
@@ -284,6 +285,8 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* GST Totals Section Styles - COMPLETELY REMOVED */
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.invoice-container {
|
.invoice-container {
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
@@ -346,6 +349,17 @@
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-container {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -356,6 +370,8 @@
|
|||||||
============================ -->
|
============================ -->
|
||||||
@php
|
@php
|
||||||
$showActions = $showActions ?? true;
|
$showActions = $showActions ?? true;
|
||||||
|
|
||||||
|
// REMOVED GST CALCULATION LOGIC
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="compact-header">
|
<div class="compact-header">
|
||||||
@@ -440,7 +456,6 @@
|
|||||||
<div class="id-value">
|
<div class="id-value">
|
||||||
@php
|
@php
|
||||||
$shipmentId = 'N/A';
|
$shipmentId = 'N/A';
|
||||||
// Try multiple ways to get shipment ID
|
|
||||||
if($invoice->shipment && $invoice->shipment->shipment_id) {
|
if($invoice->shipment && $invoice->shipment->shipment_id) {
|
||||||
$shipmentId = $invoice->shipment->shipment_id;
|
$shipmentId = $invoice->shipment->shipment_id;
|
||||||
} elseif($invoice->shipment_id) {
|
} elseif($invoice->shipment_id) {
|
||||||
@@ -550,62 +565,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php
|
<!-- ============================
|
||||||
$totalAmount = $invoice->final_amount;
|
GST TOTALS SECTION - COMPLETELY REMOVED
|
||||||
$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>
|
|
||||||
|
|
||||||
<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">
|
||||||
|
|
||||||
<a href="{{ route('admin.invoices.download', $invoice->id) }}"
|
<a href="{{ route('admin.invoices.download', $invoice->id) }}"
|
||||||
class="btn btn-primary me-2">
|
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
|
||||||
@@ -614,8 +581,7 @@
|
|||||||
<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>
|
||||||
|
</div> -->
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -624,7 +590,7 @@
|
|||||||
<!-- ============================
|
<!-- ============================
|
||||||
SHARE SCRIPT
|
SHARE SCRIPT
|
||||||
============================ -->
|
============================ -->
|
||||||
<script>
|
<!-- <script>
|
||||||
function shareInvoice() {
|
function shareInvoice() {
|
||||||
const shareData = {
|
const shareData = {
|
||||||
title: "Invoice {{ $invoice->invoice_number }}",
|
title: "Invoice {{ $invoice->invoice_number }}",
|
||||||
@@ -639,7 +605,12 @@
|
|||||||
alert("Link copied! Sharing not supported on this browser.");
|
alert("Link copied! Sharing not supported on this browser.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
|
||||||
|
// Add print functionality
|
||||||
|
function printInvoice() {
|
||||||
|
window.print();
|
||||||
|
}
|
||||||
|
</script> -->
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -333,7 +333,11 @@ a.btn.btn-primary.position-relative .badge {
|
|||||||
box-shadow: 0 0 0 2px #ffffff;
|
box-shadow: 0 0 0 2px #ffffff;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.custom-table th,
|
||||||
|
.custom-table td {
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user