Skip to content

Commit

Permalink
✨ add return module #114
Browse files Browse the repository at this point in the history
add return module #114
  • Loading branch information
sichoi42 committed Nov 5, 2022
1 parent 03d0a37 commit 083a67f
Show file tree
Hide file tree
Showing 11 changed files with 517 additions and 6 deletions.
4 changes: 4 additions & 0 deletions backend/src/v3/lent/lent.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,8 @@ export class LentTools {
runOnTransactionComplete((err) => err && this.logger.error(err));
return excepction_type;
}

async getLentCabinetId(user_id: number): Promise<number> {
return await this.lentRepository.getLentCabinetId(user_id);
}
}
1 change: 1 addition & 0 deletions backend/src/v3/lent/lent.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ const repo = {
controllers: [LentController],
providers: [LentService, repo, LentTools],
imports: [AuthModule, TypeOrmModule.forFeature([Lent, User, Cabinet])], // for JWTAuthGuard
exports: [LentTools],
})
export class LentModule {}
8 changes: 8 additions & 0 deletions backend/src/v3/lent/repository/lent.repository.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,12 @@ export interface ILentRepository {
* @return void
*/
setExpireTime(lent_id: number, expire_time: Date): Promise<void>;

/**
* 해당 user_id로 대여중인 Cabinet id를 반환합니다.
* 실패 시,
* @param user_id
* @return number
*/
getLentCabinetId(user_id: number): Promise<number>;
}
15 changes: 15 additions & 0 deletions backend/src/v3/lent/repository/lent.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,19 @@ export class LentRepository implements ILentRepository {
})
.execute();
}

async getLentCabinetId(user_id: number): Promise<number> {
const result = await this.lentRepository.findOne({
select: {
lent_cabinet_id: true,
},
where: {
lent_user_id: user_id,
},
});
if (result === null) {
return null;
}
return result.lent_cabinet_id;
}
}
12 changes: 12 additions & 0 deletions backend/src/v3/return/dto/return.cabinet.data.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Lent from 'src/entities/lent.entity';
import CabinetStatusType from 'src/enums/cabinet.status.type.enum';
import LentType from 'src/enums/lent.type.enum';

/**
* 캐비넷을 대여하기 전 캐비넷에 대한 최소 정보
*/
export class ReturnCabinetDataDto {
status: CabinetStatusType; // 사물함의 상태
lent_type: LentType; // 사물함의 타입
lents: Lent[]; // 해당 사물함을 대여하고 있는 lent 배열
}
46 changes: 45 additions & 1 deletion backend/src/v3/return/repository/return.repository.interface.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,46 @@
import Lent from "src/entities/lent.entity";
import { UserDto } from "src/v3/lent/dto/user.dto";
import { ReturnCabinetDataDto } from "../dto/return.cabinet.data.dto";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IReturnRepository {}
export interface IReturnRepository {
/**
* 해당 유저가 존재하는지 확인합니다.
* @param user_id
*/
getUserIfExist(user_id: number): Promise<UserDto>;

/**
* 대여중인 사물함을 반납하기 위해 사물함에 대한 정보를 가져옴.
* @param cabinet_id
* @return ReturnCabinetDataDto
**/
getReturnCabinetData(cabinet_id: number): Promise<ReturnCabinetDataDto>;

/**
* cabinet title, memo를 null로 설정함.
* @param cabinet_id
*/
clearCabinetInfo(cabinet_id: number): Promise<void>;

/**
* user_id에 대응하는 Lent값을 삭제합니다.
* 해당 Lent 값을 반환합니다.
* @param user_id
* @return void
*/
deleteLentByLentId(lent_id: number): Promise<void>;

/**
* 기존 lent 정보를 lent log에 추가합니다.
* @param Lent
* @return void
*/
addLentLog(lent: Lent, user: UserDto, cabinet_id: number): Promise<void>;

/**
* 해당 캐비넷을 대여중인 유저들의 user_id를 반환합니다.
* @param cabinet_id
*/
getUsersByCabinetId(cabinet_id: number): Promise<number[]>;
}
123 changes: 123 additions & 0 deletions backend/src/v3/return/repository/return.repository.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,133 @@
import { InjectRepository } from '@nestjs/typeorm';
import Cabinet from 'src/entities/cabinet.entity';
import Lent from 'src/entities/lent.entity';
import LentLog from 'src/entities/lent.log.entity';
import User from 'src/entities/user.entity';
import { UserDto } from 'src/v3/lent/dto/user.dto';
import { Repository } from 'typeorm';
import { IsolationLevel, Propagation, Transactional } from 'typeorm-transactional';
import { ReturnCabinetDataDto } from '../dto/return.cabinet.data.dto';
import { IReturnRepository } from './return.repository.interface';

