Tuesday, September 9, 2025

🟢GST InvoiceWithLogo&CopyCode

Complete Guide: Enhanced Indian Invoice System - Generate GST-Compliant Invoices with Ease

Enhanced Indian Invoice System

Complete GST-Compliant Invoicing Solution with Stock Management & Customer Database

Managing invoices for Indian businesses just got easier with this comprehensive web-based invoice system. This tool combines GST compliance, inventory management, customer database, and professional invoice generation into one powerful platform that works entirely in your browser.

📋 GST-Compliant Invoicing

Generate professional invoices with HSN/SAC codes, SGST, CGST calculations, and proper Indian tax compliance. Perfect for small to medium businesses.

📦 Stock Management

Track inventory levels, manage product codes, prices, and quantities. Get low-stock alerts and automatic inventory updates with each sale.

👥 Customer Database

Store customer information with auto-complete functionality. Never retype customer details again - just start typing and watch the magic happen.

📊 Sales Dashboard

Monitor your business performance with real-time analytics, top-selling products tracking, and revenue insights.

📱 WhatsApp Integration

Share invoices directly via WhatsApp with customizable messages. Generate PDF invoices and share them instantly.

💾 Data Management

Backup and restore your data with ease. Export/import stock and customer data separately or together.

How to Use the Invoice System

Getting Started

  1. Company Setup: Fill in your company name, address, and contact information. Upload your company logo if desired - you can drag it around and resize it on the invoice.
  2. Add Your First Customer: Go to the "Customer Database" section and add customer details. Include contact number, name, email, and address.
  3. Set Up Your Inventory: Navigate to "Stock Management" and add your products with HSN/SAC codes, descriptions, prices, and quantities.

Try Our GST-Compliant Invoice Creation Tool

Experience our GST-compliant invoice system right here! Create professional invoices with automated GST calculations, logo positioning, and inventory management.

Open Tool in New Window

Creating an Invoice

  1. Select Customer: In the "Invoice Generator" section, start typing a customer's contact number. The system will auto-complete their details.
  2. Add Items: Type product codes in the items table, and watch as descriptions, prices, and tax rates auto-populate. Use the "Browse Items" button to select from your inventory.
  3. Review & Generate: Check quantities, apply discounts if needed, and click "Generate Invoice" to see the preview with automatic tax calculations.
  4. Save & Share: Click "Save Invoice" to record the sale and update inventory. Use WhatsApp integration or PDF export to share with customers.

Smart Features That Save Time

  • Auto-Complete: Start typing customer contact numbers or product codes - the system suggests matches from your database
  • Inventory Tracking: Quantities automatically reduce when you save invoices, with warnings for insufficient stock
  • Tax Calculations: SGST and CGST are calculated automatically based on your product settings
  • Professional Branding: Upload your logo and position it anywhere on the invoice with drag-and-drop functionality

Advanced Features

Stock Management

  1. Adding Products: Include item codes, HSN/SAC codes, descriptions, prices, units of measurement, and tax rates. The system supports various units (PCS, KG, LTR, MTR, etc.).
  2. Low Stock Alerts: Items with 5 or fewer units remaining are highlighted in red to help you restock in time.
  3. Editing Items: Click "Edit" on any inventory item to modify details, or "Delete" to remove items you no longer sell.

Sales Dashboard

  1. Analytics Overview: View total revenue, order count, active customers, and products sold for different time periods.
  2. Top Products: See which items are selling best to help with inventory planning and marketing decisions.
  3. Recent Orders: Quick access to your latest invoices for customer service and order tracking.

