keyy1315 d690c3e774 refactor: improve error handling in API routes and services
- API 에러 시 반환 타입 통일
- Prisma 에러 검증 추가
2025-06-18 15:12:45 +09:00

122 lines
4.4 KiB
TypeScript

import { prisma } from '@/libs/prisma'
import { ERROR_MESSAGES } from '@/utils/common-utils'
import { SubmitTargetResponse } from '@/types/Survey'
import { HttpStatusCode } from 'axios'
import { ApiError } from 'next/dist/server/api-utils'
import { Prisma } from '@prisma/client'
export class SubmissionService {
private storeId: string
private role: string
private readonly BASE_QUERY = `
DECLARE @storeId NVARCHAR(50);
SET @storeId = @p1;
OPEN SYMMETRIC KEY SYMMETRICKEY DECRYPTION BY CERTIFICATE CERTI_QSPJP;
`
constructor(storeId: string, role: string) {
this.storeId = storeId
this.role = role
}
/**
* @description 제출 대상 조회
* @returns {Promise<SubmitTargetResponse[] | ApiError>} 제출 대상 데이터
*/
async getSubmissionTarget(): Promise<SubmitTargetResponse[] | ApiError> {
switch (this.role) {
case 'Admin_Sub':
return this.getSubmissionTargetAdminSub()
case 'Builder':
return this.getSubmissionTargetBuilder()
default:
return new ApiError(HttpStatusCode.BadRequest, ERROR_MESSAGES.BAD_REQUEST)
}
}
/**
* @description 2차점의 매핑 된 제출 대상 판매점 조회 (Admin_Sub - Musubi)
* @returns {Promise<SubmitTargetResponse[]>} 제출 대상 데이터
*/
private async getSubmissionTargetAdminSub(): Promise<SubmitTargetResponse[]> {
const query = `
SELECT
MCS.STORE_ID AS targetStoreId
, MCS.STORE_QCAST_NM AS targetStoreNm
, MCP.EOS_LOGIN_ID AS repUserId
, CONVERT(NVARCHAR(100), DecryptByKey(MCP.EMAIL)) AS repUserEmail
, MCP.AUTHORITY AS auth
FROM MS_CUST_STOREID MCS WITH(NOLOCK)
LEFT OUTER JOIN MS_CUST_PERSON MCP WITH(NOLOCK)
ON MCS.COMP_CD = MCP.COMP_CD
AND MCS.STORE_ID = MCP.STORE_ID
AND MCP.DEL_YN = 'N'
WHERE MCS.COMP_CD = '5200'
AND MCS.STORE_ID IN (SELECT STORE_ID FROM MS_CUST_AGENCY_STOREID WHERE AGENCY_STORE_ID = @storeId AND DEL_YN = 'N')
AND MCP.EMAIL IS NOT NULL
AND MCS.DEL_YN = 'N';
CLOSE SYMMETRIC KEY SYMMETRICKEY;
`
return await prisma.$queryRawUnsafe(this.BASE_QUERY + query, this.storeId)
}
/**
* @description 2차점 시공권한 user의 매핑 된 제출 대상 판매점 조회 (Builder - Musubi)
* @returns {Promise<SubmitTargetResponse[]>} 제출 대상 데이터
*/
private async getSubmissionTargetBuilder(): Promise<SubmitTargetResponse[]> {
const query = `
SELECT
MCAS.AGENCY_STORE_ID AS targetStoreId
, MCAS.AGENCY_QCAST_NM AS targetStoreNm
, BQU.USER_ID AS repUserId
, CONVERT(NVARCHAR(100), DecryptByKey(BQU.EMAIL)) AS repUserEmail
, BQU.USER_AUTH_CD AS auth
FROM MS_CUST_AGENCY_STOREID MCAS WITH(NOLOCK)
LEFT OUTER JOIN BC_QM_USER BQU WITH(NOLOCK)
ON MCAS.COMP_CD = BQU.COMP_CD
AND MCAS.AGENCY_STORE_ID = BQU.AGENCY_STORE_ID
AND MCAS.DEL_YN = 'N'
WHERE MCAS.COMP_CD = '5200'
AND MCAS.AGENCY_STORE_ID = @storeId
AND BQU.EMAIL IS NOT NULL
AND BQU.USER_AUTH_CD != 'B'
AND MCAS.DEL_YN = 'N';
CLOSE SYMMETRIC KEY SYMMETRICKEY;
`
return await prisma.$queryRawUnsafe(this.BASE_QUERY + query, this.storeId)
}
/**
* @description API ROUTE 에러 처리
* @param error 에러 객체
* @returns {ApiError} 에러 객체
*/
handleRouteError(error: any): ApiError {
console.error('❌ API ROUTE ERROR : ', error)
if (
error instanceof Prisma.PrismaClientInitializationError ||
error instanceof Prisma.PrismaClientUnknownRequestError ||
error instanceof Prisma.PrismaClientRustPanicError ||
error instanceof Prisma.PrismaClientValidationError ||
error instanceof Prisma.PrismaClientUnknownRequestError
) {
return new ApiError(HttpStatusCode.InternalServerError, ERROR_MESSAGES.PRISMA_ERROR)
}
return new ApiError(error.statusCode ?? HttpStatusCode.InternalServerError, error.message ?? ERROR_MESSAGES.FETCH_ERROR)
}
/**
* @description 비동기 함수 try-catch 처리 함수
* @param func 비동기 함수
* @returns {Promise<ApiError | any>} 에러 객체 또는 함수 결과
*/
async tryFunction(func: () => Promise<any>): Promise<ApiError | any> {
try {
return await func()
} catch (error) {
return this.handleRouteError(error)
}
}
}