Coverage for polar/customer_seat/sender.py: 50%
16 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 17:15 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 17:15 +0000
1import structlog 1a
3from polar.config import settings 1a
4from polar.email.react import render_email_template 1a
5from polar.email.schemas import SeatInvitationEmail, SeatInvitationProps 1a
6from polar.email.sender import enqueue_email 1a
7from polar.logging import Logger 1a
8from polar.models import CustomerSeat, Organization 1a
10log: Logger = structlog.get_logger() 1a
13def send_seat_invitation_email( 1a
14 customer_email: str,
15 seat: CustomerSeat,
16 organization: Organization,
17 product_name: str,
18 billing_manager_email: str,
19) -> None:
20 """
21 Send an invitation email to a customer who has been assigned a seat.
22 """
23 if not seat.invitation_token:
24 log.warning(
25 "seat_invitation.no_token",
26 seat_id=seat.id,
27 customer_email=customer_email,
28 )
29 return
31 claim_url = (
32 f"{settings.FRONTEND_BASE_URL}/{organization.slug}/portal/claim"
33 f"?token={seat.invitation_token}"
34 )
36 html_content = render_email_template(
37 SeatInvitationEmail(
38 props=SeatInvitationProps.model_validate(
39 {
40 "email": customer_email,
41 "organization": organization,
42 "product_name": product_name,
43 "billing_manager_email": billing_manager_email,
44 "claim_url": claim_url,
45 }
46 )
47 )
48 )
50 enqueue_email(
51 to_email_addr=customer_email,
52 subject=f"You've been invited to access {product_name}",
53 html_content=html_content,
54 )
56 log.info(
57 "seat_invitation.sent",
58 seat_id=seat.id,
59 customer_email=customer_email,
60 organization_id=organization.id,
61 )