{"record":{"id":"e043e0c61508477c","repo":"nopSolutions/nopCommerce","slug":"this-shipment-is-already-delivered","errorCode":null,"errorMessage":"This shipment is already delivered","messagePattern":"This shipment is already delivered","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/Libraries/Nop.Services/Orders/OrderProcessingService.cs","lineNumber":2329,"sourceCode":"    /// Marks a shipment as delivered\r\n    /// </summary>\r\n    /// <param name=\"shipment\">Shipment</param>\r\n    /// <param name=\"notifyCustomer\">True to notify customer</param>\r\n    /// <returns>A task that represents the asynchronous operation</returns>\r\n    public virtual async Task DeliverAsync(Shipment shipment, bool notifyCustomer)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(shipment);\r\n\r\n        var order = await _orderService.GetOrderByIdAsync(shipment.OrderId) ?? throw new Exception(\"Order cannot be loaded\");\r\n\r\n        if (!order.PickupInStore && !shipment.ShippedDateUtc.HasValue)\r\n            throw new Exception(\"This shipment is not shipped yet\");\r\n\r\n        if (order.PickupInStore && !shipment.ReadyForPickupDateUtc.HasValue)\r\n            throw new Exception(\"This shipment is not yet ready for pickup\");\r\n\r\n        if (shipment.DeliveryDateUtc.HasValue)\r\n            throw new Exception(\"This shipment is already delivered\");\r\n\r\n        shipment.DeliveryDateUtc = DateTime.UtcNow;\r\n        await _shipmentService.UpdateShipmentAsync(shipment);\r\n\r\n        if (!await _orderService.HasItemsToAddToShipmentAsync(order) &&\r\n            !await _orderService.HasItemsToShipAsync(order) &&\r\n            !await _orderService.HasItemsToReadyForPickupAsync(order) &&\r\n            !await _orderService.HasItemsToDeliverAsync(order))\r\n        {\r\n            order.ShippingStatusId = (int)ShippingStatus.Delivered;\r\n            await _orderService.UpdateOrderAsync(order);\r\n        }\r\n\r\n        //add a note\r\n        await AddOrderNoteAsync(order, $\"Shipment# {shipment.Id} has been delivered\");\r\n\r\n        if (order.PickupInStore)\r\n        {\r","sourceCodeStart":2311,"sourceCodeEnd":2347,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Libraries/Nop.Services/Orders/OrderProcessingService.cs#L2311-L2347","documentation":"Thrown by OrderProcessingService.DeliverAsync when shipment.DeliveryDateUtc already has a value. It is an idempotency guard preventing a shipment from being delivered twice, which would otherwise overwrite the delivery timestamp, re-run the 'order fully delivered' shipping-status logic, and re-fire notifications.","triggerScenarios":"Calling DeliverAsync on a Shipment whose DeliveryDateUtc is non-null: duplicate admin 'Deliver' clicks, re-fired carrier webhooks, or concurrent requests on the same shipment.","commonSituations":"Store staff double-clicking Deliver; an ERP sync that reprocesses delivered shipments; a webhook retry storm after a transient HTTP failure; missing idempotency keys on a custom fulfillment endpoint.","solutions":["Guard before calling: if (shipment.DeliveryDateUtc.HasValue) return;","Make the calling endpoint idempotent by keying off shipment.Id so duplicate deliver events collapse.","Disable the 'Deliver' UI action once shipment.DeliveryDateUtc is set.","For integrations, re-fetch the shipment right before delivery to narrow the check-then-act race."],"exampleFix":"// before\nawait _orderProcessingService.DeliverAsync(shipment, true);\n\n// after\nif (shipment.DeliveryDateUtc.HasValue)\n    return; // already delivered\n\nawait _orderProcessingService.DeliverAsync(shipment, true);","handlingStrategy":"validation","validationCode":"if (shipment.DeliveryDateUtc.HasValue)\n    return; // already delivered\n\nawait _orderProcessingService.DeliverAsync(shipment, true);","typeGuard":null,"tryCatchPattern":"try { await _orderProcessingService.DeliverAsync(shipment, true); }\ncatch (NopException ex) when (ex.Message == \"This shipment is already delivered\")\n{\n    // idempotent: treat as success\n}","preventionTips":["Disable the 'Deliver' UI action once shipment.DeliveryDateUtc is set.","Make the delivery endpoint idempotent, keyed on shipment.Id.","Re-fetch the shipment immediately before delivery to reduce the race."],"tags":["shipment","delivery","idempotency","order-processing"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}