Pdf Changes Done
This commit is contained in:
@@ -477,7 +477,7 @@
|
||||
}
|
||||
|
||||
/* ── SUMMARY ── */
|
||||
.summary-wrap {
|
||||
/* .summary-wrap {
|
||||
padding: 0 2.5rem 2rem;
|
||||
}
|
||||
|
||||
@@ -516,7 +516,79 @@
|
||||
.summary-row .value { font-weight: 700; color: var(--primary); }
|
||||
.summary-row.total .label { font-size: 1rem; font-weight: 700; color: var(--primary); }
|
||||
.summary-row.total .value { font-size: 1.15rem; color: #10b981; }
|
||||
.summary-row .value.red { color: #ef4444; }
|
||||
.summary-row .value.red { color: #ef4444; } */
|
||||
.summary-card-compact {
|
||||
margin: 1.5rem 2.5rem 1.5rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-lg);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
/* Header full width, curved top corners */
|
||||
.summary-header-compact {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
padding: 0.8rem 1.25rem;
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
border-top-left-radius: var(--radius);
|
||||
border-top-right-radius: var(--radius);
|
||||
}
|
||||
|
||||
/* Icon थोडा highlight */
|
||||
.summary-header-compact i {
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.summary-body-compact {
|
||||
padding: 1rem 1.25rem 0.9rem;
|
||||
}
|
||||
|
||||
.summary-row-compact {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.45rem 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.summary-row-compact:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.summary-row-compact .label {
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.summary-row-compact .value {
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.summary-row-compact.total .label {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.summary-row-compact.total .value {
|
||||
font-size: 1.05rem;
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.summary-row-compact.muted .value {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ── FOOTER ── */
|
||||
.invoice-footer {
|
||||
@@ -653,8 +725,8 @@
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════════════════ ID BOXES ═══════════════════════════ -->
|
||||
<div class="id-grid">
|
||||
<!-- Invoice ID -->
|
||||
<!-- <div class="id-grid">
|
||||
|
||||
<div class="id-box">
|
||||
<div class="id-icon-wrap id-icon-blue">
|
||||
<i class="fas fa-receipt"></i>
|
||||
@@ -663,10 +735,10 @@
|
||||
<div class="id-label">Invoice ID</div>
|
||||
<div class="id-value">{{ $invoice->invoice_number }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- Container ID -->
|
||||
<div class="id-box">
|
||||
<!-- <div class="id-box">
|
||||
<div class="id-icon-wrap id-icon-green">
|
||||
<i class="fas fa-box"></i>
|
||||
</div>
|
||||
@@ -684,25 +756,56 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- ═══════════════════════════ DATES ═══════════════════════════ -->
|
||||
<div class="date-strip">
|
||||
<!-- ═══════════════════════════ ID + DATES (ONE ROW) ═══════════════════════════ -->
|
||||
<!-- <div class="date-strip">
|
||||
<div class="date-row">
|
||||
|
||||
{{-- Container ID --}}
|
||||
<div class="date-card" style="flex: 1.2;">
|
||||
<div class="date-icon-wrap" style="background:#ecfeff;color:#0e7490;">
|
||||
<i class="fas fa-box"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="date-label">Container ID</div>
|
||||
<div class="date-value">
|
||||
@if($invoice->container && $invoice->container->container_number)
|
||||
{{ $invoice->container->container_number }}
|
||||
@elseif($invoice->container_id)
|
||||
{{ $invoice->container_id }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- छोटा arrow --}}
|
||||
<div class="date-arrow">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</div>
|
||||
|
||||
{{-- Invoice Date --}}
|
||||
<div class="date-card">
|
||||
<div class="date-icon-wrap">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="date-label">Invoice Date</div>
|
||||
<div class="date-value">{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}</div>
|
||||
<div class="date-value">
|
||||
{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- दुसरा arrow --}}
|
||||
<div class="date-arrow">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</div>
|
||||
|
||||
{{-- Due Date --}}
|
||||
<div class="date-card">
|
||||
<div class="date-icon-wrap" style="background:#fff7ed;color:#f59e0b;">
|
||||
<i class="fas fa-clock"></i>
|
||||
@@ -714,8 +817,74 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
|
||||
<!-- ═══════════════════════════ CONTAINER + INVOICE DATE + DUE DATE (ONE ROW) ═══════════════════════════ -->
|
||||
<div class="date-strip">
|
||||
<div class="date-row">
|
||||
|
||||
{{-- Container ID --}}
|
||||
<div class="date-card" style="flex: 1.2;">
|
||||
<div class="date-icon-wrap" style="background:#ecfeff;color:#0e7490;">
|
||||
<i class="fas fa-box"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="date-label">Container ID</div>
|
||||
<div class="date-value">
|
||||
@if($invoice->container && $invoice->container->container_number)
|
||||
{{ $invoice->container->container_number }}
|
||||
@elseif($invoice->container_id)
|
||||
{{ $invoice->container_id }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- छोटा arrow --}}
|
||||
<div class="date-arrow">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</div>
|
||||
|
||||
{{-- Invoice Date --}}
|
||||
<div class="date-card">
|
||||
<div class="date-icon-wrap">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="date-label">Invoice Date</div>
|
||||
<div class="date-value">
|
||||
{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- दुसरा arrow --}}
|
||||
<div class="date-arrow">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</div>
|
||||
|
||||
{{-- Due Date --}}
|
||||
<div class="date-card">
|
||||
<div class="date-icon-wrap" style="background:#fff7ed;color:#f59e0b;">
|
||||
<i class="fas fa-clock"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="date-label">Due Date</div>
|
||||
<div class="date-value {{ $invoice->status == 'overdue' ? 'overdue' : '' }}">
|
||||
{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ═══════════════════════════ CUSTOMER ═══════════════════════════ -->
|
||||
<div class="panel">
|
||||
@@ -758,82 +927,83 @@
|
||||
@endif -->
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="invoice-table items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center" style="width:44px;">
|
||||
<input type="checkbox" id="selectAllItems">
|
||||
</th>
|
||||
<th class="text-center" style="min-width:50px;">#</th>
|
||||
<th style="min-width:200px;">Description</th>
|
||||
<th class="text-center" style="min-width:75px;">CTN</th>
|
||||
<th class="text-center" style="min-width:75px;">QTY</th>
|
||||
<th class="text-center" style="min-width:95px;">TTL/QTY</th>
|
||||
<th class="text-center" style="min-width:75px;">Unit</th>
|
||||
<th class="text-center" style="min-width:110px;">Price</th>
|
||||
<th class="text-center" style="min-width:125px;">TTL Amount</th>
|
||||
<th class="text-center" style="min-width:85px;">CBM</th>
|
||||
<th class="text-center" style="min-width:95px;">TTL CBM</th>
|
||||
<th class="text-center" style="min-width:80px;">KG</th>
|
||||
<th class="text-center" style="min-width:95px;">TTL KG</th>
|
||||
<th class="text-center" style="min-width:95px;">Shop No</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($invoice->items as $i => $item)
|
||||
@php
|
||||
$alreadyGrouped = in_array($item->id, $groupedItemIds ?? []);
|
||||
@endphp
|
||||
<tr class="{{ $alreadyGrouped ? 'grouped-item-row' : '' }}">
|
||||
<td class="text-center">
|
||||
<input type="checkbox"
|
||||
class="item-select-checkbox"
|
||||
value="{{ $item->id }}"
|
||||
{{ $alreadyGrouped ? 'disabled' : '' }}>
|
||||
</td>
|
||||
<td class="text-center" style="font-weight:600;color:var(--text-muted);">{{ $i + 1 }}</td>
|
||||
<td class="desc-col" style="font-weight:600;color:var(--primary);">{{ $item->description }}</td>
|
||||
<td class="text-center">{{ $item->ctn }}</td>
|
||||
<td class="text-center">{{ $item->qty }}</td>
|
||||
<td class="text-center" style="font-weight:700;">{{ $item->ttl_qty }}</td>
|
||||
<td class="text-center">{{ $item->unit }}</td>
|
||||
<table class="invoice-table items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center" style="width:44px;">
|
||||
<input type="checkbox" id="selectAllItems">
|
||||
</th>
|
||||
<th class="text-center" style="min-width:50px;">#</th>
|
||||
<th style="min-width:200px;">Description</th>
|
||||
<th class="text-center" style="min-width:75px;">CTN</th>
|
||||
<th class="text-center" style="min-width:75px;">QTY</th>
|
||||
<th class="text-center" style="min-width:95px;">TTL/QTY</th>
|
||||
<th class="text-center" style="min-width:75px;">Unit</th>
|
||||
<th class="text-center" style="min-width:110px;">Price</th>
|
||||
<th class="text-center" style="min-width:125px;">TTL Amount</th>
|
||||
<th class="text-center" style="min-width:85px;">CBM</th>
|
||||
<th class="text-center" style="min-width:95px;">TTL CBM</th>
|
||||
<th class="text-center" style="min-width:80px;">KG</th>
|
||||
<th class="text-center" style="min-width:95px;">TTL KG</th>
|
||||
<th class="text-center" style="min-width:95px;">Shop No</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($invoice->items as $i => $item)
|
||||
@php
|
||||
$alreadyGrouped = in_array($item->id, $groupedItemIds ?? []);
|
||||
@endphp
|
||||
<tr class="{{ $alreadyGrouped ? 'grouped-item-row' : '' }}">
|
||||
<td class="text-center">
|
||||
<input type="checkbox"
|
||||
class="item-select-checkbox"
|
||||
name="item_ids[]"
|
||||
value="{{ $item->id }}"
|
||||
{{ $alreadyGrouped ? 'disabled' : '' }}>
|
||||
</td>
|
||||
<td class="text-center" style="font-weight:600;color:var(--text-muted);">{{ $i + 1 }}</td>
|
||||
<td class="desc-col" style="font-weight:600;color:var(--primary);">{{ $item->description }}</td>
|
||||
<td class="text-center">{{ $item->ctn }}</td>
|
||||
<td class="text-center">{{ $item->qty }}</td>
|
||||
<td class="text-center" style="font-weight:700;">{{ $item->ttl_qty }}</td>
|
||||
<td class="text-center">{{ $item->unit }}</td>
|
||||
|
||||
@if($isEmbedded)
|
||||
<td class="text-center" style="min-width:120px;">
|
||||
<input type="number" step="0.01" min="0"
|
||||
name="items[{{ $item->id }}][price]"
|
||||
value="{{ old('items.' . $item->id . '.price', $item->price) }}"
|
||||
class="form-control form-control-sm text-end">
|
||||
</td>
|
||||
<td class="text-center" style="min-width:140px;">
|
||||
<input type="number" step="0.01" min="0"
|
||||
name="items[{{ $item->id }}][ttl_amount]"
|
||||
value="{{ old('items.' . $item->id . '.ttl_amount', $item->ttl_amount) }}"
|
||||
class="form-control form-control-sm text-end">
|
||||
</td>
|
||||
@else
|
||||
<td class="text-center price-green">₹{{ number_format($item->price, 2) }}</td>
|
||||
<td class="text-center price-blue">₹{{ number_format($item->ttl_amount, 2) }}</td>
|
||||
@endif
|
||||
|
||||
<td class="text-center">{{ $item->cbm }}</td>
|
||||
<td class="text-center">{{ $item->ttl_cbm }}</td>
|
||||
<td class="text-center">{{ $item->kg }}</td>
|
||||
<td class="text-center">{{ $item->ttl_kg }}</td>
|
||||
<td class="text-center"><span class="badge-shop">{{ $item->shop_no }}</span></td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@if($invoice->items->isEmpty())
|
||||
<tr>
|
||||
<td colspan="15" class="text-center py-4" style="color:var(--text-muted);font-weight:600;">
|
||||
<i class="fas fa-inbox me-2" style="font-size:1.3rem;opacity:.4;"></i><br>No invoice items found.
|
||||
</td>
|
||||
</tr>
|
||||
@if($isEmbedded)
|
||||
<td class="text-center" style="min-width:120px;">
|
||||
<input type="number" step="0.01" min="0"
|
||||
name="items[{{ $item->id }}][price]"
|
||||
value="{{ old('items.' . $item->id . '.price', $item->price) }}"
|
||||
class="form-control form-control-sm text-end">
|
||||
</td>
|
||||
<td class="text-center" style="min-width:140px;">
|
||||
<input type="number" step="0.01" min="0"
|
||||
name="items[{{ $item->id }}][ttl_amount]"
|
||||
value="{{ old('items.' . $item->id . '.ttl_amount', $item->ttl_amount) }}"
|
||||
class="form-control form-control-sm text-end">
|
||||
</td>
|
||||
@else
|
||||
<td class="text-center price-green">₹{{ number_format($item->price, 2) }}</td>
|
||||
<td class="text-center price-blue">₹{{ number_format($item->ttl_amount, 2) }}</td>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<td class="text-center">{{ $item->cbm }}</td>
|
||||
<td class="text-center">{{ $item->ttl_cbm }}</td>
|
||||
<td class="text-center">{{ $item->kg }}</td>
|
||||
<td class="text-center">{{ $item->ttl_kg }}</td>
|
||||
<td class="text-center"><span class="badge-shop">{{ $item->shop_no }}</span></td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@if($invoice->items->isEmpty())
|
||||
<tr>
|
||||
<td colspan="15" class="text-center py-4" style="color:var(--text-muted);font-weight:600;">
|
||||
<i class="fas fa-inbox me-2" style="font-size:1.3rem;opacity:.4;"></i><br>No invoice items found.
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- ACTION BAR -->
|
||||
<div class="action-bar">
|
||||
@@ -1065,7 +1235,7 @@
|
||||
@endif
|
||||
|
||||
<!-- ═══════════════════════════ SUMMARY ═══════════════════════════ -->
|
||||
<div class="summary-wrap">
|
||||
<!-- <div class="summary-wrap">
|
||||
<div class="row justify-content-end">
|
||||
<div class="col-md-5">
|
||||
<div class="summary-card">
|
||||
@@ -1107,8 +1277,70 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
{{-- ===== FINAL SUMMARY (POPUP) ===== --}}
|
||||
<div class="summary-card-compact mt-3">
|
||||
<div class="summary-header-compact">
|
||||
<i class="fas fa-calculator"></i>
|
||||
<span>Final Summary</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-body-compact">
|
||||
@if($invoice->tax_type === 'gst')
|
||||
<div class="summary-row-compact">
|
||||
<span class="label">
|
||||
CGST {{ $invoice->cgst_percent ?? $invoice->gst_percent / 2 }}%
|
||||
</span>
|
||||
<span class="value red">
|
||||
₹{{ number_format($invoice->gst_amount / 2, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="summary-row-compact">
|
||||
<span class="label">
|
||||
SGST {{ $invoice->sgst_percent ?? $invoice->gst_percent / 2 }}%
|
||||
</span>
|
||||
<span class="value red">
|
||||
₹{{ number_format($invoice->gst_amount / 2, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
@elseif($invoice->tax_type === 'igst')
|
||||
<div class="summary-row-compact">
|
||||
<span class="label">
|
||||
IGST {{ $invoice->igst_percent ?? $invoice->gst_percent }}%
|
||||
</span>
|
||||
<span class="value red">
|
||||
₹{{ number_format($invoice->gst_amount, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
@else
|
||||
<div class="summary-row-compact">
|
||||
<span class="label">
|
||||
GST {{ $invoice->gst_percent }}%
|
||||
</span>
|
||||
<span class="value red">
|
||||
₹{{ number_format($invoice->gst_amount, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="summary-row-compact">
|
||||
<span class="label">Charge Groups Total</span>
|
||||
<span class="value">
|
||||
₹{{ number_format($invoice->charge_groups_total, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- <div class="summary-row-compact total">
|
||||
<span class="label">Grand Total (Items + GST + Groups)</span>
|
||||
<span class="value">
|
||||
₹{{ number_format($invoice->grand_total_with_charges, 2) }}
|
||||
</span>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ═══════════════════════════ FOOTER ═══════════════════════════ -->
|
||||
<div class="invoice-footer">
|
||||
@if($invoice->pdf_path && $showActions)
|
||||
@@ -1125,31 +1357,52 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
function shareInvoice() {
|
||||
const shareData = {
|
||||
title: "Invoice {{ $invoice->invoice_number }}",
|
||||
text: "Sharing invoice {{ $invoice->invoice_number }}",
|
||||
url: "{{ asset($invoice->pdf_path) }}"
|
||||
};
|
||||
if (navigator.share) {
|
||||
navigator.share(shareData).catch(() => {});
|
||||
} else {
|
||||
navigator.clipboard.writeText(shareData.url);
|
||||
alert("Link copied! Sharing not supported on this browser.");
|
||||
}
|
||||
function shareInvoice() {
|
||||
const shareData = {
|
||||
title: "Invoice {{ $invoice->invoice_number }}",
|
||||
text: "Sharing invoice {{ $invoice->invoice_number }}",
|
||||
url: "{{ asset($invoice->pdf_path) }}"
|
||||
};
|
||||
if (navigator.share) {
|
||||
navigator.share(shareData).catch(() => {});
|
||||
} else {
|
||||
navigator.clipboard.writeText(shareData.url);
|
||||
alert("Link copied! Sharing not supported on this browser.");
|
||||
}
|
||||
}
|
||||
|
||||
function renumberChargeGroups() {
|
||||
const groupsTbody = document.querySelector(
|
||||
'.cg-groups-panel table.invoice-table tbody'
|
||||
);
|
||||
if (!groupsTbody) return;
|
||||
|
||||
let index = 1;
|
||||
|
||||
groupsTbody.querySelectorAll('tr').forEach(row => {
|
||||
if (row.classList.contains('cg-items-row')) return;
|
||||
|
||||
const next = row.nextElementSibling;
|
||||
const isMainGroupRow = next && next.classList.contains('cg-items-row');
|
||||
if (!isMainGroupRow) return;
|
||||
|
||||
const firstCell = row.querySelector('td:first-child');
|
||||
if (firstCell) {
|
||||
firstCell.textContent = index++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const selectAll = document.getElementById('selectAllItems');
|
||||
const itemCheckboxes = document.querySelectorAll('.item-select-checkbox');
|
||||
const countSpan = document.getElementById('selectedItemsCount');
|
||||
const btnCreate = document.getElementById('btnCreateChargeGroup');
|
||||
const selectAll = document.getElementById('selectAllItems');
|
||||
const itemCheckboxes = document.querySelectorAll('.item-select-checkbox');
|
||||
const countSpan = document.getElementById('selectedItemsCount');
|
||||
const btnCreate = document.getElementById('btnCreateChargeGroup');
|
||||
|
||||
const chargeGroupBox = document.getElementById('chargeGroupBox');
|
||||
const cgCancelBtn = document.getElementById('cgCancelBtn');
|
||||
const chargeGroupBox = document.getElementById('chargeGroupBox');
|
||||
const cgCancelBtn = document.getElementById('cgCancelBtn');
|
||||
|
||||
const cgItemsTableBody = document.getElementById('cgItemsTableBody');
|
||||
const cgBasisSelect = document.getElementById('cgBasis');
|
||||
@@ -1166,6 +1419,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const cgRateHidden = document.getElementById('cgRateHidden');
|
||||
const cgForm = document.getElementById('chargeGroupForm');
|
||||
|
||||
const cgGroupName = document.getElementById('cgGroupName');
|
||||
|
||||
function updateSelectionState() {
|
||||
let selectedCount = 0;
|
||||
itemCheckboxes.forEach(cb => {
|
||||
@@ -1188,13 +1443,13 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
row.querySelector(`td:nth-child(${n})`)?.textContent.trim() ?? '';
|
||||
items.push({
|
||||
description: cellText(3),
|
||||
qty: cellText(5),
|
||||
ttlqty: cellText(6),
|
||||
cbm: cellText(10),
|
||||
ttlcbm: cellText(11),
|
||||
kg: cellText(12),
|
||||
ttlkg: cellText(13),
|
||||
amount: cellText(9),
|
||||
qty: cellText(5),
|
||||
ttlqty: cellText(6),
|
||||
cbm: cellText(10),
|
||||
ttlcbm: cellText(11),
|
||||
kg: cellText(12),
|
||||
ttlkg: cellText(13),
|
||||
amount: cellText(9),
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1258,8 +1513,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (cgRateHidden && cgRateInput) cgRateHidden.value = cgRateInput.value || 0;
|
||||
if (cgAutoTotalInput) cgAutoTotalInput.value = suggested || 0;
|
||||
if (cgTotalChargeInput) {
|
||||
cgTotalChargeInput.value = suggested ? suggested.toFixed(2) : '0';
|
||||
}
|
||||
cgTotalChargeInput.value = suggested ? suggested.toFixed(2) : '0';
|
||||
}
|
||||
}
|
||||
|
||||
itemCheckboxes.forEach(cb => {
|
||||
@@ -1271,7 +1526,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
selectAll.checked = (checked > 0 && checked === total);
|
||||
selectAll.indeterminate = (checked > 0 && checked < total);
|
||||
}
|
||||
if (!chargeGroupBox.classList.contains('d-none')) {
|
||||
if (chargeGroupBox && !chargeGroupBox.classList.contains('d-none')) {
|
||||
fillChargeGroupItemsTable();
|
||||
refreshBasisSummaryAndSuggestion();
|
||||
}
|
||||
@@ -1282,7 +1537,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
selectAll.addEventListener('change', function () {
|
||||
itemCheckboxes.forEach(cb => { if (!cb.disabled) cb.checked = selectAll.checked; });
|
||||
updateSelectionState();
|
||||
if (!chargeGroupBox.classList.contains('d-none')) {
|
||||
if (chargeGroupBox && !chargeGroupBox.classList.contains('d-none')) {
|
||||
fillChargeGroupItemsTable();
|
||||
refreshBasisSummaryAndSuggestion();
|
||||
}
|
||||
@@ -1312,244 +1567,65 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
});
|
||||
}
|
||||
|
||||
// MAIN CHANGE: normal form submit, फक्त hidden item_ids तयार करतो
|
||||
if (cgForm) {
|
||||
cgForm.addEventListener('submit', function (e) {
|
||||
// Stop normal form submit (no page reload)
|
||||
e.preventDefault();
|
||||
|
||||
// 1) Collect selected item IDs
|
||||
const selectedIds = [];
|
||||
itemCheckboxes.forEach(cb => {
|
||||
if (cb.checked && !cb.disabled) {
|
||||
selectedIds.push(cb.value);
|
||||
}
|
||||
});
|
||||
|
||||
// 2) Frontend validations (same as before)
|
||||
if (selectedIds.length === 0) {
|
||||
alert('Please select at least one item for this charge group.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cgBasisSelect || !cgBasisSelect.value) {
|
||||
alert('Please select a basis for this charge group.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!cgTotalChargeInput ||
|
||||
!cgTotalChargeInput.value ||
|
||||
parseFloat(cgTotalChargeInput.value) <= 0
|
||||
) {
|
||||
alert('Please enter total charges for this group.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) Remove previously added hidden item_ids[]
|
||||
const oldHidden = cgForm.querySelectorAll('input[name="item_ids[]"]');
|
||||
oldHidden.forEach(el => el.remove());
|
||||
|
||||
// 4) Add fresh hidden item_ids[] for current selection
|
||||
selectedIds.forEach(id => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'item_ids[]';
|
||||
input.value = id;
|
||||
cgForm.appendChild(input);
|
||||
});
|
||||
|
||||
// 5) Build AJAX request
|
||||
const url = cgForm.action;
|
||||
const formData = new FormData(cgForm);
|
||||
|
||||
// Optional: disable save button while processing
|
||||
if (cgSaveBtn) {
|
||||
cgSaveBtn.disabled = true;
|
||||
cgSaveBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Saving...';
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
throw new Error('Request failed with status ' + res.status);
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
throw new Error(data.message || 'Failed to create charge group.');
|
||||
}
|
||||
|
||||
const group = data.group;
|
||||
|
||||
// 6) Append new group main row + hidden items row
|
||||
const groupsTbody = document.querySelector(
|
||||
'.cg-groups-panel table.invoice-table tbody'
|
||||
);
|
||||
|
||||
if (groupsTbody && group) {
|
||||
const currentMainRows = groupsTbody.querySelectorAll(
|
||||
'tr:not(.cg-items-row)'
|
||||
).length;
|
||||
const index = currentMainRows + 1;
|
||||
|
||||
// Main summary row (same structure as Blade)
|
||||
const mainRow = document.createElement('tr');
|
||||
mainRow.innerHTML = `
|
||||
<td>${index}</td>
|
||||
<td style="font-weight:600;">
|
||||
${group.group_name ? group.group_name : 'Group #' + group.id}
|
||||
</td>
|
||||
<td>
|
||||
<span style="text-transform:uppercase;font-size:0.75rem;font-weight:700;color:var(--text-muted);">
|
||||
${group.basis_type}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end" style="font-family:'JetBrains Mono',monospace;font-size:0.82rem;">
|
||||
${Number(group.basis_value).toFixed(3)}
|
||||
</td>
|
||||
<td class="text-end" style="font-family:'JetBrains Mono',monospace;font-size:0.82rem;">
|
||||
${Number(group.rate).toFixed(2)}
|
||||
</td>
|
||||
<td class="text-end price-blue">
|
||||
${Number(group.total_charge).toFixed(2)}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<button type="button"
|
||||
class="cg-toggle-btn cg-toggle-items"
|
||||
data-group-id="${group.id}">
|
||||
<i class="fas fa-eye"></i> View
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
|
||||
// Hidden items row (same idea as Blade .cg-items-row)
|
||||
const itemsRow = document.createElement('tr');
|
||||
itemsRow.className = 'cg-items-row d-none';
|
||||
itemsRow.setAttribute('data-group-id', group.id);
|
||||
|
||||
let itemsTableHtml = `
|
||||
<div style="padding:1rem;background:#f8faff;border-radius:8px;margin:0.25rem 0;">
|
||||
<div style="font-weight:700;font-size:0.8rem;margin-bottom:0.6rem;color:var(--primary);">
|
||||
Items in this group
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (!group.items || group.items.length === 0) {
|
||||
itemsTableHtml += `
|
||||
<div style="color:var(--text-muted);font-size:0.82rem;">
|
||||
No items linked.
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
itemsTableHtml += `
|
||||
<div class="table-responsive">
|
||||
<table class="invoice-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Description</th>
|
||||
<th class="text-center">QTY</th>
|
||||
<th class="text-center">TTL QTY</th>
|
||||
<th class="text-center">CBM</th>
|
||||
<th class="text-center">TTL CBM</th>
|
||||
<th class="text-center">KG</th>
|
||||
<th class="text-center">TTL KG</th>
|
||||
<th class="text-end">TTL Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
group.items.forEach((it, idx) => {
|
||||
itemsTableHtml += `
|
||||
<tr>
|
||||
<td>${idx + 1}</td>
|
||||
<td>${it.description ?? ''}</td>
|
||||
<td class="text-center">${it.qty ?? ''}</td>
|
||||
<td class="text-center">${it.ttlqty ?? ''}</td>
|
||||
<td class="text-center">${it.cbm ?? ''}</td>
|
||||
<td class="text-center">${it.ttlcbm ?? ''}</td>
|
||||
<td class="text-center">${it.kg ?? ''}</td>
|
||||
<td class="text-center">${it.ttlkg ?? ''}</td>
|
||||
<td class="text-end">${Number(it.amount ?? 0).toFixed(2)}</td>
|
||||
</tr>
|
||||
`;
|
||||
cgForm.addEventListener('submit', function () {
|
||||
const selectedIds = [];
|
||||
itemCheckboxes.forEach(cb => {
|
||||
if (cb.checked && !cb.disabled) {
|
||||
selectedIds.push(cb.value);
|
||||
}
|
||||
});
|
||||
|
||||
itemsTableHtml += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
itemsTableHtml += `</div>`;
|
||||
|
||||
itemsRow.innerHTML = `
|
||||
<td colspan="7">
|
||||
${itemsTableHtml}
|
||||
</td>
|
||||
`;
|
||||
|
||||
// Append main row + items row in order
|
||||
groupsTbody.appendChild(mainRow);
|
||||
groupsTbody.appendChild(itemsRow);
|
||||
}
|
||||
|
||||
// 7) Reset Charge Group UI (hide panel, uncheck items)
|
||||
if (chargeGroupBox) {
|
||||
chargeGroupBox.classList.add('d-none');
|
||||
}
|
||||
itemCheckboxes.forEach(cb => {
|
||||
if (!cb.disabled) cb.checked = false;
|
||||
});
|
||||
if (selectAll) {
|
||||
selectAll.checked = false;
|
||||
selectAll.indeterminate = false;
|
||||
}
|
||||
updateSelectionState();
|
||||
|
||||
// Optional: clear form
|
||||
if (cgGroupName) cgGroupName.value = '';
|
||||
if (cgBasisSelect) cgBasisSelect.value = '';
|
||||
if (cgRateInput) cgRateInput.value = '';
|
||||
if (cgBasisValueSpan) cgBasisValueSpan.textContent = '0';
|
||||
if (cgBasisLabelSpan) cgBasisLabelSpan.textContent = '–';
|
||||
if (cgSuggestedTotalSpan) cgSuggestedTotalSpan.textContent = '0';
|
||||
if (cgTotalChargeInput) cgTotalChargeInput.value = '';
|
||||
})
|
||||
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('Error creating charge group. Please try again.');
|
||||
})
|
||||
.finally(() => {
|
||||
if (cgSaveBtn) {
|
||||
cgSaveBtn.disabled = false;
|
||||
cgSaveBtn.innerHTML = '<i class="fas fa-save"></i> Save Charge Group';
|
||||
if (selectedIds.length === 0) {
|
||||
alert('Please select at least one item for this charge group.');
|
||||
// default submit रोखण्यासाठी return false
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cgBasisSelect || !cgBasisSelect.value) {
|
||||
alert('Please select a basis for this charge group.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cgTotalChargeInput ||
|
||||
!cgTotalChargeInput.value ||
|
||||
parseFloat(cgTotalChargeInput.value) <= 0
|
||||
) {
|
||||
alert('Please enter total charges for this group.');
|
||||
return false;
|
||||
}
|
||||
|
||||
const oldHidden = cgForm.querySelectorAll('input[name="item_ids[]"]');
|
||||
oldHidden.forEach(el => el.remove());
|
||||
|
||||
selectedIds.forEach(id => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'item_ids[]';
|
||||
input.value = id;
|
||||
cgForm.appendChild(input);
|
||||
});
|
||||
|
||||
// इथे e.preventDefault नाही; normal submit होऊ दे
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateSelectionState();
|
||||
});
|
||||
|
||||
// View/Hide group items
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.addEventListener('click', function (e) {
|
||||
if (!e.target.classList.contains('cg-toggle-items') &&
|
||||
!e.target.closest('.cg-toggle-items')) return;
|
||||
|
||||
const btn = e.target.closest('.cg-toggle-items') || e.target;
|
||||
const groupId = btn.getAttribute('data-group-id');
|
||||
const row = document.querySelector('.cg-items-row[data-group-id="' + groupId + '"]');
|
||||
if (!row) return;
|
||||
|
||||
row.classList.toggle('d-none');
|
||||
const isHidden = row.classList.contains('d-none');
|
||||
btn.innerHTML = isHidden
|
||||
@@ -1557,6 +1633,25 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
: '<i class="fas fa-eye-slash"></i> Hide';
|
||||
});
|
||||
});
|
||||
|
||||
// simple select all (duplicate राहिला तरी harmless; गरज असल्यास काढू शकतो)
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const selectAll = document.getElementById('selectAllItems');
|
||||
const checkboxes = document.querySelectorAll('.item-select-checkbox');
|
||||
|
||||
if (selectAll) {
|
||||
selectAll.addEventListener('change', function () {
|
||||
checkboxes.forEach(cb => {
|
||||
if (!cb.disabled) {
|
||||
cb.checked = selectAll.checked;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user