# Inventory Control Examples

#### 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://manual-v2.firstresonance.io/os/ion-actions/inventory-control-examples.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
