Coverage for functions \ flipdare \ error \ stripe_error_context.py: 80%

49 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-05-08 12:22 +1000

1#!/usr/bin/env python 

2# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved. 

3# 

4# This file is part of Flipdare's proprietary software and contains 

5# confidential and copyrighted material. Unauthorised copying, 

6# modification, distribution, or use of this file is strictly 

7# prohibited without prior written permission from Flipdare Pty Ltd. 

8# 

9# This software includes third-party components licensed under MIT, 

10# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details. 

11# 

12 

13from typing import Any, Self 

14from flipdare.app_log import LOG 

15from flipdare.error.app_error_protocol import AppErrorProtocol 

16from flipdare.error.error_context import ErrorContext 

17from flipdare.error.formatted_stripe_error import FormattedStripeError 

18from flipdare.generated.shared.app_payment_error_code import AppPaymentErrorCode 

19from flipdare.message.error_message import ErrorMessage 

20from flipdare.payments.payment_types import KnownStripeErrorType 

21from flipdare.payments.core.stripe_guard import StripeGuard 

22 

23__all__ = ["StripeErrorContext"] 

24 

25 

26class StripeErrorContext(ErrorContext): 

27 

28 def __init__( 

29 self, 

30 endpoint: str, 

31 *, 

32 error_code: AppErrorProtocol, 

33 message: str, 

34 cause: str | None = None, 

35 error: Exception | None = None, 

36 ) -> None: 

37 super().__init__( 

38 endpoint=endpoint, 

39 error_code=error_code, 

40 message=message, 

41 cause=cause, 

42 error=error, 

43 ) 

44 

45 @classmethod 

46 def from_stripe_error( 

47 cls, 

48 endpoint: str, 

49 error: KnownStripeErrorType, 

50 cause: str | None = None, 

51 ) -> Self: 

52 formatted = FormattedStripeError.from_exception(error) 

53 LOG().error(str(formatted)) # fixme: this is a hack. we need to restructure error code. 

54 msg = formatted.friendly_user_message 

55 return cls( 

56 endpoint=endpoint, 

57 error_code=formatted.error_code, 

58 message=msg, 

59 cause=cause, 

60 error=error, 

61 ) 

62 

63 @classmethod 

64 def from_code( 

65 cls, 

66 endpoint: str, 

67 error_code: AppPaymentErrorCode, 

68 pledge_id: str | None = None, 

69 intent_id: str | None = None, 

70 cause: str | None = None, 

71 error: Any | None = None, 

72 ) -> Self: 

73 from flipdare.error.app_error import AppError 

74 

75 message = cls.get_user_message_for_code( 

76 error_code, 

77 pledge_id=pledge_id, 

78 intent_id=intent_id, 

79 ) 

80 

81 if StripeGuard.is_stripe_error(error): 

82 error = cls._try_from_stripe_error( 

83 endpoint=endpoint, 

84 error=error, 

85 cause=cause, 

86 ) 

87 if error is not None: 

88 return error 

89 

90 if isinstance(error, AppError): 

91 return cls( 

92 endpoint=endpoint, 

93 error_code=error_code, 

94 message=message, 

95 cause=error.message, 

96 error=error, 

97 ) 

98 else: 

99 return cls( 

100 endpoint=endpoint, 

101 error_code=error_code, 

102 message=message, 

103 cause=cause, 

104 error=error, 

105 ) 

106 

107 @classmethod 

108 def _try_from_stripe_error( 

109 cls, 

110 endpoint: str, 

111 error: Any, 

112 cause: str | None = None, 

113 ) -> Self | None: 

114 if not StripeGuard.is_stripe_error(error): 

115 return None 

116 

117 formatted = FormattedStripeError.from_exception(error) 

118 LOG().error(str(formatted)) # fixme: this is a hack. we need to restructure error code. 

119 msg = formatted.friendly_user_message 

120 return cls( 

121 endpoint=endpoint, 

122 error_code=formatted.error_code, 

123 message=msg, 

124 cause=cause, 

125 error=error, 

126 ) 

127 

128 @staticmethod 

129 def get_user_message_for_code( 

130 error_code: AppPaymentErrorCode, 

131 pledge_id: str | None = None, 

132 intent_id: str | None = None, 

133 ) -> str: 

134 user_message = ErrorMessage.for_payment(error_code) 

135 if user_message is None: 

136 LOG().error(f"No user message found for error code: {error_code}") 

137 return ErrorMessage.STR_UNKNOWN_ERROR.formatted_payment_error() 

138 

139 try: 

140 return user_message.formatted_payment_error( 

141 pledge_id=pledge_id, 

142 intent_id=intent_id, 

143 ) 

144 except Exception as e: 

145 LOG().error(f"Error formatting user message for error code {error_code}: {e}") 

146 return ErrorMessage.STR_UNKNOWN_ERROR.formatted_payment_error()