- 제품 3단계분류.md: 성분→제품→로트 분류 체계, AI display_name 채우기 절차 - reset_operational_data.py: 마스터 보존 + 운영 데이터 초기화 - restore_backup.py: 백업 선택 복원 스크립트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
172 lines
5.3 KiB
Python
172 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
운영 데이터 초기화 스크립트
|
|
- 마스터 데이터는 보존
|
|
- 운영/거래 데이터만 삭제
|
|
- prescription_rules 중복 정리
|
|
|
|
실행: python3 scripts/reset_operational_data.py
|
|
"""
|
|
|
|
import sqlite3
|
|
import os
|
|
from datetime import datetime
|
|
|
|
DB_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'database', 'kdrug.db')
|
|
|
|
# ============================================================
|
|
# 보존할 마스터 테이블 (절대 건드리지 않음)
|
|
# ============================================================
|
|
MASTER_TABLES = [
|
|
'herb_masters', # 454 - 급여 한약재 성분코드 마스터
|
|
'herb_master_extended', # 454 - 약재 확장 정보 (성미귀경, 효능)
|
|
'herb_products', # 53,769 - 보험 제품 목록
|
|
'product_companies', # 128 - 제조/유통사
|
|
'official_formulas', # 100 - 100처방 원방 마스터
|
|
'official_formula_ingredients', # 68 - 100처방 구성 약재
|
|
'herb_efficacy_tags', # 18 - 효능 태그 정의
|
|
'herb_item_tags', # 22 - 약재-태그 매핑
|
|
'survey_templates', # 56 - 설문 템플릿
|
|
]
|
|
|
|
# ============================================================
|
|
# 삭제할 운영 데이터 테이블 (FK 순서 고려 — 자식 먼저)
|
|
# ============================================================
|
|
CLEAR_TABLES = [
|
|
# 조제/판매 하위
|
|
'compound_consumptions',
|
|
'compound_ingredients',
|
|
'sales_status_history',
|
|
'sales_transactions',
|
|
'mileage_transactions',
|
|
|
|
# 조제 마스터
|
|
'compounds',
|
|
|
|
# 재고 하위
|
|
'stock_ledger',
|
|
'stock_adjustment_details',
|
|
'stock_adjustments',
|
|
'lot_variants',
|
|
'inventory_lots',
|
|
'inventory_lots_v2',
|
|
|
|
# 입고 하위
|
|
'purchase_receipt_lines',
|
|
'purchase_receipts',
|
|
|
|
# 처방
|
|
'formula_ingredients',
|
|
'formula_ingredients_backup',
|
|
'formulas',
|
|
'price_policies',
|
|
|
|
# 환자/설문
|
|
'survey_responses',
|
|
'survey_progress',
|
|
'patient_surveys',
|
|
'patients',
|
|
|
|
# 도매상/약재
|
|
'supplier_product_catalog',
|
|
'suppliers',
|
|
'herb_items',
|
|
|
|
# 규칙/로그 (재정비)
|
|
'prescription_rules',
|
|
'data_update_logs',
|
|
'disease_herb_mapping',
|
|
'herb_research_papers',
|
|
'herb_safety_info',
|
|
]
|
|
|
|
|
|
def reset_db():
|
|
conn = sqlite3.connect(DB_PATH)
|
|
conn.execute("PRAGMA foreign_keys = OFF")
|
|
cursor = conn.cursor()
|
|
|
|
print(f"DB: {DB_PATH}")
|
|
print(f"시각: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
print()
|
|
|
|
# 1. 마스터 테이블 행 수 확인 (보존 확인)
|
|
print("=" * 50)
|
|
print("보존 대상 마스터 테이블")
|
|
print("=" * 50)
|
|
for table in MASTER_TABLES:
|
|
try:
|
|
cursor.execute(f"SELECT COUNT(*) FROM [{table}]")
|
|
cnt = cursor.fetchone()[0]
|
|
print(f" ✓ {table}: {cnt}행 (보존)")
|
|
except:
|
|
print(f" - {table}: 테이블 없음 (skip)")
|
|
|
|
# 2. 운영 테이블 삭제
|
|
print()
|
|
print("=" * 50)
|
|
print("초기화 대상 운영 테이블")
|
|
print("=" * 50)
|
|
for table in CLEAR_TABLES:
|
|
try:
|
|
cursor.execute(f"SELECT COUNT(*) FROM [{table}]")
|
|
before = cursor.fetchone()[0]
|
|
cursor.execute(f"DELETE FROM [{table}]")
|
|
# AUTOINCREMENT 리셋
|
|
cursor.execute(f"DELETE FROM sqlite_sequence WHERE name = ?", (table,))
|
|
print(f" ✗ {table}: {before}행 → 0행")
|
|
except Exception as e:
|
|
print(f" - {table}: {e}")
|
|
|
|
# 3. prescription_rules 중복 제거 후 재삽입
|
|
print()
|
|
print("=" * 50)
|
|
print("prescription_rules 정리 (중복 제거)")
|
|
print("=" * 50)
|
|
rules = [
|
|
(298, 438, '상수', '두 약재가 함께 사용되면 보기 효과가 증강됨 (인삼+황기)', 0, 0),
|
|
(73, 358, '상수', '혈액순환 개선 효과가 증강됨 (당귀+천궁)', 0, 0),
|
|
(123, 193, '상사', '생강이 반하의 독성을 감소시킴', 0, 0),
|
|
(7, 6, '상반', '십팔반(十八反) - 함께 사용 금기', 5, 1),
|
|
(298, 252, '상반', '십구외(十九畏) - 함께 사용 주의', 4, 0),
|
|
]
|
|
for r in rules:
|
|
cursor.execute("""
|
|
INSERT INTO prescription_rules (herb1_id, herb2_id, relationship_type, description, severity_level, is_absolute)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
""", r)
|
|
print(f" ✓ {len(rules)}개 규칙 재삽입 (중복 제거)")
|
|
|
|
conn.commit()
|
|
conn.execute("PRAGMA foreign_keys = ON")
|
|
|
|
# 4. VACUUM
|
|
conn.execute("VACUUM")
|
|
print()
|
|
print("✓ VACUUM 완료")
|
|
|
|
# 5. 최종 확인
|
|
print()
|
|
print("=" * 50)
|
|
print("최종 상태")
|
|
print("=" * 50)
|
|
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name")
|
|
for row in cursor.fetchall():
|
|
table = row[0]
|
|
cursor.execute(f"SELECT COUNT(*) FROM [{table}]")
|
|
cnt = cursor.fetchone()[0]
|
|
marker = "★" if cnt > 0 else " "
|
|
print(f" {marker} {table}: {cnt}행")
|
|
|
|
conn.close()
|
|
print()
|
|
print("초기화 완료!")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
confirm = input("운영 데이터를 모두 초기화합니다. 계속하시겠습니까? (yes/no): ")
|
|
if confirm.strip().lower() == 'yes':
|
|
reset_db()
|
|
else:
|
|
print("취소되었습니다.")
|