Delete script draft - Klientas dalyvauja apskaitoje skolose

This commit is contained in:
2026-02-02 19:10:09 +02:00
parent 891ae221e0
commit f9a42d51ea
6 changed files with 346 additions and 13 deletions

View File

@@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import os import os
import argparse
from datetime import date, timedelta from datetime import date, timedelta
from pathlib import Path from pathlib import Path
from typing import Dict, Iterable, Optional from typing import Dict, Iterable, Optional
@@ -327,8 +328,23 @@ def _build_periods(rows: list[dict[str, object]]) -> list[dict[str, object]]:
return periods return periods
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--user-id", dest="user_id")
parser.add_argument("--sutartis-id", dest="sutartis_id")
return parser.parse_args()
def _get_sutarties_kodas(args: argparse.Namespace) -> str:
sutarties_kodas = (args.sutartis_id or "").strip()
if sutarties_kodas:
return sutarties_kodas
return input("Sutarties kodas: ").strip()
def main() -> None: def main() -> None:
sutarties_kodas = input("Sutarties kodas: ").strip() args = _parse_args()
sutarties_kodas = _get_sutarties_kodas(args)
if not sutarties_kodas: if not sutarties_kodas:
print("Missing sutarties kodas.") print("Missing sutarties kodas.")
return return

View File

@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import argparse
import os import os
from datetime import date from datetime import date
from pathlib import Path from pathlib import Path
@@ -377,8 +378,23 @@ def _build_periods(rows: list[dict[str, object]]) -> list[dict[str, object]]:
return periods return periods
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--user-id", dest="user_id")
parser.add_argument("--sutartis-id", dest="sutartis_id")
return parser.parse_args()
def _get_sutarties_kodas(args: argparse.Namespace) -> str:
sutarties_kodas = (args.sutartis_id or "").strip()
if sutarties_kodas:
return sutarties_kodas
return input("Sutarties kodas: ").strip()
def main() -> None: def main() -> None:
sutarties_kodas = input("Sutarties kodas: ").strip() args = _parse_args()
sutarties_kodas = _get_sutarties_kodas(args)
if not sutarties_kodas: if not sutarties_kodas:
print("Missing sutarties kodas.") print("Missing sutarties kodas.")
return return

View File

