karrio-server-manager 2025.5.7__py3-none-any.whl → 2026.1.1__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.
@@ -1,5 +1,6 @@
1
1
  import uuid
2
2
  import typing
3
+ import datetime
3
4
  import rest_framework.status as status
4
5
  import django.db.transaction as transaction
5
6
  from rest_framework.reverse import reverse
@@ -846,6 +847,28 @@ def create_shipment_tracker(shipment: typing.Optional[models.Shipment], context)
846
847
  # Create shipment tracker
847
848
  try:
848
849
  pkg_weight = sum([p.weight or 0.0 for p in shipment.parcels.all()], 0.0)
850
+ selected_rate = shipment.selected_rate or {}
851
+ shipping_date_str = (
852
+ shipment.options.get("shipping_date")
853
+ or shipment.options.get("shipment_date")
854
+ )
855
+
856
+ # Get estimated_delivery from selected_rate or compute from transit_days
857
+ estimated_delivery = selected_rate.get("estimated_delivery")
858
+ transit_days = selected_rate.get("transit_days")
859
+
860
+ if not estimated_delivery and transit_days and shipping_date_str:
861
+ shipping_date = lib.to_date(
862
+ shipping_date_str,
863
+ current_format="%Y-%m-%dT%H:%M",
864
+ try_formats=["%Y-%m-%d", "%Y-%m-%dT%H:%M", "%Y-%m-%dT%H:%M:%S"],
865
+ )
866
+ if shipping_date:
867
+ estimated_date = shipping_date + datetime.timedelta(
868
+ days=int(transit_days)
869
+ )
870
+ estimated_delivery = lib.fdate(estimated_date)
871
+
849
872
  tracker = models.Tracking.objects.create(
850
873
  tracking_number=shipment.tracking_number,
851
874
  delivered=False,
@@ -854,6 +877,7 @@ def create_shipment_tracker(shipment: typing.Optional[models.Shipment], context)
854
877
  test_mode=carrier.test_mode,
855
878
  created_by=shipment.created_by,
856
879
  status=TrackerStatus.pending.value,
880
+ estimated_delivery=estimated_delivery,
857
881
  events=utils.default_tracking_event(event_at=shipment.updated_at),
858
882
  options={shipment.tracking_number: dict(carrier=rate_provider)},
859
883
  meta=dict(carrier=rate_provider),
@@ -867,7 +891,8 @@ def create_shipment_tracker(shipment: typing.Optional[models.Shipment], context)
867
891
  shipment_destination_country=shipment.recipient.country_code,
868
892
  shipment_destination_postal_code=shipment.recipient.postal_code,
869
893
  shipment_service=shipment.meta.get("service_name"),
870
- shipping_date=shipment.options.get("shipment_date"),
894
+ shipping_date=shipping_date_str,
895
+ expected_delivery=estimated_delivery,
871
896
  carrier_tracking_link=utils.get_carrier_tracking_link(
872
897
  carrier, shipment.tracking_number
873
898
  ),
@@ -295,6 +295,14 @@ def update_tracker(tracker: models.Tracking, tracking_details: dict) -> models.T
295
295
  )["info"]
296
296
  changes.append("info")
297
297
 
298
+ # Sync estimated_delivery to info.expected_delivery if updated
299
+ if estimated_delivery is not None:
300
+ current_expected = (tracker.info or {}).get("expected_delivery")
301
+ if current_expected != estimated_delivery:
302
+ tracker.info = {**(tracker.info or {}), "expected_delivery": estimated_delivery}
303
+ if "info" not in changes:
304
+ changes.append("info")
305
+
298
306
  # Update images
299
307
  images = tracking_details.get("images") or {}
300
308
  delivery_image = images.get("delivery_image") if isinstance(images, dict) else getattr(images, "delivery_image", None)
@@ -5,6 +5,7 @@ from rest_framework import status
5
5
  from unittest.mock import patch, ANY
6
6
  from karrio.core.models import TrackingDetails, TrackingEvent
7
7
  from karrio.server.core.tests import APITestCase
8
+ from karrio.server.manager import serializers
8
9
  import karrio.server.manager.models as models
