Compare commits
7 Commits
cb24cf575b
...
10af713fa1
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
10af713fa1 | ||
|
|
ebb263cd36 | ||
|
|
82d9c10130 | ||
|
|
e4c07cb838 | ||
|
|
f38a5afdd7 | ||
|
|
82882e859e | ||
|
|
2d28e7c1d5 |
@@ -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;
|
||||||
@@ -484,6 +484,9 @@ tr:hover td{ background:#fbfdff; }
|
|||||||
#entryOrdersModal {
|
#entryOrdersModal {
|
||||||
z-index: 1300;
|
z-index: 1300;
|
||||||
}
|
}
|
||||||
|
#entryOrdersModal {
|
||||||
|
z-index: 1300;
|
||||||
|
}
|
||||||
|
|
||||||
/* entry summary cards */
|
/* entry summary cards */
|
||||||
.entry-summary-cards {
|
.entry-summary-cards {
|
||||||
@@ -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,18 +1750,35 @@ 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>
|
</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>
|
||||||
|
|
||||||
<!-- Installment Modal -->
|
<!-- Installment Modal -->
|
||||||
<div class="modal-fade1" id="installmentModal">
|
<div class="modal-fade1" id="installmentModal">
|
||||||
@@ -2785,8 +3049,15 @@ 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 = `
|
||||||
@@ -2854,7 +3141,6 @@ 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) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user