Coverage for benefits/enrollment_littlepay/models.py: 100%

35 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-06-06 20:07 +0000

1from django.core.exceptions import ValidationError 

2from django.db import models 

3 

4from benefits.core import context as core_context 

5from benefits.core.models import SecretNameField, Environment 

6from benefits.secrets import get_secret_by_name 

7 

8 

9class LittlepayConfig(models.Model): 

10 """Configuration for connecting to Littlepay, an entity that applies transit agency fare rules to rider transactions.""" 

11 

12 id = models.AutoField(primary_key=True) 

13 environment = models.TextField( 

14 choices=Environment, 

15 help_text="A label to indicate which environment this configuration is for.", 

16 ) 

17 agency_slug = models.SlugField( 

18 choices=core_context.AgencySlug, 

19 help_text="A label to indicate which agency this configuration is for. Note: the field that controls which configuration an agency actually uses is on the TransitAgency model.", # noqa 

20 ) 

21 audience = models.TextField( 

22 help_text="This agency's audience value used to access the TransitProcessor's API.", default="", blank=True 

23 ) 

24 client_id = models.TextField( 

25 help_text="This agency's client_id value used to access the TransitProcessor's API.", default="", blank=True 

26 ) 

27 client_secret_name = SecretNameField( 

28 help_text="The name of the secret containing this agency's client_secret value used to access the TransitProcessor's API.", # noqa: E501 

29 default="", 

30 blank=True, 

31 ) 

32 

33 @property 

34 def api_base_url(self): 

35 if self.environment == Environment.QA.value: 

36 return get_secret_by_name("littlepay-qa-api-base-url") 

37 elif self.environment == Environment.PROD.value: 

38 return get_secret_by_name("littlepay-prod-api-base-url") 

39 else: 

40 raise ValueError(f"Unexpected value for environment: {self.environment}") 

41 

42 @property 

43 def client_secret(self): 

44 secret_field = self._meta.get_field("client_secret_name") 

45 return secret_field.secret_value(self) 

46 

47 def clean(self): 

48 field_errors = {} 

49 

50 if hasattr(self, "transitagency") and self.transitagency.active: 

51 message = "This field is required when this configuration is referenced by an active transit agency." 

52 needed = dict(audience=self.audience, client_id=self.client_id, client_secret_name=self.client_secret_name) 

53 field_errors.update({k: ValidationError(message) for k, v in needed.items() if not v}) 

54 

55 if field_errors: 

56 raise ValidationError(field_errors) 

57 

58 def __str__(self): 

59 environment_label = Environment(self.environment).label if self.environment else "unknown" 

60 agency_slug = self.agency_slug if self.agency_slug else "(no agency)" 

61 return f"({environment_label}) {agency_slug}"