Skip to content

ERP Order Verification API Reference

This document provides technical details for developers working with the ERP Order Verification system. It covers the API endpoints, Temporal workflows, data structures, and implementation patterns.

Located in apps/webapp/src/services/erp/implementations/prophet21-service.ts, this private method fetches the actual order items from the P21 Data Services API.

private async fetchVerifiedOrderItems(
connection: ERPConnection,
erpOrderId: string
): Promise<Array<{ itemId: string; quantityOrdered: number; unitPrice: number; }> | null> {
// ...implementation details...
}

Purpose: Makes a GET request to P21 Data Services API endpoint /data/erp/views/v1/p21_view_oe_line to retrieve the actual items in an order as recorded in the ERP system.

Parameters:

  • connection: ERPConnection object with authentication details
  • erpOrderId: The ERP order ID to verify

Returns: Array of verified items from the ERP or null if the request fails.

Error Handling: Returns null on API error and logs detailed error information.

private async executeOrderVerification(
connection: ERPConnection,
erpOrderId: string,
sentItems: Array<{ id: string; name: string; quantity: number; price: number; }>
): Promise<
| { status: 'verified'; erpOrderId: string; verifiedItems: Array<{ itemId: string; quantityOrdered: number; unitPrice: number; }>; }
| { status: 'mismatch'; erpOrderId: string; missingOrMismatchedItems: ErpUnverifiedItemDetail[]; verifiedItems: Array<{ itemId: string; quantityOrdered: number; unitPrice: number; }>; }
| { status: 'verification_failed'; erpOrderId: string; error: { message: string; details?: any }; }
>

Purpose: Compares the items sent to the ERP with what was actually stored in the ERP system.

Parameters:

  • connection: ERPConnection object
  • erpOrderId: The ERP order ID to verify
  • sentItems: Array of items that were sent to the ERP

Returns: Verification result with appropriate status and details:

  • verified: All items match
  • mismatch: Some items missing or have quantity discrepancies
  • verification_failed: Error during verification process

Path: /api/erp/orders/generate-quote
Method: POST
File: apps/webapp/src/pages/api/erp/orders/generate-quote.ts

Pre-commits a QUOTE_PENDING row in the orders table and starts the asynchronous Temporal workflow ERPQuoteGenerationWorkflow (apps/ts-temporal-worker/src/workflows/erp-submission.ts).

Request Payload:

{
localOrderId: string; // ID of the extracted order
erpCustomerId: string;
customerName: string;
erpCompanyId: string;
erpShipToId: string;
poNumber: string;
items: Array<{
erpItemId: string;
quantity: number;
price: number;
name: string;
productId: string;
unitOfMeasure?: string;
isDeleted?: boolean;
}>;
}

Response (202 Accepted — Workflow Started):

{
workflowId: string;
orderId: string;
status: 'QUOTE_PENDING';
message: string;
}

The client awaits workflow completion via SSE (/api/temporal/workflow/[workflowId]), which resolves with the ERP order/quote number and verification outcome (verificationStatus, verificationMessage, unverifiedItems).

Response (Error — 4xx / 409 Conflict):

{
error: string;
code?: 'ALREADY_HAS_ERP_ORDER_NUMBER' | 'DUPLICATE_REQUEST_IN_PROGRESS';
erpMessage?: string;
}

Path: /api/erp/orders/[id]
Method: PUT
File: apps/webapp/src/pages/api/erp/orders/[id].ts

Handles both quote updates and non-quote sales-order updates:

  • Quote updates (QUOTE_PENDING / QUOTE_GENERATED / QUOTE_FAILED or isQuote: true): Starts the durable Temporal workflow ERPOrderUpdateWorkflow and returns 202 Accepted with { workflowId, orderId }.
  • Non-quote sales-order updates: Calls the ERP connector synchronously and returns 200 OK with the updated order and verification details.

Request Payload:

{
items: Array<{
erpItemId: string;
quantity: number;
price: number;
name?: string;
unitOfMeasure?: string;
}>;
erpCustomerId?: string;
erpShipToId?: string;
poNumber?: string;
isQuote?: boolean;
}

Response (202 Accepted for Quotes / 200 OK for Sync Updates):

