feat(pacifictrans): enable dual SuperAdmin numbers and connect DIAN billing hub to production URL
This commit is contained in:
parent
3dc430e4e3
commit
cd1f7190be
@ -1494,6 +1494,9 @@
|
|||||||
<button type="button" id="btn-billing-run-cut" class="btn-primary" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: linear-gradient(135deg, #10b981, #059669);">
|
<button type="button" id="btn-billing-run-cut" class="btn-primary" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: linear-gradient(135deg, #10b981, #059669);">
|
||||||
⚡ Ejecutar Corte Mensual Ahora
|
⚡ Ejecutar Corte Mensual Ahora
|
||||||
</button>
|
</button>
|
||||||
|
<a href="https://facturacion.almeira.com.co" target="_blank" rel="noreferrer" class="btn-primary" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: rgba(16, 185, 129, 0.15); border: 1px solid #10b981; color: #34d399; text-decoration: none; display: inline-flex; align-items: center; gap: 0.4rem;">
|
||||||
|
🏛️ Facturación Electrónica Oficial
|
||||||
|
</a>
|
||||||
<button type="button" id="btn-billing-download-csv" class="btn-toggle-payment" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: rgba(56, 189, 248, 0.15); border-color: #38bdf8; color: #38bdf8;">
|
<button type="button" id="btn-billing-download-csv" class="btn-toggle-payment" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: rgba(56, 189, 248, 0.15); border-color: #38bdf8; color: #38bdf8;">
|
||||||
📥 Descargar CSV para DIAN
|
📥 Descargar CSV para DIAN
|
||||||
</button>
|
</button>
|
||||||
@ -1591,11 +1594,12 @@
|
|||||||
<th>Cantidad Viajes</th>
|
<th>Cantidad Viajes</th>
|
||||||
<th>Estado Facturación</th>
|
<th>Estado Facturación</th>
|
||||||
<th>Fecha Cierre</th>
|
<th>Fecha Cierre</th>
|
||||||
|
<th>Acción DIAN</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="table-billing-cierres-body">
|
<tbody id="table-billing-cierres-body">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="9" style="text-align: center; padding: 2rem; color: #94a3b8;">
|
<td colspan="10" style="text-align: center; padding: 2rem; color: #94a3b8;">
|
||||||
Cargando información fiscal...
|
Cargando información fiscal...
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -5218,11 +5218,63 @@ function renderMonthlyBillingTable(cierres, mes, anio) {
|
|||||||
<td style="font-size: 0.8rem; color: #94a3b8;">
|
<td style="font-size: 0.8rem; color: #94a3b8;">
|
||||||
${fechaCierreFmt}
|
${fechaCierreFmt}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
${isApi || c.numero_factura ? `
|
||||||
|
<div style="display: flex; flex-direction: column; gap: 3px;">
|
||||||
|
<span style="font-family: monospace; font-size: 0.75rem; color: #34d399; font-weight: 700;">
|
||||||
|
${c.numero_factura || 'Factura DIAN'}
|
||||||
|
</span>
|
||||||
|
<a href="${c.pdf_url || ('https://facturacion.almeira.com.co/api/v1/invoices/' + (c.numero_factura || '') + '/pdf')}" target="_blank" rel="noreferrer" style="font-size: 0.72rem; color: #38bdf8; text-decoration: underline; cursor: pointer;">
|
||||||
|
📄 Ver PDF
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
` : `
|
||||||
|
<button type="button" class="btn-emit-invoice-dian" data-id="${id}" style="padding: 4px 8px; font-size: 0.75rem; background: linear-gradient(135deg, #10b981, #059669); color: #fff; border: none; border-radius: 6px; font-weight: 700; cursor: pointer; display: flex; align-items: center; gap: 3px;">
|
||||||
|
⚡ Facturar
|
||||||
|
</button>
|
||||||
|
`}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
attachBillingItemCheckboxListeners();
|
attachBillingItemCheckboxListeners();
|
||||||
|
attachBillingActionListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachBillingActionListeners() {
|
||||||
|
const emitBtns = document.querySelectorAll('.btn-emit-invoice-dian');
|
||||||
|
emitBtns.forEach(btn => {
|
||||||
|
btn.addEventListener('click', async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const id = btn.getAttribute('data-id');
|
||||||
|
if (!confirm('¿Deseas emitir la Factura Electrónica oficial ante la DIAN para este cierre?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Emitiendo...';
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/admin/billing/emitir-factura', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ idCierre: id })
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if (res.ok && data.success) {
|
||||||
|
alert(`✅ Factura ${data.factura.fullNumber} emitida con éxito ante la DIAN.`);
|
||||||
|
window.fetchMonthlyBillingReport();
|
||||||
|
} else {
|
||||||
|
alert(`Error al emitir factura: ${data.error || 'Fallo de emisión'}`);
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = '⚡ Facturar';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert('Error de conexión con el servidor fiscal.');
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = '⚡ Facturar';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachBillingItemCheckboxListeners() {
|
function attachBillingItemCheckboxListeners() {
|
||||||
|
|||||||
@ -1494,6 +1494,9 @@
|
|||||||
<button type="button" id="btn-billing-run-cut" class="btn-primary" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: linear-gradient(135deg, #10b981, #059669);">
|
<button type="button" id="btn-billing-run-cut" class="btn-primary" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: linear-gradient(135deg, #10b981, #059669);">
|
||||||
⚡ Ejecutar Corte Mensual Ahora
|
⚡ Ejecutar Corte Mensual Ahora
|
||||||
</button>
|
</button>
|
||||||
|
<a href="https://facturacion.almeira.com.co" target="_blank" rel="noreferrer" class="btn-primary" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: rgba(16, 185, 129, 0.15); border: 1px solid #10b981; color: #34d399; text-decoration: none; display: inline-flex; align-items: center; gap: 0.4rem;">
|
||||||
|
🏛️ Facturación Electrónica Oficial
|
||||||
|
</a>
|
||||||
<button type="button" id="btn-billing-download-csv" class="btn-toggle-payment" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: rgba(56, 189, 248, 0.15); border-color: #38bdf8; color: #38bdf8;">
|
<button type="button" id="btn-billing-download-csv" class="btn-toggle-payment" style="padding: 0.6rem 1.25rem; font-size: 0.85rem; width: auto; background: rgba(56, 189, 248, 0.15); border-color: #38bdf8; color: #38bdf8;">
|
||||||
📥 Descargar CSV para DIAN
|
📥 Descargar CSV para DIAN
|
||||||
</button>
|
</button>
|
||||||
@ -1591,11 +1594,12 @@
|
|||||||
<th>Cantidad Viajes</th>
|
<th>Cantidad Viajes</th>
|
||||||
<th>Estado Facturación</th>
|
<th>Estado Facturación</th>
|
||||||
<th>Fecha Cierre</th>
|
<th>Fecha Cierre</th>
|
||||||
|
<th>Acción DIAN</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="table-billing-cierres-body">
|
<tbody id="table-billing-cierres-body">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="9" style="text-align: center; padding: 2rem; color: #94a3b8;">
|
<td colspan="10" style="text-align: center; padding: 2rem; color: #94a3b8;">
|
||||||
Cargando información fiscal...
|
Cargando información fiscal...
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -5218,11 +5218,63 @@ function renderMonthlyBillingTable(cierres, mes, anio) {
|
|||||||
<td style="font-size: 0.8rem; color: #94a3b8;">
|
<td style="font-size: 0.8rem; color: #94a3b8;">
|
||||||
${fechaCierreFmt}
|
${fechaCierreFmt}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
${isApi || c.numero_factura ? `
|
||||||
|
<div style="display: flex; flex-direction: column; gap: 3px;">
|
||||||
|
<span style="font-family: monospace; font-size: 0.75rem; color: #34d399; font-weight: 700;">
|
||||||
|
${c.numero_factura || 'Factura DIAN'}
|
||||||
|
</span>
|
||||||
|
<a href="${c.pdf_url || ('https://facturacion.almeira.com.co/api/v1/invoices/' + (c.numero_factura || '') + '/pdf')}" target="_blank" rel="noreferrer" style="font-size: 0.72rem; color: #38bdf8; text-decoration: underline; cursor: pointer;">
|
||||||
|
📄 Ver PDF
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
` : `
|
||||||
|
<button type="button" class="btn-emit-invoice-dian" data-id="${id}" style="padding: 4px 8px; font-size: 0.75rem; background: linear-gradient(135deg, #10b981, #059669); color: #fff; border: none; border-radius: 6px; font-weight: 700; cursor: pointer; display: flex; align-items: center; gap: 3px;">
|
||||||
|
⚡ Facturar
|
||||||
|
</button>
|
||||||
|
`}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
attachBillingItemCheckboxListeners();
|
attachBillingItemCheckboxListeners();
|
||||||
|
attachBillingActionListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachBillingActionListeners() {
|
||||||
|
const emitBtns = document.querySelectorAll('.btn-emit-invoice-dian');
|
||||||
|
emitBtns.forEach(btn => {
|
||||||
|
btn.addEventListener('click', async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const id = btn.getAttribute('data-id');
|
||||||
|
if (!confirm('¿Deseas emitir la Factura Electrónica oficial ante la DIAN para este cierre?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Emitiendo...';
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/admin/billing/emitir-factura', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ idCierre: id })
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if (res.ok && data.success) {
|
||||||
|
alert(`✅ Factura ${data.factura.fullNumber} emitida con éxito ante la DIAN.`);
|
||||||
|
window.fetchMonthlyBillingReport();
|
||||||
|
} else {
|
||||||
|
alert(`Error al emitir factura: ${data.error || 'Fallo de emisión'}`);
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = '⚡ Facturar';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert('Error de conexión con el servidor fiscal.');
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = '⚡ Facturar';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachBillingItemCheckboxListeners() {
|
function attachBillingItemCheckboxListeners() {
|
||||||
|
|||||||
@ -660,6 +660,22 @@ const server = http.createServer(async (req, res) => {
|
|||||||
return sendJson(200, resultado);
|
return sendJson(200, resultado);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 13.5.4. Emitir Factura Electrónica oficial DIAN para un cierre
|
||||||
|
if (pathname === '/api/admin/billing/emitir-factura' && req.method === 'POST') {
|
||||||
|
const body = await getJsonBody();
|
||||||
|
const idCierre = body.idCierre || body.id;
|
||||||
|
if (!idCierre) {
|
||||||
|
return sendJson(400, { success: false, error: 'idCierre es requerido' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resultado = await billingConsolidationService.emitirFacturaDian(idCierre);
|
||||||
|
return sendJson(200, resultado);
|
||||||
|
} catch (err: any) {
|
||||||
|
return sendJson(500, { success: false, error: err.message || 'Error al emitir factura DIAN' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 14. Servidor de Archivos Estáticos para la Plataforma Web & APK
|
// 14. Servidor de Archivos Estáticos para la Plataforma Web & APK
|
||||||
const serveStaticFile = (filePath: string, contentType: string): boolean => {
|
const serveStaticFile = (filePath: string, contentType: string): boolean => {
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
|
|||||||
@ -171,8 +171,9 @@ export class AuthService {
|
|||||||
user = (await Promise.race([dbQuery, timeoutPromise])) as any;
|
user = (await Promise.race([dbQuery, timeoutPromise])) as any;
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
const defaultSuperId = cleanPhone === SUPER_ADMIN_PHONE ? 'usr-superadmin-platform' : `usr-superadmin-${cleanPhone}`;
|
||||||
const createPromise = User.create({
|
const createPromise = User.create({
|
||||||
appwriteId: isSuper ? 'usr-superadmin-platform' : `pt-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`,
|
appwriteId: isSuper ? defaultSuperId : `pt-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`,
|
||||||
nombre: isSuper ? (params.nombre || 'Superadministrador Principal') : (params.nombre || `Usuario ${cleanPhone.slice(-4)}`),
|
nombre: isSuper ? (params.nombre || 'Superadministrador Principal') : (params.nombre || `Usuario ${cleanPhone.slice(-4)}`),
|
||||||
telefono: cleanPhone,
|
telefono: cleanPhone,
|
||||||
email: userEmail || (isSuper ? SUPER_ADMIN_EMAIL : undefined),
|
email: userEmail || (isSuper ? SUPER_ADMIN_EMAIL : undefined),
|
||||||
|
|||||||
@ -425,6 +425,116 @@ export class BillingConsolidationService {
|
|||||||
ids: uniqueIds,
|
ids: uniqueIds,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emite la Factura Electrónica oficial ante la DIAN comunicándose con el Hub Central de Facturación.
|
||||||
|
*/
|
||||||
|
public async emitirFacturaDian(idCierre: string): Promise<any> {
|
||||||
|
const HUB_URL = process.env.FACTURACION_HUB_URL || 'https://facturacion.almeira.com.co';
|
||||||
|
const TENANT_ID = process.env.PACIFICTRANS_TENANT_ID || 'd0000002-0000-0000-0000-000000000002';
|
||||||
|
const API_KEY = process.env.PACIFICTRANS_FISCAL_API_KEY || 'pt_live_key_33c9a184ef10';
|
||||||
|
|
||||||
|
let cierre: any = null;
|
||||||
|
if (isDatabaseConnected()) {
|
||||||
|
try {
|
||||||
|
cierre = await CierreFacturacionMensual.findOne({ id: idCierre });
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
if (!cierre) {
|
||||||
|
cierre = localBillingStore.findById(idCierre);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cierre) {
|
||||||
|
throw new Error(`Cierre no encontrado con ID ${idCierre}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = Number(cierre.total_comisiones_acumuladas || 0);
|
||||||
|
const subtotal = Math.round(total / 1.19);
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
tenantId: TENANT_ID,
|
||||||
|
prefix: 'PACT',
|
||||||
|
customer: {
|
||||||
|
identificationType: '13',
|
||||||
|
identificationNumber: String(cierre.nit_o_cedula || '222222222222').replace(/\D/g, '').slice(-10) || '2222222222',
|
||||||
|
legalOrFullName: cierre.razon_social || 'Conductor Pacific Trans',
|
||||||
|
email: cierre.correo_electronico || 'facturacion@pacifictrans.com',
|
||||||
|
phone: '3167455877',
|
||||||
|
address: 'Terminal de Transportes Cali / Buenaventura',
|
||||||
|
cityName: 'Buenaventura',
|
||||||
|
departmentCode: '76',
|
||||||
|
cityCode: '76109',
|
||||||
|
taxRegime: '49',
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
sku: 'SERV-COM-TRANS',
|
||||||
|
description: `Comisión de intermediación de software y despacho de viajes - Período ${cierre.mes_calendario || cierre.mes}/${cierre.anio_calendario || cierre.anio} (${cierre.total_viajes_realizados} viajes)`,
|
||||||
|
quantity: 1,
|
||||||
|
unitPrice: subtotal,
|
||||||
|
taxPercentage: 19,
|
||||||
|
taxTypeCode: '01',
|
||||||
|
discountAmount: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
paymentMethod: {
|
||||||
|
paymentMeansCode: '48',
|
||||||
|
paymentDueDate: new Date().toISOString().split('T')[0],
|
||||||
|
},
|
||||||
|
notes: `Liquidación mensual de comisiones ID: ${cierre.id}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await fetch(`${HUB_URL}/api/v1/invoices`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': API_KEY,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (!res.ok || !data.success) {
|
||||||
|
throw new Error(data.message || 'Error al emitir factura en el Hub Fiscal');
|
||||||
|
}
|
||||||
|
|
||||||
|
const factura = data.data;
|
||||||
|
|
||||||
|
localBillingStore.actualizarFacturaDian(idCierre, {
|
||||||
|
numero_factura: factura.fullNumber,
|
||||||
|
cufe: factura.cufe,
|
||||||
|
pdf_url: `${HUB_URL}/api/v1/invoices/${factura.id}/pdf`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDatabaseConnected()) {
|
||||||
|
try {
|
||||||
|
await CierreFacturacionMensual.updateOne(
|
||||||
|
{ id: idCierre },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
estado_facturacion: 'enviado_api',
|
||||||
|
numero_factura: factura.fullNumber,
|
||||||
|
cufe: factura.cufe,
|
||||||
|
pdf_url: `${HUB_URL}/api/v1/invoices/${factura.id}/pdf`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
cierreId: idCierre,
|
||||||
|
factura: {
|
||||||
|
id: factura.id,
|
||||||
|
fullNumber: factura.fullNumber,
|
||||||
|
cufe: factura.cufe,
|
||||||
|
pdfUrl: `${HUB_URL}/api/v1/invoices/${factura.id}/pdf`,
|
||||||
|
xmlUrl: `${HUB_URL}/api/v1/invoices/${factura.id}/xml`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const billingConsolidationService = BillingConsolidationService.getInstance();
|
export const billingConsolidationService = BillingConsolidationService.getInstance();
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,9 @@ export interface LocalCierreRecord {
|
|||||||
total_viajes_realizados: number;
|
total_viajes_realizados: number;
|
||||||
estado_facturacion: EstadoFacturacion;
|
estado_facturacion: EstadoFacturacion;
|
||||||
fecha_cierre: string; // ISO string
|
fecha_cierre: string; // ISO string
|
||||||
|
numero_factura?: string;
|
||||||
|
cufe?: string;
|
||||||
|
pdf_url?: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
}
|
}
|
||||||
@ -158,6 +161,29 @@ export class LocalBillingStore {
|
|||||||
return { updatedCount: updated.length, records: updated };
|
return { updatedCount: updated.length, records: updated };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public actualizarFacturaDian(
|
||||||
|
id: string,
|
||||||
|
info: { numero_factura: string; cufe: string; pdf_url: string }
|
||||||
|
): LocalCierreRecord | null {
|
||||||
|
this.ensureInitialized();
|
||||||
|
for (const [key, r] of this.recordsMap.entries()) {
|
||||||
|
if (r.id === id) {
|
||||||
|
const mod: LocalCierreRecord = {
|
||||||
|
...r,
|
||||||
|
estado_facturacion: 'enviado_api' as any,
|
||||||
|
numero_factura: info.numero_factura,
|
||||||
|
cufe: info.cufe,
|
||||||
|
pdf_url: info.pdf_url,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
this.recordsMap.set(key, mod);
|
||||||
|
this.persist();
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public getAll(): LocalCierreRecord[] {
|
public getAll(): LocalCierreRecord[] {
|
||||||
this.ensureInitialized();
|
this.ensureInitialized();
|
||||||
return Array.from(this.recordsMap.values());
|
return Array.from(this.recordsMap.values());
|
||||||
|
|||||||
@ -4,15 +4,22 @@ import { UserRole } from '../models/User';
|
|||||||
|
|
||||||
export const SUPER_ADMIN_PHONE = '573167455877';
|
export const SUPER_ADMIN_PHONE = '573167455877';
|
||||||
export const SUPER_ADMIN_LOCAL_PHONE = '3167455877';
|
export const SUPER_ADMIN_LOCAL_PHONE = '3167455877';
|
||||||
|
export const SUPER_ADMIN_ALT_PHONE = '573106390296';
|
||||||
|
export const SUPER_ADMIN_ALT_LOCAL_PHONE = '3106390296';
|
||||||
export const SUPER_ADMIN_EMAIL = 'admin@pacifictrans.almeira.com.co';
|
export const SUPER_ADMIN_EMAIL = 'admin@pacifictrans.almeira.com.co';
|
||||||
|
|
||||||
export function isPlatformSuperAdmin(identifier?: string): boolean {
|
export function isPlatformSuperAdmin(identifier?: string): boolean {
|
||||||
if (!identifier) return false;
|
if (!identifier) return false;
|
||||||
const clean = identifier.replace(/\D/g, '');
|
const clean = identifier.replace(/\D/g, '');
|
||||||
|
const lower = identifier.toLowerCase().trim();
|
||||||
return (
|
return (
|
||||||
clean === SUPER_ADMIN_PHONE ||
|
clean === SUPER_ADMIN_PHONE ||
|
||||||
clean === SUPER_ADMIN_LOCAL_PHONE ||
|
clean === SUPER_ADMIN_LOCAL_PHONE ||
|
||||||
identifier.toLowerCase().trim() === SUPER_ADMIN_EMAIL
|
clean === SUPER_ADMIN_ALT_PHONE ||
|
||||||
|
clean === SUPER_ADMIN_ALT_LOCAL_PHONE ||
|
||||||
|
lower === SUPER_ADMIN_EMAIL ||
|
||||||
|
lower === 'carlos@almeira.com.co' ||
|
||||||
|
lower === 'innovacion4desarrollo@gmail.com'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +169,8 @@ class LocalUserStore {
|
|||||||
const isSuper = isPlatformSuperAdmin(cleanPhone) || (user.email && isPlatformSuperAdmin(user.email));
|
const isSuper = isPlatformSuperAdmin(cleanPhone) || (user.email && isPlatformSuperAdmin(user.email));
|
||||||
|
|
||||||
const existing = this.findByPhone(cleanPhone) || (user.id ? this.findById(user.id) : null);
|
const existing = this.findByPhone(cleanPhone) || (user.id ? this.findById(user.id) : null);
|
||||||
const userId = existing?.id || user.id || (isSuper ? 'usr-superadmin-platform' : `pt-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`);
|
const defaultSuperId = (cleanPhone === SUPER_ADMIN_PHONE || cleanPhone === SUPER_ADMIN_LOCAL_PHONE) ? 'usr-superadmin-platform' : `usr-superadmin-${cleanPhone}`;
|
||||||
|
const userId = existing?.id || user.id || (isSuper ? defaultSuperId : `pt-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`);
|
||||||
|
|
||||||
const nowIso = new Date().toISOString();
|
const nowIso = new Date().toISOString();
|
||||||
const record: LocalUserRecord = {
|
const record: LocalUserRecord = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user