357 lines
14 KiB
SQL
357 lines
14 KiB
SQL
-- /home/Autopartes/pos/migrations/v1.0_initial.sql
|
|
-- Tenant DB schema v1.0 — 21 tables
|
|
-- Source: design spec section 10 (tenant_{id} DB)
|
|
|
|
-- =====================
|
|
-- SUCURSALES
|
|
-- =====================
|
|
CREATE TABLE branches (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(200) NOT NULL,
|
|
address TEXT,
|
|
phone VARCHAR(20),
|
|
is_active BOOLEAN DEFAULT TRUE
|
|
);
|
|
|
|
-- =====================
|
|
-- EMPLEADOS Y PERMISOS
|
|
-- =====================
|
|
CREATE TABLE employees (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(200) NOT NULL,
|
|
email VARCHAR(200),
|
|
phone VARCHAR(20),
|
|
pin VARCHAR(100), -- hashed, 4 digitos
|
|
password_hash VARCHAR(200),
|
|
role VARCHAR(20) NOT NULL, -- owner, admin, cashier, warehouse, accountant
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
max_discount_pct NUMERIC(5,2) DEFAULT 0,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE employee_permissions (
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
permission VARCHAR(100) NOT NULL, -- 'pos.sell', 'inventory.adjust', etc.
|
|
PRIMARY KEY (employee_id, permission)
|
|
);
|
|
|
|
CREATE TABLE employee_sessions (
|
|
id SERIAL PRIMARY KEY,
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
device_id VARCHAR(200),
|
|
token VARCHAR(500) NOT NULL,
|
|
expires_at TIMESTAMPTZ NOT NULL
|
|
);
|
|
|
|
-- =====================
|
|
-- CLIENTES
|
|
-- =====================
|
|
CREATE TABLE customers (
|
|
id SERIAL PRIMARY KEY,
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
name VARCHAR(300) NOT NULL,
|
|
rfc VARCHAR(13),
|
|
razon_social VARCHAR(300),
|
|
regimen_fiscal VARCHAR(10), -- codigo SAT regimen
|
|
uso_cfdi VARCHAR(10) DEFAULT 'G03', -- codigo SAT uso CFDI
|
|
cp VARCHAR(5),
|
|
email VARCHAR(200),
|
|
phone VARCHAR(20),
|
|
address TEXT,
|
|
price_tier SMALLINT DEFAULT 1 CHECK (price_tier IN (1,2,3)), -- 1=mostrador, 2=taller, 3=mayoreo
|
|
credit_limit NUMERIC(12,2) DEFAULT 0,
|
|
credit_balance NUMERIC(12,2) DEFAULT 0, -- saldo actual de credito
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
vehicle_info JSONB, -- [{make, model, year, vin, plates}]
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
-- =====================
|
|
-- INVENTARIO
|
|
-- =====================
|
|
CREATE TABLE inventory (
|
|
id SERIAL PRIMARY KEY,
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
part_number VARCHAR(100) NOT NULL,
|
|
barcode VARCHAR(100),
|
|
name VARCHAR(300) NOT NULL,
|
|
description TEXT,
|
|
category_id INTEGER,
|
|
brand VARCHAR(100),
|
|
vehicle_compatibility JSONB,
|
|
unit VARCHAR(20) DEFAULT 'PZA',
|
|
cost NUMERIC(12,2) DEFAULT 0,
|
|
price_1 NUMERIC(12,2) DEFAULT 0, -- mostrador
|
|
price_2 NUMERIC(12,2) DEFAULT 0, -- taller
|
|
price_3 NUMERIC(12,2) DEFAULT 0, -- mayoreo
|
|
tax_rate NUMERIC(5,4) DEFAULT 0.16,
|
|
min_stock INTEGER DEFAULT 0,
|
|
max_stock INTEGER DEFAULT 0,
|
|
location VARCHAR(50), -- ubicacion en almacen
|
|
image_url VARCHAR(500),
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
catalog_part_id INTEGER, -- referencia a catalogo Nexus (via API, no FK)
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE inventory_operations (
|
|
id SERIAL PRIMARY KEY,
|
|
inventory_id INTEGER REFERENCES inventory(id),
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
operation_type VARCHAR(20) NOT NULL, -- SALE, PURCHASE, RETURN, ADJUST, TRANSFER, INITIAL
|
|
quantity INTEGER NOT NULL, -- positivo o negativo
|
|
reference_id INTEGER,
|
|
reference_type VARCHAR(50), -- 'sale', 'purchase', 'return', etc.
|
|
cost_at_time NUMERIC(12,2),
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
device_id VARCHAR(200),
|
|
notes TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
-- Stock actual = SUM(inventory_operations.quantity) WHERE inventory_id=X AND branch_id=Y
|
|
|
|
-- =====================
|
|
-- VENTAS
|
|
-- =====================
|
|
CREATE TABLE sales (
|
|
id SERIAL PRIMARY KEY,
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
customer_id INTEGER REFERENCES customers(id), -- NULL = publico general
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
register_id INTEGER, -- FK cash_registers (deferred, table below)
|
|
sale_type VARCHAR(20) NOT NULL, -- cash, credit, mixed
|
|
payment_method VARCHAR(20), -- efectivo, transferencia, tarjeta, mixto
|
|
subtotal NUMERIC(12,2) NOT NULL,
|
|
discount_total NUMERIC(12,2) DEFAULT 0,
|
|
tax_total NUMERIC(12,2) NOT NULL,
|
|
total NUMERIC(12,2) NOT NULL,
|
|
amount_paid NUMERIC(12,2) DEFAULT 0,
|
|
change_given NUMERIC(12,2) DEFAULT 0,
|
|
metodo_pago_sat VARCHAR(3), -- PUE o PPD
|
|
forma_pago_sat VARCHAR(2), -- 01, 03, 04, 99
|
|
status VARCHAR(20) DEFAULT 'completed', -- completed, cancelled, returned
|
|
device_id VARCHAR(200),
|
|
notes TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE sale_items (
|
|
id SERIAL PRIMARY KEY,
|
|
sale_id INTEGER REFERENCES sales(id),
|
|
inventory_id INTEGER REFERENCES inventory(id),
|
|
part_number VARCHAR(100),
|
|
name VARCHAR(300),
|
|
quantity INTEGER NOT NULL,
|
|
unit_price NUMERIC(12,2) NOT NULL, -- precio al momento de la venta
|
|
unit_cost NUMERIC(12,2), -- costo al momento de la venta
|
|
discount_pct NUMERIC(5,2) DEFAULT 0,
|
|
discount_amount NUMERIC(12,2) DEFAULT 0,
|
|
tax_rate NUMERIC(5,4) DEFAULT 0.16,
|
|
tax_amount NUMERIC(12,2) DEFAULT 0,
|
|
subtotal NUMERIC(12,2) NOT NULL,
|
|
clave_prod_serv VARCHAR(10), -- clave SAT
|
|
clave_unidad VARCHAR(10) -- clave unidad SAT
|
|
);
|
|
|
|
-- =====================
|
|
-- COTIZACIONES
|
|
-- =====================
|
|
CREATE TABLE quotations (
|
|
id SERIAL PRIMARY KEY,
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
customer_id INTEGER REFERENCES customers(id),
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
subtotal NUMERIC(12,2) NOT NULL,
|
|
tax_total NUMERIC(12,2) NOT NULL,
|
|
total NUMERIC(12,2) NOT NULL,
|
|
status VARCHAR(20) DEFAULT 'active', -- active, converted, expired, cancelled
|
|
valid_until DATE,
|
|
converted_sale_id INTEGER REFERENCES sales(id),
|
|
notes TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE quotation_items (
|
|
id SERIAL PRIMARY KEY,
|
|
quotation_id INTEGER REFERENCES quotations(id),
|
|
inventory_id INTEGER REFERENCES inventory(id),
|
|
part_number VARCHAR(100),
|
|
name VARCHAR(300),
|
|
quantity INTEGER NOT NULL,
|
|
unit_price NUMERIC(12,2) NOT NULL,
|
|
discount_pct NUMERIC(5,2) DEFAULT 0,
|
|
tax_rate NUMERIC(5,4) DEFAULT 0.16,
|
|
subtotal NUMERIC(12,2) NOT NULL
|
|
);
|
|
|
|
-- =====================
|
|
-- APARTADOS (LAYAWAYS)
|
|
-- =====================
|
|
CREATE TABLE layaways (
|
|
id SERIAL PRIMARY KEY,
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
customer_id INTEGER REFERENCES customers(id) NOT NULL,
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
total NUMERIC(12,2) NOT NULL,
|
|
amount_paid NUMERIC(12,2) DEFAULT 0,
|
|
status VARCHAR(20) DEFAULT 'active', -- active, completed, cancelled
|
|
expires_at DATE,
|
|
converted_sale_id INTEGER REFERENCES sales(id),
|
|
notes TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE layaway_payments (
|
|
id SERIAL PRIMARY KEY,
|
|
layaway_id INTEGER REFERENCES layaways(id),
|
|
amount NUMERIC(12,2) NOT NULL,
|
|
payment_method VARCHAR(20),
|
|
reference VARCHAR(100),
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
-- =====================
|
|
-- CAJA REGISTRADORA
|
|
-- =====================
|
|
CREATE TABLE cash_registers (
|
|
id SERIAL PRIMARY KEY,
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
register_number SMALLINT NOT NULL, -- numero de caja (1, 2, 3...)
|
|
opening_amount NUMERIC(12,2) NOT NULL, -- fondo inicial
|
|
closing_amount NUMERIC(12,2), -- monto contado al cerrar
|
|
expected_amount NUMERIC(12,2), -- monto esperado calculado
|
|
difference NUMERIC(12,2), -- closing - expected
|
|
status VARCHAR(10) DEFAULT 'open', -- open, closed
|
|
opened_at TIMESTAMPTZ DEFAULT NOW(),
|
|
closed_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE TABLE cash_movements (
|
|
id SERIAL PRIMARY KEY,
|
|
register_id INTEGER REFERENCES cash_registers(id),
|
|
type VARCHAR(5) NOT NULL, -- 'in' o 'out'
|
|
amount NUMERIC(12,2) NOT NULL,
|
|
reason VARCHAR(300) NOT NULL,
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
-- =====================
|
|
-- FACTURACION (CFDI QUEUE)
|
|
-- =====================
|
|
CREATE TABLE cfdi_queue (
|
|
id SERIAL PRIMARY KEY,
|
|
sale_id INTEGER REFERENCES sales(id),
|
|
type VARCHAR(10) NOT NULL, -- ingreso, egreso, pago
|
|
xml_unsigned TEXT, -- XML generado por POS backend
|
|
xml_signed TEXT, -- XML firmado+timbrado por Horux
|
|
uuid_fiscal VARCHAR(36), -- UUID del SAT
|
|
status VARCHAR(20) DEFAULT 'pending', -- pending, sending, stamped, failed, cancelled
|
|
retry_count SMALLINT DEFAULT 0,
|
|
provisional_folio VARCHAR(20), -- PRE-XXXXX
|
|
error_message TEXT,
|
|
cancel_motive VARCHAR(2), -- 01, 02, 03, 04
|
|
cancel_replacement_uuid VARCHAR(36), -- UUID del CFDI sustituto (motivo 01)
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
stamped_at TIMESTAMPTZ
|
|
);
|
|
|
|
-- =====================
|
|
-- CONTABILIDAD
|
|
-- =====================
|
|
CREATE TABLE accounts (
|
|
id SERIAL PRIMARY KEY,
|
|
code VARCHAR(20) NOT NULL UNIQUE,
|
|
name VARCHAR(200) NOT NULL,
|
|
parent_id INTEGER REFERENCES accounts(id),
|
|
type VARCHAR(20) NOT NULL, -- activo, pasivo, capital, ingreso, costo, gasto
|
|
sat_code VARCHAR(20),
|
|
is_system BOOLEAN DEFAULT FALSE, -- cuentas predeterminadas no editables
|
|
is_active BOOLEAN DEFAULT TRUE
|
|
);
|
|
|
|
CREATE TABLE journal_entries (
|
|
id SERIAL PRIMARY KEY,
|
|
entry_number INTEGER NOT NULL,
|
|
date DATE NOT NULL,
|
|
type VARCHAR(20), -- ingreso, egreso, diario, poliza
|
|
description TEXT,
|
|
reference_type VARCHAR(50), -- sale, purchase, cash_register, etc.
|
|
reference_id INTEGER,
|
|
status VARCHAR(20) DEFAULT 'posted', -- draft, posted, cancelled
|
|
created_by INTEGER REFERENCES employees(id),
|
|
is_auto BOOLEAN DEFAULT TRUE, -- generada automaticamente
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE journal_entry_lines (
|
|
id SERIAL PRIMARY KEY,
|
|
journal_entry_id INTEGER REFERENCES journal_entries(id),
|
|
account_id INTEGER REFERENCES accounts(id),
|
|
debit NUMERIC(14,2) DEFAULT 0,
|
|
credit NUMERIC(14,2) DEFAULT 0,
|
|
description TEXT
|
|
);
|
|
|
|
CREATE TABLE fiscal_periods (
|
|
id SERIAL PRIMARY KEY,
|
|
year SMALLINT NOT NULL,
|
|
month SMALLINT NOT NULL,
|
|
status VARCHAR(10) DEFAULT 'open', -- open, closed
|
|
closed_by INTEGER REFERENCES employees(id),
|
|
closed_at TIMESTAMPTZ,
|
|
UNIQUE (year, month)
|
|
);
|
|
|
|
-- =====================
|
|
-- AUDITORIA
|
|
-- =====================
|
|
CREATE TABLE audit_log (
|
|
id SERIAL PRIMARY KEY,
|
|
employee_id INTEGER REFERENCES employees(id),
|
|
action VARCHAR(50) NOT NULL,
|
|
entity_type VARCHAR(50),
|
|
entity_id INTEGER,
|
|
old_value JSONB,
|
|
new_value JSONB,
|
|
device_id VARCHAR(200),
|
|
ip_address VARCHAR(45),
|
|
branch_id INTEGER REFERENCES branches(id),
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
-- INSERT-only: nunca UPDATE, nunca DELETE
|
|
|
|
-- =====================
|
|
-- INDEXES
|
|
-- =====================
|
|
CREATE INDEX idx_inv_ops_inventory ON inventory_operations(inventory_id);
|
|
CREATE INDEX idx_inv_ops_branch ON inventory_operations(branch_id);
|
|
CREATE INDEX idx_inv_ops_type ON inventory_operations(operation_type);
|
|
CREATE INDEX idx_inv_ops_created ON inventory_operations(created_at);
|
|
CREATE INDEX idx_sales_branch ON sales(branch_id);
|
|
CREATE INDEX idx_sales_customer ON sales(customer_id);
|
|
CREATE INDEX idx_sales_created ON sales(created_at);
|
|
CREATE INDEX idx_sales_status ON sales(status);
|
|
CREATE INDEX idx_sale_items_sale ON sale_items(sale_id);
|
|
CREATE INDEX idx_inventory_part ON inventory(part_number);
|
|
CREATE INDEX idx_inventory_barcode ON inventory(barcode);
|
|
CREATE INDEX idx_inventory_branch ON inventory(branch_id);
|
|
CREATE INDEX idx_customers_rfc ON customers(rfc);
|
|
CREATE INDEX idx_customers_name ON customers(name);
|
|
CREATE INDEX idx_cfdi_queue_status ON cfdi_queue(status);
|
|
CREATE INDEX idx_cfdi_queue_sale ON cfdi_queue(sale_id);
|
|
CREATE INDEX idx_journal_entries_date ON journal_entries(date);
|
|
CREATE INDEX idx_journal_lines_entry ON journal_entry_lines(journal_entry_id);
|
|
CREATE INDEX idx_audit_log_action ON audit_log(action);
|
|
CREATE INDEX idx_audit_log_entity ON audit_log(entity_type, entity_id);
|
|
CREATE INDEX idx_audit_log_employee ON audit_log(employee_id);
|
|
CREATE INDEX idx_audit_log_created ON audit_log(created_at);
|
|
CREATE UNIQUE INDEX idx_inventory_branch_part ON inventory(branch_id, part_number);
|
|
CREATE INDEX idx_employee_sessions_token ON employee_sessions(token);
|
|
|
|
-- Barcode sequence
|
|
CREATE SEQUENCE IF NOT EXISTS barcode_seq START 1;
|