cambios en el server
This commit is contained in:
parent
0dbbd11bcd
commit
6d43a61d76
BIN
PLANTILLAAUT.xlsx
Normal file
BIN
PLANTILLAAUT.xlsx
Normal file
Binary file not shown.
@ -1358,6 +1358,63 @@ app.post(
|
||||
}
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/api/cargar-autorizados-masivos',
|
||||
verificarToken,
|
||||
esAdministrador,
|
||||
upload.single('archivo'),
|
||||
async (req, res) => {
|
||||
try {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ error: 'No se recibio archivo Excel' });
|
||||
}
|
||||
|
||||
const jobId = createJobId();
|
||||
const job = {
|
||||
id: jobId,
|
||||
type: 'autorizados-masivos',
|
||||
status: 'queued',
|
||||
createdAt: new Date().toISOString(),
|
||||
ownerId: req.usuario.id_usuario,
|
||||
};
|
||||
|
||||
jobs.set(jobId, job);
|
||||
|
||||
const jobTmpDir = path.join(os.tmpdir(), 'saludut_jobs', jobId);
|
||||
await fsPromises.mkdir(jobTmpDir, { recursive: true });
|
||||
const inputPath = path.join(jobTmpDir, `autorizados_${jobId}.xlsx`);
|
||||
await fsPromises.writeFile(inputPath, req.file.buffer);
|
||||
|
||||
enqueueJob(job, async () => {
|
||||
try {
|
||||
return await procesarExcelAutorizacionesMasivas(inputPath, req.usuario, {
|
||||
estadoAutorizacion: 'autorizado',
|
||||
allowMissingAmbito: true,
|
||||
defaultAmbito: 'extramural',
|
||||
allowNumeroOrdenForAnyAmbito: true,
|
||||
fechaAutorizacionKeys: [
|
||||
'FECHADEREGISTRO',
|
||||
'FECHAREGISTRO',
|
||||
'FECHADEAUTORIZACION',
|
||||
'FECHA',
|
||||
],
|
||||
});
|
||||
} finally {
|
||||
await safeUnlink(inputPath);
|
||||
await safeRemoveDir(jobTmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
return res.status(202).json(sanitizeJob(job));
|
||||
} catch (error) {
|
||||
console.error('Error creando job de autorizados masivos:', error);
|
||||
return res.status(500).json({
|
||||
error: 'Error creando el job para procesar autorizados masivos',
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/api/autorizaciones/autorrellenar',
|
||||
verificarToken,
|
||||
@ -2444,7 +2501,7 @@ async function procesarExcelReps(inputFilePath) {
|
||||
};
|
||||
}
|
||||
|
||||
async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario, options = {}) {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
await workbook.xlsx.readFile(inputFilePath);
|
||||
const sheet = workbook.worksheets[0];
|
||||
@ -2453,6 +2510,14 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
throw new Error('No se encontro una hoja en el Excel de autorizaciones');
|
||||
}
|
||||
|
||||
const {
|
||||
estadoAutorizacion = 'pendiente',
|
||||
allowMissingAmbito = false,
|
||||
defaultAmbito = '',
|
||||
allowNumeroOrdenForAnyAmbito = false,
|
||||
fechaAutorizacionKeys = [],
|
||||
} = options;
|
||||
|
||||
const headerRow = sheet.getRow(1);
|
||||
const headers = {};
|
||||
headerRow.eachCell((cell, colNumber) => {
|
||||
@ -2544,6 +2609,7 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
'NUMERODEDOCUMENTOPPL',
|
||||
'NUMERODOCUMENTOPPL',
|
||||
'DOCUMENTOPPL',
|
||||
'NUMERODEDOCUMENTO',
|
||||
'NUMERODOCUMENTO',
|
||||
]);
|
||||
const cupsRaw = getValueMulti(row, [
|
||||
@ -2653,15 +2719,19 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
ambitoAtencion = 'extramural';
|
||||
}
|
||||
if (!ambitoAtencion) {
|
||||
resumen.omitidas += 1;
|
||||
resumen.sin_ambito += 1;
|
||||
if (resumen.errores.length < 50) {
|
||||
resumen.errores.push({
|
||||
fila: i,
|
||||
error: 'Ambito intramural/extramural invalido',
|
||||
});
|
||||
if (allowMissingAmbito) {
|
||||
ambitoAtencion = defaultAmbito ? defaultAmbito : null;
|
||||
} else {
|
||||
resumen.omitidas += 1;
|
||||
resumen.sin_ambito += 1;
|
||||
if (resumen.errores.length < 50) {
|
||||
resumen.errores.push({
|
||||
fila: i,
|
||||
error: 'Ambito intramural/extramural invalido',
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const numeroOrdenRaw = getValueMulti(row, [
|
||||
@ -2670,10 +2740,15 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
'NUMEROORDEN',
|
||||
'NROORDEN',
|
||||
'NUMERODELAORDEN',
|
||||
'CODIGPODEREGISTRO',
|
||||
'CODIGODEREGISTRO',
|
||||
'CODIGOREGISTRO',
|
||||
]);
|
||||
const numeroOrden = String(numeroOrdenRaw || '').trim();
|
||||
const numeroOrdenFinal =
|
||||
ambitoAtencion === 'intramural' && numeroOrden ? numeroOrden : null;
|
||||
(ambitoAtencion === 'intramural' || allowNumeroOrdenForAnyAmbito) && numeroOrden
|
||||
? numeroOrden
|
||||
: null;
|
||||
|
||||
const estadoEntregaRaw = getValueMulti(row, [
|
||||
'ESTADODEENTREGA',
|
||||
@ -2684,6 +2759,13 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
const estadoEntrega =
|
||||
parseEstadoEntrega(estadoEntregaRaw) || 'pendiente_entrega';
|
||||
|
||||
const fechaAutorizacionRaw = fechaAutorizacionKeys.length
|
||||
? getValueMulti(row, fechaAutorizacionKeys)
|
||||
: '';
|
||||
const fechaAutorizacion = fechaAutorizacionRaw
|
||||
? String(fechaAutorizacionRaw).trim()
|
||||
: null;
|
||||
|
||||
const cupCodigo = extractCupCodigo(cupsRaw || procedimiento);
|
||||
if (!cupCodigo) {
|
||||
resumen.omitidas += 1;
|
||||
@ -2720,6 +2802,8 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
'NOMBREIPSREMITIDO',
|
||||
'NOMBREDEIPSREMITIDO',
|
||||
'IPSREMITIDO',
|
||||
'IPSSUJERIDA',
|
||||
'IPSSUGERIDA',
|
||||
]);
|
||||
const departamentoExcel =
|
||||
getValue(row, 'DEPARTAMENTO') ||
|
||||
@ -2962,7 +3046,7 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
`
|
||||
INSERT INTO autorizacion
|
||||
(interno, id_ips, numero_documento_autorizante, id_usuario_solicitante, fecha_autorizacion, observacion, cup_codigo, cie10_codigo, cie10_descripcion, tipo_autorizacion, tipo_servicio, ambito_atencion, numero_orden, estado_entrega, estado_autorizacion)
|
||||
VALUES ($1, $2, $3, $4, COALESCE($5::timestamp AT TIME ZONE '${BOGOTA_TIMEZONE}', now()), $6, $7, $8, $9, $10, $11, $12, $13, $14, 'pendiente')
|
||||
VALUES ($1, $2, $3, $4, COALESCE($5::timestamp AT TIME ZONE '${BOGOTA_TIMEZONE}', now()), $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
||||
RETURNING numero_autorizacion, fecha_autorizacion, version;
|
||||
`,
|
||||
[
|
||||
@ -2970,7 +3054,7 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
ipsInfo.id_ips,
|
||||
autorizanteDefault,
|
||||
solicitanteId,
|
||||
null,
|
||||
fechaAutorizacion,
|
||||
observacionFinal,
|
||||
cupCodigo,
|
||||
cie10Codigo,
|
||||
@ -2980,6 +3064,7 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
ambitoAtencion,
|
||||
numeroOrdenFinal,
|
||||
estadoEntrega,
|
||||
estadoAutorizacion,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
BIN
saludut-inpec/public/assets/PLANTILLAAUT.xlsx
Normal file
BIN
saludut-inpec/public/assets/PLANTILLAAUT.xlsx
Normal file
Binary file not shown.
@ -9,6 +9,7 @@ import { UsuariosComponent } from './components/usuarios/usuarios';
|
||||
import { CargarCupsComponent } from './components/cargar-cups/cargar-cups';
|
||||
import { EstadisticasAutorizacionesComponent } from './components/estadisticas-autorizaciones/estadisticas-autorizaciones';
|
||||
import { CargarAutorizacionesMasivasComponent } from './components/cargar-autorizaciones-masivas/cargar-autorizaciones-masivas';
|
||||
import { CargarAutorizadosMasivosComponent } from './components/cargar-autorizados-masivos/cargar-autorizados-masivos';
|
||||
import { CargarIpsRepsComponent } from './components/cargar-ips-reps/cargar-ips-reps';
|
||||
import { CargarPacientesComponent } from './components/cargar-pacientes/cargar-pacientes';
|
||||
|
||||
@ -67,6 +68,12 @@ export const routes: Routes = [
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
|
||||
{
|
||||
path: 'cargar-autorizados-masivos',
|
||||
component: CargarAutorizadosMasivosComponent,
|
||||
canActivate: [AuthGuard, AdminGuard],
|
||||
},
|
||||
|
||||
{
|
||||
path: 'cargar-ips-reps',
|
||||
component: CargarIpsRepsComponent,
|
||||
|
||||
@ -0,0 +1,117 @@
|
||||
/* ============================
|
||||
Carga masiva autorizados
|
||||
============================ */
|
||||
.masivas-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.masivas-card {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.masivas-card h2 {
|
||||
margin: 0 0 6px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 0 0 16px;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.form-row label {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.form-row input[type="file"] {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.form-row.acciones {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.template-row {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.template-note {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.resumen-card h2 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
background: var(--color-cup-bg);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-muted);
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.summary-note {
|
||||
margin-top: 12px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: var(--color-primary-soft);
|
||||
border: 1px solid var(--color-border);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.error-list {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.error-list h3 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.error-table {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 8px;
|
||||
max-height: 260px;
|
||||
overflow: auto;
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
<div class="page-shell">
|
||||
<div class="content-container masivas-container">
|
||||
<app-header
|
||||
title="Carga masiva de autorizados"
|
||||
subtitle="Sube la plantilla Excel y registra autorizaciones autorizadas"
|
||||
badgeText="SALUD UT"
|
||||
[showUserInfo]="isLoggedIn()"
|
||||
[userName]="getCurrentUser()?.nombre_completo"
|
||||
[userRole]="getCurrentUser()?.nombre_rol"
|
||||
[showLogout]="isLoggedIn()"
|
||||
(logout)="logout()"
|
||||
[showBack]="true"
|
||||
backLabel="Volver"
|
||||
(back)="volverDashboard()"
|
||||
></app-header>
|
||||
|
||||
<div class="card masivas-card">
|
||||
<h2>Subir plantilla</h2>
|
||||
<p class="subtitle">
|
||||
Usa la plantilla oficial de autorizados. La fecha de registro se guarda como fecha de autorizacion.
|
||||
</p>
|
||||
|
||||
<div class="form-row template-row">
|
||||
<a class="btn btn-secondary" href="assets/PLANTILLAAUT.xlsx" download>
|
||||
Descargar plantilla de autorizados
|
||||
</a>
|
||||
<span class="template-note">Plantilla oficial para carga masiva.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Archivo Excel:</label>
|
||||
<input
|
||||
#archivoInput
|
||||
type="file"
|
||||
accept=".xlsx,.xls"
|
||||
(change)="onArchivoSelected($event)"
|
||||
/>
|
||||
<span class="file-name" *ngIf="archivoFile">{{ archivoFile.name }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row acciones">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
(click)="procesarMasivo(archivoInput)"
|
||||
[disabled]="isLoading || !archivoFile"
|
||||
>
|
||||
{{ isLoading ? 'Procesando...' : 'Procesar autorizados' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="status ok" *ngIf="statusMessage">{{ statusMessage }}</div>
|
||||
<div class="status error" *ngIf="errorMessage">{{ errorMessage }}</div>
|
||||
</div>
|
||||
|
||||
<div class="card resumen-card" *ngIf="resumen">
|
||||
<h2>Resumen de la carga</h2>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Total filas</span>
|
||||
<span class="summary-value">{{ resumen.total || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Creadas</span>
|
||||
<span class="summary-value">{{ resumen.creadas || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Omitidas</span>
|
||||
<span class="summary-value">{{ resumen.omitidas || resumen.omitidos || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Duplicadas</span>
|
||||
<span class="summary-value">{{ resumen.duplicados || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Sin paciente</span>
|
||||
<span class="summary-value">{{ resumen.sin_paciente || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Sin CUPS</span>
|
||||
<span class="summary-value">{{ resumen.sin_cups || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Sin IPS</span>
|
||||
<span class="summary-value">{{ resumen.sin_ips || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Sin diagnostico</span>
|
||||
<span class="summary-value">{{ resumen.sin_diagnostico || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">Sin ambito</span>
|
||||
<span class="summary-value">{{ resumen.sin_ambito || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">CUPS no cubiertos</span>
|
||||
<span class="summary-value">{{ resumen.cups_no_cubiertos || 0 }}</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">IPS sin convenio</span>
|
||||
<span class="summary-value">{{ resumen.ips_sin_convenio || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="summary-note"
|
||||
*ngIf="(resumen.cups_no_cubiertos || 0) > 0 || (resumen.ips_sin_convenio || 0) > 0"
|
||||
>
|
||||
Se detectaron CUPS no cubiertos o IPS sin convenio. Revisa estas autorizaciones.
|
||||
</div>
|
||||
|
||||
<div class="error-list" *ngIf="errores.length">
|
||||
<h3>Errores (max 50)</h3>
|
||||
<div class="error-table">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fila</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let e of errores">
|
||||
<td>{{ e.fila || '-' }}</td>
|
||||
<td>{{ e.error || 'Error en fila' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,124 @@
|
||||
import { ChangeDetectorRef, Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Router } from '@angular/router';
|
||||
import { AppHeaderComponent } from '../shared/app-header/app-header';
|
||||
import { AuthService } from '../../services/auth';
|
||||
import { PacienteService } from '../../services/paciente';
|
||||
import { JobsService } from '../../services/jobs';
|
||||
import { JobResult, JobRowError } from '../../services/job-types';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cargar-autorizados-masivos',
|
||||
standalone: true,
|
||||
imports: [CommonModule, AppHeaderComponent],
|
||||
templateUrl: './cargar-autorizados-masivos.html',
|
||||
styleUrls: ['./cargar-autorizados-masivos.css']
|
||||
})
|
||||
export class CargarAutorizadosMasivosComponent {
|
||||
archivoFile: File | null = null;
|
||||
isLoading = false;
|
||||
statusMessage: string | null = null;
|
||||
errorMessage: string | null = null;
|
||||
resumen: JobResult | null = null;
|
||||
errores: JobRowError[] = [];
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private pacienteService: PacienteService,
|
||||
private jobsService: JobsService,
|
||||
private router: Router,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
volverDashboard(): void {
|
||||
this.router.navigate(['/dashboard']);
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.authService.logout();
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return this.authService.isLoggedIn();
|
||||
}
|
||||
|
||||
getCurrentUser(): any {
|
||||
return this.authService.getCurrentUser();
|
||||
}
|
||||
|
||||
onArchivoSelected(event: Event): void {
|
||||
const input = event.target as HTMLInputElement;
|
||||
this.archivoFile = input.files?.[0] || null;
|
||||
this.limpiarMensajes();
|
||||
this.resumen = null;
|
||||
this.errores = [];
|
||||
}
|
||||
|
||||
procesarMasivo(input?: HTMLInputElement): void {
|
||||
this.limpiarMensajes();
|
||||
this.resumen = null;
|
||||
this.errores = [];
|
||||
|
||||
if (!this.archivoFile) {
|
||||
this.errorMessage = 'Debes seleccionar el archivo Excel de autorizados.';
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
this.statusMessage = 'Subiendo archivo...';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('archivo', this.archivoFile);
|
||||
|
||||
this.pacienteService.cargarAutorizadosMasivos(formData).subscribe({
|
||||
next: (job) => {
|
||||
this.statusMessage = 'Archivo en cola. Procesando...';
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
this.jobsService.pollJob(job.id).subscribe({
|
||||
next: (estado) => {
|
||||
if (estado.status === 'completed') {
|
||||
this.resumen = estado.result || null;
|
||||
this.errores = Array.isArray(estado.result?.errores)
|
||||
? estado.result?.errores || []
|
||||
: [];
|
||||
this.statusMessage =
|
||||
estado.result?.mensaje || 'Carga masiva finalizada.';
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
if (estado.status === 'failed') {
|
||||
this.errorMessage =
|
||||
estado.error?.message ||
|
||||
'Error procesando autorizados masivos.';
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
this.cdr.detectChanges();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(error);
|
||||
this.errorMessage =
|
||||
'Error consultando el estado de la carga masiva.';
|
||||
this.isLoading = false;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: (err) => {
|
||||
console.error(err);
|
||||
this.errorMessage =
|
||||
err?.error?.error || 'Error subiendo el Excel de autorizados.';
|
||||
this.isLoading = false;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private limpiarMensajes(): void {
|
||||
this.statusMessage = null;
|
||||
this.errorMessage = null;
|
||||
}
|
||||
}
|
||||
@ -132,6 +132,41 @@
|
||||
<p>Subir plantilla Excel para crear autorizaciones pendientes</p>
|
||||
</div>
|
||||
|
||||
<!-- Carga masiva de autorizados (solo admin) -->
|
||||
<div
|
||||
class="action-card"
|
||||
*ngIf="puedeCargarAutorizadosMasivos()"
|
||||
(click)="irACargarAutorizadosMasivos()"
|
||||
>
|
||||
<span class="action-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" role="img" aria-label="">
|
||||
<path
|
||||
d="M4 5h16v10H4z"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
></path>
|
||||
<path
|
||||
d="M8 19h8"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
></path>
|
||||
<path
|
||||
d="M9 9h6M9 12h6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
<h4>Carga masiva de autorizados</h4>
|
||||
<p>Subir plantilla Excel de autorizados</p>
|
||||
<div class="admin-badge">Solo admin</div>
|
||||
</div>
|
||||
|
||||
<!-- Cargar IPS y REPS (solo administradores) -->
|
||||
<div
|
||||
class="action-card"
|
||||
@ -279,6 +314,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="permission-item"
|
||||
[class.has-permission]="puedeCargarAutorizadosMasivos()"
|
||||
[class.no-permission]="!puedeCargarAutorizadosMasivos()"
|
||||
>
|
||||
<span
|
||||
class="permission-icon"
|
||||
*ngIf="puedeCargarAutorizadosMasivos(); else noPermAutorizados"
|
||||
>
|
||||
✓
|
||||
</span>
|
||||
<ng-template #noPermAutorizados>
|
||||
<span class="permission-icon">×</span>
|
||||
</ng-template>
|
||||
<div class="permission-body">
|
||||
<span class="permission-title">Cargar autorizados masivos</span>
|
||||
<span class="permission-meta">Subir plantilla de autorizados</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="permission-item"
|
||||
[class.has-permission]="puedeVerAutorizacionesPorFecha()"
|
||||
|
||||
@ -104,6 +104,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
this.router.navigate(['/cargar-autorizaciones-masivas']);
|
||||
}
|
||||
|
||||
irACargarAutorizadosMasivos(): void {
|
||||
this.router.navigate(['/cargar-autorizados-masivos']);
|
||||
}
|
||||
|
||||
irACargarIpsReps(): void {
|
||||
this.router.navigate(['/cargar-ips-reps']);
|
||||
}
|
||||
@ -179,6 +183,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
return this.authService.puedeGenerarAutorizaciones();
|
||||
}
|
||||
|
||||
puedeCargarAutorizadosMasivos(): boolean {
|
||||
return this.authService.isAdministrador();
|
||||
}
|
||||
|
||||
puedeVerAutorizacionesPorFecha(): boolean {
|
||||
return this.authService.isLoggedIn();
|
||||
}
|
||||
|
||||
@ -386,6 +386,19 @@ export class PacienteService {
|
||||
);
|
||||
}
|
||||
|
||||
cargarAutorizadosMasivos(formData: FormData): Observable<JobResponse> {
|
||||
const token = this.authService.getToken();
|
||||
const headers = new HttpHeaders({
|
||||
'Authorization': `Bearer ${token}`
|
||||
});
|
||||
|
||||
return this.http.post<JobResponse>(
|
||||
`${this.API_URL}/cargar-autorizados-masivos`,
|
||||
formData,
|
||||
{ headers }
|
||||
);
|
||||
}
|
||||
|
||||
crearAutorizante(payload: CrearAutorizantePayload): Observable<any> {
|
||||
return this.http.post(
|
||||
`${this.API_URL}/autorizantes`,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user