Coverage for functions \ flipdare \ payments \ app_stripe_proxy_error.py: 84%

57 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 enum import StrEnum 

14from string import Template 

15from typing import Any, NoReturn, Self 

16 

17from flipdare.app_log import LOG 

18from flipdare.error.app_stripe_error import AppStripeError 

19from flipdare.error.stripe_error_context import StripeErrorContext 

20from flipdare.generated.shared.app_payment_error_code import AppPaymentErrorCode 

21 

22 

23class ProxyErrorMessage(StrEnum): 

24 _error_code: AppPaymentErrorCode 

25 _msg: str 

26 

27 def __new__( 

28 cls, 

29 code: str, 

30 error_code: AppPaymentErrorCode, 

31 msg: str, 

32 ) -> Self: 

33 obj = str.__new__(cls, code) 

34 obj._value_ = code 

35 obj._error_code = error_code 

36 obj._msg = msg 

37 return obj 

38 

39 # ACCOUNT 

40 ACCOUNT_CREATE_FAILED = ( 

41 "ACCOUNT_CREATE_FAILED", 

42 AppPaymentErrorCode.API_ERROR, 

43 "Stripe $ACCOUNT_TYPE account creation failed for $EMAIL: $STRIPE_ERROR", 

44 ) 

45 ACCOUNT_PARSE_FAILED = ( 

46 "ACCOUNT_PARSE_FAILED", 

47 AppPaymentErrorCode.API_ERROR, 

48 "Error parsing account DTO for account_id $ACCOUNT_ID: $STRIPE_ERROR", 

49 ) 

50 ACCOUNT_PAYMENTS_CHECK_FAILED = ( 

51 "ACCOUNT_PAYMENTS_CHECK_FAILED", 

52 AppPaymentErrorCode.API_ERROR, 

53 "Error checking if account $ACCOUNT_ID is ready for payments: $STRIPE_ERROR", 

54 ) 

55 ACCOUNT_MCC_UPDATE_FAILED = ( 

56 "ACCOUNT_MCC_UPDATE_FAILED", 

57 AppPaymentErrorCode.INVALID_USER, 

58 "Error updating MCC for account $ACCOUNT_ID: $STRIPE_ERROR", 

59 ) 

60 ACCOUNT_LINK_CREATE_FAILED = ( 

61 "ACCOUNT_LINK_CREATE_FAILED", 

62 AppPaymentErrorCode.LINK_CREATE_FAILED, 

63 "Stripe account link creation failed for account_id $ACCOUNT_ID: $STRIPE_ERROR", 

64 ) 

65 LOGIN_LINK_CREATE_FAILED = ( 

66 "LOGIN_LINK_CREATE_FAILED", 

67 AppPaymentErrorCode.INVALID_USER, 

68 "Error creating login link for $ACCOUNT_ID: $STRIPE_ERROR", 

69 ) 

70 # CUSTOMER 

71 CUSTOMER_CREATE_FAILED = ( 

72 "CUSTOMER_CREATE_FAILED", 

73 AppPaymentErrorCode.INVALID_USER, 

74 "Error creating customer for email $EMAIL: $STRIPE_ERROR", 

75 ) 

76 

77 CUSTOMER_RETRIEVE_FAILED = ( 

78 "CUSTOMER_RETRIEVE_FAILED", 

79 AppPaymentErrorCode.INVALID_USER, 

80 "Error retrieving customer info for $CUSTOMER_ID: $STRIPE_ERROR", 

81 ) 

82 # PAYMENT INTENT 

83 FEE_EXCEEDS_AMOUNT = ( 

84 "FEE_EXCEEDS_AMOUNT", 

85 AppPaymentErrorCode.FEE_CALC_ERROR, 

86 "Calculated application fee $FEE_AMOUNT exceeds total charge $AMOUNT for customer $CUSTOMER_ID and account $ACCOUNT_ID", 

87 ) 

88 INTENT_CREATE_FAILED = ( 

89 "INTENT_CREATE_FAILED", 

90 AppPaymentErrorCode.PAYMENT_CREATE_FAILED, 

91 "Error creating payment intent for $CONTEXT: $STRIPE_ERROR", 

92 ) 

93 INTENT_SECRET_MISSING = ( 

94 "INTENT_SECRET_MISSING", 

95 AppPaymentErrorCode.MALFORMED_INTENT, 

96 "Payment intent client secret missing for ($INTENT_ID) $CONTEXT", 

97 ) 

98 INTENT_RETRIEVE_FAILED = ( 

99 "INTENT_RETRIEVE_FAILED", 

100 AppPaymentErrorCode.API_ERROR, 

101 "Error retrieving payment intent $CONTEXT: $STRIPE_ERROR", 

102 ) 

103 INTENT_CANCEL_FAILED = ( 

104 "INTENT_CANCEL_FAILED", 

105 AppPaymentErrorCode.CANCEL_INTENT_FAILED, 

106 "Error canceling payment intent $CONTEXT: $STRIPE_ERROR", 

107 ) 