9
10
 
10
11
 
@@ -219,3 +220,65 @@ UPDATE_TRACKING_RESPONSE = {
219
220
  "source": None,
220
221
  },
221
222
  }
223
+
224
+
225
+ class TestTrackerEstimatedDelivery(APITestCase):
226
+ """Test estimated_delivery computation and sync."""
227
+
228
+ def setUp(self) -> None:
229
+ super().setUp()
230
+ self.tracker = models.Tracking.objects.create(
231
+ **{
232
+ "tracking_number": "TEST123456789",
233
+ "test_mode": True,
234
+ "delivered": False,
235
+ "events": [
236
+ {
237
+ "date": "2024-01-15",
238
+ "description": "Label created",
239
+ "code": "pending",
240
+ "time": "10:00",
241
+ }
242
+ ],
243
+ "status": "pending",
244
+ "estimated_delivery": "2024-01-20",
245
+ "created_by": self.user,
246
+ "tracking_carrier": self.dhl_carrier,
247
+ "info": {
248
+ "shipping_date": "2024-01-15",
249
+ "expected_delivery": "2024-01-20",
250
+ },
251
+ }
252
+ )
253
+
254
+ def test_update_tracker_syncs_estimated_delivery_to_info(self):
255
+ """Test that when estimated_delivery is updated, info.expected_delivery is also updated."""
256
+ tracking_details = {
257
+ "estimated_delivery": "2024-01-22",
258
+ }
259
+
260
+ serializers.tracking.update_tracker(self.tracker, tracking_details)
261
+ self.tracker.refresh_from_db()
262
+
263
+ self.assertEqual(self.tracker.estimated_delivery.isoformat(), "2024-01-22")
264
+ self.assertEqual(self.tracker.info.get("expected_delivery"), "2024-01-22")
265
+
266
+ def test_update_tracker_carrier_estimated_delivery_supersedes_info(self):
267
+ """Test that carrier's estimated_delivery supersedes existing info.expected_delivery."""
268
+ # First set a different expected_delivery in info
269
+ self.tracker.info = {**self.tracker.info, "expected_delivery": "2024-01-18"}
270
+ self.tracker.save()
271
+
272
+ # Update with carrier's estimated_delivery
273
+ tracking_details = {
274
+ "estimated_delivery": "2024-01-25",
275
+ "info": {"customer_name": "John Doe"},
276
+ }
277
+
278
+ serializers.tracking.update_tracker(self.tracker, tracking_details)
279
+ self.tracker.refresh_from_db()
280
+
281
+ # Carrier's estimated_delivery should supersede
282
+ self.assertEqual(self.tracker.estimated_delivery.isoformat(), "2024-01-25")
283
+ self.assertEqual(self.tracker.info.get("expected_delivery"), "2024-01-25")
284
+ self.assertEqual(self.tracker.info.get("customer_name"), "John Doe")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karrio_server_manager
3
- Version: 2025.5.7
3
+ Version: 2026.1.1
4
4
  Summary: Multi-carrier shipping API Shipments manager module
5
5
  Author-email: karrio <hello@karrio.io>
6
6
  License-Expression: LGPL-3.0
@@ -85,8 +85,8 @@ karrio/server/manager/serializers/manifest.py,sha256=mSneCk_7HMXpi64_7hggWvkR7Ma
85
85
  karrio/server/manager/serializers/parcel.py,sha256=733Bg26lVbEkoWtAVM5Qt2IRBS2QDuVxhG40Hiqh3bw,2621
86
86
  karrio/server/manager/serializers/pickup.py,sha256=sX0VmcQxGkXn3IEosMuFwdXh4HhdkPcuBOp79O8PoDQ,9233
87
87
  karrio/server/manager/serializers/rate.py,sha256=7vYK_v8iWEDnswqYHG2Lir16_UhHTOxW5rdC6lw3lzA,652
