M README.md => README.md +1 -0
@@ 8,6 8,7 @@ A python library and a GTK3 mobile/desktop application for tracking multiple shi
Supported carriers
------------------
+* 4PX
* DHL (needs api code)
* InPost
* PostNL
M data/org.postmarketos.Shipments.appdata.xml => data/org.postmarketos.Shipments.appdata.xml +1 -0
@@ 11,6 11,7 @@
Application to track your shipments. Supported carriers:
</p>
<ul>
+ <li>4PX</li>
<li>DHL (needs api code)</li>
<li>InPost</li>
<li>PostNL</li>
M shipments/carrier.py => shipments/carrier.py +59 -1
@@ 1,4 1,4 @@
-from datetime import datetime
+from datetime import datetime, timezone, timedelta
import requests
@@ 434,3 434,61 @@ class DHL(Carrier):
result.destination = self._addr(payload['destination'])
return result
+
+
+class Track4PX(Carrier):
+ DISPLAYNAME = '4PX'
+
+ @classmethod
+ def identify(cls, code):
+ if len(code) != 20:
+ return False
+ if not code.startswith('H'):
+ return False
+ if not code[1:].isnumeric():
+ return False
+ return True
+
+ def get_info(self, code, extra):
+ url = 'https://track.4px.com/track/v2/front/listTrack'
+ data = {
+ 'serveCodes': [code],
+ 'language': 'en-us',
+ }
+ response = requests.post(url, json=data)
+ payload = response.json()
+ result = PackageInfo(code, 'Track4PX')
+ result.carrier_name = self.DISPLAYNAME
+ result.status_category = StatusCategory.ERROR
+ result.tracking_url = 'https://track.4px.com/#/result/0/' + code
+
+ if 'data' in payload and len(payload['data']):
+ payload = payload['data'][0]
+ else:
+ result.status = payload['message']
+ return result
+
+ if payload['status'] == 0:
+ result.status_category = StatusCategory.ERROR
+ result.status = 'error'
+ elif payload['status'] == 1:
+ result.status_category = StatusCategory.IN_TRANSIT
+ result.status = 'In transit'
+ else:
+ result.status_category = StatusCategory.DELIVERED
+ result.status = 'Delivered'
+
+ for event in payload['tracks']:
+ _, tz = event['tkTimezone'].split('+')
+ tz_hour, tz_min = tz.split(':')
+ stamp = datetime.fromtimestamp(event['tkDate'] / 1000,
+ tz=timezone(timedelta(hours=int(tz_hour, 10), minutes=int(tz_min, 10))))
+ e = PackageEvent(stamp, event['tkLocation'], event['tkDesc'])
+ result.events.append(e)
+
+ result.origin = Address()
+ result.origin.country = payload['ctStartName']
+ result.destination = Address()
+ result.destination.country = payload['ctEndName']
+
+ return result