Delete script draft - Klientas dalyvauja apskaitoje skolose
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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__":
|
||||||
|
|||||||
@@ -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.")
|
||||||
|
|
||||||
|
|||||||
238
uv_app/user/multiple_contract_user_cleanup.py
Normal file
238
uv_app/user/multiple_contract_user_cleanup.py
Normal 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()
|
||||||
18
uv_app/user/multiple_contract_user_cleanup.sql
Normal file
18
uv_app/user/multiple_contract_user_cleanup.sql
Normal 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;
|
||||||
Reference in New Issue
Block a user