"""템플릿 선택 저장.""" import uuid from sqlalchemy import text from common.enums import ErrorType, PlaceCategory, SiteStatus from common.template_catalog import INDUSTRIES from services.site_payload import to_site_payload async def _place(client, headers, name="템플릿펜션", category=1): r = await client.post("/v1/place", headers=headers, json={"name": name, "category": category}) return r.json()["place"]["place_id"] async def _set_template(client, headers, pid, template_id): return (await client.post(f"/v1/place/{pid}/site/template", headers=headers, json={"template_id": template_id})).json() async def _get_site(client, headers, pid): return (await client.get(f"/v1/place/{pid}/site", headers=headers)).json() async def test_set_template_creates_site_row(auth_headers, client): """검증: 사이트 행이 없어도 템플릿을 먼저 고를 수 있고, 조회에도 그대로 나온다.""" h = await auth_headers("tpl1") pid = await _place(client, h) saved = await _set_template(client, h, pid, "paper") assert saved["result"]["code"] == ErrorType.SUCCESS.value assert saved["site"]["template_id"] == "paper" assert (await _get_site(client, h, pid))["site"]["template_id"] == "paper" async def test_unknown_template_is_refused(auth_headers, client): """검증: 등록되지 않은 id는 거절한다.""" h = await auth_headers("tpl2") pid = await _place(client, h) refused = await _set_template(client, h, pid, "stay-retro") assert refused["result"]["code"] == ErrorType.INVALID_REQUEST_DATA.value assert "site" not in refused async def test_template_outside_industry_list_is_refused(auth_headers, client): """검증: 등록된 템플릿이라도 그 업종 허용 목록에 없으면 거절한다(병원은 레트로를 못 쓴다).""" h = await auth_headers("tpl3") pid = await _place(client, h, name="템플릿의원", category=PlaceCategory.CLINIC.value) refused = await _set_template(client, h, pid, "retro") assert refused["result"]["code"] == ErrorType.INVALID_REQUEST_DATA.value async def test_empty_value_clears_to_default(auth_headers, client): """검증: 빈 값은 '고르지 않음'이다 — NULL로 돌아가 업종 기본 템플릿으로 나간다.""" h = await auth_headers("tpl4") pid = await _place(client, h) await _set_template(client, h, pid, "paper") cleared = await _set_template(client, h, pid, "") assert cleared["result"]["code"] == ErrorType.SUCCESS.value assert "template_id" not in cleared["site"] async def test_published_site_template_is_not_locked(auth_headers, client, db_engine): """검증: 발행된 사이트도 템플릿을 바꿀 수 있고, 재빌드 표시가 선다.""" h = await auth_headers("tpl5") pid = await _place(client, h) await _set_template(client, h, pid, "simple") async with db_engine.begin() as conn: await conn.execute( text("UPDATE sites SET status = :st, published_at = now() WHERE place_id = :p"), {"st": SiteStatus.PUBLISHED.value, "p": uuid.UUID(pid)}, ) changed = await _set_template(client, h, pid, "paper") assert changed["result"]["code"] == ErrorType.SUCCESS.value assert changed["site"]["template_id"] == "paper" assert changed["needs_rebuild"] is True async def test_other_owners_place_is_blocked(auth_headers, client): """검증: 남의 사업장의 템플릿은 바꿀 수 없다(PLACE_NOT_FOUND).""" h = await auth_headers("tpl6") intruder = await auth_headers("tpl7") pid = await _place(client, h) blocked = await _set_template(client, intruder, pid, "paper") assert blocked["result"]["code"] == ErrorType.PLACE_NOT_FOUND.value def test_payload_uses_saved_template_and_falls_back(): """검증: payload의 templateId는 저장값, 없으면 업종 기본 템플릿이다.""" place = {"place_id": uuid.uuid4(), "category": PlaceCategory.LODGING.value, "name": "스테이,머뭄"} snapshot = {"place": {"name": "스테이,머뭄", "category": PlaceCategory.LODGING.value}} version = {"version": 1} chosen = to_site_payload(place, snapshot, {"template_id": "paper"}, version, []) assert chosen["theme"]["templateId"] == "paper" fallback = to_site_payload(place, snapshot, {"template_id": None}, version, []) assert fallback["theme"]["templateId"] == INDUSTRIES["stay"]["defaultTemplate"]