# Order chain (send message) · Event-driven multi-chain dapps with ICMF · Learn Chromia

> The order chain holds the purchase logic, much like a typical e-commerce checkout. Once an order completes, the chain automatically sends a message about it…

Source: https://chromia.com/learn/icmf-course/order-chain/

Event-driven multi-chain dapps with ICMFLesson 4 of 7

1. [01Event-driven multi-chain dapps with ICMF](https://chromia.com/learn/icmf-course/introduction/)
2. [02Set up your project](https://chromia.com/learn/icmf-course/setup/)
3. [03Define messages](https://chromia.com/learn/icmf-course/defining-messages/)
4. [04Order chain (send message)](https://chromia.com/learn/icmf-course/order-chain/)
5. [05Delivery chain (receive message)](https://chromia.com/learn/icmf-course/delivery-chain/)
6. [06The factory chain: sending and receiving](https://chromia.com/learn/icmf-course/factory-chain/)
7. [07Test the dapp](https://chromia.com/learn/icmf-course/manual-testing/)

[Learn](https://chromia.com/learn/)[Event-driven multi-chain dapps with ICMF](https://chromia.com/learn/icmf-course/)

04 / 07Advanced

# Order chain (send message)

The order chain holds the purchase logic, much like a typical e-commerce checkout. Once an order completes, the chain automatically sends a message about it to the factory and delivery chains.

## Configuration

First, configure the order chain to use the `&sender` part you defined earlier. In `chromia.yml`, add the following under the `blockchains` property:

chromia.yml

```
blockchains:
  order_chain:
    module: order_chain
    config:
      <<: *sender
```

With this in place, the dapp has the infrastructure it needs to emit messages.

## Database Model

Create a directory named `src/order_chain`, and inside it add a `module.rell` file. This file is the module definition and needs exactly this content:

src/order\_chain/module.rell

```nolines
module;
```

The chain must record which orders were processed and what each one contained. Add a file named `entities.rell` to `src/order_chain` with this code:

src/order\_chain/entities.rell

```
entity order {
    key tx: byte_array = op_context.transaction.tx_rid;
    index customer_id: integer;
    address: text;
}

entity product {
    id: integer;
}

entity product_order {
    key order, product;
    quantity: integer;
}
```

The `product_order` entity represents the many-to-many relationship between orders and products, storing how many units of a given product were ordered. To let a client read this data, add some queries to `queries.rell`:

src/order\_chain/queries.rell

```
query list_orders() {
    val ordered_products = product_order @* {} (.order.rowid.to_integer(), (product_id = .product.id, quantity = .quantity));
    return group_products_by_id(ordered_products);
}

query get_order_id(tx: byte_array) = order @? { tx }.rowid;

query get_order_details(id: integer)
    = product_order @* { .order.rowid == rowid(id) } ( order_id = .order.rowid, product_id = .product.id, quantity = .quantity );

query get_order_details_by_tx(tx: byte_array) = get_order_details(require(get_order_id(tx)?.to_integer()));
```

Next, add a file named `functions.rell` to `src/order_chain` to hold these helper functions:

src/order\_chain/functions.rell

```
function group_products_by_id(value: list<(integer, (product_id:integer, quantity:integer))>) {
    val result = map<integer, list<(product_id:integer, quantity:integer)>>();
    for ((k, v) in value) {
        if (k not in result) result[k] = list<(product_id:integer, quantity:integer)>();
        result[k].add(v);
    }
    return result @* {} (order_id = $[0], details = $[1]);
}
```

You also need an easy way to add products to the catalog. Add a file named `operations.rell` to `src/order_chain` with the following code:

src/order\_chain/operations.rell

```
operation register_product(id: integer) {
    create product ( id );
}
```

## Sending a message

You can now create a customer order and tell the other chains about it. Start by importing the message types and messaging utilities into `src/order_chain/module.rell`:

src/order\_chain/module.rell

```
module;

import messages.{ msg, topic };
import lib.icmf.{ send_message };
```

Then define the operation a customer calls to place an order. Add this code to `src/order_chain/operations.rell`:

src/order\_chain/operations.rell

```
operation make_customer_order(details: msg.order_details) {
    val order = create order (
        customer_id = details.customer_id,
        address = details.address
    );
    val product_to_ids = product @* { .id in details.products @* { }.id }( $, .id );

    val ordered_products = list<struct<product_order>>();
    for ((p, id) in product_to_ids) {
        ordered_products.add(
        struct<product_order>(
            order = order,
            product = p,
            quantity = details.products @ { .id == id }.quantity
        )
        );
    }

    create product_order ( ordered_products );

    val order_id = order.rowid.to_integer();
    send_production_order(order_id, details.products);
    send_new_delivery(order_id, details.customer_id, details.address);
}
```

Add the following functions to `src/order_chain/functions.rell` as well. They send the order to production and start the delivery.

src/order\_chain/functions.rell

```
function send_production_order(order_id: integer, products: list<msg.product>) {
    send_message(
        topic.PRODUCTION_ORDER,
        msg.production_details(order_id, products).to_gtv()
    );
}

function send_new_delivery(order_id: integer, customer_id: integer, shipping_address: text) {
    send_message(
        topic.NEW_DELIVERY,
        msg.delivery_details(order_id, customer_id, shipping_address).to_gtv()
    );
}
```

The operation receives a struct with the order details. It creates the `order` and `product_order` entities, then sends the production order and the new delivery message. The calls to `send_message(topic: text, body: gtv)` are wrapped in helper functions for readability.

## Testing

To set up a test module for the order chain, add the following to the `blockchains:order_chain` section of `chromia.yml`.

chromia.yml

```
blockchains:
  order_chain:
    # ↓↓↓ Add this code snippet ↓↓↓
    test:
      modules:
        - test.order_chain_test
    # ↑↑↑ Add this code snippet ↑↑↑
```

Create a file named `order_chain_test.rell` in `src/test` and add this code:

src/test/order\_chain\_test.rell

```
@test module;

import order_chain.{ register_product, make_customer_order, order };
import messages.{ msg, topic };

function test_make_order() {
    val test_order = msg.order_details(0, "MyStreet 12", [msg.product(id = 12, quantity = 110)]);

    rell.test.tx().op(register_product(12)).run();
    rell.test.tx().op(make_customer_order(test_order)).run();
    val order_id = order @ { } ( .rowid.to_integer() );
    assert_events(
        (
        "icmf_message",
        (topic = topic.PRODUCTION_ORDER,
        body = msg.production_details(order_id, test_order.products).to_gtv())
            .to_gtv_pretty()),
        ("icmf_message",
        (topic = topic.NEW_DELIVERY,
        body = msg.delivery_details(order_id, customer_id = test_order.customer_id, test_order.address).to_gtv())
            .to_gtv_pretty())
    );
}
```

The test registers a product, places a customer order, and checks that the expected events were created. Run the tests, and you should see this output:

bash

```nolines
chr test
```

Result

```
Running tests for chain: order_chain
TEST: order_chain_test:test_make_order
OK: order_chain_test:test_make_order (0,628s)

------------------------------------------------------------
TEST RESULTS:

OK order_chain_test:test_make_order

SUMMARY: 0 FAILED / 1 PASSED / 1 TOTAL (0,628s)
```

For reference, here are the project structure and the full `chromia.yml` after these changes. Use them to compare against your own project at this point in the course:

Project structure

text

```
order-system-example/ ├── build/ ├── src/ │   ├── lib/ │   ├── order_chain/ │   │   ├── entities.rell │   │   ├── functions.rell │   │   ├── module.rell │   │   ├── operations.rell │   │   └── queries.rell │   ├── test/ │   │   └── order_chain_test.rell │   └── messages.rell ├── .gitignore └── chromia.yml
```

Final version of the `chromia.yml` file

chromia.yml

```
definitions:
  - &sender # Configuration for a chain that sends messages
    gtx:
      modules:
        - "net.postchain.d1.icmf.IcmfSenderGTXModule"
  - &receiver # Base configuration for a chain that receives messages
    gtx:
      modules:
        - "net.postchain.d1.icmf.IcmfReceiverGTXModule"
    sync_ext:
      - "net.postchain.d1.icmf.IcmfReceiverSynchronizationInfrastructureExtension"
  - &sender_receiver # Base configuration for a chain that will both send and receive messages
    gtx:
      modules:
        - "net.postchain.d1.icmf.IcmfSenderGTXModule"
        - "net.postchain.d1.icmf.IcmfReceiverGTXModule"
    sync_ext:
      - "net.postchain.d1.icmf.IcmfReceiverSynchronizationInfrastructureExtension"
blockchains:
  order_chain:
    module: order_chain
    config:
      <<: *sender
    test:
      modules:
        - test.order_chain_test
compile:
  rellVersion: 0.14.9
database:
  schema: schema_order_system_example
libs:
  icmf:
    registry: https://gitlab.com/chromaway/core/directory-chain
    path: src/lib/icmf
    tagOrBranch: 1.90.1
    rid: x"B56524EE85B679371EAB1A069B03BE6A3E94F36993DEA900747BA5BAE8B99122"
```

Written for this site from Chromia’s public course. Code samples are the course’s own.

[← Previous**Define messages**](https://chromia.com/learn/icmf-course/defining-messages/)[Next →**Delivery chain (receive message)**](https://chromia.com/learn/icmf-course/delivery-chain/)

On this page

* [Configuration](#configuration)
* [Database Model](#database-model)
* [Sending a message](#sending-a-message)
* [Testing](#testing)
