# Organizing with Account Sets

In this tutorial, we'll explore how to use account sets to organize your chart of accounts.


Source: https://www.twisp.com/docs/tutorials/organizing-with-account-sets

With the structure provided by account sets, you can enhance your ledger with custom materialized balances and organize accounts into groups based on their purpose or function.

> **Task:**
>
> - Create new sets with the `createAccountSet` mutation
> - Add members to a set with the `addToAccountSet` mutation
> - Get set data and its members with the `accountSet` query
> - Update fields on a set with the `updateAccountSet` mutation
> - Delete a set with the `deleteAccountSet` mutation

---

## Prerequisites

Before beginning this tutorial, you should have a basic understanding of Twisp's ledger system and how transactions, accounts, and entries work. Review the [Accounting Core](/docs/accounting-core) docs for more context.

If you'd like to follow along with the steps in this tutorial, you should have added accounts to your ledger. See the tutorial on [Setting Up Accounts](/docs/tutorials/setting-up-accounts).

## Getting started

The easiest way to interact with the Twisp GraphQL API is to login to the **Twisp Console** and use the **GraphiQL** tool.

If you prefer to use your own GraphQL client, you can send authenticated requests to the Twisp API endpoint.

To seed your setup with some example accounts, sets, and tran codes, you can use the [Example Setup](/docs/tutorials/example-setup).

## Create an account set

