[MMD-010] feat: Add fiados schema for customer credit management

- Create customer_credit_accounts table
- Create fiados table for credit sales
- Create fiado_payments table for payment tracking
- Add view v_customer_credit_summary
- Add indexes and RLS policies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Adrian Flores Cortes 2026-01-25 08:22:30 -06:00
parent 5cf220326a
commit 863ab28b09

190
init/13-fiados-schema.sql Normal file
View File

@ -0,0 +1,190 @@
-- ===========================================
-- MECANICAS DIESEL - Fiados (Credit) Schema
-- ===========================================
-- Sistema de crédito para clientes
-- Tracking de ventas a crédito y pagos
SET search_path TO service_management, public;
-- -------------------------------------------
-- CUSTOMER_CREDIT_ACCOUNTS - Cuentas de crédito
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS service_management.customer_credit_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
customer_id UUID NOT NULL REFERENCES service_management.customers(id),
-- Límites de crédito
credit_limit DECIMAL(12,2) DEFAULT 0 CHECK (credit_limit >= 0),
credit_days INTEGER DEFAULT 30 CHECK (credit_days >= 0),
-- Balances
current_balance DECIMAL(12,2) DEFAULT 0, -- Puede ser positivo (debe) o negativo (a favor)
-- Estadísticas
total_credit_given DECIMAL(14,2) DEFAULT 0,
total_payments_received DECIMAL(14,2) DEFAULT 0,
overdue_amount DECIMAL(12,2) DEFAULT 0,
-- Estado
is_active BOOLEAN DEFAULT true,
is_frozen BOOLEAN DEFAULT false, -- Congelar crédito si hay problemas
frozen_reason TEXT,
frozen_at TIMESTAMP WITH TIME ZONE,
frozen_by UUID,
-- Audit
created_by UUID,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT uq_customer_credit_account UNIQUE (tenant_id, customer_id)
);
CREATE INDEX idx_credit_accounts_tenant ON service_management.customer_credit_accounts(tenant_id);
CREATE INDEX idx_credit_accounts_customer ON service_management.customer_credit_accounts(customer_id);
CREATE INDEX idx_credit_accounts_balance ON service_management.customer_credit_accounts(tenant_id, current_balance) WHERE current_balance > 0;
CREATE INDEX idx_credit_accounts_overdue ON service_management.customer_credit_accounts(tenant_id, overdue_amount) WHERE overdue_amount > 0;
CREATE TRIGGER trg_credit_accounts_updated_at
BEFORE UPDATE ON service_management.customer_credit_accounts
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
-- RLS
SELECT create_tenant_rls_policies('service_management', 'customer_credit_accounts');
-- -------------------------------------------
-- FIADOS - Ventas a crédito
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS service_management.fiados (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
-- Relaciones
customer_id UUID NOT NULL REFERENCES service_management.customers(id),
credit_account_id UUID NOT NULL REFERENCES service_management.customer_credit_accounts(id),
order_id UUID REFERENCES service_management.service_orders(id),
-- Identificación
fiado_number VARCHAR(20) NOT NULL,
-- Monto
original_amount DECIMAL(12,2) NOT NULL CHECK (original_amount > 0),
remaining_amount DECIMAL(12,2) NOT NULL CHECK (remaining_amount >= 0),
-- Fechas
issued_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
due_at TIMESTAMP WITH TIME ZONE NOT NULL,
paid_at TIMESTAMP WITH TIME ZONE,
-- Estado
status VARCHAR(20) DEFAULT 'pending'
CHECK (status IN ('pending', 'partial', 'paid', 'overdue', 'cancelled', 'written_off')),
-- Descripción
description TEXT,
notes TEXT,
-- Audit
created_by UUID,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT uq_fiado_number UNIQUE (tenant_id, fiado_number)
);
CREATE INDEX idx_fiados_tenant ON service_management.fiados(tenant_id);
CREATE INDEX idx_fiados_customer ON service_management.fiados(customer_id);
CREATE INDEX idx_fiados_account ON service_management.fiados(credit_account_id);
CREATE INDEX idx_fiados_order ON service_management.fiados(order_id);
CREATE INDEX idx_fiados_status ON service_management.fiados(tenant_id, status);
CREATE INDEX idx_fiados_due ON service_management.fiados(due_at) WHERE status IN ('pending', 'partial');
CREATE INDEX idx_fiados_overdue ON service_management.fiados(tenant_id, due_at) WHERE status = 'overdue';
CREATE TRIGGER trg_fiados_updated_at
BEFORE UPDATE ON service_management.fiados
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
-- RLS
SELECT create_tenant_rls_policies('service_management', 'fiados');
-- -------------------------------------------
-- FIADO_PAYMENTS - Pagos/Abonos a fiados
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS service_management.fiado_payments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
-- Relaciones
customer_id UUID NOT NULL REFERENCES service_management.customers(id),
credit_account_id UUID NOT NULL REFERENCES service_management.customer_credit_accounts(id),
fiado_id UUID REFERENCES service_management.fiados(id), -- NULL si es pago general a cuenta
-- Identificación
payment_number VARCHAR(20) NOT NULL,
-- Monto
amount DECIMAL(12,2) NOT NULL CHECK (amount > 0),
-- Método de pago
payment_method VARCHAR(20) NOT NULL
CHECK (payment_method IN ('cash', 'card', 'transfer', 'check', 'other')),
payment_reference VARCHAR(100), -- Referencia de transferencia, número de cheque, etc.
-- Descripción
notes TEXT,
-- Audit
received_by UUID,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT uq_payment_number UNIQUE (tenant_id, payment_number)
);
CREATE INDEX idx_fiado_payments_tenant ON service_management.fiado_payments(tenant_id);
CREATE INDEX idx_fiado_payments_customer ON service_management.fiado_payments(customer_id);
CREATE INDEX idx_fiado_payments_account ON service_management.fiado_payments(credit_account_id);
CREATE INDEX idx_fiado_payments_fiado ON service_management.fiado_payments(fiado_id);
CREATE INDEX idx_fiado_payments_date ON service_management.fiado_payments(created_at DESC);
-- RLS
SELECT create_tenant_rls_policies('service_management', 'fiado_payments');
-- -------------------------------------------
-- COMMENTS
-- -------------------------------------------
COMMENT ON TABLE service_management.customer_credit_accounts IS 'Cuentas de crédito de clientes';
COMMENT ON COLUMN service_management.customer_credit_accounts.current_balance IS 'Saldo actual: positivo = cliente debe, negativo = saldo a favor';
COMMENT ON COLUMN service_management.customer_credit_accounts.is_frozen IS 'Crédito congelado por morosidad u otra razón';
COMMENT ON TABLE service_management.fiados IS 'Ventas a crédito (fiados) individuales';
COMMENT ON COLUMN service_management.fiados.fiado_number IS 'Número único de fiado (F-001, F-002, etc.)';
COMMENT ON COLUMN service_management.fiados.remaining_amount IS 'Monto pendiente de pago';
COMMENT ON COLUMN service_management.fiados.due_at IS 'Fecha de vencimiento basada en credit_days del cliente';
COMMENT ON TABLE service_management.fiado_payments IS 'Pagos/abonos recibidos para fiados';
COMMENT ON COLUMN service_management.fiado_payments.fiado_id IS 'NULL si el pago se aplica a la cuenta general, no a un fiado específico';
-- -------------------------------------------
-- VIEW: Customer Credit Summary
-- -------------------------------------------
CREATE OR REPLACE VIEW service_management.v_customer_credit_summary AS
SELECT
ca.tenant_id,
ca.customer_id,
c.name AS customer_name,
c.phone AS customer_phone,
ca.credit_limit,
ca.credit_days,
ca.current_balance,
ca.credit_limit - ca.current_balance AS available_credit,
ca.overdue_amount,
ca.is_active,
ca.is_frozen,
(SELECT COUNT(*) FROM service_management.fiados f WHERE f.credit_account_id = ca.id AND f.status IN ('pending', 'partial', 'overdue')) AS pending_fiados_count,
(SELECT COALESCE(SUM(f.remaining_amount), 0) FROM service_management.fiados f WHERE f.credit_account_id = ca.id AND f.status = 'overdue') AS overdue_fiados_amount,
(SELECT MAX(fp.created_at) FROM service_management.fiado_payments fp WHERE fp.credit_account_id = ca.id) AS last_payment_at
FROM service_management.customer_credit_accounts ca
JOIN service_management.customers c ON c.id = ca.customer_id;
COMMENT ON VIEW service_management.v_customer_credit_summary IS 'Resumen de crédito por cliente con estadísticas';