feat: SAT sync improvements, XML export, and operational fixes
SAT sync enhancements: - Filter active (vigente) CFDIs only via DocumentStatus to avoid SAT rejecting recibidos with "No se permite descarga de XML cancelados" - Reclassify CFDIs at save time: tipo='ingreso' received by tenant becomes 'egreso' based on RFC (emisor vs receptor) - Fix pool cleanup bug during long syncs: refresh getPool() on each saveCfdis call instead of holding stale reference for 45+ minutes - Add X-View-Tenant support to SAT controller via viewingTenantId - Add tenantMiddleware to SAT routes for global admin impersonation Cron jobs: - Add separate every-6-hours schedule for specific RFCs - ROEM691011EZ4 configured for frequent sync (00, 06, 12, 18 MX time) XML filesystem export: - Write .xml files to /var/horux/xml/<RFC>/YYYY/MM/UUID.xml - Activated per-RFC via XML_EXPORT_RFCS allowlist - Organized by year/month for browsability Auth improvements: - Send welcome + admin-notification emails on /auth/register (previously only /tenants createTenant flow sent emails) - Set role='contador' for self-registered users (not admin) to prevent new tenants from accessing cross-tenant data Infrastructure: - Set express trust proxy=1 to accept X-Forwarded-For from Nginx (fixes ERR_ERL_UNEXPECTED_X_FORWARDED_FOR from rate limiter) Operational scripts: - setup-horux360-tenant.ts: Provision Horux 360 tenant manually - send-welcome-aaron.ts: Resend welcome email for Aaron (registered before welcome-on-register was added) - export-xmls-roem.ts: Backfill filesystem XMLs from DB for ROEM Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
58
apps/api/scripts/send-welcome-aaron.ts
Normal file
58
apps/api/scripts/send-welcome-aaron.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { config } from 'dotenv';
|
||||
import { resolve } from 'path';
|
||||
config({ path: resolve(process.cwd(), '.env') });
|
||||
|
||||
import { createTransport } from 'nodemailer';
|
||||
|
||||
async function main() {
|
||||
const transporter = createTransport({
|
||||
host: 'smtp.gmail.com',
|
||||
port: 587,
|
||||
secure: false,
|
||||
requireTLS: true,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS,
|
||||
},
|
||||
});
|
||||
|
||||
// Send welcome email
|
||||
const { welcomeEmail } = await import('../src/services/email/templates/welcome.js');
|
||||
const html = welcomeEmail({
|
||||
nombre: 'Aaron Ahumada',
|
||||
email: 'aaron.ahumada.zepeda@gmail.com',
|
||||
tempPassword: '(la que elegiste al registrarte)',
|
||||
});
|
||||
|
||||
await transporter.sendMail({
|
||||
from: process.env.SMTP_FROM,
|
||||
to: 'aaron.ahumada.zepeda@gmail.com',
|
||||
subject: 'Bienvenido a Horux360',
|
||||
html,
|
||||
text: html.replace(/<[^>]*>/g, ''),
|
||||
});
|
||||
console.log('Welcome email sent to aaron.ahumada.zepeda@gmail.com');
|
||||
|
||||
// Send admin notification
|
||||
const { newClientAdminEmail } = await import('../src/services/email/templates/new-client-admin.js');
|
||||
const adminHtml = newClientAdminEmail({
|
||||
clienteNombre: 'AARON AHUMADA ZEPEDA',
|
||||
clienteRfc: 'AUZA640701TI9',
|
||||
adminEmail: 'aaron.ahumada.zepeda@gmail.com',
|
||||
adminNombre: 'Aaron Ahumada',
|
||||
tempPassword: '(elegida por el usuario)',
|
||||
databaseName: 'horux_auza640701ti9',
|
||||
plan: 'starter',
|
||||
});
|
||||
|
||||
await transporter.sendMail({
|
||||
from: process.env.SMTP_FROM,
|
||||
to: process.env.ADMIN_EMAIL,
|
||||
subject: 'Nuevo cliente: AARON AHUMADA ZEPEDA (AUZA640701TI9)',
|
||||
html: adminHtml,
|
||||
text: adminHtml.replace(/<[^>]*>/g, ''),
|
||||
});
|
||||
console.log('Admin notification sent to', process.env.ADMIN_EMAIL);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
Reference in New Issue
Block a user