"""Services for the Picnic integration.""" from __future__ import annotations from typing import cast from python_picnic_api import PicnicAPI import voluptuous as vol from homeassistant.core import HomeAssistant, ServiceCall import homeassistant.helpers.config_validation as cv from .const import ( ATTR_AMOUNT, ATTR_CONFIG_ENTRY_ID, ATTR_PRODUCT_ID, ATTR_PRODUCT_IDENTIFIERS, ATTR_PRODUCT_NAME, CONF_API, DOMAIN, SERVICE_ADD_PRODUCT_TO_CART, ) class PicnicServiceException(Exception): """Exception for Picnic services.""" async def async_register_services(hass: HomeAssistant) -> None: """Register services for the Picnic integration, if not registered yet.""" if hass.services.has_service(DOMAIN, SERVICE_ADD_PRODUCT_TO_CART): return async def async_add_product_service(call: ServiceCall): api_client = await get_api_client(hass, call.data[ATTR_CONFIG_ENTRY_ID]) await handle_add_product(hass, api_client, call) hass.services.async_register( DOMAIN, SERVICE_ADD_PRODUCT_TO_CART, async_add_product_service, schema=vol.Schema( { vol.Required(ATTR_CONFIG_ENTRY_ID): cv.string, vol.Exclusive( ATTR_PRODUCT_ID, ATTR_PRODUCT_IDENTIFIERS ): cv.positive_int, vol.Exclusive(ATTR_PRODUCT_NAME, ATTR_PRODUCT_IDENTIFIERS): cv.string, vol.Optional(ATTR_AMOUNT): vol.All(vol.Coerce(int), vol.Range(min=1)), } ), ) async def get_api_client(hass: HomeAssistant, config_entry_id: str) -> PicnicAPI: """Get the right Picnic API client based on the device id, else get the default one.""" if config_entry_id not in hass.data[DOMAIN]: raise ValueError(f"Config entry with id {config_entry_id} not found!") return hass.data[DOMAIN][config_entry_id][CONF_API] async def handle_add_product( hass: HomeAssistant, api_client: PicnicAPI, call: ServiceCall ) -> None: """Handle the call for the add_product service.""" product_id = call.data.get("product_id") if not product_id: product_id = await hass.async_add_executor_job( _product_search, api_client, cast(str, call.data["product_name"]) ) if not product_id: raise PicnicServiceException("No product found or no product ID given!") await hass.async_add_executor_job( api_client.add_product, str(product_id), call.data.get("amount", 1) ) def _product_search(api_client: PicnicAPI, product_name: str) -> None | str: """Query the api client for the product name.""" search_result = api_client.search(product_name) if not search_result or "items" not in search_result[0]: return None # Return the first valid result for item in search_result[0]["items"]: if "name" in item: return str(item["id"]) return None