cargando primer proyecto a gitea
This commit is contained in:
commit
533105e7c3
16 files changed
+1327
No files matched your search
@@ -0,0 +1,83 @@
|
||||
import pdfplumber
|
||||
import re
|
||||
import os
|
||||
|
||||
########################################################
|
||||
def extraer_texto_pdf(ruta_pdf):
|
||||
"""Extrae todo el texto de un PDF usando pdfplumber."""
|
||||
texto_completo = ""
|
||||
try:
|
||||
with pdfplumber.open(ruta_pdf) as pdf:
|
||||
for page in pdf.pages:
|
||||
texto_completo += page.extract_text() + "\n"
|
||||
return texto_completo
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error leyendo PDF {ruta_pdf}: {e}")
|
||||
return ""
|
||||
|
||||
########################################################
|
||||
def extraer_ruc(texto):
|
||||
"""Busca un RUC (11 dígitos, empieza con 10 o 20) en el texto."""
|
||||
# Intentamos buscar patrones de RUC: RUC 2060... o R.U.C. 2060...
|
||||
patrones = [
|
||||
r'R\.?U\.?C\.?\s*[:\-\s]\s*((?:10|20)\d{9})', # R.U.C: 20...
|
||||
r'\b((?:10|20)\d{9})\b' # 11 dígitos sueltos que empiecen con 10 o 20
|
||||
]
|
||||
|
||||
for patron in patrones:
|
||||
match = re.search(patron, texto, re.IGNORECASE)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return "N/A"
|
||||
|
||||
########################################################
|
||||
def extraer_tipo_documento(texto):
|
||||
"""Identifica el tipo de documento SUNAT basándose en el texto usando regex multilínea."""
|
||||
t = texto.upper()
|
||||
|
||||
patrones = {
|
||||
"01": [r'FACTURA\s+(ELECTR[OÓ]NICA|DE\s+VENTA)', r'FACTURA'],
|
||||
"03": [r'BOLETA\s+DE\s+VENTA', r'BOLETA\s+ELECTR[OÓ]NICA'],
|
||||
"07": [r'NOTA\s+DE\s+CR[EÉ]DITO'],
|
||||
"08": [r'NOTA\s+DE\s+D[EÉ]BITO'],
|
||||
"14": [r'RECIBO\s+POR\s+HONORARIOS'],
|
||||
"09": [r'GU[IÍ]A\s+DE\s+REMISI[OÓ]N']
|
||||
}
|
||||
|
||||
for tipo, regex_list in patrones.items():
|
||||
for p in regex_list:
|
||||
if re.search(p, t, re.IGNORECASE | re.MULTILINE):
|
||||
return tipo
|
||||
|
||||
return "99"
|
||||
|
||||
########################################################
|
||||
def extraer_serie_numero(texto):
|
||||
"""Busca la serie y número (ej. F001-123 o F001-0000123)."""
|
||||
# Patrón común: [FBE][A-Z0-9]{3}-\d+
|
||||
patron = re.search(r'\b([FBE][A-Z0-9]{3})\s*-\s*(\d+)\b', texto)
|
||||
if patron:
|
||||
return f"{patron.group(1)}-{patron.group(2)}"
|
||||
|
||||
# Fallback para casos donde no hay guión o hay espacios raros
|
||||
patron_alt = re.search(r'([FBE][A-Z0-9]{3})\s+(\d{1,10})', texto)
|
||||
if patron_alt:
|
||||
return f"{patron_alt.group(1)}-{patron_alt.group(2)}"
|
||||
|
||||
return "No encontrado"
|
||||
|
||||
########################################################
|
||||
def obtener_datos_pdf(ruta_pdf):
|
||||
"""Orquestador para extraer metadata de un PDF."""
|
||||
texto = extraer_texto_pdf(ruta_pdf)
|
||||
if not texto:
|
||||
return {"valido": False, "error": "No se pudo extraer texto"}
|
||||
|
||||
return {
|
||||
"valido": True,
|
||||
"tipo_doc": extraer_tipo_documento(texto),
|
||||
"ruc": extraer_ruc(texto),
|
||||
"id": extraer_serie_numero(texto)
|
||||
}
|
||||
|
||||
########################################################
|
||||
Reference in new issue
Block a user