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
« 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#
13from enum import StrEnum
14from string import Template
15from typing import Any, NoReturn, Self
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
23class ProxyErrorMessage(StrEnum):
24 _error_code: AppPaymentErrorCode
25 _msg: str
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
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 )
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 )
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 )
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 )
169 @property
170 def error_code(self) -> AppPaymentErrorCode:
171 return self._error_code
173 def message(self, **kwargs: Any) -> str:
174 return Template(self._msg).substitute(**kwargs)
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)
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 )