diff --git a/src/app/api/survey-sales/[id]/route.ts b/src/app/api/survey-sales/[id]/route.ts index eb718f4..6cc460a 100644 --- a/src/app/api/survey-sales/[id]/route.ts +++ b/src/app/api/survey-sales/[id]/route.ts @@ -2,20 +2,96 @@ import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { convertToSnakeCase } from '@/utils/common-utils' +interface Survey { + SRL_NO: string + SUBMISSION_STATUS: boolean + SUBMISSION_TARGET_ID: string | null + STORE_ID: string | null + CONSTRUCTION_POINT_ID: string | null +} + +interface SessionParams { + role: string | null + storeId: string | null + builderNo: string | null + isLoggedIn: string | null +} + +const checkT01Role = (survey: Survey): boolean => survey.SRL_NO !== '一時保存' + +const checkAdminRole = (survey: Survey, storeId: string | null): boolean => { + if (!storeId) return false + + if (survey.SUBMISSION_STATUS) { + return survey.SUBMISSION_TARGET_ID === storeId || survey.STORE_ID === storeId + } + return survey.STORE_ID === storeId +} + +const checkAdminSubRole = (survey: Survey, storeId: string | null): boolean => { + if (!storeId) return false + + if (survey.SUBMISSION_STATUS) { + return survey.SUBMISSION_TARGET_ID === storeId || (survey.STORE_ID === storeId && survey.CONSTRUCTION_POINT_ID === null) + } + return survey.STORE_ID === storeId && survey.CONSTRUCTION_POINT_ID === null +} + +const checkPartnerOrBuilderRole = (survey: Survey, builderNo: string | null): boolean => { + if (!builderNo) return false + return survey.CONSTRUCTION_POINT_ID === builderNo +} + +const checkRole = (survey: Survey, sessionParams: SessionParams): boolean => { + if (!survey || !sessionParams.role) return false + + switch (sessionParams.role) { + case 'T01': + return checkT01Role(survey) + // T01 이외 1차점 + case 'Admin': + return checkAdminRole(survey, sessionParams.storeId) + // 2차점 + case 'Admin_Sub': + return checkAdminSubRole(survey, sessionParams.storeId) + // partner + case 'Partner': + // 2차점 시공권한 user + case 'Builder': + return checkPartnerOrBuilderRole(survey, sessionParams.builderNo) + default: + return false + } +} + export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { try { const { id } = await params + const { searchParams } = new URL(request.url) + + const sessionParams: SessionParams = { + role: searchParams.get('role'), + storeId: searchParams.get('storeId'), + builderNo: searchParams.get('builderNo'), + isLoggedIn: searchParams.get('isLoggedIn'), + } // @ts-ignore - const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findUnique({ - where: { ID: Number(id) }, + const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ + where: { + ID: Number(id), + }, include: { DETAIL_INFO: true, }, }) - return NextResponse.json(survey) - } catch (error) { + if (checkRole(survey, sessionParams)) { + return NextResponse.json(survey) + } else { + return NextResponse.json({ error: '権限がありません。' }, { status: 403 }) + } + } catch (error: any) { console.error('Error fetching survey:', error) - return NextResponse.json({ error: 'Failed to fetch survey' }, { status: 500 }) + return NextResponse.json({ error: 'データの取得に失敗しました。' }, { status: 500 }) } } @@ -115,20 +191,18 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise< try { const { id } = await params const body = await request.json() - - 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(), - }, - }) - return NextResponse.json({ message: 'Survey confirmed successfully', data: survey }) - } + // @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, + SUBMISSION_TARGET_NM: body.targetNm, + UPT_DT: new Date(), + }, + }) + return NextResponse.json({ message: 'Survey confirmed successfully', data: survey }) } 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 a5d60c8..6d01bb0 100644 --- a/src/app/api/survey-sales/route.ts +++ b/src/app/api/survey-sales/route.ts @@ -11,7 +11,7 @@ type SearchParams = { sort?: string | null // 정렬 방식 offset?: string | null role?: string | null // 회원권한한 - store?: string | null // 판매점ID + storeId?: string | null // 판매점ID builderNo?: string | null // 시공ID } @@ -25,8 +25,10 @@ type WhereCondition = { const SEARCH_OPTIONS = [ 'BUILDING_NAME', // 건물명 'REPRESENTATIVE', // 담당자 - 'STORE', // 판매점 - 'CONSTRUCTION_POINT', // 시공점 + 'STORE', // 판매점명 + 'STORE_ID', // 판매점ID + 'CONSTRUCTION_POINT', // 시공점명 + 'CONSTRUCTION_POINT_ID', // 시공점ID 'CUSTOMER_NAME', // 고객명 'POST_CODE', // 우편번호 'ADDRESS', // 주소 @@ -75,11 +77,11 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { where.OR = [ { // 같은 판매점에서 작성한 제출/제출되지 않은 매물 - AND: [{ STORE_ID: { equals: params.store } }], + AND: [{ STORE_ID: { equals: params.storeId } }], }, { // MUSUBI (시공권한 X) 가 ORDER 에 제출한 매물 - AND: [{ SUBMISSION_TARGET_ID: { equals: params.store } }, { SUBMISSION_STATUS: { equals: true } }], + AND: [{ SUBMISSION_TARGET_ID: { equals: params.storeId } }, { SUBMISSION_STATUS: { equals: true } }], }, ] break @@ -88,19 +90,14 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { where.OR = [ { // MUSUBI (시공권한 X) 같은 판매점에서 작성한 제출/제출되지 않은 매물 - AND: [ - { STORE_ID: { equals: params.store } }, - { - OR: [{ CONSTRUCTION_POINT: { equals: null } }, { CONSTRUCTION_POINT: { equals: '' } }], - }, - ], + AND: [{ STORE_ID: { equals: params.storeId } }, { CONSTRUCTION_POINT_ID: { equals: params.builderNo } }], }, { // MUSUBI (시공권한 O) 가 MUSUBI 에 제출한 매물 + PARTNER 가 제출한 매물 AND: [ - { SUBMISSION_TARGET_ID: { equals: params.store } }, - { CONSTRUCTION_POINT: { not: null } }, - { CONSTRUCTION_POINT: { not: '' } }, + { SUBMISSION_TARGET_ID: { equals: params.storeId } }, + { CONSTRUCTION_POINT_ID: { not: null } }, + { CONSTRUCTION_POINT_ID: { not: '' } }, { SUBMISSION_STATUS: { equals: true } }, ], }, @@ -109,10 +106,9 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { case 'Builder': // MUSUBI (시공권한 O) case 'Partner': // PARTNER - // 시공점이 있고 STORE_ID가 시공ID와 같은 매물 + // 시공ID 같은 매물 where.AND?.push({ - CONSTRUCTION_POINT: { not: null }, - STORE_ID: { equals: params.builderNo }, + CONSTRUCTION_POINT_ID: { equals: params.builderNo }, }) break @@ -127,7 +123,7 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { }, { STORE_ID: { - equals: params.store, + equals: params.storeId, }, }, ] @@ -154,7 +150,7 @@ export async function GET(request: Request) { sort: searchParams.get('sort'), offset: searchParams.get('offset'), role: searchParams.get('role'), - store: searchParams.get('store'), //storeId + storeId: searchParams.get('storeId'), //storeId builderNo: searchParams.get('builderNo'), } diff --git a/src/components/pdf/SurveySaleDownloadPdf.tsx b/src/components/pdf/SurveySaleDownloadPdf.tsx index 02ba732..b987f04 100644 --- a/src/components/pdf/SurveySaleDownloadPdf.tsx +++ b/src/components/pdf/SurveySaleDownloadPdf.tsx @@ -10,7 +10,6 @@ import { useSpinnerStore } from '@/store/spinnerStore' export default function SurveySaleDownloadPdf() { const params = useParams() const id = params.id - const router = useRouter() const { surveyDetail, isLoadingSurveyDetail } = useSurvey(Number(id)) const { setIsShow } = useSpinnerStore() @@ -19,13 +18,13 @@ export default function SurveySaleDownloadPdf() { const isGeneratedRef = useRef(false) useEffect(() => { - setIsShow(true) if (isLoadingSurveyDetail || !surveyDetail || isGeneratedRef.current) return isGeneratedRef.current = true handleDownPdf() }, [surveyDetail?.id, isLoadingSurveyDetail]) const handleDownPdf = () => { + setIsShow(true) const options = { method: 'open' as const, resolution: Resolution.HIGH, @@ -50,12 +49,9 @@ export default function SurveySaleDownloadPdf() { generatePDF(targetRef, options).then(() => { setIsShow(false) - router.push(`/survey-sale/${id}`) + alert('PDFの生成が完了しました。 ポップアップウィンドウからダウンロードしてください。') }) } - const supplementList = supplementaryFacilities - .filter((facility) => surveyDetail?.detailInfo?.supplementaryFacilities?.includes(facility.id.toString())) - .map((facility) => facility.name) return ( <> @@ -249,11 +245,15 @@ export default function SurveySaleDownloadPdf() { boxSizing: 'border-box', }} > - {supplementList === null && surveyDetail?.detailInfo?.supplementaryFacilitiesEtc === null - ? '-' + {surveyDetail?.detailInfo?.supplementaryFacilities + ? supplementaryFacilities + .filter((facility) => surveyDetail?.detailInfo?.supplementaryFacilities?.includes(facility.id.toString())) + .map((facility) => facility.name) + .join(', ') + + (surveyDetail?.detailInfo?.supplementaryFacilitiesEtc ? `, ${surveyDetail?.detailInfo?.supplementaryFacilitiesEtc}` : '') : surveyDetail?.detailInfo?.supplementaryFacilitiesEtc - ? `${supplementList.join(', ')}, ${surveyDetail?.detailInfo?.supplementaryFacilitiesEtc}` - : supplementList.join(', ')} + ? `${surveyDetail?.detailInfo?.supplementaryFacilitiesEtc}` + : '-'} @@ -330,7 +330,11 @@ export default function SurveySaleDownloadPdf() { boxSizing: 'border-box', }} > - {surveyDetail?.detailInfo?.constructionYear === '1' ? '新築' : `既築 (${surveyDetail?.detailInfo?.constructionYear}年)`} + {surveyDetail?.detailInfo?.constructionYear === '1' + ? '新築' + : surveyDetail?.detailInfo?.constructionYearEtc + ? `既築 (${surveyDetail?.detailInfo?.constructionYear}年)` + : '-'} ([]) - const { getCommCode } = useCommCode() + const { surveyDetail } = useSurvey(Number(routeId)) + const [submitData, setSubmitData] = useState({ + saleBase: null, + targetId: null, + targetNm: null, + sender: '', + receiver: [], + reference: null, + title: '', + contents: '', + }) + + const [commCodeList, setCommCodeList] = useState([]) useEffect(() => { - if (session?.isLoggedIn && session?.role === 'Admin') { + if (!session?.isLoggedIn || !surveyDetail?.id) return + if (session?.role === 'Admin') { getCommCode('SALES_OFFICE_CD').then((codes) => { setCommCodeList(codes) }) } - }, [session]) + setSubmitData({ + ...submitData, + targetId: session?.role === 'Builder' ? surveyDetail?.storeId ?? null : null, + targetNm: session?.role === 'Builder' ? surveyDetail?.store ?? null : null, + sender: session?.email ?? '', + title: '[HANASYS現地調査] 調査物件が提出. (' + surveyDetail?.srlNo + ')', + }) + }, [session, surveyDetail]) const FORM_FIELDS: FormField[] = [ - { id: 'saleBase', name: '提出地点選択', required: session?.role === 'Admin' }, - { id: 'store', name: '提出販売店', required: true }, { id: 'sender', name: '発送者', required: true }, + { id: 'saleBase', name: '提出地点選択', required: session?.role === 'Admin' }, + { id: 'targetNm', name: '提出販売店', required: session?.role !== 'Admin' }, { id: 'receiver', name: '受信者', required: true }, { id: 'reference', name: '参考', required: false }, { id: 'title', name: 'タイトル', required: true }, - { id: 'contents', name: '内容', required: true }, + { id: 'contents', name: '内容', required: false }, ] - const [submitData, setSubmitData] = useState({ - saleBase: null, - store: '', - sender: session?.email ?? '', - receiver: [], - reference: null, - title: '[HANASYS現地調査] 調査物件が提出.', - contents: '', - }) - const { submitSurvey, isSubmittingSurvey } = useSurvey(Number(routeId)) const handleInputChange = (field: keyof SubmitFormData, value: string) => { @@ -74,7 +84,7 @@ export default function SurveySaleSubmitPopup() { const requiredFields = FORM_FIELDS.filter((field) => field.required) for (const field of requiredFields) { - if (data[field.id]?.length === 0) { + if (data[field.id] === '' || data[field.id] === null || data[field.id]?.length === 0) { alert(`${field.name}は必須入力項目です。`) const element = document.getElementById(field.id) if (element) { @@ -86,32 +96,38 @@ export default function SurveySaleSubmitPopup() { return true } + // TODO: Admin_Sub 계정 매핑된 submit target id 추가!!!! && 메일 테스트트 const handleSubmit = () => { if (validateData(submitData)) { window.neoConfirm('送信しますか? 送信後は変更・修正することはできません。', () => { setIsShow(true) - submitSurvey({ targetId: submitData.store }) sendEmail({ to: submitData.receiver, subject: submitData.title, - content: submitData.contents, + content: contentsRef.current?.innerHTML ?? '', }) .then(() => { - if (!isSubmittingSurvey) { - popupController.setSurveySaleSubmitPopup(false) - } - }) - .catch((error) => { - console.error('Error sending email:', error) - alert('メール送信に失敗しました。') + if (!isSubmittingSurvey) { + alert('提出が完了しました。') + // submitSurvey({ targetId: submitData.targetId, targetNm: submitData.targetNm }) + popupController.setSurveySaleSubmitPopup(false) + } + }) + .catch((error) => { + console.error('Error sending email:', error) + alert('メール送信に失敗しました。 再度送信してください。') }) .finally(() => { + submitSurvey({ targetId: submitData.targetId, targetNm: submitData.targetNm }) setIsShow(false) + popupController.setSurveySaleSubmitPopup(false) }) }) } } + const contentsRef = useRef(null) + const handleClose = () => { popupController.setSurveySaleSubmitPopup(false) } @@ -122,6 +138,9 @@ export default function SurveySaleSubmitPopup() { if (field.id === 'saleBase' && session?.role !== 'Admin') { return null } + if (field.id === 'targetNm' && session?.role === 'Admin') { + return null + } return (
@@ -130,12 +149,38 @@ export default function SurveySaleSubmitPopup() {
{field.id === 'contents' ? ( -