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

37 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-01 15:39 +0000

1import logging 

2 

3from django.core.exceptions import ValidationError 

4from django.db import models 

5 

6from benefits.core.models import EnrollmentGroup, Environment, SecretNameField, TransitProcessorConfig 

7from benefits.secrets import get_secret_by_name 

8 

9logger = logging.getLogger(__name__) 

10 

11 

12class LittlepayConfig(TransitProcessorConfig): 

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

14 

15 audience = models.TextField( 

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

17 ) 

18 client_id = models.TextField( 

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

20 ) 

21 client_secret_name = SecretNameField( 

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

23 default="", 

24 blank=True, 

25 ) 

26 

27 @property 

28 def api_base_url(self): 

29 if self.environment == Environment.TEST.value: 

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

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

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

33 else: 

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

35 

36 @property 

37 def client_secret(self): 

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

39 return secret_field.secret_value(self) 

40 

41 def clean(self): 

42 field_errors = {} 

43 

44 if self.pk and self.transitagency_set and any([agency.active for agency in self.transitagency_set.all()]): 

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

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

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

48 

49 if self.environment not in ["test", "prod"]: 49 ↛ 50line 49 didn't jump to line 50 because the condition on line 49 was never true

50 field_errors.update( 

51 {"environment": ValidationError("Valid environment values for Littlepay are Testing and Production.")} 

52 ) 

53 

54 if field_errors: 

55 raise ValidationError(field_errors) 

56 

57 

58class LittlepayGroup(EnrollmentGroup): 

59 group_id = models.UUIDField(default=None, blank=True, help_text="The ID of the Littlepay group for user enrollment.") 

60 

61 @staticmethod 

62 def by_id(id): 

63 """Get a LittlepayGroup instance by its ID.""" 

64 logger.debug(f"Get {LittlepayGroup.__name__} by id: {id}") 

65 return LittlepayGroup.objects.get(id=id)