# Order

Now, it's time for the order logic. In the **CreateDTO**, we'll need to start from scratch. To create an order, a payload must be received with a <mark style="color:blue;">`customer`</mark> and the order's <mark style="color:blue;">`items`</mark>. We already know that the <mark style="color:blue;">`customer`</mark> can be represented by the <mark style="color:blue;">`IdDto`</mark>, but what about the <mark style="color:blue;">`items`</mark>? How do we represent a single <mark style="color:blue;">`item`</mark>?

An <mark style="color:blue;">`orderItem`</mark> will be represented by its own DTO, containing the <mark style="color:blue;">`product`</mark> and <mark style="color:blue;">`quantity`</mark>. The <mark style="color:blue;">`price`</mark> won't be present as we should not allow any possibility of arbitrary prices being sent, don't you think? It's safer to search for it directly in the database.

Let's then begin by creating it in <mark style="color:purple;">orders</mark>/<mark style="color:purple;">dto</mark>/<mark style="color:purple;">order-item.dto</mark> with following content. We can see that, using everything we learned so far, our validation is becoming elegant and consistent.

```typescript
export class OrderItemDto {
  @IsEntity()
  readonly product: IdDto;

  @IsCardinal()
  readonly quantity: number;
}
```

Then, we should also create an **identifier** for the <mark style="color:blue;">`OrderItemDto`</mark>. Note that we check if <mark style="color:blue;">`product`</mark> exists before accessing it.

```typescript
export const orderItemDtoIdentifier = (dto: OrderItemDto) => dto.product?.id;
```

This may even be encapsulated into an **object of constants** that contains all the **identifier functions**, and they should follow the signature of <mark style="color:blue;">`ArrayUniqueIdentifier`</mark> to be compliant with the <mark style="color:blue;">`@ArrayUnique()`</mark> validator. After that, also adjust accordingly in the <mark style="color:blue;">`CreateProductDto`</mark>.

```typescript
export const IdentifierFn = {
  ID_DTO: (dto: IdDto) => dto.id,
  ORDER_ITEM_DTO: (dto: OrderItemDto) => dto.product?.id,
} as const satisfies Record<string, ArrayUniqueIdentifier>;
```

We can now conclude our <mark style="color:blue;">`CreateOrderDto`</mark>.

```typescript
export class CreateOrderDto {
  @IsEntity()
  readonly customer: IdDto;

  @ArrayNotEmpty()
  @ArrayUnique(IdentifierFn.ORDER_ITEM_DTO)
  @ValidateNested()
  @Type(() => OrderItemDto)
  readonly items: OrderItemDto[];
}
```

{% hint style="info" %}
Here, we're not obliged to use <mark style="color:blue;">`@IsDefined()`</mark> because <mark style="color:blue;">`@ArrayNotEmpty()`</mark> already enforces that the field should be an array, and not empty.
{% endhint %}

{% hint style="info" %}
An order **cannot be changed** once created. Because of that, we can delete the **UpdateDTO** file, along with the <mark style="color:blue;">`update()`</mark> method in both the **controller** and **service**.
{% endhint %}

Going now into the **service**, we can copy the product's structure, as it will be pretty similar. An <mark style="color:blue;">`order`</mark> will be fetched together with its <mark style="color:blue;">`items`</mark> and their respective <mark style="color:blue;">`products`</mark>, along with its <mark style="color:blue;">`customer`</mark> and <mark style="color:blue;">`payment`</mark>. Therefore, we can already add these relations to the <mark style="color:blue;">`findAll()`</mark> and <mark style="color:blue;">`findOne()`</mark> methods.

```typescript
relations: {
  items: {
    product: true,
  },
  customer: true,
  payment: true,
},
```

We must now write an auxiliary method that will receive the <mark style="color:blue;">`orderItemDto`</mark> and will then find its <mark style="color:blue;">`product`</mark>'s <mark style="color:blue;">`price`</mark> in the database to then return an <mark style="color:blue;">`orderItem`</mark> with a <mark style="color:blue;">`price`</mark>. Let's do so at the bottom of the service.

```typescript
private async createOrderItemWithPrice(orderItemDto: OrderItemDto) {
  const { id } = orderItemDto.product;

  const product = await this.productsRepository.findOneBy({ id });
  if (!product) {
    throw new NotFoundException('Product not found');
  }
  const { price } = product;

  const orderItem = this.orderItemsRepository.create({
    ...orderItemDto,
    price,
  });
  return orderItem;
}
```

{% hint style="info" %}
Remember to inject a <mark style="color:blue;">`Repository`</mark> for <mark style="color:blue;">`OrderItem`</mark> and <mark style="color:blue;">`Product`</mark>, and also register them inside the <mark style="color:blue;">`TypeOrmModule`</mark> in the <mark style="color:blue;">`OrdersModule`</mark>.
{% endhint %}

Finally, the <mark style="color:blue;">`create()`</mark> method will be written. We shall transform all the <mark style="color:blue;">`items`</mark> that came to also have a <mark style="color:blue;">`price`</mark>. We'll do this with the help of <mark style="color:blue;">`Promise.all()`</mark> as all the searches can be done in parallel, which is more performant. At last, the <mark style="color:blue;">`order`</mark> is saved.

```typescript
async create(createOrderDto: CreateOrderDto) {
  const { items } = createOrderDto;

  const itemsWithPrice = await Promise.all(
    items.map((item) => this.createOrderItemWithPrice(item)),
  );

  const order = this.ordersRepository.create({
    ...createOrderDto,
    items: itemsWithPrice,    
  });
  return this.ordersRepository.save(order);
}
```

{% hint style="info" %}
Due to the <mark style="color:blue;">`cascade`</mark> option we set earlier, we are saving in the database both the <mark style="color:blue;">`order`</mark> and its <mark style="color:blue;">`items`</mark>.
{% endhint %}

<mark style="color:green;">**Commit**</mark> - Implementing order logic and saving with cascade


---

# 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://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/core-module-backend-development-with-nestjs/remaining-domain/logic/order.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.
