// repository/cuis_repo.go package repositories import ( "context" "daemonService/internal/models" "daemonService/internal/models/obtencionCodigos/request" "daemonService/internal/models/obtencionCodigos/response" srv "daemonService/internal/services" "daemonService/internal/utils" "database/sql" "fmt" "net/http" ) type CuisRepository struct { CuisService *srv.CuisService ModelService models.ServiceModel } // instanciamos cuisRepository func NewCuisRepository(model models.ServiceModel, cuisService *srv.CuisService) *CuisRepository { return &CuisRepository{ModelService: model, CuisService: cuisService} } func (cr *CuisRepository) CrearNuevoRegistro(ctx context.Context, request request.SolicitudCuisCufd, codigoCuis string, fechaVigencia string, transaccion bool, cufdData response.SoapBodyCufd) error { // Obtener la hora actual de Bolivia currentBolivia, err := utils.GetCurrentBoliviaTime() if err != nil { return fmt.Errorf("error al obtener hora de Bolivia: %w", err) } // Iniciar transacción tx, err := cr.ModelService.DB.BeginTx(ctx, nil) if err != nil { cr.CuisService.LogMessage("Error al iniciar transacción: %v", err) return utils.ErrorCustom(http.StatusBadRequest, "Error al iniciar transacción") } defer func() { if err != nil { tx.Rollback() } }() // Consulta corregida para manejar actualizaciones de CUIS y CUFD query := ` WITH empresa AS ( -- Inserta o actualiza empresa usando la clave natural INSERT INTO registroEmpresa ( codigo_ambiente, codigo_modalidad, codigo_punto_venta, codigo_sistema, codigo_sucursal, nit, token_key, token_value, nombre_archivo_certificado, nombre_archivo_clave_privada ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (nit, codigo_sucursal, codigo_punto_venta) DO UPDATE SET codigo_ambiente = EXCLUDED.codigo_ambiente, codigo_modalidad = EXCLUDED.codigo_modalidad, codigo_sistema = EXCLUDED.codigo_sistema, token_key = EXCLUDED.token_key, token_value = EXCLUDED.token_value, nombre_archivo_certificado = EXCLUDED.nombre_archivo_certificado, nombre_archivo_clave_privada = EXCLUDED.nombre_archivo_clave_privada, fecha_actualizacion = CURRENT_TIMESTAMP RETURNING id ), cuis_existente AS ( -- Busca si existe un CUIS para la empresa SELECT id, cuis, registro_empresa_id FROM cuis WHERE registro_empresa_id = (SELECT id FROM empresa) LIMIT 1 ), cuis_actualizado AS ( -- Si existe CUIS pero es diferente, actualízalo UPDATE cuis SET cuis = $11, fecha_vigencia = $12, transaccion = $13, fecha_actualizacion = CURRENT_TIMESTAMP FROM cuis_existente WHERE cuis.id = cuis_existente.id AND (cuis_existente.cuis <> $11 OR cuis_existente.cuis IS NULL) RETURNING cuis.id, cuis.registro_empresa_id ), cuis_insertado AS ( -- Si no existe CUIS, inserta uno nuevo INSERT INTO cuis ( cuis, fecha_vigencia, transaccion, fecha_creacion, registro_empresa_id ) SELECT $11, $12, $13, $14, id FROM empresa WHERE NOT EXISTS (SELECT 1 FROM cuis_existente) RETURNING id, registro_empresa_id ), cuis_final AS ( -- Usa el CUIS actualizado si existe SELECT id, registro_empresa_id FROM cuis_actualizado UNION ALL -- O el insertado si no había uno previo SELECT id, registro_empresa_id FROM cuis_insertado UNION ALL -- O el existente si no se actualizó (porque era igual) SELECT id, registro_empresa_id FROM cuis_existente WHERE NOT EXISTS (SELECT 1 FROM cuis_actualizado) AND EXISTS (SELECT 1 FROM cuis_existente) ), cufd_existente AS ( -- Busca si existe un CUFD para el CUIS actual SELECT c.id, c.codigo, c.codigo_control, c.direccion, c.cuis_id FROM cufd c JOIN cuis_final cf ON c.cuis_id = cf.id LIMIT 1 ), cufd_actualizado AS ( -- Si existe CUFD pero algún valor es diferente, actualízalo UPDATE cufd SET codigo = $15, codigo_control = $16, direccion = $17, fecha_vigencia = $18, transaccion = $19, fecha_actualizacion = CURRENT_TIMESTAMP FROM cufd_existente, cuis_final WHERE cufd.id = cufd_existente.id AND cufd.cuis_id = cuis_final.id AND ( cufd_existente.codigo <> $15 OR cufd_existente.codigo_control <> $16 OR cufd_existente.direccion <> $17 OR cufd_existente.codigo IS NULL ) RETURNING (SELECT registro_empresa_id FROM cuis_final LIMIT 1) as registro_id ), cufd_insertado AS ( -- Si no existe CUFD, inserta uno nuevo INSERT INTO cufd ( codigo, codigo_control, direccion, fecha_vigencia, transaccion, fecha_creacion, cuis_id ) SELECT $15, $16, $17, $18, $19, $20, id FROM cuis_final WHERE NOT EXISTS (SELECT 1 FROM cufd_existente) RETURNING (SELECT registro_empresa_id FROM cuis_final LIMIT 1) as registro_id ), resultado_final AS ( -- Usa el resultado de cualquiera de las operaciones SELECT registro_id FROM cufd_actualizado UNION ALL SELECT registro_id FROM cufd_insertado UNION ALL -- O usa el ID de empresa si el CUFD ya existía y no cambió SELECT registro_empresa_id as registro_id FROM cuis_final WHERE NOT EXISTS (SELECT 1 FROM cufd_actualizado) AND NOT EXISTS (SELECT 1 FROM cufd_insertado) AND EXISTS (SELECT 1 FROM cufd_existente) LIMIT 1 ) SELECT registro_id FROM resultado_final LIMIT 1; ` var registroID int err = tx.QueryRowContext( ctx, query, // Parámetros para registroEmpresa request.CodigoAmbiente, request.CodigoModalidad, request.CodigoPuntoVenta, request.CodigoSistema, request.CodigoSucursal, request.Nit, request.KeyToken, request.ValueToken, request.NombreArchivoCertificado, // Nuevo parámetro request.NombreArchivoClavePrivada, // Nuevo parámetro // Parámetros para cuis codigoCuis, fechaVigencia, transaccion, currentBolivia, // Parámetros para cufd cufdData.Response.Respuesta.Codigo, cufdData.Response.Respuesta.CodigoControl, cufdData.Response.Respuesta.Direccion, cufdData.Response.Respuesta.FechaVigencia, cufdData.Response.Respuesta.Transaccion, currentBolivia, ).Scan(®istroID) if err != nil { cr.CuisService.LogMessage("Error al insertar/actualizar registros: %v", err) return utils.ErrorCustom(http.StatusInternalServerError, "Error al procesar los registros en la base de datos") } // Confirmar la transacción if err = tx.Commit(); err != nil { cr.CuisService.LogMessage("Error al confirmar transacción: %v", err) return utils.ErrorCustom(http.StatusInternalServerError, "Error al confirmar transacción") } return nil } // actualiza un registro existente de empresa y CUIS func (cr *CuisRepository) ActualizarRegistro(ctx context.Context, empresaID int, cuisID int64, req request.SolicitudCuisCufd, respRaw interface{}) error { currentBolivia, err := utils.GetCurrentBoliviaTime() if err != nil { return err } // 1. Iniciar tx tx, err := cr.ModelService.DB.BeginTx(ctx, nil) if err != nil { cr.CuisService.LogMessage("Error iniciar transacción: %d", err) return fmt.Errorf("%w", utils.ErrorCustom(http.StatusBadRequest, "Error iniciar transacción")) } defer tx.Rollback() // 2. Parsear respuesta nuevoCuis, fechaVigencia, _, err := utils.ParseSoapCuisResponse(respRaw) if err != nil { cr.CuisService.LogMessage("Error al parsear la respuesta: %d", err) return fmt.Errorf("%w", utils.ErrorCustom(http.StatusBadRequest, "Error al parsear la respuesta")) } // 3. Actualizar empresa _, err = tx.ExecContext(ctx, ` UPDATE registroEmpresa SET codigo_ambiente=$1, codigo_modalidad=$2, codigo_punto_venta=$3, codigo_sistema=$4, codigo_sucursal=$5, nit=$6, fecha_actualizacion=$7 WHERE id=$8 `, req.CodigoAmbiente, req.CodigoModalidad, req.CodigoPuntoVenta, req.CodigoSistema, req.CodigoSucursal, req.Nit, currentBolivia, empresaID, ) if err != nil { cr.CuisService.LogMessage("Error al actualizar registroEmpresa: %d", err) return fmt.Errorf("%w", utils.ErrorCustom(http.StatusBadRequest, "Error al actualizar la tabla registroEmpresa")) } // 4. Comprobar si hay un CUIS existente var existingCuis string err = tx.QueryRowContext(ctx, `SELECT cuis FROM cuis WHERE id=$1 AND registro_empresa_id=$2`, cuisID, empresaID).Scan(&existingCuis) if err != nil && err != sql.ErrNoRows { cr.CuisService.LogMessage("Error al consultar cuis existente: %d", err) return fmt.Errorf("%w", utils.ErrorCustom(http.StatusBadRequest, "Error al consultar cuis existente")) } // 5. Insertar o actualizar if err == sql.ErrNoRows { _, err = tx.ExecContext(ctx, `INSERT INTO cuis (registro_empresa_id, cuis) VALUES ($1, $2)`, empresaID, nuevoCuis) if err != nil { cr.CuisService.LogMessage("Error al insertar nuevo cuis: %d", err) return fmt.Errorf("%w", utils.ErrorCustom(http.StatusBadRequest, "Error al insertar nuevo cuis")) } } else if existingCuis != nuevoCuis { _, err = tx.ExecContext(ctx, `UPDATE cuis SET cuis=$1, fecha_vigencia=$2, fecha_actualizacion=$3 WHERE id=$4`, nuevoCuis, fechaVigencia, currentBolivia, cuisID) if err != nil { cr.CuisService.LogMessage("Error al actualizar cuis existente: %d", err) return fmt.Errorf("%w", utils.ErrorCustom(http.StatusBadRequest, "Error al actualizar cuis existente")) } } // 6. Confirmar tx if err := tx.Commit(); err != nil { cr.CuisService.LogMessage("Error al confirmar transacción: %d", err) return fmt.Errorf("%w", utils.ErrorCustom(http.StatusBadRequest, "Error al confirmar transacción")) } return nil }