Files
HoruxDespachosNuevo/apps/api/scripts/seed-demo-obligaciones-tareas.ts
Horux Dev 7df27ce66d chore: catálogo obligaciones, cierre automático, fixes SAT y facturación
- Catálogo de obligaciones fiscales expandido a 30 entradas con campo requierePago.
- Soporte de frecuencia cuatrimestral en obligaciones y declaraciones.
- Automatización de cierre de obligaciones fiscales desde Documentos › Declaraciones.
- Nuevas tablas obligacion_evidencias, obligacion_periodos estados y declaracion_obligaciones.
- Nuevo servicio obligacion-evidencias.service.ts y endpoints REST.
- Refactor de declaraciones.service.ts para vincular obligaciones y crear evidencias.
- Notificaciones por email para evidencias de obligaciones.
- Adjuntar PDFs en correo de declaración subida.
- Fix drill-down de CFDIs: carga completa al visualizar.
- Fix sincronización SAT: tipos P/N, UUID case-insensitive, no reutilizar requestId.
- Fix suscripciones pending en /configuracion/planes-despacho.
- Fix sugerencias de Clave Producto SAT: importar catálogo y robustecer autocomplete.
- Quitar toggle manual de completado en Configuración › Obligaciones fiscales › Tareas.
- Scripts de soporte para Demo Ventas y utilerías (change-user-email, resend-welcome, import-clave-prod-serv).
- Documentación de cambios en docs/CAMBIOS-2026-05-04.md.
2026-06-22 04:53:59 +00:00

