# Purchasing

Purchasing in ION allows you to order parts from a supplier in your network. You can order parts, set quantities and need dates, select terms, and quality clauses, describe supplier instructions, review and approve a purchase order, and finally create receipts against purchase orders.

#### Use Cases:

1. Ordering production-grade hardware, such as customized machined parts.
2. Order commercial off-the-shelf (COTS) parts.
3. Order office equipment.
4. Outsourcing a paint job after internally building the machined part.
5. Ordering software that does not need to be physically received.

## Purchase Statuses

The purchase status is determined by the status of all of the line items. Here is the logic of the purchase status in this specific order.

* **Draft**: If any line item is in Draft, then the purchase is in Draft. In this state, you have the ability to edit the entire purchase order before sending it to review.
* **In Review:** When any PO line is in a requested state, the purchase is "In Review". In this state, you are going through a review process and ensuring reviewers approve a purchase. Once all reviewers have approved, the purchase moves to Approved.
* **Approved:** When any PO line is in an approved state, the purchase is Approved. All reviewers have approved and now the buyer can move the purchase to Ordered and send the PDF to the vendor.
* **Ordered:** When any PO line is Ordered, the purchase is Ordered. If any line items are received, the purchase will still show the Ordered state.
* **Received:** When any PO line is Received, the purchase is Received. You will only end up in this state if all lines are received or canceled.
* **Canceled:** If all purchase lines are canceled, then the Purchase is Canceled.


# Create Purchases

This guide outlines the steps to create a purchase order

### **Step 1: Initiate Purchase Order** [0:00](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=0)

