CreateOrder

김종민·2022년 7월 5일
0

Nuber-Server

목록 보기
27/34

들어가기
order를 만드는 방법
매우 어려우므로 집중해야함.
특히, option부분이 매우 난해함.
option(name, choice, extra)부분

1. orders/dtos/create-order.dto.ts

 
import { Field, InputType, Int, ObjectType } from '@nestjs/graphql';
import { MutationOutput } from 'src/common/dtos/output.dto';
import { OrderItemOption } from '../entities/order-item.entity';

@InputType()
class CreateOrderItemInput {
  @Field(() => Int)
  dishId: number;

  @Field(() => OrderItemOption, { nullable: true })
  options?: OrderItemOption[];
}

@InputType()
export class CreateOrderInput {
  @Field(() => Int)
  restaurantId: number;
  ///식당 Id가 들어가야함.

  @Field(() => [CreateOrderItemInput])
  items: CreateOrderItemInput[];
  ///주문할 음식(items)은 CreateOrderItemInput배열로 받음!!
}

@ObjectType()
export class CreateOrderOutput extends MutationOutput {}

!!.CreateOrderInput Dto는 restaurantId와 items:CreateOrderItemInput[] 두개로 한다.
!!.CreateOrderItemInput은 dishId와 dishId의 dish에 따른 options:OrderItemOption[]으로
구성된다. OrderItemOption은 order-item.entity안에 만들어 놓은것임.

2. orders/orders.resolver.ts

import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { AuthUser } from 'src/auth/auth-user.decorator';
import { Role } from 'src/auth/role.decorator';
import { User } from 'src/users/entities/user.entity';
import { CreateOrderInput, CreateOrderOutput } from './dtos/create-order.dto';
import { Order } from './entities/order.entity';
import { OrdersService } from './orders.service';

@Resolver(() => Order)
export class OrdersResolver {
  constructor(private readonly ordersService: OrdersService) {}

  @Mutation(() => CreateOrderOutput)
  @Role(['Client']) ///Order는 Client만 만들수 있게 한다.
  async createOrder(
    @AuthUser() customer: User,  ///loggedInUser는 customer:User로 받는다.
    @Args('input') createOrderInput: CreateOrderInput,
  ): Promise<CreateOrderOutput> {
    return this.ordersService.createOrder(customer, createOrderInput);
  }
  ///customer와 createOrderInput를 넣는다.
}

3. orders/orders.service.ts

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Dish } from 'src/restaurant/entities/dish.entity';
import { Restaurant } from 'src/restaurant/entities/restaurant.entity';
import { User } from 'src/users/entities/user.entity';
import { Repository } from 'typeorm';
import { CreateOrderInput, CreateOrderOutput } from './dtos/create-order.dto';
import { OrderItem } from './entities/order-item.entity';
import { Order } from './entities/order.entity';

@Injectable()
export class OrdersService {
  constructor(
    @InjectRepository(Order)
    private readonly orders: Repository<Order>,
    @InjectRepository(Restaurant)
    private readonly restaurants: Repository<Restaurant>,
    @InjectRepository(OrderItem)
    private readonly orderItems: Repository<OrderItem>,
    @InjectRepository(Dish)
    private readonly dishes: Repository<Dish>,
  ) {}
  ///createOrder를 위해서 Order, Restaurant, OrderItem, Dish
  ///Entity를 모두 불러준다.