@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import argparse
import subprocess import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
@@ -11,10 +12,17 @@ SCRIPTS = [
] ]
def _run_script(script_path: Path, sutarties_kodas: str) -> None: def _run_script(script_path: Path, user_id: str, sutarties_kodas: str) -> None:
result = subprocess.run( result = subprocess.run(
[sys.executable, str(script_path)], [
input=f"{sutarties_kodas}\n", sys.executable,
str(script_path),
"--user-id",
user_id,
"--sutartis-id",
sutarties_kodas,
],
input="",
text=True, text=True,
check=True, check=True,
) )
@@ -22,16 +30,33 @@ def _run_script(script_path: Path, sutarties_kodas: str) -> None:
def main() -> None: def main() -> None:
sutarties_kodas = input("Sutarties kodas: ").strip() parser = argparse.ArgumentParser()
if not sutarties_kodas: parser.add_argument("--user-id", dest="user_id")
parser.add_argument("--sutartis-id", dest="sutartis_id", nargs="*")
args = parser.parse_args()
user_id = (args.user_id or "").strip()
if not user_id:
user_id = input("User ID: ").strip()
if not user_id:
print("Missing user id.")
return
sutarties_kodai = [s.strip() for s in (args.sutartis_id or []) if s.strip()]
if not sutarties_kodai:
raw = input("Sutarties kodas (comma-separated for multiple): ").strip()
if raw:
sutarties_kodai = [s.strip() for s in raw.split(",") if s.strip()]
if not sutarties_kodai:
print("Missing sutarties kodas.") print("Missing sutarties kodas.")
return return
base_dir = Path(__file__).resolve().parent base_dir = Path(__file__).resolve().parent
for script_name in SCRIPTS: for sutarties_kodas in sutarties_kodai:
script_path = base_dir / script_name for script_name in SCRIPTS:
print(f"Running {script_name}...") script_path = base_dir / script_name
_run_script(script_path, sutarties_kodas) print(f"Running {script_name} for {sutarties_kodas}...")
_run_script(script_path, user_id, sutarties_kodas)
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import argparse
import os import os
from datetime import date, datetime from datetime import date, datetime
from pathlib import Path from pathlib import Path
@@ -248,8 +249,27 @@ def _update_contract(
_post(api_key, payload) _post(api_key, payload)
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--user-id", dest="user_id")
parser.add_argument("--sutartis-id", dest="sutartis_id")
return parser.parse_args()
def _get_sutarties_kodas(args: argparse.Namespace) -> str:
sutarties_kodas = (args.sutartis_id or "").strip()
if sutarties_kodas:
return sutarties_kodas
return input("Sutarties kodas: ").strip()
def _get_user_id(args: argparse.Namespace) -> str:
return (args.user_id or "").strip()
def main() -> None: def main() -> None:
sutarties_kodas = input("Sutarties kodas: ").strip() args = _parse_args()
sutarties_kodas = _get_sutarties_kodas(args)
if not sutarties_kodas: if not sutarties_kodas:
print("Missing sutarties kodas.") print("Missing sutarties kodas.")
return return
@@ -260,7 +280,7 @@ def main() -> None:
return return
row = rows[0] row = rows[0]
client_code = str(row.get("client_code") or "").strip() client_code = _get_user_id(args) or str(row.get("client_code") or "").strip()
if not client_code: if not client_code:
raise RuntimeError("Missing client code for sutartis.") raise RuntimeError("Missing client code for sutartis.")

View File

@@ -0,0 +1,238 @@
from __future__ import annotations
import argparse
import os
from datetime import date, datetime
from pathlib import Path
from typing import Dict, Iterable
import psycopg2
import psycopg2.extras
from dotenv import load_dotenv
import requests
from uv_app.core.mssql import connect_to_mssql
from uv_app.core.pgsql import connect_to_pgsql
DOTENV_PATH = Path(__file__).resolve().parents[2] / ".env"
load_dotenv(DOTENV_PATH, override=True)
QUERY_PATH = Path(__file__).with_name("multiple_contract_user_cleanup.sql")
BASE_URL = "https://api.manorivile.lt/client/v2"
TIMEOUT = 30
def _read_query() -> str:
return QUERY_PATH.read_text(encoding="utf-8")
def _fetch_rows() -> Iterable[Dict[str, object]]:
conn = connect_to_pgsql()
if conn is None:
raise RuntimeError("Failed to connect to PostgreSQL.")
try:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cursor:
cursor.execute(_read_query())
return cursor.fetchall()
finally:
conn.close()
def _normalize_date(value: object) -> date:
if isinstance(value, date):
return value
if isinstance(value, datetime):
return value.date()
return date.min
def _pick_primary_sutartis(rows: list[Dict[str, object]]) -> Dict[str, object]:
rows_sorted = sorted(
rows,
key=lambda r: (
_normalize_date(r.get("data")),
str(r.get("sutartiesid") or ""),
),
)
return rows_sorted[0]
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument(
"--delete-rivile",
action="store_true",
help="Delete duplicate Rivile clients.",
)
return parser.parse_args()
def _get_api_key() -> str:
api_key = os.getenv("RIVILE_API_KEY", "").strip()
if not api_key:
raise RuntimeError("Missing RIVILE_API_KEY environment variable.")
return api_key
def _post(api_key: str, payload: dict) -> dict:
headers = {
"ApiKey": api_key,
"Content-Type": "application/json",
"Accept": "application/json",
}
response = requests.post(
BASE_URL,
json=payload,
headers=headers,
timeout=TIMEOUT,
)
if response.status_code != 200:
raise RuntimeError(f"Rivile HTTP {response.status_code}: {response.text}")
data = response.json()
if "errorMessage" in data:
raise RuntimeError(f"Rivile API error: {data}")
return data
def _delete_rivile_client(api_key: str, client_code: str) -> None:
payload = {
"method": "EDIT_N08",
"params": {"oper": "D", "user": api_key.split(".", 1)[0]},
"data": {"N08": {"N08_KODAS_KS": client_code}},
}
_post(api_key, payload)
def _update_rivile_client_code(api_key: str, old_code: str, new_code: str) -> None:
payload = {
"method": "EDIT_N08",
"params": {
"oper": "U",
"user": api_key.split(".", 1)[0],
"fld": "N08_KODAS_KS",
"val": old_code,
},
"data": {"N08": {"N08_KODAS_KS": new_code}},
}
_post(api_key, payload)
def main() -> None:
args = _parse_args()
rows = list(_fetch_rows())
if not rows:
print("No multi-contract clients found.")
return
by_client: dict[int, list[Dict[str, object]]] = {}
for row in rows:
by_client.setdefault(int(row["klientasid"]), []).append(row)
mssql_conn = connect_to_mssql()
if mssql_conn is None:
raise RuntimeError("Failed to connect to MSSQL.")
processed = 0
api_key = _get_api_key() if args.delete_rivile else ""
try:
for klientasid, items in by_client.items():
processed += 1
primary = _pick_primary_sutartis(items)
target_code = str(primary.get("sutartiesid") or "").strip()
current_code = str(primary.get("kodas") or "").strip()
sutarties_ids = [
str(item.get("sutartiesid") or "").strip() for item in items
]
sutarties_ids = [s for s in sutarties_ids if s]
print("=" * 80)
print(f"klientasid={klientasid}")
print(f" PG klientas.kodas={current_code}")
print(f" PG sutartiesid list={sutarties_ids}")
print(f" earliest sutartiesid={target_code}")
actions: list[str] = []
if not target_code:
print(" -> Skipping: missing sutartiesid.")
print(" -> Actions: skip (missing sutartiesid)")
continue
# Rivile (MSSQL) checks
cursor = mssql_conn.cursor()
placeholders = ",".join("?" for _ in sutarties_ids) or "?"
params = sutarties_ids or [target_code]
cursor.execute(
f"""
SELECT N08_KODAS_KS
FROM dbo.N08_KLIJ
WHERE N08_KODAS_KS IN ({placeholders})
""",
params,
)
rivile_clients = [str(row[0]).strip() for row in cursor.fetchall()]
print(f" Rivile clients found={rivile_clients}")
if len(rivile_clients) > 1:
print(" -> ERROR: multiple Rivile clients for one klientasid.")
elif not rivile_clients:
print(" -> WARNING: no Rivile client found for these codes.")
if target_code in rivile_clients:
print(" -> OK: earliest sutartiesid is present in Rivile.")
duplicates = [c for c in rivile_clients if c != target_code]
if duplicates:
print(f" -> Duplicate Rivile clients to delete: {duplicates}")
if args.delete_rivile:
for dup in duplicates:
_delete_rivile_client(api_key, dup)
print(f" Deleted Rivile client {dup}")
actions.append(f"delete {dup}")
else:
print(" (dry-run: not deleted)")
actions.append(f"would delete {duplicates}")
else:
print(" -> WARNING: earliest sutartiesid not found in Rivile.")
if args.delete_rivile:
if rivile_clients:
keep_code = rivile_clients[0]
print(
f" -> Renaming Rivile client {keep_code} -> {target_code}"
)
_update_rivile_client_code(api_key, keep_code, target_code)
actions.append(f"rename {keep_code} -> {target_code}")
duplicates = [c for c in rivile_clients if c != keep_code]
if duplicates:
print(
f" -> Deleting remaining duplicates: {duplicates}"
)
for dup in duplicates:
_delete_rivile_client(api_key, dup)
print(f" Deleted Rivile client {dup}")
actions.append(f"delete {dup}")
else:
print(" -> Cannot update: no Rivile client to rename.")
actions.append("no rivile client to rename")
elif rivile_clients:
print(
" -> (dry-run) Would rename one client to earliest and delete the rest."
)
actions.append("would rename one client to earliest and delete the rest")
if current_code == target_code:
print(f" -> PG klientas.kodas already matches earliest sutartiesid.")
else:
print(f" -> Needs update: {current_code} -> {target_code}")
actions.append(f"pg differs {current_code}->{target_code} (no pg write)")
if not actions:
actions = ["no changes"]
print(f" -> Actions: {', '.join(actions)}")
print(f"Processed klientasid with multiple contracts: {processed}")
finally:
mssql_conn.close()
print(f"Processed klientasid with multiple contracts: {processed}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,18 @@
SELECT
k.klientasid,
k.kodas,
k.vardas,
k.pavarde,
s.sutartisid,
s.sutartiesid,
s.data
FROM klientas k
JOIN sutartis s ON s.klientasid = k.klientasid
WHERE k.klientasid IN (
SELECT k2.klientasid
FROM klientas k2
JOIN sutartis s2 ON s2.klientasid = k2.klientasid
GROUP BY k2.klientasid
HAVING COUNT(*) > 1
)
ORDER BY k.klientasid;