Skip to main content

Overview

Simple Invoice uses a MySQL/MariaDB database named simple_invoice with 8 main tables. The schema uses MyISAM and InnoDB storage engines.

Tables

users

Stores user accounts with hashed passwords.
ColumnTypeConstraintsDescription
user_idINT(11)PRIMARY KEY, AUTO_INCREMENTUnique user identifier
firstnameVARCHAR(20)NOT NULLUser’s first name
lastnameVARCHAR(20)NOT NULLUser’s last name
user_nameVARCHAR(64)NOT NULL, UNIQUEUsername for login
user_password_hashVARCHAR(255)NOT NULLHashed password (using password_hash)
user_emailVARCHAR(64)NOT NULL, UNIQUEUser’s email address
date_addedDATETIMENOT NULLAccount creation timestamp
Indexes:
  • PRIMARY KEY on user_id
  • UNIQUE KEY on user_name
  • UNIQUE KEY on user_email
Default Data:
INSERT INTO users VALUES 
(1, 'Obed', 'Alvarado', 'admin', 
'$2y$10$MPVHzZ2ZPOWmtUUGCq3RXu31OTB.jo7M9LZ7PmPQYmgETSNn19ejO',
'admin@admin.com', '2016-05-21 15:06:00');
-- Default password: admin

clientes

Stores client/customer information.
ColumnTypeConstraintsDescription
id_clienteINT(11)PRIMARY KEY, AUTO_INCREMENTUnique client identifier
nombre_clienteVARCHAR(255)NOT NULL, UNIQUEClient name
telefono_clienteCHAR(30)NOT NULLClient phone number
email_clienteVARCHAR(64)NOT NULLClient email address
direccion_clienteVARCHAR(255)NOT NULLClient physical address
status_clienteTINYINT(4)NOT NULLStatus: 1=Active, 0=Inactive
date_addedDATETIMENOT NULLRecord creation timestamp
Indexes:
  • PRIMARY KEY on id_cliente
  • UNIQUE KEY on nombre_cliente
Storage Engine: MyISAM Relationships:
  • Referenced by facturas.id_cliente (foreign key constraint in application logic)

products

Stores product catalog information.
ColumnTypeConstraintsDescription
id_productoINT(11)PRIMARY KEY, AUTO_INCREMENTUnique product identifier
codigo_productoCHAR(20)NOT NULL, UNIQUEProduct code/SKU
nombre_productoCHAR(255)NOT NULLProduct name/description
status_productoTINYINT(4)NOT NULLStatus: 1=Active, 0=Inactive
date_addedDATETIMENOT NULLRecord creation timestamp
precio_productoDOUBLENOT NULLProduct sale price
Indexes:
  • PRIMARY KEY on id_producto
  • UNIQUE KEY on codigo_producto
Storage Engine: MyISAM Relationships:
  • Referenced by detalle_factura.id_producto
  • Referenced by tmp.id_producto

facturas

Stores invoice header information.
ColumnTypeConstraintsDescription
id_facturaINT(11)PRIMARY KEY, AUTO_INCREMENTUnique invoice identifier
numero_facturaINT(11)NOT NULL, UNIQUEInvoice number (display)
fecha_facturaDATETIMENOT NULLInvoice date
id_clienteINT(11)NOT NULLClient ID (references clientes)
id_vendedorINT(11)NOT NULLVendor/salesperson ID (references users)
condicionesVARCHAR(30)NOT NULLPayment terms/conditions
total_ventaVARCHAR(20)NOT NULLTotal sale amount
estado_facturaTINYINT(1)NOT NULLStatus: 1=Paid, 0=Pending
Indexes:
  • PRIMARY KEY on id_factura
  • UNIQUE KEY on numero_factura
Storage Engine: MyISAM Relationships:
  • Foreign key to clientes.id_cliente (application enforced)
  • Foreign key to users.user_id via id_vendedor (application enforced)
  • Referenced by detalle_factura.numero_factura

detalle_factura

Stores invoice line items (products on each invoice).
ColumnTypeConstraintsDescription
id_detalleINT(11)PRIMARY KEY, AUTO_INCREMENTUnique line item identifier
numero_facturaINT(11)NOT NULLInvoice number (references facturas)
id_productoINT(11)NOT NULLProduct ID (references products)
cantidadINT(11)NOT NULLQuantity ordered
precio_ventaDOUBLENOT NULLUnit price at time of sale
Indexes:
  • PRIMARY KEY on id_detalle
  • KEY on (numero_factura, id_producto)