125 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Script: seed-demo-obligaciones-tareas
*
* Crea obligaciones fiscales y tareas recurrentes para todos los contribuyentes
* del tenant Demo Ventas. Además asigna el usuario auxiliar a las tareas y
* obligaciones, y lo vincula a la cartera principal.
*
* Ejecución:
* cd apps/api && npx tsx scripts/seed-demo-obligaciones-tareas.ts
*/
import { PrismaClient } from '@prisma/client';
import { tenantDb } from '../src/config/database.ts';
import { seedTareasDefault, materializarPeriodos } from '../src/services/tareas.service.ts';
const prisma = new PrismaClient();
const DEMO_RFC = 'DEMO2501019X2';
const OBLIGACIONES = [
{ id: 'isr-provisional', nombre: 'Pago provisional de ISR', fundamento: 'Art. 14 LISR', frecuencia: 'mensual', fechaLimite: 'Día 17 del mes siguiente', categoria: 'Federal mensual' },
{ id: 'iva-mensual', nombre: 'Pago mensual definitivo de IVA', fundamento: 'Art. 5-D LIVA', frecuencia: 'mensual', fechaLimite: 'Día 17 del mes siguiente', categoria: 'Federal mensual' },
{ id: 'ret-isr-honorarios', nombre: 'Retenciones de ISR por honorarios y arrendamiento a PF', fundamento: 'Art. 106/116 LISR', frecuencia: 'mensual', fechaLimite: 'Día 17 del mes siguiente', categoria: 'Federal mensual' },
{ id: 'diot', nombre: 'DIOT (Declaración Informativa de Operaciones con Terceros)', fundamento: 'Art. 32 LIVA', frecuencia: 'mensual', fechaLimite: 'Último día del mes siguiente', categoria: 'Informativa mensual' },
{ id: 'imss-cuotas', nombre: 'Cuotas obrero-patronales IMSS', fundamento: 'LSS', frecuencia: 'mensual', fechaLimite: 'Día 17 del mes siguiente', categoria: 'Seguridad social' },
{ id: 'anual-isr-pm', nombre: 'Declaración Anual de ISR PM', fundamento: 'Art. 76 LISR', frecuencia: 'anual', fechaLimite: '31 de marzo', categoria: 'Anual' },
{ id: 'isn', nombre: 'ISN - Impuesto Sobre Nómina', fundamento: 'Ley estatal', frecuencia: 'mensual', fechaLimite: 'Varía por estado (CDMX día 17)', categoria: 'Estatal' },
{ id: 'isrtp', nombre: 'Impuesto sobre remuneración al trabajo', fundamento: 'Ley estatal', frecuencia: 'mensual', fechaLimite: 'Día 10 del mes siguiente', categoria: 'Estatal' },
];
async function main() {
console.log('🌱 Sembrando obligaciones y tareas en Demo Ventas...\n');
const tenant = await prisma.tenant.findUnique({ where: { rfc: DEMO_RFC } });
if (!tenant) throw new Error(`Tenant ${DEMO_RFC} no encontrado`);
const auxUser = await prisma.user.findUnique({ where: { email: 'auxiliar@horuxfin.com' } });
if (!auxUser) throw new Error('Usuario auxiliar no encontrado');
const supervisorUser = await prisma.user.findUnique({ where: { email: 'supervisor@horuxfin.com' } });
if (!supervisorUser) throw new Error('Usuario supervisor no encontrado');
const pool = await tenantDb.getPool(tenant.id, tenant.databaseName);
const { rows: contribuyentes } = await pool.query<{ id: string; rfc: string }>(`
SELECT entidad_id AS id, rfc FROM contribuyentes ORDER BY rfc
`);
if (contribuyentes.length === 0) throw new Error('No hay contribuyentes en el tenant demo');
for (const c of contribuyentes) {
// Obligaciones fiscales (idempotente: evita duplicados por contribuyente + catalogo_id)
let obligacionesCreadas = 0;
for (const o of OBLIGACIONES) {
const { rows: existing } = await pool.query(
`SELECT 1 FROM obligaciones_contribuyente WHERE contribuyente_id = $1 AND catalogo_id = $2 LIMIT 1`,
[c.id, o.id],
);
if (existing.length > 0) continue;
await pool.query(`
INSERT INTO obligaciones_contribuyente (
contribuyente_id, catalogo_id, nombre, fundamento, frecuencia, fecha_limite, categoria, activa, es_recomendada
) VALUES ($1, $2, $3, $4, $5, $6, $7, true, true)
`, [c.id, o.id, o.nombre, o.fundamento, o.frecuencia, o.fechaLimite, o.categoria]);
obligacionesCreadas++;
}
console.log(`${c.rfc}: ${obligacionesCreadas} obligaciones creadas`);
// Tareas default
const tareasCreadas = await seedTareasDefault(pool, c.id);
if (tareasCreadas > 0) {
await materializarPeriodos(pool, c.id);
console.log(`${c.rfc}: ${tareasCreadas} tareas creadas y periodos materializados`);
} else {
console.log(` ${c.rfc}: tareas default ya existían`);
}
}
// Asignar auxiliar a todas las obligaciones y tareas activas
await pool.query(`
INSERT INTO obligacion_asignaciones (obligacion_id, auxiliar_user_id, asignado_por)
SELECT oc.id, $1, $2
FROM obligaciones_contribuyente oc
WHERE oc.activa = true
ON CONFLICT (obligacion_id) DO UPDATE SET auxiliar_user_id = EXCLUDED.auxiliar_user_id, asignado_por = EXCLUDED.asignado_por
`, [auxUser.id, supervisorUser.id]);
console.log('✅ Auxiliar asignado a obligaciones');
await pool.query(`
INSERT INTO tarea_asignaciones (tarea_id, auxiliar_user_id, asignado_por)
SELECT tc.id, $1, $2
FROM tareas_catalogo tc
WHERE tc.active = true
ON CONFLICT (tarea_id) DO UPDATE SET auxiliar_user_id = EXCLUDED.auxiliar_user_id, asignado_por = EXCLUDED.asignado_por
`, [auxUser.id, supervisorUser.id]);
console.log('✅ Auxiliar asignado a tareas');
// Asignar auxiliar a la cartera principal
await pool.query(`
UPDATE carteras SET auxiliar_user_id = $1
WHERE parent_id IS NULL
`, [auxUser.id]);
console.log('✅ Auxiliar asignado a la cartera principal');
// Asegurar relación auxiliar-supervisor
await pool.query(`
INSERT INTO auxiliar_supervisores (auxiliar_user_id, supervisor_user_id)
VALUES ($1, $2)
ON CONFLICT (auxiliar_user_id) DO UPDATE SET supervisor_user_id = EXCLUDED.supervisor_user_id
`, [auxUser.id, supervisorUser.id]);
console.log('✅ Relación auxiliar → supervisor registrada');
console.log('\n🎉 Obligaciones y tareas listas en Demo Ventas');
}
main()
.catch((e) => {
console.error('\n❌ Error:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
await tenantDb.shutdown();
});