2015-10-31 16:40:23 +00:00
""" Postal tracking module """
# PYTHON STUFF ############################################
2017-07-08 12:38:24 +00:00
import json
2015-07-13 21:20:10 +00:00
import urllib . parse
from bs4 import BeautifulSoup
2015-10-28 19:55:02 +00:00
import re
2015-07-13 21:20:10 +00:00
from nemubot . hooks import hook
2015-10-30 20:57:45 +00:00
from nemubot . exception import IMException
2017-07-08 12:38:24 +00:00
from nemubot . tools . web import getURLContent , getJSON
2015-07-13 21:20:10 +00:00
from more import Response
2015-10-27 21:19:12 +00:00
# POSTAGE SERVICE PARSERS ############################################
2015-07-13 21:20:10 +00:00
2015-10-29 01:10:46 +00:00
def get_tnt_info ( track_id ) :
2015-10-30 19:55:02 +00:00
values = [ ]
2017-07-07 04:38:00 +00:00
data = getURLContent ( ' www.tnt.fr/public/suivi_colis/recherche/visubontransport.do?bonTransport= %s ' % track_id )
2015-10-29 01:10:46 +00:00
soup = BeautifulSoup ( data )
2015-10-30 19:55:02 +00:00
status_list = soup . find ( ' div ' , class_ = ' result__content ' )
if not status_list :
return None
last_status = status_list . find ( ' div ' , class_ = ' roster ' )
if last_status :
for info in last_status . find_all ( ' div ' , class_ = ' roster__item ' ) :
values . append ( info . get_text ( ) . strip ( ) )
if len ( values ) == 3 :
return ( values [ 0 ] , values [ 1 ] , values [ 2 ] )
2015-10-29 01:10:46 +00:00
2015-07-13 21:20:10 +00:00
def get_colissimo_info ( colissimo_id ) :
2017-07-07 04:38:00 +00:00
colissimo_data = getURLContent ( " http://www.colissimo.fr/portail_colissimo/suivre.do?colispart= %s " % colissimo_id )
2015-07-13 21:20:10 +00:00
soup = BeautifulSoup ( colissimo_data )
dataArray = soup . find ( class_ = ' dataArray ' )
if dataArray and dataArray . tbody and dataArray . tbody . tr :
date = dataArray . tbody . tr . find ( headers = " Date " ) . get_text ( )
2015-10-28 19:55:02 +00:00
libelle = re . sub ( r ' [ \ n \ t \ r] ' , ' ' ,
dataArray . tbody . tr . find ( headers = " Libelle " ) . get_text ( ) )
2015-07-13 21:20:10 +00:00
site = dataArray . tbody . tr . find ( headers = " site " ) . get_text ( ) . strip ( )
return ( date , libelle , site . strip ( ) )
2015-10-28 19:55:02 +00:00
2015-09-15 22:23:42 +00:00
def get_chronopost_info ( track_id ) :
data = urllib . parse . urlencode ( { ' listeNumeros ' : track_id } )
2017-07-07 04:38:00 +00:00
track_baseurl = " http://www.chronopost.fr/expedier/inputLTNumbersNoJahia.do?lang=fr_FR "
track_data = getURLContent ( track_baseurl , data . encode ( ' utf-8 ' ) )
2015-09-15 22:23:42 +00:00
soup = BeautifulSoup ( track_data )
infoClass = soup . find ( class_ = ' numeroColi2 ' )
if infoClass and infoClass . get_text ( ) :
info = infoClass . get_text ( ) . split ( " \n " )
if len ( info ) > = 1 :
info = info [ 1 ] . strip ( ) . split ( " \" " )
if len ( info ) > = 2 :
date = info [ 2 ]
libelle = info [ 1 ]
return ( date , libelle )
2015-10-28 19:55:02 +00:00
2015-09-15 22:23:42 +00:00
def get_colisprive_info ( track_id ) :
data = urllib . parse . urlencode ( { ' numColis ' : track_id } )
2017-07-07 04:38:00 +00:00
track_baseurl = " https://www.colisprive.com/moncolis/pages/detailColis.aspx "
track_data = getURLContent ( track_baseurl , data . encode ( ' utf-8 ' ) )
2015-09-15 22:23:42 +00:00
soup = BeautifulSoup ( track_data )
dataArray = soup . find ( class_ = ' BandeauInfoColis ' )
2015-10-28 19:55:02 +00:00
if ( dataArray and dataArray . find ( class_ = ' divStatut ' )
and dataArray . find ( class_ = ' divStatut ' ) . find ( class_ = ' tdText ' ) ) :
status = dataArray . find ( class_ = ' divStatut ' ) \
. find ( class_ = ' tdText ' ) . get_text ( )
2015-09-15 22:23:42 +00:00
return status
2015-10-28 19:55:02 +00:00
2015-07-13 21:20:10 +00:00
def get_laposte_info ( laposte_id ) :
2015-09-15 22:23:42 +00:00
data = urllib . parse . urlencode ( { ' id ' : laposte_id } )
laposte_baseurl = " http://www.part.csuivi.courrier.laposte.fr/suivi/index "
2017-07-07 04:38:00 +00:00
laposte_data = getURLContent ( laposte_baseurl , data . encode ( ' utf-8 ' ) )
2015-07-13 21:20:10 +00:00
soup = BeautifulSoup ( laposte_data )
search_res = soup . find ( class_ = ' resultat_rech_simple_table ' ) . tbody . tr
if ( soup . find ( class_ = ' resultat_rech_simple_table ' ) . thead
2015-09-15 22:23:42 +00:00
and soup . find ( class_ = ' resultat_rech_simple_table ' ) . thead . tr
and len ( search_res . find_all ( ' td ' ) ) > 3 ) :
2015-07-13 21:20:10 +00:00
field = search_res . find ( ' td ' )
poste_id = field . get_text ( )
field = field . find_next ( ' td ' )
poste_type = field . get_text ( )
field = field . find_next ( ' td ' )
poste_date = field . get_text ( )
field = field . find_next ( ' td ' )
poste_location = field . get_text ( )
field = field . find_next ( ' td ' )
poste_status = field . get_text ( )
2015-09-15 22:23:42 +00:00
2015-10-28 19:55:02 +00:00
return ( poste_type . lower ( ) , poste_id . strip ( ) , poste_status . lower ( ) ,
poste_location , poste_date )
2015-07-13 21:20:10 +00:00
2015-09-17 23:23:42 +00:00
2017-07-02 17:08:01 +00:00
def get_postnl_info ( postnl_id ) :
data = urllib . parse . urlencode ( { ' barcodes ' : postnl_id } )
postnl_baseurl = " http://www.postnl.post/details/ "
2017-07-07 04:38:00 +00:00
postnl_data = getURLContent ( postnl_baseurl , data . encode ( ' utf-8 ' ) )
2017-07-02 17:08:01 +00:00
soup = BeautifulSoup ( postnl_data )
if ( soup . find ( id = ' datatables ' )
and soup . find ( id = ' datatables ' ) . tbody
and soup . find ( id = ' datatables ' ) . tbody . tr ) :
search_res = soup . find ( id = ' datatables ' ) . tbody . tr
if len ( search_res . find_all ( ' td ' ) ) > = 3 :
field = field . find_next ( ' td ' )
post_date = field . get_text ( )
field = field . find_next ( ' td ' )
post_status = field . get_text ( )
field = field . find_next ( ' td ' )
post_destination = field . get_text ( )
return ( post_status . lower ( ) , post_destination , post_date )
2017-07-08 12:38:24 +00:00
def get_fedex_info ( fedex_id , lang = " en_US " ) :
data = urllib . parse . urlencode ( {
' data ' : json . dumps ( {
" TrackPackagesRequest " : {
" appType " : " WTRK " ,
" appDeviceType " : " DESKTOP " ,
" uniqueKey " : " " ,
" processingParameters " : { } ,
" trackingInfoList " : [
{
" trackNumberInfo " : {
" trackingNumber " : str ( fedex_id ) ,
" trackingQualifier " : " " ,
" trackingCarrier " : " "
}
}
]
}
} ) ,
' action ' : " trackpackages " ,
' locale ' : lang ,
' version ' : 1 ,
' format ' : " json "
} )
fedex_baseurl = " https://www.fedex.com/trackingCal/track "
fedex_data = getJSON ( fedex_baseurl , data . encode ( ' utf-8 ' ) )
if ( " TrackPackagesResponse " in fedex_data and
" packageList " in fedex_data [ " TrackPackagesResponse " ] and
len ( fedex_data [ " TrackPackagesResponse " ] [ " packageList " ] )
) :
return fedex_data [ " TrackPackagesResponse " ] [ " packageList " ] [ 0 ]
2015-10-27 21:19:12 +00:00
# TRACKING HANDLERS ###################################################
2015-09-17 23:23:42 +00:00
2015-10-29 01:10:46 +00:00
def handle_tnt ( tracknum ) :
info = get_tnt_info ( tracknum )
if info :
2015-10-30 19:55:02 +00:00
status , date , place = info
placestr = ' '
if place :
placestr = ' à \x02 {place} \x0f '
2015-10-29 01:10:46 +00:00
return ( ' Le colis \x02 {trackid} \x0f a actuellement le status: '
2015-10-30 19:55:02 +00:00
' \x02 {status} \x0F mis à jour le \x02 {date} \x0f {place} . '
. format ( trackid = tracknum , status = status ,
date = re . sub ( r ' \ s+ ' , ' ' , date ) , place = placestr ) )
2015-10-29 01:10:46 +00:00
2015-10-27 21:19:12 +00:00
def handle_laposte ( tracknum ) :
info = get_laposte_info ( tracknum )
2015-09-17 23:23:42 +00:00
if info :
2015-10-27 21:19:12 +00:00
poste_type , poste_id , poste_status , poste_location , poste_date = info
2015-10-28 19:55:02 +00:00
return ( " Le courrier de type \x02 %s \x0F : \x02 %s \x0F est actuellement "
" \x02 %s \x0F dans la zone \x02 %s \x0F (Mis à jour le \x02 %s \x0F "
" ). " % ( poste_type , poste_id , poste_status ,
poste_location , poste_date ) )
2015-09-17 23:23:42 +00:00
2017-07-02 17:08:01 +00:00
def handle_postnl ( tracknum ) :
info = get_postnl_info ( tracknum )
if info :
post_status , post_destination , post_date = info
return ( " PostNL \x02 %s \x0F est actuellement "
" \x02 %s \x0F vers le pays \x02 %s \x0F (Mis à jour le \x02 %s \x0F "
" ). " % ( tracknum , post_status , post_destination , post_date ) )
2015-10-27 21:19:12 +00:00
def handle_colissimo ( tracknum ) :
info = get_colissimo_info ( tracknum )
2015-09-17 23:23:42 +00:00
if info :
date , libelle , site = info
2015-10-28 19:55:02 +00:00
return ( " Colissimo: \x02 %s \x0F : \x02 %s \x0F Dernière mise à jour le "
" \x02 %s \x0F au site \x02 %s \x0F . "
% ( tracknum , libelle , date , site ) )
2015-09-17 23:23:42 +00:00
2015-10-27 21:19:12 +00:00
def handle_chronopost ( tracknum ) :
info = get_chronopost_info ( tracknum )
2015-09-17 23:23:42 +00:00
if info :
2015-10-27 21:19:12 +00:00
date , libelle = info
2015-10-28 19:55:02 +00:00
return ( " Colis Chronopost: \x02 %s \x0F : \x02 %s \x0F . Dernière mise à "
" jour \x02 %s \x0F . " % ( tracknum , libelle , date ) )
2015-09-17 23:23:42 +00:00
2015-10-27 21:19:12 +00:00
def handle_coliprive ( tracknum ) :
info = get_colisprive_info ( tracknum )
2015-09-15 22:23:42 +00:00
if info :
2015-10-27 21:19:12 +00:00
return ( " Colis Privé: \x02 %s \x0F : \x02 %s \x0F . " % ( tracknum , info ) )
2015-09-15 22:23:42 +00:00
2015-10-31 16:40:23 +00:00
2017-07-08 12:38:24 +00:00
def handle_fedex ( tracknum ) :
info = get_fedex_info ( tracknum )
if info :
if info [ " displayActDeliveryDateTime " ] != " " :
return ( " {trackingCarrierDesc} : \x02 {statusWithDetails} \x0F : in \x02 {statusLocationCity} , {statusLocationCntryCD} \x0F , delivered on: {displayActDeliveryDateTime} . " . format ( * * info ) )
elif info [ " statusLocationCity " ] != " " :
return ( " {trackingCarrierDesc} : \x02 {statusWithDetails} \x0F : estimated delivery: {displayEstDeliveryDateTime} . " . format ( * * info ) )
else :
return ( " {trackingCarrierDesc} : \x02 {statusWithDetails} \x0F : in \x02 {statusLocationCity} , {statusLocationCntryCD} \x0F , estimated delivery: {displayEstDeliveryDateTime} . " . format ( * * info ) )
2015-10-27 21:19:12 +00:00
TRACKING_HANDLERS = {
' laposte ' : handle_laposte ,
2017-07-02 17:08:01 +00:00
' postnl ' : handle_postnl ,
2015-10-27 21:19:12 +00:00
' colissimo ' : handle_colissimo ,
' chronopost ' : handle_chronopost ,
2015-10-29 01:10:46 +00:00
' coliprive ' : handle_coliprive ,
2015-10-31 16:40:23 +00:00
' tnt ' : handle_tnt ,
2017-07-08 12:38:24 +00:00
' fedex ' : handle_fedex ,
2015-10-27 21:19:12 +00:00
}
2015-09-15 22:23:42 +00:00
2015-10-28 19:55:02 +00:00
2015-10-27 21:19:12 +00:00
# HOOKS ##############################################################
2015-07-13 21:20:10 +00:00
2015-11-02 19:19:12 +00:00
@hook.command ( " track " ,
2015-10-31 16:40:23 +00:00
help = " Track postage delivery " ,
help_usage = {
" TRACKING_ID [...] " : " Track the specified postage IDs on various tracking services. "
} ,
keywords = {
" tracker=TRK " : " Precise the tracker (default: all) among: " + ' , ' . join ( TRACKING_HANDLERS )
} )
2015-10-27 21:19:12 +00:00
def get_tracking_info ( msg ) :
2015-07-13 21:20:10 +00:00
if not len ( msg . args ) :
2015-10-30 20:57:45 +00:00
raise IMException ( " Renseignez un identifiant d ' envoi. " )
2015-10-27 21:19:12 +00:00
res = Response ( channel = msg . channel , count = " ( %d suivis supplémentaires) " )
if ' tracker ' in msg . kwargs :
if msg . kwargs [ ' tracker ' ] in TRACKING_HANDLERS :
trackers = {
msg . kwargs [ ' tracker ' ] : TRACKING_HANDLERS [ msg . kwargs [ ' tracker ' ] ]
}
else :
2015-10-30 20:57:45 +00:00
raise IMException ( " No tracker named \x02 {tracker} \x0F , please use "
2015-10-28 19:55:02 +00:00
" one of the following: \x02 {trackers} \x0F "
. format ( tracker = msg . kwargs [ ' tracker ' ] ,
trackers = ' , '
. join ( TRACKING_HANDLERS . keys ( ) ) ) )
2015-10-27 21:19:12 +00:00
else :
trackers = TRACKING_HANDLERS
for tracknum in msg . args :
2015-10-28 19:55:02 +00:00
for name , tracker in trackers . items ( ) :
2015-10-27 21:19:12 +00:00
ret = tracker ( tracknum )
if ret :
res . append_message ( ret )
break
if not ret :
2015-10-28 19:55:02 +00:00
res . append_message ( " L ' identifiant \x02 {id} \x0F semble incorrect, "
" merci de vérifier son exactitude. "
. format ( id = tracknum ) )
2015-10-27 21:19:12 +00:00
return res