se agrega integración con SAP HANA, manejo de errores en el demonio y actualización de documentación
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fcc80d3c6e
commit
e6cde62e72
14 files changed
+1711
-237
No files matched your search
+34
-20
@@ -134,55 +134,69 @@ def _extract_factura_details(text: str, data: dict) -> None:
|
||||
if table_start_index != -1:
|
||||
items_lines = lines[table_start_index + 1:]
|
||||
current_item = None
|
||||
pre_item_buffer = []
|
||||
for line in items_lines:
|
||||
line = line.strip()
|
||||
if not line: continue
|
||||
if re.search(r"^(?:SUB|TOTAL|IGV|SON:|OP\.|RES|CUO|DET|BANCO|Representación|Podrá|Autorizado|FORMA|CUOTA|GRAVADO|I\.G\.V\.|DESEMBOLSO|OBSERVACION)", line, re.IGNORECASE):
|
||||
break
|
||||
amounts = re.findall(r"(?<![A-Z0-9-])(\d+(?:,\d{3})*(?:\.\d{2,}))(?![A-Z0-9-])", line)
|
||||
amounts = re.findall(r"(?<![A-Z0-9-])(\d+(?:,\d{3})*(?:\.\d{2,}))(?:(?=\s)|(?=$)|(?=[A-Z][a-z]))", line)
|
||||
if len(amounts) >= 2:
|
||||
if current_item: data["items"].append(current_item)
|
||||
qty = amounts[0]
|
||||
total = amounts[-1]
|
||||
p_unit = amounts[-2]
|
||||
if len(amounts) >= 4:
|
||||
p_unit = amounts[1]
|
||||
p_unit = amounts[-2].replace(",", "")
|
||||
total = amounts[-1].replace(",", "")
|
||||
desc_line = line
|
||||
for amt in [qty, p_unit, total]:
|
||||
desc_line = desc_line.replace(amt, "", 1)
|
||||
seen = set()
|
||||
for amt in amounts:
|
||||
if amt not in seen:
|
||||
desc_line = desc_line.replace(amt, "", 1)
|
||||
seen.add(amt)
|
||||
desc_parts = [p.strip() for p in desc_line.split() if p.strip()]
|
||||
codigo = None
|
||||
for i in range(min(3, len(desc_parts))):
|
||||
if re.search(r"[A-Z].*\d|\d.*[A-Z]|[A-Z]{2,}-\d+", desc_parts[i]):
|
||||
codigo = desc_parts[i]
|
||||
desc_parts.pop(i)
|
||||
cod = None
|
||||
for j in range(min(3, len(desc_parts))):
|
||||
if re.search(r"[A-Z].*\d|\d.*[A-Z]|[A-Z]{2,}-\d+", desc_parts[j]):
|
||||
cod = desc_parts[j]
|
||||
desc_parts.pop(j)
|
||||
break
|
||||
if desc_parts and desc_parts[0].isdigit() and len(desc_parts[0]) <= 2:
|
||||
desc_parts.pop(0)
|
||||
descripcion = " ".join(desc_parts)
|
||||
current_item = {
|
||||
"codigo": codigo,
|
||||
"codigo": cod,
|
||||
"cantidad": qty,
|
||||
"descripcion": descripcion,
|
||||
"precio_unitario": p_unit.replace(",", ""),
|
||||
"total": total.replace(",", ""),
|
||||
"precio_unitario": p_unit,
|
||||
"total": total,
|
||||
"guias_remision": [],
|
||||
"guia_transportista": None,
|
||||
"bolsas": None,
|
||||
"peso": None,
|
||||
"unidad_peso": None,
|
||||
}
|
||||
if pre_item_buffer:
|
||||
current_item["descripcion"] = " ".join(pre_item_buffer) + " " + descripcion
|
||||
pre_item_buffer = []
|
||||
elif current_item and len(line) > 5:
|
||||
current_item["descripcion"] += " " + line
|
||||
elif not current_item and len(line) > 5:
|
||||
pre_item_buffer.append(line)
|
||||
if current_item: data["items"].append(current_item)
|
||||
|
||||
# Extraer guías de cada ítem usando los mismos patrones que sunat_schema
|
||||
GUIAS_PDF_PATTERNS = [
|
||||
(r"(?:GRE\s+REMITENTE|GRR|G\.R\.R)\s*[:.]?\s*([TVE][A-Z0-9]{3,4})\s*-?\s*(\d+)", "09"),
|
||||
(r"\b(?:GRT|G\.R\.T)\s*[:.]?\s*([TVE][A-Z0-9]{3,4})\s*-?\s*(\d+)", "31"),
|
||||
]
|
||||
for item in data["items"]:
|
||||
desc = item["descripcion"]
|
||||
guias_remision_matches = re.findall(r"\b(?:GRR\w*|GR\b|G\.R\.R\.?|GUIA REMISI.N)\s*[:/\s]*((?:[TVE][A-Z0-9]{3})-\d+)", desc, re.IGNORECASE)
|
||||
item["guias_remision"] = [m.strip() for m in guias_remision_matches] if guias_remision_matches else []
|
||||
guia_transportista_match = re.search(r"\b(?:GRT\w*|GR\b|G\.R\.T\.?|GUIA TRANSPORTISTA)\s*[:/\s]*((?:[TVE][A-Z0-9]{3})-\d+)", desc, re.IGNORECASE)
|
||||
if guia_transportista_match:
|
||||
item["guia_transportista"] = guia_transportista_match.group(1).strip()
|
||||
for patron, tipo in GUIAS_PDF_PATTERNS:
|
||||
for m in re.finditer(patron, desc, re.IGNORECASE):
|
||||
numero = m.group(2).lstrip("0") or "0"
|
||||
if tipo == "09":
|
||||
item["guias_remision"].append(f"{m.group(1).upper()}-{numero}")
|
||||
else:
|
||||
item["guia_transportista"] = f"{m.group(1).upper()}-{numero}"
|
||||
bolsas_match = re.search(r"(\d+)\s*(?:BOLSAS|BLS|BOLS|SACOS)\b", desc, re.IGNORECASE)
|
||||
if bolsas_match:
|
||||
item["bolsas"] = bolsas_match.group(1)
|
||||
|
||||
Reference in new issue
Block a user