Feat: Implementa flujo completo de facturación y promociones
Este commit introduce la funcionalidad completa para la facturación mensual, la gestión de promociones y la comunicación con el cliente en el módulo de suscripciones. Backend: - Se añade el servicio de Facturación que calcula automáticamente los importes mensuales basándose en las suscripciones activas, días de entrega y precios. - Se implementa el servicio DebitoAutomaticoService, capaz de generar el archivo de texto plano para "Pago Directo Galicia" y de procesar el archivo de respuesta para la conciliación de pagos. - Se desarrolla el ABM completo para Promociones (Servicio, Repositorio, Controlador y DTOs), permitiendo la creación de descuentos por porcentaje o monto fijo. - Se implementa la lógica para asignar y desasignar promociones a suscripciones específicas. - Se añade un servicio de envío de email (EmailService) integrado con MailKit y un endpoint para notificar facturas a los clientes. - Se crea la lógica para registrar pagos manuales (efectivo, tarjeta, etc.) y actualizar el estado de las facturas. - Se añaden todos los permisos necesarios a la base de datos para segmentar el acceso a las nuevas funcionalidades. Frontend: - Se crea la página de Facturación, que permite al usuario seleccionar un período, generar la facturación, listar los resultados y generar el archivo de débito para el banco. - Se implementa la funcionalidad para subir y procesar el archivo de respuesta del banco, actualizando la UI en consecuencia. - Se añade la página completa para el ABM de Promociones. - Se integra un modal en la gestión de suscripciones para asignar y desasignar promociones a un cliente. - Se añade la opción "Enviar Email" en el menú de acciones de las facturas, conectada al nuevo endpoint del backend. - Se completan y corrigen los componentes `PagoManualModal` y `FacturacionPage` para incluir la lógica de registro de pagos y solucionar errores de TypeScript.
This commit is contained in:
74
Frontend/src/services/Suscripciones/facturacionService.ts
Normal file
74
Frontend/src/services/Suscripciones/facturacionService.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import apiClient from '../apiClient';
|
||||
import type { FacturaDto } from '../../models/dtos/Suscripciones/FacturaDto';
|
||||
import type { GenerarFacturacionResponseDto } from '../../models/dtos/Suscripciones/GenerarFacturacionResponseDto';
|
||||
import type { PagoDto } from '../../models/dtos/Suscripciones/PagoDto';
|
||||
import type { CreatePagoDto } from '../../models/dtos/Suscripciones/CreatePagoDto';
|
||||
import type { ProcesamientoLoteResponseDto } from '../../models/dtos/Suscripciones/ProcesamientoLoteResponseDto';
|
||||
|
||||
const API_URL = '/facturacion';
|
||||
const DEBITOS_URL = '/debitos';
|
||||
const PAGOS_URL = '/pagos';
|
||||
const FACTURAS_URL = '/facturas';
|
||||
|
||||
const procesarArchivoRespuesta = async (archivo: File): Promise<ProcesamientoLoteResponseDto> => {
|
||||
const formData = new FormData();
|
||||
formData.append('archivo', archivo);
|
||||
|
||||
const response = await apiClient.post<ProcesamientoLoteResponseDto>(`${DEBITOS_URL}/procesar-respuesta`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const getFacturasPorPeriodo = async (anio: number, mes: number): Promise<FacturaDto[]> => {
|
||||
const response = await apiClient.get<FacturaDto[]>(`${API_URL}/${anio}/${mes}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const generarFacturacionMensual = async (anio: number, mes: number): Promise<GenerarFacturacionResponseDto> => {
|
||||
const response = await apiClient.post<GenerarFacturacionResponseDto>(`${API_URL}/${anio}/${mes}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const generarArchivoDebito = async (anio: number, mes: number): Promise<{ fileContent: Blob, fileName: string }> => {
|
||||
const response = await apiClient.post(`${DEBITOS_URL}/${anio}/${mes}/generar-archivo`, {}, {
|
||||
responseType: 'blob',
|
||||
});
|
||||
|
||||
const contentDisposition = response.headers['content-disposition'];
|
||||
let fileName = `debito_${anio}_${mes}.txt`;
|
||||
if (contentDisposition) {
|
||||
const fileNameMatch = contentDisposition.match(/filename="(.+)"/);
|
||||
if (fileNameMatch && fileNameMatch.length > 1) {
|
||||
fileName = fileNameMatch[1];
|
||||
}
|
||||
}
|
||||
|
||||
return { fileContent: response.data, fileName: fileName };
|
||||
};
|
||||
|
||||
const getPagosPorFactura = async (idFactura: number): Promise<PagoDto[]> => {
|
||||
const response = await apiClient.get<PagoDto[]>(`${FACTURAS_URL}/${idFactura}/pagos`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const registrarPagoManual = async (data: CreatePagoDto): Promise<PagoDto> => {
|
||||
const response = await apiClient.post<PagoDto>(PAGOS_URL, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const enviarFacturaPorEmail = async (idFactura: number): Promise<void> => {
|
||||
await apiClient.post(`${API_URL}/${idFactura}/enviar-email`);
|
||||
};
|
||||
|
||||
export default {
|
||||
procesarArchivoRespuesta,
|
||||
getFacturasPorPeriodo,
|
||||
generarFacturacionMensual,
|
||||
generarArchivoDebito,
|
||||
getPagosPorFactura,
|
||||
registrarPagoManual,
|
||||
enviarFacturaPorEmail,
|
||||
};
|
||||
Reference in New Issue
Block a user