@softdin/portal-admin 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -2
- package/dist-lib/chunks/AppLayout-COCPfLWo.js +303 -0
- package/dist-lib/chunks/AuditoriaView-Bcf_kOqI.js +643 -0
- package/dist-lib/chunks/CarnetView-BsdUtYeu.js +450 -0
- package/dist-lib/chunks/CarteleraView-CRnVjt-S.js +996 -0
- package/dist-lib/chunks/CertificadosView-DvHDflcN.js +549 -0
- package/dist-lib/chunks/ChatBandejaView-HqhdSw7G.js +274 -0
- package/dist-lib/chunks/ChatConfiguracionView-BdH5gDdR.js +716 -0
- package/dist-lib/chunks/ChatConocimientoView-nKTAKxFa.js +263 -0
- package/dist-lib/chunks/ChatConversacionView-Do74V09l.js +477 -0
- package/dist-lib/chunks/ChatInformeView-BIiAH9L_.js +280 -0
- package/dist-lib/chunks/ChatRespuestasView-QFXbyg8U.js +183 -0
- package/dist-lib/chunks/EmpleadosView-BtqrO5-8.js +311 -0
- package/dist-lib/chunks/HomologacionView-UCZk4u6R.js +949 -0
- package/dist-lib/chunks/IngresoSsoView-BKkcnrYO.js +98 -0
- package/dist-lib/chunks/SolicitudesView-CYPD2A1s.js +900 -0
- package/dist-lib/chunks/TiposSolicitudView-CrWTVizl.js +168 -0
- package/dist-lib/chunks/ToggleSwitch-BYrIyheq.js +55 -0
- package/dist-lib/chunks/_plugin-vue_export-helper-BOaGB7Aw.js +8 -0
- package/dist-lib/chunks/api-M7D1c3IT.js +97 -0
- package/dist-lib/chunks/apiError-BHGbwz97.js +15 -0
- package/dist-lib/chunks/auth.store-BrGKZg-7.js +220 -0
- package/dist-lib/chunks/chat.service-C7ZQf4w3.js +241 -0
- package/dist-lib/chunks/cliente-interno.store-De39VsEE.js +203 -0
- package/dist-lib/chunks/homologacion-CoeHD7cB.js +131 -0
- package/dist-lib/chunks/portal-empleado-6KQrnsQJ.js +120 -0
- package/dist-lib/chunks/tipos-D93bLfFC.js +22 -0
- package/dist-lib/portal-admin.js +196 -0
- package/dist-lib/style.css +4813 -0
- package/dist-lib/types/App.vue.d.ts +3 -0
- package/dist-lib/types/components/AppLayout.vue.d.ts +3 -0
- package/dist-lib/types/components/CarnetClientesInternos.vue.d.ts +11 -0
- package/dist-lib/types/components/InvitacionPortalModal.vue.d.ts +20 -0
- package/dist-lib/types/components/MenuUsuario.vue.d.ts +3 -0
- package/dist-lib/types/components/VistoBuenoPortalModal.vue.d.ts +23 -0
- package/dist-lib/types/components/auditoria/AuditoriaFila.vue.d.ts +16 -0
- package/dist-lib/types/components/auditoria/AuditoriaFiltros.vue.d.ts +30 -0
- package/dist-lib/types/components/auditoria/AuditoriaPaginador.vue.d.ts +14 -0
- package/dist-lib/types/components/cartelera/PaginaCarteleraImagen.vue.d.ts +14 -0
- package/dist-lib/types/components/cartelera/PublicacionFormModal.vue.d.ts +27 -0
- package/dist-lib/types/components/cartelera/VistaCelularCartelera.vue.d.ts +34 -0
- package/dist-lib/types/components/certificados/AtenderCertificadoModal.vue.d.ts +22 -0
- package/dist-lib/types/components/certificados/RechazarCertificadoModal.vue.d.ts +18 -0
- package/dist-lib/types/components/certificados/ResumenSolicitudCertificado.vue.d.ts +8 -0
- package/dist-lib/types/components/chat/ChatClientesInternos.vue.d.ts +21 -0
- package/dist-lib/types/components/chat/ChatHorarioCampos.vue.d.ts +21 -0
- package/dist-lib/types/components/forms/ExportExcelButton.vue.d.ts +30 -0
- package/dist-lib/types/components/forms/ToggleSwitch.vue.d.ts +17 -0
- package/dist-lib/types/components/homologacion/HomologacionFila.vue.d.ts +30 -0
- package/dist-lib/types/components/homologacion/TipoPermisoFormModal.vue.d.ts +26 -0
- package/dist-lib/types/components/homologacion/TipoSolicitudFormModal.vue.d.ts +27 -0
- package/dist-lib/types/lib/auditoria.d.ts +25 -0
- package/dist-lib/types/lib/cartelera-paginas.d.ts +26 -0
- package/dist-lib/types/lib/cartelera-vigencia.d.ts +3 -0
- package/dist-lib/types/lib/export-excel-csv.d.ts +4 -0
- package/dist-lib/types/lib/export-excel.d.ts +9 -0
- package/dist-lib/types/lib/exportar-listado.d.ts +68 -0
- package/dist-lib/types/lib/homologacion.d.ts +41 -0
- package/dist-lib/types/lib/portal-empleado.d.ts +32 -0
- package/dist-lib/types/modulo.d.ts +31 -0
- package/dist-lib/types/portal-admin/config.d.ts +17 -0
- package/dist-lib/types/portal-admin/rutas.d.ts +17 -0
- package/dist-lib/types/portal-admin/tipos.d.ts +68 -0
- package/dist-lib/types/router/index.d.ts +7 -0
- package/dist-lib/types/services/api.d.ts +29 -0
- package/dist-lib/types/services/auditoria.service.d.ts +63 -0
- package/dist-lib/types/services/auth.service.d.ts +61 -0
- package/dist-lib/types/services/carnet.service.d.ts +56 -0
- package/dist-lib/types/services/cartelera.service.d.ts +69 -0
- package/dist-lib/types/services/chat.service.d.ts +279 -0
- package/dist-lib/types/services/configuracion-cliente-interno.service.d.ts +23 -0
- package/dist-lib/types/services/homologacion.service.d.ts +105 -0
- package/dist-lib/types/services/portal-empleado.service.d.ts +112 -0
- package/dist-lib/types/services/solicitudes-certificado.service.d.ts +59 -0
- package/dist-lib/types/stores/auth.store.d.ts +125 -0
- package/dist-lib/types/stores/cliente-interno.store.d.ts +65 -0
- package/dist-lib/types/utils/apiError.d.ts +4 -0
- package/dist-lib/types/views/AuditoriaView.vue.d.ts +3 -0
- package/dist-lib/types/views/CarnetView.vue.d.ts +3 -0
- package/dist-lib/types/views/CarteleraView.vue.d.ts +3 -0
- package/dist-lib/types/views/CertificadosView.vue.d.ts +3 -0
- package/dist-lib/types/views/EmpleadosView.vue.d.ts +3 -0
- package/dist-lib/types/views/HomologacionView.vue.d.ts +4 -0
- package/dist-lib/types/views/IngresoSsoView.vue.d.ts +3 -0
- package/dist-lib/types/views/LoginView.vue.d.ts +3 -0
- package/dist-lib/types/views/OlvideView.vue.d.ts +3 -0
- package/dist-lib/types/views/RestablecerView.vue.d.ts +3 -0
- package/dist-lib/types/views/SolicitudesView.vue.d.ts +3 -0
- package/dist-lib/types/views/TiposSolicitudView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatBandejaView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatConfiguracionView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatConocimientoView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatConversacionView.vue.d.ts +11 -0
- package/dist-lib/types/views/chat/ChatInformeView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatRespuestasView.vue.d.ts +3 -0
- package/package.json +66 -4
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat con RRHH del cliente de la sesión (softdin-portal-api, `routes/api.php`, grupo `rrhh`,
|
|
3
|
+
* `chat/*`; forma en app/Http/Resources/ChatJson.php). Diseño en softdin-portal-api/docs/chat-rrhh.md.
|
|
4
|
+
*/
|
|
5
|
+
export type EstadoConversacion = 'ia' | 'resuelta_ia' | 'sin_asignar' | 'asignada' | 'esperando_empleado' | 'resuelta' | 'cerrada';
|
|
6
|
+
export type VistaBandeja = 'sin_asignar' | 'mias' | 'esperando' | 'resueltas' | 'todas';
|
|
7
|
+
export interface TemaResumen {
|
|
8
|
+
id: number;
|
|
9
|
+
nombre: string;
|
|
10
|
+
descripcion: string | null;
|
|
11
|
+
confidencial: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Cliente interno (tercero cliente de SoftDIN) al que pertenece el empleado dentro del tenant. */
|
|
14
|
+
export interface ClienteInternoChat {
|
|
15
|
+
id: number;
|
|
16
|
+
nit: string | null;
|
|
17
|
+
nombre: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ConversacionResumen {
|
|
20
|
+
id: number;
|
|
21
|
+
empleado: string | null;
|
|
22
|
+
/** Desde qué cliente interno escribió el empleado; null si no se sabe. */
|
|
23
|
+
cliente_interno: ClienteInternoChat | null;
|
|
24
|
+
identificacion: string | null;
|
|
25
|
+
cargo: string | null;
|
|
26
|
+
tema: TemaResumen | null;
|
|
27
|
+
estado: EstadoConversacion;
|
|
28
|
+
asignada_a: {
|
|
29
|
+
id: number;
|
|
30
|
+
nombre: string;
|
|
31
|
+
} | null;
|
|
32
|
+
motivo_escalamiento: string | null;
|
|
33
|
+
prioridad: 'normal' | 'alta';
|
|
34
|
+
escalada_en: string | null;
|
|
35
|
+
vence_primera_respuesta_en: string | null;
|
|
36
|
+
primera_respuesta_en: string | null;
|
|
37
|
+
vence_resolucion_en: string | null;
|
|
38
|
+
resuelta_en: string | null;
|
|
39
|
+
vencida: boolean;
|
|
40
|
+
ultimo_mensaje_en: string | null;
|
|
41
|
+
ultimo_mensaje: {
|
|
42
|
+
autor: string;
|
|
43
|
+
interno: boolean;
|
|
44
|
+
extracto: string;
|
|
45
|
+
} | null;
|
|
46
|
+
no_leidos: number;
|
|
47
|
+
calificacion: number | null;
|
|
48
|
+
}
|
|
49
|
+
export interface MensajeChat {
|
|
50
|
+
id: number;
|
|
51
|
+
autor: 'empleado' | 'ia' | 'rrhh' | 'sistema';
|
|
52
|
+
autor_nombre: string | null;
|
|
53
|
+
interno: boolean;
|
|
54
|
+
cuerpo: string;
|
|
55
|
+
creado_en: string | null;
|
|
56
|
+
escrito_en: string | null;
|
|
57
|
+
/** Del asistente: los datos que consultó, ya formateados. */
|
|
58
|
+
tarjetas?: {
|
|
59
|
+
titulo: string;
|
|
60
|
+
filas: [string, string][];
|
|
61
|
+
}[];
|
|
62
|
+
/** «Me sirvió» / «No me sirvió» del empleado a una respuesta del asistente. */
|
|
63
|
+
util?: boolean | null;
|
|
64
|
+
}
|
|
65
|
+
export interface EventoChat {
|
|
66
|
+
tipo: string;
|
|
67
|
+
usuario: string | null;
|
|
68
|
+
detalle: string | null;
|
|
69
|
+
creado_en: string | null;
|
|
70
|
+
}
|
|
71
|
+
export interface ConversacionDetalle extends ConversacionResumen {
|
|
72
|
+
empleo: {
|
|
73
|
+
cargo: string | null;
|
|
74
|
+
tipo_contrato: string | null;
|
|
75
|
+
fecha_ingreso: string | null;
|
|
76
|
+
fecha_retiro: string | null;
|
|
77
|
+
dias_vacaciones: number | null;
|
|
78
|
+
vacaciones_corte: string | null;
|
|
79
|
+
solicitudes_abiertas: number;
|
|
80
|
+
};
|
|
81
|
+
mensajes: MensajeChat[];
|
|
82
|
+
eventos: EventoChat[];
|
|
83
|
+
}
|
|
84
|
+
export interface ResumenChat {
|
|
85
|
+
atiende: boolean;
|
|
86
|
+
/** El usuario está disponible para la asignación automática. */
|
|
87
|
+
disponible?: boolean;
|
|
88
|
+
es_admin: boolean;
|
|
89
|
+
sin_asignar: number;
|
|
90
|
+
mias: number;
|
|
91
|
+
vencidas: number;
|
|
92
|
+
no_leidas: number;
|
|
93
|
+
}
|
|
94
|
+
export interface HorarioChat {
|
|
95
|
+
dias: number[];
|
|
96
|
+
desde: string;
|
|
97
|
+
hasta: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Ajuste del chat para un cliente interno. Cada campo en null hereda el de todo el tenant;
|
|
101
|
+
* `activo: false` lo apaga solo para ese cliente (no lo enciende si el general está apagado).
|
|
102
|
+
*/
|
|
103
|
+
export interface AjusteClienteInternoChat {
|
|
104
|
+
cliente_interno_id: number;
|
|
105
|
+
activo: boolean | null;
|
|
106
|
+
horario: HorarioChat | null;
|
|
107
|
+
mensaje_fuera_horario: string | null;
|
|
108
|
+
}
|
|
109
|
+
export interface ConfiguracionChat {
|
|
110
|
+
activo: boolean;
|
|
111
|
+
horario: HorarioChat;
|
|
112
|
+
mensaje_fuera_horario: string | null;
|
|
113
|
+
dias_conservacion: number;
|
|
114
|
+
/** Solo los clientes con ajuste propio. Se cambian con `ajustarClienteInterno` y `heredarClienteInterno`. */
|
|
115
|
+
clientes_internos?: AjusteClienteInternoChat[];
|
|
116
|
+
/** Asistente de IA (fase 2): el cliente lo ofrece a sus empleados. */
|
|
117
|
+
ia_activa?: boolean;
|
|
118
|
+
tope_mensajes_ia_dia?: number;
|
|
119
|
+
/** Solo lectura: el servidor tiene la IA habilitada y con clave. */
|
|
120
|
+
ia_en_servidor?: boolean;
|
|
121
|
+
uso_ia_hoy?: {
|
|
122
|
+
mensajes: number;
|
|
123
|
+
llamadas: number;
|
|
124
|
+
tokens_entrada: number;
|
|
125
|
+
tokens_salida: number;
|
|
126
|
+
} | null;
|
|
127
|
+
}
|
|
128
|
+
export interface RespuestaGuardada {
|
|
129
|
+
id: number;
|
|
130
|
+
titulo: string;
|
|
131
|
+
/** `{nombre}` se reemplaza por el primer nombre del empleado al insertarla. */
|
|
132
|
+
cuerpo: string;
|
|
133
|
+
tema_id: number | null;
|
|
134
|
+
propia: boolean;
|
|
135
|
+
editable: boolean;
|
|
136
|
+
}
|
|
137
|
+
export interface TiemposChat {
|
|
138
|
+
/** Minutos hábiles. */
|
|
139
|
+
promedio: number | null;
|
|
140
|
+
mediana: number | null;
|
|
141
|
+
medidas: number;
|
|
142
|
+
/** Porcentaje dentro del plazo del tema. */
|
|
143
|
+
dentro_del_plazo: number | null;
|
|
144
|
+
}
|
|
145
|
+
export interface InformeChat {
|
|
146
|
+
desde: string;
|
|
147
|
+
hasta: string;
|
|
148
|
+
total: number;
|
|
149
|
+
por_estado: Partial<Record<EstadoConversacion, number>>;
|
|
150
|
+
resueltas_por_ia: number;
|
|
151
|
+
escaladas: number;
|
|
152
|
+
por_motivo: Record<string, number>;
|
|
153
|
+
primera_respuesta: TiemposChat;
|
|
154
|
+
sin_respuesta_vencidas: number;
|
|
155
|
+
resolucion: TiemposChat;
|
|
156
|
+
calificacion: {
|
|
157
|
+
promedio: number | null;
|
|
158
|
+
respuestas: number;
|
|
159
|
+
distribucion: Record<string, number>;
|
|
160
|
+
};
|
|
161
|
+
por_tema: {
|
|
162
|
+
tema: string;
|
|
163
|
+
total: number;
|
|
164
|
+
escaladas: number;
|
|
165
|
+
primera_respuesta_promedio: number | null;
|
|
166
|
+
calificacion_promedio: number | null;
|
|
167
|
+
}[];
|
|
168
|
+
uso_ia: {
|
|
169
|
+
mensajes: number;
|
|
170
|
+
llamadas: number;
|
|
171
|
+
tokens_entrada: number;
|
|
172
|
+
tokens_salida: number;
|
|
173
|
+
};
|
|
174
|
+
/** Solo para el admin del cliente. */
|
|
175
|
+
por_persona?: {
|
|
176
|
+
usuario: string;
|
|
177
|
+
atendidas: number;
|
|
178
|
+
resueltas: number;
|
|
179
|
+
primera_respuesta_promedio: number | null;
|
|
180
|
+
calificacion_promedio: number | null;
|
|
181
|
+
}[];
|
|
182
|
+
}
|
|
183
|
+
/** Minutos hábiles → «45 min», «3 h 20 min». */
|
|
184
|
+
export declare function duracion(min: number | null): string;
|
|
185
|
+
export interface ArticuloConocimiento {
|
|
186
|
+
id: number;
|
|
187
|
+
titulo: string;
|
|
188
|
+
contenido: string;
|
|
189
|
+
tema_id: number | null;
|
|
190
|
+
visible_en_faq: boolean;
|
|
191
|
+
orden: number;
|
|
192
|
+
activo: boolean;
|
|
193
|
+
version: number;
|
|
194
|
+
actualizado_en: string | null;
|
|
195
|
+
/** Null: general, para todo el tenant; si no, solo para los empleados de ese cliente interno. */
|
|
196
|
+
cliente_interno_id: number | null;
|
|
197
|
+
}
|
|
198
|
+
export interface TemaChat {
|
|
199
|
+
id: number;
|
|
200
|
+
nombre: string;
|
|
201
|
+
descripcion: string | null;
|
|
202
|
+
confidencial: boolean;
|
|
203
|
+
/** Lo que queda sin asignar va solo a la persona disponible con menos carga. */
|
|
204
|
+
asignacion_automatica?: boolean;
|
|
205
|
+
minutos_primera_respuesta: number;
|
|
206
|
+
minutos_resolucion: number;
|
|
207
|
+
orden: number;
|
|
208
|
+
activo: boolean;
|
|
209
|
+
/** Usuarios asignados; sin ninguno, lo atiende cualquiera que atienda el chat. */
|
|
210
|
+
personas: number[];
|
|
211
|
+
}
|
|
212
|
+
export interface PersonaChat {
|
|
213
|
+
id: number;
|
|
214
|
+
nombre: string;
|
|
215
|
+
email: string;
|
|
216
|
+
rol: 'rrhh' | 'admin';
|
|
217
|
+
es_superadmin: boolean;
|
|
218
|
+
atiende_chat: boolean;
|
|
219
|
+
disponible: boolean;
|
|
220
|
+
temas: number[];
|
|
221
|
+
}
|
|
222
|
+
export declare const chatService: {
|
|
223
|
+
resumen(): Promise<ResumenChat>;
|
|
224
|
+
conversaciones(vista: VistaBandeja, temaId: number | null, clienteInternoId?: number | null): Promise<ConversacionResumen[]>;
|
|
225
|
+
conversacion(id: number): Promise<ConversacionDetalle>;
|
|
226
|
+
responder(id: number, cuerpo: string, interno: boolean): Promise<ConversacionDetalle>;
|
|
227
|
+
tomar(id: number): Promise<ConversacionDetalle>;
|
|
228
|
+
asignar(id: number, usuarioId: number): Promise<ConversacionDetalle>;
|
|
229
|
+
/** Devuelve null si, tras pasarla a otro tema, el usuario ya no la ve. */
|
|
230
|
+
reasignar(id: number, cambio: {
|
|
231
|
+
usuario_id: number | null;
|
|
232
|
+
tema_id: number | null;
|
|
233
|
+
comentario: string;
|
|
234
|
+
}): Promise<ConversacionDetalle | null>;
|
|
235
|
+
esperando(id: number): Promise<ConversacionDetalle>;
|
|
236
|
+
resolver(id: number, comentario: string | null): Promise<ConversacionDetalle>;
|
|
237
|
+
configuracion(): Promise<ConfiguracionChat>;
|
|
238
|
+
guardarConfiguracion(c: ConfiguracionChat): Promise<ConfiguracionChat>;
|
|
239
|
+
/** Ajuste propio de un cliente interno (solo admin). Responde la configuración completa. */
|
|
240
|
+
ajustarClienteInterno(clienteInternoId: number, ajuste: Omit<AjusteClienteInternoChat, "cliente_interno_id">): Promise<ConfiguracionChat>;
|
|
241
|
+
/** Quita el ajuste: el cliente interno vuelve a lo general. */
|
|
242
|
+
heredarClienteInterno(clienteInternoId: number): Promise<ConfiguracionChat>;
|
|
243
|
+
temas(): Promise<TemaChat[]>;
|
|
244
|
+
crearTema(t: Partial<TemaChat>): Promise<TemaChat>;
|
|
245
|
+
actualizarTema(id: number, t: Partial<TemaChat>): Promise<TemaChat>;
|
|
246
|
+
personas(): Promise<PersonaChat[]>;
|
|
247
|
+
actualizarPersona(id: number, p: {
|
|
248
|
+
atiende_chat: boolean;
|
|
249
|
+
disponible?: boolean;
|
|
250
|
+
temas: number[];
|
|
251
|
+
}): Promise<PersonaChat[]>;
|
|
252
|
+
/** El propio usuario: disponible o no para la asignación automática. */
|
|
253
|
+
marcarDisponible(disponible: boolean): Promise<void>;
|
|
254
|
+
respuestas(): Promise<RespuestaGuardada[]>;
|
|
255
|
+
guardarRespuesta(r: Partial<RespuestaGuardada>): Promise<RespuestaGuardada>;
|
|
256
|
+
borrarRespuesta(id: number): Promise<void>;
|
|
257
|
+
/** Con `clienteInternoId`, solo las conversaciones de los empleados de ese cliente interno. */
|
|
258
|
+
informe(desde: string, hasta: string, clienteInternoId?: number | null): Promise<InformeChat>;
|
|
259
|
+
/** Con `clienteInternoId`, los generales más los de ese cliente; sin él, todos. */
|
|
260
|
+
conocimiento(clienteInternoId?: number | null): Promise<ArticuloConocimiento[]>;
|
|
261
|
+
guardarArticulo(a: Partial<ArticuloConocimiento>): Promise<ArticuloConocimiento>;
|
|
262
|
+
borrarArticulo(id: number): Promise<void>;
|
|
263
|
+
};
|
|
264
|
+
export declare const ESTADOS_CONVERSACION: Record<EstadoConversacion, {
|
|
265
|
+
texto: string;
|
|
266
|
+
clase: string;
|
|
267
|
+
}>;
|
|
268
|
+
export declare const MOTIVOS_ESCALAMIENTO: Record<string, string>;
|
|
269
|
+
/** Días del horario de atención: 1 = lunes … 7 = domingo. */
|
|
270
|
+
export declare const DIAS_SEMANA: {
|
|
271
|
+
n: number;
|
|
272
|
+
texto: string;
|
|
273
|
+
}[];
|
|
274
|
+
/** «Lun, Mar, Mié · 08:00–17:00». */
|
|
275
|
+
export declare function textoHorario(h: HorarioChat): string;
|
|
276
|
+
/** Fecha y hora cortas en la zona del navegador. */
|
|
277
|
+
export declare function fechaHora(iso: string | null): string;
|
|
278
|
+
/** «en 2 h», «hace 35 min»: para el plazo de respuesta. */
|
|
279
|
+
export declare function relativo(iso: string | null, ahora?: number): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuración del portal por cliente interno (softdin-portal-api, docs/integracion-softdin.md,
|
|
3
|
+
* «Configuración por cliente interno»): el carnet digital y los tipos de solicitud pueden tener
|
|
4
|
+
* un valor propio para los empleados de un cliente interno, que prevalece sobre el de todo el
|
|
5
|
+
* tenant. Sin valor propio, el cliente interno hereda el del tenant.
|
|
6
|
+
*/
|
|
7
|
+
export interface CarnetClienteInterno {
|
|
8
|
+
cliente_interno_id: number;
|
|
9
|
+
activo: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ConfiguracionCarnet {
|
|
12
|
+
/** El valor de todo el tenant. */
|
|
13
|
+
carnet_activo: boolean;
|
|
14
|
+
/** Los clientes internos con valor propio. */
|
|
15
|
+
clientes_internos: CarnetClienteInterno[];
|
|
16
|
+
}
|
|
17
|
+
export declare const carnetClientesInternosService: {
|
|
18
|
+
config(): Promise<ConfiguracionCarnet>;
|
|
19
|
+
/** Valor propio de un cliente interno. */
|
|
20
|
+
fijar(clienteInternoId: number, activo: boolean): Promise<ConfiguracionCarnet>;
|
|
21
|
+
/** Quita el valor propio: vuelve a heredar el del tenant. */
|
|
22
|
+
heredar(clienteInternoId: number): Promise<ConfiguracionCarnet>;
|
|
23
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { TipoSolicitudPortal } from './portal-empleado.service';
|
|
2
|
+
/**
|
|
3
|
+
* Homologación de lo que radica el empleado en el portal con los conceptos de novedad de seguridad social de
|
|
4
|
+
* SoftDIN, y los tipos de solicitud y de permiso que crea el administrador del portal (softdin-portal-api, rutas
|
|
5
|
+
* `rrhh/homologacion`, `rrhh/tipos-solicitud` y `rrhh/tipos-permiso`). Todo vive en SoftDIN: el portal lo edita por
|
|
6
|
+
* la API firmada y SoftDIN guarda el historial con el actor. Diseño en softdin-api/docs/portal-empleado.md.
|
|
7
|
+
*
|
|
8
|
+
* `clienteInterno` es el elegido en la barra superior (null = todo el tenant).
|
|
9
|
+
*/
|
|
10
|
+
export type GrupoHomologacion = 'incapacidad' | 'licencia' | 'vacaciones' | 'permiso' | 'tipo';
|
|
11
|
+
/** Concepto de novedad de seguridad social del cliente (los que se pueden elegir como homólogo). */
|
|
12
|
+
export interface ConceptoSeguridadSocial {
|
|
13
|
+
id: number;
|
|
14
|
+
codigo: string;
|
|
15
|
+
nombre: string;
|
|
16
|
+
/** Variable del sistema con que se liquida y se reporta en la PILA (IGE 45, IRP 46, LMA 47…). */
|
|
17
|
+
variable: number | null;
|
|
18
|
+
variable_nombre: string | null;
|
|
19
|
+
}
|
|
20
|
+
export type UnidadPermiso = 'horas' | 'dias_habiles' | 'dias_calendario';
|
|
21
|
+
export type PeriodoTopePermiso = 'evento' | 'dia' | 'semestre' | 'anio';
|
|
22
|
+
export type LineaParentesco = 'consanguinidad' | 'afinidad' | 'civil';
|
|
23
|
+
/** Grado máximo de cada línea que da derecho al permiso (el cónyuge siempre lo da); null = no pide parentesco. */
|
|
24
|
+
export type ParentescoPermiso = Partial<Record<LineaParentesco, number>> | null;
|
|
25
|
+
/** Tipo de permiso como lo publica SoftDIN (`TiposPermisoService`): la ley con los ajustes del cliente, o uno propio. */
|
|
26
|
+
export interface TipoPermisoPortal {
|
|
27
|
+
codigo: string;
|
|
28
|
+
nombre: string;
|
|
29
|
+
norma?: string | null;
|
|
30
|
+
/** ley: la plantilla tal cual; ajustado: la ley mejorada por el cliente; propio: creado por el cliente o el portal. */
|
|
31
|
+
origen?: 'ley' | 'ajustado' | 'propio' | string;
|
|
32
|
+
unidad: UnidadPermiso;
|
|
33
|
+
tope: number | null;
|
|
34
|
+
/** Tope que da la ley: se puede ampliar, nunca bajar. */
|
|
35
|
+
tope_legal?: number | null;
|
|
36
|
+
tope_periodo: PeriodoTopePermiso;
|
|
37
|
+
remunerado: boolean;
|
|
38
|
+
legal?: boolean;
|
|
39
|
+
/** Lo exige la ley: no se puede desactivar. */
|
|
40
|
+
obligatorio?: boolean;
|
|
41
|
+
soporte_requerido: boolean;
|
|
42
|
+
plazo_soporte_dias: number | null;
|
|
43
|
+
parentesco?: ParentescoPermiso;
|
|
44
|
+
activo: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface FilaHomologacion {
|
|
47
|
+
/** `incapacidad_comun`, `licencia_maternidad`, `vacaciones`, `permiso:{codigo}`, `tipo:{clave}`… */
|
|
48
|
+
clave: string;
|
|
49
|
+
grupo: GrupoHomologacion;
|
|
50
|
+
nombre: string;
|
|
51
|
+
/** Tope, si es remunerado… (lo arma SoftDIN). */
|
|
52
|
+
detalle: string | null;
|
|
53
|
+
/** Variable que exige la PILA para lo del portal (null = cualquiera). */
|
|
54
|
+
variable_esperada: number | null;
|
|
55
|
+
idconceptonovedad: number | null;
|
|
56
|
+
/** Con un cliente elegido: la homologación viene de la de todo el tenant. */
|
|
57
|
+
heredado: boolean;
|
|
58
|
+
/** La variable del concepto no es la que exige la PILA (avisa, no bloquea). */
|
|
59
|
+
advertencia: string | null;
|
|
60
|
+
/** Si SoftDIN deja cambiar la homologación de esta fila. */
|
|
61
|
+
editable: boolean;
|
|
62
|
+
/** Permisos: el tipo completo, si SoftDIN lo manda (permite editarlo desde la fila). */
|
|
63
|
+
tipo_permiso?: TipoPermisoPortal | null;
|
|
64
|
+
}
|
|
65
|
+
export interface Homologacion {
|
|
66
|
+
conceptos: ConceptoSeguridadSocial[];
|
|
67
|
+
filas: FilaHomologacion[];
|
|
68
|
+
}
|
|
69
|
+
/** Tipo de solicitud con los datos del soporte (los tipos nuevos los traen; los predeterminados pueden no traerlos). */
|
|
70
|
+
export type TipoSolicitudConSoporte = TipoSolicitudPortal & {
|
|
71
|
+
requiere_soporte?: boolean;
|
|
72
|
+
plazo_soporte_dias?: number | null;
|
|
73
|
+
};
|
|
74
|
+
export interface DatosTipoSolicitud {
|
|
75
|
+
nombre: string;
|
|
76
|
+
activo: boolean;
|
|
77
|
+
requiere_visto_bueno_nomina: boolean;
|
|
78
|
+
requiere_soporte: boolean;
|
|
79
|
+
plazo_soporte_dias: number | null;
|
|
80
|
+
}
|
|
81
|
+
/** Lo que se manda al crear un permiso o al cambiar uno propio. */
|
|
82
|
+
export interface DatosPermisoPropio {
|
|
83
|
+
nombre: string;
|
|
84
|
+
unidad: UnidadPermiso;
|
|
85
|
+
tope: number | null;
|
|
86
|
+
tope_periodo: PeriodoTopePermiso;
|
|
87
|
+
remunerado: boolean;
|
|
88
|
+
soporte_requerido: boolean;
|
|
89
|
+
plazo_soporte_dias: number | null;
|
|
90
|
+
parentesco: ParentescoPermiso;
|
|
91
|
+
activo: boolean;
|
|
92
|
+
}
|
|
93
|
+
/** Lo único que se ajusta de un permiso de la ley (mejorarlo, nunca empeorarlo). */
|
|
94
|
+
export type DatosAjustePermisoLey = Pick<DatosPermisoPropio, 'nombre' | 'tope' | 'soporte_requerido' | 'plazo_soporte_dias' | 'activo'>;
|
|
95
|
+
export declare const homologacionService: {
|
|
96
|
+
obtener(clienteInterno: number | null): Promise<Homologacion>;
|
|
97
|
+
/** `idconceptonovedad` null: quita la homologación (con un cliente elegido, vuelve a la de todo el tenant). */
|
|
98
|
+
guardar(clave: string, idconceptonovedad: number | null, clienteInterno: number | null): Promise<FilaHomologacion>;
|
|
99
|
+
/** Primero se crea en SoftDIN y después en el portal: si SoftDIN falla, no se crea nada. */
|
|
100
|
+
crearTipoSolicitud(datos: DatosTipoSolicitud, clienteInterno: number | null): Promise<TipoSolicitudConSoporte>;
|
|
101
|
+
/** `id`: el del tipo del tenant (como en Tipos de solicitud). */
|
|
102
|
+
editarTipoSolicitud(id: number, datos: DatosTipoSolicitud, clienteInterno: number | null): Promise<TipoSolicitudConSoporte>;
|
|
103
|
+
crearPermiso(datos: DatosPermisoPropio, clienteInterno: number | null): Promise<TipoPermisoPortal>;
|
|
104
|
+
editarPermiso(codigo: string, datos: DatosPermisoPropio | DatosAjustePermisoLey, clienteInterno: number | null): Promise<TipoPermisoPortal>;
|
|
105
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Administración del portal del cliente de la sesión (softdin-portal-api,
|
|
3
|
+
* `routes/api.php`, grupo `rrhh`). Diseño en softdin-api/docs/portal-empleado.md.
|
|
4
|
+
*/
|
|
5
|
+
export type EstadoSolicitudPortal = 'recibida' | 'en_aprobacion' | 'pendiente_visto_bueno' | 'aprobada' | 'rechazada' | 'rechazada_nomina' | 'cancelada';
|
|
6
|
+
export interface SolicitudPortal {
|
|
7
|
+
id: number;
|
|
8
|
+
empleado: string | null;
|
|
9
|
+
identificacion: string | null;
|
|
10
|
+
cargo: string | null;
|
|
11
|
+
tipo: string;
|
|
12
|
+
/** Concepto de SoftDIN que eligió el empleado (los de su grupo de nómina). */
|
|
13
|
+
concepto: string | null;
|
|
14
|
+
fecha_inicio: string;
|
|
15
|
+
fecha_fin: string;
|
|
16
|
+
motivo: string;
|
|
17
|
+
estado: EstadoSolicitudPortal;
|
|
18
|
+
nivel_actual: number | null;
|
|
19
|
+
niveles_total: number | null;
|
|
20
|
+
/** Aprobada, pero SoftDIN no pudo crear la novedad: nómina la registra a mano. */
|
|
21
|
+
novedad_manual: boolean;
|
|
22
|
+
radicada: string | null;
|
|
23
|
+
ultimo_comentario: string | null;
|
|
24
|
+
/** Incapacidad y licencias: el soporte ya está en el expediente del empleado en SoftDIN. */
|
|
25
|
+
tiene_soporte?: boolean;
|
|
26
|
+
/** El soporte llegó al portal y está en camino a SoftDIN. */
|
|
27
|
+
soporte_en_envio?: boolean;
|
|
28
|
+
/** Paternidad radicada sin soporte: días que quedan del plazo (negativo si venció). */
|
|
29
|
+
soporte_pendiente?: {
|
|
30
|
+
dias_restantes: number | null;
|
|
31
|
+
vence?: string | null;
|
|
32
|
+
} | null;
|
|
33
|
+
/** Datos no clínicos (el diagnóstico no llega al portal): origen y prórroga de la incapacidad. */
|
|
34
|
+
origen?: 'comun' | 'laboral' | null;
|
|
35
|
+
es_prorroga?: boolean | null;
|
|
36
|
+
/** Licencias: fecha del parto (Y-m-d). */
|
|
37
|
+
fecha_parto?: string | null;
|
|
38
|
+
}
|
|
39
|
+
export declare const portalSolicitudesService: {
|
|
40
|
+
/** Con `clienteInterno`, solo las de los empleados de ese cliente interno; sin él, todo el tenant. */
|
|
41
|
+
listar(estado?: EstadoSolicitudPortal, clienteInterno?: number | null): Promise<SolicitudPortal[]>;
|
|
42
|
+
/**
|
|
43
|
+
* Viaja firmado a SoftDIN, donde vive la novedad: al aprobar se activa; al no
|
|
44
|
+
* aprobar queda inactiva y el comentario le llega al empleado.
|
|
45
|
+
*/
|
|
46
|
+
vistoBueno(id: number, aprueba: boolean, comentario: string | null): Promise<void>;
|
|
47
|
+
};
|
|
48
|
+
export interface TipoSolicitudPortal {
|
|
49
|
+
id: number;
|
|
50
|
+
tipo: string;
|
|
51
|
+
nombre: string;
|
|
52
|
+
requiere_visto_bueno_nomina: boolean;
|
|
53
|
+
activo: boolean;
|
|
54
|
+
/** El cliente interno pedido (null = todo el tenant). */
|
|
55
|
+
cliente_interno_id?: number | null;
|
|
56
|
+
/** El cliente interno tiene su propia configuración de este tipo (si no, hereda la del tenant). */
|
|
57
|
+
personalizado?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* `id` es siempre el del tipo del tenant. Con `clienteInterno`, se ve y se cambia lo de los
|
|
61
|
+
* empleados de ese cliente interno: cambiarlo le crea su propia configuración, que prevalece.
|
|
62
|
+
*/
|
|
63
|
+
export declare const portalTiposService: {
|
|
64
|
+
listar(clienteInterno?: number | null): Promise<TipoSolicitudPortal[]>;
|
|
65
|
+
actualizar(id: number, cambios: Partial<Pick<TipoSolicitudPortal, "requiere_visto_bueno_nomina" | "activo">>, clienteInterno?: number | null): Promise<TipoSolicitudPortal>;
|
|
66
|
+
/** El cliente interno vuelve a usar lo de todo el tenant para este tipo. */
|
|
67
|
+
heredar(id: number, clienteInterno: number): Promise<TipoSolicitudPortal>;
|
|
68
|
+
};
|
|
69
|
+
export interface EmpleadoPortal {
|
|
70
|
+
/** Id del empleo en el portal (no el contrato de SoftDIN). */
|
|
71
|
+
id: number;
|
|
72
|
+
empleado: string | null;
|
|
73
|
+
identificacion: string | null;
|
|
74
|
+
/** Tercero cliente de SoftDIN al que pertenece el contrato (no el tenant). */
|
|
75
|
+
cliente_interno?: string | null;
|
|
76
|
+
cargo: string | null;
|
|
77
|
+
fecha_ingreso: string | null;
|
|
78
|
+
retirado: boolean;
|
|
79
|
+
/** Hay correo registrado: la invitación por correo es posible. */
|
|
80
|
+
tiene_correo: boolean;
|
|
81
|
+
/** pendiente: aún no activa su cuenta; activa: ya entra a la app. */
|
|
82
|
+
cuenta: 'activa' | 'pendiente';
|
|
83
|
+
}
|
|
84
|
+
export interface ClienteInterno {
|
|
85
|
+
id: number;
|
|
86
|
+
nit: string | null;
|
|
87
|
+
nombre: string;
|
|
88
|
+
/**
|
|
89
|
+
* Si el usuario puede escribir en este cliente interno (alcance por cliente del SSO de ámbito
|
|
90
|
+
* tenant). Ausente = sin restricción (servidor anterior).
|
|
91
|
+
*/
|
|
92
|
+
permitido?: boolean;
|
|
93
|
+
}
|
|
94
|
+
export type CanalInvitacion = 'qr' | 'correo';
|
|
95
|
+
export type RespuestaInvitacion = {
|
|
96
|
+
estado: 'qr';
|
|
97
|
+
cuenta_activa: boolean;
|
|
98
|
+
url: string;
|
|
99
|
+
expira_en: string;
|
|
100
|
+
} | {
|
|
101
|
+
estado: 'enviada';
|
|
102
|
+
correo: string;
|
|
103
|
+
} | {
|
|
104
|
+
estado: 'activa';
|
|
105
|
+
};
|
|
106
|
+
export declare const portalEmpleadosService: {
|
|
107
|
+
/** Empleados que SoftDIN publicó al portal; busca por nombre o documento (máximo 100). */
|
|
108
|
+
buscar(buscar: string, clienteInterno?: number | null): Promise<EmpleadoPortal[]>;
|
|
109
|
+
/** Catálogo de clientes internos del tenant que envió SoftDIN (también los que aún no tienen empleados). */
|
|
110
|
+
clientesInternos(): Promise<ClienteInterno[]>;
|
|
111
|
+
invitar(empleoId: number, canal: CanalInvitacion): Promise<RespuestaInvitacion>;
|
|
112
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solicitudes de certificado que los empleados hacen desde su Portal de autogestión
|
|
3
|
+
* cuando el certificado no se puede generar solo (o necesitan uno distinto). La solicitud
|
|
4
|
+
* vive en el portal; al atenderla, el PDF se guarda en la gestión documental de SoftDIN
|
|
5
|
+
* (el portal no guarda copia) y el empleado lo ve en «Documentos» de la app. También se
|
|
6
|
+
* puede rechazar con un motivo. softdin-portal-api, grupo `rrhh`.
|
|
7
|
+
*/
|
|
8
|
+
export type TipoCertificadoSolicitado = 'laboral' | 'ingresos_retenciones' | 'otro';
|
|
9
|
+
export type EstadoSolicitudCertificado = 'pendiente' | 'atendida' | 'rechazada';
|
|
10
|
+
export interface SolicitudCertificadoRrhh {
|
|
11
|
+
id: number;
|
|
12
|
+
tipo: TipoCertificadoSolicitado;
|
|
13
|
+
/** Año gravable (solo ingresos y retenciones). */
|
|
14
|
+
anio: number | null;
|
|
15
|
+
/** Lo que el empleado necesita que el certificado contenga. */
|
|
16
|
+
informacion: string;
|
|
17
|
+
estado: EstadoSolicitudCertificado;
|
|
18
|
+
/** Respuesta de RRHH al atender, o motivo del rechazo. */
|
|
19
|
+
respuesta: string | null;
|
|
20
|
+
/** Documento de SoftDIN donde quedó guardado el PDF entregado (cuando fue atendida). */
|
|
21
|
+
documento_id: number | null;
|
|
22
|
+
creada_en: string;
|
|
23
|
+
atendida_en: string | null;
|
|
24
|
+
empleado: {
|
|
25
|
+
nombre: string | null;
|
|
26
|
+
documento: string | null;
|
|
27
|
+
};
|
|
28
|
+
cliente_interno: {
|
|
29
|
+
id: number;
|
|
30
|
+
nombre: string;
|
|
31
|
+
} | null;
|
|
32
|
+
}
|
|
33
|
+
export interface FiltrosSolicitudesCertificado {
|
|
34
|
+
estado?: EstadoSolicitudCertificado;
|
|
35
|
+
/** Se conectará al selector global de cliente interno. */
|
|
36
|
+
cliente_interno_id?: number | null;
|
|
37
|
+
}
|
|
38
|
+
export interface DatosAtencionCertificado {
|
|
39
|
+
pdf: File;
|
|
40
|
+
titulo?: string | null;
|
|
41
|
+
respuesta?: string | null;
|
|
42
|
+
}
|
|
43
|
+
export declare const TIPOS_CERTIFICADO: Record<TipoCertificadoSolicitado, string>;
|
|
44
|
+
export declare const ESTADOS_SOLICITUD_CERTIFICADO: Record<EstadoSolicitudCertificado, {
|
|
45
|
+
texto: string;
|
|
46
|
+
clase: string;
|
|
47
|
+
}>;
|
|
48
|
+
/** Tamaño máximo del PDF que acepta el servidor (5 MB). */
|
|
49
|
+
export declare const PDF_MAXIMO_BYTES: number;
|
|
50
|
+
export declare const solicitudesCertificadoService: {
|
|
51
|
+
listar(filtros?: FiltrosSolicitudesCertificado): Promise<SolicitudCertificadoRrhh[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Guarda el PDF en SoftDIN y marca la solicitud atendida. Si SoftDIN no responde, el
|
|
54
|
+
* portal contesta 503 con el mensaje y la solicitud sigue pendiente.
|
|
55
|
+
*/
|
|
56
|
+
atender(id: number, datos: DatosAtencionCertificado): Promise<void>;
|
|
57
|
+
/** `respuesta` es el motivo que verá el empleado (5 a 1000 caracteres). */
|
|
58
|
+
rechazar(id: number, respuesta: string): Promise<void>;
|
|
59
|
+
};
|