Обновить lk/test/lk_diagnostic.py

This commit is contained in:
2026-08-11 12:32:51 +07:00
parent a9a4926e3e
commit 7c2a3f1c4a
+169 -216
View File
@@ -1,292 +1,245 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Диагностика данных сотрудника для модуля ЛК (расчетnye listki).""" """Диагностика данных сотрудника для модуля ЛК (расчетные листки)."""
import calendar
import os import os
import sys import sys
# ============================================================
# 1. Загрузка .env и путей
# ============================================================
BASE_DIR = "/opt/trueconf_bot" BASE_DIR = "/opt/trueconf_bot"
os.chdir(BASE_DIR) if os.path.exists(BASE_DIR):
os.chdir(BASE_DIR)
else:
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# Загрузка .env
def load_env(filepath): def load_env(filepath):
with open(filepath, "r", encoding="utf-8") as f: try:
for line in f: with open(filepath, "r", encoding="utf-8") as f:
line = line.strip() for line in f:
if line and not line.startswith("#") and "=" in line: line = line.strip()
key, value = line.split("=", 1) if line and not line.startswith("#") and "=" in line:
value = value.strip(' "') key, value = line.split("=", 1)
value = value.strip("'") os.environ[key.strip()] = value.strip(' "\'\r\n')
value = value.strip() except FileNotFoundError:
os.environ[key.strip()] = value print(f"⚠️ Файл {filepath} не найден.")
load_env(os.path.join(BASE_DIR, "config", ".env")) load_env(os.path.join(BASE_DIR, "config", ".env"))
# Загрузка passwork # ============================================================
for pw_path in ["/opt/passwork", os.path.join(BASE_DIR, "passwork")]: # 2. Загрузка паролей из Passwork (AD и SQL)
# ============================================================
CREDENTIALS_MAP = {
"AD_PASSWORD": os.getenv("PW_ID_AD", "").strip(' "\'\r\n'),
"DB_PASSWORD": os.getenv("PW_ID_SQL", "").strip(' "\'\r\n'),
}
passwork_paths = [
"/opt/passwork",
os.path.join(BASE_DIR, "passwork"),
os.path.join(BASE_DIR, "config", "passwork"),
]
for pw_path in passwork_paths:
if os.path.isdir(pw_path) and pw_path not in sys.path: if os.path.isdir(pw_path) and pw_path not in sys.path:
sys.path.insert(0, pw_path) sys.path.insert(0, pw_path)
from passwork import get_passwork_secrets if BASE_DIR not in sys.path:
card_name = os.getenv("PW_ID_SQL", "").strip() sys.path.insert(0, BASE_DIR)
passwork_pool = get_passwork_secrets(required_cards=[card_name])
card_data = passwork_pool[card_name] AD_USER, AD_PASSWORD, DB_USER, DB_PASSWORD = "", "", "", ""
try:
from passwork import get_passwork_secrets
required_cards = [name for name in CREDENTIALS_MAP.values() if name]
passwork_pool = get_passwork_secrets(required_cards=required_cards)
ad_card_name = CREDENTIALS_MAP.get("AD_PASSWORD")
if ad_card_name and ad_card_name in passwork_pool:
card_ad = passwork_pool[ad_card_name]
AD_USER = card_ad.get("login", "").strip(' "\'\r\n')
AD_PASSWORD = card_ad.get("password", "").strip(' "\'\r\n')
sql_card_name = CREDENTIALS_MAP.get("DB_PASSWORD")
if sql_card_name and sql_card_name in passwork_pool:
card_sql = passwork_pool[sql_card_name]
DB_USER = card_sql.get("login", "").strip(' "\'\r\n')
DB_PASSWORD = card_sql.get("password", "").strip(' "\'\r\n')
except Exception as e:
print(f"⚠️ Ошибка загрузки из Passwork: {e}")
if not AD_USER: AD_USER = os.getenv("AD_USER", "")
if not AD_PASSWORD: AD_PASSWORD = os.getenv("AD_PASSWORD", "")
if not DB_USER: DB_USER = os.getenv("DB_USER", "")
if not DB_PASSWORD: DB_PASSWORD = os.getenv("DB_PASSWORD", "")
DB_USER = card_data["login"]
DB_PASSWORD = card_data["password"]
SQL_SERVER = os.getenv("SQL_SERVER", "SRVKEM-MOBILEIN.sibcem.ru") SQL_SERVER = os.getenv("SQL_SERVER", "SRVKEM-MOBILEIN.sibcem.ru")
SQL_DB_NAME = os.getenv("SQL_DB_NAME", "BossCopy") SQL_DB_NAME = os.getenv("SQL_DB_NAME", "BossCopy")
AD_SERVER = os.getenv("AD_SERVER", "172.16.20.20")
AD_BASE = os.getenv("AD_BASE", "DC=sibcem,DC=ru")
import pymssql
import ldap3 import ldap3
import pymssql
# --- Подключение к AD --- # ============================================================
print("=" * 60) # 3. Поиск сотрудника в Active Directory
print("Диагностика сотрудника: la.guseynova@sibcem.ru") # ============================================================
print("=" * 60)
email = "la.guseynova@sibcem.ru" email = "la.guseynova@sibcem.ru"
search_id = email.replace("@tcs.sibcem.ru", "@sibcem.ru") search_id = email.replace("@tcs.sibcem.ru", "@sibcem.ru")
short_name = search_id.split("@")[0] short_name = search_id.split("@")[0]
print(f"\n--- 0. Поиск в AD ---") print("=" * 60)
print(f" Email: {email}") print(f"Диагностика сотрудника: {email}")
print(f" Search ID: {search_id}") print("=" * 60)
print(f" Short: {short_name}")
AD_SERVER = "172.16.20.20" print("\n--- 0. Поиск в AD ---")
AD_BASE = "DC=sibcem,DC=ru" card_id_ad = None
try: try:
server = ldap3.Server(AD_SERVER, connect_timeout=5)
bind_user = AD_USER
if bind_user and "@" not in bind_user and "\\" not in bind_user:
bind_user = f"{bind_user}@sibcem.ru"
conn = ldap3.Connection( conn = ldap3.Connection(
ldap3.Server(AD_SERVER, connect_timeout=5), server,
user=bind_user,
password=AD_PASSWORD,
auto_bind=True, auto_bind=True,
read_only=True auto_referrals=False
) )
# Универсальный фильтр: mail, sAMAccountName, userPrincipalName, ANR attributes_list = ["cn", "sAMAccountName", "mail", "userPrincipalName", "proxyAddresses", "extensionAttribute2"]
# ANR — Approximate Name Resolution, ищет по любому атрибуту search_filter = f"(|(sAMAccountName={short_name})(mail={search_id})(userPrincipalName={search_id})(proxyAddresses=*:{search_id}*)(proxyAddresses=*{short_name}*)(anr={short_name}))"
search_filter = f"(|(mail={search_id}*)(sAMAccountName={search_id})(userPrincipalName={search_id}*)(anr={search_id}))"
print(f" LDAP-фильтр: {search_filter}")
conn.search( conn.search(
search_base=AD_BASE, search_base=AD_BASE,
search_filter=search_filter, search_filter=search_filter,
attributes=["cn", "sAMAccountName", "mail", "userPrincipalName", "extensionAttribute2", "mobile", "personalPager"] attributes=attributes_list
) )
if conn.entries: if conn.entries:
entry = conn.entries[0] entry = conn.entries[0]
cn = str(entry.cn) cn = str(entry.cn)
sam = str(entry.sAMAccountName) sam = str(entry.sAMAccountName) if 'sAMAccountName' in entry else ""
mail = str(entry.mail) if 'mail' in entry else "" mail_val = str(entry.mail) if 'mail' in entry else ""
upn = str(entry.userPrincipalName) if 'userPrincipalName' in entry else "" upn = str(entry.userPrincipalName) if 'userPrincipalName' in entry else ""
ext2 = str(entry.extensionAttribute2) if 'extensionAttribute2' in entry else "" card_id_ad = str(entry.extensionAttribute2) if 'extensionAttribute2' in entry else None
mobile = str(entry.mobile) if 'mobile' in entry else ""
pager = str(entry.personalPager) if 'personalPager' in entry else ""
print(" ✅ НАЙДЕН В AD!")
print(f" CN: {cn}") print(f" CN: {cn}")
print(f" sAMAccountName: {sam}") print(f" sAMAccountName: {sam}")
print(f" mail: {mail}") print(f" mail: {mail_val}")
print(f" UPN: {upn}") print(f" UPN: {upn}")
print(f" extensionAttribute2 (CARD_ID): {ext2}") print(f" extensionAttribute2 (CARD_ID из AD): {card_id_ad}")
print(f" mobile: {mobile}")
print(f" pager: {pager}")
else: else:
print(" Не найден по расширенному фильтру. Пробую ANR отдельно...") print(" ❌ НЕ НАЙДЕН в AD!")
conn.search(
search_base=AD_BASE,
search_filter=f"(anr={search_id})",
attributes=["cn", "sAMAccountName", "mail", "userPrincipalName", "extensionAttribute2", "mobile", "personalPager"]
)
if conn.entries:
entry = conn.entries[0]
cn = str(entry.cn)
sam = str(entry.sAMAccountName)
mail = str(entry.mail) if 'mail' in entry else ""
upn = str(entry.userPrincipalName) if 'userPrincipalName' in entry else ""
ext2 = str(entry.extensionAttribute2) if 'extensionAttribute2' in entry else ""
mobile = str(entry.mobile) if 'mobile' in entry else ""
pager = str(entry.personalPager) if 'personalPager' in entry else ""
print(f" CN: {cn}")
print(f" sAMAccountName: {sam}")
print(f" mail: {mail}")
print(f" UPN: {upn}")
print(f" extensionAttribute2 (CARD_ID): {ext2}")
print(f" mobile: {mobile}")
print(f" pager: {pager}")
else:
print(" НЕ НАЙДЕН в AD!")
conn.unbind()
sys.exit(0)
conn.unbind() conn.unbind()
except Exception as e: except Exception as e:
print(f" Ошибка подключения к AD: {e}") print(f" Ошибка обращения к AD: {e}")
sys.exit(0)
# --- Подключение к SQL --- # ============================================================
print(f"\n--- 1. Подключение к SQL ---") # 4. Подключение к SQL Server
# ============================================================
print("\n--- 1. Подключение к SQL Server ---")
try: try:
conn_sql = pymssql.connect( conn_sql = pymssql.connect(
server=SQL_SERVER, server=SQL_SERVER,
user=DB_USER, user=DB_USER,
password=DB_PASSWORD, password=DB_PASSWORD,
database=SQL_DB_NAME, database=SQL_DB_NAME,
charset="cp1251", charset='cp1251',
login_timeout=10 login_timeout=10
) )
cursor = conn_sql.cursor() cursor = conn_sql.cursor()
print(f" Подключено к {SQL_SERVER}/{SQL_DB_NAME}") print(" Подключено к SQL Server!")
except Exception as e: except Exception as e:
print(f" Ошибка подключения к SQL: {e}") print(f" Ошибка подключения к SQL: {e}")
sys.exit(0) sys.exit(1)
# Определяем card_id: через поиск в БД # ============================================================
card_id = None # 5. Определение CARD_ID
# ============================================================
# Пробуем найти CARD_ID через PR_CARD + PR_EMP card_id = card_id_ad
print(f"\n--- 2. Поиск CARD_ID в PR_CARD ---")
cursor.execute(
"SELECT c.ID FROM UOV_SELFSERVICE_PR_CARD c "
"JOIN UOV_SELFSERVICE_PR_EMP e ON e.CARD_ID = c.ID "
"WHERE e.EMAIL_ID LIKE %s OR e.USERNAME LIKE %s",
(f"%{short_name}%", f"%{short_name}%")
)
rows = cursor.fetchall()
if rows:
for r in rows:
print(f" CARD_ID (по username): {r[0]}")
card_id = rows[0][0]
else:
print(f" Не найден по username в PR_CARD/PR_EMP")
if not card_id: if not card_id:
cursor.execute( print("\n--- 2. Поиск CARD_ID по ФИО в PR_CARD ---")
"SELECT c.ID FROM UOV_SELFSERVICE_PR_CARD c " cursor.execute("SELECT c.ID, c.NAME FROM UOV_SELFSERVICE_PR_CARD c WHERE c.NAME LIKE %s", ("%Гусейнова%",))
"JOIN UOV_SELFSERVICE_PR_EMP e ON e.CARD_ID = c.ID "
"WHERE e.EMAIL_ID LIKE %s",
(f"%{search_id.split('@')[0]}%",)
)
rows = cursor.fetchall() rows = cursor.fetchall()
if rows: if rows:
for r in rows: card_id = str(rows[0][0])
print(f" CARD_ID (по email): {r[0]}") print(f" ✅ НАЙДЕН по ФИО: CARD_ID={card_id} ({rows[0][1]})")
card_id = rows[0][0]
else:
print(f" Не найден по email в PR_CARD/PR_EMP")
if not card_id: if not card_id:
print("\n CARD_ID не найден в БД!") print(" ❌ Не удалось определить CARD_ID!")
conn_sql.close() conn_sql.close()
sys.exit(0) sys.exit(1)
print(f"\n Используем CARD_ID: {card_id}") print(f"\n Используем CARD_ID: {card_id}")
# --- 3. PR_EMP --- # ============================================================
print(f"\n--- 3. PR_EMP (профиль сотрудника) ---") # 6. Проверка доступных периодов (get_latest_payslip_months)
cursor.execute( # ============================================================
"SELECT ID, FIRM_ID, EMAIL_ID, USERNAME FROM UOV_SELFSERVICE_PR_EMP WHERE CARD_ID = %s", print("\n--- 3. Расчетные периоды (SL_YTAX) ---")
(card_id,) q_months = """
) SELECT DISTINCT TOP 6 (t.TYEAR * 12 + t.TMONTH) as CMONTH, t.TYEAR, t.TMONTH
emp_rows = cursor.fetchall() FROM UOV_SELFSERVICE_PR_EMP e
if emp_rows: JOIN UOV_SELFSERVICE_PR_CARD c on c.ID = e.CARD_ID
for r in emp_rows: JOIN UOV_SELFSERVICE_SL_YTAX t on t.CARD_ID = e.CARD_ID
print(f" EMP_ID: {r[0]}, FIRM_ID: {r[1]}, EMAIL: {r[2]}, USERNAME: {r[3]}") JOIN UOV_SELFSERVICE_PR_TRANS tr on tr.EMP_ID = e.ID
JOIN UOV_SELFSERVICE_ST_APPOINT a on a.ID = tr.APPOINT_ID
JOIN UOV_SELFSERVICE_HR_FIRM f on f.ID = e.FIRM_ID
WHERE c.ID = %s
ORDER BY CMONTH DESC
"""
cursor.execute(q_months, (card_id,))
month_rows = cursor.fetchall()
if not month_rows:
print(" ❌ Отсутствуют расчетные периоды для данного CARD_ID!")
conn_sql.close()
sys.exit(1)
print(f" Найдено периодов: {len(month_rows)}")
for r in month_rows:
print(f" • CMONTH={r[0]} ({r[1]}-{r[2]:02d})")
target_cmonth = month_rows[0][0]
# ============================================================
# 7. Тест определения организации (q_firm) для периода
# ============================================================
print(f"\n--- 4. Определение FIRM_ID для CMONTH={target_cmonth} ---")
tyear = (target_cmonth - 1) // 12
tmonth = (target_cmonth - 1) % 12 + 1
_, last_day = calendar.monthrange(tyear, tmonth)
date_start = f"{tyear}-{tmonth:02d}-01"
date_end = f"{tyear}-{tmonth:02d}-{last_day:02d}"
date_params = (date_start, date_start, date_end, date_end, date_end)
q_firm = """
select e.FIRM_ID, f.SNAME from (select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e
join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s
group by e.ID, e.FIRM_ID ) as e
join UOV_SELFSERVICE_PR_TRANS t on t.EMP_ID = e.ID
join UOV_SELFSERVICE_HR_FIRM f on f.ID = e.FIRM_ID
where ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31'))
group by e.FIRM_ID, f.SNAME
"""
cursor.execute(q_firm, (card_id, *date_params))
firm_row = cursor.fetchone()
if firm_row:
print(f" ✅ q_firm УСПЕШНО определил FIRM_ID={firm_row[0]} ({firm_row[1]}) за {tyear}-{tmonth:02d}")
else: else:
print(" ПУСТО - нет записей в PR_EMP") print(f" ❌ q_firm НЕ СМОГ определить FIRM_ID за {tyear}-{tmonth:02d}!")
# --- 4. PR_TRANS ---
print(f"\n--- 4. PR_TRANS (кадровые назначения) ---")
if emp_rows:
emp_ids = [r[0] for r in emp_rows]
placeholders = ",".join(["%s"] * len(emp_ids))
cursor.execute(
f"SELECT EMP_ID, D_FROM, D_TO, TP_ABBR, SYSPAY_ID "
f"FROM UOV_SELFSERVICE_PR_TRANS "
f"WHERE EMP_ID IN ({placeholders}) "
f"ORDER BY D_FROM DESC",
emp_ids
)
trans_rows = cursor.fetchall()
if trans_rows:
print(f" Найдено записей: {len(trans_rows)}")
for r in trans_rows[:10]:
print(f" EMP_ID: {r[0]}, D_FROM: {r[1]}, D_TO: {r[2]}, TP: {r[3]}, SYSPAY: {r[4]}")
else:
print(" ПУСТО - нет записей в PR_TRANS")
else:
print(" Пропуск (нет PR_EMP)")
# --- 5. SL_YTAX ---
print(f"\n--- 5. SL_YTAX (периоды с данными) ---")
cursor.execute(
"SELECT DISTINCT TYEAR, TMONTH, CMONTH FROM UOV_SELFSERVICE_SL_YTAX "
"WHERE CARD_ID = %s ORDER BY CMONTH DESC",
(card_id,)
)
tax_rows = cursor.fetchall()
if tax_rows:
print(f" Найдено периодов: {len(tax_rows)}")
for r in tax_rows[:10]:
print(f" {r[0]}-{r[1]:02d} (CMONTH={r[2]})")
else:
print(" ПУСТО - нет периодов в SL_YTAX")
# --- 6. Проверка q_firm ---
print(f"\n--- 6. Проверка q_firm для последнего периода ---")
if tax_rows:
latest_cmonth = tax_rows[0][2]
tyear = (latest_cmonth - 1) // 12
tmonth = (latest_cmonth - 1) % 12 + 1
import calendar
_, last_day = calendar.monthrange(tyear, tmonth)
date_start = f"{tyear}-{tmonth:02d}-01"
date_end = f"{tyear}-{tmonth:02d}-{last_day:02d}"
date_params = (date_start, date_start, date_end, date_end, date_end)
print(f" Период: {tyear}-{tmonth:02d}")
q_firm = """
select e.FIRM_ID, f.SNAME from (select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e
join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s
group by e.ID, e.FIRM_ID ) as e
join UOV_SELFSERVICE_PR_TRANS t on t.EMP_ID = e.ID
join UOV_SELFSERVICE_HR_FIRM f on f.ID = e.FIRM_ID
where ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31'))
group by e.FIRM_ID, f.SNAME
"""
cursor.execute(q_firm, (card_id, *date_params))
firm_row = cursor.fetchone()
if firm_row:
print(f" q_firm НАШЁЛ: FIRM_ID={firm_row[0]}, SNAME={firm_row[1]}")
else:
print(f" q_firm НЕ НАШЁЛ (NULL) - это вызовет ошибку!")
q_firm_fb = """
select e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e
join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID
where c.ID = %s
group by e.ID, e.FIRM_ID
"""
cursor.execute(q_firm_fb, (card_id,))
fb_row = cursor.fetchone()
if fb_row:
print(f" Фоллбэк НАШЁЛ: FIRM_ID={fb_row[0]}")
else:
print(f" Фоллбэк НЕ НАШЁЛ - критическая ошибка!")
# --- 7. Сводка ---
print(f"\n--- 7. Сводка ---")
cursor.execute(
"SELECT COUNT(DISTINCT CMONTH), MIN(CMONTH), MAX(CMONTH) FROM UOV_SELFSERVICE_SL_YTAX WHERE CARD_ID = %s",
(card_id,)
)
summary = cursor.fetchone()
if summary:
print(f" Периодов в SL_YTAX: {summary[0]}")
print(f" Диапазон: {summary[1]} - {summary[2]}")
print(f"\n{'=' * 60}") print(f"\n{'=' * 60}")
print("Диагностика завершена") print("Диагностика завершена")
print("=" * 60) print("=" * 60)
conn_sql.close() conn_sql.close()