diff --git a/inpost/api.py b/inpost/api.py index 0aac53a..f0d3e7a 100644 --- a/inpost/api.py +++ b/inpost/api.py @@ -1,8 +1,9 @@ +import logging +from typing import List + from aiohttp import ClientSession, ClientResponse from aiohttp.typedefs import StrOrURL -from typing import List -import logging -from arrow import utcnow + from inpost.static import * @@ -77,6 +78,9 @@ async def request( if autorefresh and resp.status == 401: await self.refresh_token() + headers_.update( + {'Authorization': self.auth_token} + ) resp = await self.sess.request(method, url, headers=headers_, json=data, **kwargs) match resp.status: @@ -107,6 +111,17 @@ async def from_phone_number(cls, phone_number: str | int): inp._log.info(f'initialized by from_phone_number') return inp + @classmethod + async def from_dict(cls, data: dict): + inp = cls() + await inp.set_phone_number(data['phone_number']) + inp.sms_code = data['sms_code'] + inp.auth_token = data['auth_token'] + inp.refr_token = data['refr_token'] + + inp._log.info(f'initialized by from_dict') + return inp + async def set_phone_number(self, phone_number: str | int) -> bool: """Set :class:`Inpost` phone number required for verification @@ -502,7 +517,7 @@ async def open_compartment(self) -> bool: self._log.debug(f'authorization token missing') raise NotAuthenticatedError(reason='Not logged in') - resp = await self.request(method='get', + resp = await self.request(method='post', action=f"open compartment for {self.parcel.shipment_number}", url=compartment_open, auth=True, @@ -634,6 +649,33 @@ async def close_compartment(self) -> bool: return False + async def reopen_compartment(self) -> bool: + """Reopens compartment for `Inpost.parcel` object + + :return: True if compartment gets reopened + :rtype: bool + :raises NotAuthenticatedError: User not authenticated in inpost service + :raises UnauthorizedError: Unauthorized access to inpost services, + :raises NotFoundError: Phone number not found + :raises UnidentifiedAPIError: Unexpected thing happened""" + self._log.info(f'reopening compartment for {self.parcel.shipment_number}') + + if not self.auth_token: + self._log.debug(f'authorization token missing') + raise NotAuthenticatedError(reason='Not logged in') + + resp = await self.request(method='post', + action=f"reopen compartment for {self.parcel.shipment_number}", + url=compartment_open, + auth=True, + headers=None, + data={'sessionUuid': self.parcel.compartment_properties.session_uuid}, + autorefresh=True) + + if resp.status == 200: + self._log.debug(f'opened compartment for {self.parcel.shipment_number}') + return True + async def get_prices(self) -> dict: """Fetches prices for inpost services diff --git a/inpost/static/endpoints.py b/inpost/static/endpoints.py index c2e946b..d47f0cc 100644 --- a/inpost/static/endpoints.py +++ b/inpost/static/endpoints.py @@ -9,6 +9,7 @@ parcel: str = 'https://api-inmobile-pl.easypack24.net/v3/parcels/tracked/' # get multi: str = 'https://api-inmobile-pl.easypack24.net/v3/parcels/multi/' # get collect: str = 'https://api-inmobile-pl.easypack24.net/v1/collect/validate' # post +reopen: str = 'https://api-inmobile-pl.easypack24.net/v1/collect/compartment/reopen' # post compartment_open: str = 'https://api-inmobile-pl.easypack24.net/v1/collect/compartment/open' # post compartment_status: str = 'https://api-inmobile-pl.easypack24.net/v1/collect/compartment/status' # post terminate_collect_session: str = 'https://api-inmobile-pl.easypack24.net/v1/collect/terminate' # post diff --git a/inpost/static/parcels.py b/inpost/static/parcels.py index 687ca79..a396766 100644 --- a/inpost/static/parcels.py +++ b/inpost/static/parcels.py @@ -11,11 +11,9 @@ class BaseParcel: def __init__(self, parcel_data: dict, logger: logging.Logger): - self.shipment_number: str = parcel_data['shipmentNumber'] + self.shipment_number: str = parcel_data.get('shipmentNumber') self._log: logging.Logger = logger.getChild(f'{__class__.__name__}.{self.shipment_number}') self.status: ParcelStatus = ParcelStatus[parcel_data['status']] - # self.parcel_size: ParcelLockerSize | ParcelCarrierSize = ParcelLockerSize[parcel_data['parcelSize']] \ - # if self.shipment_type == ParcelShipmentType.parcel else ParcelCarrierSize[parcel_data['parcelSize']] self.expiry_date: arrow | None = get(parcel_data['expiryDate']) if 'expiryDate' in parcel_data else None self.operations: Operations = Operations(operations_data=parcel_data['operations'], logger=self._log) self.event_log: List[EventLog] = [EventLog(eventlog_data=event, logger=self._log) @@ -33,32 +31,28 @@ class Parcel(BaseParcel): def __init__(self, parcel_data: dict, logger: logging.Logger): """Constructor method""" super().__init__(parcel_data, logger) - # self.shipment_number: str = parcel_data['shipmentNumber'] self._log: logging.Logger = logger.getChild(f'{__class__.__name__}.{self.shipment_number}') self.shipment_type: ParcelShipmentType = ParcelShipmentType[parcel_data['shipmentType']] - self._open_code: str | None = parcel_data['openCode'] if 'openCode' in parcel_data else None + self._open_code: str | None = parcel_data.get('openCode', None) self._qr_code: QRCode | None = QRCode(qrcode_data=parcel_data['qrCode'], logger=self._log) \ if 'qrCode' in parcel_data else None self.stored_date: arrow | None = get(parcel_data['storedDate']) if 'storedDate' in parcel_data else None self.pickup_date: arrow | None = get(parcel_data['pickUpDate']) if 'pickUpDate' in parcel_data else None - # self.expiry_date: arrow | None = get(parcel_data['expiryDate']) if 'expiryDate' in parcel_data else None self.parcel_size: ParcelLockerSize | ParcelCarrierSize = ParcelLockerSize[parcel_data['parcelSize']] \ if self.shipment_type == ParcelShipmentType.parcel else ParcelCarrierSize[parcel_data['parcelSize']] - self.receiver: Receiver = Receiver(receiver_data=parcel_data['receiver'], logger=self._log) - self.sender: Sender = Sender(sender_data=parcel_data['sender'], logger=self._log) + self.receiver: Receiver = Receiver(receiver_data=parcel_data['receiver'], logger=self._log) if 'receiver' in parcel_data else None + self.sender: Sender = Sender(sender_data=parcel_data['sender'], logger=self._log) if 'sender' in parcel_data else None self.pickup_point: PickupPoint = PickupPoint(pickuppoint_data=parcel_data['pickUpPoint'], logger=self._log) \ if 'pickUpPoint' in parcel_data else None self.multi_compartment: MultiCompartment | None = MultiCompartment( parcel_data['multiCompartment'], logger=self._log) if 'multiCompartment' in parcel_data else None - self.is_end_off_week_collection: bool = parcel_data['endOfWeekCollection'] - # self.operations: Operations = Operations(operations_data=parcel_data['operations'], logger=self._log) - self.status: ParcelStatus = ParcelStatus[parcel_data['status']] - # self.event_log: List[EventLog] = [EventLog(eventlog_data=event, logger=self._log) - # for event in parcel_data['eventLog']] - self.avizo_transaction_status: str = parcel_data['avizoTransactionStatus'] + self.is_end_off_week_collection: bool | None = parcel_data.get('endOfWeekCollection', None) + self.status: ParcelStatus = ParcelStatus[parcel_data['status']] if 'status' in parcel_data else None + self.avizo_transaction_status: str | None = parcel_data.get('avizoTransactionStatus', None) self.shared_to: List[SharedTo] = [SharedTo(sharedto_data=person, logger=self._log) - for person in parcel_data['sharedTo']] - self.ownership_status: ParcelOwnership = ParcelOwnership[parcel_data['ownershipStatus']] + for person in parcel_data['sharedTo']] if 'sharedTo' in parcel_data else None + self.ownership_status: ParcelOwnership = ParcelOwnership[parcel_data['ownershipStatus']] if 'ownershipStatus' in parcel_data else None + self.economy_parcel: bool | None = parcel_data.get('economyParcel', None) self._compartment_properties: CompartmentProperties | None = None self._log.debug(f'created parcel with shipment number {self.shipment_number}') @@ -338,6 +332,7 @@ def __init__(self, pickuppoint_data: dict, logger: logging.Logger): self.image_url: str = pickuppoint_data['imageUrl'] self.easy_access_zone: bool = pickuppoint_data['easyAccessZone'] self.air_sensor: bool = pickuppoint_data['airSensor'] + self.air_sensor_data: AirSensorData | None = AirSensorData(pickuppoint_data['airSensorData']) if 'airSensorData' in pickuppoint_data else None self._log: logging.Logger = logger.getChild(__class__.__name__) self._log.debug('created') @@ -604,3 +599,25 @@ def status(self, status_data: str | CompartmentActualStatus): if self._status == CompartmentActualStatus.UNKNOWN and isinstance(status_data, str): self._log.debug(f'unexpected compartment actual status: {status_data}') + + +class AirSensorData: + """Object representation of :class:`Parcel` air sensor data + + :param airsensor_data: :class:`dict` containing air sensor data for :class:`Parcel` + :type airsensor_data: dict + :param logger: :class:`logging.Logger` parent instance + :type logger: logging.Logger""" + def __init__(self, airsensor_data: dict, logger: logging.Logger): + self.updated_until: arrow = airsensor_data['updatedUntil'] + self.air_quality: str = airsensor_data['airQuality'] + self.temperature: float = airsensor_data['temperature'] + self.humidity: float = airsensor_data['humidity'] + self.pressure: float = airsensor_data['pressure'] + self.pm25_value: float = airsensor_data['pollutants']['pm25']['value'] + self.pm25_percent: float = airsensor_data['pollutants']['pm25']['percent'] + self.pm10_value: float = airsensor_data['pollutants']['pm10']['value'] + self.pm10_percent: float = airsensor_data['pollutants']['pm10']['percent'] + + self._log: logging.Logger = logger.getChild(__class__.__name__) + self._log.debug('created') diff --git a/pyproject.toml b/pyproject.toml index 605d51f..55d577e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "inpost" -version = "0.0.10" +version = "0.1.2" description = "Asynchronous InPost package allowing you to manage existing incoming parcels without mobile app" authors = ["loboda4450 ", "MrKazik99 "] maintainers = ["loboda4450 "] @@ -13,6 +13,7 @@ packages = [ ] classifiers = [ "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Framework :: aiohttp", "Intended Audience :: Developers", "Operating System :: Microsoft :: Windows",