feat(pos): add tenant DB schema v1.0 with 21 tables and indexes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
353
pos/migrations/v1.0_initial.sql
Normal file
353
pos/migrations/v1.0_initial.sql
Normal file
@@ -0,0 +1,353 @@
|
||||
-- /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);
|
||||
Reference in New Issue
Block a user