karrio-server-manager 2025.5rc35__py3-none-any.whl → 2025.5rc36__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.
@@ -22,6 +22,7 @@ from karrio.server.manager.serializers.tracking import (
22
22
  TrackerUpdateData,
23
23
  update_shipment_tracker,
24
24
  can_mutate_tracker,
25
+ update_tracker,
25
26
  )
26
27
  from karrio.server.manager.serializers.shipment import (
27
28
  ShipmentRateData,
@@ -120,64 +120,26 @@ class TrackingSerializer(TrackingDetails):
120
120
  ).data,
121
121
  carrier=carrier,
122
122
  )
123
- # update values only if changed; This is important for webhooks notification
124
- changes = []
125
- details = response.tracking
126
- info = lib.to_dict(details.info or {})
127
- events = utils.process_events(
128
- response_events=details.events, current_events=instance.events
129
- )
130
-
131
- if events != instance.events:
132
- instance.events = events
133
- changes.append("events")
134
-
135
- if response.messages != instance.messages:
136
- instance.messages = lib.to_dict(response.messages)
137
- changes.append("messages")
138
-
139
- if details.delivered != instance.delivered:
140
- instance.delivered = details.delivered
141
- changes.append("delivered")
142
-
143
- if details.status != instance.status:
144
- instance.status = details.status
145
- changes.append("status")
146
-
147
- if details.estimated_delivery != instance.estimated_delivery:
148
- instance.estimated_delivery = details.estimated_delivery
149
- changes.append("estimated_delivery")
150
-
151
- if details.options != instance.options:
152
- instance.options = details.options
153
- changes.append("options")
154
-
155
- if any(info.keys()) and info != instance.info:
156
- instance.info = serializers.process_dictionaries_mutations(
157
- ["info"], dict(info=info), instance
158
- )["info"]
159
- changes.append("info")
160
123
 
124
+ # Handle carrier change separately (not part of tracking_details)
161
125
  if carrier.id != instance.tracking_carrier.id:
162
- instance.carrier = carrier
163
- changes.append("tracking_carrier")
164
-
165
- if details.images is not None and (
166
- details.images.delivery_image != instance.delivery_image
167
- or details.images.signature_image != instance.signature_image
168
- ):
169
- changes.append("delivery_image")
170
- changes.append("signature_image")
171
- instance.delivery_image = (
172
- details.images.delivery_image or instance.delivery_image
173
- )
174
- instance.signature_image = (
175
- details.images.signature_image or instance.signature_image
176
- )
126
+ instance.tracking_carrier = carrier
127
+ instance.save(update_fields=["tracking_carrier"])
177
128
 
178
- if any(changes):
179
- instance.save(update_fields=changes)
180
- update_shipment_tracker(instance)
129
+ # Use update_tracker for the rest of the tracking details
130
+ update_tracker(
131
+ instance,
132
+ dict(
133
+ events=response.tracking.events,
134
+ messages=response.messages,
135
+ delivered=response.tracking.delivered,
136
+ status=response.tracking.status,
137
+ estimated_delivery=response.tracking.estimated_delivery,
138
+ options=response.tracking.options,
139
+ info=lib.to_dict(response.tracking.info or {}),
140
+ images=response.tracking.images,
141
+ ),
142
+ )
181
143
 
182
144
  return instance
183
145
 
@@ -246,3 +208,120 @@ def update_shipment_tracker(tracker: models.Tracking):
246
208
  tracker.shipment.save(update_fields=["status"])
247
209
  except Exception as e:
248
210
  logger.exception("Failed to update the tracked shipment", error=str(e), tracker_id=tracker.id, tracking_number=tracker.tracking_number)
