Thursday, September 18, 2025

TaxlessInvoiceWighCode

Tax-Free Invoice System - Complete User Guide

🇮🇳 Tax-Free Invoice System

A comprehensive web-based invoicing solution designed for small businesses and freelancers. Create professional invoices, manage inventory, track customers, and analyze sales - all in one powerful application.

📋System Overview

This Tax-Free Invoice System is a complete business management solution built as a single HTML file with advanced JavaScript functionality. It uses IndexedDB for local data storage, ensuring your data stays private and secure on your device.

📄 Invoice Generation

Create professional invoices with customizable company details, client information, and itemized billing.

📊 Sales Dashboard

Track revenue, orders, and sales performance with interactive charts and analytics.

📦 Inventory Management

Manage your products with HSN/SAC codes, pricing, stock levels, and automated low-stock alerts.

👥 Customer Database

Store customer information with auto-complete features and purchase history tracking.

💾 Data Management

Backup and restore your data, export to CSV, and maintain data integrity.

📱 WhatsApp Integration

Share invoices directly via WhatsApp with formatted messages and PDF attachments.

🚀Getting Started

📥 Setup Instructions

  1. Save the HTML file to your computer with a name like invoice-system.html
  2. Open the file in a modern web browser (Chrome, Firefox, Safari, or Edge)
  3. The system will automatically initialize with sample data
  4. Start by customizing your company information in the Invoice Generator section
💡 Pro Tip: Bookmark the file in your browser for quick access. The system works entirely offline after the initial load.

🔧 Technical Requirements

  • Browser Support: Chrome 60+, Firefox 58+, Safari 12+, Edge 79+
  • Storage: IndexedDB (modern browsers)
  • Internet Required: Only for CDN libraries (initial load)
  • File Size: ~50KB HTML file
  • Data Storage: Local device only (private & secure)

🧭Navigation Guide

The system is organized into five main sections, accessible via the top navigation menu:

📋 Invoice Generator

Main section for creating and customizing invoices. Includes company setup, client details, item management, and invoice preview.

📊 Sales Dashboard

Analytics and reporting section showing sales metrics, top products, recent orders, and revenue tracking.

📦 Stock Management

Inventory control center for adding, editing, and monitoring product stock levels with low-stock alerts.

👥 Customer Database

Customer relationship management with contact details, purchase history, and quick client lookup.

💾 Backup & Restore

Data management tools for backing up, restoring, and exporting your business data.

📝Creating Your First Invoice

🏢 Company Information Setup

  1. Enter your Company Name in the first field
  2. Add your complete Business Address in the textarea
  3. Include Contact Information (email, phone, website)
  4. Optionally upload a Company Logo using the file input

🖼️ Logo Management

Logo Features:
  • Upload images in JPG, PNG, or GIF format
  • Drag and drop to reposition the logo on the invoice
  • Resize by dragging the corner handles
  • Lock aspect ratio to maintain proportions
  • Double-click logo to hide/show resize handles

👤 Client Information

  1. Start typing the Client Contact Number
  2. If the client exists in your database, details will auto-populate
  3. For new clients, manually enter Name, Email, and Address
  4. The system automatically saves new client information

📦 Adding Items to Invoice

Enter HSN/SAC Code
Auto-populate Details
Set Quantity & Rate
Apply Discounts
Calculate Totals
  1. HSN/SAC Code: Enter the code and use autocomplete to select from inventory
  2. Description: Product/service description (auto-filled from inventory)
  3. Unit: Select measurement unit (PCS, KG, LTR, MTR, BOX, SET)
  4. Quantity: Enter quantity (validates against available stock)
  5. Rate: Price per unit (auto-filled from inventory)
  6. Discount: Choose percentage (%) or amount (₹) discount
⚠️ Stock Validation: The system prevents you from selling more items than available in stock. Insufficient stock items will be highlighted in red.

Advanced Features

📊 Sales Dashboard Analytics

Revenue Tracking

Monitor total revenue, orders, and customer metrics with customizable date ranges (7, 30, 90, 365 days, or custom).

Top Products

Identify your best-selling products based on quantity sold within the selected time period.

Recent Orders

Quick overview of recent transactions with invoice numbers, dates, and amounts.

📦 Inventory Management

  1. Add Items: Enter Item Code, HSN/SAC Code, Description, Rate, Unit, and Stock Quantity
  2. Set Discounts: Configure default discount (percentage or fixed amount)
  3. Stock Monitoring: Items with ≤5 units display in red for low stock alerts
  4. Edit/Delete: Modify existing items or remove discontinued products

👥 Customer Management

Customer Database

Store contact numbers, names, email addresses, and physical addresses for quick invoice generation.

Purchase History

View complete purchase history for any customer, including all invoices and items purchased.

Auto-complete

Smart search functionality that matches contact numbers or customer names for quick selection.

📱WhatsApp Integration

💬 Sending Invoice Messages

  1. Enter the recipient's WhatsApp number with country code (+91 for India)
  2. Set the maximum description length to control message size (10-50 characters)
  3. Click "Preview WhatsApp Message" to see the formatted text
  4. Click "Send via WhatsApp" to open WhatsApp with the pre-filled message

📄 PDF Sharing

Download PDF

Generate and download a professional PDF version of your invoice with company logo and formatting.

Share PDF via WhatsApp

Create PDF and share directly through WhatsApp (uses device sharing capabilities when available).

Print Invoice

Print-optimized view that hides navigation and shows only the invoice content.

📱 Mobile Tip: The WhatsApp message format is optimized for mobile viewing, with shortened descriptions and clean formatting.

💾Data Management & Backup

🔄 Backup Options

Complete Backup

Export all data (invoices, inventory, customers) to a single JSON file with timestamp.

Stock-Only Backup

Export just your inventory data for sharing product catalogs or transferring stock information.

Customer-Only Backup

Export customer database separately for CRM purposes or data migration.

Invoice Export (CSV)

Export all invoices to CSV format for accounting software or spreadsheet analysis.

📥 Restore Process

  1. Select the appropriate restore option (All Data, Stock Only, or Customers Only)
  2. Click "Choose File" and select your backup JSON file
  3. Click the corresponding "Restore" button
  4. The system will replace existing data with the backup data
⚠️ Important: Restoring data will overwrite existing information. Always create a backup before restoring from another file.

Best Practices & Tips

💡 Workflow Optimization

  1. Setup First: Configure company information and upload logo before creating invoices
  2. Build Inventory: Add your products/services to the stock management system
  3. Import Customers: Add frequent customers to enable auto-complete features
  4. Regular Backups: Export your data weekly to prevent data loss
  5. Monitor Stock: Check the dashboard regularly for low-stock alerts

🔐 Data Security

Privacy Features:
  • All data stored locally in your browser (IndexedDB)
  • No data transmitted to external servers
  • Works completely offline after initial load
  • Regular backups ensure data persistence

📱 Mobile Usage

Responsive Design

Optimized for mobile devices with touch-friendly interfaces and adaptive layouts.

Touch Controls

Logo positioning and resizing work with touch gestures on tablets and smartphones.

Mobile Sharing

WhatsApp integration works seamlessly on mobile devices with the native sharing API.

🔧Troubleshooting

❗ Common Issues

  1. Data Not Saving: Ensure you're using a modern browser with IndexedDB support
  2. PDF Generation Fails: Check if popup blockers are disabled for the page
  3. WhatsApp Not Opening: Verify the phone number format includes country code
  4. Logo Upload Issues: Use JPG, PNG, or GIF files under 5MB
  5. Backup File Errors: Ensure JSON files are valid and not corrupted

🔄 Data Recovery

Browser Data Loss: If you clear browser data, all invoices and settings will be lost. Regular backups are essential for data recovery.

🌐 Browser Compatibility

  • Recommended: Google Chrome (latest version)
  • Also Supports: Firefox, Safari, Edge (recent versions)
  • Not Supported: Internet Explorer, very old browser versions
  • Mobile: iOS Safari, Android Chrome

🎯Start Using the System

Ready to streamline your invoicing process? Save the HTML file, open it in your browser, and start creating professional invoices in minutes!


Key Benefits:

No Installation Required
Completely Free to Use
Works Offline
Professional Invoices
Inventory Management
Sales Analytics
Multiple Code Blocks

Here is The Code

