Skip to content

1. Membuat Order dan List Order

Alt text

1. Membuat Module, Controller, Service untuk order dan detail_order

terminal
npx nest g module app/order
npx nest g controller app/order
npx nest g service app/order

npx nest g module app/order_detail
npx nest g controller app/order_detail
npx nest g service app/order_detail

2. Membuat Entity order

order.entity.ts
import {
  Entity,
  BaseEntity,
  PrimaryGeneratedColumn,
  Column,
  ManyToOne,
  JoinColumn,
  OneToMany,
} from 'typeorm';
import { User } from '../auth/auth.entity';
import { Konsumen } from '../konsumen/konsumen.entity';
import { OrderDetail } from '../order_detail/detail_order.entity';

export enum Status {
  BAYAR = 'bayar',
  BELUM = 'belum bayar',
}

@Entity()
export class Order extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ nullable: false })
  nomor_order: string;

  @Column({ nullable: false })
  tanggal_order: Date;

  @Column({
    type: 'enum',
    enum: Status,
    default: Status.BELUM,
  })
  status: Status;

  @Column({ type: 'double', precision: 18, scale: 2, nullable: false })
  total_bayar: number;

  @ManyToOne(() => Konsumen, (v) => v.order, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'konsumen_id' })
  konsumen: Konsumen;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'created_by' })
  created_by: User;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'updated_by' })
  updated_by: User;

  @OneToMany(() => OrderDetail, (v) => v.order, {
    onDelete: 'CASCADE',
    cascade: ['insert', 'update'],
  })
  order_detail: OrderDetail[];

  @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
  created_at: Date;

  @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
  updated_at: Date;
}

Note

@OneToMany(() => OrderDetail, (v) => v.order, {onDelete: 'CASCADE' cascade: ['insert', 'update'],})

Pada kode di atas, kita membuat relasi pada tabel order detail dengan menambkahkan

  • onDelete: 'CASCADE' : ketika data di order di hapus , maka semua data yang adda di order_detail yang berelasi akan ikut di hapus
  • cascade: ['insert', 'update'] : ketika insert dan update maka order detail juga akan dipebaharui.

3. Membuat Entity detail_order

order_detail.entity.ts
import {
  Entity,
  BaseEntity,
  PrimaryGeneratedColumn,
  Column,
  ManyToOne,
  JoinColumn,
} from 'typeorm';
import { User } from '../auth/auth.entity';
import { Produk } from '../produk/produk.entity';
import { Order } from '../order/order.entity';

@Entity()
export class OrderDetail extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ nullable: false })
  jumlah: number;

  @ManyToOne(() => Produk, (v) => v.order_detail, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'produk_id' })
  produk: Produk;

  @ManyToOne(() => Order, (v) => v.order_detail, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'order_id' })
  order: Order;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'created_by' })
  created_by: User;

  @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
  created_at: Date;

  @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
  updated_at: Date;
}

4. Membuat DTO pada order

order.dto.ts
import { OmitType, PartialType } from '@nestjs/mapped-types';
import { Type } from 'class-transformer';
import {
  IsArray,
  IsInt,
  IsNotEmpty,
  IsObject,
  IsOptional,
  IsString,
  ValidateNested,
  IsIn,
  IsNumber,
  IsDate,
} from 'class-validator';
import { PageRequestDto } from 'src/utils/dto/page.dto';
import { Status } from './order.entity';
import { OrderDetailDto } from '../order_detail/detail_order.dto';

export class OrderDto {
  @IsInt()
  id: number;

  @IsString()
  @IsOptional()
  nomor_order: string;

  @IsDate()
  @IsNotEmpty()
  tanggal_order: Date;

  @IsString()
  @IsNotEmpty()
  @IsIn([Status.BAYAR, Status.BELUM])
  status: Status;

  @IsNumber()
  @IsNotEmpty()
  total_bayar: number;

  @IsNumber()
  @IsNotEmpty()
  konsumen_id: number;

  @IsObject()
  @IsOptional()
  updated_by: { id: number };

  @IsObject()
  @IsOptional()
  created_by: { id: number };

  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => OrderDetailDto)
  order_detail: OrderDetailDto[];
}

export class CreateOrderDto extends OmitType(OrderDto, ['id', 'updated_by']) {}

export class UpdateOrderDto extends PartialType(OrderDto) {
  @IsInt()
  @IsNotEmpty()
  id: number;
}
export class CreateOrderArrayDto {
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => CreateOrderDto)
  data: CreateOrderDto[];
}
export class findAllOrderDto extends PageRequestDto {
  @IsString()
  @IsOptional()
  nomor_order: string;

  @IsString()
  @IsOptional()
  nama_konsumen: string;

  @IsString()
  @IsOptional()
  dari_order_tanggal: Date;

  @IsString()
  @IsOptional()
  sampai_order_tanggal: Date;

  @IsOptional()
  @IsNumber()
  @Type(() => Number)
  dari_total_bayar: number;

  @IsOptional()
  @IsNumber()
  @Type(() => Number)
  sampai_total_bayar: number;

  @IsString()
  @IsOptional()
  status: string;
}

5. Membuat DTO pada detail_order

order_detail.dto.ts
import { OmitType } from '@nestjs/mapped-types';
import { IsInt, IsObject, IsOptional, IsNumber } from 'class-validator';

export class OrderDetailDto {
  @IsInt()
  @IsOptional()
  id?: number;

  @IsNumber()
  jumlah: number;

