Skip to main content

Scenario: Turn a purchase requisition into a purchase order

Goal. An employee's request for goods, raised in an external system (an e-procurement portal, a service desk, an intranet form), becomes a D365 purchase requisition, goes through the requisition's approval workflow, and ends as a purchase order to the vendor. Your system creates the requisition, submits it, approves it as the workflow's approvers, and reads back the purchase order number.

When to use. Requests that must be approved before anything is ordered. If you already know what to order and from whom, create the purchase order directly and continue with Receive and invoice a purchase order, which is also the next step after this one.

Prerequisites​

  1. Security. The D365 user your Entra application is mapped to needs:

    • MGCLatticeAccountsPayableServiceMaintain for submitPurchaseRequisition and convertPurchaseRequisitionToOrder, and MGCLatticeWorkflowServiceMaintain for submitToWorkflow and approveWorkItem (both in duty MGCLatticeIntegrationServiceOperationsDuty);
    • MGCLatticeWorkflowServiceView for getWorkflowStatus (duty MGCLatticeIntegrationServiceQueryDuty).

    The integration operator and administrator roles hold both duties. The standard D365 entities this page uses (PurchaseRequisitionHeaders, PurchaseRequisitionLines, PurchaseOrderLinesV2, WorkflowWorkItems) are secured by D365's own privileges, which the Lattice roles do not grant.

  2. The calling user is the preparer. D365 lets only a requisition's preparer submit it, so the calling D365 user must be linked to the preparer's worker (the user's Person on System administration > Users > Users). In USMF the Admin user is Julia Funderburk, worker 000020.

  3. An active requisition review workflow. A workflow of type PurchReqReview must apply to the requisition (Procurement and sourcing > Setup > Procurement and sourcing workflows). USMF ships one; its review step is assigned to the users Inga and Sara.

  4. Workflow processing is running. The Workflow message processing batch job creates the approvers' work items after a submit. Check it is Waiting or Executing on System administration > Inquiries > Batch jobs; while it is on hold, no work item is ever created.

  5. Procurement and purchasing policies. Each requisition line must pass the buying legal entity's procurement policy. In USMF the policy limits items to the Office Supplies USMF catalog (C0001 to C0004; C0001 and C0003 also need a color). The purchasing policy (Procurement and sourcing > Setup > Policies > Purchasing policies) decides whether approved lines become purchase orders automatically or wait for manual creation; step 5 depends on it. Number sequences for requisitions and purchase orders must exist.

  6. Lattice. A valid license for the write operations. To send your own requisition keys instead of D365 numbers, set up an external system (PurchReqIdExternalKey, see Cross-reference keys).

Steps​

Every service call is POST https://<your-environment>/api/services/<ServiceGroup>/<ServiceClass>/<operation> with an OAuth 2.0 client-credentials token and the request in _request. Send a new RequestId (GUID) for each logical request and the same one when you retry it.

  1. Create the requisition and its lines (OData). Purchase requisitions are shared across legal entities, so the header has no dataAreaId; each line names its buying legal entity.

    POST https://<your-environment>/data/PurchaseRequisitionHeaders

    { "RequisitionName": "Keyboards for new hires", "RequisitionPurpose": "Consumption", "PreparerPersonnelNumber": "000020" }

    The response carries the RequisitionNumber (for example 000312). Add a line:

    POST https://<your-environment>/data/PurchaseRequisitionLines

    { "RequisitionNumber": "000312", "RequisitionLineNumber": 1, "ItemNumber": "C0002",
    "RequestedPurchaseQuantity": 10, "PurchasePrice": 50, "BuyingLegalEntityId": "USMF",
    "ReceivingSiteId": "1", "ReceivingWarehouseId": "11" }
  2. Submit it to workflow. Two operations do this, with the same document checks as the requisition page's Submit: the requisition must be a draft with no workflow in progress, have lines, be submitted by its preparer and pass the submission rules. It moves to In review together with the workflow activation.

    OperationService and groupYou sendDocumentId in the answer
    submitPurchaseRequisitionMGCLatticePurchaseRequisitionService, MGCLatticeAccountsPayableServiceGroupPurchReqId (or PurchReqIdExternalKey)The requisition number; the message names the workflow correlation id
    submitToWorkflowMGCLatticeWorkflowActionService, MGCLatticeWorkflowServiceGroupWorkflowTypeName, TableName, DocumentNumber (or RecordRecId)The workflow correlation id (lower case, no braces)

    POST .../api/services/MGCLatticeAccountsPayableServiceGroup/MGCLatticePurchaseRequisitionService/submitPurchaseRequisition

    { "_request": { "RequestId": "5d2f8a61-3c4e-4b7a-9f10-2a6c8e1d4b93", "LegalEntityId": "USMF",
    "UserContext": "Admin", "PurchReqId": "000312", "Comment": "Submitted from the portal" } }

    The submitToWorkflow equivalent sends "WorkflowTypeName": "PurchReqReview", "TableName": "PurchReqTable" and "DocumentNumber": "000312".

  3. Find the workflow and who must approve it. Call getWorkflowStatus (MGCLatticeWorkflowActionService, MGCLatticeWorkflowServiceGroup) with the requisition number, the correlation id, or the requisition's RecId:

    { "_request": { "RequestId": "0e7b3c55-18d2-4f6e-a1c9-77b04d2e9a10", "LegalEntityId": "USMF", "DocumentId": "000312" } }

    DocumentStatus is the workflow's tracking status (Pending, Completed, Cancelled, Faulted, ...). StatusDetails carries WorkflowCorrelationId and one PendingWorkItem_<RecId> entry per pending work item, whose value is its assignee. The work items appear asynchronously, usually within a minute and sometimes after several, so poll until at least one is listed. The standard WorkflowWorkItems entity ($filter=RootCorrelationId eq <correlation id>) gives the same UserId, Status and Type.

  4. Approve each work item as its assignee. Call approveWorkItem (MGCLatticeWorkflowActionService, MGCLatticeWorkflowServiceGroup). ActingUserId is required and must be the assignee; UserContext never selects who acts. The action runs as that user, so the workflow history records the approver.

    { "_request": { "RequestId": "a41c6e02-95bd-4d1f-8e3a-c2d7f0b65e18", "LegalEntityId": "USMF",
    "WorkflowCorrelationId": "be1322c8-5f0a-4c55-9d2e-3a7b6c1f8e04", "ActingUserId": "Inga",
    "Comment": "Approved" } }

    DocumentId is the work item's RecId. Call getWorkflowStatus again: if another approval work item is pending (USMF assigns the review step to Inga and Sara), approve it as its assignee too, with a new RequestId, until DocumentStatus is Completed.

  5. Get the purchase order. Read the requisition's status:

    GET https://<your-environment>/data/PurchaseRequisitionHeaders?$filter=RequisitionNumber eq '000312'&$select=RequisitionStatus

    • Closed: the purchasing policy creates purchase orders automatically, so D365 released the approved requisition to a purchase order on its own, shortly after the approval. Read the order from its lines: GET https://<your-environment>/data/PurchaseOrderLinesV2?$filter=PurchaseRequisitionId eq '000312' and dataAreaId eq 'USMF'&$select=PurchaseOrderNumber&cross-company=true. Do not call the conversion.

    • Approved: the lines use manual purchase order creation. Call convertPurchaseRequisitionToOrder (MGCLatticePurchaseRequisitionService, MGCLatticeAccountsPayableServiceGroup):

      { "_request": { "RequestId": "c9f05b7e-2a61-4e38-b4d3-91e6a0c27f45", "LegalEntityId": "USMF", "PurchReqId": "000312" } }

      DocumentId is the requisition, PostedDocumentId the first purchase order created, and the message lists every order the conversion created.

How to verify​

  • submitPurchaseRequisition / submitToWorkflow: Success true, Status 3 (Succeeded), and PurchaseRequisitionHeaders.RequisitionStatus is InReview.
  • getWorkflowStatus: DocumentStatus Completed after the last approval, with no PendingWorkItem_ entry left.
  • The requisition is Approved or, when the policy released it, Closed.
  • The order exists: PurchaseOrderLinesV2 rows with PurchaseRequisitionId = your requisition, or the PostedDocumentId of the conversion in PurchaseOrderHeadersV2.
  • In D365: Procurement and sourcing > Purchase requisitions > All purchase requisitions shows the status and the workflow history; the order is on Procurement and sourcing > Purchase orders > All purchase orders.
  • The Purchase requisition approved business event fires when the approval workflow completes, if you have activated it.
  • Every call is listed on System administration > Inquiries > Lattice > Services > Service call log with its error code, message and request id.

When it goes wrong​

ErrorCode arrives as an integer (1 ValidationFailed, 2 DocumentNotFound, 3 InvalidStatus, 4 BusinessRule, 11 ConfigurationMissing); Errors carries the D365 messages.

  • The line is refused when you create it (OData error): the item is outside the procurement policy ("The product is no longer available") or is a product master without its dimensions. Use an item from the policy's catalog.
  • Submit, BusinessRule, "can only be submitted by its preparer": link the calling user to the preparer's worker, or create the requisition with the calling user's worker as preparer.
  • Submit, BusinessRule, "has no lines" or "does not pass the submission rules": the reasons are in Errors; correct the requisition and submit again (a failed request is not recorded, so its RequestId runs again).
  • Submit, InvalidStatus: the requisition is not a draft, or a workflow is already in progress.
  • Submit, ConfigurationMissing: no active PurchReqReview configuration applies to the requisition.
  • Approve, InvalidStatus with IsRetryable true: the workflow is pending but its work items are not created yet. Wait and retry. If they never appear, check that Workflow message processing is running and whether getWorkflowStatus reports Faulted with a FaultMessage detail.
  • Approve, BusinessRule, "assigned to ...": ActingUserId is not the assignee; the message names the assignees. Send one of them.
  • Approve, ValidationFailed: ActingUserId is missing or not an enabled user, or neither WorkflowCorrelationId nor WorkItemRecId was sent.
  • Approve, BusinessRule, refused by the platform: for example the workflow parameter Prevent external work item completion stops completion from outside the work item; the reason is in Errors.
  • Convert, InvalidStatus: the requisition is not Approved. When the error names Closed, the purchasing policy has already released it (also when it happens between your status read and the call): read the order from PurchaseOrderLinesV2. InReview means the approval is not complete yet.
  • Convert, ValidationFailed, "no lines left to convert": every line already has a purchase order.
  • Starting over. recallWorkflow (WorkflowCorrelationId) cancels the workflow and returns the requisition to Draft; only the workflow's originator, or a user with the workflow history's Cancel, may recall it (AccessDenied otherwise). rejectWorkItem returns the requisition to its preparer.
  • Retries. None of these operations has a preview: PreviewMode: true is refused with PreviewUnsupported. Resending the same RequestId returns the recorded result and never acts twice, so give each approval its own RequestId; a RequestId already used by another operation is refused with DuplicateRequest. TransientRuntime and RequestInProgress are safe to retry with the same RequestId.

Reference​