Click or Tap to Copy


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Tax-Free Invoice System</title>
  <!-- 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>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js"></script>
  <script src="https://unpkg.com/dexie@latest/dist/dexie.min.js"></script>
  <style>
    * { box-sizing: border-box; }
    body { 
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 
      margin: 0; 
      padding: 20px; 
      background: #f5f5f5; 
      touch-action: manipulation; 
    }
    .container { max-width: 1400px; margin: auto; }
    .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, .form-group select { 
      width: 100%; 
      padding: 10px; 
      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: 10px; 
      border: 1px solid #ddd; 
      text-align: left; 
      font-size: 14px;
    }
    .items-table th { 
      background: #e9ecef; 
      font-weight: bold; 
      color: #333;
    }
    .items-table input, .items-table select { 
      width: 100%; 
      padding: 8px; 
      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 .total-input { min-width: 80px; }
    .items-table .disc-type-select { min-width: 60px; }
    .items-table .disc-input { min-width: 80px; }
    .items-table .unit-select { 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: 8px 12px; 
      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, .export-csv-btn, .view-purchases-btn { 
      background: #28a745; 
      color: white; 
      border: none; 
      padding: 12px 20px; 
      border-radius: 5px; 
      cursor: pointer; 
      margin-right: 10px; 
      margin-top: 10px;
      font-weight: bold;
      transition: all 0.3s;
    }
    .add-item-btn:hover, .add-stock-btn:hover, .add-customer-btn:hover, 
    .backup-btn:hover, .restore-btn:hover, .save-btn:hover, .export-csv-btn:hover,
    .view-purchases-btn:hover { 
      background: #218838; 
      transform: translateY(-2px);
    }
    .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; }
    .export-csv-btn { background: #17a2b8; }
    .export-csv-btn:hover { background: #138496; }
    .view-purchases-btn { background: #6c757d; }
    .view-purchases-btn:hover { background: #5a6268; }
    .stock-table, .customer-table, .purchase-history-table {
      width: 100%;
      border-collapse: collapse;
      margin-top: 20px;
    }
    .stock-table th, .stock-table td, .customer-table th, .customer-table td,
    .purchase-history-table th, .purchase-history-table td {
      border: 1px solid #ddd;
      padding: 12px;
      text-align: left;
    }
    .stock-table th, .customer-table th, .purchase-history-table th {
      background: #f8f9fa;
      font-weight: bold;
    }
    .stock-table tr:hover, .customer-table tr:hover, .purchase-history-table tr:hover {
      background: #f5f5f5;
    }
    .edit-btn, .delete-btn {
      padding: 6px 12px;
      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, .disc-error {
      border: 2px solid #dc3545 !important;
      background-color: #fff3f3 !important;
    }
    .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: 10px 20px; 
      background: #007bff; 
      color: #fff; 
      border: none; 
      cursor: pointer; 
      border-radius: 5px; 
      font-weight: bold;
    }
    .print-btn:hover { background: #0056b3; }
    .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;
    }
    .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, .purchase-history-container {
      max-height: calc(100% - 150px); 
      overflow-y: auto; 
      border: 1px solid #dee2e6;
      border-radius: 8px; 
      margin: 0 20px 20px 20px;
    }
    .item-table, .purchase-history-table { 
      width: 100%; 
      border-collapse: collapse; 
    }
    .item-table th, .item-table td, .purchase-history-table th, .purchase-history-table td { 
      padding: 10px; 
      text-align: left; 
      border-bottom: 1px solid #dee2e6; 
    }
    .item-table th, .purchase-history-table th { 
      background: #f8f9fa; 
      position: sticky; 
      top: 0; 
      font-weight: 600; 
      color: #495057; 
    }
    .item-table tbody tr, .purchase-history-table tbody tr { 
      cursor: pointer; 
      transition: background-color 0.2s ease; 
    }
    .item-table tbody tr:hover, .purchase-history-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, .purchase-history-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, .purchase-history-container { max-height: calc(100% - 120px); }
      .items-table th, .items-table td, .stock-table th, .stock-table td, 
      .customer-table th, .customer-table td, .purchase-history-table th, .purchase-history-table td { 
        font-size: 12px; 
        padding: 6px; 
      }
      .items-table input, .items-table select { font-size: 12px; padding: 4px; }
      .item-table th, .item-table td, .purchase-history-table th, .purchase-history-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);
    }
    .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;
      font-size: 1.1rem;
    }
    .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>🇮🇳 Tax-Free 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 class="dashboard-card" style="background: linear-gradient(135deg, #ffc107, #e0a800);">
          <h4>Total Discounts</h4>
          <p id="totalDiscount">₹0.00</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-001">
        </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>HSN/SAC Code</th>
              <th>Description</th>
              <th>Unit</th>
              <th>Qty</th>
              <th>Rate (₹)</th>
              <th>Disc Type</th>
              <th>Discount</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 HSN/SAC code..."><div class="dropdown item-dropdown"></div></td>
              <td><input type="text" class="item-desc desc-input" placeholder="Service or product description"></td>
              <td><select class="item-unit unit-select"><option value="PCS">PCS</option><option value="KG">KG</option><option value="LTR">LTR</option><option value="MTR">MTR</option><option value="BOX">BOX</option><option value="SET">SET</option></select></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>
                <select class="disc-type-select">
                  <option value="percent">%</option>
                  <option value="amount">₹</option>
                </select>
              </td>
              <td><input type="number" class="item-disc disc-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>
        <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-001</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>Code</th>
              <th>Description</th>
              <th>Unit</th>
              <th>Qty</th>
              <th>Rate</th>
              <th>Discount</th>
              <th>Total</th>
            </tr>
          </thead>
          <tbody id="previewItems">
            <tr>
              <td></td>
              <td>Sample Item</td>
              <td>PCS</td>
              <td>1</td>
              <td>₹0.00</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>Discount Type</label>
          <select id="stockDiscountType">
            <option value="percent">%</option>
            <option value="amount">₹</option>
          </select>
        </div>
        <div class="form-group">
          <label>Discount</label>
          <input type="number" id="stockDiscount" value="0" 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>Discount</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="form-row">
        <div class="form-group">
          <label>Export Invoices</label>
          <button class="export-csv-btn" onclick="exportInvoicesToCSV()">Export Invoices to CSV</button>
        </div>
      </div>
      <div class="status-message" id="backupStatusMessage"></div>
    </div>
  </div>
</div>

<!-- Item Selection Dialog -->
<div class="dialog-overlay" id="dialogOverlay" onclick="closeDialog(event, 'dialogOverlay')">
  <div class="dialog" id="itemDialog" onclick="event.stopPropagation()">
    <div class="dialog-header">
      <h3>Select Items</h3>
      <div class="dialog-controls">
        <div class="size-inputs">
          <span style="font-size: 0.8rem;">W:</span>
          <input type="number" class="size-input" id="itemWidthInput" value="600" min="300" max="1200">
          <span style="font-size: 0.8rem;">H:</span>
          <input type="number" class="size-input" id="itemHeightInput" value="450" min="200" max="800">
          <button class="apply-btn" onclick="applyCustomSize('itemDialog', 'itemWidthInput', 'itemHeightInput')">Apply</button>
        </div>
        <div class="resize-controls">
          <button class="resize-btn" onclick="quickResize(400, 250, 'itemDialog', 'itemWidthInput', 'itemHeightInput')" title="Compact">XS</button>
          <button class="resize-btn" onclick="quickResize(500, 350, 'itemDialog', 'itemWidthInput', 'itemHeightInput')" title="Small">S</button>
          <button class="resize-btn" onclick="quickResize(700, 500, 'itemDialog', 'itemWidthInput', 'itemHeightInput')" title="Large">L</button>
        </div>
        <button class="close-btn" onclick="closeDialog(null, 'dialogOverlay')">&times;</button>
      </div>
    </div>
    <div class="search-section">
      <input type="text" class="search-input" id="searchInput" placeholder="Search items by code, name, or description..." oninput="searchItems()">
    </div>
    <div class="status-message" id="statusMessage"></div>
    <div class="items-container">
      <table class="item-table">
        <thead>
          <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Description</th>
            <th>Price</th>
            <th>Discount</th>
          </tr>
        </thead>
        <tbody id="itemsList2">
        </tbody>
      </table>
    </div>
  </div>
</div>

<!-- Edit Customer Dialog -->
<div class="dialog-overlay" id="editCustomerDialogOverlay" onclick="closeDialog(event, 'editCustomerDialogOverlay')">
  <div class="dialog" id="editCustomerDialog" onclick="event.stopPropagation()">
    <div class="dialog-header">
      <h3>Edit Customer</h3>
      <button class="close-btn" onclick="closeDialog(null, 'editCustomerDialogOverlay')">&times;</button>
    </div>
    <div class="form-row" style="padding: 20px;">
      <div class="form-group">
        <label>Contact Number</label>
        <input type="text" id="editCustomerContact" placeholder="Enter contact number">
      </div>
      <div class="form-group">
        <label>Customer Name</label>
        <input type="text" id="editCustomerName" placeholder="Enter customer name">
      </div>
      <div class="form-group">
        <label>Email</label>
        <input type="email" id="editCustomerEmail" placeholder="Enter email">
      </div>
      <div class="form-group">
        <label>Address</label>
        <textarea id="editCustomerAddress" placeholder="Enter address"></textarea>
      </div>
    </div>
    <div style="padding: 0 20px 20px;">
      <button class="add-customer-btn" onclick="saveEditedCustomer()">Save Changes</button>
    </div>
  </div>
</div>

<!-- Purchase History Dialog -->
<div class="dialog-overlay" id="purchaseHistoryDialogOverlay" onclick="closeDialog(event, 'purchaseHistoryDialogOverlay')">
  <div class="dialog" id="purchaseHistoryDialog" onclick="event.stopPropagation()">
    <div class="dialog-header">
      <h3>Purchase History</h3>
      <div class="dialog-controls">
        <div class="size-inputs">
          <span style="font-size: 0.8rem;">W:</span>
          <input type="number" class="size-input" id="purchaseWidthInput" value="600" min="300" max="1200">
          <span style="font-size: 0.8rem;">H:</span>
          <input type="number" class="size-input" id="purchaseHeightInput" value="450" min="200" max="800">
          <button class="apply-btn" onclick="applyCustomSize('purchaseHistoryDialog', 'purchaseWidthInput', 'purchaseHeightInput')">Apply</button>
        </div>
        <div class="resize-controls">
          <button class="resize-btn" onclick="quickResize(400, 250, 'purchaseHistoryDialog', 'purchaseWidthInput', 'purchaseHeightInput')" title="Compact">XS</button>
          <button class="resize-btn" onclick="quickResize(500, 350, 'purchaseHistoryDialog', 'purchaseWidthInput', 'purchaseHeightInput')" title="Small">S</button>
          <button class="resize-btn" onclick="quickResize(700, 500, 'purchaseHistoryDialog', 'purchaseWidthInput', 'purchaseHeightInput')" title="Large">L</button>
        </div>
        <button class="close-btn" onclick="closeDialog(null, 'purchaseHistoryDialogOverlay')">&times;</button>
      </div>
    </div>
    <div class="status-message" id="purchaseStatusMessage"></div>
    <div class="purchase-history-container">
      <table class="purchase-history-table">
        <thead>
          <tr>
            <th>Invoice Number</th>
            <th>Date</th>
            <th>Total (₹)</th>
            <th>Items</th>
          </tr>
        </thead>
        <tbody id="purchaseHistoryList">
        </tbody>
      </table>
    </div>
  </div>
</div>

<script>
// Initialize Dexie.js database
const db = new Dexie('InvoiceDB');
db.version(1).stores({
  invoices: 'invoiceNumber,clientContact,timestamp',
  inventory: 'code,hsn,description',
  customers: 'contact,name'
});

// Default data for initial population
const defaultInventory = [
  { code: 'ITM001', hsn: '8471', name: 'Wireless Mouse', description: 'Ergonomic wireless mouse with USB receiver', price: 25.99, unit: 'PCS', quantity: 50, discountType: 'percent', discount: 5 },
  { code: 'ITM002', hsn: '8471', name: 'Keyboard', description: 'Mechanical gaming keyboard with RGB lighting', price: 89.99, unit: 'PCS', quantity: 30, discountType: 'amount', discount: 10 },
  { code: 'ITM003', hsn: '9403', name: 'Monitor Stand', description: 'Adjustable aluminum monitor stand', price: 45.00, unit: 'PCS', quantity: 20, discountType: 'percent', discount: 0 },
  { code: 'ITM004', hsn: '8544', name: 'USB Cable', description: '6ft USB-C to USB-A cable', price: 12.50, unit: 'PCS', quantity: 100, discountType: 'amount', discount: 2.50 },
  { code: 'ITM005', hsn: '8525', name: 'Webcam', description: '1080p HD webcam with built-in microphone', price: 67.99, unit: 'PCS', quantity: 15, discountType: 'percent', discount: 10 }
];

const defaultCustomers = [
  { 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' }
];

// Global variables
let inventory = [];
let customerDatabase = [];
let invoices = [];
let filteredInventory = [];
let editingCustomerContact = null;

// Migrate localStorage data to IndexedDB
async function migrateLocalStorageToIndexedDB() {
  try {
    const invoiceCount = await db.invoices.count();
    if (invoiceCount > 0) return; // Skip migration if IndexedDB already has data

    const localInventory = JSON.parse(localStorage.getItem('inventory'));
    const localCustomers = JSON.parse(localStorage.getItem('customerDatabase'));
    const localInvoices = JSON.parse(localStorage.getItem('invoices'));

    if (localInventory && localInventory.length > 0) {
      await db.inventory.bulkPut(localInventory);
    } else {
      await db.inventory.bulkPut(defaultInventory);
    }

    if (localCustomers && localCustomers.length > 0) {
      await db.customers.bulkPut(localCustomers);
    } else {
      await db.customers.bulkPut(defaultCustomers);
    }

    if (localInvoices && localInvoices.length > 0) {
      await db.invoices.bulkPut(localInvoices);
    }

    // Clear localStorage after migration
    localStorage.removeItem('inventory');
    localStorage.removeItem('customerDatabase');
    localStorage.removeItem('invoices');
  } catch (error) {
    showStatus('Error migrating data to IndexedDB: ' + error.message, 'error');
  }
}

// Load data from IndexedDB
async function loadDataFromIndexedDB() {
  try {
    inventory = await db.inventory.toArray();
    customerDatabase = await db.customers.toArray();
    invoices = await db.invoices.toArray();
    filteredInventory = [...inventory];
  } catch (error) {
    showStatus('Error loading data from IndexedDB: ' + error.message, 'error');
  }
}

// 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
async function generateInvoiceNumber() {
  try {
    const existingInvoices = await db.invoices.toArray();
    const existingNumbers = existingInvoices.map(inv => parseInt(inv.invoiceNumber.replace('INV-', '')));
    const nextNumber = existingNumbers.length ? Math.max(...existingNumbers) + 1 : 1;
    return `INV-${String(nextNumber).padStart(3, '0')}`;
  } catch (error) {
    showStatus('Error generating invoice number: ' + error.message, 'error');
    return `INV-${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`;
  }
}

// Navigation functionality
function setupNavigation() {
  const navButtons = document.querySelectorAll('.nav-btn');
  navButtons.forEach(button => {
    button.addEventListener('click', function() {
      navButtons.forEach(btn => btn.classList.remove('active'));
      this.classList.add('active');
      document.querySelectorAll('.section').forEach(section => section.classList.remove('active'));
      document.getElementById(this.getAttribute('data-section')).classList.add('active');
    });
  });
}

// Show status message
function showStatus(message, type) {
  const statusMessage = document.getElementById('statusMessage') || document.getElementById('backupStatusMessage');
  statusMessage.textContent = message;
  statusMessage.className = `status-message status-${type}`;
  statusMessage.style.display = 'block';
  setTimeout(() => {
    statusMessage.style.display = 'none';
  }, 3000);
}

// Show purchase history status message
function showPurchaseStatus(message, type) {
  const statusMessage = document.getElementById('purchaseStatusMessage');
  statusMessage.textContent = message;
  statusMessage.className = `status-message status-${type}`;
  statusMessage.style.display = 'block';
  setTimeout(() => {
    statusMessage.style.display = 'none';
  }, 3000);
}

// Add new item row
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 HSN/SAC code..."><div class="dropdown item-dropdown"></div></td>
    <td><input type="text" class="item-desc desc-input" placeholder="Service or product description"></td>
    <td><select class="item-unit unit-select"><option value="PCS">PCS</option><option value="KG">KG</option><option value="LTR">LTR</option><option value="MTR">MTR</option><option value="BOX">BOX</option><option value="SET">SET</option></select></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>
      <select class="disc-type-select">
        <option value="percent">%</option>
        <option value="amount">₹</option>
      </select>
    </td>
    <td><input type="number" class="item-disc disc-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();
  return newRow;
}

// Remove item row
function removeItem(button) {
  const itemsList = document.getElementById('itemsList').querySelector('tbody');
  if (itemsList.children.length > 1) {
    button.closest('tr').remove();
    updateItemTotals();
  } else {
    showStatus('At least one item is required.', 'error');
  }
}

// Attach input listeners for real-time calculations
function attachInputListeners(row) {
  row.querySelectorAll('.item-qty, .item-rate, .item-disc, .disc-type-select').forEach(input => {
    input.addEventListener('input', () => {
      const hsnCode = row.querySelector('.item-code').value;
      const itemCode = row.querySelector('.item-code').getAttribute('data-item-code');
      const qty = parseInt(row.querySelector('.item-qty').value) || 0;
      const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
      const discType = row.querySelector('.disc-type-select').value;
      const rate = parseFloat(row.querySelector('.item-rate').value) || 0;

      // Validate quantity using item code, not HSN code
      if (input.classList.contains('item-qty') && itemCode) {
        const item = inventory.find(i => i.code === itemCode); // Use item 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');
        }
      }

      // Validate discount
      if (input.classList.contains('item-disc') || input.classList.contains('disc-type-select')) {
        if (discType === 'percent' && disc > 100) {
          input.classList.add('disc-error');
          showStatus('Discount percentage cannot exceed 100%.', 'error');
          input.value = 100;
        } else if (discType === 'amount' && disc > qty * rate) {
          input.classList.add('disc-error');
          showStatus('Discount amount cannot exceed subtotal.', 'error');
          input.value = qty * rate;
        } else {
          input.classList.remove('disc-error');
        }
      }

      updateItemTotal(row);
      updateItemTotals();
    });
  });
}

// Update individual item total
function updateItemTotal(row) {
  const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
  const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
  const discType = row.querySelector('.disc-type-select').value;
  const disc = parseFloat(row.querySelector('.item-disc').value) || 0;

  const subtotal = qty * rate;
  let discAmount = discType === 'percent' ? subtotal * (disc / 100) : disc;
  const lineTotal = subtotal - discAmount;

  row.querySelector('.item-total').value = lineTotal.toFixed(2);
}

// Update all item totals and invoice preview
function updateItemTotals() {
  const rows = document.querySelectorAll('.item-row');
  let subtotal = 0, totalDiscount = 0, 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 disc = parseFloat(row.querySelector('.item-disc').value) || 0;
    const discType = row.querySelector('.disc-type-select').value;
    const rate = parseFloat(row.querySelector('.item-rate').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 (discType === 'percent' && disc > 100) {
      canGenerate = false;
      row.querySelector('.item-disc').classList.add('disc-error');
      showStatus('Discount percentage cannot exceed 100%.', 'error');
    } else if (discType === 'amount' && disc > qty * rate) {
      canGenerate = false;
      row.querySelector('.item-disc').classList.add('disc-error');
      showStatus('Discount amount cannot exceed subtotal.', 'error');
    } else {
      row.querySelector('.item-disc').classList.remove('disc-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 discType = row.querySelector('.disc-type-select').value;
    const disc = parseFloat(row.querySelector('.item-disc').value) || 0;

    const subtotalAmount = qty * rate;
    let discAmount = discType === 'percent' ? subtotalAmount * (disc / 100) : disc;
    const lineTotal = subtotalAmount - discAmount;

    row.querySelector('.item-total').value = lineTotal.toFixed(2);
    subtotal += subtotalAmount;
    totalDiscount += discAmount;
    grandTotal += lineTotal;
  });

  const totalsRow = `
    <tr>
      <td colspan="3"></td>
      <td colspan="2">Subtotal</td>
      <td>₹${subtotal.toFixed(2)}</td>
    </tr>
    <tr>
      <td colspan="3"></td>
      <td colspan="2">Total Discount</td>
      <td>₹${totalDiscount.toFixed(2)}</td>
    </tr>
    <tr>
      <td colspan="3"></td>
      <td colspan="2"><strong>Grand Total</strong></td>
      <td><strong>₹${grandTotal.toFixed(2)}</strong></td>
    </tr>
  `;
  generateInvoice(totalsRow);
}

// Save invoice and update inventory
async function saveInvoice() {
  try {
    const invoice = {
      invoiceNumber: document.getElementById('invoiceNumber').value || await 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,
      grandTotal: 0,
      timestamp: new Date().toISOString()
    };

    const rows = document.querySelectorAll('.item-row');
    let canSave = true;

    rows.forEach(row => {
      const hsnCode = row.querySelector('.item-code').value; // This is now HSN code
      const itemCode = row.querySelector('.item-code').getAttribute('data-item-code'); // Get actual item code
      const qty = parseInt(row.querySelector('.item-qty').value) || 0;
      const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
      const discType = row.querySelector('.disc-type-select').value;
      const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
      
      // Find item by item code for inventory check
      const item = inventory.find(i => i.code === itemCode);

      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');
      }
      if (discType === 'percent' && disc > 100) {
        canSave = false;
        row.querySelector('.item-disc').classList.add('disc-error');
        showStatus('Discount percentage cannot exceed 100%.', 'error');
      } else if (discType === 'amount' && disc > qty * rate) {
        canSave = false;
        row.querySelector('.item-disc').classList.add('disc-error');
        showStatus('Discount amount cannot exceed subtotal.', 'error');
      }
    });

    if (!canSave) return;

    rows.forEach(row => {
      const hsnCode = row.querySelector('.item-code').value; // HSN code for display
      const itemCode = row.querySelector('.item-code').getAttribute('data-item-code'); // Item code for inventory
      const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
      const unit = row.querySelector('.item-unit').value || 'PCS';
      const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
      const discType = row.querySelector('.disc-type-select').value;
      const disc = parseFloat(row.querySelector('.item-disc').value) || 0;

      const subtotalAmount = qty * rate;
      let discAmount = discType === 'percent' ? subtotalAmount * (disc / 100) : disc;
      const lineTotal = subtotalAmount - discAmount;

      invoice.items.push({
        code: sanitizeInput(hsnCode), // Store HSN code for invoice display
        itemCode: sanitizeInput(itemCode), // Store item code for inventory tracking
        description: sanitizeInput(row.querySelector('.item-desc').value),
        quantity: qty,
        unit: unit,
        rate: rate,
        discountType: discType,
        discount: disc,
        total: lineTotal
      });

      invoice.subtotal += subtotalAmount;
      invoice.totalDiscount += discAmount;
      invoice.grandTotal += lineTotal;

      // Update inventory using item code, not HSN code
      const item = inventory.find(i => i.code === itemCode);
      if (item) item.quantity -= qty;
    });

    if (!invoice.clientContact || !invoice.clientName || invoice.items.length === 0) {
      showStatus('Please fill in client details and add at least one item.', 'error');
      return;
    }

    await db.invoices.put(invoice);
    await db.inventory.bulkPut(inventory);
    invoices = await db.invoices.toArray();
    loadStockTable();
    showStatus('Invoice saved successfully!', 'success');
    updateDashboard();

    // Reset form
    document.getElementById('invoiceNumber').value = await generateInvoiceNumber();
    document.getElementById('clientContact').value = '';
    document.getElementById('clientName').value = '';
    document.getElementById('clientEmail').value = '';
    document.getElementById('clientAddress').value = '';
    document.getElementById('whatsappNumber').value = '';
    const itemsList = document.getElementById('itemsList').querySelector('tbody');
    itemsList.innerHTML = `
      <tr class="item-row">
        <td><input type="text" class="item-code code-input" placeholder="Enter HSN/SAC code..."><div class="dropdown item-dropdown"></div></td>
        <td><input type="text" class="item-desc desc-input" placeholder="Service or product description"></td>
        <td><select class="item-unit unit-select"><option value="PCS">PCS</option><option value="KG">KG</option><option value="LTR">LTR</option><option value="MTR">MTR</option><option value="BOX">BOX</option><option value="SET">SET</option></select></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>
          <select class="disc-type-select">
            <option value="percent">%</option>
            <option value="amount">₹</option>
          </select>
        </td>
        <td><input type="number" class="item-disc disc-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>
    `;
    document.querySelectorAll('.item-row').forEach(row => {
      attachInputListeners(row);
      setupItemAutocomplete(row);
    });
  } catch (error) {
    showStatus('Error saving invoice: ' + error.message, 'error');
  }
}

// Format date for display
function formatDate(dateString) {
  if (!dateString) return '';
  const date = new Date(dateString);
  return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' });
}

// Generate invoice preview
function generateInvoice(totalsRow) {
  const companyName = sanitizeInput(document.getElementById('companyName').value) || 'Your Company Name';
  const companyAddress = sanitizeInput(document.getElementById('companyAddress').value) || '123 Business Street, City, State - ZIP';
  const companyContact = sanitizeInput(document.getElementById('companyContact').value) || 'Email: info@company.com | Phone: +91 9037393709';
  const clientName = sanitizeInput(document.getElementById('clientName').value) || 'Customer Name';
  const clientAddress = sanitizeInput(document.getElementById('clientAddress').value) || 'Customer Address';
  const clientContact = sanitizeInput(document.getElementById('clientContact').value) || 'Customer Contact';
  const clientEmail = sanitizeInput(document.getElementById('clientEmail').value) || 'Customer Email';
  const invoiceNumber = sanitizeInput(document.getElementById('invoiceNumber').value) || 'INV-001';
  const invoiceDate = document.getElementById('invoiceDate').value || formatDate(new Date());
  const dueDate = document.getElementById('dueDate').value || formatDate(new Date());

  let itemsHTML = '';
  let grandTotal = 0;

  document.querySelectorAll('.item-row').forEach(row => {
    const code = sanitizeInput(row.querySelector('.item-code').value);
    const description = sanitizeInput(row.querySelector('.item-desc').value) || 'Sample Item';
    const unit = row.querySelector('.item-unit').value || 'PCS';
    const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
    const rate = parseFloat(row.querySelector('.item-rate').value) || 0;
    const discType = row.querySelector('.disc-type-select').value;
    const disc = parseFloat(row.querySelector('.item-disc').value) || 0;
    const subtotal = qty * rate;
    let discAmount = discType === 'percent' ? subtotal * (disc / 100) : disc;
    const lineTotal = subtotal - discAmount;
    grandTotal += lineTotal;

    itemsHTML += `
      <tr>
        <td>${code}</td>
        <td>${description}</td>
        <td>${unit}</td>
        <td>${qty}</td>
        <td>₹${rate.toFixed(2)}</td>
        <td>${disc}${discType === 'percent' ? '%' : '₹'}</td>
        <td>₹${lineTotal.toFixed(2)}</td>
      </tr>
    `;
  });

  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);
  document.getElementById('previewItems').innerHTML = itemsHTML;
  document.getElementById('previewTotal').textContent = `₹${grandTotal.toFixed(2)}`;
}

