Guest User

Untitled

a guest
Jun 10th, 2025
280
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 63.99 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Inventory & Sales Order Management</title>
  7. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  8. <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  9. <style>
  10. * {
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  15. }
  16.  
  17. :root {
  18. --primary: #3498db;
  19. --secondary: #2c3e50;
  20. --success: #27ae60;
  21. --warning: #f39c12;
  22. --danger: #e74c3c;
  23. --light: #f8f9fa;
  24. --dark: #343a40;
  25. --gray: #6c757d;
  26. }
  27.  
  28. body {
  29. background-color: #f5f7fa;
  30. color: #333;
  31. }
  32.  
  33. .container {
  34. max-width: 1200px;
  35. margin: 0 auto;
  36. padding: 0 15px;
  37. }
  38.  
  39. /* Login Screen */
  40. .login-container {
  41. display: flex;
  42. justify-content: center;
  43. align-items: center;
  44. height: 100vh;
  45. background: linear-gradient(135deg, var(--secondary), var(--primary));
  46. }
  47.  
  48. .login-card {
  49. background: white;
  50. border-radius: 10px;
  51. box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
  52. width: 100%;
  53. max-width: 400px;
  54. padding: 30px;
  55. }
  56.  
  57. .login-card h2 {
  58. text-align: center;
  59. margin-bottom: 30px;
  60. color: var(--secondary);
  61. }
  62.  
  63. .role-selector {
  64. display: flex;
  65. justify-content: center;
  66. gap: 20px;
  67. margin-bottom: 30px;
  68. }
  69.  
  70. .role-btn {
  71. padding: 15px 20px;
  72. border: 2px solid #ddd;
  73. border-radius: 8px;
  74. background: white;
  75. cursor: pointer;
  76. text-align: center;
  77. transition: all 0.3s ease;
  78. flex: 1;
  79. }
  80.  
  81. .role-btn.active {
  82. border-color: var(--primary);
  83. background-color: rgba(52, 152, 219, 0.1);
  84. transform: translateY(-5px);
  85. box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
  86. }
  87.  
  88. .role-btn i {
  89. font-size: 24px;
  90. margin-bottom: 10px;
  91. display: block;
  92. color: var(--primary);
  93. }
  94.  
  95. .login-btn {
  96. width: 100%;
  97. padding: 12px;
  98. background-color: var(--primary);
  99. color: white;
  100. border: none;
  101. border-radius: 5px;
  102. font-size: 16px;
  103. font-weight: 600;
  104. cursor: pointer;
  105. transition: background-color 0.3s;
  106. }
  107.  
  108. .login-btn:hover {
  109. background-color: #2980b9;
  110. }
  111.  
  112. /* App Header */
  113. .app-header {
  114. background-color: var(--secondary);
  115. color: white;
  116. padding: 15px 0;
  117. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  118. }
  119.  
  120. .header-content {
  121. display: flex;
  122. justify-content: space-between;
  123. align-items: center;
  124. }
  125.  
  126. .app-title {
  127. font-size: 24px;
  128. font-weight: 600;
  129. }
  130.  
  131. .user-info {
  132. display: flex;
  133. align-items: center;
  134. gap: 10px;
  135. }
  136.  
  137. .user-role {
  138. background-color: var(--primary);
  139. padding: 5px 10px;
  140. border-radius: 20px;
  141. font-size: 12px;
  142. }
  143.  
  144. .logout-btn {
  145. background: none;
  146. border: none;
  147. color: white;
  148. cursor: pointer;
  149. font-size: 14px;
  150. }
  151.  
  152. /* Navigation */
  153. .nav-container {
  154. background-color: white;
  155. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
  156. margin-bottom: 20px;
  157. }
  158.  
  159. .nav-menu {
  160. display: flex;
  161. list-style: none;
  162. padding: 0;
  163. }
  164.  
  165. .nav-item {
  166. padding: 15px 20px;
  167. cursor: pointer;
  168. transition: background-color 0.3s;
  169. font-weight: 500;
  170. }
  171.  
  172. .nav-item.active {
  173. background-color: rgba(52, 152, 219, 0.1);
  174. color: var(--primary);
  175. border-bottom: 3px solid var(--primary);
  176. }
  177.  
  178. /* Main Content */
  179. .content-section {
  180. background-color: white;
  181. border-radius: 8px;
  182. box-shadow: 0 2px 15px rgba(0, 0, 0, 0.05);
  183. padding: 25px;
  184. margin-bottom: 25px;
  185. display: none;
  186. }
  187.  
  188. .content-section.active {
  189. display: block;
  190. }
  191.  
  192. .section-header {
  193. display: flex;
  194. justify-content: space-between;
  195. align-items: center;
  196. margin-bottom: 25px;
  197. padding-bottom: 15px;
  198. border-bottom: 1px solid #eee;
  199. }
  200.  
  201. .section-title {
  202. font-size: 22px;
  203. font-weight: 600;
  204. color: var(--secondary);
  205. }
  206.  
  207. .btn {
  208. padding: 10px 20px;
  209. border-radius: 5px;
  210. border: none;
  211. font-weight: 600;
  212. cursor: pointer;
  213. transition: all 0.3s;
  214. }
  215.  
  216. .btn-primary {
  217. background-color: var(--primary);
  218. color: white;
  219. }
  220.  
  221. .btn-success {
  222. background-color: var(--success);
  223. color: white;
  224. }
  225.  
  226. .btn-warning {
  227. background-color: var(--warning);
  228. color: white;
  229. }
  230.  
  231. .btn-danger {
  232. background-color: var(--danger);
  233. color: white;
  234. }
  235.  
  236. .btn:hover {
  237. opacity: 0.9;
  238. transform: translateY(-2px);
  239. }
  240.  
  241. /* Tables */
  242. .table-container {
  243. overflow-x: auto;
  244. }
  245.  
  246. .data-table {
  247. width: 100%;
  248. border-collapse: collapse;
  249. }
  250.  
  251. .data-table th {
  252. background-color: #f1f5f9;
  253. text-align: left;
  254. padding: 12px 15px;
  255. font-weight: 600;
  256. color: var(--secondary);
  257. }
  258.  
  259. .data-table td {
  260. padding: 12px 15px;
  261. border-bottom: 1px solid #eee;
  262. }
  263.  
  264. .data-table tr:hover {
  265. background-color: #f8fafc;
  266. }
  267.  
  268. .action-cell {
  269. display: flex;
  270. gap: 10px;
  271. }
  272.  
  273. .action-btn {
  274. padding: 5px 10px;
  275. border-radius: 4px;
  276. font-size: 14px;
  277. cursor: pointer;
  278. border: none;
  279. background-color: #f1f1f1;
  280. }
  281.  
  282. .action-btn i {
  283. margin-right: 5px;
  284. }
  285.  
  286. .edit-btn {
  287. background-color: rgba(52, 152, 219, 0.1);
  288. color: var(--primary);
  289. }
  290.  
  291. .delete-btn {
  292. background-color: rgba(231, 76, 60, 0.1);
  293. color: var(--danger);
  294. }
  295.  
  296. /* Forms */
  297. .form-container {
  298. max-width: 600px;
  299. margin: 0 auto;
  300. }
  301.  
  302. .form-group {
  303. margin-bottom: 20px;
  304. }
  305.  
  306. .form-label {
  307. display: block;
  308. margin-bottom: 8px;
  309. font-weight: 500;
  310. }
  311.  
  312. .form-control {
  313. width: 100%;
  314. padding: 12px;
  315. border: 1px solid #ddd;
  316. border-radius: 5px;
  317. font-size: 16px;
  318. }
  319.  
  320. .form-control:focus {
  321. outline: none;
  322. border-color: var(--primary);
  323. box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
  324. }
  325.  
  326. .form-row {
  327. display: flex;
  328. gap: 20px;
  329. }
  330.  
  331. .form-col {
  332. flex: 1;
  333. }
  334.  
  335. /* Dashboard */
  336. .dashboard-stats {
  337. display: grid;
  338. grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  339. gap: 20px;
  340. margin-bottom: 30px;
  341. }
  342.  
  343. .stat-card {
  344. background-color: white;
  345. border-radius: 8px;
  346. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
  347. padding: 20px;
  348. text-align: center;
  349. }
  350.  
  351. .stat-value {
  352. font-size: 32px;
  353. font-weight: 700;
  354. margin: 10px 0;
  355. color: var(--primary);
  356. }
  357.  
  358. .stat-label {
  359. color: var(--gray);
  360. font-size: 14px;
  361. }
  362.  
  363. .chart-container {
  364. margin-top: 30px;
  365. height: 400px;
  366. }
  367.  
  368. /* Status Badges */
  369. .status-badge {
  370. padding: 5px 10px;
  371. border-radius: 20px;
  372. font-size: 12px;
  373. font-weight: 600;
  374. display: inline-block;
  375. }
  376.  
  377. .status-new {
  378. background-color: rgba(155, 89, 182, 0.1);
  379. color: #9b59b6;
  380. }
  381.  
  382. .status-in-progress {
  383. background-color: rgba(52, 152, 219, 0.1);
  384. color: var(--primary);
  385. }
  386.  
  387. .status-unpaid {
  388. background-color: rgba(243, 156, 18, 0.1);
  389. color: var(--warning);
  390. }
  391.  
  392. .status-paid {
  393. background-color: rgba(46, 204, 113, 0.1);
  394. color: #2ecc71;
  395. }
  396.  
  397. .status-fulfilled {
  398. background-color: rgba(39, 174, 96, 0.1);
  399. color: var(--success);
  400. }
  401.  
  402. .status-voided {
  403. background-color: rgba(231, 76, 60, 0.1);
  404. color: var(--danger);
  405. }
  406.  
  407. /* Responsive */
  408. @media (max-width: 768px) {
  409. .form-row {
  410. flex-direction: column;
  411. gap: 0;
  412. }
  413.  
  414. .dashboard-stats {
  415. grid-template-columns: 1fr;
  416. }
  417.  
  418. .nav-menu {
  419. overflow-x: auto;
  420. }
  421. }
  422. </style>
  423. </head>
  424. <body>
  425. <!-- Login Screen -->
  426. <div id="login-screen" class="login-container">
  427. <div class="login-card">
  428. <h2>Inventory & Sales Order Management</h2>
  429. <div class="role-selector">
  430. <div class="role-btn" data-role="manager">
  431. <i class="fas fa-user-tie"></i>
  432. Manager
  433. </div>
  434. <div class="role-btn" data-role="salesperson">
  435. <i class="fas fa-user"></i>
  436. Salesperson
  437. </div>
  438. </div>
  439. <button id="login-btn" class="login-btn">Login to Dashboard</button>
  440. </div>
  441. </div>
  442.  
  443. <!-- App Container -->
  444. <div id="app-container" style="display: none;">
  445. <!-- Header -->
  446. <header class="app-header">
  447. <div class="container">
  448. <div class="header-content">
  449. <div class="app-title">Inventory & Sales Order Management</div>
  450. <div class="user-info">
  451. <span id="current-username">John Doe</span>
  452. <span id="current-role" class="user-role">Manager</span>
  453. <button id="logout-btn" class="logout-btn">
  454. <i class="fas fa-sign-out-alt"></i> Logout
  455. </button>
  456. </div>
  457. </div>
  458. </div>
  459. </header>
  460.  
  461. <!-- Navigation -->
  462. <nav class="nav-container">
  463. <div class="container">
  464. <ul class="nav-menu">
  465. <li class="nav-item active" data-section="dashboard">Dashboard</li>
  466. <li class="nav-item" data-section="inventory">Inventory</li>
  467. <li class="nav-item" data-section="sales-orders">Sales Orders</li>
  468. <li class="nav-item" data-section="customers">Customers</li>
  469. <li class="nav-item manager-only" data-section="reports">Reports</li>
  470. </ul>
  471. </div>
  472. </nav>
  473.  
  474. <!-- Main Content -->
  475. <main class="container">
  476. <!-- Dashboard -->
  477. <section id="dashboard" class="content-section active">
  478. <div class="section-header">
  479. <h2 class="section-title">Dashboard</h2>
  480. <div>
  481. <button class="btn btn-primary" id="export-report">
  482. <i class="fas fa-download"></i> Export Report
  483. </button>
  484. </div>
  485. </div>
  486.  
  487. <div class="dashboard-stats">
  488. <div class="stat-card">
  489. <div class="stat-label">Total Products</div>
  490. <div class="stat-value" id="total-products">0</div>
  491. <div class="stat-label">In Inventory</div>
  492. </div>
  493.  
  494. <div class="stat-card">
  495. <div class="stat-label">Total Sales</div>
  496. <div class="stat-value" id="total-sales">$0.00</div>
  497. <div class="stat-label">This Month</div>
  498. </div>
  499.  
  500. <div class="stat-card">
  501. <div class="stat-label">Unpaid Orders</div>
  502. <div class="stat-value" id="unpaid-orders">0</div>
  503. <div class="stat-label">Require Attention</div>
  504. </div>
  505.  
  506. <div class="stat-card">
  507. <div class="stat-label">Low Stock Items</div>
  508. <div class="stat-value" id="low-stock">0</div>
  509. <div class="stat-label">Need Replenishment</div>
  510. </div>
  511. </div>
  512.  
  513. <div class="section-header">
  514. <h3 class="section-title">Sales Performance</h3>
  515. <div>
  516. <select id="timeframe-select" class="form-control" style="width: auto;">
  517. <option value="week">Last Week</option>
  518. <option value="month">Last Month</option>
  519. <option value="year">Last Year</option>
  520. </select>
  521. </div>
  522. </div>
  523.  
  524. <div class="chart-container">
  525. <canvas id="sales-chart"></canvas>
  526. </div>
  527. </section>
  528.  
  529. <!-- Inventory Management -->
  530. <section id="inventory" class="content-section">
  531. <div class="section-header">
  532. <h2 class="section-title">Inventory Management</h2>
  533. <div>
  534. <button class="btn btn-primary" id="add-product-btn">
  535. <i class="fas fa-plus"></i> Add Product
  536. </button>
  537. </div>
  538. </div>
  539.  
  540. <div class="table-container">
  541. <table class="data-table">
  542. <thead>
  543. <tr>
  544. <th>Product Name</th>
  545. <th>Category</th>
  546. <th>Cost Price</th>
  547. <th>Selling Price</th>
  548. <th>Quantity</th>
  549. <th>Actions</th>
  550. </tr>
  551. </thead>
  552. <tbody id="inventory-table-body">
  553. <!-- Inventory items will be populated here -->
  554. </tbody>
  555. </table>
  556. </div>
  557. </section>
  558.  
  559. <!-- Sales Orders -->
  560. <section id="sales-orders" class="content-section">
  561. <div class="section-header">
  562. <h2 class="section-title">Sales Orders</h2>
  563. <div>
  564. <button class="btn btn-primary" id="create-order-btn">
  565. <i class="fas fa-plus"></i> Create Order
  566. </button>
  567. </div>
  568. </div>
  569.  
  570. <div class="table-container">
  571. <table class="data-table">
  572. <thead>
  573. <tr>
  574. <th>Order #</th>
  575. <th>Customer</th>
  576. <th>Date</th>
  577. <th>Total Amount</th>
  578. <th>Status</th>
  579. <th>Actions</th>
  580. </tr>
  581. </thead>
  582. <tbody id="orders-table-body">
  583. <!-- Orders will be populated here -->
  584. </tbody>
  585. </table>
  586. </div>
  587. </section>
  588.  
  589. <!-- Customer Management -->
  590. <section id="customers" class="content-section">
  591. <div class="section-header">
  592. <h2 class="section-title">Customer Management</h2>
  593. <div>
  594. <button class="btn btn-primary" id="add-customer-btn">
  595. <i class="fas fa-plus"></i> Add Customer
  596. </button>
  597. </div>
  598. </div>
  599.  
  600. <div class="form-group">
  601. <input type="text" id="customer-search" class="form-control" placeholder="Search customers by name, business, or phone...">
  602. </div>
  603.  
  604. <div class="table-container">
  605. <table class="data-table">
  606. <thead>
  607. <tr>
  608. <th>Name</th>
  609. <th>Business</th>
  610. <th>Email</th>
  611. <th>Phone</th>
  612. <th>Actions</th>
  613. </tr>
  614. </thead>
  615. <tbody id="customers-table-body">
  616. <!-- Customers will be populated here -->
  617. </tbody>
  618. </table>
  619. </div>
  620. </section>
  621.  
  622. <!-- Reports -->
  623. <section id="reports" class="content-section">
  624. <div class="section-header">
  625. <h2 class="section-title">Reports</h2>
  626. <div>
  627. <button class="btn btn-primary" id="export-all-btn">
  628. <i class="fas fa-download"></i> Export All
  629. </button>
  630. </div>
  631. </div>
  632.  
  633. <div class="form-row">
  634. <div class="form-col">
  635. <div class="form-group">
  636. <label class="form-label">Date Range</label>
  637. <div style="display: flex; gap: 10px;">
  638. <input type="date" id="start-date" class="form-control">
  639. <input type="date" id="end-date" class="form-control">
  640. </div>
  641. </div>
  642. </div>
  643. <div class="form-col">
  644. <div class="form-group">
  645. <label class="form-label">Salesperson</label>
  646. <select id="salesperson-filter" class="form-control">
  647. <option value="all">All Salespersons</option>
  648. <!-- Salespersons will be populated here -->
  649. </select>
  650. </div>
  651. </div>
  652. </div>
  653.  
  654. <div class="form-group">
  655. <button class="btn btn-primary" id="generate-report-btn">Generate Report</button>
  656. </div>
  657.  
  658. <div class="chart-container">
  659. <canvas id="report-chart"></canvas>
  660. </div>
  661.  
  662. <div class="table-container">
  663. <table class="data-table">
  664. <thead>
  665. <tr>
  666. <th>Order #</th>
  667. <th>Date</th>
  668. <th>Customer</th>
  669. <th>Salesperson</th>
  670. <th>Amount</th>
  671. <th>Status</th>
  672. </tr>
  673. </thead>
  674. <tbody id="report-table-body">
  675. <!-- Report data will be populated here -->
  676. </tbody>
  677. </table>
  678. </div>
  679. </section>
  680. </main>
  681. </div>
  682.  
  683. <!-- Add Product Modal -->
  684. <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;">
  685. <div style="background: white; width: 100%; max-width: 600px; border-radius: 8px; padding: 25px;">
  686. <h2 style="margin-bottom: 20px;">Add New Product</h2>
  687. <form id="product-form">
  688. <div class="form-group">
  689. <label class="form-label">Product Name</label>
  690. <input type="text" class="form-control" name="name" required>
  691. </div>
  692.  
  693. <div class="form-row">
  694. <div class="form-col">
  695. <div class="form-group">
  696. <label class="form-label">Category</label>
  697. <input type="text" class="form-control" name="category" required>
  698. </div>
  699. </div>
  700. <div class="form-col">
  701. <div class="form-group">
  702. <label class="form-label">Quantity in Stock</label>
  703. <input type="number" class="form-control" name="quantity" min="0" required>
  704. </div>
  705. </div>
  706. </div>
  707.  
  708. <div class="form-row">
  709. <div class="form-col">
  710. <div class="form-group">
  711. <label class="form-label">Cost Price ($)</label>
  712. <input type="number" class="form-control" name="cost_price" min="0" step="0.01" required>
  713. </div>
  714. </div>
  715. <div class="form-col">
  716. <div class="form-group">
  717. <label class="form-label">Selling Price ($)</label>
  718. <input type="number" class="form-control" name="selling_price" min="0" step="0.01" required>
  719. </div>
  720. </div>
  721. </div>
  722.  
  723. <div class="form-group" style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;">
  724. <button type="button" class="btn btn-danger" id="cancel-product-btn">Cancel</button>
  725. <button type="submit" class="btn btn-primary">Save Product</button>
  726. </div>
  727. </form>
  728. </div>
  729. </div>
  730.  
  731. <!-- Order Modal -->
  732. <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;">
  733. <div style="background: white; width: 100%; max-width: 800px; border-radius: 8px; padding: 25px; max-height: 90vh; overflow-y: auto;">
  734. <h2 style="margin-bottom: 20px;">Create Sales Order</h2>
  735. <form id="order-form">
  736. <div class="form-group">
  737. <label class="form-label">Customer</label>
  738. <select class="form-control" name="customer_id" required>
  739. <option value="">Select a customer</option>
  740. <!-- Customers will be populated here -->
  741. </select>
  742. </div>
  743.  
  744. <div class="form-row">
  745. <div class="form-col">
  746. <div class="form-group">
  747. <label class="form-label">Salesperson</label>
  748. <input type="text" class="form-control" value="John Doe" readonly>
  749. </div>
  750. </div>
  751. <div class="form-col">
  752. <div class="form-group">
  753. <label class="form-label">Order Date</label>
  754. <input type="date" class="form-control" name="order_date" required>
  755. </div>
  756. </div>
  757. </div>
  758.  
  759. <h3 style="margin: 20px 0 15px;">Order Items</h3>
  760. <div id="order-items-container">
  761. <!-- Order items will be added here -->
  762. </div>
  763.  
  764. <div class="form-group">
  765. <button type="button" class="btn btn-secondary" id="add-item-btn">
  766. <i class="fas fa-plus"></i> Add Item
  767. </button>
  768. </div>
  769.  
  770. <div style="margin-top: 20px; border-top: 1px solid #eee; padding-top: 20px;">
  771. <div class="form-row">
  772. <div class="form-col">
  773. <div class="form-group">
  774. <label class="form-label">Discount (%)</label>
  775. <input type="number" class="form-control" name="discount" min="0" max="100" value="0">
  776. </div>
  777. </div>
  778. <div class="form-col">
  779. <div class="form-group">
  780. <label class="form-label">Total Amount</label>
  781. <input type="text" class="form-control" id="order-total" value="$0.00" readonly>
  782. </div>
  783. </div>
  784. </div>
  785. </div>
  786.  
  787. <div class="form-group" style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;">
  788. <button type="button" class="btn btn-danger" id="cancel-order-btn">Cancel</button>
  789. <button type="submit" class="btn btn-primary">Create Order</button>
  790. </div>
  791. </form>
  792. </div>
  793. </div>
  794.  
  795. <script>
  796. // App State
  797. const state = {
  798. currentUser: null,
  799. currentRole: null,
  800. products: [
  801. { id: 1, name: "Laptop", category: "Electronics", cost_price: 800, selling_price: 1200, quantity: 15 },
  802. { id: 2, name: "Smartphone", category: "Electronics", cost_price: 400, selling_price: 700, quantity: 30 },
  803. { id: 3, name: "Desk Chair", category: "Furniture", cost_price: 120, selling_price: 250, quantity: 8 },
  804. { id: 4, name: "Coffee Maker", category: "Appliances", cost_price: 50, selling_price: 100, quantity: 12 },
  805. { id: 5, name: "Wireless Headphones", category: "Electronics", cost_price: 80, selling_price: 150, quantity: 22 }
  806. ],
  807. customers: [
  808. { id: 1, first_name: "John", last_name: "Smith", business: "Smith Corp", email: "[email protected]", phone: "555-1234" },
  809. { id: 2, first_name: "Emily", last_name: "Johnson", business: "Johnson LLC", email: "[email protected]", phone: "555-5678" },
  810. { id: 3, first_name: "Michael", last_name: "Williams", business: "Williams Inc", email: "[email protected]", phone: "555-9012" },
  811. { id: 4, first_name: "Sarah", last_name: "Brown", business: "Brown Enterprises", email: "[email protected]", phone: "555-3456" }
  812. ],
  813. orders: [
  814. { id: 1, number: "SO-0001", customer_id: 1, date: "2023-05-15", items: [
  815. { product_id: 1, quantity: 1, price: 1200 },
  816. { product_id: 5, quantity: 2, price: 150 }
  817. ], discount: 10, status: "paid", salesperson: "John Doe", payment_status: "paid" },
  818. { id: 2, number: "SO-0002", customer_id: 2, date: "2023-05-18", items: [
  819. { product_id: 3, quantity: 3, price: 250 }
  820. ], discount: 0, status: "fulfilled", salesperson: "Jane Smith", payment_status: "paid" },
  821. { id: 3, number: "SO-0003", customer_id: 3, date: "2023-05-20", items: [
  822. { product_id: 2, quantity: 2, price: 700 },
  823. { product_id: 4, quantity: 1, price: 100 }
  824. ], discount: 5, status: "unpaid", salesperson: "John Doe", payment_status: "unpaid" }
  825. ],
  826. salespersons: ["John Doe", "Jane Smith", "Robert Johnson"]
  827. };
  828.  
  829. // DOM Elements
  830. const elements = {
  831. loginScreen: document.getElementById('login-screen'),
  832. appContainer: document.getElementById('app-container'),
  833. roleBtns: document.querySelectorAll('.role-btn'),
  834. loginBtn: document.getElementById('login-btn'),
  835. currentUsername: document.getElementById('current-username'),
  836. currentRole: document.getElementById('current-role'),
  837. logoutBtn: document.getElementById('logout-btn'),
  838. navItems: document.querySelectorAll('.nav-item'),
  839. contentSections: document.querySelectorAll('.content-section'),
  840. totalProducts: document.getElementById('total-products'),
  841. totalSales: document.getElementById('total-sales'),
  842. unpaidOrders: document.getElementById('unpaid-orders'),
  843. lowStock: document.getElementById('low-stock'),
  844. salesChart: document.getElementById('sales-chart'),
  845. inventoryTableBody: document.getElementById('inventory-table-body'),
  846. ordersTableBody: document.getElementById('orders-table-body'),
  847. customersTableBody: document.getElementById('customers-table-body'),
  848. reportTableBody: document.getElementById('report-table-body'),
  849. addProductBtn: document.getElementById('add-product-btn'),
  850. productModal: document.getElementById('product-modal'),
  851. productForm: document.getElementById('product-form'),
  852. cancelProductBtn: document.getElementById('cancel-product-btn'),
  853. createOrderBtn: document.getElementById('create-order-btn'),
  854. orderModal: document.getElementById('order-modal'),
  855. orderForm: document.getElementById('order-form'),
  856. cancelOrderBtn: document.getElementById('cancel-order-btn'),
  857. addItemBtn: document.getElementById('add-item-btn'),
  858. orderItemsContainer: document.getElementById('order-items-container'),
  859. orderTotal: document.getElementById('order-total'),
  860. customerSearch: document.getElementById('customer-search'),
  861. exportReportBtn: document.getElementById('export-report'),
  862. exportAllBtn: document.getElementById('export-all-btn'),
  863. generateReportBtn: document.getElementById('generate-report-btn'),
  864. salespersonFilter: document.getElementById('salesperson-filter'),
  865. reportChart: document.getElementById('report-chart'),
  866. timeframeSelect: document.getElementById('timeframe-select')
  867. };
  868.  
  869. // Initialize the application
  870. function initApp() {
  871. // Event Listeners
  872. elements.roleBtns.forEach(btn => {
  873. btn.addEventListener('click', () => {
  874. elements.roleBtns.forEach(b => b.classList.remove('active'));
  875. btn.classList.add('active');
  876. state.currentRole = btn.dataset.role;
  877. });
  878. });
  879.  
  880. elements.loginBtn.addEventListener('click', handleLogin);
  881. elements.logoutBtn.addEventListener('click', handleLogout);
  882.  
  883. elements.navItems.forEach(item => {
  884. item.addEventListener('click', () => {
  885. // Only allow managers to access reports
  886. if (item.dataset.section === 'reports' && state.currentRole !== 'manager') return;
  887.  
  888. elements.navItems.forEach(i => i.classList.remove('active'));
  889. item.classList.add('active');
  890.  
  891. elements.contentSections.forEach(section => {
  892. section.classList.remove('active');
  893. if (section.id === item.dataset.section) {
  894. section.classList.add('active');
  895. }
  896. });
  897. });
  898. });
  899.  
  900. elements.addProductBtn.addEventListener('click', () => {
  901. elements.productModal.style.display = 'flex';
  902. elements.productForm.reset();
  903. });
  904.  
  905. elements.cancelProductBtn.addEventListener('click', () => {
  906. elements.productModal.style.display = 'none';
  907. });
  908.  
  909. elements.productForm.addEventListener('submit', handleAddProduct);
  910.  
  911. elements.createOrderBtn.addEventListener('click', () => {
  912. elements.orderModal.style.display = 'flex';
  913. elements.orderForm.reset();
  914. elements.orderItemsContainer.innerHTML = '';
  915. updateOrderTotal();
  916. populateCustomerSelect();
  917. });
  918.  
  919. elements.cancelOrderBtn.addEventListener('click', () => {
  920. elements.orderModal.style.display = 'none';
  921. });
  922.  
  923. elements.addItemBtn.addEventListener('click', addOrderItem);
  924.  
  925. elements.orderForm.addEventListener('submit', handleCreateOrder);
  926.  
  927. elements.customerSearch.addEventListener('input', filterCustomers);
  928.  
  929. elements.exportReportBtn.addEventListener('click', () => {
  930. alert('Report exported as CSV and PDF');
  931. });
  932.  
  933. elements.exportAllBtn.addEventListener('click', () => {
  934. alert('All reports exported successfully');
  935. });
  936.  
  937. elements.generateReportBtn.addEventListener('click', generateReport);
  938.  
  939. elements.timeframeSelect.addEventListener('change', updateSalesChart);
  940.  
  941. // Set initial role selection
  942. elements.roleBtns[0].classList.add('active');
  943. state.currentRole = 'manager';
  944.  
  945. // Initialize charts
  946. initCharts();
  947. }
  948.  
  949. // Handle login
  950. function handleLogin() {
  951. state.currentUser = state.currentRole === 'manager' ? 'Jane Manager' : 'John Salesperson';
  952.  
  953. elements.currentUsername.textContent = state.currentUser;
  954. elements.currentRole.textContent = state.currentRole === 'manager' ? 'Manager' : 'Salesperson';
  955.  
  956. elements.loginScreen.style.display = 'none';
  957. elements.appContainer.style.display = 'block';
  958.  
  959. // Update all views
  960. renderInventory();
  961. renderOrders();
  962. renderCustomers();
  963. updateDashboardStats();
  964. updateSalesChart();
  965.  
  966. // Hide manager-only elements for salesperson
  967. if (state.currentRole === 'salesperson') {
  968. document.querySelectorAll('.manager-only').forEach(el => {
  969. el.style.display = 'none';
  970. });
  971. }
  972. }
  973.  
  974. // Handle logout
  975. function handleLogout() {
  976. elements.loginScreen.style.display = 'flex';
  977. elements.appContainer.style.display = 'none';
  978. }
  979.  
  980. // Render inventory table
  981. function renderInventory() {
  982. elements.inventoryTableBody.innerHTML = '';
  983.  
  984. state.products.forEach(product => {
  985. const row = document.createElement('tr');
  986.  
  987. row.innerHTML = `
  988. <td>${product.name}</td>
  989. <td>${product.category}</td>
  990. <td>$${product.cost_price.toFixed(2)}</td>
  991. <td>$${product.selling_price.toFixed(2)}</td>
  992. <td>${product.quantity}</td>
  993. <td class="action-cell">
  994. <button class="action-btn edit-btn" data-id="${product.id}">
  995. <i class="fas fa-edit"></i> Edit
  996. </button>
  997. ${state.currentRole === 'manager' ?
  998. `<button class="action-btn delete-btn" data-id="${product.id}">
  999. <i class="fas fa-trash"></i> Delete
  1000. </button>` : ''}
  1001. </td>
  1002. `;
  1003.  
  1004. elements.inventoryTableBody.appendChild(row);
  1005. });
  1006.  
  1007. // Add event listeners to action buttons
  1008. document.querySelectorAll('.edit-btn').forEach(btn => {
  1009. btn.addEventListener('click', () => {
  1010. const productId = parseInt(btn.dataset.id);
  1011. editProduct(productId);
  1012. });
  1013. });
  1014.  
  1015. document.querySelectorAll('.delete-btn').forEach(btn => {
  1016. btn.addEventListener('click', () => {
  1017. const productId = parseInt(btn.dataset.id);
  1018. deleteProduct(productId);
  1019. });
  1020. });
  1021. }
  1022.  
  1023. // Render orders table
  1024. function renderOrders() {
  1025. elements.ordersTableBody.innerHTML = '';
  1026.  
  1027. state.orders.forEach(order => {
  1028. const customer = state.customers.find(c => c.id === order.customer_id);
  1029. const customerName = customer ? `${customer.first_name} ${customer.last_name}` : 'Unknown';
  1030. const totalAmount = calculateOrderTotal(order);
  1031.  
  1032. let statusClass = '';
  1033. switch (order.status) {
  1034. case 'new': statusClass = 'status-new'; break;
  1035. case 'in-progress': statusClass = 'status-in-progress'; break;
  1036. case 'voided': statusClass = 'status-voided'; break;
  1037. case 'unpaid': statusClass = 'status-unpaid'; break;
  1038. case 'paid': statusClass = 'status-paid'; break;
  1039. case 'fulfilled': statusClass = 'status-fulfilled'; break;
  1040. }
  1041.  
  1042. const row = document.createElement('tr');
  1043.  
  1044. row.innerHTML = `
  1045. <td>${order.number}</td>
  1046. <td>${customerName}</td>
  1047. <td>${order.date}</td>
  1048. <td>$${totalAmount.toFixed(2)}</td>
  1049. <td><span class="status-badge ${statusClass}">${order.status}</span></td>
  1050. <td class="action-cell">
  1051. <button class="action-btn edit-btn" data-id="${order.id}">
  1052. <i class="fas fa-eye"></i> View
  1053. </button>
  1054. ${state.currentRole === 'manager' && order.status !== 'voided' ?
  1055. `<button class="action-btn delete-btn" data-id="${order.id}">
  1056. <i class="fas fa-ban"></i> Void
  1057. </button>` : ''}
  1058. </td>
  1059. `;
  1060.  
  1061. elements.ordersTableBody.appendChild(row);
  1062. });
  1063.  
  1064. // Add event listeners to action buttons
  1065. document.querySelectorAll('.edit-btn').forEach(btn => {
  1066. btn.addEventListener('click', () => {
  1067. const orderId = parseInt(btn.dataset.id);
  1068. viewOrder(orderId);
  1069. });
  1070. });
  1071.  
  1072. document.querySelectorAll('.delete-btn').forEach(btn => {
  1073. btn.addEventListener('click', () => {
  1074. const orderId = parseInt(btn.dataset.id);
  1075. voidOrder(orderId);
  1076. });
  1077. });
  1078. }
  1079.  
  1080. // Render customers table
  1081. function renderCustomers() {
  1082. elements.customersTableBody.innerHTML = '';
  1083.  
  1084. state.customers.forEach(customer => {
  1085. const row = document.createElement('tr');
  1086.  
  1087. row.innerHTML = `
  1088. <td>${customer.first_name} ${customer.last_name}</td>
  1089. <td>${customer.business}</td>
  1090. <td>${customer.email}</td>
  1091. <td>${customer.phone}</td>
  1092. <td class="action-cell">
  1093. <button class="action-btn edit-btn" data-id="${customer.id}">
  1094. <i class="fas fa-edit"></i> Edit
  1095. </button>
  1096. <button class="action-btn delete-btn" data-id="${customer.id}">
  1097. <i class="fas fa-trash"></i> Delete
  1098. </button>
  1099. </td>
  1100. `;
  1101.  
  1102. elements.customersTableBody.appendChild(row);
  1103. });
  1104.  
  1105. // Add event listeners to action buttons
  1106. document.querySelectorAll('.edit-btn').forEach(btn => {
  1107. btn.addEventListener('click', () => {
  1108. const customerId = parseInt(btn.dataset.id);
  1109. editCustomer(customerId);
  1110. });
  1111. });
  1112.  
  1113. document.querySelectorAll('.delete-btn').forEach(btn => {
  1114. btn.addEventListener('click', () => {
  1115. const customerId = parseInt(btn.dataset.id);
  1116. deleteCustomer(customerId);
  1117. });
  1118. });
  1119. }
  1120.  
  1121. // Filter customers based on search input
  1122. function filterCustomers() {
  1123. const searchTerm = elements.customerSearch.value.toLowerCase();
  1124.  
  1125. if (!searchTerm) {
  1126. renderCustomers();
  1127. return;
  1128. }
  1129.  
  1130. const filteredCustomers = state.customers.filter(customer => {
  1131. return (
  1132. customer.first_name.toLowerCase().includes(searchTerm) ||
  1133. customer.last_name.toLowerCase().includes(searchTerm) ||
  1134. (customer.business && customer.business.toLowerCase().includes(searchTerm)) ||
  1135. customer.phone.includes(searchTerm)
  1136. );
  1137. });
  1138.  
  1139. elements.customersTableBody.innerHTML = '';
  1140.  
  1141. filteredCustomers.forEach(customer => {
  1142. const row = document.createElement('tr');
  1143.  
  1144. row.innerHTML = `
  1145. <td>${customer.first_name} ${customer.last_name}</td>
  1146. <td>${customer.business}</td>
  1147. <td>${customer.email}</td>
  1148. <td>${customer.phone}</td>
  1149. <td class="action-cell">
  1150. <button class="action-btn edit-btn" data-id="${customer.id}">
  1151. <i class="fas fa-edit"></i> Edit
  1152. </button>
  1153. <button class="action-btn delete-btn" data-id="${customer.id}">
  1154. <i class="fas fa-trash"></i> Delete
  1155. </button>
  1156. </td>
  1157. `;
  1158.  
  1159. elements.customersTableBody.appendChild(row);
  1160. });
  1161.  
  1162. // Reattach event listeners
  1163. document.querySelectorAll('.edit-btn').forEach(btn => {
  1164. btn.addEventListener('click', () => {
  1165. const customerId = parseInt(btn.dataset.id);
  1166. editCustomer(customerId);
  1167. });
  1168. });
  1169.  
  1170. document.querySelectorAll('.delete-btn').forEach(btn => {
  1171. btn.addEventListener('click', () => {
  1172. const customerId = parseInt(btn.dataset.id);
  1173. deleteCustomer(customerId);
  1174. });
  1175. });
  1176. }
  1177.  
  1178. // Add a new product
  1179. function handleAddProduct(e) {
  1180. e.preventDefault();
  1181.  
  1182. const formData = new FormData(elements.productForm);
  1183. const product = {
  1184. id: state.products.length + 1,
  1185. name: formData.get('name'),
  1186. category: formData.get('category'),
  1187. cost_price: parseFloat(formData.get('cost_price')),
  1188. selling_price: parseFloat(formData.get('selling_price')),
  1189. quantity: parseInt(formData.get('quantity'))
  1190. };
  1191.  
  1192. state.products.push(product);
  1193. renderInventory();
  1194. elements.productModal.style.display = 'none';
  1195. updateDashboardStats();
  1196. }
  1197.  
  1198. // Add an item to an order
  1199. function addOrderItem() {
  1200. const itemCount = elements.orderItemsContainer.children.length;
  1201.  
  1202. const itemDiv = document.createElement('div');
  1203. itemDiv.className = 'form-row';
  1204. itemDiv.style.marginBottom = '15px';
  1205. itemDiv.style.paddingBottom = '15px';
  1206. itemDiv.style.borderBottom = '1px solid #eee';
  1207.  
  1208. itemDiv.innerHTML = `
  1209. <div class="form-col">
  1210. <div class="form-group">
  1211. <label class="form-label">Product</label>
  1212. <select class="form-control item-product" required>
  1213. <option value="">Select a product</option>
  1214. ${state.products.map(p => `<option value="${p.id}">${p.name} ($${p.selling_price.toFixed(2)})</option>`).join('')}
  1215. </select>
  1216. </div>
  1217. </div>
  1218. <div class="form-col">
  1219. <div class="form-group">
  1220. <label class="form-label">Quantity</label>
  1221. <input type="number" class="form-control item-quantity" min="1" value="1" required>
  1222. </div>
  1223. </div>
  1224. <div class="form-col" style="display: flex; align-items: flex-end;">
  1225. <button type="button" class="btn btn-danger remove-item-btn" style="height: 42px;">
  1226. <i class="fas fa-times"></i>
  1227. </button>
  1228. </div>
  1229. `;
  1230.  
  1231. elements.orderItemsContainer.appendChild(itemDiv);
  1232.  
  1233. // Add event listener for remove button
  1234. itemDiv.querySelector('.remove-item-btn').addEventListener('click', () => {
  1235. itemDiv.remove();
  1236. updateOrderTotal();
  1237. });
  1238.  
  1239. // Add event listeners for product and quantity changes
  1240. itemDiv.querySelector('.item-product').addEventListener('change', updateOrderTotal);
  1241. itemDiv.querySelector('.item-quantity').addEventListener('input', updateOrderTotal);
  1242. }
  1243.  
  1244. // Update order total amount
  1245. function updateOrderTotal() {
  1246. let total = 0;
  1247.  
  1248. document.querySelectorAll('.form-row').forEach(row => {
  1249. const productSelect = row.querySelector('.item-product');
  1250. const quantityInput = row.querySelector('.item-quantity');
  1251.  
  1252. if (productSelect.value && quantityInput.value) {
  1253. const productId = parseInt(productSelect.value);
  1254. const product = state.products.find(p => p.id === productId);
  1255. const quantity = parseInt(quantityInput.value);
  1256.  
  1257. if (product) {
  1258. total += product.selling_price * quantity;
  1259. }
  1260. }
  1261. });
  1262.  
  1263. // Apply discount
  1264. const discount = parseFloat(elements.orderForm.querySelector('[name="discount"]').value) || 0;
  1265. if (discount > 0) {
  1266. total = total * (1 - discount / 100);
  1267. }
  1268.  
  1269. elements.orderTotal.value = `$${total.toFixed(2)}`;
  1270. }
  1271.  
  1272. // Populate customer select in order form
  1273. function populateCustomerSelect() {
  1274. const select = elements.orderForm.querySelector('[name="customer_id"]');
  1275. select.innerHTML = '<option value="">Select a customer</option>';
  1276.  
  1277. state.customers.forEach(customer => {
  1278. const option = document.createElement('option');
  1279. option.value = customer.id;
  1280. option.textContent = `${customer.first_name} ${customer.last_name} (${customer.business})`;
  1281. select.appendChild(option);
  1282. });
  1283. }
  1284.  
  1285. // Handle order creation
  1286. function handleCreateOrder(e) {
  1287. e.preventDefault();
  1288.  
  1289. const formData = new FormData(elements.orderForm);
  1290. const items = [];
  1291.  
  1292. document.querySelectorAll('.form-row').forEach(row => {
  1293. const productSelect = row.querySelector('.item-product');
  1294. const quantityInput = row.querySelector('.item-quantity');
  1295.  
  1296. if (productSelect.value && quantityInput.value) {
  1297. const productId = parseInt(productSelect.value);
  1298. const product = state.products.find(p => p.id === productId);
  1299. const quantity = parseInt(quantityInput.value);
  1300.  
  1301. if (product) {
  1302. items.push({
  1303. product_id: productId,
  1304. quantity: quantity,
  1305. price: product.selling_price
  1306. });
  1307. }
  1308. }
  1309. });
  1310.  
  1311. if (items.length === 0) {
  1312. alert('Please add at least one item to the order');
  1313. return;
  1314. }
  1315.  
  1316. const order = {
  1317. id: state.orders.length + 1,
  1318. number: `SO-${String(state.orders.length + 1).padStart(4, '0')}`,
  1319. customer_id: parseInt(formData.get('customer_id')),
  1320. date: formData.get('order_date'),
  1321. items: items,
  1322. discount: parseFloat(formData.get('discount')) || 0,
  1323. status: 'new',
  1324. salesperson: state.currentUser,
  1325. payment_status: 'unpaid'
  1326. };
  1327.  
  1328. state.orders.push(order);
  1329. renderOrders();
  1330. elements.orderModal.style.display = 'none';
  1331. updateDashboardStats();
  1332. }
  1333.  
  1334. // Calculate order total
  1335. function calculateOrderTotal(order) {
  1336. let total = 0;
  1337.  
  1338. order.items.forEach(item => {
  1339. total += item.price * item.quantity;
  1340. });
  1341.  
  1342. if (order.discount > 0) {
  1343. total = total * (1 - order.discount / 100);
  1344. }
  1345.  
  1346. return total;
  1347. }
  1348.  
  1349. // Update dashboard stats
  1350. function updateDashboardStats() {
  1351. // Total products
  1352. elements.totalProducts.textContent = state.products.length;
  1353.  
  1354. // Total sales (this month)
  1355. const currentMonth = new Date().getMonth();
  1356. const monthlySales = state.orders
  1357. .filter(order => new Date(order.date).getMonth() === currentMonth && order.payment_status === 'paid')
  1358. .reduce((sum, order) => sum + calculateOrderTotal(order), 0);
  1359.  
  1360. elements.totalSales.textContent = `$${monthlySales.toFixed(2)}`;
  1361.  
  1362. // Unpaid orders
  1363. const unpaidCount = state.orders.filter(order => order.payment_status === 'unpaid').length;
  1364. elements.unpaidOrders.textContent = unpaidCount;
  1365.  
  1366. // Low stock items
  1367. const lowStockCount = state.products.filter(product => product.quantity < 10).length;
  1368. elements.lowStock.textContent = lowStockCount;
  1369. }
  1370.  
  1371. // Initialize charts
  1372. function initCharts() {
  1373. // Sales Chart
  1374. const salesCtx = elements.salesChart.getContext('2d');
  1375. state.salesChart = new Chart(salesCtx, {
  1376. type: 'bar',
  1377. data: {
  1378. labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4'],
  1379. datasets: [{
  1380. label: 'Sales ($)',
  1381. data: [4200, 5800, 5100, 6700],
  1382. backgroundColor: 'rgba(52, 152, 219, 0.7)',
  1383. borderColor: 'rgba(52, 152, 219, 1)',
  1384. borderWidth: 1
  1385. }]
  1386. },
  1387. options: {
  1388. responsive: true,
  1389. maintainAspectRatio: false,
  1390. scales: {
  1391. y: {
  1392. beginAtZero: true
  1393. }
  1394. }
  1395. }
  1396. });
  1397.  
  1398. // Report Chart
  1399. const reportCtx = elements.reportChart.getContext('2d');
  1400. state.reportChart = new Chart(reportCtx, {
  1401. type: 'bar',
  1402. data: {
  1403. labels: state.salespersons,
  1404. datasets: [{
  1405. label: 'Sales Performance',
  1406. data: [8500, 7200, 6800],
  1407. backgroundColor: [
  1408. 'rgba(46, 204, 113, 0.7)',
  1409. 'rgba(52, 152, 219, 0.7)',
  1410. 'rgba(155, 89, 182, 0.7)'
  1411. ],
  1412. borderColor: [
  1413. 'rgba(46, 204, 113, 1)',
  1414. 'rgba(52, 152, 219, 1)',
  1415. 'rgba(155, 89, 182, 1)'
  1416. ],
  1417. borderWidth: 1
  1418. }]
  1419. },
  1420. options: {
  1421. responsive: true,
  1422. maintainAspectRatio: false,
  1423. scales: {
  1424. y: {
  1425. beginAtZero: true
  1426. }
  1427. }
  1428. }
  1429. });
  1430.  
  1431. // Populate salesperson filter
  1432. state.salespersons.forEach(sp => {
  1433. const option = document.createElement('option');
  1434. option.value = sp;
  1435. option.textContent = sp;
  1436. elements.salespersonFilter.appendChild(option);
  1437. });
  1438. }
  1439.  
  1440. // Update sales chart based on timeframe
  1441. function updateSalesChart() {
  1442. const timeframe = elements.timeframeSelect.value;
  1443.  
  1444. let labels, data;
  1445.  
  1446. switch (timeframe) {
  1447. case 'week':
  1448. labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
  1449. data = [1200, 1900, 1500, 1800, 2200, 1700, 1400];
  1450. break;
  1451. case 'month':
  1452. labels = ['Week 1', 'Week 2', 'Week 3', 'Week 4'];
  1453. data = [4200, 5800, 5100, 6700];
  1454. break;
  1455. case 'year':
  1456. labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  1457. data = [18500, 19200, 17800, 21000, 22500, 23000, 24500, 23800, 21500, 22000, 23500, 28000];
  1458. break;
  1459. }
  1460.  
  1461. state.salesChart.data.labels = labels;
  1462. state.salesChart.data.datasets[0].data = data;
  1463. state.salesChart.update();
  1464. }
  1465.  
  1466. // Generate report
  1467. function generateReport() {
  1468. const startDate = elements.startDate.value;
  1469. const endDate = elements.endDate.value;
  1470. const salesperson = elements.salespersonFilter.value;
  1471.  
  1472. // Filter orders based on criteria
  1473. let filteredOrders = [...state.orders];
  1474.  
  1475. if (startDate && endDate) {
  1476. filteredOrders = filteredOrders.filter(order => {
  1477. return order.date >= startDate && order.date <= endDate;
  1478. });
  1479. }
  1480.  
  1481. if (salesperson !== 'all') {
  1482. filteredOrders = filteredOrders.filter(order => order.salesperson === salesperson);
  1483. }
  1484.  
  1485. // Render report table
  1486. elements.reportTableBody.innerHTML = '';
  1487.  
  1488. filteredOrders.forEach(order => {
  1489. const customer = state.customers.find(c => c.id === order.customer_id);
  1490. const customerName = customer ? `${customer.first_name} ${customer.last_name}` : 'Unknown';
  1491. const totalAmount = calculateOrderTotal(order);
  1492.  
  1493. let statusClass = '';
  1494. switch (order.status) {
  1495. case 'new': statusClass = 'status-new'; break;
  1496. case 'in-progress': statusClass = 'status-in-progress'; break;
  1497. case 'voided': statusClass = 'status-voided'; break;
  1498. case 'unpaid': statusClass = 'status-unpaid'; break;
  1499. case 'paid': statusClass = 'status-paid'; break;
  1500. case 'fulfilled': statusClass = 'status-fulfilled'; break;
  1501. }
  1502.  
  1503. const row = document.createElement('tr');
  1504.  
  1505. row.innerHTML = `
  1506. <td>${order.number}</td>
  1507. <td>${order.date}</td>
  1508. <td>${customerName}</td>
  1509. <td>${order.salesperson}</td>
  1510. <td>$${totalAmount.toFixed(2)}</td>
  1511. <td><span class="status-badge ${statusClass}">${order.status}</span></td>
  1512. `;
  1513.  
  1514. elements.reportTableBody.appendChild(row);
  1515. });
  1516.  
  1517. // Update report chart
  1518. if (salesperson === 'all') {
  1519. state.reportChart.data.labels = state.salespersons;
  1520. state.reportChart.data.datasets[0].data = [8500, 7200, 6800];
  1521. } else {
  1522. state.reportChart.data.labels = [salesperson];
  1523. state.reportChart.data.datasets[0].data = [filteredOrders.reduce((sum, order) => sum + calculateOrderTotal(order), 0)];
  1524. }
  1525.  
  1526. state.reportChart.update();
  1527. }
  1528.  
  1529. // Edit a product
  1530. function editProduct(id) {
  1531. const product = state.products.find(p => p.id === id);
  1532. if (!product) return;
  1533.  
  1534. elements.productForm.querySelector('[name="name"]').value = product.name;
  1535. elements.productForm.querySelector('[name="category"]').value = product.category;
  1536. elements.productForm.querySelector('[name="cost_price"]').value = product.cost_price;
  1537. elements.productForm.querySelector('[name="selling_price"]').value = product.selling_price;
  1538. elements.productForm.querySelector('[name="quantity"]').value = product.quantity;
  1539.  
  1540. elements.productModal.style.display = 'flex';
  1541.  
  1542. // Update form submit to handle edit
  1543. const originalSubmit = elements.productForm.onsubmit;
  1544. elements.productForm.onsubmit = function(e) {
  1545. e.preventDefault();
  1546.  
  1547. const formData = new FormData(elements.productForm);
  1548.  
  1549. product.name = formData.get('name');
  1550. product.category = formData.get('category');
  1551. product.cost_price = parseFloat(formData.get('cost_price'));
  1552. product.selling_price = parseFloat(formData.get('selling_price'));
  1553. product.quantity = parseInt(formData.get('quantity'));
  1554.  
  1555. renderInventory();
  1556. elements.productModal.style.display = 'none';
  1557. updateDashboardStats();
  1558.  
  1559. // Restore original submit handler
  1560. elements.productForm.onsubmit = originalSubmit;
  1561. };
  1562. }
  1563.  
  1564. // Delete a product
  1565. function deleteProduct(id) {
  1566. if (confirm('Are you sure you want to delete this product?')) {
  1567. state.products = state.products.filter(p => p.id !== id);
  1568. renderInventory();
  1569. updateDashboardStats();
  1570. }
  1571. }
  1572.  
  1573. // View an order
  1574. function viewOrder(id) {
  1575. const order = state.orders.find(o => o.id === id);
  1576. if (!order) return;
  1577.  
  1578. alert(`Viewing order: ${order.number}\nStatus: ${order.status}\nTotal: $${calculateOrderTotal(order).toFixed(2)}`);
  1579. }
  1580.  
  1581. // Void an order
  1582. function voidOrder(id) {
  1583. const order = state.orders.find(o => o.id === id);
  1584. if (!order) return;
  1585.  
  1586. if (confirm(`Are you sure you want to void order ${order.number}?`)) {
  1587. order.status = 'voided';
  1588. renderOrders();
  1589. }
  1590. }
  1591.  
  1592. // Edit a customer
  1593. function editCustomer(id) {
  1594. const customer = state.customers.find(c => c.id === id);
  1595. if (!customer) return;
  1596.  
  1597. alert(`Editing customer: ${customer.first_name} ${customer.last_name}`);
  1598. }
  1599.  
  1600. // Delete a customer
  1601. function deleteCustomer(id) {
  1602. if (confirm('Are you sure you want to delete this customer?')) {
  1603. state.customers = state.customers.filter(c => c.id !== id);
  1604. renderCustomers();
  1605. }
  1606. }
  1607.  
  1608. // Initialize the application when the DOM is loaded
  1609. document.addEventListener('DOMContentLoaded', initApp);
  1610. </script>
  1611. </body>
  1612. </html>
  1613.  
Advertisement
Add Comment
Please, Sign In to add comment