Skip to content

Goods Received Notes (أذونات استلام البضائع)

Record goods received from suppliers. Supports 3 modes controlled by the purchases.grn_mode setting.

GRN Modes

ModeDescriptionFlow
directGRN endpoints disabledStock added on Purchase Bill approval
grnStandard receivingDraft → Approved (stock added)
grn_qualityReceiving + quality checkDraft → Pending Quality → Quality Approved/Rejected → Approved

Status Workflow

grn Mode

grn_quality Mode

StatusEditableCan Submit QualityCan Quality CheckCan ApproveCan Cancel
draftYesYes*NoYes**Yes
pending_qualityNoNoYesNoYes
quality_approvedNoNoNoYesYes
quality_rejectedNoNoNoNoYes
approvedNoNoNoNoNo
cancelledNoNoNoNoNo

*Submit Quality only in grn_quality mode. **Approve from draft only in grn mode.

Entity Attributes

PurchaseGrn

FieldTypeDescription
idintegerPrimary key
company_idintegerTenant company
branch_idintegerBranch (nullable)
grn_numberstringAuto-generated (e.g., GRN-2026-00001)
datedateReceipt date
purchase_order_idintegerSource PO (nullable)
warehouse_idintegerReceiving warehouse
supplier_idintegerSupplier business partner ID
supplier_namestringCached supplier name
statusenumSee workflow above (6 states)
referencestringExternal reference
notes / notes_artextAdditional notes
quality_notestextQuality check notes
total_quantitydecimal(15,3)Sum of item quantities
total_costdecimal(15,3)Sum of item costs
inventory_receipt_idintegerCreated inventory receipt (after approve)
created_byintegerCreator user ID
approved_byintegerApprover user ID
approved_atdatetimeApproval timestamp
quality_checked_byintegerQuality checker user ID
quality_checked_atdatetimeQuality check timestamp
cancelled_byintegerCanceller user ID
cancelled_atdatetimeCancellation timestamp
cancellation_reasontextCancellation reason

PurchaseGrnItem

FieldTypeDescription
idintegerPrimary key
purchase_grn_idintegerFK to GRN
purchase_order_item_idintegerFK to PO item (nullable)
product_idintegerProduct
product_variant_idintegerOptional variant
unit_idintegerUnit of measure
description / description_arstringItem description
quantitydecimal(15,3)Received quantity
accepted_quantitydecimal(15,3)Accepted after quality (nullable)
rejected_quantitydecimal(15,3)Rejected after quality (nullable)
unit_costdecimal(15,3)Unit cost
total_costdecimal(15,3)Calculated total cost
batch_numberstringBatch tracking
expiry_datedateExpiry date
serial_numbersjsonSerial numbers array
rejection_reasontextReason for rejection
notestextItem-level notes
sort_orderintegerDisplay order

API Endpoints

MethodEndpointPermissionDescription
GET/api/purchases/grnspurchases.grns.viewList GRNs
POST/api/purchases/grnspurchases.grns.createCreate GRN
GET/api/purchases/grns/{id}purchases.grns.viewShow GRN
PUT/api/purchases/grns/{id}purchases.grns.updateUpdate GRN
DELETE/api/purchases/grns/{id}purchases.grns.deleteDelete draft GRN
POST/api/purchases/grns/{id}/submit-qualitypurchases.grns.approveSubmit for quality check
POST/api/purchases/grns/{id}/quality-checkpurchases.grns.approveRecord quality results
POST/api/purchases/grns/{id}/approvepurchases.grns.approveApprove GRN
POST/api/purchases/grns/{id}/cancelpurchases.grns.cancelCancel GRN

Query Parameters (List)

ParameterTypeDescription
statusstringFilter by status
purchase_order_idintegerFilter by purchase order
supplier_idintegerFilter by supplier
warehouse_idintegerFilter by warehouse
date_fromdateStart date filter
date_todateEnd date filter
searchstringSearch in grn_number, reference

Examples

Create GRN from Purchase Order

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

Quality Check (Accept/Reject Items)

bash
curl -X POST /api/purchases/grns/1/quality-check \
  -H "Authorization: Bearer {token}" \
  -d '{
    "approved": true,
    "quality_notes": "5 items had damaged packaging",
    "items": [
      {
        "id": 1,
        "accepted_quantity": 45,
        "rejected_quantity": 5,
        "rejection_reason": "Damaged packaging"
      }
    ]
  }'
dart
await dio.post('/api/purchases/grns/1/quality-check', data: {
  'approved': true,
  'quality_notes': '5 items had damaged packaging',
  'items': [
    {
      'id': 1,
      'accepted_quantity': 45,
      'rejected_quantity': 5,
      'rejection_reason': 'Damaged packaging',
    }
  ],
});

Approve GRN (Stock Integration)

bash
curl -X POST /api/purchases/grns/1/approve \
  -H "Authorization: Bearer {token}"
dart
await dio.post('/api/purchases/grns/1/approve');

Stock Integration

When a GRN is approved:

  1. Inventory Receipt is created with reference_type = 'purchase'
  2. The receipt is auto-approved via the Inventory module's ApproveReceipt action
  3. Stock balances are increased, cost layers created, inventory movements recorded
  4. If linked to a PO, the PO item's received_quantity is updated
  5. The PO's receive_status is recalculated (pending / partial / complete)

In quality mode (grn_quality), only the accepted_quantity goes to stock. Rejected items are recorded but do not create stock entries.

Business Rules

  • GRN endpoints return 403 when purchases.grn_mode is set to direct
  • GRNs are auto-numbered using the GRN sequence (e.g., GRN-2026-00001)
  • Only draft GRNs can be edited or deleted
  • Submit for quality is only available in grn_quality mode
  • Quality check records accepted_quantity and rejected_quantity per item with optional rejection reasons
  • Approve can be called from draft (in grn mode) or quality_approved (in grn_quality mode)
  • Approved GRNs cannot be cancelled (stock has already been added)
  • The inventory_receipt_id field links to the created inventory receipt for traceability

Moon ERP API Documentation