Sf orders
Salesforce Order Management for orders, returns, and cases via Cirra AI MCP Server. Use when asked about order status, return orders, return labels, support cases from returns, or the order-to-return-to-case lifecycle. Usage: /sf-orders [order|return|case] {details} ...From its SKILL.md
npx -y skills add cirra-ai/skills --skill sf-ordersAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
18.9 KB, as published. Nobody here has run it
Salesforce Order Management Expert
Manage orders, returns, and support cases in Salesforce using the Cirra AI MCP Server. Covers the full order-to-return-to-case lifecycle using standard Salesforce objects (Order, ReturnOrder, ReturnOrderLineItem, Case).
Dispatch
Parse $ARGUMENTS to determine the operation:
| First argument or intent | Workflow |
|---|---|
order, order status, order details | Order Status |
return, return order, RMA, return label | Return Management |
case, support case, case from return | Case Management |
| (no argument or unclear) | Ask the user (see below) |
When the operation is missing or unclear, you MUST use AskUserQuestion before proceeding:
AskUserQuestion(question="What would you like to do?\n\n1. **Order** — query order status and details\n2. **Return** — create a return order or send a return label\n3. **Case** — create or update a support case")
Do NOT guess the operation or default to one. Wait for the user's answer.
Core Responsibilities
- Order Status: Query order details and line items
- Return Creation: Create ReturnOrder with line items from an existing Order
- Return Label Email: Send return shipping label to customer (flow preferred; Task fallback)
- Case Management: Create and update support cases linked to returns
Phase 1: Initialization & Capability Detection
FIRST: Call cirra_ai_init() with no parameters:
cirra_ai_init()
- If a default org is configured, proceed immediately and confirm with the user:
"I've connected to [org]. Would you like me to use the defaults, or do you want to select different options?"
- If no default is configured, ask for the Salesforce user/alias before proceeding.
Do not ask for org details before calling cirra_ai_init().
THEN: Detect available objects and packages.
Step 1: Check which objects are available
Use sobject_describe on each required object to verify it exists. Call sobject_describe for Order, ReturnOrder, and Case. If the call succeeds, the object is available; if it returns an error (object not found), the object is not available in this org.
Set capability flags:
HAS_ORDERS = trueifsobject_describe(sObject="Order")succeedsHAS_RETURNS = trueifsobject_describe(sObject="ReturnOrder")succeedsHAS_CASES = trueifsobject_describe(sObject="Case")succeeds (almost always true)
If ReturnOrder is missing, inform the user that return operations are unavailable because Order Management / Service Cloud is not enabled. The skill can still handle order status checks and general case management.
Step 2: Check for return label infrastructure (if HAS_RETURNS = true)
Use sobject_describe on ReturnOrder and look for LabelEmailSent__c (Checkbox) and LabelEmailSentDate__c (DateTime).
HAS_LABEL_TRACKING = trueif both fields exist
Then check for the return label flow using tooling_api_query:
-
sObject:
FlowDefinition -
whereClause:
DeveloperName = 'Send_Return_Label_Email' AND ActiveVersionId != null -
HAS_RETURN_LABEL_FLOW = trueif the query returns a result with an active version
If the flow doesn't exist and the user needs email functionality, see references/metadata-setup.md.
Capability Summary
| Operation | Requires |
|---|---|
| Check Order Status | HAS_ORDERS |
| Create Return | HAS_ORDERS + HAS_RETURNS |
| Email Return Label | HAS_RETURNS (flow preferred; Task fallback if no flow) |
| Update Case Status | HAS_CASES |
| Create Case from Return | HAS_RETURNS + HAS_CASES |
Tool Usage Notes
The Cirra AI MCP Server's soql_query tool requires structured parameters, not raw SOQL strings. Always provide:
sObject— the object API namefields— array of field names (relationship fields likeAccount.Nameare supported)whereClause— the WHERE condition (without theWHEREkeyword)orderBy— ORDER BY clause (pass empty string""if not needed)groupBy— GROUP BY clause (pass empty string""if not needed)limit— max records to return
The tool does not support subqueries in the fields array. To get child records (e.g., OrderItems for an Order), run a separate query on the child object with a WHERE filter on the parent ID.
For DML operations, use sobject_dml with sObject, operation (insert/update/delete/upsert), and records array. For delete operations, use recordIds (string array of IDs) instead of records.
IMPORTANT — Resolved IDs: When a lookup query accepts both an ID and a human-readable number (e.g., Id OR OrderNumber), always use the Id returned from the query result for all subsequent operations (DML, child queries, updates). Never pass raw user input (which may be a number, not an ID) into DML or relationship queries.
IMPORTANT — Input format detection: Before constructing a whereClause that accepts user input, detect whether the input is a Salesforce ID (15 or 18 alphanumeric characters) or a human-readable number/string. Using Id = '{value}' OR SomeNumber = '{value}' causes a MALFORMED_ID error when the value is not a valid ID format because Salesforce validates the Id field before evaluating the OR. Instead:
- If input matches a Salesforce ID pattern (15 or 18 alphanumeric chars): use
Id = '{value}' - Otherwise: use the number/name field only (e.g.,
OrderNumber = '{value}')
1. Check Order Status
When a user asks about an order's status, shipping, or details:
Query the order
The user may provide a Salesforce ID (15/18 chars) or an OrderNumber. Detect the input format (see Tool Usage Notes) and use the appropriate whereClause.
Use soql_query:
- sObject:
Order - fields:
["Id", "OrderNumber", "Status", "TotalAmount", "AccountId", "Account.Name", "EffectiveDate", "EndDate", "Description", "Type"] - whereClause:
Id = '{orderId}'(if ID format) orOrderNumber = '{orderId}'(if number format) - orderBy:
OrderNumber - groupBy: ``
- limit:
1
Query line items
Use the Order Id from the query result above (not the raw user input).
Use soql_query:
- sObject:
OrderItem - fields:
["Id", "OrderId", "Product2.Name", "Quantity", "UnitPrice", "TotalPrice", "Description"] - whereClause:
OrderId = '{order.Id}' - orderBy:
CreatedDate ASC - groupBy: ``
- limit:
200
Present results
- Order Number, Status, Total Amount
- Account name
- Line items in table format (Product, Quantity, Unit Price, Total)
- Links to records using
link_build
2. Create Return Order
When a user wants to return items from an order:
Discovery Phase
Gather requirements:
- Which order? (ID or order number)
- Which line item(s) to return? (specific item or auto-detect first item)
- Return reason: Defective, Damaged, Wrong Item, Not Needed, Quality Issue, Size/Color, Other
- Quantity to return
- Optional description
Pre-Creation Validation
Step 1: Verify the order exists and get its details.
Use soql_query:
- sObject:
Order - fields:
["Id", "OrderNumber", "Status", "AccountId", "Account.Name", "TotalAmount"] - whereClause:
Id = '{orderId}'(if ID format) orOrderNumber = '{orderId}'(if number format) - orderBy: ``
- groupBy: ``
- limit:
1
Step 2: Get order line items (use the Order Id from Step 1, not raw user input).
Use soql_query:
- sObject:
OrderItem - fields:
["Id", "OrderId", "Product2Id", "Product2.Name", "Quantity", "UnitPrice", "TotalPrice"] - whereClause:
OrderId = '{order.Id}' - orderBy:
CreatedDate ASC - groupBy: ``
- limit:
200
If the user didn't specify a line item, present available items and ask which one(s) to return. If there's only one item, or the user says "auto-detect", use the first item.
Step 3: Validate return quantity — cannot exceed original order quantity.
Create the Return
Step 1: Create the ReturnOrder using sobject_dml:
- sObject:
ReturnOrder - operation:
insert - records:
[ { "OrderId": "<original_order_id>", "AccountId": "<account_id_from_order>", "Status": "Draft", "Description": "Return for Order Item <line_item_id> - <reason>" } ]
Step 2: Create the ReturnOrderLineItem using sobject_dml:
- sObject:
ReturnOrderLineItem - operation:
insert - records:
[ { "ReturnOrderId": "<return_order_id_from_step1>", "OrderItemId": "<line_item_id>", "Product2Id": "<product_id_from_order_item>", "QuantityReturned": "<quantity>", "Description": "Return <quantity> unit(s) - <reason>" } ]
Step 3: Update ReturnOrder status to Submitted using sobject_dml:
- sObject:
ReturnOrder - operation:
update - records:
[ { "Id": "<return_order_id>", "Status": "Submitted" } ]
Rollback on failure: If ReturnOrderLineItem creation fails, delete the ReturnOrder:
- sObject:
ReturnOrder - operation:
delete - recordIds:
["<return_order_id>"]
Verification
Query the created return order using soql_query:
- sObject:
ReturnOrder - fields:
["Id", "ReturnOrderNumber", "Status", "Description", "AccountId", "OrderId"] - whereClause:
Id = '{return_order_id}' - orderBy: ``
- groupBy: ``
- limit:
1
Then query line items separately:
- sObject:
ReturnOrderLineItem - fields:
["Id", "Product2.Name", "QuantityReturned", "Description"] - whereClause:
ReturnOrderId = '{return_order_id}' - orderBy: ``
- groupBy: ``
- limit:
200
Present results with the return order number, status, and a link to the record.
3. Email Return Label
When a user wants to send a return shipping label to a customer:
Prerequisites
HAS_RETURNSmust be true- The ReturnOrder must be in "Approved" or "Partially Fulfilled" status
- If
HAS_LABEL_TRACKING = true, check that the label hasn't already been sent
Validation
Step 1: Verify the return order.
Use soql_query:
- sObject:
ReturnOrder - fields:
["Id", "ReturnOrderNumber", "OrderId", "Status", "Description"](addLabelEmailSent__c, LabelEmailSentDate__cifHAS_LABEL_TRACKING = true) - whereClause:
Id = '{returnOrderId}'(if ID format) orReturnOrderNumber = '{returnOrderId}'(if number format) - orderBy: ``
- groupBy: ``
- limit:
1
Step 2: Business validation:
- Status must be "Approved" or "Partially Fulfilled"
- If
LabelEmailSent__c = true, reject: "Return label already sent on {date}" - Validate email format
Send the Label
If HAS_RETURN_LABEL_FLOW = true, the flow should be triggered. Since the Cirra AI MCP doesn't have a direct "run flow" tool, guide the user to trigger the flow manually or use tooling_api_dml.
If HAS_LABEL_TRACKING = true and the flow was triggered successfully, update the tracking fields:
Use sobject_dml:
- sObject:
ReturnOrder - operation:
update - records:
[ { "Id": "{returnOrder.Id}", "LabelEmailSent__c": true, "LabelEmailSentDate__c": "<current_datetime_ISO>" } ]
If HAS_RETURN_LABEL_FLOW = false, create a Task record as a fallback so the label can be sent manually. Do not update LabelEmailSent__c — no email has actually been sent yet.
Use the ReturnOrder Id and ReturnOrderNumber from the Step 1 query result for all fields below.
Use sobject_dml:
- sObject:
Task - operation:
insert - records:
[ { "Subject": "Send Return Label - {returnOrder.ReturnOrderNumber}", "Description": "Send return shipping label to {customerEmail} for return order {returnOrder.ReturnOrderNumber}", "Status": "Not Started", "Priority": "High", "WhatId": "{returnOrder.Id}", "ActivityDate": "<today>" } ]
4. Update Case Status
When a user wants to update a support case:
Validation
Step 1: Verify the case exists.
Use soql_query:
- sObject:
Case - fields:
["Id", "CaseNumber", "Status", "Priority", "OwnerId", "Owner.Name", "Subject", "Description", "IsClosed", "AccountId", "Account.Name"] - whereClause:
Id = '{caseId}'(if ID format) orCaseNumber = '{caseId}'(if number format) - orderBy: ``
- groupBy: ``
- limit:
1
Step 2: Apply business rules:
- If
IsClosed = trueand new status is not "Closed", reject: "Cannot reopen a closed case. Please create a new case instead." - If current status equals requested status, inform: "Case is already in {status} status."
- Validate status transition (see
references/status-transitions.md)
Status Transition Rules (Quick Reference)
| Current Status | Allowed Transitions |
|---|---|
| New | Working, Escalated, Closed |
| Working | Escalated, Closed |
| Escalated | Working, Closed |
| Closed | (none — cannot reopen) |
Apply the Update
Use the Case Id from the Step 1 query result (not the raw user input, which may be a CaseNumber).
Use sobject_dml:
- sObject:
Case - operation:
update - records:
[ { "Id": "{case.Id}", "Status": "{newStatus}" } ]
Add optional fields if provided: Priority, OwnerId (resolve user first via soql_query on User).
Create audit trail if a reason was provided:
Use sobject_dml:
- sObject:
CaseComment - operation:
insert - records:
[ { "ParentId": "{case.Id}", "CommentBody": "Status changed from {previousStatus} to {newStatus}. Reason: {reason}", "IsPublished": false } ]
Present results with the updated case number, new status, and a link.
5. Create Case from Return
When a user wants to create a support case linked to a return order:
Validation
Step 1: Get the return order.
Use soql_query:
- sObject:
ReturnOrder - fields:
["Id", "ReturnOrderNumber", "OrderId", "Status", "Description", "AccountId", "Account.Name", "CaseId"] - whereClause:
Id = '{returnOrderId}'(if ID format) orReturnOrderNumber = '{returnOrderId}'(if number format) - orderBy: ``
- groupBy: ``
- limit:
1
Step 2: Get return line items (use the ReturnOrder Id from Step 1, not raw user input).
Use soql_query:
- sObject:
ReturnOrderLineItem - fields:
["Id", "Product2Id", "Product2.Name", "QuantityReturned", "Description"] - whereClause:
ReturnOrderId = '{returnOrder.Id}' - orderBy: ``
- groupBy: ``
- limit:
200
Step 3: Business validation:
- If
CaseIdis already populated, reject: "A case already exists for this return order. Case ID: {CaseId}" - Status must be "Submitted", "Approved", or "Partially Fulfilled"
Step 4: Get order details for context.
Use soql_query:
- sObject:
Order - fields:
["Id", "OrderNumber", "AccountId", "Account.Name", "TotalAmount"] - whereClause:
Id = '{orderId_from_return}' - orderBy: ``
- groupBy: ``
- limit:
1
Create the Case
Determine priority based on return line item descriptions:
- Defective, Damaged, or Quality Issue → High
- All others → Medium
Use sobject_dml:
- sObject:
Case - operation:
insert - records:
[ { "Subject": "Return Order Issue - {ReturnOrderNumber}", "Description": "Case created for return order {ReturnOrderNumber}.\n\nOrder: {OrderNumber}\nReturn Status: {Status}\nReturn Description: {Description}\n\nReturning Items:\n1. {Product Name} (Qty: {QuantityReturned}) - {Description}", "Status": "New", "Priority": "<determined_priority>", "Origin": "Web", "Type": "Other", "AccountId": "{accountId_from_order}" } ]
Link the case back to the return order (use the ReturnOrder Id from Step 1):
Use sobject_dml:
- sObject:
ReturnOrder - operation:
update - records:
[ { "Id": "{returnOrder.Id}", "CaseId": "{new_case_id}" } ]
Note: The CaseId field on ReturnOrder is a standard field. If the update fails (field not available), log the warning but don't fail — the case was still created.
Present Results
- Case number and ID with link
- Priority level
- Return order number with link
- Summary of items being returned in table format
6. Notifications (Optional)
Slack webhook alerts and other external notifications are not handled by the Cirra AI MCP Server directly. If the user needs notification workflows:
- Use the
sf-flowskill to create a notification flow - Platform Events or Custom Notifications are native Salesforce alternatives
Presenting Results
For all operations, follow these patterns:
Always include:
- Record IDs and human-readable numbers (OrderNumber, ReturnOrderNumber, CaseNumber)
- Links to records using
link_build - Status information
- Summary tables for line items
Table format for order items:
| # | Product | Quantity | Unit Price | Total |
|---|---------|----------|------------|-------|
Table format for return items:
| # | Product | Qty Returned | Description |
|---|---------|-------------|-------------|
When to Load References
- field-reference.md: When troubleshooting field errors, understanding object relationships, or needing the full list of available fields on Order, ReturnOrder, or Case
- metadata-setup.md: When the org is missing required custom fields or flows and they need to be deployed
- status-transitions.md: When dealing with complex status validation across ReturnOrder and Case lifecycles
Common Issues
ReturnOrder object not found: The org needs Service Cloud or Order Management enabled. ReturnOrder is a standard object but requires specific licenses.
Cannot create ReturnOrderLineItem — OrderItemId not valid: Verify the OrderItem belongs to the Order referenced by the ReturnOrder. Query OrderItems where OrderId matches.
ReturnOrder status won't change to "Submitted": Check if there are validation rules or process builders that prevent the transition. Some orgs require line items before status can change.
CaseId field not available on ReturnOrder: Standard field but may not be visible in all editions. The case is still created; just the link back won't be set. The user can create a custom lookup if needed.
Return quantity exceeds original order quantity: Query the OrderItem to get the original Quantity and validate before creating the return.