Skip to main content

Overview

The Sales API provides functions for recording sales transactions and querying sales history. All functions are asynchronous and return Promises.

Sale Object Structure

Sales records follow this structure:
{
  id: number,           // Auto-generated unique identifier
  date: string,         // ISO 8601 date string (e.g., '2026-03-07T10:30:00.000Z')
  items: Array<Object>, // Array of items in the sale
  subtotal: number,     // Subtotal before discount
  discount: number,     // Discount amount applied
  total: number         // Final total after discount
}

Sale Item Structure

Each item in the items array has this structure:
{
  id: number,           // Product ID
  name: string,         // Product name
  price: number,        // Unit price
  qty: number           // Quantity sold
}

addSale()

Records a new sale transaction in the database.
sale
object
required
The sale object containing date, items, and total
id
Promise<number>
Resolves with the auto-generated ID of the new sale record

Implementation

js/db.js
export async function addSale(sale) {
  return tx('sales', 'readwrite', (s) => s.add(sale));
}

Example Usage

import { addSale } from './js/db.js';

// Record a simple sale
const sale = {
  date: new Date().toISOString(),
  items: [
    { id: 1, name: 'Coffee', price: 3.99, qty: 2 },
    { id: 3, name: 'Sandwich', price: 5.50, qty: 1 }
  ],
  subtotal: 13.48,
  discount: 0,
  total: 13.48
};

const saleId = await addSale(sale);
console.log(`Sale recorded with ID: ${saleId}`);

// Record a sale with discount
const discountedSale = {
  date: new Date().toISOString(),
  items: [
    { id: 1, name: 'Coffee', price: 3.99, qty: 5 },
    { id: 2, name: 'Tea', price: 2.99, qty: 3 },
    { id: 3, name: 'Sandwich', price: 5.50, qty: 2 }
  ],
  subtotal: 39.92,
  discount: 3.99,  // 10% discount
  total: 35.93
};

await addSale(discountedSale);

Error Handling

try {
  const saleId = await addSale(sale);
  console.log('Sale recorded successfully');
} catch (error) {
  console.error('Failed to record sale:', error);
  // Handle: database unavailable, invalid data, etc.
}
Important Notes:
  • Always use ISO 8601 date strings for the date field
  • Ensure the total equals subtotal - discount
  • The items array should not be empty
  • Set discount to 0 if no discount is applied

getSalesInRange()

Retrieves sales records within a specified date range.
fromISO
string
required
Start date in ISO 8601 format (inclusive)
toISO
string
required
End date in ISO 8601 format (inclusive)
sales
Promise<Array<Object>>
Resolves with an array of sale objects within the date range

Implementation

js/db.js
export async function getSalesInRange(fromISO, toISO) {
  return tx('sales', 'readonly', (s) => {
    const idx = s.index('date');
    const range = IDBKeyRange.bound(fromISO, toISO);
    return new Promise((resolve) => {
      const rows = [];
      idx.openCursor(range).onsuccess = (e) => {
        const cur = e.target.result;
        if (cur) { rows.push(cur.value); cur.continue(); }
        else resolve(rows);
      };
    });
  });
}

Example Usage

import { getSalesInRange } from './js/db.js';

// Get sales for today
const today = new Date();
today.setHours(0, 0, 0, 0);
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);

const todaySales = await getSalesInRange(
  today.toISOString(),
  tomorrow.toISOString()
);
console.log(`Sales today: ${todaySales.length}`);

// Get sales for a specific week
const weekStart = new Date('2026-03-01T00:00:00.000Z');
const weekEnd = new Date('2026-03-07T23:59:59.999Z');

const weeklySales = await getSalesInRange(
  weekStart.toISOString(),
  weekEnd.toISOString()
);

// Calculate weekly total
const weeklyTotal = weeklySales.reduce((sum, sale) => sum + sale.total, 0);
console.log(`Weekly total: ₹${weeklyTotal.toFixed(2)}`);

// Get sales for the current month
const monthStart = new Date();
monthStart.setDate(1);
monthStart.setHours(0, 0, 0, 0);

const monthEnd = new Date();
monthEnd.setMonth(monthEnd.getMonth() + 1);
monthEnd.setDate(0);
monthEnd.setHours(23, 59, 59, 999);

const monthlySales = await getSalesInRange(
  monthStart.toISOString(),
  monthEnd.toISOString()
);

Error Handling

try {
  const sales = await getSalesInRange(fromDate, toDate);
  if (sales.length === 0) {
    console.log('No sales in this period');
  }
} catch (error) {
  console.error('Failed to retrieve sales:', error);
}
Performance Notes:
  • Uses the date index for efficient range queries
  • Returns results in date order (ascending)
  • Both start and end dates are inclusive

getAllSales()

Retrieves all sales records from the database.
sales
Promise<Array<Object>>
Resolves with an array of all sale objects

Implementation

js/db.js
export async function getAllSales() {
  return tx('sales', 'readonly', (s) => {
    return new Promise((resolve) => {
      const items = [];
      s.openCursor().onsuccess = (e) => {
        const cur = e.target.result;
        if (cur) { items.push(cur.value); cur.continue(); }
        else resolve(items);
      };
    });
  });
}

Example Usage

import { getAllSales } from './js/db.js';

// Get all sales
const allSales = await getAllSales();
console.log(`Total sales: ${allSales.length}`);

// Calculate total revenue
const totalRevenue = allSales.reduce((sum, sale) => sum + sale.total, 0);
console.log(`Total revenue: ₹${totalRevenue.toFixed(2)}`);

// Find best-selling products
const productSales = {};
allSales.forEach(sale => {
  sale.items.forEach(item => {
    if (!productSales[item.name]) {
      productSales[item.name] = 0;
    }
    productSales[item.name] += item.qty;
  });
});

console.log('Product sales:', productSales);

// Get average sale amount
if (allSales.length > 0) {
  const average = totalRevenue / allSales.length;
  console.log(`Average sale: ₹${average.toFixed(2)}`);
}

Error Handling

try {
  const sales = await getAllSales();
  console.log(`Retrieved ${sales.length} sales`);
} catch (error) {
  console.error('Failed to retrieve sales:', error);
}
Use Cases:
  • Generating complete sales reports
  • Calculating lifetime revenue
  • Analyzing sales patterns
  • Exporting data for backup
Performance Considerations:
  • Returns all records (can be memory-intensive for large datasets)
  • Consider using getSalesInRange() for filtered queries
  • Results are not guaranteed to be in any specific order

Build docs developers (and LLMs) love