49f08f001d
P5-W2 원천세·부가세 분기신고 미커밋분 + P5-W3 메뉴/권한 보강(V74) + P5-W3 본론(V75~V78)을 일괄 정리. - V75 accounting_close / account_balance_snapshot (회계 결산) - V76 retention_anomaly_alert / forecast_kpi_monthly (이상치·예측 KPI) - V77 year_end_statement (연말 지급명세서) - V78 P5-W3 본론 메뉴 4 + 권한 + 공통코드 7그룹 + 테스트데이터 - api: AccountingClose/YearEndStatement/ForecastKpi/RetentionAnomaly Service+Controller - batch: BatchConfig Step 11/12 (원천세·부가세 분기) 연결 - frontend: 4화면(AccountingClose/YearEndStatement/RetentionAnomaly/ForecastKpi) + API 모듈 4 + 라우트 - frontend: usePermission/PermissionButton EXECUTE 권한 누락 보강 - fix: YearEndStatementMapper.xml 미존재 컬럼 a.agent_code 참조 제거 통합검증: Flyway V74~V78 운영DB 적용(v78), 4모듈 compileJava + 프론트 build PASS, 스모크 GET 8/8 + 쓰기 4/4 PASS, verify_v74.py 20/20 PASS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
"""
|
|
V74 적용 후 갭 재검증 스크립트 (DB 복귀 시 실행)
|
|
작성: 2026-05-17 (infra)
|
|
|
|
사용법:
|
|
python verify_v74.py
|
|
# DB UP 시 자동으로 V74 적용 결과 검증. 갭 0건이면 PASS.
|
|
# ga-api 재기동 후 Flyway V74 자동 적용(멱등) → 그 후 이 스크립트 실행.
|
|
"""
|
|
import psycopg2
|
|
|
|
conn = psycopg2.connect(
|
|
host="192.168.0.60",
|
|
port=55432,
|
|
dbname="trading_ai",
|
|
user="kyu",
|
|
password="7895123",
|
|
options="-c search_path=ga",
|
|
connect_timeout=8
|
|
)
|
|
cur = conn.cursor()
|
|
|
|
# 1. Flyway 버전 확인
|
|
cur.execute("SELECT version FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 1")
|
|
ver = cur.fetchone()[0]
|
|
print("[FLYWAY] Latest version: %s" % ver)
|
|
if ver != "74":
|
|
print(" WARNING: V74 not yet applied (current=%s). Run ga-api to apply." % ver)
|
|
|
|
# 2. 행 수 확인
|
|
for tbl in ["menu", "menu_permission", "role_menu_permission", "role"]:
|
|
cur.execute("SELECT COUNT(*) FROM %s" % tbl)
|
|
print("[COUNT] %s: %s" % (tbl, cur.fetchone()[0]))
|
|
|
|
# 3. V74 갭 보강 항목 검증
|
|
print("\n--- V74 보강 검증 ---")
|
|
checks = []
|
|
|
|
# (b) menu_permission 3건
|
|
for mc, pc in [("NOTICE", "DELETE"), ("SYSTEM_DATA_DICT", "DELETE"), ("TERM_SETTLE", "APPROVE")]:
|
|
cur.execute("""
|
|
SELECT COUNT(*) FROM menu_permission mp
|
|
JOIN menu m ON m.menu_id = mp.menu_id
|
|
WHERE m.menu_code = %s AND mp.perm_code = %s
|
|
""", (mc, pc))
|
|
cnt = cur.fetchone()[0]
|
|
status = "PASS" if cnt > 0 else "FAIL"
|
|
checks.append(status)
|
|
print(" [%s] menu_permission %s/%s: %s" % (status, mc, pc, cnt))
|
|
|
|
# (c) role_menu_permission 6건 (3 perm x 2 roles)
|
|
for role in ["SUPER_ADMIN", "ADMIN"]:
|
|
for mc, pc in [("NOTICE", "DELETE"), ("SYSTEM_DATA_DICT", "DELETE"), ("TERM_SETTLE", "APPROVE")]:
|
|
cur.execute("""
|
|
SELECT COUNT(*) FROM role_menu_permission rmp
|
|
JOIN role r ON r.role_id = rmp.role_id
|
|
JOIN menu m ON m.menu_id = rmp.menu_id
|
|
WHERE r.role_code = %s AND m.menu_code = %s AND rmp.perm_code = %s AND rmp.is_granted = 'Y'
|
|
""", (role, mc, pc))
|
|
cnt = cur.fetchone()[0]
|
|
status = "PASS" if cnt > 0 else "FAIL"
|
|
checks.append(status)
|
|
print(" [%s] grant %s/%s/%s: %s" % (status, role, mc, pc, cnt))
|
|
|
|
# (route) menu_path 11건
|
|
route_checks = [
|
|
("REINSTATE_COMM", "/commission/reinstatement"),
|
|
("PERSIST_BONUS", "/commission/persistency"),
|
|
("OVERRIDE_LEDGER", "/commission/override-ledger"),
|
|
("AGENT_CONTRACT", "/agent/contracts"),
|
|
("AGENT_LICENSE", "/agent/licenses"),
|
|
("AGENT_TRAINING", "/agent/trainings"),
|
|
("ENDORSE", "/contracts/endorsements"),
|
|
("COMPLAINT", "/contracts/complaints"),
|
|
("APPROVAL", "/system/approvals"),
|
|
("NOTICE", "/system/notices"),
|
|
("WITHDRAW", "/payments/withdraw"),
|
|
]
|
|
for mc, expected_path in route_checks:
|
|
cur.execute("SELECT menu_path FROM menu WHERE menu_code = %s", (mc,))
|
|
row = cur.fetchone()
|
|
actual = row[0] if row else "NOT_FOUND"
|
|
status = "PASS" if actual == expected_path else "FAIL"
|
|
checks.append(status)
|
|
print(" [%s] menu_path %s: %s (expected %s)" % (status, mc, actual, expected_path))
|
|
|
|
# Summary
|
|
total = len(checks)
|
|
passed = checks.count("PASS")
|
|
failed = checks.count("FAIL")
|
|
print("\n[RESULT] %d/%d PASS, %d FAIL" % (passed, total, failed))
|
|
if failed == 0:
|
|
print("[OVERALL] V74 검증 완료 - 모든 갭 해소 확인")
|
|
else:
|
|
print("[OVERALL] FAIL 항목 있음 - V74 재적용 또는 SQL 확인 필요")
|
|
|
|
conn.close()
|