211
+
212
+
213
+ def update_tracker(tracker: models.Tracking, tracking_details: dict) -> models.Tracking:
214
+ """Update tracker with new tracking details from webhook or external source.
215
+
216
+ This utility function consolidates the change detection logic for updating
217
+ a tracker instance. It only saves fields that have changed and triggers
218
+ the shipment status update via update_shipment_tracker.
219
+
220
+ Args:
221
+ tracker: The Tracking model instance to update
222
+ tracking_details: Dictionary containing tracking details with keys like:
223
+ - events: List of tracking event dictionaries
224
+ - messages: List of message dictionaries
225
+ - delivered: Boolean delivery status
226
+ - status: Tracker status string
227
+ - estimated_delivery: Estimated delivery date string
228
+ - options: Dictionary of tracking options
229
+ - meta: Dictionary of metadata
230
+ - info: Dictionary of tracking info
231
+ - images: Dictionary with delivery_image and signature_image
232
+
233
+ Returns:
234
+ The updated Tracking model instance
235
+ """
236
+ try:
237
+ changes = []
238
+
239
+ # Process events - merge with existing events
240
+ new_events = tracking_details.get("events") or []
241
+ if new_events:
242
+ events = utils.process_events(
243
+ response_events=new_events, current_events=tracker.events
244
+ )
245
+ if events != tracker.events:
246
+ tracker.events = events
247
+ changes.append("events")
248
+
249
+ # Update messages
250
+ messages = tracking_details.get("messages")
251
+ if messages is not None and messages != tracker.messages:
252
+ tracker.messages = lib.to_dict(messages)
253
+ changes.append("messages")
254
+
255
+ # Update delivered status
256
+ delivered = tracking_details.get("delivered")
257
+ if delivered is not None and delivered != tracker.delivered:
258
+ tracker.delivered = delivered
259
+ changes.append("delivered")
260
+
261
+ # Update status
262
+ status = tracking_details.get("status")
263
+ if status is not None and status != tracker.status:
264
+ tracker.status = status
265
+ changes.append("status")
266
+
267
+ # Update estimated delivery
268
+ estimated_delivery = tracking_details.get("estimated_delivery")
269
+ if estimated_delivery is not None and estimated_delivery != tracker.estimated_delivery:
270
+ tracker.estimated_delivery = estimated_delivery
271
+ changes.append("estimated_delivery")
272
+
273
+ # Update options
274
+ options = tracking_details.get("options")
275
+ if options is not None and options != tracker.options:
276
+ tracker.options = options
277
+ changes.append("options")
278
+
279
+ # Update meta
280
+ meta = tracking_details.get("meta")
281
+ if meta is not None and meta != tracker.meta:
282
+ tracker.meta = {**(tracker.meta or {}), **meta}
283
+ changes.append("meta")
284
+
285
+ # Update info - merge with existing info
286
+ info = tracking_details.get("info") or {}
287
+ if any(info.keys()) and info != tracker.info:
288
+ tracker.info = serializers.process_dictionaries_mutations(
289
+ ["info"], dict(info=info), tracker
290
+ )["info"]
291
+ changes.append("info")
292
+
293
+ # Update images
294
+ images = tracking_details.get("images") or {}
295
+ delivery_image = images.get("delivery_image") if isinstance(images, dict) else getattr(images, "delivery_image", None)
296
+ signature_image = images.get("signature_image") if isinstance(images, dict) else getattr(images, "signature_image", None)
297
+
298
+ if delivery_image is not None or signature_image is not None:
299
+ if delivery_image != tracker.delivery_image or signature_image != tracker.signature_image:
300
+ if delivery_image is not None:
301
+ tracker.delivery_image = delivery_image
302
+ changes.append("delivery_image")
303
+ if signature_image is not None:
304
+ tracker.signature_image = signature_image
305
+ changes.append("signature_image")
306
+
307
+ # Save changes and update associated shipment
308
+ if any(changes):
309
+ tracker.save(update_fields=changes)
310
+ update_shipment_tracker(tracker)
311
+ logger.info(
312
+ "Tracker updated via webhook",
313
+ tracker_id=tracker.id,
314
+ tracking_number=tracker.tracking_number,
315
+ changes=changes,
316
+ )
317
+
318
+ return tracker
319
+
320
+ except Exception as e:
321
+ logger.exception(
322
+ "Failed to update tracker",
323
+ error=str(e),
324
+ tracker_id=tracker.id,
325
+ tracking_number=tracker.tracking_number,
326
+ )
327
+ return tracker
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karrio_server_manager
3
- Version: 2025.5rc35
3
+ Version: 2025.5rc36
4
4
  Summary: Multi-carrier shipping API Shipments manager module
5
5
  Author-email: karrio <hello@karrio.io>
6
6
  License-Expression: Apache-2.0
@@ -73,7 +73,7 @@ karrio/server/manager/migrations/0064_shipment_shipment_created_at_idx_and_more.
73
73
  karrio/server/manager/migrations/0065_alter_address_city_alter_address_company_name_and_more.py,sha256=m0KQSz8cnJzaXUlaAKdqU0duZ8wSQeTYQCIeam3Wivw,6279
