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
- 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.
- Add Your First Customer: Go to the "Customer Database" section and add customer details. Include contact number, name, email, and address.
- 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.
Creating an Invoice
- Select Customer: In the "Invoice Generator" section, start typing a customer's contact number. The system will auto-complete their details.
- 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.
- Review & Generate: Check quantities, apply discounts if needed, and click "Generate Invoice" to see the preview with automatic tax calculations.
- 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
- 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.).
- Low Stock Alerts: Items with 5 or fewer units remaining are highlighted in red to help you restock in time.
- Editing Items: Click "Edit" on any inventory item to modify details, or "Delete" to remove items you no longer sell.
Sales Dashboard
- Analytics Overview: View total revenue, order count, active customers, and products sold for different time periods.
- Top Products: See which items are selling best to help with inventory planning and marketing decisions.
- Recent Orders: Quick access to your latest invoices for customer service and order tracking.
Technical Specifications
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
- Set Up WhatsApp Number: Enter the customer's WhatsApp number in international format (e.g., +919037393709).
- Customize Message: Adjust the description length and choose whether to include GST details in the WhatsApp message.
- Preview Before Sending: Click "Preview WhatsApp Message" to see exactly what will be sent to your customer.
- 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 FileHere 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')">×</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')">×</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