# 수인약품 API 리버스 엔지니어링 문서

## 개요
수인약품 웹 주문 시스템의 API 구조를 분석한 문서입니다.
지오영 API와 같은 하이브리드 방식 (Playwright 로그인 → requests 직접 호출)으로 구현합니다.

## 기본 정보

- **Base URL**: `http://sooinpharm.co.kr`
- **인코딩**: EUC-KR (한글 파라미터 인코딩 시 주의)
- **거래처 코드**: `50911` (청춘약국)
- **세션 관리**: 쿠키 기반 (ASP 세션)

---

## 1. 로그인

### 로그인 페이지
- **URL**: `/Homepage/intro.asp`
- **Method**: POST (JavaScript 함수 `chkLogin()` 호출)

### 필드
| 필드명 | 설명 | 예시 |
|--------|------|------|
| tx_id | 아이디 | thug0bin |
| tx_pw | 비밀번호 | @Trajet6640 |

### 인증 쿠키
로그인 성공 시 ASP 세션 쿠키가 발급됨:
- `ASPSESSIONID*` (세션 ID)

### 로그인 성공 확인
- 로그인 후 페이지에 "로그아웃" 링크 존재 여부로 확인
- 로그인 후 자동으로 `/Service/Order/Order.asp`로 리다이렉트

---

## 2. 제품 검색 API

### URL
```
GET /Service/Order/Order.asp
```

### 파라미터
| 파라미터 | 필수 | 설명 | 값 예시 |
|----------|------|------|---------|
| so | N | 제품분류 | 0=전체, 1=전문, 2=일반 |
| so2 | N | 주문분류 | 0=전체, 1=다빈도, 2=관심, 3=재주문 |
| so3 | N | 검색타입 | **1=제품명, 2=KD코드, 3=표준코드** |
| tx_maker | N | 제조사 | 한독 |
| tx_physic | N | 검색어 | 073100220 (KD코드) |
| tx_ven | Y | 거래처코드 | 50911 |
| currVenNm | Y | 약국명 | 청춘약국 (URL인코딩) |
| sDate | N | 시작일 | 20260306 |
| eDate | N | 종료일 | 20260306 |
| sa | N | 정렬 | phy=제품명순, ven=제조사순 |
| Page | N | 페이지번호 | 1 |
| tx_StockLoc | N | 재고위치 | '00001' |
| df | N | 기간필터 | t=3개월 |

### KD코드 검색 예시 URL
```
/Service/Order/Order.asp?so=0&so2=0&so3=2&tx_physic=073100220&tx_ven=50911&currVenNm=%EC%B2%AD%EC%B6%98%EC%95%BD%EA%B5%AD&sDate=20260306&eDate=20260306&df=t
```

### 응답 (HTML)
HTML 테이블 형식으로 반환. BeautifulSoup로 파싱 필요.

#### 테이블 구조
```html
<tr class="ln_physic">
    <td>073100220</td>           <!-- KD코드 -->
    <td>한국오가논</td>           <!-- 제조사 -->
    <td>
        <a href="./PhysicInfo.asp?pc=32495&...">
            (오가논)코자정 50mg(PTP)
        </a>
    </td>                         <!-- 제품명 (pc=내부코드) -->
    <td>30T</td>                  <!-- 규격 -->
    <td>보험전문</td>              <!-- 구분 -->
    <td>14,220</td>               <!-- 단가 -->
    <td>238</td>                  <!-- 재고 -->
    <td>
        <input name="qty_0">      <!-- 수량입력 -->
        <input type="hidden" name="pc_0" value="32495">  <!-- 내부코드 -->
        <input type="hidden" name="stock_0" value="238">
        <input type="hidden" name="price_0" value="14220">
    </td>
</tr>
```

#### 핵심 필드 추출
- **KD코드**: 첫 번째 td
- **제조사**: 두 번째 td
- **제품명**: 세 번째 td의 a 태그 텍스트
- **내부코드(pc)**: a 태그 href에서 `pc=xxxxx` 추출
- **규격**: 네 번째 td
- **단가**: 여섯 번째 td (콤마 제거 후 int)
- **재고**: 일곱 번째 td

---

## 3. 장바구니 추가 API

### URL
```
POST /Service/Order/BagOrder.asp
```

### Content-Type
```
application/x-www-form-urlencoded
```