74
74
  karrio/server/manager/migrations/0066_commodity_image_url_commodity_product_id_and_more.py,sha256=Jw7bEBmqzDSp6zw0xcAiKc9aDCsa3Wrw-oTM8r9Pqfc,997
75
75
  karrio/server/manager/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
- karrio/server/manager/serializers/__init__.py,sha256=cbi3PpPA8nw_le56PbGP_Ua1kDyyxOt88_Vn9uESbpI,1411
76
+ karrio/server/manager/serializers/__init__.py,sha256=YVwGfjpb-_PezzGc8N8oLTkORan0hZ2muGj2PYG3n0g,1431
77
77
  karrio/server/manager/serializers/address.py,sha256=yGKvZiNukeI15LEDdbo1ycqqK8QW77ak_vyLMIKyglI,2779
78
78
  karrio/server/manager/serializers/commodity.py,sha256=PKrW-xAYkiNByk5RF8up_Bt1Z8mJV_BGW0mPWT9w4ME,1658
79
79
  karrio/server/manager/serializers/customs.py,sha256=gMGC4TJMykjgELBLFHL6v7kPQ5YQKe7cQcMnOGBLL84,2872
@@ -83,7 +83,7 @@ karrio/server/manager/serializers/parcel.py,sha256=733Bg26lVbEkoWtAVM5Qt2IRBS2QD
83
83
  karrio/server/manager/serializers/pickup.py,sha256=sX0VmcQxGkXn3IEosMuFwdXh4HhdkPcuBOp79O8PoDQ,9233
84
84
  karrio/server/manager/serializers/rate.py,sha256=7vYK_v8iWEDnswqYHG2Lir16_UhHTOxW5rdC6lw3lzA,652
85
85
  karrio/server/manager/serializers/shipment.py,sha256=G4vA51UFHvBVNNR9z3Vtac-Y7GexjGadPOCRxSUVqRE,30355
86
- karrio/server/manager/serializers/tracking.py,sha256=TguVVqNwbKSdDx0m614jP3PiBrkNiQ7fq1A7Ulw7jjo,9241
86
+ karrio/server/manager/serializers/tracking.py,sha256=ixrAjIiZQsvSt4y0qtisGkt6TFOJ3ORNkJAQVt6YQrA,12483
87
87
  karrio/server/manager/tests/__init__.py,sha256=Y1UNteEE60vWdUAkjbldu_r_-h4u0He8-UoiBgTjKcU,391
88
88
  karrio/server/manager/tests/test_addresses.py,sha256=pNkZC_yJyb29ZlEOtOAs4blcEYiOarw0zhZIZC5uj1w,3111
89
89
  karrio/server/manager/tests/test_custom_infos.py,sha256=iv2cLdZVoVWFZK_mDUEnrZssncAnQcn87Rn2sAk8UQI,2731
@@ -100,7 +100,7 @@ karrio/server/manager/views/parcels.py,sha256=hZY45rg6SrTWfQqyJ38MGKSor1yqgPUEVH
100
100
  karrio/server/manager/views/pickups.py,sha256=gmpxz9ot1OR-BP1qh-0MXU3kUJi1ht_74hfaLJzJ42w,5503
101
101
  karrio/server/manager/views/shipments.py,sha256=_5EJfgxEO6H2EdQQbaSwILgnim7slqxMKDkEk_97F9c,10267
102
102
  karrio/server/manager/views/trackers.py,sha256=3oGn2qDpHgk8GZvuz-Cb93Fc0j_h_HbXQR692Zhfiok,12363
103
- karrio_server_manager-2025.5rc35.dist-info/METADATA,sha256=-JSntjwNP7P042MXocTMVzOu12bar9whAxp_ueeUd6w,734
104
- karrio_server_manager-2025.5rc35.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
105
- karrio_server_manager-2025.5rc35.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
106
- karrio_server_manager-2025.5rc35.dist-info/RECORD,,
103
+ karrio_server_manager-2025.5rc36.dist-info/METADATA,sha256=gqVdjXCp3F4TIfvQWnxEJ76Js6deZo0n6BRct9pJC9I,734
104
+ karrio_server_manager-2025.5rc36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
105
+ karrio_server_manager-2025.5rc36.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
106
+ karrio_server_manager-2025.5rc36.dist-info/RECORD,,