"""Connector to the ows-account microservice.""" import logging from dataclasses import dataclass from enum import Enum from typing import List, Optional from uuid import UUID import httpx from owsclient import AsyncOwsClient from pydantic import BaseModel logger = logging.getLogger(__name__) DEFAULT_OWS_ACCOUNT_REQUEST_TIMEOUT = httpx.Timeout(10) class LookupVendor(BaseModel): """Vendor object returned by the ows-account service. Example response: { "vendor_id": 21989, "uuid": "ec1fd7e2-9c95-4e09-a037-e924e0244283", "company_brand_uuid": "d25a4cd1-e820-45f2-be5c-56edcfeb8298", "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", } """ vendor_id: int uuid: UUID company_brand_uuid: Optional[UUID] = None parent_company_uuid: Optional[UUID] = None class LookupSubaccount(BaseModel): """Subaccount object returned by the ows-account service. Example response: { "subaccount_id": 1111, "uuid": "fff741c2-6def-4493-bfdf-c2bcb1128e02", "vendor_uuid": "fff741c2-6def-4493-bfdf-c2bcb1128e02", "company_brand_uuid": "d25a4cd1-e820-45f2-be5c-56edcfeb8298", "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", } """ subaccount_id: int uuid: UUID vendor_uuid: Optional[UUID] = None company_brand_uuid: Optional[UUID] = None parent_company_uuid: Optional[UUID] = None class LookupCompanyBrand(BaseModel): """CompanyBrand object returned by the ows-account service. Example response: { "uuid": "fff741c2-6def-4493-bfdf-c2bcb1128e02", "company_brand_id": 1111, "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", } """ uuid: UUID company_brand_id: int parent_company_uuid: Optional[UUID] = None class LookupParentCompany(BaseModel): """ParentCompany object returned by the ows-account service. Example response: { "uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", "parent_company_id": 1, } """ uuid: UUID parent_company_id: int PARENT_COMPANY_HIERARCHIES = { UUID("f1594122-7f99-4916-b103-08b0444c7b46"): LookupParentCompany( uuid=UUID("f1594122-7f99-4916-b103-08b0444c7b46"), # SME parent_company_id=1, ), UUID("955a1bbd-b623-4ea1-ab5f-8d6620c442fb"): LookupParentCompany( uuid=UUID("955a1bbd-b623-4ea1-ab5f-8d6620c442fb"), # The Orchard parent_company_id=2, ), } class LookupVendorFetchFlags(str, Enum): """Flag to request extra fields from LookupVendor.""" TENANT_HIERARCHY = "TENANT_HIERARCHY" DEFAULT_FETCH_FLAGS = [LookupVendorFetchFlags.TENANT_HIERARCHY] class LookupByUuidRequest(BaseModel): """Base lookup by uuid request schema.""" uuids: List[UUID] fetch_flags: Optional[List[LookupVendorFetchFlags]] = None class LookupVendorsRequest(LookupByUuidRequest): """Vendor lookup request (used for the demo endpoint).""" pass class LookupSubaccountsRequest(LookupByUuidRequest): """Subaccount lookup request (used for infra endpoint).""" pass class LookupVendorsResponse(BaseModel): """Vendor lookup dataloader response. { "vendors": [ { "vendor_id": 6971, "uuid": "fff741c2-6def-4493-bfdf-c2bcb1128e02", "company_brand_uuid": "27dbeb7f-8041-4b57-aded-4a4154685660" "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", }, null, { "vendor_id": 21989, "uuid": "ec1fd7e2-9c95-4e09-a037-e924e0244283", "company_brand_uuid": "f9868cd1-250b-4065-8720-29bb60af6686" "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", }, ] } """ vendors: List[Optional[LookupVendor]] class LookupSubaccountsResponse(BaseModel): """Subaccount lookup response. { "subaccounts": [ { "subaccount_id": 6971, "uuid": "fff741c2-6def-4493-bfdf-c2bcb1128e02", "vendor_uuid": "faaaeb15-5cd1-4938-aa16-09bd080c4b60", "company_brand_uuid": "27dbeb7f-8041-4b57-aded-4a4154685660" "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", }, { "subaccount_id": 21989, "uuid": "ec1fd7e2-9c95-4e09-a037-e924e0244283" "vendor_uuid": "a46f992b-ee06-4aaf-8765-e3532ae5e8fb", "company_brand_uuid": "f9868cd1-250b-4065-8720-29bb60af6686" "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", } ] } """ subaccounts: List[Optional[LookupSubaccount]] class LookupCompanyBrandsResponse(BaseModel): """CompanyBrand lookup response. { "company_brands": [ { "uuid": "fff741c2-6def-4493-bfdf-c2bcb1128e02", "company_brand_id": 1111, "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", }, { "uuid": "ec1fd7e2-9c95-4e09-a037-e924e0244283" "company_brand_id": 21989, "parent_company_uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", } ] } """ company_brands: List[Optional[LookupCompanyBrand]] class LookupParentCompaniesResponse(BaseModel): """ParentCompany lookup response. { "parent_companies": [ { "parent_company_id": 1, "uuid": "f1594122-7f99-4916-b103-08b0444c7b46", }, { "parent_company_id": 2, "uuid": "955a1bbd-b623-4ea1-ab5f-8d6620c442fb", }, null, ] } """ parent_companies: List[Optional[LookupParentCompany]] @dataclass class OwsAccountClient: """Connector to ows-account microservice.""" async_ows_client: AsyncOwsClient service_name = "ows-account" ############# Lookup By UUIDs methods ############# async def lookup_vendors_by_uuids( self, uuids: List[UUID], fetch_flags: Optional[List[LookupVendorFetchFlags]] = None, ) -> LookupVendorsResponse: """Get Vendor information for one or more UUIDs. Callers should handle httpx exceptions. """ if not len(uuids): return LookupVendorsResponse(vendors=[]) response = await self.async_ows_client.post( self.service_name, path="/lookup/vendors/uuids/", json={ "uuids": [str(_uuid) for _uuid in uuids], "fetch_flags": fetch_flags if fetch_flags else [], }, timeout=DEFAULT_OWS_ACCOUNT_REQUEST_TIMEOUT, ) response.raise_for_status() return LookupVendorsResponse.model_validate_json(response.content) async def lookup_subaccounts_by_uuids( self, uuids: List[UUID], fetch_flags: Optional[List[LookupVendorFetchFlags]] = None, ) -> LookupSubaccountsResponse: """Get Subaccount information for one or more UUIDs.""" if not len(uuids): return LookupSubaccountsResponse(subaccounts=[]) response = await self.async_ows_client.post( self.service_name, path="/lookup/subaccounts/uuids/", json={ "uuids": [str(_uuid) for _uuid in uuids], "fetch_flags": fetch_flags if fetch_flags else [], }, timeout=DEFAULT_OWS_ACCOUNT_REQUEST_TIMEOUT, ) response.raise_for_status() return LookupSubaccountsResponse.model_validate_json(response.content) async def lookup_company_brands_by_uuids( self, uuids: List[UUID], ) -> LookupCompanyBrandsResponse: """Get CompanyBrand information for one or more UUIDs.""" if not len(uuids): return LookupCompanyBrandsResponse(company_brands=[]) response = await self.async_ows_client.post( self.service_name, path="/lookup/company-brands/uuids/", json={"uuids": [str(_uuid) for _uuid in uuids]}, timeout=DEFAULT_OWS_ACCOUNT_REQUEST_TIMEOUT, ) response.raise_for_status() return LookupCompanyBrandsResponse.model_validate_json(response.content) def lookup_parent_companies_by_uuids( self, uuids: List[UUID], ) -> LookupParentCompaniesResponse: """Get parent company information for one or more UUIDs.""" if not len(uuids): return LookupParentCompaniesResponse(parent_companies=[]) parent_companies = LookupParentCompaniesResponse( parent_companies=[ PARENT_COMPANY_HIERARCHIES.get(uuid, None) for uuid in uuids ] ) return LookupParentCompaniesResponse.model_validate(parent_companies) ############# Lookup By IDs methods ############# async def lookup_vendors_by_ids( self, vendor_ids: List[int], fetch_flags: Optional[List[LookupVendorFetchFlags]] = None, ) -> LookupVendorsResponse: """Get Vendor information for one or more vendor_ids.""" if not len(vendor_ids): return LookupVendorsResponse(vendors=[]) response = await self.async_ows_client.post( self.service_name, path="/lookup/vendors/vendor-ids/", json={ "vendor_ids": [int(_vendor_id) for _vendor_id in vendor_ids], "fetch_flags": fetch_flags if fetch_flags else [], }, timeout=DEFAULT_OWS_ACCOUNT_REQUEST_TIMEOUT, ) response.raise_for_status() return LookupVendorsResponse.model_validate_json(response.content) async def lookup_subaccounts_by_ids( self, subaccount_ids: List[int], fetch_flags: Optional[List[LookupVendorFetchFlags]] = None, ) -> LookupSubaccountsResponse: """Get Subaccount information for one or more subaccount_ids.""" if not len(subaccount_ids): return LookupSubaccountsResponse(subaccounts=[]) response = await self.async_ows_client.post( self.service_name, path="/lookup/subaccounts/subaccount-ids/", json={ "subaccount_ids": subaccount_ids, "fetch_flags": fetch_flags if fetch_flags else [], }, timeout=DEFAULT_OWS_ACCOUNT_REQUEST_TIMEOUT, ) response.raise_for_status() return LookupSubaccountsResponse.model_validate_json(response.content) async def lookup_company_brands_by_ids( self, company_brand_ids: List[int], ) -> LookupCompanyBrandsResponse: """Get CompanyBrand information for one or more company_brand_ids.""" if not len(company_brand_ids): return LookupCompanyBrandsResponse(company_brands=[]) response = await self.async_ows_client.post( self.service_name, path="/lookup/company-brands/company-brand-ids/", json={"company_brand_ids": company_brand_ids}, timeout=DEFAULT_OWS_ACCOUNT_REQUEST_TIMEOUT, ) response.raise_for_status() return LookupCompanyBrandsResponse.model_validate_json(response.content)