55import asyncio
66from dataclasses import dataclass
77from datetime import datetime
8+ import re
89from typing import Any , Literal
910
1011from lfx .log .logger import logger
2829)
2930from langflow .services .paddle .client import get_paddle_client
3031
32+ _PADDLE_CUSTOMER_ID_RE = re .compile (r"(ctm_[a-z0-9]+)" , re .IGNORECASE )
33+
3134
3235async def ensure_paddle_customer_for_user (
3336 * ,
@@ -56,6 +59,11 @@ async def _get_paddle_customer_id() -> str | None:
5659 return await get_paddle_customer_id_from_clerk_payload ()
5760
5861
62+ def _extract_customer_id_from_error (exc : Exception ) -> str | None :
63+ match = _PADDLE_CUSTOMER_ID_RE .search (str (exc ))
64+ return match .group (1 ) if match else None
65+
66+
5967async def _create_paddle_customer_and_update_clerk_metadata (
6068 client : Client ,
6169 clerk_user_id : str ,
@@ -76,35 +84,55 @@ async def _create_paddle_customer_and_update_clerk_metadata(
7684 PADDLE_CUSTOM_DATA_USER_ID_KEY : str (clerk_user_id ),
7785 }
7886 ),
87+ ),
7988 )
80- )
8189 logger .info (f"Paddle customer creation response: { customer } " )
8290 except Exception as exc : # noqa: BLE001
83- if not _is_customer_already_exists_error (exc ):
84- raise
85- logger .info (
86- "Paddle customer already exists for email %s; resolving existing customer." ,
87- email ,
88- )
89- existing_customer = await _find_existing_paddle_customer (
90- client = client ,
91- email = email ,
92- clerk_user_id = clerk_user_id ,
93- )
94- if existing_customer is None :
95- logger .exception ("Unable to resolve existing Paddle customer for email %s." , email )
96- raise
91+ customer_id = _extract_customer_id_from_error (exc )
92+
93+ if not customer_id :
94+ if not _is_customer_already_exists_error (exc ):
95+ raise
96+
97+ logger .info (
98+ "Paddle customer already exists for email %s; resolving existing customer." ,
99+ email ,
100+ )
101+ customer = await _find_existing_paddle_customer (
102+ client = client ,
103+ email = email ,
104+ clerk_user_id = clerk_user_id ,
105+ )
106+ if customer is None :
107+ logger .exception ("Unable to resolve existing Paddle customer for email %s." , email )
108+ raise
109+ else :
110+ logger .info (
111+ "Paddle reports existing customer %s for email %s" ,
112+ customer_id ,
113+ email ,
114+ )
115+ try :
116+ customer = await asyncio .to_thread (client .customers .get , customer_id )
117+ except Exception as exc : # noqa: BLE001
118+ logger .exception (
119+ "Failed to retrieve existing Paddle customer with ID %s for clerk user %s." ,
120+ customer_id ,
121+ clerk_user_id ,
122+ )
123+ raise
124+
97125 await _sync_paddle_customer_metadata (
98126 client = client ,
99- customer = existing_customer ,
127+ customer = customer ,
100128 clerk_user_id = clerk_user_id ,
101129 )
102- paddle_customer_id = existing_customer . id
130+
103131 await update_clerk_public_metadata (
104132 clerk_user_id = clerk_user_id ,
105- public_metadata = {PADDLE_CUSTOMER_ID_KEY : paddle_customer_id },
133+ public_metadata = {PADDLE_CUSTOMER_ID_KEY : customer . id },
106134 )
107- return paddle_customer_id
135+ return customer . id
108136
109137 paddle_customer_id = customer .id
110138
@@ -119,7 +147,12 @@ async def _create_paddle_customer_and_update_clerk_metadata(
119147
120148def _is_customer_already_exists_error (exc : Exception ) -> bool :
121149 message = str (exc ).lower ()
122- return "customer already exists" in message or ("already exists" in message and "customer" in message )
150+ return (
151+ "customer already exists" in message
152+ or ("already exists" in message and "customer" in message )
153+ or ("customer email conflicts" in message )
154+ or ("email conflicts" in message and "customer" in message )
155+ )
123156
124157
125158async def _find_existing_paddle_customer (
@@ -159,8 +192,16 @@ async def _sync_paddle_customer_metadata(
159192
160193 updated_custom_data = dict (existing_custom_data )
161194 updated_custom_data [PADDLE_CUSTOM_DATA_USER_ID_KEY ] = str (clerk_user_id )
162- await asyncio .to_thread (
163- client .customers .update ,
164- customer .id ,
165- UpdateCustomer (custom_data = CustomData (updated_custom_data )),
166- )
195+ try :
196+ await asyncio .to_thread (
197+ client .customers .update ,
198+ customer .id ,
199+ UpdateCustomer (custom_data = CustomData (updated_custom_data )),
200+ )
201+ except Exception as exc : # noqa: BLE001
202+ logger .exception (
203+ "Failed to sync Paddle customer metadata for customer %s and clerk user %s." ,
204+ customer .id ,
205+ clerk_user_id ,
206+ )
207+ raise
0 commit comments