Skip to main content

Overview

The Product & Inventory module provides a comprehensive catalog management system designed specifically for vehicle service businesses. Track oils, filters, parts, and services with automatic maintenance frequency calculations based on kilometers.

Key Features

  • Barcode-based product identification
  • Category-based organization
  • Maintenance frequency tracking (km-based)
  • Unit of measure support (SUNAT compliant)
  • Tax affectation configuration
  • Multi-category filtering

Product Data Model

Each product contains detailed information for accurate billing and inventory management:
interface Product {
  id: string;
  codigoBarras: string;           // Barcode
  nombre: string;                 // Product name
  categoria: string;              // Category
  precioVenta: number;            // Sale price
  unidadMedida: string;           // Unit of measure (NIU, GAL, LTR, etc.)
  frecuenciaCambioKm?: number;    // Maintenance frequency in kilometers
  afectacionIgv: string;          // Tax affectation ("10" = taxable)
}

Example Product Records

{
  id: "prod-001",
  codigoBarras: "7751234567801",
  nombre: "Aceite Castrol Magnatec 10W-40 (Galón)",
  categoria: "Aceites de Motor",
  precioVenta: 120.00,
  unidadMedida: "GAL",
  frecuenciaCambioKm: 5000,
  afectacionIgv: "10"
}
{
  id: "prod-002",
  codigoBarras: "7751234567802",
  nombre: "Filtro de Aceite Bosh TOY-01",
  categoria: "Filtros",
  precioVenta: 25.00,
  unidadMedida: "NIU",
  frecuenciaCambioKm: 5000,
  afectacionIgv: "10"
}
{
  id: "prod-005",
  codigoBarras: "7751234567805",
  nombre: "Pastillas de Freno Delanteras Toyota",
  categoria: "Repuestos",
  precioVenta: 180.00,
  unidadMedida: "PAR",
  frecuenciaCambioKm: 30000,
  afectacionIgv: "10"
}

Product Categories

The system organizes products into logical categories for easy navigation:

Standard Categories

  • Aceites de Motor - Engine oils and lubricants
  • Filtros - Oil, air, and fuel filters
  • Refrigerantes - Coolants and antifreeze
  • Repuestos - Parts and replacement components

Dynamic Category Management

Categories are automatically extracted from product records:
const categories = useMemo(() => {
  const uniqueCategories = new Set(db.products.map(p => p.categoria));
  return ["TODAS", ...Array.from(uniqueCategories)];
}, []);

Maintenance Frequency Tracking

A unique feature of MotorDesk is kilometer-based maintenance frequency tracking:
When products with frecuenciaCambioKm are used in a service, the system automatically calculates the next service interval by adding the frequency to the current mileage.

Frequency Display

// Display frequency badge (src/pages/Products.tsx:54)
{product.frecuenciaCambioKm ? (
  <span className="flex items-center gap-1.5 bg-orange-50 px-2.5 py-1 rounded-full">
    <Activity size={12} />
    {product.frecuenciaCambioKm.toLocaleString()} KM
  </span>
) : (
  <span className="text-slate-300 text-xs italic">N/A</span>
)}

Common Maintenance Intervals

Product TypeTypical FrequencyExample Products
Oil Change5,000 kmEngine oil, oil filters
Coolant20,000 kmAntifreeze, coolant
Brake Service30,000 kmBrake pads, brake fluid
Synthetic Oil10,000 kmHigh-performance oils

Search and Filtering

The product inventory supports dual filtering:
const filteredProducts = useMemo(() => {
  return db.products.filter((p) => {
    // Category filter
    const matchCategory = selectedCategory === "TODAS" || p.categoria === selectedCategory;
    
    // Text search filter
    const term = searchTerm.toLowerCase();
    const matchSearch =
      p.nombre.toLowerCase().includes(term) ||
      p.codigoBarras.toLowerCase().includes(term) ||
      p.categoria.toLowerCase().includes(term);
    
    return matchCategory && matchSearch;
  });
}, [searchTerm, selectedCategory]);
1

Search by Text

Enter product name, barcode, or category in the search box for instant filtering.
2

Filter by Category

Use the category dropdown to show only products from a specific category or “TODAS” for all products.
3

Combined Filtering

Both filters work together - search within a specific category for precise results.

Unit of Measure (SUNAT Compliant)

MotorDesk supports standard SUNAT unit codes for proper electronic billing:

Common Units

  • NIU - Unidad (Unit) - Default for most items
  • GAL - Galón (Gallon) - For bulk oils
  • LTR - Litro (Liter) - For liquids
  • PAR - Par (Pair) - For matched components