// Generate PDF
async function generatePDF() {
  try {
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF();
    const invoiceBox = document.querySelector('.invoice-box');
    const logoElement = document.querySelector('.invoice-logo img');
    const logoPosition = JSON.parse(localStorage.getItem('logoPosition')) || { x: 20, y: 20, width: 100, height: 50 };

    // Add logo if present
    if (logoElement && logoElement.src) {
      try {
        const imgData = await getImageData(logoElement);
        doc.addImage(imgData, 'PNG', logoPosition.x, logoPosition.y, logoPosition.width, logoPosition.height);
      } catch (error) {
        console.error('Error adding logo to PDF:', error);
      }
    }

    // Add company details
    doc.setFontSize(14);
    doc.setFont('helvetica', 'bold');
    doc.text(document.getElementById('previewCompanyName').textContent, 20, logoPosition.y + logoPosition.height + 10);
    doc.setFontSize(10);
    doc.setFont('helvetica', 'normal');
    doc.text(document.getElementById('previewCompanyAddress').textContent, 20, logoPosition.y + logoPosition.height + 20);
    doc.text(document.getElementById('previewCompanyContact').textContent, 20, logoPosition.y + logoPosition.height + 30);

    // Add invoice header
    doc.setFontSize(16);
    doc.setTextColor(255, 0, 0);
    doc.text('INVOICE', 140, 40);
    doc.setTextColor(0);
    doc.setFontSize(10);
    doc.text(`Invoice #: ${document.getElementById('previewInvoiceNumber').textContent}`, 140, 50);
    doc.text(`Invoice Date: ${document.getElementById('previewInvoiceDate').textContent}`, 140, 60);
    doc.text(`Due Date: ${document.getElementById('previewDueDate').textContent}`, 140, 70);

    // Add bill to
    doc.text('Bill To', 20, 80);
    doc.text(document.getElementById('previewClientName').textContent, 20, 90);
    doc.text(document.getElementById('previewClientAddress').textContent, 20, 100);
    doc.text(`Contact: ${document.getElementById('previewClientContact').textContent}`, 20, 110);
    doc.text(`Email: ${document.getElementById('previewClientEmail').textContent}`, 20, 120);

    // Add items table
    const items = [];
    document.querySelectorAll('#previewItems tr').forEach(row => {
      const cells = row.querySelectorAll('td');
      items.push([
        cells[0].textContent,
        cells[1].textContent,
        cells[2].textContent,
        cells[3].textContent,
        cells[4].textContent,
        cells[5].textContent,
        cells[6].textContent
      ]);
    });

    doc.autoTable({
      startY: 130,
      head: [['Code', 'Description', 'Unit', 'Qty', 'Rate', 'Discount', 'Total']],
      body: items,
      theme: 'grid',
      headStyles: { fillColor: [248, 249, 250], textColor: [0, 0, 0] },
      styles: { fontSize: 10 },
    });

    // Add total
    const finalY = doc.lastAutoTable.finalY;
    doc.setFontSize(12);
    doc.setFont('helvetica', 'bold');
    doc.text(`Grand Total: ${document.getElementById('previewTotal').textContent}`, 140, finalY + 10);

    doc.save(`Invoice_${document.getElementById('previewInvoiceNumber').textContent}.pdf`);
  } catch (error) {
    showStatus('Error generating PDF: ' + error.message, 'error');
  }
}