88
- karrio/server/manager/serializers/shipment.py,sha256=XuqCsB8TBYtn270JNKyvmYglDZttEfLED69NYN-uVyA,37500
89
- karrio/server/manager/serializers/tracking.py,sha256=BViFnLlojwbRuy3U1rP2Vp_UqWRjwTd_4OVrhNAfkEA,12712
88
+ karrio/server/manager/serializers/shipment.py,sha256=sZuYnv0LexG1JzrfBCGfaQncGlFHqbvQQKVVueX-2GY,38608
89
+ karrio/server/manager/serializers/tracking.py,sha256=Qg4fXzdU7wwTyZq4ybR1-X3ipQ35b1gZTPQ2rTNWfVg,13141
90
90
  karrio/server/manager/tests/__init__.py,sha256=Y1UNteEE60vWdUAkjbldu_r_-h4u0He8-UoiBgTjKcU,391
91
91
  karrio/server/manager/tests/test_addresses.py,sha256=pNkZC_yJyb29ZlEOtOAs4blcEYiOarw0zhZIZC5uj1w,3111
92
92
  karrio/server/manager/tests/test_custom_infos.py,sha256=iv2cLdZVoVWFZK_mDUEnrZssncAnQcn87Rn2sAk8UQI,2731
@@ -95,7 +95,7 @@ karrio/server/manager/tests/test_manifests.py,sha256=X35ZTXTFEM4Gxdjz598yiNNkOOK
95
95
  karrio/server/manager/tests/test_parcels.py,sha256=lVLBOsHzXgXQvYjHIUy5oiPvrMfxYpueVvvhtuhstWk,2559
96
96
  karrio/server/manager/tests/test_pickups.py,sha256=8jxddwTnBvBM9FOyWxW9TtZ-GOVYUje7HQ2EZjsbtD8,10681
97
97
  karrio/server/manager/tests/test_shipments.py,sha256=S_mDZtCFd1R5S40AA83LfmQsGJGrJ52gwDzh2SY4YIM,39751
98
- karrio/server/manager/tests/test_trackers.py,sha256=DNeGR-MQ6E_HIARuDUod7bIfhRgem3by-_rMLJR5JfM,7325
98
+ karrio/server/manager/tests/test_trackers.py,sha256=my4UR3GBRt1MrPzrpSrwE3gE_okvsU3hFovuSHhFzF0,9856
99
99
  karrio/server/manager/views/__init__.py,sha256=kDFUaORRQ3Xh0ZPm-Jk88Ss8dgGYM57iUFXb9TPMzh0,401
100
100
  karrio/server/manager/views/addresses.py,sha256=7YCAs2ZYgd1icYwMcGGWfX7A7vZEL4BEAbU4eIxhiMY,4620
101
101
  karrio/server/manager/views/customs.py,sha256=-ZreiKyJ1xeLeNVG53nMfRQFeURduWr1QkDItdLPnE8,4875
@@ -105,7 +105,7 @@ karrio/server/manager/views/parcels.py,sha256=hZY45rg6SrTWfQqyJ38MGKSor1yqgPUEVH
105
105
  karrio/server/manager/views/pickups.py,sha256=gmpxz9ot1OR-BP1qh-0MXU3kUJi1ht_74hfaLJzJ42w,5503
106
106
  karrio/server/manager/views/shipments.py,sha256=vdJFgIKnSHEb2FVGtqJbiMoHuMqzWtDpINMH4UaEtQQ,13154
107
107
  karrio/server/manager/views/trackers.py,sha256=3oGn2qDpHgk8GZvuz-Cb93Fc0j_h_HbXQR692Zhfiok,12363
108
- karrio_server_manager-2025.5.7.dist-info/METADATA,sha256=XazOdL7uDHjIEM2eIv1ZOJcLQjqXo92DMzGTsivtK2k,730
109
- karrio_server_manager-2025.5.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
- karrio_server_manager-2025.5.7.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
111
- karrio_server_manager-2025.5.7.dist-info/RECORD,,
108
+ karrio_server_manager-2026.1.1.dist-info/METADATA,sha256=xxPVvF-JAwDbxVc5NyNE880ZnVuD8AUssmxF_tUQXhI,730
109
+ karrio_server_manager-2026.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
+ karrio_server_manager-2026.1.1.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
111
+ karrio_server_manager-2026.1.1.dist-info/RECORD,,