diff --git a/src/app/api/survey-sales/[id]/route.ts b/src/app/api/survey-sales/[id]/route.ts index 415d1e6..db5c9df 100644 --- a/src/app/api/survey-sales/[id]/route.ts +++ b/src/app/api/survey-sales/[id]/route.ts @@ -19,34 +19,55 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ } } +const getNewSrlNo = async (srlNo: string, storeId: string) => { + let newSrlNo = srlNo + console.log('srlNo:: ', srlNo) + if (srlNo.startsWith('一時保存')) { + //@ts-ignore + const lastSurvey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ + where: { + SRL_NO: { + startsWith: storeId, + }, + }, + orderBy: { + ID: 'desc', + }, + }) + const lastNo = lastSurvey ? parseInt(lastSurvey.SRL_NO.slice(-3)) : 0 + newSrlNo = + storeId + + new Date().getFullYear().toString().slice(-2) + + (new Date().getMonth() + 1).toString().padStart(2, '0') + + new Date().getDate().toString().padStart(2, '0') + + (lastNo + 1).toString().padStart(3, '0') + } + return newSrlNo +} + export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { try { const { id } = await params const body = await request.json() - const { DETAIL_INFO, ...basicInfo } = body + const { detailInfo, ...basicInfo } = body.survey - console.log('body:: ', body) + // PUT 요청 시 임시저장 여부 확인 후 임시저장 시 기존 SRL_NO 사용, 기본 저장 시 새로운 SRL_NO 생성 + const newSrlNo = body.isTemporary ? body.survey.srlNo : await getNewSrlNo(body.survey.srlNo, body.storeId) // @ts-ignore const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.update({ where: { ID: Number(id) }, data: { ...convertToSnakeCase(basicInfo), + SRL_NO: newSrlNo, UPT_DT: new Date(), - DETAIL_INFO: DETAIL_INFO ? { - upsert: { - create: convertToSnakeCase(DETAIL_INFO), - update: convertToSnakeCase(DETAIL_INFO), - where: { - BASIC_INFO_ID: Number(id) - } - } - } : undefined + DETAIL_INFO: { + update: convertToSnakeCase(detailInfo), + }, }, include: { - DETAIL_INFO: true - } + DETAIL_INFO: true, + }, }) - console.log('survey:: ', survey) return NextResponse.json(survey) } catch (error) { console.error('Error updating survey:', error) @@ -92,49 +113,24 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise< const { id } = await params const body = await request.json() - if (body.submit) { + // 제출 시 기존 SRL_NO 확인 후 '임시저장'으로 시작하면 새로운 SRL_NO 생성 + const newSrlNo = await getNewSrlNo(body.srlNo, body.storeId) + + if (body.targetId) { // @ts-ignore const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.update({ where: { ID: Number(id) }, data: { SUBMISSION_STATUS: true, SUBMISSION_DATE: new Date(), + SUBMISSION_TARGET_ID: body.targetId, UPT_DT: new Date(), + SRL_NO: newSrlNo, }, }) + console.log(survey) return NextResponse.json({ message: 'Survey confirmed successfully' }) } - // } else { - // // @ts-ignore - // const hasDetails = await prisma.SD_SURVEY_SALES_DETAIL_INFO.findUnique({ - // where: { BASIC_INFO_ID: Number(id) }, - // }) - - // if (hasDetails) { - // //@ts-ignore - // const result = await prisma.SD_SURVEY_SALES_BASIC_INFO.update({ - // where: { ID: Number(id) }, - // data: { - // UPT_DT: new Date(), - // DETAIL_INFO: { - // update: convertToSnakeCase(body.DETAIL_INFO), - // }, - // }, - // }) - // return NextResponse.json(result) - // } else { - // // @ts-ignore - // const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.update({ - // where: { ID: Number(id) }, - // data: { - // DETAIL_INFO: { - // create: convertToSnakeCase(body.DETAIL_INFO), - // }, - // }, - // }) - // return NextResponse.json({ message: 'Survey detail created successfully' }) - // } - // } } catch (error) { console.error('Error updating survey:', error) return NextResponse.json({ error: 'Failed to update survey' }, { status: 500 }) diff --git a/src/app/api/survey-sales/route.ts b/src/app/api/survey-sales/route.ts index 3298f5d..7d51802 100644 --- a/src/app/api/survey-sales/route.ts +++ b/src/app/api/survey-sales/route.ts @@ -1,6 +1,7 @@ import { NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { convertToSnakeCase } from '@/utils/common-utils' +import { equal } from 'assert' /** * 검색 파라미터 */ @@ -87,13 +88,14 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { switch (params.role) { case 'Admin': // 1차점 - // 같은 판매점에서 작성된 매물 + 2차점에서 제출받은 매물 where.OR = [ { + // 같은 판매점에서 작성한 제출/제출되지 않은 매물 AND: [{ STORE: { equals: params.store } }], }, { - AND: [{ STORE: { startsWith: params.store } }, { SUBMISSION_STATUS: { equals: true } }], + // MUSUBI (시공권한 X) 가 ORDER 에 제출한 매물 + AND: [{ SUBMISSION_TARGET_ID: { equals: params.store } }, { SUBMISSION_STATUS: { equals: true } }], }, ] break @@ -101,6 +103,7 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { case 'Admin_Sub': // 2차점 where.OR = [ { + // MUSUBI (시공권한 X) 같은 판매점에서 작성한 제출/제출되지 않은 매물 AND: [ { STORE: { equals: params.store } }, { @@ -109,8 +112,9 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { ], }, { + // MUSUBI (시공권한 O) 가 MUSUBI 에 제출한 매물 + PARTNER 가 제출한 매물 AND: [ - { STORE: { equals: params.store } }, + { SUBMISSION_TARGET_ID: { equals: params.store } }, { CONSTRUCTION_POINT: { not: null } }, { CONSTRUCTION_POINT: { not: '' } }, { SUBMISSION_STATUS: { equals: true } }, @@ -119,8 +123,8 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { ] break - case 'Builder': // 2차점 시공권한 - case 'Partner': // Partner + case 'Builder': // MUSUBI (시공권한 O) + case 'Partner': // PARTNER // 같은 시공ID에서 작성된 매물 where.AND?.push({ CONSTRUCTION_POINT: { equals: params.builderNo }, @@ -128,6 +132,21 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { break case 'T01': + where.OR = [ + { + NOT: { + SRL_NO: { + startsWith: '一時保存', + }, + }, + }, + { + STORE: { + equals: params.store, + }, + }, + ] + break case 'User': // 모든 매물 조회 가능 (추가 조건 없음) break @@ -219,22 +238,47 @@ export async function PUT(request: Request) { } } -export async function POST(request: Request) { +export async function POST(request: Request) { try { const body = await request.json() - console.log('body:: ', body) - const { detailInfo, ...basicInfo } = body + // 임시 저장 시 임시저장 + 000 으로 저장 + // 기본 저장 시 판매점ID + yyMMdd + 000 으로 저장 + const baseSrlNo = + body.survey.srlNo ?? + body.storeId + + new Date().getFullYear().toString().slice(-2) + + (new Date().getMonth() + 1).toString().padStart(2, '0') + + new Date().getDate().toString().padStart(2, '0') - // 기본 정보 생성 - //@ts-ignore + // @ts-ignore + const lastSurvey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ + where: { + SRL_NO: { + startsWith: body.storeId, + }, + }, + orderBy: { + SRL_NO: 'desc', + }, + }) + + // 마지막 번호 추출 + const lastNumber = lastSurvey ? parseInt(lastSurvey.SRL_NO.slice(-3)) : 0 + + // 새로운 srlNo 생성 - 임시저장일 경우 '임시저장' 으로 저장 + const newSrlNo = baseSrlNo.startsWith('一時保存') ? baseSrlNo : baseSrlNo + (lastNumber + 1).toString().padStart(3, '0') + + const { detailInfo, ...basicInfo } = body.survey + // @ts-ignore const result = await prisma.SD_SURVEY_SALES_BASIC_INFO.create({ data: { ...convertToSnakeCase(basicInfo), + SRL_NO: newSrlNo, DETAIL_INFO: { - create: convertToSnakeCase(detailInfo) - } - } + create: convertToSnakeCase(detailInfo), + }, + }, }) return NextResponse.json(result) } catch (error) { diff --git a/src/components/survey-sale/detail/BasicForm.tsx b/src/components/survey-sale/detail/BasicForm.tsx index 0942abb..b984101 100644 --- a/src/components/survey-sale/detail/BasicForm.tsx +++ b/src/components/survey-sale/detail/BasicForm.tsx @@ -25,7 +25,7 @@ export default function BasicForm(props: { basicInfo: SurveyBasicRequest; setBas setBasicInfo({ ...basicInfo, representative: session.userNm ?? '', - store: session.storeNm ?? null, + store: session.role === 'Partner' ? null : session.storeNm ?? null, constructionPoint: session.builderNo ?? null, }) } diff --git a/src/components/survey-sale/detail/ButtonForm.tsx b/src/components/survey-sale/detail/ButtonForm.tsx index a22ac5c..8f8e3dd 100644 --- a/src/components/survey-sale/detail/ButtonForm.tsx +++ b/src/components/survey-sale/detail/ButtonForm.tsx @@ -22,8 +22,15 @@ export default function ButtonForm(props: { const params = useParams() const routeId = params.id - const [isSubmitProcess, setIsSubmitProcess] = useState(false) // ------------------------------------------------------------ + const [saveData, setSaveData] = useState({ + ...props.data.basic, + detailInfo: props.data.roof, + }) + + // !!!!!!!!!! + const [tempTargetId, setTempTargetId] = useState('') + // -------------------------------------------------------------- // 권한 // 제출권한 ㅇ @@ -34,39 +41,63 @@ export default function ButtonForm(props: { useEffect(() => { if (session?.isLoggedIn) { - setIsSubmiter(session.storeNm === props.data.basic.store && session.builderNo === props.data.basic.constructionPoint) + switch (session?.role) { + // T01 제출권한 없음 + case 'T01': + setIsSubmiter(false) + break + // 1차 판매점(Order) + 2차 판매점(Musubi) => 같은 판매점 제출권한 + case 'Admin': + case 'Admin_Sub': + setIsSubmiter(session.storeNm === props.data.basic.store && session.builderNo === props.data.basic.constructionPoint) + break + // 시공권한 User(Musubi) + Partner => 같은 시공ID 제출권한 + case 'Builder': + case 'Partner': + setIsSubmiter(session.builderNo === props.data.basic.constructionPoint) + break + default: + setIsSubmiter(false) + break + } + setIsWriter(session.userNm === props.data.basic.representative) } + setSaveData({ + ...props.data.basic, + detailInfo: props.data.roof, + }) }, [session, props.data]) // ------------------------------------------------------------ // 저장/임시저장/수정 + const id = Number(routeId) ? Number(routeId) : Number(idParam) - const id = routeId ? Number(routeId) : Number(idParam) const { deleteSurvey, submitSurvey, updateSurvey } = useServey(Number(id)) const { validateSurveyDetail, createSurvey } = useServey() - let saveData = { - ...props.data.basic, - detailInfo: props.data.roof, - } - const handleSave = (isTemporary: boolean) => { + const handleSave = (isTemporary: boolean, isSubmitProcess = false) => { const emptyField = validateSurveyDetail(props.data.roof) - console.log('handleSave, emptyField:: ', emptyField) + const hasEmptyField = emptyField?.trim() !== '' + if (isTemporary) { - tempSaveProcess() + hasEmptyField ? tempSaveProcess() : saveProcess(emptyField, false) } else { - saveProcess(emptyField) + saveProcess(emptyField, isSubmitProcess) } } const tempSaveProcess = async () => { if (idParam) { - await updateSurvey(saveData) - router.push(`/survey-sale/detail?id=${idParam}&isTemporary=true`) + await updateSurvey({ survey: saveData, isTemporary: true }) + router.push(`/survey-sale/${idParam}`) } else { - const id = await createSurvey(saveData) - router.push(`/survey-sale/detail?id=${id}&isTemporary=true`) + const updatedData = { + ...saveData, + srlNo: '一時保存', + } + const id = await createSurvey(updatedData) + router.push(`/survey-sale/${id}`) } alert('一時保存されました。') } @@ -78,30 +109,40 @@ export default function ButtonForm(props: { } } - const saveProcess = async (emptyField: string) => { - if (emptyField.trim() === '') { + const saveProcess = async (emptyField: string | null, isSubmitProcess?: boolean) => { + if (emptyField?.trim() === '') { if (idParam) { - // 수정 페이지에서 작성 후 제출 if (isSubmitProcess) { - saveData = { + const updatedData = { ...saveData, submissionStatus: true, submissionDate: new Date().toISOString(), + submissionTargetId: tempTargetId, } + await updateSurvey({ survey: updatedData, isTemporary: false, storeId: session.storeId ?? '' }) + router.push(`/survey-sale/${idParam}`) + } else { + await updateSurvey({ survey: saveData, isTemporary: false, storeId: session.storeId ?? '' }) + router.push(`/survey-sale/${idParam}`) } - await updateSurvey(saveData) - router.push(`/survey-sale/${idParam}`) } else { - const id = await createSurvey(saveData) if (isSubmitProcess) { + const updatedData = { + ...saveData, + submissionStatus: true, + submissionDate: new Date().toISOString(), + submissionTargetId: tempTargetId, + } + const id = await createSurvey(updatedData) submitProcess(id) - return + } else { + const id = await createSurvey(saveData) + router.push(`/survey-sale/${id}`) } - router.push(`/survey-sale/${id}`) } alert('保存されました。') } else { - if (emptyField.includes('Unit')) { + if (emptyField?.includes('Unit')) { alert('電気契約容量の単位を入力してください。') focusInput(emptyField as keyof SurveyDetailInfo) } else { @@ -123,17 +164,25 @@ export default function ButtonForm(props: { } const handleSubmit = async () => { + if (props.data.basic.srlNo?.startsWith('一時保存')) { + alert('一時保存されたデータは提出できません。') + return + } + if (tempTargetId.trim() === '') { + alert('提出対象店舗を入力してください。') + return + } window.neoConfirm('提出しますか?', async () => { - setIsSubmitProcess(true) - if (routeId) { + if (Number(routeId)) { submitProcess() } else { - handleSave(false) + handleSave(false, true) } }) } + const submitProcess = async (saveId?: number) => { - await submitSurvey(saveId) + await submitSurvey({ saveId: saveId, targetId: tempTargetId, storeId: session.storeId ?? '', srlNo: '一時保存' }) alert('提出されました。') router.push('/survey-sale') } @@ -159,7 +208,7 @@ export default function ButtonForm(props: { {(isWriter || !isSubmiter) && } - {!isSubmit && isSubmiter && } + {!isSubmit && isSubmiter && } )} @@ -170,7 +219,7 @@ export default function ButtonForm(props: { - + {session?.role !== 'T01' && }{' '} )} @@ -210,15 +259,20 @@ function EditButton(props: { setMode: (mode: Mode) => void; id: string; mode: Mo ) } -function SubmitButton(props: { handleSubmit: () => void }) { - const { handleSubmit } = props +function SubmitButton(props: { handleSubmit: () => void; setTempTargetId: (targetId: string) => void }) { + const { handleSubmit, setTempTargetId } = props return ( -
- {/* 제출 */} - -
+ <> +
+ {/* 제출 */} + +
+
+ setTempTargetId(e.target.value)} /> +
+ ) } @@ -256,7 +310,6 @@ function TempButton(props: { setMode: (mode: Mode) => void; handleSave: (isTempo +
調査物件登録
diff --git a/src/hooks/useSurvey.ts b/src/hooks/useSurvey.ts index 043cfce..1bfa614 100644 --- a/src/hooks/useSurvey.ts +++ b/src/hooks/useSurvey.ts @@ -65,9 +65,9 @@ export function useServey(id?: number): { isDeletingSurvey: boolean createSurvey: (survey: SurveyRegistRequest) => Promise createSurveyDetail: (params: { surveyId: number; surveyDetail: SurveyDetailCoverRequest }) => void - updateSurvey: (survey: SurveyRegistRequest) => void + updateSurvey: ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string }) => void deleteSurvey: () => Promise - submitSurvey: (saveId?: number) => void + submitSurvey: (params: { saveId?: number; targetId?: string; storeId?: string; srlNo?: string }) => void validateSurveyDetail: (surveyDetail: SurveyDetailRequest) => string getZipCode: (zipCode: string) => Promise refetchSurveyList: () => void @@ -119,7 +119,7 @@ export function useServey(id?: number): { const { mutateAsync: createSurvey, isPending: isCreatingSurvey } = useMutation({ mutationFn: async (survey: SurveyRegistRequest) => { - const resp = await axiosInstance(null).post('/api/survey-sales', survey) + const resp = await axiosInstance(null).post('/api/survey-sales', { survey: survey, storeId: session?.storeId ?? null }) return resp.data.id ?? 0 }, onSuccess: (data) => { @@ -130,10 +130,14 @@ export function useServey(id?: number): { }) const { mutate: updateSurvey, isPending: isUpdatingSurvey } = useMutation({ - mutationFn: async (survey: SurveyRegistRequest) => { + mutationFn: async ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string }) => { console.log('updateSurvey, survey:: ', survey) if (id === undefined) throw new Error('id is required') - const resp = await axiosInstance(null).put(`/api/survey-sales/${id}`, survey) + const resp = await axiosInstance(null).put(`/api/survey-sales/${id}`, { + survey: survey, + isTemporary: isTemporary, + storeId: storeId, + }) return resp.data }, onSuccess: () => { @@ -166,11 +170,13 @@ export function useServey(id?: number): { }) const { mutateAsync: submitSurvey } = useMutation({ - mutationFn: async (saveId?: number) => { + mutationFn: async ({ saveId, targetId, storeId, srlNo }: { saveId?: number; targetId?: string; storeId?: string; srlNo?: string }) => { const submitId = saveId ?? id if (!submitId) throw new Error('id is required') const resp = await axiosInstance(null).patch(`/api/survey-sales/${submitId}`, { - submit: true, + targetId, + storeId, + srlNo, }) return resp.data }, diff --git a/src/types/Survey.ts b/src/types/Survey.ts index 36e7aa5..8066836 100644 --- a/src/types/Survey.ts +++ b/src/types/Survey.ts @@ -14,6 +14,8 @@ export type SurveyBasicInfo = { detailInfo: SurveyDetailInfo | null regDt: Date uptDt: Date + submissionTargetId: string | null + srlNo: string | null //판매점IDyyMMdd000 } export type SurveyDetailInfo = { @@ -70,6 +72,8 @@ export type SurveyBasicRequest = { addressDetail: string | null submissionStatus: boolean submissionDate: string | null + submissionTargetId: string | null + srlNo: string | null //판매점IDyyMMdd000 } export type SurveyDetailRequest = { @@ -127,6 +131,8 @@ export type SurveyRegistRequest = { submissionStatus: boolean submissionDate: string | null detailInfo: SurveyDetailRequest | null + submissionTargetId: string | null + srlNo: string | null //판매점IDyyMMdd000 } export type Mode = 'CREATE' | 'EDIT' | 'READ' | 'TEMP' // 등록 | 수정 | 상세 | 임시저장