feat(dispatch): 배송사 로고 파일 확장자 자동 감지(png 우선)

디스크에 있는 <슬러그>.png 또는 .svg 를 탐지해 URL 반환(png 우선),
없으면 텍스트 폴백. 새 로고는 파일 1개 + 키워드 1줄로 추가 가능.
lru_cache 로 페이지당 반복 stat 최소화.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 16:08:45 +09:00
parent a65ca65a8b
commit fd4ef9180c
+23 -12
View File
@@ -14,6 +14,8 @@
from __future__ import annotations from __future__ import annotations
from functools import lru_cache
from pathlib import Path
from typing import Any, Iterable from typing import Any, Iterable
# ── 작업 상태 필드(토글 대상) ── # ── 작업 상태 필드(토글 대상) ──
@@ -204,11 +206,11 @@ def normalize_quantity(value: Any) -> int:
# ── 배송사 로고 ── # ── 배송사 로고 ──
# 배송사명(부분 일치, 소문자) → 슬러그. 로고 SVG 가 있는 슬러그만 이미지 # 배송사명(부분 일치, 소문자) → 슬러그. 슬러그 이름의 이미지 파일이 실제
# 렌더하고, 없으면 텍스트 배지로 폴백한다. 새 배송사 로고 추가 절차: # 있으면 이미지로 렌더하고, 없으면 텍스트 배지로 폴백한다(깨진 이미지 방지).
# 1) app/static/dispatch/courier/<슬러그>.svg 추가 # 새 배송사 로고 추가: 파일 1개 + 키워드 1줄.
# 2) 아래 _COURIER_KEYWORDS 에 (키워드, 슬러그) 추가 # 1) app/static/dispatch/courier/<슬러그>.png (또는 .svg) 추가
# 3) _COURIER_LOGO_AVAILABLE 에 슬러그 추가 # 2) 아래 _COURIER_KEYWORDS 에 (배송사명키워드, 슬러그) 추가
_COURIER_KEYWORDS: tuple[tuple[str, str], ...] = ( _COURIER_KEYWORDS: tuple[tuple[str, str], ...] = (
("ninja", "ninjavan"), ("ninja", "ninjavan"),
("j&t", "jnt"), ("j&t", "jnt"),
@@ -223,8 +225,9 @@ _COURIER_KEYWORDS: tuple[tuple[str, str], ...] = (
("spx", "spx"), ("spx", "spx"),
) )
# 실제 SVG 파일이 있는 슬러그만(없는 건 텍스트 폴백 → 깨진 이미지 방지). # 로고 파일 디렉토리(app/static/dispatch/courier). png 를 svg 보다 우선한다.
_COURIER_LOGO_AVAILABLE: frozenset[str] = frozenset({"ninjavan", "jnt"}) _COURIER_DIR = Path(__file__).resolve().parents[2] / "static" / "dispatch" / "courier"
_COURIER_EXTS: tuple[str, ...] = (".png", ".svg")
def courier_slug(provider: Any) -> str: def courier_slug(provider: Any) -> str:
@@ -238,12 +241,20 @@ def courier_slug(provider: Any) -> str:
return "" return ""
def courier_logo_url(provider: Any) -> str: @lru_cache(maxsize=128)
"""배송사명 → 로고 SVG URL. SVG 없는 배송사는 ""(템플릿이 텍스트로 폴백).""" def _logo_url_for_slug(slug: str) -> str:
slug = courier_slug(provider) """슬러그에 해당하는 실제 로고 파일 URL(png 우선). 없으면 ""."""
if slug in _COURIER_LOGO_AVAILABLE: if not slug:
return f"/static/dispatch/courier/{slug}.svg"
return "" return ""
for ext in _COURIER_EXTS:
if (_COURIER_DIR / f"{slug}{ext}").exists():
return f"/static/dispatch/courier/{slug}{ext}"
return ""
def courier_logo_url(provider: Any) -> str:
"""배송사명 → 로고 이미지 URL. 파일 없으면 ""(템플릿이 텍스트로 폴백)."""
return _logo_url_for_slug(courier_slug(provider))
def sku_summary(parcels: list[dict[str, Any]]) -> list[dict[str, Any]]: def sku_summary(parcels: list[dict[str, Any]]) -> list[dict[str, Any]]: