karrio-server-events 2025.5rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. karrio/server/events/__init__.py +3 -0
  2. karrio/server/events/admin.py +3 -0
  3. karrio/server/events/apps.py +11 -0
  4. karrio/server/events/filters.py +63 -0
  5. karrio/server/events/migrations/0001_initial.py +65 -0
  6. karrio/server/events/migrations/0002_event.py +39 -0
  7. karrio/server/events/migrations/0003_auto_20220303_1210.py +25 -0
  8. karrio/server/events/migrations/0004_custom_migration_2022_4.py +41 -0
  9. karrio/server/events/migrations/0005_event_event_object_idx.py +18 -0
  10. karrio/server/events/migrations/0006_webhook_events_alter_event_data.py +85 -0
  11. karrio/server/events/migrations/0007_auto_20221130_0255.py +30 -0
  12. karrio/server/events/migrations/0008_alter_event_type.py +18 -0
  13. karrio/server/events/migrations/0009_alter_webhook_enabled_events.py +45 -0
  14. karrio/server/events/migrations/__init__.py +0 -0
  15. karrio/server/events/models.py +83 -0
  16. karrio/server/events/router.py +3 -0
  17. karrio/server/events/serializers/__init__.py +1 -0
  18. karrio/server/events/serializers/base.py +63 -0
  19. karrio/server/events/serializers/event.py +9 -0
  20. karrio/server/events/serializers/webhook.py +27 -0
  21. karrio/server/events/signals.py +138 -0
  22. karrio/server/events/task_definitions/__init__.py +1 -0
  23. karrio/server/events/task_definitions/base/__init__.py +64 -0
  24. karrio/server/events/task_definitions/base/archiving.py +58 -0
  25. karrio/server/events/task_definitions/base/tracking.py +227 -0
  26. karrio/server/events/task_definitions/base/webhook.py +116 -0
  27. karrio/server/events/tasks.py +20 -0
  28. karrio/server/events/tests/__init__.py +7 -0
  29. karrio/server/events/tests/test_events.py +138 -0
  30. karrio/server/events/tests/test_tracking_tasks.py +345 -0
  31. karrio/server/events/tests/test_webhooks.py +132 -0
  32. karrio/server/events/tests.py +3 -0
  33. karrio/server/events/urls.py +10 -0
  34. karrio/server/events/views/__init__.py +2 -0
  35. karrio/server/events/views/webhooks.py +173 -0
  36. karrio/server/graph/schemas/__init__.py +1 -0
  37. karrio/server/graph/schemas/events/__init__.py +47 -0
  38. karrio/server/graph/schemas/events/inputs.py +43 -0
  39. karrio/server/graph/schemas/events/mutations.py +56 -0
  40. karrio/server/graph/schemas/events/types.py +79 -0
  41. karrio_server_events-2025.5rc1.dist-info/METADATA +28 -0
  42. karrio_server_events-2025.5rc1.dist-info/RECORD +44 -0
  43. karrio_server_events-2025.5rc1.dist-info/WHEEL +5 -0
  44. karrio_server_events-2025.5rc1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,138 @@
1
+ from datetime import datetime
2
+ from unittest.mock import ANY
3
+
4
+ from karrio.server.events import serializers
5
+ from karrio.server.graph.tests.base import GraphTestCase
6
+ from karrio.server.events.task_definitions.base import webhook
7
+
8
+
9
+ class TestEventCreation(GraphTestCase):
10
+ def setUp(self) -> None:
11
+ super().setUp()
12
+
13
+ event_data = TRACKER_VALUE
14
+ context = dict(user_id=self.user.id, test_mode=False)
15
+ event_type = serializers.EventTypes.tracker_created.value
16
+ event_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f%z")
17
+
18
+ webhook.notify_webhook_subscribers(event_type, event_data, event_at, context)
19
+
20
+ # def test_query_events(self):
21
+ # response = self.query(
22
+ # """
23
+ # query get_events {
24
+ # events {
25
+ # edges {
26
+ # node {
27
+ # id
28
+ # type
29
+ # data
30
+ # test_mode
31
+ # pending_webhooks
32
+ # }
33
+ # }
34
+ # }
35
+ # }
36
+ # """,
37
+ # operation_name="get_events",
38
+ # )
39
+ # response_data = response.data
40
+
41
+ # self.assertResponseNoErrors(response)
42
+ # self.assertDictEqual(response_data, EVENTS_RESPONSE)
43
+
44
+ def test_query_event(self):
45
+ response = self.query(
46
+ """
47
+ query get_event($id: String!) {
48
+ event(id: $id) {
49
+ id
50
+ type
51
+ data
52
+ test_mode
53
+ pending_webhooks
54
+ }
55
+ }
56
+ """,
57
+ operation_name="get_event",
58
+ variables=dict(id=self.user.event_set.first().id),
59
+ )
60
+ response_data = response.data
61
+
62
+ self.assertResponseNoErrors(response)
63
+ self.assertDictEqual(response_data, EVENT_RESPONSE)
64
+
65
+
66
+ TRACKER_VALUE = {
67
+ "tracking_number": "1Z12345E6205277936",
68
+ "test_mode": False,
69
+ "delivered": False,
70
+ "events": [
71
+ {
72
+ "date": "2012-10-04",
73
+ "description": "Order Processed: Ready for UPS",
74
+ "location": "FR",
75
+ "code": "MP",
76
+ "time": "13:58",
77
+ }
78
+ ],
79
+ "status": "in_transit",
80
+ }
81
+
82
+ EVENTS_RESPONSE = {
83
+ "data": {
84
+ "events": {
85
+ "edges": [
86
+ {
87
+ "node": {
88
+ "id": ANY,
89
+ "type": "tracker_created",
90
+ "data": {
91
+ "events": [
92
+ {
93
+ "code": "MP",
94
+ "date": "2012-10-04",
95
+ "time": "13:58",
96
+ "location": "FR",
97
+ "description": "Order Processed: Ready for UPS",
98
+ }
99
+ ],
100
+ "status": "in_transit",
101
+ "delivered": False,
102
+ "test_mode": False,
103
+ "tracking_number": "1Z12345E6205277936",
104
+ },
105
+ "test_mode": False,
106
+ "pending_webhooks": 0,
107
+ }
108
+ }
109
+ ]
110
+ }
111
+ }
112
+ }
113
+
114
+ EVENT_RESPONSE = {
115
+ "data": {
116
+ "event": {
117
+ "id": ANY,
118
+ "type": "tracker_created",
119
+ "data": {
120
+ "events": [
121
+ {
122
+ "code": "MP",
123
+ "date": "2012-10-04",
124
+ "time": "13:58",
125
+ "location": "FR",
126
+ "description": "Order Processed: Ready for UPS",
127
+ }
128
+ ],
129
+ "status": "in_transit",
130
+ "delivered": False,
131
+ "test_mode": False,
132
+ "tracking_number": "1Z12345E6205277936",
133
+ },
134
+ "test_mode": False,
135
+ "pending_webhooks": 0,
136
+ }
137
+ }
138
+ }
@@ -0,0 +1,345 @@
1
+ import json
2
+ import datetime
3
+ from time import sleep
4
+ from unittest.mock import patch, ANY
5
+ from django.urls import reverse
6
+ from rest_framework import status
7
+ from karrio.core.models import TrackingDetails, TrackingEvent
8
+ from karrio.server.core.tests import APITestCase
9
+ from karrio.server.manager import models
10
+ from karrio.server.events.task_definitions.base import tracking
11
+
12
+
13
+ class TestTrackersBackgroundUpdate(APITestCase):
14
+ def setUp(self) -> None:
15
+ super().setUp()
16
+ trackers = [
17
+ {
18
+ "tracking_number": "1Z12345E6205277936",
19
+ "test_mode": True,
20
+ "delivered": False,
21
+ "events": [
22
+ {
23
+ "date": "2012-10-04",
24
+ "description": "Order Processed: Ready for UPS",
25
+ "location": "FR",
26
+ "code": "MP",
27
+ "time": "13:58",
28
+ }
29
+ ],
30
+ "status": "in_transit",
31
+ "created_by": self.user,
32
+ "tracking_carrier": self.ups_carrier,
33
+ "info": {
34
+ "carrier_tracking_link": "https://www.ups.com/track?loc=en_US&requester=QUIC&tracknum=1Z12345E6205277936/trackdetails",
35
+ "shipment_service": "UPS Ground",
36
+ },
37
+ },
38
+ {
39
+ "tracking_number": "00340434292135100124",
40
+ "test_mode": True,
41
+ "delivered": False,
42
+ "events": [
43
+ {
44
+ "date": "2021-01-11",
45
+ "description": "The instruction data for this shipment have been provided by the sender to DHL electronically",
46
+ "location": "BONN",
47
+ "code": "pre-transit",
48
+ "time": "20:34",
49
+ }
50
+ ],
51
+ "status": "in_transit",
52
+ "created_by": self.user,
53
+ "tracking_carrier": self.dhl_carrier,
54
+ "info": {
55
+ "carrier_tracking_link": "https://www.dhl.com/ca-en/home/tracking/tracking-parcel.html?submit=1&tracking-id=00340434292135100124",
56
+ "package_weight": 0.74,
57
+ "package_weight_unit": "KG",
58
+ "shipping_date": "2021-01-11",
59
+ },
60
+ },
61
+ ]
62
+ [models.Tracking.objects.create(**t) for t in trackers]
63
+
64
+ def test_get_trackers(self):
65
+ url = reverse("karrio.server.manager:trackers-list")
66
+
67
+ response = self.client.get(url)
68
+ response_data = json.loads(response.content)
69
+
70
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
71
+ self.assertDictEqual(response_data, TRACKERS_LIST)
72
+
73
+ def test_get_updated_trackers(self):
74
+ url = reverse("karrio.server.manager:trackers-list")
75
+
76
+ with patch(
77
+ "karrio.server.events.task_definitions.base.tracking.utils.identity"
78
+ ) as mocks:
79
+ mocks.return_value = RETURNED_UPDATED_VALUE
80
+ sleep(0.1)
81
+ tracking.update_trackers(delta=datetime.timedelta(seconds=0.1))
82
+
83
+ response = self.client.get(url)
84
+ response_data = json.loads(response.content)
85
+
86
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
87
+ self.assertDictEqual(response_data, UPDATED_TRACKERS_LIST)
88
+
89
+
90
+ RETURNED_VALUE = (
91
+ [
92
+ TrackingDetails(
93
+ carrier_id="ups_package",
94
+ carrier_name="ups",
95
+ tracking_number="1Z12345E6205277936",
96
+ delivered=False,
97
+ events=[
98
+ TrackingEvent(
99
+ code="KB",
100
+ date="2010-08-30",
101
+ description="UPS INTERNAL ACTIVITY CODE",
102
+ location="BONN",
103
+ time="10:39",
104
+ )
105
+ ],
106
+ status="in_transit",
107
+ info={
108
+ "carrier_tracking_link": "https://www.ups.com/track?loc=en_US&requester=QUIC&tracknum=1Z12345E6205277936/trackdetails",
109
+ "shipment_service": "UPS Ground",
110
+ },
111
+ )
112
+ ],
113
+ [],
114
+ )
115
+
116
+ TRACKING_RESPONSE = {
117
+ "id": ANY,
118
+ "carrier_id": "ups_package",
119
+ "carrier_name": "ups",
120
+ "tracking_number": "1Z12345E6205277936",
121
+ "test_mode": True,
122
+ "delivered": False,
123
+ "events": [
124
+ {
125
+ "code": "KB",
126
+ "date": "2010-08-30",
127
+ "description": "UPS INTERNAL ACTIVITY CODE",
128
+ "location": "BONN",
129
+ "time": "10:39",
130
+ }
131
+ ],
132
+ }
133
+
134
+ TRACKERS_LIST = {
135
+ "count": 2,
136
+ "next": ANY,
137
+ "previous": ANY,
138
+ "results": [
139
+ {
140
+ "id": ANY,
141
+ "info": ANY,
142
+ "object_type": "tracker",
143
+ "carrier_name": "dhl_express",
144
+ "carrier_id": "dhl_express",
145
+ "tracking_number": "00340434292135100124",
146
+ "delivery_image_url": None,
147
+ "signature_image_url": None,
148
+ "estimated_delivery": ANY,
149
+ "events": [
150
+ {
151
+ "date": "2021-01-11",
152
+ "description": "The instruction data for this shipment have been provided by the sender to DHL electronically",
153
+ "location": "BONN",
154
+ "code": "pre-transit",
155
+ "time": "20:34",
156
+ "latitude": None,
157
+ "longitude": None,
158
+ }
159
+ ],
160
+ "delivered": False,
161
+ "status": "in_transit",
162
+ "test_mode": True,
163
+ "messages": [],
164
+ "meta": {},
165
+ "metadata": {},
166
+ },
167
+ {
168
+ "id": ANY,
169
+ "info": ANY,
170
+ "object_type": "tracker",
171
+ "carrier_name": "ups",
172
+ "carrier_id": "ups_package",
173
+ "tracking_number": "1Z12345E6205277936",
174
+ "delivery_image_url": None,
175
+ "signature_image_url": None,
176
+ "estimated_delivery": ANY,
177
+ "events": [
178
+ {
179
+ "date": "2012-10-04",
180
+ "description": "Order Processed: Ready for UPS",
181
+ "location": "FR",
182
+ "code": "MP",
183
+ "time": "13:58",
184
+ "latitude": None,
185
+ "longitude": None,
186
+ }
187
+ ],
188
+ "delivered": False,
189
+ "status": "in_transit",
190
+ "test_mode": True,
191
+ "messages": [],
192
+ "meta": {},
193
+ "metadata": {},
194
+ },
195
+ ],
196
+ }
197
+
198
+ RETURNED_UPDATED_VALUE = (
199
+ [
200
+ TrackingDetails(
201
+ carrier_id="dhl_express",
202
+ carrier_name="dhl_express",
203
+ tracking_number="00340434292135100124",
204
+ delivered=False,
205
+ events=[
206
+ TrackingEvent(
207
+ code="pre-transit",
208
+ date="2021-03-02",
209
+ description="JESSICA",
210
+ location="Oderweg 2, AMSTERDAM",
211
+ time="07:53",
212
+ ),
213
+ TrackingEvent(
214
+ code="pre-transit",
215
+ date="2021-01-11",
216
+ description="The instruction data for this shipment have been provided by the sender to DHL electronically",
217
+ location="BONN",
218
+ time="20:34",
219
+ ),
220
+ ],
221
+ info={
222
+ "carrier_tracking_link": "https://www.dhl.com/ca-en/home/tracking/tracking-parcel.html?submit=1&tracking-id=00340434292135100124",
223
+ "package_weight": "0.74",
224
+ "package_weight_unit": "KG",
225
+ "shipment_service": "dhl_express_worldwide",
226
+ "shipping_date": "2021-01-11",
227
+ "signed_by": "Jane Doe",
228
+ },
229
+ )
230
+ ],
231
+ [],
232
+ )
233
+
234
+ UPDATED_TRACKERS_LIST = {
235
+ "count": 2,
236
+ "next": None,
237
+ "previous": None,
238
+ "results": [
239
+ {
240
+ "id": ANY,
241
+ "object_type": "tracker",
242
+ "carrier_name": "dhl_express",
243
+ "carrier_id": "dhl_express",
244
+ "tracking_number": "00340434292135100124",
245
+ "events": [
246
+ {
247
+ "date": "2021-03-02",
248
+ "description": "JESSICA",
249
+ "location": "Oderweg 2, AMSTERDAM",
250
+ "code": "pre-transit",
251
+ "time": "07:53",
252
+ "latitude": None,
253
+ "longitude": None,
254
+ },
255
+ {
256
+ "date": "2021-01-11",
257
+ "description": "The instruction data for this shipment have been provided by the sender to DHL electronically",
258
+ "location": "BONN",
259
+ "code": "pre-transit",
260
+ "time": "20:34",
261
+ "latitude": None,
262
+ "longitude": None,
263
+ },
264
+ ],
265
+ "delivered": False,
266
+ "test_mode": True,
267
+ "status": "in_transit",
268
+ "estimated_delivery": ANY,
269
+ "delivery_image_url": None,
270
+ "signature_image_url": None,
271
+ "messages": [],
272
+ "meta": {},
273
+ "metadata": {},
274
+ "info": {
275
+ "carrier_tracking_link": "https://www.dhl.com/ca-en/home/tracking/tracking-parcel.html?submit=1&tracking-id=00340434292135100124",
276
+ "customer_name": None,
277
+ "expected_delivery": None,
278
+ "note": None,
279
+ "order_date": None,
280
+ "order_id": None,
281
+ "package_weight": "0.74",
282
+ "package_weight_unit": "KG",
283
+ "shipment_delivery_date": None,
284
+ "shipment_destination_country": None,
285
+ "shipment_destination_postal_code": None,
286
+ "shipment_origin_country": None,
287
+ "shipment_origin_postal_code": None,
288
+ "shipment_package_count": None,
289
+ "shipment_pickup_date": None,
290
+ "shipment_service": "dhl_express_worldwide",
291
+ "shipping_date": "2021-01-11",
292
+ "signed_by": "Jane Doe",
293
+ "source": None,
294
+ },
295
+ },
296
+ {
297
+ "id": ANY,
298
+ "object_type": "tracker",
299
+ "carrier_name": "ups",
300
+ "carrier_id": "ups_package",
301
+ "tracking_number": "1Z12345E6205277936",
302
+ "events": [
303
+ {
304
+ "date": "2012-10-04",
305
+ "description": "Order Processed: Ready for UPS",
306
+ "location": "FR",
307
+ "code": "MP",
308
+ "time": "13:58",
309
+ "latitude": None,
310
+ "longitude": None,
311
+ }
312
+ ],
313
+ "delivered": False,
314
+ "test_mode": True,
315
+ "status": "in_transit",
316
+ "estimated_delivery": ANY,
317
+ "delivery_image_url": None,
318
+ "signature_image_url": None,
319
+ "messages": [],
320
+ "meta": {},
321
+ "metadata": {},
322
+ "info": {
323
+ "carrier_tracking_link": "https://www.ups.com/track?loc=en_US&requester=QUIC&tracknum=1Z12345E6205277936/trackdetails",
324
+ "customer_name": None,
325
+ "expected_delivery": None,
326
+ "note": None,
327
+ "order_date": None,
328
+ "order_id": None,
329
+ "package_weight": None,
330
+ "package_weight_unit": None,
331
+ "shipment_delivery_date": None,
332
+ "shipment_destination_country": None,
333
+ "shipment_destination_postal_code": None,
334
+ "shipment_origin_country": None,
335
+ "shipment_origin_postal_code": None,
336
+ "shipment_package_count": None,
337
+ "shipment_pickup_date": None,
338
+ "shipment_service": "UPS Ground",
339
+ "shipping_date": None,
340
+ "signed_by": None,
341
+ "source": None,
342
+ },
343
+ },
344
+ ],
345
+ }
@@ -0,0 +1,132 @@
1
+ import json
2
+ from unittest.mock import ANY, patch
3
+ from requests import Response
4
+
5
+ from django.urls import reverse
6
+ from django.utils import timezone
7
+ from rest_framework import status
8
+
9
+ from karrio.server.core.tests import APITestCase
10
+ from karrio.server.events.models import Webhook
11
+ from karrio.server.events.task_definitions.base.webhook import (
12
+ notify_webhook_subscribers,
13
+ )
14
+
15
+ NOTIFICATION_DATETIME = timezone.now()
16
+
17
+
18
+ class TestWebhooks(APITestCase):
19
+ def test_create_webhook(self):
20
+ url = reverse("karrio.server.events:webhook-list")
21
+ data = WEBHOOK_DATA
22
+
23
+ response = self.client.post(url, data)
24
+ response_data = json.loads(response.content)
25
+
26
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
27
+ self.assertDictEqual(response_data, WEBHOOK_RESPONSE)
28
+
29
+
30
+ class TestWebhookDetails(APITestCase):
31
+ def setUp(self) -> None:
32
+ super().setUp()
33
+ self.webhook: Webhook = Webhook.objects.create(
34
+ **{
35
+ "url": "http://localhost:8080",
36
+ "description": "Testing Hook",
37
+ "enabled_events": ["all"],
38
+ "test_mode": True,
39
+ "disabled": False,
40
+ "id": ANY,
41
+ "last_event_at": None,
42
+ "created_by": self.user,
43
+ }
44
+ )
45
+
46
+ def test_update_webhook(self):
47
+ url = reverse(
48
+ "karrio.server.events:webhook-details", kwargs=dict(pk=self.webhook.pk)
49
+ )
50
+ data = WEBHOOK_UPDATE_DATA
51
+
52
+ response = self.client.patch(url, data)
53
+ response_data = json.loads(response.content)
54
+
55
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
56
+ self.assertDictEqual(response_data, WEBHOOK_UPDATED_RESPONSE)
57
+
58
+ def test_webhook_notify(self):
59
+ url = reverse(
60
+ "karrio.server.events:webhook-details", kwargs=dict(pk=self.webhook.pk)
61
+ )
62
+
63
+ with patch(
64
+ "karrio.server.events.task_definitions.base.webhook.identity"
65
+ ) as mocks:
66
+ response = Response()
67
+ response.status_code = 200
68
+ mocks.return_value = response
69
+
70
+ notify_webhook_subscribers(
71
+ event="shipment.purchased",
72
+ data={"shipment": "content"},
73
+ event_at=NOTIFICATION_DATETIME,
74
+ ctx=dict(
75
+ user_id=self.user.id,
76
+ test_mode=True,
77
+ ),
78
+ )
79
+
80
+ response = self.client.get(url)
81
+ response_data = json.loads(response.content)
82
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
83
+ self.assertDictEqual(response_data, WEBHOOK_NOTIFIED_RESPONSE)
84
+
85
+
86
+ WEBHOOK_DATA = {
87
+ "url": "http://localhost:8080",
88
+ "description": "Testing Hook",
89
+ "enabled_events": ["all"],
90
+ "test_mode": True,
91
+ }
92
+
93
+ WEBHOOK_RESPONSE = {
94
+ "url": "http://localhost:8080",
95
+ "description": "Testing Hook",
96
+ "enabled_events": ["all"],
97
+ "test_mode": True,
98
+ "disabled": False,
99
+ "id": ANY,
100
+ "object_type": "webhook",
101
+ "secret": ANY,
102
+ "last_event_at": None,
103
+ }
104
+
105
+ WEBHOOK_UPDATE_DATA = {
106
+ "description": "Testing Hook Updated",
107
+ "enabled_events": ["shipment_purchased", "shipment_cancelled"],
108
+ }
109
+
110
+ WEBHOOK_UPDATED_RESPONSE = {
111
+ "url": "http://localhost:8080",
112
+ "description": "Testing Hook Updated",
113
+ "enabled_events": ["shipment_purchased", "shipment_cancelled"],
114
+ "test_mode": True,
115
+ "disabled": False,
116
+ "id": ANY,
117
+ "object_type": "webhook",
118
+ "secret": ANY,
119
+ "last_event_at": None,
120
+ }
121
+
122
+ WEBHOOK_NOTIFIED_RESPONSE = {
123
+ "url": "http://localhost:8080",
124
+ "description": "Testing Hook",
125
+ "enabled_events": ["all"],
126
+ "test_mode": True,
127
+ "disabled": False,
128
+ "id": ANY,
129
+ "object_type": "webhook",
130
+ "secret": ANY,
131
+ "last_event_at": NOTIFICATION_DATETIME.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
132
+ }
@@ -0,0 +1,3 @@
1
+ from django.test import TestCase
2
+
3
+ # Create your tests here.
@@ -0,0 +1,10 @@
1
+ """
2
+ karrio server events module urls
3
+ """
4
+ from django.urls import include, path
5
+ from karrio.server.events.views import router
6
+
7
+ app_name = 'karrio.server.events'
8
+ urlpatterns = [
9
+ path('v1/', include(router.urls)),
10
+ ]
@@ -0,0 +1,2 @@
1
+ import karrio.server.events.views.webhooks
2
+ from karrio.server.events.router import router