Skip to content

Commit 24a22f7

Browse files
committed
feat(portaswitch): support two search modes for account lookup
1 parent e94b2ab commit 24a22f7

File tree

2 files changed

+75
-56
lines changed

2 files changed

+75
-56
lines changed

app/bss/adapters/portaswitch/adapter.py

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -428,14 +428,14 @@ def retrieve_contacts(self, session: SessionInfo, user: UserInfo) -> list[Contac
428428
contacts.append(Serializer.get_contact_info_by_account(account, i_account))
429429
case PortaSwitchContactsSelectingMode.PHONEBOOK:
430430
phonebook = self._account_api.get_phonebook_list(access_token, 1, 100)['phonebook_rec_list']
431-
431+
432432
# Extract phone numbers from phonebook records
433433
phonebook_numbers = set()
434434
for record in phonebook:
435435
phone_number = record.get("phone_number", "").replace("+", "")
436436
if phone_number:
437437
phonebook_numbers.add(phone_number)
438-
438+
439439
# Get accounts mapping only for phonebook numbers (on-demand)
440440
number_to_accounts = self._get_number_to_customer_accounts_map_for_numbers(phonebook_numbers)
441441

@@ -461,7 +461,7 @@ def retrieve_contacts(self, session: SessionInfo, user: UserInfo) -> list[Contac
461461
case PortaSwitchContactsSelectingMode.PHONE_DIRECTORY:
462462
phone_directories = self._account_api.get_phone_directory_list(access_token, 1, 100)[
463463
'phone_directory_list']
464-
464+
465465
# Extract phone numbers from phone directory records
466466
phone_directory_numbers = set()
467467
for directory in phone_directories:
@@ -475,7 +475,7 @@ def retrieve_contacts(self, session: SessionInfo, user: UserInfo) -> list[Contac
475475
office_number = record.get("office_number", "").replace("+", "")
476476
if office_number:
477477
phone_directory_numbers.add(office_number)
478-
478+
479479
# Get accounts mapping only for phone directory numbers (on-demand)
480480
number_to_accounts = self._get_number_to_customer_accounts_map_for_numbers(phone_directory_numbers)
481481

@@ -855,8 +855,9 @@ def _check_allowed_addons(self, account_info: dict):
855855
def _get_number_to_customer_accounts_map_for_numbers(self, target_numbers: set[str]) -> dict[str, dict]:
856856
"""Return a mapping of phone numbers to customer accounts, optimized for specific numbers.
857857
858-
This method searches for accounts on-demand, fetching them in batches of 1000
859-
and stopping when all target numbers are found or all accounts are processed.
858+
This method supports two search modes:
859+
1. If CONTACTS_SELECTING_CUSTOMER_IDS is configured: searches through customer accounts in batches
860+
2. If CONTACTS_SELECTING_CUSTOMER_IDS is not configured: searches each number individually using get_account_info
860861
861862
Args:
862863
target_numbers: Set of phone numbers to search for
@@ -866,44 +867,58 @@ def _get_number_to_customer_accounts_map_for_numbers(self, target_numbers: set[s
866867
"""
867868
if not target_numbers:
868869
return {}
869-
870+
870871
number_to_accounts = {}
871-
remaining_numbers = target_numbers.copy()
872-
873-
# Search through each customer's accounts
874-
for customer_id in self._portaswitch_settings.CONTACTS_SELECTING_CUSTOMER_IDS:
875-
if not remaining_numbers:
876-
break # All numbers found, no need to continue
877-
878-
try:
879-
# Get accounts for this customer in batches
880-
offset = 0
881-
limit = 1000
882-
883-
while remaining_numbers and offset < 10000: # Safety limit to prevent infinite loops
884-
accounts = self._admin_api.get_account_list(int(customer_id), limit, offset)
885-
page = accounts.get("account_list", []) if isinstance(accounts, dict) else []
886-
total = accounts.get("total") if isinstance(accounts, dict) else None
887-
888-
# Process accounts in this batch
889-
for account in page:
890-
account_number = account.get("id", "")
891-
if account_number in remaining_numbers:
892-
number_to_accounts[account_number] = account
893-
remaining_numbers.remove(account_number)
894-
895-
# Stop if we've processed all accounts or found all target numbers
896-
if not remaining_numbers or len(page) < limit:
897-
break
898-
if total is not None and offset + len(page) >= int(total):
899-
break
900-
901-
offset += limit
902-
903-
except Exception as e:
904-
logging.warning(f"Error fetching accounts for customer {customer_id}: {e}")
905-
continue
906-
872+
873+
# Check if CONTACTS_SELECTING_CUSTOMER_IDS is configured
874+
if self._portaswitch_settings.CONTACTS_SELECTING_CUSTOMER_IDS:
875+
# Use batch search through customer accounts
876+
remaining_numbers = target_numbers.copy()
877+
878+
# Search through each customer's accounts
879+
for customer_id in self._portaswitch_settings.CONTACTS_SELECTING_CUSTOMER_IDS:
880+
if not remaining_numbers:
881+
break # All numbers found, no need to continue
882+
883+
try:
884+
# Get accounts for this customer in batches
885+
offset = 0
886+
limit = 1000
887+
888+
while remaining_numbers and offset < 10000: # Safety limit to prevent infinite loops
889+
accounts = self._admin_api.get_account_list(int(customer_id), limit, offset)
890+
page = accounts.get("account_list", []) if isinstance(accounts, dict) else []
891+
total = accounts.get("total") if isinstance(accounts, dict) else None
892+
893+
# Process accounts in this batch
894+
for account in page:
895+
account_number = account.get("id", "")
896+
if account_number in remaining_numbers:
897+
number_to_accounts[account_number] = account
898+
remaining_numbers.remove(account_number)
899+
900+
# Stop if we've processed all accounts or found all target numbers
901+
if not remaining_numbers or len(page) < limit:
902+
break
903+
if total is not None and offset + len(page) >= int(total):
904+
break
905+
906+
offset += limit
907+
908+
except Exception as e:
909+
logging.warning(f"Error fetching accounts for customer {customer_id}: {e}")
910+
continue
911+
else:
912+
# Use individual search for each number
913+
for number in target_numbers:
914+
try:
915+
account_info = self._admin_api.get_account_info(id=number).get("account_info")
916+
if account_info:
917+
number_to_accounts[number] = account_info
918+
except Exception as e:
919+
logging.debug(f"Account not found for number {number}: {e}")
920+
continue
921+
907922
logging.debug(f"Found {len(number_to_accounts)} accounts out of {len(target_numbers)} target numbers")
908923
return number_to_accounts
909924

app/bss/adapters/portaswitch/config.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@
1111
)
1212

1313

14+
def parse_string_list(value: Union[List, str, int, None]) -> List[str]:
15+
if not value:
16+
return []
17+
if isinstance(value, int):
18+
return [str(value)]
19+
if isinstance(value, str):
20+
return [x.strip() for x in value.split(';') if x.strip()]
21+
if isinstance(value, list):
22+
return [str(x).strip() for x in value if str(x).strip()]
23+
24+
1425
class PortaSwitchSettings(BaseSettings):
1526
ADMIN_API_URL: str
1627
ADMIN_API_LOGIN: str
@@ -37,9 +48,8 @@ def decode_contacts_selecting_extension_types(cls, v: Union[List, str]) -> List[
3748

3849
@field_validator("CONTACTS_SELECTING_CUSTOMER_IDS", mode='before')
3950
@classmethod
40-
def decode_contacts_selecting_customer_ids(cls, v: Union[List, str]) -> List[str]:
41-
v = str(v)
42-
return [x.strip() for x in v.split(';')] if v else v
51+
def decode_contacts_selecting_customer_ids(cls, v: Union[List, str, int, None]) -> List[str]:
52+
return parse_string_list(v)
4353

4454
@field_validator("CONTACTS_CUSTOM", mode='before')
4555
@classmethod
@@ -49,11 +59,8 @@ def decode_contacts_custom(cls, v: Union[List, str]) -> List[dict]:
4959

5060
@field_validator("ALLOWED_ADDONS", mode='before')
5161
@classmethod
52-
def decode_allowed_addons(cls, v: Union[List, str]) -> List[str]:
53-
if isinstance(v, int):
54-
v = str(v)
55-
56-
return [x.strip() for x in v.split(';')] if isinstance(v, str) else v
62+
def decode_allowed_addons(cls, v: Union[List, str, int, None]) -> List[str]:
63+
return parse_string_list(v)
5764

5865
model_config = {
5966
"env_prefix": "PORTASWITCH_",
@@ -67,11 +74,8 @@ class OTPSettings(BaseSettings):
6774

6875
@field_validator("IGNORE_ACCOUNTS", mode='before')
6976
@classmethod
70-
def decode_ignore_accounts(cls, v: Union[List, str]) -> List[str]:
71-
if isinstance(v, int):
72-
v = str(v)
73-
74-
return [x.strip() for x in v.split(';')] if isinstance(v, str) else v
77+
def decode_ignore_accounts(cls, v: Union[List, str, int, None]) -> List[str]:
78+
return parse_string_list(v)
7579

7680
model_config = {
7781
"env_prefix": "OTP_",

0 commit comments

Comments
 (0)