Skip to content

Commit 3dc52d1

Browse files
committed
feat: implement async methods for capacity categories and add comprehensive tests
1 parent e2f569e commit 3dc52d1

File tree

4 files changed

+366
-35
lines changed

4 files changed

+366
-35
lines changed

ofsc/async_client/metadata.py

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,10 +451,70 @@ async def get_capacity_area(self, label: str) -> CapacityArea:
451451
async def get_capacity_categories(
452452
self, offset: int = 0, limit: int = 100
453453
) -> CapacityCategoryListResponse:
454-
raise NotImplementedError("Async method not yet implemented")
454+
"""Get all capacity categories with pagination.
455+
456+
Args:
457+
offset: Starting record number (default 0)
458+
limit: Maximum number to return (default 100)
459+
460+
Returns:
461+
CapacityCategoryListResponse: List of capacity categories
462+
463+
Raises:
464+
OFSCAuthenticationError: If authentication fails (401)
465+
OFSCAuthorizationError: If authorization fails (403)
466+
OFSCApiError: For other API errors
467+
OFSCNetworkError: For network/transport errors
468+
"""
469+
url = urljoin(self.baseUrl, "/rest/ofscMetadata/v1/capacityCategories")
470+
params = {"offset": offset, "limit": limit}
471+
472+
try:
473+
response = await self._client.get(url, headers=self.headers, params=params)
474+
response.raise_for_status()
475+
data = response.json()
476+
if "links" in data and not hasattr(CapacityCategoryListResponse, "links"):
477+
del data["links"]
478+
return CapacityCategoryListResponse.model_validate(data)
479+
except httpx.HTTPStatusError as e:
480+
self._handle_http_error(e, "Failed to get capacity categories")
481+
raise
482+
except httpx.TransportError as e:
483+
raise OFSCNetworkError(f"Network error: {str(e)}") from e
455484

456485
async def get_capacity_category(self, label: str) -> CapacityCategory:
457-
raise NotImplementedError("Async method not yet implemented")
486+
"""Get a single capacity category by label.
487+
488+
Args:
489+
label: The capacity category label to retrieve
490+
491+
Returns:
492+
CapacityCategory: The capacity category details
493+
494+
Raises:
495+
OFSCNotFoundError: If capacity category not found (404)
496+
OFSCAuthenticationError: If authentication fails (401)
497+
OFSCAuthorizationError: If authorization fails (403)
498+
OFSCApiError: For other API errors
499+
OFSCNetworkError: For network/transport errors
500+
"""
501+
encoded_label = quote_plus(label)
502+
url = urljoin(
503+
self.baseUrl, f"/rest/ofscMetadata/v1/capacityCategories/{encoded_label}"
504+
)
505+
506+
try:
507+
response = await self._client.get(url, headers=self.headers)
508+
response.raise_for_status()
509+
data = response.json()
510+
if "links" in data and not hasattr(CapacityCategory, "links"):
511+
del data["links"]
512+
return CapacityCategory.model_validate(data)
513+
except httpx.HTTPStatusError as e:
514+
self._handle_http_error(e, f"Failed to get capacity category '{label}'")
515+
raise
516+
except httpx.TransportError as e:
517+
raise OFSCNetworkError(f"Network error: {str(e)}") from e
458518

459519
# endregion
460520

ofsc/models.py

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -457,39 +457,6 @@ class BulkUpdateResponse(BaseModel):
457457
results: Optional[List[BulkUpdateResult]] = None
458458

459459

460-
# region 202403 Capacity Categories
461-
class Item(BaseModel):
462-
label: str
463-
name: Optional[str] = None
464-
465-
466-
class ItemList(RootModel[List[Item]]):
467-
def __iter__(self):
468-
return iter(self.root)
469-
470-
def __getitem__(self, item):
471-
return self.root[item]
472-
473-
474-
class CapacityCategory(BaseModel):
475-
label: str
476-
name: str
477-
timeSlots: Optional[ItemList] = None
478-
translations: Annotated[Optional[TranslationList], Field(alias="translations")] = (
479-
None
480-
)
481-
workSkillGroups: Optional[ItemList] = None
482-
workSkills: Optional[ItemList] = None
483-
active: bool
484-
model_config = ConfigDict(extra="allow")
485-
486-
487-
class CapacityCategoryListResponse(OFSResponseList[CapacityCategory]):
488-
pass
489-
490-
491-
# endregion
492-
493460
# region 202404 Metadata - Time Slots
494461
# endregion
495462
# region 202404 Metadata - Workzones
@@ -1423,6 +1390,38 @@ class CapacityAreaListResponse(OFSResponseList[CapacityArea]):
14231390
# endregion Metadata / Capacity Areas
14241391

14251392
# region Metadata / Capacity Categories
1393+
1394+
1395+
class Item(BaseModel):
1396+
label: str
1397+
name: Optional[str] = None
1398+
1399+
1400+
class ItemList(RootModel[list[Item]]):
1401+
def __iter__(self): # type: ignore[override]
1402+
return iter(self.root)
1403+
1404+
def __getitem__(self, item):
1405+
return self.root[item]
1406+
1407+
1408+
class CapacityCategory(BaseModel):
1409+
label: str
1410+
name: str
1411+
timeSlots: Optional[ItemList] = None
1412+
translations: Annotated[Optional[TranslationList], Field(alias="translations")] = (
1413+
None
1414+
)
1415+
workSkillGroups: Optional[ItemList] = None
1416+
workSkills: Optional[ItemList] = None
1417+
active: bool
1418+
model_config = ConfigDict(extra="allow")
1419+
1420+
1421+
class CapacityCategoryListResponse(OFSResponseList[CapacityCategory]):
1422+
pass
1423+
1424+
14261425
# endregion Metadata / Capacity Categories
14271426

14281427
# region Metadata / Forms

scripts/capture_api_responses.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,35 @@
278278
"metadata": {"capacity_area_label": "NONEXISTENT_AREA_12345"},
279279
},
280280
],
281+
"capacity_categories": [
282+
{
283+
"name": "get_capacity_categories_200_success",
284+
"description": "Get all capacity categories with pagination",
285+
"method": "GET",
286+
"path": "/rest/ofscMetadata/v1/capacityCategories",
287+
"params": {"offset": 0, "limit": 100},
288+
"body": None,
289+
"metadata": {},
290+
},
291+
{
292+
"name": "get_capacity_category_200_success",
293+
"description": "Get a single capacity category by label",
294+
"method": "GET",
295+
"path": "/rest/ofscMetadata/v1/capacityCategories/EST",
296+
"params": None,
297+
"body": None,
298+
"metadata": {"capacity_category_label": "EST"},
299+
},
300+
{
301+
"name": "get_capacity_category_404_not_found",
302+
"description": "Get a non-existent capacity category",
303+
"method": "GET",
304+
"path": "/rest/ofscMetadata/v1/capacityCategories/NONEXISTENT_CATEGORY_12345",
305+
"params": None,
306+
"body": None,
307+
"metadata": {"capacity_category_label": "NONEXISTENT_CATEGORY_12345"},
308+
},
309+
],
281310
"non_working_reasons": [
282311
{
283312
"name": "get_non_working_reasons_200_success",

0 commit comments

Comments
 (0)