| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- import { useState } from "react"
- import { toast } from "sonner"
- import type { EstadoEnvio, RespuestaVerificacionSRI } from "@/types/envio-sri"
- import { extractInfoFromXml } from "@/lib/xml-utils"
- export function useEnvioSRI() {
- const [xmlFile, setXmlFile] = useState<File | null>(null)
- const [p12File, setP12File] = useState<File | null>(null)
- const [password, setPassword] = useState("")
- const [signedXml, setSignedXml] = useState<string | null>(null)
- const [accessKey, setAccessKey] = useState<string>("")
- const [ambiente, setAmbiente] = useState<'1' | '2'>('1') // 1=Pruebas, 2=Producción
- const [isLoading, setIsLoading] = useState(false)
- const [estadoEnvio, setEstadoEnvio] = useState<EstadoEnvio>("idle")
- const [respuestaAutorizacion, setRespuestaAutorizacion] = useState<RespuestaVerificacionSRI | null>(null)
- // Paso 1: Firmar el XML (opcional si ya viene firmado)
- const handleSign = async () => {
- if (!xmlFile || !p12File || !password) {
- toast.error("Por favor completa todos los campos para firmar")
- return false
- }
- setIsLoading(true)
- setSignedXml(null)
- try {
- const formData = new FormData()
- formData.append("xml", xmlFile)
- formData.append("p12", p12File)
- formData.append("password", password)
- const response = await fetch("/api/sign-invoice", {
- method: "POST",
- body: formData,
- })
- const data = await response.json()
- if (!response.ok) {
- throw new Error(data.details || data.error || "Error al firmar")
- }
- setSignedXml(data.signedXml)
- toast.success("XML firmado exitosamente")
- return true
- } catch (error) {
- console.error(error)
- toast.error(error instanceof Error ? error.message : "Error al firmar el XML")
- return false
- } finally {
- setIsLoading(false)
- }
- }
- // Paso 2: Enviar al SRI
- const handleEnviarSRI = async () => {
- if (!signedXml) {
- toast.error("Primero debes firmar el XML o cargar uno firmado")
- return false
- }
- if (!accessKey.trim()) {
- toast.error("Debes ingresar la clave de acceso del documento")
- return false
- }
- setIsLoading(true)
- setEstadoEnvio("enviando")
- try {
- const response = await fetch("/api/send-to-sri", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ signedXml }),
- })
- const data = await response.json()
- if (!response.ok) {
- throw new Error(data.details || data.error || "Error al enviar")
- }
- // Actualizar el estado según la respuesta del SRI
- setEstadoEnvio(data.estado)
- // Si hay mensajes (errores/advertencias), guardarlos en respuestaAutorizacion
- if (data.mensajes && data.mensajes.length > 0) {
- setRespuestaAutorizacion({
- success: true,
- estado: data.estado,
- mensajes: data.mensajes,
- numeroAutorizacion: data.claveAcceso, // Usamos la clave de acceso como referencia
- })
- }
- if (data.estado === "devuelto") {
- toast.error("Documento devuelto por el SRI. Revisa los mensajes de error.")
- } else if (data.estado === "verificando") {
- toast.success("Documento enviado al SRI, verificando estado...")
- // Automáticamente verificar el estado
- await handleVerificarEstado()
- }
- return true
- } catch (error) {
- console.error(error)
- toast.error(error instanceof Error ? error.message : "Error al enviar al SRI")
- setEstadoEnvio("error")
- return false
- } finally {
- setIsLoading(false)
- }
- }
- // Paso 3: Verificar estado
- const handleVerificarEstado = async () => {
- if (!accessKey.trim()) {
- toast.error("Debes ingresar la clave de acceso")
- return false
- }
- setIsLoading(true)
- setEstadoEnvio("verificando")
- try {
- const response = await fetch("/api/poll-sri", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ accessKey }),
- })
- const data: RespuestaVerificacionSRI = await response.json()
- if (!response.ok) {
- throw new Error(data.details || data.error || "Error al verificar")
- }
- setRespuestaAutorizacion(data)
- setEstadoEnvio(data.estado)
- if (data.estado === "autorizado") {
- toast.success("¡Documento autorizado por el SRI!")
- } else if (data.estado === "devuelto") {
- toast.warning("Documento devuelto por el SRI")
- } else if (data.estado === "no_autorizado") {
- toast.error("Documento no autorizado por el SRI")
- }
- return true
- } catch (error) {
- console.error(error)
- toast.error(error instanceof Error ? error.message : "Error al verificar estado")
- setEstadoEnvio("error")
- return false
- } finally {
- setIsLoading(false)
- }
- }
- // Cargar un XML firmado directamente
- const handleLoadSignedXml = async (file: File) => {
- try {
- const content = await file.text()
- // Extraer información del XML automáticamente
- const info = extractInfoFromXml(content)
- if (!info.claveAcceso) {
- toast.error("No se pudo encontrar la clave de acceso en el XML")
- return
- }
- // Validar que la clave de acceso tenga 49 dígitos
- if (info.claveAcceso.length !== 49) {
- toast.error("La clave de acceso debe tener 49 dígitos")
- return
- }
- setSignedXml(content)
- setXmlFile(file)
- setAccessKey(info.claveAcceso)
- // Establecer el ambiente si se encuentra en el XML
- if (info.ambiente) {
- setAmbiente(info.ambiente)
- }
- toast.success(`XML cargado: ${file.name}`)
- toast.info(`Clave de acceso extraída: ${info.claveAcceso.substring(0, 10)}...`)
- } catch (error) {
- toast.error("Error al leer el archivo XML")
- }
- }
- // Descargar XML firmado
- const handleDownloadSigned = () => {
- if (!signedXml) return
- const blob = new Blob([signedXml], { type: "application/xml" })
- const url = URL.createObjectURL(blob)
- const a = document.createElement("a")
- a.href = url
- a.download = `factura_firmada_${new Date().getTime()}.xml`
- document.body.appendChild(a)
- a.click()
- document.body.removeChild(a)
- URL.revokeObjectURL(url)
- toast.success("XML firmado descargado")
- }
- // Descargar comprobante autorizado
- const handleDownloadAutorizado = () => {
- if (!respuestaAutorizacion?.comprobante) return
- const blob = new Blob([respuestaAutorizacion.comprobante], { type: "application/xml" })
- const url = URL.createObjectURL(blob)
- const a = document.createElement("a")
- a.href = url
- a.download = `factura_autorizada_${accessKey}.xml`
- document.body.appendChild(a)
- a.click()
- document.body.removeChild(a)
- URL.revokeObjectURL(url)
- toast.success("Comprobante autorizado descargado")
- }
- // Reset
- const handleReset = () => {
- setXmlFile(null)
- setP12File(null)
- setPassword("")
- setSignedXml(null)
- setAccessKey("")
- setEstadoEnvio("idle")
- setRespuestaAutorizacion(null)
- }
- return {
- // State
- xmlFile,
- p12File,
- password,
- signedXml,
- accessKey,
- ambiente,
- isLoading,
- estadoEnvio,
- respuestaAutorizacion,
- // Setters
- setXmlFile,
- setP12File,
- setPassword,
- setAccessKey,
- // Actions
- handleSign,
- handleEnviarSRI,
- handleVerificarEstado,
- handleLoadSignedXml,
- handleDownloadSigned,
- handleDownloadAutorizado,
- handleReset,
- }
- }
|