"""예약 요청 메일 — 발행본 폼이 보낸 것을 사장님에게 전달한다. ★ 저장하지 않는다. place_id 로 받는 사람만 찾고, 나머지는 전부 메일 본문으로 나간다. ★ 발행된 사이트의 업장만 받는다 — place_id 를 손으로 바꿔 아무 업장에나 메일을 쏘는 길을 막는다. """ from sqlalchemy import select from common.database.db_session_manager import DB_SESSION_MNG from common.database.model.models import places, sites, users from common.enums import DBWRType, SiteStatus from common.logger import LOG from services import mail_service NOT_AVAILABLE = "지금은 온라인 예약 요청을 받을 수 없습니다. 전화로 문의해 주세요." SENT = "예약 요청을 보냈습니다. 사장님이 확인 후 연락드립니다." class BookingRequestService: async def send(self, body): from router.v1.site.booking_request import ResBookingRequest target = await self._target(body.place_id) if not target: return ResBookingRequest(success=False, message=NOT_AVAILABLE) place_name, owner_email = target if not mail_service.is_configured() or not mail_service.is_valid_address(owner_email): LOG.w("[booking-request] 받는 주소나 SMTP 설정이 없어 전달하지 못했다") return ResBookingRequest(success=False, message=NOT_AVAILABLE) reply_to = body.email if body.email and mail_service.is_valid_address(body.email) else None ok = mail_service.send( to=owner_email, subject=f"[예약 요청] {place_name} — {body.name} 님", text=_body(place_name, body), reply_to=reply_to, ) if not ok: return ResBookingRequest(success=False, message=NOT_AVAILABLE) LOG.i(f"[booking-request] 전달 완료 place={body.place_id}") return ResBookingRequest(success=True, message=SENT) async def _target(self, place_id) -> tuple[str, str] | None: """(상호명, 사장님 이메일). 발행된 사이트가 없으면 None.""" def query(session): return session.execute( select(places.name, users.email) .join(sites, sites.place_id == places.place_id) .join(users, users.user_id == places.owner_user_id) .where( places.place_id == place_id, places.deleted == False, # noqa: E712 sites.deleted == False, # noqa: E712 sites.status == SiteStatus.PUBLISHED.value, ) ) result = await DB_SESSION_MNG.execute_lambda(places.DBType(), DBWRType.DB_READ.value, query) row = result.first() if result is not None else None if not row or not row[1]: return None return str(row[0] or ""), str(row[1]) def _body(place_name: str, body) -> str: lines = [ f"{place_name} 예약 요청이 도착했습니다.", "", f"성함 {body.name}", f"연락처 {body.phone}", ] if body.email: lines.append(f"이메일 {body.email}") if body.stay: lines.append(f"일정 {body.stay}") if body.guests: lines.append(f"인원 {body.guests}") if body.message: lines += ["", "요청사항", body.message.strip()] lines += [ "", "— 이 메일은 발행 사이트의 예약 요청 폼에서 자동으로 보냈습니다.", " 예약이 확정된 것은 아니며, 손님에게 직접 연락하셔야 합니다.", ] return "\n".join(lines)