fix(cafe24): 모바일 상세설명 '직접등록' 오적용·적용직후 읽기지연 수정
- PUT 시 mobile_description 필드를 더 이상 보내지 않는다. 그 필드를 보내는 순간 카페24가 모바일 상세설명 설정을 "직접 등록"으로 바꿔버림을 실물로 확인(separated_mobile_description 이 'T'가 됨). 대신 separated_mobile_description="F" 만 지정해 "PC 상세설명과 동일"을 강제하고, 카페24가 모바일 값을 PC 와 자동으로 맞추게 한다. 화면 적용(apply)과 예약 적용(worker) 양쪽 다 수정. - products.wait_for_description 추가 — 적용 직후 카페24 관리자 API 의 짧은 읽기 지연(쓰기 직후 몇 초간 이전 값을 돌려줌 — 쇼핑몰 화면에는 바로 반영됨)을 0.8초 간격 최대 3회 재확인으로 흡수. "쇼핑몰엔 반영됐는데 카페24 상품관리 화면만 적용 안 된 것처럼 보이는" 증상 완화. - CAFE24_SHOP_URL 예시를 www.miras.co.kr 로 갱신(.env.example) — 실제 값은 운영 서버 .env 에서 직접 설정해야 함(코드는 그대로 이 값을 읽어 다이렉트 주소를 만듦). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@@ -149,6 +150,34 @@ def fetch_descriptions(client: Cafe24Client, product_no: int) -> Descriptions:
|
||||
return descriptions_from_product(get_product(client, product_no))
|
||||
|
||||
|
||||
def wait_for_description(
|
||||
client: Cafe24Client,
|
||||
product_no: int,
|
||||
expected: str,
|
||||
*,
|
||||
attempts: int = 3,
|
||||
delay: float = 0.8,
|
||||
) -> bool:
|
||||
"""PUT 직후 카페24 관리자 API 가 새 값을 돌려줄 때까지 짧게 재확인한다.
|
||||
|
||||
실물에서 관찰된 지연: PUT 이 성공하고 쇼핑몰 화면(고객이 보는 상세페이지)에는
|
||||
바로 반영되는데도, 관리자 API(`GET /admin/products/{no}`)는 몇 초간 직전 값을
|
||||
돌려줄 때가 있다. 그 상태에서 다른 상품을 봤다가 다시 돌아오면 우리 편집기가
|
||||
"적용 안 된 것"처럼 보인다 — 우리 쪽 캐시 문제가 아니라 카페24 쪽 읽기 지연이다.
|
||||
적용 직후 여기서 짧게 흡수해, 화면에 돌아왔을 때는 이미 새 값이 보이게 한다.
|
||||
실패해도 PUT 자체는 이미 성공했으므로 예외를 던지지 않는다.
|
||||
"""
|
||||
for _ in range(max(1, attempts)):
|
||||
time.sleep(delay)
|
||||
try:
|
||||
current = fetch_descriptions(client, product_no)
|
||||
except Exception: # noqa: BLE001 — 확인 실패는 무시(적용 자체는 이미 성공)
|
||||
return False
|
||||
if current.description == expected:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _flag_value(flag: bool) -> str:
|
||||
"""카페24는 boolean 을 'T'/'F' 문자열로 받는다."""
|
||||
return "T" if flag else "F"
|
||||
@@ -158,6 +187,7 @@ def build_update_payload(
|
||||
*,
|
||||
description: str | None = None,
|
||||
mobile_description: str | None = None,
|
||||
separated_mobile_description: str | None = None,
|
||||
product_name: str | None = None,
|
||||
display: bool | None = None,
|
||||
selling: bool | None = None,
|
||||
@@ -168,6 +198,11 @@ def build_update_payload(
|
||||
`None` 인 항목은 payload 에 넣지 않는다 = 그 필드를 건드리지 않는다.
|
||||
예약에서 "진열만 켜기"처럼 상세설명 없이 상태만 바꾸는 경우가 있으므로
|
||||
description 도 생략할 수 있다.
|
||||
|
||||
⚠️ `mobile_description` 을 명시적으로 보내면 카페24가 `separated_mobile_description`
|
||||
을 'T'(관리자 화면 "직접 등록")로 바꿔버린다(실물 확인). "PC 상세설명과 동일"을
|
||||
유지하려면 `mobile_description` 은 보내지 말고 `separated_mobile_description="F"`
|
||||
만 지정할 것 — `update_descriptions` 가 이 방식을 쓴다.
|
||||
"""
|
||||
request: dict[str, Any] = {}
|
||||
if description is not None:
|
||||
@@ -176,6 +211,8 @@ def build_update_payload(
|
||||
request["product_name"] = product_name
|
||||
if mobile_description is not None:
|
||||
request["mobile_description"] = mobile_description
|
||||
if separated_mobile_description is not None:
|
||||
request["separated_mobile_description"] = separated_mobile_description
|
||||
if display is not None:
|
||||
request["display"] = _flag_value(display)
|
||||
if selling is not None:
|
||||
@@ -192,6 +229,7 @@ def update_product(
|
||||
*,
|
||||
description: str | None = None,
|
||||
mobile_description: str | None = None,
|
||||
separated_mobile_description: str | None = None,
|
||||
product_name: str | None = None,
|
||||
display: bool | None = None,
|
||||
selling: bool | None = None,
|
||||
@@ -207,6 +245,7 @@ def update_product(
|
||||
payload = build_update_payload(
|
||||
description=description,
|
||||
mobile_description=mobile_description,
|
||||
separated_mobile_description=separated_mobile_description,
|
||||
product_name=product_name,
|
||||
display=display,
|
||||
selling=selling,
|
||||
@@ -225,15 +264,21 @@ def update_descriptions(
|
||||
product_no: int,
|
||||
*,
|
||||
description: str,
|
||||
mobile_description: str | None = None,
|
||||
shop_no: int | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""상세설명만 교체하는 지름길. 실제 전송은 `update_product` 가 한다."""
|
||||
"""상세설명 교체 + "PC 상세설명과 동일" 강제.
|
||||
|
||||
`mobile_description` 필드는 보내지 않는다 — 보내는 순간 카페24 관리자
|
||||
화면의 모바일 상세설명 설정이 "직접 등록"으로 바뀌어버리기 때문이다(실물
|
||||
확인). 대신 `separated_mobile_description="F"` 만 지정하면 카페24가 모바일
|
||||
값을 PC 와 자동으로 맞춰주면서 설정도 "PC 상세설명과 동일하게 사용"으로
|
||||
유지된다.
|
||||
"""
|
||||
return update_product(
|
||||
client,
|
||||
product_no,
|
||||
description=description,
|
||||
mobile_description=mobile_description,
|
||||
separated_mobile_description="F",
|
||||
shop_no=shop_no,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user