Skip to content

Purchase Orders (أوامر الشراء)

Formal purchase orders sent to suppliers. Can be created standalone or converted from an approved Purchase Request.

Status Workflow

StatusEditableCan SubmitCan ApproveCan ConfirmCan SendCan CancelCan Close
draftYesYesNoNoNoYesNo
pending_approvalNoNoYesNoNoYesNo
approvedNoNoNoYesNoYesNo
confirmedNoNoNoNoYesYes*Yes
sentNoNoNoNoYesYes*Yes
partially_receivedNoNoNoNoNoNoYes
fully_receivedNoNoNoNoNoNoYes
partially_billedNoNoNoNoNoNoYes
fully_billedNoNoNoNoNoNoYes
closedNoNoNoNoNoNoNo
cancelledNoNoNoNoNoNoNo

*Cancel is blocked if any items have received or billed quantities > 0.

Entity Attributes

PurchaseOrder

FieldTypeDescription
idintegerPrimary key
company_idintegerTenant company
branch_idintegerBranch (nullable)
order_numberstringAuto-generated (e.g., PO-2026-00001)
datedateOrder date
expected_delivery_datedateExpected delivery date
supplier_idintegerSupplier business partner ID
supplier_namestringCached supplier name
warehouse_idintegerReceiving warehouse
purchase_request_idintegerSource PR (nullable)
statusenumSee workflow above (11 states)
receive_statusenumpending, partial, complete
bill_statusenumpending, partial, complete
referencestringExternal reference
subjectstringOrder subject
notes / notes_artextAdditional notes
terms / terms_artextPayment/delivery terms
currency_codestringCurrency (default KWD)
exchange_ratedecimal(12,6)Exchange rate
payment_terms_daysintegerPayment terms in days
subtotaldecimal(15,3)Sum of line totals
discount_amountdecimal(15,3)Sum of line discounts
tax_amountdecimal(15,3)Sum of line taxes
totaldecimal(15,3)subtotal + tax_amount
created_byintegerCreator user ID
approved_byintegerApprover user ID
approved_atdatetimeApproval timestamp
confirmed_byintegerConfirmer user ID
confirmed_atdatetimeConfirmation timestamp
cancelled_byintegerCanceller user ID
cancelled_atdatetimeCancellation timestamp
cancellation_reasontextCancellation reason
rejection_reasontextRejection reason

PurchaseOrderItem

FieldTypeDescription
idintegerPrimary key
purchase_order_idintegerFK to purchase order
product_idintegerProduct
product_variant_idintegerOptional variant
unit_idintegerUnit of measure
description / description_arstringItem description
quantitydecimal(15,3)Ordered quantity
unit_costdecimal(15,3)Unit cost
discount_percentdecimal(8,3)Discount percentage
discount_amountdecimal(15,3)Calculated discount amount
tax_rate_idintegerOptional tax rate
tax_amountdecimal(15,3)Calculated tax amount
line_totaldecimal(15,3)Line total after discount
received_quantitydecimal(15,3)Quantity received via GRN
billed_quantitydecimal(15,3)Quantity billed
notestextItem-level notes
sort_orderintegerDisplay order

API Endpoints

MethodEndpointPermissionDescription
GET/api/purchases/orderspurchases.orders.viewList purchase orders
POST/api/purchases/orderspurchases.orders.createCreate purchase order
GET/api/purchases/orders/{id}purchases.orders.viewShow purchase order
PUT/api/purchases/orders/{id}purchases.orders.updateUpdate purchase order
DELETE/api/purchases/orders/{id}purchases.orders.deleteDelete draft order
POST/api/purchases/orders/{id}/submit-approvalpurchases.orders.approveSubmit for approval
POST/api/purchases/orders/{id}/approvepurchases.orders.approveApprove order
POST/api/purchases/orders/{id}/rejectpurchases.orders.approveReject order
POST/api/purchases/orders/{id}/confirmpurchases.orders.confirmConfirm order
POST/api/purchases/orders/{id}/sendpurchases.orders.manageMark sent to supplier
POST/api/purchases/orders/{id}/cancelpurchases.orders.manageCancel order
POST/api/purchases/orders/{id}/closepurchases.orders.manageClose order
POST/api/purchases/requests/{id}/convert-to-orderpurchases.orders.createConvert PR to PO

Query Parameters (List)

ParameterTypeDescription
statusstringFilter by status
receive_statusstringFilter by receive status
bill_statusstringFilter by bill status
supplier_idintegerFilter by supplier
warehouse_idintegerFilter by warehouse
purchase_request_idintegerFilter by source PR
date_fromdateStart date filter
date_todateEnd date filter
searchstringSearch in order_number, reference, subject

Examples

Create Purchase Order

bash
curl -X POST /api/purchases/orders \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-02-25",
    "supplier_id": 1,
    "expected_delivery_date": "2026-03-15",
    "payment_terms_days": 30,
    "items": [
      {
        "product_id": 1,
        "unit_id": 1,
        "quantity": 100,
        "unit_cost": 25.000
      }
    ]
  }'
dart
final response = await dio.post('/api/purchases/orders', data: {
  'date': '2026-02-25',
  'supplier_id': 1,
  'expected_delivery_date': '2026-03-15',
  'payment_terms_days': 30,
  'items': [
    {
      'product_id': 1,
      'unit_id': 1,
      'quantity': 100,
      'unit_cost': 25.000,
    }
  ],
});

Convert Purchase Request to Order

bash
curl -X POST /api/purchases/requests/1/convert-to-order \
  -H "Authorization: Bearer {token}" \
  -d '{"supplier_id": 1}'
dart
await dio.post('/api/purchases/requests/1/convert-to-order', data: {
  'supplier_id': 1,
});

Reject Order

bash
curl -X POST /api/purchases/orders/1/reject \
  -H "Authorization: Bearer {token}" \
  -d '{"reason": "Budget exceeded"}'
dart
await dio.post('/api/purchases/orders/1/reject', data: {
  'reason': 'Budget exceeded',
});

Business Rules

  • Purchase orders are auto-numbered using the PO sequence (e.g., PO-2026-00001)
  • Only draft orders can be edited or deleted
  • Submitting for approval requires at least one item
  • Rejection requires a reason and returns the order to draft status for editing
  • Cancel is blocked if any items have received_quantity > 0 or billed_quantity > 0
  • Creating from a Purchase Request marks the PR as converted and copies all items
  • The subtotal, discount_amount, tax_amount, and total are automatically recalculated when items change
  • receive_status and bill_status are updated automatically when GRNs/Bills are processed

Moon ERP API Documentation