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.
		
			
				
	
	
		
			74 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			74 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 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,
 | |
| }; |