  async createOrder(
    customer: User,
    { restaurantId, items }: CreateOrderInput,
  ): Promise<CreateOrderOutput> {
  ///restaurantId와 items를 input한다.
  ///items는 CreateOrderItemInput[]
  ///CreateOrderItemInput은 
  ///@InputType()
  ///class CreateOrderItemInput {
 /// @Field(() => Int)
 /// dishId: number;
 /// @Field(() => OrderItemOption, { nullable: true })
 /// options?: OrderItemOption[]; OrderItemOption[]은 oreder-item entity안에있음
 /// name:string, choice?:string, extra:number로 구성됨.

  
    try {
      const restaurant = await this.restaurants.findOne(restaurantId);
      if (!restaurant) {
        return {
          ok: false,
          error: 'Restaurant not found',
        };
      }
      ///먼저, 입력받은 restaurantId로 restaurant찾음. 없음 error
      
      let orderFinalPrice = 0;
      ///주문 최종가격을 let으로 설정해서 일단 0으로 잡아놓음.
      
      const orderItems: OrderItem[] = [];
      ///orderItems를 만들어서 빈배열을 default값으로!
      ///type은 OrderItem[]배열로! OrederItem은 dish, options로 구성된 entity
      
      for (const item of items) {
      ///맨 위에서 restaurantId와 함께 입력받은 items를 하나씩 구분함.
      ///items는 (dishId와 options)로 구성됨.
        const dish = await this.dishes.findOne(item.dishId);
        ///dishId로 item의 dish를 찾음.
        if (!dish) {
          return {
            ok: false,
            error: 'Dish not found',
          };
        }
        ///못찾으면 error를 리턴함.
        
        let dishFinalPrice = dish.price;
        ///dish가격을 let으로 설정해 놓음.

        for (const itemOption of item.options) {
        ///분리한 각각의 item의 option들을 분리함.(사이즈, 맵기정도, 토핑등등)
        ///item.option은 OrderItemOption으로 oreder-item entity안에있음
        
          const dishOption = dish.options.find(
            (dishOption) => dishOption.name === itemOption.name,
          );
          ///dish option에서 Order option이랑 같은 단어를 찾음.
          ///Size:L 라고Order option에서 입력한 거를 dish option에서
          ///찾아서 return해줌. 여기서 name은 Size, 맛등을 말함.
          ///choice는 XL, L, sm, very Spice, Spice등등..
          ///아래에 dish entity의 DishOption이랑, DishChoice를 참고할 것.
          
          if (dishOption) {
            if (dishOption.extra) {
              dishFinalPrice = dishFinalPrice + dishOption.extra;
              ///json이 일치하는 option에 extra라 있으면, dishFinalPrice에 더함.
              
            } else {
              const dishOptionChoice = dishOption.choices.find(
                (optionChoice) => optionChoice.name === itemOption.choice,
              );
              ///dishOption.choices Entity에서 item.Options.choice와
              ///name이 같은 것을 찾아서 optionChoice로 return 해줌.
              
              if (dishOptionChoice) {
                if (dishOptionChoice.extra) {
                  dishFinalPrice = dishFinalPrice + dishOptionChoice.extra;
                }
                ///찾은 option에 Extra가 있으면, dishFinalPrice에 더해줌.
              }
            }
          }
        }
        orderFinalPrice = orderFinalPrice + dishFinalPrice;
        ///다 더해진 dishFinalPrice를 orderFinalPrice에 더해줌.
        
        const orderItem = await this.orderItems.save(
          this.orderItems.create({
            dish,
            options: item.options,
          }),
        );
        ///OrderItem entity에 위에서 나온 dish와 options들을 더해서
        ///orderItem을 만들고 저장해줌.
        
        
        orderItems.push(orderItem);
        ///orederItems에 위에서 만든 orderItem을 push해 줌.
      }
      
      await this.orders.save(
        this.orders.create({
          customer,
          restaurant,
          total: orderFinalPrice,
          items: orderItems,
        }),
      );
      ///위에서 만든것들을, orders entity에 create 및 save해줌.
      
      return {
        ok: true,
      };
    } catch {
      return {
        ok: false,
        error: 'Could not create Order.',
      };
    }
  }
}

dish.entity.ts

@InputType('DishChoiceInputType', { isAbstract: true })
@ObjectType()
export class DishChoice {
  @Field(() => String)
  name: string;

  @Field(() => Int, { nullable: true })
  extra?: number;
}

@InputType('DishOptionInputType', { isAbstract: true })
@ObjectType()
export class DishOption {
  @Field(() => String)
  name: string;

  @Field(() => [DishChoice], { nullable: true })
  choices?: DishChoice[];

  @Field(() => Int, { nullable: true })
  extra?: number;
}

지금까지 만든 API중에 가장 어려운 부분이니
집중해서 봐야할 부분.

profile
코딩하는초딩쌤

0개의 댓글