# 도매상 API 통합 가이드 > 작성일: 2026-03-06 > 버전: 1.0 ## 📦 패키지 구조 ``` pharmacy-wholesale-api/ # 별도 리포지토리 ├── wholesale/ │ ├── __init__.py # SooinSession, GeoYoungSession 노출 │ ├── base.py # WholesaleSession 공통 인터페이스 │ ├── sooin.py # 수인약품 API │ └── geoyoung.py # 지오영 API └── docs/ └── SOOIN.md # 수인약품 상세 문서 pharmacy-pos-qr-system/backend/ # 기존 프로젝트 ├── wholesale_path.py # 패키지 경로 설정 ├── sooin_api.py # Flask Blueprint (wholesale 사용) └── geoyoung_api.py # Flask Blueprint (wholesale 사용) ``` --- ## 🔌 도매상별 API 특성 | 항목 | 지오영 | 수인약품 | |------|--------|----------| | 웹사이트 | gwn.geoweb.kr | sooinpharm.co.kr | | 인증 방식 | Playwright → requests | Playwright → requests | | 세션 유효시간 | 30분 | 30분 | | 검색 코드 | 보험코드 (KD) | KD코드 + 내부코드 (pc) | | 장바구니 추가 | productCode 필요 | internal_code (pc) 필요 | | **개별 삭제** | ❌ 없음 | ✅ 체크박스 soft delete | | 장바구니 조회 | PartialProductCart | Bag.asp | --- ## 🔑 핵심 발견: 코드 체계 ### 지오영 ``` 보험코드 (KD코드) → 검색 → productCode (내부) → 장바구니 추가 ``` ### 수인약품 ``` KD코드 → 검색 → internal_code (pc) → 장바구니 추가 ↓ PhysicInfo.asp?pc=32495 에서 추출 ``` **⚠️ 중요:** `internal_code`가 없으면 장바구니 추가 불가! --- ## 🛒 수인약품 개별 취소 (Soft Delete) ### 발견 과정 - `kind=delOne` API 존재하지만 작동 안 함 - 체크박스가 실제 "취소" 역할 - `ControlBag.asp` AJAX 엔드포인트 발견 ### API 사용법 ```python from wholesale import SooinSession session = SooinSession() session.login() # 장바구니 조회 (체크 상태 포함) cart = session.get_cart() # cart['items'][0]['checked'] = False (활성) # cart['items'][0]['active'] = True # 항목 취소 (체크) session.cancel_item(row_index=0) # 또는 session.cancel_item(product_code="32495") # 취소 복원 (체크 해제) session.restore_item(row_index=0) ``` ### 내부 동작 ``` POST /Service/Order/ControlBag.asp Content-Type: application/x-www-form-urlencoded; charset=euc-kr X-Requested-With: XMLHttpRequest vc=50911 (거래처코드) pc=32495 (내부 제품코드) f=true (true=취소, false=복원) pg= (제품구분, 빈값) pdno= (제품번호, 빈값) tmdt= (기한, 빈값) ``` --- ## 📊 SQLite 스키마 연동 ### order_context (AI 학습용) ```sql -- 새로 추가된 필드 (2026-03-06) wholesaler_id TEXT, -- 'geoyoung' 또는 'sooin' wholesaler_price INTEGER, -- 도매상 가격 internal_code TEXT, -- 도매상 내부 코드 was_cancelled BOOLEAN, -- 취소 여부 (수인 soft delete) ``` ### 도매상별 주문 시 기록할 데이터 ```python order_context = { 'drug_code': 'D12345', 'product_name': '아세탑정', 'wholesaler_id': 'sooin', 'internal_code': '32495', # 수인 내부코드 'ordered_spec': '30T', 'ordered_qty': 2, 'wholesaler_price': 4800, 'available_specs': '["30T", "500T"]', 'spec_stocks': '{"30T": 0, "500T": 0}', # 재고 상황 'selection_reason': 'only_option', 'was_cancelled': False } ``` --- ## 🔄 Flask API 엔드포인트 ### 수인약품 (/api/sooin/*) | 메서드 | 경로 | 설명 | |--------|------|------| | GET | /stock | 재고 검색 | | GET | /cart | 장바구니 조회 | | POST | /order | 장바구니 추가 | | POST | /cart/clear | 장바구니 비우기 | | POST | /cart/cancel | **항목 취소 (soft delete)** | | POST | /cart/restore | **항목 복원** | | POST | /confirm | 주문 전송 | ### 지오영 (/api/geoyoung/*) | 메서드 | 경로 | 설명 | |--------|------|------| | GET | /stock | 재고 검색 | | GET | /cart | 장바구니 조회 | | POST | /order | 장바구니 추가 | | POST | /cart/clear | 장바구니 비우기 | | POST | /cart/cancel | **항목 삭제 (hard delete)** | | POST | /cart/restore | ❌ NOT_SUPPORTED | | POST | /confirm | 주문 전송 | ### 개별 삭제 API 차이 | 도매상 | cancel 동작 | restore 가능 | 내부 API | |--------|-------------|-------------|----------| | 수인 | 체크박스 soft delete | ✅ 가능 | ControlBag.asp | | 지오영 | 완전 삭제 | ❌ 불가 | DataCart/del | --- ## 📁 관련 문서 | 문서 | 위치 | 내용 | |------|------|------| | AI ERP 자동주문 기획 | `docs/AI_ERP_AUTO_ORDER_SYSTEM.md` | 전체 시스템 설계 | | 지오영 API 분석 | `docs/GEOYOUNG_API_REVERSE_ENGINEERING.md` | 지오영 리버스 엔지니어링 | | 수인 API 분석 | `pharmacy-wholesale-api/docs/SOOIN.md` | 수인 리버스 엔지니어링 | | 사용량 조회 가이드 | `docs/RX_USAGE_GEOYOUNG_GUIDE.md` | 처방 사용량 조회 | --- ## ✅ 체크리스트 ### 완료 - [x] 지오영 API 연동 - [x] 수인약품 API 연동 - [x] 개별 취소 기능 (수인) - soft delete - [x] 개별 삭제 기능 (지오영) - hard delete - [x] Flask Blueprint 통합 - [x] wholesale 패키지 분리 - [x] SQLite 스키마 업데이트 ### 진행 예정 - [ ] daily_usage 자동 수집 - [ ] AI 규격 선택 모델 - [ ] AI 도매상 선택 모델 - [ ] 자동 주문 Level 1 (승인 후 실행) --- *업데이트: 2026-03-06 by 용림 🐉*