Storage Engine: MyISAM Relationships:
  • Foreign key to facturas.numero_factura (application enforced)
  • Foreign key to products.id_producto (application enforced)
Calculated Fields:
  • Line total = cantidad × precio_venta

perfil

Stores company/business profile settings (singleton table with one row).
ColumnTypeConstraintsDescription
id_perfilINT(11)PRIMARY KEY, AUTO_INCREMENTProfile identifier (always 1)
nombre_empresaVARCHAR(150)NOT NULLCompany name
direccionVARCHAR(255)NOT NULLCompany address
ciudadVARCHAR(100)NOT NULLCity
codigo_postalVARCHAR(100)NOT NULLPostal/ZIP code
estadoVARCHAR(100)NOT NULLState/province
telefonoVARCHAR(20)NOT NULLCompany phone
emailVARCHAR(64)NOT NULLCompany email
impuestoINT(2)NOT NULLTax/IVA percentage (e.g., 13)
monedaVARCHAR(6)NOT NULLCurrency symbol
logo_urlVARCHAR(255)NOT NULLPath to company logo image
Indexes:
  • PRIMARY KEY on id_perfil
Storage Engine: InnoDB Default Data:
INSERT INTO perfil VALUES 
(1, 'SISTEMAS WEB LA', 'Colonias Los Andes #250', 'Moncagua', 
'3301', 'San Miguel', '+(503) 2682-555', 'info@obedalvarado.pw', 
13, '$', 'img/1478792451_google30.png');
Usage:
  • Used in invoice PDF generation
  • Tax percentage applied to all invoices
  • Currency symbol displayed throughout application

tmp

Temporary storage for invoice line items during invoice creation (session-based).
ColumnTypeConstraintsDescription
id_tmpINT(11)PRIMARY KEY, AUTO_INCREMENTUnique temporary item identifier
id_productoINT(11)NOT NULLProduct ID (references products)
cantidad_tmpINT(11)NOT NULLQuantity
precio_tmpDOUBLE(8,2)NULLUnit price
session_idVARCHAR(100)NOT NULLPHP session ID
Indexes:
  • PRIMARY KEY on id_tmp
Storage Engine: MyISAM Usage:
  • Stores products added to invoice before finalization
  • Each user session has its own set of temporary items
  • Items are moved to detalle_factura when invoice is finalized
  • Should be periodically cleaned of old sessions

currencies

Reference table for supported currencies (pre-populated).
ColumnTypeConstraintsDescription
idINT(10) UNSIGNEDPRIMARY KEY, AUTO_INCREMENTCurrency identifier
nameVARCHAR(255)NOT NULLCurrency name
symbolVARCHAR(255)NOT NULLCurrency symbol (HTML encoded)
precisionVARCHAR(255)NOT NULLDecimal precision (e.g., “2”)
thousand_separatorVARCHAR(255)NOT NULLThousands separator (e.g., ”,“)
decimal_separatorVARCHAR(255)NOT NULLDecimal separator (e.g., ”.”)
codeVARCHAR(255)NOT NULLISO currency code
Indexes:
  • PRIMARY KEY on id
Storage Engine: InnoDB Supported Currencies: 32 currencies including USD, EUR, GBP, CAD, MXN, BRL, ARS, COP, etc. Example Data:
(1, 'US Dollar', '$', '2', ',', '.', 'USD'),
(2, 'Libra Esterlina', '£', '2', ',', '.', 'GBP'),
(3, 'Euro', '€', '2', '.', ',', 'EUR')

Entity Relationship Diagram

┌─────────────┐
│    users    │
├─────────────┤
│ user_id (PK)│───┐
│ firstname   │   │
│ lastname    │   │
│ user_name   │   │
│ user_email  │   │
└─────────────┘   │


┌─────────────┐   │      ┌──────────────┐
│  clientes   │   │      │   facturas   │
├─────────────┤   │      ├──────────────┤
│id_cliente(PK)───┼─────→│id_factura(PK)│
│nombre_cliente   │      │numero_factura│←───┐
│telefono_cliente │      │fecha_factura │    │
│email_cliente│   │      │id_cliente(FK)│    │
│direccion_cliente│      │id_vendedor(FK)───┘
│status_cliente│         │condiciones   │
└─────────────┘         │total_venta   │
                         │estado_factura│
┌─────────────┐         └──────────────┘
│  products   │                │
├─────────────┤                │
│id_producto(PK)──┬────────────┘
│codigo_producto│ │
│nombre_producto│ │  ┌────────────────┐
│precio_producto│ │  │detalle_factura │
│status_producto│ │  ├────────────────┤
└─────────────┘  │  │id_detalle (PK) │
                  └→│numero_factura(FK)
