2025-05-17 11:36:26 -04:00

120 lines
3.3 KiB
Go

package facturacionOperaciones
import (
"api-soap-facturacion/internal/config"
"api-soap-facturacion/internal/logger"
mfo "api-soap-facturacion/internal/models/facturacionOperaciones"
"api-soap-facturacion/pkg/soap"
"bytes"
"context"
"encoding/xml"
"fmt"
"io"
"net/http"
"time"
)
// Constantes de configuración
const (
DefaultTimeout = 30 * time.Second
ContentType = "text/xml;charset=UTF-8"
SoapAction = "https://siat.impuestos.gob.bo/registroPuntoVenta"
SiatEndpoint = "https://pilotosiatservicios.impuestos.gob.bo/v2/FacturacionOperaciones"
)
// NewClient crea una nueva instancia del cliente SOAP
func NewClient(options *ClientOptions, config config.APIConfig, log logger.Logger) *Client {
// Configurar cliente SOAP
factOperaciones := soap.ClientOptions{
Endpoint: config.Endpoint,
Username: config.Username,
Password: config.Password,
Timeout: config.Timeout * time.Second,
Headers: map[string]string{
"User-Agent": "soap-api-client/1.0",
},
}
client := &Client{
endpointURL: SiatEndpoint,
soapClient: soap.NewClient(factOperaciones),
logger: log,
}
if options != nil {
if options.EndpointURL != "" {
client.endpointURL = options.EndpointURL
}
if options.HTTPClient != nil {
client.httpClient = options.HTTPClient
}
}
if client.httpClient == nil {
timeout := DefaultTimeout
if options != nil && options.Timeout > 0 {
timeout = options.Timeout
}
client.httpClient = &http.Client{
Timeout: timeout,
}
}
return client
}
// envía una solicitud para registrar un punto de venta en SIAT
func (c *Client) RegistrarPuntoVenta(ctx context.Context, solicitud mfo.SolicitudRegistroPuntoVenta) (*mfo.RespuestaRegistroPuntoVenta, error) {
// Preparar la petición SOAP
request := mfo.RegistroPuntoVentaRequest{
SoapEnv: "http://schemas.xmlsoap.org/soap/envelope/",
Siat: "https://siat.impuestos.gob.bo/",
}
request.Body.RegistroPuntoVenta.Solicitud = solicitud
// Convertir la petición a XML
requestBody, err := xml.MarshalIndent(request, "", " ")
if err != nil {
return nil, fmt.Errorf("error al convertir la solicitud a XML: %w", err)
}
// Crear la petición HTTP con el contexto
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.endpointURL, bytes.NewReader(requestBody))
if err != nil {
return nil, fmt.Errorf("error al crear la petición HTTP: %w", err)
}
// Configurar encabezados
req.Header.Set("Content-Type", ContentType)
req.Header.Set("SOAPAction", SoapAction)
// Realizar la petición HTTP
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error al realizar la petición HTTP: %w", err)
}
defer resp.Body.Close()
// Leer el cuerpo de la respuesta
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error al leer la respuesta: %w", err)
}
// Verificar el código de estado HTTP
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error en la respuesta HTTP: %s, cuerpo: %s", resp.Status, respBody)
}
// Parsear la respuesta
var soapResponse mfo.RegistroPuntoVentaResponse
if err := xml.Unmarshal(respBody, &soapResponse); err != nil {
return nil, fmt.Errorf("error al parsear la respuesta XML: %w, cuerpo: %s", err, respBody)
}
return &soapResponse.Body.RegistroPuntoVentaResponse.Respuesta, nil
}