Example #1
0
    def get_parcel_tracking(self, _id):
        # 13 is the magic length of colissimo tracking ids
        if len(_id) != 13:
            raise ParcelNotFound(
                u"Colissimo ID's must have 13 print character")
        data = self.browser.get_tracking_info(_id)
        p = Parcel(_id)
        label = data['message']
        if data['error']:
            raise ParcelNotFound(label + u" (id = %s@%s)" % (_id, self.name))
        p.info = label
        # TODO, need to know the delivery message
        if u"remis au gardien ou" in label or u"Votre colis est livré" in label:
            p.status = p.STATUS_ARRIVED
        elif u"pas encore pris en charge par La Poste" in label:
            p.status = p.STATUS_PLANNED
        else:
            p.status = p.STATUS_IN_TRANSIT

        ev = Event(0)
        ev.activity = label
        ev.date = date(*reversed([int(x) for x in data['date'].split("/")]))
        p.history = [ev]

        return p
Example #2
0
 def get_info(self, _id):
     if u'errors' in self.doc:
         raise ParcelNotFound("No such ID: %s" % _id)
     elif u'results' in self.doc:
         result = self.doc[u'results'][0]
         p = Parcel(_id)
         p.history = [self.build_event(e) for e in result[u'checkpoints']]
         p.status = self.STATUSES.get(result[u'delivery'][u'code'], Parcel.STATUS_UNKNOWN)
         p.info = p.history[0].activity
         return p
     else:
         raise ParcelNotFound("Unexpected reply from server")
Example #3
0
    def get_info(self, _id):
        result_id = self.doc.xpath('//th[@class="mm_sendungsnummer"]')
        if not result_id:
            raise ParcelNotFound("No such ID: %s" % _id)
        result_id = result_id[0].text
        if result_id != _id:
            raise ParcelNotFound("ID mismatch: expecting %s, got %s" %
                                 (_id, result_id))

        p = Parcel(_id)
        events = self.doc.xpath(
            '//div[@class="accordion-inner"]/table/tbody/tr')
        p.history = [self.build_event(i, tr) for i, tr in enumerate(events)]
        p.status, p.info = self.guess_status(p.history[-1])
        return p
Example #4
0
 def get_tracking_info(self, _id):
     self.tracking_url.stay_or_go(_id=_id)
     events = list(self.page.iter_infos())
     if len(events) == 0:
         error = self.page.get_error()
         raise ParcelNotFound(u"Parcel not found: {}".format(error))
     return events
Example #5
0
    def get_info(self, _id):
        result_id = self.doc.get("TrackingStatusJSON", {}).get("shipmentInfo", {}).get("parcelNumber", None)
        if not result_id:
            raise ParcelNotFound("No such ID: %s" % _id)
        if not _id.startswith(result_id):
            raise ParcelNotFound("ID mismatch: expecting %s, got %s" % (_id, result_id))

        p = Parcel(_id)
        events = self.doc.get("TrackingStatusJSON", {}).get("statusInfos", [])
        p.history = [self.build_event(i, data) for i, data in enumerate(events)]
        p.status = self.guess_status(
            self.doc.get("TrackingStatusJSON", {}).
            get("shipmentInfo", {}).
            get("deliveryStatus"))
        p.info = p.history[-1].activity
        return p
Example #6
0
    def get_info(self, _id):
        result_id = self.doc.xpath(
            '//table[@id="shipment-details-table"]//tr[position()=1]/td[@id="td-bold"]'
        )
        if not result_id:
            raise ParcelNotFound("No such ID: %s" % _id)
        result_id = result_id[0].text
        if result_id != _id:
            raise ParcelNotFound("ID mismatch: expecting %s, got %s" %
                                 (_id, result_id))

        p = Parcel(_id)
        events = self.doc.xpath('//div[@id="shipment-event-table-cell"]')
        p.history = [self.build_event(i, div) for i, div in enumerate(events)]
        most_recent = p.history[0]
        p.status, p.info = self.guess_status(p.history)
        p.info = most_recent.activity
        return p
Example #7
0
    def get_info(self, _id):
        result_id = self.doc.xpath('//th[@class="mm_sendungsnummer"]')
        if not result_id:
            raise ParcelNotFound("No such ID: %s" % _id)
        result_id = result_id[0].text
        if result_id != _id:
            raise ParcelNotFound("ID mismatch: expecting %s, got %s" % (_id, result_id))

        p = Parcel(_id)
        events = self.doc.xpath('//div[@class="accordion-inner"]/table/tbody/tr')
        p.history = [self.build_event(i, tr) for i, tr in enumerate(events)]
        status_msgs = self.doc.xpath('//tr[@class="mm_mailing_process "]//img[contains(@src, "ACTIVE")]/@alt')
        if len(status_msgs) > 0:
            p.status = self.STATUSES.get(status_msgs[-1], Parcel.STATUS_UNKNOWN)
        else:
            p.status = Parcel.STATUS_UNKNOWN
        p.info = p.history[-1].activity
        return p
Example #8
0
    def get_info(self, _id):
        shipments = self.doc["shipments"]
        if not shipments:
            raise ParcelNotFound("No such ID: %s" % _id)
        shipment = shipments[0]
        result_id = shipment["trackingCode"]
        if result_id != _id:
            raise ParcelNotFound("ID mismatch: expecting %s, got %s" %
                                 (_id, result_id))

        p = Parcel(_id)
        if shipment["estimatedDeliveryTime"]:
            p.arrival = parse_date(shipment["estimatedDeliveryTime"],
                                   ignoretz=True)
        events = shipment["events"]
        p.history = [
            self.build_event(i, data) for i, data in enumerate(events)
        ]
        most_recent = p.history[0]
        p.status, p.info = self.guess_status(p.history)
        p.info = most_recent.activity
        return p
