Delivery Notes (أذونات التسليم)
The Delivery Notes API manages the shipping and delivery lifecycle — creating delivery notes from confirmed orders, confirming them (with optional stock deduction), tracking shipments, and recording delivery.
Entity Attributes
SalesDeliveryNote (Header)
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | auto | Primary key |
delivery_number | string | auto | Auto-generated via SequenceService (e.g., DN-00001) |
date | date | yes | Delivery note date |
customer_id | FK | auto | Copied from the source order |
order_id | FK | yes | Source confirmed order |
invoice_id | FK | no | Optional linked invoice |
warehouse_id | FK | yes | Source warehouse for stock deduction |
branch_id | FK | auto | Copied from the source order |
status | enum | auto | draft, confirmed, shipped, delivered, cancelled |
shipping_address | text | no | Delivery address |
carrier_name | string | no | Shipping carrier (e.g., DHL, FedEx) |
tracking_number | string | no | Shipment tracking number |
shipping_method | string | no | Shipping method (Express, Standard, etc.) |
shipping_cost | decimal(15,3) | no | Shipping cost |
estimated_delivery | date | no | Estimated delivery date |
shipped_at | datetime | auto | When the shipment was dispatched |
delivered_at | datetime | auto | When delivery was completed |
received_by | string | no | Name of the person who received delivery |
notes / notes_ar | text | no | Notes in English / Arabic |
confirmed_by | FK | auto | User who confirmed |
confirmed_at | datetime | auto | Confirmation timestamp |
cancelled_by | FK | auto | User who cancelled |
cancelled_at | datetime | auto | Cancellation timestamp |
cancellation_reason | text | no | Reason for cancellation |
SalesDeliveryNoteItem (Line Item)
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | auto | Primary key |
order_item_id | FK | yes | Source order line item |
product_id | FK | auto | Copied from order item |
product_variant_id | FK | auto | Copied from order item |
unit_id | FK | auto | Copied from order item |
quantity | decimal(15,3) | yes | Delivery quantity (max = remaining delivery qty) |
batch_number | string | no | Batch/lot number |
serial_numbers | JSON | no | Array of serial numbers |
notes | text | no | Line item notes |
sort_order | integer | no | Display order |
ER Diagram
Delivery Note Lifecycle
Confirmation Flow (Critical)
When a delivery note is confirmed (POST /api/sales/delivery-notes/{id}/confirm), the following happens atomically:
Step 1: Stock Deduction (conditional)
If sales.stock_deduction_point = 'delivery':
- For each line item with
product.track_inventory = true - Decreases stock via
StockService::decreaseStock()with movement typeIssue - Records inventory movement for audit trail
If
sales.stock_deduction_point = 'invoice', stock is not deducted on delivery confirmation — it happens when the invoice is posted instead.
Step 2: Update Order Delivery Quantities
- For each line item linked to an order item:
- Increments
order_item.delivered_quantityby the delivery quantity
- Increments
- Calls
order.recalculateDeliveryStatus()to update the order'sdelivery_status(pending → partial → complete)
Cancellation Flow
When a confirmed/shipped delivery note is cancelled:
- Stock restored — if
sales.stock_deduction_point = 'delivery', stock is increased back viaStockService::increaseStock() - Order quantities reversed — each order item's
delivered_quantityis decremented - Delivery status recalculated — order's
delivery_statusis recalculated
Partial Delivery Support
Multiple delivery notes can be created for a single order. The system tracks:
remaining_delivery_qty = order_item.quantity - order_item.delivered_quantityEach new delivery note validates that the requested quantity does not exceed the remaining deliverable amount.
API Endpoints
| Method | Endpoint | Description | Permission |
|---|---|---|---|
GET | /api/sales/delivery-notes | List delivery notes (paginated) | sales.delivery_notes.view |
POST | /api/sales/delivery-notes | Create a delivery note from order | sales.delivery_notes.create |
GET | /api/sales/delivery-notes/{id} | Get delivery note details | sales.delivery_notes.view |
PUT | /api/sales/delivery-notes/{id} | Update a draft delivery note | sales.delivery_notes.update |
DELETE | /api/sales/delivery-notes/{id} | Delete a draft delivery note | sales.delivery_notes.delete |
POST | /api/sales/delivery-notes/{id}/confirm | Confirm delivery note | sales.delivery_notes.confirm |
POST | /api/sales/delivery-notes/{id}/ship | Mark as shipped | sales.delivery_notes.ship |
POST | /api/sales/delivery-notes/{id}/deliver | Mark as delivered | sales.delivery_notes.deliver |
POST | /api/sales/delivery-notes/{id}/cancel | Cancel delivery note | sales.delivery_notes.cancel |
POST | /api/sales/orders/{id}/create-delivery-note | Auto-create DN from order | sales.delivery_notes.create |
Query Parameters (List)
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by delivery note status |
customer_id | integer | Filter by customer |
order_id | integer | Filter by source order |
warehouse_id | integer | Filter by warehouse |
branch_id | integer | Filter by branch |
date_from | date | Delivery notes from this date |
date_to | date | Delivery notes up to this date |
search | string | Search in delivery_number, tracking_number, carrier_name |
Request / Response Examples
Create Delivery Note
bash
curl -X POST /api/sales/delivery-notes \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"order_id": 1,
"warehouse_id": 1,
"date": "2026-02-24",
"shipping_address": "123 Main St, Kuwait City",
"items": [
{
"order_item_id": 1,
"quantity": 5,
"batch_number": "LOT-2026-001"
}
]
}'dart
final response = await dio.post('/api/sales/delivery-notes', data: {
'order_id': 1,
'warehouse_id': 1,
'date': '2026-02-24',
'shipping_address': '123 Main St, Kuwait City',
'items': [
{
'order_item_id': 1,
'quantity': 5,
'batch_number': 'LOT-2026-001',
}
],
});Create From Order (auto-populate)
bash
curl -X POST /api/sales/orders/1/create-delivery-note \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"warehouse_id": 1}'dart
final response = await dio.post('/api/sales/orders/1/create-delivery-note', data: {
'warehouse_id': 1,
});Ship Delivery Note
bash
curl -X POST /api/sales/delivery-notes/1/ship \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"carrier_name": "DHL Express",
"tracking_number": "TRK-12345678",
"shipping_method": "Express",
"shipping_cost": 15.500,
"estimated_delivery": "2026-02-28"
}'dart
final response = await dio.post('/api/sales/delivery-notes/1/ship', data: {
'carrier_name': 'DHL Express',
'tracking_number': 'TRK-12345678',
'shipping_method': 'Express',
'shipping_cost': 15.500,
'estimated_delivery': '2026-02-28',
});Deliver
bash
curl -X POST /api/sales/delivery-notes/1/deliver \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"received_by": "Ahmed Hassan"}'dart
final response = await dio.post('/api/sales/delivery-notes/1/deliver', data: {
'received_by': 'Ahmed Hassan',
});Cancel Delivery Note
bash
curl -X POST /api/sales/delivery-notes/1/cancel \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"cancellation_reason": "Customer changed delivery address"}'dart
final response = await dio.post('/api/sales/delivery-notes/1/cancel', data: {
'cancellation_reason': 'Customer changed delivery address',
});Business Rules
- Delivery notes can only be created from confirmed orders — draft or cancelled orders are rejected
- Delivery quantity cannot exceed remaining deliverable amount — tracked across all non-cancelled delivery notes for the same order item
- Product and unit are copied from the order item — cannot be manually adjusted
- Only draft delivery notes can be edited or deleted
- Stock deduction depends on
sales.stock_deduction_pointsetting — either on delivery confirmation or invoice posting - Cancellation restores everything — if confirmed, stock is restored and order quantities are reversed
- Customer and branch are inherited from the source order
- Multiple delivery notes per order — supports partial deliveries