// Share PDF via WhatsApp
async function sharePDF() {
    const { jsPDF } = window.jspdf;
    const invoiceBox = document.querySelector('.invoice-box');
    const whatsappNumber = document.getElementById('whatsappNumber').value;
    if (!whatsappNumber) {
        showStatus('Please enter a WhatsApp number.', 'error');
        return;
    }
    try {
        const canvas = await html2canvas(invoiceBox, { scale: 2, useCORS: true });
        const imgData = canvas.toDataURL('image/jpeg', 1.0);
        const pdf = new jsPDF({
            orientation: 'portrait',
            unit: 'mm',
            format: 'a4'
        });
        const imgWidth = 190;
        const pageHeight = 295;
        const imgHeight = canvas.height * imgWidth / canvas.width;
        let heightLeft = imgHeight;
        let position = 10;

        pdf.addImage(imgData, 'JPEG', 10, position, imgWidth, imgHeight);
        heightLeft -= pageHeight - 20;

        while (heightLeft > 0) {
            position = heightLeft - imgHeight + 10;
            pdf.addPage();
            pdf.addImage(imgData, 'JPEG', 10, position, imgWidth, imgHeight);
            heightLeft -= pageHeight - 20;
        }

        const pdfBlob = pdf.output('blob');
        const file = new File([pdfBlob], `Invoice_${document.getElementById('invoiceNumber').value}.pdf`, { type: 'application/pdf' });
        const formattedNumber = whatsappNumber.replace(/[^0-9]/g, '');
        if (navigator.share) {
            await navigator.share({
                files: [file],
                title: `Invoice ${document.getElementById('invoiceNumber').value}`,
                text: `Here is your invoice #${document.getElementById('invoiceNumber').value}`
            });
            showStatus('PDF shared successfully!', 'success');
        } else {
            const encodedMessage = encodeURIComponent(`Here is your invoice #${document.getElementById('invoiceNumber').value}`);
            const pdfDataUri = pdf.output('datauristring');
            const whatsappUrl = `https://wa.me/${formattedNumber}?text=${encodedMessage}`;
            window.open(whatsappUrl, '_blank');
            showStatus('PDF cannot be shared directly. Opening WhatsApp with a link to send manually.', 'success');
        }
    } catch (error) {
        console.error('Error sharing PDF:', error);
        showStatus('Failed to share PDF.', 'error');
    }
}

