863 lines
32 KiB
PHP
863 lines
32 KiB
PHP
@extends('admin.layouts.app')
|
||
|
||
@section('page-title', 'Edit Invoice')
|
||
|
||
@section('content')
|
||
<style>
|
||
:root {
|
||
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
--success-gradient: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||
--warning-gradient: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
||
--danger-gradient: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||
--glass-bg: rgba(255, 255, 255, 0.95);
|
||
--glass-border: rgba(255, 255, 255, 0.2);
|
||
--shadow-soft: 0 8px 32px rgba(0, 0, 0, 0.08);
|
||
--shadow-medium: 0 12px 48px rgba(0, 0, 0, 0.12);
|
||
--shadow-strong: 0 20px 60px rgba(0, 0, 0, 0.15);
|
||
--border-radius: 12px;
|
||
}
|
||
|
||
body {
|
||
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
|
||
font-family: "Inter", "Segoe UI", system-ui, sans-serif;
|
||
}
|
||
|
||
@keyframes fadeUp {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateY(20px) scale(0.98);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateY(0) scale(1);
|
||
}
|
||
}
|
||
|
||
.glass-card {
|
||
background: var(--glass-bg);
|
||
backdrop-filter: blur(20px);
|
||
border-radius: var(--border-radius);
|
||
border: 1px solid var(--glass-border);
|
||
box-shadow: var(--shadow-strong);
|
||
position: relative;
|
||
overflow: hidden;
|
||
animation: fadeUp 0.6s ease;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.glass-card::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(
|
||
45deg,
|
||
rgba(102, 126, 234, 0.03),
|
||
rgba(118, 75, 162, 0.03) 50%,
|
||
rgba(16, 185, 129, 0.03)
|
||
);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.card-header-compact {
|
||
background: var(--primary-gradient);
|
||
color: #fff;
|
||
padding: 1rem 1.5rem;
|
||
border: none;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.card-header-compact h4 {
|
||
margin: 0;
|
||
font-weight: 700;
|
||
font-size: 1.3rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.card-body-compact {
|
||
padding: 1.5rem;
|
||
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.form-grid-compact {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||
gap: 1rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.form-group-compact {
|
||
position: relative;
|
||
}
|
||
|
||
.form-label-compact {
|
||
font-weight: 600;
|
||
color: #374151;
|
||
margin-bottom: 8px;
|
||
font-size: 0.9rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.form-control-compact,
|
||
.form-select-compact {
|
||
border: 2px solid #e2e8f0;
|
||
border-radius: 8px;
|
||
padding: 10px 12px;
|
||
font-size: 0.9rem;
|
||
transition: all 0.3s ease;
|
||
background: #ffffff;
|
||
width: 100%;
|
||
}
|
||
|
||
.form-control-compact:focus,
|
||
.form-select-compact:focus {
|
||
border-color: #667eea;
|
||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
||
outline: none;
|
||
}
|
||
|
||
.btn-compact {
|
||
padding: 10px 20px;
|
||
border-radius: 8px;
|
||
font-weight: 600;
|
||
font-size: 0.9rem;
|
||
transition: all 0.3s ease;
|
||
border: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.btn-success-compact {
|
||
background: var(--success-gradient);
|
||
color: white;
|
||
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
|
||
}
|
||
|
||
.btn-success-compact:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 20px rgba(16, 185, 129, 0.4);
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary-compact {
|
||
background: var(--primary-gradient);
|
||
color: white;
|
||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
||
}
|
||
|
||
.btn-primary-compact:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
|
||
color: white;
|
||
}
|
||
|
||
.btn-danger-compact {
|
||
background: var(--danger-gradient);
|
||
color: white;
|
||
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
|
||
}
|
||
|
||
.btn-danger-compact:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 20px rgba(239, 68, 68, 0.4);
|
||
color: white;
|
||
}
|
||
|
||
.summary-grid-compact {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 1rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.summary-card-compact {
|
||
background: #ffffff;
|
||
padding: 1rem;
|
||
border-radius: 8px;
|
||
box-shadow: var(--shadow-soft);
|
||
border-left: 4px solid;
|
||
text-align: center;
|
||
}
|
||
|
||
.summary-card-compact.total {
|
||
border-left-color: #10b981;
|
||
}
|
||
|
||
.summary-card-compact.paid {
|
||
border-left-color: #3b82f6;
|
||
}
|
||
|
||
.summary-card-compact.remaining {
|
||
border-left-color: #f59e0b;
|
||
}
|
||
|
||
.summary-value-compact {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.summary-label-compact {
|
||
font-size: 0.8rem;
|
||
color: #64748b;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
.amount-breakdown-compact {
|
||
background: #ffffff;
|
||
padding: 1rem;
|
||
border-radius: 8px;
|
||
box-shadow: var(--shadow-soft);
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.breakdown-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 0.5rem 0;
|
||
border-bottom: 1px solid #f1f5f9;
|
||
}
|
||
|
||
.breakdown-row:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.breakdown-label {
|
||
font-weight: 600;
|
||
color: #374151;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.breakdown-value {
|
||
font-weight: 600;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.table-compact {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-bottom: 0;
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.table-compact thead th {
|
||
background: var(--primary-gradient);
|
||
color: #ffffff;
|
||
padding: 0.75rem 1rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
font-size: 0.8rem;
|
||
border: none;
|
||
}
|
||
|
||
.table-compact tbody tr {
|
||
background: #ffffff;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.table-compact tbody tr:hover {
|
||
background: #f8fafc;
|
||
}
|
||
|
||
.table-compact tbody td {
|
||
padding: 0.75rem 1rem;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.badge-compact {
|
||
padding: 0.25rem 0.75rem;
|
||
border-radius: 20px;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.glass-card {
|
||
margin: 0.5rem;
|
||
border-radius: 10px;
|
||
}
|
||
.card-body-compact {
|
||
padding: 1rem;
|
||
}
|
||
.form-grid-compact {
|
||
grid-template-columns: 1fr;
|
||
gap: 0.75rem;
|
||
}
|
||
.summary-grid-compact {
|
||
grid-template-columns: 1fr;
|
||
gap: 0.75rem;
|
||
}
|
||
.btn-compact {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
.table-compact {
|
||
font-size: 0.8rem;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<div class="container-fluid py-3">
|
||
{{-- Invoice Overview --}}
|
||
<div class="glass-card">
|
||
<div class="card-header-compact">
|
||
<h4>
|
||
<i class="fas fa-file-invoice me-2"></i>
|
||
Invoice Overview
|
||
</h4>
|
||
</div>
|
||
<div class="card-body-compact">
|
||
@include('admin.popup_invoice', ['invoice' => $invoice, 'shipment' => $shipment])
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Edit Invoice Header --}}
|
||
<div class="glass-card">
|
||
<div class="card-header-compact">
|
||
<h4>
|
||
<i class="fas fa-edit me-2"></i>
|
||
Edit Invoice Details
|
||
</h4>
|
||
</div>
|
||
<div class="card-body-compact">
|
||
<form action="{{ route('admin.invoices.update', $invoice->id) }}" method="POST">
|
||
@csrf
|
||
|
||
<div class="form-grid-compact">
|
||
{{-- Invoice Date --}}
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-calendar-day"></i> Invoice Date
|
||
</label>
|
||
<input type="date"
|
||
name="invoice_date"
|
||
class="form-control-compact"
|
||
value="{{ old('invoice_date', $invoice->invoice_date) }}"
|
||
required>
|
||
</div>
|
||
|
||
{{-- Due Date --}}
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-clock"></i> Due Date
|
||
</label>
|
||
<input type="date"
|
||
name="due_date"
|
||
class="form-control-compact"
|
||
value="{{ old('due_date', $invoice->due_date) }}"
|
||
required>
|
||
</div>
|
||
|
||
{{-- Final Amount (With GST) – Charge Groups Total --}}
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-money-bill-wave"></i> Final Amount (With GST)
|
||
</label>
|
||
<input type="number"
|
||
step="0.01"
|
||
class="form-control-compact"
|
||
value="{{ $invoice->grand_total_with_charges }}"
|
||
readonly>
|
||
</div>
|
||
|
||
{{-- Status --}}
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-tasks"></i> Status
|
||
</label>
|
||
<select name="status" class="form-select-compact" required>
|
||
<option value="pending" {{ old('status', $invoice->status) === 'pending' ? 'selected' : '' }}>Pending</option>
|
||
<option value="paying" {{ old('status', $invoice->status) === 'paying' ? 'selected' : '' }}>Paying</option>
|
||
<option value="paid" {{ old('status', $invoice->status) === 'paid' ? 'selected' : '' }}>Paid</option>
|
||
<option value="overdue" {{ old('status', $invoice->status) === 'overdue' ? 'selected' : '' }}>Overdue</option>
|
||
</select>
|
||
|
||
</div>
|
||
|
||
{{-- Notes --}}
|
||
<div class="form-group-compact" style="grid-column: 1 / -1;">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-sticky-note"></i> Notes
|
||
</label>
|
||
<textarea name="notes"
|
||
rows="3"
|
||
class="form-control-compact"
|
||
placeholder="Add any additional notes...">{{ old('notes', $invoice->notes) }}</textarea>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="text-end mt-3">
|
||
<button type="submit" class="btn-success-compact btn-compact">
|
||
<i class="fas fa-save me-2"></i>Update Invoice
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
@php
|
||
$totalPaid = $invoice->totalPaid();
|
||
$remaining = $invoice->remainingAmount();
|
||
|
||
// Mixed tax type label from charge groups
|
||
$taxTypes = $invoice->chargeGroups
|
||
? $invoice->chargeGroups->pluck('tax_type')->filter()->unique()->values()
|
||
: collect([]);
|
||
|
||
$taxTypeLabel = 'None';
|
||
|
||
if ($taxTypes->count() === 1) {
|
||
if ($taxTypes[0] === 'gst') {
|
||
$taxTypeLabel = 'GST (CGST + SGST)';
|
||
} elseif ($taxTypes[0] === 'igst') {
|
||
$taxTypeLabel = 'IGST';
|
||
} else {
|
||
$taxTypeLabel = strtoupper($taxTypes[0]);
|
||
}
|
||
} elseif ($taxTypes->count() > 1) {
|
||
$parts = [];
|
||
if ($taxTypes->contains('gst')) {
|
||
$parts[] = 'GST (CGST + SGST)';
|
||
}
|
||
if ($taxTypes->contains('igst')) {
|
||
$parts[] = 'IGST';
|
||
}
|
||
$taxTypeLabel = implode(' + ', $parts);
|
||
}
|
||
@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">Tax Type</span>
|
||
<span class="breakdown-value text-primary">
|
||
{{ $taxTypeLabel }}
|
||
</span>
|
||
</div>
|
||
|
||
<div class="breakdown-row">
|
||
<span class="breakdown-label">GST Amount</span>
|
||
<span class="breakdown-value text-warning" id="gstAmount">
|
||
₹{{ 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">Grand Total (Charges + GST)</span>
|
||
<span class="breakdown-value fw-bold text-dark" id="totalInvoiceWithGst">
|
||
₹{{ number_format($invoice->grand_total_with_charges, 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(max(0, $remaining), 2) }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Summary cards --}}
|
||
<div class="summary-grid-compact">
|
||
<div class="summary-card-compact total">
|
||
<div class="summary-value-compact text-success" id="totalInvoiceWithGstCard">
|
||
₹{{ number_format($invoice->grand_total_with_charges, 2) }}
|
||
</div>
|
||
<div class="summary-label-compact">Grand Total (Charges + GST)</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(max(0, $remaining), 2) }}
|
||
</div>
|
||
<div class="summary-label-compact">Remaining</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Installment Management --}}
|
||
<div class="glass-card">
|
||
<div class="card-header-compact d-flex justify-content-between align-items-center">
|
||
<h4 class="mb-0">
|
||
<i class="fas fa-credit-card me-2"></i>Installment Payments
|
||
</h4>
|
||
@if($remaining > 0)
|
||
<button id="toggleInstallmentForm" class="btn-primary-compact btn-compact">
|
||
<i class="fas fa-plus-circle me-2"></i>Add Installment
|
||
</button>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="card-body-compact">
|
||
{{-- Installment Form --}}
|
||
<div id="installmentForm" class="d-none mb-3">
|
||
<div class="glass-card" style="background: rgba(248, 250, 252, 0.8);">
|
||
<div class="card-header-compact" style="background: var(--success-gradient);">
|
||
<h4 class="mb-0">
|
||
<i class="fas fa-plus-circle me-2"></i>Add New Installment
|
||
</h4>
|
||
</div>
|
||
<div class="card-body-compact">
|
||
<form id="installmentSubmitForm">
|
||
@csrf
|
||
|
||
<div class="form-grid-compact">
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-calendar-day"></i> Installment Date
|
||
</label>
|
||
<input type="date"
|
||
name="installment_date"
|
||
class="form-control-compact"
|
||
required>
|
||
</div>
|
||
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-credit-card"></i> Payment Method
|
||
</label>
|
||
<select name="payment_method"
|
||
class="form-select-compact"
|
||
required>
|
||
<option value="cash">Cash</option>
|
||
<option value="bank">Bank Transfer</option>
|
||
<option value="upi">UPI</option>
|
||
<option value="cheque">Cheque</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-hashtag"></i> Reference No
|
||
</label>
|
||
<input type="text"
|
||
name="reference_no"
|
||
class="form-control-compact"
|
||
placeholder="Enter reference number">
|
||
</div>
|
||
|
||
<div class="form-group-compact">
|
||
<label class="form-label-compact">
|
||
<i class="fas fa-money-bill-wave"></i> Amount
|
||
</label>
|
||
<input type="number"
|
||
name="amount"
|
||
id="installmentAmount"
|
||
class="form-control-compact"
|
||
step="0.01"
|
||
min="1"
|
||
max="{{ max(0, $remaining) }}"
|
||
required
|
||
placeholder="Enter installment amount">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="text-end mt-2">
|
||
<button type="submit"
|
||
class="btn-success-compact btn-compact"
|
||
id="installmentSubmitBtn">
|
||
<i class="fas fa-paper-plane me-2"></i>Submit Installment
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Installment History --}}
|
||
<h6 class="fw-bold mb-2 text-dark">
|
||
<i class="fas fa-history me-2"></i>Installment History
|
||
</h6>
|
||
|
||
<div id="noInstallmentsMsg"
|
||
class="{{ $invoice->installments->count() ? 'd-none' : '' }} text-center text-muted fw-bold py-4">
|
||
No installments found. Click Add Installment to create one.
|
||
</div>
|
||
|
||
<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">
|
||
@foreach($invoice->installments as $i)
|
||
<tr data-id="{{ $i->id }}">
|
||
<td class="fw-bold text-muted">{{ $loop->iteration }}</td>
|
||
<td>{{ $i->installment_date }}</td>
|
||
<td>
|
||
<span class="badge-compact bg-primary bg-opacity-10 text-primary">
|
||
{{ strtoupper($i->payment_method) }}
|
||
</span>
|
||
</td>
|
||
<td>
|
||
@if($i->reference_no)
|
||
<span class="text-muted">{{ $i->reference_no }}</span>
|
||
@else
|
||
<span class="text-muted">-</span>
|
||
@endif
|
||
</td>
|
||
<td class="fw-bold text-success">
|
||
₹{{ number_format($i->amount, 2) }}
|
||
</td>
|
||
<td>
|
||
<button class="btn-danger-compact btn-compact btn-sm deleteInstallment">
|
||
<i class="fas fa-trash me-1"></i>Delete
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
@endforeach
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener("DOMContentLoaded", function () {
|
||
const toggleBtn = document.getElementById("toggleInstallmentForm");
|
||
const formBox = document.getElementById("installmentForm");
|
||
|
||
if (toggleBtn && formBox) {
|
||
toggleBtn.addEventListener("click", function (e) {
|
||
e.preventDefault();
|
||
formBox.classList.toggle("d-none");
|
||
});
|
||
}
|
||
|
||
const submitForm = document.getElementById("installmentSubmitForm");
|
||
const submitBtn = document.getElementById("installmentSubmitBtn");
|
||
|
||
const formatINR = (amt) => {
|
||
return Number(amt).toLocaleString("en-IN", {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2
|
||
});
|
||
};
|
||
|
||
if (submitForm && submitBtn) {
|
||
submitForm.addEventListener("submit", function (e) {
|
||
e.preventDefault();
|
||
|
||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Processing...';
|
||
submitBtn.disabled = true;
|
||
|
||
fetch("{{ route('admin.invoice.installment.store', $invoice->id) }}", {
|
||
method: "POST",
|
||
headers: {
|
||
"X-CSRF-TOKEN": submitForm.querySelector('input[name="_token"]').value,
|
||
"Accept": "application/json",
|
||
},
|
||
body: new FormData(submitForm)
|
||
})
|
||
.then(res => res.json())
|
||
.then(data => {
|
||
submitBtn.innerHTML = '<i class="fas fa-paper-plane me-2"></i>Submit Installment';
|
||
submitBtn.disabled = false;
|
||
|
||
if (data.status === "error") {
|
||
alert(data.message);
|
||
return;
|
||
}
|
||
|
||
const table = document.getElementById("installmentTable");
|
||
const index = table.rows.length + 1;
|
||
|
||
document.getElementById("noInstallmentsMsg")?.classList.add("d-none");
|
||
|
||
table.insertAdjacentHTML("beforeend", `
|
||
<tr data-id="${data.installment.id}">
|
||
<td class="fw-bold text-muted">${index}</td>
|
||
<td>${data.installment.installment_date}</td>
|
||
<td>
|
||
<span class="badge-compact bg-primary bg-opacity-10 text-primary">
|
||
${data.installment.payment_method.toUpperCase()}
|
||
</span>
|
||
</td>
|
||
<td>
|
||
${data.installment.reference_no
|
||
? `<span class="text-muted">${data.installment.reference_no}</span>`
|
||
: '<span class="text-muted">-</span>'}
|
||
</td>
|
||
<td class="fw-bold text-success">
|
||
₹${formatINR(data.installment.amount)}
|
||
</td>
|
||
<td>
|
||
<button class="btn-danger-compact btn-compact btn-sm deleteInstallment">
|
||
<i class="fas fa-trash me-1"></i>Delete
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
`);
|
||
|
||
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("baseAmount")) {
|
||
document.getElementById("baseAmount").textContent = "₹" + formatINR(data.chargeGroupsTotal);
|
||
}
|
||
if (document.getElementById("gstAmount")) {
|
||
document.getElementById("gstAmount").textContent = "₹" + formatINR(data.gstAmount);
|
||
}
|
||
|
||
if (document.getElementById("totalInvoiceWithGst")) {
|
||
document.getElementById("totalInvoiceWithGst").textContent =
|
||
"₹" + formatINR(data.grandTotal);
|
||
}
|
||
const totalCard = document.getElementById("totalInvoiceWithGstCard");
|
||
if (totalCard) {
|
||
totalCard.textContent = "₹" + formatINR(data.grandTotal);
|
||
}
|
||
|
||
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
|
||
if (paidCard) paidCard.textContent = "₹" + formatINR(data.totalPaid);
|
||
|
||
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
|
||
if (remainingCard) remainingCard.textContent = "₹" + formatINR(data.remaining);
|
||
|
||
submitForm.reset();
|
||
|
||
if (data.isCompleted && toggleBtn) {
|
||
toggleBtn.remove();
|
||
formBox.classList.add("d-none");
|
||
}
|
||
|
||
alert(data.message);
|
||
})
|
||
.catch(() => {
|
||
submitBtn.innerHTML = '<i class="fas fa-paper-plane me-2"></i>Submit Installment';
|
||
submitBtn.disabled = false;
|
||
alert("Something went wrong. Please try again.");
|
||
});
|
||
});
|
||
}
|
||
|
||
document.addEventListener("click", function (e) {
|
||
if (!e.target.classList.contains("deleteInstallment") &&
|
||
!e.target.closest(".deleteInstallment")) {
|
||
return;
|
||
}
|
||
e.preventDefault();
|
||
|
||
if (!confirm("Are you sure you want to delete this installment?")) {
|
||
return;
|
||
}
|
||
|
||
const btn = e.target.closest(".deleteInstallment");
|
||
const row = btn.closest("tr");
|
||
const id = row.getAttribute("data-id");
|
||
|
||
fetch("{{ url('admin/installment') }}/" + id, {
|
||
method: "DELETE",
|
||
headers: {
|
||
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').getAttribute("content"),
|
||
"Accept": "application/json",
|
||
},
|
||
})
|
||
.then(res => res.json())
|
||
.then(data => {
|
||
if (data.status === "success") {
|
||
row.style.opacity = 0;
|
||
setTimeout(() => row.remove(), 300);
|
||
|
||
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("baseAmount")) {
|
||
document.getElementById("baseAmount").textContent = "₹" + formatINR(data.chargeGroupsTotal);
|
||
}
|
||
if (document.getElementById("gstAmount")) {
|
||
document.getElementById("gstAmount").textContent = "₹" + formatINR(data.gstAmount);
|
||
}
|
||
if (document.getElementById("totalInvoiceWithGst")) {
|
||
document.getElementById("totalInvoiceWithGst").textContent =
|
||
"₹" + formatINR(data.grandTotal);
|
||
}
|
||
const totalCard = document.getElementById("totalInvoiceWithGstCard");
|
||
if (totalCard) {
|
||
totalCard.textContent = "₹" + formatINR(data.grandTotal);
|
||
}
|
||
|
||
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
|
||
if (paidCard) paidCard.textContent = "₹" + formatINR(data.totalPaid);
|
||
|
||
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
|
||
if (remainingCard) remainingCard.textContent = "₹" + formatINR(data.remaining);
|
||
|
||
if (data.isZero) {
|
||
document.getElementById("noInstallmentsMsg")?.classList.remove("d-none");
|
||
}
|
||
|
||
alert(data.message);
|
||
} else {
|
||
alert(data.message || "Something went wrong. Please try again.");
|
||
}
|
||
})
|
||
.catch(() => {
|
||
alert("Something went wrong. Please try again.");
|
||
});
|
||
});
|
||
|
||
// Auto due date = invoice date + 10 days
|
||
const invoiceDateInput = document.querySelector('input[name="invoice_date"]');
|
||
const dueDateInput = document.querySelector('input[name="due_date"]');
|
||
|
||
if (invoiceDateInput && dueDateInput) {
|
||
invoiceDateInput.addEventListener('change', function() {
|
||
const selectedDate = new Date(this.value);
|
||
|
||
if (!isNaN(selectedDate.getTime())) {
|
||
selectedDate.setDate(selectedDate.getDate() + 10);
|
||
const year = selectedDate.getFullYear();
|
||
const month = String(selectedDate.getMonth() + 1).padStart(2, '0');
|
||
const day = String(selectedDate.getDate()).padStart(2, '0');
|
||
dueDateInput.value = `${year}-${month}-${day}`;
|
||
}
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
@endsection
|