# 전문의약품 사용량 조회 + 지오영 주문 시스템 > 작성일: 2026-03-06 > 상태: 1단계 완료 (재고 조회), 2단계 진행 예정 (자동 주문) --- ## 📋 개요 약국의 전문의약품(처방전 조제) 사용량을 기간별로 조회하고, 지오영 도매상에서 재고를 확인하여 주문까지 연결하는 시스템. ### 핵심 기능 1. **사용량 조회**: 기간별 전문의약품 사용량 집계 2. **현재고 표시**: PIT3000 재고 데이터 연동 3. **지오영 재고 조회**: 도매상 재고 실시간 확인 4. **규격별 표시**: 30T, 100T, 300T 등 다양한 규격 5. **주문 장바구니**: 선택 품목 장바구니 담기 --- ## 🗂️ 파일 구조 ``` pharmacy-pos-qr-system/backend/ ├── app.py # Flask 메인 (Blueprint 등록) ├── geoyoung_api.py # 지오영 API 모듈 ⭐ NEW └── templates/ ├── admin_rx_usage.html # 전문의약품 사용량 페이지 ⭐ NEW └── admin_usage.html # OTC 사용량 페이지 ⭐ NEW ``` --- ## 🔗 API 엔드포인트 ### 1. 전문의약품 사용량 조회 ``` GET /api/rx-usage?start_date=2026-03-01&end_date=2026-03-06&sort=qty_desc ``` **파라미터:** | 파라미터 | 설명 | 예시 | |---------|------|------| | start_date | 시작일 (YYYY-MM-DD) | 2026-03-01 | | end_date | 종료일 (YYYY-MM-DD) | 2026-03-06 | | search | 검색어 (약품명, 코드) | 레바미피드 | | sort | 정렬 (qty_desc, qty_asc, name_asc, amount_desc, rx_desc) | qty_desc | **응답:** ```json { "success": true, "items": [ { "drug_code": "670400830", "product_name": "휴니즈레바미피드정_(0.1g/1정)", "supplier": "(주)휴온스메디텍", "total_qty": 15, "total_dose": 980, "total_amount": 12500, "prescription_count": 45, "current_stock": 3809, "barcode": "", "thumbnail": null } ], "stats": { "period_days": 6, "product_count": 312, "total_qty": 1500, "total_dose": 15042, "total_amount": 321837881 } } ``` ### 2. 지오영 재고 조회 (보험코드) ``` GET /api/geoyoung/stock?kd_code=670400830 ``` **응답:** ```json { "success": true, "keyword": "670400830", "count": 2, "items": [ { "insurance_code": "670400830", "manufacturer": "휴온스메디텍", "product_name": "레바미피드정 300T 휴온스메디케어(구.휴니즈)", "specification": "300T", "stock": 0 }, { "insurance_code": "670400830", "manufacturer": "휴온스메디텍", "product_name": "레바미피드정 30T 휴온스메디케어(구.휴니즈)", "specification": "30T", "stock": 0 } ] } ``` ### 3. 지오영 재고 조회 (제품명 → 성분 추출) ``` GET /api/geoyoung/stock-by-name?product_name=휴니즈레바미피드정_(0.1g/1정) ``` 성분명 "레바미피드"를 추출하여 검색 → 여러 제약사 제품 반환 ### 4. 지오영 세션 상태 ``` GET /api/geoyoung/session-status ``` --- ## 🗄️ 데이터베이스 구조 ### MSSQL - PM_PRES (처방전) **PS_sub_pharm** - 처방 상세 | 컬럼 | 설명 | |------|------| | PreSerial | 처방전 일련번호 | | Indate | 조제일 (YYYYMMDD) | | DrugCode | 약품코드 | | QUAN | 수량 | | Days | 투약일수 | | DRUPRICE | 약가 | ### MSSQL - PM_DRUG (약품) **CD_GOODS** - 약품 마스터 | 컬럼 | 설명 | |------|------| | DrugCode | 약품코드 (PK) | | GoodsName | 약품명 | | SplName | 제조사명 | | BARCODE | 바코드 | **IM_total** - 현재고 ⭐ 중요 | 컬럼 | 설명 | |------|------| | DrugCode | 약품코드 | | **IM_QT_sale_debit** | **현재고 수량** | ### 현재고 조회 쿼리 ```sql SELECT P.DrugCode, G.GoodsName, ISNULL(IT.IM_QT_sale_debit, 0) as current_stock FROM PS_sub_pharm P LEFT JOIN PM_DRUG.dbo.CD_GOODS G ON P.DrugCode = G.DrugCode LEFT JOIN PM_DRUG.dbo.IM_total IT ON P.DrugCode = IT.DrugCode ``` --- ## 🏭 지오영 API 연동 ### 아키텍처 ``` [브라우저] → [Flask API] → [GeoyoungSession] → [지오영 웹] ↓ [Playwright 로그인] (최초 1회) ↓ [requests 검색] (이후 빠름) ``` ### 세션 관리 (geoyoung_api.py) ```python class GeoyoungSession: """싱글톤 패턴, 세션 30분 유지""" def login(self): # Playwright로 로그인 → 쿠키 획득 # requests 세션에 쿠키 복사 def search_stock(self, keyword): # requests로 빠른 검색 # POST /Home/PartialSearchProduct ``` ### 성능 | 요청 | 소요시간 | 비고 | |------|----------|------| | 첫 요청 (로그인) | ~12초 | Playwright 브라우저 | | 이후 요청 | **~2.5초** | requests 재사용 | | 세션 유효기간 | 30분 | 자동 재로그인 | ### 지오영 로그인 정보 ``` URL: https://gwn.geoweb.kr ID: 7390 PW: trajet6640 ``` --- ## 💻 UI 사용법 ### 페이지 접속 ``` http://localhost:7001/admin/rx-usage ``` ### 기능 1. **날짜 선택**: 시작일/종료일 지정 2. **검색**: 약품명, 코드로 필터 3. **정렬**: 투약량순, 처방건수순, 금액순 4. **지오영 조회**: 행 **더블클릭** → 모달 5. **장바구니**: 체크 후 "장바구니 추가" 6. **주문서**: "주문서 생성" → 클립보드 복사 ### 색상 의미 (현재고) - 🟢 초록: 재고 충분 (현재고 > 사용량) - 🟡 노랑: 재고 부족 (현재고 < 사용량) - 🔴 빨강: 재고 없음 (0) --- ## 🚀 향후 개발 계획 ### 2단계: 자동 주문 - [ ] 지오영 장바구니 담기 API - [ ] 주문 확정 API (dry_run 모드) - [ ] 주문 내역 SQLite 저장 ### 3단계: 다중 도매상 - [ ] 수인 API 연동 - [ ] 도매상 선택 UI - [ ] 재고 비교 (A사 vs B사) ### 4단계: 스마트 주문 - [ ] 사용량 기반 최적 규격 추천 - 예: 220개 필요 → "30T x 8개" vs "300T x 1개" - [ ] 분할 주문 (오전/오후) - [ ] 주문 누적 관리 ### 5단계: 주문 DB ```sql -- SQLite: orders.db CREATE TABLE orders ( id INTEGER PRIMARY KEY, order_date TEXT, wholesaler TEXT, -- 'geoyoung', 'sooin' drug_code TEXT, product_name TEXT, specification TEXT, -- '30T', '300T' quantity INTEGER, status TEXT, -- 'pending', 'ordered', 'delivered' created_at TEXT ); ``` --- ## 🔧 트러블슈팅 ### 문제: 지오영 로그인 실패 **원인**: requests만으로는 로그인 불가 (JavaScript 필요) **해결**: Playwright 하이브리드 방식 (로그인만 Playwright) ### 문제: 검색 결과 0개 **원인**: 보험코드가 아닌 내부 코드로 검색 **해결**: 보험코드(KD코드) 사용, 또는 성분명으로 재검색 ### 문제: 현재고가 0으로 표시 **원인**: IM_inventory 테이블이 비어있음 **해결**: `IM_total.IM_QT_sale_debit` 컬럼 사용 ### 문제: Flask 서버 시작 안됨 **원인**: stdout 인코딩 문제 (Start-Process 사용 시) **해결**: geoyoung_api.py에서 stdout 재설정 코드 제거 --- ## 📝 관련 파일 참조 ### 지오영 크롤러 원본 ``` c:\Users\청춘약국\source\person-lookup-web-local\crawler\ ├── gangwon_geoyoung_api.py # API 클라이언트 ├── gangwon_geoyoung_order.py # 주문 자동화 (order_by_kd_code) └── gangwon_geoyoung_crawler.py # 데이터 크롤링 ``` ### 주문 함수 사용 예시 ```python from gangwon_geoyoung_order import order_by_kd_code # 테스트 (실제 주문 안함) result = await order_by_kd_code("670400830", quantity=10, dry_run=True) # 실제 주문 result = await order_by_kd_code("670400830", quantity=10, dry_run=False) ``` --- ## ✅ 체크리스트 - [x] 전문의약품 사용량 조회 API - [x] 현재고 표시 (IM_total) - [x] 지오영 재고 조회 API - [x] 지오영 세션 관리 (속도 개선) - [x] UI 모달 (더블클릭) - [x] 장바구니 기능 - [ ] 지오영 실제 주문 연동 - [ ] 주문 내역 DB 저장 - [ ] 다중 도매상 지원