To create a new [AccountSet](/docs/reference/graphql/types/object#account-set), we'll use the `createAccountSet` mutation. This mutation takes several arguments:

- `accountSetId`: A unique identifier for the account set.
- `journalId`: The ID of the journal to which the account set belongs.
- `name`: The name of the account set.
- `description`: A description of the account set.
- `normalBalanceType`: The normal balance to use for rolling up balances for this account set (either `DEBIT` or `CREDIT`).

Let's create an account set to hold customer's accounts. We'll call it `"Customers"` and set the `normalBalanceType` to `CREDIT`:

**Request**

```graphql
mutation CreateAccountSet($accountSetCustomersId: UUID!, $journalGLId: UUID!) {
  createAccountSet(
    input: {
      accountSetId: $accountSetCustomersId
      journalId: $journalGLId
      name: "Customers"
      description: "All customer wallets."
      normalBalanceType: DEBIT
    }
  ) {
    accountSetId
    name
    description
    code
  }
}
```
**Response**

```json
{
  "data": {
    "createAccountSet": {
      "accountSetId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8",
      "name": "Customers",
      "description": "All customer wallets.",
      "code": "Ke8_GJexQNmYUifxYHtsqIIstZ_OUUg3g5Eq87el_FE"
    }
  }
}
```
**Variables**

```json
{
  "journalGLId": "822cb59f-ce51-4837-8391-2af3b7a5fc51",
  "accountSetCustomersId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8"
}
```

This operation will add a new account set to the ledger. Note the `DEBIT` balance type indicates that this account set is of the type that has a debit normal balance, which means that debits increase the balance and credits decrease the balance.

## Add set members

To add an account to an account set, use the mutation `addToAccountSet`. The mutation takes two arguments:

- `id`: Unique identifier for the account set to which the member will be added.
- `member`: An `AccountSetMemberInput` object containing the unique identifier of the account or account set to be added as a member, as well as the type of member (`ACCOUNT` or `ACCOUNT_SET`).

**Request**

```graphql
mutation AddToAccountSet(
  $accountSetCustomersId: UUID!
  $accountCustomerAliciaId: UUID!
) {
  addToAccountSet(
    id: $accountSetCustomersId
    member: { memberId: $accountCustomerAliciaId, memberType: ACCOUNT }
  ) {
    accountSetId
    members(first: 10) {
      nodes {
        ... on Account {
          accountId
          name
          code
        }
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "addToAccountSet": {
      "accountSetId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8",
      "members": {
        "nodes": [
          {
            "accountId": "260fd651-8819-4f99-9c8a-87d27e03ee4c",
            "name": "Alicia",
            "code": "CUST.Alicia"
          }
        ]
      }
    }
  }
}
```
**Variables**

```json
{
  "accountSetCustomersId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8",
  "accountCustomerAliciaId": "260fd651-8819-4f99-9c8a-87d27e03ee4c"
}
```

The `addToAccountSet` field returns the updated account set, including its ID and the list of members. In this case, the list of members is limited to the first 10 nodes, and only the `accountId`, `name`, and `code` fields are included in the response.

> **Task:**
>
> Try creating another account for a customer named "Bobby", then add their account to the "Customers" account set.

## Nest account sets within other sets

One powerful feature of [AccountSets](/docs/reference/graphql/types/object#account-set) is that they can be nested within other sets. This allows us to create more complex structures for our chart of accounts.

To nest one AccountSet within another, it's as simple as use the same `addToAccountSet` mutation, but with a `memberType` of `ACCOUNT_SET`. For example:

```graphql
mutation AddToAccountSetNested(
  addToAccountSet(
    id: "<ID for parent account set>"
    member: { memberId: "<ID of child account set", memberType: ACCOUNT_SET }
  ) {
    accountSetId
    members(first: 10) {
      nodes {
        __typename
        ... on AccountSet {
          accountSetId
          name
        }
      }
    }
  }
}
```

> **Note:**
>
> A sub-set can only be nested (or later re-nested) while it has never been populated — that is, while it is empty and has never contained a member. Once a set has ever held a member, it is structurally frozen and cannot be attached to or detached from a parent. To restructure a hierarchy that is already in use, create a new set, move the members into it, then soft-delete the old set.

By adding nested sets, you can create tree-like structures. Can you recreate this tree using the commands you've learned so far?

```mermaid
graph BT
  cust[/Customers\]
  inac[/Inactive customers\]
  alicia[Alicia]
  bobby[Bobby]
  cal[Cal]

  alicia & bobby & inac --> cust
  cal --> inac
```

## Query members of an account set

To query the members, we'll use the `accountSet` query and request the `members` field of the "Customers" set created earlier.

**Request**

```graphql
query GetAccountSet {
  accountSet(id: "29ef3f18-97b1-40d9-9852-27f1607b6ca8") {
    accountSetId
    name
    description
    members(first: 10) {
      nodes {
        ... on Account {
          accountId
          code
          name
        }
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "accountSet": {
      "accountSetId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8",
      "name": "Customers",
      "description": "All customer wallets.",
      "members": {
        "nodes": [
          {
            "accountId": "ae9d36cb-dcf5-41a9-bc1e-99a1cf56ef5b",
            "code": "CUST.Bobby",
            "name": "Bobby"
          },
          {
            "accountId": "260fd651-8819-4f99-9c8a-87d27e03ee4c",
            "code": "CUST.Alicia",
            "name": "Alicia"
          }
        ]
      }
    }
  }
}
```

Note that the `members` field returns a paginated response. Because account sets can contain accounts _or_ other account sets, we can use an [inline fragment](https://graphql.org/learn/queries/#inline-fragments) to specify which fields are to be returned depending on the type.

The "Customers" set only contains accounts at this point, so no fields for account sets need to be specified.

> **Note:**
>
> If you are unfamiliar with union types in GraphQL, you can find a good summary on the official docs: [https://graphql.org/learn/schema/#union-types](https://graphql.org/learn/schema/#union-types).

## Update fields on an account set

The `updateAccountSet` mutation is used to update fields of an existing account set (name, description, metadata, etc.).

It takes as input the `id` of the account set to be updated and an `input` object containing the fields to update.

**Request**

```graphql
mutation UpdateAccountSet($accountSetCustomersId: UUID!) {
  updateAccountSet(
    id: $accountSetCustomersId
    input: { name: "Customer Wallets", code: "CUSTOMERS.WALLETS" }
  ) {
    accountSetId
    name
    code
    history(first: 2) {
      nodes {
        version
        name
        code
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "updateAccountSet": {
      "accountSetId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8",
      "name": "Customer Wallets",
      "code": "CUSTOMERS.WALLETS",
      "history": {
        "nodes": [
          {
            "version": 3,
            "name": "Customer Wallets",
            "code": "CUSTOMERS.WALLETS"
          },
          {
            "version": 2,
            "name": "Customers",
            "code": "Ke8_GJexQNmYUifxYHtsqIIstZ_OUUg3g5Eq87el_FE"
          }
        ]
      }
    }
  }
}
```
**Variables**

```json
{
  "accountSetCustomersId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8"
}
```

This mutation can be useful when there is a need to update the name of an existing account set due to changes in an organization's structure or operations. The response from the mutation can be used to verify that the update was successful and to track changes to the account set over time.

## Delete an account set

The `deleteAccountSet` mutation performs a mark-only soft delete of an existing account set. It takes as input the `id` of the account set to be deleted. Rather than removing anything, it marks the set deleted; the set must be empty first (remove its members before deleting), and the delete does not remove members or alter the membership graph. There is no un-delete.

**Request**

```graphql
mutation DeleteAccountSet($accountSetCustomersId: UUID!) {
  deleteAccountSet(id: $accountSetCustomersId) {
    accountSetId
  }
}
```
**Response**

```json
{
  "data": {
    "deleteAccountSet": {
      "accountSetId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8"
    }
  }
}
```
**Variables**

```json
{
  "accountSetCustomersId": "29ef3f18-97b1-40d9-9852-27f1607b6ca8"
}
```

This mutation can be useful when an account set is no longer needed or was created in error. If the set still has members, empty it first, then delete it.

## Conclusion

In this tutorial, we've explored how to use [AccountSets](/docs/reference/graphql/types/object#account-set) to organize accounts.

We've covered how to create an account set, add members to it, nest sets within other sets, query set members, update fields of a set, and delete a set.

By using account sets to organize your chart of accounts, you can create more flexible and powerful structures that better fit the needs of your business or organization.
