feat(animal-chat): APC 코드 2024년 체계 지원 및 피부약 2단계 추천
## APC 코드 체계 확장 - 기존: 023%만 검색 (~2023년 제품만) - 변경: 02% OR 92% + 13자리 검증 - 02%: 2023년 이전 item_seq (9자리) 기반 APC - 92%: 2024년 이후 item_seq (10자리) 기반 APC - 999% 등 청구프로그램 임의코드는 제외 ## 동물약 챗봇 피부약 추천 개선 - 피부약 2단계 추천 구조 추가 - 1차(치료): 의약품 (개시딘겔, 테르비덤 등) - 2차(보조케어): 의약외품 (스킨카솔 - 회복기 피부보호) - 스킨카솔은 의약외품임을 명시하여 치료제로 오인 방지 ## 기타 - RAG 테스트 스크립트 추가 - 수인약품 API 문서화
This commit is contained in:
63
docs/RX_USAGE_ORDER_DETAIL_IMPL.md
Normal file
63
docs/RX_USAGE_ORDER_DETAIL_IMPL.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Rx-Usage 주문량 상세 (도매상별) 툴팁 기능
|
||||
|
||||
## 구현일: 2026-06-19
|
||||
|
||||
## 배경
|
||||
- `/admin/rx-usage` 페이지에서 주문량이 합계로만 표시됨
|
||||
- 사용자가 어떤 도매상에 얼마나 주문했는지 확인 필요
|
||||
|
||||
## 구현 내용
|
||||
|
||||
### 1. 데이터 구조 변경 (`loadOrderData` 함수)
|
||||
|
||||
**기존:**
|
||||
```javascript
|
||||
orderDataByKd[kd] = {
|
||||
product_name, spec, boxes, units,
|
||||
sources: ['지오영', '수인'] // 이름만 저장
|
||||
};
|
||||
```
|
||||
|
||||
**변경:**
|
||||
```javascript
|
||||
orderDataByKd[kd] = {
|
||||
product_name, spec, boxes, units,
|
||||
details: [
|
||||
{ vendor: 'geoyoung', name: '지오영', boxes: 10, units: 100 },
|
||||
{ vendor: 'sooin', name: '수인', boxes: 5, units: 50 }
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
### 2. 툴팁 CSS 추가
|
||||
|
||||
```css
|
||||
.order-qty-cell { position: relative; cursor: pointer; }
|
||||
.order-qty-tooltip { /* 툴팁 스타일 */ }
|
||||
.order-qty-vendor-dot.geoyoung { background: #06b6d4; }
|
||||
.order-qty-vendor-dot.sooin { background: #a855f7; }
|
||||
.order-qty-vendor-dot.baekje { background: #f59e0b; }
|
||||
.order-qty-vendor-dot.dongwon { background: #22c55e; }
|
||||
```
|
||||
|
||||
### 3. `getOrderedQty()` 함수 수정
|
||||
|
||||
- 단일 도매상: 단순 숫자 표시
|
||||
- 복수 도매상: hover 시 도매상별 상세 툴팁 표시
|
||||
|
||||
## 수정 파일
|
||||
- `backend/templates/admin_rx_usage.html`
|
||||
|
||||
## 동작
|
||||
1. 주문량 셀에 마우스 hover
|
||||
2. 2개 이상 도매상에서 주문한 경우 툴팁 표시
|
||||
3. 각 도매상별 수량과 합계 표시
|
||||
|
||||
## 확장 포인트
|
||||
- `vendorConfig` 객체에 새 도매상 추가 시 자동 지원
|
||||
- 도매상별 색상은 CSS의 `.order-qty-vendor-dot` 클래스로 관리
|
||||
|
||||
## 테스트
|
||||
- URL: http://localhost:7001/admin/rx-usage
|
||||
- 기간 조회 후 "주문량" 컬럼 확인
|
||||
- 여러 도매상 주문이 있는 품목에서 hover 시 툴팁 확인
|
||||
130
docs/SUIN_API_FIX.md
Normal file
130
docs/SUIN_API_FIX.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# 수인 API 주문 수량 파싱 문제 수정
|
||||
|
||||
**날짜**: 2026-03-09
|
||||
**문제**: 라미실크림 15g 주문 시 **1개 → 15개**로 잘못 표시
|
||||
**원인**: `parse_spec` 함수에서 용량 단위(g, ml)를 정량 단위(T, 정)로 착각
|
||||
|
||||
## 📋 문제 상황
|
||||
|
||||
| 도매상 | 제품 | 실제 주문 | 표시된 수량 |
|
||||
|--------|------|----------|------------|
|
||||
| 동원 | 라미실크림 15g | 1개 | **1개** ✅ |
|
||||
| 수인 | 라미실크림 15g | 1개 | **15개** ❌ |
|
||||
|
||||
## 🔍 원인 분석
|
||||
|
||||
### 문제 코드 위치
|
||||
- **파일**: `sooin_api.py` (Flask Blueprint)
|
||||
- **API**: `GET /api/sooin/orders/summary-by-kd`
|
||||
- **함수**: `parse_spec()`
|
||||
|
||||
### 기존 코드 (문제)
|
||||
```python
|
||||
def parse_spec(spec: str) -> int:
|
||||
if not spec:
|
||||
return 1
|
||||
match = re.search(r'(\d+)', spec)
|
||||
return int(match.group(1)) if match else 1
|
||||
```
|
||||
|
||||
**문제점**: 규격에서 **숫자만 추출**
|
||||
- `'30T'` → 30 (정제 30정) ✅
|
||||
- `'15g'` → 15 🚨 **문제!** (튜브 15그램인데 15개로 계산)
|
||||
|
||||
### 계산 과정
|
||||
```
|
||||
수인 라미실크림 15g 1박스 주문
|
||||
→ quantity = 1
|
||||
→ per_unit = parse_spec('15g') = 15
|
||||
→ total_units = 1 × 15 = 15개 ❌
|
||||
```
|
||||
|
||||
### 동원 API는 정상인 이유
|
||||
동원의 `parse_spec()` (wholesale/dongwon.py:1718-1720):
|
||||
```python
|
||||
# mg/ml 등의 용량 단위는 1로 처리
|
||||
if re.search(r'\d+\s*(mg|ml|g)\b', spec, re.IGNORECASE):
|
||||
return 1
|
||||
```
|
||||
|
||||
## ✅ 수정 내용
|
||||
|
||||
### 수정된 코드
|
||||
```python
|
||||
def parse_spec(spec: str) -> int:
|
||||
"""
|
||||
규격에서 박스당 단위 수 추출
|
||||
|
||||
정량 단위 (T, 정, 캡슐, C, PTP, 포 등): 숫자 추출
|
||||
용량 단위 (g, ml, mL, mg, L 등): 1 반환 (튜브/병 단위)
|
||||
|
||||
예시:
|
||||
- '30T' → 30 (정제 30정)
|
||||
- '100정(PTP)' → 100
|
||||
- '15g' → 1 (튜브 1개)
|
||||
- '10ml' → 1 (병 1개)
|
||||
- '500mg' → 1 (용량 표시)
|
||||
"""
|
||||
if not spec:
|
||||
return 1
|
||||
|
||||
spec_lower = spec.lower()
|
||||
|
||||
# 용량 단위 패턴: 숫자 + g/ml/mg/l (단독 또는 끝)
|
||||
# 이 경우 튜브/병 단위이므로 1 반환
|
||||
volume_pattern = r'^\d+\s*(g|ml|mg|l)(\s|$|\)|/)'
|
||||
if re.search(volume_pattern, spec_lower):
|
||||
return 1
|
||||
|
||||
# 정량 단위 패턴: 숫자 + T/정/캡슐/C/PTP/포
|
||||
qty_pattern = r'(\d+)\s*(t|정|캡슐?|c|ptp|포|tab|cap)'
|
||||
qty_match = re.search(qty_pattern, spec_lower)
|
||||
if qty_match:
|
||||
return int(qty_match.group(1))
|
||||
|
||||
# 기본: 숫자만 있으면 추출하되, 용량 단위 재확인
|
||||
# 끝에 g/ml이 있으면 1 반환
|
||||
if re.search(r'\d+(g|ml)$', spec_lower):
|
||||
return 1
|
||||
|
||||
# 그 외 숫자 추출
|
||||
match = re.search(r'(\d+)', spec)
|
||||
return int(match.group(1)) if match else 1
|
||||
```
|
||||
|
||||
### 수정 결과
|
||||
| 규격 | 기존 결과 | 수정 후 결과 |
|
||||
|------|----------|-------------|
|
||||
| `'30T'` | 30 | 30 ✅ |
|
||||
| `'100정(PTP)'` | 100 | 100 ✅ |
|
||||
| `'15g'` | 15 ❌ | **1** ✅ |
|
||||
| `'10ml'` | 10 ❌ | **1** ✅ |
|
||||
| `'500mg'` | 500 ❌ | **1** ✅ |
|
||||
|
||||
## 📁 관련 파일
|
||||
|
||||
| 파일 | 역할 |
|
||||
|------|------|
|
||||
| `backend/sooin_api.py` | Flask Blueprint (수정됨) |
|
||||
| `wholesale/sooin.py` | 수인약품 핵심 API 클래스 |
|
||||
| `wholesale/dongwon.py` | 동원약품 API (참고) |
|
||||
|
||||
## 🔄 적용 방법
|
||||
|
||||
```bash
|
||||
# Flask 서버 재시작
|
||||
pm2 restart flask-pharmacy
|
||||
```
|
||||
|
||||
## 🧪 테스트
|
||||
|
||||
```bash
|
||||
# 수인 주문 조회 API 테스트
|
||||
curl "http://localhost:7001/api/sooin/orders/summary-by-kd?start_date=2026-03-01&end_date=2026-03-09"
|
||||
```
|
||||
|
||||
## 📝 참고
|
||||
|
||||
- **도매상 API 문서**: `docs/WHOLESALE_API_INTEGRATION.md`
|
||||
- **수인 API 문서**: `docs/SOOIN_API.md`
|
||||
- **동원 API**: 이미 올바른 `parse_spec` 로직 적용됨
|
||||
Reference in New Issue
Block a user