blob: 1deaa64d88e038cbe79ccd30fa0fc6d2c509c8da (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
;;; delivery-track.el --- Track packages -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2024 Óscar Nájera
;;
;; Author: Óscar Nájera <hi@oscarnajera.com>
;; Maintainer: Óscar Nájera <hi@oscarnajera.com>
;; Created: August 28, 2024
;; Modified: August 28, 2024
;; Version: 0.0.1
;; Keywords: abbrev bib c calendar comm convenience data docs emulations extensions faces files frames games hardware help hypermedia i18n internal languages lisp local maint mail matching mouse multimedia news outlines processes terminals tex tools unix vc wp
;; Homepage: https://github.com/titan/delivery-track
;; Package-Requires: ((emacs "29.1"))
;;
;; This file is not part of GNU Emacs.
;;
;;; Commentary:
;;
;; Track packages
;;
;;; Code:
(require 'org)
(require 'org-id)
(require 'url)
(defvar url-http-end-of-headers)
(defun delivery-track-write-time! (timestring)
"Insert an org inactive timestamp from a parse-able TIMESTRING."
(thread-first
timestring
(parse-time-string)
(encode-time)
(org-insert-timestamp t t)))
(defun delivery-track-org--history (events window)
"String with all EVENTS and hint of delivery time WINDOW."
(with-temp-buffer
(insert "** Shipment reverse history\n")
(when window
(insert "Delivery window: ")
(delivery-track-write-time! (car window))
(insert "--")
(delivery-track-write-time! (cdr window))
(insert "\n"))
(seq-doseq (event events)
(seq-let (time status) event
(delivery-track-write-time! time)
(insert " " status "\n")))
(buffer-string)))
(defun delivery-track-org-entry (buffer shipment-id status events &optional window)
"Write update on BUFFER the SHIPMENT-ID with STATUS and EVENTS.
Optionally give the delivery WINDOW."
(with-current-buffer buffer
(goto-char (org-find-entry-with-id shipment-id))
(org-entry-put nil "status" status)
(org-next-visible-heading 1)
(seq-let (level _rlevel _todo _prio headline)
(org-heading-components)
(when (and (= level 2)
(string= "Shipment reverse history" headline))
(org-cut-subtree))
(insert (delivery-track-org--history events window)))))
(defun delivery-track--process-response (_request-status buffer provider-parser)
"Process API response with PROVIDER-PARSER and update into BUFFER."
(goto-char url-http-end-of-headers)
(apply #'delivery-track-org-entry
buffer
(funcall provider-parser (json-parse-buffer))))
(defun delivery-track-entry--dhl (response)
"Parse DHL RESPONSE into standard delivery-track info for writer."
(let* ((shipment-info (seq-find
(lambda (item)
(eq t (gethash "hasCompleteDetails" item)))
(gethash "sendungen" response)))
(details (gethash "sendungsdetails" shipment-info))
(history (gethash "sendungsverlauf" details))
(delivery (gethash "zustellung" details)))
(list
(gethash "id" shipment-info)
(gethash "kurzStatus" history)
(thread-last
(gethash "events" history)
(seq-keep (lambda (event)
(when-let ((time (gethash "datum" event)))
(list time (gethash "status" event)))))
(reverse))
(when-let ((from (gethash "zustellzeitfensterVon" delivery))
(to (gethash "zustellzeitfensterBis" delivery)))
(cons from to)))))
(defun delivery-track-entry--hermes (response)
"Parse hermes RESPONSE into standard delivery-track info for writer."
(list
(gethash "barcode" response)
(thread-last response (gethash "status") (gethash "parcelStatus"))
(thread-last
(gethash "parcelHistory" response)
(seq-keep (lambda (event)
(when-let ((time (gethash "timestamp" event)))
(list time (gethash "statusHistoryText" event)))))
(reverse))))
(defun delivery-track--dhl-de (track-id)
"Async request to dhl API using TRACK-ID.
Write update on the org-node in current buffer."
(let* ((url-request-method "GET")
(params `((piececode ,track-id)
("noRedirect" true)
(language "en"))))
(thread-first
"https://www.dhl.de/int-verfolgen/data/search?"
(concat (url-build-query-string params))
(url-retrieve #'delivery-track--process-response
(list (current-buffer) #'delivery-track-entry--dhl)))))
(defun delivery-track--hermes-de (track-id)
"Async request to hermes API using TRACK-ID.
Write update on the org-node in current buffer."
(let* ((url-request-method "GET")
(url-request-extra-headers
'(("User-Agent" . "Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0"))))
(thread-first
"https://api.my-deliveries.de/tnt/parcelservice/parceldetails/"
(concat track-id)
(url-retrieve #'delivery-track--process-response
(list (current-buffer) #'delivery-track-entry--hermes)))))
(defun delivery-track-update (track-id provider)
"Update tracking information for TRACK-ID under PROVIDER.
Interactive defaults to current buffer's org-node id and provider properties."
(interactive (list (read-string "What is the tracking id? " (org-id-get))
(completing-read "Which service provider? "
'(dhl hermes) nil t (org-entry-get nil "provider"))))
(pcase provider
("dhl" (delivery-track--dhl-de track-id ))
("hermes" (delivery-track--hermes-de track-id))))
(provide 'delivery-track)
;;; delivery-track.el ends here
|