  @IsObject()
  produk: { id: number };

  @IsObject()
  @IsOptional()
  updated_by: { id: number };
  @IsObject()
  @IsOptional()
  created_by: { id: number };
}

6. Membuat Endpoint create order

Service create order

order.service.ts
import {
  HttpException,
  HttpStatus,
  Inject,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import BaseResponse from 'src/utils/response/base.response';
import { Between, Like, Repository } from 'typeorm';
import { Order } from './order.entity';
import { ResponsePagination, ResponseSuccess } from 'src/interface/response';
import { CreateOrderDto, UpdateOrderDto, findAllOrderDto } from './order.dto';
import { REQUEST } from '@nestjs/core';
import { Workbook } from 'exceljs';
import { Response } from 'express';

@Injectable()
export class OrderService extends BaseResponse {
  constructor(
    @InjectRepository(Order)
    private readonly orderRepository: Repository<Order>,
    @Inject(REQUEST) private req: any,
  ) {
    super();
  }

  generateInvoice(): string {
    return `INV` + new Date().getTime();
  }

  async createOrder(payload: CreateOrderDto): Promise<ResponseSuccess> {

    try {
      const invoice = this.generateInvoice();
      payload.nomor_order = invoice;

      payload.order_detail &&
        payload.order_detail.forEach((item) => {
          item.created_by = this.req.user.id;
        });

      await this.orderRepository.save({
        ...payload,
        konsumen: {
          id: payload.konsumen_id,
        },
      });

      return this._success('OK');
    } catch (err) {
      console.log('err', err);
      throw new HttpException('Ada Kesalahan', HttpStatus.UNPROCESSABLE_ENTITY);
    }
  }  
}

Controller create order

order.controller.ts
import {
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Put,
  Res,
  UseGuards,
} from '@nestjs/common';
import { OrderService } from './order.service';
import { JwtGuard } from '../auth/auth.guard';
import { InjectCreatedBy } from 'src/utils/decorator/inject-created_by.decorator';
import { CreateOrderDto, UpdateOrderDto, findAllOrderDto } from './order.dto';
import { Pagination } from 'src/utils/decorator/pagination.decorator';
import { InjectUpdatedBy } from 'src/utils/decorator/inject-updated_by.decorator';
import { Response } from 'express';

@UseGuards(JwtGuard)
@Controller('order')
export class OrderController {
  constructor(private readonly orderService: OrderService) {}

  @Post('tambah')
  async createOrder(@InjectCreatedBy() payload: CreateOrderDto) {
    return this.orderService.createOrder(payload);
  }


}

Pengujian di Postman

Alt text

payload
 {
     "tanggal_order" : "2023-09-01",
     "status" : "belum bayar",
     "total_bayar" : 200000,
     "konsumen_id" : 1,
     "order_detail" : [
         {
             "jumlah" : 10,

             "produk" : {
                 "id" : 1
             }


         },
         {
             "jumlah" : 10,

             "produk" : {
                 "id" : 3
             }


         }
     ]
 }

Setelah success silahkan cek di tabel order dan tabel detail_order

tabel order

Alt text

tabel order_detail

Alt text

7. Membuat Endpoint list order

Service list order

order.service.ts
async findAll(query: findAllOrderDto): Promise<ResponsePagination> {
    const {
      page,
      pageSize,
      limit,
      nomor_order,
      dari_order_tanggal,
      sampai_order_tanggal,
      status,
      dari_total_bayar,
      sampai_total_bayar,
      nama_konsumen,
    } = query;

    const filterQuery: any = [];

    if (nomor_order) {
      filterQuery.nomor_order = Like(`%${nomor_order}%`);
    }

    if (nama_konsumen) {
      filterQuery.konsumen = {
        nama_konsumen: Like(`%${nama_konsumen}%`),
      };
    }
    if (status) {
      filterQuery.status = Like(`%${status}%`);
    }
    if (dari_total_bayar && sampai_total_bayar) {
      filterQuery.total_bayar = Between(dari_total_bayar, sampai_total_bayar);
    }
    if (dari_total_bayar && !!sampai_total_bayar === false) {
      filterQuery.total_bayar = Between(dari_total_bayar, dari_total_bayar);
    }

    if (dari_order_tanggal && sampai_order_tanggal) {
      filterQuery.tanggal_order = Between(
        dari_order_tanggal,
        sampai_order_tanggal,
      );
    }
    if (dari_order_tanggal && !!sampai_order_tanggal === false) {
      filterQuery.tanggal_order = Between(
        dari_order_tanggal,
        sampai_order_tanggal,
      );
    }

    const total = await this.orderRepository.count({
      where: filterQuery,
    });

    const result = await this.orderRepository.find({
      where: filterQuery,
      relations: [
        'created_by',
        'konsumen',
        'order_detail',
        'order_detail.produk',
      ],
      select: {
        id: true,
        nomor_order: true,
        status: true,
        total_bayar: true,
        tanggal_order: true,

        konsumen: {
          id: true,
          nama_konsumen: true,
        },
        created_by: {
          id: true,
          nama: true,
        },

        order_detail: {
          id: true,

          jumlah: true,
          produk: {
            nama_produk: true,
          },
        },
      },

      skip: limit,
      take: pageSize,
    });
    return this._pagination('OK', result, total, page, pageSize);
  }

Controller list order

order.controller.ts
@Get('list')
  async listOrder(@Pagination() query: findAllOrderDto) {
    return this.orderService.findAll(query);
  }

Alt text