### 파라미터 (각 제품당)
| 파라미터 | 설명 | 예시 |
|----------|------|------|
| qty_N | 수량 | 1 |
| pc_N | 내부 제품코드 | 32495 |
| stock_N | 현재 재고 | 238 |
| saleqty_N | 판매수량 | 0 |
| price_N | 단가 | 14220 |
| soldout_N | 품절여부 | N |
| ordunitqty_N | 주문단위수량 | 1 |
| bidqty_N | 입찰수량 | 0 |
| outqty_N | 출고수량 | 0 |
| overqty_N | 초과수량 | 0 |
| manage_N | 관리여부 | N |
| prodno_N | 제품번호 | (빈값) |
| termdt_N | 종료일자 | (빈값) |

> N은 0부터 시작하는 행 인덱스

### 요청 예시
```
qty_0=1&pc_0=32495&stock_0=238&saleqty_0=0&price_0=14220&soldout_0=N&ordunitqty_0=1&bidqty_0=0&outqty_0=0&overqty_0=0&manage_0=N&prodno_0=&termdt_0=
```

### 응답
HTML (장바구니 iframe 내용)

---

## 4. 장바구니 비우기 API

### URL
```
GET /Service/Order/BagOrder.asp?kind=del&currVenCd=50911&currMkind=&currRealVenCd=
```

### 파라미터
| 파라미터 | 설명 | 값 |
|----------|------|-----|
| kind | 동작 | del |
| currVenCd | 거래처코드 | 50911 |
| currMkind | 종류 | (빈값) |
| currRealVenCd | 실제거래처코드 | (빈값) |

---

## 5. 장바구니 조회 API

### URL
```
GET /Service/Order/BagOrder.asp?currVenCd=50911
```

### 응답 (HTML)
```html
<table class="tbl_list">
    <tr>
        <td>건별취소</td>
        <td>제품명</td>
        <td>수량</td>
        <td>금액</td>
    </tr>
    <tr>
        <td><a href="...">X</a></td>
        <td>(오가논)코자정 50mg(PTP)</td>
        <td>1</td>
        <td>14,220</td>
    </tr>
</table>
<div>
    <dt>주문품목</dt><dd>1개</dd>
    <dt>주문금액</dt><dd>14,220원</dd>
</div>
```

---

## 6. 주문 전송 API

### URL (추정)
```
POST /Service/Order/BagOrder.asp
```

### 파라미터
| 파라미터 | 설명 |
|----------|------|
| kind | order (추정) |
| memo | 주문메모 |
| currVenCd | 거래처코드 |

> 실제 주문 전송은 iframe 내 버튼 클릭으로 수행됨
> 정확한 API 파라미터는 추가 분석 필요

---

## 7. 제품 상세 정보 API

### URL
```
GET /Service/Order/PhysicInfo.asp
```

### 파라미터
| 파라미터 | 설명 | 예시 |
|----------|------|------|
| pc | 내부제품코드 | 32495 |
| ln | 행번호 | 0 |
| currVenCd | 거래처코드 | 50911 |
| currLoc | 재고위치 | '00001' |

---

## 구현 전략

### 지오영 API 패턴 적용

1. **Playwright 로그인**
   - 초기 로그인만 Playwright 사용
   - 쿠키 획득 후 requests 세션에 복사
   - 세션 30분 유효 (재로그인 필요 시 자동 갱신)

2. **requests 직접 호출**
   - 검색: GET /Service/Order/Order.asp
   - 장바구니 추가: POST /Service/Order/BagOrder.asp
   - 장바구니 비우기: GET /Service/Order/BagOrder.asp?kind=del
   - 장바구니 조회: GET /Service/Order/BagOrder.asp

3. **HTML 파싱**
   - BeautifulSoup 사용
   - 테이블 행에서 제품 정보 추출
   - 내부코드(pc) 추출 (장바구니 추가용)

### 예상 성능
- 기존 Playwright: ~30초/주문
- requests 직접 호출: **~1초/주문**

---

## 주의사항

1. **EUC-KR 인코딩**
   - 한글 파라미터는 EUC-KR로 인코딩
   - `urllib.parse.quote(text.encode('euc-kr'))`

2. **세션 관리**
   - ASP 세션 쿠키 유지 필수
   - 장시간 미사용 시 세션 만료

3. **동시 접속**
   - 동일 계정 동시 접속 시 세션 충돌 가능

4. **재고 실시간성**
   - 검색 시점의 재고 정보
   - 주문 전 재고 재확인 권장

---

## 작성일
- 2026-03-06
- 리버스 엔지니어링 by Claude

