@@ -1,265 +1,245 @@
#!/usr/bin/env python3
""" Диагностика данных сотрудника для модуля ЛК (расчетnye listki ). """
""" Диагностика данных сотрудника для модуля ЛК (расчетные листки ). """
import calendar
import os
import sys
# ============================================================
# 1. Загрузка .env и путей
# ============================================================
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 ) :
with open ( filepath , " r " , encoding = " utf-8 " ) as f :
for line in f :
line = line . strip ( )
if line and not line . startswith ( " # " ) and " = " in line :
key , value = line . split ( " = " , 1 )
value = value . strip ( ' " ' )
value = value . strip ( " ' " )
value = value . strip ( )
os . environ [ key . strip ( ) ] = value
try :
with open ( filepath , " r " , encoding = " utf-8 " ) as f :
for line in f :
line = line . strip ( )
if line and not line . startswith ( " # " ) and " = " in line :
key , value = line . split ( " = " , 1 )
os . environ [ key . strip ( ) ] = value . strip ( ' " \' \r \n ' )
except FileNotFoundError :
print ( f " ⚠️ Файл { filepath } не найден. " )
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 :
sys . path . insert ( 0 , pw_path )
from passwork import get_passwork_secrets
card_name = os . getenv ( " PW_ID_SQL " , " " ) . strip ( )
passwork_pool = get_passwork_secrets ( required_cards = [ card_name ] )
card_data = passwork_pool [ card_name ]
if BASE_DIR not in sys . path :
sys . path . insert ( 0 , BASE_DIR )
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_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 calendar
# --- Подключение к AD ---
print ( " = " * 60 )
print ( " Диагностика сотрудника: la.guseynova@sibcem.ru " )
print ( " = " * 60 )
import pymssql
# ============================================================
# 3. Поиск сотрудника в Active Directory
# ============================================================
email = " la.guseynova@sibcem.ru "
search_id = email . replace ( " @tcs.sibcem.ru " , " @sibcem.ru " )
short_name = search_id . split ( " @ " ) [ 0 ]
print ( f " \n --- 0. Поиск в AD --- " )
print ( f " Email : { email } " )
print ( f " Search ID: { search_id } " )
print ( f " Short (без домена): { short_name } " )
print ( " = " * 60 )
print ( f " Диагностика сотрудника : { email } " )
print ( " = " * 60 )
AD_SERVER = " 172.16.20.20 "
AD_BASE = " DC=sibcem,DC=ru "
print ( " \n --- 0. Поиск в AD --- " )
card_id_ad = None
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 (
ldap3 . Server ( AD_SERVER , connect_timeout = 5 ) ,
server ,
user = bind_user ,
password = AD_PASSWORD ,
auto_bind = True ,
read_only = True
auto_referrals = False
)
search_filter = f " (|(mail= { search_id } *)(sAMAccountName= { short_name } )(userPrincipalName= { search_id } *)(anr= { short_name } )) "
print ( f " LDAP-фильтр: { search_filter } " )
attributes_list = [ " cn " , " sAMAccountName " , " mail " , " userPrincipalName " , " proxyAddresses " , " extensionAttribute2 " ]
search_filter = f " (|(sAMAccountName= { short_name } )(mail= { search_id } )(userPrincipalName= { search_id } )(proxyAddresses=*: { search_id } *)(proxyAddresses=* { short_name } *)(anr= { short_name } )) "
conn . search (
search_base = AD_BASE ,
search_filter = search_filter ,
attributes = [ " cn " , " sAMAccountName " , " mail " , " userPrincipalName " , " extensionAttribute2 " , " mobile " , " personalPager " ]
attributes = attributes_list
)
if conn . entries :
entry = conn . entries [ 0 ]
cn = str ( entry . cn )
sam = str ( entry . sAMAccountName )
mail = str ( entry . mail ) if ' mail ' in entry else " "
sam = str ( entry . sAMAccountName ) if ' sAMAccountName ' in entry else " "
mail_val = 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 " "
card_id_ad = str ( entry . extensionAttribute2 ) if ' extensionAttribute2 ' in entry else None
print ( f " \n НАЙДЕН: " )
print ( " ✅ НАЙДЕН В AD! " )
print ( f " CN: { cn } " )
print ( f " sAMAccountName: { sam } " )
print ( f " mail: { mail } " )
print ( f " mail: { mail_val } " )
print ( f " UPN: { upn } " )
print ( f " extensionAttribute2 (CARD_ID): { ext2 } " )
print ( f " mobile: { mobile } " )
print ( f " pager: { pager } " )
print ( f " extensionAttribute2 (CARD_ID из AD ): { card_id_ad } " )
else :
print ( " Не найден ! " )
conn . unbind ( )
sys . exit ( 0 )
print ( " ❌ НЕ НАЙДЕН в AD ! " )
conn . unbind ( )
except Exception as e :
print ( f " Ошибка подключ ения к AD: { e } " )
sys . exit ( 0 )
print ( f " ❌ Ошибка обращ ения к AD: { e } " )
# --- Подключение к SQL ---
print ( f " \n --- 1 . Подключение к SQL --- " )
# ============================================================
# 4 . Подключение к SQL Server
# ============================================================
print ( " \n --- 1. Подключение к SQL Server --- " )
try :
conn_sql = pymssql . connect (
server = SQL_SERVER ,
user = DB_USER ,
password = DB_PASSWORD ,
database = SQL_DB_NAME ,
charset = " cp1251 " ,
charset = ' cp1251 ' ,
login_timeout = 10
)
cursor = conn_sql . cursor ( )
print ( f " Подключено к { SQL_SERVER } / { SQL_DB_NAME } " )
print ( " ✅ Подключено к SQL Server! " )
except Exception as e :
print ( f " Ошибка подключения к SQL: { e } " )
sys . exit ( 0 )
print ( f " ❌ Ошибка подключения к SQL: { e } " )
sys . exit ( 1 )
# --- Получаем CARD_ID ---
card_id = None
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 " )
# ============================================================
# 5. Определение CARD_ID
# ============================================================
card_id = card_id_ad
if not card_id :
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 " ,
( f " % { search_id . split ( ' @ ' ) [ 0 ] } % " , )
)
print ( " \n --- 2. Поиск CARD_ID по ФИО в PR_CARD --- " )
cursor . execute ( " SELECT c.ID, c.NAME FROM UOV_SELFSERVICE_PR_CARD c WHERE c.NAME LIKE %s " , ( " % Гусейнова % " , ) )
rows = cursor . fetchall ( )
if rows :
for r in rows :
print ( f " CARD_ID (по email): { r [ 0 ] } " )
card_id = rows [ 0 ] [ 0 ]
else :
print ( f " CARD_ID не найден ! " )
conn_sql . close ( )
sys . exit ( 0 )
card_id = str ( rows [ 0 ] [ 0 ] )
print ( f " ✅ НАЙДЕН по ФИО: CARD_ID= { card_id } ( { rows [ 0 ] [ 1 ] } ) " )
if not card_id :
print ( " ❌ Не удалось определить CARD_ID ! " )
conn_sql . close ( )
sys . exit ( 1 )
print ( f " \n Используем CARD_ID: { card_id } " )
# --- PR_EMP ---
print ( f " \n --- 3. PR_EMP (профиль сотрудника) --- " )
cursor . execute (
" SELECT ID, FIRM_ID, EMAIL_ID, USERNAME FROM UOV_SELFSERVICE_PR_EMP WHERE CARD_ID = %s " ,
( card_id , )
)
emp_rows = cursor . fetchall ( )
if emp_rows :
for r in emp_rows :
print ( f " EMP_ID: { r [ 0 ] } , FIRM_ID: { r [ 1 ] } , EMAIL: { r [ 2 ] } , USERNAME: { r [ 3 ] } " )
# ============================================================
# 6. Проверка доступных периодов (get_latest_payslip_months)
# ============================================================
print ( " \n --- 3. Расчетные периоды (SL_YTAX) --- " )
q_months = """
SELECT DISTINCT TOP 6 (t.TYEAR * 12 + t.TMONTH) as CMONTH, t.TYEAR, t.TMONTH
FROM UOV_SELFSERVICE_PR_EMP e
JOIN UOV_SELFSERVICE_PR_CARD c on c.ID = e.CARD_ID
JOIN UOV_SELFSERVICE_SL_YTAX t on t.CARD_ID = e.CARD_ID
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 :
print ( " ПУСТО - нет записей в PR_EMP " )
# --- 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) " )
# --- 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 :
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 :
for tax_row in tax_rows :
tyear = tax_row [ 0 ]
tmonth = tax_row [ 1 ]
cmonth = tax_row [ 2 ]
_ , 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 " { tyear } - { tmonth : 02d } (CMONTH= { cmonth } ): ✅ FIRM_ID= { firm_row [ 0 ] } , SNAME= { firm_row [ 1 ] } " )
else :
print ( f " { tyear } - { tmonth : 02d } (CMONTH= { cmonth } ): ❌ q_firm НЕ НАШЁЛ FIRM_ID! " )
# Фоллбэк
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 " Фоллбэк НЕ НАШЁЛ - критическая ошибка! " )
else :
print ( " Нет периодов для проверки " )
# --- 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 " ❌ q_firm НЕ СМОГ определить FIRM_ID за { tyear } - { tmonth : 02d } ! " )
print ( f " \n { ' = ' * 60 } " )
print ( " Диагностика завершена " )
print ( " = " * 60 )
conn_sql . close ( )
conn_sql . close ( )