108 INTENT_REAUTH_FAILED = ( 

109 "INTENT_REAUTH_FAILED", 

110 AppPaymentErrorCode.INTENT_REAUTH_FAILED, 

111 "Error reauthorizing payment intent for $CONTEXT: $STRIPE_ERROR", 

112 ) 

113 INTENT_LIST_FAILED = ( 

114 "INTENT_LIST_FAILED", 

115 AppPaymentErrorCode.API_ERROR, 

116 "Error listing payment intents for customer_id $CUSTOMER_ID: $STRIPE_ERROR", 

117 ) 

118 INTENT_CAPTURE_FAILED = ( 

119 "INTENT_CAPTURE_FAILED", 

120 AppPaymentErrorCode.PAYMENT_CAPTURE_FAILED, 

121 "Error capturing payment intent $INTENT_ID: $STRIPE_ERROR", 

122 ) 

123 INTENT_PARSE_FAILED = ( 

124 "INTENT_PARSE_FAILED", 

125 AppPaymentErrorCode.MALFORMED_INTENT, 

126 "Failed to parse payment intent after capture for $INTENT_ID: $STRIPE_ERROR", 

127 ) 

128 # EPHEMERAL KEY / CHARGE 

129 EPHEMERAL_KEY_CREATE_FAILED = ( 

130 "EPHEMERAL_KEY_CREATE_FAILED", 

131 AppPaymentErrorCode.API_ERROR, 

132 "Error creating ephemeral key for $CONTEXT: $STRIPE_ERROR", 

133 ) 

134 EPHEMERAL_KEY_SECRET_MISSING = ( 

135 "EPHEMERAL_KEY_SECRET_MISSING", 

136 AppPaymentErrorCode.MALFORMED_INTENT, 

137 "Ephemeral key secret missing for ($INTENT_ID): $CONTEXT", 

138 ) 

139 CHARGE_RESPONSE_CREATE_FAILED = ( 

140 "CHARGE_RESPONSE_CREATE_FAILED", 

141 AppPaymentErrorCode.MALFORMED_INTENT, 

142 "Failed to create charge response schema for $CONTEXT: $STRIPE_ERROR", 

143 ) 

144 # TRANSFER 

145 TRANSFER_FAILED = ( 

146 "TRANSFER_FAILED", 

147 AppPaymentErrorCode.API_ERROR, 

148 "Error creating transfer for charge $CHARGE_ID to account $ACCOUNT_ID: $STRIPE_ERROR", 

149 ) 

150 

151 TRANSFER_PARSE_FAILED = ( 

152 "TRANSFER_PARSE_FAILED", 

153 AppPaymentErrorCode.API_ERROR, 

154 "Error parsing transfer response for charge $CHARGE_ID to account $ACCOUNT_ID: $STRIPE_ERROR", 

155 ) 

156 

157 # REFUND 

158 REFUND_TRANSFER_FAILED = ( 

159 "REFUND_TRANSFER_FAILED", 

160 AppPaymentErrorCode.FEE_REFUND_FAILED, 

161 "Error refunding excessive fee for intent $INTENT_ID: $STRIPE_ERROR", 

162 ) 

163 REFUND_NO_STATUS = ( 

164 "REFUND_NO_STATUS", 

165 AppPaymentErrorCode.REFUND_FAILED, 

166 "No status for refund $REFUND_ID on payment intent $INTENT_ID", 

167 ) 

168 

169 @property 

170 def error_code(self) -> AppPaymentErrorCode: 

171 return self._error_code 

172 

173 def message(self, **kwargs: Any) -> str: 

174 return Template(self._msg).substitute(**kwargs) 

175 

176 

177class ProxyErrorBuilder: 

178 @staticmethod 

179 def raise_error( 

180 msg_enum: ProxyErrorMessage, 

181 endpoint: str, 

182 error: Exception | None = None, 

183 **kwargs: Any, 

184 ) -> NoReturn: 

185 msg = msg_enum.message(**kwargs) 

186 LOG().error(msg) 

187 ctx = StripeErrorContext.from_code( 

188 endpoint=endpoint, 

189 error_code=msg_enum.error_code, 

190 cause=msg, 

191 error=error, 

192 ) 

193 if error is not None: 

194 raise AppStripeError.from_context(ctx) from error 

195 raise AppStripeError.from_context(ctx) 

196 

197 @staticmethod 

198 def account_error( 

199 endpoint: str, 

200 account_type: str, 

201 email: str, 

202 stripe_error: Exception, 

203 ) -> NoReturn: 

204 ProxyErrorBuilder.raise_error( 

205 ProxyErrorMessage.ACCOUNT_CREATE_FAILED, 

206 endpoint=endpoint, 

207 error=stripe_error, 

208 ACCOUNT_TYPE=account_type, 

209 EMAIL=email, 

210 STRIPE_ERROR=stripe_error, 

211 )