Example #9
0
    def iter_events(self, merchant, code, name):
        data = dict(codeEnseigne=merchant,
                    nomClient=name,
                    typeRecherche='EXP',
                    valeur=code)
        # Ref: https://www.relaiscolis.com/js/lib/suivi.js
        req = self.open('/suivi-de-colis/index/tracking/', data=data)
        resp = None
        try:
            resp = req.json()
            if resp and 'error' in resp:
                raise ParcelNotFound(resp['error']['msg'])
        except (ValueError, KeyError):
            self.raise_for_status(req)
            raise
        else:
            self.raise_for_status(req)

        def ensure_list(data):
            if isinstance(data, list):
                return data
            return [data]

        parcel_data = ensure_list(resp['Colis']['Colis'])[-1]
        events_data = ensure_list(parcel_data['ListEvenements'].get(
            'Evenement', []))

        final_location = None
        try:
            relay = resp['Relais']['Relais']
            name = relay['Nom'].strip()
            city = relay['Commune'].strip()
            final_location = ' '.join((name, city))
        except KeyError:
            pass

        for event_data in events_data:
            event = Event()
            event.date = parse_date(event_data['Date'].strip())
            event.activity = event_data['Libelle'].strip()

            if final_location and ("Votre colis est disponible"
                                   in event.activity):
                event.location = final_location
            yield event
Example #10
0
    def get_parcel_tracking(self, id):
        """
        Get information abouut a parcel.

        :param id: ID of the parcel
        :type id: :class:`str`
        :rtype: :class:`Parcel`
        :raises: :class:`ParcelNotFound`
        """
        self._browser = None
        if len(id) == 10 or len(id) == 20:
            self.BROWSER = DHLExpressBrowser
        elif len(id) == 12 or len(id) == 16:
            self.BROWSER = DeutschePostDHLBrowser
        else:
            ParcelNotFound("Wrong length for ID: %s" % id)

        return self.browser.get_tracking_info(id)
Example #11
0
    def get_parcel_tracking(self, _id):
        # 13 is the magic length of colissimo tracking ids
        if len(_id) != 13:
            raise ParcelNotFound(u"Colissimo ID's must have 13 print character")

        events = self.browser.get_tracking_info(_id)
        p = Parcel(_id)
        p.history = events

        first = events[0]
        p.info = first.activity

        if u"remis au gardien ou" in p.info or u"Votre colis est livré" in p.info:
            p.status = p.STATUS_ARRIVED
        elif u"pas encore pris en charge par La Poste" in p.info:
            p.status = p.STATUS_PLANNED
        else:
            p.status = p.STATUS_IN_TRANSIT

        return p
Example #12
0
 def get_info(self, _id):
     raise ParcelNotFound("No such ID: %s" % _id)
Example #13
0
    def get_parcel_tracking(self, _id):
        """
        Get information about a parcel.

        :param _id: _id of the parcel
        :type _id: :class:`str`
        :rtype: :class:`Parcel`
        :raises: :class:`ParcelNotFound`
        """
        # Tracking number format:
        # - 2 chars: optional merchant identifier (eg, AM for Amazon, 85 for cdiscount, ...)
        # - 10 digits: shipment tracking number
        # - 2 digits: optional suffix, seems to always be "01" when present but is never sent to the API
        #
        # Many merchants seem to give only the 10 digits tracking number so the user needs to
        # manually select the merchant from a list in that case.

        merchant = None
        code = None

        _id = _id.strip().upper()

        if len(_id) == 10:
            code = _id
        elif len(_id) in (12, 14):
            merchant = _id[:2]
            code = _id[2:12]
        else:
            raise ParcelNotFound(
                "Tracking number must be 10, 12 or 14 characters long.")

        merchant = merchant or self.config['merchant'].get()

        if not merchant:
            # No merchant info in the tracking number
            # we have to ask the user to select it
            merchants = self.browser.get_merchants()
            raise BrowserQuestion(
                Value(
                    'merchant',
                    label='Merchant prefix (prepend to tracking number): ',
                    tiny=False,
                    choices=merchants,
                ))

        self.config['merchant'].set(None)
        name = self.config['last_name'].get()[:4].ljust(4).upper()

        events = list(self.browser.iter_events(merchant, code, name))

        parcel = Parcel(merchant + code)
        parcel.arrival = NotAvailable

        # This is what the legacy tracking website used to show
        # when there are no events yet
        parcel.info = "Votre commande est en cours d'acheminement dans notre réseau."

        parcel.history = events
        parcel.status = Parcel.STATUS_IN_TRANSIT

        if not events:
            parcel.status = Parcel.STATUS_PLANNED
            return parcel

        parcel.info = events[0].activity

        arrived_event = next(
            (event for event in events
             if "Votre colis est disponible" in event.activity), None)

        if arrived_event:
            parcel.status = Parcel.STATUS_ARRIVED
            parcel.arrival = arrived_event.date

        return parcel
Example #14
0
 def parse(self, el):
     error = CleanText('//div[has-class("ch-colis-information")]')(el)
     if "pas d'information" in error:
         raise ParcelNotFound(error)
Example #15
0
 def get_tracking_info(self, _id):
     try:
         return self.search_page.go(id=_id).get_info(_id)
     except HTTPNotFound:
         raise ParcelNotFound("No such ID: %s" % _id)