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

1import structlog 1a

2 

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

9 

10log: Logger = structlog.get_logger() 1a

11 

12 

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 

30 

31 claim_url = ( 

32 f"{settings.FRONTEND_BASE_URL}/{organization.slug}/portal/claim" 

33 f"?token={seat.invitation_token}" 

34 ) 

35 

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 ) 

49 

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 ) 

55 

56 log.info( 

57 "seat_invitation.sent", 

58 seat_id=seat.id, 

59 customer_email=customer_email, 

60 organization_id=organization.id, 

61 )