From d9a8cbedc3c36d679a3a84e4b2bb6aefb765495b Mon Sep 17 00:00:00 2001 From: Seunghee Lee <49032882+eeseung@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:36:13 +0900 Subject: [PATCH] =?UTF-8?q?feat(BE):=20=EC=9D=98=EA=B3=BC=20=EC=95=BD?= =?UTF-8?q?=ED=92=88=20=ED=9E=88=EC=8A=A4=ED=86=A0=EB=A6=AC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20API=20=EA=B5=AC=ED=98=84=20(#72)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: deletedAt 컬럼 select 옵션 수정 * feat: 의과 약품 히스토리 조회 DTO 추가 * feat: 의과 약품 히스토리 조회 API 구현 --- .../entity/m_medicine_categories.entity.ts | 2 +- .../m-medicines/entity/m-medicines.entity.ts | 2 +- .../paginate-m-prescription-history.dto.ts | 22 +++++ .../m-prescriptions.controller.ts | 20 +++++ .../m-prescriptions.service.ts | 80 +++++++++++++++++++ 5 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 backend/src/m-prescriptions/dto/paginate-m-prescription-history.dto.ts diff --git a/backend/src/m-medicine-categories/entity/m_medicine_categories.entity.ts b/backend/src/m-medicine-categories/entity/m_medicine_categories.entity.ts index cf3d204..7463fec 100644 --- a/backend/src/m-medicine-categories/entity/m_medicine_categories.entity.ts +++ b/backend/src/m-medicine-categories/entity/m_medicine_categories.entity.ts @@ -17,7 +17,7 @@ export class M_Medicine_Categories extends BaseModel { subCategory: string; /** 소분류 삭제 여부 */ - @DeleteDateColumn({ select: false }) + @DeleteDateColumn() deletedAt: Date | null; @OneToMany(() => M_Medicines, (medicine) => medicine.category) diff --git a/backend/src/m-medicines/entity/m-medicines.entity.ts b/backend/src/m-medicines/entity/m-medicines.entity.ts index bab42cc..709a8e9 100644 --- a/backend/src/m-medicines/entity/m-medicines.entity.ts +++ b/backend/src/m-medicines/entity/m-medicines.entity.ts @@ -95,7 +95,7 @@ export class M_Medicines extends BaseModel { isExcluded: boolean; /** 삭제 여부 */ - @DeleteDateColumn({ select: false }) + @DeleteDateColumn() deletedAt: Date | null; @OneToMany(() => M_Prescriptions, (prescription) => prescription.medicine) diff --git a/backend/src/m-prescriptions/dto/paginate-m-prescription-history.dto.ts b/backend/src/m-prescriptions/dto/paginate-m-prescription-history.dto.ts new file mode 100644 index 0000000..4269f26 --- /dev/null +++ b/backend/src/m-prescriptions/dto/paginate-m-prescription-history.dto.ts @@ -0,0 +1,22 @@ +import { ApiPropertyOptional, OmitType } from '@nestjs/swagger'; +import { IsOptional, IsString } from 'class-validator'; +import { BasePaginationDto } from 'src/common/dto/base-pagination.dto'; + +export class PaginateMPrescriptionHistoryDto extends OmitType( + BasePaginationDto, + ['page'], +) { + @ApiPropertyOptional({ + description: '약품명', + }) + @IsString() + @IsOptional() + name: string; + + @ApiPropertyOptional({ + description: '성분명/함량', + }) + @IsString() + @IsOptional() + ingredient: string; +} diff --git a/backend/src/m-prescriptions/m-prescriptions.controller.ts b/backend/src/m-prescriptions/m-prescriptions.controller.ts index 8b7a38d..d7c66f9 100644 --- a/backend/src/m-prescriptions/m-prescriptions.controller.ts +++ b/backend/src/m-prescriptions/m-prescriptions.controller.ts @@ -2,14 +2,17 @@ import { Body, Controller, Delete, + Get, HttpStatus, Param, ParseIntPipe, Patch, + Query, } from '@nestjs/common'; import { MPrescriptionsService } from './m-prescriptions.service'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { UpdateMPrescriptionDto } from './dto/update-m-prescription.dto'; +import { PaginateMPrescriptionHistoryDto } from './dto/paginate-m-prescription-history.dto'; @ApiTags('의과') @Controller('m/prescriptions') @@ -50,4 +53,21 @@ export class MPrescriptionsController { ) { return this.mPrescriptionsService.deletePrescription(prescriptionId); } + + @Get('history/:startDate/:endDate') + @ApiOperation({ + summary: '히스토리 조회', + description: 'cursor pagination - cursor 쿼리 파라미터를 이용해야 합니다.', + }) + async getMPrescriptionHistory( + @Param('startDate') startDate: string, + @Param('endDate') endDate: string, + @Query() paginateMPrescriptionHistoryDto: PaginateMPrescriptionHistoryDto, + ) { + return this.mPrescriptionsService.getPaginateHistory( + startDate, + endDate, + paginateMPrescriptionHistoryDto, + ); + } } diff --git a/backend/src/m-prescriptions/m-prescriptions.service.ts b/backend/src/m-prescriptions/m-prescriptions.service.ts index 30c7923..0f1cc22 100644 --- a/backend/src/m-prescriptions/m-prescriptions.service.ts +++ b/backend/src/m-prescriptions/m-prescriptions.service.ts @@ -10,6 +10,8 @@ import { CreateMPrescriptionDto } from './dto/create-m-prescription.dto'; import { M_Charts } from 'src/m-charts/entity/m-charts.entity'; import { M_Medicines } from 'src/m-medicines/entity/m-medicines.entity'; import { UpdateMPrescriptionDto } from './dto/update-m-prescription.dto'; +import { PaginateMPrescriptionHistoryDto } from './dto/paginate-m-prescription-history.dto'; +import { endOfDay, startOfDay } from 'date-fns'; @Injectable() export class MPrescriptionsService { @@ -103,4 +105,82 @@ export class MPrescriptionsService { return prescriptionId; } + + async getPaginateHistory( + startDate: string, + endDate: string, + paginateDto: PaginateMPrescriptionHistoryDto, + ) { + const start = startOfDay(startDate); + const end = endOfDay(endDate); + + if (start.getTime() > end.getTime()) { + throw new BadRequestException('날짜를 올바르게 설정해주세요.'); + } + + const query = this.mPrescriptionsRepository + .createQueryBuilder('prescription') + .withDeleted() + .innerJoinAndSelect('prescription.medicine', 'medicine') + .leftJoinAndSelect( + 'medicine.category', + 'category', + 'medicine.categoryId = category.id', + ) + .where('prescription.isCompleted = :isCompleted', { isCompleted: true }) + .andWhere('prescription.createdAt >= :start', { start }) + .andWhere('prescription.createdAt <= :end', { end }); + + if (paginateDto.name) { + query.andWhere('medicine.name like :name', { + name: `%${paginateDto.name}%`, + }); + } + if (paginateDto.ingredient) { + query.andWhere('medicine.ingredient like :ingredient', { + ingredient: `%${paginateDto.ingredient}%`, + }); + } + if (paginateDto.cursor) { + query.andWhere('medicine.id < :cursor', { cursor: paginateDto.cursor }); + } + + query + .select([ + 'prescription.medicineId', + 'medicine.id', + 'medicine.name', + 'medicine.ingredient', + 'medicine.totalAmount', + 'medicine.deletedAt', + 'category.mainCategory', + 'category.subCategory', + 'category.deletedAt', + ]) + .addSelect('SUM(prescription.dosesTotal) as dosesTotalSum') + .groupBy('prescription.medicineId') + .orderBy({ 'medicine.id': 'DESC' }) + .limit(paginateDto.take); + + const data = await query.getRawMany(); + const count = await query.getCount(); + let hasNext: boolean = true; + let cursor: number; + + if (count <= paginateDto.take || data.length <= 0) { + hasNext = false; + cursor = null; + } else { + cursor = data[data.length - 1].medicine_id; + } + + return { + data: data, + meta: { + count: data.length, + cursor, + hasNext, + }, + }; + } }