Technical Specifications

  • Works entirely in web browsers - no installation required
  • Data stored locally in your browser for privacy
  • Mobile-responsive design for tablets and phones
  • Supports logo upload with drag-and-drop positioning
  • PDF generation with professional formatting
  • WhatsApp Web API integration for instant sharing
  • JSON backup/restore for data portability
  • Print-optimized invoice layouts
  • GST-compliant tax calculations for Indian businesses
  • HTML5 Canvas for PDF generation
  • Data Backup & Security

    Your business data is precious. This system stores everything locally in your browser and provides comprehensive backup options:

    • Full Backup: Export all invoices, inventory, and customer data in one file
    • Selective Backup: Export just stock data or customer information separately
    • Easy Restore: Import your data back from JSON files with validation checks
    • Privacy First: No data is sent to external servers - everything stays on your device

    WhatsApp Integration Guide

    1. Set Up WhatsApp Number: Enter the customer's WhatsApp number in international format (e.g., +919037393709).
    2. Customize Message: Adjust the description length and choose whether to include GST details in the WhatsApp message.
    3. Preview Before Sending: Click "Preview WhatsApp Message" to see exactly what will be sent to your customer.
    4. Send Invoice: Use "Send via WhatsApp" for text messages or "Share PDF via WhatsApp" for document sharing.

    Perfect for These Businesses

    • Retail Stores: Electronics, clothing, general merchandise
    • Service Providers: Consultants, repair services, freelancers
    • Small Manufacturers: Custom products, handicrafts, food items
    • Distributors: Product resellers, wholesale businesses
    • Online Sellers: E-commerce businesses, social media sellers

    Start Using the Enhanced Indian Invoice System Today

    Transform your invoicing process with this comprehensive, GST-compliant solution. No downloads, no subscriptions - just professional invoicing at your fingertips.

    Try the System Now Download HTML File
    Multiple Code Blocks

    Here is the code

    Click or tap to cooy it

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=yes">
      <title>Invoice Generator</title>
      <!-- Include html2canvas and jsPDF libraries -->
      <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
      <style>
        /* Your provided CSS remains unchanged */
        * { box-sizing: border-box; }
        body { 
          font-family: Arial, sans-serif; 
          margin: 0; 
          padding: 20px; 
          background: #f5f5f5; 
          touch-action: manipulation; 
        }
    
        .container { max-width: 1400px; margin: auto; }
    
        /* Navigation Menu Styles */
        .nav-menu {
          background: linear-gradient(135deg, #007bff, #0056b3);
          padding: 15px 20px;
          margin-bottom: 20px;
          border-radius: 8px;
          box-shadow: 0 4px 6px rgba(0,0,0,0.1);
        }
        .nav-menu h2 {
          color: white;
          margin: 0 0 15px 0;
          text-align: center;
        }
        .nav-buttons {
          display: flex;
          gap: 15px;
          justify-content: center;
          flex-wrap: wrap;
        }
        .nav-btn {
          background: rgba(255,255,255,0.2);
          color: white;
          border: 2px solid rgba(255,255,255,0.3);
          padding: 12px 24px;
          border-radius: 6px;
          cursor: pointer;
          font-weight: bold;
          transition: all 0.3s;
          backdrop-filter: blur(10px);
        }
        .nav-btn:hover {
          background: rgba(255,255,255,0.3);
          transform: translateY(-2px);
        }
        .nav-btn.active {
          background: white;
          color: #007bff;
          border-color: white;
        }
    
        .section { display: none; }
        .section.active { display: block; }
        .input-section { 
          background: white; 
          padding: 20px; 
          margin-bottom: 20px; 
          border-radius: 8px; 
          box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        .invoice-preview { 
          background: white; 
          padding: 0; 
          border-radius: 8px; 
          box-shadow: 0 2px 5px rgba(0,0,0,0.1); 
        }
    
        h3 { margin-top: 0; color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }
    
        .form-row { display: flex; gap: 15px; margin-bottom: 15px; flex-wrap: wrap; }
        .form-group { flex: 1; min-width: 200px; position: relative; }
        .form-group label { display: block; margin-bottom: 5px; font-weight: bold; color: #555; }
        .form-group input, .form-group textarea { 
          width: 100%; 
          padding: 8px; 
          border: 1px solid #ddd; 
          border-radius: 4px; 
          font-size: 14px;
        }
        .form-group textarea { resize: vertical; height: 80px; }
    
        .auto-populated {
          background-color: #e8f5e8 !important;
          border-color: #28a745 !important;
          transition: background-color 0.5s ease;
        }
    
        .dropdown {
          position: absolute;
          top: 100%;
          left: 0;
          right: 0;
          background: white;
          border: 1px solid #ddd;
          border-top: none;
          max-height: 200px;
          overflow-y: auto;
          z-index: 1000;
          display: none;
          box-shadow: 0 4px 6px rgba(0,0,0,0.1);
        }
        .dropdown-item {
          padding: 10px;
          cursor: pointer;
          border-bottom: 1px solid #eee;
        }
        .dropdown-item:hover {
          background: #f5f5f5;
        }
    
        .items-section { margin-top: 20px; }
        .items-table { 
          width: 100%; 
          border-collapse: collapse; 
          background: #f8f9fa; 
          border-radius: 5px; 
          overflow: hidden;
        }
        .items-table th, .items-table td { 
          padding: 8px; 
          border: 1px solid #ddd; 
          text-align: left; 
          font-size: 14px;
        }
        .items-table th { 
          background: #e9ecef; 
          font-weight: bold; 
          color: #333;
        }
        .items-table input { 
          width: 100%; 
          padding: 6px; 
          border: 1px solid #ccc; 
          border-radius: 4px; 
          font-size: 14px;
        }
        .items-table .code-input { min-width: 100px; }
        .items-table .desc-input { min-width: 200px; }
        .items-table .qty-input, .items-table .rate-input, .items-table .disc-input, .items-table .sgst-input, .items-table .cgst-input, .items-table .total-input { min-width: 80px; }
        .items-table .total-input {
          background: #f0f0f0;
          text-align: right;
          pointer-events: none;
        }
        .items-table .remove-btn { 
          background: #dc3545; 
          color: white; 
          border: none; 
          padding: 6px 10px; 
          border-radius: 4px; 
          cursor: pointer; 
          width: 100%;
        }
        .items-table .remove-btn:hover { background: #c82333; }
    
        .add-item-btn, .generate-btn, .browse-items-btn, .add-stock-btn, .add-customer-btn, .backup-btn, .restore-btn, .save-btn { 
          background: #28a745; 
          color: white; 
          border: none; 
          padding: 10px 20px; 
          border-radius: 5px; 
          cursor: pointer; 
          margin-right: 10px; 
          margin-top: 10px;
        }
        .add-item-btn:hover, .add-stock-btn:hover, .add-customer-btn:hover, .backup-btn:hover, .restore-btn:hover, .save-btn:hover { background: #218838; }
        .browse-items-btn { background: #17a2b8; }
        .browse-items-btn:hover { background: #138496; }
        .generate-btn { background: #007bff; }
        .generate-btn:hover { background: #0056b3; }
        .save-btn { background: #ffc107; color: #333; }
        .save-btn:hover { background: #e0a800; }
    
        .stock-table, .customer-table {
          width: 100%;
          border-collapse: collapse;
          margin-top: 20px;
        }
        .stock-table th, .stock-table td, .customer-table th, .customer-table td {
          border: 1px solid #ddd;
          padding: 12px;
          text-align: left;
        }
        .stock-table th, .customer-table th {
          background: #f8f9fa;
          font-weight: bold;
        }
        .stock-table tr:hover, .customer-table tr:hover {
          background: #f5f5f5;
        }
    
        .edit-btn, .delete-btn {
          padding: 5px 10px;
          margin: 2px;
          border: none;
          border-radius: 3px;
          cursor: pointer;
          font-size: 12px;
        }
        .edit-btn { background: #ffc107; color: #333; }
        .edit-btn:hover { background: #e0a800; }
        .delete-btn { background: #dc3545; color: white; }
        .delete-btn:hover { background: #c82333; }
    
        .low-stock {
          color: #dc3545;
          font-weight: bold;
        }
    
        .quantity-error {
          border: 2px solid #dc3545 !important;
          background-color: #fff3f3 !important;
        }
    
        /* Invoice Styles */
        .invoice-box {
          max-width: 700px; 
          margin: auto; 
          padding: 20px;
          border: 1px solid #ddd; 
          border-radius: 8px; 
          background: white;
          position: relative;
        }
        .company-header {
          text-align: center; 
          margin-bottom: 20px;
        }
        .company-header h2 { margin: 0; color: #333; }
        .company-header p { margin: 2px 0; font-size: 13px; color: #666; }
        .header { display: flex; justify-content: space-between; margin-bottom: 20px; }
        .bill-to { font-size: 14px; }
        .invoice-details { text-align: right; font-size: 14px; }
        .invoice-table { 
          width: 100%; 
          border-collapse: collapse; 
          margin-top: 20px; 
        }
        .invoice-table, .invoice-table th, .invoice-table td { border: 1px solid #ccc; }
        .invoice-table th, .invoice-table td { padding: 8px; text-align: left; }
        .invoice-table th { background: #f8f9fa; }
        .total { text-align: right; font-weight: bold; margin-top: 10px; font-size: 16px; }
        .print-btn { 
          margin-top: 20px; 
          padding: 8px 16px; 
          background: #007bff; 
          color: #fff; 
          border: none; 
          cursor: pointer; 
          border-radius: 5px; 
        }
        .print-btn:hover { background: #0056b3; }
    
        /* Logo Styles */
        .invoice-logo {
          position: absolute;
          top: 20px;
          left: 20px;
          z-index: 10;
          cursor: move;
          user-select: none;
          -webkit-user-select: none;
          touch-action: none;
        }
        .invoice-logo img {
          width: 100%;
          height: 100%;
          object-fit: contain;
        }
        .invoice-logo.active {
          border: 2px dashed #007bff;
        }
        .resize-handle {
          position: absolute;
          width: 12px;
          height: 12px;
          background: #007bff;
          border-radius: 50%;
          display: none;
        }
        .invoice-logo.active .resize-handle {
          display: block;
        }
        .resize-handle.top-left {
          top: -6px;
          left: -6px;
          cursor: nwse-resize;
        }
        .resize-handle.top-right {
          top: -6px;
          right: -6px;
          cursor: nesw-resize;
        }
        .resize-handle.bottom-left {
          bottom: -6px;
          left: -6px;
          cursor: nesw-resize;
        }
        .resize-handle.bottom-right {
          bottom: -6px;
          right: -6px;
          cursor: nwse-resize;
        }
        .logo-controls {
          margin-top: 20px;
          display: flex;
          flex-wrap: wrap;
          gap: 10px;
          align-items: center;
        }
        .logo-controls input[type="number"] {
          width: 80px;
          padding: 6px;
          border: 1px solid #ddd;
          border-radius: 4px;
        }
        .logo-controls button {
          padding: 8px 16px;
          border: none;
          border-radius: 4px;
          cursor: pointer;
          font-size: 14px;
        }
        .reset-logo-btn {
          background: #6c757d;
          color: white;
        }
        .reset-logo-btn:hover {
          background: #5a6268;
        }
        .remove-logo-btn {
          background: #dc3545;
          color: white;
        }
        .remove-logo-btn:hover {
          background: #c82333;
        }
    
        /* Floating Dialog Styles */
        .dialog-overlay {
          position: fixed; 
          top: 0; 
          left: 0; 
          width: 100%; 
          height: 100%;
          background: rgba(0, 0, 0, 0.5); 
          z-index: 1000; 
          display: none;
          align-items: center;
          justify-content: center;
        }
        .dialog {
          background: white; 
          border-radius: 12px; 
          padding: 0; 
          width: 90%;
          max-width: 600px; 
          min-width: 300px; 
          max-height: 80vh; 
          min-height: 200px;
          overflow: hidden; 
          box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
          position: relative;
        }
        .dialog-header {
          display: flex; 
          justify-content: space-between; 
          align-items: center;
          padding: 15px 20px 10px 20px; 
          border-bottom: 2px solid #e9ecef;
          background: #f8f9fa; 
          -webkit-user-select: none; 
          user-select: none;
          touch-action: none;
        }
        .dialog-controls { 
          display: flex; 
          align-items: center; 
          gap: 10px; 
          flex-wrap: wrap; 
        }
        .size-inputs { 
          display: flex; 
          gap: 5px; 
          align-items: center; 
          margin-right: 10px; 
        }
        .size-input { 
          width: 60px; 
          padding: 2px 5px; 
          border: 1px solid #ddd; 
          border-radius: 3px; 
          font-size: 0.8rem; 
          text-align: center; 
        }
        .resize-btn, .apply-btn { 
          border: none; 
          padding: 4px 8px; 
          border-radius: 4px; 
          cursor: pointer; 
          font-size: 0.8rem; 
        }
        .resize-btn { 
          background: #6c757d; 
          color: white; 
          font-weight: 600; 
        }
        .resize-btn:hover { background: #5a6268; }
        .apply-btn { background: #007bff; color: white; }
        .apply-btn:hover { background: #0056b3; }
        .dialog-header h3 { color: #495057; margin: 0; border: none; }
        .close-btn {
          background: none; 
          border: none; 
          font-size: 1.5rem; 
          cursor: pointer;
          color: #6c757d; 
          padding: 5px; 
          border-radius: 50%; 
          width: 35px; 
          height: 35px;
          display: flex; 
          align-items: center; 
          justify-content: center;
        }
        .close-btn:hover { background: #f8f9fa; color: #495057; }
        .search-section { margin-bottom: 20px; padding: 0 20px; }
        .search-input {
          width: 100%; 
          padding: 12px; 
          border: 2px solid #dee2e6; 
          border-radius: 8px; 
          font-size: 1rem;
        }
        .search-input:focus { 
          outline: none; 
          border-color: #4facfe; 
          box-shadow: 0 0 0 3px rgba(79, 172, 254, 0.1); 
        }
        .items-container {
          max-height: calc(100% - 150px); 
          overflow-y: auto; 
          border: 1px solid #dee2e6;
          border-radius: 8px; 
          margin: 0 20px 20px 20px;
        }
        .item-table { width: 100%; border-collapse: collapse; }
        .item-table th, .item-table td { 
          padding: 10px; 
          text-align: left; 
          border-bottom: 1px solid #dee2e6; 
        }
        .item-table th { 
          background: #f8f9fa; 
          position: sticky; 
          top: 0; 
          font-weight: 600; 
          color: #495057; 
        }
        .item-table tbody tr { 
          cursor: pointer; 
          transition: background-color 0.2s ease; 
        }
        .item-table tbody tr:hover { background-color: #e3f2fd; }
        .status-message {
          padding: 10px; 
          margin: 10px 20px; 
          border-radius: 6px; 
          font-size: 0.9rem; 
          display: none;
        }
        .status-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
        .status-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
    
        @media print {
          body { background: white; }
          .input-section, .nav-menu { display: none; }
          .invoice-preview { box-shadow: none; }
          .dialog-overlay { display: none !important; }
          .invoice-logo.active { border: none !important; }
          .resize-handle { display: none !important; }
        }
        @media (max-width: 768px) {
          .form-row { flex-direction: column; }
          .items-section, .stock-table, .customer-table { 
            overflow-x: auto; 
            display: block;
          }
          .items-table th, .items-table td { min-width: 60px; }
          .items-table .desc-input { min-width: 120px; }
          .items-table .remove-btn { min-width: 80px; }
          .dialog { width: 90%; min-width: 250px; max-width: 95vw; }
          .dialog-header { padding: 10px 15px; }
          .size-input { width: 50px; font-size: 0.7rem; }
          .resize-btn, .apply-btn { padding: 3px 6px; font-size: 0.7rem; }
          .nav-buttons { flex-direction: column; align-items: center; }
          .nav-btn { width: 200px; }
          .logo-controls input[type="number"] { width: 60px; }
        }
        @media (max-width: 480px) {
          .dialog { min-height: 150px; }
          .items-container { max-height: calc(100% - 120px); }
          .items-table th, .items-table td, .stock-table th, .stock-table td, .customer-table th, .customer-table td { 
            font-size: 12px; 
            padding: 6px; 
          }
          .items-table input { font-size: 12px; padding: 4px; }
          .item-table th, .item-table td { font-size: 12px; padding: 6px; }
          .resize-handle { width: 10px; height: 10px; }
        }
        .hidden { display: none; }
        .whatsapp-section {
          background: #e8f5e8;
          padding: 15px;
          border-radius: 5px;
          margin-top: 20px;
          border-left: 4px solid #25d366;
        }
        .whatsapp-section h3 {
          color: #333;
          border-bottom: 2px solid #25d366;
        }
        .btn-whatsapp {
          background: #25d366;
          color: white;
          padding: 10px 20px;
          border: none;
          border-radius: 5px;
          cursor: pointer;
          font-weight: bold;
          transition: all 0.3s;
        }
        .btn-whatsapp:hover {
          background: #20c360;
          transform: translateY(-2px);
        }
        .whatsapp-preview {
          max-height: 200px;
          overflow-y: auto;
          border: 1px solid #ddd;
          margin-top: 15px;
          padding: 10px;
          background: #f8f9fa;
          border-radius: 4px;
          white-space: pre-wrap;
          font-family: monospace;
          display: none;
        }
        .pdf-btn {
          background: #007bff;
          color: white;
          padding: 10px 20px;
          border: none;
          border-radius: 5px;
          cursor: pointer;
          margin-right: 10px;
          margin-top: 10px;
        }
        .pdf-btn:hover {
          background: #0056b3;
        }
        .pdf-btn.share {
          background: linear-gradient(135deg, #17a2b8, #20c997);
        }
        /* Dashboard Styles */
        .stats-grid {
          display: grid;
          grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
          gap: 20px;
          margin-bottom: 20px;
        }
        .dashboard-grid {
          display: grid;
          grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
          gap: 20px;
        }
        .dashboard-card {
          background: white;
          padding: 20px;
          border-radius: 8px;
          box-shadow: 0 2px 5px rgba(0,0,0,0.1);
          transition: transform 0.3s, box-shadow 0.3s;
        }
        .dashboard-card:hover {
          transform: translateY(-5px);
          box-shadow: 0 4px 10px rgba(0,0,0,0.2);
        }
        .dashboard-card h4 {
          margin: 0 0 10px;
          color: #333;
        }
        .dashboard-card p {
          margin: 0;
          font-size: 1.5rem;
          font-weight: bold;
          color: white;
        }
        .top-products-list, .recent-orders-list {
          max-height: 200px;
          overflow-y: auto;
          margin-top: 10px;
        }
        .top-products-list div, .recent-orders-list div {
          padding: 10px;
          border-bottom: 1px solid #eee;
          display: flex;
          justify-content: space-between;
          align-items: center;
          cursor: pointer;
          transition: background 0.2s;
        }
        .top-products-list div:hover, .recent-orders-list div:hover {
          background: #f5f5f5;
        }
        .refresh-btn {
          background: #007bff;
          color: white;
          border: none;
          padding: 10px 20px;
          border-radius: 5px;
          cursor: pointer;
          margin-top: 10px;
        }
        .refresh-btn:hover {
          background: #0056b3;
        }
        @media (max-width: 768px) {
          .stats-grid, .dashboard-grid {
            grid-template-columns: 1fr;
          }
        }
      </style>
    </head>
    <body>
    <div class="container">
      <!-- Navigation Menu -->
      <div class="nav-menu">
        <h2>🇮🇳 Enhanced Indian Invoice System</h2>
        <div class="nav-buttons">
          <button class="nav-btn active" data-section="invoice">📋 Invoice Generator</button>
          <button class="nav-btn" data-section="dashboard">📊 Sales Dashboard</button>
          <button class="nav-btn" data-section="stock">📦 Stock Management</button>
          <button class="nav-btn" data-section="customers">👥 Customer Database</button>
          <button class="nav-btn" data-section="backup-restore">💾 Backup & Restore</button>
        </div>
      </div>
    
      <!-- Sales Dashboard Section -->
      <div class="section" id="dashboard">
        <div class="input-section">
          <h3>📊 Sales Dashboard</h3>
          <div class="form-row">
            <div class="form-group">
              <label>Date Range</label>
              <select id="dateRangeFilter" onchange="toggleCustomDateRange()">
                <option value="7">Last 7 days</option>
                <option value="30">Last 30 days</option>
                <option value="90">Last 90 days</option>
                <option value="365">Last 365 days</option>
                <option value="custom">Custom Range</option>
              </select>
            </div>
            <div class="form-group hidden" id="customDateRange">
              <label>From</label>
              <input type="date" id="fromDate">
              <label>To</label>
              <input type="date" id="toDate">
            </div>
            <div class="form-group">
              <button class="refresh-btn" onclick="updateDashboard()">Refresh</button>
              <button class="refresh-btn" onclick="clearInvoices()">Clear Invoices</button>
            </div>
          </div>
          <div class="stats-grid">
            <div class="dashboard-card" style="background: linear-gradient(135deg, #28a745, #218838);">
              <h4>Total Revenue</h4>
              <p id="totalRevenue">₹0.00</p>
            </div>
            <div class="dashboard-card" style="background: linear-gradient(135deg, #007bff, #0056b3);">
              <h4>Total Orders</h4>
              <p id="totalOrders">0</p>
            </div>
            <div class="dashboard-card" style="background: linear-gradient(135deg, #ff4d4f, #cf1322);">
              <h4>Active Customers</h4>
              <p id="totalCustomers">0</p>
            </div>
            <div class="dashboard-card" style="background: linear-gradient(135deg, #17a2b8, #117a8b);">
              <h4>Products Sold</h4>
              <p id="totalProducts">0</p>
            </div>
          </div>
          <div class="dashboard-grid">
            <div class="dashboard-card">
              <h4>Top Selling Products</h4>
              <div class="top-products-list" id="topProductsList"></div>
            </div>
            <div class="dashboard-card">
              <h4>Recent Orders</h4>
              <div class="recent-orders-list" id="recentOrdersList"></div>
            </div>
          </div>
        </div>
      </div>
    
      <!-- Invoice Generator Section -->
      <div class="section active" id="invoice">
        <div class="input-section">
          <h3>📝 Invoice Generator</h3>
          <!-- Company Info -->
          <div class="form-row">
            <div class="form-group">
              <label>Company Name</label>
              <input type="text" id="companyName" value="Your Company Name">
            </div>
          </div>
          <div class="form-row">
            <div class="form-group">
              <label>Company Address</label>
              <textarea id="companyAddress">123 Business Street, City, State - ZIP</textarea>
            </div>
            <div class="form-group">
              <label>Contact Info</label>
              <textarea id="companyContact">Email: info@company.com
    Phone: +91 9037393709</textarea>
            </div>
          </div>
          <!-- Logo Upload -->
          <h3>🖼️ Logo</h3>
          <div class="form-row">
            <div class="form-group">
              <label>Upload Logo</label>
              <input type="file" id="logoUpload" accept="image/*">
            </div>
            <div class="form-group logo-controls">
              <label>Width (px)</label>
              <input type="number" id="logoWidth" min="20" max="300" placeholder="Width">
              <label>Height (px)</label>
              <input type="number" id="logoHeight" min="20" max="300" placeholder="Height">
              <label><input type="checkbox" id="lockAspectRatio" checked> Lock Aspect Ratio</label>
              <button class="reset-logo-btn" onclick="resetLogoPosition()">Reset Position</button>
              <button class="remove-logo-btn" onclick="removeLogo()">Remove Logo</button>
            </div>
          </div>
          <p style="font-size: 12px; color: #666;">Tip: Tap logo to show handles, drag to move, or tap handles to resize. Double-tap logo to hide handles.</p>
          <!-- Bill To -->
          <h3>👤 Bill To</h3>
          <div class="form-row">
            <div class="form-group">
              <label>Client Contact Number</label>
              <input type="text" id="clientContact" placeholder="Enter contact number">
              <div class="dropdown" id="contactDropdown"></div>
            </div>
            <div class="form-group">
              <label>Client Name</label>
              <input type="text" id="clientName" placeholder="Name will auto-populate">
            </div>
          </div>
          <div class="form-row">
            <div class="form-group">
              <label>Client Email</label>
              <input type="email" id="clientEmail" placeholder="Email will auto-populate">
            </div>
            <div class="form-group">
              <label>Client Address</label>
              <textarea id="clientAddress" placeholder="Address will auto-populate"></textarea>
            </div>
          </div>
          <!-- Invoice Details -->
          <h3>📋 Invoice Details</h3>
          <div class="form-row">
            <div class="form-group">
              <label>Invoice Number</label>
              <input type="text" id="invoiceNumber" value="INV-004">
            </div>
            <div class="form-group">
              <label>Invoice Date</label>
              <input type="date" id="invoiceDate">
            </div>
            <div class="form-group">
              <label>Due Date</label>
              <input type="date" id="dueDate">
            </div>
          </div>
          <!-- Items Section -->
          <h3>📦 Items</h3>
          <div class="items-section">
            <table class="items-table" id="itemsList">
              <thead>
                <tr>
                  <th>Item Code</th>
                  <th>Description</th>
                  <th>Qty</th>
                  <th>Rate (₹)</th>
                  <th>Disc %</th>
                  <th>SGST %</th>
                  <th>CGST %</th>
                  <th>Total (₹)</th>
                  <th>Action</th>
                </tr>
              </thead>
              <tbody>
                <tr class="item-row">
                  <td><input type="text" class="item-code code-input" placeholder="Enter item code..."><div class="dropdown item-dropdown"></div></td>
                  <td><input type="text" class="item-desc desc-input" placeholder="Service or product description"></td>
                  <td><input type="number" class="item-qty qty-input" value="1" min="1"></td>
                  <td><input type="number" class="item-rate rate-input" value="0" step="0.01" min="0"></td>
                  <td><input type="number" class="item-disc disc-input" value="0" step="0.01" min="0" max="100"></td>
                  <td><input type="number" class="item-sgst sgst-input" value="0" step="0.01" min="0"></td>
                  <td><input type="number" class="item-cgst cgst-input" value="0" step="0.01" min="0"></td>
                  <td><input type="text" class="item-total total-input" value="0.00" readonly></td>
                  <td><button class="remove-btn" onclick="removeItem(this)">Remove</button></td>
                </tr>
              </tbody>
            </table>
            <button class="add-item-btn" onclick="addItem()">+ Add Item</button>
            <button class="browse-items-btn" onclick="openItemDialog()">📋 Browse Items</button>
            <button class="generate-btn" onclick="updateItemTotals()">Generate Invoice</button>
            <button class="save-btn" onclick="saveInvoice()">Save Invoice</button>
          </div>
          <!-- WhatsApp Section -->
          <div class="whatsapp-section">
            <h3>Send Invoice via WhatsApp</h3>
            <div class="form-row">
              <div class="form-group">
                <label>WhatsApp Number</label>
                <input type="text" id="whatsappNumber" placeholder="Enter phone number (e.g., +919037393709)">
              </div>
              <div class="form-group">
                <label>Max Description Length</label>
                <input type="number" id="whatsappDescLength" value="20" min="10" max="50">
              </div>
              <div class="form-group">
                <label><input type="checkbox" id="gstEnabled" checked> Include GST in Message</label>
              </div>
            </div>
            <button class="btn-whatsapp" onclick="generateWhatsAppMessage()">Preview WhatsApp Message</button>
            <div class="whatsapp-preview" id="whatsappPreview" style="display: none;"></div>
            <button class="btn-whatsapp" style="margin-top: 10px;" onclick="sendWhatsApp()">Send via WhatsApp</button>
          </div>
          <div class="pdf-buttons">
            <button class="pdf-btn download" onclick="generatePDF()">Download PDF</button>
            <button class="pdf-btn share" onclick="sharePDF()">Share PDF via WhatsApp</button>
            <button class="pdf-btn print" onclick="printInvoice()">Print Invoice</button>
          </div>
        </div>
        <!-- Invoice Preview -->
        <div class="invoice-preview" id="invoicePreview">
          <div class="invoice-box">
            <div class="company-header">
              <h2 id="previewCompanyName">Your Company Name</h2>
              <p id="previewCompanyAddress">123 Business Street, City, State - ZIP</p>
              <p id="previewCompanyContact">Email: info@company.com | Phone: +91 9037393709</p>
            </div>
            <div class="header">
              <div class="bill-to">
                <b>Bill To</b><br>
                <span id="previewClientName">Customer Name</span><br>
                <span id="previewClientAddress">Customer Address</span><br>
                Contact: <span id="previewClientContact">Customer Contact</span><br>
                Email: <span id="previewClientEmail">Customer Email</span>
              </div>
              <div class="invoice-details">
                <b style="color:red;">INVOICE</b><br>
                Invoice #: <span id="previewInvoiceNumber">INV-004</span><br>
                Invoice Date: <span id="previewInvoiceDate">27 August 2025</span><br>
                Due Date: <span id="previewDueDate">26 September 2025</span>
              </div>
            </div>
            <table class="invoice-table">
              <thead>
                <tr>
                  <th>HSN/SAC</th>
                  <th>Description</th>
                  <th>Qty</th>
                  <th>Rate</th>
                  <th>Disc %</th>
                  <th>SGST %</th>
                  <th>CGST %</th>
                  <th>Total</th>
                </tr>
              </thead>
              <tbody id="previewItems">
                <tr>
                  <td></td><td>Sample Item</td><td>1</td><td>₹0.00</td><td>0</td><td>0</td><td>0</td><td>₹0.00</td>
                </tr>
              </tbody>
            </table>
            <p class="total">Grand Total: <span id="previewTotal">₹0.00</span></p>
            <button class="print-btn" onclick="window.print()">Print / Save as PDF</button>
          </div>
        </div>
      </div>
      <!-- Stock Management Section -->
      <div class="section" id="stock">
        <div class="input-section">
          <h3>📦 Stock Management</h3>
          <div class="form-row">
            <div class="form-group">
              <label>Item Code</label>
              <input type="text" id="stockCode" placeholder="e.g., ITM001">
            </div>
            <div class="form-group">
              <label>HSN/SAC Code</label>
              <input type="text" id="stockHSN" placeholder="e.g., 8471">
            </div>
            <div class="form-group">
              <label>Description</label>
              <input type="text" id="stockDescription" placeholder="e.g., Ergonomic wireless mouse">
            </div>
          </div>
          <div class="form-row">
            <div class="form-group">
              <label>Rate (₹)</label>
              <input type="number" id="stockPrice" placeholder="e.g., 25.99" step="0.01" min="0">
            </div>
            <div class="form-group">
              <label>Unit of Measurement</label>
              <select id="stockUnit">
                <option value="PCS">PCS - Pieces</option>
                <option value="KG">KG - Kilogram</option>
                <option value="LTR">LTR - Liter</option>
                <option value="MTR">MTR - Meter</option>
                <option value="BOX">BOX - Box</option>
                <option value="SET">SET - Set</option>
              </select>
            </div>
            <div class="form-group">
              <label>Quantity</label>
              <input type="number" id="stockQuantity" min="0" placeholder="Enter quantity">
            </div>
          </div>
          <div class="form-row">
            <div class="form-group">
              <label>SGST Rate (%)</label>
              <input type="number" id="stockSGST" value="9" step="0.01" min="0">
            </div>
            <div class="form-group">
              <label>CGST Rate (%)</label>
              <input type="number" id="stockCGST" value="9" step="0.01" min="0">
            </div>
          </div>
          <button class="add-stock-btn" onclick="addStockItem()">Add to Inventory</button>
          <table class="stock-table" id="stockTable">
            <thead>
              <tr>
                <th>Item Code</th>
                <th>HSN/SAC</th>
                <th>Description</th>
                <th>Rate (₹)</th>
                <th>Unit</th>
                <th>SGST %</th>
                <th>CGST %</th>
                <th>Quantity</th>
                <th>Actions</th>
              </tr>
            </thead>
            <tbody id="stockTableBody">
            </tbody>
          </table>
        </div>
      </div>
      <!-- Customer Database Section -->
      <div class="section" id="customers">
        <div class="input-section">
          <h3>👥 Customer Database</h3>
          <div class="form-row">
            <div class="form-group">
              <label>Contact Number</label>
              <input type="text" id="newCustomerContact" placeholder="Enter contact number">
            </div>
            <div class="form-group">
              <label>Customer Name</label>
              <input type="text" id="newCustomerName" placeholder="Enter customer name">
            </div>
            <div class="form-group">
              <label>Email</label>
              <input type="email" id="newCustomerEmail" placeholder="Enter email">
            </div>
          </div>
          <div class="form-row">
            <div class="form-group">
              <label>Address</label>
              <textarea id="newCustomerAddress" placeholder="Enter address"></textarea>
            </div>
          </div>
          <button class="add-customer-btn" onclick="addCustomer()">+ Add Customer</button>
          <table class="customer-table" id="customerTable">
            <thead>
              <tr>
                <th>Contact</th>
                <th>Name</th>
                <th>Email</th>
                <th>Address</th>
                <th>Actions</th>
              </tr>
            </thead>
            <tbody id="customerTableBody">
            </tbody>
          </table>
        </div>
      </div>
      <!-- Backup & Restore Section -->
      <div class="section" id="backup-restore">
        <div class="input-section">
          <h3>💾 Backup & Restore</h3>
          <div class="form-row">
            <div class="form-group">
              <label>Backup All Data</label>
              <button class="backup-btn" onclick="backupData()">Backup Data to JSON</button>
            </div>
            <div class="form-group">
              <label>Restore All Data</label>
              <input type="file" id="restoreFileInput" accept=".json">
              <button class="restore-btn" onclick="restoreData()">Restore Data</button>
            </div>
          </div>
          <div class="form-row">
            <div class="form-group">
              <label>Backup Stock Data Only</label>
              <button class="backup-btn" onclick="backupStockData()">Backup Stock to JSON</button>
            </div>
            <div class="form-group">
              <label>Restore Stock Data Only</label>
              <input type="file" id="restoreStockFileInput" accept=".json">
              <button class="restore-btn" onclick="restoreStockData()">Restore Stock Data</button>
            </div>
          </div>
          <div class="form-row">
            <div class="form-group">
              <label>Backup Customer Data Only</label>
              <button class="backup-btn" onclick="backupCustomerData()">Backup Customers to JSON</button>
            </div>
            <div class="form-group">
              <label>Restore Customer Data Only</label>
              <input type="file" id="restoreCustomerFileInput" accept=".json">
              <button class="restore-btn" onclick="restoreCustomerData()">Restore Customer Data</button>
            </div>
          </div>
          <div class="status-message" id="backupStatusMessage"></div>
        </div>
      </div>
    </div>
    
    <!-- Item Selection Dialog -->
    <div class="dialog-overlay" id="dialogOverlay" onclick="closeDialog(event, 'dialogOverlay')">
      <div class="dialog" id="itemDialog" onclick="event.stopPropagation()">
        <div class="dialog-header">
          <h3>Select Items</h3>
          <div class="dialog-controls">
            <div class="size-inputs">
              <span style="font-size: 0.8rem;">W:</span>
              <input type="number" class="size-input" id="itemWidthInput" value="600" min="300" max="1200">
              <span style="font-size: 0.8rem;">H:</span>
              <input type="number" class="size-input" id="itemHeightInput" value="450" min="200" max="800">
              <button class="apply-btn" onclick="applyCustomSize('itemDialog', 'itemWidthInput', 'itemHeightInput')">Apply</button>
            </div>
            <div class="resize-controls">
              <button class="resize-btn" onclick="quickResize(400, 250, 'itemDialog', 'itemWidthInput', 'itemHeightInput')" title="Compact">XS</button>
              <button class="resize-btn" onclick="quickResize(500, 350, 'itemDialog', 'itemWidthInput', 'itemHeightInput')" title="Small">S</button>
              <button class="resize-btn" onclick="quickResize(700, 500, 'itemDialog', 'itemWidthInput', 'itemHeightInput')" title="Large">L</button>
            </div>
            <button class="close-btn" onclick="closeDialog(null, 'dialogOverlay')">&times;</button>
          </div>
        </div>
        <div class="search-section">
          <input type="text" class="search-input" id="searchInput" placeholder="Search items by code, name, or description..." oninput="searchItems()">
        </div>
        <div class="status-message" id="statusMessage"></div>
        <div class="items-container">
          <table class="item-table">
            <thead>
              <tr>
                <th>Item Code</th>
                <th>HSN/SAC</th>
                <th>Description</th>
                <th>Price</th>
                <th>SGST %</th>
                <th>CGST %</th>
              </tr>
            </thead>
            <tbody id="itemsList2">
            </tbody>
          </table>
        </div>
      </div>
    </div>
    
    <!-- Edit Customer Dialog -->
    <div class="dialog-overlay" id="editCustomerDialogOverlay" onclick="closeDialog(event, 'editCustomerDialogOverlay')">
      <div class="dialog" id="editCustomerDialog" onclick="event.stopPropagation()">
        <div class="dialog-header">
          <h3>Edit Customer</h3>
          <button class="close-btn" onclick="closeDialog(null, 'editCustomerDialogOverlay')">&times;</button>
        </div>
        <div class="form-row" style="padding: 20px;">
          <div class="form-group">
            <label>Contact Number</label>
            <input type="text" id="editCustomerContact" placeholder="Enter contact number">
          </div>
          <div class="form-group">
            <label>Customer Name</label>
            <input type="text" id="editCustomerName" placeholder="Enter customer name">
          </div>
          <div class="form-group">
            <label>Email</label>
            <input type="email" id="editCustomerEmail" placeholder="Enter email">
          </div>
          <div class="form-group">
            <label>Address</label>
            <textarea id="editCustomerAddress" placeholder="Enter address"></textarea>
          </div>
        </div>
        <div style="padding: 0 20px 20px;">
          <button class="add-customer-btn" onclick="saveEditedCustomer()">Save Changes</button>
        </div>
      </div>
    </div>
    
    <script>
    const inventory = [
      { code: 'ITM001', hsn: '8471', name: 'Wireless Mouse', description: 'Ergonomic wireless mouse with USB receiver', price: 25.99, unit: 'PCS', quantity: 50, sgst: 9, cgst: 9 },
      { code: 'ITM002', hsn: '8471', name: 'Keyboard', description: 'Mechanical gaming keyboard with RGB lighting', price: 89.99, unit: 'PCS', quantity: 30, sgst: 9, cgst: 9 },
      { code: 'ITM003', hsn: '9403', name: 'Monitor Stand', description: 'Adjustable aluminum monitor stand', price: 45.00, unit: 'PCS', quantity: 20, sgst: 9, cgst: 9 },
      { code: 'ITM004', hsn: '8544', name: 'USB Cable', description: '6ft USB-C to USB-A cable', price: 12.50, unit: 'PCS', quantity: 100, sgst: 9, cgst: 9 },
      { code: 'ITM005', hsn: '8525', name: 'Webcam', description: '1080p HD webcam with built-in microphone', price: 67.99, unit: 'PCS', quantity: 15, sgst: 9, cgst: 9 },
      { code: 'ITM006', hsn: '9405', name: 'Desk Lamp', description: 'LED desk lamp with touch control', price: 34.99, unit: 'PCS', quantity: 25, sgst: 9, cgst: 9 },
      { code: 'ITM007', hsn: '8504', name: 'Phone Charger', description: 'Fast charging wireless phone charger', price: 28.99, unit: 'PCS', quantity: 40, sgst: 9, cgst: 9 },
      { code: 'ITM008', hsn: '8518', name: 'Speakers', description: 'Bluetooth desktop speakers', price: 55.00, unit: 'PCS', quantity: 10, sgst: 9, cgst: 9 },
      { code: 'ITM009', hsn: '4016', name: 'Mouse Pad', description: 'Extra large gaming mouse pad', price: 19.99, unit: 'PCS', quantity: 60, sgst: 9, cgst: 9 },
      { code: 'ITM010', hsn: '8518', name: 'Headphones', description: 'Noise-canceling over-ear headphones', price: 149.99, unit: 'PCS', quantity: 5, sgst: 9, cgst: 9 },
      { code: 'ITM011', hsn: '8473', name: 'External Drive', description: '1TB portable external hard drive', price: 79.99, unit: 'PCS', quantity: 12, sgst: 9, cgst: 9 },
      { code: 'ITM012', hsn: '3926', name: 'Cable Organizer', description: 'Desktop cable management solution', price: 15.99, unit: 'PCS', quantity: 80, sgst: 9, cgst: 9 }
    ];
    
    let customerDatabase = [
      { contact: "+919037393709", name: "John Doe", email: "john@example.com", address: "123 Main St, City" },
      { contact: "+919876543210", name: "Jane Smith", email: "jane@example.com", address: "456 Park Ave, City" }
    ];
    
    let filteredInventory = [...inventory];
    let isDragging = false;
    let dragOffset = { x: 0, y: 0 };
    let activeDialog = null;
    let editingCustomerIndex = null;
    let invoices = JSON.parse(localStorage.getItem('invoices')) || [];
    
    // Logo variables
    let logoElement = null;
    let isLogoDragging = false;
    let isResizing = false;
    let resizeHandle = null;
    let logoStartPos = { x: 0, y: 0 };
    let logoStartSize = { width: 0, height: 0 };
    let originalAspectRatio = 1;
    let lastTapTime = 0;
    
    // Input sanitization function
    function sanitizeInput(input) {
      return input.replace(/[<>"'&]/g, '');
    }
    
    // Debounce function for autocomplete
    function debounce(func, wait) {
      let timeout;
      return function executedFunction(...args) {
        const later = () => {
          clearTimeout(timeout);
          func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    }
    
    // Generate unique invoice number
    function generateInvoiceNumber() {
      const existingNumbers = invoices.map(inv => parseInt(inv.invoiceNumber.replace('INV-', '')));
      const nextNumber = existingNumbers.length ? Math.max(...existingNumbers) + 1 : 1;
      return `INV-${String(nextNumber).padStart(3, '0')}`;
    }
    
    // Core Functions
    function addItem() {
      const itemsList = document.getElementById('itemsList').querySelector('tbody');
      const newRow = document.createElement('tr');
      newRow.className = 'item-row';
      newRow.innerHTML = `
        <td><input type="text" class="item-code code-input" placeholder="Enter item code..."><div class="dropdown item-dropdown"></div></td>
        <td><input type="text" class="item-desc desc-input" placeholder="Service or product description"></td>
        <td><input type="number" class="item-qty qty-input" value="1" min="1"></td>
        <td><input type="number" class="item-rate rate-input" value="0" step="0.01" min="0"></td>
        <td><input type="number" class="item-disc disc-input" value="0" step="0.01" min="0" max="100"></td>
        <td><input type="number" class="item-sgst sgst-input" value="0" step="0.01" min="0"></td>
        <td><input type="number" class="item-cgst cgst-input" value="0" step="0.01" min="0"></td>
        <td><input type="text" class="item-total total-input" value="0.00" readonly></td>
        <td><button class="remove-btn" onclick="removeItem(this)">Remove</button></td>
      `;
      itemsList.appendChild(newRow);
      attachInputListeners(newRow);
      setupItemAutocomplete(newRow);
      updateItemTotals();
    }
    
    function removeItem(button) {
      const itemsList = document.getElementById('itemsList').querySelector('tbody');
      if (itemsList.children.length > 1) {
        button.closest('tr').remove();
        updateItemTotals();
      } else {
        alert('You must have at least one item.');
      }
    }
    
    function attachInputListeners(row) {
      row.querySelectorAll('.item-qty, .item-rate, .item-disc, .item-sgst, .item-cgst').forEach(input => {
        input.addEventListener('input', () => {
          const code = row.querySelector('.item-code').value;
          const qty = parseInt(row.querySelector('.item-qty').value) || 0;
          if (input.classList.contains('item-qty') && code) {
            const item = inventory.find(i => i.code === code);
            if (item && qty > item.quantity) {
              input.classList.add('quantity-error');
              showStatus(`Insufficient stock for ${item.description}. Available: ${item.quantity} units.`, 'error');
              input.value = item.quantity;
            } else {
              input.classList.remove('quantity-error');
            }
          }
          updateItemTotal(row);
          updateItemTotals();
        });
      });
    }
    
    function updateItemTotal(row) {
      const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
      const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
      const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
      const sgst = parseFloat(row.querySelector('.item-sgst').value) || 0;
      const cgst = parseFloat(row.querySelector('.item-cgst').value) || 0;
      const subtotal = qty * rate;
      const discAmount = subtotal * (disc / 100);
      const afterDisc = subtotal - discAmount;
      const sgstAmount = afterDisc * (sgst / 100);
      const cgstAmount = afterDisc * (cgst / 100);
      const lineTotal = afterDisc + sgstAmount + cgstAmount;
      row.querySelector('.item-total').value = lineTotal.toFixed(2);
    }
    
    function updateItemTotals() {
      const rows = document.querySelectorAll('.item-row');
      let subtotal = 0;
      let totalDiscount = 0;
      let totalSGST = 0;
      let totalCGST = 0;
      let grandTotal = 0;
      let canGenerate = true;
    
      rows.forEach(row => {
        const code = row.querySelector('.item-code').value;
        const qty = parseInt(row.querySelector('.item-qty').value) || 0;
        const item = inventory.find(i => i.code === code);
        if (item && qty > item.quantity) {
          canGenerate = false;
          row.querySelector('.item-qty').classList.add('quantity-error');
          showStatus(`Insufficient stock for ${item.description}. Available: ${item.quantity} units.`, 'error');
        } else {
          row.querySelector('.item-qty').classList.remove('quantity-error');
        }
      });
    
      if (!canGenerate) {
        return;
      }
    
      rows.forEach(row => {
        const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
        const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
        const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
        const sgst = parseFloat(row.querySelector('.item-sgst').value) || 0;
        const cgst = parseFloat(row.querySelector('.item-cgst').value) || 0;
        const subtotalAmount = qty * rate;
        const discAmount = subtotalAmount * (disc / 100);
        const afterDisc = subtotalAmount - discAmount;
        const sgstAmount = afterDisc * (sgst / 100);
        const cgstAmount = afterDisc * (cgst / 100);
        const lineTotal = afterDisc + sgstAmount + cgstAmount;
    
        row.querySelector('.item-total').value = lineTotal.toFixed(2);
        subtotal += subtotalAmount;
        totalDiscount += discAmount;
        totalSGST += sgstAmount;
        totalCGST += cgstAmount;
        grandTotal += lineTotal;
      });
    
      const totalsRow = `
        <tr>
          <td colspan="4"></td>
          <td colspan="3">Subtotal</td>
          <td>₹${subtotal.toFixed(2)}</td>
        </tr>
        <tr>
          <td colspan="4"></td>
          <td colspan="3">Total Discount</td>
          <td>₹${totalDiscount.toFixed(2)}</td>
        </tr>
        <tr>
          <td colspan="4"></td>
          <td colspan="3">Total SGST</td>
          <td>₹${totalSGST.toFixed(2)}</td>
        </tr>
        <tr>
          <td colspan="4"></td>
          <td colspan="3">Total CGST</td>
          <td>₹${totalCGST.toFixed(2)}</td>
        </tr>
        <tr>
          <td colspan="4"></td>
          <td colspan="3"><strong>Grand Total</strong></td>
          <td><strong>₹${grandTotal.toFixed(2)}</strong></td>
        </tr>
      `;
      generateInvoice(totalsRow);
    }
    
    function saveInvoice() {
      const invoice = {
        invoiceNumber: document.getElementById('invoiceNumber').value || generateInvoiceNumber(),
        invoiceDate: document.getElementById('invoiceDate').value,
        dueDate: document.getElementById('dueDate').value,
        clientContact: sanitizeInput(document.getElementById('clientContact').value),
        clientName: sanitizeInput(document.getElementById('clientName').value),
        clientEmail: sanitizeInput(document.getElementById('clientEmail').value),
        clientAddress: sanitizeInput(document.getElementById('clientAddress').value),
        items: [],
        subtotal: 0,
        totalDiscount: 0,
        totalSGST: 0,
        totalCGST: 0,
        grandTotal: 0,
        timestamp: new Date().toISOString()
      };
    
      const rows = document.querySelectorAll('.item-row');
      let canSave = true;
    
      rows.forEach(row => {
        const code = row.querySelector('.item-code').value;
        const qty = parseInt(row.querySelector('.item-qty').value) || 0;
        const item = inventory.find(i => i.code === code);
        if (item && qty > item.quantity) {
          canSave = false;
          row.querySelector('.item-qty').classList.add('quantity-error');
          showStatus(`Insufficient stock for ${item.description}. Available: ${item.quantity} units.`, 'error');
        } else {
          row.querySelector('.item-qty').classList.remove('quantity-error');
        }
      });
    
      if (!canSave) {
        return;
      }
    
      if (!invoice.clientContact || !invoice.clientName || !invoice.invoiceDate || !invoice.dueDate) {
        showStatus('Please fill in all invoice details (client contact, name, invoice date, due date).', 'error');
        return;
      }
    
      rows.forEach(row => {
        const code = row.querySelector('.item-code').value;
        const description = row.querySelector('.item-desc').value;
        const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
        const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
        const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
        const sgst = parseFloat(row.querySelector('.item-sgst').value) || 0;
        const cgst = parseFloat(row.querySelector('.item-cgst').value) || 0;
        const subtotal = qty * rate;
        const discAmount = subtotal * (disc / 100);
        const afterDisc = subtotal - discAmount;
        const sgstAmount = afterDisc * (sgst / 100);
        const cgstAmount = afterDisc * (cgst / 100);
        const lineTotal = afterDisc + sgstAmount + cgstAmount;
    
        const item = inventory.find(i => i.code === code);
        invoice.items.push({
          code: sanitizeInput(code),
          hsn: item ? item.hsn : '',
          description: sanitizeInput(description),
          quantity: qty,
          rate: rate,
          discount: disc,
          sgst: sgst,
          cgst: cgst,
          total: lineTotal
        });
    
        invoice.subtotal += subtotal;
        invoice.totalDiscount += discAmount;
        invoice.totalSGST += sgstAmount;
        invoice.totalCGST += cgstAmount;
        invoice.grandTotal += lineTotal;
    
        // Update inventory quantity
        if (item) {
          item.quantity -= qty;
        }
      });
    
      if (invoice.items.length === 0) {
        showStatus('Please add at least one item to the invoice.', 'error');
        return;
      }
    
      invoices.push(invoice);
      localStorage.setItem('invoices', JSON.stringify(invoices));
      loadStockTable();
      updateDashboard();
      showStatus('Invoice saved successfully!', 'success');
    }
    
    function generateInvoice(totalsRow) {
      const companyName = document.getElementById('companyName').value;
      const companyAddress = document.getElementById('companyAddress').value;
      const companyContact = document.getElementById('companyContact').value;
      const clientName = document.getElementById('clientName').value;
      const clientAddress = document.getElementById('clientAddress').value;
      const clientContact = document.getElementById('clientContact').value;
      const clientEmail = document.getElementById('clientEmail').value;
      const invoiceNumber = document.getElementById('invoiceNumber').value;
      const invoiceDate = document.getElementById('invoiceDate').value;
      const dueDate = document.getElementById('dueDate').value;
    
      document.getElementById('previewCompanyName').textContent = companyName;
      document.getElementById('previewCompanyAddress').textContent = companyAddress;
      document.getElementById('previewCompanyContact').textContent = companyContact;
      document.getElementById('previewClientName').textContent = clientName;
      document.getElementById('previewClientAddress').textContent = clientAddress;
      document.getElementById('previewClientContact').textContent = clientContact;
      document.getElementById('previewClientEmail').textContent = clientEmail;
      document.getElementById('previewInvoiceNumber').textContent = invoiceNumber;
      document.getElementById('previewInvoiceDate').textContent = formatDate(invoiceDate);
      document.getElementById('previewDueDate').textContent = formatDate(dueDate);
    
      const previewItems = document.getElementById('previewItems');
      previewItems.innerHTML = '';
      const rows = document.querySelectorAll('.item-row');
      rows.forEach(row => {
        const code = row.querySelector('.item-code').value;
        const item = inventory.find(i => i.code === code);
        const hsn = item ? item.hsn : '';
        const description = row.querySelector('.item-desc').value;
        const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
        const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
        const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
        const sgst = parseFloat(row.querySelector('.item-sgst').value) || 0;
        const cgst = parseFloat(row.querySelector('.item-cgst').value) || 0;
        const subtotal = qty * rate;
        const discAmount = subtotal * (disc / 100);
        const afterDisc = subtotal - discAmount;
        const sgstAmount = afterDisc * (sgst / 100);
        const cgstAmount = afterDisc * (cgst / 100);
        const lineTotal = afterDisc + sgstAmount + cgstAmount;
    
        const tr = document.createElement('tr');
        tr.innerHTML = `
          <td>${hsn}</td>
          <td>${sanitizeInput(description)}</td>
          <td>${qty}</td>
          <td>₹${rate.toFixed(2)}</td>
          <td>${disc}%</td>
          <td>${sgst}%</td>
          <td>${cgst}%</td>
          <td>₹${lineTotal.toFixed(2)}</td>
        `;
        previewItems.appendChild(tr);
      });
    
      previewItems.innerHTML += totalsRow;
      document.getElementById('previewTotal').textContent = `₹${document.querySelector('#itemsList tbody tr:last-child td:last-child').textContent}`;
    }
    
    function formatDate(dateStr) {
      if (!dateStr) return '';
      const date = new Date(dateStr);
      return date.toLocaleDateString('en-IN', { day: 'numeric', month: 'long', year: 'numeric' });
    }
    
    function generateWhatsAppMessage() {
      const companyName = document.getElementById('companyName').value;
      const invoiceNumber = document.getElementById('invoiceNumber').value;
      const invoiceDate = document.getElementById('invoiceDate').value;
      const clientName = document.getElementById('clientName').value;
      const descLength = parseInt(document.getElementById('whatsappDescLength').value) || 20;
      const includeGST = document.getElementById('gstEnabled').checked;
      const rows = document.querySelectorAll('.item-row');
      let grandTotal = 0;
      let message = `*Invoice from ${sanitizeInput(companyName)}*\n`;
      message += `Invoice #: ${sanitizeInput(invoiceNumber)}\n`;
      message += `Date: ${formatDate(invoiceDate)}\n`;
      message += `To: ${sanitizeInput(clientName)}\n\n`;
      message += `*Items:*\n`;
    
      rows.forEach(row => {
        const code = row.querySelector('.item-code').value;
        const item = inventory.find(i => i.code === code);
        const hsn = item ? item.hsn : '';
        let description = row.querySelector('.item-desc').value;
        const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
        const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
        const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
        const sgst = parseFloat(row.querySelector('.item-sgst').value) || 0;
        const cgst = parseFloat(row.querySelector('.item-cgst').value) || 0;
        const subtotal = qty * rate;
        const discAmount = subtotal * (disc / 100);
        const afterDisc = subtotal - discAmount;
        const sgstAmount = afterDisc * (sgst / 100);
        const cgstAmount = afterDisc * (cgst / 100);
        const lineTotal = afterDisc + sgstAmount + cgstAmount;
    
        description = description.length > descLength ? description.substring(0, descLength) + '...' : description;
        message += `- ${sanitizeInput(description)} (HSN/SAC: ${hsn}) x${qty} @ ₹${rate.toFixed(2)}`;
        if (disc > 0) message += `, Disc: ${disc}%`;
        if (includeGST) {
          message += `, SGST: ${sgst}%, CGST: ${cgst}%`;
        }
        message += ` = ₹${lineTotal.toFixed(2)}\n`;
        grandTotal += lineTotal;
      });
    
      message += `\n*Grand Total: ₹${grandTotal.toFixed(2)}*\n`;
      message += `Thank you for your business!`;
    
      const preview = document.getElementById('whatsappPreview');
      preview.textContent = message;
      preview.style.display = 'block';
    }
    
    function sendWhatsApp() {
      const phone = document.getElementById('whatsappNumber').value.replace(/\D/g, '');
      const message = document.getElementById('whatsappPreview').textContent;
      if (!phone) {
        showStatus('Please enter a valid WhatsApp number.', 'error');
        return;
      }
      const url = `https://wa.me/${phone}?text=${encodeURIComponent(message)}`;
      window.open(url, '_blank');
    }
    
    function generatePDF() {
      console.log('Starting PDF generation...');
      if (!window.jspdf || !window.jspdf.jsPDF) {
        alert('jsPDF library not loaded. Please refresh the page.');
        return;
      }
      if (!window.html2canvas) {
        alert('html2canvas library not loaded. Please refresh the page.');
        return;
      }
      const invoiceBox = document.querySelector('.invoice-box');
      if (!invoiceBox) {
        alert('Invoice preview not found. Please generate the invoice first.');
        return;
      }
      try {
        html2canvas(invoiceBox, {
          scale: 2,
          useCORS: true,
          allowTaint: true,
          logging: true
        }).then(canvas => {
          try {
            const { jsPDF } = window.jspdf;
            const doc = new jsPDF();
            const imgData = canvas.toDataURL('image/png');
            const imgProps = doc.getImageProperties(imgData);
            const pdfWidth = doc.internal.pageSize.getWidth();
            const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
            doc.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
            const invoiceNumber = document.getElementById('invoiceNumber').value || 'Untitled';
            const timestamp = new Date().toISOString().replace(/[-:.]/g, ''); // e.g., 20250910T185100
            doc.save(`invoice_${invoiceNumber}_${timestamp}.pdf`);
            console.log('PDF download triggered successfully.');
          } catch (innerErr) {
            console.error('Error in html2canvas callback:', innerErr);
            alert('Failed to generate PDF: ' + innerErr.message);
          }
        }).catch(err => {
          console.error('html2canvas error:', err);
          alert('html2canvas failed: ' + err.message);
        });
      } catch (err) {
        console.error('jsPDF error:', err);
        alert('PDF generation error: ' + err.message);
      }
    }
    
    function sharePDF() {
      const { jsPDF } = window.jspdf;
      const invoiceBox = document.querySelector('.invoice-box');
      const companyName = document.getElementById('companyName').value || 'Your Company Name';
      const whatsappNumber = document.getElementById('whatsappNumber').value;
      if (!whatsappNumber) {
        showStatus('Please enter a WhatsApp number.', 'error');
        return;
      }
      html2canvas(invoiceBox, { scale: 2 }).then(canvas => {
        const imgData = canvas.toDataURL('image/png');
        const pdf = new jsPDF({
          orientation: 'portrait',
          unit: 'mm',
          format: 'a4'
        });
        const imgProps = pdf.getImageProperties(imgData);
        const pdfWidth = pdf.internal.pageSize.getWidth();
        const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
        pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
        const pdfBlob = pdf.output('blob');
        const file = new File([pdfBlob], `${companyName.replace(/\s+/g, '_')}_Invoice_${document.getElementById('invoiceNumber').value}.pdf`, { type: 'application/pdf' });
        const shareData = {
          files: [file],
          title: `${companyName} Invoice`,
          text: `Here is your invoice from ${companyName}.`
        };
        if (navigator.canShare && navigator.canShare({ files: [file] })) {
          navigator.share(shareData).catch(err => {
            showStatus('Error sharing PDF: ' + err.message, 'error');
          });
        } else {
          const url = `https://api.whatsapp.com/send?phone=${encodeURIComponent(whatsappNumber)}&text=${encodeURIComponent(shareData.text)}`;
          window.open(url, '_blank');
          showStatus('PDF sharing not supported on this device. Opened WhatsApp with message.', 'error');
        }
      });
    }
    
    function printInvoice() {
      window.print();
    }
    
    function showStatus(message, type) {
      const statusMessage = document.getElementById('statusMessage');
      statusMessage.textContent = message;
      statusMessage.className = `status-message status-${type}`;
      statusMessage.style.display = 'block';
      setTimeout(() => {
        statusMessage.style.display = 'none';
      }, 3000);
    }
    
    function setupItemAutocomplete(row) {
      const codeInput = row.querySelector('.item-code');
      const dropdown = row.querySelector('.item-dropdown');
      const updateDropdown = debounce(() => {
        const value = codeInput.value.toLowerCase();
        dropdown.innerHTML = '';
        if (!value) {
          dropdown.style.display = 'none';
          return;
        }
        const matches = inventory.filter(item =>
          item.code.toLowerCase().includes(value) ||
          item.name.toLowerCase().includes(value) ||
          item.description.toLowerCase().includes(value)
        );
        matches.forEach(item => {
          const div = document.createElement('div');
          div.className = 'dropdown-item';
          div.textContent = `${item.code} - ${item.name} (${item.description})`;
          div.addEventListener('click', () => {
            codeInput.value = item.code;
            row.querySelector('.item-desc').value = item.description;
            row.querySelector('.item-rate').value = item.price.toFixed(2);
            row.querySelector('.item-sgst').value = item.sgst.toFixed(2);
            row.querySelector('.item-cgst').value = item.cgst.toFixed(2);
            row.querySelector('.item-qty').classList.remove('quantity-error');
            updateItemTotal(row);
            updateItemTotals();
            dropdown.style.display = 'none';
          });
          dropdown.appendChild(div);
        });
        dropdown.style.display = matches.length ? 'block' : 'none';
      }, 300);
    
      codeInput.addEventListener('input', updateDropdown);
      codeInput.addEventListener('focus', () => updateDropdown());
      codeInput.addEventListener('blur', () => {
        setTimeout(() => {
          dropdown.style.display = 'none';
        }, 200);
      });
    }
    
    function setupCustomerAutocomplete() {
      const contactInput = document.getElementById('clientContact');
      const dropdown = document.getElementById('contactDropdown');
      const updateDropdown = debounce(() => {
        const value = contactInput.value.toLowerCase();
        dropdown.innerHTML = '';
        if (!value) {
          dropdown.style.display = 'none';
          return;
        }
        const matches = customerDatabase.filter(customer =>
          customer.contact.toLowerCase().includes(value) ||
          customer.name.toLowerCase().includes(value)
        );
        matches.forEach(customer => {
          const div = document.createElement('div');
          div.className = 'dropdown-item';
          div.textContent = `${customer.contact} - ${customer.name}`;
          div.addEventListener('click', () => {
            contactInput.value = customer.contact;
            document.getElementById('clientName').value = customer.name;
            document.getElementById('clientEmail').value = customer.email;
            document.getElementById('clientAddress').value = customer.address;
            document.getElementById('whatsappNumber').value = customer.contact;
            ['clientName', 'clientEmail', 'clientAddress'].forEach(id => {
              document.getElementById(id).classList.add('auto-populated');
              setTimeout(() => document.getElementById(id).classList.remove('auto-populated'), 1000);
            });
            dropdown.style.display = 'none';
          });
          dropdown.appendChild(div);
        });
        dropdown.style.display = matches.length ? 'block' : 'none';
      }, 300);
    
      contactInput.addEventListener('input', updateDropdown);
      contactInput.addEventListener('focus', () => updateDropdown());
      contactInput.addEventListener('blur', () => {
        setTimeout(() => {
          dropdown.style.display = 'none';
        }, 200);
      });
    }
    
    function openItemDialog() {
      const dialog = document.getElementById('dialogOverlay');
      activeDialog = dialog;
      dialog.style.display = 'flex';
      searchItems();
    }
    
    function closeDialog(event, overlayId) {
      if (event && event.target.id !== overlayId) return;
      const dialog = document.getElementById(overlayId);
      dialog.style.display = 'none';
      activeDialog = null;
      document.getElementById('searchInput').value = '';
      searchItems();
    }
    
    function searchItems() {
      const searchValue = document.getElementById('searchInput').value.toLowerCase();
      filteredInventory = inventory.filter(item =>
        item.code.toLowerCase().includes(searchValue) ||
        item.name.toLowerCase().includes(searchValue) ||
        item.description.toLowerCase().includes(searchValue) ||
        item.hsn.toLowerCase().includes(searchValue)
      );
      loadItemDialog();
    }
    
    function loadItemDialog() {
      const tbody = document.getElementById('itemsList2');
      tbody.innerHTML = '';
      filteredInventory.forEach(item => {
        const tr = document.createElement('tr');
        tr.innerHTML = `
          <td>${item.code}</td>
          <td>${item.hsn}</td>
          <td>${item.description}</td>
          <td>₹${item.price.toFixed(2)}</td>
          <td>${item.sgst}%</td>
          <td>${item.cgst}%</td>
        `;
        tr.addEventListener('click', () => {
          const row = document.querySelector('.item-row:last-child');
          row.querySelector('.item-code').value = item.code;
          row.querySelector('.item-desc').value = item.description;
          row.querySelector('.item-rate').value = item.price.toFixed(2);
          row.querySelector('.item-sgst').value = item.sgst.toFixed(2);
          row.querySelector('.item-cgst').value = item.cgst.toFixed(2);
          updateItemTotal(row);
          updateItemTotals();
          closeDialog(null, 'dialogOverlay');
        });
        tbody.appendChild(tr);
      });
    }
    
    function applyCustomSize(dialogId, widthInputId, heightInputId) {
      const dialog = document.getElementById(dialogId);
      const width = parseInt(document.getElementById(widthInputId).value);
      const height = parseInt(document.getElementById(heightInputId).value);
      if (width >= 300 && width <= 1200 && height >= 200 && height <= 800) {
        dialog.style.width = `${width}px`;
        dialog.style.height = `${height}px`;
      }
    }
    
    function quickResize(width, height, dialogId, widthInputId, heightInputId) {
      document.getElementById(widthInputId).value = width;
      document.getElementById(heightInputId).value = height;
      applyCustomSize(dialogId, widthInputId, heightInputId);
    }
    
    function addStockItem() {
      const code = sanitizeInput(document.getElementById('stockCode').value);
      const hsn = sanitizeInput(document.getElementById('stockHSN').value);
      const description = sanitizeInput(document.getElementById('stockDescription').value);
      const price = parseFloat(document.getElementById('stockPrice').value) || 0;
      const unit = document.getElementById('stockUnit').value;
      const quantity = parseInt(document.getElementById('stockQuantity').value) || 0;
      const sgst = parseFloat(document.getElementById('stockSGST').value) || 0;
      const cgst = parseFloat(document.getElementById('stockCGST').value) || 0;
    
      if (!code || !description || price <= 0 || quantity < 0) {
        showStatus('Please fill in all stock item details correctly.', 'error');
        return;
      }
    
      if (inventory.find(item => item.code === code)) {
        showStatus('Item code already exists.', 'error');
        return;
      }
    
      inventory.push({ code, hsn, name: description.split(' ')[0], description, price, unit, quantity, sgst, cgst });
      loadStockTable();
      ['stockCode', 'stockHSN', 'stockDescription', 'stockPrice', 'stockQuantity', 'stockSGST', 'stockCGST'].forEach(id => {
        document.getElementById(id).value = id.includes('GST') ? '9' : '';
      });
      showStatus('Stock item added successfully!', 'success');
    }
    
    function loadStockTable() {
      const tbody = document.getElementById('stockTableBody');
      tbody.innerHTML = '';
      inventory.forEach((item, index) => {
        const tr = document.createElement('tr');
        tr.innerHTML = `
          <td>${item.code}</td>
          <td>${item.hsn}</td>
          <td>${item.description}</td>
          <td>₹${item.price.toFixed(2)}</td>
          <td>${item.unit}</td>
          <td>${item.sgst}%</td>
          <td>${item.cgst}%</td>
          <td class="${item.quantity < 10 ? 'low-stock' : ''}">${item.quantity}</td>
          <td>
            <button class="edit-btn" onclick="editStockItem(${index})">Edit</button>
            <button class="delete-btn" onclick="deleteStockItem(${index})">Delete</button>
          </td>
        `;
        tbody.appendChild(tr);
      });
    }
    
    function editStockItem(index) {
      const item = inventory[index];
      document.getElementById('stockCode').value = item.code;
      document.getElementById('stockHSN').value = item.hsn;
      document.getElementById('stockDescription').value = item.description;
      document.getElementById('stockPrice').value = item.price;
      document.getElementById('stockUnit').value = item.unit;
      document.getElementById('stockQuantity').value = item.quantity;
      document.getElementById('stockSGST').value = item.sgst;
      document.getElementById('stockCGST').value = item.cgst;
      inventory.splice(index, 1);
      loadStockTable();
      showStatus('Edit the item details and click Add to save.', 'success');
    }
    
    function deleteStockItem(index) {
      if (confirm('Are you sure you want to delete this item?')) {
        inventory.splice(index, 1);
        loadStockTable();
        showStatus('Stock item deleted successfully!', 'success');
      }
    }
    
    function addCustomer() {
      const contact = sanitizeInput(document.getElementById('newCustomerContact').value);
      const name = sanitizeInput(document.getElementById('newCustomerName').value);
      const email = sanitizeInput(document.getElementById('newCustomerEmail').value);
      const address = sanitizeInput(document.getElementById('newCustomerAddress').value);
    
      if (!contact || !name) {
        showStatus('Please fill in contact number and customer name.', 'error');
        return;
      }
    
      if (customerDatabase.find(customer => customer.contact === contact)) {
        showStatus('Customer with this contact number already exists.', 'error');
        return;
      }
    
      customerDatabase.push({ contact, name, email, address });
      loadCustomerTable();
      ['newCustomerContact', 'newCustomerName', 'newCustomerEmail', 'newCustomerAddress'].forEach(id => {
        document.getElementById(id).value = '';
      });
      showStatus('Customer added successfully!', 'success');
    }
    
    function loadCustomerTable() {
      const tbody = document.getElementById('customerTableBody');
      tbody.innerHTML = '';
      customerDatabase.forEach((customer, index) => {
        const tr = document.createElement('tr');
        tr.innerHTML = `
          <td>${customer.contact}</td>
          <td>${customer.name}</td>
          <td>${customer.email || '-'}</td>
          <td>${customer.address || '-'}</td>
          <td>
            <button class="edit-btn" onclick="editCustomer(${index})">Edit</button>
            <button class="delete-btn" onclick="deleteCustomer(${index})">Delete</button>
          </td>
        `;
        tbody.appendChild(tr);
      });
    }
    
    function editCustomer(index) {
      editingCustomerIndex = index;
      const customer = customerDatabase[index];
      document.getElementById('editCustomerContact').value = customer.contact;
      document.getElementById('editCustomerName').value = customer.name;
      document.getElementById('editCustomerEmail').value = customer.email;
      document.getElementById('editCustomerAddress').value = customer.address;
      document.getElementById('editCustomerDialogOverlay').style.display = 'flex';
    }
    
    function saveEditedCustomer() {
      const contact = sanitizeInput(document.getElementById('editCustomerContact').value);
      const name = sanitizeInput(document.getElementById('editCustomerName').value);
      const email = sanitizeInput(document.getElementById('editCustomerEmail').value);
      const address = sanitizeInput(document.getElementById('editCustomerAddress').value);
    
      if (!contact || !name) {
        showStatus('Please fill in contact number and customer name.', 'error');
        return;
      }
    
      if (customerDatabase.find((customer, idx) => idx !== editingCustomerIndex && customer.contact === contact)) {
        showStatus('Customer with this contact number already exists.', 'error');
        return;
      }
    
      customerDatabase[editingCustomerIndex] = { contact, name, email, address };
      loadCustomerTable();
      closeDialog(null, 'editCustomerDialogOverlay');
      showStatus('Customer updated successfully!', 'success');
      editingCustomerIndex = null;
    }
    
    function deleteCustomer(index) {
      if (confirm('Are you sure you want to delete this customer?')) {
        customerDatabase.splice(index, 1);
        loadCustomerTable();
        showStatus('Customer deleted successfully!', 'success');
      }
    }
    
    function backupData() {
      const data = {
        inventory: inventory,
        customers: customerDatabase,
        invoices: invoices
      };
      const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = `backup_${new Date().toISOString().split('T')[0]}.json`;
      link.click();
      URL.revokeObjectURL(url);
      showStatus('Backup created successfully!', 'success');
    }
    
    function restoreData() {
      const fileInput = document.getElementById('restoreFileInput');
      const file = fileInput.files[0];
      if (!file) {
        showStatus('Please select a file to restore.', 'error');
        return;
      }
      const reader = new FileReader();
      reader.onload = function(e) {
        try {
          const data = JSON.parse(e.target.result);
          inventory.length = 0;
          inventory.push(...data.inventory);
          customerDatabase.length = 0;
          customerDatabase.push(...data.customers);
          invoices.length = 0;
          invoices.push(...data.invoices);
          loadStockTable();
          loadCustomerTable();
          updateDashboard();
          showStatus('Data restored successfully!', 'success');
        } catch (err) {
          showStatus('Invalid backup file.', 'error');
        }
      };
      reader.readAsText(file);
    }
    
    function backupStockData() {
      const blob = new Blob([JSON.stringify(inventory, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = `stock_backup_${new Date().toISOString().split('T')[0]}.json`;
      link.click();
      URL.revokeObjectURL(url);
      showStatus('Stock data backed up successfully!', 'success');
    }
    
    function restoreStockData() {
      const fileInput = document.getElementById('restoreStockFileInput');
      const file = fileInput.files[0];
      if (!file) {
        showStatus('Please select a file to restore.', 'error');
        return;
      }
      const reader = new FileReader();
      reader.onload = function(e) {
        try {
          inventory.length = 0;
          inventory.push(...JSON.parse(e.target.result));
          loadStockTable();
          showStatus('Stock data restored successfully!', 'success');
        } catch (err) {
          showStatus('Invalid stock backup file.', 'error');
        }
      };
      reader.readAsText(file);
    }
    
    function backupCustomerData() {
      const blob = new Blob([JSON.stringify(customerDatabase, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = `customer_backup_${new Date().toISOString().split('T')[0]}.json`;
      link.click();
      URL.revokeObjectURL(url);
      showStatus('Customer data backed up successfully!', 'success');
    }
    
    function restoreCustomerData() {
      const fileInput = document.getElementById('restoreCustomerFileInput');
      const file = fileInput.files[0];
      if (!file) {
        showStatus('Please select a file to restore.', 'error');
        return;
      }
      const reader = new FileReader();
      reader.onload = function(e) {
        try {
          customerDatabase.length = 0;
          customerDatabase.push(...JSON.parse(e.target.result));
          loadCustomerTable();
          showStatus('Customer data restored successfully!', 'success');
        } catch (err) {
          showStatus('Invalid customer backup file.', 'error');
        }
      };
      reader.readAsText(file);
    }
    
    function toggleCustomDateRange() {
      const select = document.getElementById('dateRangeFilter');
      const customRange = document.getElementById('customDateRange');
      customRange.classList.toggle('hidden', select.value !== 'custom');
    }
    
    function updateDashboard() {
      const dateRange = document.getElementById('dateRangeFilter').value;
      let fromDate, toDate = new Date();
      if (dateRange === 'custom') {
        fromDate = new Date(document.getElementById('fromDate').value);
        toDate = new Date(document.getElementById('toDate').value);
        if (!fromDate || !toDate || fromDate > toDate) {
          showStatus('Please select a valid date range.', 'error');
          return;
        }
      } else {
        fromDate = new Date();
        fromDate.setDate(toDate.getDate() - parseInt(dateRange));
      }
    
      const filteredInvoices = invoices.filter(inv => {
        const invDate = new Date(inv.timestamp);
        return invDate >= fromDate && invDate <= toDate;
      });
    
      let totalRevenue = 0;
      let totalOrders = filteredInvoices.length;
      let totalProducts = 0;
      const customerSet = new Set();
      const productSales = {};
    
      filteredInvoices.forEach(inv => {
        totalRevenue += inv.grandTotal;
        inv.items.forEach(item => {
          totalProducts += item.quantity;
          productSales[item.code] = productSales[item.code] || { code: item.code, description: item.description, quantity: 0 };
          productSales[item.code].quantity += item.quantity;
        });
        customerSet.add(inv.clientContact);
      });
    
      document.getElementById('totalRevenue').textContent = `₹${totalRevenue.toFixed(2)}`;
      document.getElementById('totalOrders').textContent = totalOrders;
      document.getElementById('totalCustomers').textContent = customerSet.size;
      document.getElementById('totalProducts').textContent = totalProducts;
    
      const topProductsList = document.getElementById('topProductsList');
      topProductsList.innerHTML = '';
      Object.values(productSales)
        .sort((a, b) => b.quantity - a.quantity)
        .slice(0, 5)
        .forEach(product => {
          const div = document.createElement('div');
          div.textContent = `${product.code} - ${product.description} (${product.quantity} sold)`;
          topProductsList.appendChild(div);
        });
    
      const recentOrdersList = document.getElementById('recentOrdersList');
      recentOrdersList.innerHTML = '';
      filteredInvoices
        .sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
        .slice(0, 5)
        .forEach(inv => {
          const div = document.createElement('div');
          div.textContent = `${inv.invoiceNumber} - ${inv.clientName} (₹${inv.grandTotal.toFixed(2)})`;
          div.addEventListener('click', () => loadInvoiceToForm(inv));
          recentOrdersList.appendChild(div);
        });
    }
    
    function loadInvoiceToForm(invoice) {
      document.getElementById('invoiceNumber').value = invoice.invoiceNumber;
      document.getElementById('invoiceDate').value = invoice.invoiceDate;
      document.getElementById('dueDate').value = invoice.dueDate;
      document.getElementById('clientContact').value = invoice.clientContact;
      document.getElementById('clientName').value = invoice.clientName;
      document.getElementById('clientEmail').value = invoice.clientEmail;
      document.getElementById('clientAddress').value = invoice.clientAddress;
      document.getElementById('whatsappNumber').value = invoice.clientContact;
    
      const itemsList = document.getElementById('itemsList').querySelector('tbody');
      itemsList.innerHTML = '';
      invoice.items.forEach(item => {
        const row = document.createElement('tr');
        row.className = 'item-row';
        row.innerHTML = `
          <td><input type="text" class="item-code code-input" value="${item.code}" placeholder="Enter item code..."><div class="dropdown item-dropdown"></div></td>
          <td><input type="text" class="item-desc desc-input" value="${item.description}" placeholder="Service or product description"></td>
          <td><input type="number" class="item-qty qty-input" value="${item.quantity}" min="1"></td>
          <td><input type="number" class="item-rate rate-input" value="${item.rate.toFixed(2)}" step="0.01" min="0"></td>
          <td><input type="number" class="item-disc disc-input" value="${item.discount}" step="0.01" min="0" max="100"></td>
          <td><input type="number" class="item-sgst sgst-input" value="${item.sgst}" step="0.01" min="0"></td>
          <td><input type="number" class="item-cgst cgst-input" value="${item.cgst}" step="0.01" min="0"></td>
          <td><input type="text" class="item-total total-input" value="${item.total.toFixed(2)}" readonly></td>
          <td><button class="remove-btn" onclick="removeItem(this)">Remove</button></td>
        `;
        itemsList.appendChild(row);
        attachInputListeners(row);
        setupItemAutocomplete(row);
      });
      updateItemTotals();
      showStatus('Invoice loaded successfully!', 'success');
    }
    
    function clearInvoices() {
      if (confirm('Are you sure you want to clear all invoices? This cannot be undone.')) {
        invoices = [];
        localStorage.setItem('invoices', JSON.stringify(invoices));
        updateDashboard();
        showStatus('All invoices cleared.', 'success');
      }
    }
    
    function handleLogoUpload() {
      const fileInput = document.getElementById('logoUpload');
      fileInput.addEventListener('change', (e) => {
        const file = e.target.files[0];
        if (!file) return;
        const reader = new FileReader();
        reader.onload = function(event) {
          if (logoElement) logoElement.remove();
          logoElement = document.createElement('div');
          logoElement.className = 'invoice-logo';
          logoElement.innerHTML = `
            <img src="${event.target.result}" alt="Logo">
            <div class="resize-handle top-left"></div>
            <div class="resize-handle top-right"></div>
            <div class="resize-handle bottom-left"></div>
            <div class="resize-handle bottom-right"></div>
          `;
          document.querySelector('.invoice-box').prepend(logoElement);
          const img = logoElement.querySelector('img');
          img.onload = () => {
            originalAspectRatio = img.naturalWidth / img.naturalHeight;
            logoElement.style.width = '100px';
            logoElement.style.height = '100px';
            document.getElementById('logoWidth').value = 100;
            document.getElementById('logoHeight').value = 100;
            setupLogoInteractions();
          };
        };
        reader.readAsDataURL(file);
      });
    }
    
    function setupLogoInteractions() {
      if (!logoElement) return;
    
      logoElement.addEventListener('mousedown', startLogoDrag);
      logoElement.addEventListener('touchstart', startLogoDrag);
      logoElement.addEventListener('dblclick', toggleLogoHandles);
    
      const handles = logoElement.querySelectorAll('.resize-handle');
      handles.forEach(handle => {
        handle.addEventListener('mousedown', (e) => startResize(e, handle));
        handle.addEventListener('touchstart', (e) => startResize(e, handle));
      });
    
      document.getElementById('logoWidth').addEventListener('input', updateLogoSize);
      document.getElementById('logoHeight').addEventListener('input', updateLogoSize);
    }
    
    function startLogoDrag(e) {
      e.preventDefault();
      if (isResizing) return;
      isLogoDragging = true;
      const rect = logoElement.getBoundingClientRect();
      const clientX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
      const clientY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY;
      dragOffset.x = clientX - rect.left;
      dragOffset.y = clientY - rect.top;
      document.addEventListener('mousemove', dragLogo);
      document.addEventListener('touchmove', dragLogo);
      document.addEventListener('mouseup', stopLogoDrag);
      document.addEventListener('touchend', stopLogoDrag);
    }
    
    function dragLogo(e) {
      if (!isLogoDragging) return;
      const clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
      const clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
      const invoiceBox = document.querySelector('.invoice-box').getBoundingClientRect();
      let newLeft = clientX - dragOffset.x - invoiceBox.left;
      let newTop = clientY - dragOffset.y - invoiceBox.top;
      newLeft = Math.max(0, Math.min(newLeft, invoiceBox.width - logoElement.offsetWidth));
      newTop = Math.max(0, Math.min(newTop, invoiceBox.height - logoElement.offsetHeight));
      logoElement.style.left = `${newLeft}px`;
      logoElement.style.top = `${newTop}px`;
    }
    
    function stopLogoDrag() {
      isLogoDragging = false;
      document.removeEventListener('mousemove', dragLogo);
      document.removeEventListener('touchmove', dragLogo);
      document.removeEventListener('mouseup', stopLogoDrag);
      document.removeEventListener('touchend', stopLogoDrag);
    }
    
    function startResize(e, handle) {
      e.preventDefault();
      isResizing = true;
      resizeHandle = handle;
      const rect = logoElement.getBoundingClientRect();
      logoStartPos = { x: rect.left, y: rect.top };
      logoStartSize = { width: rect.width, height: rect.height };
      document.addEventListener('mousemove', resizeLogo);
      document.addEventListener('touchmove', resizeLogo);
      document.addEventListener('mouseup', stopResize);
      document.addEventListener('touchend', stopResize);
    }
    
    function resizeLogo(e) {
      if (!isResizing) return;
      const clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
      const clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
      const invoiceBox = document.querySelector('.invoice-box').getBoundingClientRect();
      let newWidth, newHeight, newLeft, newTop;
    
      if (resizeHandle.classList.contains('top-left')) {
        newWidth = logoStartSize.width + (logoStartPos.x - clientX);
        newHeight = document.getElementById('lockAspectRatio').checked
          ? newWidth / originalAspectRatio
          : logoStartSize.height + (logoStartPos.y - clientY);
        newLeft = logoStartPos.x + logoStartSize.width - newWidth;
        newTop = document.getElementById('lockAspectRatio').checked
          ? logoStartPos.y + logoStartSize.height - newHeight
          : logoStartPos.y + logoStartSize.height - newHeight;
      } else if (resizeHandle.classList.contains('top-right')) {
        newWidth = clientX - logoStartPos.x;
        newHeight = document.getElementById('lockAspectRatio').checked
          ? newWidth / originalAspectRatio
          : logoStartSize.height + (logoStartPos.y - clientY);
        newLeft = logoStartPos.x;
        newTop = document.getElementById('lockAspectRatio').checked
          ? logoStartPos.y + logoStartSize.height - newHeight
          : logoStartPos.y + logoStartSize.height - newHeight;
      } else if (resizeHandle.classList.contains('bottom-left')) {
        newWidth = logoStartSize.width + (logoStartPos.x - clientX);
        newHeight = document.getElementById('lockAspectRatio').checked
          ? newWidth / originalAspectRatio
          : clientY - logoStartPos.y;
        newLeft = logoStartPos.x + logoStartSize.width - newWidth;
        newTop = logoStartPos.y;
      } else {
        newWidth = clientX - logoStartPos.x;
        newHeight = document.getElementById('lockAspectRatio').checked
          ? newWidth / originalAspectRatio
          : clientY - logoStartPos.y;
        newLeft = logoStartPos.x;
        newTop = logoStartPos.y;
      }
    
      newWidth = Math.max(20, Math.min(newWidth, 300));
      newHeight = Math.max(20, Math.min(newHeight, 300));
      newLeft = Math.max(0, Math.min(newLeft, invoiceBox.width - newWidth));
      newTop = Math.max(0, Math.min(newTop, invoiceBox.height - newHeight));
    
      logoElement.style.width = `${newWidth}px`;
      logoElement.style.height = `${newHeight}px`;
      logoElement.style.left = `${newLeft}px`;
      logoElement.style.top = `${newTop}px`;
    
      document.getElementById('logoWidth').value = Math.round(newWidth);
      document.getElementById('logoHeight').value = Math.round(newHeight);
    }
    
    function stopResize() {
      isResizing = false;
      resizeHandle = null;
      document.removeEventListener('mousemove', resizeLogo);
      document.removeEventListener('touchmove', resizeLogo);
      document.removeEventListener('mouseup', stopResize);
      document.removeEventListener('touchend', stopResize);
    }
    
    function updateLogoSize() {
      if (!logoElement) return;
      let width = parseInt(document.getElementById('logoWidth').value) || 100;
      let height = parseInt(document.getElementById('logoHeight').value) || 100;
      if (document.getElementById('lockAspectRatio').checked) {
        if (document.activeElement.id === 'logoWidth') {
          height = width / originalAspectRatio;
        } else {
          width = height * originalAspectRatio;
        }
      }
      width = Math.max(20, Math.min(width, 300));
      height = Math.max(20, Math.min(height, 300));
      logoElement.style.width = `${width}px`;
      logoElement.style.height = `${height}px`;
      document.getElementById('logoWidth').value = Math.round(width);
      document.getElementById('logoHeight').value = Math.round(height);
    }
    
    function resetLogoPosition() {
      if (logoElement) {
        logoElement.style.left = '20px';
        logoElement.style.top = '20px';
        logoElement.style.width = '100px';
        logoElement.style.height = '100px';
        document.getElementById('logoWidth').value = 100;
        document.getElementById('logoHeight').value = 100;
      }
    }
    
    function removeLogo() {
      if (logoElement) {
        logoElement.remove();
        logoElement = null;
        document.getElementById('logoUpload').value = '';
        document.getElementById('logoWidth').value = '';
        document.getElementById('logoHeight').value = '';
      }
    }
    
    function toggleLogoHandles() {
      if (!logoElement) return;
      const currentTime = new Date().getTime();
      if (currentTime - lastTapTime < 300) {
        logoElement.classList.toggle('active');
      }
      lastTapTime = currentTime;
    }
    
    // Initialize application
    document.addEventListener('DOMContentLoaded', () => {
      document.querySelectorAll('.nav-btn').forEach(btn => {
        btn.addEventListener('click', () => {
          document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
          btn.classList.add('active');
          document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
          document.getElementById(btn.dataset.section).classList.add('active');
        });
      });
    
      document.querySelectorAll('.item-row').forEach(row => {
        attachInputListeners(row);
        setupItemAutocomplete(row);
      });
    
      setupCustomerAutocomplete();
      handleLogoUpload();
      loadStockTable();
      loadCustomerTable();
      updateDashboard();
    
      // Set default dates
      const today = new Date().toISOString().split('T')[0];
      document.getElementById('invoiceDate').value = today;
      document.getElementById('dueDate').value = new Date(new Date().setMonth(new Date().getMonth() + 1)).toISOString().split('T')[0];
    });
    </script>
    </body>
    </html>

    No comments:

    Post a Comment