Unit Display

// Product name with unit badge (src/pages/Products.tsx:52)
<td>
  <strong className="block text-slate-800 text-sm">{product.nombre}</strong>
  <span className="font-black text-[10px] text-slate-400 uppercase tracking-widest">
    {product.unidadMedida}
  </span>
</td>

Barcode System

Each product uses a unique barcode for quick identification:
// Barcode display with icon (src/pages/Products.tsx:51)
<div className="flex items-center gap-1.5 bg-slate-100 px-2 py-1 border border-slate-200 rounded w-fit font-mono text-xs">
  <Barcode size={12} />
  {product.codigoBarras}
</div>
Barcodes should follow EAN-13 format (13 digits) for standard retail products, or use internal numbering for custom services.

Product Table Interface

The main product inventory displays comprehensive information:
// Product table structure (src/pages/Products.tsx:44)
<table className={styles.table}>
  <thead>
    <tr>
      <th>CÓDIGO</th>
      <th>PRODUCTO</th>
      <th>CATEGORÍA</th>
      <th>FREC. CAMBIO</th>
      <th>PRECIO</th>
      <th className="text-center">ACCIONES</th>
    </tr>
  </thead>
  <tbody>
    {currentProducts.map((product: any) => (
      <tr key={product.id} className="hover:bg-slate-50 transition-colors">
        <td>
          <div className="flex items-center gap-1.5">
            <Barcode size={12} />{product.codigoBarras}
          </div>
        </td>
        <td>
          <strong>{product.nombre}</strong>
          <span className="text-xs">{product.unidadMedida}</span>
        </td>
        <td><span className={styles.categoryBadge}>{product.categoria}</span></td>
        <td>
          {product.frecuenciaCambioKm ? (
            <span className="bg-orange-50 text-orange-600">
              <Activity size={12} />{product.frecuenciaCambioKm.toLocaleString()} KM
            </span>
          ) : <span>N/A</span>}
        </td>
        <td>S/ {Number(product.precioVenta).toFixed(2)}</td>
      </tr>
    ))}
  </tbody>
</table>

Tax Affectation (IGV)

Products are configured with SUNAT tax affectation codes:
Most products use code “10” which means they are subject to 18% IGV (Impuesto General a las Ventas).
The system supports other SUNAT codes like “20” (Exempt), “30” (Unaffected) for specialized products or services.
afectacionIgv: "10"  // 10 = Taxable with 18% IGV

Product Actions

Each product supports the following operations:
ActionIconDescription
View DetailsEyeView complete product information and usage history
EditEdit2Modify product details, pricing, or frequency
DeleteTrash2Remove product from catalog (with confirmation)

Product Form Modal

Adding or editing products is handled through a dedicated modal:
// Form data structure
const [formData, setFormData] = useState({
  codigoBarras: "",
  nombre: "",
  categoria: "",
  precioVenta: "",
  unidadMedida: "NIU",
  frecuenciaCambioKm: "",
  afectacionIgv: "10"
});
1

Enter Barcode

Input the product’s barcode or generate an internal code.
2

Product Details

Fill in product name, select category from dropdown, and set unit of measure.
3

Pricing and Tax

Set the sale price and confirm tax affectation (default: “10” for taxable).
4

Maintenance Frequency

For maintenance products, set the kilometer interval (optional).

Pagination System

The product list includes pagination for large catalogs:
const totalPages = Math.ceil(filteredProducts.length / itemsPerPage);
const currentProducts = useMemo(() => {
  const startIndex = (currentPage - 1) * itemsPerPage;
  return filteredProducts.slice(startIndex, startIndex + itemsPerPage);
}, [filteredProducts, currentPage, itemsPerPage]);

Integration with Sales Module

Products are directly searchable and selectable in the sales module:
const filteredProducts = db.products.filter(
  (p) =>
    p.nombre.toLowerCase().includes(productSearch.toLowerCase()) ||
    p.codigoBarras?.includes(productSearch)
);
When a product is added to a sales cart, its precioVenta becomes the precioUnitario and can be adjusted per sale if needed.

Best Practices

Product Management Guidelines

  • Use descriptive names that include brand and specifications
  • Always set maintenance frequency for service products
  • Keep prices updated to reflect current costs
  • Organize products into logical categories
  • Use standard SUNAT unit codes for compliance
  • Include complete barcode information for inventory tracking

Build docs developers (and LLMs) love