diff --git a/modules/cli/karrio_cli/resources/events.py b/modules/cli/karrio_cli/resources/events.py index 70d51f6049..e2187bdc46 100644 --- a/modules/cli/karrio_cli/resources/events.py +++ b/modules/cli/karrio_cli/resources/events.py @@ -70,7 +70,7 @@ def list_events( "type": "shipment_purchased", "data": { "shipment_id": "shp_123456789", - "status": "purchased" + "status": "created" }, "test_mode": false, "pending_webhooks": 0, @@ -134,7 +134,7 @@ def retrieve_event( "type": "shipment_purchased", "data": { "shipment_id": "shp_123456789", - "status": "purchased" + "status": "created" }, "test_mode": false, "pending_webhooks": 0, diff --git a/modules/core/karrio/server/core/gateway.py b/modules/core/karrio/server/core/gateway.py index 76174f185e..f28087da36 100644 --- a/modules/core/karrio/server/core/gateway.py +++ b/modules/core/karrio/server/core/gateway.py @@ -416,7 +416,7 @@ def process_parcel_refs(parcels: typing.List[dict]) -> list: "selected_rate_id": shipment_rate["id"], "parcels": process_parcel_refs(payload["parcels"]), "tracking_url": process_tracking_url(shipment_rate), - "status": serializers.ShipmentStatus.purchased.value, + "status": serializers.ShipmentStatus.created.value, "created_at": datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f%z" ), diff --git a/modules/core/karrio/server/core/serializers.py b/modules/core/karrio/server/core/serializers.py index f3df61ff06..ae49a6fcdf 100644 --- a/modules/core/karrio/server/core/serializers.py +++ b/modules/core/karrio/server/core/serializers.py @@ -16,7 +16,7 @@ class PickupStatus(utils.Enum): class ShipmentStatus(utils.Enum): draft = "draft" - purchased = "purchased" + created = "created" cancelled = "cancelled" shipped = "shipped" in_transit = "in_transit" diff --git a/modules/core/karrio/server/core/tests/test_resource_token.py b/modules/core/karrio/server/core/tests/test_resource_token.py index 1ba55a9b5c..bf01981f97 100644 --- a/modules/core/karrio/server/core/tests/test_resource_token.py +++ b/modules/core/karrio/server/core/tests/test_resource_token.py @@ -458,7 +458,7 @@ def setUp(self): parcels=[self.parcel_data], created_by=self.user, test_mode=True, - status="purchased", + status="created", tracking_number="TEST123456", label="JVBERi0xLjQKMSAwIG9iago8PAovVGl0bGUgKP7/AFQAZQBzAHQpCj4+CmVuZG9iagoyIDAgb2JqCjw8Cj4+CmVuZG9iagozIDAgb2JqCjw8Cj4+CmVuZG9iagp4cmVmCjAgNAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDA2OCAwMDAwMCBuIAowMDAwMDAwMDg5IDAwMDAwIG4gCnRyYWlsZXIKPDwKL1NpemUgNAo+PgpzdGFydHhyZWYKMTEwCiUlRU9GCg==", # Base64 encoded minimal PDF label_type="PDF", diff --git a/modules/core/karrio/server/core/utils.py b/modules/core/karrio/server/core/utils.py index 5cf0848ba7..3746661259 100644 --- a/modules/core/karrio/server/core/utils.py +++ b/modules/core/karrio/server/core/utils.py @@ -3,7 +3,7 @@ import inspect import functools from concurrent import futures -from datetime import timedelta, datetime +from datetime import timedelta, datetime, timezone from typing import TypeVar, Union, Callable, Any, List, Optional from django.conf import settings @@ -804,14 +804,18 @@ def default_tracking_event( code: str = None, description: str = None, ): + _event_dt = (event_at or datetime.now(timezone.utc)).astimezone(timezone.utc) + _timestamp = _event_dt.strftime("%Y-%m-%dT%H:%M:%S.") + f"{_event_dt.microsecond // 1000:03d}Z" return [ DP.to_dict( datatypes.TrackingEvent( - date=DF.fdate(event_at or datetime.now()), - description=(description or "Label created and ready for shipment"), + date=_event_dt.strftime("%Y-%m-%d"), + description=(description or "Shipment label created"), location="", code=(code or "CREATED"), - time=DF.ftime(event_at or datetime.now()), + time=_event_dt.strftime("%I:%M %p"), + timestamp=_timestamp, + status="created", ) ) ] diff --git a/modules/data/karrio/server/data/resources/shipments.py b/modules/data/karrio/server/data/resources/shipments.py index 051b99c402..1abda15be9 100644 --- a/modules/data/karrio/server/data/resources/shipments.py +++ b/modules/data/karrio/server/data/resources/shipments.py @@ -104,7 +104,7 @@ def shipment_export_resource(query_params: dict, context, **kwargs): if "status" not in query_params: queryset = queryset.filter( - Q(status__in=["purchased", "delivered", "shipped", "in_transit"]), + Q(status__in=["created", "delivered", "shipped", "in_transit"]), ) class Resource(resources.ModelResource): diff --git a/modules/documents/karrio/server/documents/utils.py b/modules/documents/karrio/server/documents/utils.py index 7fa6f40613..8f9a895eed 100644 --- a/modules/documents/karrio/server/documents/utils.py +++ b/modules/documents/karrio/server/documents/utils.py @@ -293,7 +293,7 @@ "created_at": "2022-03-25 13:17:48.646853+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000135", @@ -597,7 +597,7 @@ "created_at": "2022-03-25 13:38:17.742127+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000136", @@ -830,7 +830,7 @@ "created_at": "2022-03-25 13:17:48.646853+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000135", @@ -1111,7 +1111,7 @@ "created_at": "2022-03-25 13:38:17.742127+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000136", @@ -1343,7 +1343,7 @@ "created_at": "2022-03-25 13:17:48.646853+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000135", @@ -1636,7 +1636,7 @@ "created_at": "2022-03-25 13:38:17.742127+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000136", @@ -1868,7 +1868,7 @@ "created_at": "2022-03-25 13:17:48.646853+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000135", @@ -2122,7 +2122,7 @@ "created_at": "2022-03-25 13:38:17.742127+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000136", @@ -2354,7 +2354,7 @@ "created_at": "2022-03-25 13:17:48.646853+00:00", "metadata": {"order_ids": "1073459962,394873849374"}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "generic", "carrier_id": "tst-overland", "tracking_number": "0000000135", diff --git a/modules/events/karrio/server/events/signals.py b/modules/events/karrio/server/events/signals.py index 24079bf2e8..d64517dfde 100644 --- a/modules/events/karrio/server/events/signals.py +++ b/modules/events/karrio/server/events/signals.py @@ -41,10 +41,10 @@ def shipment_updated( if created: return - if is_bound and instance.status == serializers.ShipmentStatus.purchased.value: + if is_bound and instance.status == serializers.ShipmentStatus.created.value: event = EventTypes.shipment_purchased.value elif ( - status_updated and instance.status == serializers.ShipmentStatus.purchased.value + status_updated and instance.status == serializers.ShipmentStatus.created.value ): event = EventTypes.shipment_purchased.value elif ( diff --git a/modules/manager/karrio/server/manager/migrations/0089_rename_purchased_to_created_and_remove_choices.py b/modules/manager/karrio/server/manager/migrations/0089_rename_purchased_to_created_and_remove_choices.py new file mode 100644 index 0000000000..da0fd22010 --- /dev/null +++ b/modules/manager/karrio/server/manager/migrations/0089_rename_purchased_to_created_and_remove_choices.py @@ -0,0 +1,29 @@ +from django.db import migrations, models + + +def rename_purchased_to_created(apps, schema_editor): + Shipment = apps.get_model("manager", "Shipment") + Shipment.objects.filter(status="purchased").update(status="created") + + +class Migration(migrations.Migration): + + dependencies = [ + ("manager", "0088_shipment_order_id"), + ] + + operations = [ + migrations.RunPython( + rename_purchased_to_created, + migrations.RunPython.noop, + ), + migrations.AlterField( + model_name="shipment", + name="status", + field=models.CharField( + max_length=50, + db_index=True, + default="draft", + ), + ), + ] diff --git a/modules/manager/karrio/server/manager/models.py b/modules/manager/karrio/server/manager/models.py index 82b82b17b2..1db9dbe4cc 100644 --- a/modules/manager/karrio/server/manager/models.py +++ b/modules/manager/karrio/server/manager/models.py @@ -823,9 +823,8 @@ class Meta: ) status = models.CharField( max_length=50, - choices=serializers.SHIPMENT_STATUS, - default=serializers.SHIPMENT_STATUS[0][0], db_index=True, + default="draft", ) label_type = models.CharField(max_length=25, null=True, blank=True) tracking_number = models.CharField( diff --git a/modules/manager/karrio/server/manager/serializers/document.py b/modules/manager/karrio/server/manager/serializers/document.py index 407b163b5a..cd82e1459d 100644 --- a/modules/manager/karrio/server/manager/serializers/document.py +++ b/modules/manager/karrio/server/manager/serializers/document.py @@ -112,7 +112,7 @@ def can_upload_shipment_document(shipment: models.Shipment, context=None): if shipment.status not in [ core.ShipmentStatus.shipped.value, - core.ShipmentStatus.purchased.value, + core.ShipmentStatus.created.value, core.ShipmentStatus.in_transit.value, ]: raise exceptions.APIException( diff --git a/modules/manager/karrio/server/manager/serializers/shipment.py b/modules/manager/karrio/server/manager/serializers/shipment.py index 421fa35678..137b9d95af 100644 --- a/modules/manager/karrio/server/manager/serializers/shipment.py +++ b/modules/manager/karrio/server/manager/serializers/shipment.py @@ -590,7 +590,7 @@ class ShipmentCancelSerializer(Shipment): def update( self, instance: models.Shipment, validated_data: dict, context=None, **kwargs ) -> datatypes.ConfirmationResponse: - if instance.status == ShipmentStatus.purchased.value: + if instance.status == ShipmentStatus.created.value: # Resolve carrier from carrier snapshot carrier = resolve_carrier(instance.carrier or {}, context) gateway.Shipments.cancel( @@ -826,7 +826,7 @@ def can_mutate_shipment( if update and [*(payload or {}).keys()] == ["metadata"]: return - if purchase and shipment.status == ShipmentStatus.purchased.value: + if purchase and shipment.status == ShipmentStatus.created.value: raise exceptions.APIException( f"The shipment is '{shipment.status}' and cannot be purchased again", code="state_error", @@ -841,7 +841,7 @@ def can_mutate_shipment( ) if delete and shipment.status not in [ - ShipmentStatus.purchased.value, + ShipmentStatus.created.value, ShipmentStatus.draft.value, ]: raise exceptions.APIException( diff --git a/modules/manager/karrio/server/manager/tests/test_shipments.py b/modules/manager/karrio/server/manager/tests/test_shipments.py index 3449718bfa..de5fd6ce4a 100644 --- a/modules/manager/karrio/server/manager/tests/test_shipments.py +++ b/modules/manager/karrio/server/manager/tests/test_shipments.py @@ -203,7 +203,7 @@ def test_cancel_purchased_shipment(self): "karrio.server.manager:shipment-cancel", kwargs=dict(pk=self.shipment.pk), ) - self.shipment.status = "purchased" + self.shipment.status = "created" self.shipment.shipment_identifier = "123456789012" # Set selected_rate and carrier snapshot self.shipment.selected_rate = { @@ -247,7 +247,7 @@ def test_purchase_shipment_with_has_alternative_services(self): self.assertResponseNoErrors(response) # type: ignore self.assertDictEqual( dict(status=response_data["status"], service=response_data["service"]), - dict(status="purchased", service="canadapost_expedited_parcel"), + dict(status="created", service="canadapost_expedited_parcel"), ) @@ -278,7 +278,7 @@ def test_single_call_label_purchase(self): "rates_count": len(response_data["rates"]), }, { - "status": "purchased", + "status": "created", "carrier_name": "canadapost", "service": "canadapost_priority", "tracking_number": "123456789012", @@ -320,7 +320,7 @@ def test_single_call_label_purchase_skip_rates(self): ), }, { - "status": "purchased", + "status": "created", "carrier_name": "canadapost", "service": "canadapost_priority", "tracking_number": "123456789012", @@ -356,7 +356,7 @@ def test_single_call_label_purchase_skip_rates_with_carrier_ids(self): ), }, { - "status": "purchased", + "status": "created", "carrier_name": "canadapost", "service": "canadapost_priority", "tracking_number": "123456789012", @@ -731,7 +731,7 @@ def test_single_call_label_purchase_skip_rates_with_carrier_ids(self): "created_at": ANY, "metadata": {}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "canadapost", "carrier_id": "canadapost", "tracking_number": "123456789012", diff --git a/modules/orders/karrio/server/orders/signals.py b/modules/orders/karrio/server/orders/signals.py index 3b8f9131b8..5588cb6448 100644 --- a/modules/orders/karrio/server/orders/signals.py +++ b/modules/orders/karrio/server/orders/signals.py @@ -80,7 +80,7 @@ def _update_order_line_items_fulfillment(order, shipment_instance): When a shipment is purchased/fulfilled, decrement the unfulfilled_quantity of the corresponding order line items. """ - if shipment_instance.status not in ["purchased", "transit", "delivered"]: + if shipment_instance.status not in ["created", "transit", "delivered"]: return # Build a map of parent_id -> quantity from shipment items diff --git a/modules/orders/karrio/server/orders/tests/test_orders.py b/modules/orders/karrio/server/orders/tests/test_orders.py index 99111be9c6..2d51480b70 100644 --- a/modules/orders/karrio/server/orders/tests/test_orders.py +++ b/modules/orders/karrio/server/orders/tests/test_orders.py @@ -173,7 +173,7 @@ def test_partial_order_when_some_items_are_fulfilled(self): shipment_response = self.client.post(shipment_url, data) shipment_data = json.loads(shipment_response.content) shipment = manager.Shipment.objects.get(pk=shipment_data["id"]) - shipment.status = "purchased" + shipment.status = "created" shipment.save() # Fetch related order @@ -223,7 +223,7 @@ def test_fulfilled_order_when_all_items_are_fulfilled(self): self.assertEqual(shipment_response.status_code, status.HTTP_201_CREATED) shipment = manager.Shipment.objects.get(pk=shipment_data["id"]) - shipment.status = "purchased" + shipment.status = "created" shipment.save() # Fetch related order @@ -948,7 +948,7 @@ def test_fulfilled_order_when_all_items_are_fulfilled(self): "created_at": ANY, "metadata": {}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": None, "carrier_id": None, "tracking_number": None, @@ -1206,7 +1206,7 @@ def test_fulfilled_order_when_all_items_are_fulfilled(self): "created_at": ANY, "metadata": {}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": None, "carrier_id": None, "tracking_number": None, diff --git a/modules/pricing/karrio/server/pricing/signals.py b/modules/pricing/karrio/server/pricing/signals.py index 9c676f292f..0a75ac8fce 100644 --- a/modules/pricing/karrio/server/pricing/signals.py +++ b/modules/pricing/karrio/server/pricing/signals.py @@ -191,7 +191,7 @@ def on_shipment_saved(sender, instance, created, **kwargs): # Only capture fees when: # 1. Shipment has a selected_rate (label was purchased) # 2. Shipment status indicates it's been purchased/processed - if instance.selected_rate and instance.status not in ["draft", "created"]: + if instance.selected_rate and instance.status not in ["draft"]: # Check if we've already captured fees for this shipment if not models.Fee.objects.filter(shipment_id=instance.id).exists(): capture_fees_for_shipment(instance) diff --git a/modules/pricing/karrio/server/pricing/tests.py b/modules/pricing/karrio/server/pricing/tests.py index 92b326a60d..c17f543289 100644 --- a/modules/pricing/karrio/server/pricing/tests.py +++ b/modules/pricing/karrio/server/pricing/tests.py @@ -301,7 +301,7 @@ def test_capture_fees_from_shipment(self): # Create a shipment with markup in extra_charges # The signal should automatically capture fees on save shipment = manager.Shipment.objects.create( - status="purchased", + status="created", test_mode=True, shipper={"city": "Montreal"}, recipient={"city": "Toronto"}, @@ -354,7 +354,7 @@ def test_capture_fees_function_directly(self): # Create shipment with status that won't trigger signal shipment = manager.Shipment.objects.create( - status="created", # Signal won't fire for this status + status="draft", # Signal won't fire for this status test_mode=True, shipper={"city": "Montreal"}, recipient={"city": "Toronto"}, @@ -406,7 +406,7 @@ def test_no_duplicate_fee_capture(self): # Create shipment - signal will capture fee shipment = manager.Shipment.objects.create( - status="purchased", + status="created", test_mode=True, shipper={"city": "Montreal"}, recipient={"city": "Toronto"}, diff --git a/modules/proxy/karrio/server/proxy/tests/test_shipping.py b/modules/proxy/karrio/server/proxy/tests/test_shipping.py index cbc49e518d..bac3bdc044 100644 --- a/modules/proxy/karrio/server/proxy/tests/test_shipping.py +++ b/modules/proxy/karrio/server/proxy/tests/test_shipping.py @@ -296,7 +296,7 @@ def test_shipping_failed_cancel(self): "created_at": ANY, "metadata": {}, "messages": [], - "status": "purchased", + "status": "created", "carrier_name": "canadapost", "carrier_id": "canadapost", "tracking_number": "123456789012",