// Print invoice
function printInvoice() {
  window.print();
}

// Get image data for PDF
async function getImageData(imgElement) {
  const canvas = await html2canvas(imgElement, { scale: 2 });
  return canvas.toDataURL('image/png');
}

// Setup item autocomplete
function setupItemAutocomplete(row) {
  const codeInput = row.querySelector('.item-code');
  const dropdown = row.querySelector('.item-dropdown');
  codeInput.addEventListener('input', debounce(async function() {
    const query = codeInput.value.toLowerCase();
    const filteredItems = inventory.filter(item =>
      item.code.toLowerCase().includes(query) ||
      item.description.toLowerCase().includes(query) ||
      item.hsn.toLowerCase().includes(query)
    );

    dropdown.innerHTML = '';
    if (filteredItems.length > 0 && query) {
      filteredItems.forEach(item => {
        const div = document.createElement('div');
        div.className = 'dropdown-item';
        div.innerHTML = `<strong>${item.code}</strong> - ${item.description} (₹${item.price}, Stock: ${item.quantity})`;
        div.onclick = () => {
          // CHANGE: Store HSN code instead of item code
          codeInput.value = item.hsn; // Changed from item.code to item.hsn
          row.querySelector('.item-desc').value = item.description;
          row.querySelector('.item-rate').value = item.price;
          row.querySelector('.item-unit').value = item.unit;
          row.querySelector('.disc-type-select').value = item.discountType;
          row.querySelector('.item-disc').value = item.discount;
          // Store item code separately for inventory tracking
          codeInput.setAttribute('data-item-code', item.code);
          updateItemTotal(row);
          updateItemTotals();
          dropdown.innerHTML = '';
          dropdown.style.display = 'none';
        };
        dropdown.appendChild(div);
      });
      dropdown.style.display = 'block';
    } else {
      dropdown.style.display = 'none';
    }
  }, 300));

  document.addEventListener('click', (e) => {
    if (!row.contains(e.target)) {
      dropdown.style.display = 'none';
    }
  });
}

// Setup client autocomplete
function setupClientAutocomplete() {
  const contactInput = document.getElementById('clientContact');
  const dropdown = document.getElementById('contactDropdown');
  contactInput.addEventListener('input', debounce(async function() {
    const query = contactInput.value.toLowerCase();
    const filteredClients = customerDatabase.filter(client =>
      client.contact.toLowerCase().includes(query) ||
      client.name.toLowerCase().includes(query)
    );

    dropdown.innerHTML = '';
    if (filteredClients.length > 0 && query) {
      filteredClients.forEach(client => {
        const div = document.createElement('div');
        div.className = 'dropdown-item';
        div.innerHTML = `<strong>${client.contact}</strong> - ${client.name}`;
        div.onclick = () => {
          contactInput.value = client.contact;
          document.getElementById('clientName').value = client.name;
          document.getElementById('clientEmail').value = client.email;
          document.getElementById('clientAddress').value = client.address;
          document.getElementById('whatsappNumber').value = client.contact;
          [document.getElementById('clientName'), document.getElementById('clientEmail'), document.getElementById('clientAddress')].forEach(input => {
            input.classList.add('auto-populated');
            setTimeout(() => input.classList.remove('auto-populated'), 1000);
          });
          dropdown.innerHTML = '';
          dropdown.style.display = 'none';
        };
        dropdown.appendChild(div);
      });
      dropdown.style.display = 'block';
    } else {
      dropdown.style.display = 'none';
    }
  }, 300));

  document.addEventListener('click', (e) => {
    if (!contactInput.contains(e.target) && !dropdown.contains(e.target)) {
      dropdown.style.display = 'none';
    }
  });
}

// Add stock item
async function addStockItem() {
  try {
    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 discountType = document.getElementById('stockDiscountType').value;
    const discount = parseFloat(document.getElementById('stockDiscount').value) || 0;

    if (!code || !description || price <= 0 || quantity < 0) {
      showStatus('Please fill all fields with valid data.', 'error');
      return;
    }

    if (discountType === 'percent' && discount > 100) {
      showStatus('Discount percentage cannot exceed 100%.', 'error');
      return;
    }

    const existingItem = inventory.find(item => item.code === code);
    if (existingItem) {
      existingItem.hsn = hsn;
      existingItem.description = description;
      existingItem.price = price;
      existingItem.unit = unit;
      existingItem.quantity = quantity;
      existingItem.discountType = discountType;
      existingItem.discount = discount;
      await db.inventory.put(existingItem);
    } else {
      const newItem = { code, hsn, description, price, unit, quantity, discountType, discount };
      await db.inventory.put(newItem);
      inventory.push(newItem);
    }

    document.getElementById('stockCode').value = '';
    document.getElementById('stockHSN').value = '';
    document.getElementById('stockDescription').value = '';
    document.getElementById('stockPrice').value = '';
    document.getElementById('stockUnit').value = 'PCS';
    document.getElementById('stockQuantity').value = '';
    document.getElementById('stockDiscountType').value = 'percent';
    document.getElementById('stockDiscount').value = '0';

    loadStockTable();
    showStatus('Item added to inventory successfully!', 'success');
  } catch (error) {
    showStatus('Error adding stock item: ' + error.message, 'error');
  }
}

