feat(dispatch): 라벨 PDF에서 받는 사람(이름/전화/주소) 추출

xlsx 엔 받는 사람이 없거나(Shopee) 가려져(TikTok) 라벨 PDF 를 출처로 사용.
업로드 시 Order ID 로 박스와 조인해 채운다(하이브리드).

- pdf_parser.py 추가 (pdfplumber)
  · Shopee SPX 라벨: 2단 중 왼쪽 열만 읽어 Recipient 블록 추출(전화 미표시)
  · TikTok 라벨: 배송사별 양식 대응 — To <이름> (+60)…(Ninja), Receiver <이름>(NDD)
  · 주소 영역에 섞인 10자리+ 바코드 숫자 제거(우편번호 5자리 보존)
  · PDF 없거나 파싱 실패해도 업로드 진행(PII 만 빈 값)
- router: 라벨 PDF 파싱 결과를 parcels 에 머지 후 저장
- requirements: pdfplumber>=0.11 (Docker 재빌드 필요)
- new.html: PDF 가 받는 사람 출처임을 안내(권장)
- .gitignore: docs/samples/ (실제 고객 PII PDF — 커밋 금지)
- 문서 갱신

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 14:45:35 +09:00
parent 691eecee52
commit 106cf70922
6 changed files with 244 additions and 6 deletions
+10 -2
View File
@@ -154,8 +154,16 @@ python -m app.modules.dispatch.tests.test_grouping # 앱 의존성 설치 환
- 스택: FastAPI · PostgreSQL(psycopg3) · Jinja2 · 기존 ERP CSS(Bootstrap 미사용,
레포 공통 `erp.css` 재사용) · **openpyxl**(스펙의 pandas 대신, 레포 의존성 경량 유지).
- 코드: `app/modules/dispatch/` (`store.py` 순수 로직 / `parser.py` 엑셀 파싱 /
`export.py` 취합 출고 엑셀 생성 / `db.py` DB I/O / `router.py` 라우팅 /
`templates/dispatch/` 화면).
`pdf_parser.py` 라벨 PDF 받는사람 추출 / `export.py` 취합 출고 엑셀 생성 /
`db.py` DB I/O / `router.py` 라우팅 / `templates/dispatch/` 화면).
- 데이터 출처(하이브리드):
- **xlsx** = 박스/SKU/수량/주문/송장. TikTok 은 표준 컬럼, Shopee 는 SKU·수량이
`product_info` 한 셀에 묶여 있어 `store.parse_shopee_product_info` 로 분해.
- **라벨 PDF** = 받는 사람 이름/전화/주소. xlsx 엔 없거나 가려져 있어 PDF 가 출처.
업로드 시 Order ID 로 박스와 조인(`pdf_parser.extract_recipients`, pdfplumber).
TikTok 라벨은 배송사마다 양식이 달라 `To <이름> (+60)…`(Ninja)·`Receiver <이름>`
(NDD) 등을 모두 처리. Shopee SPX 라벨은 2단 중 왼쪽 열만 읽는다(전화 미표시).
PDF 가 없거나 파싱 실패해도 업로드는 진행(해당 PII 만 빈 값).
- 개인정보 보관: `dispatch_parcels.recipient_name/recipient_phone/recipient_address`.
기존 DB 에는 마이그레이션 `scripts/sql/dispatch_add_recipient_columns.sql` 로 컬럼을
추가한다(멱등). 접근/보관 기간 정책을 별도로 검토할 것.