๋ฒ์ : 1.0
์์ฑ์ผ: 2026-03-06
์์ฑ์: ์ฉ๋ฆผ (with ์ฝ์ฌ๋)
์ํ: ๊ธฐํ ์๋ฃ, ๊ฐ๋ฐ ๋๊ธฐ
"์ฝ์ฌ๋์ด ์ฃผ๋ฌธ์ ์ ๊ฒฝ ์ฐ์ง ์์๋ ๋๋ ์ฝ๊ตญ"
AI๊ฐ ์ฌ์ฉ๋, ์ฌ๊ณ , ๋๋งค์ ์ํฉ, ๊ณผ๊ฑฐ ์ฃผ๋ฌธ ํจํด์ ํ์ตํ์ฌ:
- ์ธ์ ์ฃผ๋ฌธํ ์ง
- ์ด๋ ๋๋งค์์ ์ฃผ๋ฌธํ ์ง
- ์ด๋ค ๊ท๊ฒฉ์ผ๋ก ์ฃผ๋ฌธํ ์ง
- ์ผ๋ง๋ ์ฃผ๋ฌธํ ์ง
๋ชจ๋ ๊ฒ์ ์๋์ผ๋ก ๊ฒฐ์ ํ๊ณ ์คํํฉ๋๋ค.
| AS-IS | TO-BE |
|---|---|
| ๋งค์ผ ์ฌ๊ณ ํ์ธ | AI๊ฐ ์๋ ๋ชจ๋ํฐ๋ง |
| ์๋์ผ๋ก ๋๋งค์ ์ ํ | AI๊ฐ ์ต์ ๋๋งค์ ์ ํ |
| ๊ฒฝํ์ ์์กดํ ์ฃผ๋ฌธ๋ | ๋ฐ์ดํฐ ๊ธฐ๋ฐ ์ต์ ์ฃผ๋ฌธ๋ |
| ์ฃผ๋ฌธ ๋๋ฝ/์ง์ฐ ๋ฐ์ | ์ ์ ์ ์๋ ์ฃผ๋ฌธ |
| ๋ฐฐ์ก ๋ง๊ฐ ๋์นจ | ๋ง๊ฐ์๊ฐ ์๋ ์๋ฆผ |
"AI๋ ๋์ฒดํ๋ ๊ฒ์ด ์๋๋ผ, ์ฝ์ฌ๋์ ๋ฐฉ์์ ์๋ํํฉ๋๋ค."
| ๋๋งค์ | ์ฌ๊ณ ์กฐํ | ์ฅ๋ฐ๊ตฌ๋ | ์ฃผ๋ฌธ | ์ทจ์/๋ณต์ | ์๊ณ | ์๋งค์ถ |
|---|---|---|---|---|---|---|
| ์ง์ค์ | โ | โ | โ ํ์ ํฌํจ | โ | โ | โ |
| ์์ธ์ฝํ | โ | โ | โ | โ | โ | โ |
| ๋ฐฑ์ ์ฝํ | โ | โ | โ | โณ | โ | โ |
orders.db
โโโ wholesalers # ๋๋งค์ ๋ง์คํฐ
โโโ orders # ์ฃผ๋ฌธ ํค๋
โโโ order_items # ์ฃผ๋ฌธ ํ๋ชฉ
โโโ order_logs # ์ฃผ๋ฌธ ์ด๋ ฅ
โโโ order_context # AI ํ์ต์ฉ ์ปจํ
์คํธ โญ
โโโ daily_usage # ์ผ๋ณ ์ฌ์ฉ๋ ์๊ณ์ด
โโโ order_patterns # AI ๋ถ์ ๊ฒฐ๊ณผ
โโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโ
โ ๋๋งค์ โ ๋ฐฐ์ก โ ์ฃผ๋ฌธ ๋ง๊ฐ โ ๋์ฐฉ ์์ โ ๋น๊ณ โ
โโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ ์ง์ค์ โ ์ค์ โ 10:00 โ 11:30 โ ๋น์ผ โ
โ โ ์คํ โ 13:00 โ 15:00 โ ๋น์ผ โ
โโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ ์์ธ โ ์คํ โ 13:00 โ 14:30 โ ๋น์ผ โ
โโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ ๋ฐฑ์ โ ์ต์ผ โ 16:00 โ ๋ค์๋ 15:00 โ โ ๏ธ ์ต์ผ โ
โโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AI ์๋๋ฐ์ฃผ์์คํ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ ๋ฐ์ดํฐ ์์ง โ โ AI ๋ถ์ โ โ ์๋ ์คํ โ
โ โ โ โ โ โ
โ โข POS ํ๋งค โโโโโโโถโ โข ์ฌ์ฉ๋ ์์ธก โโโโโโโถโ โข ๋๋งค์ API โ
โ โข ์ฒ๋ฐฉ์ ์กฐ์ โ โ โข ์ฌ๊ณ ๋ถ์ โ โ โข ์ฃผ๋ฌธ ์คํ โ
โ โข ํ์ฌ ์ฌ๊ณ โ โ โข ์ฃผ๋ฌธ ์ถ์ฒ โ โ โข ๊ฒฐ๊ณผ ํผ๋๋ฐฑ โ
โ โข ๋๋งค์ ์ฌ๊ณ โ โ โข ํจํด ํ์ต โ โ โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโ
โ ํ์ต ๋ฃจํ โ
โ โ
โ ์ฃผ๋ฌธ ๊ฒฐ๊ณผ ํ๊ฐ โ
โ โ ๋ชจ๋ธ ์
๋ฐ์ดํธ โ
โ โ ์ ๋ต ์กฐ์ โ
โโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๋ฐ์ดํฐ ๋ ์ด์ด โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โ
โ โ PIT3000 โ โ SQLite โ โ ์ง์ค์ โ โ ์์ธ โ โ
โ โ (MSSQL) โ โ Orders DB โ โ API โ โ API โ โ
โ โโโโโโโฌโโโโโโโ โโโโโโโฌโโโโโโโ โโโโโโโฌโโโโโโโ โโโโโโโฌโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ์๋น์ค ๋ ์ด์ด โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ InventorySync โ โ UsageAnalyzer โ โ OrderExecutor โ โ
โ โ ์ฌ๊ณ ๋๊ธฐํ โ โ ์ฌ์ฉ๋ ๋ถ์ โ โ ์ฃผ๋ฌธ ์คํ โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ AIPredictor โ โ AIOptimizer โ โ AILearner โ โ
โ โ ์์ ์์ธก โ โ ๊ท๊ฒฉ/๋๋งค์ โ โ ํจํด ํ์ต โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ์ธํฐํ์ด์ค ๋ ์ด์ด โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ ์น ๋์๋ณด๋ โ โ ์๋ฆผ ์์คํ
โ โ ๊ด๋ฆฌ์ ์ฑ โ โ
โ โ ์ฌ๊ณ /์ฃผ๋ฌธ/AI โ โ ์นดํก/ํ
๋ ๊ทธ๋จ โ โ ์๋ ๊ฐ์
โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ ์ค์: ์ ๋ฌธ์์ฝํ(ETC)์ ๋ณดํ์ฝ๊ฐ ๊ณ ์ !
- 30T๋ 300T๋ 1T๋น ๊ฐ๊ฒฉ ๋์ผ
- ๋จ๊ฐ ํจ์จ์ OTC/๋น๊ธ์ฌ์์๋ง ์๋ฏธ ์์
ํ์ต ๋ฐ์ดํฐ:
- ์ฝํ๋ณ ๊ณผ๊ฑฐ ์ฃผ๋ฌธ ๊ท๊ฒฉ (30T, 100T, 300T, 500T)
- ๊ฐ ๊ท๊ฒฉ ์ ํ ์์ ์ ์ฌ๊ณ /์ฌ์ฉ๋
- ์ ํ ๊ฒฐ๊ณผ (๋จ์ ์ฌ๊ณ , ๋ค์ ์ฃผ๋ฌธ๊น์ง ๊ธฐ๊ฐ)
- ๋๋งค์๋ณ ๊ท๊ฒฉ ์ฌ๊ณ ํํฉ
ํ์ต ๋ชฉํ:
- ์ฌ์ฉ๋ ๋๋น ์ต์ ๊ท๊ฒฉ ์์ธก
- ์ฌ๊ณ ์๋ ๊ท๊ฒฉ ์ฐ์ ์ ํ
- ๋ญ๋น ์ต์ํ (์ ํต๊ธฐํ ๊ณ ๋ ค)
- ์๋ถ vs ๋์ฉ๋ ์ ํธ๋ ํ์
์์ ์๋๋ฆฌ์ค:
| ํ์๋ | ๊ฐ๋ฅ ๊ท๊ฒฉ | AI ์ ํ | ์ด์ |
|--------|-----------|---------|------|
| 280T | 30T(์ฌ๊ณ 50), 100T(ํ์ ), 300T(์ฌ๊ณ 10) | 30T x 10 | 100T ํ์ , ์๋ถ ์ ํธ |
| 800T | 30T(์ฌ๊ณ 100), 300T(์ฌ๊ณ 5) | 300T x 3 | ๋๋, ์ฌ๊ณ ์ถฉ๋ถ |
| 50T | 30T(์ฌ๊ณ 20), 100T(์ฌ๊ณ 10) | 30T x 2 | ์๋, ๋น ๋ฅธ ํ์ |
ํ์ต ๋ฐ์ดํฐ:
- ์ฃผ๋ฌธ ์์ ์ ์ฌ๊ณ ์์ค
- ์ฌ๊ณ ์์ง๊น์ง ๋จ์ ์ผ์
- ์ฃผ๋ฌธ ํ ์
๊ณ ๊น์ง ๋ฆฌ๋ํ์
- ํ์ ๋ฐ์ ์ด๋ ฅ
ํ์ต ๋ชฉํ:
- ์ฝ์ฌ๋์ ์ฌ๊ณ ์ ํธ๋ ํ์
- ํ์ดํธํ: ์ต์ ์ฌ๊ณ ์ ์ง (ํ๊ธ ํ๋ฆ ์ค์)
- ์ฌ์ ํ: ์์ ์ฌ๊ณ ํ๋ณด (ํ์ ๋ฐฉ์ง ์ค์)
์ฌ๊ณ ์ ๋ต ํ๋กํ์ผ:
class InventoryStrategy:
TIGHT = {
'safety_days': 2, # ์์ ์ฌ๊ณ 2์ผ์น
'reorder_point': 0.8, # 80% ์์ง ์ ์ฃผ๋ฌธ
'order_coverage': 7 # 7์ผ์น ์ฃผ๋ฌธ
}
MODERATE = {
'safety_days': 5,
'reorder_point': 0.6,
'order_coverage': 14
}
CONSERVATIVE = {
'safety_days': 10,
'reorder_point': 0.5,
'order_coverage': 30
}
ํ์ต ๋ฐ์ดํฐ:
- ๋๋งค์๋ณ ์ฃผ๋ฌธ ๋น๋
- ๋๋งค์๋ณ ์ฌ๊ณ ์ํฉ
- ๋๋งค์๋ณ ๋ฐฐ์ก ์ค์ผ์ค
- ์๋ณ ํ๋ ์ฌ์ฉ๋
- ๋ถํ ์ฃผ๋ฌธ ํจํด
ํ์ต ๋ชฉํ:
- ๊ธฐ๋ณธ ๋๋งค์ ์ ํธ๋
- ์ํฉ๋ณ ๋์ฒด ๋๋งค์
- ํ๋ ๊ณ ๋ คํ ๋ถ๋ฐฐ
- ๋ฐฐ์ก ์๊ฐ ๊ณ ๋ ค (๊ธด๊ธ ์)
๋๋งค์ ์ ํ ๋ก์ง:
def select_wholesaler(drug_code, quantity, need_by_time=None):
"""
AI๊ฐ ํ์ตํ ๋๋งค์ ์ ํ ๋ก์ง
์ฐ์ ์์:
1. ์ฌ๊ณ (์๋ ๊ณณ ์ฐ์ )
2. ๋ฐฐ์ก (need_by_time ์ถฉ์กฑ ๊ฐ๋ฅํ ๊ณณ)
3. ํ๋ (์ฌ์ ์๋ ๊ณณ)
4. ์ ํธ๋ (๊ณผ๊ฑฐ ํจํด)
"""
candidates = []
for ws in ['geoyoung', 'sooin', 'baekje']:
score = 0
# 1. ์ฌ๊ณ ์ฒดํฌ
if has_stock(ws, drug_code, quantity):
score += 100
else:
continue # ์ฌ๊ณ ์์ผ๋ฉด ์ ์ธ
# 2. ๋ฐฐ์ก ์๊ฐ ์ฒดํฌ
if need_by_time:
delivery = get_next_delivery(ws, need_by_time)
if delivery['can_deliver']:
score += 50
else:
score -= 30 # ๊ฐ์
# 3. ํ๋ ์ฒดํฌ
limit_usage = get_limit_usage(ws)
if limit_usage < 0.9:
score += 30
elif limit_usage >= 1.0:
score -= 50 # ํ๋ ์ด๊ณผ
# 4. ํ์ต๋ ์ ํธ๋
score += ai_model.preference_score(ws, drug_code) * 20
candidates.append((ws, score))
return max(candidates, key=lambda x: x[1])[0]
ํ์ต ๋ฐ์ดํฐ:
- ํ๋ฃจ ์ค ์ฃผ๋ฌธ ์์ (์ค์ /์คํ)
- ์์ผ๋ณ ์ฃผ๋ฌธ ํจํด
- ๋ฐฐ์ก ๋ง๊ฐ ์๊ฐ ์ ์ฃผ๋ฌธ ์ฌ๋ถ
ํ์ต ๋ชฉํ:
- ์ต์ ์ฃผ๋ฌธ ์์ ํ์
- ๋ฐฐ์ก ๋ง๊ฐ ๋์น์ง ์๊ธฐ
- ๋ถํ ์ฃผ๋ฌธ (์ค์ /์คํ) ํจํด
๋ชฉ์ : ๊ฐ์ ๋ ์ด๋ฏธ ์ฃผ๋ฌธํ ํ๋ชฉ ์๋ ์ฐจ๊ฐ
def calculate_order_qty(drug_code, usage_qty, current_stock):
# ์ค๋ "์ค์ ๋ก" ์ฃผ๋ฌธ ์๋ฃ๋ ์๋ ์กฐํ
today_ordered = get_today_orders(drug_code)
# ํ์๋ = ์ฌ์ฉ๋ - ํ์ฌ๊ณ - ์ ์ฃผ๋ฌธ๋
needed = usage_qty - current_stock - today_ordered
if needed > 0:
return calculate_spec_qty(needed)
return 0
โ ๏ธ ํต์ฌ: ์ค์ ์ฃผ๋ฌธ๋ง ์นด์ดํธ
SELECT SUM(oi.total_dose) as today_ordered
FROM order_items oi
JOIN orders o ON oi.order_id = o.id
WHERE oi.drug_code = ?
AND o.order_date = DATE('now')
AND o.is_dry_run = 0 -- dry_run ์ ์ธ!
AND oi.status IN ('success', 'submitted')
๋ชฉ์ : ์๋ณ ๊ฑฐ๋ ํ๋ ์ค์ ๋ฐ ์๋ ๋ถ๋ฐฐ
[ํ๋ ๋๋ฌ ์ ๋์]
1. 90% ๋๋ฌ โ ๊ฒฝ๊ณ ์๋ฆผ
2. 100% ๋๋ฌ โ ๋ค๋ฅธ ๋๋งค์์ผ๋ก ์๋ ์ ํ
3. ์ฅ๋ฐ๊ตฌ๋ ๋จ๊ณ์์ ๋ฏธ๋ฆฌ ๋ถ๋ฅ
๋ชฉ์ : ์ฃผ๋ฌธ ๋ง๊ฐ์๊ฐ + ๋ฐฐ์ก ๋์ฐฉ์๊ฐ ๋ถ๋ฆฌ ๊ด๋ฆฌ
AI ํ๋จ ์์:
ํ์ฌ ์ค์ 11์, "์คํ 3์์ ํ์"
โ ์ง์ค์ ์ค์ : 10์ ๋ง๊ฐ ์ง๋จ โ
โ ์ง์ค์ ์คํ: 13์ ๋ง๊ฐ โ 15:00 ๋์ฐฉ (โ ๏ธ ๋ฑ ๋ง์)
โ ์์ธ: 13์ ๋ง๊ฐ โ 14:30 ๋์ฐฉ (โ
์ฌ์ )
โ ๋ฐฑ์ : ๋ด์ผ ๋์ฐฉ โ
๊ฒฐ๋ก : ์์ธ ์ถ์ฒ (14:30 ๋์ฐฉ, 30๋ถ ์ฌ์ )
์๋๋ฆฌ์ค 1: ์ฌ๊ณ ์์
- A๋๋งค์ ์ฌ๊ณ 0 โ B๋๋งค์ ๊ฒ์ โ ์ฌ๊ณ ์์ผ๋ฉด B๋ก ์ฃผ๋ฌธ
์๋๋ฆฌ์ค 2: ์ฃผ๋ฌธ ์ค๋ฅ
- A๋๋งค์ API ์ค๋ฅ โ 3ํ ์ฌ์๋ โ ์คํจ ์ B๋๋งค์
์๋๋ฆฌ์ค 3: ๋ถ๋ถ ์ฑ๊ณต
- 10๊ฐ ํ๋ชฉ ์ค 7๊ฐ ์ฑ๊ณต, 3๊ฐ ์คํจ
- ์คํจํ 3๊ฐ โ B๋๋งค์์ผ๋ก ์๋ ์ฌ์๋
[๋ฆฌํฌํธ]
- ์ต์ข
์ฃผ๋ฌธ ๊ฒฐ๊ณผ ๋ฆฌํฌํธ
- ์๋ฆผ: "A๋๋งค์ ํ์ ๋ก B๋๋งค์์ผ๋ก ๋ณ๊ฒฝ๋จ"
-- ์ฃผ๋ฌธ ์ปจํ
์คํธ (AI ํ์ต์ฉ)
CREATE TABLE order_context (
id INTEGER PRIMARY KEY,
order_item_id INTEGER,
-- ์ฝํ ์ ๋ณด
drug_code TEXT,
product_name TEXT,
-- ์ฃผ๋ฌธ ์์ ์ํฉ
stock_at_order INTEGER,
usage_1d INTEGER,
usage_7d INTEGER,
usage_30d INTEGER,
avg_daily_usage REAL,
-- ์ฃผ๋ฌธ ๊ฒฐ์
ordered_spec TEXT,
ordered_qty INTEGER,
wholesaler_id TEXT,
-- ์ ํ์ง ์ ๋ณด (AI ํ์ต์ฉ)
available_specs JSON,
spec_stocks JSON,
selection_reason TEXT,
-- ์์ธก vs ์ค์
predicted_days_coverage REAL,
actual_days_to_reorder INTEGER,
-- ๊ฒฐ๊ณผ ํ๊ฐ
was_optimal BOOLEAN,
stockout_occurred BOOLEAN,
created_at TIMESTAMP
);
-- ๋๋งค์ ํ๋ ๊ด๋ฆฌ
CREATE TABLE wholesaler_limits (
id INTEGER PRIMARY KEY,
wholesaler_id TEXT NOT NULL,
monthly_limit INTEGER DEFAULT 0,
warning_threshold REAL DEFAULT 0.9,
priority INTEGER DEFAULT 1,
is_active INTEGER DEFAULT 1,
created_at TIMESTAMP,
FOREIGN KEY (wholesaler_id) REFERENCES wholesalers(id)
);
-- ๋ฐฐ์ก ์ค์ผ์ค
CREATE TABLE delivery_schedules (
id INTEGER PRIMARY KEY,
wholesaler_id TEXT NOT NULL,
delivery_seq INTEGER NOT NULL,
delivery_name TEXT,
order_cutoff_time TEXT NOT NULL, -- ์ฃผ๋ฌธ ๋ง๊ฐ (HH:MM)
delivery_days_offset INTEGER DEFAULT 0, -- 0=๋น์ผ, 1=์ต์ผ
delivery_arrival_time TEXT NOT NULL, -- ๋์ฐฉ ์์ (HH:MM)
weekdays TEXT, -- JSON [1,2,3,4,5]
is_active INTEGER DEFAULT 1,
UNIQUE(wholesaler_id, delivery_seq)
);
-- ์ค์ ๋ฐฐ์ก ์ค์ผ์ค ๋ฐ์ดํฐ
INSERT INTO delivery_schedules VALUES
('geoyoung', 1, '์ค์ ๋ฐฐ์ก', '10:00', 0, '11:30'),
('geoyoung', 2, '์คํ๋ฐฐ์ก', '13:00', 0, '15:00'),
('sooin', 1, '์คํ๋ฐฐ์ก', '13:00', 0, '14:30'),
('baekje', 1, '์ต์ผ๋ฐฐ์ก', '16:00', 1, '15:00');
-- ์๋ณ ์ฌ์ฉ๋ ์ถ์
CREATE TABLE wholesaler_monthly_usage (
id INTEGER PRIMARY KEY,
wholesaler_id TEXT NOT NULL,
year_month TEXT NOT NULL,
total_orders INTEGER DEFAULT 0,
total_amount INTEGER DEFAULT 0,
UNIQUE(wholesaler_id, year_month)
);
-- ์ฃผ๋ฌธ ์ฌ์๋ ๋ก๊ทธ
CREATE TABLE order_fallback_log (
id INTEGER PRIMARY KEY,
order_item_id INTEGER NOT NULL,
original_wholesaler TEXT NOT NULL,
original_error TEXT,
fallback_wholesaler TEXT NOT NULL,
fallback_result TEXT,
created_at TIMESTAMP
);
-- orders ํ
์ด๋ธ ํ์ฅ
ALTER TABLE orders ADD COLUMN is_dry_run INTEGER DEFAULT 0;
-- order_items ํ
์ด๋ธ ํ์ฅ
ALTER TABLE order_items ADD COLUMN fallback_from_wholesaler TEXT;
ALTER TABLE order_items ADD COLUMN prior_order_qty INTEGER DEFAULT 0;
| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ๊ธฐ๋ฅ |
|---|---|---|
/api/wholesaler/limits |
GET | ํ๋ ์กฐํ |
/api/wholesaler/limits/{id} |
PUT | ํ๋ ์ค์ |
/api/wholesaler/schedules |
GET | ๋ฐฐ์ก ์ค์ผ์ค |
/api/wholesaler/can-deliver-by |
POST | ๋ฐฐ์ก ๊ฐ๋ฅ ์ฌ๋ถ |
| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ๊ธฐ๋ฅ |
|---|---|---|
/api/order/today/{drug_code} |
GET | ์ค๋ ์ฃผ๋ฌธ๋ |
/api/order/recommend-spec |
POST | ๊ท๊ฒฉ ์ถ์ฒ |
/api/order/create |
POST | ์ฃผ๋ฌธ ์์ฑ |
/api/order/submit |
POST | ์ฃผ๋ฌธ ์ ์ถ (dry_run ์ง์) |
/api/order/retry |
POST | ์คํจ ์ฌ์๋ |
| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ๊ธฐ๋ฅ |
|---|---|---|
/api/ai/daily-analysis |
GET | ์ผ์ผ ๋ถ์ |
/api/ai/recommendations |
GET | ์ฃผ๋ฌธ ์ถ์ฒ |
/api/ai/training-data |
GET | ํ์ต ๋ฐ์ดํฐ |
/api/ai/patterns/{drug_code} |
GET | ํจํด ๋ถ์ |
def should_auto_execute(order_plan):
level = settings.automation_level
if level == 0:
return False
if level == 1:
return False # ํญ์ ์น์ธ ํ์
if level == 2:
conditions = [
order_plan['confidence'] > 0.9,
order_plan['estimated_cost'] < 100000,
order_plan['drug_code'] in trusted_drugs,
order_plan['urgency'] != 'critical'
]
return all(conditions)
if level == 3:
return not is_anomaly(order_plan)
| ์ ํ | ์กฐ๊ฑด | ์ฐ์ ์์ |
|---|---|---|
| ์น์ธ ์์ฒญ | ์๋ ์คํ ์ ๋๋ ์ฃผ๋ฌธ | ๋์ |
| ์ฃผ๋ฌธ ์๋ฃ | ์๋ ์ฃผ๋ฌธ ์คํ๋จ | ๋ณดํต |
| ํ๋ ๊ฒฝ๊ณ | 90% ๋๋ฌ | ๋์ |
| ํ์ ๊ธด๊ธ | ์ฌ๊ณ 0, ๋น์ผ ํ์ | ๊ธด๊ธ |
| ๋ฐฐ์ก ๋ง๊ฐ | ๋ง๊ฐ 30๋ถ ์ | ๋์ |
| ๋๋งค์ ๋ณ๊ฒฝ | ํ์ ๋ก ๋ค๋ฅธ ๋๋งค์ | ๋ณดํต |
๐ฆ ์ฃผ๋ฌธ ์น์ธ ์์ฒญ
์ฝํ: ์ฝฉ์ฝ๋ฅด์ 2.5mg
ํ์ฌ๊ณ : 45๊ฐ (3์ผ์น)
์ถ์ฒ ์ฃผ๋ฌธ: 300T x 2๋ฐ์ค
๋๋งค์: ์ง์ค์ (์ ์ฌ๋ฐฐ์ก 11:00 ๋ง๊ฐ)
์์ ๊ธ์ก: 72,000์
[์น์ธ] [์์ ] [๊ฑฐ์ ]
โ ๏ธ ๋ฐฐ์ก ๋ง๊ฐ ์๋ฆผ
์ง์ค์ ์คํ๋ฐฐ์ก ๋ง๊ฐ 30๋ถ ์ !
ํ์ฌ ์ฅ๋ฐ๊ตฌ๋: 5ํ๋ชฉ
13:00๊น์ง ์ฃผ๋ฌธํ์ง ์์ผ๋ฉด ๋ค์ ๋ฐฐ์ก์ ๋ด์ผ์
๋๋ค.
[์ง๊ธ ์ฃผ๋ฌธ] [๋์ค์]
| ์งํ | ํ์ฌ | ๋ชฉํ |
|---|---|---|
| ์ฃผ๋ฌธ ์์ ์๊ฐ | 30๋ถ/์ผ | 0๋ถ (์๋) |
| ํ์ ๋ฐ์๋ฅ | 5% | <1% |
| ์ฌ๊ณ ํ์ ์จ | - | +20% |
| ๋ฐฐ์ก ๋ง๊ฐ ๋์นจ | ๊ฐ๋ | 0ํ |
| ์ฃผ๋ฌธ ๋น์ฉ ์ ๊ฐ | - | 5-10% (OTC) |
docs/AI_ERP_AUTO_ORDER_SYSTEM.mddocs/์๋๋ฐ์ฃผ์์คํ
_๊ณ ๋ํ_๊ธฐํ์_v2.mddocs/GEOYOUNG_API_REVERSE_ENGINEERING.mddocs/RX_USAGE_GEOYOUNG_GUIDE.md๐ ์ฉ๋ฆผ: ์ด ๋ฌธ์๋ AI_ERP_AUTO_ORDER_SYSTEM.md(๋น์ /AI๋ชจ๋ธ)์
์๋๋ฐ์ฃผ์์คํ _๊ณ ๋ํ_๊ธฐํ์_v2.md(API/DB์์ธ)๋ฅผ ํตํฉํ ๋ง์คํฐ ๊ธฐํ์์ ๋๋ค.