// 202 Accepted (Quote update via ERPOrderUpdateWorkflow):
{
workflowId: string;
orderId: string;
}
// 200 OK (Synchronous update / resolved workflow result):
{
erpOrderNumber: string;
verificationStatus: 'verified' | 'mismatch' | 'verification_failed' | null;
verificationMessage: string;
unverifiedItems: ErpUnverifiedItemDetail[];
}

Path: /api/erp/orders/[id]/submit
Method: POST
File: apps/webapp/src/pages/api/erp/orders/[id]/submit.ts

Used by the review-v2 workbench (ReviewSubmitFlow.tsx) and orderEditStore to submit an order directly to the ERP. Runs server-side validation gates (price review, serialization, discounts, address deliverability, revision conflicts, work-item ownership) and starts ERPOrderSubmissionWorkflow, returning HTTP 202 Accepted with { workflowId, orderId, erpOrderRef? }.

interface ErpUnverifiedItemDetail {
id: string; // erpItemId
name: string; // Item name
sentQuantity: number; // Quantity that was sent to ERP
erpQuantity?: number; // Quantity found in ERP (if item exists but with different quantity)
reason: 'missing' | 'quantity_mismatch'; // Why the item failed verification
}
type VerificationResult =
| { status: 'verified'; erpOrderId: string; verifiedItems: P21VerifiedItem[] }
| {
status: 'mismatch';
erpOrderId: string;
missingOrMismatchedItems: ErpUnverifiedItemDetail[];
verifiedItems: P21VerifiedItem[];
}
| {
status: 'verification_failed';
erpOrderId: string;
error: { message: string; details?: any };
};
interface P21VerifiedItem {
itemId: string; // from p21_view_oe_line.item_id
quantityOrdered: number; // from p21_view_oe_line.qty_ordered
unitPrice: number; // from p21_view_oe_line.unit_price
}

The verification system uses these columns on the orders table (packages/db/src/schema/orders.ts):

erpVerificationStatus: text('erp_verification_status'),
erpUnverifiedItemIds: jsonb('erp_unverified_item_ids').$type<ErpUnverifiedItemDetail[]>(),

The verification data is managed in apps/webapp/src/stores/pdfOrder/order.ts (and actions in apps/webapp/src/stores/pdfOrder/actions.ts). Key properties:

// In ExtractedOrderData interface
erpVerificationStatus?: 'verified' | 'mismatch' | 'verification_failed' | 'pending' | null;
erpUnverifiedItemDetails?: ErpUnverifiedItemDetail[] | null;
// Store atom for displaying verification messages
submissionMessage = atom<string | null>(null);

The store has two methods that interact with verification:

  1. generateQuoteInERP - Creates a new quote and processes verification results
  2. updateQuoteInERP - Updates an existing quote and processes verification results

Both methods handle the verification data in a similar way:

// Example from updateQuoteInERP (simplified)
const updatedOrder = { ...orderToUpdate };
if (data.verificationStatus) updatedOrder.erpVerificationStatus = data.verificationStatus;
if (data.unverifiedItems) updatedOrder.erpUnverifiedItemDetails = data.unverifiedItems;
editingOrder.set(updatedOrder);
if (data.verificationMessage) submissionMessage.set(data.verificationMessage);
  1. Data Services API vs Transaction API: The verification system uses the P21 Data Services API (/data/erp/views/v1/p21_view_oe_line) because the transaction-based approach failed with 400 errors.

  2. Error Handling Strategy: The system logs details at various levels but keeps user-facing errors actionable and context-appropriate.

  3. Verification Timing: Verification runs immediately after successful order creation or update. It’s a separate process from the order creation/update itself.

  4. Persistence Strategy: Verification data is stored in the database to ensure it’s available after page refreshes or navigation.

  5. Backward Compatibility: The verification functionality is designed as an enhancement, not a requirement. If verification fails, the order creation/update is still considered successful.

  1. Look at the erpVerificationStatus and erpUnverifiedItemIds fields in the order record
  2. Check the logs for calls to fetchVerifiedOrderItems and executeOrderVerification
  3. Verify that the P21 Data Services API is accessible (may require different permissions than the transaction API)
  4. If verification is failing, check the error details in the logs
  1. The verification depends on the P21 Data Services API, which may have different permissions or availability than the transaction API
  2. Verification is a point-in-time check and does not continuously monitor the order
  3. Some order modifications in the ERP might not be detected if they don’t affect item IDs or quantities