// Load stock table
async function loadStockTable() {
  try {
    const stockTableBody = document.getElementById('stockTableBody');
    stockTableBody.innerHTML = '';
    inventory = await db.inventory.toArray();
    inventory.forEach(item => {
      const row = document.createElement('tr');
      row.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.discount}${item.discountType === 'percent' ? '%' : '₹'}</td>
        <td class="${item.quantity <= 5 ? 'low-stock' : ''}">${item.quantity}</td>
        <td>
          <button class="edit-btn" onclick="editStockItem('${item.code}')">Edit</button>
          <button class="delete-btn" onclick="deleteStockItem('${item.code}')">Delete</button>
        </td>
      `;
      stockTableBody.appendChild(row);
    });
  } catch (error) {
    showStatus('Error loading stock table: ' + error.message, 'error');
  }
}

// Edit stock item
async function editStockItem(code) {
  const item = inventory.find(i => i.code === code);
  if (item) {
    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('stockDiscountType').value = item.discountType;
    document.getElementById('stockDiscount').value = item.discount;
    await deleteStockItem(code, false);
  }
}

// Delete stock item
async function deleteStockItem(code, showMessage = true) {
  try {
    await db.inventory.delete(code);
    inventory = inventory.filter(item => item.code !== code);
    loadStockTable();
    if (showMessage) showStatus('Item deleted successfully!', 'success');
  } catch (error) {
    showStatus('Error deleting stock item: ' + error.message, 'error');
  }
}

// Add customer
async function addCustomer() {
  try {
    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('Contact number and name are required.', 'error');
      return;
    }

    const existingCustomer = customerDatabase.find(c => c.contact === contact);
    if (existingCustomer) {
      existingCustomer.name = name;
      existingCustomer.email = email;
      existingCustomer.address = address;
      await db.customers.put(existingCustomer);
    } else {
      const newCustomer = { contact, name, email, address };
      await db.customers.put(newCustomer);
      customerDatabase.push(newCustomer);
    }

    document.getElementById('newCustomerContact').value = '';
    document.getElementById('newCustomerName').value = '';
    document.getElementById('newCustomerEmail').value = '';
    document.getElementById('newCustomerAddress').value = '';

    loadCustomerTable();
    showStatus('Customer added successfully!', 'success');
  } catch (error) {
    showStatus('Error adding customer: ' + error.message, 'error');
  }
}

// Load customer table
async function loadCustomerTable() {
  try {
    const customerTableBody = document.getElementById('customerTableBody');
    customerTableBody.innerHTML = '';
    customerDatabase = await db.customers.toArray();
    customerDatabase.forEach(customer => {
      const row = document.createElement('tr');
      row.innerHTML = `
        <td>${customer.contact}</td>
        <td>${customer.name}</td>
        <td>${customer.email || '-'}</td>
        <td>${customer.address || '-'}</td>
        <td>
          <button class="edit-btn" onclick="openEditCustomerDialog('${customer.contact}')">Edit</button>
          <button class="delete-btn" onclick="deleteCustomer('${customer.contact}')">Delete</button>
          <button class="view-purchases-btn" onclick="viewPurchaseHistory('${customer.contact}')">View Purchases</button>
        </td>
      `;
      customerTableBody.appendChild(row);
    });
  } catch (error) {
    showStatus('Error loading customer table: ' + error.message, 'error');
  }
}

// Open edit customer dialog
function openEditCustomerDialog(contact) {
  const customer = customerDatabase.find(c => c.contact === contact);
  if (customer) {
    editingCustomerContact = contact;
    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';
  }
}

// Save edited customer
async function saveEditedCustomer() {
  try {
    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('Contact number and name are required.', 'error');
      return;
    }

    await db.customers.delete(editingCustomerContact);
    const updatedCustomer = { contact, name, email, address };
    await db.customers.put(updatedCustomer);
    customerDatabase = customerDatabase.map(c => c.contact === editingCustomerContact ? updatedCustomer : c);
    editingCustomerContact = null;

    closeDialog(null, 'editCustomerDialogOverlay');
    loadCustomerTable();
    showStatus('Customer updated successfully!', 'success');
  } catch (error) {
    showStatus('Error updating customer: ' + error.message, 'error');
  }
}

// Delete customer
async function deleteCustomer(contact) {
  try {
    await db.customers.delete(contact);
    customerDatabase = customerDatabase.filter(c => c.contact !== contact);
    loadCustomerTable();
    showStatus('Customer deleted successfully!', 'success');
  } catch (error) {
    showStatus('Error deleting customer: ' + error.message, 'error');
  }
}

// View purchase history
async function viewPurchaseHistory(contact) {
  try {
    const customerInvoices = invoices.filter(inv => inv.clientContact === contact);
    const purchaseHistoryList = document.getElementById('purchaseHistoryList');
    purchaseHistoryList.innerHTML = '';

    if (customerInvoices.length === 0) {
      showPurchaseStatus('No purchase history found for this customer.', 'error');
      document.getElementById('purchaseHistoryDialogOverlay').style.display = 'flex';
      return;
    }

    customerInvoices.forEach(invoice => {
      const itemsSummary = invoice.items.map(item => `${item.description} (Qty: ${item.quantity})`).join(', ');
      const row = document.createElement('tr');
      row.innerHTML = `
        <td>${invoice.invoiceNumber}</td>
        <td>${formatDate(invoice.invoiceDate)}</td>
        <td>₹${invoice.grandTotal.toFixed(2)}</td>
        <td>${itemsSummary}</td>
      `;
      purchaseHistoryList.appendChild(row);
    });

    document.getElementById('purchaseHistoryDialogOverlay').style.display = 'flex';
  } catch (error) {
    showPurchaseStatus('Error loading purchase history: ' + error.message, 'error');
  }
}

// Open item selection dialog
async function openItemDialog() {
  try {
    filteredInventory = await db.inventory.toArray();
    loadItemDialog();
    document.getElementById('dialogOverlay').style.display = 'flex';
  } catch (error) {
    showStatus('Error opening item dialog: ' + error.message, 'error');
  }
}

// Load items into dialog
function loadItemDialog() {
  const itemsList = document.getElementById('itemsList2');
  itemsList.innerHTML = '';
  filteredInventory.forEach(item => {
    const row = document.createElement('tr');
    row.innerHTML = `
      <td>${item.code}</td>
      <td>${item.name || item.description}</td>
      <td>${item.description}</td>
      <td>₹${item.price.toFixed(2)}</td>
      <td>${item.discount}${item.discountType === 'percent' ? '%' : '₹'}</td>
    `;
    row.onclick = () => {
      const newRow = addItem();
      // CHANGE: Set HSN code in the visible field, store item code in data attribute
      newRow.querySelector('.item-code').value = item.hsn; // Changed to HSN
      newRow.querySelector('.item-code').setAttribute('data-item-code', item.code); // Store item code
      newRow.querySelector('.item-desc').value = item.description;
      newRow.querySelector('.item-rate').value = item.price;
      newRow.querySelector('.item-unit').value = item.unit;
      newRow.querySelector('.disc-type-select').value = item.discountType;
      newRow.querySelector('.item-disc').value = item.discount;
      updateItemTotal(newRow);
      updateItemTotals();
    };
    itemsList.appendChild(row);
  });
}


// Search items in dialog
function searchItems() {
  const query = document.getElementById('searchInput').value.toLowerCase();
  filteredInventory = inventory.filter(item =>
    item.code.toLowerCase().includes(query) ||
    item.description.toLowerCase().includes(query) ||
    item.hsn.toLowerCase().includes(query)
  );
  loadItemDialog();
}

// Close dialog
function closeDialog(event, dialogId) {
  if (event && event.target.id !== dialogId) return;
  document.getElementById(dialogId).style.display = 'none';
}

// Dialog resizing
function applyCustomSize(dialogId, widthInputId, heightInputId) {
  const dialog = document.getElementById(dialogId);
  const width = parseInt(document.getElementById(widthInputId).value) || 600;
  const height = parseInt(document.getElementById(heightInputId).value) || 450;
  dialog.style.width = `${Math.max(300, Math.min(width, 1200))}px`;
  dialog.style.maxHeight = `${Math.max(200, Math.min(height, 800))}px`;
}

function quickResize(width, height, dialogId, widthInputId, heightInputId) {
  document.getElementById(widthInputId).value = width;
  document.getElementById(heightInputId).value = height;
  applyCustomSize(dialogId, widthInputId, heightInputId);
}

// Generate WhatsApp message
function generateWhatsAppMessage() {
  const phoneNumber = document.getElementById('whatsappNumber').value;
  const maxDescLength = parseInt(document.getElementById('whatsappDescLength').value) || 20;
  if (!phoneNumber) {
    showStatus('Please enter a WhatsApp number.', 'error');
    return;
  }

  let message = `Invoice from ${document.getElementById('previewCompanyName').textContent}\n`;
  message += `Invoice #: ${document.getElementById('previewInvoiceNumber').textContent}\n`;
  message += `Date: ${document.getElementById('previewInvoiceDate').textContent}\n`;
  message += `Bill To: ${document.getElementById('previewClientName').textContent}\n\n`;
  message += `Items:\n`;

  document.querySelectorAll('.item-row').forEach(row => {
    const description = row.querySelector('.item-desc').value;
    const qty = row.querySelector('.item-qty').value;
    const rate = row.querySelector('.item-rate').value;
    const unit = row.querySelector('.item-unit').value;
    const disc = row.querySelector('.item-disc').value;
    const discType = row.querySelector('.disc-type-select').value;
    const total = row.querySelector('.item-total').value;
    const shortDesc = description.length > maxDescLength ? description.substring(0, maxDescLength) + '...' : description;
    message += `- ${shortDesc} (${qty} ${unit} @ ₹${parseFloat(rate).toFixed(2)}, Disc: ${disc}${discType === 'percent' ? '%' : '₹'}) = ₹${parseFloat(total).toFixed(2)}\n`;
  });

  message += `\nGrand Total: ${document.getElementById('previewTotal').textContent}`;
  const preview = document.getElementById('whatsappPreview');
  preview.textContent = message;
  preview.style.display = 'block';
}

// Send WhatsApp message
function sendWhatsApp() {
  const phoneNumber = document.getElementById('whatsappNumber').value;
  const preview = document.getElementById('whatsappPreview').textContent;
  if (!phoneNumber || !preview) {
    showStatus('Please generate a WhatsApp message first.', 'error');
    return;
  }
  const whatsappUrl = `https://wa.me/${phoneNumber}?text=${encodeURIComponent(preview)}`;
  window.open(whatsappUrl, '_blank');
  showStatus('WhatsApp message sent!', 'success');
}

// Backup all data
async function backupData() {
  try {
    const data = {
      inventory: await db.inventory.toArray(),
      customers: await db.customers.toArray(),
      invoices: await db.invoices.toArray()
    };
    const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `invoice_backup_${new Date().toISOString().split('T')[0]}.json`;
    a.click();
    URL.revokeObjectURL(url);
    showStatus('Backup created successfully!', 'success');
  } catch (error) {
    showStatus('Error creating backup: ' + error.message, 'error');
  }
}

// Restore all data
async function restoreData() {
  try {
    const fileInput = document.getElementById('restoreFileInput');
    const file = fileInput.files[0];
    if (!file) {
      showStatus('Please select a backup file.', 'error');
      return;
    }

    const reader = new FileReader();
    reader.onload = async (e) => {
      try {
        const data = JSON.parse(e.target.result);
        await db.transaction('rw', db.inventory, db.customers, db.invoices, async () => {
          await db.inventory.clear();
          await db.customers.clear();
          await db.invoices.clear();
          if (data.inventory) await db.inventory.bulkPut(data.inventory);
          if (data.customers) await db.customers.bulkPut(data.customers);
          if (data.invoices) await db.invoices.bulkPut(data.invoices);
        });
        await loadDataFromIndexedDB();
        loadStockTable();
        loadCustomerTable();
        updateDashboard();
        showStatus('Data restored successfully!', 'success');
      } catch (error) {
        showStatus('Error restoring data: ' + error.message, 'error');
      }
    };
    reader.readAsText(file);
  } catch (error) {
    showStatus('Error initiating restore: ' + error.message, 'error');
  }
}

// Backup stock data
async function backupStockData() {
  try {
    const inventory = await db.inventory.toArray();
    const blob = new Blob([JSON.stringify(inventory, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `stock_backup_${new Date().toISOString().split('T')[0]}.json`;
    a.click();
    URL.revokeObjectURL(url);
    showStatus('Stock backup created successfully!', 'success');
  } catch (error) {
    showStatus('Error creating stock backup: ' + error.message, 'error');
  }
}

// Restore stock data
async function restoreStockData() {
  try {
    const fileInput = document.getElementById('restoreStockFileInput');
    const file = fileInput.files[0];
    if (!file) {
      showStatus('Please select a stock backup file.', 'error');
      return;
    }

    const reader = new FileReader();
    reader.onload = async (e) => {
      try {
        const inventoryData = JSON.parse(e.target.result);
        await db.inventory.clear();
        await db.inventory.bulkPut(inventoryData);
        inventory = await db.inventory.toArray();
        loadStockTable();
        showStatus('Stock data restored successfully!', 'success');
      } catch (error) {
        showStatus('Error restoring stock data: ' + error.message, 'error');
      }
    };
    reader.readAsText(file);
  } catch (error) {
    showStatus('Error initiating stock restore: ' + error.message, 'error');
  }
}

// Backup customer data
async function backupCustomerData() {
  try {
    const customers = await db.customers.toArray();
    const blob = new Blob([JSON.stringify(customers, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `customer_backup_${new Date().toISOString().split('T')[0]}.json`;
    a.click();
    URL.revokeObjectURL(url);
    showStatus('Customer backup created successfully!', 'success');
  } catch (error) {
    showStatus('Error creating customer backup: ' + error.message, 'error');
  }
}

// Restore customer data
async function restoreCustomerData() {
  try {
    const fileInput = document.getElementById('restoreCustomerFileInput');
    const file = fileInput.files[0];
    if (!file) {
      showStatus('Please select a customer backup file.', 'error');
      return;
    }

    const reader = new FileReader();
    reader.onload = async (e) => {
      try {
        const customerData = JSON.parse(e.target.result);
        await db.customers.clear();
        await db.customers.bulkPut(customerData);
        customerDatabase = await db.customers.toArray();
        loadCustomerTable();
        showStatus('Customer data restored successfully!', 'success');
      } catch (error) {
        showStatus('Error restoring customer data: ' + error.message, 'error');
      }
    };
    reader.readAsText(file);
  } catch (error) {
    showStatus('Error initiating customer restore: ' + error.message, 'error');
  }
}

// Export invoices to CSV
function exportInvoicesToCSV() {
  let csv = 'Invoice Number,Invoice Date,Due Date,Client Name,Client Contact,Client Email,Client Address,Item Code,Item Description,Item Unit,Item Quantity,Item Rate,Item Discount Type,Item Discount,Item Total,Invoice Subtotal,Invoice Total Discount,Invoice Grand Total\n';

  invoices.forEach(invoice => {
    invoice.items.forEach(item => {
      // Sanitize fields to handle special characters
      const invoiceNumber = `"${sanitizeInput(invoice.invoiceNumber)}"`;
      const invoiceDate = `"${formatDate(invoice.invoiceDate)}"`;
      const dueDate = `"${formatDate(invoice.dueDate)}"`;
      const clientName = `"${sanitizeInput(invoice.clientName).replace(/"/g, '""')}"`;
      const clientContact = `"${sanitizeInput(invoice.clientContact).replace(/"/g, '""')}"`;
      const clientEmail = `"${sanitizeInput(invoice.clientEmail).replace(/"/g, '""')}"`;
      const clientAddress = `"${sanitizeInput(invoice.clientAddress).replace(/"/g, '""')}"`;
      const itemCode = `"${sanitizeInput(item.code).replace(/"/g, '""')}"`;
      const itemDescription = `"${sanitizeInput(item.description).replace(/"/g, '""')}"`;
      const itemUnit = `"${item.unit}"`;
      const itemQuantity = `"${item.quantity}"`;
      const itemRate = `"${item.rate.toFixed(2)}"`;
      const itemDiscountType = `"${item.discountType}"`;
      const itemDiscount = `"${item.discount.toFixed(2)}"`;
      const itemTotal = `"${item.total.toFixed(2)}"`;
      const invoiceSubtotal = `"${invoice.subtotal.toFixed(2)}"`;
      const invoiceTotalDiscount = `"${invoice.totalDiscount.toFixed(2)}"`;
      const invoiceGrandTotal = `"${invoice.grandTotal.toFixed(2)}"`;

      csv += `${invoiceNumber},${invoiceDate},${dueDate},${clientName},${clientContact},${clientEmail},${clientAddress},${itemCode},${itemDescription},${itemUnit},${itemQuantity},${itemRate},${itemDiscountType},${itemDiscount},${itemTotal},${invoiceSubtotal},${invoiceTotalDiscount},${invoiceGrandTotal}\n`;
    });
  });

  const blob = new Blob([csv], { type: 'text/csv' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'invoices_export.csv';
  a.click();
  URL.revokeObjectURL(url);
  showStatus('Invoices exported to CSV successfully.', 'success');
}
// Update sales dashboard
async function updateDashboard() {
  try {
    const dateRange = document.getElementById('dateRangeFilter').value;
    let startDate, endDate = new Date();
    if (dateRange === 'custom') {
      startDate = new Date(document.getElementById('fromDate').value);
      endDate = new Date(document.getElementById('toDate').value);
    } else {
      startDate = new Date();
      startDate.setDate(endDate.getDate() - parseInt(dateRange));
    }

    const invoices = await db.invoices.toArray();
    const filteredInvoices = invoices.filter(inv => {
      const invDate = new Date(inv.timestamp);
      return invDate >= startDate && invDate <= endDate;
    });

    let totalRevenue = 0, totalOrders = filteredInvoices.length, totalProducts = 0, totalDiscount = 0;
    const productSales = {};
    const recentOrders = [];

    filteredInvoices.forEach(inv => {
      totalRevenue += inv.grandTotal;
      totalDiscount += inv.totalDiscount;
      inv.items.forEach(item => {
        totalProducts += item.quantity;
        productSales[item.code] = (productSales[item.code] || 0) + item.quantity;
      });
      recentOrders.push({
        invoiceNumber: inv.invoiceNumber,
        date: formatDate(inv.timestamp),
        total: inv.grandTotal,
        client: inv.clientName
      });
    });

    const topProducts = Object.entries(productSales)
      .map(([code, qty]) => {
        const item = inventory.find(i => i.code === code);
        return { code, name: item ? item.description : code, quantity: qty };
      })
      .sort((a, b) => b.quantity - a.quantity)
      .slice(0, 5);

    document.getElementById('totalRevenue').textContent = `₹${totalRevenue.toFixed(2)}`;
    document.getElementById('totalOrders').textContent = totalOrders;
    document.getElementById('totalCustomers').textContent = new Set(filteredInvoices.map(inv => inv.clientContact)).size;
    document.getElementById('totalProducts').textContent = totalProducts;
    document.getElementById('totalDiscount').textContent = `₹${totalDiscount.toFixed(2)}`;

    const topProductsList = document.getElementById('topProductsList');
    topProductsList.innerHTML = '';
    topProducts.forEach(product => {
      const div = document.createElement('div');
      div.innerHTML = `<span>${product.name}</span><span>${product.quantity} units</span>`;
      topProductsList.appendChild(div);
    });

    const recentOrdersList = document.getElementById('recentOrdersList');
    recentOrdersList.innerHTML = '';
    recentOrders.slice(0, 5).forEach(order => {
      const div = document.createElement('div');
      div.innerHTML = `<span>${order.invoiceNumber} - ${order.client}</span><span>${order.date} | ₹${order.total.toFixed(2)}</span>`;
      recentOrdersList.appendChild(div);
    });
  } catch (error) {
    showStatus('Error updating dashboard: ' + error.message, 'error');
  }
}

// Toggle custom date range
function toggleCustomDateRange() {
  const dateRange = document.getElementById('dateRangeFilter').value;
  document.getElementById('customDateRange').classList.toggle('hidden', dateRange !== 'custom');
  updateDashboard();
}

// Clear all invoices
async function clearInvoices() {
  if (!confirm('Are you sure you want to clear all invoices? This action cannot be undone.')) return;
  try {
    await db.invoices.clear();
    invoices = [];
    updateDashboard();
    showStatus('All invoices cleared successfully!', 'success');
  } catch (error) {
    showStatus('Error clearing invoices: ' + error.message, 'error');
  }
}

// Logo handling
let isDragging = false, isResizing = false, startX, startY, startWidth, startHeight;
const logoElement = document.createElement('div');
logoElement.className = 'invoice-logo';
logoElement.innerHTML = `
  <img id="logoImg" style="display:none;">
  <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);

function setupLogo() {
  const logoUpload = document.getElementById('logoUpload');
  const logoImg = document.getElementById('logoImg');
  const logoWidthInput = document.getElementById('logoWidth');
  const logoHeightInput = document.getElementById('logoHeight');
  const lockAspectRatio = document.getElementById('lockAspectRatio');
  let aspectRatio = 1;

  const savedLogo = localStorage.getItem('logo');
  const savedPosition = JSON.parse(localStorage.getItem('logoPosition'));
  if (savedLogo && savedPosition) {
    logoImg.src = savedLogo;
    logoImg.style.display = 'block';
    logoElement.style.left = `${savedPosition.x}px`;
    logoElement.style.top = `${savedPosition.y}px`;
    logoElement.style.width = `${savedPosition.width}px`;
    logoElement.style.height = `${savedPosition.height}px`;
    logoWidthInput.value = savedPosition.width;
    logoHeightInput.value = savedPosition.height;
    aspectRatio = savedPosition.width / savedPosition.height;
  }

  logoUpload.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (file) {
      const reader = new FileReader();
      reader.onload = (e) => {
        logoImg.src = e.target.result;
        logoImg.style.display = 'block';
        const img = new Image();
        img.src = e.target.result;
        img.onload = () => {
          aspectRatio = img.width / img.height;
          const width = 100;
          const height = width / aspectRatio;
          logoElement.style.width = `${width}px`;
          logoElement.style.height = `${height}px`;
          logoWidthInput.value = width;
          logoHeightInput.value = height;
          saveLogoPosition();
        };
        localStorage.setItem('logo', e.target.result);
      };
      reader.readAsDataURL(file);
    }
  });

  logoElement.addEventListener('mousedown', (e) => {
    if (e.target.classList.contains('resize-handle')) {
      isResizing = true;
      startX = e.clientX;
      startY = e.clientY;
      startWidth = parseFloat(getComputedStyle(logoElement).width);
      startHeight = parseFloat(getComputedStyle(logoElement).height);
      logoElement.classList.add('active');
      e.preventDefault();
    } else if (e.target === logoImg) {
      isDragging = true;
      startX = e.clientX - parseFloat(logoElement.style.left || 0);
      startY = e.clientY - parseFloat(logoElement.style.top || 0);
      logoElement.classList.add('active');
      e.preventDefault();
    }
  });

  document.addEventListener('mousemove', (e) => {
    if (isDragging) {
      logoElement.style.left = `${e.clientX - startX}px`;
      logoElement.style.top = `${e.clientY - startY}px`;
      saveLogoPosition();
    } else if (isResizing) {
      const handle = document.activeElement || e.target;
      let newWidth = startWidth;
      let newHeight = startHeight;
      const deltaX = e.clientX - startX;
      const deltaY = e.clientY - startY;

      if (handle.classList.contains('top-left')) {
        newWidth = startWidth - deltaX;
        newHeight = lockAspectRatio.checked ? newWidth / aspectRatio : startHeight - deltaY;
        logoElement.style.left = `${parseFloat(logoElement.style.left || 0) + deltaX}px`;
        logoElement.style.top = `${parseFloat(logoElement.style.top || 0) + deltaY}px`;
      } else if (handle.classList.contains('top-right')) {
        newWidth = startWidth + deltaX;
        newHeight = lockAspectRatio.checked ? newWidth / aspectRatio : startHeight - deltaY;
        logoElement.style.top = `${parseFloat(logoElement.style.top || 0) + deltaY}px`;
      } else if (handle.classList.contains('bottom-left')) {
        newWidth = startWidth - deltaX;
        newHeight = lockAspectRatio.checked ? newWidth / aspectRatio : startHeight + deltaY;
        logoElement.style.left = `${parseFloat(logoElement.style.left || 0) + deltaX}px`;
      } else if (handle.classList.contains('bottom-right')) {
        newWidth = startWidth + deltaX;
        newHeight = lockAspectRatio.checked ? newWidth / aspectRatio : startHeight + deltaY;
      }

      newWidth = Math.max(20, Math.min(newWidth, 300));
      newHeight = Math.max(20, Math.min(newHeight, 300));
      logoElement.style.width = `${newWidth}px`;
      logoElement.style.height = `${newHeight}px`;
      logoWidthInput.value = Math.round(newWidth);
      logoHeightInput.value = Math.round(newHeight);
      saveLogoPosition();
    }
  });

  document.addEventListener('mouseup', () => {
    isDragging = false;
    isResizing = false;
  });

  logoElement.addEventListener('dblclick', () => {
    logoElement.classList.toggle('active');
  });

  logoWidthInput.addEventListener('input', () => {
    let width = parseFloat(logoWidthInput.value) || 100;
    width = Math.max(20, Math.min(width, 300));
    logoElement.style.width = `${width}px`;
    if (lockAspectRatio.checked) {
      const height = width / aspectRatio;
      logoElement.style.height = `${height}px`;
      logoHeightInput.value = Math.round(height);
    }
    saveLogoPosition();
  });

  logoHeightInput.addEventListener('input', () => {
    let height = parseFloat(logoHeightInput.value) || 50;
    height = Math.max(20, Math.min(height, 300));
    logoElement.style.height = `${height}px`;
    if (lockAspectRatio.checked) {
      const width = height * aspectRatio;
      logoElement.style.width = `${width}px`;
      logoWidthInput.value = Math.round(width);
    }
    saveLogoPosition();
  });

  function saveLogoPosition() {
    const position = {
      x: parseFloat(logoElement.style.left || 20),
      y: parseFloat(logoElement.style.top || 20),
      width: parseFloat(logoElement.style.width || 100),
      height: parseFloat(logoElement.style.height || 50)
    };
    localStorage.setItem('logoPosition', JSON.stringify(position));
  }
}

function resetLogoPosition() {
  const logoImg = document.getElementById('logoImg');
  if (logoImg.src) {
    logoElement.style.left = '20px';
    logoElement.style.top = '20px';
    logoElement.style.width = '100px';
    logoElement.style.height = '50px';
    document.getElementById('logoWidth').value = 100;
    document.getElementById('logoHeight').value = 50;
    localStorage.setItem('logoPosition', JSON.stringify({ x: 20, y: 20, width: 100, height: 50 }));
  }
}

function removeLogo() {
  const logoImg = document.getElementById('logoImg');
  logoImg.src = '';
  logoImg.style.display = 'none';
  logoElement.style.width = '0px';
  logoElement.style.height = '0px';
  document.getElementById('logoWidth').value = '';
  document.getElementById('logoHeight').value = '';
  localStorage.removeItem('logo');
  localStorage.removeItem('logoPosition');
}

// Initialize application
async function initialize() {
  await migrateLocalStorageToIndexedDB();
  await loadDataFromIndexedDB();
  setupNavigation();
  setupClientAutocomplete();
  document.querySelectorAll('.item-row').forEach(row => {
    attachInputListeners(row);
    setupItemAutocomplete(row);
  });
  loadStockTable();
  loadCustomerTable();
  updateDashboard();
  setupLogo();

  // Set default dates
  const today = new Date().toISOString().split('T')[0];
  document.getElementById('invoiceDate').value = today;
  document.getElementById('dueDate').value = today;
  document.getElementById('invoiceNumber').value = await generateInvoiceNumber();
}

document.addEventListener('DOMContentLoaded', initialize);
</script>
</body>
</html>

No comments:

Post a Comment