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.
2025-08-01 12:53:17 -03:00
import React , { useState , useEffect } from 'react' ;
import { Modal , Box , Typography , TextField , Button , CircularProgress , Alert , FormControl , InputLabel , Select , MenuItem , type SelectChangeEvent , InputAdornment } from '@mui/material' ;
import type { FacturaDto } from '../../../models/dtos/Suscripciones/FacturaDto' ;
import type { CreatePagoDto } from '../../../models/dtos/Suscripciones/CreatePagoDto' ;
import type { FormaPagoDto } from '../../../models/dtos/Suscripciones/FormaPagoDto' ;
import formaPagoService from '../../../services/Suscripciones/formaPagoService' ;
const modalStyle = {
position : 'absolute' as 'absolute' ,
top : '50%' ,
left : '50%' ,
transform : 'translate(-50%, -50%)' ,
width : { xs : '95%' , sm : '80%' , md : '500px' } ,
bgcolor : 'background.paper' ,
border : '2px solid #000' ,
boxShadow : 24 ,
p : 4 ,
maxHeight : '90vh' ,
overflowY : 'auto'
} ;
interface PagoManualModalProps {
open : boolean ;
onClose : ( ) = > void ;
onSubmit : ( data : CreatePagoDto ) = > Promise < void > ;
factura : FacturaDto | null ;
errorMessage? : string | null ;
clearErrorMessage : ( ) = > void ;
}
const PagoManualModal : React.FC < PagoManualModalProps > = ( { open , onClose , onSubmit , factura , errorMessage , clearErrorMessage } ) = > {
const [ formData , setFormData ] = useState < Partial < CreatePagoDto > > ( { } ) ;
const [ formasDePago , setFormasDePago ] = useState < FormaPagoDto [ ] > ( [ ] ) ;
const [ loading , setLoading ] = useState ( false ) ;
const [ loadingFormasPago , setLoadingFormasPago ] = useState ( false ) ;
const [ localErrors , setLocalErrors ] = useState < { [ key : string ] : string | null } > ( { } ) ;
useEffect ( ( ) = > {
const fetchFormasDePago = async ( ) = > {
setLoadingFormasPago ( true ) ;
try {
const data = await formaPagoService . getAllFormasDePago ( ) ;
setFormasDePago ( data . filter ( fp = > ! fp . requiereCBU ) ) ;
} catch ( error ) {
setLocalErrors ( prev = > ( { . . . prev , formasDePago : 'Error al cargar formas de pago.' } ) ) ;
} finally {
setLoadingFormasPago ( false ) ;
}
} ;
if ( open && factura ) {
fetchFormasDePago ( ) ;
setFormData ( {
idFactura : factura.idFactura ,
2025-08-08 09:48:15 -03:00
monto : factura.saldoPendiente , // Usar el saldo pendiente como valor por defecto
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.
2025-08-01 12:53:17 -03:00
fechaPago : new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ]
} ) ;
setLocalErrors ( { } ) ;
}
} , [ open , factura ] ) ;
const validate = ( ) : boolean = > {
const errors : { [ key : string ] : string | null } = { } ;
if ( ! formData . idFormaPago ) errors . idFormaPago = "Seleccione una forma de pago." ;
if ( ! formData . fechaPago ) errors . fechaPago = "La fecha de pago es obligatoria." ;
2025-08-08 09:48:15 -03:00
const monto = formData . monto ? ? 0 ;
const saldo = factura ? . saldoPendiente ? ? 0 ;
if ( monto <= 0 ) {
errors . monto = "El monto debe ser mayor a cero." ;
} else if ( monto > saldo ) {
// Usamos toFixed(2) para mostrar el formato de moneda correcto en el mensaje
errors . monto = ` El monto no puede superar el saldo pendiente de $ ${ saldo . toFixed ( 2 ) } . ` ;
}
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.
2025-08-01 12:53:17 -03:00
setLocalErrors ( errors ) ;
return Object . keys ( errors ) . length === 0 ;
} ;
const handleInputChange = ( e : React.ChangeEvent < HTMLInputElement > ) = > {
const { name , value } = e . target ;
const finalValue = name === 'monto' && value !== '' ? parseFloat ( value ) : value ;
setFormData ( prev = > ( { . . . prev , [ name ] : finalValue } ) ) ;
if ( localErrors [ name ] ) setLocalErrors ( prev = > ( { . . . prev , [ name ] : null } ) ) ;
if ( errorMessage ) clearErrorMessage ( ) ;
} ;
const handleSelectChange = ( e : SelectChangeEvent < any > ) = > {
const { name , value } = e . target ;
setFormData ( prev = > ( { . . . prev , [ name ] : value } ) ) ;
if ( localErrors [ name ] ) setLocalErrors ( prev = > ( { . . . prev , [ name ] : null } ) ) ;
if ( errorMessage ) clearErrorMessage ( ) ;
} ;
const handleSubmit = async ( e : React.FormEvent < HTMLFormElement > ) = > {
e . preventDefault ( ) ;
clearErrorMessage ( ) ;
if ( ! validate ( ) ) return ;
setLoading ( true ) ;
let success = false ;
try {
await onSubmit ( formData as CreatePagoDto ) ;
success = true ;
} catch ( error ) {
success = false ;
} finally {
setLoading ( false ) ;
if ( success ) onClose ( ) ;
}
} ;
if ( ! factura ) return null ;
return (
< Modal open = { open } onClose = { onClose } >
< Box sx = { modalStyle } >
< Typography variant = "h6" > Registrar Pago Manual < / Typography >
2025-08-08 09:48:15 -03:00
< Typography variant = "subtitle1" gutterBottom sx = { { fontWeight : 'bold' } } >
Saldo Pendiente : $ { factura . saldoPendiente . toFixed ( 2 ) }
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.
2025-08-01 12:53:17 -03:00
< / Typography >
< Box component = "form" onSubmit = { handleSubmit } sx = { { mt : 2 } } >
< TextField name = "fechaPago" label = "Fecha de Pago" type = "date" value = { formData . fechaPago || '' } onChange = { handleInputChange } required fullWidth margin = "dense" InputLabelProps = { { shrink : true } } error = { ! ! localErrors . fechaPago } helperText = { localErrors . fechaPago } / >
< FormControl fullWidth margin = "dense" error = { ! ! localErrors . idFormaPago } >
< InputLabel id = "forma-pago-label" required > Forma de Pago < / InputLabel >
< Select name = "idFormaPago" labelId = "forma-pago-label" value = { formData . idFormaPago || '' } onChange = { handleSelectChange } label = "Forma de Pago" disabled = { loadingFormasPago } >
{ formasDePago . map ( fp = > < MenuItem key = { fp . idFormaPago } value = { fp . idFormaPago } > { fp . nombre } < / MenuItem > ) }
< / Select >
< / FormControl >
< TextField name = "monto" label = "Monto Pagado" type = "number" value = { formData . monto || '' } onChange = { handleInputChange } required fullWidth margin = "dense" error = { ! ! localErrors . monto } helperText = { localErrors . monto } InputProps = { { startAdornment : < InputAdornment position = "start" > $ < / InputAdornment > } } inputProps = { { step : "0.01" } } / >
< TextField name = "referencia" label = "Referencia (Opcional)" value = { formData . referencia || '' } onChange = { handleInputChange } fullWidth margin = "dense" / >
< TextField name = "observaciones" label = "Observaciones (Opcional)" value = { formData . observaciones || '' } onChange = { handleInputChange } fullWidth margin = "dense" multiline rows = { 2 } / >
{ errorMessage && < Alert severity = "error" sx = { { mt : 2 } } > { errorMessage } < / Alert > }
< Box sx = { { mt : 3 , display : 'flex' , justifyContent : 'flex-end' , gap : 1 } } >
< Button onClick = { onClose } color = "secondary" disabled = { loading } > Cancelar < / Button >
< Button type = "submit" variant = "contained" disabled = { loading || loadingFormasPago } >
{ loading ? < CircularProgress size = { 24 } / > : 'Registrar Pago' }
< / Button >
< / Box >
< / Box >
< / Box >
< / Modal >
) ;
} ;
export default PagoManualModal ;