Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Inventory & Sales Order Management</title>
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- }
- :root {
- --primary: #3498db;
- --secondary: #2c3e50;
- --success: #27ae60;
- --warning: #f39c12;
- --danger: #e74c3c;
- --light: #f8f9fa;
- --dark: #343a40;
- --gray: #6c757d;
- }
- body {
- background-color: #f5f7fa;
- color: #333;
- }
- .container {
- max-width: 1200px;
- margin: 0 auto;
- padding: 0 15px;
- }
- /* Login Screen */
- .login-container {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- background: linear-gradient(135deg, var(--secondary), var(--primary));
- }
- .login-card {
- background: white;
- border-radius: 10px;
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
- width: 100%;
- max-width: 400px;
- padding: 30px;
- }
- .login-card h2 {
- text-align: center;
- margin-bottom: 30px;
- color: var(--secondary);
- }
- .role-selector {
- display: flex;
- justify-content: center;
- gap: 20px;
- margin-bottom: 30px;
- }
- .role-btn {
- padding: 15px 20px;
- border: 2px solid #ddd;
- border-radius: 8px;
- background: white;
- cursor: pointer;
- text-align: center;
- transition: all 0.3s ease;
- flex: 1;
- }
- .role-btn.active {
- border-color: var(--primary);
- background-color: rgba(52, 152, 219, 0.1);
- transform: translateY(-5px);
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
- }
- .role-btn i {
- font-size: 24px;
- margin-bottom: 10px;
- display: block;
- color: var(--primary);
- }
- .login-btn {
- width: 100%;
- padding: 12px;
- background-color: var(--primary);
- color: white;
- border: none;
- border-radius: 5px;
- font-size: 16px;
- font-weight: 600;
- cursor: pointer;
- transition: background-color 0.3s;
- }
- .login-btn:hover {
- background-color: #2980b9;
- }
- /* App Header */
- .app-header {
- background-color: var(--secondary);
- color: white;
- padding: 15px 0;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- }
- .header-content {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .app-title {
- font-size: 24px;
- font-weight: 600;
- }
- .user-info {
- display: flex;
- align-items: center;
- gap: 10px;
- }
- .user-role {
- background-color: var(--primary);
- padding: 5px 10px;
- border-radius: 20px;
- font-size: 12px;
- }
- .logout-btn {
- background: none;
- border: none;
- color: white;
- cursor: pointer;
- font-size: 14px;
- }
- /* Navigation */
- .nav-container {
- background-color: white;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
- margin-bottom: 20px;
- }
- .nav-menu {
- display: flex;
- list-style: none;
- padding: 0;
- }
- .nav-item {
- padding: 15px 20px;
- cursor: pointer;
- transition: background-color 0.3s;
- font-weight: 500;
- }
- .nav-item.active {
- background-color: rgba(52, 152, 219, 0.1);
- color: var(--primary);
- border-bottom: 3px solid var(--primary);
- }
- /* Main Content */
- .content-section {
- background-color: white;
- border-radius: 8px;
- box-shadow: 0 2px 15px rgba(0, 0, 0, 0.05);
- padding: 25px;
- margin-bottom: 25px;
- display: none;
- }
- .content-section.active {
- display: block;
- }
- .section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 25px;
- padding-bottom: 15px;
- border-bottom: 1px solid #eee;
- }
- .section-title {
- font-size: 22px;
- font-weight: 600;
- color: var(--secondary);
- }
- .btn {
- padding: 10px 20px;
- border-radius: 5px;
- border: none;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s;
- }
- .btn-primary {
- background-color: var(--primary);
- color: white;
- }
- .btn-success {
- background-color: var(--success);
- color: white;
- }
- .btn-warning {
- background-color: var(--warning);
- color: white;
- }
- .btn-danger {
- background-color: var(--danger);
- color: white;
- }
- .btn:hover {
- opacity: 0.9;
- transform: translateY(-2px);
- }
- /* Tables */
- .table-container {
- overflow-x: auto;
- }
- .data-table {
- width: 100%;
- border-collapse: collapse;
- }
- .data-table th {
- background-color: #f1f5f9;
- text-align: left;
- padding: 12px 15px;
- font-weight: 600;
- color: var(--secondary);
- }
- .data-table td {
- padding: 12px 15px;
- border-bottom: 1px solid #eee;
- }
- .data-table tr:hover {
- background-color: #f8fafc;
- }
- .action-cell {
- display: flex;
- gap: 10px;
- }
- .action-btn {
- padding: 5px 10px;
- border-radius: 4px;
- font-size: 14px;
- cursor: pointer;
- border: none;
- background-color: #f1f1f1;
- }
- .action-btn i {
- margin-right: 5px;
- }
- .edit-btn {
- background-color: rgba(52, 152, 219, 0.1);
- color: var(--primary);
- }
- .delete-btn {
- background-color: rgba(231, 76, 60, 0.1);
- color: var(--danger);
- }
- /* Forms */
- .form-container {
- max-width: 600px;
- margin: 0 auto;
- }
- .form-group {
- margin-bottom: 20px;
- }
- .form-label {
- display: block;
- margin-bottom: 8px;
- font-weight: 500;
- }
- .form-control {
- width: 100%;
- padding: 12px;
- border: 1px solid #ddd;
- border-radius: 5px;
- font-size: 16px;
- }
- .form-control:focus {
- outline: none;
- border-color: var(--primary);
- box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
- }
- .form-row {
- display: flex;
- gap: 20px;
- }
- .form-col {
- flex: 1;
- }
- /* Dashboard */
- .dashboard-stats {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
- gap: 20px;
- margin-bottom: 30px;
- }
- .stat-card {
- background-color: white;
- border-radius: 8px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
- padding: 20px;
- text-align: center;
- }
- .stat-value {
- font-size: 32px;
- font-weight: 700;
- margin: 10px 0;
- color: var(--primary);
- }
- .stat-label {
- color: var(--gray);
- font-size: 14px;
- }
- .chart-container {
- margin-top: 30px;
- height: 400px;
- }
- /* Status Badges */
- .status-badge {
- padding: 5px 10px;
- border-radius: 20px;
- font-size: 12px;
- font-weight: 600;
- display: inline-block;
- }
- .status-new {
- background-color: rgba(155, 89, 182, 0.1);
- color: #9b59b6;
- }
- .status-in-progress {
- background-color: rgba(52, 152, 219, 0.1);
- color: var(--primary);
- }
- .status-unpaid {
- background-color: rgba(243, 156, 18, 0.1);
- color: var(--warning);
- }
- .status-paid {
- background-color: rgba(46, 204, 113, 0.1);
- color: #2ecc71;
- }
- .status-fulfilled {
- background-color: rgba(39, 174, 96, 0.1);
- color: var(--success);
- }
- .status-voided {
- background-color: rgba(231, 76, 60, 0.1);
- color: var(--danger);
- }
- /* Responsive */
- @media (max-width: 768px) {
- .form-row {
- flex-direction: column;
- gap: 0;
- }
- .dashboard-stats {
- grid-template-columns: 1fr;
- }
- .nav-menu {
- overflow-x: auto;
- }
- }
- </style>
- </head>
- <body>
- <!-- Login Screen -->
- <div id="login-screen" class="login-container">
- <div class="login-card">
- <h2>Inventory & Sales Order Management</h2>
- <div class="role-selector">
- <div class="role-btn" data-role="manager">
- <i class="fas fa-user-tie"></i>
- Manager
- </div>
- <div class="role-btn" data-role="salesperson">
- <i class="fas fa-user"></i>
- Salesperson
- </div>
- </div>
- <button id="login-btn" class="login-btn">Login to Dashboard</button>
- </div>
- </div>
- <!-- App Container -->
- <div id="app-container" style="display: none;">
- <!-- Header -->
- <header class="app-header">
- <div class="container">
- <div class="header-content">
- <div class="app-title">Inventory & Sales Order Management</div>
- <div class="user-info">
- <span id="current-username">John Doe</span>
- <span id="current-role" class="user-role">Manager</span>
- <button id="logout-btn" class="logout-btn">
- <i class="fas fa-sign-out-alt"></i> Logout
- </button>
- </div>
- </div>
- </div>
- </header>
- <!-- Navigation -->
- <nav class="nav-container">
- <div class="container">
- <ul class="nav-menu">
- <li class="nav-item active" data-section="dashboard">Dashboard</li>
- <li class="nav-item" data-section="inventory">Inventory</li>
- <li class="nav-item" data-section="sales-orders">Sales Orders</li>
- <li class="nav-item" data-section="customers">Customers</li>
- <li class="nav-item manager-only" data-section="reports">Reports</li>
- </ul>
- </div>
- </nav>
- <!-- Main Content -->
- <main class="container">
- <!-- Dashboard -->
- <section id="dashboard" class="content-section active">
- <div class="section-header">
- <h2 class="section-title">Dashboard</h2>
- <div>
- <button class="btn btn-primary" id="export-report">
- <i class="fas fa-download"></i> Export Report
- </button>
- </div>
- </div>
- <div class="dashboard-stats">
- <div class="stat-card">
- <div class="stat-label">Total Products</div>
- <div class="stat-value" id="total-products">0</div>
- <div class="stat-label">In Inventory</div>
- </div>
- <div class="stat-card">
- <div class="stat-label">Total Sales</div>
- <div class="stat-value" id="total-sales">$0.00</div>
- <div class="stat-label">This Month</div>
- </div>
- <div class="stat-card">
- <div class="stat-label">Unpaid Orders</div>
- <div class="stat-value" id="unpaid-orders">0</div>
- <div class="stat-label">Require Attention</div>
- </div>
- <div class="stat-card">
- <div class="stat-label">Low Stock Items</div>
- <div class="stat-value" id="low-stock">0</div>
- <div class="stat-label">Need Replenishment</div>
- </div>
- </div>
- <div class="section-header">
- <h3 class="section-title">Sales Performance</h3>
- <div>
- <select id="timeframe-select" class="form-control" style="width: auto;">
- <option value="week">Last Week</option>
- <option value="month">Last Month</option>
- <option value="year">Last Year</option>
- </select>
- </div>
- </div>
- <div class="chart-container">
- <canvas id="sales-chart"></canvas>
- </div>
- </section>
- <!-- Inventory Management -->
- <section id="inventory" class="content-section">
- <div class="section-header">
- <h2 class="section-title">Inventory Management</h2>
- <div>
- <button class="btn btn-primary" id="add-product-btn">
- <i class="fas fa-plus"></i> Add Product
- </button>
- </div>
- </div>
- <div class="table-container">
- <table class="data-table">
- <thead>
- <tr>
- <th>Product Name</th>
- <th>Category</th>
- <th>Cost Price</th>
- <th>Selling Price</th>
- <th>Quantity</th>
- <th>Actions</th>
- </tr>
- </thead>
- <tbody id="inventory-table-body">
- <!-- Inventory items will be populated here -->
- </tbody>
- </table>
- </div>
- </section>
- <!-- Sales Orders -->
- <section id="sales-orders" class="content-section">
- <div class="section-header">
- <h2 class="section-title">Sales Orders</h2>
- <div>
- <button class="btn btn-primary" id="create-order-btn">
- <i class="fas fa-plus"></i> Create Order
- </button>
- </div>
- </div>
- <div class="table-container">
- <table class="data-table">
- <thead>
- <tr>
- <th>Order #</th>
- <th>Customer</th>
- <th>Date</th>
- <th>Total Amount</th>
- <th>Status</th>
- <th>Actions</th>
- </tr>
- </thead>
- <tbody id="orders-table-body">
- <!-- Orders will be populated here -->
- </tbody>
- </table>
- </div>
- </section>
- <!-- Customer Management -->
- <section id="customers" class="content-section">
- <div class="section-header">
- <h2 class="section-title">Customer Management</h2>
- <div>
- <button class="btn btn-primary" id="add-customer-btn">
- <i class="fas fa-plus"></i> Add Customer
- </button>
- </div>
- </div>
- <div class="form-group">
- <input type="text" id="customer-search" class="form-control" placeholder="Search customers by name, business, or phone...">
- </div>
- <div class="table-container">
- <table class="data-table">
- <thead>
- <tr>
- <th>Name</th>
- <th>Business</th>
- <th>Email</th>
- <th>Phone</th>
- <th>Actions</th>
- </tr>
- </thead>
- <tbody id="customers-table-body">
- <!-- Customers will be populated here -->
- </tbody>
- </table>
- </div>
- </section>
- <!-- Reports -->
- <section id="reports" class="content-section">
- <div class="section-header">
- <h2 class="section-title">Reports</h2>
- <div>
- <button class="btn btn-primary" id="export-all-btn">
- <i class="fas fa-download"></i> Export All
- </button>
- </div>
- </div>
- <div class="form-row">
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Date Range</label>
- <div style="display: flex; gap: 10px;">
- <input type="date" id="start-date" class="form-control">
- <input type="date" id="end-date" class="form-control">
- </div>
- </div>
- </div>
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Salesperson</label>
- <select id="salesperson-filter" class="form-control">
- <option value="all">All Salespersons</option>
- <!-- Salespersons will be populated here -->
- </select>
- </div>
- </div>
- </div>
- <div class="form-group">
- <button class="btn btn-primary" id="generate-report-btn">Generate Report</button>
- </div>
- <div class="chart-container">
- <canvas id="report-chart"></canvas>
- </div>
- <div class="table-container">
- <table class="data-table">
- <thead>
- <tr>
- <th>Order #</th>
- <th>Date</th>
- <th>Customer</th>
- <th>Salesperson</th>
- <th>Amount</th>
- <th>Status</th>
- </tr>
- </thead>
- <tbody id="report-table-body">
- <!-- Report data will be populated here -->
- </tbody>
- </table>
- </div>
- </section>
- </main>
- </div>
- <!-- Add Product Modal -->
- <div id="product-modal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center;">
- <div style="background: white; width: 100%; max-width: 600px; border-radius: 8px; padding: 25px;">
- <h2 style="margin-bottom: 20px;">Add New Product</h2>
- <form id="product-form">
- <div class="form-group">
- <label class="form-label">Product Name</label>
- <input type="text" class="form-control" name="name" required>
- </div>
- <div class="form-row">
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Category</label>
- <input type="text" class="form-control" name="category" required>
- </div>
- </div>
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Quantity in Stock</label>
- <input type="number" class="form-control" name="quantity" min="0" required>
- </div>
- </div>
- </div>
- <div class="form-row">
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Cost Price ($)</label>
- <input type="number" class="form-control" name="cost_price" min="0" step="0.01" required>
- </div>
- </div>
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Selling Price ($)</label>
- <input type="number" class="form-control" name="selling_price" min="0" step="0.01" required>
- </div>
- </div>
- </div>
- <div class="form-group" style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;">
- <button type="button" class="btn btn-danger" id="cancel-product-btn">Cancel</button>
- <button type="submit" class="btn btn-primary">Save Product</button>
- </div>
- </form>
- </div>
- </div>
- <!-- Order Modal -->
- <div id="order-modal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; overflow-y: auto;">
- <div style="background: white; width: 100%; max-width: 800px; border-radius: 8px; padding: 25px; max-height: 90vh; overflow-y: auto;">
- <h2 style="margin-bottom: 20px;">Create Sales Order</h2>
- <form id="order-form">
- <div class="form-group">
- <label class="form-label">Customer</label>
- <select class="form-control" name="customer_id" required>
- <option value="">Select a customer</option>
- <!-- Customers will be populated here -->
- </select>
- </div>
- <div class="form-row">
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Salesperson</label>
- <input type="text" class="form-control" value="John Doe" readonly>
- </div>
- </div>
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Order Date</label>
- <input type="date" class="form-control" name="order_date" required>
- </div>
- </div>
- </div>
- <h3 style="margin: 20px 0 15px;">Order Items</h3>
- <div id="order-items-container">
- <!-- Order items will be added here -->
- </div>
- <div class="form-group">
- <button type="button" class="btn btn-secondary" id="add-item-btn">
- <i class="fas fa-plus"></i> Add Item
- </button>
- </div>
- <div style="margin-top: 20px; border-top: 1px solid #eee; padding-top: 20px;">
- <div class="form-row">
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Discount (%)</label>
- <input type="number" class="form-control" name="discount" min="0" max="100" value="0">
- </div>
- </div>
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Total Amount</label>
- <input type="text" class="form-control" id="order-total" value="$0.00" readonly>
- </div>
- </div>
- </div>
- </div>
- <div class="form-group" style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;">
- <button type="button" class="btn btn-danger" id="cancel-order-btn">Cancel</button>
- <button type="submit" class="btn btn-primary">Create Order</button>
- </div>
- </form>
- </div>
- </div>
- <script>
- // App State
- const state = {
- currentUser: null,
- currentRole: null,
- products: [
- { id: 1, name: "Laptop", category: "Electronics", cost_price: 800, selling_price: 1200, quantity: 15 },
- { id: 2, name: "Smartphone", category: "Electronics", cost_price: 400, selling_price: 700, quantity: 30 },
- { id: 3, name: "Desk Chair", category: "Furniture", cost_price: 120, selling_price: 250, quantity: 8 },
- { id: 4, name: "Coffee Maker", category: "Appliances", cost_price: 50, selling_price: 100, quantity: 12 },
- { id: 5, name: "Wireless Headphones", category: "Electronics", cost_price: 80, selling_price: 150, quantity: 22 }
- ],
- customers: [
- { id: 1, first_name: "John", last_name: "Smith", business: "Smith Corp", email: "[email protected]", phone: "555-1234" },
- { id: 2, first_name: "Emily", last_name: "Johnson", business: "Johnson LLC", email: "[email protected]", phone: "555-5678" },
- { id: 3, first_name: "Michael", last_name: "Williams", business: "Williams Inc", email: "[email protected]", phone: "555-9012" },
- { id: 4, first_name: "Sarah", last_name: "Brown", business: "Brown Enterprises", email: "[email protected]", phone: "555-3456" }
- ],
- orders: [
- { id: 1, number: "SO-0001", customer_id: 1, date: "2023-05-15", items: [
- { product_id: 1, quantity: 1, price: 1200 },
- { product_id: 5, quantity: 2, price: 150 }
- ], discount: 10, status: "paid", salesperson: "John Doe", payment_status: "paid" },
- { id: 2, number: "SO-0002", customer_id: 2, date: "2023-05-18", items: [
- { product_id: 3, quantity: 3, price: 250 }
- ], discount: 0, status: "fulfilled", salesperson: "Jane Smith", payment_status: "paid" },
- { id: 3, number: "SO-0003", customer_id: 3, date: "2023-05-20", items: [
- { product_id: 2, quantity: 2, price: 700 },
- { product_id: 4, quantity: 1, price: 100 }
- ], discount: 5, status: "unpaid", salesperson: "John Doe", payment_status: "unpaid" }
- ],
- salespersons: ["John Doe", "Jane Smith", "Robert Johnson"]
- };
- // DOM Elements
- const elements = {
- loginScreen: document.getElementById('login-screen'),
- appContainer: document.getElementById('app-container'),
- roleBtns: document.querySelectorAll('.role-btn'),
- loginBtn: document.getElementById('login-btn'),
- currentUsername: document.getElementById('current-username'),
- currentRole: document.getElementById('current-role'),
- logoutBtn: document.getElementById('logout-btn'),
- navItems: document.querySelectorAll('.nav-item'),
- contentSections: document.querySelectorAll('.content-section'),
- totalProducts: document.getElementById('total-products'),
- totalSales: document.getElementById('total-sales'),
- unpaidOrders: document.getElementById('unpaid-orders'),
- lowStock: document.getElementById('low-stock'),
- salesChart: document.getElementById('sales-chart'),
- inventoryTableBody: document.getElementById('inventory-table-body'),
- ordersTableBody: document.getElementById('orders-table-body'),
- customersTableBody: document.getElementById('customers-table-body'),
- reportTableBody: document.getElementById('report-table-body'),
- addProductBtn: document.getElementById('add-product-btn'),
- productModal: document.getElementById('product-modal'),
- productForm: document.getElementById('product-form'),
- cancelProductBtn: document.getElementById('cancel-product-btn'),
- createOrderBtn: document.getElementById('create-order-btn'),
- orderModal: document.getElementById('order-modal'),
- orderForm: document.getElementById('order-form'),
- cancelOrderBtn: document.getElementById('cancel-order-btn'),
- addItemBtn: document.getElementById('add-item-btn'),
- orderItemsContainer: document.getElementById('order-items-container'),
- orderTotal: document.getElementById('order-total'),
- customerSearch: document.getElementById('customer-search'),
- exportReportBtn: document.getElementById('export-report'),
- exportAllBtn: document.getElementById('export-all-btn'),
- generateReportBtn: document.getElementById('generate-report-btn'),
- salespersonFilter: document.getElementById('salesperson-filter'),
- reportChart: document.getElementById('report-chart'),
- timeframeSelect: document.getElementById('timeframe-select')
- };
- // Initialize the application
- function initApp() {
- // Event Listeners
- elements.roleBtns.forEach(btn => {
- btn.addEventListener('click', () => {
- elements.roleBtns.forEach(b => b.classList.remove('active'));
- btn.classList.add('active');
- state.currentRole = btn.dataset.role;
- });
- });
- elements.loginBtn.addEventListener('click', handleLogin);
- elements.logoutBtn.addEventListener('click', handleLogout);
- elements.navItems.forEach(item => {
- item.addEventListener('click', () => {
- // Only allow managers to access reports
- if (item.dataset.section === 'reports' && state.currentRole !== 'manager') return;
- elements.navItems.forEach(i => i.classList.remove('active'));
- item.classList.add('active');
- elements.contentSections.forEach(section => {
- section.classList.remove('active');
- if (section.id === item.dataset.section) {
- section.classList.add('active');
- }
- });
- });
- });
- elements.addProductBtn.addEventListener('click', () => {
- elements.productModal.style.display = 'flex';
- elements.productForm.reset();
- });
- elements.cancelProductBtn.addEventListener('click', () => {
- elements.productModal.style.display = 'none';
- });
- elements.productForm.addEventListener('submit', handleAddProduct);
- elements.createOrderBtn.addEventListener('click', () => {
- elements.orderModal.style.display = 'flex';
- elements.orderForm.reset();
- elements.orderItemsContainer.innerHTML = '';
- updateOrderTotal();
- populateCustomerSelect();
- });
- elements.cancelOrderBtn.addEventListener('click', () => {
- elements.orderModal.style.display = 'none';
- });
- elements.addItemBtn.addEventListener('click', addOrderItem);
- elements.orderForm.addEventListener('submit', handleCreateOrder);
- elements.customerSearch.addEventListener('input', filterCustomers);
- elements.exportReportBtn.addEventListener('click', () => {
- alert('Report exported as CSV and PDF');
- });
- elements.exportAllBtn.addEventListener('click', () => {
- alert('All reports exported successfully');
- });
- elements.generateReportBtn.addEventListener('click', generateReport);
- elements.timeframeSelect.addEventListener('change', updateSalesChart);
- // Set initial role selection
- elements.roleBtns[0].classList.add('active');
- state.currentRole = 'manager';
- // Initialize charts
- initCharts();
- }
- // Handle login
- function handleLogin() {
- state.currentUser = state.currentRole === 'manager' ? 'Jane Manager' : 'John Salesperson';
- elements.currentUsername.textContent = state.currentUser;
- elements.currentRole.textContent = state.currentRole === 'manager' ? 'Manager' : 'Salesperson';
- elements.loginScreen.style.display = 'none';
- elements.appContainer.style.display = 'block';
- // Update all views
- renderInventory();
- renderOrders();
- renderCustomers();
- updateDashboardStats();
- updateSalesChart();
- // Hide manager-only elements for salesperson
- if (state.currentRole === 'salesperson') {
- document.querySelectorAll('.manager-only').forEach(el => {
- el.style.display = 'none';
- });
- }
- }
- // Handle logout
- function handleLogout() {
- elements.loginScreen.style.display = 'flex';
- elements.appContainer.style.display = 'none';
- }
- // Render inventory table
- function renderInventory() {
- elements.inventoryTableBody.innerHTML = '';
- state.products.forEach(product => {
- const row = document.createElement('tr');
- row.innerHTML = `
- <td>${product.name}</td>
- <td>${product.category}</td>
- <td>$${product.cost_price.toFixed(2)}</td>
- <td>$${product.selling_price.toFixed(2)}</td>
- <td>${product.quantity}</td>
- <td class="action-cell">
- <button class="action-btn edit-btn" data-id="${product.id}">
- <i class="fas fa-edit"></i> Edit
- </button>
- ${state.currentRole === 'manager' ?
- `<button class="action-btn delete-btn" data-id="${product.id}">
- <i class="fas fa-trash"></i> Delete
- </button>` : ''}
- </td>
- `;
- elements.inventoryTableBody.appendChild(row);
- });
- // Add event listeners to action buttons
- document.querySelectorAll('.edit-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const productId = parseInt(btn.dataset.id);
- editProduct(productId);
- });
- });
- document.querySelectorAll('.delete-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const productId = parseInt(btn.dataset.id);
- deleteProduct(productId);
- });
- });
- }
- // Render orders table
- function renderOrders() {
- elements.ordersTableBody.innerHTML = '';
- state.orders.forEach(order => {
- const customer = state.customers.find(c => c.id === order.customer_id);
- const customerName = customer ? `${customer.first_name} ${customer.last_name}` : 'Unknown';
- const totalAmount = calculateOrderTotal(order);
- let statusClass = '';
- switch (order.status) {
- case 'new': statusClass = 'status-new'; break;
- case 'in-progress': statusClass = 'status-in-progress'; break;
- case 'voided': statusClass = 'status-voided'; break;
- case 'unpaid': statusClass = 'status-unpaid'; break;
- case 'paid': statusClass = 'status-paid'; break;
- case 'fulfilled': statusClass = 'status-fulfilled'; break;
- }
- const row = document.createElement('tr');
- row.innerHTML = `
- <td>${order.number}</td>
- <td>${customerName}</td>
- <td>${order.date}</td>
- <td>$${totalAmount.toFixed(2)}</td>
- <td><span class="status-badge ${statusClass}">${order.status}</span></td>
- <td class="action-cell">
- <button class="action-btn edit-btn" data-id="${order.id}">
- <i class="fas fa-eye"></i> View
- </button>
- ${state.currentRole === 'manager' && order.status !== 'voided' ?
- `<button class="action-btn delete-btn" data-id="${order.id}">
- <i class="fas fa-ban"></i> Void
- </button>` : ''}
- </td>
- `;
- elements.ordersTableBody.appendChild(row);
- });
- // Add event listeners to action buttons
- document.querySelectorAll('.edit-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const orderId = parseInt(btn.dataset.id);
- viewOrder(orderId);
- });
- });
- document.querySelectorAll('.delete-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const orderId = parseInt(btn.dataset.id);
- voidOrder(orderId);
- });
- });
- }
- // Render customers table
- function renderCustomers() {
- elements.customersTableBody.innerHTML = '';
- state.customers.forEach(customer => {
- const row = document.createElement('tr');
- row.innerHTML = `
- <td>${customer.first_name} ${customer.last_name}</td>
- <td>${customer.business}</td>
- <td>${customer.email}</td>
- <td>${customer.phone}</td>
- <td class="action-cell">
- <button class="action-btn edit-btn" data-id="${customer.id}">
- <i class="fas fa-edit"></i> Edit
- </button>
- <button class="action-btn delete-btn" data-id="${customer.id}">
- <i class="fas fa-trash"></i> Delete
- </button>
- </td>
- `;
- elements.customersTableBody.appendChild(row);
- });
- // Add event listeners to action buttons
- document.querySelectorAll('.edit-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const customerId = parseInt(btn.dataset.id);
- editCustomer(customerId);
- });
- });
- document.querySelectorAll('.delete-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const customerId = parseInt(btn.dataset.id);
- deleteCustomer(customerId);
- });
- });
- }
- // Filter customers based on search input
- function filterCustomers() {
- const searchTerm = elements.customerSearch.value.toLowerCase();
- if (!searchTerm) {
- renderCustomers();
- return;
- }
- const filteredCustomers = state.customers.filter(customer => {
- return (
- customer.first_name.toLowerCase().includes(searchTerm) ||
- customer.last_name.toLowerCase().includes(searchTerm) ||
- (customer.business && customer.business.toLowerCase().includes(searchTerm)) ||
- customer.phone.includes(searchTerm)
- );
- });
- elements.customersTableBody.innerHTML = '';
- filteredCustomers.forEach(customer => {
- const row = document.createElement('tr');
- row.innerHTML = `
- <td>${customer.first_name} ${customer.last_name}</td>
- <td>${customer.business}</td>
- <td>${customer.email}</td>
- <td>${customer.phone}</td>
- <td class="action-cell">
- <button class="action-btn edit-btn" data-id="${customer.id}">
- <i class="fas fa-edit"></i> Edit
- </button>
- <button class="action-btn delete-btn" data-id="${customer.id}">
- <i class="fas fa-trash"></i> Delete
- </button>
- </td>
- `;
- elements.customersTableBody.appendChild(row);
- });
- // Reattach event listeners
- document.querySelectorAll('.edit-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const customerId = parseInt(btn.dataset.id);
- editCustomer(customerId);
- });
- });
- document.querySelectorAll('.delete-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- const customerId = parseInt(btn.dataset.id);
- deleteCustomer(customerId);
- });
- });
- }
- // Add a new product
- function handleAddProduct(e) {
- e.preventDefault();
- const formData = new FormData(elements.productForm);
- const product = {
- id: state.products.length + 1,
- name: formData.get('name'),
- category: formData.get('category'),
- cost_price: parseFloat(formData.get('cost_price')),
- selling_price: parseFloat(formData.get('selling_price')),
- quantity: parseInt(formData.get('quantity'))
- };
- state.products.push(product);
- renderInventory();
- elements.productModal.style.display = 'none';
- updateDashboardStats();
- }
- // Add an item to an order
- function addOrderItem() {
- const itemCount = elements.orderItemsContainer.children.length;
- const itemDiv = document.createElement('div');
- itemDiv.className = 'form-row';
- itemDiv.style.marginBottom = '15px';
- itemDiv.style.paddingBottom = '15px';
- itemDiv.style.borderBottom = '1px solid #eee';
- itemDiv.innerHTML = `
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Product</label>
- <select class="form-control item-product" required>
- <option value="">Select a product</option>
- ${state.products.map(p => `<option value="${p.id}">${p.name} ($${p.selling_price.toFixed(2)})</option>`).join('')}
- </select>
- </div>
- </div>
- <div class="form-col">
- <div class="form-group">
- <label class="form-label">Quantity</label>
- <input type="number" class="form-control item-quantity" min="1" value="1" required>
- </div>
- </div>
- <div class="form-col" style="display: flex; align-items: flex-end;">
- <button type="button" class="btn btn-danger remove-item-btn" style="height: 42px;">
- <i class="fas fa-times"></i>
- </button>
- </div>
- `;
- elements.orderItemsContainer.appendChild(itemDiv);
- // Add event listener for remove button
- itemDiv.querySelector('.remove-item-btn').addEventListener('click', () => {
- itemDiv.remove();
- updateOrderTotal();
- });
- // Add event listeners for product and quantity changes
- itemDiv.querySelector('.item-product').addEventListener('change', updateOrderTotal);
- itemDiv.querySelector('.item-quantity').addEventListener('input', updateOrderTotal);
- }
- // Update order total amount
- function updateOrderTotal() {
- let total = 0;
- document.querySelectorAll('.form-row').forEach(row => {
- const productSelect = row.querySelector('.item-product');
- const quantityInput = row.querySelector('.item-quantity');
- if (productSelect.value && quantityInput.value) {
- const productId = parseInt(productSelect.value);
- const product = state.products.find(p => p.id === productId);
- const quantity = parseInt(quantityInput.value);
- if (product) {
- total += product.selling_price * quantity;
- }
- }
- });
- // Apply discount
- const discount = parseFloat(elements.orderForm.querySelector('[name="discount"]').value) || 0;
- if (discount > 0) {
- total = total * (1 - discount / 100);
- }
- elements.orderTotal.value = `$${total.toFixed(2)}`;
- }
- // Populate customer select in order form
- function populateCustomerSelect() {
- const select = elements.orderForm.querySelector('[name="customer_id"]');
- select.innerHTML = '<option value="">Select a customer</option>';
- state.customers.forEach(customer => {
- const option = document.createElement('option');
- option.value = customer.id;
- option.textContent = `${customer.first_name} ${customer.last_name} (${customer.business})`;
- select.appendChild(option);
- });
- }
- // Handle order creation
- function handleCreateOrder(e) {
- e.preventDefault();
- const formData = new FormData(elements.orderForm);
- const items = [];
- document.querySelectorAll('.form-row').forEach(row => {
- const productSelect = row.querySelector('.item-product');
- const quantityInput = row.querySelector('.item-quantity');
- if (productSelect.value && quantityInput.value) {
- const productId = parseInt(productSelect.value);
- const product = state.products.find(p => p.id === productId);
- const quantity = parseInt(quantityInput.value);
- if (product) {
- items.push({
- product_id: productId,
- quantity: quantity,
- price: product.selling_price
- });
- }
- }
- });
- if (items.length === 0) {
- alert('Please add at least one item to the order');
- return;
- }
- const order = {
- id: state.orders.length + 1,
- number: `SO-${String(state.orders.length + 1).padStart(4, '0')}`,
- customer_id: parseInt(formData.get('customer_id')),
- date: formData.get('order_date'),
- items: items,
- discount: parseFloat(formData.get('discount')) || 0,
- status: 'new',
- salesperson: state.currentUser,
- payment_status: 'unpaid'
- };
- state.orders.push(order);
- renderOrders();
- elements.orderModal.style.display = 'none';
- updateDashboardStats();
- }
- // Calculate order total
- function calculateOrderTotal(order) {
- let total = 0;
- order.items.forEach(item => {
- total += item.price * item.quantity;
- });
- if (order.discount > 0) {
- total = total * (1 - order.discount / 100);
- }
- return total;
- }
- // Update dashboard stats
- function updateDashboardStats() {
- // Total products
- elements.totalProducts.textContent = state.products.length;
- // Total sales (this month)
- const currentMonth = new Date().getMonth();
- const monthlySales = state.orders
- .filter(order => new Date(order.date).getMonth() === currentMonth && order.payment_status === 'paid')
- .reduce((sum, order) => sum + calculateOrderTotal(order), 0);
- elements.totalSales.textContent = `$${monthlySales.toFixed(2)}`;
- // Unpaid orders
- const unpaidCount = state.orders.filter(order => order.payment_status === 'unpaid').length;
- elements.unpaidOrders.textContent = unpaidCount;
- // Low stock items
- const lowStockCount = state.products.filter(product => product.quantity < 10).length;
- elements.lowStock.textContent = lowStockCount;
- }
- // Initialize charts
- function initCharts() {
- // Sales Chart
- const salesCtx = elements.salesChart.getContext('2d');
- state.salesChart = new Chart(salesCtx, {
- type: 'bar',
- data: {
- labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4'],
- datasets: [{
- label: 'Sales ($)',
- data: [4200, 5800, 5100, 6700],
- backgroundColor: 'rgba(52, 152, 219, 0.7)',
- borderColor: 'rgba(52, 152, 219, 1)',
- borderWidth: 1
- }]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- scales: {
- y: {
- beginAtZero: true
- }
- }
- }
- });
- // Report Chart
- const reportCtx = elements.reportChart.getContext('2d');
- state.reportChart = new Chart(reportCtx, {
- type: 'bar',
- data: {
- labels: state.salespersons,
- datasets: [{
- label: 'Sales Performance',
- data: [8500, 7200, 6800],
- backgroundColor: [
- 'rgba(46, 204, 113, 0.7)',
- 'rgba(52, 152, 219, 0.7)',
- 'rgba(155, 89, 182, 0.7)'
- ],
- borderColor: [
- 'rgba(46, 204, 113, 1)',
- 'rgba(52, 152, 219, 1)',
- 'rgba(155, 89, 182, 1)'
- ],
- borderWidth: 1
- }]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- scales: {
- y: {
- beginAtZero: true
- }
- }
- }
- });
- // Populate salesperson filter
- state.salespersons.forEach(sp => {
- const option = document.createElement('option');
- option.value = sp;
- option.textContent = sp;
- elements.salespersonFilter.appendChild(option);
- });
- }
- // Update sales chart based on timeframe
- function updateSalesChart() {
- const timeframe = elements.timeframeSelect.value;
- let labels, data;
- switch (timeframe) {
- case 'week':
- labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
- data = [1200, 1900, 1500, 1800, 2200, 1700, 1400];
- break;
- case 'month':
- labels = ['Week 1', 'Week 2', 'Week 3', 'Week 4'];
- data = [4200, 5800, 5100, 6700];
- break;
- case 'year':
- labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
- data = [18500, 19200, 17800, 21000, 22500, 23000, 24500, 23800, 21500, 22000, 23500, 28000];
- break;
- }
- state.salesChart.data.labels = labels;
- state.salesChart.data.datasets[0].data = data;
- state.salesChart.update();
- }
- // Generate report
- function generateReport() {
- const startDate = elements.startDate.value;
- const endDate = elements.endDate.value;
- const salesperson = elements.salespersonFilter.value;
- // Filter orders based on criteria
- let filteredOrders = [...state.orders];
- if (startDate && endDate) {
- filteredOrders = filteredOrders.filter(order => {
- return order.date >= startDate && order.date <= endDate;
- });
- }
- if (salesperson !== 'all') {
- filteredOrders = filteredOrders.filter(order => order.salesperson === salesperson);
- }
- // Render report table
- elements.reportTableBody.innerHTML = '';
- filteredOrders.forEach(order => {
- const customer = state.customers.find(c => c.id === order.customer_id);
- const customerName = customer ? `${customer.first_name} ${customer.last_name}` : 'Unknown';
- const totalAmount = calculateOrderTotal(order);
- let statusClass = '';
- switch (order.status) {
- case 'new': statusClass = 'status-new'; break;
- case 'in-progress': statusClass = 'status-in-progress'; break;
- case 'voided': statusClass = 'status-voided'; break;
- case 'unpaid': statusClass = 'status-unpaid'; break;
- case 'paid': statusClass = 'status-paid'; break;
- case 'fulfilled': statusClass = 'status-fulfilled'; break;
- }
- const row = document.createElement('tr');
- row.innerHTML = `
- <td>${order.number}</td>
- <td>${order.date}</td>
- <td>${customerName}</td>
- <td>${order.salesperson}</td>
- <td>$${totalAmount.toFixed(2)}</td>
- <td><span class="status-badge ${statusClass}">${order.status}</span></td>
- `;
- elements.reportTableBody.appendChild(row);
- });
- // Update report chart
- if (salesperson === 'all') {
- state.reportChart.data.labels = state.salespersons;
- state.reportChart.data.datasets[0].data = [8500, 7200, 6800];
- } else {
- state.reportChart.data.labels = [salesperson];
- state.reportChart.data.datasets[0].data = [filteredOrders.reduce((sum, order) => sum + calculateOrderTotal(order), 0)];
- }
- state.reportChart.update();
- }
- // Edit a product
- function editProduct(id) {
- const product = state.products.find(p => p.id === id);
- if (!product) return;
- elements.productForm.querySelector('[name="name"]').value = product.name;
- elements.productForm.querySelector('[name="category"]').value = product.category;
- elements.productForm.querySelector('[name="cost_price"]').value = product.cost_price;
- elements.productForm.querySelector('[name="selling_price"]').value = product.selling_price;
- elements.productForm.querySelector('[name="quantity"]').value = product.quantity;
- elements.productModal.style.display = 'flex';
- // Update form submit to handle edit
- const originalSubmit = elements.productForm.onsubmit;
- elements.productForm.onsubmit = function(e) {
- e.preventDefault();
- const formData = new FormData(elements.productForm);
- product.name = formData.get('name');
- product.category = formData.get('category');
- product.cost_price = parseFloat(formData.get('cost_price'));
- product.selling_price = parseFloat(formData.get('selling_price'));
- product.quantity = parseInt(formData.get('quantity'));
- renderInventory();
- elements.productModal.style.display = 'none';
- updateDashboardStats();
- // Restore original submit handler
- elements.productForm.onsubmit = originalSubmit;
- };
- }
- // Delete a product
- function deleteProduct(id) {
- if (confirm('Are you sure you want to delete this product?')) {
- state.products = state.products.filter(p => p.id !== id);
- renderInventory();
- updateDashboardStats();
- }
- }
- // View an order
- function viewOrder(id) {
- const order = state.orders.find(o => o.id === id);
- if (!order) return;
- alert(`Viewing order: ${order.number}\nStatus: ${order.status}\nTotal: $${calculateOrderTotal(order).toFixed(2)}`);
- }
- // Void an order
- function voidOrder(id) {
- const order = state.orders.find(o => o.id === id);
- if (!order) return;
- if (confirm(`Are you sure you want to void order ${order.number}?`)) {
- order.status = 'voided';
- renderOrders();
- }
- }
- // Edit a customer
- function editCustomer(id) {
- const customer = state.customers.find(c => c.id === id);
- if (!customer) return;
- alert(`Editing customer: ${customer.first_name} ${customer.last_name}`);
- }
- // Delete a customer
- function deleteCustomer(id) {
- if (confirm('Are you sure you want to delete this customer?')) {
- state.customers = state.customers.filter(c => c.id !== id);
- renderCustomers();
- }
- }
- // Initialize the application when the DOM is loaded
- document.addEventListener('DOMContentLoaded', initApp);
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment