Compare commits
3 Commits
dev
...
cb24cf575b
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
cb24cf575b | ||
|
|
9423c79c80 | ||
|
|
8a958b9c48 |
@@ -9,6 +9,7 @@ use App\Models\InvoiceItem;
|
||||
use Mpdf\Mpdf;
|
||||
use App\Models\InvoiceInstallment;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
|
||||
class AdminInvoiceController extends Controller
|
||||
{
|
||||
@@ -43,7 +44,14 @@ class AdminInvoiceController extends Controller
|
||||
$invoice = Invoice::with(['order.shipments'])->findOrFail($id);
|
||||
$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);
|
||||
|
||||
// Generate PDF if missing
|
||||
if (
|
||||
!$invoice->pdf_path ||
|
||||
!file_exists(public_path($invoice->pdf_path))
|
||||
) {
|
||||
// ALWAYS regenerate to reflect latest HTML/CSS
|
||||
$this->generateInvoicePDF($invoice);
|
||||
$invoice->refresh();
|
||||
}
|
||||
|
||||
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.
@@ -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 url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
@@ -700,9 +700,9 @@
|
||||
padding: 2px 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="container-fluid">
|
||||
<!-- Header - Removed gradient -->
|
||||
<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>
|
||||
@@ -830,6 +830,7 @@
|
||||
<th class="table-header">Order Total</th>
|
||||
<th class="table-header">Total Payable</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">Status</th>
|
||||
<th class="table-header" width="100">Actions</th>
|
||||
@@ -907,8 +908,11 @@
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="total-column">
|
||||
<span class="fw-bold text-success">
|
||||
₹{{ number_format($totalPaid, 2) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
|
||||
<!-- Create Date -->
|
||||
@@ -984,9 +988,9 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Add hover effects to table rows
|
||||
const tableRows = document.querySelectorAll('.table tbody tr');
|
||||
@@ -1013,6 +1017,6 @@
|
||||
@endif
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@endsection
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1160,6 +1160,101 @@ body, .container-fluid {
|
||||
break-inside: avoid;
|
||||
}
|
||||
}
|
||||
/* =====================================================
|
||||
GLOBAL EDGE-TO-EDGE + ZOOM SAFE PATCH (CSS ONLY)
|
||||
===================================================== */
|
||||
|
||||
/* 1️⃣ Kill boxed layouts on desktop & zoom */
|
||||
html, body {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
/* 2️⃣ Force container-fluid to truly span full width */
|
||||
.container-fluid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding-left: clamp(12px, 1.8vw, 28px) !important;
|
||||
padding-right: clamp(12px, 1.8vw, 28px) !important;
|
||||
}
|
||||
|
||||
/* 3️⃣ Zoom-safe scaling (VERY IMPORTANT) */
|
||||
body {
|
||||
font-size: clamp(14px, 0.95vw, 16px);
|
||||
}
|
||||
|
||||
/* =====================================================
|
||||
DASHBOARD CARD & GRID FIXES (NO HTML CHANGE)
|
||||
===================================================== */
|
||||
|
||||
/* 4️⃣ Make stat grids auto-adjust on zoom */
|
||||
.stats-row,
|
||||
.shipment-totals-row {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important;
|
||||
gap: clamp(12px, 1.5vw, 20px) !important;
|
||||
}
|
||||
|
||||
/* 5️⃣ Prevent hover zoom breaking layout */
|
||||
.stats-card:hover,
|
||||
.card:hover,
|
||||
.table tbody tr:hover {
|
||||
transform: translateY(-4px) !important;
|
||||
}
|
||||
|
||||
/* =====================================================
|
||||
TABLE ZOOM FIX (NO MORE CRUSHING / OVERFLOW)
|
||||
===================================================== */
|
||||
|
||||
/* 6️⃣ Tables behave like shipment page */
|
||||
.table-responsive {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* 7️⃣ Remove hard min-widths that break zoom */
|
||||
.table,
|
||||
.custom-table-modal,
|
||||
.shipment-details-table {
|
||||
width: 100% !important;
|
||||
min-width: max-content !important;
|
||||
}
|
||||
|
||||
/* 8️⃣ Let text wrap naturally when zoomed */
|
||||
.table td,
|
||||
.table th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* =====================================================
|
||||
MODALS – EDGE TO EDGE WITHOUT TOUCHING MARKUP
|
||||
===================================================== */
|
||||
|
||||
.modal-xl {
|
||||
max-width: 96vw !important;
|
||||
width: 96vw !important;
|
||||
margin: 1vh auto !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.modal-xl {
|
||||
max-width: 100vw !important;
|
||||
width: 100vw !important;
|
||||
margin: 0 !important;
|
||||
height: 100vh !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* =====================================================
|
||||
FINAL SAFETY – PREVENT LAYOUT SHRINK ON ZOOM
|
||||
===================================================== */
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="container-fluid py-3">
|
||||
|
||||
@@ -274,6 +274,30 @@ body {
|
||||
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
|
||||
-------------------------------------------------- */
|
||||
@@ -316,7 +340,7 @@ body {
|
||||
-------------------------------------------------- */
|
||||
.amount-breakdown-compact {
|
||||
background: white;
|
||||
padding: 1rem;
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--shadow-soft);
|
||||
margin-bottom: 1.5rem;
|
||||
@@ -391,6 +415,15 @@ body {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------
|
||||
HEADER ACTION BUTTONS
|
||||
-------------------------------------------------- */
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------
|
||||
RESPONSIVE DESIGN
|
||||
-------------------------------------------------- */
|
||||
@@ -422,6 +455,13 @@ body {
|
||||
.table-compact {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
@@ -454,10 +494,21 @@ body {
|
||||
|
||||
<!-- Invoice Preview Section -->
|
||||
<div class="glass-card">
|
||||
<div class="card-header-compact">
|
||||
<div class="card-header-compact d-flex justify-content-between align-items-center">
|
||||
<h4>
|
||||
<i class="fas fa-file-invoice me-2"></i>Invoice Overview
|
||||
</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 class="card-body-compact invoice-preview-wrapper">
|
||||
@include('admin.popup_invoice', [
|
||||
@@ -468,6 +519,89 @@ body {
|
||||
</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 -->
|
||||
<div class="glass-card">
|
||||
<div class="card-header-compact">
|
||||
@@ -577,81 +711,6 @@ body {
|
||||
</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 -->
|
||||
<div class="glass-card">
|
||||
<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">
|
||||
<i class="fas fa-history me-2"></i>Installment History
|
||||
</h6>
|
||||
@if($invoice->installments->count() > 0)
|
||||
<div class="table-responsive">
|
||||
<table class="table-compact">
|
||||
<thead>
|
||||
@@ -776,24 +836,87 @@ body {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add this just above the table -->
|
||||
<div id="noInstallmentsMsg" class="d-none text-center text-muted fw-bold py-4">
|
||||
@else
|
||||
<div id="noInstallmentsMsg" class="text-center text-muted fw-bold py-4">
|
||||
No installments found. Click "Add Installment" to create one.
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table ...>
|
||||
<tbody id="installmentTable">
|
||||
@foreach($invoice->installments as $i)
|
||||
...
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
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
|
||||
const toggleBtn = document.getElementById("toggleInstallmentForm");
|
||||
const formBox = document.getElementById("installmentForm");
|
||||
@@ -814,6 +937,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
|
||||
if (submitForm) {
|
||||
submitForm.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -839,9 +963,40 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
}
|
||||
|
||||
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}">
|
||||
<td class="fw-bold text-muted">${index}</td>
|
||||
<td>${data.installment.installment_date}</td>
|
||||
@@ -860,15 +1015,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
</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("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");
|
||||
if (paidCard) paidCard.textContent = formatINR(data.totalPaid);
|
||||
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.");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Delete Installment
|
||||
document.addEventListener("click", function (e) {
|
||||
@@ -911,15 +1063,27 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
.then(data => {
|
||||
if (data.status === "success") {
|
||||
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("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
|
||||
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");
|
||||
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);
|
||||
} else {
|
||||
@@ -940,6 +1112,4 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -11,59 +11,67 @@
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
.container {
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 850px;
|
||||
margin: 24px auto 0 auto;
|
||||
background: #fff;
|
||||
border-radius: 13px;
|
||||
box-shadow: 0 2px 14px rgba(40,105,160,0.08);
|
||||
padding: 35px 32px 18px 32px;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* ================= HEADER FIX ================= */
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
overflow: hidden; /* clears floats */
|
||||
border-bottom: 2px solid #E6EBF0;
|
||||
padding-bottom: 13px;
|
||||
}
|
||||
.logo-company {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.logo {
|
||||
}
|
||||
|
||||
/* LEFT SIDE */
|
||||
.logo-company {
|
||||
float: left;
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
/* RIGHT SIDE */
|
||||
.invoice-details {
|
||||
float: right;
|
||||
width: 35%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Logo */
|
||||
.logo {
|
||||
height: 50px;
|
||||
margin-right: 13px;
|
||||
}
|
||||
.company-details {
|
||||
margin-top: 0;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* Company text */
|
||||
.company-details {
|
||||
font-size: 15px;
|
||||
}
|
||||
.company-title {
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.company-title {
|
||||
font-size: 21px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.company-sub {
|
||||
font-size: 16px;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.invoice-details {
|
||||
text-align: right;
|
||||
min-width: 220px;
|
||||
}
|
||||
.invoice-title {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* Invoice */
|
||||
.invoice-title {
|
||||
font-weight: bold;
|
||||
font-size: 23px;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.paid-label {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.paid-tag {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* Paid / Status */
|
||||
.paid-tag {
|
||||
background: #23BF47;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
@@ -72,8 +80,9 @@
|
||||
font-size: 17px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
.paid-tag:before {
|
||||
}
|
||||
|
||||
.paid-tag:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 7px;
|
||||
@@ -82,99 +91,80 @@
|
||||
height: 10px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.paid-date {
|
||||
}
|
||||
|
||||
.paid-date {
|
||||
font-size: 14px;
|
||||
color: #23BF47;
|
||||
margin-top: 2px;
|
||||
}
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.bill-section {
|
||||
/* ================= REST ================= */
|
||||
|
||||
.bill-section {
|
||||
background: #F3F7FB;
|
||||
border-radius: 11px;
|
||||
padding: 20px 18px 13px 18px;
|
||||
margin: 28px 0 16px 0;
|
||||
box-shadow: 0 0px 0px #0000;
|
||||
}
|
||||
.bill-title {
|
||||
}
|
||||
|
||||
.bill-title {
|
||||
font-size: 17px;
|
||||
font-weight: bold;
|
||||
color: #23355D;
|
||||
margin-bottom: 4px;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
.bill-details {
|
||||
}
|
||||
|
||||
.bill-details {
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 9px;
|
||||
margin-bottom: 13px;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
th {
|
||||
}
|
||||
|
||||
th {
|
||||
background: #F6F7F9;
|
||||
padding: 10px 0;
|
||||
font-size: 15px;
|
||||
color: #6781A6;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
text-align: left;
|
||||
}
|
||||
td {
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 7px 0;
|
||||
color: #222;
|
||||
font-size: 15px;
|
||||
border: none;
|
||||
text-align: left;
|
||||
}
|
||||
tbody tr:not(:last-child) td {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
tbody tr:not(:last-child) td {
|
||||
border-bottom: 1px solid #E6EBF0;
|
||||
}
|
||||
tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.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 {
|
||||
}
|
||||
|
||||
.footer {
|
||||
border-top: 1.2px solid #E6EBF0;
|
||||
margin-top: 25px;
|
||||
padding-top: 12px;
|
||||
font-size: 16px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
}
|
||||
.footer strong {
|
||||
color: #222;
|
||||
}
|
||||
.gst-row td {
|
||||
color: #23BF47;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.total-row td {
|
||||
font-weight: bold;
|
||||
font-size: 17px;
|
||||
border-top: 2px solid #E6EBF0;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -241,18 +231,47 @@
|
||||
<td>{{ number_format($item->ttl_amount, 0) }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
{{-- SUBTOTAL --}}
|
||||
<tr class="totals-row">
|
||||
<td colspan="3" style="text-align:right;">Subtotal:</td>
|
||||
<td>{{ number_format($invoice->subtotal, 0) }}</td>
|
||||
<td colspan="3" style="text-align:right;">total</td>
|
||||
<td style="text-align:right;">
|
||||
₹ {{ number_format($invoice->final_amount, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- TAX --}}
|
||||
@if($invoice->tax_type === 'gst' && $invoice->gst_amount > 0)
|
||||
|
||||
<tr class="gst-row">
|
||||
<td colspan="3" style="text-align:right;">GST ({{ $invoice->gst_percent }}%):</td>
|
||||
<td>{{ number_format($invoice->gst_amount, 0) }}</td>
|
||||
<td colspan="3" style="text-align:right;">
|
||||
GST ({{ $invoice->gst_percent }}%)
|
||||
</td>
|
||||
<td style="text-align:right;">
|
||||
₹ {{ number_format($invoice->gst_amount, 2) }}
|
||||
</td>
|
||||
</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">
|
||||
<td colspan="3" style="text-align:right;">Total:</td>
|
||||
<td>{{ number_format($invoice->final_amount_with_gst, 0) }}</td>
|
||||
<td colspan="3" style="text-align:right;">Total Amount</td>
|
||||
<td style="text-align:right;">
|
||||
₹ {{ number_format($invoice->final_amount_with_gst, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- 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 rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
/* ALL YOUR EXISTING CSS STAYS HERE - EXCEPT GST TOTALS SECTION REMOVED */
|
||||
:root {
|
||||
--primary: #2c3e50;
|
||||
--secondary: #3498db;
|
||||
@@ -284,6 +285,8 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* GST Totals Section Styles - COMPLETELY REMOVED */
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.invoice-container {
|
||||
margin: 1rem;
|
||||
@@ -346,6 +349,17 @@
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.invoice-container {
|
||||
box-shadow: none;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -356,6 +370,8 @@
|
||||
============================ -->
|
||||
@php
|
||||
$showActions = $showActions ?? true;
|
||||
|
||||
// REMOVED GST CALCULATION LOGIC
|
||||
@endphp
|
||||
|
||||
<div class="compact-header">
|
||||
@@ -440,7 +456,6 @@
|
||||
<div class="id-value">
|
||||
@php
|
||||
$shipmentId = 'N/A';
|
||||
// Try multiple ways to get shipment ID
|
||||
if($invoice->shipment && $invoice->shipment->shipment_id) {
|
||||
$shipmentId = $invoice->shipment->shipment_id;
|
||||
} elseif($invoice->shipment_id) {
|
||||
@@ -550,62 +565,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php
|
||||
$totalAmount = $invoice->final_amount;
|
||||
$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>
|
||||
|
||||
<!-- ============================
|
||||
GST TOTALS SECTION - COMPLETELY REMOVED
|
||||
============================ -->
|
||||
|
||||
<!-- ============================
|
||||
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) }}"
|
||||
class="btn btn-primary me-2">
|
||||
<i class="fas fa-download me-1"></i> Download PDF
|
||||
@@ -614,8 +581,7 @@
|
||||
<button class="btn btn-success" onclick="shareInvoice()">
|
||||
<i class="fas fa-share me-1"></i> Share
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -624,7 +590,7 @@
|
||||
<!-- ============================
|
||||
SHARE SCRIPT
|
||||
============================ -->
|
||||
<script>
|
||||
<!-- <script>
|
||||
function shareInvoice() {
|
||||
const shareData = {
|
||||
title: "Invoice {{ $invoice->invoice_number }}",
|
||||
@@ -639,7 +605,12 @@
|
||||
alert("Link copied! Sharing not supported on this browser.");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
// Add print functionality
|
||||
function printInvoice() {
|
||||
window.print();
|
||||
}
|
||||
</script> -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -333,7 +333,11 @@ a.btn.btn-primary.position-relative .badge {
|
||||
box-shadow: 0 0 0 2px #ffffff;
|
||||
|
||||
}
|
||||
|
||||
.custom-table th,
|
||||
.custom-table td {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1400,6 +1400,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@forelse($availableOrders as $order)
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
Reference in New Issue
Block a user