"""Services for the seventeentrack integration.""" from typing import Any, Final from pyseventeentrack.package import PACKAGE_STATUS_MAP, Package import voluptuous as vol from homeassistant.config_entries import ConfigEntry, ConfigEntryState from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_LOCATION from homeassistant.core import ( HomeAssistant, ServiceCall, ServiceResponse, SupportsResponse, callback, ) from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers import config_validation as cv, selector from homeassistant.util import slugify from . import SeventeenTrackCoordinator from .const import ( ATTR_CONFIG_ENTRY_ID, ATTR_DESTINATION_COUNTRY, ATTR_INFO_TEXT, ATTR_ORIGIN_COUNTRY, ATTR_PACKAGE_FRIENDLY_NAME, ATTR_PACKAGE_STATE, ATTR_PACKAGE_TRACKING_NUMBER, ATTR_PACKAGE_TYPE, ATTR_STATUS, ATTR_TIMESTAMP, ATTR_TRACKING_INFO_LANGUAGE, ATTR_TRACKING_NUMBER, DOMAIN, SERVICE_ADD_PACKAGE, SERVICE_ARCHIVE_PACKAGE, SERVICE_GET_PACKAGES, ) SERVICE_GET_PACKAGES_SCHEMA: Final = vol.Schema( { vol.Required(ATTR_CONFIG_ENTRY_ID): cv.string, vol.Optional(ATTR_PACKAGE_STATE): selector.SelectSelector( selector.SelectSelectorConfig( multiple=True, options=[ value.lower().replace(" ", "_") for value in PACKAGE_STATUS_MAP.values() ], mode=selector.SelectSelectorMode.DROPDOWN, translation_key=ATTR_PACKAGE_STATE, ) ), } ) SERVICE_ADD_PACKAGE_SCHEMA: Final = vol.Schema( { vol.Required(ATTR_CONFIG_ENTRY_ID): cv.string, vol.Required(ATTR_PACKAGE_TRACKING_NUMBER): cv.string, vol.Required(ATTR_PACKAGE_FRIENDLY_NAME): cv.string, } ) SERVICE_ARCHIVE_PACKAGE_SCHEMA: Final = vol.Schema( { vol.Required(ATTR_CONFIG_ENTRY_ID): cv.string, vol.Required(ATTR_PACKAGE_TRACKING_NUMBER): cv.string, } ) async def _get_packages(call: ServiceCall) -> ServiceResponse: """Get packages from 17Track.""" config_entry_id = call.data[ATTR_CONFIG_ENTRY_ID] package_states = call.data.get(ATTR_PACKAGE_STATE, []) await _validate_service(call.hass, config_entry_id) seventeen_coordinator: SeventeenTrackCoordinator = call.hass.data[DOMAIN][ config_entry_id ] live_packages = sorted( await seventeen_coordinator.client.profile.packages( show_archived=seventeen_coordinator.show_archived ) ) return { "packages": [ _package_to_dict(package) for package in live_packages if slugify(package.status) in package_states or package_states == [] ] } async def _add_package(call: ServiceCall) -> None: """Add a new package to 17Track.""" config_entry_id = call.data[ATTR_CONFIG_ENTRY_ID] tracking_number = call.data[ATTR_PACKAGE_TRACKING_NUMBER] friendly_name = call.data[ATTR_PACKAGE_FRIENDLY_NAME] await _validate_service(call.hass, config_entry_id) seventeen_coordinator: SeventeenTrackCoordinator = call.hass.data[DOMAIN][ config_entry_id ] await seventeen_coordinator.client.profile.add_package( tracking_number, friendly_name ) async def _archive_package(call: ServiceCall) -> None: config_entry_id = call.data[ATTR_CONFIG_ENTRY_ID] tracking_number = call.data[ATTR_PACKAGE_TRACKING_NUMBER] await _validate_service(call.hass, config_entry_id) seventeen_coordinator: SeventeenTrackCoordinator = call.hass.data[DOMAIN][ config_entry_id ] await seventeen_coordinator.client.profile.archive_package(tracking_number) def _package_to_dict(package: Package) -> dict[str, Any]: result = { ATTR_DESTINATION_COUNTRY: package.destination_country, ATTR_ORIGIN_COUNTRY: package.origin_country, ATTR_PACKAGE_TYPE: package.package_type, ATTR_TRACKING_INFO_LANGUAGE: package.tracking_info_language, ATTR_TRACKING_NUMBER: package.tracking_number, ATTR_LOCATION: package.location, ATTR_STATUS: package.status, ATTR_INFO_TEXT: package.info_text, ATTR_FRIENDLY_NAME: package.friendly_name, } if timestamp := package.timestamp: result[ATTR_TIMESTAMP] = timestamp.isoformat() return result async def _validate_service(hass: HomeAssistant, config_entry_id: str) -> None: entry: ConfigEntry | None = hass.config_entries.async_get_entry(config_entry_id) if not entry: raise ServiceValidationError( translation_domain=DOMAIN, translation_key="invalid_config_entry", translation_placeholders={ "config_entry_id": config_entry_id, }, ) if entry.state != ConfigEntryState.LOADED: raise ServiceValidationError( translation_domain=DOMAIN, translation_key="unloaded_config_entry", translation_placeholders={ "config_entry_id": entry.title, }, ) @callback def async_setup_services(hass: HomeAssistant) -> None: """Set up the services for the seventeentrack integration.""" hass.services.async_register( DOMAIN, SERVICE_GET_PACKAGES, _get_packages, schema=SERVICE_GET_PACKAGES_SCHEMA, supports_response=SupportsResponse.ONLY, ) hass.services.async_register( DOMAIN, SERVICE_ADD_PACKAGE, _add_package, schema=SERVICE_ADD_PACKAGE_SCHEMA, ) hass.services.async_register( DOMAIN, SERVICE_ARCHIVE_PACKAGE, _archive_package, schema=SERVICE_ARCHIVE_PACKAGE_SCHEMA, )