export class ReturnRepository implements IReturnRepository {
constructor(
@InjectRepository(Cabinet) private cabinetRepository: Repository<Cabinet>,
@InjectRepository(User) private userRepository: Repository<User>,
@InjectRepository(Lent) private lentRepository: Repository<Lent>,
@InjectRepository(LentLog) private lentLogRepository: Repository<LentLog>,
) {}

async getUserIfExist(user_id: number): Promise<UserDto> {
const result = await this.userRepository.findOne({
where: {
user_id: user_id,
}
})
if (!result) {
return null;
}
return {
user_id: result.user_id,
intra_id: result.intra_id,
};
}

@Transactional({
propagation: Propagation.REQUIRED,
isolationLevel: IsolationLevel.SERIALIZABLE,
})
async getReturnCabinetData(
cabinet_id: number,
): Promise<ReturnCabinetDataDto> {
const result = await this.cabinetRepository.find({
relations: {
lent: true,
},
select: {
status: true,
lent_type: true,
lent: true,
},
where: {
cabinet_id: cabinet_id,
},
lock: {
mode: 'pessimistic_write',
},
});
if (result.length === 0) {
return null;
}
return {
status: result[0].status,
lent_type: result[0].lent_type,
lents: result[0].lent,
};
}

@Transactional({
propagation: Propagation.REQUIRED,
isolationLevel: IsolationLevel.SERIALIZABLE,
})
async clearCabinetInfo(cabinet_id: number): Promise<void> {
await this.cabinetRepository
.createQueryBuilder()
.update({
title: null,
memo: null,
})
.where({
cabinet_id: cabinet_id,
})
.execute();
}

@Transactional({
propagation: Propagation.REQUIRED,
isolationLevel: IsolationLevel.SERIALIZABLE,
})
async deleteLentByLentId(lent_id: number): Promise<void> {
await this.lentRepository
.createQueryBuilder(this.deleteLentByLentId.name)
.delete()
.from(Lent)
.where({
lent_id: lent_id,
})
.execute();
}

async addLentLog(
lent: Lent,
user: UserDto,
cabinet_id: number,
): Promise<void> {
await this.lentLogRepository
.createQueryBuilder(this.addLentLog.name)
.insert()
.into(LentLog)
.values({
log_user_id: user.user_id,
log_intra_id: user.intra_id,
log_cabinet_id: cabinet_id,
lent_time: lent.lent_time,
return_time: new Date(),
})
.execute();
}

async getUsersByCabinetId(cabinet_id: number): Promise<number[]> {
const result = await this.lentRepository.find({
select: {
lent_user_id: true,
},
where: {
lent_cabinet_id: cabinet_id,
}
});
if (result.length === 0) {
return null;
}
return result.map((lent) => lent.lent_user_id);
}
}
103 changes: 103 additions & 0 deletions backend/src/v3/return/return.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { forwardRef, Inject, Injectable, Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import Lent from "src/entities/lent.entity";
import CabinetStatusType from "src/enums/cabinet.status.type.enum";
import { LentService } from "src/lent/lent.service";
import { ILentRepository } from "src/lent/repository/lent.repository.interface";
import { IsolationLevel, Propagation, runOnTransactionComplete, Transactional } from "typeorm-transactional";
import { CabinetService } from "../cabinet/cabinet.service";
import { UserDto } from "../lent/dto/user.dto";
import { IReturnRepository } from "./repository/return.repository.interface";
import { ReturnService } from "./return.service";

@Injectable()
export class ReturnTools {
private logger = new Logger(ReturnTools.name);
constructor(
@Inject('IReturnRepository')
private returnRepository: IReturnRepository,
private cabinetService: CabinetService,
@Inject(forwardRef(() => ReturnService))
private lentService: LentService,
// private banService: BanService,
@Inject(ConfigService) private configService: ConfigService,
) {}

@Transactional({
propagation: Propagation.REQUIRED,
isolationLevel: IsolationLevel.SERIALIZABLE,
})
async clearCabinetInfo(cabinet_id: number): Promise<void> {
this.logger.debug(`Called ${ReturnTools.name} ${this.clearCabinetInfo.name}`);
await this.returnRepository.clearCabinetInfo(cabinet_id);
}

@Transactional({
propagation: Propagation.REQUIRED,
isolationLevel: IsolationLevel.SERIALIZABLE,
})
async returnStateTransition(
cabinet_id: number,
user: UserDto,
): Promise<Lent> {
this.logger.debug(
`Called ${ReturnTools.name} ${this.returnStateTransition.name}`,
);
// 대여하고 있는 유저들의 대여 정보를 포함하는 cabinet 정보를 가져옴.
// 가져오는 정보 : 캐비넷 상태, 캐비넷 대여타입, 캐비넷을 빌린 사람들의 인원 수
const cabinet = await this.returnRepository.getReturnCabinetData(cabinet_id);
const lent = cabinet.lents.filter(
(lent) => lent.lent_user_id === user.user_id,
)[0];
const lent_count = cabinet.lents.length;
// 2. cabinet_status에 따라 처리.
switch (cabinet.status) {
case CabinetStatusType.AVAILABLE:
if (lent_count - 1 === 0) {
await this.clearCabinetInfo(cabinet_id);
}
break;
case CabinetStatusType.SET_EXPIRE_FULL:
// TODO: Cabinet 모듈이 구현되면 해당 모듈에서 가져와서 사용.
// await this.cabinetInfoService.updateCabinetStatus(
// cabinet_id,
// CabinetStatusType.SET_EXPIRE_AVAILABLE,
// );
case CabinetStatusType.SET_EXPIRE_AVAILABLE:
if (lent_count - 1 === 0) {
// TODO: Cabinet 모듈이 구현되면 해당 모듈에서 가져와서 사용.
// await this.cabinetInfoService.updateCabinetStatus(
// cabinet_id,
// CabinetStatusType.AVAILABLE,
// );
await this.clearCabinetInfo(cabinet_id);
}
break;
case CabinetStatusType.BANNED:
case CabinetStatusType.EXPIRED:
// TODO: 해당 상태에서 반납을 했을 때 메인에서는 연체 누적 연체 일수만큼 패널티를 주게 되는데
// 이 부분은 어드민에서도 유지를 하는게 좋을까요?
// const overdue = await this.banService.calDateDiff(
// lent.expire_time,
// new Date(),
// );
// const cumulative = await this.banService.addOverdueDays(user.user_id);
// await this.banService.blockingUser(lent, overdue + cumulative, false);
// if (
// cabinet.status === CabinetStatusType.EXPIRED &&
// lent_count - 1 === 0
// ) {
// // TODO: Cabinet 모듈이 구현되면 해당 모듈에서 가져와서 사용.
// // await this.cabinetInfoService.updateCabinetStatus(
// // cabinet_id,
// // CabinetStatusType.AVAILABLE,
// // );
// }
break;
}
// 3. Lent Table에서 값 제거.
await this.returnRepository.deleteLentByLentId(lent.lent_id);
runOnTransactionComplete((err) => err && this.logger.error(err));
return lent;
}
}
Loading

0 comments on commit 083a67f

Please sign in to comment.