agrego script que agrega las clausulas para financiado
This commit is contained in:
878
clausulas_financiado.py
Normal file
878
clausulas_financiado.py
Normal file
@@ -0,0 +1,878 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
warnings.simplefilter("ignore", ResourceWarning)
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import re
|
||||
import ast
|
||||
import unicodedata
|
||||
import datetime as dt
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
# --------------------
|
||||
# Boot libs (Rocketbot portable)
|
||||
# --------------------
|
||||
base_dir = os.path.dirname(sys.executable)
|
||||
libs_dir = os.path.join(base_dir, "py_libs", "py310")
|
||||
sys.path.insert(0, libs_dir)
|
||||
|
||||
for k in list(sys.modules.keys()):
|
||||
if k == "pyparsing" or k.startswith("pyparsing."):
|
||||
del sys.modules[k]
|
||||
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.errors import HttpError
|
||||
from google.oauth2 import service_account
|
||||
from google.oauth2.credentials import Credentials
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request as GRequest
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# GOOGLE AUTH
|
||||
# -----------------------------------------------------------
|
||||
SCOPES = {scopes_api_google}
|
||||
|
||||
|
||||
def _load_json(path):
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def get_services(credentials_json_path, token_json_path):
|
||||
info = _load_json(credentials_json_path)
|
||||
|
||||
if isinstance(info, dict) and info.get("type") == "service_account":
|
||||
creds = service_account.Credentials.from_service_account_file(
|
||||
credentials_json_path,
|
||||
scopes=SCOPES,
|
||||
)
|
||||
docs = build("docs", "v1", credentials=creds, cache_discovery=False)
|
||||
drive = build("drive", "v3", credentials=creds, cache_discovery=False)
|
||||
return docs, drive, "service_account"
|
||||
|
||||
creds = None
|
||||
if os.path.exists(token_json_path):
|
||||
creds = Credentials.from_authorized_user_file(token_json_path, SCOPES)
|
||||
|
||||
if (not creds) or (not creds.valid):
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(GRequest())
|
||||
else:
|
||||
flow = InstalledAppFlow.from_client_secrets_file(credentials_json_path, SCOPES)
|
||||
try:
|
||||
creds = flow.run_local_server(port=0)
|
||||
except Exception:
|
||||
creds = flow.run_console()
|
||||
|
||||
os.makedirs(os.path.dirname(token_json_path), exist_ok=True)
|
||||
with open(token_json_path, "w", encoding="utf-8") as f:
|
||||
f.write(creds.to_json())
|
||||
|
||||
docs = build("docs", "v1", credentials=creds, cache_discovery=False)
|
||||
drive = build("drive", "v3", credentials=creds, cache_discovery=False)
|
||||
return docs, drive, "oauth"
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# ROCKETBOT VAR HELPERS
|
||||
# -----------------------------------------------------------
|
||||
def _sv(name, value):
|
||||
try:
|
||||
SetVar(name, value)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def _missing(v) -> bool:
|
||||
if v is None:
|
||||
return True
|
||||
if isinstance(v, str):
|
||||
s = v.strip()
|
||||
return s == "" or s == "ERROR_NOT_VAR"
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def _gv(name, default=None):
|
||||
try:
|
||||
v = GetVar(name)
|
||||
except Exception:
|
||||
return default
|
||||
return default if _missing(v) else v
|
||||
|
||||
|
||||
|
||||
def _first_non_empty(*values):
|
||||
for v in values:
|
||||
if str(v or "").strip() != "":
|
||||
return v
|
||||
return ""
|
||||
|
||||
|
||||
|
||||
def _norm_alnum(s: str) -> str:
|
||||
if s is None:
|
||||
return ""
|
||||
s = unicodedata.normalize("NFKD", str(s)).lower()
|
||||
out = []
|
||||
for ch in s:
|
||||
if unicodedata.category(ch) == "Mn":
|
||||
continue
|
||||
if ch.isalnum():
|
||||
out.append(ch)
|
||||
return "".join(out)
|
||||
|
||||
|
||||
|
||||
def _gvs(name, default="") -> str:
|
||||
v = _gv(name, default)
|
||||
if v is None:
|
||||
return default
|
||||
s = str(v).strip()
|
||||
return default if (s == "" or s == "ERROR_NOT_VAR") else s
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# DRIVE / DOC HELPERS
|
||||
# -----------------------------------------------------------
|
||||
def extract_doc_id_from_url(url):
|
||||
m = re.search(r"/document/d/([a-zA-Z0-9_-]+)", url or "")
|
||||
return m.group(1) if m else ""
|
||||
|
||||
|
||||
|
||||
def ensure_docs_api_compatible(drive_service, file_id: str):
|
||||
meta = drive_service.files().get(
|
||||
fileId=file_id,
|
||||
fields="id,name,mimeType,shortcutDetails",
|
||||
supportsAllDrives=True,
|
||||
).execute()
|
||||
|
||||
if meta.get("mimeType") == "application/vnd.google-apps.shortcut":
|
||||
target = (meta.get("shortcutDetails") or {}).get("targetId", "")
|
||||
if not target:
|
||||
raise RuntimeError("Es shortcut pero no trae targetId.")
|
||||
file_id = target
|
||||
meta = drive_service.files().get(
|
||||
fileId=file_id,
|
||||
fields="id,name,mimeType",
|
||||
supportsAllDrives=True,
|
||||
).execute()
|
||||
|
||||
if meta.get("mimeType") != "application/vnd.google-apps.document":
|
||||
new_name = (meta.get("name") or "Documento") + " (Google Docs)"
|
||||
converted = drive_service.files().copy(
|
||||
fileId=file_id,
|
||||
body={"name": new_name, "mimeType": "application/vnd.google-apps.document"},
|
||||
fields="id,name,mimeType",
|
||||
supportsAllDrives=True,
|
||||
).execute()
|
||||
return converted["id"], converted, True
|
||||
|
||||
return file_id, meta, False
|
||||
|
||||
|
||||
|
||||
def docs_get(docs_service, doc_id: str):
|
||||
return docs_service.documents().get(documentId=doc_id).execute()
|
||||
|
||||
|
||||
|
||||
def _walk_tabs(tabs):
|
||||
if not tabs:
|
||||
return
|
||||
for t in tabs:
|
||||
yield t
|
||||
for x in _walk_tabs(t.get("childTabs") or []):
|
||||
yield x
|
||||
|
||||
|
||||
|
||||
def _get_tab_body_content(doc, tab_id):
|
||||
tabs = doc.get("tabs")
|
||||
if not tabs:
|
||||
return (doc.get("body") or {}).get("content", [])
|
||||
|
||||
for t in _walk_tabs(tabs):
|
||||
tid = ((t.get("tabProperties") or {}).get("tabId")) or ""
|
||||
if tid == (tab_id or ""):
|
||||
dtab = t.get("documentTab") or {}
|
||||
return (dtab.get("body") or {}).get("content", [])
|
||||
|
||||
return []
|
||||
|
||||
|
||||
|
||||
def _paragraph_text(paragraph: dict) -> str:
|
||||
parts = []
|
||||
for pe in (paragraph.get("elements") or []):
|
||||
tr = pe.get("textRun") or {}
|
||||
txt = tr.get("content")
|
||||
if txt:
|
||||
parts.append(txt)
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
|
||||
def collect_paragraphs(doc: dict):
|
||||
out = []
|
||||
|
||||
def walk_content(content_list, tab_id=None):
|
||||
for el in content_list or []:
|
||||
if not isinstance(el, dict):
|
||||
continue
|
||||
|
||||
p = el.get("paragraph")
|
||||
if p:
|
||||
text = _paragraph_text(p)
|
||||
out.append(
|
||||
{
|
||||
"tabId": tab_id or "",
|
||||
"startIndex": int(el.get("startIndex", 0)),
|
||||
"endIndex": int(el.get("endIndex", 0)),
|
||||
"text": text,
|
||||
"norm_alnum": _norm_alnum(text),
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
t = el.get("table")
|
||||
if t:
|
||||
for row in t.get("tableRows", []):
|
||||
for cell in row.get("tableCells", []):
|
||||
walk_content(cell.get("content", []), tab_id=tab_id)
|
||||
continue
|
||||
|
||||
toc = el.get("tableOfContents")
|
||||
if toc:
|
||||
walk_content(toc.get("content", []), tab_id=tab_id)
|
||||
continue
|
||||
|
||||
walk_content((doc.get("body") or {}).get("content", []), tab_id=None)
|
||||
|
||||
for t in _walk_tabs(doc.get("tabs") or []):
|
||||
tab_id = ((t.get("tabProperties") or {}).get("tabId")) or ""
|
||||
dtab = t.get("documentTab") or {}
|
||||
walk_content((dtab.get("body") or {}).get("content", []), tab_id=tab_id)
|
||||
|
||||
out.sort(key=lambda x: (x["tabId"], x["startIndex"]))
|
||||
return out
|
||||
|
||||
|
||||
def _find_marker_by_paragraph_scan(doc, marker: str, restrict_tab_id=None, min_doc_index=None, max_doc_index=None):
|
||||
target = _norm_alnum(marker)
|
||||
if not target:
|
||||
return None
|
||||
|
||||
for p in collect_paragraphs(doc):
|
||||
tab_id = p.get("tabId") or ""
|
||||
start = int(p.get("startIndex", 0))
|
||||
end = int(p.get("endIndex", 0))
|
||||
norm = p.get("norm_alnum", "")
|
||||
|
||||
if restrict_tab_id is not None and (tab_id != (restrict_tab_id or "")):
|
||||
continue
|
||||
if min_doc_index is not None and end <= int(min_doc_index):
|
||||
continue
|
||||
if max_doc_index is not None and start >= int(max_doc_index):
|
||||
continue
|
||||
|
||||
pos = norm.find(target)
|
||||
if pos != -1:
|
||||
return {
|
||||
"tabId": tab_id or None,
|
||||
"start": start,
|
||||
"end": end,
|
||||
"mode": "paragraph_fallback",
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# BODY MARKER SEARCH BY INDEX
|
||||
# -----------------------------------------------------------
|
||||
def _iter_text_chars_from_body(doc, tab_id):
|
||||
content = _get_tab_body_content(doc, tab_id)
|
||||
|
||||
def walk(content_list):
|
||||
for el in content_list or []:
|
||||
if not isinstance(el, dict):
|
||||
continue
|
||||
|
||||
p = el.get("paragraph")
|
||||
if p:
|
||||
for pe in p.get("elements", []):
|
||||
tr = pe.get("textRun")
|
||||
if not tr:
|
||||
continue
|
||||
txt = tr.get("content", "")
|
||||
st = pe.get("startIndex")
|
||||
if st is None or txt is None:
|
||||
continue
|
||||
for i, ch in enumerate(txt):
|
||||
yield int(st) + i, ch
|
||||
continue
|
||||
|
||||
t = el.get("table")
|
||||
if t:
|
||||
for row in t.get("tableRows", []):
|
||||
for cell in row.get("tableCells", []):
|
||||
yield from walk(cell.get("content", []))
|
||||
continue
|
||||
|
||||
toc = el.get("tableOfContents")
|
||||
if toc:
|
||||
yield from walk(toc.get("content", []))
|
||||
continue
|
||||
|
||||
yield from walk(content)
|
||||
|
||||
|
||||
|
||||
def find_marker_in_body(doc, marker: str, restrict_tab_id=None, min_doc_index=None, max_doc_index=None):
|
||||
target = _norm_alnum(marker)
|
||||
if not target:
|
||||
return None
|
||||
|
||||
tabs = doc.get("tabs")
|
||||
tab_ids = [None]
|
||||
if tabs:
|
||||
tab_ids = []
|
||||
for t in _walk_tabs(tabs):
|
||||
tid = ((t.get("tabProperties") or {}).get("tabId")) or ""
|
||||
tab_ids.append(tid)
|
||||
|
||||
if restrict_tab_id is not None:
|
||||
tab_ids = [restrict_tab_id]
|
||||
|
||||
for tab_id in tab_ids:
|
||||
norm_chars = []
|
||||
norm_to_docidx = []
|
||||
|
||||
for doc_i, ch in _iter_text_chars_from_body(doc, tab_id):
|
||||
if min_doc_index is not None and int(doc_i) < int(min_doc_index):
|
||||
continue
|
||||
if max_doc_index is not None and int(doc_i) >= int(max_doc_index):
|
||||
continue
|
||||
|
||||
if ch.isalnum():
|
||||
norm_chars.append(ch.lower())
|
||||
norm_to_docidx.append(int(doc_i))
|
||||
|
||||
norm_text = "".join(norm_chars)
|
||||
pos = norm_text.find(target)
|
||||
|
||||
if pos != -1:
|
||||
start_doc = norm_to_docidx[pos]
|
||||
end_doc = norm_to_docidx[pos + len(target) - 1] + 1
|
||||
return {
|
||||
"tabId": tab_id,
|
||||
"start": int(start_doc),
|
||||
"end": int(end_doc),
|
||||
"mode": "fuzzy_alnum",
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# BATCH UPDATE HELPERS
|
||||
# -----------------------------------------------------------
|
||||
def _loc(index, tab_id=None):
|
||||
d = {"index": int(index)}
|
||||
if tab_id:
|
||||
d["tabId"] = tab_id
|
||||
return d
|
||||
|
||||
|
||||
|
||||
def _range(start, end, tab_id=None):
|
||||
d = {"startIndex": int(start), "endIndex": int(end)}
|
||||
if tab_id:
|
||||
d["tabId"] = tab_id
|
||||
return d
|
||||
|
||||
|
||||
|
||||
def _batch_update(docs_service, doc_id, reqs):
|
||||
docs_service.documents().batchUpdate(
|
||||
documentId=doc_id,
|
||||
body={"requests": reqs},
|
||||
).execute()
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# CLAUSULAS TEXT / FORMAT HELPERS
|
||||
# -----------------------------------------------------------
|
||||
SECTION_TITLE_RE = re.compile(
|
||||
r"^(CUARTA|QUINTA|SEXTA|SEPTIMA|S[ÉE]PTIMA|OCTAVA|NOVENA|D[ÉE]CIMA|UND[ÉE]CIMA|DECIMA SEGUNDA|D[ÉE]CIMA SEGUNDA|DECIMA TERCERA|D[ÉE]CIMA TERCERA|DECIMA CUARTA|D[ÉE]CIMA CUARTA|DECIMA QUINTA|D[ÉE]CIMA QUINTA)\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
ANNEX_RE = re.compile(r"^ANEXO\s+[IVXLC]+\b", re.IGNORECASE)
|
||||
LEADING_NUM_RE = re.compile(r"^\d+(?:\.\d+)*\.?")
|
||||
UPPER_TOKEN_RE = re.compile(
|
||||
r"(?<![A-Za-zÁÉÍÓÚÜÑáéíóúüñ])(?:[A-ZÁÉÍÓÚÜÑ0-9][A-ZÁÉÍÓÚÜÑ0-9()./º°\-]*[A-ZÁÉÍÓÚÜÑ0-9)])(?![A-Za-zÁÉÍÓÚÜÑáéíóúüñ])"
|
||||
)
|
||||
|
||||
CLAUSULAS_START_TOKEN = "RBCLAUSULASSTARTTOKENZXQ"
|
||||
CLAUSULAS_END_TOKEN = "RBCLAUSULASENDTOKENZXQ"
|
||||
|
||||
|
||||
def _is_section_title_line(line: str) -> bool:
|
||||
s = str(line or "").strip()
|
||||
return bool(SECTION_TITLE_RE.match(s))
|
||||
|
||||
|
||||
def _is_annex_line(line: str) -> bool:
|
||||
s = str(line or "").strip()
|
||||
return bool(ANNEX_RE.match(s))
|
||||
|
||||
|
||||
def _compose_clausulas_text(lines, nl="\n"):
|
||||
out = []
|
||||
total = len(lines)
|
||||
for i, raw_line in enumerate(lines):
|
||||
line = str(raw_line or "")
|
||||
prev_line = str(lines[i - 1] if i > 0 else "")
|
||||
next_line = str(lines[i + 1] if i + 1 < total else "")
|
||||
|
||||
if _is_section_title_line(line) and out and out[-1] != "":
|
||||
out.append("")
|
||||
|
||||
if _is_annex_line(line) and (not _is_annex_line(prev_line)) and out and out[-1] != "":
|
||||
out.append("")
|
||||
|
||||
out.append(line)
|
||||
|
||||
if _is_annex_line(line) and (i == total - 1 or not _is_annex_line(next_line)):
|
||||
out.append("")
|
||||
|
||||
return nl.join(out)
|
||||
|
||||
|
||||
def _find_char_range_exact(doc, text: str, restrict_tab_id=None):
|
||||
target = str(text or "")
|
||||
if target == "":
|
||||
return None
|
||||
|
||||
tabs = doc.get("tabs")
|
||||
tab_ids = [None]
|
||||
if tabs:
|
||||
tab_ids = []
|
||||
for t in _walk_tabs(tabs):
|
||||
tid = ((t.get("tabProperties") or {}).get("tabId")) or ""
|
||||
tab_ids.append(tid)
|
||||
|
||||
if restrict_tab_id is not None:
|
||||
tab_ids = [restrict_tab_id]
|
||||
|
||||
for tab_id in tab_ids:
|
||||
chars = []
|
||||
idxs = []
|
||||
for doc_i, ch in _iter_text_chars_from_body(doc, tab_id):
|
||||
chars.append(ch)
|
||||
idxs.append(int(doc_i))
|
||||
|
||||
big = "".join(chars)
|
||||
pos = big.find(target)
|
||||
if pos != -1:
|
||||
start_doc = idxs[pos]
|
||||
end_doc = idxs[pos + len(target) - 1] + 1
|
||||
return {
|
||||
"tabId": tab_id,
|
||||
"start": int(start_doc),
|
||||
"end": int(end_doc),
|
||||
"mode": "exact_text",
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _heading_prefix_len(line: str) -> int:
|
||||
if not line:
|
||||
return 0
|
||||
first_lower = None
|
||||
for i, ch in enumerate(line):
|
||||
if ch.isalpha() and ch == ch.lower() and ch != ch.upper():
|
||||
first_lower = i
|
||||
break
|
||||
if first_lower is None:
|
||||
end = len(line)
|
||||
else:
|
||||
end = first_lower
|
||||
while end > 0 and line[end - 1].isspace():
|
||||
end -= 1
|
||||
return max(0, end)
|
||||
|
||||
|
||||
def _append_text_style(reqs, start, end, tab_id=None, *, bold=None, italic=None):
|
||||
if end <= start:
|
||||
return
|
||||
fields = []
|
||||
style = {}
|
||||
if bold is not None:
|
||||
style["bold"] = bool(bold)
|
||||
fields.append("bold")
|
||||
if italic is not None:
|
||||
style["italic"] = bool(italic)
|
||||
fields.append("italic")
|
||||
if not fields:
|
||||
return
|
||||
reqs.append(
|
||||
{
|
||||
"updateTextStyle": {
|
||||
"range": _range(start, end, tab_id),
|
||||
"textStyle": style,
|
||||
"fields": ",".join(fields),
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _build_clausulas_style_requests(texto_clausulas: str, content_start: int, tab_id=None):
|
||||
reqs = []
|
||||
_append_text_style(
|
||||
reqs,
|
||||
content_start,
|
||||
content_start + len(texto_clausulas),
|
||||
tab_id=tab_id,
|
||||
bold=False,
|
||||
italic=False,
|
||||
)
|
||||
|
||||
offset = 0
|
||||
for chunk in texto_clausulas.splitlines(True):
|
||||
line = chunk[:-1] if chunk.endswith("\n") else chunk
|
||||
line_start = content_start + offset
|
||||
line_end = line_start + len(line)
|
||||
|
||||
if line:
|
||||
if _is_annex_line(line):
|
||||
_append_text_style(reqs, line_start, line_end, tab_id=tab_id, bold=False, italic=True)
|
||||
else:
|
||||
if _is_section_title_line(line):
|
||||
pref_len = _heading_prefix_len(line)
|
||||
if pref_len > 0:
|
||||
_append_text_style(
|
||||
reqs,
|
||||
line_start,
|
||||
line_start + pref_len,
|
||||
tab_id=tab_id,
|
||||
bold=True,
|
||||
)
|
||||
|
||||
m_num = LEADING_NUM_RE.match(line)
|
||||
if m_num:
|
||||
_append_text_style(
|
||||
reqs,
|
||||
line_start + m_num.start(),
|
||||
line_start + m_num.end(),
|
||||
tab_id=tab_id,
|
||||
bold=True,
|
||||
)
|
||||
|
||||
for m in UPPER_TOKEN_RE.finditer(line):
|
||||
token = m.group(0)
|
||||
if token.strip("-.") == "":
|
||||
continue
|
||||
_append_text_style(
|
||||
reqs,
|
||||
line_start + m.start(),
|
||||
line_start + m.end(),
|
||||
tab_id=tab_id,
|
||||
bold=True,
|
||||
)
|
||||
|
||||
offset += len(chunk)
|
||||
|
||||
return reqs
|
||||
|
||||
|
||||
def replace_marker_by_text_with_format(
|
||||
docs_service,
|
||||
doc_id: str,
|
||||
marker: str,
|
||||
replacement_text: str,
|
||||
debug_prefix: str,
|
||||
):
|
||||
doc = docs_get(docs_service, doc_id)
|
||||
_sv(f"{debug_prefix}_marker", marker)
|
||||
_sv(f"{debug_prefix}_marker_norm", _norm_alnum(marker))
|
||||
_sv(f"{debug_prefix}_paragraphs_count", str(len(collect_paragraphs(doc))))
|
||||
_sv(f"{debug_prefix}_replacement_len", str(len(replacement_text or "")))
|
||||
|
||||
wrapped_text = CLAUSULAS_START_TOKEN + replacement_text + CLAUSULAS_END_TOKEN
|
||||
|
||||
resp = docs_service.documents().batchUpdate(
|
||||
documentId=doc_id,
|
||||
body={
|
||||
"requests": [
|
||||
{
|
||||
"replaceAllText": {
|
||||
"containsText": {
|
||||
"text": marker,
|
||||
"matchCase": True,
|
||||
},
|
||||
"replaceText": wrapped_text,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
).execute()
|
||||
|
||||
replies = resp.get("replies") or []
|
||||
info = ((replies[0] if replies else {}).get("replaceAllText") or {})
|
||||
changed = int(info.get("occurrencesChanged", 0))
|
||||
|
||||
_sv(f"{debug_prefix}_scope", "replaceAllText_with_format")
|
||||
_sv(f"{debug_prefix}_occurrences_changed", str(changed))
|
||||
|
||||
if changed <= 0:
|
||||
raise RuntimeError(
|
||||
f"No se encontró el marcador como texto reemplazable: '{marker}'. "
|
||||
f"occurrencesChanged=0"
|
||||
)
|
||||
|
||||
doc_after_insert = docs_get(docs_service, doc_id)
|
||||
start_hit = _find_char_range_exact(doc_after_insert, CLAUSULAS_START_TOKEN)
|
||||
end_hit = _find_char_range_exact(doc_after_insert, CLAUSULAS_END_TOKEN)
|
||||
|
||||
if not start_hit or not end_hit:
|
||||
raise RuntimeError("Se reemplazó el marcador, pero no pude localizar los tokens internos para aplicar formato.")
|
||||
|
||||
tab_id = start_hit.get("tabId")
|
||||
content_start = int(start_hit["end"])
|
||||
content_end = int(end_hit["start"])
|
||||
|
||||
_sv(f"{debug_prefix}_tabId", "" if tab_id is None else str(tab_id))
|
||||
_sv(f"{debug_prefix}_start", str(content_start))
|
||||
_sv(f"{debug_prefix}_end", str(content_end))
|
||||
|
||||
reqs = []
|
||||
reqs.extend(_build_clausulas_style_requests(replacement_text, content_start, tab_id=tab_id))
|
||||
|
||||
reqs.append({"deleteContentRange": {"range": _range(end_hit["start"], end_hit["end"], end_hit.get("tabId"))}})
|
||||
reqs.append({"deleteContentRange": {"range": _range(start_hit["start"], start_hit["end"], start_hit.get("tabId"))}})
|
||||
|
||||
_batch_update(docs_service, doc_id, reqs)
|
||||
_sv(f"{debug_prefix}_found", "1")
|
||||
|
||||
|
||||
# Rocketbot quirk FIX
|
||||
globals().update(locals())
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# MAIN
|
||||
# -----------------------------------------------------------
|
||||
try:
|
||||
NL = "\n"
|
||||
_sv("error_clausulas", "")
|
||||
|
||||
# usar SOLO current_url
|
||||
url_doc = _gvs("current_url", "")
|
||||
if url_doc == "":
|
||||
raise RuntimeError("Falta current_url con la URL exacta del documento a procesar.")
|
||||
|
||||
_sv("debug_current_url_var", url_doc)
|
||||
_sv("debug_gdoc_url_var", _gvs("gdoc_url", ""))
|
||||
_sv("gdoc_url_used", url_doc)
|
||||
|
||||
raw_id = extract_doc_id_from_url(url_doc)
|
||||
if not raw_id:
|
||||
raise RuntimeError("No pude extraer documentId de la URL.")
|
||||
|
||||
_sv("gdoc_original_id", raw_id)
|
||||
|
||||
cred_path = _gvs("gdoc_sa_json", "")
|
||||
if cred_path == "":
|
||||
raise RuntimeError("Falta la variable gdoc_sa_json.")
|
||||
|
||||
if not os.path.isabs(cred_path):
|
||||
cred_path = os.path.join(base_dir, cred_path)
|
||||
|
||||
if not os.path.exists(cred_path):
|
||||
raise RuntimeError("No existe credentials.json: " + cred_path)
|
||||
|
||||
token_path = _gvs("gdoc_token_json", "")
|
||||
if token_path == "":
|
||||
token_path = os.path.join(base_dir, "credentials", "token_gdocs_drive.json")
|
||||
if not os.path.isabs(token_path):
|
||||
token_path = os.path.join(base_dir, token_path)
|
||||
|
||||
docs_service, drive_service, auth_mode = get_services(cred_path, token_path)
|
||||
_sv("gdoc_auth_mode", auth_mode)
|
||||
|
||||
doc_id, meta_file, converted = ensure_docs_api_compatible(drive_service, raw_id)
|
||||
_sv("gdoc_id", doc_id)
|
||||
_sv("gdoc_converted", "1" if converted else "0")
|
||||
_sv("gdoc_url_final", f"https://docs.google.com/document/d/{doc_id}/edit")
|
||||
_sv("gdoc_name", meta_file.get("name", ""))
|
||||
|
||||
doc_before = docs_get(docs_service, doc_id)
|
||||
_sv("gdoc_revision_before", doc_before.get("revisionId", ""))
|
||||
|
||||
# --------------------
|
||||
# UBICAR SECCIONES
|
||||
# --------------------
|
||||
paragraphs = collect_paragraphs(doc_before)
|
||||
_sv("gdoc_paragraphs_count", str(len(paragraphs)))
|
||||
|
||||
key_seg = _norm_alnum("SEGUNDA")
|
||||
key_prec = _norm_alnum("PRECIO")
|
||||
key_ter = _norm_alnum("TERCERO")
|
||||
key_pago = _norm_alnum("PAGO")
|
||||
key_cuarta = _norm_alnum("CUARTA")
|
||||
|
||||
segunda_title = None
|
||||
tercero_title = None
|
||||
cuarta_title = None
|
||||
|
||||
for p in paragraphs:
|
||||
n = p["norm_alnum"]
|
||||
if segunda_title is None and (key_seg in n and key_prec in n):
|
||||
segunda_title = p
|
||||
if tercero_title is None and (key_ter in n and key_pago in n):
|
||||
tercero_title = p
|
||||
if cuarta_title is None and n.startswith(key_cuarta):
|
||||
cuarta_title = p
|
||||
|
||||
precio_tab = None
|
||||
precio_min = None
|
||||
precio_max = None
|
||||
|
||||
if segunda_title:
|
||||
precio_tab = segunda_title.get("tabId") or ""
|
||||
precio_min = int(segunda_title.get("startIndex", 0))
|
||||
if tercero_title and ((tercero_title.get("tabId") or "") == precio_tab):
|
||||
precio_max = int(tercero_title.get("startIndex", 0))
|
||||
|
||||
fp_tab = None
|
||||
fp_min = None
|
||||
fp_max = None
|
||||
|
||||
if tercero_title:
|
||||
fp_tab = tercero_title.get("tabId") or ""
|
||||
fp_min = int(tercero_title.get("startIndex", 0))
|
||||
if cuarta_title and ((cuarta_title.get("tabId") or "") == fp_tab):
|
||||
fp_max = int(cuarta_title.get("startIndex", 0))
|
||||
|
||||
_sv("precio_tab", "" if precio_tab is None else str(precio_tab))
|
||||
_sv("precio_min", "" if precio_min is None else str(precio_min))
|
||||
_sv("precio_max", "" if precio_max is None else str(precio_max))
|
||||
_sv("fp_tab", "" if fp_tab is None else str(fp_tab))
|
||||
_sv("fp_min", "" if fp_min is None else str(fp_min))
|
||||
_sv("fp_max", "" if fp_max is None else str(fp_max))
|
||||
|
||||
# --------------------
|
||||
# MARCADORES
|
||||
# --------------------
|
||||
marker_clausulas_dinamicas = _gvs("marker_clausulas_dinamicas", "MARKER_CLAUSULAS_DINAMICAS")
|
||||
|
||||
if marker_clausulas_dinamicas == "":
|
||||
raise RuntimeError("La variable marker_clausulas_dinamicas está vacía.")
|
||||
|
||||
_sv("gdoc_marker_clausulas_dinamicas_used", marker_clausulas_dinamicas)
|
||||
|
||||
plan_pagos_raw = _first_non_empty(
|
||||
_gvs("plan_pagos", ""),
|
||||
_gvs("plan_de_pagos", ""),
|
||||
)
|
||||
plan_pagos = _norm_alnum(plan_pagos_raw)
|
||||
|
||||
_sv("debug_plan_pagos_raw", plan_pagos_raw)
|
||||
_sv("debug_plan_pagos_norm", plan_pagos)
|
||||
|
||||
if plan_pagos == "financiado":
|
||||
clausulas_lines = [
|
||||
'CUARTA: OBLIGACIONES DE LA VENDEDORA:',
|
||||
'4.1 Se obliga a construir edificios y unidades por sí o por terceros conforme a las siguientes condiciones:',
|
||||
'4.2 Tanto los planos arquitectónicos de las unidades adquiridas como su ubicación dentro del edificio son detallados en el Anexo III del CONTRATO y los cuales EL(LOS) COMPRADOR(ES) declara conocer y acepta.----------------------------------------------------------------------------------------------------------',
|
||||
'4.3 Las obras del edificio iniciaran en el startConstruction. ZUBA S.A.E.C.A. dará a conocer del inicio de la ejecución de las obras por medio de las páginas oficiales. Las unidades deberán ser entregadas por ZUBA S.A.E.C.A. a EL(LOS) COMPRADOR(ES) en el endConstruction desde el inicio de las obras. Tanto el plazo de inicio de obras como el plazo de entrega de las unidades podrá ser prorrogado por las causales de fuerza mayor establecidas en la Cláusula 7 del contrato, o 4 (cuatro) meses. -------------------------------------------------------------------------',
|
||||
'4.4 Finalizadas las obras en los plazos establecidos se entregará la posesión de la unidad a EL(LOS) COMPRADOR(ES), asegurando que el acceso a las unidades pueda hacerse en forma segura y razonablemente cómoda a criterio de la dirección de obra. La falta de detalles de terminación de las unidades, o de las instalaciones o servicios comunes del EDIFICIO project que no sean esenciales para el acceso, habitabilidad o uso normal de las unidades, no se considerará causa legítima de rechazo de la entrega y posesión por parte de EL(LOS) COMPRADOR(ES).',
|
||||
'4.4.1. La o las unidades se entregarán desocupadas, en un todo de acuerdo a las especificaciones técnicas detalladas en la memoria descriptiva que firmada por las partes se considera integrante de este contrato de compraventa, y se adjunta como Anexo II EL(LOS) COMPRADOR(ES) deja constancia que conoce y acepta la calidad y marca de los detalles constructivos y de terminación, así como los de los artefactos, accesorios y materiales a emplearse en la edificación, conviniéndose que su enumeración ha sido hecha a título ejemplificativo y que la EL VENDEDOR podrá decidir libremente introducir los cambios que estime convenientes, conservando el nivel de calidad representado por las marcas señaladas. Se conviene expresamente que EL(LOS) COMPRADOR(ES) no podrá oponerse a recibir la o las unidades por falta de terminación de detalles generales del edificio o partes comunes. A los efectos de la toma y entrega de la posesión, EL(LOS) COMPRADOR(ES) se encontrará obligada a aceptarla siempre que la o las unidades se encuentren en condiciones razonables de ser habitadas. Esto último se entenderá cuando, salvo pequeños detalles, estén terminadas en sus superficies propias y cuando estuvieren funcionando los ascensores y los servicios generales que correspondan por la época al momento que ocurra la entrega, aun cuando continúen en ejecución los trabajos en las partes comunes. ------------------------',
|
||||
'4.5 Garantizar la calidad de materiales y tecnologías constructivas para la ejecución de las obras.---',
|
||||
'4.6 Transferir a EL(LOS) COMPRADOR(ES) la propiedad de las unidades adquiridas una vez que estén concluidas las gestiones de las cuentas corrientes catastrales y se hallen finiquitadas las documentaciones escriturales por parte de las autoridades competentes. ----------------------------------',
|
||||
'QUINTA: OBLIGACIONES DE EL(LOS) COMPRADOR(ES): Se menciona puntos a tener en cuenta como obligación:',
|
||||
'5.1 El pago regular de sus compromisos ante ZUBA S.A.E.C.A. según se detalla en la Cláusula 3.',
|
||||
'5.2 La demora en cualquier pago quedará establecida por el solo vencimiento, sin necesidad de reclamación o notificación judicial o extrajudicial, generándose una penalidad del 3% sobre el valor de la cuota adeudada.-----------------------------------------------------------------------------------------------------',
|
||||
'5.3 Todos los pagos indicados en esta cláusula 3 deberán ser abonados en la dirección declarada por EL VENDEDOR, teniendo en cuenta las condiciones declaradas en el ANEXO V.------------------------------',
|
||||
'5.4 Destinar la unidad adquirida únicamente para fines residenciales, absteniéndose EL(LOS) COMPRADOR(ES) a darle un uso de distinta naturaleza.-------------------------------------------------------',
|
||||
'5.5 Abonar todos los gastos y costos relacionados a las unidades adquiridas, los impuestos, tasas, contribuciones, consumo de servicios públicos, expensas, y/o costos impuestos a EL(LOS) COMPRADOR(ES) por el Reglamento de Copropiedad y Administración desde la entrega de las unidades por parte de ZUBA S.A.E.C.A., incluso si la propiedad de las unidades aún no ha sido transferida a EL(LOS) COMPRADOR(ES).-------------------------------------------------------------------------',
|
||||
'5.6 Mantener indemne a ZUBA S.A.E.C.A. de todo daño, perjuicio, gasto, costo o reclamo generado a partir de la entrega de las unidades por parte de ZUBA S.A.E.C.A.----------------------------------------',
|
||||
'5.7 Suscribir y cumplir con las normas de convivencia establecidas en el Reglamento de Propiedad Horizontal de Copropietarios, que será suscripto por los propietarios y/o residentes de las unidades del edificio previo a la toma de posesión de las unidades, sujeto a modificaciones sugeridas por las autoridades competentes y a aquellas que ZUBA S.A.E.C.A. considere conveniente para el mejor funcionamiento del consorcio de copropietarios.------------------------------------------------------------------',
|
||||
'5.8 Demostrar fehacientemente que los fondos a ser utilizados durante toda la relación comercial con ZUBA S.A.E.C.A. provienen y provendrán de operaciones lícitas, conforme a la Ley N° 1015/97, sus modificaciones y las resoluciones dictadas por la SEPRELAD.---------------------------------------',
|
||||
'5.9 Cumplir con las disposiciones que las leyes y reglamentaciones en materia de prevención de lavado de dinero dispongan proveyendo de toda la documentación razonablemente requerida para el cumplimiento de lo solicitado por la SEPRELAD.--------------------------------------------------------------',
|
||||
'5.10 Autorizar en forma irrevocable, otorgando suficiente mandato a favor de ZUBA S.A.E.C.A. en los términos del Art. 917 inc. "a" del Código Civil Paraguayo, para que por propia cuenta y/o a través de empresas especializadas ZUBA S.A.E.C.A. pueda recabar información relacionada al COMPRADOR a fin de verificar y/o confirmar de los datos proveídos. Dicha información podrá ser utilizada por ZUBA S.A.E.C.A. tanto para análisis de crédito.-------------------------------------------------',
|
||||
'SEXTA: ANALISIS CREDITICIO: La firma ZUBA S.A.E.C.A. realizará un análisis crediticio en un plazo de hasta 30 días antes de finalizar la etapa de FINANCIACION PRE ENTREGA para la posesión provisoria de la unidad, asegurando que el acceso pueda hacerse en forma segura. En el caso de que EL(LOS) COMPRADOR(ES) no cumplan los parámetros de análisis, éstos podrán presentar un garante solidario y firmar un pagaré por el monto a financiar.---------------',
|
||||
'SEPTIMA: IMPOSIBILIDAD DE EJECUCIÓN DE LAS OBRAS POR CAUSAS NO IMPUTABLES A ZUBA S.A.E.C.A. no será responsable por el retardo o la inejecución de sus obligaciones por hechos de fuerza mayor. Se entiende por hechos de fuerza mayor aquellos hechos que escapen al control de las partes, imposibiliten el cumplimiento de sus obligaciones y que no sean imputables a las mismas, entendiéndose por tales:',
|
||||
'7.1 Fenómenos meteorológicos que imposibiliten la continuación de las obras tales como lluvias, inundaciones, tormentas, vendavales, tornados, etc.-------------------------------------------------------------',
|
||||
'7.2 Huelgas, bloqueos, cierres de ruta, u otros conflictos laborales significativos que impidan el acceso a las obras.--------------------------------------------------------------------------------------------------------',
|
||||
'7.3 Revueltas, actos o maniobras subversivas en nuestro país que afecten directa o indirectamente a las obras.------------------------------------------------------------------------------------------------------------------',
|
||||
'7.4 Carencia o escasez a nivel departamental, nacional o regional de materiales indispensables para las obras, tales como cemento, varillas de acero, etc.----------------------------------------------------------',
|
||||
'7.5 Expropiaciones, confiscaciones o destrucciones ordenadas por cualquier autoridad del gobierno paraguayo.--------------------------------------------------------------------------------------------------------------------',
|
||||
'7.6 Hostilidades bélicas, invasiones armadas, guerra civil, revoluciones o insurrecciones que afecten directa o indirectamente al Paraguay.--------------------------------------------------------------------------------',
|
||||
'7.7 Ausencia, demora, suspensión o revocación de permisos emitidos por autoridades competentes, sean permisos de órganos estatales o municipales, para registrar, autorizar o ejecutar las obras como así también toda suspensión de obras ordenada por autoridad competente.------------------------',
|
||||
'7.8 Emergencias sanitarias de cualquier naturaleza, incluyendo brotes epidémicos de enfermedades infectocontagiosas como Covid-19, dengue u otros. --------------------------------------------------------------',
|
||||
'7.9 Incumplimientos contractuales de cualquiera de los gremios contratistas o subcontratistas que intervengan en la obra.-----------------------------------------------------------------------------------------------------',
|
||||
'7.10. Existencia de medidas judiciales, administrativas y/o municipales que detengan retrasen el avance de la obra, incluyendo medidas cautelares y falta de conexiones de servicios ocasionados por demora de las prestadoras.----------------------------------------------------------------------------------------',
|
||||
'7.11. En general, cualquier otra causa fuerza del control de ZUBA S.A.E.C.A. que impidan el cumplimiento de sus obligaciones y que no hayan acontecido por causa imputable a ella.-------------',
|
||||
'Cualquier otra causa que no le sea imputable exclusivamente a ZUBA S.A.E.C.A., el plazo de entrega de la posesión se extenderá automáticamente hasta que cesen las causas de la demora, sin que pueda considerarse que ZUBA S.A.E.C.A. incurrió en mora.-----------------------------------------',
|
||||
'Si acontece una de las causales mencionadas, ZUBA S.A.E.C.A. notificará inmediatamente a la otra sobre dicha situación. La inejecución o el retardo en la ejecución de las obligaciones persistirá mientras dure la causal. Si una causal persiste por más de 1 año, cualquiera de las partes podrá rescindir el contrato sin generar obligación alguna. En caso de que desaparezcan las causas que impidan la ejecución de las obras, las obligaciones de ZUBA S.A.E.C.A. serán exigibles nuevamente en su totalidad. En la medida que el cumplimiento parcial de sus obligaciones sea posible, las partes cumplirán con las demás obligaciones del contrato que no se vean afectadas por la causal de fuerza mayor.---------------------',
|
||||
'OCTAVA: RECEPCIÓN O POSESION DE LAS UNIDADES: Las partes suscribirán un acta al momento de la entrega de las unidades a EL(LOS) COMPRADOR(ES). El acta contendrá la fecha, las condiciones de entrega de las unidades y observaciones pendientes, si las hubiere. De existir observaciones pendientes y ajustes puntuales que deban realizarse en las unidades, las partes podrán optar por realizar un acta de recepción provisoria donde se dejará constancia de la entrega de la posesión a EL(LOS) COMPRADOR(ES) y de las observaciones pendientes a ser corregidas en un plazo no mayor a los 45 días. Salvadas las observaciones y terminados los ajustes, las partes suscribirán un acta de recepción definitiva donde dejarán constancia del cumplimiento de todas las obligaciones contractuales por parte de ZUBA S.A.E.C.A. A partir de la toma de posesión, EL(LOS) COMPRADOR(ES) asume la responsabilidad por su mantenimiento, conservación y todos los riesgos que afecten a las unidades.--------------------------------------------------',
|
||||
'NOVENA: CESIÓN: Este contrato de Compraventa no podrá ser cedido ni transferido a terceros por cualquier título que fuese sin previa conformidad por escrito de la VENDEDORA, bajo apercibimiento de rescisión del mismo en forma automática y sin necesidad de interpelación judicial o extrajudicial alguna, en razón de que los antecedentes personales y patrimoniales de EL(LOS) COMPRADOR(ES) fueron determinantes y decisivos para la concreción de la transacción objeto del presente. Por lo tanto, EL(LOS) COMPRADOR(ES) únicamente con el consentimiento de manera excepcional expreso y por escrito de la VENDEDORA y siempre que se encuentre(n) al día con sus obligaciones, podrá(n) transferir a terceros este contrato de Compraventa y/o los derechos y obligaciones del mismo, en las condiciones establecidas por la VENDEDORA.------------------------',
|
||||
'Para que la cesión sea aprobada por la VENDEDORA, el que sustituya al cedente deberá acreditar patrimonio suficiente que le posibilite el cumplimiento de las obligaciones pendientes y ofrecer las garantías suficientes a satisfacción de la VENDEDORA.--------------------------------------------------------',
|
||||
'En todos los casos, EL(LOS) COMPRADOR(ES) y el(los) Cesionario(s) quedarán obligados mancomunada y solidariamente al pago de los impuestos, tasas y/o contribuciones, que graven la cesión de contrato.',
|
||||
'DECIMA: ESCRITURACIÓN: Los trámites para la escritura pública traslativa de dominio a favor de EL(LOS) COMPRADOR(ES) serán iniciados ante un escribano que sea designado únicamente por ZUBA S.A.E.C.A., una vez culminado el registro de todas las unidades del edificio en la Municipalidad, en la Dirección de Catastros, en la Dirección General de los Registros Públicos y en los demás órganos públicos intervinientes, y cancelado el precio en su totalidad. EL(LOS) COMPRADOR(ES) costeará todos los gastos relacionados a la Escrituración de las unidades adquiridas hasta que las mismas finalicen en la jurisdicción correspondiente, exonerando de toda responsabilidad a ZUBA S.A.E.C.A. por toda demora ocasionada por parte de las entidades públicas a la Escritura Pública traslativa de dominio. EL(LOS) COMPRADOR(ES) deberá suscribir la escritura pública traslativa de dominio de las unidades incluso si aún existan observaciones pendientes asentadas en el acta de recepción provisoria, o aún existan obras pendientes en áreas comunes del edificio.--------------------------------------------------------',
|
||||
'UNDÉCIMA: MODIFICACIÓN DE LAS OBRAS: EL(LOS) COMPRADOR(ES) declara conocer y aceptar que:',
|
||||
'11.1 Las numeraciones de los departamentos, cocheras y bauleras pueden sufrir variaciones, no así la ubicación de dichas unidades.-----------------------------------------------------------------------------------',
|
||||
'11.2 Conoce los detalles constructivos, de terminación, artefactos, accesorios y materiales a emplearse en la edificación de las unidades y manifiesta su conformidad con los mismos, pudiendo ZUBA S.A.E.C.A. decidir libremente introducir los cambios que estime convenientes, manteniendo el nivel de calidad representado.-------------------------------------------------------------------------------------',
|
||||
'11.3 Las unidades podrán sufrir las modificaciones impuestas por la marcha o dirección de obra antes de su entrega por parte de ZUBA S.A.E.C.A., sea en la cantidad de metros cuadrados, fachadas, materiales y/o nomenclatura. En caso de que se modifiquen los metros cuadrados de las unidades, dichas modificaciones serán de más o menos cinco por ciento (5%) de la cantidad de metros cuadrados establecidos inicialmente para las unidades.---------------------------------------------',
|
||||
'11.4 ZUBA S.A.E.C.A. podrá realizar los cambios y modificaciones de los proyectos sin necesidad de consulta ni autorización previa de EL(LOS) COMPRADOR(ES).---------------------------------------',
|
||||
'11.5 EL(LOS) COMPRADOR(ES) No podrá realizar alteraciones y/o agregados y/o instalar equipos exteriores que afecten la fachada y la estructura de las unidades, sin autorización expresa por escrito previamente otorgada por ZUBA S.A.E.C.A.--------------------------------------------------------------------',
|
||||
'11.6 EL(LOS) COMPRADOR(ES) No podrá realizar modificaciones ni obras adicionales en el interior de las unidades, ni alterar partes propias de las unidades hasta tanto estén expedidos las autorizaciones finales de los organismos y reparticiones competentes.--------------------------------------',
|
||||
'11.7 EL(LOS) COMPRADOR(ES) conoce que las unidades adquiridas, que forman parte del EDIFICIO project no cuenta aún con asignación individualizada de C.C.C (Cuenta Corriente Catastral) hasta que las mismas se hayan finiquitado ante las instituciones públicas correspondientes.------------------------------------------------------------------------------------------------------------',
|
||||
'DECIMA SEGUNDA: INCUMPLIMIENTO DE EL(LOS) COMPRADOR(ES): El incumplimiento por parte de EL(LOS) COMPRADOR(ES) de cualquier obligación dará derecho a ZUBA S.A.E.C.A. sin necesidad de interpelación judicial o extrajudicial alguna, a:',
|
||||
'12.1 Exigir el cumplimiento forzoso de cualquiera de las obligaciones establecidas en el contrato.',
|
||||
'12.2 De resolver el contrato en ejercicio, ZUBA S.A.E.C.A. devolverá a EL(LOS) COMPRADOR(ES) las sumas recibidas en concepto de pago del precio de venta hasta la fecha de la resolución, deduciendo del monto devuelto una suma equivalente al 40% del precio de venta en concepto de indemnización por incumplimiento del contrato. ZUBA S.A.E.C.A. depositará el monto en una escribanía de su elección y notificará a EL(LOS) COMPRADOR(ES). El escribano público labrará acta de la resolución del contrato y de la entrega de suma de dinero a EL(LOS) COMPRADOR(ES) en las condiciones mencionadas.-------------------------------------------------------------------',
|
||||
'DECIMA TERCERA: NOTIFICACIONES: Todas las notificaciones u otras comunicaciones serán entregadas vía correo electrónico o en caso excepcional se hará entrega de forma personal. Cualquiera de las dos modalidades que se opte para la notificación deberá tener el acuse de recepción surtiendo efectos y serán eficaces todas las notificaciones que se realizaren en tales condiciones.---------------------------------------------------------------------------------------------------',
|
||||
'La constitución de un nuevo domicilio deberá ser comunicado por escrito en forma física o correo electrónico dando aviso de dicho cambio, la cual surtirá efectos a partir de la recepción de la misma.',
|
||||
'DECIMA CUARTA: ANEXOS: CLAUSULA_FIRMA_DIGITALEl contrato junto con los ANEXOS contiene la totalidad de los acuerdos, estipulaciones y previsiones convenidos por las partes, dejando automáticamente sin efecto cualquier acuerdo, comunicación o manifestación previa, ya sea oral o escrita. Ninguna modificación o adición a este podrá ser admitida salvo que sea formalizada por escrito entre ambas partes.------------------------------------------------------',
|
||||
'ANEXO I PROFORMA DE PAGOS',
|
||||
'ANEXO II - ESPECIFICACIONES TECNICAS',
|
||||
'ANEXO III - PLANOS ARQUITECTONICOS DE LAS UNIDADES ADQUIRIDAS',
|
||||
'ANEXO IV - ADMINISTRACION DE LA PROPIEDAD HORIZONTAL',
|
||||
'ANEXO V - DATOS PARA REALIZAR PAGOS',
|
||||
'DECIMA QUINTA: JURISDICCIÓN COMPETENTE: En caso de surgir cualquier disputa entre las partes en relación con la existencia, validez, interpretación o ejecución del CONTRATO DE COMPRAVENTA, las mismas acuerdan someterse a la competencia de los tribunales de Asunción, con exclusión de cualquier otra jurisdicción que correspondiere.----------------------------------------------',
|
||||
]
|
||||
texto_clausulas = _compose_clausulas_text(clausulas_lines, nl=NL)
|
||||
|
||||
print(f"Insertando cláusulas para plan: {plan_pagos}")
|
||||
|
||||
replace_marker_by_text_with_format(
|
||||
docs_service=docs_service,
|
||||
doc_id=doc_id,
|
||||
marker=marker_clausulas_dinamicas,
|
||||
replacement_text=texto_clausulas,
|
||||
debug_prefix="res_clausula",
|
||||
)
|
||||
|
||||
_sv("status_proceso", "Clausulas insertadas correctamente")
|
||||
else:
|
||||
_sv("status_proceso", f"Plan {plan_pagos} no requiere inserción o no reconocido")
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
error_msg = f"Error en script: {str(e)} - {traceback.format_exc()}"
|
||||
print(error_msg)
|
||||
_sv("status_proceso", "ERROR")
|
||||
_sv("error_clausulas", error_msg)
|
||||
raise
|
||||
Reference in New Issue
Block a user