┌─────────────┐    │id_producto (FK)│
│     tmp     │    │cantidad        │
├─────────────┤    │precio_venta    │
│id_tmp (PK)  │    └────────────────┘
│id_producto(FK)─┘
│cantidad_tmp │
│precio_tmp   │
│session_id   │
└─────────────┘

┌─────────────┐
│   perfil    │
├─────────────┤
│id_perfil(PK)│ (singleton: id=1)
│nombre_empresa
│direccion    │
│impuesto     │
│moneda       │
└─────────────┘

SQL Schema Export

The complete schema can be found in simple_invoice.sql in the source code root directory.
CREATE TABLE users (
  user_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  firstname VARCHAR(20) NOT NULL,
  lastname VARCHAR(20) NOT NULL,
  user_name VARCHAR(64) NOT NULL UNIQUE,
  user_password_hash VARCHAR(255) NOT NULL,
  user_email VARCHAR(64) NOT NULL UNIQUE,
  date_added DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE clientes (
  id_cliente INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  nombre_cliente VARCHAR(255) NOT NULL UNIQUE,
  telefono_cliente CHAR(30) NOT NULL,
  email_cliente VARCHAR(64) NOT NULL,
  direccion_cliente VARCHAR(255) NOT NULL,
  status_cliente TINYINT(4) NOT NULL,
  date_added DATETIME NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE products (
  id_producto INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  codigo_producto CHAR(20) NOT NULL UNIQUE,
  nombre_producto CHAR(255) NOT NULL,
  status_producto TINYINT(4) NOT NULL,
  date_added DATETIME NOT NULL,
  precio_producto DOUBLE NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE facturas (
  id_factura INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  numero_factura INT(11) NOT NULL UNIQUE,
  fecha_factura DATETIME NOT NULL,
  id_cliente INT(11) NOT NULL,
  id_vendedor INT(11) NOT NULL,
  condiciones VARCHAR(30) NOT NULL,
  total_venta VARCHAR(20) NOT NULL,
  estado_factura TINYINT(1) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE detalle_factura (
  id_detalle INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  numero_factura INT(11) NOT NULL,
  id_producto INT(11) NOT NULL,
  cantidad INT(11) NOT NULL,
  precio_venta DOUBLE NOT NULL,
  KEY numero_factura (numero_factura, id_producto)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE tmp (
  id_tmp INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  id_producto INT(11) NOT NULL,
  cantidad_tmp INT(11) NOT NULL,
  precio_tmp DOUBLE(8,2) DEFAULT NULL,
  session_id VARCHAR(100) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE perfil (
  id_perfil INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  nombre_empresa VARCHAR(150) NOT NULL,
  direccion VARCHAR(255) NOT NULL,
  ciudad VARCHAR(100) NOT NULL,
  codigo_postal VARCHAR(100) NOT NULL,
  estado VARCHAR(100) NOT NULL,
  telefono VARCHAR(20) NOT NULL,
  email VARCHAR(64) NOT NULL,
  impuesto INT(2) NOT NULL,
  moneda VARCHAR(6) NOT NULL,
  logo_url VARCHAR(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Data Integrity Notes

Foreign Key Constraints: The schema uses MyISAM engine for most tables, which does not support foreign key constraints. Data integrity is enforced at the application level through PHP validation.
Cascade Deletions: When deleting records:
  • Deleting a client: Check for associated invoices first
  • Deleting a product: Check for references in detalle_factura
  • Deleting an invoice: Manually delete associated detalle_factura records
Application-Level Constraints:
  • Clients with invoices cannot be deleted
  • Products with invoice line items cannot be deleted
  • User ID 1 (admin) cannot be deleted
  • Deleting an invoice also deletes its line items

Common Queries

SELECT 
  f.numero_factura,
  f.fecha_factura,
  c.nombre_cliente,
  u.firstname,
  u.lastname,
  f.total_venta,
  f.estado_factura
FROM facturas f
JOIN clientes c ON f.id_cliente = c.id_cliente
JOIN users u ON f.id_vendedor = u.user_id
WHERE f.id_factura = ?;

SELECT 
  p.codigo_producto,
  p.nombre_producto,
  d.cantidad,
  d.precio_venta,
  (d.cantidad * d.precio_venta) as total
FROM detalle_factura d
JOIN products p ON d.id_producto = p.id_producto
WHERE d.numero_factura = ?;

Build docs developers (and LLMs) love