- official_formulas, official_formula_ingredients 테이블 스키마 추가 - 100처방 마스터데이터 등록 가이드 (Agent용 절차/규칙/코드 템플릿) - 한약국 첩제 vs OTC 상담 가이드 - 한약국 AI데이터 기본이해 문서 - 가미패독산 업셀링 칼럼, 입고장 수정기능 구현 문서 - CLAUDE.md에 참고 문서 경로 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
258 lines
12 KiB
SQL
258 lines
12 KiB
SQL
-- 한약 재고관리 시스템 데이터베이스 스키마
|
|
-- SQLite 기준
|
|
|
|
-- 1) 도매상/공급업체
|
|
CREATE TABLE IF NOT EXISTS suppliers (
|
|
supplier_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
business_no TEXT,
|
|
contact_person TEXT,
|
|
phone TEXT,
|
|
address TEXT,
|
|
is_active INTEGER DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 2) 약재 마스터 (보험코드 9자리 기준)
|
|
CREATE TABLE IF NOT EXISTS herb_items (
|
|
herb_item_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
insurance_code TEXT UNIQUE, -- 보험코드 (9자리)
|
|
herb_name TEXT NOT NULL, -- 약재명
|
|
specification TEXT, -- 규격/품질
|
|
default_unit TEXT DEFAULT 'g', -- 기본 단위
|
|
is_active INTEGER DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 3) 환자 정보
|
|
CREATE TABLE IF NOT EXISTS patients (
|
|
patient_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
phone TEXT NOT NULL,
|
|
jumin_no TEXT, -- 주민번호 (암호화 필요)
|
|
gender TEXT CHECK(gender IN ('M', 'F')),
|
|
birth_date DATE,
|
|
address TEXT,
|
|
notes TEXT,
|
|
is_active INTEGER DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(phone, name)
|
|
);
|
|
|
|
-- 4) 입고장 헤더
|
|
CREATE TABLE IF NOT EXISTS purchase_receipts (
|
|
receipt_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
supplier_id INTEGER NOT NULL,
|
|
receipt_date DATE NOT NULL,
|
|
receipt_no TEXT, -- 입고 번호/전표번호
|
|
vat_included INTEGER DEFAULT 1, -- 부가세 포함 여부
|
|
vat_rate REAL DEFAULT 0.10, -- 부가세율
|
|
total_amount REAL, -- 총 입고액
|
|
source_file TEXT, -- Excel 파일명
|
|
notes TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (supplier_id) REFERENCES suppliers(supplier_id)
|
|
);
|
|
|
|
-- 5) 입고장 상세 라인
|
|
CREATE TABLE IF NOT EXISTS purchase_receipt_lines (
|
|
line_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
receipt_id INTEGER NOT NULL,
|
|
herb_item_id INTEGER NOT NULL,
|
|
origin_country TEXT, -- 원산지
|
|
quantity_g REAL NOT NULL, -- 구입량(g)
|
|
unit_price_per_g REAL NOT NULL, -- g당 단가 (VAT 포함)
|
|
line_total REAL, -- 라인 총액
|
|
expiry_date DATE, -- 유효기간
|
|
lot_number TEXT, -- 로트번호
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (receipt_id) REFERENCES purchase_receipts(receipt_id),
|
|
FOREIGN KEY (herb_item_id) REFERENCES herb_items(herb_item_id)
|
|
);
|
|
|
|
-- 6) 재고 로트 (입고 라인별 재고 관리)
|
|
CREATE TABLE IF NOT EXISTS inventory_lots (
|
|
lot_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
herb_item_id INTEGER NOT NULL,
|
|
supplier_id INTEGER NOT NULL,
|
|
receipt_line_id INTEGER NOT NULL,
|
|
received_date DATE NOT NULL,
|
|
origin_country TEXT,
|
|
unit_price_per_g REAL NOT NULL,
|
|
quantity_received REAL NOT NULL, -- 입고 수량
|
|
quantity_onhand REAL NOT NULL, -- 현재 재고
|
|
expiry_date DATE,
|
|
lot_number TEXT,
|
|
is_depleted INTEGER DEFAULT 0, -- 소진 여부
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (herb_item_id) REFERENCES herb_items(herb_item_id),
|
|
FOREIGN KEY (supplier_id) REFERENCES suppliers(supplier_id),
|
|
FOREIGN KEY (receipt_line_id) REFERENCES purchase_receipt_lines(line_id)
|
|
);
|
|
|
|
-- 7) 재고 원장 (모든 재고 변동 기록)
|
|
CREATE TABLE IF NOT EXISTS stock_ledger (
|
|
ledger_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
event_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
event_type TEXT NOT NULL CHECK(event_type IN ('RECEIPT', 'CONSUME', 'ADJUST', 'DISCARD', 'RETURN')),
|
|
herb_item_id INTEGER NOT NULL,
|
|
lot_id INTEGER,
|
|
quantity_delta REAL NOT NULL, -- 증감량 (+입고, -사용)
|
|
unit_cost_per_g REAL,
|
|
reference_table TEXT, -- 참조 테이블 (compounds, adjustments 등)
|
|
reference_id INTEGER, -- 참조 ID
|
|
notes TEXT,
|
|
created_by TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (herb_item_id) REFERENCES herb_items(herb_item_id),
|
|
FOREIGN KEY (lot_id) REFERENCES inventory_lots(lot_id)
|
|
);
|
|
|
|
-- 8) 처방 마스터 (약속 처방)
|
|
-- 8-1) 100처방 원방 마스터
|
|
CREATE TABLE IF NOT EXISTS official_formulas (
|
|
official_formula_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
formula_number INTEGER NOT NULL UNIQUE, -- 연번 (1~100)
|
|
formula_name TEXT NOT NULL, -- 처방명 (예: 쌍화탕)
|
|
formula_name_hanja TEXT, -- 한자명 (예: 雙和湯)
|
|
source_text TEXT, -- 출전 (예: 화제국방)
|
|
description TEXT, -- 설명/효능
|
|
reference_notes TEXT, -- 상담참고자료 (OTC 대비 차별점, 구성 해설, 업셀링 포인트 등)
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 8-2) 100처방 원방 구성 약재 (성분코드 기반)
|
|
CREATE TABLE IF NOT EXISTS official_formula_ingredients (
|
|
ingredient_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
official_formula_id INTEGER NOT NULL,
|
|
ingredient_code TEXT NOT NULL, -- herb_masters.ingredient_code 기준
|
|
grams_per_cheop REAL NOT NULL, -- 1첩당 그램수
|
|
notes TEXT, -- 역할 (예: 군약, 신약, 좌약, 사약)
|
|
sort_order INTEGER DEFAULT 0,
|
|
FOREIGN KEY (official_formula_id) REFERENCES official_formulas(official_formula_id),
|
|
UNIQUE (official_formula_id, ingredient_code)
|
|
);
|
|
|
|
-- 8-3) 운영 처방 (조제에 사용)
|
|
CREATE TABLE IF NOT EXISTS formulas (
|
|
formula_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
formula_code TEXT UNIQUE, -- 처방 코드
|
|
formula_name TEXT NOT NULL, -- 처방명 (예: 쌍화탕)
|
|
formula_type TEXT DEFAULT 'CUSTOM', -- CUSTOM(약속처방), STANDARD 등
|
|
official_formula_id INTEGER, -- 100처방 마스터 참조 (원방 기반인 경우)
|
|
base_cheop INTEGER DEFAULT 20, -- 기본 첩수 (1제 기준)
|
|
base_pouches INTEGER DEFAULT 30, -- 기본 파우치수 (1제 기준)
|
|
description TEXT,
|
|
is_active INTEGER DEFAULT 1,
|
|
created_by TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (official_formula_id) REFERENCES official_formulas(official_formula_id)
|
|
);
|
|
|
|
-- 9) 처방 구성 약재
|
|
CREATE TABLE IF NOT EXISTS formula_ingredients (
|
|
ingredient_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
formula_id INTEGER NOT NULL,
|
|
herb_item_id INTEGER NOT NULL,
|
|
grams_per_cheop REAL NOT NULL, -- 1첩당 그램수
|
|
notes TEXT,
|
|
sort_order INTEGER DEFAULT 0,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (formula_id) REFERENCES formulas(formula_id),
|
|
FOREIGN KEY (herb_item_id) REFERENCES herb_items(herb_item_id),
|
|
UNIQUE (formula_id, herb_item_id)
|
|
);
|
|
|
|
-- 10) 조제 작업 (처방 실행)
|
|
CREATE TABLE IF NOT EXISTS compounds (
|
|
compound_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
patient_id INTEGER,
|
|
formula_id INTEGER,
|
|
compound_date DATE NOT NULL,
|
|
je_count REAL NOT NULL, -- 제수 (1제, 0.5제 등)
|
|
cheop_total REAL NOT NULL, -- 총 첩수
|
|
pouch_total REAL NOT NULL, -- 총 파우치수
|
|
cost_total REAL, -- 원가 총액
|
|
sell_price_total REAL, -- 판매 총액
|
|
prescription_no TEXT, -- 처방전 번호
|
|
status TEXT DEFAULT 'PREPARED', -- PREPARED, DISPENSED, CANCELLED
|
|
notes TEXT,
|
|
created_by TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
|
|
FOREIGN KEY (formula_id) REFERENCES formulas(formula_id)
|
|
);
|
|
|
|
-- 11) 조제 약재 구성 (실제 조제시 사용된 약재 - 가감 포함)
|
|
CREATE TABLE IF NOT EXISTS compound_ingredients (
|
|
compound_ingredient_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
compound_id INTEGER NOT NULL,
|
|
herb_item_id INTEGER NOT NULL,
|
|
grams_per_cheop REAL NOT NULL, -- 1첩당 그램수 (가감 반영)
|
|
total_grams REAL NOT NULL, -- 총 사용량
|
|
notes TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (compound_id) REFERENCES compounds(compound_id),
|
|
FOREIGN KEY (herb_item_id) REFERENCES herb_items(herb_item_id)
|
|
);
|
|
|
|
-- 12) 조제 소비 내역 (로트별 차감)
|
|
CREATE TABLE IF NOT EXISTS compound_consumptions (
|
|
consumption_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
compound_id INTEGER NOT NULL,
|
|
herb_item_id INTEGER NOT NULL,
|
|
lot_id INTEGER NOT NULL,
|
|
quantity_used REAL NOT NULL, -- 사용량(g)
|
|
unit_cost_per_g REAL NOT NULL, -- 단가
|
|
cost_amount REAL, -- 원가액
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (compound_id) REFERENCES compounds(compound_id),
|
|
FOREIGN KEY (herb_item_id) REFERENCES herb_items(herb_item_id),
|
|
FOREIGN KEY (lot_id) REFERENCES inventory_lots(lot_id)
|
|
);
|
|
|
|
-- 인덱스 생성
|
|
CREATE INDEX IF NOT EXISTS idx_herb_items_name ON herb_items(herb_name);
|
|
CREATE INDEX IF NOT EXISTS idx_herb_items_code ON herb_items(insurance_code);
|
|
CREATE INDEX IF NOT EXISTS idx_inventory_lots_herb ON inventory_lots(herb_item_id, is_depleted);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_ledger_herb ON stock_ledger(herb_item_id, event_time);
|
|
CREATE INDEX IF NOT EXISTS idx_compounds_patient ON compounds(patient_id);
|
|
CREATE INDEX IF NOT EXISTS idx_compounds_date ON compounds(compound_date);
|
|
CREATE INDEX IF NOT EXISTS idx_patients_phone ON patients(phone);
|
|
|
|
-- 뷰 생성 (자주 사용되는 조회)
|
|
-- 현재 재고 현황
|
|
CREATE VIEW IF NOT EXISTS v_current_stock AS
|
|
SELECT
|
|
h.herb_item_id,
|
|
h.insurance_code,
|
|
h.herb_name,
|
|
SUM(il.quantity_onhand) as total_quantity,
|
|
COUNT(DISTINCT il.lot_id) as lot_count,
|
|
AVG(il.unit_price_per_g) as avg_unit_price
|
|
FROM herb_items h
|
|
LEFT JOIN inventory_lots il ON h.herb_item_id = il.herb_item_id AND il.is_depleted = 0
|
|
GROUP BY h.herb_item_id, h.insurance_code, h.herb_name;
|
|
|
|
-- 처방별 구성 약재 뷰
|
|
CREATE VIEW IF NOT EXISTS v_formula_details AS
|
|
SELECT
|
|
f.formula_id,
|
|
f.formula_name,
|
|
f.formula_code,
|
|
h.herb_name,
|
|
fi.grams_per_cheop,
|
|
h.insurance_code
|
|
FROM formulas f
|
|
JOIN formula_ingredients fi ON f.formula_id = fi.formula_id
|
|
JOIN herb_items h ON fi.herb_item_id = h.herb_item_id
|
|
WHERE f.is_active = 1
|
|
ORDER BY f.formula_id, fi.sort_order; |