![generated-image-at-00:00:00](https://loom.com/i/9cbb5f6f439b4b1c9039d03e4e579b7c?workflows_screenshot=true)

* Open the ION system.
* Click on 'Create Purchase Order' to start the process.

### **Step 2: Assign Procurement Agent** [0:15](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=15)

![generated-image-at-00:00:15](https://loom.com/i/62e7daa0b0db4dbf9074eb5bff59021e?workflows_screenshot=true)

* Assign the purchase order to yourself or the designated procurement agent.

### **Step 3: Fill Out Purchase Order Details** [0:21](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=21)

![generated-image-at-00:00:21](https://loom.com/i/16d33aebdce04d0d912be79f15442fff?workflows_screenshot=true)

* Add relevant labels to the purchase order.
* Enter all necessary details including:
  * Supplier information
  * Default terms
  * Billing and shipping locations
  * Specific supplier instructions.

### **Step 4: Add Purchase Order Line** [0:55](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=55)

![generated-image-at-00:00:55](https://loom.com/i/84266a65592744f8a0cb347b87c4e61c?workflows_screenshot=true)

* Click on 'Add Line' to include items in the order.
* Select the part you wish to order.

### **Step 5: Set Quantity and Cost** [1:08](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=68)

![generated-image-at-00:01:08](https://loom.com/i/5955c94345b447ca8b13f0509458580c?workflows_screenshot=true)

* Specify the quantity of the item.
* Enter the cost of the item.
* Optionally, click the info button to view historical costs for reference.

### **Step 6: Specify Need Date** [1:32](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=92)

![generated-image-at-00:01:32](https://loom.com/i/c0ac7801bf114bdf8c70b184f20b72fa?workflows_screenshot=true)

* Enter the expected need date for the order.

### **Step 7: Add Quality Clauses, Bulk Update Attributes, Add SNs** [1:45](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=105)

![generated-image-at-00:01:45](https://loom.com/i/36258df90b7142139ffa423ed1c672e9?workflows_screenshot=true)

* Include any quality clauses or additional attributes as necessary.

#### Bulk Updating

1. You can bulk update attributes across PO Lines by selecting the lines you need to change, and selecting change attributes.

   <figure><img src="/files/PZVBfZVFzqFhVugtjxBJ" alt=""><figcaption></figcaption></figure>
2. From there, select the attribute you want to bulk update, and update that attribute across all PO lines.

   <figure><img src="/files/QkpRu5NwNvESZMu7Ie6R" alt="" width="563"><figcaption></figcaption></figure>

#### Autogenerate or Manually Update SNs and Lot numbers

Select the inventory and hit Generate SNs as seen below. This will generate SNs for all selected inventory on the PO line.

<figure><img src="/files/8npgOg8W1k1BmNrstkXc" alt=""><figcaption></figcaption></figure>

In addition you will have the ability to manually update the SN or Lot number per inventory line.

### Step 8: Copy PO Lines

You will also have the ability to copy PO lines by simply selecting the PO line you want to duplicate and hitting copy in the bottom floating toolbar.

### **Step 8: Add Fees** [1:52](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=112)

![generated-image-at-00:01:52](https://loom.com/i/b781ad1d6f824a0994d54f0a5b9b4f69?workflows_screenshot=true)

* If applicable, add any fees such as sales tax (e.g., 8%).
* You have too options, fixed which is a fixed amount, or percentage which is a percentage of the PO line subtotal.

{% hint style="info" %}
You can change the PO Line subtotal by selecting Fee Exempt on PO lines to not include them in the subtotal.
{% endhint %}

### **Step 9: Review Summary and Attachments** [2:06](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=126)

![generated-image-at-00:02:06](https://loom.com/i/55ad38614ab54c04aadf7da02cd9a3c4?workflows_screenshot=true)

* Review the summary of the purchase order.
* Upload any necessary attachments or documents.

### **Step 10: Submit for Approval** [2:19](https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466?t=139)

![generated-image-at-00:02:19](https://loom.com/i/f086b95a5ac8424e96f3d8bbbfd2a909?workflows_screenshot=true)

* Submit the completed purchase order for approval.

#### Cautionary Notes

* Ensure all details are accurate before submission to avoid delays.
* Double-check the assigned procurement agent to ensure proper accountability.

#### Tips for Efficiency

* Use historical cost data to make informed decisions on pricing.
* Keep supplier instructions clear and concise to avoid misunderstandings.
* You can also duplicate a PO by selecting Duplicate in the overflow menu at the top of the Purchase.

#### Link to Loom

<https://loom.com/share/dbcefa0d4b0149dbb8a766bc7f27c466>


# Approve Purchases

This guide outlines the steps required to submit a purchase order for approval and the subsequent approval process.

### **Step 1: Submit Purchase Order for Approval** [0:00](https://loom.com/share/37cb13c6737b4caba27c59a018d33ae3?t=0)

![generated-image-at-00:00:00](https://loom.com/i/81295eed9aa94af8bfa1947b419575ac?workflows_screenshot=true)

* Ensure that the purchase order is complete with all necessary lines, fees, and taxes.
* Click on 'Approval Setup' to configure the approval process.
* Set the approval threshold (e.g., $2,000) and designate the engineering team as the approvers.

### **Step 2: Review Purchase Order** [0:27](https://loom.com/share/37cb13c6737b4caba27c59a018d33ae3?t=27)

![generated-image-at-00:00:27](https://loom.com/i/69d94fc2c0224fe2ad5d016781ff4db3?workflows_screenshot=true)

* As the reviewer, navigate to the review section of the purchase order system.
* Click on 'Reviews' to find the purchase order that needs approval.
* Check who is responsible for reviewing the order.

### **Step 3: Assign Review Responsibility** [0:45](https://loom.com/share/37cb13c6737b4caba27c59a018d33ae3?t=45)

![generated-image-at-00:00:45](https://loom.com/i/27cec3062413403394d398e66068e2da?workflows_screenshot=true)

* If necessary, assign the review task to yourself by selecting the appropriate option.
* Ensure you have the required roles and permissions to approve or reject the purchase order.

### **Step 4: Approve Purchase Order** [1:05](https://loom.com/share/37cb13c6737b4caba27c59a018d33ae3?t=65)

![generated-image-at-00:01:05](https://loom.com/i/023ceb3059714a2c99853151ce06adcd?workflows_screenshot=true)

* Click on the 'Approve' button to approve the purchase order.
* Confirm that the status of the purchase order changes to 'Approved'.

### **Step 5: Notify and Mark as Ordered** [1:23](https://loom.com/share/37cb13c6737b4caba27c59a018d33ae3?t=83)

![generated-image-at-00:01:23](https://loom.com/i/04791e37897e43a6a0fa2d99cacc65cb?workflows_screenshot=true)

* The original owner of the purchase order should send an email to notify relevant parties.
* Use the email client that opens to send the purchase order.
* Click the Order button to mark the Purchase as Ordered after emailing the relevant supplier.

#### Cautionary Notes

* Ensure all details in the purchase order are accurate before submission to avoid delays in approval.
* Double-check the approval threshold to ensure it aligns with company policy.

#### Tips for Efficiency

* Familiarize yourself with the purchase order system to navigate quickly.
* Keep a checklist of required information for purchase orders to streamline the submission process.

#### Link to Loom

<https://loom.com/share/37cb13c6737b4caba27c59a018d33ae3>


# Receiving

Receipts are used to track the event of bringing parts into the factory from outside suppliers. They allow population of key inventory fields such as serial number, lot, and location. Importantly, receipts can be tied to purchase orders to automatically mark purchase orders as received when all line items are delivered.


# Create Receipts

This guide outlines the steps to create a receipt against a purchase order in ION

### **Step 1: Start Creating a Receipt** [0:00](https://loom.com/share/a55ae933611f46ec886747d36ffb39c1?t=0)

![generated-image-at-00:00:00](https://loom.com/i/04da922a272a48359939ad99d30a9b6c?workflows_screenshot=true)

* Open the ION system.
* Navigate to the receipt creation section.
* Click on 'Create Receipt'.

### **Step 2: Select Purchase Order** [0:14](https://loom.com/share/a55ae933611f46ec886747d36ffb39c1?t=14)

![generated-image-at-00:00:14](https://loom.com/i/b5dd96b6c4b345bbad77c1afacf8ba49?workflows_screenshot=true)

* From the list of available purchase orders, select the one you wish to receive against.

### **Step 3: Choose Line Items** [0:28](https://loom.com/share/a55ae933611f46ec886747d36ffb39c1?t=28)

![generated-image-at-00:00:28](https://loom.com/i/d3d6f27343bd4d09942889d1914b0a82?workflows_screenshot=true)

* Review the line items associated with the selected purchase order.
* Decide if you need to split the quantity into bags (e.g., bags of 500).
* If splitting, enter the desired quantity for each bag.

### **Step 4: Add Additional Information** [0:37](https://loom.com/share/a55ae933611f46ec886747d36ffb39c1?t=37)

![generated-image-at-00:00:37](https://loom.com/i/12f3fccffeda4f0ca50463593c64a43a?workflows_screenshot=true)

* Fill in any other required information related to the receipt.

### **Step 5: Set Location and Quantity** [0:55](https://loom.com/share/a55ae933611f46ec886747d36ffb39c1?t=55)

![generated-image-at-00:00:55](https://loom.com/i/ed3035da6e3644b58e8b6a025caf34bb?workflows_screenshot=true)

* Specify the location where the items will be received.

{% hint style="warning" %}
Setting the receiving location will not immediately update the inventory locations. Instead, it will update the selected received inventory once the Create Receipt button is clicked. Once the Create Receipt button is selected, ION will set all of the selected inventory's location to the receiving location and then will create the receipt.
{% endhint %}

* Adjust the receiving quantity as necessary.

### **Step 6: Create the Receipt** [0:55](https://loom.com/share/a55ae933611f46ec886747d36ffb39c1?t=55)

![generated-image-at-00:00:55](https://loom.com/i/ed3035da6e3644b58e8b6a025caf34bb?workflows_screenshot=true)

* Once all information is entered, click on 'Create Receipt' to finalize the process.

#### Cautionary Notes

* Ensure that all quantities and locations are accurate before finalizing the receipt.
* Double-check the selected purchase order to avoid errors in processing.

#### Tips for Efficiency

* Familiarize yourself with the layout of the ION system to navigate quickly.
* Use keyboard shortcuts where available to speed up the process.
* Keep a checklist of common errors to avoid during receipt creation.

#### Link to Loom

<https://loom.com/share/a55ae933611f46ec886747d36ffb39c1>


# Kitting

Kitting in ION allows you to request inventory to be delivered to a particular location. You will select which parts and quantities you need, and ION automatically selects inventory to be picked and delivered based on FIFO methodology. The kit also allows you to manually select specific lot number or serial numbers to be delivered. Once the kit is delivered, the inventory is moved to the delivery location.

#### Use cases for kitting include:

1. Delivering material for a particular build run.
2. Delivering material to a lineside rack to be used for multiple builds.
3. Moving parts from the incoming receiving rack to a warehouse bin.
4. Reserving parts for a R\&D test or run.

## Kit Statuses and Workflows

Below are the various stages of a kit and how to make the most of them. Remember, you can move from any status to any status in ION

**Draft:** This is the default status of a newly created kit. As a manufacturing engineer or technician, you should use this status when filling out parts that you need at the lineside or at any other location. At this stage, set the *deliver to location* of the kit.

**Requested:** Once the creator of the kit has finished, determine what parts are needed and where, then set the status of the kit to requested. Inventory teams can filter for kits that are requested to understand which are ready to be actioned on. At this stage, you can assign the kit to the appropriate team member to fulfill.

**In Progress:** Once you are kitting the relevant inventory for a kit, mark the kit as in progress to show both other inventory personnel and the kit requestor that the kit is already being worked on. Kitted inventory will be marked with the [kitted](broken://pages/wA8aTiYqIH0THP2eL5ra) status.

{% hint style="info" %}
The kit will automatically move to In Progress if you kit any material when the kit is in a Requested status.
{% endhint %}

**Delivered:** After delivering the kit, mark the kit as delivered. This will set all of the inventory in the kit to the location of the [kit's *deliver to location* automatically.](broken://pages/k3i98KMvXLx8tBZDxvar)

{% hint style="info" %}
See [Broken mention](broken://pages/k3i98KMvXLx8tBZDxvar) for more details.
{% endhint %}

**Completed:** If you need to return a kit ot part of a kit back to your warehouse, mark the kit as completed. This will mark the inventory that has not been installed as available. This however will not change the location of the inventory that is being returned. You can use the current location of the kit to change location of the kitted inventory all at once.

**Canceled:** When a kit is no longer needed, mark it as canceled.

### New vs Legacy

Based on the ability to split kits, auto-selected inventory, show total inventory counts, and more, we are predicting a 3 - 5x improvement on kits with larger improvements coming from larger kits. See this video for a comparison between the two interfaces.

{% embed url="<https://www.loom.com/share/7853483fc7ff485c9ab381189b3c6742?sid=3aacae3c-b24e-4dd6-a8fc-c205e5fda891>" %}


# Request Parts

Create a Kit to Request Parts to be delivered to a Location

This guide outlines the steps for production teams, planners, technicians, and manufacturing engineers to request parts from inventory via a kit, ensuring efficient and accurate part delivery.

### **Step 1: Start the Kit Request**

![generated-image-at-00:00:00](https://loom.com/i/402d21a7437f4cbf925c5fb36f5d200a?workflows_screenshot=true)

* Begin by accessing the kit request system and hitting Request Parts in the top right.

### **Step 2: Fill Out Kit Details**

<figure><img src="/files/AuszRsVwjMRLoPd6EFuG" alt="" width="563"><figcaption></figcaption></figure>

* Assign the request to yourself if you need more time to fill out the details of the kit.
* Specify the delivery location (e.g., line site location).
* Include any additional information, such as Due Date / Priority.
* Attachments can be uploaded in the attachments section below.
* The submit request button in the top right is not enabled until the delivery location is populated and all request parts have enough available and kitted inventory to fulfill them. This status can be manually overridden by clicking the status button.
  * If you do not have enough inventory, see [#step-5-split-kit-if-needed-4-06](#step-5-split-kit-if-needed-4-06 "mention") for our suggestion.

### **Step 3: Request Parts**

<div data-full-width="false"><figure><img src="/files/kQPDvfGtULMn89ySGMRj" alt="" width="563"><figcaption></figcaption></figure></div>

* Scroll down to the 'Parts' section.
* Choose to request a single part at a time or add multiple parts quickly by hitting the dropdown arrow and selection "Add Multiple Parts to Kit"

![generated-image-at-00:02:24](https://loom.com/i/a664878f4cc4439cb700696216ebce8f?workflows_screenshot=true)

* When selecting "Add Multiple Parts to Kit", select an assembly and mBOM to see all of the mBOM parts and their respective part-level attributes.
* Review the original mBOM quantity, select/filter for which parts you want to add, and request additional spares as needed.
* If necessary, only select the parts that will be added to the kit.

### **Step 4: Review Inventory Information**

* Check the total available quantity in the warehouse you specify. By updating the warehouse location field, ION will only show available inventory in that warehouse parent location. Later, this will also influence the FIFO recommendations.
  * Based on the delivery location, ION will suggest which warehouse location the inventory team will pick from. You can choose to accept this recommendation or select another one.

{% hint style="warning" %}
We strongly encourage you to set up one warehouse location per building or top-level location. This will allow ION to accurately suggest which warehouse will be used for picking, given that the delivery location is in that building or top-level location. See below for the suggested Warehouse given Doug's Desk is a workcenter within the First Resonance HQ and that Andres Warehouse is the only warehouse in the HQ.
{% endhint %}

<figure><img src="/files/PNqi31kx6harfNXPF8u2" alt="" width="563"><figcaption></figcaption></figure>

* Verify the quantity already delivered to the line site.
* Note the quantity on order and the earliest ETA for that inventory.
* The available inventory quantity takes into account inventory availability for:
  * Other revisions, if part interchangeability is enabled
  * mBOM substitutes if this came from an mBOM
* After you have kitted any inventory, the remaining requested quantity will be fulfilled by auto-selected inventory. The autoselected inventory logic is below.
* The auto-selected FIFO inventory will be chosen based on the received or creation date of the inventory. FIFO treats the following inventory equally in its calculation:
  * Other revisions, if part interchangeability is enabled
  * mBOM substitutes if this came from an mBOM

### **Step 5: Split Kit if Needed**

* If no inventory is available or is still being delivered, we strongly recommend holding the kit request until inventory arrives or splitting the kit as needed to get a partial delivery. This provides clarity for the material handlers as they no longer need to guess or understand which parts they need to pick.
* In this workflow, the requester is in charge of ensuring there is enough available inventory to fulfill the kit to provide the clarity needed for the material handlers.

{% hint style="warning" %}
In the future, we will add metrics for the average completion time of a Kit; it is paramount that partial kits get split off and held in the Draft status for that metric not to be diluted by kits where only a subset of the parts got delivered.
{% endhint %}

<figure><img src="/files/YUGkuYjw9ZC5KJuC5vAl" alt="" width="563"><figcaption></figcaption></figure>

* If creating a partial kit, split off parts that are not ready for delivery. You can only split off parts that have no inventory already kitted to them, as we believe this decision should be made before kitting the parts. This will split the entire line(s) into the new kit, and all of the details of the original kit will be copied.

### **Step 6: Pre-Allocate Parts (if necessary)**

<figure><img src="/files/JoDmkKsAIYUHUrG637Z7" alt="" width="563"><figcaption></figcaption></figure>

* Override automatic selections or add kitted inventory by clicking "Select Inventory".
* The 'Select Inventory' modal will show all inventory that will be kitted as green at the top of the list. This is inclusive of newly selected inventory and previously kitted inventory. This can be used to remove existing kitted inventory by deselecting the inventory.

### **Step 7: Submit the Kit Request**

* Submit the completed kit request in the top right of the page.
* Optionally, assign the request to a material handler for processing.

#### Copt Kit

Copying a kit will copy all of the requested information, the parts, and their requested quantities to a new kit. We recommend using this when needing to be more granular for how much inventory to get delivered for each line.

#### Cautionary Notes

* Ensure that all required fields are filled out accurately to avoid delays in processing.
* Do not submit a kit request if there is no available inventory unless you are creating a partial kit.

#### Tips for Efficiency

* Regularly check inventory levels to anticipate part shortages.
* Familiarize yourself with the mBOM system to streamline part selection.
* Communicate with the inventory team to clarify any uncertainties regarding part availability.

#### Link to Loom

{% embed url="<https://loom.com/share/8e20460a544a4e389bb0fd9c38894a88>" %}

#### Current Known Issues

* We are actively solving for Part Interchangeability within the Kitting workflow.
* Lead time needs to be updated to reflect days, hours, instead of seconds.
* Custom attributes on the multiple add parts to kit button is not loading in.
* The warehouse location button is not correctly setting the available inventory


# Fulfill Kits

As a material handler, here is the guide to fulfilling a kit

As a material handler, the way you interact with a kit is different than those who need to request parts from the kit. As a result, the kitting interface changes dynamically based on the stage of the kit to make it more efficient for you to understand what to do next. You can always flip between the Request Parts and Fulfill Parts tab as needed, however.

### **Step 1: Access the Assigned Kit**

<figure><img src="/files/AFFMhnrFdmAwzH10tWmn" alt="" width="563"><figcaption></figcaption></figure>

* If you are a material handler, locate the kit assigned to you.
* Click on the kit to begin the fulfillment process.

### **Step 2: Verify the Auto Generated Pick List**

<figure><img src="/files/a1nOgWvvPr1MNwQJGF28" alt=""><figcaption></figcaption></figure>

* A pick list will be automatically generated for you. This is in the fulfill parts tab.
* This pick list includes:
  * Items that are already kitted by the requester.
  * Items are selected based on a first-in, first-out (FIFO) methodology that fulfills the remaining unfulfilled quantity of each requested part if available inventory exists ***based on the warehouse location selected.***
    * The warehouse location automatically filters out the auto selected inventory to inventory that is available in the warehouse location to avoid the kit list from suggesting that you pick materials from other lineside locations or other facilities.
  * The quantity of the inventory that will be split from the original quantity if it will be split off during kitting (only applicable for FIFO selected parts).
  * The inventory (both already kitted and auto-selected) are sorted alphabetically by location for efficient picking.
  * Kitted items not in the selected warehouse location will show at the bottom of the list with a warning.
  * A 'Not at Location' badge for only kitted items that are not in the selected warehouse.
* If you need to, you can replace parts that have been auto-selected or kitted by selecting Replace

<figure><img src="/files/PIpiCq6ZLTie3OIMYa7x" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
To avoid kitted parts that are not in the warehouse location from dropping off the automated kit list, we keep them in the list but label them as 'Not at Location'. See the image below for more details.
{% endhint %}

<figure><img src="/files/QrTUXMbjmjSVfSY2eCDG" alt=""><figcaption></figcaption></figure>

### **Step 3: Navigate the Factory**

* Use the pick list to navigate through the factory.

{% hint style="info" %}
We highly recommend organizing your locations in an alphabetical manner that allows you to neatly wind through your warehouse to get the goods you need!
{% endhint %}

### **Step 4: Begin Picking Items**

* Start picking the inventory listed on your pick list by clicking the ***Kit*** button on each inventory that is not already kitted (i.e. FIFO). The kit button will only appear for auto-selected materials and once clicked will simply kit the inventory.
* As you start kitting once the kit status is ***Requested***, the kit status will automatically change to 'in progress'.
* You can also replace items on the pick list with another inventory item. For already kitted items, this will remove it and replace it with the new selected inventory. For an auto-selected inventory item, this will kit the selected inventory and decrement the auto-selected inventory for that part in the pick list by the newly kitted inventory

### **Step 5: Complete the Picking Process**

* Continue picking until all items on the list have been collected.
* Once everything is picked, the option to complete or deliver in the top right the kit will appear enabled.

<figure><img src="/files/2xOdCQVS9JEJbXAv8dGz" alt="" width="563"><figcaption></figcaption></figure>

* If there is a run associated with the kit, the top right button will show as 'delivered'.
* If there is no run, the top right button will show as 'complete'.
* Note the difference in inventory status:
  * Delivered: Inventory remains marked as kitted.
  * Completed: Inventory is marked as available.
  * ***In both scenarios, the inventory in the kit is moved to the delivery location.***

### Shortage Table

At the bottom of the pick list, you may occasionally see a shortage table, which will show any parts that do not have the requested part quantity fulfilled by kitted and auto-selected parts.

### Staging Inventory

Occasionally, you will need to stage all of the inventory kitted and the kit itself at a particular location. To do that, you will need to click the stage inventory button in the kit actions menu, as shown below, and select a location. Once this is set, the kitted inventory will automatically move to that location, and the current location of the kit will show in the requested information section.

<figure><img src="/files/KtAJjwuLW0CnT2KYZtFA" alt=""><figcaption></figcaption></figure>

#### Link to Loom

{% embed url="<https://loom.com/share/99682a70cff04385b1051e6205f19df2>" %}

#### Known Issues

* Scanning is currently not available, but is planned to be included.
* Clicking Kit on Autoselect inventory is kitting them, but it does not visually represent that change.
* Locations are currently sorted by ID and not by name.


# Inventory

In ION, an **inventory item** is a persistent digital twin representing a specific quantity of a part—typically a single serial-numbered unit or a lot-tracked batch.

* **Creation and Persistence:**\
  The inventory item record is created at the earliest opportunity (e.g., the moment a purchase line is entered) and persists throughout the lifecycle of the corresponding physical piece.
* **Rich Metadata:**\
  Each item carries detailed metadata, including:
  * Location
  * Supplier information
  * Cost
  * Lot or serial numbers
  * Quantity
  * Organizational defined attributes
* **Lifecycle Statuses:**\
  Rather than being deleted when consumed, each inventory item transitions through clearly defined statuses:

  * On Order
  * Available
  * Work In Progress (WIP)
  * Kitted
  * Installed
  * Scrapped
  * Unavailable

  This ensures that you can always determine the current location and state of an item, answering questions such as "Where is serial XYZ right now?" and facilitating accurate audits of each hand-off.

  The **Unavailable** status is also used by the issue disposition workflow. When inventory is associated with an issue, a disposition type configured as **Release on Resolve** or **Permanently Unavailable** can move that inventory to **Unavailable** while the issue is being processed or as part of the final disposition. For more detail, see [Disposition Types](/quality/disposition-types).
* **Traceability and Searchability:**\
  Multiple inventory items can exist simultaneously for the same part number across various locations or tracking schemes, providing granular traceability without sacrificing ease of search across the factory.


# Create A Table View

## Table View Customization

<https://loom.com/share/724759bd385f4506b41d23b863fe8c92>

#### Objective

This SOP outlines the steps to customize the inventory screen for optimal information retrieval based on specific roles within the factory setting.

#### Key Steps

**1. Accessing the Inventory Screen** [0:00](https://loom.com/share/724759bd385f4506b41d23b863fe8c92?t=0)

<figure><img src="/files/4AESctxOtlgtTnM0zleL" alt=""><figcaption></figcaption></figure>

* Navigate to the inventory screen in the system.
* Familiarize yourself with the layout and available features.

**2. Generalized Search Functionality** [0:19](https://loom.com/share/724759bd385f4506b41d23b863fe8c92?t=19)

<figure><img src="/files/95G4Q7ruag8cwPH4sXzc" alt=""><figcaption></figcaption></figure>

* Use the main search bar to search for:
  * Part numbers
  * Descriptions
  * Lots
  * Serial numbers
* Example: If you don't know the part number, search using the description.

**3. Utilizing Specific Filters** [1:04](https://loom.com/share/724759bd385f4506b41d23b863fe8c92?t=64)

<figure><img src="/files/mFJFLFm7xOc6meFFPTfU" alt=""><figcaption></figcaption></figure>

* To refine your search results, apply specific filters:
  * Example: Filter by 'lot' to see all items containing 'lot' in the lot number.

**4. Customizing Your View** [1:59](https://loom.com/share/724759bd385f4506b41d23b863fe8c92?t=119)

<figure><img src="/files/cpEIqofEnnO2ERQBzFei" alt=""><figcaption></figcaption></figure>

* Adjust the displayed information based on your role:
  * Prioritize important fields (e.g., lot and issues).
  * Remove unnecessary fields (e.g., kidding or installed quantities).

**5. Saving Your Customized View** [3:03](https://loom.com/share/724759bd385f4506b41d23b863fe8c92?t=183)

<figure><img src="/files/Ou6gWMMhTGilM8mTlaN5" alt=""><figcaption></figcaption></figure>

* After customizing your view, save it:
  * Name your view (e.g., 'Lot Focused Inventory').
  * Provide a brief description.

**6. Accessing and Sharing Views** [3:32](https://loom.com/share/724759bd385f4506b41d23b863fe8c92?t=212)

<figure><img src="/files/zGQXACfu27o6SWzpV1OR" alt=""><figcaption></figcaption></figure>

* Toggle between saved views as needed.
* To share your view:
  * Copy the JSON configuration to your clipboard.
  * Share it with colleagues for them to import.

**7. Reapplying Filters** [4:30](https://loom.com/share/724759bd385f4506b41d23b863fe8c92?t=270)

<figure><img src="/files/0q0enFAlsoGEYghC0Axu" alt=""><figcaption></figcaption></figure>

* Return to the inventory screen and click on your saved filters to apply them as needed.

#### Tips for Efficiency

* Regularly review and update your saved views to reflect any changes in your responsibilities. These are stored locally so they will be cleared with your cache.


# Create Inventory

## Manually Creating New Inventory in ION

#### Objective

This process outlines the steps to create inventory from the inventory page in the ION system, ensuring accurate tracking and management of parts.

#### Key Steps

**1. Access the Inventory Page** [0:00](https://loom.com/share/19c117548481430b832813f441d126fd?t=0)

![generated-image-at-00:00:00](https://loom.com/i/feec38cd84aa4a319c95a8204378b7bc?workflows_screenshot=true)

* Navigate to the inventory page in the ION system.
* Locate the top right button for creating new inventory.

**2. Identify Create and Submit Actions** [0:14](https://loom.com/share/19c117548481430b832813f441d126fd?t=14)

![generated-image-at-00:00:14](https://loom.com/i/e26c81e5d3344dd2a7f415167adf885a?workflows_screenshot=true)

* Understand that create actions are typically found in the top right corner of the page.
* Submit actions are usually located in the bottom right corner.

**3. Search for the Specific Part** [0:24](https://loom.com/share/19c117548481430b832813f441d126fd?t=24)

![generated-image-at-00:00:24](https://loom.com/i/03efee574c224137a308758504a024d7?workflows_screenshot=true)

* Use the search function to find the specific part you want to create inventory for.
* Example: Search for 'NAS 1306 bolts'.

**4. Specify Quantity and Location** [0:35](https://loom.com/share/19c117548481430b832813f441d126fd?t=35)

![generated-image-at-00:00:35](https://loom.com/i/e3c5dd9c32084ec28b0713c519c7ce76?workflows_screenshot=true)

* Enter the quantity of parts you wish to create (e.g., 500).
* Specify the receiving location (e.g., your desk for inspection).

**5. Provide Additional Details** [0:48](https://loom.com/share/19c117548481430b832813f441d126fd?t=48)

![generated-image-at-00:00:48](https://loom.com/i/05554608ecd5495cba1be786d3ee1d93?workflows_screenshot=true)

* Indicate if this is a first article from a customer or a new supplier.
* Enter the lot number as required.

**6. Create the Inventory Item** [1:00](https://loom.com/share/19c117548481430b832813f441d126fd?t=60)

![generated-image-at-00:01:00](https://loom.com/i/7dfa99cdbfa740378914bac05edd3d55?workflows_screenshot=true)

* Click the button to create the inventory item.
* Confirm that the inventory has been successfully created.

**7. Verify New Inventory** [1:00](https://loom.com/share/19c117548481430b832813f441d126fd?t=60)

<figure><img src="/files/lkGTLCVouIGbiD3mltB5" alt=""><figcaption></figcaption></figure>

* Remove any filters on the inventory page.
* Search for the newly created inventory to ensure it appears correctly.

#### Cautionary Notes

* Ensure all required fields are filled out accurately to avoid errors in inventory tracking.
* Double-check the part number and lot number before finalizing the creation.

#### Tips for Efficiency

* Familiarize yourself with the layout of the ION system to navigate quickly.
* Use keyboard shortcuts where possible to speed up the process.
* Regularly update your inventory to maintain accurate records.

#### Link to Loom

<https://loom.com/share/19c117548481430b832813f441d126fd>


# Inventory Actions

A guide on splitting, moving, scrapping, and adjusting an inventory line.

### **Access Inventory Item Details**

The **Actions button** (the three vertical dots in the “Actions” column of each inventory row) provides quick access to essential inventory operations and detailed information for every inventory item.

#### How to Use

1. **Locate** the desired inventory row in the Inventory table.
2. **Click** the three dots (…) under the Actions column.
3. **Select** the action you wish to perform (Split, Move, Adjust, Print).
4. **Follow** the prompts or complete the necessary fields to execute the action.

<figure><img src="/files/DH8gWn13m7EGK3DsFKQt" alt=""><figcaption><p>The <strong>Actions button</strong> (the three vertical dots in the “Actions” column of each inventory row)</p></figcaption></figure>

### What You Can See

Clicking the Actions button opens a panel displaying key details for the selected inventory item, including:

* **Part Number**
* **Revision**
* **Inventory ID**
* **Inventory Status** (e.g., Available, On Order, Kitted)
* **Quantity**
* **Current Location**
* **PO Number** (if item was purchased)
* **Run Number** (if item was internally built)

This information gives you a snapshot of the inventory item’s current state and traceability.

### What You Can Do

Within this panel, you have access to several critical inventory management actions:<br>

1. **Split Inventory**
   1. Divide an inventory lot into smaller quantities.
   2. Assign split quantities to different locations as needed.
   3. Useful for distributing stock across work centers or kitting jobs.<br>
2. **Move Inventory**
   1. Change the storage location of an inventory item.
   2. Supports physical moves between bins, stockrooms, or work centers.<br>
3. **Adjust Inventory**
   1. Update the recorded quantity to match physical stock.
   2. Use for correcting count errors, scrap events, or reconciliation activities.
   3. **When adjusting inventory, the workflow will allow you to capture the rationale or reason for the adjustment as a comment tied to the inventory item.** *This can include notes such as “cycle count discrepancy,” “scrap,” or “found extra stock,” providing a clear audit trail and supporting compliance requirements.*<br>
4. **Print Label**
   1. Generate and print a barcode label for the inventory item.
   2. Useful for tagging items during receiving, kitting, or transfer processes.

## A Guided Walkthrough: Splitting Inventory

This procedure explains how to split inventory items in the inventory table. Common use cases include cycle counts and partial inventory moves—for example, when R\&D quickly pulls 20 washers from a lot of 300 for an untracked prototype build.

### **Step 1: Access Inventory Item**

![generated-image-at-00:00:18](https://loom.com/i/8fb57ad4620a4e7ea5406f44d0bf38c9?workflows_screenshot=true)

* Navigate to the inventory table page.
* Click on a specific inventory item that has a quantity greater than 1.

### **Step 2: Select Split Action** [0:29](https://loom.com/share/9f6c4cf548b44937933f433a7735fd56?t=29)

![generated-image-at-00:00:29](https://loom.com/i/0eeaa7dc383449769e667fa265539f5e?workflows_screenshot=true)

* Locate the actions menu on the left side of the screen.
* Click on the 'Split' action.

### **Step 3: Choose Split Type** [0:37](https://loom.com/share/9f6c4cf548b44937933f433a7735fd56?t=37)

![generated-image-at-00:00:37](https://loom.com/i/5bfe3bcaa5a94ef5a2af070a919536e9?workflows_screenshot=true)

* Decide whether to make an even split or a custom split.
* For an even split, select the number of lines you want to split into.
* For a custom split, enter the specific quantity you wish to split.

### **Step 4: Check Inventory Allocation** [0:57](https://loom.com/share/9f6c4cf548b44937933f433a7735fd56?t=57)

![generated-image-at-00:00:57](https://loom.com/i/4f69b539d3ea405e80f6976aeb43d5bf?workflows_screenshot=true)

* Ensure that the total quantity you want to split does not exceed the available inventory.
* If there is a shortfall, fulfill the required quantity before proceeding.

### **Step 5: Update Locations (if necessary)** [1:19](https://loom.com/share/9f6c4cf548b44937933f433a7735fd56?t=79)

![generated-image-at-00:01:19](https://loom.com/i/e366ab0d614d474790b52e6b5edd95f4?workflows_screenshot=true)

* If you need to change the locations of the split inventory, adjust the location settings accordingly.

### **Step 6: Execute Split** [1:36](https://loom.com/share/9f6c4cf548b44937933f433a7735fd56?t=96)

![generated-image-at-00:01:36](https://loom.com/i/8543c2dbf30c4c138025b19d38a403df?workflows_screenshot=true)

* Click on the 'Split Inventory' button to execute the split.

### **Step 7: Confirm Split Success** [1:50](https://loom.com/share/9f6c4cf548b44937933f433a7735fd56?t=110)

![generated-image-at-00:01:50](https://loom.com/i/6eb4c965dd274cfaa6d67d3a6b5a4fc0?workflows_screenshot=true)

* Look for a successful split notification.
* Verify the updated inventory quantities to ensure they reflect the split.

#### Cautionary Notes

* Ensure that the total quantity being split does not exceed the available inventory to avoid errors.
* Double-check location changes to prevent misallocation of inventory.

#### Link to Loom

<https://loom.com/share/9f6c4cf548b44937933f433a7735fd56>


# ION Actions

ION Actions turn your physical controls into digital guardrails.

ION Actions allows you to define, manage, and automate business rules that govern your manufacturing processes directly within ION, leveraging the power and flexibility of GraphQL. Actions enable users to create, edit, update, or delete rules that determine workflow behaviors, enforce data validation, and manage conditions for status transitions.

### Key Action Fields

Each Action consists of key attributes that define its behavior and purpose:

* **Title:** Clearly identifies the Action's intent, appearing in toast notifications and serving as an internal reference for logging and tracking purposes.
* **Context:** Contains all necessary data used within the Action's script. This may include details such as model attributes, user roles, and specific issue details, structured as a JSON string for easy integration within GraphQL.
* **Code:** A Python-based script executed whenever the Action is triggered. This script defines the logic, conditions, and behaviors enforced by the Action. If conditions specified in the code are not met, a ValidationError is triggered.
* **Target:** Specifies the object or entity you wish to control and monitor for changes. The target is selected from a dropdown list during the initial creation of an Action.
* **Event:** Determines when the Action's Python code is evaluated. You can choose from UPDATE, CREATE, or DELETE events based on when you want the Action to execute in response to changes in the target.

Use cases for Actions include:

* Controlling when and how statuses within workflows can be updated or progressed.
* Ensuring critical fields are filled out before proceeding in a process.
* Validate that certain conditions are met before building critical hardware.
  * Example: making sure parts are flight worthy before installation.

### Actions Statuses

Below is guidance on creating and managing Actions effectively:

* **Enabled:** Actions in this status are live and actively enforced throughout your organization's production workflows. Newly created actions set to enabled will immediately influence workflow behaviors based on their conditions.
* **Disabled:** Actions in this status are not evaluated or enforced. Disabling Actions allows safe testing and refinement without disrupting live workflows, providing flexibility to toggle Actions between enabled and disabled states as needed.

Remember, you must enable rules within your organizational settings before using Actions to automate and enforce your processes. To do so you can follow the following instructions:

### Turn rules on in your environment: <a href="#id-2.-turn-rules-on-in-your-environment" id="id-2.-turn-rules-on-in-your-environment"></a>

First, rules must be enabled in your organization settings in order to use them.

Check that the rules are enabled with the below query:

```
{
  me {
    organization {
      id
      _etag
      settings {
        rules {
          enabled
        }
      }
    }
  }
}
```

If they are not, enable them with this mutation:

<pre><code><strong>mutation UpdateOrganization($input: UpdateOrganizationInput!) {
</strong>  updateOrganization(input: $input) {
    organization {
      settings {
        rules {
          enabled
          errorState
          errorStateMessage
        }
      }
    }
  }
}
</code></pre>

With the following input variables (retrieve the `etag` from the first query):

```
{
  "input": {
    "id": <populate from first query>,
    "etag": "<populate from first query>",
    "settings": {
      "rules": {
        "enabled": true
      }
    }
  }
}
```


# Aug. 2025 ION Actions Transition

Determine what must change to effectively leverage the improved ION Actions executions rolling out in August 2025.

{% hint style="info" %}
Improved ION Actions are now live in your sandbox environment for validation. The First Resonance team will reach out to customers that have Actions that must be transitioned. Otherwise, check out the new [capabilities](/supply-chain/inventory/inventory-actions)! ([GOV](https://app-v2.staging.gov.buildwithion.com/actions)) ([PUB](https://app-v2.staging.buildwithion.com/actions))
{% endhint %}

### ION Actions Update: Summer 2025

In the summer of 2025, both the frontend and backend of ION Actions received updates to enhance user visibility and control over digital guardrails. These improvements have also optimized ION Actions' performance and expanded use cases, including more granular inventory control.

Due to these upgrades, some existing ION Actions will require modifications. This documentation provides guidelines on identifying and updating those actions, allowing you to test and validate changes in your Sandbox environments before the scheduled deployment to all production environments at the end of August 2025.

### Required Changes

The primary change involves modifying the context queries, particularly transitioning from using `edges` queries to simpler direct-object queries.

Below is guidance on updating your existing rules to conform to the new schema:

#### Old Schema Example

Here is an example of a common action defined using the old schema:

```javascript
{
    title: "Issue Must Have an Assignee Before Being Submitted for Review.",
    ruleType: "VALIDATION",
    eventType: "CREATE",
    target: "ISSUEAPPROVALREQUEST",
    code: "if (context.get('issueApprovalRequests', {}).get('issue', {}).get('status') in ['PENDING','IN_PROGRESS'] and context.get('issueApprovalRequests', {}).get('issue', {}).get('assignedTo') is None): raise ValidationError()",
    context: "{issueApprovalRequests(filters: {id: {eq: $id}}) {edges {node {id issue {status assignedTo {id}}}}}}",
}
```

#### New Schema Example

Below is the equivalent action reformatted according to the new schema:

```javascript
{
    title: "Issue Must Have an Assignee Before Being Submitted for Review.",
    ruleType: "VALIDATION",
    eventType: "CREATE",
    target: "ISSUEAPPROVALREQUEST",
    code: "issue_approval_request = context.get('issueApprovalRequest') or {}\nissue = issue_approval_request.get('issue') or {}\nstatus = issue.get('status')\nassigned_to = issue.get('assignedTo')\n\nif status in ['PENDING', 'IN_PROGRESS'] and assigned_to is None:\n    raise ValidationError()\n",
    context: "{\n  issueApprovalRequest(id: $id) {\n    id\n    issue {\n      status\n      assignedTo {\n        id\n      }\n    }\n  }\n}"
}
```

#### Key Changes to Note

* **Context Query:**
  * Replace `edges` queries with direct-object queries. Instead of wrapping your queries inside `{ edges { node { }}}`, directly reference the target object.
  * This simplifies accessing data within the rule logic, enhancing clarity and reducing complexity.
* **Code Adjustments:**
  * Adjust the code logic to directly access the simplified context object structure as demonstrated in the new schema example.

### Recommended Workflow

To efficiently iterate on ION Actions, we recommend using the New ION Experience, which provides a dedicated management page for Actions. Refer to the documentation on [Managing Actions](/os/ion-actions/managing-actions) for instructions on how to find, edit, and manage Actions using this new interface. If you do not know how to access the new ION experience, talk to your CSM today! Please test any rules you need to transition in your sandbox environment today. We will reach out individually to customers who require coordination for the production rollout.


# Managing Actions

## Creating and Managing ION Actions

<https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c>

#### Objective

This SOP outlines the steps to create, manage, and understand ION Actions within the ION platform, ensuring that users can effectively implement business logic in their organization.

#### Key Steps

**1. Overview of ION Actions** [0:00](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=0)

<figure><img src="/files/Hg8C29PMtUGBMZCA36uG" alt=""><figcaption></figcaption></figure>

* Ion Actions are programmatic rules and validations that align digital processes with physical outcomes.
* Users can manage these actions through a new interface.

**2. Viewing and Managing Actions** [0:37](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=37)

<figure><img src="/files/BilB2yR0UwZIJn2H0Urr" alt=""><figcaption></figcaption></figure>

* Access the list of all deployed ION Actions in your environment.
* Actions can be enabled or disabled as needed, especially in sandbox environments before production deployment.

**3. Enabling and Disabling Actions** [1:03](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=63)

<figure><img src="/files/zV1pJrLbZD6rXX6tRIdm" alt=""><figcaption></figcaption></figure>

* Use multi-select checkboxes next to action IDs to toggle actions on or off.
* To select all actions, click the header of the action table.

**4. Searching for Specific Actions** [1:37](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=97)

<figure><img src="/files/25FIMWGPcC38phN3LKDF" alt=""><figcaption></figcaption></figure>

* Use the search function to find actions related to specific keywords (e.g., 'QL' for quality levels).
* Understand the target and trigger of each action.

**5. Accessing Action Details** [2:29](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=149)

<figure><img src="/files/wXxpGsxtOj7dUUkGvUsd" alt=""><figcaption></figcaption></figure>

* Click on an action to view details such as creator, last update, and specific action settings.
* Edit action details, including target and title, which affects error messages.

**6. Sharing Actions Across Environments** [3:48](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=228)

<figure><img src="/files/N0jCmiDU2ie9J18C8WKg" alt=""><figcaption></figcaption></figure>

* Use the share functionality to copy the mutation for an action.
* Paste the mutation into the GraphQL editor of another environment to replicate the action.

**7. Understanding Context for Actions** [4:21](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=261)

<figure><img src="/files/heS2vYOdW4YToCI7oGBH" alt=""><figcaption></figcaption></figure>

* Context is crucial for actions as it determines what data the rule can access.
* Test context queries against different run IDs to ensure proper validation.

**8. Editing Action Logic** [5:07](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=307)

<figure><img src="/files/zQoQOwFvT7wfDes2fnax" alt=""><figcaption></figcaption></figure>

* Modify the code that defines the validation logic for the action.
* Use the context query to reference attributes needed for comparisons.

{% hint style="info" %}
For advanced use cases you can also leverage the changes dictionary that is provided each time an ION Action is ran. While you do not have visibility into the exact changes dictionary, [this documentation](/os/ion-actions/managing-actions/changes-dictionary) will help you understand the formatting of that dictionary you have to work with.
{% endhint %}

{% content-ref url="/pages/MTdfJOzedssQtrvnjcI4" %}
[Changes Dictionary](/os/ion-actions/managing-actions/changes-dictionary)
{% endcontent-ref %}

**9. Saving Changes** [6:20](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=380)

<figure><img src="/files/l5VHjkX7yMVUnBOo0HsI" alt=""><figcaption></figcaption></figure>

* Click the save button to apply any changes made to the ION Action.
* Be cautious with changes to avoid unintended updates.

**10. Monitoring ION Actions** [6:57](https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c?t=417)

<figure><img src="/files/d79NSheHw8r0noo9cywf" alt=""><figcaption></figcaption></figure>

* Regularly check which ION Actions are enabled and their intended outcomes.
* Stay updated on new features and improvements in the ION Actions interface.

#### Cautionary Notes

* Always test changes in a sandbox environment before deploying to production.
* Be careful when editing action logic to avoid introducing errors that could block processes.

#### Tips for Efficiency

* Utilize the search function to quickly locate specific actions.
* Regularly review and document changes made to actions for future reference.
* Familiarize yourself with GraphQL to streamline the sharing and editing process.

#### Link to Loom

<https://loom.com/share/a041c87ef6e0499f81a02b18a31e912c>


# Changes Dictionary

Examples of what the changes dictionary looks like for a few ION Action targets.

In general, the best practice is to use as much information as possible from the **context** you define, which always represents the **“after” state**, when writing your rules.

For example, including status in your context ensures you cannot transition **into** that status without meeting the required conditions. An ION Action written on target ISSUE event UPDATE will show status as IN PROGRESS if status is included in the context and you just move the issue from PENDING to IN PROGRESS.

However, there are times when it is beneficial to look at what exactly has changed. The **changes dictionary** allows you to track both **before** and **after** states. This is useful for controlling transitions, validating updates, or detecting changes to specific attributes.

### Access the Changes

To access the changes dictionary you can use statement like the following in your code.

{% hint style="info" %}
Please use Python coding best practices when writing ION actions. This is simply meant as a helpful guide. Example: `(context.get('changes', {}).get('procedures', {}).get('status', {}).get('new') == 'in_review’)`
{% endhint %}

You will notice that fields within the changes dictionary are all `snake_cased` in the examples that follow.

***

### Issues – Update

The changes dictionary for Issues updates captures modifications to steps, attributes, statuses, approvals, and root cause conditions.

*Note: This is only an example of what the changes dictionary can contain. It is not a complete list of all possible changes.*

```json
'changes': {
  'issues': {
    'must_close_by_run_step_id': {'new': 2116, 'old': None},
    'status': {'new': 'in_progress', 'old': 'pending'},
    'cause_condition': {
      'new': [
        {'id': '71e5a1db-f3d3-4815-9965-3e5af6dba303', 'type': 'p', 'children': [{'text': 'fix me. Content in the main issue section updated'}]},
        {'id': '4a84a6af-d02b-44ac-a59c-26c083cd00e5', 'type': 'p', 'children': [{'text': ''}]}
      ],
      'old': [
        {'id': '71e5a1db-f3d3-4815-9965-3e5af6dba303', 'type': 'p', 'children': [{'text': 'fix me'}]},
        {'id': '4a84a6af-d02b-44ac-a59c-26c083cd00e5', 'type': 'p', 'children': [{'text': ''}]}
      ]
    }
  },
  'issuesAttributes': {
    'MAX_INVENTORY': {'new': 10, 'old': None},
    'Issue Origin': {'new': 'Engineering', 'old': None}
  },
  'issueApprovals': {},
  'issueApprovalRequests': {
    'status': {'new': 'approved', 'old': 'pending'}
  },
  'entities': {}
}

```

***

### PartKitInventory – Create

When installing inventory onto a kit, the changes dictionary captures both inventory status and kitting quantity.

*Note: This is only an example of what the changes dictionary can contain. It is not a complete list of all possible changes.*

```json
'changes': {
  'partsInventory': {
    'status': {'new': 'kitted', 'old': 'available'},
    'quantity_kitted': {'new': 1, 'old': 0}
  },
  'partKitInventories': {}
}

```

***

### PartKit – Update

PartKit updates track team assignments, delivery location changes, and kit-level attributes.

*Note: This is only an example of what the changes dictionary can contain. It is not a complete list of all possible changes.*

```json
'changes': {
  'userSubscriptions': {},
  'partsKits': {
    'assigned_team_id': {'new': 2, 'old': None},
    'delivery_location_id': {'new': 19, 'old': None}
  },
  'partKitAttributes': {
    'Date Kitted': {'new': '2025-09-08T07:00:00', 'old': None}
  }
}

```

***

### Inventory – Update

Inventory updates capture cost changes, lot tracking, status/location transitions, and attribute updates.

*Note: This is only an example of what the changes dictionary can contain. It is not a complete list of all possible changes.*

```json
'changes': {
  'partsInventory': {
    '_cost': {'new': 20, 'old': None},
    'status': {'new': 'unavailable', 'old': 'available'},
    'lot_number': {'new': 'Lot Test 123', 'old': None},
    'location_id': {'new': 19, 'old': 67},
    'origin_mbom_id': {'new': 412, 'old': None},
    'is_location_available': {'new': False, 'old': True}
  },
  'partsInventoriesAttributes': {
    'Pedigree': {'new': 'Tier 2', 'old': None},
    'mass': {'new': 200, 'old': None}
  }
}

```

***

### Procedure – Update

Procedure updates track both status changes and procedural attributes.

*Note: This is only an example of what the changes dictionary can contain. It is not a complete list of all possible changes.*

```json
'changes': {
  'procedures': {
    'status': {'new': 'in_review', 'old': 'draft'}
  },
  'proceduresAttributes': {
    'Responsible ME': {'new': 962, 'old': None}
  }
}

```


# Action Execution Logs

Use Action Execution Logs to easily develop and debug ION Actions.

{% hint style="info" %}
Execution Logs are subject to a 30-day retention period. All logs are permanently deleted once this period expires.
{% endhint %}

ION Action Execution Logs provide visibility into the exact code and execution context used during an ION Action run. They capture validation messages, Actions which have run, the target record, and more. This enables you to quickly troubleshoot failures, and confirm correct behavior during development and debugging. Logs are scoped to an Event and Target combination during a mutation. When multiple ION Actions share the same Event and Target, their execution is grouped into a single log.

**Logs can be accessed in two ways:**

**From the Actions tab:** Navigate to the Actions tab and click Action Executions in the top-right of the header. This opens a table view showing all execution logs.

**From an individual ION Action:** Open a specific ION Action’s page and select the Executions tab next to the Context and Code tabs. This view displays a table of execution logs filtered to that specific ION Action.

### Search Bar

The search bar in the top left of table is a powerful tool that can be used to quickly find the log you are looking for.

<figure><img src="/files/Yc6WWCTFgeGJ01Ukvn5T" alt=""><figcaption></figcaption></figure>

The search bar will search on the following fields:

* ION Action ID
* ION Request ID
* Target Record ID
* Target
* Event

Additional filters are available by clicking the Filters button. When both filters and search are applied, results must match all selected filters *and* the search query.

### Table Actions

The 'Actions' column provides some actions to quickly work with the logs in the table.

* **View Execution:** Opens the Execution Log's page
* **Copy Link:** Copies link to the Execution Log's page
* **Download Code:** Downloads the executed code into a Python file.
* **Quick View:** Opens a quick view modal, giving a quick glimpse at the execution code.

<figure><img src="/files/pL8IrEFII6eqmZMcgMIL" alt=""><figcaption></figcaption></figure>

#### Downloading Code and Debugging Locally

The 'Download Code' table action allows you to download the executed code into Python file. To bulk download, you can select multiple rows and use the action bar at the bottom to download a Zip file with a Python file for each log.

<figure><img src="/files/76Z9EAvLWMB2eMPrDU1E" alt=""><figcaption></figcaption></figure>

Once you've downloaded the code, you can run the code locally by installing Python 3 and opening your favorite IDE or terminal. Run `python3 name_of_log_file.py` in your terminal and get the exact output of the Action. Edit the file and run it again until you get the desired result, then transfer your changes to the relevant ION Action.

#### Quick View

Open a quick view of a log using the table actions above. The Quick View modal show the executed code, the timestamp and high level metadata. The arrows in the top right or the left and right arrow keys can be used to navigate to the next log. When navigating between logs, it will respect the current logs display on the table.

<figure><img src="/files/FSeC3L7NHQW8Hwcvqh6n" alt=""><figcaption></figcaption></figure>

### Execution Log Page

You can navigate to the Action Execution Log by clicking on it's timestamp or by using the 'View Execution' button in table actions. This page will display all relevant metadata and give a better view of the code and context ran.

<figure><img src="/files/kBbVCcBU9Lx3mxQftWKA" alt=""><figcaption></figcaption></figure>

The code is displayed in an easy to read formatted way and the context can be expanded to view as a formatted JSON using the 'Show Execution Context' button.

<figure><img src="/files/73AODv7wPsWTM6oFwJ65" alt=""><figcaption></figcaption></figure>

### Key Execution Log Fields

Each log contains code, context and metadata from the execution:

* **Created At:** The time at which the log was created. This lines up with the timestamp that the Action was triggered and is a great way to quickly find relevant logs.
* **Event:** The type of event which triggered the ION Action
* **Target:** The type of record (Part Inventory, Run Step, etc) the ION Action is run against.
* **Target Record ID:** The ID of the target record. A log with an UPDATE Event, Target of PART and Target Record ID of 34 means the Action was triggered by updating part with ID 34. This is another great way to filter to find a specific log - especially if you know the record ID of the object you triggered the Action with.
* **Validation Message:** The is the message you see when an Action raises a validation. This message can be the expected message from validation or it can be a Python level error like (SyntaxError or NameError) that occurred while running the Action.
* **Raised Action:** The Raised Action is the action which raised the validation message.
* **Executed Action IDs:** This is the list of all Actions which ran in the log.
* **Execution Time**: The time in milliseconds it took an action to run.
* **ION Request ID:** This is the ID of the ION request during which the log was created. This can be found on the error toast given during an error.
* **Triggered By:** The user which ran the operation which triggered the ION Action to run. This is a great way to filter logs when you know who triggered it.

### Structure of the Execution Log Code

When an Event and Target combination matches multiple ION Actions, those Actions are squashed together at execution time. Squashing merges both the code and the requested context so that every triggered Action can run with the data it requires.

During this squashing process, additional processing occurs to prepare the Actions for execution.

#### Example

Consider two Actions configured with:

* **Event:** `CREATE`
* **Target:** `RUNS`

When a Run is created, both Actions are triggered. Instead of executing independently, they are squashed into a single execution flow, which is reflected in the execution log.

<div align="center" data-full-width="false"><figure><img src="/files/sPVIgRBs7HIzBEL572lg" alt=""><figcaption><p>Action 535 - On CREATE RUNS, selects dueDate in context and ensures it is filled out.</p></figcaption></figure></div>

<figure><img src="/files/pEdS8xb6uNKNOYHwNHyI" alt=""><figcaption><p>Action 240 - On CREATE RUNS, selects procedureId in context and ensures it is filled out</p></figcaption></figure>

When a Run is created, both Actions are triggered. They are squashed together and the log looks like this:

<figure><img src="/files/rT6VzTbi2ZOgPdRYDHjy" alt=""><figcaption><p>Action Execution Log for creating a Run with the above Actions enabled</p></figcaption></figure>

#### ValidationError

A `ValidationError` class is defined and included in all execution logs.\
This class standardizes error handling across Actions. If a `ValidationError` is thrown within Action code, the Action ID and name are automatically injected into the executed code, making it clear which Action caused the failure.

#### run\_rule

Wraps each of the triggered Actions into a single executable unit. This is where code from each Action is combined and ran. The ordering is based on `id` of the action.

#### Execution Context (ctx)

The `ctx` object represents the **combined context** for all squashed Actions. Each Action declares the specific fields it needs in the context query. During squashing all requested fields are merged into a single context object.

From the example:

* Action 535 requests `dueDate` in the context
* Action 240 requests `procedureId` in the context

The resulting context contains both:

<figure><img src="/files/GEtJcgQ48zRmXIQQ1mrr" alt=""><figcaption></figcaption></figure>


# Inventory Control Examples

Current Status: Available in Customers Sandbox Environments

#### Inventory Control via ION Actions

ION Actions provides improved capabilities to systematically manage and control inventory creation and updates. This can be leveraged in use cases where you may want to be more granular than ION's out of the box inventory control permissions. Below is an overview to guide your integration of this functionality into your organizations ION Actions code:

**Understanding Inventory Terms**

* **Inventory in Code**: In ION Actions, Inventory is represented as `partInventory`. The individual component, which may have multiple inventory entries, is simply referred to as `part`.

**Creating Inventory Actions**

* When creating new inventory entries, utilize the rule target `partInventory` with the event `CREATE`.
* Incorporate the `howCreated` attribute in your `partInventory` context. This attribute indicates the method of inventory creation, allowing you to implement precise access controls based on the source of the creation event.
  * Example creation methods indicated by `howCreated`:
    * `manual`: Manually created inventory entries.
    * `run_made`: Inventory created as a result of production runs.
    * `po_line_made`: Inventory generated from purchase order lines.
  * Additional scenarios include inventory creation resulting from splits, such as partially assigning lots to an issue or partially kitting inventory to a kit.

Below are all the possible values these columns can contain:

```python
    # backfilled for inventory prior to this creation
    UNKNOWN
    # creating (no splitting)
    MANUAL # eg create inventory row from inventory table page
    RUN_MADE #eg create inventory via a make run
    PO_LINE_MADE #eg create inventory by creating a PO line
    # manual/direct splits
    DIRECT_SPLIT #eg splitting inventory via the invenotry table
    # installing splits
    PARTIAL_INSTALL
    PARTIAL_UNINSTALL
    # kitting splits
    PARTIAL_KIT
    PARTIAL_UNKIT
    # scrapping splits
    PARTIAL_SCRAP
    PARTIAL_UNSCRAP
    # receiving splits
    PARTIAL_RECEIVE # no partial unreceive
    # assigning issues split
    PARTIAL_ASSIGN_TO_ISSUE # no partial unassign
```

**Tracking Inventory Splits**

* The `howLastSplit` attribute, available in the `partInventory` context, provides insight into how a given inventory item was last divided or modified.

**Context Example**

Below is a practical example demonstrating how to set up context on `partInventory` for leveraging these new attributes effectively in ION Actions:

```graphql
{\n  partInventory(id: $id) {\n    howCreated\n    howLastSplit\n    id\n    part {\n      partType\n    }\n  }\n}
```

**Example Use Cases**

What follows are a few example createRule mutations you can deploy in sandbox to help you get started using the data available in the `partInventory` context:

* **Control who can create inventory via run creation**:

```python
mutation {
  createRule(input: {
    title: "No Permissions to Create Inventory via Creating a Run",
    target: PARTINVENTORY,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  partInventory(id: $id) {\n    howCreated\n    id\n    part {\n      partType\n    }\n  }\n}",
    code: "RUN_ALLOWED_ROLES = {'planner','rando'}   # ← add or remove roles here\n\npart_inv = context.get('partInventory') or {}\nuser_roles = set(context.get('currentUser', {}).get('roles', []))\nif part_inv.get('howCreated') == 'RUN_MADE':\n    if RUN_ALLOWED_ROLES.isdisjoint(user_roles):\n      raise ValidationError()",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}
```

* **Control who can create inventory via the inventory table**:

```python
mutation {
  createRule(input: {
    title: "No Permissions to Create Inventory via Inventory Table",
    target: PARTINVENTORY,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  partInventory(id: $id) {\n    howCreated\n    id\n    part {\n      partType\n    }\n  }\n}",
    code: "MANUAL_ALLOWED_ROLES = {'planner','rando'}   # ← add or remove roles here\n\npart_inv = context.get('partInventory') or {}\nuser_roles = set(context.get('currentUser', {}).get('roles', []))\nif part_inv.get('howCreated') == 'MANUAL':\n  if MANUAL_ALLOWED_ROLES.isdisjoint(user_roles):\n    raise ValidationError()",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}
```

* **Variation on the above code: Control who can create inventory but allow 'TOOL' inventory type creation**:

```python
mutation {
  createRule(input: {
    title: "No Permissions to Create Non-Tool Inventory via Inventory Table",
    target: PARTINVENTORY,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  partInventory(id: $id) {\n    howCreated\n    id\n    part {\n      partType\n    }\n  }\n}",
    code: "MANUAL_ALLOWED_ROLES = {'planner','rando'}   # ← add or remove roles here\n\npart_inv = context.get('partInventory') or {}\nuser_roles = set(context.get('currentUser', {}).get('roles', []))\nif part_inv.get('howCreated') == 'MANUAL':\n  if part_inv.get('part').get('partType') != 'TOOL':\n    if MANUAL_ALLOWED_ROLES.isdisjoint(user_roles):\n      raise ValidationError()",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}
```

* **Control who can split inventory on the inventory table**:

```python
mutation {
  createRule(input: {
    title: "No Permissions to Split Inventory via Inventory Table",
    target: PARTINVENTORY,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  partInventory(id: $id) {\n    howCreated\n    id\n    part {\n      partType\n    }\n  }\n}",
    code: "MANUAL_SPLIT_ALLOWED_ROLES = {'planner','rando'}   # ← add or remove roles here\n\npart_inv = context.get('partInventory') or {}\nuser_roles = set(context.get('currentUser', {}).get('roles', []))\nif part_inv.get('howCreated') == 'DIRECT_SPLIT':\n  if MANUAL_SPLIT_ALLOWED_ROLES.isdisjoint(user_roles):\n    raise ValidationError()",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}

```

Any of the above ION Actions can be quickly adjusted by modifying the value specified for `howCreated` in your python logic. For example, you could replace `'MANUAL'` with `'RUN_MADE'` or `'PARTIAL_KIT'` to change the targeted creation event.


# Installation Control Examples

A guide for developers making ION Actions on abomInstallation events.

### Creating Ion Actions for A-Bomb Installations

#### Objective

This outlines the steps to develop ion actions for A-bomb installations, focusing on identifying and utilizing necessary IDs for successful execution of the context query. This aids in developing ION Actions.

#### Key Steps

**Step 1: Understand the Context for Ion Actions** [0:00](https://loom.com/share/d8dd4e1a7eb844d4bf74e3a11f5457b1?t=0)

* Create an abomInstallation Action and start out with this base template for the context query (INITIAL SETUP SHOWN IN IMAGE BELOW):

```
query ($buildRequirementId: ID!, $partInventoryId: ID!) {
  abomInstallation(
    buildRequirementId: $buildRequirementId
    partInventoryId: $partInventoryId
  ) {
    id
    partInventory {
      id
    }
  }
}
```

* The inputs necessary to test the context for this rule will be the following.

```
{
  "buildRequirementId":INSERT ID HERE, 
  "partInventoryId":INSERT ID HERE
}
```

* Recognize that A-bomb installations require two IDs:
  * Build Requirement ID
  * Part Inventory ID
* These IDs are essential for rule context development.
* Once the ION Action is live, these IDs will be passed into the ion action during execution. To help develop these rules we recommend the following steps to know what IDs to test with.

<figure><img src="/files/0nTnARs9xsB1TjcAyzLb" alt=""><figcaption></figcaption></figure>

**Step 2: Install GraphQL Network Inspector** [1:32](https://loom.com/share/d8dd4e1a7eb844d4bf74e3a11f5457b1?t=92)

* Install the [GraphQL Network Inspector tool](https://chromewebstore.google.com/detail/graphql-network-inspector/ndlbedplllcgconngcnfmkadhokfaaln?pli=1) to monitor the execution of your ion actions.
* This tool helps you see the IDs and data being processed so you can effectively develop the ION Action.

**Step 3: Execute a Mutation to Install Part Inventory** [2:15](https://loom.com/share/d8dd4e1a7eb844d4bf74e3a11f5457b1?t=135)

<figure><img src="/files/6WstQd2LFFdBefLCsBZs" alt=""><figcaption></figcaption></figure>

* Right click and open the inspect tool, toggle to the GraphQL tab so you can see what mutations are called.
* Replicate the action you are trying to control, in this case installing something onto an aBOM.
* Focus on the mutation called `install part inventory`.
* See that the request includes both a Build Requirement ID and Part Inventory ID.

**Step 4: Analyze the Response for IDs** [3:14](https://loom.com/share/d8dd4e1a7eb844d4bf74e3a11f5457b1?t=194)

<figure><img src="/files/Ozf4KBE9bzTDEzBhv6qI" alt=""><figcaption></figcaption></figure>

* Check the response tab for the InstallPartInventory query which will contain a `partInventoryId`, which may differ from the one passed in during the request (in the case were splitting happened from a partial install).
* Note the `buildRequirementId` and the new `partInventoryId` for your records, you can pass these into the inputs within the ION Actions context interface to see what the context will return.

**Step 5: Save the Context of the Rule Query** [5:26](https://loom.com/share/d8dd4e1a7eb844d4bf74e3a11f5457b1?t=326)

<figure><img src="/files/zqwkJG59EeLp03pUeO7m" alt=""><figcaption></figcaption></figure>

* Pass in the input variables based on the query response to understand what this specific context returned. This will help you define the logic to use within the code portion of the ION Action. ***In the example image above the id's happened to be:***

```
{
  "buildRequirementId":2622, 
  "partInventoryId":2079
}
```

* Save the context query of your ION action with the explicit save icon below the play button to avoid re-entering the query formatting in future sessions. (You will need to specify the query inputs each time.)

**Step 6: Access Origin Part Inventory Attributes** [6:28](https://loom.com/share/d8dd4e1a7eb844d4bf74e3a11f5457b1?t=388)

<figure><img src="/files/mLCPqgHvZtHw23of5s0s" alt=""><figcaption></figcaption></figure>

* If you split an inventory, you can use the originPartInventory field to access information related to the original inventory item "pre" the split.
* Now that you know what the context will return, write code within the code tab to determine installation eligibility!
  * ION Actions code can now access the context in the following manor: `context.get("abomInstallation", {}).get("partInventory", {}).get(.......`

#### Cautionary Notes

* Ensure that you are using the correct IDs to avoid errors in your ion actions.

#### Tips for Efficiency

* Regularly use the GraphQL Network Inspector to familiarize yourself with the IDs and data flow.

#### Link to Loom

<https://loom.com/share/d8dd4e1a7eb844d4bf74e3a11f5457b1>


# Attribute Examples

Current Status: Available in Customers Sandbox Environments

#### Controlling Attribute Population at Creation

This powerful use case allows you to enforce attribute assignment rules precisely at the creation event, ensuring correct attribute values before the inventory moves further through your workflow, preventing potential discrepancies with subsequent stakeholders.

* **Control custom attribute population on run creation for BUILD procedures (example attribute key ‘Pedigree’)**:

```python
mutation {
  createRule(input: {
    title: "Must Have Pedigree Populated at Run Creation",
    target: RUN,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  run(id: $id) {\n    attributes {\n      key\n      value\n    }\n    procedure {\n      type\n    }\n  }\n}",
    code: "run = context.get('run', {})\nproc_type = ((run.get('procedure') or {}).get('type') or '').upper()\n\nif proc_type == 'BUILD':\n    pedigree_val = next(\n        (a.get('value') for a in run.get('attributes', [])\n          if a.get('key') == 'Pedigree'),\n        None,                    # use None as the default\n    )\n\n    # Missing if it’s None **or** empty/whitespace\n    if pedigree_val is None or not str(pedigree_val).strip():\n        raise ValidationError()\n\n\n\n",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}
```

* **Verify inventory attribute population by referencing part attributes**:

This example checks attributes at the part level to ensure that the inventory instance about to be created is allowed to have the assigned attribute value. In the scenario below, the inventory attribute ‘Pedigree’ cannot be set to ‘Flight’ unless the part-level attribute ‘Flight Worthy’ is marked as ‘Yes’. This rule includes exit paths if the procedure does not exist or is not of type ‘BUILD’.

```python
mutation {
  createRule(input: {
    title: "Run Pedigree Cannot be Flight due to Part Library Not Being Flight Worthy",
    target: RUN,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  run(id: $id) {\n    part {\n      Attributes {\n        key\n        value\n      }\n    }\n    Attributes {\n      key\n      value\n    }\n    procedure {\n      type\n      Attributes {\n        key\n        value\n      }\n    }\n  }\n}",
    code: "run = context.get('run') or {}\nprocedure_type = (run.get('procedure') or {}).get('type')\n\n# Exit early if the run isn't a BUILD or if procedure is missing\nif procedure_type != 'BUILD':\n    return\n\n# Grab run-level pedigree\nrun_attrs = run.get('Attributes', []) or []\nrun_pedigree = next(\n    (attr.get('value') for attr in run_attrs if attr.get('key') == 'Pedigree'),\n    None\n)\n\n# Grab part-level flight-worthy flag (if there's a part at all)\npart = run.get('part') or {}\npart_attrs = part.get('Attributes', []) or []\npart_worthy = next(\n    (attr.get('value') for attr in part_attrs if attr.get('key') == 'Flight Worthy'),\n    None\n)\n\n# Enforce the pedigree vs. flight-worthy rule\nif run_pedigree in ('Flight') and part_worthy not in ('Yes'):\n    raise ValidationError()",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}
```


# Quality Examples

To ensure data accuracy in non-conformance workflows, follow these example rules. These guidelines emphasize capturing data before proceeding to subsequent steps.

<details>

<summary>Issue Must Have an Assignee Before Being Submitted for Review</summary>

```
mutation {
  createRule(input: {
    title: "Issue Must Have an Assignee Before Being Submitted for Review.",
    target: ISSUEAPPROVALREQUEST,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  issueApprovalRequest(id: $id) {\n    id\n    issue {\n      status\n      assignedTo {\n        id\n      }\n    }\n  }\n}",
    code: "issue_approval_request = context.get('issueApprovalRequest') or {}\nissue = issue_approval_request.get('issue') or {}\nstatus = issue.get('status')\nassigned_to = issue.get('assignedTo')\n\nif status in ['PENDING', 'IN_PROGRESS'] and assigned_to is None:\n    raise ValidationError()\n",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}
```

</details>

<details>

<summary>Cause Condition, Expected Condition, and Disposition text must be populated before moving through review.</summary>

```
mutation {
  createRule(input: {
    title: "All Issue Text Fields Must Be Filled In Before Requesting Reviews",
    target: ISSUEAPPROVALREQUEST,
    ruleType: VALIDATION,
    eventType: CREATE,
    enabled: true,
    context: "{\n  issueApprovalRequest(id: $id) {\n    id\n    issue {\n      status\n      causeCondition\n      expectedCondition\n      disposition\n    }\n  }\n}",
    code: "def has_text(node):\n    return bool(\n      node.get('text')\n      or any(has_text(child) for child in node.get('children') or [])\n    )\n\nissue_approval_request = context.get('issueApprovalRequest') or {}\nissue = issue_approval_request.get('issue') or {}\nis_status_ok = issue.get('status') in ['PENDING', 'IN_PROGRESS']\n\nif is_status_ok:\n  disposition = issue.get('disposition', [])\n  expected_condition = issue.get('expectedCondition', [])\n  cause_condition = issue.get('causeCondition', [])\n  \n  if (\n    not disposition\n    or not expected_condition\n    or not cause_condition\n    or not any(has_text(d) for d in disposition)\n    or not any(has_text(d) for d in expected_condition)\n    or not any(has_text(d) for d in cause_condition)\n  ):\n    raise ValidationError()\n",
    errorState: BLOCK
  }) {
    rule {
      id
    }
  }
}
```

</details>


# ION Actions Best Practices

### Overview

The Ion Actions engine enables powerful automation and business logic within ION by allowing users to define rules that respond to object events such as **Work Order updates**, **Issue creation**, or **Part changes**. Rules are written in Python and executed dynamically based on event triggers.

This document outlines best practices for writing, testing, and managing Ion Action rules. Following these guidelines will help ensure reliable behavior, maintainability, and consistency across your automation logic.

***

### 1. Rule Execution and Behavior

#### **Chained Execution**

When multiple rules target the **same object** and **event type** (for example, `Issues Update`), they are **chained together** and executed sequentially. The execution order is determined by internal rule IDs, which are **not user-controlled** and may vary. Because of this, rule order should not be relied upon.

#### **Avoid Top-Level `return` Statements**

If a `return` statement is used at the top level of a rule, the Ion Actions engine will stop executing that rule **and all subsequent rules in the chain**. This can lead to unintended skipping of logic defined in other rules that share the same event target.

**Example (Problematic):**

```python
if issue.status == "Closed":
    return  # ❌ This stops execution of all following rules for this event
```

#### **Use Nested Returns Instead**

To safely control flow within your rule without affecting other chained rules, scope your `return` statements within functions or conditionals. This allows the Ion engine to continue executing subsequent rules.

**Example (Recommended):**

```python
if issue.status == "Closed":
    def handle_closed_issue():
        # Logic specific to closed issues
        return "Handled closed issue"  # ✅ Nested return affects only this function

    handle_closed_issue()
```

#### **Additional Recommendations**

* **Avoid relying on rule execution order.** Each rule should be self-contained and independent.
* **Use variables for decision-making.** Employ local variables or persistent storage to manage conditional logic instead of using `return` to control flow.
* **Test extensively.** Validate behavior across multiple chained rules to ensure predictable outcomes.

***

### 2. Rule Development and Deployment

#### **Version Control and Collaboration**

* As larger organizations scale and have internal software teams we see success in storing Ion Action rules in a **version-controlled repository** (e.g., GitHub or similar).
* Connect your repository to the Ion API to enable direct, auditable deployment of rules.
* Use **pull requests** or **merge reviews** to facilitate peer review, ensuring code quality and alignment with operational standards.
* This approach allows engineers and operations teams to collaborate within familiar development workflows.

#### **Deployment Process**

* Maintain **staging and production environments** for rule deployment.
* Test rules thoroughly in staging before promoting them to production.
* Use automated or semi-automated deployment pipelines to push rules, reducing manual copying and minimizing risk.
* Clearly document rule changes and maintain an internal changelog for traceability.

#### **Governance and Documentation**

* Treat Ion as the **execution platform** for rule logic, while managing source, versioning, and review externally at scale.
* Implement a code review process before merging changes to production.
* Maintain a clear audit trail for compliance and troubleshooting.


# Procedures


# Creating and Updating Procedures

This SOP outlines the steps to effectively create and manage procedures using the new ION interface, ensuring clarity and efficiency for team members. It is packed with performance and usability upgrades to make it much easier for manufacturing engineers to use.

#### Key Steps

### **1. Overview of the New Interface**

![generated-image-at-00:00:00](https://loom.com/i/5070d2c260c443789258aa4c8dfa08a1?workflows_screenshot=true)

* The new ION experience features three main tabs:
  * **Steps**: Main tab for procedure details.
  * **Dependencies**: Manage dependencies between steps.
  * **Overview**: General information about the procedure.

### **2. Using the Steps Tab**

![generated-image-at-00:00:22](https://loom.com/i/21d728648e0041d285b6c2d3539bb921?workflows_screenshot=true)

* Access the **Steps** tab to view all information related to your procedure step.
* Utilize the upgraded content editor for:
  * **To Do** lists.
  * **Markdown** for formatting (headers, callouts).
  * Enhanced **table functionality** (insert columns, merge cells, paint cells, add/remove borders).
* Set attributes such as location, lead time, and labor time for each step.

### **3. Adding Steps**

![generated-image-at-00:03:01](https://loom.com/i/4d95c50e4a9a442395f04bdc9a74c6e2?workflows_screenshot=true)

* To add a step:
  * Hover over an existing operation or step.
  * Click **Add Step Below** or **Child Step**.
  * Enter the step name, set the location, and type of step.
  * Search for existing standard steps if applicable.

### **4. Managing Dependencies**

![generated-image-at-00:03:47](https://loom.com/i/ac9f5fbd597d4c45a1598ced33208118?workflows_screenshot=true)

* Access the **Dependencies** tab to:
  * Rearrange dependencies easily.
  * Add or remove dependencies with auto-formatting.
  * View child steps quickly.

### **5. Overview Tab Details**

![generated-image-at-00:05:05](https://loom.com/i/b8b7350b413b4d35b1cd2bd652597c9f?workflows_screenshot=true)

* In the **Overview** tab:
  * Enter a description of the procedure.
  * View related information (type, attributes, project code, responsible engineer).
  * Check associated parts and their approval status.
  * Access version history to view different versions of the procedure.

### **6. Reviewing Procedure Version History**

![generated-image-at-00:05:29](https://loom.com/i/bdbb6115b10b45a68599ad64766437b6?workflows_screenshot=true)

* Click on **Version History** to:
  * Switch between different versions of the procedure.
  * Review related runs and issues for each version.

#### Cautionary Notes

* Ensure all steps are clearly defined to avoid confusion.
* Regularly update the procedure to reflect any changes in processes or requirements.

#### Tips for Efficiency

* Familiarize yourself with the Markdown formatting to enhance documentation clarity.
* Utilize the search function for existing standard steps to save time when adding new steps.
* Regularly check the version history to stay updated on changes and issues.

{% embed url="<https://loom.com/share/ef576a2e31844eb98593aed23e5a1703>" %}


# Standard Operating Procedures

This SOP outlines the steps to create, manage, and link standard operating procedures within the Ion system. Many of our customers have detailed instructions that the manufacturing engineers want to maintain outside of the actual build instructions. This guide helps explain how you can use the Procedure Family Link to make that achievable in ION.

#### Key Steps

### **Step 1: Create a New SOP**

![generated-image-at-00:00:01](https://loom.com/i/0c184986f4d14247a12dc268cecf6b4d?workflows_screenshot=true)

* Begin by accessing the Ion system.
* Select the option to create a new standard operating procedure (SOP).
* Use a relevant title for the SOP, e.g., 'Torque SOP'.

### **Step 2: Fill in SOP Details**

![generated-image-at-00:00:30](https://loom.com/i/05394e187e99415ca259b40bcf40191e?workflows_screenshot=true)

* Input all necessary details for the SOP.
* Include specific information such as:
  * Fastener types (e.g., '4 fasteners')
  * Torque specifications (e.g., 'Tor 2X')
  * Any secondary locking features.

### **Step 3: Review and Release the SOP**

![generated-image-at-00:01:07](https://loom.com/i/1de533c406994674b1bbaa3bb5379cc7?workflows_screenshot=true)

* Go through the review process to ensure all information is accurate.
* Once reviewed, proceed to release the SOP.

### **Step 4: Version Control of SOPs**

![generated-image-at-00:01:21](https://loom.com/i/6a70873ac1a74a57856f371b4cfe585f?workflows_screenshot=true)

* Utilize the procedure approval engine to create new versions of the SOP as needed.
* For example, create a version 2 (V2) of the SOP and release it.

### **Step 5: Copy Procedure Family Link**

![generated-image-at-00:01:46](https://loom.com/i/66c469f18e0e480c8446a784657111ac?workflows_screenshot=true)

* Use the 'copy procedure family' link to reference the SOP in other procedures.
* This ensures that any linked procedures will always point to the latest version of the SOP.

### **Step 6: Tagging SOPs**

![generated-image-at-00:02:12](https://loom.com/i/ebc7e660c15b488cb1d9b6fb20450d6e?workflows_screenshot=true)

* When referencing the SOP in another document, tag it appropriately.
* Ensure the link directs users to the correct SOP.

### **Step 7: Accessing the Latest Version**

![generated-image-at-00:02:32](https://loom.com/i/e834cff9bd64492aa96403cf79d038a4?workflows_screenshot=true)

* Test the link to ensure it directs to the latest version of the SOP.
* Confirm that even older versions of the SOP will redirect to the most current version.

#### Cautionary Notes

* Ensure all details entered in the SOP are accurate to avoid confusion.
* Regularly review SOPs to keep them up-to-date with current practices.

#### Tips for Efficiency

* Use templates for SOPs to streamline the creation process.
* Regularly schedule reviews of SOPs to ensure they remain relevant and accurate.

{% embed url="<https://loom.com/share/3a56d509f55f41dca9ac565abcc51b5f>" %}


# Backwards Compatibility Considerations

This guide outlines the steps to effectively roll out the new procedures module in the Ion Experience while ensuring compatibility and functionality.

#### Key Steps

### **1. Understanding New Functionality**

![generated-image-at-00:00:00](https://loom.com/i/e65cff2afe4246dfbf12bd1eccbf6be8?workflows_screenshot=true)

* Familiarize yourself with the new content editor features:
  * To-do lists
  * Markdown headers
  * Table functionality (colored cells, merging, adding/removing cells, borders, splitting cells)
  * Toggles for hidden content
  * Code blocks for various coding languages
  * Block quotes and callouts with emojis
  * Table of contents driven by headers
  * Date and function capabilities.

### **2. Compatibility Awareness**

![generated-image-at-00:01:11](https://loom.com/i/c3d0f2a1d34543ff9e731ef28de5be11?workflows_screenshot=true)

* Recognize that the new features are only applicable in the new Ion Experience.
* Understand that content will not render correctly in the old Ion Experience:
  * To-do lists will not appear as checklists.
  * Headers will not format correctly.
  * Tables will lack proper merging and coloring.
  * Toggles will not function.
  * Code blocks, block quotes, callouts, table of contents, dates, and equations will be absent.

### **3. Timing for Implementation**

![generated-image-at-00:01:51](https://loom.com/i/7641f6dae31848768986b2477cadc8f5?workflows_screenshot=true)

* Avoid using the new functionality until both the procedures and run modules are rolled out in the new Ion Experience.

#### Cautionary Notes

* Ensure all team members are aware of the differences between the old and new Ion Experiences to prevent confusion.
* Do not attempt to use new features in the old Ion Experience as it may lead to errors and miscommunication.

#### Tips for Efficiency

* Schedule a training session for team members to familiarize them with the new features before rollout.
* Create a checklist of new functionalities to ensure all team members are utilizing them effectively after the rollout.

{% embed url="<https://loom.com/share/9381d2caf8df4273a37f037cab2fc2cc>" %}


# Reviewing Procedures

This outlines the steps to effectively use the Procedures Approval System in ION for procedure approval and release.

**1. Navigate to Settings** [0:21](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=21)

![](https://loom.com/i/cc63a35853ec4114b5644c8d78659549?workflows_screenshot=true)

* Open the ION application.
* Go to the **Settings** section.
* Locate the **Procedures** section.

**2. Add Roles and Reviewers** [0:36](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=36)

![](https://loom.com/i/243871efee1f439c8f8f01d80e91d9d9?workflows_screenshot=true)

* In the Procedures section, find the option to add roles.
* Specify the number of reviewers needed for procedure sign-off.

**3. Assign Reviewers** [0:44](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=44)

![](https://loom.com/i/615cced4e40941de9add23a2de8ae58c?workflows_screenshot=true)

* Return to your procedure.
* Assign the required reviewers to each sign-off role.

**4. Gather Feedback** [0:59](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=59)

![](https://loom.com/i/f84b5b58c7294f3aa4a50194f3179362?workflows_screenshot=true)

* Review feedback and comments from technicians regarding the procedure.
* Ensure all feedback is accounted for before moving to in-review status.

**5. Address Feedback** [1:15](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=75)

![](https://loom.com/i/42fcf3f9b7204b9d82f357f3e3263c83?workflows_screenshot=true)

* Make necessary changes based on the feedback received.
* Acknowledge that feedback has been resolved in the procedure.

**6. Move to In-Review Status** [1:47](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=107)

![](https://loom.com/i/68d331a72d3346059f5ff464e0aae80b?workflows_screenshot=true)

* If all feedback is resolved, move the procedure to **in-review** status.
* If feedback is not resolved, you can still move to in-review using the drop-down in the header.

**7. Approve the Procedure** [1:58](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=118)

![](https://loom.com/i/75efcd4281db4b0b85fef3a29e9f968c?workflows_screenshot=true)

* As an assigned approver, click the **approve** button to approve the procedure.
* Comments can be added in the feed during the approval process.

**8. Log Approval** [2:12](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=132)

![](https://loom.com/i/eb12f6fe1ba347daabdd31ead1432c67?workflows_screenshot=true)

* Ensure that the approval is logged in the feed for tracking purposes.

**9. Review Comments** [2:37](https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31?t=157)

![](https://loom.com/i/2e8d29dddf8b45559ffdf8e541e35712?workflows_screenshot=true)

* Check that all comments and feedback have been addressed before finalizing the procedure.

#### Cautionary Notes

* We suggest you not move to in-review status until all feedback is accounted for to avoid missing critical changes, however we do not block you from doing so. Use the status selector in the header to do this manually.

#### Link to Loom

<https://loom.com/share/dc5f3ce89b7a4e7a88ac97eedb27cf31>


# Locations


# Manage Locations

## Creating, Updating, and Searching Factory Locations in ION

#### Objective

This SOP outlines the steps to create and manage factory locations within the ION system, ensuring clarity and efficiency in operations.

#### Key Steps

**1. Overview of Factory Page** [0:00](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=0)

<figure><img src="/files/zO3oEPIY4xkqZE4yjkh4" alt=""><figcaption></figcaption></figure>

* Access the factory page in ION to view locations within your factory.
* Understand that locations can have types and can be nested.

**2. Understanding Location Types and Nesting** [0:16](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=16)

<figure><img src="/files/unoTJ3NbOhubuyVP8qXI" alt=""><figcaption></figcaption></figure>

* Locations can include warehouses, wings, subclassifications, racks, and totes.
* Use the nested setup to traverse through factory locations or utilize the search function.

**3. Viewing Location Information** [0:56](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=56)

<figure><img src="/files/lsjGAlBO5WEzGbRDGC9C" alt=""><figcaption></figcaption></figure>

* Click on a specific location to view its overview, including:
  * Issues
  * Inventory
  * Procedure steps
* Note if the location has sub-locations.

**4. Modifying Location Information** [1:34](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=94)

<figure><img src="/files/1Hv6OJC9RiQe3aqnmpoC" alt=""><figcaption></figcaption></figure>

* To change location information (e.g., supervisors, type), access the location settings.

**5. Quick Glance at Related Steps** [1:44](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=104)

<figure><img src="/files/LvohqxXvXrSzXxzasuxW" alt=""><figcaption></figcaption></figure>

* Use the quick glance feature to see related steps for each location.

**6. Creating a Sub-location** [2:03](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=123)

<figure><img src="/files/hXXBMaahWAP9DX1iWahQ" alt=""><figcaption></figcaption></figure>

* Navigate to sub-locations and click 'Create'.
* Set the type of the new location (e.g., tote).

**7. Confirming New Location Creation** [2:39](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=159)

<figure><img src="/files/hXXBMaahWAP9DX1iWahQ" alt=""><figcaption></figcaption></figure>

* Ensure the new location is visible and linked to its parent location.

**8. Navigating Back to Parent Location** [2:56](https://loom.com/share/5581b5e1cf9747f18590d36c041300dc?t=176)

<figure><img src="/files/skhlWPt6ThkKLmGiRcDz" alt=""><figcaption></figcaption></figure>

* Return to the parent location to confirm the visibility of the newly created sub-location.

#### Cautionary Notes

* Ensure that all location types are correctly defined to avoid confusion.
* Double-check the nesting structure to maintain clarity in location hierarchy.

#### Tips for Efficiency

* Use the search function to quickly locate specific locations instead of manually navigating through the nested setup.
* Regularly update location information to reflect any changes in supervisors or types.

#### Link to Loom

<https://loom.com/share/5581b5e1cf9747f18590d36c041300dc>


# Create Issues

Create Issues at a moments notice, from anywhere within the application.

### Overview

Creating issues quickly ensures that problems are documented and routed to the right people without slowing down production. From anywhere in ION, a simple keyboard shortcut (Command-Shift-I) (Command-K) on Macs and (Control-Shift-I)(Control-K) on PCs opens the issue form or command menu where you can create issues. Users can add details such as the run and step where the issue occurred, related parts, descriptions of the problem, and the expected condition. This keeps critical context tied to the issue from the start.

Once captured, issues can be assigned to specific users and routed to the appropriate teams or locations. Required fields or attributes specific to the organization can also be filled in to support faster review and resolution. By standardizing how issues are logged, teams ensure that problems are well-defined, actionable, and resolved quickly, reducing downtime and maintaining quality.

### Creating an Issue in ION

#### Key Steps

**Step 1: Open Create New Issue Form** [0:00](https://loom.com/share/5add1d772eb14fc5a413e8b771ab927c?t=0)

![](https://loom.com/i/a7cf1a8249f444d496c619a48c765f54?workflows_screenshot=true)

* Press **Command-Shift-I** from anywhere within ION to open the Create New Issue form.
* Input the necessary information regarding the issue.

**Step 2: Select Run and Step (if applicable)** [0:34](https://loom.com/share/5add1d772eb14fc5a413e8b771ab927c?t=34)

![](https://loom.com/i/75ad50a3214a4719ad89f2dea11ed87a?workflows_screenshot=true)

* If the issue was found during a specific Run Step, select the appropriate **Run** and **Step** where the issue occurred.
* Note: This step is not mandatory.

**Step 3: Describe the Issue** [0:54](https://loom.com/share/5add1d772eb14fc5a413e8b771ab927c?t=54)

![](https://loom.com/i/0d60aa6f59f943e58b8a4ceec32743b3?workflows_screenshot=true)

* Select the parts related to the issue.
* Provide a description of why the issue is being captured.
* Include the expected condition for clarity.

**Step 4: Assign and Route the Issue** [1:27](https://loom.com/share/5add1d772eb14fc5a413e8b771ab927c?t=87)

![](https://loom.com/i/9a0f4bdb8d4643449a245706312c16b0?workflows_screenshot=true)

* Assign the issue to the appropriate locations.
* Designate a user responsible for addressing the issue.

**Step 5: Fill Out Required Attributes** [1:45](https://loom.com/share/5add1d772eb14fc5a413e8b771ab927c?t=105)

![](https://loom.com/i/a583a02b64ad47a487ddc8966dc3f1c4?workflows_screenshot=true)

* If your organization has specific attributes that need to be filled out, complete them in this section.
* Review all information to ensure completeness for quick resolution.
* Double-check the assigned user and locations to ensure proper routing of the issue or take advantage of ION's automated routing systems in the ION Marketplace.

#### Tips for Efficiency

* Familiarize yourself with the keyboard shortcuts (Command-Shift-I)(Control-Shift-I) to quickly access the issue creation form.

#### Link to Loom

<https://loom.com/share/5add1d772eb14fc5a413e8b771ab927c>


# Contain Affected Inventory

Prevent quality escapes by quickly capturing all defects on one issue ticket.

### Overview

When a defect or anomaly is discovered, the first priority is containment—making sure potentially affected parts do not continue down the production line or reach customers. Quickly attaching inventory to an issue ticket allows teams to isolate all related parts, whether they share a lot, serial number, or another attribute. This immediate action reduces risk, prevents costly escapes, and ensures every affected unit is accounted for.

By grouping inventory to a single issue ticket, manufacturers also gain a clear foundation for root cause analysis, disposition, and compliance. Instead of manually tracking affected parts across multiple systems, teams have one structured place to document the issue, evaluate corrective actions, and ensure regulatory traceability. The result is faster response, fewer errors, and stronger overall quality control.

Associating inventory with an issue can also affect its status. Depending on the issue's disposition type and its **Availability Behavior**, inventory may stay available, become **Unavailable** until the issue is resolved, or become permanently unavailable. Inventory already in **Installed**, **Work In Progress (WIP)**, or **Scrapped** status is not changed by this rule. For configuration details, see [Disposition Types](/quality/disposition-types).

### How To

#### Key Steps

**1. Access the Inventory Screen** [0:00](https://loom.com/share/0ec507b8846e4d7fb212fb0713fb6547?t=0)

![](https://loom.com/i/056720c4e99f49b88048fd2cdd1f4abd?workflows_screenshot=true)

* Open the ION application.
* Navigate to the inventory screen via the side bar to begin the process of filtering and selecting parts.

**2. Filter Inventory by Shared Attributes** [0:55](https://loom.com/share/0ec507b8846e4d7fb212fb0713fb6547?t=55)

* Determine the shared attribute for the inventory you want to group (e.g., lot number, serial number).
* Use the filtering options to display only the relevant inventory items.

**3. Select Relevant Inventory Items** [1:08](https://loom.com/share/0ec507b8846e4d7fb212fb0713fb6547?t=68)

![](https://loom.com/i/9b51e0656d0e4b6f93a63a097fcbd05f?workflows_screenshot=true)

* Review the filtered inventory list.
* Select all items that share the common attribute (e.g., all items from lot two).

**4. Open the Command Menu** [2:11](https://loom.com/share/0ec507b8846e4d7fb212fb0713fb6547?t=131)

* Press Command + K (Mac), Ctrl + K (Windows) to open ION's command menu.

**5. Create an Issue Ticket** [2:22](https://loom.com/share/0ec507b8846e4d7fb212fb0713fb6547?t=142)

![](https://loom.com/i/5b0757ae97b84856b572b4534fc34a62?workflows_screenshot=true)

* In the command menu, select the option to create an issue.
* Enter a title for the issue (this is the only required field).
  * Example title: "Identified parts outside of run execution step."
* Click to create the issue.

**6. Review the Created Issue** [2:59](https://loom.com/share/0ec507b8846e4d7fb212fb0713fb6547?t=179)

![](https://loom.com/i/e2c8223615bc432583e5b805a12ba257?workflows_screenshot=true)

* After creating the issue, navigate to view it.
* Confirm that all selected parts are associated with the issue ticket.

#### Cautionary Notes

* Ensure that the filtering criteria accurately reflects the inventory you wish to group to avoid misclassification.
* Double-check the title of the issue for clarity and relevance to the identified parts.

#### Tips for Efficiency

* Familiarize yourself with the filtering options to quickly access relevant inventory.
* Use keyboard shortcuts (like Command + K) to streamline the process of creating issue tickets.

#### Link to Loom

<https://loom.com/share/0ec507b8846e4d7fb212fb0713fb6547>


# Split / Clone Issues

### Overview

When a large issue contains many parts, not all inventory needs to be treated the same way. Splitting inventory into detailed issue tickets allows teams to apply the right disposition to the right parts—for example, scrapping defective pieces while reworking others that can be repaired and returned to production. This flexibility ensures that inventory is not lumped into a one-size-fits-all decision, reducing unnecessary waste and enabling faster resolution.

The split workflow maintains full traceability by linking detailed tickets back to the original issue. Key fields, such as cause or condition, can be copied to ensure consistency, while each new ticket holds its own inventory assignments, quantities, and notes. This structured approach gives teams a clear, tabular view of related issues, helping them quickly navigate across hundreds of parts and resolve them with the appropriate teams. The result is better control, faster decision-making, and improved overall quality management.

### Procedure for Splitting Inventory Issues into Detailed Tickets

#### Key Steps

**1. Understanding the Need for Splitting Issues** [0:00](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=0)

![](https://loom.com/i/97f28377be8547ee9c1a83be006f92b2?workflows_screenshot=true)

* Identify when an issue contains multiple inventory items with varying conditions.
* Recognize the need to handle different items (e.g., scrap vs. rework) separately.

**2. Accessing the Issue Menu** [0:39](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=39)

<figure><img src="/files/wdtghxwGYj9lhrOvUEEm" alt="" width="563"><figcaption></figcaption></figure>

* Open the issue ticket that contains the inventory.
* Navigate to the menu to clone or split the issue.

**3. Creating Detailed Tickets** [1:03](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=63)

![](https://loom.com/i/be5b7c7360734d7b870f22a9200f14d9?workflows_screenshot=true)

* Use the left-to-right flow to add a new ticket for the specific inventory disposition.
* Specify the type of disposition (e.g., scrap, rework) for the new ticket.

**4. Adding Notes and Disposition Type** [1:36](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=96)

![](https://loom.com/i/9b6805942d494dffaa63163f2cef9996?workflows_screenshot=true)

* Include brief notes explaining the reason for the disposition.
* Select the appropriate disposition type from the options provided.
* Select what fields you want to copy over to the new issues from the Copy Settings menu.

**5. Selecting Inventory for the New Ticket** [2:00](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=120)

![](https://loom.com/i/db743313e3bc4194acc16029afbe751b?workflows_screenshot=true)

* Highlight the inventory items to be included in the new ticket by dragging or clicking.
* Use command-click to select multiple items if needed.

**6. Adjusting Inventory Quantities** [2:40](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=160)

![](https://loom.com/i/256ee242f7124dc28c72dbb55def88ac?workflows_screenshot=true)

* If using a lot tracker, adjust the quantity of inventory being assigned to the new ticket.

**7. Removing and Assigning Inventory** [3:05](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=185)

![](https://loom.com/i/567fb36c966f4fb883eeb867088e392e?workflows_screenshot=true)

* Click 'remove and assign' to transfer the selected inventory from the source ticket to the new ticket.

**8. Creating Additional Tickets as Needed** [3:37](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=217)

![](https://loom.com/i/fc06ade13acd4c76bd51f7174b429f14?workflows_screenshot=true)

* Repeat the process to create additional tickets for other dispositions (e.g., rework) as necessary.

**9. Verifying Inventory Changes** [4:41](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=281)

![](https://loom.com/i/e02f755e885c49189b6e5faaf63d136d?workflows_screenshot=true)

* Check the original issue to confirm that the inventory quantities have been updated accordingly.

**10. Reviewing Related Issues** [5:12](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=312)

![](https://loom.com/i/ca6851b5dff6421eb2add824ab5894b0?workflows_screenshot=true)

* Navigate to related issues for traceability and to view the status and details of each ticket.

**11. Copying Settings and Attributes** [5:34](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=334)

![](https://loom.com/i/e4bb6ec45f9c49e3a6a254262f928491?workflows_screenshot=true)

* View the data specified within the copy settings menu of the Split / Cline issues window is now copied over to the newly created detail issues.

**12. Final Review and Navigation** [6:03](https://loom.com/share/1a2feadfc5b44d86ac516572242f042c?t=363)

* Confirm that all changes are correctly reflected and that navigation between related issues is clear.

#### Link to Loom

<https://loom.com/share/1a2feadfc5b44d86ac516572242f042c>


# Disposition Types

Configure issue disposition types and control whether associated inventory stays available, becomes unavailable, or is permanently blocked.

### Overview

Disposition types define how inventory should be handled when it is associated with an issue. Each disposition type includes an **Availability Behavior** setting that determines whether the linked inventory remains available right away, becomes unavailable until the issue is resolved, or is made permanently unavailable.

This behavior lets quality teams match inventory control to the actual intent of the disposition. For example, a "Use As Is" disposition may leave inventory available immediately, while a "Rework" disposition may temporarily hold the inventory until the issue is resolved, and a "Scrap" disposition may keep it permanently unavailable.

### Availability Behavior

Each disposition type can be configured with one of these availability behaviors:

| Availability Behavior   | What Happens to Associated Inventory                                                                                            |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Available Immediately   | Inventory remains in its current available state after being associated with the issue.                                         |
| Release on Resolve      | Inventory is set to **Unavailable** while the issue is open, then can return to normal availability when the issue is resolved. |
| Permanently Unavailable | Inventory is set to **Unavailable** when associated with the issue and stays unavailable as part of the disposition outcome.    |

### Default Availability Behavior

Organizations can also set a default availability behavior from **Settings > Issues**. This default is used when creating or editing disposition types so teams have a consistent starting point.

<figure><img src="/files/lrRBLOAg0oBkx8bYdhka" alt=""><figcaption><p>Default availability behavior in Issue Settings.</p></figcaption></figure>

<figure><img src="/files/8CJx9UZdePDqjIcgbXnZ" alt=""><figcaption><p>Changing the org-level default availability behavior.</p></figcaption></figure>

### Status Exceptions

Availability behavior does not affect every inventory status. Inventory that is already in one of these statuses is not changed by issue association:

* **Installed**
* **Work In Progress (WIP)**
* **Scrapped**

These exceptions prevent issue workflows from overwriting statuses that already reflect a stronger lifecycle state.

### Configuring Disposition Types

Go to **Settings > Issues** to manage disposition types. Each row in the Disposition Types table includes:

* **Active** to control whether the disposition can be used
* **Title** for the user-facing name
* **Description** for internal guidance
* **Availability Behavior** to control inventory status changes for inventory associated with issues using that disposition

<figure><img src="/files/9U8wEDgHgtEoVS0dLXQd" alt=""><figcaption><p>Disposition Types settings, including the Availability Behavior column.</p></figcaption></figure>

<figure><img src="/files/H3A1oIKD6CHYzgc8MPwd" alt=""><figcaption><p>Editing a disposition type's availability behavior.</p></figcaption></figure>

### Common Disposition Types

The right behavior depends on how your team wants inventory to move through quality review. Typical examples:

| Disposition Type         | Recommended Availability Behavior | Why                                                                                   |
| ------------------------ | --------------------------------- | ------------------------------------------------------------------------------------- |
| Use As Is                | Available Immediately             | The issue is documented, but the inventory does not need to be held.                  |
| Rework to Print          | Release on Resolve                | The inventory should be held while rework is pending, then released after resolution. |
| Return to Vendor         | Permanently Unavailable           | The inventory should no longer be available for internal use.                         |
| Scrap                    | Permanently Unavailable           | The inventory should never return to available stock.                                 |
| Await Engineering Review | Release on Resolve                | The inventory should be held until a decision is made.                                |

### End-to-End Behavior

The full inventory flow works like this:

1. Inventory is associated with an issue.
2. The issue's disposition type determines the applicable **Availability Behavior**.
3. If the behavior is **Release on Resolve** or **Permanently Unavailable**, the inventory status changes to **Unavailable** unless it is already **Installed**, **WIP**, or **Scrapped**.
4. If the behavior is **Available Immediately**, the inventory remains available.
5. When the issue is resolved, inventory held under **Release on Resolve** can be released from **Unavailable** according to the issue outcome.
6. Inventory marked by **Permanently Unavailable** remains unavailable as part of the final disposition.

### Related Pages

For the workflow that links inventory to issues, see [Contain Affected Inventory](/quality/contain-affected-inventory). For the inventory lifecycle and status definitions, see [Inventory](/supply-chain/inventory).


# Intent Management

Deploy Intent/Pedigree/Tiers/Grades to the production floor

ION's Intent Management lets your organization track, enforce, and propagate intent designations across parts, inventory, purchases, procedures and runs. Examples of intent designations include flight vs. non-flight, production vs. prototype, or any graded quality level your team uses.

{% hint style="info" %}
Contact your Manufacturing Success Manager to enable this feature for your organization.
{% endhint %}

## What Problems Does Intent Management Solve?

Without intent enforcement, teams must rely on manual processes to ensure that only the right-grade parts end up in critical assemblies. ION's intent management automates these checks by:

* Validating that inventory meets intent requirements when it is kitted or installed.
* Propagating intent automatically from purchase orders, runs, and issues.
* Blocking or downgrading intent assignments that would violate your quality policies.
* Requiring that users set intent at key workflow steps (run creation, step start, etc.).

## Navigating to Intent Settings

1. Navigate to **Settings** from the user icon at the bottom of the sidebar.
2. Select **Intent** from the left sidebar.
3. From this page you can configure all settings described below.

## Setting Up Intent Options

Before enabling enforcement policies, define your organization's intent options (e.g., Flight, Dev ...), and put them in the correct order.

### How Intent Options work

* Each option has a label (for example, Flight, Production, Development).
* Each option also has a rank.
* Lower rank means higher/stricter quality (rank 0 is most strict).
* This ranking is what settings like `requireKitIntentMatch` and `requireInstallIntentMatch` compare.

### Aliasing Intent

For various reasons, an organization may refer to Intent by a different name. Common alternatives include pedigree, quality level, and tier — driven by regulatory requirements or internal conventions.

ION's intent management supports this flexibility through the Intent Alias organization setting, which lets you define what your organization calls Intent within ION. The configured alias is used as the label wherever Intent appears in the UI.

{% hint style="info" %}
Regardless of the configured alias, the API field remains `intentOption`.
{% endhint %}

### Recommended setup flow

1. List your quality tiers from most strict to least strict.
2. Create each intent option.
3. Order them so strictest is first (lowest rank).
4. Verify the hierarchy with your quality/manufacturing owners.
5. Enable the relevant policy settings described in this guide.

### Example hierarchy

| Rank | Value               |
| ---- | ------------------- |
| 1    | Flight              |
| 2    | Critical Non-Flight |
| 3    | Development         |

{% hint style="warning" %}
If this order is wrong, enforcement behavior will be wrong (for example, allowing lower-grade inventory where it should be blocked).
{% endhint %}

## Quick Reference

* [Run Controls](/quality/intent-management/run-controls) — intent enforcement during run creation, step execution, and inspection runs
* [Inventory Controls](/quality/intent-management/inventory-controls) — intent enforcement during procurement, kitting, issue resolution, and manual inventory creation
* [Install Controls](/quality/intent-management/install-controls) — intent enforcement when inventory is installed into assemblies
* [Part Intent/Quality](/quality/intent-management/part-intent-quality) — enforcement based on the part's own intent rating


# Run Controls

This page covers intent settings that apply during the run lifecycle — from creation through step execution to intent updates and inspection runs.

## Required at Run Create

Setting key: `requiredAtRunCreate`

### What it does

Required at Run Create forces users to specify an intent designation when creating a run. Without this setting, intent is optional at run creation.

This ensures that every run starts with a clear quality designation, which downstream settings like Run Intent Side Effect can then use to automatically stamp intent onto inventory.

You can apply this requirement to all runs or scope it to specific procedure types.

### When it runs

At run creation time — when a user submits the new run form.

### Configuration options

| Field            | Possible Values            | Description                                                                              |
| ---------------- | -------------------------- | ---------------------------------------------------------------------------------------- |
| `enabled`        | `true` / `false`           | Turns the check on or off. Default: `false`                                              |
| `procedureTypes` | Procedure type identifiers | Limits enforcement to the listed procedure types. Leave empty to apply to all run types. |

### Notes

When `procedureTypes` contains specific values, only runs of those procedure types require intent. All other run types remain optional.

### Example scenario

Your organization only requires intent on Build procedure types. Set `enabled: true` and `procedureTypes: ["build"]`. Users creating a Build run must select an intent. A user creating an Inspection run will not be required to select an intent.

***

## Required at Run Step Start

Setting key: `requiredAtRunStepStart`

### What it does

Required at Run Step Start prevents a technician from starting a run step unless the run has an intent designation set. If the run's intent field is empty, the step start action is blocked until intent is assigned.

This setting is useful when intent might not be required at run creation but must be confirmed before any active work begins. It serves as a second enforcement point — catching cases where a run slipped through creation without intent.

### When it runs

When a user attempts to start a run step — the check occurs at the moment the step start action is triggered.

### Configuration options

| Field            | Possible Values            | Description                                                                              |
| ---------------- | -------------------------- | ---------------------------------------------------------------------------------------- |
| `enabled`        | `true` / `false`           | Turns the check on or off. Default: `false`                                              |
| `procedureTypes` | Procedure type identifiers | Limits enforcement to the listed procedure types. Leave empty to apply to all run types. |

### Notes

This setting can be used in combination with `requiredAtRunCreate` for layered enforcement, or independently as a fallback check.

### Example scenario

Your organization creates runs from work orders that may be auto-generated, so intent is not always set at creation. You still want to ensure intent is confirmed before a technician begins working. Enable `requiredAtRunStepStart` so that when a technician tries to start Step 1 of a run, ION checks for intent. If it is missing, the technician sees a prompt to set it before proceeding.

***

## Required on Run Intent Update

Setting key: `requiredOnRunIntentUpdate`

### What it does

Required on Run Intent Update prevents users from clearing or unsetting the intent on a run after it has been set. Once intent is assigned to a run, it cannot be removed — it can only be changed to a different intent value.

This ensures that runs always carry a valid intent designation once one has been applied. Without this setting, a user could inadvertently (or intentionally) remove intent from a run mid-execution, losing the quality designation for that work order.

### When it runs

When a user updates the intent field on a run — the check fires at the point of saving the update.

### Configuration options

| Field            | Possible Values            | Description                                                                              |
| ---------------- | -------------------------- | ---------------------------------------------------------------------------------------- |
| `enabled`        | `true` / `false`           | Turns the check on or off. Default: `false`                                              |
| `procedureTypes` | Procedure type identifiers | Limits enforcement to the listed procedure types. Leave empty to apply to all run types. |

### Notes

This setting only blocks clearing intent. Changing from one intent value to another is still permitted.

When `procedureTypes` is empty and `enabled` is true, the restriction applies to all runs.

### Example scenario

A Flight-grade run is in progress. A user accidentally attempts to clear the intent designation while editing the run details. With `requiredOnRunIntentUpdate` enabled, the update is rejected and the run retains its Flight designation. The user can change it to a different intent (e.g., Qualification) but cannot leave it blank.

***

## Run Intent Side Effect

Setting key: `runIntentSideEffect`

### What it does

Run Intent Side Effect automatically propagates the run's intent designation to the run's inventory — the inventory record that represents the unit being built by the run.

When a run has intent set, this setting ensures the assembly inventory it produces carries that same intent, without requiring a separate manual update.

### When it runs

When intent is updated on a run — the run's assembly inventory is updated to match.

### Configuration options

| Field                          | Possible Values  | Description                                                                                                                            |
| ------------------------------ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`                      | `true` / `false` | Turns the check on or off. Default: `false`                                                                                            |
| `downgradeInventoryOnMismatch` | `true` / `false` | When the run's intent is lower quality than the assembly inventory's intent, downgrade the inventory to match the run. Default: `true` |

### Mismatch behavior

| Situation                                          | Behavior                                                                                                                    |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Assembly inventory has no intent                   | Run intent is copied to the inventory.                                                                                      |
| Run intent is higher quality than inventory intent | Blocked — an error is raised. You cannot assign a higher-quality intent to the run than the assembly inventory already has. |
| Run intent is lower quality than inventory intent  | Controlled by `downgradeInventoryOnMismatch` (see below).                                                                   |

`downgradeInventoryOnMismatch` behavior (applies only when run intent is lower quality than inventory intent)

| Value   | Behavior                                                                    |
| ------- | --------------------------------------------------------------------------- |
| `true`  | The assembly inventory is downgraded to match the run's lower intent.       |
| `false` | The assembly inventory intent is left unchanged. No side effect is applied. |

### Example scenarios

**Scenario 1 — Run creates new assembly inventory**

A Development run is created to build a prototype unit. At run creation, ION creates a new assembly inventory record for that unit with no intent set. With `runIntentSideEffect` enabled, the new inventory is immediately stamped with Development intent. No manual step is needed.

**Scenario 2 — Existing Flight-grade inventory is assigned to a Development run**

A Development run is started, but the assembly inventory associated with the run was previously designated Flight. The run's intent is lower quality than the inventory's intent, so the block does not apply. Instead, `downgradeInventoryOnMismatch` controls the outcome:

* With `downgradeInventoryOnMismatch: true`: the assembly inventory is downgraded from Flight to Development to match the run.
* With `downgradeInventoryOnMismatch: false`: the assembly inventory retains its Flight designation. No side effect is applied.

**Scenario 3 — Blocked attempting to set run intent above inventory intent**

A Development assembly inventory is on the run and a user attempts to set the run's intent to Flight. Because Flight is a higher quality tier than Development, this is blocked with a validation error. The run's intent cannot exceed the quality of its assembly inventory.

***

## Is Inspection Run Required

Setting key: `intentOption.isInspectionRunRequired`

### What it does

When a part is added to a receipt, ION automatically creates inspection runs for any inspection procedures associated with that part.

This setting controls whether those inspection runs are required for a given intent option.

When inventory is added to a receipt, ION checks the inventory's intent:

* If the inventory has no intent set, inspection runs are created.
* If the inventory's intent has `isInspectionRunRequired: true`, inspection runs are created.
* If the inventory's intent has `isInspectionRunRequired: false`, inspection runs are not created.

Unlike the other intent settings in this section, this one is configured per intent option rather than globally. That allows you to require inspection runs for some intents while skipping them for others.

### Notes

This setting applies at the intent option level, not at the run level.

If inventory has no intent assigned, inspection runs are still created by default.

This setting only affects whether inspection runs are automatically created during receipt. It does not prevent users from creating inspection runs manually later if needed.

### Example scenarios

**Scenario 1 — Flight inventory requires inspection**

A receipt includes an ASME pressure fitting, which has an associated inspection part procedure. The received inventory is assigned the Flight intent, and that intent option has `isInspectionRunRequired: true`.

When the PO line is added to the receipt, ION automatically creates the inspection run.

**Scenario 2 — Development inventory does not require inspection**

A receipt includes ASME pressure fitting PN, which has the same associated inspection part procedure. The received inventory is assigned the Development intent, and that intent option has `isInspectionRunRequired: false`.

When the PO line is added to the receipt, ION does not automatically create an inspection run.


# Inventory Controls

This page covers intent settings that apply during an inventory's lifecycle - from purchasing, to kitting and issues.

## PO Line Side Effect

Setting key: `poLineSideEffect`

### What it does

PO Line Side Effect assigns intent to any on order inventory linked to a PO line when intent is set on that line. Designating intent at the procurement stage ensures that inventory is correctly classified without requiring manual updates later.

### When it runs

When intent is assigned to a PO line - existing on order inventory linked to that line receives the intent at that moment.

When inventory is created from a PO line - inventory is created when adding a quantity to a PO line. If intent has already been set on the PO line at this time, it will also be set on the newly created inventory.

If the PO line has no intent set, no side effect occurs and linked inventory is unaffected.

Note: If Part Quality Check is enabled, it also runs at this point. A PO line intent that exceeds the part's rating will be blocked or downgraded before the line is saved.

### Configuration options

| Field     | Possible Values  | Description                                 |
| --------- | ---------------- | ------------------------------------------- |
| `enabled` | `true` / `false` | Turns the check on or off. Default: `false` |

### Example scenario

Your procurement team sets Flight intent on a PO line for Flight-grade fasteners. All inventory linked to that line is automatically stamped with Flight intent at that moment — no manual update required.

A separate PO line on the same order for development spares has Development intent set — linked inventory for that line is updated to Development intent.

***

## Kit Intent Match

Setting key: `requireKitIntentMatch`

### What it does

Kit Intent Match enforces that inventory being added to a kit meets the intent requirement of the assembly inventory on the run associated with that kit. It also enforces this check at kit delivery time. If the inventory's intent does not meet the required threshold, the action is blocked with an error.

This prevents lower-grade inventory from being kitted for higher-grade assemblies — for example, stopping a development-grade component from being kitted into a flight-grade assembly.

### When it runs

On adding a kit item - when a piece of inventory is added to a kit.

On kit delivery - when the kit is delivered and associated with an assembly.

### Configuration options

| Field     | Possible Values         | Description                                 |
| --------- | ----------------------- | ------------------------------------------- |
| `enabled` | `true` / `false`        | Turns the check on or off. Default: `false` |
| `mode`    | `hierarchical`, `exact` | How the intent comparison is evaluated      |

### Mode values

| Mode           | Behavior                                                                                                                                                             |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hierarchical` | The inventory's intent must be **equal or higher rank** than the assembly's intent. Lower-grade inventory is blocked from installation into higher-grade assemblies. |
| `exact`        | The inventory's intent must **exactly match** the assembly's intent. Only exact-match intent is accepted.                                                            |

### Example scenario

Your assembly is designated Flight. With `mode: hierarchical`, any inventory with a Flight or higher intent can be kitted in. Inventory designated Development is blocked. With `mode: exact`, only Flight-designated inventory is accepted — even a higher-grade designation would be rejected.

***

## Upgrade/Downgrade With Issues

Setting key: `issueIntentUpdate`

### What it does

Issue Intent Update automatically updates the intent of inventory when an issue is resolved against it. The new intent is determined by a mapping configured in your issue dispositions — each disposition type can specify what intent value the affected inventory should receive.

This allows quality events (nonconformances, deviations, dispositions) to directly affect the quality designation of the inventory involved, without requiring a separate manual update.

### When it runs

When an issue is resolved — the intent update is applied to each of the issue's inventory.

The intent change is driven by your disposition-to-intent mapping. If a disposition has no intent configured, no change is made to the inventory's intent.

### Configuration options

| Field     | Possible Values  | Description                                 |
| --------- | ---------------- | ------------------------------------------- |
| `enabled` | `true` / `false` | Turns the check on or off. Default: `false` |

Note: The specific disposition-to-intent mappings are configured on each disposition type, not within this setting. This setting acts as the global on/off switch.

### Example scenario

Your organization has a "Downgrade to Dev" disposition type mapped to Development intent. A Flight-grade connector has a nonconformance raised against it for a cosmetic scratch. The quality team reviews it and determines it is still functional, but not to Flight standard. They disposition the issue as Downgrade to Dev. ION automatically downgrades the connector's intent to Development - it remains available in inventory and can still be used in Development builds, but is blocked from being kitted or installed into Flight assemblies.

***

## Manually Created Inventory

Setting key: `requiredAtManualInventoryCreate`

### What it does

When manually creating inventory this setting ensures an intent is set on the inventory. This prevents inventory from entering ION without an intent assigned.

When enabled, this setting requires users to select an intent when manually creating inventory. This helps ensure that manually created inventory is classified from the start, rather than entering the system with no quality designation.

### Configuration options

| Field     | Possible Values  | Description                                 |
| --------- | ---------------- | ------------------------------------------- |
| `enabled` | `true` / `false` | Turns the check on or off. Default: `false` |

### Example scenario

An inventory specialist manually creates inventory for a titanium bracket and tries to save it without assigning an intent. With `requiredAtManualInventoryCreate` enabled, ION prevents the inventory from being created until an intent is selected.


# Install Controls

This page covers intent enforcement settings that apply when inventory is installed into an assembly.

## Install Intent Match

Setting key: `requireInstallIntentMatch`

### What it does

Install Intent Match enforces that inventory meets the intent requirement of the parent assembly when it is installed to the aBOM. If the installed inventory's intent does not meet the parent's intent, the installation is blocked with an error.

### When it runs

On aBOM install - when inventory is installed into an assembly via the as-built BOM.

### Configuration options

| Field     | Possible Values         | Description                                 |
| --------- | ----------------------- | ------------------------------------------- |
| `enabled` | `true` / `false`        | Turns the check on or off. Default: `false` |
| `mode`    | `hierarchical`, `exact` | How the intent comparison is evaluated.     |

### Mode values

| Mode           | Behavior                                                                                                                                                             |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hierarchical` | The inventory's intent must be **equal or higher rank** than the assembly's intent. Lower-grade inventory is blocked from installation into higher-grade assemblies. |
| `exact`        | The inventory's intent must **exactly match** the assembly's intent. Only exact-match intent is accepted.                                                            |

### Example scenario

A technician attempts to install a Development-grade sensor into a Flight-grade assembly during a run. With `requireInstallIntentMatch` enabled and `mode: hierarchical`, the installation is blocked and the technician sees an error. They must either source a Flight-grade sensor or reclassify the inventory before proceeding.

***

## Downgrade on Install

Setting key: `downgradeOnInstall`

### What it does

Downgrade on Install automatically lowers the intent of inventory to match the parent assembly's intent when the inventory is installed. For Made on Assembly (MOA) installs, the child's intent is synced to the parent assembly's intent.

This setting reflects the principle that an installed component takes on the quality level of what it becomes part of. A Flight-grade component installed into a Development assembly effectively becomes a Development component, because the resulting assembly is Development.

### When it runs

At the moment of aBOM installation - when inventory is installed into an assembly.

The downgrade happens only when the assembly's intent is lower than the inventory's current intent. If the assembly's intent is equal or higher, no change is made. It is recommended to enable this setting in combination with Install Intent Match above.

### Configuration options

| Field     | Possible Values  | Description                                 |
| --------- | ---------------- | ------------------------------------------- |
| `enabled` | `true` / `false` | Turns the check on or off. Default: `false` |

### Example scenario

A Flight-grade actuator is in stock. A technician installs it into a Development assembly. With `downgradeOnInstall` enabled, the actuator's intent is automatically changed to Development at the moment of installation — because it is now part of a Development assembly and can no longer be treated as Flight-grade inventory.

If the technician instead installed the same actuator into a Flight-grade assembly, no downgrade would occur.


# Part Intent/Quality

This page covers intent settings that apply based on a part's intent rating — enforcing that inventory intent stays within the bounds of what the underlying part supports.

## Part Quality Check

Setting key: `partQualityCheck`

### What it does

Part Quality Check enforces that the intent assigned to a piece of inventory does not exceed the intent rating of the part itself. Each part in your catalog can have a maximum intent designation (e.g., a part rated only for Development use). This setting prevents assigning a higher-grade intent to inventory than the part is rated for.

Depending on the configured mode, violations either block the assignment entirely or silently downgrade the intent to the part's own rating.

### When it runs

Any time intent is assigned to a piece of inventory — including manual assignment, receipt from a PO line, run side effects, and issue resolution.

### Configuration options

| Field     | Possible Values      | Description                                                             |
| --------- | -------------------- | ----------------------------------------------------------------------- |
| `enabled` | `true` / `false`     | Turns the check on or off. Default: `false`                             |
| `mode`    | `block`, `downgrade` | What happens when the inventory's intent would exceed the part's rating |

### Mode values

| Mode        | Behavior                                                                                                                                            |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `block`     | Raises an error and **prevents the intent assignment**. The user must either select a lower intent value or use a different part.                   |
| `downgrade` | Silently **uses the part's own intent rating** instead of the requested value. No error is shown; the system applies the lower value automatically. |

### Example scenario — Direct Assignment

A part is rated for Development use only. A user attempts to assign Flight intent to a piece of inventory of that part.

* With `mode: block`: the assignment fails with an error explaining that the part's maximum intent is Development.
* With `mode: downgrade`: the assignment succeeds, but the inventory is recorded as Development intent rather than Flight — matching the part's own rating.

### Example scenario — Purchase Order Line

A buyer is creating a PO line for a part that is rated only for Development use, and attempts to set Flight intent on the line. Part Quality Check intercepts the assignment at that point:

* With `mode: block`: saving the PO line fails with an error. The buyer must either select a Development (or lower) intent on the line, or switch to a Flight-rated part number.
* With `mode: downgrade`: the PO line is saved, but with Development intent rather than the requested Flight intent — the part's rating takes precedence silently.


# Attachments

<figure><img src="/files/A9s1f1aZfwVorunPNagU" alt=""><figcaption></figcaption></figure>

Attachments has it's own section on most pages allowing users to upload attachments to the object itself or to a specific attribute if configured correctly. To upload, select which attribute you want to upload and click to upload or drag and drop files there.

* Object level attachments: Some modules have the ability to store as many attributes as needed at the object level. Examples of this include purchase orders, parts, steps, issues, etc.
* Attribute level attachments: Organizations can also configure specific attributes that can be uploaded to. These are configured in the organization settings and can only store one attribute at a time.

If object level attachments exists, ION will default to uploading there unless an attribute is selected as seen below.

<figure><img src="/files/Zs0djoZemKrtUuEiHWgI" alt=""><figcaption></figcaption></figure>


# Data Snapshots

Create a full snapshot of your organization's data and attachments from ION for backup, compliance, or analytics purposes.

### Overview

Data snapshots let you create a complete copy of your organization's data from ION. Snapshots are useful for backups, compliance requirements, data warehousing, or feeding external analytics tools. By default, a snapshot includes both:

* **Tables** -- All of your organization's structured data (parts, inventory, BOMs, runs, issues, etc.).
* **Attachments** -- All documents, images, and other files uploaded across ION, including those attached to runs, procedures, issues, and more.

If needed, you can choose to snapshot only tables or only attachments.

### How Data Snapshots Work

Data snapshots run automatically on a scheduled cadence configured for your organization. To get started, reach out to your account team to set up your snapshot schedule and delivery destination.

Once a snapshot completes, you can download the resulting files from the **data snapshots page**. You can also track the status of all snapshots from the snapshot history table.

{% hint style="warning" %}
The data snapshots page is only accessible to organization admins for security purposes. All snapshot data is encrypted at rest and in transit using TLS.
{% endhint %}

***

## What You Receive

Snapshots are delivered as `.tar` archives. A tables snapshot contains one compressed file per table (`.csv.gz` or `.jsonl.gz`), and an attachments snapshot contains all uploaded files.

For large snapshots, ION automatically splits the output into multiple `.tar` files labeled with a part number (e.g., `snapshot_tables_part1_2026-03-31-143022.tar`, `snapshot_tables_part2_2026-03-31-143022.tar`).

***

## Delivery Destinations

By default, snapshots are stored in ION and made available for download through the UI. Snapshots stored in ION are retained for **30 days**, after which they are automatically deleted.

{% hint style="success" %}
**Recommended:** Set up [Customer S3 Delivery](/platform/data-snapshots/customer-s3-delivery-setup) to have snapshots delivered directly to your own AWS S3 bucket. This gives you full ownership of the snapshot files, the ability to apply your own retention and access policies, and seamless integration with your existing data infrastructure.
{% endhint %}

***

## Scheduling

Snapshots can be scheduled to run weekly or monthly. Your account team will configure the cadence during onboarding.

***

## Onboarding

To get started with data snapshots:

1. **Contact your account team** -- Let us know you'd like to set up data snapshots and whether you need tables, attachments, or both.
2. **Choose a delivery destination** -- Snapshots can be downloaded from ION directly, or delivered to your own S3 bucket (recommended).
3. **Set up customer-managed S3 delivery** (if applicable) -- Follow the [Customer S3 Delivery Setup](/platform/data-snapshots/customer-s3-delivery-setup) guide to create your bucket, configure an IAM role, and share your configuration with us for validation.
4. **Go live** -- Once configured, snapshots run on your chosen schedule and are delivered automatically.

***

## Snapshot History

The data snapshots page shows the status of all snapshots for your organization:

| Status      | Description                                                                      |
| ----------- | -------------------------------------------------------------------------------- |
| Pending     | The snapshot is waiting to be processed.                                         |
| In Progress | The snapshot is currently running.                                               |
| Completed   | The snapshot finished successfully and files are available for download.         |
| Failed      | The snapshot encountered an error. Check the error details for more information. |

<figure><img src="/files/mZxVd96g8mVa1uyuBeiP" alt=""><figcaption><p>Data snapshots page with the download panel for a completed snapshot.</p></figcaption></figure>


# Customer S3 Delivery Setup

Set up an S3 bucket in your AWS account to receive automated data snapshots from ION.

### Overview

This guide walks you through setting up an S3 bucket in your AWS account to receive automated data snapshots from ION. Once configured, snapshots are delivered directly to your bucket as `.tar` archives.

### What You Need

* An S3 bucket in your AWS account
* An IAM role that First Resonance assumes to write to your bucket
* An external ID (provided by First Resonance) for secure role assumption

Once configured, snapshots are delivered to:

```
s3://<your-bucket>/<tenant-schema>/<job-id>/
```

***

### Step 1: Create an S3 Bucket

Create a bucket in your preferred AWS region, either through the AWS console or using the CLI:

```bash
aws s3 mb s3://<your-bucket> --region <your-region>
```

We recommend enabling:

* **Versioning** -- protects against accidental overwrites.
* **Server-side encryption** (SSE-S3 or SSE-KMS) -- encrypts data at rest.

***

### Step 2: Create an IAM Role

Create an IAM role that First Resonance will assume to deliver snapshots to your bucket.

#### Trust Policy

The trust policy allows First Resonance to assume the role using an external ID. Replace `<fr-account-id>` with the First Resonance AWS account ID for your environment (provided by your account team), and `<external-id>` with the external ID we provide.

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<fr-account-id>:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "<external-id>"
        }
      }
    }
  ]
}
```

The external ID prevents the [confused deputy problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) and ensures only First Resonance can assume this role.

#### Permission Policy

Attach the following policy to the role. Replace `<your-bucket>` with your bucket name.

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SnapshotDeliveryBucketAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:AbortMultipartUpload",
        "s3:ListBucketMultipartUploads",
        "s3:ListMultipartUploadParts",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::<your-bucket>",
        "arn:aws:s3:::<your-bucket>/*"
      ]
    }
  ]
}
```

{% hint style="info" %}
`s3:PutObject` handles the core upload. The additional permissions allow First Resonance to clean up incomplete uploads and list bucket contents for verification.
{% endhint %}

***

### Step 3: Send Your Configuration

Provide the following details to your account team:

| Field         | Description                                     |
| ------------- | ----------------------------------------------- |
| Bucket name   | Your S3 bucket name.                            |
| Bucket region | The AWS region where your bucket is located.    |
| Role ARN      | The full ARN of the IAM role created in Step 2. |

First Resonance will provide the external ID and configure your snapshot schedule.

***

### Step 4: Validation

After we receive your configuration, our system validates access by:

1. Assuming the IAM role with the external ID.
2. Verifying the bucket exists and is accessible.
3. Writing and deleting a small test object.

If validation fails, we will reach out with the specific error so you can adjust permissions.

***

### What Gets Delivered

Each snapshot creates files under your bucket with this structure:

```
s3://<your-bucket>/
  └── <tenant-schema>/
      └── <job-id>/
          ├── snapshot_tables_<job-id>.tar
          └── snapshot_attachments_<job-id>.tar
```

For large snapshots that are split into multiple files, each file includes a part number (e.g., `snapshot_tables_part1_<job-id>.tar`, `snapshot_tables_part2_<job-id>.tar`).

* **snapshot\_tables** -- all database tables as compressed CSV files, bundled into a tar archive.
* **snapshot\_attachments** -- file attachments bundled into a tar archive.

***

### Troubleshooting

| Issue                                        | Cause                                                   | Fix                                                                                              |
| -------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Role assumption fails (AccessDenied)         | Trust policy does not allow the First Resonance account | Verify the `Principal` in the trust policy matches the account ID provided by your account team. |
| Role assumption fails with correct principal | External ID mismatch                                    | Verify the `sts:ExternalId` condition matches the value provided by First Resonance.             |
| Access denied to bucket                      | Missing or incorrect permission policy                  | Verify the permission policy is attached to the role and the bucket name matches.                |
| Test write fails (AccessDenied)              | Role lacks `s3:PutObject` permission                    | Check the permission policy includes `PutObject` on the bucket resource.                         |
| Bucket does not exist                        | Wrong bucket name or region                             | Verify the bucket name and that it exists in the expected region.                                |

***

### Security Notes

* First Resonance uses **STS AssumeRole** with short-lived credentials that are automatically refreshed during long-running snapshots. No credentials are stored.
* The **external ID** ensures only First Resonance can assume the role.
* First Resonance only writes to your tenant's prefix and does not read or modify other data in your bucket.
* All data is transmitted over HTTPS (TLS).

***

### Related Pages

For an overview of data snapshots, see [Data Snapshots](/platform/data-snapshots).


# Importers


# MBOM Imports


# Location Imports


